Implementation of GetVolumeNameForVolumeMountPointW (depends on mount manager, so...
[reactos.git] / reactos / lib / kernel32 / file / volume.c
index d463c9e..31fb8b2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: volume.c,v 1.35 2004/01/12 20:02:42 weiden Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
@@ -13,7 +13,7 @@
  */
 //WINE copyright notice:
 /*
- * DOS drives handling functions 
+ * DOS drives handling functions
  *
  * Copyright 1993 Erik Bos
  * Copyright 1996 Alexandre Julliard
@@ -22,7 +22,7 @@
 #include <k32.h>
 
 #define NDEBUG
-#include <kernel32/kernel32.h>
+#include "../include/debug.h"
 
 
 #define MAX_DOS_DRIVES 26
@@ -87,7 +87,7 @@ GetLogicalDriveStringsA(DWORD nBufferLength,
    DWORD drive, count;
    DWORD dwDriveMap;
 
-   dwDriveMap = SharedUserData->DosDeviceMap;
+   dwDriveMap = GetLogicalDrives();
 
    for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
      {
@@ -124,7 +124,7 @@ GetLogicalDriveStringsW(DWORD nBufferLength,
    DWORD drive, count;
    DWORD dwDriveMap;
 
-   dwDriveMap = SharedUserData->DosDeviceMap;
+   dwDriveMap = GetLogicalDrives();
 
    for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
      {
@@ -155,14 +155,31 @@ GetLogicalDriveStringsW(DWORD nBufferLength,
 DWORD STDCALL
 GetLogicalDrives(VOID)
 {
-  return(SharedUserData->DosDeviceMap);
+       NTSTATUS Status;
+       PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
+
+       /* Get the Device Map for this Process */
+       Status = NtQueryInformationProcess(NtCurrentProcess(),
+                                          ProcessDeviceMap,
+                                          &ProcessDeviceMapInfo,
+                                          sizeof(ProcessDeviceMapInfo),
+                                          NULL);
+
+       /* Return the Drive Map */
+       if (!NT_SUCCESS(Status))
+       {
+               SetLastErrorByStatus(Status);
+               return 0;
+       }
+
+        return ProcessDeviceMapInfo.Query.DriveMap;
 }
 
 
 /*
  * @implemented
  */
-WINBOOL STDCALL
+BOOL STDCALL
 GetDiskFreeSpaceA (
        LPCSTR  lpRootPathName,
        LPDWORD lpSectorsPerCluster,
@@ -171,50 +188,26 @@ GetDiskFreeSpaceA (
        LPDWORD lpTotalNumberOfClusters
        )
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       WINBOOL Result;
+   PWCHAR RootPathNameW=NULL;
 
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-
-       RtlInitUnicodeString (&RootPathNameU,
-                             NULL);
-
-       if (lpRootPathName)
-       {
-               /* convert ansi (or oem) string to unicode */
-               if (bIsFileApiAnsi)
-                       RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                                     &RootPathName,
-                                                     TRUE);
-               else
-                       RtlOemStringToUnicodeString (&RootPathNameU,
-                                                    &RootPathName,
-                                                    TRUE);
-       }
+   if (lpRootPathName)
+   {
+      if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+         return FALSE;
+   }
 
-       Result = GetDiskFreeSpaceW (RootPathNameU.Buffer,
+       return GetDiskFreeSpaceW (RootPathNameW,
                                    lpSectorsPerCluster,
                                    lpBytesPerSector,
                                    lpNumberOfFreeClusters,
                                    lpTotalNumberOfClusters);
-
-       if (lpRootPathName)
-       {
-               RtlFreeHeap (RtlGetProcessHeap (),
-                            0,
-                            RootPathNameU.Buffer);
-       }
-
-       return Result;
 }
 
 
 /*
  * @implemented
  */
-WINBOOL STDCALL
+BOOL STDCALL
 GetDiskFreeSpaceW(
     LPCWSTR lpRootPathName,
     LPDWORD lpSectorsPerCluster,
@@ -236,8 +229,8 @@ GetDiskFreeSpaceW(
     else
     {
         GetCurrentDirectoryW (MAX_PATH, RootPathName);
-        RootPathName[3] = 0;
     }
+    RootPathName[3] = 0;
 
   hFile = InternalOpenDirW(RootPathName, FALSE);
   if (INVALID_HANDLE_VALUE == hFile)
@@ -263,6 +256,7 @@ GetDiskFreeSpaceW(
     *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
     *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
     CloseHandle(hFile);
+
     return TRUE;
 }
 
@@ -270,59 +264,35 @@ GetDiskFreeSpaceW(
 /*
  * @implemented
  */
-WINBOOL STDCALL
+BOOL STDCALL
 GetDiskFreeSpaceExA (
-       LPCSTR          lpDirectoryName,
+       LPCSTR lpDirectoryName   OPTIONAL,
        PULARGE_INTEGER lpFreeBytesAvailableToCaller,
        PULARGE_INTEGER lpTotalNumberOfBytes,
        PULARGE_INTEGER lpTotalNumberOfFreeBytes
        )
 {
-       UNICODE_STRING DirectoryNameU;
-       ANSI_STRING DirectoryName;
-       WINBOOL Result;
-
-       RtlInitAnsiString (&DirectoryName,
-                          (LPSTR)lpDirectoryName);
-
-       RtlInitUnicodeString (&DirectoryNameU,
-                             NULL);
+   PWCHAR DirectoryNameW=NULL;
 
        if (lpDirectoryName)
        {
-               /* convert ansi (or oem) string to unicode */
-               if (bIsFileApiAnsi)
-                       RtlAnsiStringToUnicodeString (&DirectoryNameU,
-                                                     &DirectoryName,
-                                                     TRUE);
-               else
-                       RtlOemStringToUnicodeString (&DirectoryNameU,
-                                                    &DirectoryName,
-                                                    TRUE);
+      if (!(DirectoryNameW = FilenameA2W(lpDirectoryName, FALSE)))
+         return FALSE;
        }
 
-       Result = GetDiskFreeSpaceExW (DirectoryNameU.Buffer,
+   return GetDiskFreeSpaceExW (DirectoryNameW ,
                                      lpFreeBytesAvailableToCaller,
                                      lpTotalNumberOfBytes,
                                      lpTotalNumberOfFreeBytes);
-
-       if (lpDirectoryName)
-       {
-               RtlFreeHeap (RtlGetProcessHeap (),
-                            0,
-                            DirectoryNameU.Buffer);
-       }
-
-       return Result;
 }
 
 
 /*
  * @implemented
  */
-WINBOOL STDCALL
+BOOL STDCALL
 GetDiskFreeSpaceExW(
-    LPCWSTR lpDirectoryName,
+    LPCWSTR lpDirectoryName OPTIONAL,
     PULARGE_INTEGER lpFreeBytesAvailableToCaller,
     PULARGE_INTEGER lpTotalNumberOfBytes,
     PULARGE_INTEGER lpTotalNumberOfFreeBytes
@@ -335,6 +305,10 @@ GetDiskFreeSpaceExW(
     HANDLE hFile;
     NTSTATUS errCode;
 
+    /*
+    FIXME: this is obviously wrong for UNC paths, symbolic directories etc.
+    -Gunnar
+    */
     if (lpDirectoryName)
     {
         wcsncpy (RootPathName, lpDirectoryName, 3);
@@ -342,15 +316,15 @@ GetDiskFreeSpaceExW(
     else
     {
         GetCurrentDirectoryW (MAX_PATH, RootPathName);
-        RootPathName[3] = 0;
     }
+    RootPathName[3] = 0;
 
     hFile = InternalOpenDirW(RootPathName, FALSE);
     if (INVALID_HANDLE_VALUE == hFile)
     {
         return FALSE;
     }
-   
+
     errCode = NtQueryVolumeInformationFile(hFile,
                                            &IoStatusBlock,
                                            &FileFsSize,
@@ -370,7 +344,7 @@ GetDiskFreeSpaceExW(
        if (lpFreeBytesAvailableToCaller)
         lpFreeBytesAvailableToCaller->QuadPart =
             BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
-       
+
        if (lpTotalNumberOfBytes)
         lpTotalNumberOfBytes->QuadPart =
             BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
@@ -379,6 +353,7 @@ GetDiskFreeSpaceExW(
             BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
 
     CloseHandle(hFile);
+
     return TRUE;
 }
 
@@ -389,30 +364,12 @@ GetDiskFreeSpaceExW(
 UINT STDCALL
 GetDriveTypeA(LPCSTR lpRootPathName)
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       UINT Result;
-
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-
-       /* convert ansi (or oem) string to unicode */
-       if (bIsFileApiAnsi)
-               RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                             &RootPathName,
-                                             TRUE);
-       else
-               RtlOemStringToUnicodeString (&RootPathNameU,
-                                            &RootPathName,
-                                            TRUE);
+   PWCHAR RootPathNameW;
 
-       Result = GetDriveTypeW (RootPathNameU.Buffer);
+   if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+      return DRIVE_UNKNOWN;
 
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    RootPathNameU.Buffer);
-
-       return Result;
+   return GetDriveTypeW(RootPathNameW);
 }
 
 
@@ -443,17 +400,38 @@ GetDriveTypeW(LPCWSTR lpRootPathName)
        {
                CloseHandle(hFile);
                SetLastErrorByStatus (errCode);
-               return 0;       
+               return 0;
        }
        CloseHandle(hFile);
-       return (UINT)FileFsDevice.DeviceType;
+
+        switch (FileFsDevice.DeviceType)
+        {
+               case FILE_DEVICE_CD_ROM:
+               case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
+                       return DRIVE_CDROM;
+               case FILE_DEVICE_VIRTUAL_DISK:
+                       return DRIVE_RAMDISK;
+               case FILE_DEVICE_NETWORK_FILE_SYSTEM:
+                       return DRIVE_REMOTE;
+               case FILE_DEVICE_DISK:
+               case FILE_DEVICE_DISK_FILE_SYSTEM:
+                       if (FileFsDevice.Characteristics & FILE_REMOTE_DEVICE)
+                               return DRIVE_REMOTE;
+                       if (FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA)
+                               return DRIVE_REMOVABLE;
+                       return DRIVE_FIXED;
+        }
+
+        DPRINT1("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice.DeviceType);
+
+       return DRIVE_UNKNOWN;
 }
 
 
 /*
  * @implemented
  */
-WINBOOL STDCALL
+BOOL STDCALL
 GetVolumeInformationA(
        LPCSTR  lpRootPathName,
        LPSTR   lpVolumeNameBuffer,
@@ -465,34 +443,26 @@ GetVolumeInformationA(
        DWORD   nFileSystemNameSize
        )
 {
-  UNICODE_STRING RootPathNameU;
   UNICODE_STRING FileSystemNameU;
-  UNICODE_STRING VolumeNameU;
-  ANSI_STRING RootPathName;
+  UNICODE_STRING VolumeNameU = {0};
   ANSI_STRING VolumeName;
   ANSI_STRING FileSystemName;
-  WINBOOL Result;
+  PWCHAR RootPathNameW;
+  BOOL Result;
 
-  RtlInitAnsiString (&RootPathName,
-                    (LPSTR)lpRootPathName);
-
-  /* convert ansi (or oem) string to unicode */
-  if (bIsFileApiAnsi)
-    RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                 &RootPathName,
-                                 TRUE);
-  else
-    RtlOemStringToUnicodeString (&RootPathNameU,
-                                &RootPathName,
-                                TRUE);
+  if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+     return FALSE;
 
   if (lpVolumeNameBuffer)
     {
-      VolumeNameU.Length = 0;
       VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
       VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
                                            0,
                                            VolumeNameU.MaximumLength);
+      if (VolumeNameU.Buffer == NULL)
+      {
+          goto FailNoMem;
+      }
     }
 
   if (lpFileSystemNameBuffer)
@@ -502,9 +472,22 @@ GetVolumeInformationA(
       FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
                                                0,
                                                FileSystemNameU.MaximumLength);
+      if (FileSystemNameU.Buffer == NULL)
+      {
+          if (VolumeNameU.Buffer != NULL)
+          {
+              RtlFreeHeap(RtlGetProcessHeap(),
+                          0,
+                          VolumeNameU.Buffer);
+          }
+
+FailNoMem:
+          SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+          return FALSE;
+      }
     }
 
-  Result = GetVolumeInformationW (RootPathNameU.Buffer,
+  Result = GetVolumeInformationW (RootPathNameW,
                                  lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
                                  nVolumeNameSize,
                                  lpVolumeSerialNumber,
@@ -564,9 +547,6 @@ GetVolumeInformationA(
        }
     }
 
-  RtlFreeHeap (RtlGetProcessHeap (),
-              0,
-              RootPathNameU.Buffer);
   if (lpVolumeNameBuffer)
     {
       RtlFreeHeap (RtlGetProcessHeap (),
@@ -590,7 +570,7 @@ GetVolumeInformationA(
 /*
  * @implemented
  */
-WINBOOL STDCALL
+BOOL STDCALL
 GetVolumeInformationW(
     LPCWSTR lpRootPathName,
     LPWSTR lpVolumeNameBuffer,
@@ -610,7 +590,7 @@ GetVolumeInformationW(
 
   HANDLE hFile;
   NTSTATUS errCode;
+
   FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
   FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
 
@@ -620,12 +600,12 @@ GetVolumeInformationW(
   if (!lpRootPathName || !wcscmp(lpRootPathName, L""))
   {
       GetCurrentDirectoryW (MAX_PATH, RootPathName);
-      RootPathName[3] = 0;
   }
   else
   {
-      wcsncpy (RootPathName, lpRootPathName, min(MAX_PATH, wcslen(lpRootPathName)));
+      wcsncpy (RootPathName, lpRootPathName, 3);
   }
+  RootPathName[3] = 0;
 
   hFile = InternalOpenDirW(RootPathName, FALSE);
   if (hFile == INVALID_HANDLE_VALUE)
@@ -639,7 +619,7 @@ GetVolumeInformationW(
                                          FileFsVolume,
                                          FS_VOLUME_BUFFER_SIZE,
                                          FileFsVolumeInformation);
-  if ( !NT_SUCCESS(errCode) ) 
+  if ( !NT_SUCCESS(errCode) )
     {
       DPRINT("Status: %x\n", errCode);
       CloseHandle(hFile);
@@ -654,8 +634,8 @@ GetVolumeInformationW(
     {
       if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
         {
-         memcpy(lpVolumeNameBuffer, 
-                FileFsVolume->VolumeLabel, 
+         memcpy(lpVolumeNameBuffer,
+                FileFsVolume->VolumeLabel,
                 FileFsVolume->VolumeLabelLength);
          lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
        }
@@ -688,8 +668,8 @@ GetVolumeInformationW(
     {
       if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
         {
-         memcpy(lpFileSystemNameBuffer, 
-                FileFsAttribute->FileSystemName, 
+         memcpy(lpFileSystemNameBuffer,
+                FileFsAttribute->FileSystemName,
                 FileFsAttribute->FileSystemNameLength);
          lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
        }
@@ -706,53 +686,35 @@ GetVolumeInformationW(
 /*
  * @implemented
  */
-WINBOOL
+BOOL
 STDCALL
 SetVolumeLabelA (
        LPCSTR  lpRootPathName,
-       LPCSTR  lpVolumeName
+       LPCSTR  lpVolumeName /* NULL if deleting label */
        )
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       UNICODE_STRING VolumeNameU;
-       ANSI_STRING VolumeName;
-       WINBOOL Result;
-
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-       RtlInitAnsiString (&VolumeName,
-                          (LPSTR)lpVolumeName);
-
-       /* convert ansi (or oem) strings to unicode */
-       if (bIsFileApiAnsi)
-       {
-               RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                             &RootPathName,
-                                             TRUE);
-               RtlAnsiStringToUnicodeString (&VolumeNameU,
-                                             &VolumeName,
-                                             TRUE);
-       }
-       else
-       {
-               RtlOemStringToUnicodeString (&RootPathNameU,
-                                            &RootPathName,
-                                            TRUE);
-               RtlOemStringToUnicodeString (&VolumeNameU,
-                                            &VolumeName,
-                                            TRUE);
-       }
+       PWCHAR RootPathNameW;
+   PWCHAR VolumeNameW = NULL;
+       BOOL Result;
+
+   if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+      return FALSE;
+
+   if (lpVolumeName)
+   {
+      if (!(VolumeNameW = FilenameA2W(lpVolumeName, TRUE)))
+         return FALSE;
+   }
 
-       Result = SetVolumeLabelW (RootPathNameU.Buffer,
-                                 VolumeNameU.Buffer);
+   Result = SetVolumeLabelW (RootPathNameW,
+                             VolumeNameW);
 
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    RootPathNameU.Buffer);
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    VolumeNameU.Buffer);
+   if (VolumeNameW)
+   {
+          RtlFreeHeap (RtlGetProcessHeap (),
+                       0,
+                   VolumeNameW );
+   }
 
        return Result;
 }
@@ -761,21 +723,28 @@ SetVolumeLabelA (
 /*
  * @implemented
  */
-WINBOOL STDCALL
-SetVolumeLabelW(LPCWSTR lpRootPathName,
-               LPCWSTR lpVolumeName)
+BOOL STDCALL
+SetVolumeLabelW(
+   LPCWSTR lpRootPathName,
+   LPCWSTR lpVolumeName /* NULL if deleting label */
+   )
 {
    PFILE_FS_LABEL_INFORMATION LabelInfo;
    IO_STATUS_BLOCK IoStatusBlock;
    ULONG LabelLength;
    HANDLE hFile;
    NTSTATUS Status;
-   
+
    LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
    LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
                               0,
                               sizeof(FILE_FS_LABEL_INFORMATION) +
                               LabelLength);
+   if (LabelInfo == NULL)
+   {
+       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       return FALSE;
+   }
    LabelInfo->VolumeLabelLength = LabelLength;
    memcpy(LabelInfo->VolumeLabel,
          lpVolumeName,
@@ -789,7 +758,7 @@ SetVolumeLabelW(LPCWSTR lpRootPathName,
                    LabelInfo);
         return FALSE;
    }
-   
+
    Status = NtSetVolumeInformationFile(hFile,
                                       &IoStatusBlock,
                                       LabelInfo,
@@ -813,4 +782,192 @@ SetVolumeLabelW(LPCWSTR lpRootPathName,
    return TRUE;
 }
 
+/**
+ * @name GetVolumeNameForVolumeMountPointW
+ *
+ * Return an unique volume name for a drive root or mount point.
+ *
+ * @param VolumeMountPoint
+ *        Pointer to string that contains either root drive name or
+ *        mount point name.
+ * @param VolumeName
+ *        Pointer to buffer that is filled with resulting unique
+ *        volume name on success.
+ * @param VolumeNameLength
+ *        Size of VolumeName buffer in TCHARs.
+ *
+ * @return
+ *     TRUE when the function succeeds and the VolumeName buffer is filled,
+ *     FALSE otherwise.
+ */
+
+BOOL WINAPI
+GetVolumeNameForVolumeMountPointW(
+   IN LPCWSTR VolumeMountPoint,
+   OUT LPWSTR VolumeName,
+   IN DWORD VolumeNameLength)
+{
+   UNICODE_STRING NtFileName;
+   OBJECT_ATTRIBUTES ObjectAttributes;
+   HANDLE FileHandle;
+   IO_STATUS_BLOCK Iosb;
+   PVOID Buffer;
+   ULONG BufferLength;
+   PMOUNTDEV_NAME MountDevName;
+   PMOUNTMGR_MOUNT_POINT MountPoint;
+   ULONG MountPointSize;
+   PMOUNTMGR_MOUNT_POINTS MountPoints;
+   ULONG Index;
+   PUCHAR SymbolicLinkName;
+   NTSTATUS Status;
+
+   /*
+    * First step is to convert the passed volume mount point name to
+    * an NT acceptable name.
+    */
+
+   RtlDosPathNameToNtPathName_U(L"e:\\", &NtFileName, NULL, NULL);
+   if (NtFileName.Length > sizeof(WCHAR) &&
+       NtFileName.Buffer[(NtFileName.Length / sizeof(WCHAR)) - 1] == '\\')
+      NtFileName.Length -= sizeof(WCHAR);
+
+   /*
+    * Query mount point device name which we will later use for determining
+    * the volume name.
+    */
+
+   InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
+   Status = NtOpenFile(&FileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE,
+                       &ObjectAttributes, &Iosb,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE,
+                       FILE_SYNCHRONOUS_IO_NONALERT);
+   RtlFreeUnicodeString(&NtFileName);
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastErrorByStatus(Status);
+      return FALSE;
+   }
+
+   BufferLength = sizeof(MOUNTDEV_NAME) + 50 * sizeof(WCHAR);
+   do
+   {
+      MountDevName = Buffer = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
+      Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
+                                     IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
+                                     NULL, 0, Buffer, BufferLength);
+      if (Status == STATUS_BUFFER_OVERFLOW)
+      {
+         BufferLength = sizeof(MOUNTDEV_NAME) + MountDevName->NameLength;
+         continue;
+      }
+      else if (!NT_SUCCESS(Status))
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, Buffer);
+         SetLastErrorByStatus(Status);
+         return FALSE;
+      }
+   }
+   while (!NT_SUCCESS(Status));
+
+   NtClose(FileHandle);
+
+   /*
+    * Get the mount point information from mount manager.
+    */
+
+   MountPointSize = MountDevName->NameLength + sizeof(MOUNTMGR_MOUNT_POINT);
+   MountPoint = RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize);
+   RtlZeroMemory(MountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
+   MountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
+   MountPoint->DeviceNameLength = MountDevName->NameLength;
+   RtlCopyMemory(MountPoint + 1, MountDevName->Name, MountDevName->NameLength);
+   RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
+
+   RtlInitUnicodeString(&NtFileName, L"\\??\\MountPointManager");
+   InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
+   Status = NtOpenFile(&FileHandle, FILE_GENERIC_READ, &ObjectAttributes,
+                       &Iosb, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                       FILE_SYNCHRONOUS_IO_NONALERT);
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastErrorByStatus(Status);
+      RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+      return FALSE;
+   }
+
+   BufferLength = sizeof(MOUNTMGR_MOUNT_POINTS);
+   do
+   {
+      MountPoints = Buffer = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
+      Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
+                                     IOCTL_MOUNTMGR_QUERY_POINTS,
+                                     MountPoint, MountPointSize,
+                                     Buffer, BufferLength);
+      if (Status == STATUS_BUFFER_OVERFLOW)
+      {
+         BufferLength = MountPoints->Size;
+         continue;
+      }
+      else if (!NT_SUCCESS(Status))
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+         RtlFreeHeap(GetProcessHeap(), 0, Buffer);
+         SetLastErrorByStatus(Status);
+         return FALSE;
+      }
+   }
+   while (!NT_SUCCESS(Status));
+
+   RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+   NtClose(FileHandle);
+
+   /*
+    * Now we've gathered info about all mount points mapped to our device, so
+    * select the correct one and copy it into the output buffer.
+    */
+
+   for (Index = 0; Index < MountPoints->NumberOfMountPoints; Index++)
+   {
+      MountPoint = MountPoints->MountPoints + Index;
+      SymbolicLinkName = (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset;
+      
+      /*
+       * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
+       * (with the last slash being optional) style symbolic links.
+       */
+
+      if (MountPoint->SymbolicLinkNameLength == 48 * sizeof(WCHAR) ||
+          (MountPoint->SymbolicLinkNameLength == 49 * sizeof(WCHAR) &&
+           SymbolicLinkName[49] == L'\\'))
+      {
+         if (RtlCompareMemory(SymbolicLinkName, L"\\??\\Volume{",
+                              11 * sizeof(WCHAR)) == 11 * sizeof(WCHAR) &&
+             SymbolicLinkName[19] == L'-' && SymbolicLinkName[24] == L'-' &&
+             SymbolicLinkName[29] == L'-' && SymbolicLinkName[34] == L'-' &&
+             SymbolicLinkName[47] == L'}')
+         {
+            if (VolumeNameLength >= MountPoint->SymbolicLinkNameLength / sizeof(WCHAR))
+            {
+               RtlCopyMemory(VolumeName,
+                             (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset,
+                             MountPoint->SymbolicLinkNameLength);
+               VolumeName[1] = L'\\';
+               RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+               return TRUE;
+            }
+
+            RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+            SetLastError(ERROR_FILENAME_EXCED_RANGE);
+
+            return FALSE;
+         }
+      }
+   }
+
+   RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+   SetLastError(ERROR_INVALID_PARAMETER);
+
+   return FALSE;
+}
+
 /* EOF */