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
;
42 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
43 BOOLEAN DriverActive
);
46 /* FUNCTIONS *****************************************************************/
54 IN PDEVICE_OBJECT DeviceObject
,
55 IN PFILE_OBJECT FileObject
62 IoInitFileSystemImplementation(VOID
)
64 InitializeListHead(&FileSystemListHead
);
65 ExInitializeResourceLite(&FileSystemListLock
);
67 InitializeListHead(&FsChangeNotifyListHead
);
68 KeInitializeGuardedMutex(&FsChangeNotifyListLock
);
73 IoShutdownRegisteredFileSystems(VOID
)
75 PLIST_ENTRY current_entry
;
76 FILE_SYSTEM_OBJECT
* current
;
79 IO_STATUS_BLOCK IoStatusBlock
;
82 DPRINT("IoShutdownRegisteredFileSystems()\n");
84 KeEnterCriticalRegion();
85 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
86 KeInitializeEvent(&Event
,
90 current_entry
= FileSystemListHead
.Flink
;
91 while (current_entry
!=(&FileSystemListHead
))
93 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
95 /* send IRP_MJ_SHUTDOWN */
96 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
97 current
->DeviceObject
,
104 Status
= IoCallDriver(current
->DeviceObject
,Irp
);
105 if (Status
== STATUS_PENDING
)
107 KeWaitForSingleObject(&Event
,
114 current_entry
= current_entry
->Flink
;
117 ExReleaseResourceLite(&FileSystemListLock
);
118 KeLeaveCriticalRegion();
123 IopMountFileSystem(PDEVICE_OBJECT DeviceObject
,
124 PDEVICE_OBJECT DeviceToMount
)
126 IO_STATUS_BLOCK IoStatusBlock
;
127 PIO_STACK_LOCATION StackPtr
;
132 DPRINT("IopMountFileSystem(DeviceObject 0x%p, DeviceToMount 0x%p)\n",
133 DeviceObject
,DeviceToMount
);
135 ASSERT_IRQL(PASSIVE_LEVEL
);
137 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
138 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
141 return(STATUS_INSUFFICIENT_RESOURCES
);
144 Irp
->UserIosb
= &IoStatusBlock
;
145 DPRINT("Irp->UserIosb 0x%p\n", Irp
->UserIosb
);
146 Irp
->UserEvent
= &Event
;
147 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
149 StackPtr
= IoGetNextIrpStackLocation(Irp
);
150 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
151 StackPtr
->MinorFunction
= IRP_MN_MOUNT_VOLUME
;
153 StackPtr
->Control
= 0;
154 StackPtr
->DeviceObject
= DeviceObject
;
155 StackPtr
->FileObject
= NULL
;
156 StackPtr
->CompletionRoutine
= NULL
;
158 StackPtr
->Parameters
.MountVolume
.Vpb
= DeviceToMount
->Vpb
;
159 StackPtr
->Parameters
.MountVolume
.DeviceObject
= DeviceToMount
;
161 Status
= IoCallDriver(DeviceObject
,Irp
);
162 if (Status
==STATUS_PENDING
)
164 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
165 Status
= IoStatusBlock
.Status
;
173 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject
)
175 IO_STATUS_BLOCK IoStatusBlock
;
176 PIO_STACK_LOCATION StackPtr
;
181 DPRINT("IopLoadFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
183 ASSERT_IRQL(PASSIVE_LEVEL
);
185 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
186 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
189 return(STATUS_INSUFFICIENT_RESOURCES
);
192 Irp
->UserIosb
= &IoStatusBlock
;
193 DPRINT("Irp->UserIosb 0x%p\n", Irp
->UserIosb
);
194 Irp
->UserEvent
= &Event
;
195 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
197 StackPtr
= IoGetNextIrpStackLocation(Irp
);
198 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
199 StackPtr
->MinorFunction
= IRP_MN_LOAD_FILE_SYSTEM
;
201 StackPtr
->Control
= 0;
202 StackPtr
->DeviceObject
= DeviceObject
;
203 StackPtr
->FileObject
= NULL
;
204 StackPtr
->CompletionRoutine
= NULL
;
206 Status
= IoCallDriver(DeviceObject
,Irp
);
207 if (Status
==STATUS_PENDING
)
209 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
210 Status
= IoStatusBlock
.Status
;
218 IoMountVolume(IN PDEVICE_OBJECT DeviceObject
,
219 IN BOOLEAN AllowRawMount
)
221 * FUNCTION: Mounts a logical volume
223 * DeviceObject = Device to mount
227 PLIST_ENTRY current_entry
;
228 FILE_SYSTEM_OBJECT
* current
;
230 DEVICE_TYPE MatchingDeviceType
;
231 PDEVICE_OBJECT DevObject
;
233 ASSERT_IRQL(PASSIVE_LEVEL
);
235 DPRINT("IoMountVolume(DeviceObject 0x%p AllowRawMount %x)\n",
236 DeviceObject
, AllowRawMount
);
238 switch (DeviceObject
->DeviceType
)
240 case FILE_DEVICE_DISK
:
241 case FILE_DEVICE_VIRTUAL_DISK
: /* ?? */
242 MatchingDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
245 case FILE_DEVICE_CD_ROM
:
246 MatchingDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
249 case FILE_DEVICE_NETWORK
:
250 MatchingDeviceType
= FILE_DEVICE_NETWORK_FILE_SYSTEM
;
253 case FILE_DEVICE_TAPE
:
254 MatchingDeviceType
= FILE_DEVICE_TAPE_FILE_SYSTEM
;
258 CPRINT("No matching file system type found for device type: %x\n",
259 DeviceObject
->DeviceType
);
260 return(STATUS_UNRECOGNIZED_VOLUME
);
263 KeEnterCriticalRegion();
264 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
265 current_entry
= FileSystemListHead
.Flink
;
266 while (current_entry
!=(&FileSystemListHead
))
268 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
269 if (current
->DeviceObject
->DeviceType
!= MatchingDeviceType
)
271 current_entry
= current_entry
->Flink
;
274 /* If we are not allowed to mount this volume as a raw filesystem volume
275 then don't try this */
276 if (!AllowRawMount
&& RawFsIsRawFileSystemDeviceObject(current
->DeviceObject
))
278 Status
= STATUS_UNRECOGNIZED_VOLUME
;
282 Status
= IopMountFileSystem(current
->DeviceObject
,
287 case STATUS_FS_DRIVER_REQUIRED
:
288 DevObject
= current
->DeviceObject
;
289 ExReleaseResourceLite(&FileSystemListLock
);
290 Status
= IopLoadFileSystem(DevObject
);
291 if (!NT_SUCCESS(Status
))
293 KeLeaveCriticalRegion();
296 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
297 current_entry
= FileSystemListHead
.Flink
;
301 DeviceObject
->Vpb
->Flags
= DeviceObject
->Vpb
->Flags
|
303 ExReleaseResourceLite(&FileSystemListLock
);
304 KeLeaveCriticalRegion();
305 return(STATUS_SUCCESS
);
307 case STATUS_UNRECOGNIZED_VOLUME
:
309 current_entry
= current_entry
->Flink
;
312 ExReleaseResourceLite(&FileSystemListLock
);
313 KeLeaveCriticalRegion();
315 return(STATUS_UNRECOGNIZED_VOLUME
);
319 /**********************************************************************
324 * Verify the file system type and volume information or mount
329 * Device to verify or mount
340 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
341 IN BOOLEAN AllowRawMount
)
343 IO_STATUS_BLOCK IoStatusBlock
;
344 PIO_STACK_LOCATION StackPtr
;
348 PDEVICE_OBJECT DevObject
;
350 DPRINT("IoVerifyVolume(DeviceObject 0x%p AllowRawMount %x)\n",
351 DeviceObject
, AllowRawMount
);
353 Status
= STATUS_SUCCESS
;
355 KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
361 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
363 /* Issue verify request to the FSD */
364 DevObject
= DeviceObject
->Vpb
->DeviceObject
;
366 KeInitializeEvent(&Event
,
370 Irp
= IoAllocateIrp(DevObject
->StackSize
, TRUE
);
373 return(STATUS_INSUFFICIENT_RESOURCES
);
376 Irp
->UserIosb
= &IoStatusBlock
;
377 Irp
->UserEvent
= &Event
;
378 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
380 StackPtr
= IoGetNextIrpStackLocation(Irp
);
381 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
382 StackPtr
->MinorFunction
= IRP_MN_VERIFY_VOLUME
;
384 StackPtr
->Control
= 0;
385 StackPtr
->DeviceObject
= DevObject
;
386 StackPtr
->FileObject
= NULL
;
387 StackPtr
->CompletionRoutine
= NULL
;
389 StackPtr
->Parameters
.VerifyVolume
.Vpb
= DeviceObject
->Vpb
;
390 StackPtr
->Parameters
.VerifyVolume
.DeviceObject
= DeviceObject
;
392 Status
= IoCallDriver(DevObject
,
394 if (Status
==STATUS_PENDING
)
396 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
397 Status
= IoStatusBlock
.Status
;
400 if (NT_SUCCESS(Status
))
402 KeSetEvent(&DeviceObject
->DeviceLock
,
405 return(STATUS_SUCCESS
);
409 if (Status
== STATUS_WRONG_VOLUME
)
411 /* Clean existing VPB. This unmounts the filesystem. */
412 DPRINT("Wrong volume!\n");
414 DeviceObject
->Vpb
->DeviceObject
= NULL
;
415 DeviceObject
->Vpb
->Flags
&= ~VPB_MOUNTED
;
418 /* Start mount sequence */
419 Status
= IoMountVolume(DeviceObject
,
422 KeSetEvent(&DeviceObject
->DeviceLock
,
433 PDEVICE_OBJECT STDCALL
434 IoGetDeviceToVerify(IN PETHREAD Thread
)
436 * FUNCTION: Returns a pointer to the device, representing a removable-media
437 * device, that is the target of the given thread's I/O request
440 return(Thread
->DeviceToVerify
);
448 IoSetDeviceToVerify(IN PETHREAD Thread
,
449 IN PDEVICE_OBJECT DeviceObject
)
451 Thread
->DeviceToVerify
= DeviceObject
;
459 IoSetHardErrorOrVerifyDevice(IN PIRP Irp
,
460 IN PDEVICE_OBJECT DeviceObject
)
462 Irp
->Tail
.Overlay
.Thread
->DeviceToVerify
= DeviceObject
;
470 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
472 PFILE_SYSTEM_OBJECT Fs
;
474 DPRINT("IoRegisterFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
476 Fs
= ExAllocatePoolWithTag(NonPagedPool
,
477 sizeof(FILE_SYSTEM_OBJECT
),
481 Fs
->DeviceObject
= DeviceObject
;
482 KeEnterCriticalRegion();
483 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
485 /* The RAW filesystem device objects must be last in the list so the
486 raw filesystem driver is the last filesystem driver asked to mount
487 a volume. It is always the first filesystem driver registered so
488 we use InsertHeadList() here as opposed to the other alternative
490 InsertHeadList(&FileSystemListHead
,
493 ExReleaseResourceLite(&FileSystemListLock
);
494 KeLeaveCriticalRegion();
496 IopNotifyFileSystemChange(DeviceObject
,
505 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
507 PLIST_ENTRY current_entry
;
508 PFILE_SYSTEM_OBJECT current
;
510 DPRINT("IoUnregisterFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
512 KeEnterCriticalRegion();
513 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
514 current_entry
= FileSystemListHead
.Flink
;
515 while (current_entry
!=(&FileSystemListHead
))
517 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
518 if (current
->DeviceObject
== DeviceObject
)
520 RemoveEntryList(current_entry
);
521 ExFreePoolWithTag(current
, TAG_FILE_SYSTEM
);
522 ExReleaseResourceLite(&FileSystemListLock
);
523 KeLeaveCriticalRegion();
524 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
527 current_entry
= current_entry
->Flink
;
529 ExReleaseResourceLite(&FileSystemListLock
);
530 KeLeaveCriticalRegion();
534 /**********************************************************************
536 * IoGetBaseFileSystemDeviceObject@4
539 * Get the DEVICE_OBJECT associated to
548 * From Bo Branten's ntifs.h v13.
552 PDEVICE_OBJECT STDCALL
553 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
555 PDEVICE_OBJECT DeviceObject
= NULL
;
559 * If the FILE_OBJECT's VPB is defined,
560 * get the device from it.
562 if (NULL
!= (Vpb
= FileObject
->Vpb
))
564 if (NULL
!= (DeviceObject
= Vpb
->DeviceObject
))
566 /* Vpb->DeviceObject DEFINED! */
571 * If that failed, try the VPB
572 * in the FILE_OBJECT's DeviceObject.
574 DeviceObject
= FileObject
->DeviceObject
;
575 if (NULL
== (Vpb
= DeviceObject
->Vpb
))
577 /* DeviceObject->Vpb UNDEFINED! */
581 * If that pointer to the VPB is again
582 * undefined, return directly the
583 * device object from the FILE_OBJECT.
586 (NULL
== Vpb
->DeviceObject
)
594 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
595 BOOLEAN DriverActive
)
597 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
600 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
601 Entry
= FsChangeNotifyListHead
.Flink
;
602 while (Entry
!= &FsChangeNotifyListHead
)
604 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
606 (ChangeEntry
->FSDNotificationProc
)(DeviceObject
, DriverActive
);
608 Entry
= Entry
->Flink
;
610 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
618 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
619 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
621 PFS_CHANGE_NOTIFY_ENTRY Entry
;
623 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
624 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
625 TAG_FS_CHANGE_NOTIFY
);
627 return(STATUS_INSUFFICIENT_RESOURCES
);
629 Entry
->DriverObject
= DriverObject
;
630 Entry
->FSDNotificationProc
= FSDNotificationProc
;
632 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
633 InsertHeadList(&FsChangeNotifyListHead
,
634 &Entry
->FsChangeNotifyList
);
635 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
637 return(STATUS_SUCCESS
);
645 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
646 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
648 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
651 Entry
= FsChangeNotifyListHead
.Flink
;
652 while (Entry
!= &FsChangeNotifyListHead
)
654 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
655 if (ChangeEntry
->DriverObject
== DriverObject
&&
656 ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
)
658 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
659 RemoveEntryList(Entry
);
660 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
662 ExFreePoolWithTag(Entry
, TAG_FS_CHANGE_NOTIFY
);
666 Entry
= Entry
->Flink
;