3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/fs.c
6 * PURPOSE: Filesystem functions
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
18 /* TYPES *******************************************************************/
20 typedef struct _FILE_SYSTEM_OBJECT
22 PDEVICE_OBJECT DeviceObject
;
24 } FILE_SYSTEM_OBJECT
, *PFILE_SYSTEM_OBJECT
;
26 typedef struct _FS_CHANGE_NOTIFY_ENTRY
28 LIST_ENTRY FsChangeNotifyList
;
29 PDRIVER_OBJECT DriverObject
;
30 PDRIVER_FS_NOTIFICATION FSDNotificationProc
;
31 } FS_CHANGE_NOTIFY_ENTRY
, *PFS_CHANGE_NOTIFY_ENTRY
;
33 /* GLOBALS ******************************************************************/
35 static ERESOURCE FileSystemListLock
;
36 static LIST_ENTRY FileSystemListHead
;
38 static KGUARDED_MUTEX FsChangeNotifyListLock
;
39 static LIST_ENTRY FsChangeNotifyListHead
;
41 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
42 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
46 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
47 BOOLEAN DriverActive
);
50 /* FUNCTIONS *****************************************************************/
58 IN PDEVICE_OBJECT DeviceObject
,
59 IN PFILE_OBJECT FileObject
70 IN HANDLE DeviceHandle
,
71 IN HANDLE EventHandle OPTIONAL
,
72 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
73 IN PVOID ApcContext OPTIONAL
,
74 OUT PIO_STATUS_BLOCK IoStatusBlock
,
75 IN ULONG IoControlCode
,
77 IN ULONG InputBufferSize
,
78 OUT PVOID OutputBuffer
,
79 IN ULONG OutputBufferSize
83 PFILE_OBJECT FileObject
;
84 PDEVICE_OBJECT DeviceObject
;
86 PIO_STACK_LOCATION StackPtr
;
88 KPROCESSOR_MODE PreviousMode
;
90 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
91 "ApcContext %x IoStatusBlock %x IoControlCode %x "
92 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
93 "OutputBufferSize %x)\n",
94 DeviceHandle
,EventHandle
,ApcRoutine
,ApcContext
,IoStatusBlock
,
95 IoControlCode
,InputBuffer
,InputBufferSize
,OutputBuffer
,
98 PreviousMode
= ExGetPreviousMode();
100 /* Check granted access against the access rights from IoContolCode */
101 Status
= ObReferenceObjectByHandle(DeviceHandle
,
102 (IoControlCode
>> 14) & 0x3,
105 (PVOID
*) &FileObject
,
107 if (!NT_SUCCESS(Status
))
112 if (EventHandle
!= NULL
)
114 Status
= ObReferenceObjectByHandle(EventHandle
,
120 if (!NT_SUCCESS(Status
))
122 ObDereferenceObject(FileObject
);
128 KeResetEvent(&FileObject
->Event
);
129 ptrEvent
= &FileObject
->Event
;
132 DeviceObject
= FileObject
->DeviceObject
;
134 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
,
144 /* Trigger FileObject/Event dereferencing */
145 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
147 Irp
->RequestorMode
= PreviousMode
;
148 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= ApcRoutine
;
149 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
= ApcContext
;
151 StackPtr
= IoGetNextIrpStackLocation(Irp
);
152 StackPtr
->FileObject
= FileObject
;
153 StackPtr
->DeviceObject
= DeviceObject
;
154 StackPtr
->Parameters
.FileSystemControl
.InputBufferLength
= InputBufferSize
;
155 StackPtr
->Parameters
.FileSystemControl
.OutputBufferLength
=
157 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
159 Status
= IoCallDriver(DeviceObject
,Irp
);
160 if (Status
== STATUS_PENDING
&& (FileObject
->Flags
& FO_SYNCHRONOUS_IO
))
162 KeWaitForSingleObject(ptrEvent
,
165 FileObject
->Flags
& FO_ALERTABLE_IO
,
167 Status
= IoStatusBlock
->Status
;
175 IoInitFileSystemImplementation(VOID
)
177 InitializeListHead(&FileSystemListHead
);
178 ExInitializeResourceLite(&FileSystemListLock
);
180 InitializeListHead(&FsChangeNotifyListHead
);
181 KeInitializeGuardedMutex(&FsChangeNotifyListLock
);
186 IoShutdownRegisteredFileSystems(VOID
)
188 PLIST_ENTRY current_entry
;
189 FILE_SYSTEM_OBJECT
* current
;
192 IO_STATUS_BLOCK IoStatusBlock
;
195 DPRINT("IoShutdownRegisteredFileSystems()\n");
197 KeEnterCriticalRegion();
198 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
199 KeInitializeEvent(&Event
,
203 current_entry
= FileSystemListHead
.Flink
;
204 while (current_entry
!=(&FileSystemListHead
))
206 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
208 /* send IRP_MJ_SHUTDOWN */
209 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
210 current
->DeviceObject
,
217 Status
= IoCallDriver(current
->DeviceObject
,Irp
);
218 if (Status
== STATUS_PENDING
)
220 KeWaitForSingleObject(&Event
,
227 current_entry
= current_entry
->Flink
;
230 ExReleaseResourceLite(&FileSystemListLock
);
231 KeLeaveCriticalRegion();
236 IopMountFileSystem(PDEVICE_OBJECT DeviceObject
,
237 PDEVICE_OBJECT DeviceToMount
)
239 IO_STATUS_BLOCK IoStatusBlock
;
240 PIO_STACK_LOCATION StackPtr
;
245 DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
246 DeviceObject
,DeviceToMount
);
248 ASSERT_IRQL(PASSIVE_LEVEL
);
250 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
251 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
254 return(STATUS_INSUFFICIENT_RESOURCES
);
257 Irp
->UserIosb
= &IoStatusBlock
;
258 DPRINT("Irp->UserIosb %x\n", Irp
->UserIosb
);
259 Irp
->UserEvent
= &Event
;
260 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
262 StackPtr
= IoGetNextIrpStackLocation(Irp
);
263 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
264 StackPtr
->MinorFunction
= IRP_MN_MOUNT_VOLUME
;
266 StackPtr
->Control
= 0;
267 StackPtr
->DeviceObject
= DeviceObject
;
268 StackPtr
->FileObject
= NULL
;
269 StackPtr
->CompletionRoutine
= NULL
;
271 StackPtr
->Parameters
.MountVolume
.Vpb
= DeviceToMount
->Vpb
;
272 StackPtr
->Parameters
.MountVolume
.DeviceObject
= DeviceToMount
;
274 Status
= IoCallDriver(DeviceObject
,Irp
);
275 if (Status
==STATUS_PENDING
)
277 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
278 Status
= IoStatusBlock
.Status
;
286 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject
)
288 IO_STATUS_BLOCK IoStatusBlock
;
289 PIO_STACK_LOCATION StackPtr
;
294 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject
);
296 ASSERT_IRQL(PASSIVE_LEVEL
);
298 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
299 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
302 return(STATUS_INSUFFICIENT_RESOURCES
);
305 Irp
->UserIosb
= &IoStatusBlock
;
306 DPRINT("Irp->UserIosb %x\n", Irp
->UserIosb
);
307 Irp
->UserEvent
= &Event
;
308 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
310 StackPtr
= IoGetNextIrpStackLocation(Irp
);
311 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
312 StackPtr
->MinorFunction
= IRP_MN_LOAD_FILE_SYSTEM
;
314 StackPtr
->Control
= 0;
315 StackPtr
->DeviceObject
= DeviceObject
;
316 StackPtr
->FileObject
= NULL
;
317 StackPtr
->CompletionRoutine
= NULL
;
319 Status
= IoCallDriver(DeviceObject
,Irp
);
320 if (Status
==STATUS_PENDING
)
322 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
323 Status
= IoStatusBlock
.Status
;
331 IoMountVolume(IN PDEVICE_OBJECT DeviceObject
,
332 IN BOOLEAN AllowRawMount
)
334 * FUNCTION: Mounts a logical volume
336 * DeviceObject = Device to mount
340 PLIST_ENTRY current_entry
;
341 FILE_SYSTEM_OBJECT
* current
;
343 DEVICE_TYPE MatchingDeviceType
;
344 PDEVICE_OBJECT DevObject
;
346 ASSERT_IRQL(PASSIVE_LEVEL
);
348 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
349 DeviceObject
, AllowRawMount
);
351 switch (DeviceObject
->DeviceType
)
353 case FILE_DEVICE_DISK
:
354 case FILE_DEVICE_VIRTUAL_DISK
: /* ?? */
355 MatchingDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
358 case FILE_DEVICE_CD_ROM
:
359 MatchingDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
362 case FILE_DEVICE_NETWORK
:
363 MatchingDeviceType
= FILE_DEVICE_NETWORK_FILE_SYSTEM
;
366 case FILE_DEVICE_TAPE
:
367 MatchingDeviceType
= FILE_DEVICE_TAPE_FILE_SYSTEM
;
371 CPRINT("No matching file system type found for device type: %x\n",
372 DeviceObject
->DeviceType
);
373 return(STATUS_UNRECOGNIZED_VOLUME
);
376 KeEnterCriticalRegion();
377 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
378 current_entry
= FileSystemListHead
.Flink
;
379 while (current_entry
!=(&FileSystemListHead
))
381 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
382 if (current
->DeviceObject
->DeviceType
!= MatchingDeviceType
)
384 current_entry
= current_entry
->Flink
;
387 /* If we are not allowed to mount this volume as a raw filesystem volume
388 then don't try this */
389 if (!AllowRawMount
&& RawFsIsRawFileSystemDeviceObject(current
->DeviceObject
))
391 Status
= STATUS_UNRECOGNIZED_VOLUME
;
395 Status
= IopMountFileSystem(current
->DeviceObject
,
400 case STATUS_FS_DRIVER_REQUIRED
:
401 DevObject
= current
->DeviceObject
;
402 ExReleaseResourceLite(&FileSystemListLock
);
403 Status
= IopLoadFileSystem(DevObject
);
404 if (!NT_SUCCESS(Status
))
406 KeLeaveCriticalRegion();
409 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
410 current_entry
= FileSystemListHead
.Flink
;
414 DeviceObject
->Vpb
->Flags
= DeviceObject
->Vpb
->Flags
|
416 ExReleaseResourceLite(&FileSystemListLock
);
417 KeLeaveCriticalRegion();
418 return(STATUS_SUCCESS
);
420 case STATUS_UNRECOGNIZED_VOLUME
:
422 current_entry
= current_entry
->Flink
;
425 ExReleaseResourceLite(&FileSystemListLock
);
426 KeLeaveCriticalRegion();
428 return(STATUS_UNRECOGNIZED_VOLUME
);
432 /**********************************************************************
437 * Verify the file system type and volume information or mount
442 * Device to verify or mount
453 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
454 IN BOOLEAN AllowRawMount
)
456 IO_STATUS_BLOCK IoStatusBlock
;
457 PIO_STACK_LOCATION StackPtr
;
461 PDEVICE_OBJECT DevObject
;
463 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
464 DeviceObject
, AllowRawMount
);
466 Status
= STATUS_SUCCESS
;
468 KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
474 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
476 /* Issue verify request to the FSD */
477 DevObject
= DeviceObject
->Vpb
->DeviceObject
;
479 KeInitializeEvent(&Event
,
483 Irp
= IoAllocateIrp(DevObject
->StackSize
, TRUE
);
486 return(STATUS_INSUFFICIENT_RESOURCES
);
489 Irp
->UserIosb
= &IoStatusBlock
;
490 Irp
->UserEvent
= &Event
;
491 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
493 StackPtr
= IoGetNextIrpStackLocation(Irp
);
494 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
495 StackPtr
->MinorFunction
= IRP_MN_VERIFY_VOLUME
;
497 StackPtr
->Control
= 0;
498 StackPtr
->DeviceObject
= DevObject
;
499 StackPtr
->FileObject
= NULL
;
500 StackPtr
->CompletionRoutine
= NULL
;
502 StackPtr
->Parameters
.VerifyVolume
.Vpb
= DeviceObject
->Vpb
;
503 StackPtr
->Parameters
.VerifyVolume
.DeviceObject
= DeviceObject
;
505 Status
= IoCallDriver(DevObject
,
507 if (Status
==STATUS_PENDING
)
509 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
510 Status
= IoStatusBlock
.Status
;
513 if (NT_SUCCESS(Status
))
515 KeSetEvent(&DeviceObject
->DeviceLock
,
518 return(STATUS_SUCCESS
);
522 if (Status
== STATUS_WRONG_VOLUME
)
524 /* Clean existing VPB. This unmounts the filesystem. */
525 DPRINT("Wrong volume!\n");
527 DeviceObject
->Vpb
->DeviceObject
= NULL
;
528 DeviceObject
->Vpb
->Flags
&= ~VPB_MOUNTED
;
531 /* Start mount sequence */
532 Status
= IoMountVolume(DeviceObject
,
535 KeSetEvent(&DeviceObject
->DeviceLock
,
546 PDEVICE_OBJECT STDCALL
547 IoGetDeviceToVerify(IN PETHREAD Thread
)
549 * FUNCTION: Returns a pointer to the device, representing a removable-media
550 * device, that is the target of the given thread's I/O request
553 return(Thread
->DeviceToVerify
);
561 IoSetDeviceToVerify(IN PETHREAD Thread
,
562 IN PDEVICE_OBJECT DeviceObject
)
564 Thread
->DeviceToVerify
= DeviceObject
;
572 IoSetHardErrorOrVerifyDevice(IN PIRP Irp
,
573 IN PDEVICE_OBJECT DeviceObject
)
575 Irp
->Tail
.Overlay
.Thread
->DeviceToVerify
= DeviceObject
;
583 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
585 PFILE_SYSTEM_OBJECT Fs
;
587 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject
);
589 Fs
= ExAllocatePoolWithTag(NonPagedPool
,
590 sizeof(FILE_SYSTEM_OBJECT
),
594 Fs
->DeviceObject
= DeviceObject
;
595 KeEnterCriticalRegion();
596 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
598 /* The RAW filesystem device objects must be last in the list so the
599 raw filesystem driver is the last filesystem driver asked to mount
600 a volume. It is always the first filesystem driver registered so
601 we use InsertHeadList() here as opposed to the other alternative
603 InsertHeadList(&FileSystemListHead
,
606 ExReleaseResourceLite(&FileSystemListLock
);
607 KeLeaveCriticalRegion();
609 IopNotifyFileSystemChange(DeviceObject
,
618 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
620 PLIST_ENTRY current_entry
;
621 PFILE_SYSTEM_OBJECT current
;
623 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject
);
625 KeEnterCriticalRegion();
626 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
627 current_entry
= FileSystemListHead
.Flink
;
628 while (current_entry
!=(&FileSystemListHead
))
630 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
631 if (current
->DeviceObject
== DeviceObject
)
633 RemoveEntryList(current_entry
);
634 ExFreePoolWithTag(current
, TAG_FILE_SYSTEM
);
635 ExReleaseResourceLite(&FileSystemListLock
);
636 KeLeaveCriticalRegion();
637 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
640 current_entry
= current_entry
->Flink
;
642 ExReleaseResourceLite(&FileSystemListLock
);
643 KeLeaveCriticalRegion();
647 /**********************************************************************
649 * IoGetBaseFileSystemDeviceObject@4
652 * Get the DEVICE_OBJECT associated to
661 * From Bo Branten's ntifs.h v13.
665 PDEVICE_OBJECT STDCALL
666 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
668 PDEVICE_OBJECT DeviceObject
= NULL
;
672 * If the FILE_OBJECT's VPB is defined,
673 * get the device from it.
675 if (NULL
!= (Vpb
= FileObject
->Vpb
))
677 if (NULL
!= (DeviceObject
= Vpb
->DeviceObject
))
679 /* Vpb->DeviceObject DEFINED! */
684 * If that failed, try the VPB
685 * in the FILE_OBJECT's DeviceObject.
687 DeviceObject
= FileObject
->DeviceObject
;
688 if (NULL
== (Vpb
= DeviceObject
->Vpb
))
690 /* DeviceObject->Vpb UNDEFINED! */
694 * If that pointer to the VPB is again
695 * undefined, return directly the
696 * device object from the FILE_OBJECT.
699 (NULL
== Vpb
->DeviceObject
)
707 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
708 BOOLEAN DriverActive
)
710 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
713 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
714 Entry
= FsChangeNotifyListHead
.Flink
;
715 while (Entry
!= &FsChangeNotifyListHead
)
717 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
719 (ChangeEntry
->FSDNotificationProc
)(DeviceObject
, DriverActive
);
721 Entry
= Entry
->Flink
;
723 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
731 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
732 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
734 PFS_CHANGE_NOTIFY_ENTRY Entry
;
736 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
737 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
738 TAG_FS_CHANGE_NOTIFY
);
740 return(STATUS_INSUFFICIENT_RESOURCES
);
742 Entry
->DriverObject
= DriverObject
;
743 Entry
->FSDNotificationProc
= FSDNotificationProc
;
745 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
746 InsertHeadList(&FsChangeNotifyListHead
,
747 &Entry
->FsChangeNotifyList
);
748 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
750 return(STATUS_SUCCESS
);
758 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
759 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
761 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
764 Entry
= FsChangeNotifyListHead
.Flink
;
765 while (Entry
!= &FsChangeNotifyListHead
)
767 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
768 if (ChangeEntry
->DriverObject
== DriverObject
&&
769 ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
)
771 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
772 RemoveEntryList(Entry
);
773 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
775 ExFreePoolWithTag(Entry
, TAG_FS_CHANGE_NOTIFY
);
779 Entry
= Entry
->Flink
;