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;
45 static KSPIN_LOCK FsChangeNotifyListLock;
46 static LIST_ENTRY FsChangeNotifyListHead;
47 #endif /* LIBCAPTIVE */
49 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
51 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
55 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
56 BOOLEAN DriverActive);
57 #endif /* LIBCAPTIVE */
60 /* FUNCTIONS *****************************************************************/
66 IN HANDLE DeviceHandle,
67 IN HANDLE EventHandle OPTIONAL,
68 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
69 IN PVOID ApcContext OPTIONAL,
70 OUT PIO_STATUS_BLOCK IoStatusBlock,
71 IN ULONG IoControlCode,
73 IN ULONG InputBufferSize,
74 OUT PVOID OutputBuffer,
75 IN ULONG OutputBufferSize
79 PFILE_OBJECT FileObject;
80 PDEVICE_OBJECT DeviceObject;
82 PIO_STACK_LOCATION StackPtr;
86 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
87 "ApcContext %x IoStatusBlock %x IoControlCode %x "
88 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
89 "OutputBufferSize %x)\n",
90 DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
91 IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
94 Status = ObReferenceObjectByHandle(DeviceHandle,
95 FILE_READ_DATA | FILE_WRITE_DATA,
98 (PVOID *) &FileObject,
101 if (!NT_SUCCESS(Status))
106 if (EventHandle != NULL)
108 Status = ObReferenceObjectByHandle (EventHandle,
114 if (!NT_SUCCESS(Status))
116 ObDereferenceObject(FileObject);
122 KeResetEvent (&FileObject->Event);
123 ptrEvent = &FileObject->Event;
127 DeviceObject = FileObject->DeviceObject;
129 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
139 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
140 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
142 StackPtr = IoGetNextIrpStackLocation(Irp);
143 StackPtr->FileObject = FileObject;
144 StackPtr->DeviceObject = DeviceObject;
145 StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
146 StackPtr->Parameters.FileSystemControl.OutputBufferLength =
148 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
150 Status = IoCallDriver(DeviceObject,Irp);
151 if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
153 KeWaitForSingleObject(ptrEvent,Executive,KernelMode,FALSE,NULL);
154 Status = IoSB.Status;
158 *IoStatusBlock = IoSB;
163 #endif /* LIBCAPTIVE */
166 IoInitFileSystemImplementation(VOID)
168 InitializeListHead(&FileSystemListHead);
169 KeInitializeSpinLock(&FileSystemListLock);
172 InitializeListHead(&FsChangeNotifyListHead);
173 KeInitializeSpinLock(&FsChangeNotifyListLock);
174 #endif /* LIBCAPTIVE */
179 IoShutdownRegisteredFileSystems(VOID)
182 PLIST_ENTRY current_entry;
183 FILE_SYSTEM_OBJECT* current,*current_last=NULL;
186 IO_STATUS_BLOCK IoStatusBlock;
189 DPRINT("IoShutdownRegisteredFileSystems()\n");
192 /* filesystems cannot be called at DISPATCH_LEVEL */
193 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
194 #endif /* LIBCAPTIVE */
195 KeInitializeEvent(&Event,NotificationEvent,FALSE);
197 /* 'current' will get IoDeleteDevice()ed by IRP_MJ_SHUTDOWN! */
198 while ((current_entry = FileSystemListHead.Flink)!=(&FileSystemListHead))
200 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
201 if (current==current_last)
203 /* At least ntfs.sys-NT5.1sp1 appears to not to unregister itself.
204 * It does not import symbol IoUnregisterFileSystem() at all!
205 * BTW also ext2fsd.sys<=v0.10A also forgets to call IoUnregisterFileSystem().
207 DPRINT("IoShutdownRegisteredFileSystems(): WARNING: filesystem forgot to call IoUnregisterFileSystem() !!!\n");
208 IoUnregisterFileSystem(current->DeviceObject);
211 current_last=current;
213 /* send IRP_MJ_SHUTDOWN */
214 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
215 current->DeviceObject,
222 Status = IoCallDriver(current->DeviceObject,Irp);
223 if (Status==STATUS_PENDING)
225 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
230 /* filesystems cannot be called at DISPATCH_LEVEL */
231 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
232 #endif /* LIBCAPTIVE */
237 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
238 PDEVICE_OBJECT DeviceToMount)
240 IO_STATUS_BLOCK IoStatusBlock;
241 PIO_STACK_LOCATION StackPtr;
246 DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
247 DeviceObject,DeviceToMount);
249 assert_irql(PASSIVE_LEVEL);
250 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
253 return(STATUS_INSUFFICIENT_RESOURCES);
255 KeInitializeEvent(Event, NotificationEvent, FALSE);
257 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
261 return(STATUS_INSUFFICIENT_RESOURCES);
264 Irp->UserIosb = &IoStatusBlock;
265 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
266 Irp->UserEvent = Event;
267 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
269 StackPtr = IoGetNextIrpStackLocation(Irp);
270 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
271 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
273 StackPtr->Control = 0;
274 StackPtr->DeviceObject = DeviceObject;
275 StackPtr->FileObject = NULL;
276 StackPtr->CompletionRoutine = NULL;
278 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
279 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
281 Status = IoCallDriver(DeviceObject,Irp);
282 if (Status==STATUS_PENDING)
284 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
285 Status = IoStatusBlock.Status;
295 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
297 IO_STATUS_BLOCK IoStatusBlock;
298 PIO_STACK_LOCATION StackPtr;
303 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
305 assert_irql(PASSIVE_LEVEL);
306 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
309 return(STATUS_INSUFFICIENT_RESOURCES);
311 KeInitializeEvent(Event, NotificationEvent, FALSE);
313 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
317 return(STATUS_INSUFFICIENT_RESOURCES);
320 Irp->UserIosb = &IoStatusBlock;
321 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
322 Irp->UserEvent = Event;
323 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
325 StackPtr = IoGetNextIrpStackLocation(Irp);
326 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
327 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
329 StackPtr->Control = 0;
330 StackPtr->DeviceObject = DeviceObject;
331 StackPtr->FileObject = NULL;
332 StackPtr->CompletionRoutine = NULL;
334 Status = IoCallDriver(DeviceObject,Irp);
335 if (Status==STATUS_PENDING)
337 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
338 Status = IoStatusBlock.Status;
348 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
349 IN BOOLEAN AllowRawMount)
351 * FUNCTION: Mounts a logical volume
353 * DeviceObject = Device to mount
358 PLIST_ENTRY current_entry;
359 FILE_SYSTEM_OBJECT* current;
361 DEVICE_TYPE MatchingDeviceType;
363 assert_irql(PASSIVE_LEVEL);
365 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
366 DeviceObject, AllowRawMount);
368 switch (DeviceObject->DeviceType)
370 case FILE_DEVICE_DISK:
371 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
372 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
375 case FILE_DEVICE_CD_ROM:
376 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
379 case FILE_DEVICE_NETWORK:
380 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
383 case FILE_DEVICE_TAPE:
384 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
388 CPRINT("No matching file system type found for device type: %x\n",
389 DeviceObject->DeviceType);
390 return(STATUS_UNRECOGNIZED_VOLUME);
393 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
394 current_entry = FileSystemListHead.Flink;
395 while (current_entry!=(&FileSystemListHead))
397 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
398 if (current->DeviceObject->DeviceType != MatchingDeviceType)
400 current_entry = current_entry->Flink;
403 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
404 Status = IopMountFileSystem(current->DeviceObject,
406 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
409 case STATUS_FS_DRIVER_REQUIRED:
410 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
411 Status = IopLoadFileSystem(current->DeviceObject);
412 if (!NT_SUCCESS(Status))
416 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
417 current_entry = FileSystemListHead.Flink;
421 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
423 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
424 return(STATUS_SUCCESS);
426 case STATUS_UNRECOGNIZED_VOLUME:
428 current_entry = current_entry->Flink;
431 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
433 return(STATUS_UNRECOGNIZED_VOLUME);
438 /**********************************************************************
443 * Verify the file system type and volume information or mount
448 * Device to verify or mount
457 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
458 IN BOOLEAN AllowRawMount)
460 IO_STATUS_BLOCK IoStatusBlock;
461 PIO_STACK_LOCATION StackPtr;
466 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
467 DeviceObject, AllowRawMount);
469 Status = STATUS_SUCCESS;
471 KeWaitForSingleObject(&DeviceObject->DeviceLock,
477 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
479 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
481 /* Issue verify request to the FSD */
482 Event = ExAllocatePool(NonPagedPool,
485 return(STATUS_INSUFFICIENT_RESOURCES);
487 KeInitializeEvent(Event,
491 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
495 return(STATUS_INSUFFICIENT_RESOURCES);
498 Irp->UserIosb = &IoStatusBlock;
499 Irp->UserEvent = Event;
500 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
502 StackPtr = IoGetNextIrpStackLocation(Irp);
503 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
504 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
506 StackPtr->Control = 0;
507 StackPtr->DeviceObject = DeviceObject;
508 StackPtr->FileObject = NULL;
509 StackPtr->CompletionRoutine = NULL;
511 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
512 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
514 Status = IoCallDriver(DeviceObject,
516 if (Status==STATUS_PENDING)
518 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
519 Status = IoStatusBlock.Status;
523 if (NT_SUCCESS(Status))
525 KeSetEvent(&DeviceObject->DeviceLock,
528 return(STATUS_SUCCESS);
532 if (Status == STATUS_WRONG_VOLUME)
534 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
535 DPRINT("Wrong volume!\n");
537 DeviceObject->Vpb->DeviceObject = NULL;
538 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
541 /* Start mount sequence */
542 Status = IoMountVolume(DeviceObject,
545 KeSetEvent(&DeviceObject->DeviceLock,
553 PDEVICE_OBJECT STDCALL
554 IoGetDeviceToVerify(IN PETHREAD Thread)
556 * FUNCTION: Returns a pointer to the device, representing a removable-media
557 * device, that is the target of the given thread's I/O request
560 return(Thread->DeviceToVerify);
565 IoSetDeviceToVerify(IN PETHREAD Thread,
566 IN PDEVICE_OBJECT DeviceObject)
568 Thread->DeviceToVerify = DeviceObject;
571 #endif /* LIBCAPTIVE */
574 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
575 IN PDEVICE_OBJECT DeviceObject)
577 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
582 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
584 PFILE_SYSTEM_OBJECT Fs;
586 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
588 Fs = ExAllocatePoolWithTag(NonPagedPool,
589 sizeof(FILE_SYSTEM_OBJECT),
593 Fs->DeviceObject = DeviceObject;
594 ExInterlockedInsertTailList(&FileSystemListHead,
596 &FileSystemListLock);
598 IopNotifyFileSystemChange(DeviceObject,
600 #endif /* LIBCAPTIVE */
605 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
608 PLIST_ENTRY current_entry;
609 PFILE_SYSTEM_OBJECT current;
611 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
613 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
614 current_entry = FileSystemListHead.Flink;
615 while (current_entry!=(&FileSystemListHead))
617 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
618 if (current->DeviceObject == DeviceObject)
620 RemoveEntryList(current_entry);
622 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
624 IopNotifyFileSystemChange(DeviceObject, FALSE);
625 #endif /* LIBCAPTIVE */
628 current_entry = current_entry->Flink;
630 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
636 /**********************************************************************
638 * IoGetBaseFileSystemDeviceObject@4
641 * Get the DEVICE_OBJECT associated to
650 * From Bo Branten's ntifs.h v13.
652 PDEVICE_OBJECT STDCALL
653 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
655 PDEVICE_OBJECT DeviceObject = NULL;
659 * If the FILE_OBJECT's VPB is defined,
660 * get the device from it.
662 if (NULL != (Vpb = FileObject->Vpb))
664 if (NULL != (DeviceObject = Vpb->DeviceObject))
666 /* Vpb->DeviceObject DEFINED! */
671 * If that failed, try the VPB
672 * in the FILE_OBJECT's DeviceObject.
674 DeviceObject = FileObject->DeviceObject;
675 if (NULL == (Vpb = DeviceObject->Vpb))
677 /* DeviceObject->Vpb UNDEFINED! */
681 * If that pointer to the VPB is again
682 * undefined, return directly the
683 * device object from the FILE_OBJECT.
686 (NULL == Vpb->DeviceObject)
694 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
695 BOOLEAN DriverActive)
697 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
701 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
702 Entry = FsChangeNotifyListHead.Flink;
703 while (Entry != &FsChangeNotifyListHead)
705 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
707 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
709 Entry = Entry->Flink;
711 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
716 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
717 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
719 PFS_CHANGE_NOTIFY_ENTRY Entry;
721 Entry = ExAllocatePoolWithTag(NonPagedPool,
722 sizeof(FS_CHANGE_NOTIFY_ENTRY),
723 TAG_FS_CHANGE_NOTIFY);
725 return(STATUS_INSUFFICIENT_RESOURCES);
727 Entry->DriverObject = DriverObject;
728 Entry->FSDNotificationProc = FSDNotificationProc;
730 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
731 &Entry->FsChangeNotifyList,
732 &FsChangeNotifyListLock);
734 return(STATUS_SUCCESS);
739 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
740 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
742 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
746 Entry = FsChangeNotifyListHead.Flink;
747 while (Entry != &FsChangeNotifyListHead)
749 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
750 if (ChangeEntry->DriverObject == DriverObject &&
751 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
753 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
754 RemoveEntryList(Entry);
755 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
761 Entry = Entry->Flink;
765 #endif /* LIBCAPTIVE */