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;
44 static KSPIN_LOCK FsChangeNotifyListLock;
45 static LIST_ENTRY FsChangeNotifyListHead;
47 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
48 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
52 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
53 BOOLEAN DriverActive);
56 /* FUNCTIONS *****************************************************************/
60 IN HANDLE DeviceHandle,
61 IN HANDLE EventHandle OPTIONAL,
62 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
63 IN PVOID ApcContext OPTIONAL,
64 OUT PIO_STATUS_BLOCK IoStatusBlock,
65 IN ULONG IoControlCode,
67 IN ULONG InputBufferSize,
68 OUT PVOID OutputBuffer,
69 IN ULONG OutputBufferSize
73 PFILE_OBJECT FileObject;
74 PDEVICE_OBJECT DeviceObject;
76 PIO_STACK_LOCATION StackPtr;
80 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
81 "ApcContext %x IoStatusBlock %x IoControlCode %x "
82 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
83 "OutputBufferSize %x)\n",
84 DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
85 IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
88 Status = ObReferenceObjectByHandle(DeviceHandle,
89 FILE_READ_DATA | FILE_WRITE_DATA,
92 (PVOID *) &FileObject,
95 if (!NT_SUCCESS(Status))
100 if (EventHandle != NULL)
102 Status = ObReferenceObjectByHandle (EventHandle,
108 if (!NT_SUCCESS(Status))
110 ObDereferenceObject(FileObject);
116 KeResetEvent (&FileObject->Event);
117 ptrEvent = &FileObject->Event;
121 DeviceObject = FileObject->DeviceObject;
123 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
133 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
134 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
136 StackPtr = IoGetNextIrpStackLocation(Irp);
137 StackPtr->FileObject = FileObject;
138 StackPtr->DeviceObject = DeviceObject;
139 StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
140 StackPtr->Parameters.FileSystemControl.OutputBufferLength =
142 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
144 Status = IoCallDriver(DeviceObject,Irp);
145 if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
147 KeWaitForSingleObject(ptrEvent,Executive,KernelMode,FALSE,NULL);
148 Status = IoSB.Status;
152 *IoStatusBlock = IoSB;
159 IoInitFileSystemImplementation(VOID)
161 InitializeListHead(&FileSystemListHead);
162 ExInitializeResourceLite(&FileSystemListLock);
164 InitializeListHead(&FsChangeNotifyListHead);
165 KeInitializeSpinLock(&FsChangeNotifyListLock);
170 IoShutdownRegisteredFileSystems(VOID)
172 PLIST_ENTRY current_entry;
173 FILE_SYSTEM_OBJECT* current;
176 IO_STATUS_BLOCK IoStatusBlock;
179 DPRINT("IoShutdownRegisteredFileSystems()\n");
181 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
182 KeInitializeEvent(&Event,
186 current_entry = FileSystemListHead.Flink;
187 while (current_entry!=(&FileSystemListHead))
189 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
191 /* send IRP_MJ_SHUTDOWN */
192 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
193 current->DeviceObject,
200 Status = IoCallDriver(current->DeviceObject,Irp);
201 if (Status == STATUS_PENDING)
203 KeWaitForSingleObject(&Event,
210 current_entry = current_entry->Flink;
213 ExReleaseResourceLite(&FileSystemListLock);
218 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
219 PDEVICE_OBJECT DeviceToMount)
221 IO_STATUS_BLOCK IoStatusBlock;
222 PIO_STACK_LOCATION StackPtr;
227 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
228 DeviceObject,DeviceToMount);
230 assert_irql(PASSIVE_LEVEL);
232 KeInitializeEvent(&Event, NotificationEvent, FALSE);
233 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
236 return(STATUS_INSUFFICIENT_RESOURCES);
239 Irp->UserIosb = &IoStatusBlock;
240 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
241 Irp->UserEvent = &Event;
242 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
244 StackPtr = IoGetNextIrpStackLocation(Irp);
245 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
246 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
248 StackPtr->Control = 0;
249 StackPtr->DeviceObject = DeviceObject;
250 StackPtr->FileObject = NULL;
251 StackPtr->CompletionRoutine = NULL;
253 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
254 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
256 Status = IoCallDriver(DeviceObject,Irp);
257 if (Status==STATUS_PENDING)
259 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
260 Status = IoStatusBlock.Status;
268 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
270 IO_STATUS_BLOCK IoStatusBlock;
271 PIO_STACK_LOCATION StackPtr;
276 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
278 assert_irql(PASSIVE_LEVEL);
280 KeInitializeEvent(&Event, NotificationEvent, FALSE);
281 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
284 return(STATUS_INSUFFICIENT_RESOURCES);
287 Irp->UserIosb = &IoStatusBlock;
288 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
289 Irp->UserEvent = &Event;
290 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
292 StackPtr = IoGetNextIrpStackLocation(Irp);
293 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
294 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
296 StackPtr->Control = 0;
297 StackPtr->DeviceObject = DeviceObject;
298 StackPtr->FileObject = NULL;
299 StackPtr->CompletionRoutine = NULL;
301 Status = IoCallDriver(DeviceObject,Irp);
302 if (Status==STATUS_PENDING)
304 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
305 Status = IoStatusBlock.Status;
313 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
314 IN BOOLEAN AllowRawMount)
316 * FUNCTION: Mounts a logical volume
318 * DeviceObject = Device to mount
322 PLIST_ENTRY current_entry;
323 FILE_SYSTEM_OBJECT* current;
325 DEVICE_TYPE MatchingDeviceType;
326 PDEVICE_OBJECT DevObject;
328 assert_irql(PASSIVE_LEVEL);
330 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
331 DeviceObject, AllowRawMount);
333 switch (DeviceObject->DeviceType)
335 case FILE_DEVICE_DISK:
336 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
337 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
340 case FILE_DEVICE_CD_ROM:
341 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
344 case FILE_DEVICE_NETWORK:
345 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
348 case FILE_DEVICE_TAPE:
349 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
353 CPRINT("No matching file system type found for device type: %x\n",
354 DeviceObject->DeviceType);
355 return(STATUS_UNRECOGNIZED_VOLUME);
358 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
359 current_entry = FileSystemListHead.Flink;
360 while (current_entry!=(&FileSystemListHead))
362 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
363 if (current->DeviceObject->DeviceType != MatchingDeviceType)
365 current_entry = current_entry->Flink;
368 Status = IopMountFileSystem(current->DeviceObject,
372 case STATUS_FS_DRIVER_REQUIRED:
373 DevObject = current->DeviceObject;
374 ExReleaseResourceLite(&FileSystemListLock);
375 Status = IopLoadFileSystem(DevObject);
376 if (!NT_SUCCESS(Status))
380 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
381 current_entry = FileSystemListHead.Flink;
385 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
387 ExReleaseResourceLite(&FileSystemListLock);
388 return(STATUS_SUCCESS);
390 case STATUS_UNRECOGNIZED_VOLUME:
392 current_entry = current_entry->Flink;
395 ExReleaseResourceLite(&FileSystemListLock);
397 return(STATUS_UNRECOGNIZED_VOLUME);
401 /**********************************************************************
406 * Verify the file system type and volume information or mount
411 * Device to verify or mount
420 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
421 IN BOOLEAN AllowRawMount)
423 IO_STATUS_BLOCK IoStatusBlock;
424 PIO_STACK_LOCATION StackPtr;
429 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
430 DeviceObject, AllowRawMount);
432 Status = STATUS_SUCCESS;
434 KeWaitForSingleObject(&DeviceObject->DeviceLock,
440 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
442 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
444 /* Issue verify request to the FSD */
446 KeInitializeEvent(&Event,
450 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
453 return(STATUS_INSUFFICIENT_RESOURCES);
456 Irp->UserIosb = &IoStatusBlock;
457 Irp->UserEvent = &Event;
458 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
460 StackPtr = IoGetNextIrpStackLocation(Irp);
461 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
462 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
464 StackPtr->Control = 0;
465 StackPtr->DeviceObject = DeviceObject;
466 StackPtr->FileObject = NULL;
467 StackPtr->CompletionRoutine = NULL;
469 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
470 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
472 Status = IoCallDriver(DeviceObject,
474 if (Status==STATUS_PENDING)
476 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
477 Status = IoStatusBlock.Status;
480 if (NT_SUCCESS(Status))
482 KeSetEvent(&DeviceObject->DeviceLock,
485 return(STATUS_SUCCESS);
489 if (Status == STATUS_WRONG_VOLUME)
491 /* Clean existing VPB. This unmounts the filesystem (in an ugly way). */
492 DPRINT("Wrong volume!\n");
494 DeviceObject->Vpb->DeviceObject = NULL;
495 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
498 /* Start mount sequence */
499 Status = IoMountVolume(DeviceObject,
502 KeSetEvent(&DeviceObject->DeviceLock,
510 PDEVICE_OBJECT STDCALL
511 IoGetDeviceToVerify(IN PETHREAD Thread)
513 * FUNCTION: Returns a pointer to the device, representing a removable-media
514 * device, that is the target of the given thread's I/O request
517 return(Thread->DeviceToVerify);
522 IoSetDeviceToVerify(IN PETHREAD Thread,
523 IN PDEVICE_OBJECT DeviceObject)
525 Thread->DeviceToVerify = DeviceObject;
530 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
531 IN PDEVICE_OBJECT DeviceObject)
533 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
538 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
540 PFILE_SYSTEM_OBJECT Fs;
542 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
544 Fs = ExAllocatePoolWithTag(NonPagedPool,
545 sizeof(FILE_SYSTEM_OBJECT),
549 Fs->DeviceObject = DeviceObject;
550 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
552 InsertTailList(&FileSystemListHead,
555 ExReleaseResourceLite(&FileSystemListLock);
557 IopNotifyFileSystemChange(DeviceObject,
563 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
565 PLIST_ENTRY current_entry;
566 PFILE_SYSTEM_OBJECT current;
568 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
570 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
571 current_entry = FileSystemListHead.Flink;
572 while (current_entry!=(&FileSystemListHead))
574 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
575 if (current->DeviceObject == DeviceObject)
577 RemoveEntryList(current_entry);
579 ExReleaseResourceLite(&FileSystemListLock);
580 IopNotifyFileSystemChange(DeviceObject, FALSE);
583 current_entry = current_entry->Flink;
585 ExReleaseResourceLite(&FileSystemListLock);
589 /**********************************************************************
591 * IoGetBaseFileSystemDeviceObject@4
594 * Get the DEVICE_OBJECT associated to
603 * From Bo Branten's ntifs.h v13.
605 PDEVICE_OBJECT STDCALL
606 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
608 PDEVICE_OBJECT DeviceObject = NULL;
612 * If the FILE_OBJECT's VPB is defined,
613 * get the device from it.
615 if (NULL != (Vpb = FileObject->Vpb))
617 if (NULL != (DeviceObject = Vpb->DeviceObject))
619 /* Vpb->DeviceObject DEFINED! */
624 * If that failed, try the VPB
625 * in the FILE_OBJECT's DeviceObject.
627 DeviceObject = FileObject->DeviceObject;
628 if (NULL == (Vpb = DeviceObject->Vpb))
630 /* DeviceObject->Vpb UNDEFINED! */
634 * If that pointer to the VPB is again
635 * undefined, return directly the
636 * device object from the FILE_OBJECT.
639 (NULL == Vpb->DeviceObject)
647 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
648 BOOLEAN DriverActive)
650 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
654 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
655 Entry = FsChangeNotifyListHead.Flink;
656 while (Entry != &FsChangeNotifyListHead)
658 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
660 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
662 Entry = Entry->Flink;
664 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
669 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
670 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
672 PFS_CHANGE_NOTIFY_ENTRY Entry;
674 Entry = ExAllocatePoolWithTag(NonPagedPool,
675 sizeof(FS_CHANGE_NOTIFY_ENTRY),
676 TAG_FS_CHANGE_NOTIFY);
678 return(STATUS_INSUFFICIENT_RESOURCES);
680 Entry->DriverObject = DriverObject;
681 Entry->FSDNotificationProc = FSDNotificationProc;
683 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
684 &Entry->FsChangeNotifyList,
685 &FsChangeNotifyListLock);
687 return(STATUS_SUCCESS);
692 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
693 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
695 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
699 Entry = FsChangeNotifyListHead.Flink;
700 while (Entry != &FsChangeNotifyListHead)
702 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
703 if (ChangeEntry->DriverObject == DriverObject &&
704 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
706 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
707 RemoveEntryList(Entry);
708 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
714 Entry = Entry->Flink;