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)
202 KeBugCheck(0); /* filesystem forgot to call IoUnregisterFileSystem() */
203 current_last=current;
205 /* send IRP_MJ_SHUTDOWN */
206 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
207 current->DeviceObject,
214 Status = IoCallDriver(current->DeviceObject,Irp);
215 if (Status==STATUS_PENDING)
217 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
222 /* filesystems cannot be called at DISPATCH_LEVEL */
223 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
224 #endif /* LIBCAPTIVE */
229 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
230 PDEVICE_OBJECT DeviceToMount)
232 IO_STATUS_BLOCK IoStatusBlock;
233 PIO_STACK_LOCATION StackPtr;
238 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
239 DeviceObject,DeviceToMount);
241 assert_irql(PASSIVE_LEVEL);
242 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
245 return(STATUS_INSUFFICIENT_RESOURCES);
247 KeInitializeEvent(Event, NotificationEvent, FALSE);
249 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
253 return(STATUS_INSUFFICIENT_RESOURCES);
256 Irp->UserIosb = &IoStatusBlock;
257 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
258 Irp->UserEvent = Event;
259 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
261 StackPtr = IoGetNextIrpStackLocation(Irp);
262 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
263 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
265 StackPtr->Control = 0;
266 StackPtr->DeviceObject = DeviceObject;
267 StackPtr->FileObject = NULL;
268 StackPtr->CompletionRoutine = NULL;
270 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
271 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
273 Status = IoCallDriver(DeviceObject,Irp);
274 if (Status==STATUS_PENDING)
276 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
277 Status = IoStatusBlock.Status;
287 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
289 IO_STATUS_BLOCK IoStatusBlock;
290 PIO_STACK_LOCATION StackPtr;
295 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
297 assert_irql(PASSIVE_LEVEL);
298 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
301 return(STATUS_INSUFFICIENT_RESOURCES);
303 KeInitializeEvent(Event, NotificationEvent, FALSE);
305 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
309 return(STATUS_INSUFFICIENT_RESOURCES);
312 Irp->UserIosb = &IoStatusBlock;
313 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
314 Irp->UserEvent = Event;
315 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
317 StackPtr = IoGetNextIrpStackLocation(Irp);
318 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
319 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
321 StackPtr->Control = 0;
322 StackPtr->DeviceObject = DeviceObject;
323 StackPtr->FileObject = NULL;
324 StackPtr->CompletionRoutine = NULL;
326 Status = IoCallDriver(DeviceObject,Irp);
327 if (Status==STATUS_PENDING)
329 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
330 Status = IoStatusBlock.Status;
340 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
341 IN BOOLEAN AllowRawMount)
343 * FUNCTION: Mounts a logical volume
345 * DeviceObject = Device to mount
350 PLIST_ENTRY current_entry;
351 FILE_SYSTEM_OBJECT* current;
353 DEVICE_TYPE MatchingDeviceType;
355 assert_irql(PASSIVE_LEVEL);
357 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
358 DeviceObject, AllowRawMount);
360 switch (DeviceObject->DeviceType)
362 case FILE_DEVICE_DISK:
363 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
364 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
367 case FILE_DEVICE_CD_ROM:
368 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
371 case FILE_DEVICE_NETWORK:
372 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
375 case FILE_DEVICE_TAPE:
376 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
380 CPRINT("No matching file system type found for device type: %x\n",
381 DeviceObject->DeviceType);
382 return(STATUS_UNRECOGNIZED_VOLUME);
385 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
386 current_entry = FileSystemListHead.Flink;
387 while (current_entry!=(&FileSystemListHead))
389 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
390 if (current->DeviceObject->DeviceType != MatchingDeviceType)
392 current_entry = current_entry->Flink;
395 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
396 Status = IopMountFileSystem(current->DeviceObject,
398 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
401 case STATUS_FS_DRIVER_REQUIRED:
402 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
403 Status = IopLoadFileSystem(current->DeviceObject);
404 if (!NT_SUCCESS(Status))
408 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
409 current_entry = FileSystemListHead.Flink;
413 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
415 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
416 return(STATUS_SUCCESS);
418 case STATUS_UNRECOGNIZED_VOLUME:
420 current_entry = current_entry->Flink;
423 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
425 return(STATUS_UNRECOGNIZED_VOLUME);
430 /**********************************************************************
435 * Verify the file system type and volume information or mount
440 * Device to verify or mount
449 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
450 IN BOOLEAN AllowRawMount)
452 IO_STATUS_BLOCK IoStatusBlock;
453 PIO_STACK_LOCATION StackPtr;
458 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
459 DeviceObject, AllowRawMount);
461 Status = STATUS_SUCCESS;
463 KeWaitForSingleObject(&DeviceObject->DeviceLock,
469 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
471 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
473 /* Issue verify request to the FSD */
474 Event = ExAllocatePool(NonPagedPool,
477 return(STATUS_INSUFFICIENT_RESOURCES);
479 KeInitializeEvent(Event,
483 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
487 return(STATUS_INSUFFICIENT_RESOURCES);
490 Irp->UserIosb = &IoStatusBlock;
491 Irp->UserEvent = Event;
492 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
494 StackPtr = IoGetNextIrpStackLocation(Irp);
495 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
496 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
498 StackPtr->Control = 0;
499 StackPtr->DeviceObject = DeviceObject;
500 StackPtr->FileObject = NULL;
501 StackPtr->CompletionRoutine = NULL;
503 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
504 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
506 Status = IoCallDriver(DeviceObject,
508 if (Status==STATUS_PENDING)
510 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
511 Status = IoStatusBlock.Status;
515 if (NT_SUCCESS(Status))
517 KeSetEvent(&DeviceObject->DeviceLock,
520 return(STATUS_SUCCESS);
524 if (Status == STATUS_WRONG_VOLUME)
526 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
527 DPRINT("Wrong volume!\n");
529 DeviceObject->Vpb->DeviceObject = NULL;
530 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
533 /* Start mount sequence */
534 Status = IoMountVolume(DeviceObject,
537 KeSetEvent(&DeviceObject->DeviceLock,
545 PDEVICE_OBJECT STDCALL
546 IoGetDeviceToVerify(IN PETHREAD Thread)
548 * FUNCTION: Returns a pointer to the device, representing a removable-media
549 * device, that is the target of the given thread's I/O request
552 return(Thread->DeviceToVerify);
557 IoSetDeviceToVerify(IN PETHREAD Thread,
558 IN PDEVICE_OBJECT DeviceObject)
560 Thread->DeviceToVerify = DeviceObject;
563 #endif /* LIBCAPTIVE */
566 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
567 IN PDEVICE_OBJECT DeviceObject)
569 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
574 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
576 PFILE_SYSTEM_OBJECT Fs;
578 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
580 Fs = ExAllocatePoolWithTag(NonPagedPool,
581 sizeof(FILE_SYSTEM_OBJECT),
585 Fs->DeviceObject = DeviceObject;
586 ExInterlockedInsertTailList(&FileSystemListHead,
588 &FileSystemListLock);
590 IopNotifyFileSystemChange(DeviceObject,
592 #endif /* LIBCAPTIVE */
597 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
600 PLIST_ENTRY current_entry;
601 PFILE_SYSTEM_OBJECT current;
603 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
605 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
606 current_entry = FileSystemListHead.Flink;
607 while (current_entry!=(&FileSystemListHead))
609 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
610 if (current->DeviceObject == DeviceObject)
612 RemoveEntryList(current_entry);
614 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
616 IopNotifyFileSystemChange(DeviceObject, FALSE);
617 #endif /* LIBCAPTIVE */
620 current_entry = current_entry->Flink;
622 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
628 /**********************************************************************
630 * IoGetBaseFileSystemDeviceObject@4
633 * Get the DEVICE_OBJECT associated to
642 * From Bo Branten's ntifs.h v13.
644 PDEVICE_OBJECT STDCALL
645 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
647 PDEVICE_OBJECT DeviceObject = NULL;
651 * If the FILE_OBJECT's VPB is defined,
652 * get the device from it.
654 if (NULL != (Vpb = FileObject->Vpb))
656 if (NULL != (DeviceObject = Vpb->DeviceObject))
658 /* Vpb->DeviceObject DEFINED! */
663 * If that failed, try the VPB
664 * in the FILE_OBJECT's DeviceObject.
666 DeviceObject = FileObject->DeviceObject;
667 if (NULL == (Vpb = DeviceObject->Vpb))
669 /* DeviceObject->Vpb UNDEFINED! */
673 * If that pointer to the VPB is again
674 * undefined, return directly the
675 * device object from the FILE_OBJECT.
678 (NULL == Vpb->DeviceObject)
686 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
687 BOOLEAN DriverActive)
689 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
693 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
694 Entry = FsChangeNotifyListHead.Flink;
695 while (Entry != &FsChangeNotifyListHead)
697 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
699 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
701 Entry = Entry->Flink;
703 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
708 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
709 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
711 PFS_CHANGE_NOTIFY_ENTRY Entry;
713 Entry = ExAllocatePoolWithTag(NonPagedPool,
714 sizeof(FS_CHANGE_NOTIFY_ENTRY),
715 TAG_FS_CHANGE_NOTIFY);
717 return(STATUS_INSUFFICIENT_RESOURCES);
719 Entry->DriverObject = DriverObject;
720 Entry->FSDNotificationProc = FSDNotificationProc;
722 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
723 &Entry->FsChangeNotifyList,
724 &FsChangeNotifyListLock);
726 return(STATUS_SUCCESS);
731 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
732 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
734 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
738 Entry = FsChangeNotifyListHead.Flink;
739 while (Entry != &FsChangeNotifyListHead)
741 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
742 if (ChangeEntry->DriverObject == DriverObject &&
743 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
745 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
746 RemoveEntryList(Entry);
747 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
753 Entry = Entry->Flink;
757 #endif /* LIBCAPTIVE */