2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/misc.c
5 * PURPOSE: VFAT Filesystem
10 /* INCLUDES *****************************************************************/
17 /* GLOBALS ******************************************************************/
19 const char* MajorFunctionNames
[] =
22 "IRP_MJ_CREATE_NAMED_PIPE",
26 "IRP_MJ_QUERY_INFORMATION",
27 "IRP_MJ_SET_INFORMATION",
30 "IRP_MJ_FLUSH_BUFFERS",
31 "IRP_MJ_QUERY_VOLUME_INFORMATION",
32 "IRP_MJ_SET_VOLUME_INFORMATION",
33 "IRP_MJ_DIRECTORY_CONTROL",
34 "IRP_MJ_FILE_SYSTEM_CONTROL",
35 "IRP_MJ_DEVICE_CONTROL",
36 "IRP_MJ_INTERNAL_DEVICE_CONTROL",
38 "IRP_MJ_LOCK_CONTROL",
40 "IRP_MJ_CREATE_MAILSLOT",
41 "IRP_MJ_QUERY_SECURITY",
42 "IRP_MJ_SET_SECURITY",
44 "IRP_MJ_SYSTEM_CONTROL",
45 "IRP_MJ_DEVICE_CHANGE",
49 "IRP_MJ_MAXIMUM_FUNCTION"
52 static LONG QueueCount
= 0;
54 static VOID
VfatFreeIrpContext(PVFAT_IRP_CONTEXT
);
55 static PVFAT_IRP_CONTEXT
VfatAllocateIrpContext(PDEVICE_OBJECT
, PIRP
);
56 static NTSTATUS
VfatQueueRequest(PVFAT_IRP_CONTEXT
);
58 /* FUNCTIONS ****************************************************************/
63 IN PVFAT_IRP_CONTEXT IrpContext
)
68 DPRINT("VfatLockControl(IrpContext %p)\n", IrpContext
);
72 Fcb
= (PVFATFCB
)IrpContext
->FileObject
->FsContext
;
74 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
76 return STATUS_INVALID_DEVICE_REQUEST
;
79 if (vfatFCBIsDirectory(Fcb
))
81 return STATUS_INVALID_PARAMETER
;
84 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
85 Status
= FsRtlProcessFileLock(&Fcb
->FileLock
,
94 IN PVFAT_IRP_CONTEXT IrpContext
)
96 IoSkipCurrentIrpStackLocation(IrpContext
->Irp
);
98 IrpContext
->Flags
&= ~IRPCONTEXT_COMPLETE
;
100 return IoCallDriver(IrpContext
->DeviceExt
->StorageDevice
, IrpContext
->Irp
);
106 IN PVFAT_IRP_CONTEXT IrpContext
)
109 BOOLEAN QueueIrp
, CompleteIrp
;
111 DPRINT("VfatDispatchRequest (IrpContext %p), is called for %s\n", IrpContext
,
112 IrpContext
->MajorFunction
>= IRP_MJ_MAXIMUM_FUNCTION
? "????" : MajorFunctionNames
[IrpContext
->MajorFunction
]);
116 FsRtlEnterFileSystem();
118 switch (IrpContext
->MajorFunction
)
121 Status
= VfatClose(IrpContext
);
125 Status
= VfatCreate(IrpContext
);
129 Status
= VfatRead(IrpContext
);
133 Status
= VfatWrite (IrpContext
);
136 case IRP_MJ_FILE_SYSTEM_CONTROL
:
137 Status
= VfatFileSystemControl(IrpContext
);
140 case IRP_MJ_QUERY_INFORMATION
:
141 Status
= VfatQueryInformation (IrpContext
);
144 case IRP_MJ_SET_INFORMATION
:
145 Status
= VfatSetInformation (IrpContext
);
148 case IRP_MJ_DIRECTORY_CONTROL
:
149 Status
= VfatDirectoryControl(IrpContext
);
152 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
153 Status
= VfatQueryVolumeInformation(IrpContext
);
156 case IRP_MJ_SET_VOLUME_INFORMATION
:
157 Status
= VfatSetVolumeInformation(IrpContext
);
160 case IRP_MJ_LOCK_CONTROL
:
161 Status
= VfatLockControl(IrpContext
);
164 case IRP_MJ_DEVICE_CONTROL
:
165 Status
= VfatDeviceControl(IrpContext
);
169 Status
= VfatCleanup(IrpContext
);
172 case IRP_MJ_FLUSH_BUFFERS
:
173 Status
= VfatFlush(IrpContext
);
177 Status
= VfatPnp(IrpContext
);
181 DPRINT1("Unexpected major function %x\n", IrpContext
->MajorFunction
);
182 Status
= STATUS_DRIVER_INTERNAL_ERROR
;
185 QueueIrp
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_QUEUE
);
186 CompleteIrp
= BooleanFlagOn(IrpContext
->Flags
, IRPCONTEXT_COMPLETE
);
188 ASSERT((!CompleteIrp
&& !QueueIrp
) ||
189 (CompleteIrp
&& !QueueIrp
) ||
190 (!CompleteIrp
&& QueueIrp
));
194 IrpContext
->Irp
->IoStatus
.Status
= Status
;
195 IoCompleteRequest(IrpContext
->Irp
, IrpContext
->PriorityBoost
);
200 /* Reset our status flags before queueing the IRP */
201 IrpContext
->Flags
|= IRPCONTEXT_COMPLETE
;
202 IrpContext
->Flags
&= ~IRPCONTEXT_QUEUE
;
203 Status
= VfatQueueRequest(IrpContext
);
207 /* Unless the IRP was queued, always free the IRP context */
208 VfatFreeIrpContext(IrpContext
);
211 FsRtlExitFileSystem();
218 VfatHandleDeferredWrite(
222 VfatDispatchRequest((PVFAT_IRP_CONTEXT
)IrpContext
);
228 IN PDEVICE_OBJECT DeviceObject
,
232 PVFAT_IRP_CONTEXT IrpContext
;
234 DPRINT("VfatBuildRequest (DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
236 ASSERT(DeviceObject
);
239 IrpContext
= VfatAllocateIrpContext(DeviceObject
, Irp
);
240 if (IrpContext
== NULL
)
242 Status
= STATUS_INSUFFICIENT_RESOURCES
;
243 Irp
->IoStatus
.Status
= Status
;
244 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
248 Status
= VfatDispatchRequest(IrpContext
);
256 PVFAT_IRP_CONTEXT IrpContext
)
259 ExFreeToNPagedLookasideList(&VfatGlobalData
->IrpContextLookasideList
, IrpContext
);
264 VfatAllocateIrpContext(
265 PDEVICE_OBJECT DeviceObject
,
268 PVFAT_IRP_CONTEXT IrpContext
;
269 /*PIO_STACK_LOCATION Stack;*/
272 DPRINT("VfatAllocateIrpContext(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
274 ASSERT(DeviceObject
);
277 IrpContext
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->IrpContextLookasideList
);
280 RtlZeroMemory(IrpContext
, sizeof(VFAT_IRP_CONTEXT
));
281 IrpContext
->Irp
= Irp
;
282 IrpContext
->DeviceObject
= DeviceObject
;
283 IrpContext
->DeviceExt
= DeviceObject
->DeviceExtension
;
284 IrpContext
->Stack
= IoGetCurrentIrpStackLocation(Irp
);
285 ASSERT(IrpContext
->Stack
);
286 MajorFunction
= IrpContext
->MajorFunction
= IrpContext
->Stack
->MajorFunction
;
287 IrpContext
->MinorFunction
= IrpContext
->Stack
->MinorFunction
;
288 IrpContext
->FileObject
= IrpContext
->Stack
->FileObject
;
289 IrpContext
->Flags
= IRPCONTEXT_COMPLETE
;
291 /* Easy cases that can wait */
292 if (MajorFunction
== IRP_MJ_CLEANUP
||
293 MajorFunction
== IRP_MJ_CREATE
||
294 MajorFunction
== IRP_MJ_SHUTDOWN
||
295 MajorFunction
== IRP_MJ_CLOSE
/* likely to be fixed */)
297 SetFlag(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
299 /* Cases that can wait if synchronous IRP */
300 else if ((MajorFunction
== IRP_MJ_DEVICE_CONTROL
||
301 MajorFunction
== IRP_MJ_QUERY_INFORMATION
||
302 MajorFunction
== IRP_MJ_SET_INFORMATION
||
303 MajorFunction
== IRP_MJ_FLUSH_BUFFERS
||
304 MajorFunction
== IRP_MJ_LOCK_CONTROL
||
305 MajorFunction
== IRP_MJ_QUERY_VOLUME_INFORMATION
||
306 MajorFunction
== IRP_MJ_SET_VOLUME_INFORMATION
||
307 MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
||
308 MajorFunction
== IRP_MJ_WRITE
||
309 MajorFunction
== IRP_MJ_READ
) &&
310 IoIsOperationSynchronous(Irp
))
312 SetFlag(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
314 /* Cases that can wait if synchronous or if no FO */
315 else if ((MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
||
316 MajorFunction
== IRP_MJ_PNP
) &&
317 (IoGetCurrentIrpStackLocation(Irp
)->FileObject
== NULL
||
318 IoIsOperationSynchronous(Irp
)))
320 SetFlag(IrpContext
->Flags
, IRPCONTEXT_CANWAIT
);
323 KeInitializeEvent(&IrpContext
->Event
, NotificationEvent
, FALSE
);
324 IrpContext
->RefCount
= 0;
325 IrpContext
->PriorityBoost
= IO_NO_INCREMENT
;
330 static WORKER_THREAD_ROUTINE VfatDoRequest
;
338 InterlockedDecrement(&QueueCount
);
339 DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
340 IrpContext
, ((PVFAT_IRP_CONTEXT
)IrpContext
)->MajorFunction
, QueueCount
);
341 VfatDispatchRequest((PVFAT_IRP_CONTEXT
)IrpContext
);
347 PVFAT_IRP_CONTEXT IrpContext
)
349 InterlockedIncrement(&QueueCount
);
350 DPRINT("VfatQueueRequest(IrpContext %p), %d\n", IrpContext
, QueueCount
);
352 ASSERT(IrpContext
!= NULL
);
353 ASSERT(IrpContext
->Irp
!= NULL
);
354 ASSERT(!(IrpContext
->Flags
& IRPCONTEXT_QUEUE
) &&
355 (IrpContext
->Flags
& IRPCONTEXT_COMPLETE
));
357 IrpContext
->Flags
|= IRPCONTEXT_CANWAIT
;
358 IoMarkIrpPending(IrpContext
->Irp
);
359 ExInitializeWorkItem(&IrpContext
->WorkQueueItem
, VfatDoRequest
, IrpContext
);
360 ExQueueWorkItem(&IrpContext
->WorkQueueItem
, CriticalWorkQueue
);
361 return STATUS_PENDING
;
373 return MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, (Paging
? HighPagePriority
: NormalPagePriority
));
377 return Irp
->UserBuffer
;
385 IN LOCK_OPERATION Operation
)
391 return STATUS_SUCCESS
;
394 IoAllocateMdl(Irp
->UserBuffer
, Length
, FALSE
, FALSE
, Irp
);
396 if (!Irp
->MdlAddress
)
398 return STATUS_INSUFFICIENT_RESOURCES
;
403 MmProbeAndLockPages(Irp
->MdlAddress
, Irp
->RequestorMode
, Operation
);
405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
407 IoFreeMdl(Irp
->MdlAddress
);
408 Irp
->MdlAddress
= NULL
;
409 _SEH2_YIELD(return _SEH2_GetExceptionCode());
413 return STATUS_SUCCESS
;
417 VfatCheckForDismount(
418 IN PDEVICE_EXTENSION DeviceExt
,
426 DPRINT1("VfatCheckForDismount(%p, %u)\n", DeviceExt
, Force
);
428 /* If the VCB is OK (not under uninitialization) and we don't force dismount, do nothing */
429 if (BooleanFlagOn(DeviceExt
->Flags
, VCB_GOOD
) && !Force
)
435 * NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
436 * as well as MS' fastfat, perform a comparison check of the current VCB's
437 * VPB ReferenceCount with some sort of "dangling"/"residual" open count,
438 * depending on whether or not we are in IRP_MJ_CREATE.
439 * It seems to be related to the fact that the volume root directory as
440 * well as auxiliary data stream(s) are still opened, and only these are
441 * allowed to be opened at that moment. After analysis it appears that for
442 * the ReactOS' fastfat, this number is equal to "3".
447 IoAcquireVpbSpinLock(&OldIrql
);
449 /* Reference it and check if a create is being done */
450 Vpb
= DeviceExt
->IoVPB
;
451 DPRINT("Vpb->ReferenceCount = %d\n", Vpb
->ReferenceCount
);
452 if (Vpb
->ReferenceCount
!= UnCleanCount
|| DeviceExt
->OpenHandleCount
!= 0)
454 /* If we force-unmount, copy the VPB to our local own to prepare later dismount */
455 if (Force
&& Vpb
->RealDevice
->Vpb
== Vpb
&& DeviceExt
->SpareVPB
!= NULL
)
457 RtlZeroMemory(DeviceExt
->SpareVPB
, sizeof(VPB
));
458 DeviceExt
->SpareVPB
->Type
= IO_TYPE_VPB
;
459 DeviceExt
->SpareVPB
->Size
= sizeof(VPB
);
460 DeviceExt
->SpareVPB
->RealDevice
= DeviceExt
->IoVPB
->RealDevice
;
461 DeviceExt
->SpareVPB
->DeviceObject
= NULL
;
462 DeviceExt
->SpareVPB
->Flags
= DeviceExt
->IoVPB
->Flags
& VPB_REMOVE_PENDING
;
463 DeviceExt
->IoVPB
->RealDevice
->Vpb
= DeviceExt
->SpareVPB
;
464 DeviceExt
->SpareVPB
= NULL
;
465 DeviceExt
->IoVPB
->Flags
|= VPB_PERSISTENT
;
467 /* We are uninitializing, the VCB cannot be used anymore */
468 ClearFlag(DeviceExt
->Flags
, VCB_GOOD
);
471 /* Don't do anything for now */
476 /* Otherwise, delete the volume */
479 /* Swap the VPB with our local own */
480 if (Vpb
->RealDevice
->Vpb
== Vpb
&& DeviceExt
->SpareVPB
!= NULL
)
482 RtlZeroMemory(DeviceExt
->SpareVPB
, sizeof(VPB
));
483 DeviceExt
->SpareVPB
->Type
= IO_TYPE_VPB
;
484 DeviceExt
->SpareVPB
->Size
= sizeof(VPB
);
485 DeviceExt
->SpareVPB
->RealDevice
= DeviceExt
->IoVPB
->RealDevice
;
486 DeviceExt
->SpareVPB
->DeviceObject
= NULL
;
487 DeviceExt
->SpareVPB
->Flags
= DeviceExt
->IoVPB
->Flags
& VPB_REMOVE_PENDING
;
488 DeviceExt
->IoVPB
->RealDevice
->Vpb
= DeviceExt
->SpareVPB
;
489 DeviceExt
->SpareVPB
= NULL
;
490 DeviceExt
->IoVPB
->Flags
|= VPB_PERSISTENT
;
492 /* We are uninitializing, the VCB cannot be used anymore */
493 ClearFlag(DeviceExt
->Flags
, VCB_GOOD
);
497 * We defer setting the VPB's DeviceObject to NULL for later because
498 * we want to handle the closing of the internal opened meta-files.
501 /* Clear the mounted and locked flags in the VPB */
502 ClearFlag(Vpb
->Flags
, VPB_MOUNTED
| VPB_LOCKED
);
505 /* Release lock and return status */
506 IoReleaseVpbSpinLock(OldIrql
);
508 /* If we were to delete, delete volume */
511 LARGE_INTEGER Zero
= {{0,0}};
514 /* We are uninitializing, the VCB cannot be used anymore */
515 ClearFlag(DeviceExt
->Flags
, VCB_GOOD
);
517 /* Invalidate and close the internal opened meta-files */
518 if (DeviceExt
->RootFcb
)
520 Fcb
= DeviceExt
->RootFcb
;
521 CcUninitializeCacheMap(Fcb
->FileObject
,
524 ObDereferenceObject(Fcb
->FileObject
);
525 DeviceExt
->RootFcb
= NULL
;
528 if (DeviceExt
->VolumeFcb
)
530 Fcb
= DeviceExt
->VolumeFcb
;
531 #ifndef VOLUME_IS_NOT_CACHED_WORK_AROUND_IT
532 CcUninitializeCacheMap(Fcb
->FileObject
,
535 ObDereferenceObject(Fcb
->FileObject
);
537 DeviceExt
->VolumeFcb
= NULL
;
540 if (DeviceExt
->FATFileObject
)
542 Fcb
= (PVFATFCB
)DeviceExt
->FATFileObject
->FsContext
;
543 CcUninitializeCacheMap(DeviceExt
->FATFileObject
,
546 ObDereferenceObject(DeviceExt
->FATFileObject
);
547 DeviceExt
->FATFileObject
->FsContext
= NULL
;
548 DeviceExt
->FATFileObject
= NULL
;
553 * Now that the closing of the internal opened meta-files has been
554 * handled, we can now set the VPB's DeviceObject to NULL.
556 Vpb
->DeviceObject
= NULL
;
558 /* If we have a local VPB, we'll have to delete it
559 * but we won't dismount us - something went bad before
561 if (DeviceExt
->SpareVPB
)
563 ExFreePool(DeviceExt
->SpareVPB
);
565 /* Otherwise, delete any of the available VPB if its reference count is zero */
566 else if (DeviceExt
->IoVPB
->ReferenceCount
== 0)
568 ExFreePool(DeviceExt
->IoVPB
);
571 /* Remove the volume from the list */
572 ExAcquireResourceExclusiveLite(&VfatGlobalData
->VolumeListLock
, TRUE
);
573 RemoveEntryList(&DeviceExt
->VolumeListEntry
);
574 ExReleaseResourceLite(&VfatGlobalData
->VolumeListLock
);
576 /* Uninitialize the notify synchronization object */
577 FsRtlNotifyUninitializeSync(&DeviceExt
->NotifySync
);
579 /* Release resources */
580 ExFreePoolWithTag(DeviceExt
->Statistics
, TAG_STATS
);
581 ExDeleteResourceLite(&DeviceExt
->DirResource
);
582 ExDeleteResourceLite(&DeviceExt
->FatResource
);
584 /* Dismount our device if possible */
585 ObfDereferenceObject(DeviceExt
->StorageDevice
);
586 IoDeleteDevice(DeviceExt
->VolumeDevice
);