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;
44 static KSPIN_LOCK FsChangeNotifyListLock;
45 static LIST_ENTRY FsChangeNotifyListHead;
46 #endif /* LIBCAPTIVE */
48 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
50 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
54 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
55 BOOLEAN DriverActive);
56 #endif /* LIBCAPTIVE */
59 /* FUNCTIONS *****************************************************************/
68 IN HANDLE DeviceHandle,
69 IN HANDLE EventHandle OPTIONAL,
70 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
71 IN PVOID ApcContext OPTIONAL,
72 OUT PIO_STATUS_BLOCK IoStatusBlock,
73 IN ULONG IoControlCode,
75 IN ULONG InputBufferSize,
76 OUT PVOID OutputBuffer,
77 IN ULONG OutputBufferSize
81 PFILE_OBJECT FileObject;
82 PDEVICE_OBJECT DeviceObject;
84 PEXTENDED_IO_STACK_LOCATION StackPtr;
88 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
89 "ApcContext %x IoStatusBlock %x IoControlCode %x "
90 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
91 "OutputBufferSize %x)\n",
92 DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
93 IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
96 Status = ObReferenceObjectByHandle(DeviceHandle,
97 FILE_READ_DATA | FILE_WRITE_DATA,
100 (PVOID *) &FileObject,
103 if (!NT_SUCCESS(Status))
108 if (EventHandle != NULL)
110 Status = ObReferenceObjectByHandle (EventHandle,
116 if (!NT_SUCCESS(Status))
118 ObDereferenceObject(FileObject);
124 KeResetEvent (&FileObject->Event);
125 ptrEvent = &FileObject->Event;
129 DeviceObject = FileObject->DeviceObject;
131 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
141 //trigger FileObject/Event dereferencing
142 Irp->Tail.Overlay.OriginalFileObject = FileObject;
144 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
145 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
147 StackPtr = (PEXTENDED_IO_STACK_LOCATION) IoGetNextIrpStackLocation(Irp);
148 StackPtr->FileObject = FileObject;
149 StackPtr->DeviceObject = DeviceObject;
150 StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
151 StackPtr->Parameters.FileSystemControl.OutputBufferLength =
153 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
155 Status = IoCallDriver(DeviceObject,Irp);
156 if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
158 KeWaitForSingleObject(ptrEvent,Executive,KernelMode,FALSE,NULL);
159 Status = IoSB.Status;
163 *IoStatusBlock = IoSB;
168 #endif /* LIBCAPTIVE */
171 IoInitFileSystemImplementation(VOID)
173 InitializeListHead(&FileSystemListHead);
174 ExInitializeResourceLite(&FileSystemListLock);
177 InitializeListHead(&FsChangeNotifyListHead);
178 KeInitializeSpinLock(&FsChangeNotifyListLock);
179 #endif /* LIBCAPTIVE */
184 IoShutdownRegisteredFileSystems(VOID)
186 PLIST_ENTRY current_entry;
187 FILE_SYSTEM_OBJECT* current,*current_last=NULL;
190 IO_STATUS_BLOCK IoStatusBlock;
193 DPRINT("IoShutdownRegisteredFileSystems()\n");
195 KeInitializeEvent(&Event,
200 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
202 /* 'current' will get IoDeleteDevice()ed by IRP_MJ_SHUTDOWN! */
203 if ((current_entry = FileSystemListHead.Flink)!=(&FileSystemListHead))
205 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
206 if (current==current_last)
208 /* At least ntfs.sys-NT5.1sp1 appears to not to unregister itself.
209 * It does not import symbol IoUnregisterFileSystem() at all!
210 * BTW also ext2fsd.sys<=v0.10A also forgets to call IoUnregisterFileSystem().
212 DPRINT("IoShutdownRegisteredFileSystems(): WARNING: filesystem forgot to call IoUnregisterFileSystem() !!!\n");
213 /* IoUnregisterFileSystem() acquires the lock exclusively. */
214 ExReleaseResourceLite(&FileSystemListLock);
215 IoUnregisterFileSystem(current->DeviceObject);
216 /* Reacquire 'FileSystemListLock'. */
219 current_last=current;
221 /* IoUnregisterFileSystem() acquires the lock exclusively. */
222 ExReleaseResourceLite(&FileSystemListLock);
224 /* send IRP_MJ_SHUTDOWN */
225 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
226 current->DeviceObject,
233 Status = IoCallDriver(current->DeviceObject,Irp);
234 if (Status==STATUS_PENDING)
236 KeWaitForSingleObject(&Event,
243 /* Reacquire 'FileSystemListLock'. */
247 ExReleaseResourceLite(&FileSystemListLock);
252 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
253 PDEVICE_OBJECT DeviceToMount)
255 IO_STATUS_BLOCK IoStatusBlock;
256 PIO_STACK_LOCATION StackPtr;
261 DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
262 DeviceObject,DeviceToMount);
264 assert_irql(PASSIVE_LEVEL);
266 KeInitializeEvent(&Event, NotificationEvent, FALSE);
267 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
270 return(STATUS_INSUFFICIENT_RESOURCES);
273 Irp->UserIosb = &IoStatusBlock;
274 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
275 Irp->UserEvent = &Event;
276 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
278 StackPtr = IoGetNextIrpStackLocation(Irp);
279 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
280 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
282 StackPtr->Control = 0;
283 StackPtr->DeviceObject = DeviceObject;
284 StackPtr->FileObject = NULL;
285 StackPtr->CompletionRoutine = NULL;
287 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
288 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
290 Status = IoCallDriver(DeviceObject,Irp);
291 if (Status==STATUS_PENDING)
293 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
294 Status = IoStatusBlock.Status;
302 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
304 IO_STATUS_BLOCK IoStatusBlock;
305 PIO_STACK_LOCATION StackPtr;
310 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
312 assert_irql(PASSIVE_LEVEL);
314 KeInitializeEvent(&Event, NotificationEvent, FALSE);
315 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
318 return(STATUS_INSUFFICIENT_RESOURCES);
321 Irp->UserIosb = &IoStatusBlock;
322 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
323 Irp->UserEvent = &Event;
324 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
326 StackPtr = IoGetNextIrpStackLocation(Irp);
327 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
328 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
330 StackPtr->Control = 0;
331 StackPtr->DeviceObject = DeviceObject;
332 StackPtr->FileObject = NULL;
333 StackPtr->CompletionRoutine = NULL;
335 Status = IoCallDriver(DeviceObject,Irp);
336 if (Status==STATUS_PENDING)
338 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
339 Status = IoStatusBlock.Status;
347 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
348 IN BOOLEAN AllowRawMount)
350 * FUNCTION: Mounts a logical volume
352 * DeviceObject = Device to mount
356 PLIST_ENTRY current_entry;
357 FILE_SYSTEM_OBJECT* current;
359 DEVICE_TYPE MatchingDeviceType;
360 PDEVICE_OBJECT DevObject;
362 assert_irql(PASSIVE_LEVEL);
364 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
365 DeviceObject, AllowRawMount);
367 switch (DeviceObject->DeviceType)
369 case FILE_DEVICE_DISK:
370 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
371 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
374 case FILE_DEVICE_CD_ROM:
375 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
378 case FILE_DEVICE_NETWORK:
379 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
382 case FILE_DEVICE_TAPE:
383 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
387 CPRINT("No matching file system type found for device type: %x\n",
388 DeviceObject->DeviceType);
389 return(STATUS_UNRECOGNIZED_VOLUME);
392 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
393 current_entry = FileSystemListHead.Flink;
394 while (current_entry!=(&FileSystemListHead))
396 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
397 if (current->DeviceObject->DeviceType != MatchingDeviceType)
399 current_entry = current_entry->Flink;
402 /* If we are not allowed to mount this volume as a raw filesystem volume
403 then don't try this */
405 if (!AllowRawMount && RawFsIsRawFileSystemDeviceObject(current->DeviceObject))
407 Status = STATUS_UNRECOGNIZED_VOLUME;
410 #endif /* LIBCAPTIVE */
412 Status = IopMountFileSystem(current->DeviceObject,
417 case STATUS_FS_DRIVER_REQUIRED:
418 DevObject = current->DeviceObject;
419 ExReleaseResourceLite(&FileSystemListLock);
420 Status = IopLoadFileSystem(DevObject);
421 if (!NT_SUCCESS(Status))
425 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
426 current_entry = FileSystemListHead.Flink;
430 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
432 ExReleaseResourceLite(&FileSystemListLock);
433 return(STATUS_SUCCESS);
435 case STATUS_UNRECOGNIZED_VOLUME:
437 current_entry = current_entry->Flink;
440 ExReleaseResourceLite(&FileSystemListLock);
442 return(STATUS_UNRECOGNIZED_VOLUME);
447 /**********************************************************************
452 * Verify the file system type and volume information or mount
457 * Device to verify or mount
468 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
469 IN BOOLEAN AllowRawMount)
471 IO_STATUS_BLOCK IoStatusBlock;
472 PIO_STACK_LOCATION StackPtr;
476 PDEVICE_OBJECT DevObject;
478 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
479 DeviceObject, AllowRawMount);
481 Status = STATUS_SUCCESS;
483 KeWaitForSingleObject(&DeviceObject->DeviceLock,
489 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
491 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
493 /* Issue verify request to the FSD */
494 DevObject = DeviceObject->Vpb->DeviceObject;
496 KeInitializeEvent(&Event,
500 Irp = IoAllocateIrp(DevObject->StackSize, TRUE);
503 return(STATUS_INSUFFICIENT_RESOURCES);
506 Irp->UserIosb = &IoStatusBlock;
507 Irp->UserEvent = &Event;
508 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
510 StackPtr = IoGetNextIrpStackLocation(Irp);
511 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
512 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
514 StackPtr->Control = 0;
515 StackPtr->DeviceObject = DevObject;
516 StackPtr->FileObject = NULL;
517 StackPtr->CompletionRoutine = NULL;
519 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
520 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
522 Status = IoCallDriver(DevObject,
524 if (Status==STATUS_PENDING)
526 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
527 Status = IoStatusBlock.Status;
530 if (NT_SUCCESS(Status))
532 KeSetEvent(&DeviceObject->DeviceLock,
535 return(STATUS_SUCCESS);
539 if (Status == STATUS_WRONG_VOLUME)
541 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
542 DPRINT("Wrong volume!\n");
544 DeviceObject->Vpb->DeviceObject = NULL;
545 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
548 /* Start mount sequence */
549 Status = IoMountVolume(DeviceObject,
552 KeSetEvent(&DeviceObject->DeviceLock,
563 PDEVICE_OBJECT STDCALL
564 IoGetDeviceToVerify(IN PETHREAD Thread)
566 * FUNCTION: Returns a pointer to the device, representing a removable-media
567 * device, that is the target of the given thread's I/O request
570 return(Thread->DeviceToVerify);
578 IoSetDeviceToVerify(IN PETHREAD Thread,
579 IN PDEVICE_OBJECT DeviceObject)
581 Thread->DeviceToVerify = DeviceObject;
584 #endif /* LIBCAPTIVE */
590 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
591 IN PDEVICE_OBJECT DeviceObject)
593 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
601 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
603 PFILE_SYSTEM_OBJECT Fs;
605 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
607 Fs = ExAllocatePoolWithTag(NonPagedPool,
608 sizeof(FILE_SYSTEM_OBJECT),
612 Fs->DeviceObject = DeviceObject;
613 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
615 /* The RAW filesystem device objects must be last in the list so the
616 raw filesystem driver is the last filesystem driver asked to mount
617 a volume. It is always the first filesystem driver registered so
618 we use InsertHeadList() here as opposed to the other alternative
620 InsertHeadList(&FileSystemListHead,
623 ExReleaseResourceLite(&FileSystemListLock);
626 IopNotifyFileSystemChange(DeviceObject,
628 #endif /* LIBCAPTIVE */
636 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
638 PLIST_ENTRY current_entry;
639 PFILE_SYSTEM_OBJECT current;
641 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
643 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
644 current_entry = FileSystemListHead.Flink;
645 while (current_entry!=(&FileSystemListHead))
647 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
648 if (current->DeviceObject == DeviceObject)
650 RemoveEntryList(current_entry);
652 ExReleaseResourceLite(&FileSystemListLock);
654 IopNotifyFileSystemChange(DeviceObject, FALSE);
655 #endif /* LIBCAPTIVE */
658 current_entry = current_entry->Flink;
660 ExReleaseResourceLite(&FileSystemListLock);
666 /**********************************************************************
668 * IoGetBaseFileSystemDeviceObject@4
671 * Get the DEVICE_OBJECT associated to
680 * From Bo Branten's ntifs.h v13.
684 PDEVICE_OBJECT STDCALL
685 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
687 PDEVICE_OBJECT DeviceObject = NULL;
691 * If the FILE_OBJECT's VPB is defined,
692 * get the device from it.
694 if (NULL != (Vpb = FileObject->Vpb))
696 if (NULL != (DeviceObject = Vpb->DeviceObject))
698 /* Vpb->DeviceObject DEFINED! */
703 * If that failed, try the VPB
704 * in the FILE_OBJECT's DeviceObject.
706 DeviceObject = FileObject->DeviceObject;
707 if (NULL == (Vpb = DeviceObject->Vpb))
709 /* DeviceObject->Vpb UNDEFINED! */
713 * If that pointer to the VPB is again
714 * undefined, return directly the
715 * device object from the FILE_OBJECT.
718 (NULL == Vpb->DeviceObject)
726 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
727 BOOLEAN DriverActive)
729 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
733 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
734 Entry = FsChangeNotifyListHead.Flink;
735 while (Entry != &FsChangeNotifyListHead)
737 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
739 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
741 Entry = Entry->Flink;
743 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
751 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
752 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
754 PFS_CHANGE_NOTIFY_ENTRY Entry;
756 Entry = ExAllocatePoolWithTag(NonPagedPool,
757 sizeof(FS_CHANGE_NOTIFY_ENTRY),
758 TAG_FS_CHANGE_NOTIFY);
760 return(STATUS_INSUFFICIENT_RESOURCES);
762 Entry->DriverObject = DriverObject;
763 Entry->FSDNotificationProc = FSDNotificationProc;
765 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
766 &Entry->FsChangeNotifyList,
767 &FsChangeNotifyListLock);
769 return(STATUS_SUCCESS);
777 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
778 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
780 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
784 Entry = FsChangeNotifyListHead.Flink;
785 while (Entry != &FsChangeNotifyListHead)
787 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
788 if (ChangeEntry->DriverObject == DriverObject &&
789 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
791 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
792 RemoveEntryList(Entry);
793 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
799 Entry = Entry->Flink;
803 #endif /* LIBCAPTIVE */