Guy Albertelli : kernel32: Fix GetVolumeNameForVolumeMountPointW to match Mountmgr.

Alexandre Julliard julliard at winehq.org
Tue May 26 09:24:57 CDT 2009


Module: wine
Branch: master
Commit: c1f161a678e75f12b9378df9fba7a951c39cf242
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=c1f161a678e75f12b9378df9fba7a951c39cf242

Author: Guy Albertelli <galberte at neo.rr.com>
Date:   Sat May 23 23:45:07 2009 -0400

kernel32: Fix GetVolumeNameForVolumeMountPointW to match Mountmgr.

---

 dlls/kernel32/tests/volume.c |   14 ++---
 dlls/kernel32/volume.c       |  126 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 125 insertions(+), 15 deletions(-)

diff --git a/dlls/kernel32/tests/volume.c b/dlls/kernel32/tests/volume.c
index e447e0f..dab59bc 100644
--- a/dlls/kernel32/tests/volume.c
+++ b/dlls/kernel32/tests/volume.c
@@ -129,7 +129,9 @@ static void test_GetVolumeNameForVolumeMountPointA(void)
     ok(reti < MAX_PATH, "temp path should fit into MAX_PATH\n");
 
     ret = pGetVolumeNameForVolumeMountPointA(path, volume, 0);
-    ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
+    ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE,
+        "GetVolumeNameForVolumeMountPointA succeeded or wrong error, last=%d\n",
+        GetLastError());
 
     if (0) { /* these crash on XP */
     ret = pGetVolumeNameForVolumeMountPointA(path, NULL, len);
@@ -147,14 +149,12 @@ static void test_GetVolumeNameForVolumeMountPointA(void)
 
     /* test with too small buffer */
     ret = pGetVolumeNameForVolumeMountPointA(path, volume, 10);
-todo_wine
     ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE,
             "GetVolumeNameForVolumeMountPointA failed, wrong error returned, was %d, should be ERROR_FILENAME_EXCED_RANGE\n",
              GetLastError());
 
     /* Try on a arbitrary directory */
     ret = pGetVolumeNameForVolumeMountPointA(temp_path, volume, len);
-todo_wine
     ok(ret == FALSE && GetLastError() == ERROR_NOT_A_REPARSE_POINT,
         "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
         temp_path, GetLastError());
@@ -169,7 +169,6 @@ todo_wine
     {
         path[2] = '\\';
         ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
-todo_wine
         ok(ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND,
             "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
             path, GetLastError());
@@ -177,7 +176,6 @@ todo_wine
         /* Try without trailing \ and on a non-existent dos drive  */
         path[2] = 0;
         ret = pGetVolumeNameForVolumeMountPointA(path, volume, len);
-todo_wine
         ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME,
             "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n",
             path, GetLastError());
@@ -197,7 +195,9 @@ static void test_GetVolumeNameForVolumeMountPointW(void)
     }
 
     ret = pGetVolumeNameForVolumeMountPointW(path, volume, 0);
-    ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n");
+    ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE,
+        "GetVolumeNameForVolumeMountPointA succeeded or wrong error, last=%d\n",
+        GetLastError());
 
     if (0) { /* these crash on XP */
     ret = pGetVolumeNameForVolumeMountPointW(path, NULL, len);
@@ -387,7 +387,6 @@ static void test_enum_vols(void)
     /* get the unique volume name for the windows drive  */
     ret = pGetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH );
     ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n");
-todo_wine
     ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1);
 
     /* get first unique volume name of list  */
@@ -405,7 +404,6 @@ todo_wine
             break;
         }
     } while (pFindNextVolumeA( hFind, Volume_2, MAX_PATH ));
-todo_wine
     ok(found, "volume name %s not found by Find[First/Next]Volume\n", Volume_1);
     pFindVolumeClose( hFind );
 }
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c
index 1b44ace..0f4161c 100644
--- a/dlls/kernel32/volume.c
+++ b/dlls/kernel32/volume.c
@@ -788,20 +788,132 @@ BOOL WINAPI GetVolumeNameForVolumeMountPointA( LPCSTR path, LPSTR volume, DWORD
  */
 BOOL WINAPI GetVolumeNameForVolumeMountPointW( LPCWSTR path, LPWSTR volume, DWORD size )
 {
+    static const WCHAR prefixW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
+    static const WCHAR volumeW[] = {'\\','?','?','\\','V','o','l','u','m','e','{',0};
+    static const WCHAR trailingW[] = {'\\',0};
+
+    MOUNTMGR_MOUNT_POINT *input = NULL, *o1;
+    MOUNTMGR_MOUNT_POINTS *output = NULL;
+    WCHAR *p;
+    char *r;
+    DWORD i, i_size = 1024, o_size = 1024;
+    WCHAR nonpersist_name[200];
+    WCHAR symlink_name[MAX_PATH];
+    NTSTATUS status;
+    HANDLE mgr = INVALID_HANDLE_VALUE;
     BOOL ret = FALSE;
-    static const WCHAR fmt[] =
-        { '\\','\\','?','\\','V','o','l','u','m','e','{','%','0','2','x','}','\\',0 };
 
     TRACE("(%s, %p, %x)\n", debugstr_w(path), volume, size);
+    if (path[lstrlenW(path)-1] != '\\')
+    {
+        SetLastError( ERROR_INVALID_NAME );
+        return FALSE;
+    }
+
+    if (size < 50)
+    {
+        SetLastError( ERROR_FILENAME_EXCED_RANGE );
+        return FALSE;
+    }
+    /* if length of input is > 3 then it must be a mounted folder */
+    if (lstrlenW(path) > 3)
+    {
+        FIXME("Mounted Folders are not yet supported\n");
+        SetLastError( ERROR_NOT_A_REPARSE_POINT );
+        return FALSE;
+    }
+
+    mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ,
+                        NULL, OPEN_EXISTING, 0, 0 );
+    if (mgr == INVALID_HANDLE_VALUE) return FALSE;
+
+    if (!(input = HeapAlloc( GetProcessHeap(), 0, i_size )))
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        goto err_ret;
+    }
+
+    if (!(output = HeapAlloc( GetProcessHeap(), 0, o_size )))
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        goto err_ret;
+    }
+
+    /* construct the symlink name as "\DosDevices\C:" */
+    lstrcpyW( symlink_name, prefixW );
+    lstrcatW( symlink_name, path );
+    symlink_name[lstrlenW(symlink_name)-1] = 0;
+
+    /* Take the mount point and get the "nonpersistent name" */
+    /* We will then take that and get the volume name        */
+    status = read_nt_symlink( symlink_name, nonpersist_name,
+                                sizeof(nonpersist_name)/sizeof(WCHAR) );
+    TRACE("read_nt_symlink got stat=%x, for %s, got <%s>\n", status,
+            debugstr_w(symlink_name), debugstr_w(nonpersist_name));
+    if (status != STATUS_SUCCESS)
+    {
+        SetLastError( ERROR_FILE_NOT_FOUND );
+        goto err_ret;
+    }
+
+    /* Now take the "nonpersistent name" and ask the mountmgr  */
+    /* to give us all the mount points.  One of them will be   */
+    /* the volume name  (format of \??\Volume{).               */
+    memset( input, 0, sizeof(*input) );  /* clear all input parameters */
+    input->DeviceNameOffset = sizeof(*input);
+    input->DeviceNameLength = lstrlenW( nonpersist_name) * sizeof(WCHAR);
+    memcpy( input + 1, nonpersist_name, input->DeviceNameLength );
+
+    output->Size = o_size;
+
+    /* now get the true volume name from the mountmgr   */
+    if (!DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, input, i_size,
+                        output, o_size, NULL, NULL ))
+        goto err_ret;
 
-    if (!path || !path[0]) return FALSE;
+    /* Verify and return the data, note string is not null terminated  */
+    TRACE("found %d matching mount points\n", output->NumberOfMountPoints);
+    if (output->NumberOfMountPoints < 1)
+    {
+        SetLastError( ERROR_NO_VOLUME_ID );
+        goto err_ret;
+    }
+    o1 = &output->MountPoints[0];
 
-    if (size >= sizeof(fmt) / sizeof(WCHAR))
+    /* look for the volume name in returned values  */
+    for(i=0;i<output->NumberOfMountPoints;i++)
     {
-        /* FIXME: will break when we support volume mounts */
-        sprintfW( volume, fmt, tolowerW( path[0] ) - 'a' );
-        ret = TRUE;
+        p = (WCHAR*)((char *)output + o1->SymbolicLinkNameOffset);
+        r = (char *)output + o1->UniqueIdOffset;
+        TRACE("found symlink=%s, unique=%s, devname=%s\n",
+            debugstr_wn(p, o1->SymbolicLinkNameLength/sizeof(WCHAR)),
+            debugstr_an(r, o1->UniqueIdLength),
+            debugstr_wn((WCHAR*)((char *)output + o1->DeviceNameOffset),
+                            o1->DeviceNameLength/sizeof(WCHAR)));
+
+        if (!strncmpW( p, volumeW, (sizeof(volumeW)-1)/sizeof(WCHAR) ))
+        {
+            /* is there space in the return variable ?? */
+            if ((o1->SymbolicLinkNameLength/sizeof(WCHAR))+2 > size)
+            {
+                SetLastError( ERROR_FILENAME_EXCED_RANGE );
+                goto err_ret;
+            }
+            memcpy( volume, p, o1->SymbolicLinkNameLength );
+            volume[o1->SymbolicLinkNameLength / sizeof(WCHAR)] = 0;
+            lstrcatW( volume, trailingW );
+            /* change second char from '?' to '\'  */
+            volume[1] = '\\';
+            ret = TRUE;
+            break;
+        }
+        o1++;
     }
+
+err_ret:
+    HeapFree( GetProcessHeap(), 0, input );
+    HeapFree( GetProcessHeap(), 0, output );
+    CloseHandle( mgr );
     return ret;
 }
 




More information about the wine-cvs mailing list