1 /* $Id: fs.c,v 1.25 2002/04/27 19:22:55 hbirr 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
;
39 /* GLOBALS ******************************************************************/
41 static KSPIN_LOCK FileSystemListLock
;
42 static LIST_ENTRY FileSystemListHead
;
44 static KSPIN_LOCK FsChangeNotifyListLock
;
45 static LIST_ENTRY FsChangeNotifyListHead
;
47 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
48 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
52 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
53 BOOLEAN DriverActive
);
56 /* FUNCTIONS *****************************************************************/
60 IN HANDLE DeviceHandle
,
61 IN HANDLE EventHandle OPTIONAL
,
62 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL
,
63 IN PVOID ApcContext OPTIONAL
,
64 OUT PIO_STATUS_BLOCK IoStatusBlock
,
65 IN ULONG IoControlCode
,
67 IN ULONG InputBufferSize
,
68 OUT PVOID OutputBuffer
,
69 IN ULONG OutputBufferSize
73 PFILE_OBJECT FileObject
;
74 PDEVICE_OBJECT DeviceObject
;
76 PIO_STACK_LOCATION StackPtr
;
80 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
81 "ApcContext %x IoStatusBlock %x IoControlCode %x "
82 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
83 "OutputBufferSize %x)\n",
84 DeviceHandle
,EventHandle
,ApcRoutine
,ApcContext
,IoStatusBlock
,
85 IoControlCode
,InputBuffer
,InputBufferSize
,OutputBuffer
,
88 Status
= ObReferenceObjectByHandle(DeviceHandle
,
89 FILE_READ_DATA
| FILE_WRITE_DATA
,
92 (PVOID
*) &FileObject
,
95 if (!NT_SUCCESS(Status
))
100 if (EventHandle
!= NULL
)
102 Status
= ObReferenceObjectByHandle (EventHandle
,
108 if (!NT_SUCCESS(Status
))
110 ObDereferenceObject(FileObject
);
116 KeResetEvent (&FileObject
->Event
);
117 ptrEvent
= &FileObject
->Event
;
121 DeviceObject
= FileObject
->DeviceObject
;
123 Irp
= IoBuildDeviceIoControlRequest(IoControlCode
,
133 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= ApcRoutine
;
134 Irp
->Overlay
.AsynchronousParameters
.UserApcContext
= ApcContext
;
136 StackPtr
= IoGetNextIrpStackLocation(Irp
);
137 StackPtr
->FileObject
= FileObject
;
138 StackPtr
->DeviceObject
= DeviceObject
;
139 StackPtr
->Parameters
.FileSystemControl
.InputBufferLength
= InputBufferSize
;
140 StackPtr
->Parameters
.FileSystemControl
.OutputBufferLength
=
142 StackPtr
->MajorFunction
= IRP_MJ_FILE_SYSTEM_CONTROL
;
144 Status
= IoCallDriver(DeviceObject
,Irp
);
145 if (Status
== STATUS_PENDING
&& !(FileObject
->Flags
& FO_SYNCHRONOUS_IO
))
147 KeWaitForSingleObject(ptrEvent
,Executive
,KernelMode
,FALSE
,NULL
);
148 Status
= IoSB
.Status
;
152 *IoStatusBlock
= IoSB
;
159 IoInitFileSystemImplementation(VOID
)
161 InitializeListHead(&FileSystemListHead
);
162 KeInitializeSpinLock(&FileSystemListLock
);
164 InitializeListHead(&FsChangeNotifyListHead
);
165 KeInitializeSpinLock(&FsChangeNotifyListLock
);
170 IoShutdownRegisteredFileSystems(VOID
)
173 PLIST_ENTRY current_entry
;
174 FILE_SYSTEM_OBJECT
* current
;
177 IO_STATUS_BLOCK IoStatusBlock
;
180 DPRINT("IoShutdownRegisteredFileSystems()\n");
182 KeAcquireSpinLock(&FileSystemListLock
,&oldlvl
);
183 KeInitializeEvent(&Event
,NotificationEvent
,FALSE
);
185 current_entry
= FileSystemListHead
.Flink
;
186 while (current_entry
!=(&FileSystemListHead
))
188 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
190 /* send IRP_MJ_SHUTDOWN */
191 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN
,
192 current
->DeviceObject
,
199 Status
= IoCallDriver(current
->DeviceObject
,Irp
);
200 if (Status
==STATUS_PENDING
)
202 KeWaitForSingleObject(&Event
,Executive
,KernelMode
,FALSE
,NULL
);
205 current_entry
= current_entry
->Flink
;
208 KeReleaseSpinLock(&FileSystemListLock
,oldlvl
);
213 IoAskFileSystemToMountDevice(PDEVICE_OBJECT DeviceObject
,
214 PDEVICE_OBJECT DeviceToMount
)
217 IO_STATUS_BLOCK IoStatusBlock
;
219 PKEVENT Event
; // KEVENT must be allocated from non paged pool, not stack
221 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
222 DeviceObject
,DeviceToMount
);
224 assert_irql(PASSIVE_LEVEL
);
225 Event
= ExAllocatePool( NonPagedPool
, sizeof( KEVENT
) );
227 return STATUS_INSUFFICIENT_RESOURCES
;
228 KeInitializeEvent(Event
,NotificationEvent
,FALSE
);
229 Irp
= IoBuildFilesystemControlRequest(IRP_MN_MOUNT_VOLUME
,
234 Status
= IoCallDriver(DeviceObject
,Irp
);
235 if (Status
==STATUS_PENDING
)
237 KeWaitForSingleObject(Event
,Executive
,KernelMode
,FALSE
,NULL
);
238 Status
= IoStatusBlock
.Status
;
246 IoAskFileSystemToLoad(IN PDEVICE_OBJECT DeviceObject
)
253 IoTryToMountStorageDevice(IN PDEVICE_OBJECT DeviceObject
,
254 IN BOOLEAN AllowRawMount
)
256 * FUNCTION: Trys to mount a storage device
258 * DeviceObject = Device to try and mount
263 PLIST_ENTRY current_entry
;
264 FILE_SYSTEM_OBJECT
* current
;
266 DEVICE_TYPE MatchingDeviceType
;
268 assert_irql(PASSIVE_LEVEL
);
270 DPRINT("IoTryToMountStorageDevice(DeviceObject %x)\n",DeviceObject
);
272 switch (DeviceObject
->DeviceType
)
274 case FILE_DEVICE_DISK
:
275 case FILE_DEVICE_VIRTUAL_DISK
: /* ?? */
276 MatchingDeviceType
= FILE_DEVICE_DISK_FILE_SYSTEM
;
279 case FILE_DEVICE_CD_ROM
:
280 MatchingDeviceType
= FILE_DEVICE_CD_ROM_FILE_SYSTEM
;
283 case FILE_DEVICE_NETWORK
:
284 MatchingDeviceType
= FILE_DEVICE_NETWORK_FILE_SYSTEM
;
287 case FILE_DEVICE_TAPE
:
288 MatchingDeviceType
= FILE_DEVICE_TAPE_FILE_SYSTEM
;
292 CPRINT("No matching file system type found for device type: %x\n",
293 DeviceObject
->DeviceType
);
294 return(STATUS_UNRECOGNIZED_VOLUME
);
297 KeAcquireSpinLock(&FileSystemListLock
,&oldlvl
);
298 current_entry
= FileSystemListHead
.Flink
;
299 while (current_entry
!=(&FileSystemListHead
))
301 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
302 if (current
->DeviceObject
->DeviceType
!= MatchingDeviceType
)
304 current_entry
= current_entry
->Flink
;
307 KeReleaseSpinLock(&FileSystemListLock
,oldlvl
);
308 Status
= IoAskFileSystemToMountDevice(current
->DeviceObject
,
310 KeAcquireSpinLock(&FileSystemListLock
,&oldlvl
);
313 case STATUS_FS_DRIVER_REQUIRED
:
314 KeReleaseSpinLock(&FileSystemListLock
,oldlvl
);
315 (void)IoAskFileSystemToLoad(DeviceObject
);
316 KeAcquireSpinLock(&FileSystemListLock
,&oldlvl
);
317 current_entry
= FileSystemListHead
.Flink
;
321 DeviceObject
->Vpb
->Flags
= DeviceObject
->Vpb
->Flags
|
323 KeReleaseSpinLock(&FileSystemListLock
,oldlvl
);
324 return(STATUS_SUCCESS
);
326 case STATUS_UNRECOGNIZED_VOLUME
:
328 current_entry
= current_entry
->Flink
;
331 KeReleaseSpinLock(&FileSystemListLock
,oldlvl
);
333 return(STATUS_UNRECOGNIZED_VOLUME
);
337 /**********************************************************************
342 * Veriyfy the file system type and volume information or mount
347 * Device to verify or mount
356 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject
,
357 IN BOOLEAN AllowRawMount
)
359 IO_STATUS_BLOCK IoStatusBlock
;
364 DPRINT1("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
368 Status
= STATUS_SUCCESS
;
370 KeWaitForSingleObject(&DeviceObject
->DeviceLock
,
376 if (DeviceObject
->Vpb
->Flags
& VPB_MOUNTED
)
378 /* Issue verify request to the FSD */
379 Event
= ExAllocatePool(NonPagedPool
,
382 return(STATUS_INSUFFICIENT_RESOURCES
);
384 KeInitializeEvent(Event
,
388 Irp
= IoBuildFilesystemControlRequest(IRP_MN_VERIFY_VOLUME
,
392 NULL
); //DeviceToMount);
394 Status
= IoCallDriver(DeviceObject
,
396 if (Status
==STATUS_PENDING
)
398 KeWaitForSingleObject(Event
,Executive
,KernelMode
,FALSE
,NULL
);
399 Status
= IoStatusBlock
.Status
;
403 if (NT_SUCCESS(Status
))
405 KeSetEvent(&DeviceObject
->DeviceLock
,
408 return(STATUS_SUCCESS
);
412 if (Status
== STATUS_WRONG_VOLUME
)
414 /* FIXME: Replace existing VPB by a new one */
415 DPRINT1("Wrong volume!\n");
420 /* Start mount sequence */
421 Status
= IoTryToMountStorageDevice(DeviceObject
,
424 KeSetEvent(&DeviceObject
->DeviceLock
,
432 PDEVICE_OBJECT STDCALL
433 IoGetDeviceToVerify(IN PETHREAD Thread
)
435 * FUNCTION: Returns a pointer to the device, representing a removable-media
436 * device, that is the target of the given thread's I/O request
439 return(Thread
->DeviceToVerify
);
444 IoSetDeviceToVerify(IN PETHREAD Thread
,
445 IN PDEVICE_OBJECT DeviceObject
)
447 Thread
->DeviceToVerify
= DeviceObject
;
452 IoSetHardErrorOrVerifyDevice(IN PIRP Irp
,
453 IN PDEVICE_OBJECT DeviceObject
)
455 Irp
->Tail
.Overlay
.Thread
->DeviceToVerify
= DeviceObject
;
460 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
462 PFILE_SYSTEM_OBJECT Fs
;
464 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject
);
466 Fs
= ExAllocatePoolWithTag(NonPagedPool
,
467 sizeof(FILE_SYSTEM_OBJECT
),
471 Fs
->DeviceObject
= DeviceObject
;
472 ExInterlockedInsertTailList(&FileSystemListHead
,
474 &FileSystemListLock
);
475 IopNotifyFileSystemChange(DeviceObject
,
481 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject
)
484 PLIST_ENTRY current_entry
;
485 PFILE_SYSTEM_OBJECT current
;
487 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject
);
489 KeAcquireSpinLock(&FileSystemListLock
,&oldlvl
);
490 current_entry
= FileSystemListHead
.Flink
;
491 while (current_entry
!=(&FileSystemListHead
))
493 current
= CONTAINING_RECORD(current_entry
,FILE_SYSTEM_OBJECT
,Entry
);
494 if (current
->DeviceObject
== DeviceObject
)
496 RemoveEntryList(current_entry
);
498 KeReleaseSpinLock(&FileSystemListLock
,oldlvl
);
499 IopNotifyFileSystemChange(DeviceObject
, FALSE
);
502 current_entry
= current_entry
->Flink
;
504 KeReleaseSpinLock(&FileSystemListLock
,oldlvl
);
508 /**********************************************************************
510 * IoGetBaseFileSystemDeviceObject@4
513 * Get the DEVICE_OBJECT associated to
522 * From Bo Branten's ntifs.h v13.
524 PDEVICE_OBJECT STDCALL
525 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject
)
527 PDEVICE_OBJECT DeviceObject
= NULL
;
531 * If the FILE_OBJECT's VPB is defined,
532 * get the device from it.
534 if (NULL
!= (Vpb
= FileObject
->Vpb
))
536 if (NULL
!= (DeviceObject
= Vpb
->DeviceObject
))
538 /* Vpb->DeviceObject DEFINED! */
543 * If that failed, try the VPB
544 * in the FILE_OBJECT's DeviceObject.
546 DeviceObject
= FileObject
->DeviceObject
;
547 if (NULL
== (Vpb
= DeviceObject
->Vpb
))
549 /* DeviceObject->Vpb UNDEFINED! */
553 * If that pointer to the VPB is again
554 * undefined, return directly the
555 * device object from the FILE_OBJECT.
558 (NULL
== Vpb
->DeviceObject
)
566 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject
,
567 BOOLEAN DriverActive
)
569 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
573 KeAcquireSpinLock(&FsChangeNotifyListLock
,&oldlvl
);
574 Entry
= FsChangeNotifyListHead
.Flink
;
575 while (Entry
!= &FsChangeNotifyListHead
)
577 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
579 (ChangeEntry
->FSDNotificationProc
)(DeviceObject
, DriverActive
);
581 Entry
= Entry
->Flink
;
583 KeReleaseSpinLock(&FsChangeNotifyListLock
,oldlvl
);
588 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
589 IN PFSDNOTIFICATIONPROC FSDNotificationProc
)
591 PFS_CHANGE_NOTIFY_ENTRY Entry
;
593 Entry
= ExAllocatePoolWithTag(NonPagedPool
,
594 sizeof(FS_CHANGE_NOTIFY_ENTRY
),
595 TAG_FS_CHANGE_NOTIFY
);
597 return(STATUS_INSUFFICIENT_RESOURCES
);
599 Entry
->DriverObject
= DriverObject
;
600 Entry
->FSDNotificationProc
= FSDNotificationProc
;
602 ExInterlockedInsertHeadList(&FsChangeNotifyListHead
,
603 &Entry
->FsChangeNotifyList
,
604 &FsChangeNotifyListLock
);
606 return(STATUS_SUCCESS
);
611 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject
,
612 IN PFSDNOTIFICATIONPROC FSDNotificationProc
)
614 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry
;
618 Entry
= FsChangeNotifyListHead
.Flink
;
619 while (Entry
!= &FsChangeNotifyListHead
)
621 ChangeEntry
= CONTAINING_RECORD(Entry
, FS_CHANGE_NOTIFY_ENTRY
, FsChangeNotifyList
);
622 if (ChangeEntry
->DriverObject
== DriverObject
&&
623 ChangeEntry
->FSDNotificationProc
== FSDNotificationProc
)
625 KeAcquireSpinLock(&FsChangeNotifyListLock
,&oldlvl
);
626 RemoveEntryList(Entry
);
627 KeReleaseSpinLock(&FsChangeNotifyListLock
,oldlvl
);
633 Entry
= Entry
->Flink
;