ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

volume.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.