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 FILE_SYSTEM_OBJECT
* current
;
78 IO_STATUS_BLOCK IoStatusBlock
;
81 DPRINT("IoShutdownRegisteredFileSystems()\n");
83 KeEnterCriticalRegion();
84 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
85 KeInitializeEvent(&Event
,
89 LIST_FOR_EACH(current
, &FileSystemListHead
, FILE_SYSTEM_OBJECT
,Entry
)
91 /* send IRP_MJ_SHUTDOWN */
92 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
93 current
->DeviceObject
,
100 Status
= IoCallDriver(current
->DeviceObject
,Irp
);
101 if (Status
== STATUS_PENDING
)
103 KeWaitForSingleObject(&Event
,
111 ExReleaseResourceLite(&FileSystemListLock
);
112 KeLeaveCriticalRegion();
117 IopMountFileSystem(PDEVICE_OBJECT DeviceObject
,
118 PDEVICE_OBJECT DeviceToMount
)
120 IO_STATUS_BLOCK IoStatusBlock
;
121 PIO_STACK_LOCATION StackPtr
;
126 DPRINT("IopMountFileSystem(DeviceObject 0x%p, DeviceToMount 0x%p)\n",
127 DeviceObject
,DeviceToMount
);
129 ASSERT_IRQL(PASSIVE_LEVEL
);
131 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
132 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
135 return(STATUS_INSUFFICIENT_RESOURCES
);
138 Irp
->UserIosb
= &IoStatusBlock
;
139 DPRINT("Irp->UserIosb 0x%p\n", Irp
->UserIosb
);
140 Irp
->UserEvent
= &Event
;
141 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
143 StackPtr
= IoGetNextIrpStackLocation(Irp
);
144 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
145 StackPtr
->MinorFunction
= IRP_MN_MOUNT_VOLUME
;
147 StackPtr
->Control
= 0;
148 StackPtr
->DeviceObject
= DeviceObject
;
149 StackPtr
->FileObject
= NULL
;
150 StackPtr
->CompletionRoutine
= NULL
;
152 StackPtr
->Parameters
.MountVolume
.Vpb
= DeviceToMount
->Vpb
;
153 StackPtr
->Parameters
.MountVolume
.DeviceObject
= DeviceToMount
;
155 Status
= IoCallDriver(DeviceObject
,Irp
);
156 if (Status
==STATUS_PENDING
)
158 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
159 Status
= IoStatusBlock
.Status
;
167 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject
)
169 IO_STATUS_BLOCK IoStatusBlock
;
170 PIO_STACK_LOCATION StackPtr
;
175 DPRINT("IopLoadFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
177 ASSERT_IRQL(PASSIVE_LEVEL
);
179 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
180 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
183 return(STATUS_INSUFFICIENT_RESOURCES
);
186 Irp
->UserIosb
= &IoStatusBlock
;
187 DPRINT("Irp->UserIosb 0x%p\n", Irp
->UserIosb
);
188 Irp
->UserEvent
= &Event
;
189 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
191 StackPtr
= IoGetNextIrpStackLocation(Irp
);
192 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
193 StackPtr
->MinorFunction
= IRP_MN_LOAD_FILE_SYSTEM
;
195 StackPtr
->Control
= 0;
196 StackPtr
->DeviceObject
= DeviceObject
;
197 StackPtr
->FileObject
= NULL
;
198 StackPtr
->CompletionRoutine
= NULL
;
200 Status
= IoCallDriver(DeviceObject
,Irp
);
201 if (Status
==STATUS_PENDING
)
203 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
204 Status
= IoStatusBlock
.Status
;
212 IoMountVolume(IN PDEVICE_OBJECT DeviceObject
,
213 IN BOOLEAN AllowRawMount
)
215 * FUNCTION: Mounts a logical volume
217 * DeviceObject = Device to mount
221 PFILE_SYSTEM_OBJECT current
;
223 DEVICE_TYPE MatchingDeviceType
;
224 PDEVICE_OBJECT DevObject
;
226 ASSERT_IRQL(PASSIVE_LEVEL
);
228 DPRINT("IoMountVolume(DeviceObject 0x%p AllowRawMount %x)\n",
229 DeviceObject
, AllowRawMount
);
231 switch (DeviceObject
->DeviceType
)
233 case FILE_DEVICE_DISK
:
234 case FILE_DEVICE_VIRTUAL_DISK
: /* ?? */
235 MatchingDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
238 case FILE_DEVICE_CD_ROM
:
239 MatchingDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
242 case FILE_DEVICE_NETWORK
:
243 MatchingDeviceType
= FILE_DEVICE_NETWORK_FILE_SYSTEM
;
246 case FILE_DEVICE_TAPE
:
247 MatchingDeviceType
= FILE_DEVICE_TAPE_FILE_SYSTEM
;
251 CPRINT("No matching file system type found for device type: %x\n",
252 DeviceObject
->DeviceType
);
253 return(STATUS_UNRECOGNIZED_VOLUME
);
256 KeEnterCriticalRegion();
257 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
260 LIST_FOR_EACH(current
,&FileSystemListHead
, FILE_SYSTEM_OBJECT
, Entry
)
262 if (current
->DeviceObject
->DeviceType
!= MatchingDeviceType
)
266 /* If we are not allowed to mount this volume as a raw filesystem volume
267 then don't try this */
268 if (!AllowRawMount
&& RawFsIsRawFileSystemDeviceObject(current
->DeviceObject
))
270 Status
= STATUS_UNRECOGNIZED_VOLUME
;
274 Status
= IopMountFileSystem(current
->DeviceObject
,
279 case STATUS_FS_DRIVER_REQUIRED
:
280 DevObject
= current
->DeviceObject
;
281 ExReleaseResourceLite(&FileSystemListLock
);
282 Status
= IopLoadFileSystem(DevObject
);
283 if (!NT_SUCCESS(Status
))
285 KeLeaveCriticalRegion();
288 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
292 DeviceObject
->Vpb
->Flags
= DeviceObject
->Vpb
->Flags
|
294 ExReleaseResourceLite(&FileSystemListLock
);
295 KeLeaveCriticalRegion();
296 return(STATUS_SUCCESS
);
298 case STATUS_UNRECOGNIZED_VOLUME
:
304 ExReleaseResourceLite(&FileSystemListLock
);
305 KeLeaveCriticalRegion();
307 return(STATUS_UNRECOGNIZED_VOLUME
);
311 /**********************************************************************
316 * Verify the file system type and volume information or mount
321 * Device to verify or mount
332 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
333 IN BOOLEAN AllowRawMount
)
335 IO_STATUS_BLOCK IoStatusBlock
;
336 PIO_STACK_LOCATION StackPtr
;
340 PDEVICE_OBJECT DevObject
;
342 DPRINT("IoVerifyVolume(DeviceObject 0x%p AllowRawMount %x)\n",
343 DeviceObject
, AllowRawMount
);
345 Status
= STATUS_SUCCESS
;
347 KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
353 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
355 /* Issue verify request to the FSD */
356 DevObject
= DeviceObject
->Vpb
->DeviceObject
;
358 KeInitializeEvent(&Event
,
362 Irp
= IoAllocateIrp(DevObject
->StackSize
, TRUE
);
365 return(STATUS_INSUFFICIENT_RESOURCES
);
368 Irp
->UserIosb
= &IoStatusBlock
;
369 Irp
->UserEvent
= &Event
;
370 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
372 StackPtr
= IoGetNextIrpStackLocation(Irp
);
373 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
374 StackPtr
->MinorFunction
= IRP_MN_VERIFY_VOLUME
;
376 StackPtr
->Control
= 0;
377 StackPtr
->DeviceObject
= DevObject
;
378 StackPtr
->FileObject
= NULL
;
379 StackPtr
->CompletionRoutine
= NULL
;
381 StackPtr
->Parameters
.VerifyVolume
.Vpb
= DeviceObject
->Vpb
;
382 StackPtr
->Parameters
.VerifyVolume
.DeviceObject
= DeviceObject
;
384 Status
= IoCallDriver(DevObject
,
386 if (Status
==STATUS_PENDING
)
388 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
389 Status
= IoStatusBlock
.Status
;
392 if (NT_SUCCESS(Status
))
394 KeSetEvent(&DeviceObject
->DeviceLock
,
397 return(STATUS_SUCCESS
);
401 if (Status
== STATUS_WRONG_VOLUME
)
403 /* Clean existing VPB. This unmounts the filesystem. */
404 DPRINT("Wrong volume!\n");
406 DeviceObject
->Vpb
->DeviceObject
= NULL
;
407 DeviceObject
->Vpb
->Flags
&= ~VPB_MOUNTED
;
410 /* Start mount sequence */
411 Status
= IoMountVolume(DeviceObject
,
414 KeSetEvent(&DeviceObject
->DeviceLock
,
425 PDEVICE_OBJECT STDCALL
426 IoGetDeviceToVerify(IN PETHREAD Thread
)
428 * FUNCTION: Returns a pointer to the device, representing a removable-media
429 * device, that is the target of the given thread's I/O request
432 return(Thread
->DeviceToVerify
);
440 IoSetDeviceToVerify(IN PETHREAD Thread
,
441 IN PDEVICE_OBJECT DeviceObject
)
443 Thread
->DeviceToVerify
= DeviceObject
;
451 IoSetHardErrorOrVerifyDevice(IN PIRP Irp
,
452 IN PDEVICE_OBJECT DeviceObject
)
454 Irp
->Tail
.Overlay
.Thread
->DeviceToVerify
= DeviceObject
;
462 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
464 PFILE_SYSTEM_OBJECT Fs
;
466 DPRINT("IoRegisterFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
468 Fs
= ExAllocatePoolWithTag(NonPagedPool
,
469 sizeof(FILE_SYSTEM_OBJECT
),
473 Fs
->DeviceObject
= DeviceObject
;
474 KeEnterCriticalRegion();
475 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
477 /* The RAW filesystem device objects must be last in the list so the
478 raw filesystem driver is the last filesystem driver asked to mount
479 a volume. It is always the first filesystem driver registered so
480 we use InsertHeadList() here as opposed to the other alternative
482 InsertHeadList(&FileSystemListHead
,
485 ExReleaseResourceLite(&FileSystemListLock
);
486 KeLeaveCriticalRegion();
488 IopNotifyFileSystemChange(DeviceObject
,
497 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
499 PFILE_SYSTEM_OBJECT current
;
501 DPRINT("IoUnregisterFileSystem(DeviceObject 0x%p)\n", DeviceObject
);
503 KeEnterCriticalRegion();
504 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
506 LIST_FOR_EACH(current
,&FileSystemListHead
, FILE_SYSTEM_OBJECT
,Entry
)
508 if (current
->DeviceObject
== DeviceObject
)
510 RemoveEntryList(¤t
->Entry
);
511 ExFreePoolWithTag(current
, TAG_FILE_SYSTEM
);
512 ExReleaseResourceLite(&FileSystemListLock
);
513 KeLeaveCriticalRegion();
514 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
519 ExReleaseResourceLite(&FileSystemListLock
);
520 KeLeaveCriticalRegion();
524 /**********************************************************************
526 * IoGetBaseFileSystemDeviceObject@4
529 * Get the DEVICE_OBJECT associated to
538 * From Bo Branten's ntifs.h v13.
542 PDEVICE_OBJECT STDCALL
543 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
545 PDEVICE_OBJECT DeviceObject
= NULL
;
549 * If the FILE_OBJECT's VPB is defined,
550 * get the device from it.
552 if (NULL
!= (Vpb
= FileObject
->Vpb
))
554 if (NULL
!= (DeviceObject
= Vpb
->DeviceObject
))
556 /* Vpb->DeviceObject DEFINED! */
561 * If that failed, try the VPB
562 * in the FILE_OBJECT's DeviceObject.
564 DeviceObject
= FileObject
->DeviceObject
;
565 if (NULL
== (Vpb
= DeviceObject
->Vpb
))
567 /* DeviceObject->Vpb UNDEFINED! */
571 * If that pointer to the VPB is again
572 * undefined, return directly the
573 * device object from the FILE_OBJECT.
576 (NULL
== Vpb
->DeviceObject
)
584 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
585 BOOLEAN DriverActive
)
587 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
589 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
590 LIST_FOR_EACH(ChangeEntry
, &FsChangeNotifyListHead
,FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
)
592 (ChangeEntry
->FSDNotificationProc
)(DeviceObject
, DriverActive
);
594 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
602 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
603 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
605 PFS_CHANGE_NOTIFY_ENTRY Entry
;
607 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
608 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
609 TAG_FS_CHANGE_NOTIFY
);
611 return(STATUS_INSUFFICIENT_RESOURCES
);
613 Entry
->DriverObject
= DriverObject
;
614 Entry
->FSDNotificationProc
= FSDNotificationProc
;
616 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
617 InsertHeadList(&FsChangeNotifyListHead
,
618 &Entry
->FsChangeNotifyList
);
619 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
621 return(STATUS_SUCCESS
);
629 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
630 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc
)
632 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
634 LIST_FOR_EACH(ChangeEntry
, &FsChangeNotifyListHead
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
)
636 if (ChangeEntry
->DriverObject
== DriverObject
&&
637 ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
)
639 KeAcquireGuardedMutex(&FsChangeNotifyListLock
);
640 RemoveEntryList(&ChangeEntry
->FsChangeNotifyList
);
641 KeReleaseGuardedMutex(&FsChangeNotifyListLock
);
643 ExFreePoolWithTag(ChangeEntry
, TAG_FS_CHANGE_NOTIFY
);