[NTOSKRNL]
authorPierre Schweitzer <pierre@reactos.org>
Tue, 31 Jan 2012 18:18:46 +0000 (18:18 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Tue, 31 Jan 2012 18:18:46 +0000 (18:18 +0000)
Implement IoVolumeDeviceToDosName(), taking advantage of newcomer in the branch, MountMgr :-).
This implementation will in fact don't work as MountMgr doesn't implement that part... But the day it's ready, this function will be!

svn path=/branches/usb-bringup-trunk/; revision=55354

ntoskrnl/include/ntoskrnl.h
ntoskrnl/io/iomgr/volume.c

index 4af4b96..9a823e4 100644 (file)
@@ -31,6 +31,7 @@
 #include <ntifs.h>
 #include <wdmguid.h>
 #include <arc/arc.h>
+#include <mountmgr.h>
 #undef NTHALAPI
 #define NTHALAPI __declspec(dllimport)
 #include <ndk/asm.h>
index 9d7030e..d336385 100644 (file)
@@ -1269,15 +1269,165 @@ IoSetSystemPartition(IN PUNICODE_STRING VolumeNameString)
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
 IoVolumeDeviceToDosName(IN PVOID VolumeDeviceObject,
                         OUT PUNICODE_STRING DosName)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    PIRP Irp;
+    ULONG Length;
+    KEVENT Event;
+    NTSTATUS Status;
+    PFILE_OBJECT FileObject;
+    PDEVICE_OBJECT DeviceObject;
+    IO_STATUS_BLOCK IoStatusBlock;
+    UNICODE_STRING MountMgrDevice;
+    MOUNTMGR_VOLUME_PATHS VolumePath;
+    PMOUNTMGR_VOLUME_PATHS VolumePathPtr;
+    /*
+     * This variable with be required to query device name.
+     * It's based on MOUNTDEV_NAME (mountmgr.h).
+     * Doing it that way will prevent dyn memory allocation.
+     * Device name won't be longer.
+     */
+    struct
+    {
+        USHORT NameLength;
+        WCHAR DeviceName[256];
+    } DeviceName;
+
+    PAGED_CODE();
+
+    /* First step, getting device name */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
+                                        VolumeDeviceObject, NULL, 0,
+                                        &DeviceName, sizeof(DeviceName),
+                                        FALSE, &Event, &IoStatusBlock);
+    if (!Irp)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = IoCallDriver(VolumeDeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock.Status;
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Now that we have the device name, we can query the MountMgr
+     * So, get its device object first.
+     */
+    RtlInitUnicodeString(&MountMgrDevice, MOUNTMGR_DEVICE_NAME);
+    Status = IoGetDeviceObjectPointer(&MountMgrDevice, FILE_READ_ATTRIBUTES,
+                                      &FileObject, &DeviceObject);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Then, use the proper IOCTL to query the DOS name */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
+                                        DeviceObject, &DeviceName, sizeof(DeviceName),
+                                        &VolumePath, sizeof(VolumePath),
+                                        FALSE, &Event, &IoStatusBlock);
+    if (!Irp)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto DereferenceFO;
+    }
+
+    Status = IoCallDriver(VolumeDeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock.Status;
+    }
+
+    /* Only tolerated failure here is buffer too small, which is
+     * expected.
+     */
+    if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
+    {
+        goto DereferenceFO;
+    }
+
+    /* Compute needed size to store DOS name.
+     * Even if MOUNTMGR_VOLUME_PATHS allows bigger
+     * name lengths than MAXUSHORT, we can't use
+     * them, because we have to return this in an UNICODE_STRING
+     * that stores length on USHORT.
+     */ 
+    Length = VolumePath.MultiSzLength + sizeof(VolumePath);
+    if (Length > MAXUSHORT)
+    {
+        Status = STATUS_INVALID_BUFFER_SIZE;
+        goto DereferenceFO;
+    }
+
+    /* Reallocate memory, even in case of success, because
+     * that's the buffer that will be returned to caller
+     */
+    VolumePathPtr = ExAllocatePoolWithTag(PagedPool, Length, 'D2d ');
+    if (!VolumePathPtr)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto DereferenceFO;
+    }
+
+    /* Requery DOS path with proper size */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH,
+                                        DeviceObject, &DeviceName, sizeof(DeviceName),
+                                        VolumePathPtr, Length,
+                                        FALSE, &Event, &IoStatusBlock);
+    if (!Irp)
+    {
+        Status = STATUS_INSUFFICIENT_RESOURCES;
+        goto ReleaseMemory;
+    }
+
+    Status = IoCallDriver(VolumeDeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock.Status;
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        goto ReleaseMemory;
+    }
+
+    /* Set output string */
+    DosName->Length = VolumePathPtr->MultiSzLength;
+    DosName->MaximumLength = VolumePathPtr->MultiSzLength + sizeof(UNICODE_NULL);
+    /* Our MOUNTMGR_VOLUME_PATHS will be used as output buffer */
+    DosName->Buffer = (PWSTR)VolumePathPtr;
+    /* Move name at the begin, RtlMoveMemory is OK with overlapping */
+    RtlMoveMemory(DosName->Buffer, VolumePathPtr->MultiSz, VolumePathPtr->MultiSzLength);
+    DosName->Buffer[DosName->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+    /* DON'T release buffer, just dereference FO, and return success */
+    Status = STATUS_SUCCESS;
+    goto DereferenceFO;
+
+ReleaseMemory:
+    ExFreePoolWithTag(VolumePathPtr, 'D2d ');
+
+DereferenceFO:
+    ObDereferenceObject(FileObject);
+
+    return Status;
 }
 
 /* EOF */