Sync with trunk (r48545)
[reactos.git] / drivers / filesystems / fastfat_new / fastfat.c
1 /*
2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/fastfat.c
5 * PURPOSE: Initialization routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* GLOBALS ******************************************************************/
15
16 FAT_GLOBAL_DATA FatGlobalData;
17 FAST_MUTEX FatCloseQueueMutex;
18
19 /* FUNCTIONS ****************************************************************/
20
21
22 NTSTATUS
23 NTAPI
24 DriverEntry(PDRIVER_OBJECT DriverObject,
25 PUNICODE_STRING RegistryPath)
26 {
27 PDEVICE_OBJECT DeviceObject;
28 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Fat");
29 NTSTATUS Status;
30
31 /* Create a device object */
32 Status = IoCreateDevice(DriverObject,
33 0,
34 &DeviceName,
35 FILE_DEVICE_DISK_FILE_SYSTEM,
36 0,
37 FALSE,
38 &DeviceObject);
39
40 if (!NT_SUCCESS(Status)) return Status;
41
42 /* Zero global storage */
43 RtlZeroMemory(&FatGlobalData, sizeof(FAT_GLOBAL_DATA));
44 FatGlobalData.DriverObject = DriverObject;
45 FatGlobalData.DiskDeviceObject = DeviceObject;
46 FatGlobalData.SystemProcess = PsGetCurrentProcess();
47
48 /* Fill major function handlers */
49 DriverObject->MajorFunction[IRP_MJ_CLOSE] = FatClose;
50 DriverObject->MajorFunction[IRP_MJ_CREATE] = FatCreate;
51 DriverObject->MajorFunction[IRP_MJ_READ] = FatRead;
52 DriverObject->MajorFunction[IRP_MJ_WRITE] = FatWrite;
53 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = FatFileSystemControl;
54 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = FatQueryInformation;
55 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = FatSetInformation;
56 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = FatDirectoryControl;
57 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = FatQueryVolumeInfo;
58 DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = FatSetVolumeInfo;
59 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = FatShutdown;
60 DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = FatLockControl;
61 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FatDeviceControl;
62 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FatCleanup;
63 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = FatFlushBuffers;
64 //DriverObject->MajorFunction[IRP_MJ_QUERY_EA]
65 //DriverObject->MajorFunction[IRP_MJ_SET_EA]
66 //DriverObject->MajorFunction[IRP_MJ_PNP]
67
68 DriverObject->DriverUnload = NULL;
69
70 /* Initialize cache manager callbacks */
71 FatGlobalData.CacheMgrCallbacks.AcquireForLazyWrite = FatAcquireForLazyWrite;
72 FatGlobalData.CacheMgrCallbacks.ReleaseFromLazyWrite = FatReleaseFromLazyWrite;
73 FatGlobalData.CacheMgrCallbacks.AcquireForReadAhead = FatAcquireForReadAhead;
74 FatGlobalData.CacheMgrCallbacks.ReleaseFromReadAhead = FatReleaseFromReadAhead;
75
76 FatGlobalData.CacheMgrNoopCallbacks.AcquireForLazyWrite = FatNoopAcquire;
77 FatGlobalData.CacheMgrNoopCallbacks.ReleaseFromLazyWrite = FatNoopRelease;
78 FatGlobalData.CacheMgrNoopCallbacks.AcquireForReadAhead = FatNoopAcquire;
79 FatGlobalData.CacheMgrNoopCallbacks.ReleaseFromReadAhead = FatNoopRelease;
80
81 /* Initialize Fast I/O dispatchers */
82 FatInitFastIoRoutines(&FatGlobalData.FastIoDispatch);
83 DriverObject->FastIoDispatch = &FatGlobalData.FastIoDispatch;
84
85 /* Initialize lookaside lists */
86 ExInitializeNPagedLookasideList(&FatGlobalData.NonPagedFcbList,
87 NULL,
88 NULL,
89 0,
90 sizeof(FCB),
91 TAG_FCB,
92 0);
93
94 ExInitializeNPagedLookasideList(&FatGlobalData.ResourceList,
95 NULL,
96 NULL,
97 0,
98 sizeof(ERESOURCE),
99 TAG_CCB,
100 0);
101
102 ExInitializeNPagedLookasideList(&FatGlobalData.IrpContextList,
103 NULL,
104 NULL,
105 0,
106 sizeof(FAT_IRP_CONTEXT),
107 TAG_IRP,
108 0);
109
110 /* Initialize synchronization resource for the global data */
111 ExInitializeResourceLite(&FatGlobalData.Resource);
112
113 /* Initialize queued close stuff */
114 InitializeListHead(&FatGlobalData.AsyncCloseList);
115 InitializeListHead(&FatGlobalData.DelayedCloseList);
116 FatGlobalData.FatCloseItem = IoAllocateWorkItem(DeviceObject);
117 ExInitializeFastMutex(&FatCloseQueueMutex);
118
119 /* Initialize global VCB list */
120 InitializeListHead(&FatGlobalData.VcbListHead);
121
122 /* Register and reference our filesystem */
123 IoRegisterFileSystem(DeviceObject);
124 ObReferenceObject(DeviceObject);
125 return STATUS_SUCCESS;
126 }
127
128 PFAT_IRP_CONTEXT
129 NTAPI
130 FatBuildIrpContext(PIRP Irp,
131 BOOLEAN CanWait)
132 {
133 PIO_STACK_LOCATION IrpSp;
134 PFAT_IRP_CONTEXT IrpContext;
135 PVOLUME_DEVICE_OBJECT VolumeObject;
136
137 /* Get current IRP stack location */
138 IrpSp = IoGetCurrentIrpStackLocation(Irp);
139
140 /* Allocate memory for the Irp context */
141 IrpContext = ExAllocateFromNPagedLookasideList(&FatGlobalData.IrpContextList);
142
143 /* Zero init memory */
144 RtlZeroMemory(IrpContext, sizeof(FAT_IRP_CONTEXT));
145
146 /* Save IRP, MJ and MN */
147 IrpContext->Irp = Irp;
148 IrpContext->Stack = IrpSp;
149 IrpContext->MajorFunction = IrpSp->MajorFunction;
150 IrpContext->MinorFunction = IrpSp->MinorFunction;
151
152 /* Set DeviceObject */
153 if (IrpSp->FileObject)
154 {
155 IrpContext->DeviceObject = IrpSp->FileObject->DeviceObject;
156
157 /* Save VCB pointer */
158 VolumeObject = (PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject;
159 IrpContext->Vcb = &VolumeObject->Vcb;
160
161 /* TODO: Handle write-through */
162 }
163 else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL)
164 {
165 /* Handle FSCTRL case */
166 IrpContext->DeviceObject = IrpSp->Parameters.MountVolume.Vpb->RealDevice;
167 }
168
169 /* Set Wait flag */
170 if (CanWait) IrpContext->Flags |= IRPCONTEXT_CANWAIT;
171
172 /* Return prepared context */
173 return IrpContext;
174 }
175
176 VOID
177 NTAPI
178 FatDestroyIrpContext(PFAT_IRP_CONTEXT IrpContext)
179 {
180 PAGED_CODE();
181
182 /* Make sure it has no pinned stuff */
183 ASSERT(IrpContext->PinCount == 0);
184
185 /* If there is a FatIo context associated with it - free it */
186 if (IrpContext->FatIoContext)
187 {
188 if (!(IrpContext->Flags & IRPCONTEXT_STACK_IO_CONTEXT))
189 {
190 /* If a zero mdl was allocated - free it */
191 if (IrpContext->FatIoContext->ZeroMdl)
192 IoFreeMdl(IrpContext->FatIoContext->ZeroMdl);
193
194 /* Free memory of FatIo context */
195 ExFreePool(IrpContext->FatIoContext);
196 }
197 }
198
199 /* Free memory */
200 ExFreeToNPagedLookasideList(&FatGlobalData.IrpContextList, IrpContext);
201 }
202
203 VOID
204 NTAPI
205 FatCompleteRequest(PFAT_IRP_CONTEXT IrpContext OPTIONAL,
206 PIRP Irp OPTIONAL,
207 NTSTATUS Status)
208 {
209 PAGED_CODE();
210
211 if (IrpContext)
212 {
213 /* TODO: Unpin repinned BCBs */
214 //ASSERT(IrpContext->Repinned.Bcb[0] == NULL);
215 //FatUnpinRepinnedBcbs( IrpContext );
216
217 /* Destroy IRP context */
218 FatDestroyIrpContext(IrpContext);
219 }
220
221 /* Complete the IRP */
222 if (Irp)
223 {
224 /* Cleanup IoStatus.Information in case of error input operation */
225 if (NT_ERROR(Status) && (Irp->Flags & IRP_INPUT_OPERATION))
226 {
227 Irp->IoStatus.Information = 0;
228 }
229
230 /* Save status and complete this IRP */
231 Irp->IoStatus.Status = Status;
232 IoCompleteRequest( Irp, IO_DISK_INCREMENT );
233 }
234 }
235
236 VOID
237 NTAPI
238 FatDequeueRequest(IN PVOID Context)
239 {
240 PFAT_IRP_CONTEXT IrpContext;
241
242 IrpContext = (PFAT_IRP_CONTEXT) Context;
243
244 /* Enter critical region. */
245 FsRtlEnterFileSystem();
246
247 /* Handle top level IRP Correctly. */
248 if (!FlagOn(IrpContext->Flags, IRPCONTEXT_TOPLEVEL))
249 IoSetTopLevelIrp((PIRP) FSRTL_FSP_TOP_LEVEL_IRP);
250
251 /* Enable Synchronous IO. */
252 SetFlag(IrpContext->Flags, IRPCONTEXT_CANWAIT);
253
254 /* Invoke the handler routine. */
255 IrpContext->QueuedOperationHandler(IrpContext);
256
257 /* Restore top level IRP. */
258 IoSetTopLevelIrp(NULL);
259
260 /* Leave critical region. */
261 FsRtlExitFileSystem();
262 }
263
264 VOID
265 NTAPI
266 FatQueueRequest(IN PFAT_IRP_CONTEXT IrpContext,
267 IN PFAT_OPERATION_HANDLER OperationHandler)
268 {
269 /* Save the worker routine. */
270 IrpContext->QueuedOperationHandler = OperationHandler;
271
272 /* Indicate if top level IRP was set. */
273 if (IoGetTopLevelIrp() == IrpContext->Irp)
274 SetFlag(IrpContext->Flags, IRPCONTEXT_TOPLEVEL);
275
276 /* Initialize work item. */
277 ExInitializeWorkItem(&IrpContext->WorkQueueItem,
278 FatDequeueRequest,
279 IrpContext);
280 ExQueueWorkItem(&IrpContext->WorkQueueItem,
281 DelayedWorkQueue);
282 }
283
284 TYPE_OF_OPEN
285 NTAPI
286 FatDecodeFileObject(IN PFILE_OBJECT FileObject,
287 OUT PVCB *Vcb,
288 OUT PFCB *FcbOrDcb,
289 OUT PCCB *Ccb)
290 {
291 TYPE_OF_OPEN TypeOfOpen = UnopenedFileObject;
292 PVOID FsContext = FileObject->FsContext;
293 PVOID FsContext2 = FileObject->FsContext2;
294
295 /* If FsContext is NULL, then everything is NULL */
296 if (!FsContext)
297 {
298 *Ccb = NULL;
299 *FcbOrDcb = NULL;
300 *Vcb = NULL;
301
302 return TypeOfOpen;
303 }
304
305 /* CCB is always stored in FsContext2 */
306 *Ccb = FsContext2;
307
308 /* Switch according to the NodeType */
309 switch (FatNodeType(FsContext))
310 {
311 /* Volume */
312 case FAT_NTC_VCB:
313 *FcbOrDcb = NULL;
314 *Vcb = FsContext;
315
316 TypeOfOpen = ( *Ccb == NULL ? VirtualVolumeFile : UserVolumeOpen );
317
318 break;
319
320 /* Root or normal directory*/
321 case FAT_NTC_ROOT_DCB:
322 case FAT_NTC_DCB:
323 *FcbOrDcb = FsContext;
324 *Vcb = (*FcbOrDcb)->Vcb;
325
326 TypeOfOpen = (*Ccb == NULL ? DirectoryFile : UserDirectoryOpen);
327
328 DPRINT("Referencing a directory: %wZ\n", &(*FcbOrDcb)->FullFileName);
329 break;
330
331 /* File */
332 case FAT_NTC_FCB:
333 *FcbOrDcb = FsContext;
334 *Vcb = (*FcbOrDcb)->Vcb;
335
336 TypeOfOpen = (*Ccb == NULL ? EaFile : UserFileOpen);
337
338 DPRINT("Referencing a file: %wZ\n", &(*FcbOrDcb)->FullFileName);
339
340 break;
341
342 default:
343 DPRINT1("Unknown node type %x\n", FatNodeType(FsContext));
344 ASSERT(FALSE);
345 }
346
347 return TypeOfOpen;
348 }
349
350 VOID
351 NTAPI
352 FatSetFileObject(PFILE_OBJECT FileObject,
353 TYPE_OF_OPEN TypeOfOpen,
354 PVOID Fcb,
355 PCCB Ccb)
356 {
357 if (Fcb)
358 {
359 /* Check Fcb's type */
360 if (FatNodeType(Fcb) == FAT_NTC_VCB)
361 {
362 FileObject->Vpb = ((PVCB)Fcb)->Vpb;
363 }
364 else
365 {
366 FileObject->Vpb = ((PFCB)Fcb)->Vcb->Vpb;
367 }
368 }
369
370 /* Set FsContext */
371 if (FileObject)
372 {
373 FileObject->FsContext = Fcb;
374 FileObject->FsContext2 = Ccb;
375 }
376 }
377
378
379 BOOLEAN
380 NTAPI
381 FatAcquireExclusiveVcb(IN PFAT_IRP_CONTEXT IrpContext,
382 IN PVCB Vcb)
383 {
384 /* Acquire VCB's resource if possible */
385 if (ExAcquireResourceExclusiveLite(&Vcb->Resource,
386 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
387 {
388 return TRUE;
389 }
390 else
391 {
392 return FALSE;
393 }
394 }
395
396 BOOLEAN
397 NTAPI
398 FatAcquireSharedVcb(IN PFAT_IRP_CONTEXT IrpContext,
399 IN PVCB Vcb)
400 {
401 /* Acquire VCB's resource if possible */
402 if (ExAcquireResourceSharedLite(&Vcb->Resource,
403 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
404 {
405 return TRUE;
406 }
407 else
408 {
409 return FALSE;
410 }
411 }
412
413 VOID
414 NTAPI
415 FatReleaseVcb(IN PFAT_IRP_CONTEXT IrpContext,
416 IN PVCB Vcb)
417 {
418 /* Release VCB's resource */
419 ExReleaseResourceLite(&Vcb->Resource);
420 }
421
422 BOOLEAN
423 NTAPI
424 FatAcquireExclusiveFcb(IN PFAT_IRP_CONTEXT IrpContext,
425 IN PFCB Fcb)
426 {
427 RetryLockingE:
428 /* Try to acquire the exclusive lock*/
429 if (ExAcquireResourceExclusiveLite(Fcb->Header.Resource,
430 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
431 {
432 /* Wait same way MS's FASTFAT wait, i.e.
433 checking that there are outstanding async writes,
434 or someone is waiting on it*/
435 if (Fcb->OutstandingAsyncWrites &&
436 ((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
437 !FlagOn(IrpContext->Irp->Flags, IRP_NOCACHE) ||
438 ExGetSharedWaiterCount(Fcb->Header.Resource) ||
439 ExGetExclusiveWaiterCount(Fcb->Header.Resource)))
440 {
441 KeWaitForSingleObject(Fcb->OutstandingAsyncEvent,
442 Executive,
443 KernelMode,
444 FALSE,
445 NULL);
446
447 /* Release the lock */
448 FatReleaseFcb(IrpContext, Fcb);
449
450 /* Retry */
451 goto RetryLockingE;
452 }
453
454 /* Return success */
455 return TRUE;
456 }
457
458 /* Return failure */
459 return FALSE;
460 }
461
462 BOOLEAN
463 NTAPI
464 FatAcquireSharedFcb(IN PFAT_IRP_CONTEXT IrpContext,
465 IN PFCB Fcb)
466 {
467 RetryLockingS:
468 /* Try to acquire the shared lock*/
469 if (ExAcquireResourceSharedLite(Fcb->Header.Resource,
470 BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
471 {
472 /* Wait same way MS's FASTFAT wait, i.e.
473 checking that there are outstanding async writes,
474 or someone is waiting on it*/
475 if (Fcb->OutstandingAsyncWrites &&
476 ((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
477 !FlagOn(IrpContext->Irp->Flags, IRP_NOCACHE) ||
478 ExGetSharedWaiterCount(Fcb->Header.Resource) ||
479 ExGetExclusiveWaiterCount(Fcb->Header.Resource)))
480 {
481 KeWaitForSingleObject(Fcb->OutstandingAsyncEvent,
482 Executive,
483 KernelMode,
484 FALSE,
485 NULL);
486
487 /* Release the lock */
488 FatReleaseFcb(IrpContext, Fcb);
489
490 /* Retry */
491 goto RetryLockingS;
492 }
493
494 /* Return success */
495 return TRUE;
496 }
497
498 /* Return failure */
499 return FALSE;
500 }
501
502 VOID
503 NTAPI
504 FatReleaseFcb(IN PFAT_IRP_CONTEXT IrpContext,
505 IN PFCB Fcb)
506 {
507 /* Release FCB's resource */
508 ExReleaseResourceLite(Fcb->Header.Resource);
509 }
510
511 PVOID
512 FASTCALL
513 FatMapUserBuffer(PIRP Irp)
514 {
515 if (!Irp->MdlAddress)
516 return Irp->UserBuffer;
517 else
518 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
519 }
520
521 BOOLEAN
522 NTAPI
523 FatIsTopLevelIrp(IN PIRP Irp)
524 {
525 if (!IoGetTopLevelIrp())
526 {
527 IoSetTopLevelIrp(Irp);
528 return TRUE;
529 }
530
531 return FALSE;
532 }
533
534 VOID
535 NTAPI
536 FatNotifyReportChange(IN PFAT_IRP_CONTEXT IrpContext,
537 IN PVCB Vcb,
538 IN PFCB Fcb,
539 IN ULONG Filter,
540 IN ULONG Action)
541 {
542 if (Fcb->FullFileName.Buffer == NULL)
543 FatSetFullFileNameInFcb(IrpContext, Fcb);
544
545 ASSERT(Fcb->FullFileName.Length != 0 );
546 ASSERT(Fcb->FileNameLength != 0 );
547 ASSERT(Fcb->FullFileName.Length > Fcb->FileNameLength );
548 ASSERT(Fcb->FullFileName.Buffer[(Fcb->FullFileName.Length - Fcb->FileNameLength)/sizeof(WCHAR) - 1] == L'\\' );
549
550 FsRtlNotifyFullReportChange(Vcb->NotifySync,
551 &Vcb->NotifyList,
552 (PSTRING)&Fcb->FullFileName,
553 (USHORT)(Fcb->FullFileName.Length -
554 Fcb->FileNameLength),
555 NULL,
556 NULL,
557 Filter,
558 Action,
559 NULL);
560 }
561
562 /* EOF */