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;