kernel32: Implement and test GetVolumePathNamesForVolumeName. (try 3)

Hans Leidekker hans at codeweavers.com
Tue Mar 29 06:03:42 CDT 2011


This version performs a second query to find DOS device links.
---
 dlls/kernel32/tests/volume.c |  169 ++++++++++++++++++++++++++++++++++++++++++
 dlls/kernel32/volume.c       |  159 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 322 insertions(+), 6 deletions(-)

diff --git a/dlls/kernel32/tests/volume.c b/dlls/kernel32/tests/volume.c
index 15f7e3c..fb920f3 100644
--- a/dlls/kernel32/tests/volume.c
+++ b/dlls/kernel32/tests/volume.c
@@ -32,6 +32,8 @@ static BOOL (WINAPI *pFindVolumeClose)(HANDLE);
 static UINT (WINAPI *pGetLogicalDriveStringsA)(UINT,LPSTR);
 static UINT (WINAPI *pGetLogicalDriveStringsW)(UINT,LPWSTR);
 static BOOL (WINAPI *pGetVolumeInformationA)(LPCSTR, LPSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPSTR, DWORD);
+static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameA)(LPCSTR, LPSTR, DWORD, LPDWORD);
+static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameW)(LPCWSTR, LPWSTR, DWORD, LPDWORD);
 
 /* ############################### */
 
@@ -525,6 +527,169 @@ static void test_disk_extents(void)
     CloseHandle( handle );
 }
 
+static void test_GetVolumePathNamesForVolumeNameA(void)
+{
+    BOOL ret;
+    char volume[MAX_PATH], buffer[MAX_PATH];
+    DWORD len, error;
+
+    if (!pGetVolumePathNamesForVolumeNameA || !pGetVolumeNameForVolumeMountPointA)
+    {
+        win_skip("required functions not found\n");
+        return;
+    }
+
+    ret = pGetVolumeNameForVolumeMountPointA( "c:\\", volume, sizeof(volume) );
+    ok(ret, "failed to get volume name %u\n", GetLastError());
+    trace("c:\\ -> %s\n", volume);
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, 0, NULL );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( "", NULL, 0, NULL );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( volume, NULL, 0, NULL );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error);
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, 0, NULL );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error);
+
+    memset( buffer, 0xff, sizeof(buffer) );
+    ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, sizeof(buffer), NULL );
+    ok(ret, "failed to get path names %u\n", GetLastError());
+    ok(!strcmp( "C:\\", buffer ), "expected \"\\C:\" got \"%s\"\n", buffer);
+    ok(!buffer[4], "expected double null-terminated buffer\n");
+
+    len = 0;
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, 0, &len );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    len = 0;
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, sizeof(buffer), &len );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    len = 0;
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( NULL, buffer, sizeof(buffer), &len );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    len = 0;
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameA( NULL, buffer, sizeof(buffer), &len );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    len = 0;
+    memset( buffer, 0xff, sizeof(buffer) );
+    ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, sizeof(buffer), &len );
+    ok(ret, "failed to get path names %u\n", GetLastError());
+    ok(len == 5 || broken(len == 2), "expected 5 got %u\n", len);
+    ok(!strcmp( "C:\\", buffer ), "expected \"\\C:\" got \"%s\"\n", buffer);
+    ok(!buffer[4], "expected double null-terminated buffer\n");
+}
+
+static void test_GetVolumePathNamesForVolumeNameW(void)
+{
+    static const WCHAR empty[] = {0};
+    static const WCHAR drive_c[] = {'c',':','\\',0};
+    static const WCHAR volume_null[] = {'\\','\\','?','\\','V','o','l','u','m','e',
+        '{','0','0','0','0','0','0','0','0','-','0','0','0','0','-','0','0','0','0',
+        '-','0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0','}','\\',0};
+    BOOL ret;
+    WCHAR volume[MAX_PATH], buffer[MAX_PATH];
+    DWORD len, error;
+
+    if (!pGetVolumePathNamesForVolumeNameW || !pGetVolumeNameForVolumeMountPointW)
+    {
+        win_skip("required functions not found\n");
+        return;
+    }
+
+    ret = pGetVolumeNameForVolumeMountPointW( drive_c, volume, sizeof(volume)/sizeof(volume[0]) );
+    ok(ret, "failed to get volume name %u\n", GetLastError());
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameW( empty, NULL, 0, NULL );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameW( volume, NULL, 0, NULL );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error);
+
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, 0, NULL );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error);
+
+    if (0) { /* crash */
+    ret = pGetVolumePathNamesForVolumeNameW( volume, NULL, sizeof(buffer), NULL );
+    ok(ret, "failed to get path names %u\n", GetLastError());
+    }
+
+    ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), NULL );
+    ok(ret, "failed to get path names %u\n", GetLastError());
+
+    len = 0;
+    memset( buffer, 0xff, sizeof(buffer) );
+    ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len );
+    ok(ret, "failed to get path names %u\n", GetLastError());
+    ok(len == 5, "expected 5 got %u\n", len);
+    ok(!buffer[4], "expected double null-terminated buffer\n");
+
+    len = 0;
+    volume[1] = '?';
+    volume[lstrlenW( volume ) - 1] = 0;
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error);
+
+    len = 0;
+    volume[0] = '\\';
+    volume[1] = 0;
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    todo_wine ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error);
+
+    len = 0;
+    lstrcpyW( volume, volume_null );
+    SetLastError( 0xdeadbeef );
+    ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len );
+    error = GetLastError();
+    ok(!ret, "expected failure\n");
+    ok(error == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND got %u\n", error);
+}
+
 START_TEST(volume)
 {
     hdll = GetModuleHandleA("kernel32.dll");
@@ -536,6 +701,8 @@ START_TEST(volume)
     pGetLogicalDriveStringsA = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsA");
     pGetLogicalDriveStringsW = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsW");
     pGetVolumeInformationA = (void *) GetProcAddress(hdll, "GetVolumeInformationA");
+    pGetVolumePathNamesForVolumeNameA = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameA");
+    pGetVolumePathNamesForVolumeNameW = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameW");
 
     test_query_dos_deviceA();
     test_FindFirstVolume();
@@ -546,4 +713,6 @@ START_TEST(volume)
     test_GetVolumeInformationA();
     test_enum_vols();
     test_disk_extents();
+    test_GetVolumePathNamesForVolumeNameA();
+    test_GetVolumePathNamesForVolumeNameW();
 }
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c
index 1684967..6177781 100644
--- a/dlls/kernel32/volume.c
+++ b/dlls/kernel32/volume.c
@@ -1625,19 +1625,166 @@ BOOL WINAPI GetVolumePathNameW(LPCWSTR filename, LPWSTR volumepathname, DWORD bu
  */
 BOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR volumename, LPSTR volumepathname, DWORD buflen, PDWORD returnlen)
 {
-    FIXME("(%s, %p, %d, %p), stub!\n", debugstr_a(volumename), volumepathname, buflen, returnlen);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    BOOL ret;
+    WCHAR *volumenameW = NULL, *volumepathnameW;
+
+    if (volumename && !(volumenameW = FILE_name_AtoW( volumename, TRUE ))) return FALSE;
+    if (!(volumepathnameW = HeapAlloc( GetProcessHeap(), 0, buflen * sizeof(WCHAR) )))
+    {
+        HeapFree( GetProcessHeap(), 0, volumenameW );
+        return FALSE;
+    }
+    if ((ret = GetVolumePathNamesForVolumeNameW( volumenameW, volumepathnameW, buflen, returnlen )))
+    {
+        char *path = volumepathname;
+        const WCHAR *pathW = volumepathnameW;
+
+        while (*pathW)
+        {
+            int len = strlenW( pathW ) + 1;
+            FILE_name_WtoA( pathW, len, path, buflen );
+            buflen -= len;
+            pathW += len;
+            path += len;
+        }
+        path[0] = 0;
+    }
+    HeapFree( GetProcessHeap(), 0, volumenameW );
+    HeapFree( GetProcessHeap(), 0, volumepathnameW );
+    return ret;
 }
 
+static MOUNTMGR_MOUNT_POINTS *query_mount_points( HANDLE mgr, MOUNTMGR_MOUNT_POINT *input, DWORD insize )
+{
+    MOUNTMGR_MOUNT_POINTS *output;
+    DWORD outsize = 1024;
+
+    for (;;)
+    {
+        if (!(output = HeapAlloc( GetProcessHeap(), 0, outsize )))
+        {
+            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+            return NULL;
+        }
+        if (DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, input, insize, output, outsize, NULL, NULL )) break;
+        outsize = output->Size;
+        HeapFree( GetProcessHeap(), 0, output );
+        if (GetLastError() != ERROR_MORE_DATA) return NULL;
+    }
+    return output;
+}
 /***********************************************************************
  *           GetVolumePathNamesForVolumeNameW   (KERNEL32.@)
  */
 BOOL WINAPI GetVolumePathNamesForVolumeNameW(LPCWSTR volumename, LPWSTR volumepathname, DWORD buflen, PDWORD returnlen)
 {
-    FIXME("(%s, %p, %d, %p), stub!\n", debugstr_w(volumename), volumepathname, buflen, returnlen);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    static const WCHAR dosdevicesW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\'};
+    HANDLE mgr;
+    DWORD len, size;
+    MOUNTMGR_MOUNT_POINT *spec;
+    MOUNTMGR_MOUNT_POINTS *link, *target = NULL;
+    WCHAR *name, *path;
+    BOOL ret = FALSE;
+    UINT i, j;
+
+    TRACE("%s, %p, %u, %p\n", debugstr_w(volumename), volumepathname, buflen, returnlen);
+
+    if (!volumename || (len = strlenW( volumename )) != 49)
+    {
+        SetLastError( ERROR_INVALID_NAME );
+        return FALSE;
+    }
+    mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
+    if (mgr == INVALID_HANDLE_VALUE) return FALSE;
+
+    size = sizeof(*spec) + sizeof(WCHAR) * (len - 1); /* remove trailing backslash */
+    if (!(spec = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto done;
+    spec->SymbolicLinkNameOffset = sizeof(*spec);
+    spec->SymbolicLinkNameLength = size - sizeof(*spec);
+    name = (WCHAR *)((char *)spec + spec->SymbolicLinkNameOffset);
+    memcpy( name, volumename, size - sizeof(*spec) );
+    name[1] = '?'; /* map \\?\ to \??\ */
+
+    target = query_mount_points( mgr, spec, size );
+    HeapFree( GetProcessHeap(), 0, spec );
+    if (!target)
+    {
+        goto done;
+    }
+    if (!target->NumberOfMountPoints)
+    {
+        SetLastError( ERROR_FILE_NOT_FOUND );
+        goto done;
+    }
+    len = 0;
+    path = volumepathname;
+    for (i = 0; i < target->NumberOfMountPoints; i++)
+    {
+        link = NULL;
+        if (target->MountPoints[i].DeviceNameOffset)
+        {
+            const WCHAR *device = (const WCHAR *)((const char *)target + target->MountPoints[i].DeviceNameOffset);
+            USHORT device_len = target->MountPoints[i].DeviceNameLength;
+ 
+            size = sizeof(*spec) + device_len;
+            if (!(spec = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto done;
+            spec->DeviceNameOffset = sizeof(*spec);
+            spec->DeviceNameLength = device_len;
+            memcpy( (char *)spec + spec->DeviceNameOffset, device, device_len );
+
+            link = query_mount_points( mgr, spec, size );
+            HeapFree( GetProcessHeap(), 0, spec );
+        }
+        else if (target->MountPoints[i].UniqueIdOffset)
+        {
+            const WCHAR *id = (const WCHAR *)((const char *)target + target->MountPoints[i].UniqueIdOffset);
+            USHORT id_len = target->MountPoints[i].UniqueIdLength;
+
+            size = sizeof(*spec) + id_len;
+            if (!(spec = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto done;
+            spec->UniqueIdOffset = sizeof(*spec);
+            spec->UniqueIdLength = id_len;
+            memcpy( (char *)spec + spec->UniqueIdOffset, id, id_len );
+
+            link = query_mount_points( mgr, spec, size );
+            HeapFree( GetProcessHeap(), 0, spec );
+        }
+        if (!link) continue;
+        for (j = 0; j < link->NumberOfMountPoints; j++)
+        {
+            const WCHAR *linkname;
+
+            if (!link->MountPoints[j].SymbolicLinkNameOffset) continue;
+            linkname = (const WCHAR *)((const char *)link + link->MountPoints[j].SymbolicLinkNameOffset);
+
+            if (link->MountPoints[j].SymbolicLinkNameLength == sizeof(dosdevicesW) + 2 * sizeof(WCHAR) &&
+                !memicmpW( linkname, dosdevicesW, sizeof(dosdevicesW) / sizeof(WCHAR) ))
+            {
+                len += 4;
+                if (volumepathname && len < buflen)
+                {
+                    path[0] = linkname[sizeof(dosdevicesW) / sizeof(WCHAR)];
+                    path[1] = ':';
+                    path[2] = '\\';
+                    path[3] = 0;
+                    path += 4;
+                }
+            }
+        }
+        HeapFree( GetProcessHeap(), 0, link );
+    }
+    if (buflen <= len) SetLastError( ERROR_MORE_DATA );
+    else if (volumepathname)
+    {
+        volumepathname[len] = 0;
+        ret = TRUE;
+    }
+    if (returnlen) *returnlen = len + 1;
+
+done:
+    HeapFree( GetProcessHeap(), 0, target );
+    CloseHandle( mgr );
+    return ret;
 }
 
 /***********************************************************************
-- 
1.7.1






More information about the wine-patches mailing list