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 */
224 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
225 PDEVICE_OBJECT DeviceToMount)
227 IO_STATUS_BLOCK IoStatusBlock;
228 PIO_STACK_LOCATION StackPtr;
233 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
234 DeviceObject,DeviceToMount);
236 assert_irql(PASSIVE_LEVEL);
237 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
240 return(STATUS_INSUFFICIENT_RESOURCES);
242 KeInitializeEvent(Event, NotificationEvent, FALSE);
244 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
248 return(STATUS_INSUFFICIENT_RESOURCES);
251 Irp->UserIosb = &IoStatusBlock;
252 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
253 Irp->UserEvent = Event;
254 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
256 StackPtr = IoGetNextIrpStackLocation(Irp);
257 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
258 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
260 StackPtr->Control = 0;
261 StackPtr->DeviceObject = DeviceObject;
262 StackPtr->FileObject = NULL;
263 StackPtr->CompletionRoutine = NULL;
265 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
266 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
268 Status = IoCallDriver(DeviceObject,Irp);
269 if (Status==STATUS_PENDING)
271 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
272 Status = IoStatusBlock.Status;
282 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
284 IO_STATUS_BLOCK IoStatusBlock;
285 PIO_STACK_LOCATION StackPtr;
290 DPRINT("IopLoadFileSystem(DeviceObject %x)\n", DeviceObject);
292 assert_irql(PASSIVE_LEVEL);
293 Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT));
296 return(STATUS_INSUFFICIENT_RESOURCES);
298 KeInitializeEvent(Event, NotificationEvent, FALSE);
300 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
304 return(STATUS_INSUFFICIENT_RESOURCES);
307 Irp->UserIosb = &IoStatusBlock;
308 DPRINT("Irp->UserIosb %x\n", Irp->UserIosb);
309 Irp->UserEvent = Event;
310 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
312 StackPtr = IoGetNextIrpStackLocation(Irp);
313 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
314 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
316 StackPtr->Control = 0;
317 StackPtr->DeviceObject = DeviceObject;
318 StackPtr->FileObject = NULL;
319 StackPtr->CompletionRoutine = NULL;
321 Status = IoCallDriver(DeviceObject,Irp);
322 if (Status==STATUS_PENDING)
324 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
325 Status = IoStatusBlock.Status;
335 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
336 IN BOOLEAN AllowRawMount)
338 * FUNCTION: Mounts a logical volume
340 * DeviceObject = Device to mount
345 PLIST_ENTRY current_entry;
346 FILE_SYSTEM_OBJECT* current;
348 DEVICE_TYPE MatchingDeviceType;
350 assert_irql(PASSIVE_LEVEL);
352 DPRINT("IoMountVolume(DeviceObject %x AllowRawMount %x)\n",
353 DeviceObject, AllowRawMount);
355 switch (DeviceObject->DeviceType)
357 case FILE_DEVICE_DISK:
358 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
359 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
362 case FILE_DEVICE_CD_ROM:
363 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
366 case FILE_DEVICE_NETWORK:
367 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
370 case FILE_DEVICE_TAPE:
371 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
375 CPRINT("No matching file system type found for device type: %x\n",
376 DeviceObject->DeviceType);
377 return(STATUS_UNRECOGNIZED_VOLUME);
380 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
381 current_entry = FileSystemListHead.Flink;
382 while (current_entry!=(&FileSystemListHead))
384 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
385 if (current->DeviceObject->DeviceType != MatchingDeviceType)
387 current_entry = current_entry->Flink;
390 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
391 Status = IopMountFileSystem(current->DeviceObject,
393 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
396 case STATUS_FS_DRIVER_REQUIRED:
397 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
398 Status = IopLoadFileSystem(current->DeviceObject);
399 if (!NT_SUCCESS(Status))
403 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
404 current_entry = FileSystemListHead.Flink;
408 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
410 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
411 return(STATUS_SUCCESS);
413 case STATUS_UNRECOGNIZED_VOLUME:
415 current_entry = current_entry->Flink;
418 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
420 return(STATUS_UNRECOGNIZED_VOLUME);
425 /**********************************************************************
430 * Verify the file system type and volume information or mount
435 * Device to verify or mount
444 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
445 IN BOOLEAN AllowRawMount)
447 IO_STATUS_BLOCK IoStatusBlock;
448 PIO_STACK_LOCATION StackPtr;
453 DPRINT("IoVerifyVolume(DeviceObject %x AllowRawMount %x)\n",
454 DeviceObject, AllowRawMount);
456 Status = STATUS_SUCCESS;
458 KeWaitForSingleObject(&DeviceObject->DeviceLock,
464 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
466 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
468 /* Issue verify request to the FSD */
469 Event = ExAllocatePool(NonPagedPool,
472 return(STATUS_INSUFFICIENT_RESOURCES);
474 KeInitializeEvent(Event,
478 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
482 return(STATUS_INSUFFICIENT_RESOURCES);
485 Irp->UserIosb = &IoStatusBlock;
486 Irp->UserEvent = Event;
487 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
489 StackPtr = IoGetNextIrpStackLocation(Irp);
490 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
491 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
493 StackPtr->Control = 0;
494 StackPtr->DeviceObject = DeviceObject;
495 StackPtr->FileObject = NULL;
496 StackPtr->CompletionRoutine = NULL;
498 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
499 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
501 Status = IoCallDriver(DeviceObject,
503 if (Status==STATUS_PENDING)
505 KeWaitForSingleObject(Event,Executive,KernelMode,FALSE,NULL);
506 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;
560 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
561 IN PDEVICE_OBJECT DeviceObject)
563 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
566 #endif /* LIBCAPTIVE */
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 ExInterlockedInsertTailList(&FileSystemListHead,
583 &FileSystemListLock);
585 IopNotifyFileSystemChange(DeviceObject,
587 #endif /* LIBCAPTIVE */
593 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
596 PLIST_ENTRY current_entry;
597 PFILE_SYSTEM_OBJECT current;
599 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
601 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
602 current_entry = FileSystemListHead.Flink;
603 while (current_entry!=(&FileSystemListHead))
605 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
606 if (current->DeviceObject == DeviceObject)
608 RemoveEntryList(current_entry);
610 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
611 IopNotifyFileSystemChange(DeviceObject, FALSE);
614 current_entry = current_entry->Flink;
616 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
620 /**********************************************************************
622 * IoGetBaseFileSystemDeviceObject@4
625 * Get the DEVICE_OBJECT associated to
634 * From Bo Branten's ntifs.h v13.
636 PDEVICE_OBJECT STDCALL
637 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
639 PDEVICE_OBJECT DeviceObject = NULL;
643 * If the FILE_OBJECT's VPB is defined,
644 * get the device from it.
646 if (NULL != (Vpb = FileObject->Vpb))
648 if (NULL != (DeviceObject = Vpb->DeviceObject))
650 /* Vpb->DeviceObject DEFINED! */
655 * If that failed, try the VPB
656 * in the FILE_OBJECT's DeviceObject.
658 DeviceObject = FileObject->DeviceObject;
659 if (NULL == (Vpb = DeviceObject->Vpb))
661 /* DeviceObject->Vpb UNDEFINED! */
665 * If that pointer to the VPB is again
666 * undefined, return directly the
667 * device object from the FILE_OBJECT.
670 (NULL == Vpb->DeviceObject)
678 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
679 BOOLEAN DriverActive)
681 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
685 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
686 Entry = FsChangeNotifyListHead.Flink;
687 while (Entry != &FsChangeNotifyListHead)
689 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
691 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
693 Entry = Entry->Flink;
695 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
700 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
701 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
703 PFS_CHANGE_NOTIFY_ENTRY Entry;
705 Entry = ExAllocatePoolWithTag(NonPagedPool,
706 sizeof(FS_CHANGE_NOTIFY_ENTRY),
707 TAG_FS_CHANGE_NOTIFY);
709 return(STATUS_INSUFFICIENT_RESOURCES);
711 Entry->DriverObject = DriverObject;
712 Entry->FSDNotificationProc = FSDNotificationProc;
714 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
715 &Entry->FsChangeNotifyList,
716 &FsChangeNotifyListLock);
718 return(STATUS_SUCCESS);
723 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
724 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
726 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
730 Entry = FsChangeNotifyListHead.Flink;
731 while (Entry != &FsChangeNotifyListHead)
733 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
734 if (ChangeEntry->DriverObject == DriverObject &&
735 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
737 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
738 RemoveEntryList(Entry);
739 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
745 Entry = Entry->Flink;
749 #endif /* LIBCAPTIVE */