1 /* $Id: fs.c,v 1.36 2003/08/07 11:47:33 silverblade Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/fs.c
6 * PURPOSE: Filesystem functions
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/io.h>
16 #include <internal/ps.h>
17 #include <internal/pool.h>
20 #include <internal/debug.h>
23 /* TYPES *******************************************************************/
25 typedef struct _FILE_SYSTEM_OBJECT
27 PDEVICE_OBJECT DeviceObject
;
29 } FILE_SYSTEM_OBJECT
, *PFILE_SYSTEM_OBJECT
;
31 typedef struct _FS_CHANGE_NOTIFY_ENTRY
33 LIST_ENTRY FsChangeNotifyList
;
34 PDRIVER_OBJECT DriverObject
;
35 PFSDNOTIFICATIONPROC FSDNotificationProc
;
36 } FS_CHANGE_NOTIFY_ENTRY
, *PFS_CHANGE_NOTIFY_ENTRY
;
38 /* GLOBALS ******************************************************************/
40 static ERESOURCE FileSystemListLock
;
41 static LIST_ENTRY FileSystemListHead
;
43 static KSPIN_LOCK FsChangeNotifyListLock
;
44 static LIST_ENTRY FsChangeNotifyListHead
;
46 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
47 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
51 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
52 BOOLEAN DriverActive
);
55 /* FUNCTIONS *****************************************************************/
62 IN HANDLE DeviceHandle
,
63 IN HANDLE EventHandle OPTIONAL
,
64 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
65 IN PVOID ApcContext OPTIONAL
,
66 OUT PIO_STATUS_BLOCK IoStatusBlock
,
67 IN ULONG IoControlCode
,
69 IN ULONG InputBufferSize
,
70 OUT PVOID OutputBuffer
,
71 IN ULONG OutputBufferSize
75 PFILE_OBJECT FileObject
;
76 PDEVICE_OBJECT DeviceObject
;
78 PEXTENDED_IO_STACK_LOCATION StackPtr
;
82 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
83 "ApcContext %x IoStatusBlock %x IoControlCode %x "
84 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
85 "OutputBufferSize %x)\n",
86 DeviceHandle
,EventHandle
,ApcRoutine
,ApcContext
,IoStatusBlock
,
87 IoControlCode
,InputBuffer
,InputBufferSize
,OutputBuffer
,
90 Status
= ObReferenceObjectByHandle(DeviceHandle
,
91 FILE_READ_DATA
| FILE_WRITE_DATA
,
94 (PVOID
*) &FileObject
,
97 if (!NT_SUCCESS(Status
))
102 if (EventHandle
!= NULL
)
104 Status
= ObReferenceObjectByHandle (EventHandle
,
110 if (!NT_SUCCESS(Status
))
112 ObDereferenceObject(FileObject
);
118 KeResetEvent (&FileObject
->Event
);
119 ptrEvent
= &FileObject
->Event
;
123 DeviceObject
= FileObject
->DeviceObject
;
125 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
,
135 //trigger FileObject/Event dereferencing
136 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
138 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= ApcRoutine
;
139 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
= ApcContext
;
141 StackPtr
= (PEXTENDED_IO_STACK_LOCATION
) IoGetNextIrpStackLocation(Irp
);
142 StackPtr
->FileObject
= FileObject
;
143 StackPtr
->DeviceObject
= DeviceObject
;
144 StackPtr
->Parameters
.FileSystemControl
.InputBufferLength
= InputBufferSize
;
145 StackPtr
->Parameters
.FileSystemControl
.OutputBufferLength
=
147 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
149 Status
= IoCallDriver(DeviceObject
,Irp
);
150 if (Status
== STATUS_PENDING
&& !(FileObject
->Flags
& FO_SYNCHRONOUS_IO
))
152 KeWaitForSingleObject(ptrEvent
,Executive
,KernelMode
,FALSE
,NULL
);
153 Status
= IoSB
.Status
;
157 *IoStatusBlock
= IoSB
;
164 IoInitFileSystemImplementation(VOID
)
166 InitializeListHead(&FileSystemListHead
);
167 ExInitializeResourceLite(&FileSystemListLock
);
169 InitializeListHead(&FsChangeNotifyListHead
);
170 KeInitializeSpinLock(&FsChangeNotifyListLock
);
175 IoShutdownRegisteredFileSystems(VOID
)
177 PLIST_ENTRY current_entry
;
178 FILE_SYSTEM_OBJECT
* current
;
181 IO_STATUS_BLOCK IoStatusBlock
;
184 DPRINT("IoShutdownRegisteredFileSystems()\n");
186 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
187 KeInitializeEvent(&Event
,
191 current_entry
= FileSystemListHead
.Flink
;
192 while (current_entry
!=(&FileSystemListHead
))
194 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
196 /* send IRP_MJ_SHUTDOWN */
197 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
198 current
->DeviceObject
,
205 Status
= IoCallDriver(current
->DeviceObject
,Irp
);
206 if (Status
== STATUS_PENDING
)
208 KeWaitForSingleObject(&Event
,
215 current_entry
= current_entry
->Flink
;
218 ExReleaseResourceLite(&FileSystemListLock
);
223 IopMountFileSystem(PDEVICE_OBJECT DeviceObject
,
224 PDEVICE_OBJECT DeviceToMount
)
226 IO_STATUS_BLOCK IoStatusBlock
;
227 PIO_STACK_LOCATION StackPtr
;
232 DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
233 DeviceObject
,DeviceToMount
);
235 assert_irql(PASSIVE_LEVEL
);
237 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
238 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
241 return(STATUS_INSUFFICIENT_RESOURCES
);
244 Irp
->UserIosb
= &IoStatusBlock
;
245 DPRINT("Irp->UserIosb %x\n", Irp
->UserIosb
);
246 Irp
->UserEvent
= &Event
;
247 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
249 StackPtr
= IoGetNextIrpStackLocation(Irp
);
250 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
251 StackPtr
->MinorFunction
= IRP_MN_MOUNT_VOLUME
;
253 StackPtr
->Control
= 0;
254 StackPtr
->DeviceObject
= DeviceObject
;
255 StackPtr
->FileObject
= NULL
;
256 StackPtr
->CompletionRoutine
= NULL
;
258 StackPtr
->Parameters
.MountVolume
.Vpb
= DeviceToMount
->Vpb
;
259 StackPtr
->Parameters
.MountVolume
.DeviceObject
= DeviceToMount
;
261 Status
= IoCallDriver(DeviceObject
,Irp
);
262 if (Status
==STATUS_PENDING
)
264 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
265 Status
= IoStatusBlock
.Status
;
273 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject
)
275 IO_STATUS_BLOCK IoStatusBlock
;
276 PIO_STACK_LOCATION StackPtr
;
281 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject
);
283 assert_irql(PASSIVE_LEVEL
);
285 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
286 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
289 return(STATUS_INSUFFICIENT_RESOURCES
);
292 Irp
->UserIosb
= &IoStatusBlock
;
293 DPRINT("Irp->UserIosb %x\n", Irp
->UserIosb
);
294 Irp
->UserEvent
= &Event
;
295 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
297 StackPtr
= IoGetNextIrpStackLocation(Irp
);
298 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
299 StackPtr
->MinorFunction
= IRP_MN_LOAD_FILE_SYSTEM
;
301 StackPtr
->Control
= 0;
302 StackPtr
->DeviceObject
= DeviceObject
;
303 StackPtr
->FileObject
= NULL
;
304 StackPtr
->CompletionRoutine
= NULL
;
306 Status
= IoCallDriver(DeviceObject
,Irp
);
307 if (Status
==STATUS_PENDING
)
309 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
310 Status
= IoStatusBlock
.Status
;
318 IoMountVolume(IN PDEVICE_OBJECT DeviceObject
,
319 IN BOOLEAN AllowRawMount
)
321 * FUNCTION: Mounts a logical volume
323 * DeviceObject = Device to mount
327 PLIST_ENTRY current_entry
;
328 FILE_SYSTEM_OBJECT
* current
;
330 DEVICE_TYPE MatchingDeviceType
;
331 PDEVICE_OBJECT DevObject
;
333 assert_irql(PASSIVE_LEVEL
);
335 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
336 DeviceObject
, AllowRawMount
);
338 switch (DeviceObject
->DeviceType
)
340 case FILE_DEVICE_DISK
:
341 case FILE_DEVICE_VIRTUAL_DISK
: /* ?? */
342 MatchingDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
345 case FILE_DEVICE_CD_ROM
:
346 MatchingDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
349 case FILE_DEVICE_NETWORK
:
350 MatchingDeviceType
= FILE_DEVICE_NETWORK_FILE_SYSTEM
;
353 case FILE_DEVICE_TAPE
:
354 MatchingDeviceType
= FILE_DEVICE_TAPE_FILE_SYSTEM
;
358 CPRINT("No matching file system type found for device type: %x\n",
359 DeviceObject
->DeviceType
);
360 return(STATUS_UNRECOGNIZED_VOLUME
);
363 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
364 current_entry
= FileSystemListHead
.Flink
;
365 while (current_entry
!=(&FileSystemListHead
))
367 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
368 if (current
->DeviceObject
->DeviceType
!= MatchingDeviceType
)
370 current_entry
= current_entry
->Flink
;
373 /* If we are not allowed to mount this volume as a raw filesystem volume
374 then don't try this */
375 if (!AllowRawMount
&& RawFsIsRawFileSystemDeviceObject(current
->DeviceObject
))
377 Status
= STATUS_UNRECOGNIZED_VOLUME
;
381 Status
= IopMountFileSystem(current
->DeviceObject
,
386 case STATUS_FS_DRIVER_REQUIRED
:
387 DevObject
= current
->DeviceObject
;
388 ExReleaseResourceLite(&FileSystemListLock
);
389 Status
= IopLoadFileSystem(DevObject
);
390 if (!NT_SUCCESS(Status
))
394 ExAcquireResourceSharedLite(&FileSystemListLock
,TRUE
);
395 current_entry
= FileSystemListHead
.Flink
;
399 DeviceObject
->Vpb
->Flags
= DeviceObject
->Vpb
->Flags
|
401 ExReleaseResourceLite(&FileSystemListLock
);
402 return(STATUS_SUCCESS
);
404 case STATUS_UNRECOGNIZED_VOLUME
:
406 current_entry
= current_entry
->Flink
;
409 ExReleaseResourceLite(&FileSystemListLock
);
411 return(STATUS_UNRECOGNIZED_VOLUME
);
415 /**********************************************************************
420 * Verify the file system type and volume information or mount
425 * Device to verify or mount
436 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
437 IN BOOLEAN AllowRawMount
)
439 IO_STATUS_BLOCK IoStatusBlock
;
440 PIO_STACK_LOCATION StackPtr
;
444 PDEVICE_OBJECT DevObject
;
446 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
447 DeviceObject
, AllowRawMount
);
449 Status
= STATUS_SUCCESS
;
451 KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
457 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
459 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
461 /* Issue verify request to the FSD */
462 DevObject
= DeviceObject
->Vpb
->DeviceObject
;
464 KeInitializeEvent(&Event
,
468 Irp
= IoAllocateIrp(DevObject
->StackSize
, TRUE
);
471 return(STATUS_INSUFFICIENT_RESOURCES
);
474 Irp
->UserIosb
= &IoStatusBlock
;
475 Irp
->UserEvent
= &Event
;
476 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
478 StackPtr
= IoGetNextIrpStackLocation(Irp
);
479 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
480 StackPtr
->MinorFunction
= IRP_MN_VERIFY_VOLUME
;
482 StackPtr
->Control
= 0;
483 StackPtr
->DeviceObject
= DevObject
;
484 StackPtr
->FileObject
= NULL
;
485 StackPtr
->CompletionRoutine
= NULL
;
487 StackPtr
->Parameters
.VerifyVolume
.Vpb
= DeviceObject
->Vpb
;
488 StackPtr
->Parameters
.VerifyVolume
.DeviceObject
= DeviceObject
;
490 Status
= IoCallDriver(DevObject
,
492 if (Status
==STATUS_PENDING
)
494 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
495 Status
= IoStatusBlock
.Status
;
498 if (NT_SUCCESS(Status
))
500 KeSetEvent(&DeviceObject
->DeviceLock
,
503 return(STATUS_SUCCESS
);
507 if (Status
== STATUS_WRONG_VOLUME
)
509 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
510 DPRINT("Wrong volume!\n");
512 DeviceObject
->Vpb
->DeviceObject
= NULL
;
513 DeviceObject
->Vpb
->Flags
&= ~VPB_MOUNTED
;
516 /* Start mount sequence */
517 Status
= IoMountVolume(DeviceObject
,
520 KeSetEvent(&DeviceObject
->DeviceLock
,
531 PDEVICE_OBJECT STDCALL
532 IoGetDeviceToVerify(IN PETHREAD Thread
)
534 * FUNCTION: Returns a pointer to the device, representing a removable-media
535 * device, that is the target of the given thread's I/O request
538 return(Thread
->DeviceToVerify
);
546 IoSetDeviceToVerify(IN PETHREAD Thread
,
547 IN PDEVICE_OBJECT DeviceObject
)
549 Thread
->DeviceToVerify
= DeviceObject
;
557 IoSetHardErrorOrVerifyDevice(IN PIRP Irp
,
558 IN PDEVICE_OBJECT DeviceObject
)
560 Irp
->Tail
.Overlay
.Thread
->DeviceToVerify
= DeviceObject
;
568 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
570 PFILE_SYSTEM_OBJECT Fs
;
572 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject
);
574 Fs
= ExAllocatePoolWithTag(NonPagedPool
,
575 sizeof(FILE_SYSTEM_OBJECT
),
579 Fs
->DeviceObject
= DeviceObject
;
580 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
582 /* The RAW filesystem device objects must be last in the list so the
583 raw filesystem driver is the last filesystem driver asked to mount
584 a volume. It is always the first filesystem driver registered so
585 we use InsertHeadList() here as opposed to the other alternative
587 InsertHeadList(&FileSystemListHead
,
590 ExReleaseResourceLite(&FileSystemListLock
);
592 IopNotifyFileSystemChange(DeviceObject
,
601 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
603 PLIST_ENTRY current_entry
;
604 PFILE_SYSTEM_OBJECT current
;
606 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject
);
608 ExAcquireResourceExclusiveLite(&FileSystemListLock
, TRUE
);
609 current_entry
= FileSystemListHead
.Flink
;
610 while (current_entry
!=(&FileSystemListHead
))
612 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
613 if (current
->DeviceObject
== DeviceObject
)
615 RemoveEntryList(current_entry
);
617 ExReleaseResourceLite(&FileSystemListLock
);
618 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
621 current_entry
= current_entry
->Flink
;
623 ExReleaseResourceLite(&FileSystemListLock
);
627 /**********************************************************************
629 * IoGetBaseFileSystemDeviceObject@4
632 * Get the DEVICE_OBJECT associated to
641 * From Bo Branten's ntifs.h v13.
645 PDEVICE_OBJECT STDCALL
646 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
648 PDEVICE_OBJECT DeviceObject
= NULL
;
652 * If the FILE_OBJECT's VPB is defined,
653 * get the device from it.
655 if (NULL
!= (Vpb
= FileObject
->Vpb
))
657 if (NULL
!= (DeviceObject
= Vpb
->DeviceObject
))
659 /* Vpb->DeviceObject DEFINED! */
664 * If that failed, try the VPB
665 * in the FILE_OBJECT's DeviceObject.
667 DeviceObject
= FileObject
->DeviceObject
;
668 if (NULL
== (Vpb
= DeviceObject
->Vpb
))
670 /* DeviceObject->Vpb UNDEFINED! */
674 * If that pointer to the VPB is again
675 * undefined, return directly the
676 * device object from the FILE_OBJECT.
679 (NULL
== Vpb
->DeviceObject
)
687 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
688 BOOLEAN DriverActive
)
690 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
694 KeAcquireSpinLock(&FsChangeNotifyListLock
,&oldlvl
);
695 Entry
= FsChangeNotifyListHead
.Flink
;
696 while (Entry
!= &FsChangeNotifyListHead
)
698 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
700 (ChangeEntry
->FSDNotificationProc
)(DeviceObject
, DriverActive
);
702 Entry
= Entry
->Flink
;
704 KeReleaseSpinLock(&FsChangeNotifyListLock
,oldlvl
);
712 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
713 IN PFSDNOTIFICATIONPROC FSDNotificationProc
)
715 PFS_CHANGE_NOTIFY_ENTRY Entry
;
717 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
718 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
719 TAG_FS_CHANGE_NOTIFY
);
721 return(STATUS_INSUFFICIENT_RESOURCES
);
723 Entry
->DriverObject
= DriverObject
;
724 Entry
->FSDNotificationProc
= FSDNotificationProc
;
726 ExInterlockedInsertHeadList(&FsChangeNotifyListHead
,
727 &Entry
->FsChangeNotifyList
,
728 &FsChangeNotifyListLock
);
730 return(STATUS_SUCCESS
);
738 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
739 IN PFSDNOTIFICATIONPROC FSDNotificationProc
)
741 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
745 Entry
= FsChangeNotifyListHead
.Flink
;
746 while (Entry
!= &FsChangeNotifyListHead
)
748 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
749 if (ChangeEntry
->DriverObject
== DriverObject
&&
750 ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
)
752 KeAcquireSpinLock(&FsChangeNotifyListLock
,&oldlvl
);
753 RemoveEntryList(Entry
);
754 KeReleaseSpinLock(&FsChangeNotifyListLock
,oldlvl
);
760 Entry
= Entry
->Flink
;