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 ERESOURCE 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 ExInitializeResourceLite(&FileSystemListLock);
172 InitializeListHead(&FsChangeNotifyListHead);
173 KeInitializeSpinLock(&FsChangeNotifyListLock);
174 #endif /* LIBCAPTIVE */
179 IoShutdownRegisteredFileSystems(VOID)
181 PLIST_ENTRY current_entry;
182 FILE_SYSTEM_OBJECT* current,*current_last=NULL;
185 IO_STATUS_BLOCK IoStatusBlock;
188 DPRINT("IoShutdownRegisteredFileSystems()\n");
190 KeInitializeEvent(&Event,
195 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
197 /* 'current' will get IoDeleteDevice()ed by IRP_MJ_SHUTDOWN! */
198 if ((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() acquires the lock exclusively. */
209 ExReleaseResourceLite(&FileSystemListLock);
210 IoUnregisterFileSystem(current->DeviceObject);
211 /* Reacquire 'FileSystemListLock'. */
214 current_last=current;
216 /* IoUnregisterFileSystem() acquires the lock exclusively. */
217 ExReleaseResourceLite(&FileSystemListLock);
219 /* send IRP_MJ_SHUTDOWN */
220 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
221 current->DeviceObject,
228 Status = IoCallDriver(current->DeviceObject,Irp);
229 if (Status==STATUS_PENDING)
231 KeWaitForSingleObject(&Event,
238 /* Reacquire 'FileSystemListLock'. */
242 ExReleaseResourceLite(&FileSystemListLock);
247 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
248 PDEVICE_OBJECT DeviceToMount)
250 IO_STATUS_BLOCK IoStatusBlock;
251 PIO_STACK_LOCATION StackPtr;
256 DPRINT("IopMountFileSystem(DeviceObject %x, DeviceToMount %x)\n",
257 DeviceObject,DeviceToMount);
259 assert_irql(PASSIVE_LEVEL);
261 KeInitializeEvent(&Event, NotificationEvent, FALSE);
262 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
265 return(STATUS_INSUFFICIENT_RESOURCES);
268 Irp->UserIosb = &IoStatusBlock;
269 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
270 Irp->UserEvent = &Event;
271 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
273 StackPtr = IoGetNextIrpStackLocation(Irp);
274 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
275 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
277 StackPtr->Control = 0;
278 StackPtr->DeviceObject = DeviceObject;
279 StackPtr->FileObject = NULL;
280 StackPtr->CompletionRoutine = NULL;
282 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
283 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
285 Status = IoCallDriver(DeviceObject,Irp);
286 if (Status==STATUS_PENDING)
288 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
289 Status = IoStatusBlock.Status;
297 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
299 IO_STATUS_BLOCK IoStatusBlock;
300 PIO_STACK_LOCATION StackPtr;
305 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
307 assert_irql(PASSIVE_LEVEL);
309 KeInitializeEvent(&Event, NotificationEvent, FALSE);
310 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
313 return(STATUS_INSUFFICIENT_RESOURCES);
316 Irp->UserIosb = &IoStatusBlock;
317 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
318 Irp->UserEvent = &Event;
319 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
321 StackPtr = IoGetNextIrpStackLocation(Irp);
322 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
323 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
325 StackPtr->Control = 0;
326 StackPtr->DeviceObject = DeviceObject;
327 StackPtr->FileObject = NULL;
328 StackPtr->CompletionRoutine = NULL;
330 Status = IoCallDriver(DeviceObject,Irp);
331 if (Status==STATUS_PENDING)
333 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
334 Status = IoStatusBlock.Status;
342 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
343 IN BOOLEAN AllowRawMount)
345 * FUNCTION: Mounts a logical volume
347 * DeviceObject = Device to mount
351 PLIST_ENTRY current_entry;
352 FILE_SYSTEM_OBJECT* current;
354 DEVICE_TYPE MatchingDeviceType;
355 PDEVICE_OBJECT DevObject;
357 assert_irql(PASSIVE_LEVEL);
359 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
360 DeviceObject, AllowRawMount);
362 switch (DeviceObject->DeviceType)
364 case FILE_DEVICE_DISK:
365 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
366 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
369 case FILE_DEVICE_CD_ROM:
370 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
373 case FILE_DEVICE_NETWORK:
374 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
377 case FILE_DEVICE_TAPE:
378 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
382 CPRINT("No matching file system type found for device type: %x\n",
383 DeviceObject->DeviceType);
384 return(STATUS_UNRECOGNIZED_VOLUME);
387 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
388 current_entry = FileSystemListHead.Flink;
389 while (current_entry!=(&FileSystemListHead))
391 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
392 if (current->DeviceObject->DeviceType != MatchingDeviceType)
394 current_entry = current_entry->Flink;
397 Status = IopMountFileSystem(current->DeviceObject,
401 case STATUS_FS_DRIVER_REQUIRED:
402 DevObject = current->DeviceObject;
403 ExReleaseResourceLite(&FileSystemListLock);
404 Status = IopLoadFileSystem(DevObject);
405 if (!NT_SUCCESS(Status))
409 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
410 current_entry = FileSystemListHead.Flink;
414 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
416 ExReleaseResourceLite(&FileSystemListLock);
417 return(STATUS_SUCCESS);
419 case STATUS_UNRECOGNIZED_VOLUME:
421 current_entry = current_entry->Flink;
424 ExReleaseResourceLite(&FileSystemListLock);
426 return(STATUS_UNRECOGNIZED_VOLUME);
431 /**********************************************************************
436 * Verify the file system type and volume information or mount
441 * Device to verify or mount
450 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
451 IN BOOLEAN AllowRawMount)
453 IO_STATUS_BLOCK IoStatusBlock;
454 PIO_STACK_LOCATION StackPtr;
459 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
460 DeviceObject, AllowRawMount);
462 Status = STATUS_SUCCESS;
464 KeWaitForSingleObject(&DeviceObject->DeviceLock,
470 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
472 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
474 /* Issue verify request to the FSD */
476 KeInitializeEvent(&Event,
480 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
483 return(STATUS_INSUFFICIENT_RESOURCES);
486 Irp->UserIosb = &IoStatusBlock;
487 Irp->UserEvent = &Event;
488 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
490 StackPtr = IoGetNextIrpStackLocation(Irp);
491 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
492 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
494 StackPtr->Control = 0;
495 StackPtr->DeviceObject = DeviceObject;
496 StackPtr->FileObject = NULL;
497 StackPtr->CompletionRoutine = NULL;
499 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
500 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
502 Status = IoCallDriver(DeviceObject,
504 if (Status==STATUS_PENDING)
506 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
507 Status = IoStatusBlock.Status;
510 if (NT_SUCCESS(Status))
512 KeSetEvent(&DeviceObject->DeviceLock,
515 return(STATUS_SUCCESS);
519 if (Status == STATUS_WRONG_VOLUME)
521 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
522 DPRINT("Wrong volume!\n");
524 DeviceObject->Vpb->DeviceObject = NULL;
525 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
528 /* Start mount sequence */
529 Status = IoMountVolume(DeviceObject,
532 KeSetEvent(&DeviceObject->DeviceLock,
540 PDEVICE_OBJECT STDCALL
541 IoGetDeviceToVerify(IN PETHREAD Thread)
543 * FUNCTION: Returns a pointer to the device, representing a removable-media
544 * device, that is the target of the given thread's I/O request
547 return(Thread->DeviceToVerify);
552 IoSetDeviceToVerify(IN PETHREAD Thread,
553 IN PDEVICE_OBJECT DeviceObject)
555 Thread->DeviceToVerify = DeviceObject;
558 #endif /* LIBCAPTIVE */
561 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
562 IN PDEVICE_OBJECT DeviceObject)
564 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
569 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
571 PFILE_SYSTEM_OBJECT Fs;
573 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
575 Fs = ExAllocatePoolWithTag(NonPagedPool,
576 sizeof(FILE_SYSTEM_OBJECT),
580 Fs->DeviceObject = DeviceObject;
581 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
583 InsertTailList(&FileSystemListHead,
586 ExReleaseResourceLite(&FileSystemListLock);
589 IopNotifyFileSystemChange(DeviceObject,
591 #endif /* LIBCAPTIVE */
596 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
598 PLIST_ENTRY current_entry;
599 PFILE_SYSTEM_OBJECT current;
601 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
603 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
604 current_entry = FileSystemListHead.Flink;
605 while (current_entry!=(&FileSystemListHead))
607 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
608 if (current->DeviceObject == DeviceObject)
610 RemoveEntryList(current_entry);
612 ExReleaseResourceLite(&FileSystemListLock);
614 IopNotifyFileSystemChange(DeviceObject, FALSE);
615 #endif /* LIBCAPTIVE */
618 current_entry = current_entry->Flink;
620 ExReleaseResourceLite(&FileSystemListLock);
626 /**********************************************************************
628 * IoGetBaseFileSystemDeviceObject@4
631 * Get the DEVICE_OBJECT associated to
640 * From Bo Branten's ntifs.h v13.
642 PDEVICE_OBJECT STDCALL
643 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
645 PDEVICE_OBJECT DeviceObject = NULL;
649 * If the FILE_OBJECT's VPB is defined,
650 * get the device from it.
652 if (NULL != (Vpb = FileObject->Vpb))
654 if (NULL != (DeviceObject = Vpb->DeviceObject))
656 /* Vpb->DeviceObject DEFINED! */
661 * If that failed, try the VPB
662 * in the FILE_OBJECT's DeviceObject.
664 DeviceObject = FileObject->DeviceObject;
665 if (NULL == (Vpb = DeviceObject->Vpb))
667 /* DeviceObject->Vpb UNDEFINED! */
671 * If that pointer to the VPB is again
672 * undefined, return directly the
673 * device object from the FILE_OBJECT.
676 (NULL == Vpb->DeviceObject)
684 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
685 BOOLEAN DriverActive)
687 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
691 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
692 Entry = FsChangeNotifyListHead.Flink;
693 while (Entry != &FsChangeNotifyListHead)
695 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
697 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
699 Entry = Entry->Flink;
701 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
706 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
707 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
709 PFS_CHANGE_NOTIFY_ENTRY Entry;
711 Entry = ExAllocatePoolWithTag(NonPagedPool,
712 sizeof(FS_CHANGE_NOTIFY_ENTRY),
713 TAG_FS_CHANGE_NOTIFY);
715 return(STATUS_INSUFFICIENT_RESOURCES);
717 Entry->DriverObject = DriverObject;
718 Entry->FSDNotificationProc = FSDNotificationProc;
720 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
721 &Entry->FsChangeNotifyList,
722 &FsChangeNotifyListLock);
724 return(STATUS_SUCCESS);
729 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
730 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
732 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
736 Entry = FsChangeNotifyListHead.Flink;
737 while (Entry != &FsChangeNotifyListHead)
739 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
740 if (ChangeEntry->DriverObject == DriverObject &&
741 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
743 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
744 RemoveEntryList(Entry);
745 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
751 Entry = Entry->Flink;
755 #endif /* LIBCAPTIVE */