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