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 */
180 IoShutdownRegisteredFileSystems(VOID)
183 PLIST_ENTRY current_entry;
184 FILE_SYSTEM_OBJECT* current;
187 IO_STATUS_BLOCK IoStatusBlock;
190 DPRINT("IoShutdownRegisteredFileSystems()\n");
192 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
193 KeInitializeEvent(&Event,NotificationEvent,FALSE);
195 current_entry = FileSystemListHead.Flink;
196 while (current_entry!=(&FileSystemListHead))
198 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
200 /* send IRP_MJ_SHUTDOWN */
201 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
202 current->DeviceObject,
209 Status = IoCallDriver(current->DeviceObject,Irp);
210 if (Status==STATUS_PENDING)
212 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
215 current_entry = current_entry->Flink;
218 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
221 #endif /* LIBCAPTIVE */
225 #endif /* LIBCAPTIVE */
227 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
228 PDEVICE_OBJECT DeviceToMount)
230 IO_STATUS_BLOCK IoStatusBlock;
231 PIO_STACK_LOCATION StackPtr;
236 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
237 DeviceObject,DeviceToMount);
239 assert_irql(PASSIVE_LEVEL);
240 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
243 return(STATUS_INSUFFICIENT_RESOURCES);
245 KeInitializeEvent(Event, NotificationEvent, FALSE);
247 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
251 return(STATUS_INSUFFICIENT_RESOURCES);
254 Irp->UserIosb = &IoStatusBlock;
255 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
256 Irp->UserEvent = Event;
257 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
259 StackPtr = IoGetNextIrpStackLocation(Irp);
260 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
261 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
263 StackPtr->Control = 0;
264 StackPtr->DeviceObject = DeviceObject;
265 StackPtr->FileObject = NULL;
266 StackPtr->CompletionRoutine = NULL;
268 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
269 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
271 Status = IoCallDriver(DeviceObject,Irp);
272 if (Status==STATUS_PENDING)
274 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
275 Status = IoStatusBlock.Status;
285 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
287 IO_STATUS_BLOCK IoStatusBlock;
288 PIO_STACK_LOCATION StackPtr;
293 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
295 assert_irql(PASSIVE_LEVEL);
296 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
299 return(STATUS_INSUFFICIENT_RESOURCES);
301 KeInitializeEvent(Event, NotificationEvent, FALSE);
303 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
307 return(STATUS_INSUFFICIENT_RESOURCES);
310 Irp->UserIosb = &IoStatusBlock;
311 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
312 Irp->UserEvent = Event;
313 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
315 StackPtr = IoGetNextIrpStackLocation(Irp);
316 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
317 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
319 StackPtr->Control = 0;
320 StackPtr->DeviceObject = DeviceObject;
321 StackPtr->FileObject = NULL;
322 StackPtr->CompletionRoutine = NULL;
324 Status = IoCallDriver(DeviceObject,Irp);
325 if (Status==STATUS_PENDING)
327 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
328 Status = IoStatusBlock.Status;
338 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
339 IN BOOLEAN AllowRawMount)
341 * FUNCTION: Mounts a logical volume
343 * DeviceObject = Device to mount
348 PLIST_ENTRY current_entry;
349 FILE_SYSTEM_OBJECT* current;
351 DEVICE_TYPE MatchingDeviceType;
353 assert_irql(PASSIVE_LEVEL);
355 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
356 DeviceObject, AllowRawMount);
358 switch (DeviceObject->DeviceType)
360 case FILE_DEVICE_DISK:
361 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
362 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
365 case FILE_DEVICE_CD_ROM:
366 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
369 case FILE_DEVICE_NETWORK:
370 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
373 case FILE_DEVICE_TAPE:
374 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
378 CPRINT("No matching file system type found for device type: %x\n",
379 DeviceObject->DeviceType);
380 return(STATUS_UNRECOGNIZED_VOLUME);
383 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
384 current_entry = FileSystemListHead.Flink;
385 while (current_entry!=(&FileSystemListHead))
387 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
388 if (current->DeviceObject->DeviceType != MatchingDeviceType)
390 current_entry = current_entry->Flink;
393 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
394 Status = IopMountFileSystem(current->DeviceObject,
396 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
399 case STATUS_FS_DRIVER_REQUIRED:
400 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
401 Status = IopLoadFileSystem(current->DeviceObject);
402 if (!NT_SUCCESS(Status))
406 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
407 current_entry = FileSystemListHead.Flink;
411 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
413 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
414 return(STATUS_SUCCESS);
416 case STATUS_UNRECOGNIZED_VOLUME:
418 current_entry = current_entry->Flink;
421 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
423 return(STATUS_UNRECOGNIZED_VOLUME);
428 /**********************************************************************
433 * Verify the file system type and volume information or mount
438 * Device to verify or mount
447 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
448 IN BOOLEAN AllowRawMount)
450 IO_STATUS_BLOCK IoStatusBlock;
451 PIO_STACK_LOCATION StackPtr;
456 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
457 DeviceObject, AllowRawMount);
459 Status = STATUS_SUCCESS;
461 KeWaitForSingleObject(&DeviceObject->DeviceLock,
467 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
469 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
471 /* Issue verify request to the FSD */
472 Event = ExAllocatePool(NonPagedPool,
475 return(STATUS_INSUFFICIENT_RESOURCES);
477 KeInitializeEvent(Event,
481 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
485 return(STATUS_INSUFFICIENT_RESOURCES);
488 Irp->UserIosb = &IoStatusBlock;
489 Irp->UserEvent = Event;
490 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
492 StackPtr = IoGetNextIrpStackLocation(Irp);
493 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
494 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
496 StackPtr->Control = 0;
497 StackPtr->DeviceObject = DeviceObject;
498 StackPtr->FileObject = NULL;
499 StackPtr->CompletionRoutine = NULL;
501 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
502 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
504 Status = IoCallDriver(DeviceObject,
506 if (Status==STATUS_PENDING)
508 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
509 Status = IoStatusBlock.Status;
513 if (NT_SUCCESS(Status))
515 KeSetEvent(&DeviceObject->DeviceLock,
518 return(STATUS_SUCCESS);
522 if (Status == STATUS_WRONG_VOLUME)
524 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
525 DPRINT("Wrong volume!\n");
527 DeviceObject->Vpb->DeviceObject = NULL;
528 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
531 /* Start mount sequence */
532 Status = IoMountVolume(DeviceObject,
535 KeSetEvent(&DeviceObject->DeviceLock,
543 PDEVICE_OBJECT STDCALL
544 IoGetDeviceToVerify(IN PETHREAD Thread)
546 * FUNCTION: Returns a pointer to the device, representing a removable-media
547 * device, that is the target of the given thread's I/O request
550 return(Thread->DeviceToVerify);
555 IoSetDeviceToVerify(IN PETHREAD Thread,
556 IN PDEVICE_OBJECT DeviceObject)
558 Thread->DeviceToVerify = DeviceObject;
563 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
564 IN PDEVICE_OBJECT DeviceObject)
566 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
569 #endif /* LIBCAPTIVE */
572 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
574 PFILE_SYSTEM_OBJECT Fs;
576 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
578 Fs = ExAllocatePoolWithTag(NonPagedPool,
579 sizeof(FILE_SYSTEM_OBJECT),
583 Fs->DeviceObject = DeviceObject;
584 ExInterlockedInsertTailList(&FileSystemListHead,
586 &FileSystemListLock);
588 IopNotifyFileSystemChange(DeviceObject,
590 #endif /* LIBCAPTIVE */
596 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
599 PLIST_ENTRY current_entry;
600 PFILE_SYSTEM_OBJECT current;
602 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
604 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
605 current_entry = FileSystemListHead.Flink;
606 while (current_entry!=(&FileSystemListHead))
608 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
609 if (current->DeviceObject == DeviceObject)
611 RemoveEntryList(current_entry);
613 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
614 IopNotifyFileSystemChange(DeviceObject, FALSE);
617 current_entry = current_entry->Flink;
619 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
623 /**********************************************************************
625 * IoGetBaseFileSystemDeviceObject@4
628 * Get the DEVICE_OBJECT associated to
637 * From Bo Branten's ntifs.h v13.
639 PDEVICE_OBJECT STDCALL
640 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
642 PDEVICE_OBJECT DeviceObject = NULL;
646 * If the FILE_OBJECT's VPB is defined,
647 * get the device from it.
649 if (NULL != (Vpb = FileObject->Vpb))
651 if (NULL != (DeviceObject = Vpb->DeviceObject))
653 /* Vpb->DeviceObject DEFINED! */
658 * If that failed, try the VPB
659 * in the FILE_OBJECT's DeviceObject.
661 DeviceObject = FileObject->DeviceObject;
662 if (NULL == (Vpb = DeviceObject->Vpb))
664 /* DeviceObject->Vpb UNDEFINED! */
668 * If that pointer to the VPB is again
669 * undefined, return directly the
670 * device object from the FILE_OBJECT.
673 (NULL == Vpb->DeviceObject)
681 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
682 BOOLEAN DriverActive)
684 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
688 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
689 Entry = FsChangeNotifyListHead.Flink;
690 while (Entry != &FsChangeNotifyListHead)
692 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
694 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
696 Entry = Entry->Flink;
698 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
703 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
704 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
706 PFS_CHANGE_NOTIFY_ENTRY Entry;
708 Entry = ExAllocatePoolWithTag(NonPagedPool,
709 sizeof(FS_CHANGE_NOTIFY_ENTRY),
710 TAG_FS_CHANGE_NOTIFY);
712 return(STATUS_INSUFFICIENT_RESOURCES);
714 Entry->DriverObject = DriverObject;
715 Entry->FSDNotificationProc = FSDNotificationProc;
717 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
718 &Entry->FsChangeNotifyList,
719 &FsChangeNotifyListLock);
721 return(STATUS_SUCCESS);
726 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
727 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
729 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
733 Entry = FsChangeNotifyListHead.Flink;
734 while (Entry != &FsChangeNotifyListHead)
736 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
737 if (ChangeEntry->DriverObject == DriverObject &&
738 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
740 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
741 RemoveEntryList(Entry);
742 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
748 Entry = Entry->Flink;
752 #endif /* LIBCAPTIVE */