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);
223 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
224 PDEVICE_OBJECT DeviceToMount)
226 IO_STATUS_BLOCK IoStatusBlock;
227 PIO_STACK_LOCATION StackPtr;
232 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
233 DeviceObject,DeviceToMount);
235 assert_irql(PASSIVE_LEVEL);
236 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
239 return(STATUS_INSUFFICIENT_RESOURCES);
241 KeInitializeEvent(Event, NotificationEvent, FALSE);
243 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
247 return(STATUS_INSUFFICIENT_RESOURCES);
250 Irp->UserIosb = &IoStatusBlock;
251 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
252 Irp->UserEvent = Event;
253 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
255 StackPtr = IoGetNextIrpStackLocation(Irp);
256 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
257 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
259 StackPtr->Control = 0;
260 StackPtr->DeviceObject = DeviceObject;
261 StackPtr->FileObject = NULL;
262 StackPtr->CompletionRoutine = NULL;
264 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
265 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
267 Status = IoCallDriver(DeviceObject,Irp);
268 if (Status==STATUS_PENDING)
270 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
271 Status = IoStatusBlock.Status;
281 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
283 IO_STATUS_BLOCK IoStatusBlock;
284 PIO_STACK_LOCATION StackPtr;
289 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
291 assert_irql(PASSIVE_LEVEL);
292 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
295 return(STATUS_INSUFFICIENT_RESOURCES);
297 KeInitializeEvent(Event, NotificationEvent, FALSE);
299 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
303 return(STATUS_INSUFFICIENT_RESOURCES);
306 Irp->UserIosb = &IoStatusBlock;
307 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
308 Irp->UserEvent = Event;
309 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
311 StackPtr = IoGetNextIrpStackLocation(Irp);
312 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
313 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
315 StackPtr->Control = 0;
316 StackPtr->DeviceObject = DeviceObject;
317 StackPtr->FileObject = NULL;
318 StackPtr->CompletionRoutine = NULL;
320 Status = IoCallDriver(DeviceObject,Irp);
321 if (Status==STATUS_PENDING)
323 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
324 Status = IoStatusBlock.Status;
334 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
335 IN BOOLEAN AllowRawMount)
337 * FUNCTION: Mounts a logical volume
339 * DeviceObject = Device to mount
344 PLIST_ENTRY current_entry;
345 FILE_SYSTEM_OBJECT* current;
347 DEVICE_TYPE MatchingDeviceType;
349 assert_irql(PASSIVE_LEVEL);
351 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
352 DeviceObject, AllowRawMount);
354 switch (DeviceObject->DeviceType)
356 case FILE_DEVICE_DISK:
357 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
358 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
361 case FILE_DEVICE_CD_ROM:
362 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
365 case FILE_DEVICE_NETWORK:
366 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
369 case FILE_DEVICE_TAPE:
370 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
374 CPRINT("No matching file system type found for device type: %x\n",
375 DeviceObject->DeviceType);
376 return(STATUS_UNRECOGNIZED_VOLUME);
379 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
380 current_entry = FileSystemListHead.Flink;
381 while (current_entry!=(&FileSystemListHead))
383 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
384 if (current->DeviceObject->DeviceType != MatchingDeviceType)
386 current_entry = current_entry->Flink;
389 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
390 Status = IopMountFileSystem(current->DeviceObject,
392 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
395 case STATUS_FS_DRIVER_REQUIRED:
396 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
397 Status = IopLoadFileSystem(current->DeviceObject);
398 if (!NT_SUCCESS(Status))
402 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
403 current_entry = FileSystemListHead.Flink;
407 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
409 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
410 return(STATUS_SUCCESS);
412 case STATUS_UNRECOGNIZED_VOLUME:
414 current_entry = current_entry->Flink;
417 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
419 return(STATUS_UNRECOGNIZED_VOLUME);
423 /**********************************************************************
428 * Verify the file system type and volume information or mount
433 * Device to verify or mount
442 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
443 IN BOOLEAN AllowRawMount)
445 IO_STATUS_BLOCK IoStatusBlock;
446 PIO_STACK_LOCATION StackPtr;
451 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
452 DeviceObject, AllowRawMount);
454 Status = STATUS_SUCCESS;
456 KeWaitForSingleObject(&DeviceObject->DeviceLock,
462 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
464 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
466 /* Issue verify request to the FSD */
467 Event = ExAllocatePool(NonPagedPool,
470 return(STATUS_INSUFFICIENT_RESOURCES);
472 KeInitializeEvent(Event,
476 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
480 return(STATUS_INSUFFICIENT_RESOURCES);
483 Irp->UserIosb = &IoStatusBlock;
484 Irp->UserEvent = Event;
485 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
487 StackPtr = IoGetNextIrpStackLocation(Irp);
488 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
489 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
491 StackPtr->Control = 0;
492 StackPtr->DeviceObject = DeviceObject;
493 StackPtr->FileObject = NULL;
494 StackPtr->CompletionRoutine = NULL;
496 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
497 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
499 Status = IoCallDriver(DeviceObject,
501 if (Status==STATUS_PENDING)
503 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
504 Status = IoStatusBlock.Status;
508 if (NT_SUCCESS(Status))
510 KeSetEvent(&DeviceObject->DeviceLock,
513 return(STATUS_SUCCESS);
517 if (Status == STATUS_WRONG_VOLUME)
519 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
520 DPRINT("Wrong volume!\n");
522 DeviceObject->Vpb->DeviceObject = NULL;
523 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
526 /* Start mount sequence */
527 Status = IoMountVolume(DeviceObject,
530 KeSetEvent(&DeviceObject->DeviceLock,
538 PDEVICE_OBJECT STDCALL
539 IoGetDeviceToVerify(IN PETHREAD Thread)
541 * FUNCTION: Returns a pointer to the device, representing a removable-media
542 * device, that is the target of the given thread's I/O request
545 return(Thread->DeviceToVerify);
550 IoSetDeviceToVerify(IN PETHREAD Thread,
551 IN PDEVICE_OBJECT DeviceObject)
553 Thread->DeviceToVerify = DeviceObject;
558 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
559 IN PDEVICE_OBJECT DeviceObject)
561 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
564 #endif /* LIBCAPTIVE */
567 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
569 PFILE_SYSTEM_OBJECT Fs;
571 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
573 Fs = ExAllocatePoolWithTag(NonPagedPool,
574 sizeof(FILE_SYSTEM_OBJECT),
578 Fs->DeviceObject = DeviceObject;
579 ExInterlockedInsertTailList(&FileSystemListHead,
581 &FileSystemListLock);
583 IopNotifyFileSystemChange(DeviceObject,
585 #endif /* LIBCAPTIVE */
591 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
594 PLIST_ENTRY current_entry;
595 PFILE_SYSTEM_OBJECT current;
597 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
599 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
600 current_entry = FileSystemListHead.Flink;
601 while (current_entry!=(&FileSystemListHead))
603 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
604 if (current->DeviceObject == DeviceObject)
606 RemoveEntryList(current_entry);
608 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
609 IopNotifyFileSystemChange(DeviceObject, FALSE);
612 current_entry = current_entry->Flink;
614 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
618 /**********************************************************************
620 * IoGetBaseFileSystemDeviceObject@4
623 * Get the DEVICE_OBJECT associated to
632 * From Bo Branten's ntifs.h v13.
634 PDEVICE_OBJECT STDCALL
635 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
637 PDEVICE_OBJECT DeviceObject = NULL;
641 * If the FILE_OBJECT's VPB is defined,
642 * get the device from it.
644 if (NULL != (Vpb = FileObject->Vpb))
646 if (NULL != (DeviceObject = Vpb->DeviceObject))
648 /* Vpb->DeviceObject DEFINED! */
653 * If that failed, try the VPB
654 * in the FILE_OBJECT's DeviceObject.
656 DeviceObject = FileObject->DeviceObject;
657 if (NULL == (Vpb = DeviceObject->Vpb))
659 /* DeviceObject->Vpb UNDEFINED! */
663 * If that pointer to the VPB is again
664 * undefined, return directly the
665 * device object from the FILE_OBJECT.
668 (NULL == Vpb->DeviceObject)
676 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
677 BOOLEAN DriverActive)
679 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
683 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
684 Entry = FsChangeNotifyListHead.Flink;
685 while (Entry != &FsChangeNotifyListHead)
687 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
689 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
691 Entry = Entry->Flink;
693 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
698 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
699 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
701 PFS_CHANGE_NOTIFY_ENTRY Entry;
703 Entry = ExAllocatePoolWithTag(NonPagedPool,
704 sizeof(FS_CHANGE_NOTIFY_ENTRY),
705 TAG_FS_CHANGE_NOTIFY);
707 return(STATUS_INSUFFICIENT_RESOURCES);
709 Entry->DriverObject = DriverObject;
710 Entry->FSDNotificationProc = FSDNotificationProc;
712 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
713 &Entry->FsChangeNotifyList,
714 &FsChangeNotifyListLock);
716 return(STATUS_SUCCESS);
721 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
722 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
724 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
728 Entry = FsChangeNotifyListHead.Flink;
729 while (Entry != &FsChangeNotifyListHead)
731 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
732 if (ChangeEntry->DriverObject == DriverObject &&
733 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
735 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
736 RemoveEntryList(Entry);
737 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
743 Entry = Entry->Flink;
747 #endif /* LIBCAPTIVE */