kernel32: Implement and test GetVolumePathNamesForVolumeName. (try 2)
Hans Leidekker
hans at codeweavers.com
Wed Mar 16 03:22:02 CDT 2011
This version queries the mount manager.
---
dlls/kernel32/tests/volume.c | 169 ++++++++++++++++++++++++++++++++++++++++++
dlls/kernel32/volume.c | 132 +++++++++++++++++++++++++++++++--
2 files changed, 295 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..7ee282d 100644
--- a/dlls/kernel32/volume.c
+++ b/dlls/kernel32/volume.c
@@ -1625,9 +1625,48 @@ 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 int map_dos_device( const WCHAR *device, UINT device_len )
+{
+ int i;
+ DWORD len;
+ WCHAR devices[MAX_PATH], drive[] = {'A',':','\\',0};
+
+ for (i = 0; i < 26; i++)
+ {
+ drive[0] = 'A' + i;
+ len = QueryDosDeviceW( drive, devices, MAX_PATH );
+ if (len >= device_len + 2 && !memicmpW( devices, device, device_len ) && !devices[device_len]) return i;
+ }
+ return -1;
}
/***********************************************************************
@@ -1635,9 +1674,90 @@ BOOL WINAPI GetVolumePathNamesForVolumeNameA(LPCSTR volumename, LPSTR volumepath
*/
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;
+ HANDLE mgr;
+ DWORD len, insize, outsize = 1024;
+ MOUNTMGR_MOUNT_POINT *input;
+ MOUNTMGR_MOUNT_POINTS *output = NULL;
+ WCHAR *name, *path;
+ BOOL ret = FALSE;
+ UINT i;
+
+ 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;
+
+ insize = sizeof(*input) + sizeof(WCHAR) * (len - 1); /* remove trailing backslash */
+ if (!(input = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, insize ))) goto done;
+ input->SymbolicLinkNameOffset = sizeof(*input);
+ input->SymbolicLinkNameLength = insize - sizeof(*input);
+ name = (WCHAR *)((char *)input + input->SymbolicLinkNameOffset);
+ memcpy( name, volumename, insize - sizeof(*input) );
+ name[1] = '?'; /* map \\?\ to \??\ */
+
+ for (;;)
+ {
+ if (!(output = HeapAlloc( GetProcessHeap(), 0, outsize )))
+ {
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto done;
+ }
+ if (!DeviceIoControl( mgr, IOCTL_MOUNTMGR_QUERY_POINTS, input, insize, output, outsize, NULL, NULL ))
+ {
+ if (GetLastError() != ERROR_MORE_DATA) goto done;
+ outsize = output->Size;
+ HeapFree( GetProcessHeap(), 0, output );
+ continue;
+ }
+ break;
+ }
+ if (output->NumberOfMountPoints < 1)
+ {
+ SetLastError( ERROR_FILE_NOT_FOUND );
+ goto done;
+ }
+ len = 0;
+ path = volumepathname;
+ for (i = 0; i < output->NumberOfMountPoints; i++)
+ {
+ if (output->MountPoints[i].DeviceNameOffset)
+ {
+ const WCHAR *device = (const WCHAR *)((const char *)output + output->MountPoints[i].DeviceNameOffset);
+ UINT device_len = output->MountPoints[i].DeviceNameLength / sizeof(WCHAR);
+ int drive = map_dos_device( device, device_len );
+
+ if (drive != -1)
+ {
+ len += 4;
+ if (volumepathname && len < buflen)
+ {
+ path[0] = 'A' + drive;
+ path[1] = ':';
+ path[2] = '\\';
+ path[3] = 0;
+ path += 4;
+ }
+ }
+ }
+ }
+ if (buflen <= len) SetLastError( ERROR_MORE_DATA );
+ else if (volumepathname)
+ {
+ volumepathname[len] = 0;
+ ret = TRUE;
+ }
+ if (returnlen) *returnlen = len + 1;
+
+done:
+ HeapFree( GetProcessHeap(), 0, input );
+ HeapFree( GetProcessHeap(), 0, output );
+ CloseHandle( mgr );
+ return ret;
}
/***********************************************************************
--
1.7.1
More information about the wine-patches
mailing list