Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvolume.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/io/iomgr/volume.c 00005 * PURPOSE: Volume and File System I/O Support 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Hervé Poussineau (hpoussin@reactos.org) 00008 * Eric Kohl 00009 * Pierre Schweitzer (pierre.schweitzer@reactos.org) 00010 */ 00011 00012 /* INCLUDES *****************************************************************/ 00013 00014 #include <ntoskrnl.h> 00015 #define NDEBUG 00016 #include <debug.h> 00017 00018 #if defined (ALLOC_PRAGMA) 00019 #pragma alloc_text(INIT, IoInitFileSystemImplementation) 00020 #pragma alloc_text(INIT, IoInitVpbImplementation) 00021 #endif 00022 00023 /* GLOBALS ******************************************************************/ 00024 00025 ERESOURCE IopDatabaseResource; 00026 LIST_ENTRY IopDiskFileSystemQueueHead, IopNetworkFileSystemQueueHead; 00027 LIST_ENTRY IopCdRomFileSystemQueueHead, IopTapeFileSystemQueueHead; 00028 LIST_ENTRY IopFsNotifyChangeQueueHead; 00029 ULONG IopFsRegistrationOps; 00030 00031 /* PRIVATE FUNCTIONS *********************************************************/ 00032 00033 /* 00034 * @halfplemented 00035 */ 00036 VOID 00037 NTAPI 00038 IopDecrementDeviceObjectRef(IN PDEVICE_OBJECT DeviceObject, 00039 IN BOOLEAN UnloadIfUnused) 00040 { 00041 KIRQL OldIrql; 00042 00043 /* Acquire lock */ 00044 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock); 00045 ASSERT(DeviceObject->ReferenceCount > 0); 00046 00047 if (--DeviceObject->ReferenceCount > 0) 00048 { 00049 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 00050 return; 00051 } 00052 00053 /* Release lock */ 00054 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql); 00055 00056 /* Here, DO is not referenced any longer, check if we have to unload it */ 00057 if (UnloadIfUnused || IoGetDevObjExtension(DeviceObject)->ExtensionFlags & 00058 (DOE_UNLOAD_PENDING | DOE_DELETE_PENDING | DOE_REMOVE_PENDING)) 00059 { 00060 /* Unload the driver */ 00061 IopUnloadDevice(DeviceObject); 00062 } 00063 } 00064 00065 /* 00066 * @implemented 00067 */ 00068 VOID 00069 NTAPI 00070 IopDecrementDeviceObjectHandleCount(IN PDEVICE_OBJECT DeviceObject) 00071 { 00072 /* Just decrease reference count */ 00073 IopDecrementDeviceObjectRef(DeviceObject, FALSE); 00074 } 00075 00076 /* 00077 * @implemented 00078 */ 00079 PVPB 00080 NTAPI 00081 IopCheckVpbMounted(IN POPEN_PACKET OpenPacket, 00082 IN PDEVICE_OBJECT DeviceObject, 00083 IN PUNICODE_STRING RemainingName, 00084 OUT PNTSTATUS Status) 00085 { 00086 BOOLEAN Alertable, Raw; 00087 KIRQL OldIrql; 00088 PVPB Vpb = NULL; 00089 00090 /* Lock the VPBs */ 00091 IoAcquireVpbSpinLock(&OldIrql); 00092 00093 /* Set VPB mount settings */ 00094 Raw = !RemainingName->Length && !OpenPacket->RelatedFileObject; 00095 Alertable = (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT) ? 00096 TRUE: FALSE; 00097 00098 /* Start looping until the VPB is mounted */ 00099 while (!(DeviceObject->Vpb->Flags & VPB_MOUNTED)) 00100 { 00101 /* Release the lock */ 00102 IoReleaseVpbSpinLock(OldIrql); 00103 00104 /* Mount the volume */ 00105 *Status = IopMountVolume(DeviceObject, 00106 Raw, 00107 FALSE, 00108 Alertable, 00109 &Vpb); 00110 00111 /* Check if we failed or if we were alerted */ 00112 if (!(NT_SUCCESS(*Status)) || 00113 (*Status == STATUS_USER_APC) || 00114 (*Status == STATUS_ALERTED)) 00115 { 00116 /* Dereference the device, since IopParseDevice referenced it */ 00117 IopDereferenceDeviceObject(DeviceObject, FALSE); 00118 00119 /* Check if it was a total failure */ 00120 if (!NT_SUCCESS(*Status)) return NULL; 00121 00122 /* Otherwise we were alerted */ 00123 *Status = STATUS_WRONG_VOLUME; 00124 return NULL; 00125 } 00126 00127 /* Re-acquire the lock */ 00128 IoAcquireVpbSpinLock(&OldIrql); 00129 } 00130 00131 /* Make sure the VPB isn't locked */ 00132 Vpb = DeviceObject->Vpb; 00133 if (Vpb->Flags & VPB_LOCKED) 00134 { 00135 /* We're locked, so fail */ 00136 *Status = STATUS_ACCESS_DENIED; 00137 Vpb = NULL; 00138 } 00139 else 00140 { 00141 /* Success! Reference the VPB */ 00142 Vpb->ReferenceCount++; 00143 } 00144 00145 /* Release the lock and return the VPB */ 00146 IoReleaseVpbSpinLock(OldIrql); 00147 return Vpb; 00148 } 00149 00150 /* 00151 * @implemented 00152 */ 00153 NTSTATUS 00154 NTAPI 00155 IopCreateVpb(IN PDEVICE_OBJECT DeviceObject) 00156 { 00157 PVPB Vpb; 00158 00159 /* Allocate the Vpb */ 00160 Vpb = ExAllocatePoolWithTag(NonPagedPool, 00161 sizeof(VPB), 00162 TAG_VPB); 00163 if (!Vpb) return STATUS_INSUFFICIENT_RESOURCES; 00164 00165 /* Clear it so we don't waste time manually */ 00166 RtlZeroMemory(Vpb, sizeof(VPB)); 00167 00168 /* Set the Header and Device Field */ 00169 Vpb->Type = IO_TYPE_VPB; 00170 Vpb->Size = sizeof(VPB); 00171 Vpb->RealDevice = DeviceObject; 00172 00173 /* Link it to the Device Object */ 00174 DeviceObject->Vpb = Vpb; 00175 return STATUS_SUCCESS; 00176 } 00177 00178 /* 00179 * @implemented 00180 */ 00181 VOID 00182 NTAPI 00183 IopDereferenceVpbAndFree(IN PVPB Vpb) 00184 { 00185 KIRQL OldIrql; 00186 00187 /* Lock the VPBs and decrease references */ 00188 IoAcquireVpbSpinLock(&OldIrql); 00189 Vpb->ReferenceCount--; 00190 00191 /* Check if we're out of references */ 00192 if (!Vpb->ReferenceCount && Vpb->RealDevice->Vpb == Vpb && 00193 !(Vpb->Flags & VPB_PERSISTENT)) 00194 { 00195 /* Release VPB lock */ 00196 IoReleaseVpbSpinLock(OldIrql); 00197 00198 /* And free VPB */ 00199 ExFreePoolWithTag(Vpb, TAG_VPB); 00200 } 00201 else 00202 { 00203 /* Release VPB lock */ 00204 IoReleaseVpbSpinLock(OldIrql); 00205 } 00206 } 00207 00208 /* 00209 * @implemented 00210 */ 00211 BOOLEAN 00212 NTAPI 00213 IopReferenceVerifyVpb(IN PDEVICE_OBJECT DeviceObject, 00214 OUT PDEVICE_OBJECT *FileSystemObject, 00215 OUT PVPB *Vpb) 00216 { 00217 KIRQL OldIrql; 00218 PVPB LocalVpb; 00219 BOOLEAN Result = FALSE; 00220 00221 /* Lock the VPBs and assume failure */ 00222 IoAcquireVpbSpinLock(&OldIrql); 00223 *Vpb = NULL; 00224 *FileSystemObject = NULL; 00225 00226 /* Get the VPB and make sure it's mounted */ 00227 LocalVpb = DeviceObject->Vpb; 00228 if ((LocalVpb) && (LocalVpb->Flags & VPB_MOUNTED)) 00229 { 00230 /* Return it */ 00231 *Vpb = LocalVpb; 00232 *FileSystemObject = LocalVpb->DeviceObject; 00233 00234 /* Reference it */ 00235 LocalVpb->ReferenceCount++; 00236 Result = TRUE; 00237 } 00238 00239 /* Release the VPB lock and return status */ 00240 IoReleaseVpbSpinLock(OldIrql); 00241 return Result; 00242 } 00243 00244 PVPB 00245 NTAPI 00246 IopMountInitializeVpb(IN PDEVICE_OBJECT DeviceObject, 00247 IN PDEVICE_OBJECT AttachedDeviceObject, 00248 IN BOOLEAN Raw) 00249 { 00250 KIRQL OldIrql; 00251 PVPB Vpb; 00252 00253 /* Lock the VPBs */ 00254 IoAcquireVpbSpinLock(&OldIrql); 00255 Vpb = DeviceObject->Vpb; 00256 00257 /* Set the VPB as mounted and possibly raw */ 00258 Vpb->Flags |= VPB_MOUNTED | (Raw ? VPB_RAW_MOUNT : 0); 00259 00260 /* Set the stack size */ 00261 Vpb->DeviceObject->StackSize = AttachedDeviceObject->StackSize; 00262 00263 /* Add one for the FS Driver */ 00264 Vpb->DeviceObject->StackSize++; 00265 00266 /* Set the VPB in the device extension */ 00267 IoGetDevObjExtension(Vpb->DeviceObject)->Vpb = Vpb; 00268 00269 /* Reference it */ 00270 Vpb->ReferenceCount++; 00271 00272 /* Release the VPB lock and return it */ 00273 IoReleaseVpbSpinLock(OldIrql); 00274 return Vpb; 00275 } 00276 00277 /* 00278 * @implemented 00279 */ 00280 VOID 00281 FORCEINLINE 00282 IopNotifyFileSystemChange(IN PDEVICE_OBJECT DeviceObject, 00283 IN BOOLEAN DriverActive) 00284 { 00285 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry; 00286 PLIST_ENTRY ListEntry; 00287 00288 /* Loop the list */ 00289 ListEntry = IopFsNotifyChangeQueueHead.Flink; 00290 while (ListEntry != &IopFsNotifyChangeQueueHead) 00291 { 00292 /* Get the entry */ 00293 ChangeEntry = CONTAINING_RECORD(ListEntry, 00294 FS_CHANGE_NOTIFY_ENTRY, 00295 FsChangeNotifyList); 00296 00297 /* Call the notification procedure */ 00298 ChangeEntry->FSDNotificationProc(DeviceObject, DriverActive); 00299 00300 /* Go to the next entry */ 00301 ListEntry = ListEntry->Flink; 00302 } 00303 } 00304 00305 /* 00306 * @implemented 00307 */ 00308 ULONG 00309 FASTCALL 00310 IopInterlockedIncrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue, 00311 IN PULONG Ulong) 00312 { 00313 KIRQL Irql; 00314 ULONG OldValue; 00315 00316 Irql = KeAcquireQueuedSpinLock(Queue); 00317 OldValue = (*Ulong)++; 00318 KeReleaseQueuedSpinLock(Queue, Irql); 00319 00320 return OldValue; 00321 } 00322 00323 /* 00324 * @implemented 00325 */ 00326 ULONG 00327 FASTCALL 00328 IopInterlockedDecrementUlong(IN KSPIN_LOCK_QUEUE_NUMBER Queue, 00329 IN PULONG Ulong) 00330 { 00331 KIRQL Irql; 00332 ULONG OldValue; 00333 00334 Irql = KeAcquireQueuedSpinLock(Queue); 00335 OldValue = (*Ulong)--; 00336 KeReleaseQueuedSpinLock(Queue, Irql); 00337 00338 return OldValue; 00339 } 00340 00341 /* 00342 * @implemented 00343 */ 00344 VOID 00345 NTAPI 00346 IopShutdownBaseFileSystems(IN PLIST_ENTRY ListHead) 00347 { 00348 PLIST_ENTRY ListEntry; 00349 PDEVICE_OBJECT DeviceObject; 00350 IO_STATUS_BLOCK StatusBlock; 00351 PIRP Irp; 00352 KEVENT Event; 00353 NTSTATUS Status; 00354 00355 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00356 00357 /* Get the first entry and start looping */ 00358 ListEntry = ListHead->Flink; 00359 while (ListEntry != ListHead) 00360 { 00361 /* Get the device object */ 00362 DeviceObject = CONTAINING_RECORD(ListEntry, 00363 DEVICE_OBJECT, 00364 Queue.ListEntry); 00365 00366 /* Get the attached device */ 00367 DeviceObject = IoGetAttachedDevice(DeviceObject); 00368 00369 ObReferenceObject(DeviceObject); 00370 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 00371 00372 /* Build the shutdown IRP and call the driver */ 00373 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN, 00374 DeviceObject, 00375 NULL, 00376 0, 00377 NULL, 00378 &Event, 00379 &StatusBlock); 00380 Status = IoCallDriver(DeviceObject, Irp); 00381 if (Status == STATUS_PENDING) 00382 { 00383 /* Wait on the driver */ 00384 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00385 } 00386 00387 /* Reset the event */ 00388 KeClearEvent(&Event); 00389 00390 IopDecrementDeviceObjectRef(DeviceObject, FALSE); 00391 ObDereferenceObject(DeviceObject); 00392 00393 /* Go to the next entry */ 00394 ListEntry = ListEntry->Flink; 00395 } 00396 } 00397 00398 /* 00399 * @implemented 00400 */ 00401 VOID 00402 NTAPI 00403 IopLoadFileSystemDriver(IN PDEVICE_OBJECT DeviceObject) 00404 { 00405 IO_STATUS_BLOCK IoStatusBlock; 00406 PIO_STACK_LOCATION StackPtr; 00407 KEVENT Event; 00408 PIRP Irp; 00409 NTSTATUS Status; 00410 PDEVICE_OBJECT AttachedDeviceObject = DeviceObject; 00411 PAGED_CODE(); 00412 00413 /* Loop as long as we're attached */ 00414 while (AttachedDeviceObject->AttachedDevice) 00415 { 00416 /* Get the attached device object */ 00417 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; 00418 } 00419 00420 /* Initialize the event and build the IRP */ 00421 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00422 Irp = IoBuildDeviceIoControlRequest(IRP_MJ_DEVICE_CONTROL, 00423 AttachedDeviceObject, 00424 NULL, 00425 0, 00426 NULL, 00427 0, 00428 FALSE, 00429 &Event, 00430 &IoStatusBlock); 00431 if (Irp) 00432 { 00433 /* Set the major and minor functions */ 00434 StackPtr = IoGetNextIrpStackLocation(Irp); 00435 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; 00436 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM; 00437 00438 /* Call the driver */ 00439 Status = IoCallDriver(AttachedDeviceObject, Irp); 00440 if (Status == STATUS_PENDING) 00441 { 00442 /* Wait on it */ 00443 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00444 } 00445 } 00446 00447 /* Dereference DO - FsRec? - Comment out call, since it breaks up 2nd stage boot, needs more research. */ 00448 // IopDecrementDeviceObjectRef(AttachedDeviceObject, TRUE); 00449 } 00450 00451 /* 00452 * @implemented 00453 */ 00454 NTSTATUS 00455 NTAPI 00456 IopMountVolume(IN PDEVICE_OBJECT DeviceObject, 00457 IN BOOLEAN AllowRawMount, 00458 IN BOOLEAN DeviceIsLocked, 00459 IN BOOLEAN Alertable, 00460 OUT PVPB *Vpb) 00461 { 00462 KEVENT Event; 00463 NTSTATUS Status; 00464 IO_STATUS_BLOCK IoStatusBlock; 00465 PIRP Irp; 00466 PIO_STACK_LOCATION StackPtr; 00467 PLIST_ENTRY FsList, ListEntry; 00468 LIST_ENTRY LocalList; 00469 PDEVICE_OBJECT AttachedDeviceObject = DeviceObject; 00470 PDEVICE_OBJECT FileSystemDeviceObject, ParentFsDeviceObject; 00471 ULONG FsStackOverhead, RegistrationOps; 00472 PAGED_CODE(); 00473 00474 /* Check if the device isn't already locked */ 00475 if (!DeviceIsLocked) 00476 { 00477 /* Lock it ourselves */ 00478 Status = KeWaitForSingleObject(&DeviceObject->DeviceLock, 00479 Executive, 00480 KeGetPreviousMode(), 00481 Alertable, 00482 NULL); 00483 if ((Status == STATUS_ALERTED) || (Status == STATUS_USER_APC)) 00484 { 00485 /* Don't mount if we were interrupted */ 00486 return Status; 00487 } 00488 } 00489 00490 /* Acquire the FS Lock*/ 00491 KeEnterCriticalRegion(); 00492 ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE); 00493 00494 /* Make sure we weren't already mounted */ 00495 if (!(DeviceObject->Vpb->Flags & (VPB_MOUNTED | VPB_REMOVE_PENDING))) 00496 { 00497 /* Initialize the event to wait on */ 00498 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00499 00500 /* Remove the verify flag and get the actual device to mount */ 00501 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 00502 while (AttachedDeviceObject->AttachedDevice) 00503 { 00504 /* Get the next one */ 00505 AttachedDeviceObject = AttachedDeviceObject->AttachedDevice; 00506 } 00507 00508 /* Reference it */ 00509 ObReferenceObject(AttachedDeviceObject); 00510 00511 /* For a mount operation, this can only be a Disk, CD-ROM or tape */ 00512 if ((DeviceObject->DeviceType == FILE_DEVICE_DISK) || 00513 (DeviceObject->DeviceType == FILE_DEVICE_VIRTUAL_DISK)) 00514 { 00515 /* Use the disk list */ 00516 FsList = &IopDiskFileSystemQueueHead; 00517 } 00518 else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM) 00519 { 00520 /* Use the CD-ROM list */ 00521 FsList = &IopCdRomFileSystemQueueHead; 00522 } 00523 else 00524 { 00525 /* It's gotta be a tape... */ 00526 FsList = &IopTapeFileSystemQueueHead; 00527 } 00528 00529 /* Now loop the fs list until one of the file systems accepts us */ 00530 Status = STATUS_UNSUCCESSFUL; 00531 ListEntry = FsList->Flink; 00532 while ((ListEntry != FsList) && !(NT_SUCCESS(Status))) 00533 { 00534 /* 00535 * If we're not allowed to mount this volume and this is our last 00536 * (but not only) chance to mount it... 00537 */ 00538 if (!(AllowRawMount) && 00539 (ListEntry->Flink == FsList) && 00540 (ListEntry != FsList->Flink)) 00541 { 00542 /* Then fail this mount request */ 00543 break; 00544 } 00545 00546 /* 00547 * Also check if this is a raw mount and there are other file 00548 * systems on the list. 00549 */ 00550 if ((DeviceObject->Vpb->Flags & VPB_RAW_MOUNT) && 00551 (ListEntry->Flink != FsList)) 00552 { 00553 /* Then skip this entry */ 00554 continue; 00555 } 00556 00557 /* Get the Device Object for this FS */ 00558 FileSystemDeviceObject = CONTAINING_RECORD(ListEntry, 00559 DEVICE_OBJECT, 00560 Queue.ListEntry); 00561 ParentFsDeviceObject = FileSystemDeviceObject; 00562 00563 /* 00564 * If this file system device is attached to some other device, 00565 * then we must make sure to increase the stack size for the IRP. 00566 * The default is +1, for the FS device itself. 00567 */ 00568 FsStackOverhead = 1; 00569 while (FileSystemDeviceObject->AttachedDevice) 00570 { 00571 /* Get the next attached device and increase overhead */ 00572 FileSystemDeviceObject = FileSystemDeviceObject-> 00573 AttachedDevice; 00574 FsStackOverhead++; 00575 } 00576 00577 /* Clear the event */ 00578 KeClearEvent(&Event); 00579 00580 /* Allocate the IRP */ 00581 Irp = IoAllocateIrp(AttachedDeviceObject->StackSize + 00582 (UCHAR)FsStackOverhead, 00583 TRUE); 00584 if (!Irp) 00585 { 00586 /* Fail */ 00587 Status = STATUS_INSUFFICIENT_RESOURCES; 00588 break; 00589 } 00590 00591 /* Setup the IRP */ 00592 Irp->UserIosb = &IoStatusBlock; 00593 Irp->UserEvent = &Event; 00594 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00595 Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO; 00596 Irp->RequestorMode = KernelMode; 00597 00598 /* Get the I/O Stack location and set it up */ 00599 StackPtr = IoGetNextIrpStackLocation(Irp); 00600 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; 00601 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME; 00602 StackPtr->Flags = AllowRawMount; 00603 StackPtr->Parameters.MountVolume.Vpb = DeviceObject->Vpb; 00604 StackPtr->Parameters.MountVolume.DeviceObject = 00605 AttachedDeviceObject; 00606 00607 /* Save registration operations */ 00608 RegistrationOps = IopFsRegistrationOps; 00609 00610 /* Release locks */ 00611 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 00612 ExReleaseResourceLite(&IopDatabaseResource); 00613 00614 /* Call the driver */ 00615 Status = IoCallDriver(FileSystemDeviceObject, Irp); 00616 if (Status == STATUS_PENDING) 00617 { 00618 /* Wait on it */ 00619 KeWaitForSingleObject(&Event, 00620 Executive, 00621 KernelMode, 00622 FALSE, 00623 NULL); 00624 Status = IoStatusBlock.Status; 00625 } 00626 00627 ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE); 00628 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 00629 00630 /* Check if mounting was successful */ 00631 if (NT_SUCCESS(Status)) 00632 { 00633 /* Mount the VPB */ 00634 *Vpb = IopMountInitializeVpb(DeviceObject, 00635 AttachedDeviceObject, 00636 (DeviceObject->Vpb->Flags & 00637 VPB_RAW_MOUNT)); 00638 } 00639 else 00640 { 00641 /* Check if we failed because of the user */ 00642 if ((IoIsErrorUserInduced(Status)) && 00643 (IoStatusBlock.Information == 1)) 00644 { 00645 /* Break out and fail */ 00646 break; 00647 } 00648 00649 /* If there were registration operations in the meanwhile */ 00650 if (RegistrationOps != IopFsRegistrationOps) 00651 { 00652 /* We need to setup a local list to pickup where we left */ 00653 LocalList.Flink = FsList->Flink; 00654 ListEntry = &LocalList; 00655 00656 Status = STATUS_UNRECOGNIZED_VOLUME; 00657 } 00658 00659 /* Otherwise, check if we need to load the FS driver */ 00660 if (Status == STATUS_FS_DRIVER_REQUIRED) 00661 { 00662 /* We need to release the lock */ 00663 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 00664 ExReleaseResourceLite(&IopDatabaseResource); 00665 00666 /* Release the device lock if we're holding it */ 00667 if (!DeviceIsLocked) 00668 { 00669 KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE); 00670 } 00671 00672 /* Leave critical section */ 00673 KeLeaveCriticalRegion(); 00674 00675 /* Load the FS */ 00676 IopLoadFileSystemDriver(ParentFsDeviceObject); 00677 00678 /* Check if the device isn't already locked */ 00679 if (!DeviceIsLocked) 00680 { 00681 /* Lock it ourselves */ 00682 Status = KeWaitForSingleObject(&DeviceObject-> 00683 DeviceLock, 00684 Executive, 00685 KeGetPreviousMode(), 00686 Alertable, 00687 NULL); 00688 if ((Status == STATUS_ALERTED) || 00689 (Status == STATUS_USER_APC)) 00690 { 00691 /* Don't mount if we were interrupted */ 00692 ObDereferenceObject(AttachedDeviceObject); 00693 return Status; 00694 } 00695 } 00696 00697 /* Reacquire the lock */ 00698 KeEnterCriticalRegion(); 00699 ExAcquireResourceSharedLite(&IopDatabaseResource, TRUE); 00700 00701 /* When we released the lock, make sure nobody beat us */ 00702 if (DeviceObject->Vpb->Flags & VPB_MOUNTED) 00703 { 00704 /* Someone did, break out */ 00705 Status = STATUS_SUCCESS; 00706 break; 00707 } 00708 00709 /* Start over by setting a failure */ 00710 Status = STATUS_UNRECOGNIZED_VOLUME; 00711 00712 /* We need to setup a local list to pickup where we left */ 00713 LocalList.Flink = FsList->Flink; 00714 ListEntry = &LocalList; 00715 } 00716 00717 /* 00718 * Check if we failed with any other error then an unrecognized 00719 * volume, and if this request doesn't allow mounting the raw 00720 * file system. 00721 */ 00722 if (!(AllowRawMount) && 00723 (Status != STATUS_UNRECOGNIZED_VOLUME) && 00724 (FsRtlIsTotalDeviceFailure(Status))) 00725 { 00726 /* Break out and give up */ 00727 break; 00728 } 00729 } 00730 00731 /* Go to the next FS entry */ 00732 ListEntry = ListEntry->Flink; 00733 } 00734 00735 /* Dereference the device if we failed */ 00736 if (!NT_SUCCESS(Status)) ObDereferenceObject(AttachedDeviceObject); 00737 } 00738 else if (DeviceObject->Vpb->Flags & VPB_REMOVE_PENDING) 00739 { 00740 /* Someone wants to remove us */ 00741 Status = STATUS_DEVICE_DOES_NOT_EXIST; 00742 } 00743 else 00744 { 00745 /* Someone already mounted us */ 00746 Status = STATUS_SUCCESS; 00747 } 00748 00749 /* Release the FS lock */ 00750 ExReleaseResourceLite(&IopDatabaseResource); 00751 KeLeaveCriticalRegion(); 00752 00753 /* Release the device lock if we're holding it */ 00754 if (!DeviceIsLocked) KeSetEvent(&DeviceObject->DeviceLock, 0, FALSE); 00755 00756 /* Check if we failed to mount the boot partition */ 00757 if ((!NT_SUCCESS(Status)) && 00758 (DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION) && 00759 ExpInitializationPhase < 2) 00760 { 00761 /* Bugcheck the system */ 00762 KeBugCheckEx(INACCESSIBLE_BOOT_DEVICE, 00763 (ULONG_PTR)DeviceObject, 00764 Status, 00765 0, 00766 0); 00767 } 00768 00769 /* Return the mount status */ 00770 return Status; 00771 } 00772 00773 /* 00774 * @implemented 00775 */ 00776 VOID 00777 NTAPI 00778 IopNotifyAlreadyRegisteredFileSystems(IN PLIST_ENTRY ListHead, 00779 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine, 00780 BOOLEAN SkipRawFs) 00781 { 00782 PLIST_ENTRY ListEntry; 00783 PDEVICE_OBJECT DeviceObject; 00784 00785 /* Browse the whole list */ 00786 ListEntry = ListHead->Flink; 00787 while (ListEntry != ListHead) 00788 { 00789 /* Check if we reached rawfs and if we have to skip it */ 00790 if (ListEntry->Flink == ListHead && SkipRawFs) 00791 { 00792 return; 00793 } 00794 00795 /* Otherwise, get DO and notify */ 00796 DeviceObject = CONTAINING_RECORD(ListEntry, 00797 DEVICE_OBJECT, 00798 Queue.ListEntry); 00799 00800 DriverNotificationRoutine(DeviceObject, TRUE); 00801 00802 /* Go to the next entry */ 00803 ListEntry = ListEntry->Flink; 00804 } 00805 } 00806 00807 /* PUBLIC FUNCTIONS **********************************************************/ 00808 00809 /* 00810 * @implemented 00811 */ 00812 NTSTATUS 00813 NTAPI 00814 IoEnumerateRegisteredFiltersList(OUT PDRIVER_OBJECT *DriverObjectList, 00815 IN ULONG DriverObjectListSize, 00816 OUT PULONG ActualNumberDriverObjects) 00817 { 00818 PLIST_ENTRY ListEntry; 00819 NTSTATUS Status = STATUS_SUCCESS; 00820 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry; 00821 ULONG ListSize = 0, MaximumSize = DriverObjectListSize / sizeof(PDRIVER_OBJECT); 00822 00823 /* Acquire the FS lock */ 00824 KeEnterCriticalRegion(); 00825 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 00826 00827 /* Browse the whole list */ 00828 ListEntry = IopFsNotifyChangeQueueHead.Flink; 00829 while (ListEntry != &IopFsNotifyChangeQueueHead) 00830 { 00831 ChangeEntry = CONTAINING_RECORD(ListEntry, 00832 FS_CHANGE_NOTIFY_ENTRY, 00833 FsChangeNotifyList); 00834 00835 /* If buffer is still big enough */ 00836 if (ListSize < MaximumSize) 00837 { 00838 /* Reference the driver object */ 00839 ObReferenceObject(ChangeEntry->DriverObject); 00840 /* And pass it to the caller */ 00841 DriverObjectList[ListSize] = ChangeEntry->DriverObject; 00842 } 00843 else 00844 { 00845 Status = STATUS_BUFFER_TOO_SMALL; 00846 } 00847 00848 /* Increase size counter */ 00849 ListSize++; 00850 00851 /* Go to the next entry */ 00852 ListEntry = ListEntry->Flink; 00853 } 00854 00855 /* Return list size */ 00856 *ActualNumberDriverObjects = ListSize; 00857 00858 /* Release the FS lock */ 00859 ExReleaseResourceLite(&IopDatabaseResource); 00860 KeLeaveCriticalRegion(); 00861 00862 return Status; 00863 } 00864 00865 /* 00866 * @implemented 00867 */ 00868 NTSTATUS 00869 NTAPI 00870 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject, 00871 IN BOOLEAN AllowRawMount) 00872 { 00873 IO_STATUS_BLOCK IoStatusBlock; 00874 PIO_STACK_LOCATION StackPtr; 00875 KEVENT Event; 00876 PIRP Irp; 00877 NTSTATUS Status, VpbStatus; 00878 PDEVICE_OBJECT FileSystemDeviceObject; 00879 PVPB Vpb, NewVpb; 00880 //BOOLEAN WasNotMounted = TRUE; 00881 00882 /* Wait on the device lock */ 00883 Status = KeWaitForSingleObject(&DeviceObject->DeviceLock, 00884 Executive, 00885 KernelMode, 00886 FALSE, 00887 NULL); 00888 ASSERT(Status == STATUS_SUCCESS); 00889 00890 /* Reference the VPB */ 00891 if (IopReferenceVerifyVpb(DeviceObject, &FileSystemDeviceObject, &Vpb)) 00892 { 00893 /* Initialize the event */ 00894 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00895 00896 /* Find the actual File System DO */ 00897 //WasNotMounted = FALSE; 00898 FileSystemDeviceObject = DeviceObject->Vpb->DeviceObject; 00899 while (FileSystemDeviceObject->AttachedDevice) 00900 { 00901 /* Go to the next one */ 00902 FileSystemDeviceObject = FileSystemDeviceObject->AttachedDevice; 00903 } 00904 00905 /* Allocate the IRP */ 00906 Irp = IoAllocateIrp(FileSystemDeviceObject->StackSize, FALSE); 00907 if (!Irp) 00908 { 00909 Status = STATUS_INSUFFICIENT_RESOURCES; 00910 goto Release; 00911 } 00912 00913 /* Set it up */ 00914 Irp->UserIosb = &IoStatusBlock; 00915 Irp->UserEvent = &Event; 00916 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00917 Irp->Flags = IRP_MOUNT_COMPLETION | IRP_SYNCHRONOUS_PAGING_IO; 00918 Irp->RequestorMode = KernelMode; 00919 00920 /* Get the I/O Stack location and set it */ 00921 StackPtr = IoGetNextIrpStackLocation(Irp); 00922 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL; 00923 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME; 00924 StackPtr->Flags = AllowRawMount ? SL_ALLOW_RAW_MOUNT : 0; 00925 StackPtr->Parameters.VerifyVolume.Vpb = Vpb; 00926 StackPtr->Parameters.VerifyVolume.DeviceObject = 00927 DeviceObject->Vpb->DeviceObject; 00928 00929 /* Call the driver */ 00930 Status = IoCallDriver(FileSystemDeviceObject, Irp); 00931 if (Status == STATUS_PENDING) 00932 { 00933 /* Wait on it */ 00934 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00935 Status = IoStatusBlock.Status; 00936 } 00937 00938 /* Dereference the VPB */ 00939 IopDereferenceVpbAndFree(Vpb); 00940 } 00941 00942 /* Check if we had the wrong volume or didn't mount at all */ 00943 if (Status == STATUS_WRONG_VOLUME) 00944 { 00945 /* Create a VPB */ 00946 VpbStatus = IopCreateVpb(DeviceObject); 00947 if (NT_SUCCESS(VpbStatus)) 00948 { 00949 PoVolumeDevice(DeviceObject); 00950 00951 /* Mount it */ 00952 VpbStatus = IopMountVolume(DeviceObject, 00953 AllowRawMount, 00954 TRUE, 00955 FALSE, 00956 &NewVpb); 00957 00958 /* If we got a new VPB, dereference it */ 00959 if (NewVpb) 00960 { 00961 IopInterlockedDecrementUlong(LockQueueIoVpbLock, &NewVpb->ReferenceCount); 00962 } 00963 } 00964 00965 /* If we failed, remove the verify flag */ 00966 if (!NT_SUCCESS(VpbStatus)) DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 00967 } 00968 00969 Release: 00970 /* Signal the device lock and return */ 00971 KeSetEvent(&DeviceObject->DeviceLock, IO_NO_INCREMENT, FALSE); 00972 return Status; 00973 } 00974 00975 /* 00976 * @implemented 00977 */ 00978 VOID 00979 NTAPI 00980 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject) 00981 { 00982 PLIST_ENTRY FsList = NULL; 00983 PAGED_CODE(); 00984 00985 /* Acquire the FS lock */ 00986 KeEnterCriticalRegion(); 00987 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 00988 00989 /* Check what kind of FS this is */ 00990 if (DeviceObject->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) 00991 { 00992 /* Use the disk list */ 00993 FsList = &IopDiskFileSystemQueueHead; 00994 } 00995 else if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) 00996 { 00997 /* Use the network device list */ 00998 FsList = &IopNetworkFileSystemQueueHead; 00999 } 01000 else if (DeviceObject->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) 01001 { 01002 /* Use the CD-ROM list */ 01003 FsList = &IopCdRomFileSystemQueueHead; 01004 } 01005 else if (DeviceObject->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) 01006 { 01007 /* Use the tape list */ 01008 FsList = &IopTapeFileSystemQueueHead; 01009 } 01010 01011 /* Make sure that we have a valid list */ 01012 if (FsList) 01013 { 01014 /* Check if we should insert it at the top or bottom of the list */ 01015 if (DeviceObject->Flags & DO_LOW_PRIORITY_FILESYSTEM) 01016 { 01017 /* At the bottom */ 01018 InsertTailList(FsList->Blink, &DeviceObject->Queue.ListEntry); 01019 } 01020 else 01021 { 01022 /* On top */ 01023 InsertHeadList(FsList, &DeviceObject->Queue.ListEntry); 01024 } 01025 } 01026 01027 /* Update operations counter */ 01028 IopFsRegistrationOps++; 01029 01030 /* Clear the initializing flag */ 01031 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 01032 01033 /* Notify file systems of the addition */ 01034 IopNotifyFileSystemChange(DeviceObject, TRUE); 01035 01036 /* Release the FS Lock */ 01037 ExReleaseResourceLite(&IopDatabaseResource); 01038 KeLeaveCriticalRegion(); 01039 01040 /* Ensure driver won't be unloaded */ 01041 IopInterlockedIncrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 01042 } 01043 01044 /* 01045 * @implemented 01046 */ 01047 VOID 01048 NTAPI 01049 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject) 01050 { 01051 PAGED_CODE(); 01052 01053 /* Acquire the FS lock */ 01054 KeEnterCriticalRegion(); 01055 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 01056 01057 /* Simply remove the entry - if queued */ 01058 if (DeviceObject->Queue.ListEntry.Flink) 01059 { 01060 RemoveEntryList(&DeviceObject->Queue.ListEntry); 01061 } 01062 01063 /* And notify all registered file systems */ 01064 IopNotifyFileSystemChange(DeviceObject, FALSE); 01065 01066 /* Update operations counter */ 01067 IopFsRegistrationOps++; 01068 01069 /* Then release the lock */ 01070 ExReleaseResourceLite(&IopDatabaseResource); 01071 KeLeaveCriticalRegion(); 01072 01073 /* Decrease reference count to allow unload */ 01074 IopInterlockedDecrementUlong(LockQueueIoDatabaseLock, (PULONG)&DeviceObject->ReferenceCount); 01075 } 01076 01077 /* 01078 * @implemented 01079 */ 01080 NTSTATUS 01081 NTAPI 01082 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject, 01083 IN PDRIVER_FS_NOTIFICATION DriverNotificationRoutine) 01084 { 01085 PFS_CHANGE_NOTIFY_ENTRY Entry; 01086 PAGED_CODE(); 01087 01088 /* Acquire the list lock */ 01089 KeEnterCriticalRegion(); 01090 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 01091 01092 /* Check if that driver is already registered (successive calls) 01093 * See MSDN note: http://msdn.microsoft.com/en-us/library/ff548499%28v=vs.85%29.aspx 01094 */ 01095 if (!IsListEmpty(&IopFsNotifyChangeQueueHead)) 01096 { 01097 Entry = CONTAINING_RECORD(IopFsNotifyChangeQueueHead.Blink, 01098 FS_CHANGE_NOTIFY_ENTRY, 01099 FsChangeNotifyList); 01100 01101 if (Entry->DriverObject == DriverObject && 01102 Entry->FSDNotificationProc == DriverNotificationRoutine) 01103 { 01104 /* Release the lock */ 01105 ExReleaseResourceLite(&IopDatabaseResource); 01106 01107 return STATUS_DEVICE_ALREADY_ATTACHED; 01108 } 01109 } 01110 01111 /* Allocate a notification entry */ 01112 Entry = ExAllocatePoolWithTag(PagedPool, 01113 sizeof(FS_CHANGE_NOTIFY_ENTRY), 01114 TAG_FS_CHANGE_NOTIFY); 01115 if (!Entry) 01116 { 01117 /* Release the lock */ 01118 ExReleaseResourceLite(&IopDatabaseResource); 01119 01120 return STATUS_INSUFFICIENT_RESOURCES; 01121 } 01122 01123 /* Save the driver object and notification routine */ 01124 Entry->DriverObject = DriverObject; 01125 Entry->FSDNotificationProc = DriverNotificationRoutine; 01126 01127 /* Insert it into the notification list */ 01128 InsertTailList(&IopFsNotifyChangeQueueHead, &Entry->FsChangeNotifyList); 01129 01130 /* Start notifying all already present FS */ 01131 IopNotifyAlreadyRegisteredFileSystems(&IopNetworkFileSystemQueueHead, DriverNotificationRoutine, FALSE); 01132 IopNotifyAlreadyRegisteredFileSystems(&IopCdRomFileSystemQueueHead, DriverNotificationRoutine, TRUE); 01133 IopNotifyAlreadyRegisteredFileSystems(&IopDiskFileSystemQueueHead, DriverNotificationRoutine, TRUE); 01134 IopNotifyAlreadyRegisteredFileSystems(&IopTapeFileSystemQueueHead, DriverNotificationRoutine, TRUE); 01135 01136 /* Release the lock */ 01137 ExReleaseResourceLite(&IopDatabaseResource); 01138 KeLeaveCriticalRegion(); 01139 01140 /* Reference the driver */ 01141 ObReferenceObject(DriverObject); 01142 return STATUS_SUCCESS; 01143 } 01144 01145 /* 01146 * @implemented 01147 */ 01148 VOID 01149 NTAPI 01150 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject, 01151 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc) 01152 { 01153 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry; 01154 PLIST_ENTRY NextEntry; 01155 PAGED_CODE(); 01156 01157 /* Acquire the list lock */ 01158 KeEnterCriticalRegion(); 01159 ExAcquireResourceExclusiveLite(&IopDatabaseResource, TRUE); 01160 01161 /* Loop the list */ 01162 NextEntry = IopFsNotifyChangeQueueHead.Flink; 01163 while (NextEntry != &IopFsNotifyChangeQueueHead) 01164 { 01165 /* Get the entry */ 01166 ChangeEntry = CONTAINING_RECORD(NextEntry, 01167 FS_CHANGE_NOTIFY_ENTRY, 01168 FsChangeNotifyList); 01169 01170 /* Check if it matches this de-registration */ 01171 if ((ChangeEntry->DriverObject == DriverObject) && 01172 (ChangeEntry->FSDNotificationProc == FSDNotificationProc)) 01173 { 01174 /* It does, remove it from the list */ 01175 RemoveEntryList(&ChangeEntry->FsChangeNotifyList); 01176 ExFreePoolWithTag(ChangeEntry, TAG_FS_CHANGE_NOTIFY); 01177 break; 01178 } 01179 01180 /* Go to the next entry */ 01181 NextEntry = NextEntry->Flink; 01182 } 01183 01184 /* Release the lock and dereference the driver */ 01185 ExReleaseResourceLite(&IopDatabaseResource); 01186 KeLeaveCriticalRegion(); 01187 01188 /* Dereference the driver */ 01189 ObDereferenceObject(DriverObject); 01190 } 01191 01192 /* 01193 * @implemented 01194 */ 01195 VOID 01196 NTAPI 01197 IoAcquireVpbSpinLock(OUT PKIRQL Irql) 01198 { 01199 /* Simply acquire the lock */ 01200 *Irql = KeAcquireQueuedSpinLock(LockQueueIoVpbLock); 01201 } 01202 01203 /* 01204 * @implemented 01205 */ 01206 VOID 01207 NTAPI 01208 IoReleaseVpbSpinLock(IN KIRQL Irql) 01209 { 01210 /* Just release the lock */ 01211 KeReleaseQueuedSpinLock(LockQueueIoVpbLock, Irql); 01212 } 01213 01214 /* 01215 * @implemented 01216 */ 01217 NTSTATUS 01218 NTAPI 01219 IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString) 01220 { 01221 NTSTATUS Status; 01222 HANDLE RootHandle, KeyHandle; 01223 UNICODE_STRING HKLMSystem, KeyString; 01224 WCHAR Buffer[sizeof(L"SystemPartition") / sizeof(WCHAR)]; 01225 01226 RtlInitUnicodeString(&HKLMSystem, L"\\REGISTRY\\MACHINE\\SYSTEM"); 01227 01228 /* Open registry to save data (HKLM\SYSTEM) */ 01229 Status = IopOpenRegistryKeyEx(&RootHandle, 0, &HKLMSystem, KEY_ALL_ACCESS); 01230 if (!NT_SUCCESS(Status)) 01231 { 01232 return Status; 01233 } 01234 01235 /* Create or open Setup subkey */ 01236 KeyString.Buffer = Buffer; 01237 KeyString.Length = sizeof(L"Setup") - sizeof(UNICODE_NULL); 01238 KeyString.MaximumLength = sizeof(L"Setup"); 01239 RtlCopyMemory(Buffer, L"Setup", sizeof(L"Setup")); 01240 Status = IopCreateRegistryKeyEx(&KeyHandle, 01241 RootHandle, 01242 &KeyString, 01243 KEY_ALL_ACCESS, 01244 REG_OPTION_NON_VOLATILE, 01245 NULL); 01246 ZwClose(RootHandle); 01247 if (!NT_SUCCESS(Status)) 01248 { 01249 return Status; 01250 } 01251 01252 /* Store caller value */ 01253 KeyString.Length = sizeof(L"SystemPartition") - sizeof(UNICODE_NULL); 01254 KeyString.MaximumLength = sizeof(L"SystemPartition"); 01255 RtlCopyMemory(Buffer, L"SystemPartition", sizeof(L"SystemPartition")); 01256 Status = ZwSetValueKey(KeyHandle, 01257 &KeyString, 01258 0, 01259 REG_SZ, 01260 VolumeNameString->Buffer, 01261 VolumeNameString->Length + sizeof(UNICODE_NULL)); 01262 ZwClose(KeyHandle); 01263 01264 return Status; 01265 } 01266 01267 /* 01268 * @implemented 01269 */ 01270 NTSTATUS 01271 NTAPI 01272 IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject, 01273 OUT PUNICODE_STRING DosName) 01274 { 01275 PIRP Irp; 01276 ULONG Length; 01277 KEVENT Event; 01278 NTSTATUS Status; 01279 PFILE_OBJECT FileObject; 01280 PDEVICE_OBJECT DeviceObject; 01281 IO_STATUS_BLOCK IoStatusBlock; 01282 UNICODE_STRING MountMgrDevice; 01283 MOUNTMGR_VOLUME_PATHS VolumePath; 01284 PMOUNTMGR_VOLUME_PATHS VolumePathPtr; 01285 /* 01286 * This variable with be required to query device name. 01287 * It's based on MOUNTDEV_NAME (mountmgr.h). 01288 * Doing it that way will prevent dyn memory allocation. 01289 * Device name won't be longer. 01290 */ 01291 struct 01292 { 01293 USHORT NameLength; 01294 WCHAR DeviceName[256]; 01295 } DeviceName; 01296 01297 PAGED_CODE(); 01298 01299 /* First step, getting device name */ 01300 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01301 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 01302 VolumeDeviceObject, NULL, 0, 01303 &DeviceName, sizeof(DeviceName), 01304 FALSE, &Event, &IoStatusBlock); 01305 if (!Irp) 01306 { 01307 return STATUS_INSUFFICIENT_RESOURCES; 01308 } 01309 01310 Status = IoCallDriver(VolumeDeviceObject, Irp); 01311 if (Status == STATUS_PENDING) 01312 { 01313 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01314 Status = IoStatusBlock.Status; 01315 } 01316 01317 if (!NT_SUCCESS(Status)) 01318 { 01319 return Status; 01320 } 01321 01322 /* Now that we have the device name, we can query the MountMgr 01323 * So, get its device object first. 01324 */ 01325 RtlInitUnicodeString(&MountMgrDevice, MOUNTMGR_DEVICE_NAME); 01326 Status = IoGetDeviceObjectPointer(&MountMgrDevice, FILE_READ_ATTRIBUTES, 01327 &FileObject, &DeviceObject); 01328 if (!NT_SUCCESS(Status)) 01329 { 01330 return Status; 01331 } 01332 01333 /* Then, use the proper IOCTL to query the DOS name */ 01334 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01335 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, 01336 DeviceObject, &DeviceName, sizeof(DeviceName), 01337 &VolumePath, sizeof(VolumePath), 01338 FALSE, &Event, &IoStatusBlock); 01339 if (!Irp) 01340 { 01341 Status = STATUS_INSUFFICIENT_RESOURCES; 01342 goto DereferenceFO; 01343 } 01344 01345 Status = IoCallDriver(VolumeDeviceObject, Irp); 01346 if (Status == STATUS_PENDING) 01347 { 01348 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01349 Status = IoStatusBlock.Status; 01350 } 01351 01352 /* Only tolerated failure here is buffer too small, which is 01353 * expected. 01354 */ 01355 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 01356 { 01357 goto DereferenceFO; 01358 } 01359 01360 /* Compute needed size to store DOS name. 01361 * Even if MOUNTMGR_VOLUME_PATHS allows bigger 01362 * name lengths than MAXUSHORT, we can't use 01363 * them, because we have to return this in an UNICODE_STRING 01364 * that stores length on USHORT. 01365 */ 01366 Length = VolumePath.MultiSzLength + sizeof(VolumePath); 01367 if (Length > MAXUSHORT) 01368 { 01369 Status = STATUS_INVALID_BUFFER_SIZE; 01370 goto DereferenceFO; 01371 } 01372 01373 /* Reallocate memory, even in case of success, because 01374 * that's the buffer that will be returned to caller 01375 */ 01376 VolumePathPtr = ExAllocatePoolWithTag(PagedPool, Length, 'D2d '); 01377 if (!VolumePathPtr) 01378 { 01379 Status = STATUS_INSUFFICIENT_RESOURCES; 01380 goto DereferenceFO; 01381 } 01382 01383 /* Requery DOS path with proper size */ 01384 KeInitializeEvent(&Event, NotificationEvent, FALSE); 01385 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, 01386 DeviceObject, &DeviceName, sizeof(DeviceName), 01387 VolumePathPtr, Length, 01388 FALSE, &Event, &IoStatusBlock); 01389 if (!Irp) 01390 { 01391 Status = STATUS_INSUFFICIENT_RESOURCES; 01392 goto ReleaseMemory; 01393 } 01394 01395 Status = IoCallDriver(VolumeDeviceObject, Irp); 01396 if (Status == STATUS_PENDING) 01397 { 01398 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 01399 Status = IoStatusBlock.Status; 01400 } 01401 01402 if (!NT_SUCCESS(Status)) 01403 { 01404 goto ReleaseMemory; 01405 } 01406 01407 /* Set output string */ 01408 DosName->Length = (USHORT)VolumePathPtr->MultiSzLength; 01409 DosName->MaximumLength = (USHORT)VolumePathPtr->MultiSzLength + sizeof(UNICODE_NULL); 01410 /* Our MOUNTMGR_VOLUME_PATHS will be used as output buffer */ 01411 DosName->Buffer = (PWSTR)VolumePathPtr; 01412 /* Move name at the begin, RtlMoveMemory is OK with overlapping */ 01413 RtlMoveMemory(DosName->Buffer, VolumePathPtr->MultiSz, VolumePathPtr->MultiSzLength); 01414 DosName->Buffer[DosName->Length / sizeof(WCHAR)] = UNICODE_NULL; 01415 01416 /* DON'T release buffer, just dereference FO, and return success */ 01417 Status = STATUS_SUCCESS; 01418 goto DereferenceFO; 01419 01420 ReleaseMemory: 01421 ExFreePoolWithTag(VolumePathPtr, 'D2d '); 01422 01423 DereferenceFO: 01424 ObDereferenceObject(FileObject); 01425 01426 return Status; 01427 } 01428 01429 /* EOF */ Generated on Thu May 24 2012 04:19:27 for ReactOS by
1.7.6.1
|