Module: wine Branch: master Commit: c1f161a678e75f12b9378df9fba7a951c39cf242 URL: http://source.winehq.org/git/wine.git/?a=commit;h=c1f161a678e75f12b9378df9fb...
Author: Guy Albertelli galberte@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; }