1 /* 2 * Unit test suite for volume functions 3 * 4 * Copyright 2006 Stefan Leichter 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "wine/test.h" 22 #include "winbase.h" 23 #include "winioctl.h" 24 #include <stdio.h> 25 #include "wine/ddk/ntddcdvd.h" 26 27 #include <pshpack1.h> 28 struct COMPLETE_DVD_LAYER_DESCRIPTOR 29 { 30 DVD_DESCRIPTOR_HEADER Header; 31 DVD_LAYER_DESCRIPTOR Descriptor; 32 UCHAR Padding; 33 }; 34 #include <poppack.h> 35 C_ASSERT(sizeof(struct COMPLETE_DVD_LAYER_DESCRIPTOR) == 22); 36 37 #include <pshpack1.h> 38 struct COMPLETE_DVD_MANUFACTURER_DESCRIPTOR 39 { 40 DVD_DESCRIPTOR_HEADER Header; 41 DVD_MANUFACTURER_DESCRIPTOR Descriptor; 42 UCHAR Padding; 43 }; 44 #include <poppack.h> 45 C_ASSERT(sizeof(struct COMPLETE_DVD_MANUFACTURER_DESCRIPTOR) == 2053); 46 47 static HINSTANCE hdll; 48 static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD); 49 static BOOL (WINAPI * pGetVolumeNameForVolumeMountPointW)(LPCWSTR, LPWSTR, DWORD); 50 static HANDLE (WINAPI *pFindFirstVolumeA)(LPSTR,DWORD); 51 static BOOL (WINAPI *pFindNextVolumeA)(HANDLE,LPSTR,DWORD); 52 static BOOL (WINAPI *pFindVolumeClose)(HANDLE); 53 static UINT (WINAPI *pGetLogicalDriveStringsA)(UINT,LPSTR); 54 static UINT (WINAPI *pGetLogicalDriveStringsW)(UINT,LPWSTR); 55 static BOOL (WINAPI *pGetVolumeInformationA)(LPCSTR, LPSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPSTR, DWORD); 56 static BOOL (WINAPI *pGetVolumePathNameA)(LPCSTR, LPSTR, DWORD); 57 static BOOL (WINAPI *pGetVolumePathNameW)(LPWSTR, LPWSTR, DWORD); 58 static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameA)(LPCSTR, LPSTR, DWORD, LPDWORD); 59 static BOOL (WINAPI *pGetVolumePathNamesForVolumeNameW)(LPCWSTR, LPWSTR, DWORD, LPDWORD); 60 61 /* ############################### */ 62 63 static void test_query_dos_deviceA(void) 64 { 65 char drivestr[] = "a:"; 66 char *p, *buffer, buffer2[2000]; 67 DWORD ret, ret2, buflen=32768; 68 BOOL found = FALSE; 69 70 /* callers must guess the buffer size */ 71 SetLastError(0xdeadbeef); 72 ret = QueryDosDeviceA( NULL, NULL, 0 ); 73 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, 74 "QueryDosDeviceA(no buffer): returned %u, le=%u\n", ret, GetLastError()); 75 76 buffer = HeapAlloc( GetProcessHeap(), 0, buflen ); 77 SetLastError(0xdeadbeef); 78 ret = QueryDosDeviceA( NULL, buffer, buflen ); 79 ok((ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER), 80 "QueryDosDeviceA failed to return list, last error %u\n", GetLastError()); 81 82 if (ret && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { 83 p = buffer; 84 for (;;) { 85 if (!strlen(p)) break; 86 ret2 = QueryDosDeviceA( p, buffer2, sizeof(buffer2) ); 87 ok(ret2, "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", p, GetLastError()); 88 p += strlen(p) + 1; 89 if (ret <= (p-buffer)) break; 90 } 91 } 92 93 for (;drivestr[0] <= 'z'; drivestr[0]++) { 94 /* Older W2K fails with ERROR_INSUFFICIENT_BUFFER when buflen is > 32767 */ 95 ret = QueryDosDeviceA( drivestr, buffer, buflen - 1); 96 ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, 97 "QueryDosDeviceA failed to return current mapping for %s, last error %u\n", drivestr, GetLastError()); 98 if(ret) { 99 for (p = buffer; *p; p++) *p = toupper(*p); 100 if (strstr(buffer, "HARDDISK") || strstr(buffer, "RAMDISK")) found = TRUE; 101 } 102 } 103 ok(found, "expected at least one devicename to contain HARDDISK or RAMDISK\n"); 104 HeapFree( GetProcessHeap(), 0, buffer ); 105 } 106 107 static void test_define_dos_deviceA(void) 108 { 109 char drivestr[3]; 110 char buf[MAX_PATH]; 111 DWORD ret; 112 113 /* Find an unused drive letter */ 114 drivestr[1] = ':'; 115 drivestr[2] = 0; 116 for (drivestr[0] = 'a'; drivestr[0] <= 'z'; drivestr[0]++) { 117 ret = QueryDosDeviceA( drivestr, buf, sizeof(buf)); 118 if (!ret) break; 119 } 120 if (drivestr[0] > 'z') { 121 skip("can't test creating a dos drive, none available\n"); 122 return; 123 } 124 125 /* Map it to point to the current directory */ 126 ret = GetCurrentDirectoryA(sizeof(buf), buf); 127 ok(ret, "GetCurrentDir\n"); 128 129 ret = DefineDosDeviceA(0, drivestr, buf); 130 todo_wine 131 ok(ret, "Could not make drive %s point to %s!\n", drivestr, buf); 132 133 if (!ret) { 134 skip("can't test removing fake drive\n"); 135 } else { 136 ret = DefineDosDeviceA(DDD_REMOVE_DEFINITION, drivestr, NULL); 137 ok(ret, "Could not remove fake drive %s!\n", drivestr); 138 } 139 } 140 141 static void test_FindFirstVolume(void) 142 { 143 char volume[51]; 144 HANDLE handle; 145 146 /* not present before w2k */ 147 if (!pFindFirstVolumeA) { 148 win_skip("FindFirstVolumeA not found\n"); 149 return; 150 } 151 152 handle = pFindFirstVolumeA( volume, 0 ); 153 ok( handle == INVALID_HANDLE_VALUE, "succeeded with short buffer\n" ); 154 ok( GetLastError() == ERROR_MORE_DATA || /* XP */ 155 GetLastError() == ERROR_FILENAME_EXCED_RANGE, /* Vista */ 156 "wrong error %u\n", GetLastError() ); 157 handle = pFindFirstVolumeA( volume, 49 ); 158 ok( handle == INVALID_HANDLE_VALUE, "succeeded with short buffer\n" ); 159 ok( GetLastError() == ERROR_FILENAME_EXCED_RANGE, "wrong error %u\n", GetLastError() ); 160 handle = pFindFirstVolumeA( volume, 51 ); 161 ok( handle != INVALID_HANDLE_VALUE, "failed err %u\n", GetLastError() ); 162 if (handle != INVALID_HANDLE_VALUE) 163 { 164 do 165 { 166 ok( strlen(volume) == 49, "bad volume name %s\n", volume ); 167 ok( !memcmp( volume, "\\\\?\\Volume{", 11 ), "bad volume name %s\n", volume ); 168 ok( !memcmp( volume + 47, "}\\", 2 ), "bad volume name %s\n", volume ); 169 } while (pFindNextVolumeA( handle, volume, MAX_PATH )); 170 ok( GetLastError() == ERROR_NO_MORE_FILES, "wrong error %u\n", GetLastError() ); 171 pFindVolumeClose( handle ); 172 } 173 } 174 175 static void test_GetVolumeNameForVolumeMountPointA(void) 176 { 177 BOOL ret; 178 char volume[MAX_PATH], path[] = "c:\\"; 179 DWORD len = sizeof(volume), reti; 180 char temp_path[MAX_PATH]; 181 182 /* not present before w2k */ 183 if (!pGetVolumeNameForVolumeMountPointA) { 184 win_skip("GetVolumeNameForVolumeMountPointA not found\n"); 185 return; 186 } 187 188 reti = GetTempPathA(MAX_PATH, temp_path); 189 ok(reti != 0, "GetTempPathA error %d\n", GetLastError()); 190 ok(reti < MAX_PATH, "temp path should fit into MAX_PATH\n"); 191 192 ret = pGetVolumeNameForVolumeMountPointA(path, volume, 0); 193 ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); 194 ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE || 195 GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */ 196 "wrong error, last=%d\n", GetLastError()); 197 198 if (0) { /* these crash on XP */ 199 ret = pGetVolumeNameForVolumeMountPointA(path, NULL, len); 200 ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); 201 202 ret = pGetVolumeNameForVolumeMountPointA(NULL, volume, len); 203 ok(ret == FALSE, "GetVolumeNameForVolumeMountPointA succeeded\n"); 204 } 205 206 ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); 207 ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); 208 ok(!strncmp( volume, "\\\\?\\Volume{", 11), 209 "GetVolumeNameForVolumeMountPointA failed to return valid string <%s>\n", 210 volume); 211 212 /* test with too small buffer */ 213 ret = pGetVolumeNameForVolumeMountPointA(path, volume, 10); 214 ok(ret == FALSE && GetLastError() == ERROR_FILENAME_EXCED_RANGE, 215 "GetVolumeNameForVolumeMountPointA failed, wrong error returned, was %d, should be ERROR_FILENAME_EXCED_RANGE\n", 216 GetLastError()); 217 218 /* Try on an arbitrary directory */ 219 /* On FAT filesystems it seems that GetLastError() is set to 220 ERROR_INVALID_FUNCTION. */ 221 ret = pGetVolumeNameForVolumeMountPointA(temp_path, volume, len); 222 ok(ret == FALSE && (GetLastError() == ERROR_NOT_A_REPARSE_POINT || 223 GetLastError() == ERROR_INVALID_FUNCTION), 224 "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", 225 temp_path, GetLastError()); 226 227 /* Try on a nonexistent dos drive */ 228 path[2] = 0; 229 for (;path[0] <= 'z'; path[0]++) { 230 ret = QueryDosDeviceA( path, volume, len); 231 if(!ret) break; 232 } 233 if (path[0] <= 'z') 234 { 235 path[2] = '\\'; 236 ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); 237 ok(ret == FALSE && GetLastError() == ERROR_FILE_NOT_FOUND, 238 "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", 239 path, GetLastError()); 240 241 /* Try without trailing \ and on a nonexistent dos drive */ 242 path[2] = 0; 243 ret = pGetVolumeNameForVolumeMountPointA(path, volume, len); 244 ok(ret == FALSE && GetLastError() == ERROR_INVALID_NAME, 245 "GetVolumeNameForVolumeMountPointA failed on %s, last=%d\n", 246 path, GetLastError()); 247 } 248 } 249 250 static void test_GetVolumeNameForVolumeMountPointW(void) 251 { 252 BOOL ret; 253 WCHAR volume[MAX_PATH], path[] = {'c',':','\\',0}; 254 DWORD len = sizeof(volume) / sizeof(WCHAR); 255 256 /* not present before w2k */ 257 if (!pGetVolumeNameForVolumeMountPointW) { 258 win_skip("GetVolumeNameForVolumeMountPointW not found\n"); 259 return; 260 } 261 262 ret = pGetVolumeNameForVolumeMountPointW(path, volume, 0); 263 ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n"); 264 ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE || 265 GetLastError() == ERROR_INVALID_PARAMETER, /* Vista */ 266 "wrong error, last=%d\n", GetLastError()); 267 268 if (0) { /* these crash on XP */ 269 ret = pGetVolumeNameForVolumeMountPointW(path, NULL, len); 270 ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n"); 271 272 ret = pGetVolumeNameForVolumeMountPointW(NULL, volume, len); 273 ok(ret == FALSE, "GetVolumeNameForVolumeMountPointW succeeded\n"); 274 } 275 276 ret = pGetVolumeNameForVolumeMountPointW(path, volume, len); 277 ok(ret == TRUE, "GetVolumeNameForVolumeMountPointW failed\n"); 278 } 279 280 static void test_GetLogicalDriveStringsA(void) 281 { 282 UINT size, size2; 283 char *buf, *ptr; 284 285 ok( pGetLogicalDriveStringsA != NULL, "GetLogicalDriveStringsA not available\n"); 286 if(!pGetLogicalDriveStringsA) { 287 return; 288 } 289 290 size = pGetLogicalDriveStringsA(0, NULL); 291 ok(size%4 == 1, "size = %d\n", size); 292 293 buf = HeapAlloc(GetProcessHeap(), 0, size); 294 295 *buf = 0; 296 size2 = pGetLogicalDriveStringsA(2, buf); 297 ok(size2 == size, "size2 = %d\n", size2); 298 ok(!*buf, "buf changed\n"); 299 300 size2 = pGetLogicalDriveStringsA(size, buf); 301 ok(size2 == size-1, "size2 = %d\n", size2); 302 303 for(ptr = buf; ptr < buf+size2; ptr += 4) { 304 ok(('A' <= *ptr && *ptr <= 'Z'), "device name '%c' is not uppercase\n", *ptr); 305 ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]); 306 ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]); 307 ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]); 308 } 309 ok(!*ptr, "buf[size2] is not nullbyte\n"); 310 311 HeapFree(GetProcessHeap(), 0, buf); 312 } 313 314 static void test_GetLogicalDriveStringsW(void) 315 { 316 UINT size, size2; 317 WCHAR *buf, *ptr; 318 319 ok( pGetLogicalDriveStringsW != NULL, "GetLogicalDriveStringsW not available\n"); 320 if(!pGetLogicalDriveStringsW) { 321 return; 322 } 323 324 SetLastError(0xdeadbeef); 325 size = pGetLogicalDriveStringsW(0, NULL); 326 if (size == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { 327 win_skip("GetLogicalDriveStringsW not implemented\n"); 328 return; 329 } 330 ok(size%4 == 1, "size = %d\n", size); 331 332 buf = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); 333 334 *buf = 0; 335 size2 = pGetLogicalDriveStringsW(2, buf); 336 ok(size2 == size, "size2 = %d\n", size2); 337 ok(!*buf, "buf changed\n"); 338 339 size2 = pGetLogicalDriveStringsW(size, buf); 340 ok(size2 == size-1, "size2 = %d\n", size2); 341 342 for(ptr = buf; ptr < buf+size2; ptr += 4) { 343 ok('A' <= *ptr && *ptr <= 'Z', "device name '%c' is not uppercase\n", *ptr); 344 ok(ptr[1] == ':', "ptr[1] = %c, expected ':'\n", ptr[1]); 345 ok(ptr[2] == '\\', "ptr[2] = %c expected '\\'\n", ptr[2]); 346 ok(!ptr[3], "ptr[3] = %c expected nullbyte\n", ptr[3]); 347 } 348 ok(!*ptr, "buf[size2] is not nullbyte\n"); 349 350 HeapFree(GetProcessHeap(), 0, buf); 351 } 352 353 static void test_GetVolumeInformationA(void) 354 { 355 BOOL ret; 356 UINT result; 357 char Root_Colon[]="C:"; 358 char Root_Slash[]="C:\\"; 359 char Root_UNC[]="\\\\?\\C:\\"; 360 char volume[MAX_PATH+1]; 361 DWORD vol_name_size=MAX_PATH+1, vol_serial_num=-1, max_comp_len=0, fs_flags=0, fs_name_len=MAX_PATH+1; 362 char vol_name_buf[MAX_PATH+1], fs_name_buf[MAX_PATH+1]; 363 char windowsdir[MAX_PATH+10]; 364 char currentdir[MAX_PATH+1]; 365 366 ok( pGetVolumeInformationA != NULL, "GetVolumeInformationA not found\n"); 367 if(!pGetVolumeInformationA) { 368 return; 369 } 370 371 /* get windows drive letter and update strings for testing */ 372 result = GetWindowsDirectoryA(windowsdir, sizeof(windowsdir)); 373 ok(result < sizeof(windowsdir), "windowsdir is abnormally long!\n"); 374 ok(result != 0, "GetWindowsDirectory: error %d\n", GetLastError()); 375 Root_Colon[0] = windowsdir[0]; 376 Root_Slash[0] = windowsdir[0]; 377 Root_UNC[4] = windowsdir[0]; 378 379 result = GetCurrentDirectoryA(MAX_PATH, currentdir); 380 ok(result, "GetCurrentDirectory: error %d\n", GetLastError()); 381 /* Note that GetCurrentDir yields no trailing slash for subdirs */ 382 383 /* check for NO error on no trailing \ when current dir is root dir */ 384 ret = SetCurrentDirectoryA(Root_Slash); 385 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 386 ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, 387 NULL, NULL, fs_name_buf, fs_name_len); 388 ok(ret, "GetVolumeInformationA root failed, last error %u\n", GetLastError()); 389 390 /* check for error on no trailing \ when current dir is subdir (windows) of queried drive */ 391 ret = SetCurrentDirectoryA(windowsdir); 392 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 393 SetLastError(0xdeadbeef); 394 ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, 395 NULL, NULL, fs_name_buf, fs_name_len); 396 ok(!ret && (GetLastError() == ERROR_INVALID_NAME), 397 "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError()); 398 399 /* reset current directory */ 400 ret = SetCurrentDirectoryA(currentdir); 401 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 402 403 if (toupper(currentdir[0]) == toupper(windowsdir[0])) { 404 skip("Please re-run from another device than %c:\n", windowsdir[0]); 405 /* FIXME: Use GetLogicalDrives to find another device to avoid this skip. */ 406 } else { 407 char Root_Env[]="=C:"; /* where MS maintains the per volume directory */ 408 Root_Env[1] = windowsdir[0]; 409 410 /* C:\windows becomes the current directory on drive C: */ 411 /* Note that paths to subdirs are stored without trailing slash, like what GetCurrentDir yields. */ 412 ret = SetEnvironmentVariableA(Root_Env, windowsdir); 413 ok(ret, "SetEnvironmentVariable %s failed\n", Root_Env); 414 415 ret = SetCurrentDirectoryA(windowsdir); 416 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 417 ret = SetCurrentDirectoryA(currentdir); 418 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 419 420 /* windows dir is current on the root drive, call fails */ 421 SetLastError(0xdeadbeef); 422 ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, 423 NULL, NULL, fs_name_buf, fs_name_len); 424 ok(!ret && (GetLastError() == ERROR_INVALID_NAME), 425 "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError()); 426 427 /* Try normal drive letter with trailing \ */ 428 ret = pGetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size, NULL, 429 NULL, NULL, fs_name_buf, fs_name_len); 430 ok(ret, "GetVolumeInformationA with \\ failed, last error %u\n", GetLastError()); 431 432 ret = SetCurrentDirectoryA(Root_Slash); 433 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 434 ret = SetCurrentDirectoryA(currentdir); 435 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 436 437 /* windows dir is STILL CURRENT on root drive; the call fails as before, */ 438 /* proving that SetCurrentDir did not remember the other drive's directory */ 439 SetLastError(0xdeadbeef); 440 ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, 441 NULL, NULL, fs_name_buf, fs_name_len); 442 ok(!ret && (GetLastError() == ERROR_INVALID_NAME), 443 "GetVolumeInformationA did%s fail, last error %u\n", ret ? " not":"", GetLastError()); 444 445 /* Now C:\ becomes the current directory on drive C: */ 446 ret = SetEnvironmentVariableA(Root_Env, Root_Slash); /* set =C:=C:\ */ 447 ok(ret, "SetEnvironmentVariable %s failed\n", Root_Env); 448 449 /* \ is current on root drive, call succeeds */ 450 ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, 451 NULL, NULL, fs_name_buf, fs_name_len); 452 ok(ret, "GetVolumeInformationA failed, last error %u\n", GetLastError()); 453 454 /* again, SetCurrentDirectory on another drive does not matter */ 455 ret = SetCurrentDirectoryA(Root_Slash); 456 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 457 ret = SetCurrentDirectoryA(currentdir); 458 ok(ret, "SetCurrentDirectory: error %d\n", GetLastError()); 459 460 /* \ is current on root drive, call succeeds */ 461 ret = pGetVolumeInformationA(Root_Colon, vol_name_buf, vol_name_size, NULL, 462 NULL, NULL, fs_name_buf, fs_name_len); 463 ok(ret, "GetVolumeInformationA failed, last error %u\n", GetLastError()); 464 } 465 466 /* try null root directory to return "root of the current directory" */ 467 ret = pGetVolumeInformationA(NULL, vol_name_buf, vol_name_size, NULL, 468 NULL, NULL, fs_name_buf, fs_name_len); 469 ok(ret, "GetVolumeInformationA failed on null root dir, last error %u\n", GetLastError()); 470 471 /* Try normal drive letter with trailing \ */ 472 ret = pGetVolumeInformationA(Root_Slash, vol_name_buf, vol_name_size, 473 &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); 474 ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", Root_Slash, GetLastError()); 475 476 /* try again with drive letter and the "disable parsing" prefix */ 477 SetLastError(0xdeadbeef); 478 ret = pGetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size, 479 &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); 480 ok(ret, "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", Root_UNC, GetLastError()); 481 482 /* try again with device name space */ 483 Root_UNC[2] = '.'; 484 SetLastError(0xdeadbeef); 485 ret = pGetVolumeInformationA(Root_UNC, vol_name_buf, vol_name_size, 486 &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); 487 ok(ret, "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", Root_UNC, GetLastError()); 488 489 /* try again with a directory off the root - should generate error */ 490 if (windowsdir[strlen(windowsdir)-1] != '\\') strcat(windowsdir, "\\"); 491 SetLastError(0xdeadbeef); 492 ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size, 493 &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); 494 ok(!ret && (GetLastError()==ERROR_DIR_NOT_ROOT), 495 "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", windowsdir, GetLastError()); 496 /* A subdir with trailing \ yields DIR_NOT_ROOT instead of INVALID_NAME */ 497 if (windowsdir[strlen(windowsdir)-1] == '\\') windowsdir[strlen(windowsdir)-1] = 0; 498 SetLastError(0xdeadbeef); 499 ret = pGetVolumeInformationA(windowsdir, vol_name_buf, vol_name_size, 500 &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); 501 ok(!ret && (GetLastError()==ERROR_INVALID_NAME), 502 "GetVolumeInformationA did%s fail, root=%s, last error=%u\n", ret ? " not":"", windowsdir, GetLastError()); 503 504 if (!pGetVolumeNameForVolumeMountPointA) { 505 win_skip("GetVolumeNameForVolumeMountPointA not found\n"); 506 return; 507 } 508 /* get the unique volume name for the windows drive */ 509 ret = pGetVolumeNameForVolumeMountPointA(Root_Slash, volume, MAX_PATH); 510 ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); 511 512 /* try again with unique volume name */ 513 ret = pGetVolumeInformationA(volume, vol_name_buf, vol_name_size, 514 &vol_serial_num, &max_comp_len, &fs_flags, fs_name_buf, fs_name_len); 515 ok(ret, "GetVolumeInformationA failed, root=%s, last error=%u\n", volume, GetLastError()); 516 } 517 518 /* Test to check that unique volume name from windows dir mount point */ 519 /* matches at least one of the unique volume names returned from the */ 520 /* FindFirstVolumeA/FindNextVolumeA list. */ 521 static void test_enum_vols(void) 522 { 523 DWORD ret; 524 HANDLE hFind = INVALID_HANDLE_VALUE; 525 char Volume_1[MAX_PATH] = {0}; 526 char Volume_2[MAX_PATH] = {0}; 527 char path[] = "c:\\"; 528 BOOL found = FALSE; 529 char windowsdir[MAX_PATH]; 530 531 if (!pGetVolumeNameForVolumeMountPointA) { 532 win_skip("GetVolumeNameForVolumeMountPointA not found\n"); 533 return; 534 } 535 536 /*get windows drive letter and update strings for testing */ 537 ret = GetWindowsDirectoryA( windowsdir, sizeof(windowsdir) ); 538 ok(ret < sizeof(windowsdir), "windowsdir is abnormally long!\n"); 539 ok(ret != 0, "GetWindowsDirectory: error %d\n", GetLastError()); 540 path[0] = windowsdir[0]; 541 542 /* get the unique volume name for the windows drive */ 543 ret = pGetVolumeNameForVolumeMountPointA( path, Volume_1, MAX_PATH ); 544 ok(ret == TRUE, "GetVolumeNameForVolumeMountPointA failed\n"); 545 ok(strlen(Volume_1) == 49, "GetVolumeNameForVolumeMountPointA returned wrong length name %s\n", Volume_1); 546 547 /* get first unique volume name of list */ 548 hFind = pFindFirstVolumeA( Volume_2, MAX_PATH ); 549 ok(hFind != INVALID_HANDLE_VALUE, "FindFirstVolume failed, err=%u\n", 550 GetLastError()); 551 /* ReactOS */ 552 if (hFind != INVALID_HANDLE_VALUE) { 553 do 554 { 555 /* validate correct length of unique volume name */ 556 ok(strlen(Volume_2) == 49, "Find[First/Next]Volume returned wrong length name %s\n", Volume_1); 557 if (memcmp(Volume_1, Volume_2, 49) == 0) 558 { 559 found = TRUE; 560 break; 561 } 562 } while (pFindNextVolumeA( hFind, Volume_2, MAX_PATH )); 563 ok(found, "volume name %s not found by Find[First/Next]Volume\n", Volume_1); 564 pFindVolumeClose( hFind ); 565 } 566 } 567 568 static void test_disk_extents(void) 569 { 570 BOOL ret; 571 DWORD size; 572 HANDLE handle; 573 static DWORD data[16]; 574 575 handle = CreateFileA( "\\\\.\\c:", GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); 576 if (handle == INVALID_HANDLE_VALUE) 577 { 578 win_skip("can't open c: drive %u\n", GetLastError()); 579 return; 580 } 581 size = 0; 582 ret = DeviceIoControl( handle, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, &data, 583 sizeof(data), &data, sizeof(data), &size, NULL ); 584 if (!ret && GetLastError() == ERROR_INVALID_FUNCTION) 585 { 586 win_skip("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS not supported\n"); 587 CloseHandle( handle ); 588 return; 589 } 590 ok(ret, "DeviceIoControl failed %u\n", GetLastError()); 591 ok(size == 32, "expected 32, got %u\n", size); 592 CloseHandle( handle ); 593 } 594 595 static void test_GetVolumePathNameA(void) 596 { 597 char volume_path[MAX_PATH], cwd[MAX_PATH]; 598 struct { 599 const char *file_name; 600 const char *path_name; 601 DWORD path_len; 602 DWORD error; 603 DWORD broken_error; 604 } test_paths[] = { 605 { /* test 0: NULL parameters, 0 output length */ 606 NULL, NULL, 0, 607 ERROR_INVALID_PARAMETER, 0xdeadbeef /* winxp */ 608 }, 609 { /* test 1: empty input, NULL output, 0 output length */ 610 "", NULL, 0, 611 ERROR_INVALID_PARAMETER, 0xdeadbeef /* winxp */ 612 }, 613 { /* test 2: valid input, NULL output, 0 output length */ 614 "C:\\", NULL, 0, 615 ERROR_INVALID_PARAMETER, ERROR_FILENAME_EXCED_RANGE /* winxp */ 616 }, 617 { /* test 3: valid input, valid output, 0 output length */ 618 "C:\\", "C:\\", 0, 619 ERROR_INVALID_PARAMETER, ERROR_FILENAME_EXCED_RANGE /* winxp */ 620 }, 621 { /* test 4: valid input, valid output, 1 output length */ 622 "C:\\", "C:\\", 1, 623 ERROR_FILENAME_EXCED_RANGE, NO_ERROR 624 }, 625 { /* test 5: valid input, valid output, valid output length */ 626 "C:\\", "C:\\", sizeof(volume_path), 627 NO_ERROR, NO_ERROR 628 }, 629 { /* test 6: lowercase input, uppercase output, valid output length */ 630 "c:\\", "C:\\", sizeof(volume_path), 631 NO_ERROR, NO_ERROR 632 }, 633 { /* test 7: poor quality input, valid output, valid output length */ 634 "C::", "C:\\", sizeof(volume_path), 635 NO_ERROR, NO_ERROR 636 }, 637 { /* test 8: really bogus input, valid output, 1 output length */ 638 "\\\\$$$", "C:\\", 1, 639 ERROR_INVALID_NAME, ERROR_FILENAME_EXCED_RANGE 640 }, 641 { /* test 9: a reasonable DOS path that is guaranteed to exist */ 642 "C:\\windows\\system32", "C:\\", sizeof(volume_path), 643 NO_ERROR, NO_ERROR 644 }, 645 { /* test 10: a reasonable DOS path that shouldn't exist */ 646 "C:\\windows\\system32\\AnInvalidFolder", "C:\\", sizeof(volume_path), 647 NO_ERROR, NO_ERROR 648 }, 649 { /* test 11: a reasonable NT-converted DOS path that shouldn't exist */ 650 "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:\\", sizeof(volume_path), 651 NO_ERROR, NO_ERROR 652 }, 653 { /* test 12: an unreasonable NT-converted DOS path */ 654 "\\\\?\\InvalidDrive:\\AnInvalidFolder", "\\\\?\\InvalidDrive:\\" /* win2k, winxp */, 655 sizeof(volume_path), 656 ERROR_INVALID_NAME, NO_ERROR 657 }, 658 { /* test 13: an unreasonable NT volume path */ 659 "\\\\?\\Volume{00000000-00-0000-0000-000000000000}\\AnInvalidFolder", 660 "\\\\?\\Volume{00000000-00-0000-0000-000000000000}\\" /* win2k, winxp */, 661 sizeof(volume_path), 662 ERROR_INVALID_NAME, NO_ERROR 663 }, 664 { /* test 14: an unreasonable NT-ish path */ 665 "\\\\ReallyBogus\\InvalidDrive:\\AnInvalidFolder", 666 "\\\\ReallyBogus\\InvalidDrive:\\" /* win2k, winxp */, sizeof(volume_path), 667 ERROR_INVALID_NAME, NO_ERROR 668 }, 669 { /* test 15: poor quality input, valid output, valid (but short) output length */ 670 "C::", "C:\\", 4, 671 NO_ERROR, ERROR_MORE_DATA 672 }, 673 { /* test 16: unused drive letter */ 674 "M::", "C:\\", 4, 675 ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA 676 }, 677 { /* test 17: an unreasonable DOS path */ 678 "InvalidDrive:\\AnInvalidFolder", "%CurrentDrive%\\", sizeof(volume_path), 679 NO_ERROR, NO_ERROR 680 }, 681 { /* test 18: a reasonable device path */ 682 "\\??\\CdRom0", "%CurrentDrive%\\", sizeof(volume_path), 683 NO_ERROR, NO_ERROR 684 }, 685 { /* test 19: an unreasonable device path */ 686 "\\??\\ReallyBogus", "%CurrentDrive%\\", sizeof(volume_path), 687 NO_ERROR, NO_ERROR 688 }, 689 { /* test 20 */ 690 "C:", "C:", 2, 691 ERROR_FILENAME_EXCED_RANGE, NO_ERROR 692 }, 693 { /* test 21 */ 694 "C:", "C:", 3, 695 NO_ERROR, ERROR_FILENAME_EXCED_RANGE 696 }, 697 { /* test 22 */ 698 "C:\\", "C:", 2, 699 ERROR_FILENAME_EXCED_RANGE, NO_ERROR 700 }, 701 { /* test 23 */ 702 "C:\\", "C:", 3, 703 NO_ERROR, ERROR_FILENAME_EXCED_RANGE 704 }, 705 { /* test 24 */ 706 "C::", "C:", 2, 707 ERROR_FILENAME_EXCED_RANGE, NO_ERROR 708 }, 709 { /* test 25 */ 710 "C::", "C:", 3, 711 NO_ERROR, ERROR_FILENAME_EXCED_RANGE 712 }, 713 { /* test 26 */ 714 "C::", "C:\\", 4, 715 NO_ERROR, ERROR_MORE_DATA 716 }, 717 { /* test 27 */ 718 "C:\\windows\\system32\\AnInvalidFolder", "C:", 3, 719 NO_ERROR, ERROR_FILENAME_EXCED_RANGE 720 }, 721 { /* test 28 */ 722 "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:", 3, 723 ERROR_FILENAME_EXCED_RANGE, NO_ERROR 724 }, 725 { /* test 29 */ 726 "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:", 6, 727 ERROR_FILENAME_EXCED_RANGE, NO_ERROR 728 }, 729 { /* test 30 */ 730 "\\\\?\\C:\\AnInvalidFolder", "\\\\?\\C:", 7, 731 NO_ERROR, ERROR_FILENAME_EXCED_RANGE 732 }, 733 { /* test 31 */ 734 "\\\\?\\c:\\AnInvalidFolder", "\\\\?\\c:", 7, 735 NO_ERROR, ERROR_FILENAME_EXCED_RANGE 736 }, 737 { /* test 32 */ 738 "C:/", "C:\\", 4, 739 NO_ERROR, ERROR_MORE_DATA 740 }, 741 { /* test 33 */ 742 "M:/", "", 4, 743 ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA 744 }, 745 { /* test 34 */ 746 "C:ABC:DEF:\\AnInvalidFolder", "C:\\", 4, 747 NO_ERROR, ERROR_MORE_DATA 748 }, 749 { /* test 35 */ 750 "?:ABC:DEF:\\AnInvalidFolder", "?:\\" /* win2k, winxp */, sizeof(volume_path), 751 ERROR_FILE_NOT_FOUND, NO_ERROR 752 }, 753 { /* test 36 */ 754 "relative/path", "%CurrentDrive%\\", sizeof(volume_path), 755 NO_ERROR, NO_ERROR 756 }, 757 { /* test 37 */ 758 "/unix-style/absolute/path", "%CurrentDrive%\\", sizeof(volume_path), 759 NO_ERROR, NO_ERROR 760 }, 761 { /* test 38 */ 762 "\\??\\C:\\NonExistent", "%CurrentDrive%\\", sizeof(volume_path), 763 NO_ERROR, NO_ERROR 764 }, 765 { /* test 39 */ 766 "\\??\\M:\\NonExistent", "%CurrentDrive%\\", sizeof(volume_path), 767 NO_ERROR, NO_ERROR 768 }, 769 { /* test 40 */ 770 "somefile:def", "%CurrentDrive%\\", sizeof(volume_path), 771 NO_ERROR, NO_ERROR 772 }, 773 { /* test 41 */ 774 "s:omefile", "S:\\" /* win2k, winxp */, sizeof(volume_path), 775 ERROR_FILE_NOT_FOUND, NO_ERROR 776 }, 777 }; 778 BOOL ret, success; 779 DWORD error; 780 UINT i; 781 782 /* GetVolumePathNameA is not present before w2k */ 783 if (!pGetVolumePathNameA) 784 { 785 win_skip("required functions not found\n"); 786 return; 787 } 788 789 /* Obtain the drive of the working directory */ 790 ret = GetCurrentDirectoryA( sizeof(cwd), cwd ); 791 ok( ret, "Failed to obtain the current working directory.\n" ); 792 cwd[2] = 0; 793 ret = SetEnvironmentVariableA( "CurrentDrive", cwd ); 794 ok( ret, "Failed to set an environment variable for the current working drive.\n" ); 795 796 for (i=0; i<sizeof(test_paths)/sizeof(test_paths[0]); i++) 797 { 798 BOOL broken_ret = test_paths[i].broken_error == NO_ERROR; 799 char *output = (test_paths[i].path_name != NULL ? volume_path : NULL); 800 BOOL expected_ret = test_paths[i].error == NO_ERROR; 801 802 volume_path[0] = 0; 803 if (test_paths[i].path_len < sizeof(volume_path)) 804 volume_path[ test_paths[i].path_len ] = 0x11; 805 806 SetLastError( 0xdeadbeef ); 807 ret = pGetVolumePathNameA( test_paths[i].file_name, output, test_paths[i].path_len ); 808 error = GetLastError(); 809 ok(ret == expected_ret || broken(ret == broken_ret), 810 "GetVolumePathName test %d %s unexpectedly.\n", 811 i, test_paths[i].error == NO_ERROR ? "failed" : "succeeded"); 812 813 if (ret) 814 { 815 char path_name[MAX_PATH]; 816 817 ExpandEnvironmentStringsA( test_paths[i].path_name, path_name, MAX_PATH); 818 /* If we succeeded then make sure the path is correct */ 819 success = (strcmp( volume_path, path_name ) == 0) 820 || broken(strcasecmp( volume_path, path_name ) == 0) /* XP */; 821 ok(success, "GetVolumePathName test %d unexpectedly returned path %s (expected %s).\n", 822 i, volume_path, path_name); 823 } 824 else 825 { 826 /* On success Windows always returns ERROR_MORE_DATA, so only worry about failure */ 827 success = (error == test_paths[i].error || broken(error == test_paths[i].broken_error)); 828 ok(success, "GetVolumePathName test %d unexpectedly returned error 0x%x (expected 0x%x).\n", 829 i, error, test_paths[i].error); 830 } 831 832 if (test_paths[i].path_len < sizeof(volume_path)) 833 ok(volume_path[ test_paths[i].path_len ] == 0x11, 834 "GetVolumePathName test %d corrupted byte after end of buffer.\n", i); 835 } 836 } 837 838 static void test_GetVolumePathNameW(void) 839 { 840 static WCHAR drive_c1[] = {'C',':',0}; 841 static WCHAR drive_c2[] = {'C',':','\\',0}; 842 WCHAR volume_path[MAX_PATH]; 843 BOOL ret; 844 845 if (!pGetVolumePathNameW) 846 { 847 win_skip("required functions not found\n"); 848 return; 849 } 850 851 volume_path[0] = 0; 852 volume_path[1] = 0x11; 853 ret = pGetVolumePathNameW( drive_c1, volume_path, 1 ); 854 ok(!ret, "GetVolumePathNameW test succeeded unexpectedly.\n"); 855 ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE, "GetVolumePathNameW unexpectedly returned error 0x%x (expected 0x%x).\n", 856 GetLastError(), ERROR_FILENAME_EXCED_RANGE); 857 ok(volume_path[1] == 0x11, "GetVolumePathW corrupted byte after end of buffer.\n"); 858 859 volume_path[0] = 0; 860 volume_path[2] = 0x11; 861 ret = pGetVolumePathNameW( drive_c1, volume_path, 2 ); 862 ok(!ret, "GetVolumePathNameW test succeeded unexpectedly.\n"); 863 ok(GetLastError() == ERROR_FILENAME_EXCED_RANGE, "GetVolumePathNameW unexpectedly returned error 0x%x (expected 0x%x).\n", 864 GetLastError(), ERROR_FILENAME_EXCED_RANGE); 865 ok(volume_path[2] == 0x11, "GetVolumePathW corrupted byte after end of buffer.\n"); 866 867 volume_path[0] = 0; 868 volume_path[3] = 0x11; 869 ret = pGetVolumePathNameW( drive_c1, volume_path, 3 ); 870 ok(ret || broken(!ret) /* win2k */, "GetVolumePathNameW test failed unexpectedly.\n"); 871 ok(memcmp(volume_path, drive_c1, sizeof(drive_c1)) == 0 872 || broken(volume_path[0] == 0) /* win2k */, 873 "GetVolumePathNameW unexpectedly returned wrong path.\n"); 874 ok(volume_path[3] == 0x11, "GetVolumePathW corrupted byte after end of buffer.\n"); 875 876 volume_path[0] = 0; 877 volume_path[4] = 0x11; 878 ret = pGetVolumePathNameW( drive_c1, volume_path, 4 ); 879 ok(ret, "GetVolumePathNameW test failed unexpectedly.\n"); 880 ok(memcmp(volume_path, drive_c2, sizeof(drive_c2)) == 0, "GetVolumePathNameW unexpectedly returned wrong path.\n"); 881 ok(volume_path[4] == 0x11, "GetVolumePathW corrupted byte after end of buffer.\n"); 882 } 883 884 static void test_GetVolumePathNamesForVolumeNameA(void) 885 { 886 BOOL ret; 887 char volume[MAX_PATH], buffer[MAX_PATH]; 888 DWORD len, error; 889 890 if (!pGetVolumePathNamesForVolumeNameA || !pGetVolumeNameForVolumeMountPointA) 891 { 892 win_skip("required functions not found\n"); 893 return; 894 } 895 896 ret = pGetVolumeNameForVolumeMountPointA( "c:\\", volume, sizeof(volume) ); 897 ok(ret, "failed to get volume name %u\n", GetLastError()); 898 trace("c:\\ -> %s\n", volume); 899 900 SetLastError( 0xdeadbeef ); 901 ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, 0, NULL ); 902 error = GetLastError(); 903 ok(!ret, "expected failure\n"); 904 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 905 906 SetLastError( 0xdeadbeef ); 907 ret = pGetVolumePathNamesForVolumeNameA( "", NULL, 0, NULL ); 908 error = GetLastError(); 909 ok(!ret, "expected failure\n"); 910 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 911 912 SetLastError( 0xdeadbeef ); 913 ret = pGetVolumePathNamesForVolumeNameA( volume, NULL, 0, NULL ); 914 error = GetLastError(); 915 ok(!ret, "expected failure\n"); 916 ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); 917 918 SetLastError( 0xdeadbeef ); 919 ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, 0, NULL ); 920 error = GetLastError(); 921 ok(!ret, "expected failure\n"); 922 ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); 923 924 memset( buffer, 0xff, sizeof(buffer) ); 925 ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, sizeof(buffer), NULL ); 926 ok(ret, "failed to get path names %u\n", GetLastError()); 927 ok(!strcmp( "C:\\", buffer ), "expected \"\\C:\" got \"%s\"\n", buffer); 928 ok(!buffer[4], "expected double null-terminated buffer\n"); 929 930 len = 0; 931 SetLastError( 0xdeadbeef ); 932 ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, 0, &len ); 933 error = GetLastError(); 934 ok(!ret, "expected failure\n"); 935 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 936 937 len = 0; 938 SetLastError( 0xdeadbeef ); 939 ret = pGetVolumePathNamesForVolumeNameA( NULL, NULL, sizeof(buffer), &len ); 940 error = GetLastError(); 941 ok(!ret, "expected failure\n"); 942 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 943 944 len = 0; 945 SetLastError( 0xdeadbeef ); 946 ret = pGetVolumePathNamesForVolumeNameA( NULL, buffer, sizeof(buffer), &len ); 947 error = GetLastError(); 948 ok(!ret, "expected failure\n"); 949 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 950 951 len = 0; 952 SetLastError( 0xdeadbeef ); 953 ret = pGetVolumePathNamesForVolumeNameA( NULL, buffer, sizeof(buffer), &len ); 954 error = GetLastError(); 955 ok(!ret, "expected failure\n"); 956 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 957 958 len = 0; 959 memset( buffer, 0xff, sizeof(buffer) ); 960 ret = pGetVolumePathNamesForVolumeNameA( volume, buffer, sizeof(buffer), &len ); 961 ok(ret, "failed to get path names %u\n", GetLastError()); 962 ok(len == 5 || broken(len == 2), "expected 5 got %u\n", len); 963 ok(!strcmp( "C:\\", buffer ), "expected \"\\C:\" got \"%s\"\n", buffer); 964 ok(!buffer[4], "expected double null-terminated buffer\n"); 965 } 966 967 static void test_GetVolumePathNamesForVolumeNameW(void) 968 { 969 static const WCHAR empty[] = {0}; 970 static const WCHAR drive_c[] = {'c',':','\\',0}; 971 static const WCHAR volume_null[] = {'\\','\\','?','\\','V','o','l','u','m','e', 972 '{','0','0','0','0','0','0','0','0','-','0','0','0','0','-','0','0','0','0', 973 '-','0','0','0','0','-','0','0','0','0','0','0','0','0','0','0','0','0','}','\\',0}; 974 BOOL ret; 975 WCHAR volume[MAX_PATH], buffer[MAX_PATH]; 976 DWORD len, error; 977 978 #ifdef __REACTOS__ 979 /* due to failing all calls to GetVolumeNameForVolumeMountPointW, this 980 * buffer never gets initialized and could cause a buffer overflow later */ 981 volume[0] = '$'; 982 volume[1] = 0; 983 #endif /* __REACTOS__ */ 984 985 if (!pGetVolumePathNamesForVolumeNameW || !pGetVolumeNameForVolumeMountPointW) 986 { 987 win_skip("required functions not found\n"); 988 return; 989 } 990 991 ret = pGetVolumeNameForVolumeMountPointW( drive_c, volume, sizeof(volume)/sizeof(volume[0]) ); 992 ok(ret, "failed to get volume name %u\n", GetLastError()); 993 994 SetLastError( 0xdeadbeef ); 995 ret = pGetVolumePathNamesForVolumeNameW( empty, NULL, 0, NULL ); 996 error = GetLastError(); 997 ok(!ret, "expected failure\n"); 998 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 999 1000 SetLastError( 0xdeadbeef ); 1001 ret = pGetVolumePathNamesForVolumeNameW( volume, NULL, 0, NULL ); 1002 error = GetLastError(); 1003 ok(!ret, "expected failure\n"); 1004 ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); 1005 1006 SetLastError( 0xdeadbeef ); 1007 ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, 0, NULL ); 1008 error = GetLastError(); 1009 ok(!ret, "expected failure\n"); 1010 ok(error == ERROR_MORE_DATA, "expected ERROR_MORE_DATA got %u\n", error); 1011 1012 if (0) { /* crash */ 1013 ret = pGetVolumePathNamesForVolumeNameW( volume, NULL, sizeof(buffer), NULL ); 1014 ok(ret, "failed to get path names %u\n", GetLastError()); 1015 } 1016 1017 ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), NULL ); 1018 ok(ret, "failed to get path names %u\n", GetLastError()); 1019 1020 len = 0; 1021 memset( buffer, 0xff, sizeof(buffer) ); 1022 ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); 1023 ok(ret, "failed to get path names %u\n", GetLastError()); 1024 ok(len == 5, "expected 5 got %u\n", len); 1025 ok(!buffer[4], "expected double null-terminated buffer\n"); 1026 1027 len = 0; 1028 volume[1] = '?'; 1029 volume[lstrlenW( volume ) - 1] = 0; 1030 SetLastError( 0xdeadbeef ); 1031 ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); 1032 error = GetLastError(); 1033 ok(!ret, "expected failure\n"); 1034 ok(error == ERROR_INVALID_NAME, "expected ERROR_INVALID_NAME got %u\n", error); 1035 1036 len = 0; 1037 volume[0] = '\\'; 1038 volume[1] = 0; 1039 SetLastError( 0xdeadbeef ); 1040 ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); 1041 error = GetLastError(); 1042 ok(!ret, "expected failure\n"); 1043 todo_wine ok(error == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got %u\n", error); 1044 1045 len = 0; 1046 lstrcpyW( volume, volume_null ); 1047 SetLastError( 0xdeadbeef ); 1048 ret = pGetVolumePathNamesForVolumeNameW( volume, buffer, sizeof(buffer), &len ); 1049 error = GetLastError(); 1050 ok(!ret, "expected failure\n"); 1051 ok(error == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND got %u\n", error); 1052 } 1053 1054 static void test_dvd_read_structure(HANDLE handle) 1055 { 1056 int i; 1057 DWORD nbBytes; 1058 BOOL ret; 1059 DVD_READ_STRUCTURE dvdReadStructure; 1060 DVD_LAYER_DESCRIPTOR dvdLayerDescriptor; 1061 struct COMPLETE_DVD_LAYER_DESCRIPTOR completeDvdLayerDescriptor; 1062 DVD_COPYRIGHT_DESCRIPTOR dvdCopyrightDescriptor; 1063 struct COMPLETE_DVD_MANUFACTURER_DESCRIPTOR completeDvdManufacturerDescriptor; 1064 1065 dvdReadStructure.BlockByteOffset.QuadPart = 0; 1066 dvdReadStructure.SessionId = 0; 1067 dvdReadStructure.LayerNumber = 0; 1068 1069 1070 /* DvdPhysicalDescriptor */ 1071 dvdReadStructure.Format = 0; 1072 1073 SetLastError(0xdeadbeef); 1074 1075 /* Test whether this ioctl is supported */ 1076 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), 1077 &completeDvdLayerDescriptor, sizeof(struct COMPLETE_DVD_LAYER_DESCRIPTOR), &nbBytes, NULL); 1078 1079 if(!ret) 1080 { 1081 skip("IOCTL_DVD_READ_STRUCTURE not supported: %u\n", GetLastError()); 1082 return; 1083 } 1084 1085 /* Confirm there is always a header before the actual data */ 1086 ok( completeDvdLayerDescriptor.Header.Length == 0x0802, "Length is 0x%04x instead of 0x0802\n", completeDvdLayerDescriptor.Header.Length); 1087 ok( completeDvdLayerDescriptor.Header.Reserved[0] == 0, "Reserved[0] is %x instead of 0\n", completeDvdLayerDescriptor.Header.Reserved[0]); 1088 ok( completeDvdLayerDescriptor.Header.Reserved[1] == 0, "Reserved[1] is %x instead of 0\n", completeDvdLayerDescriptor.Header.Reserved[1]); 1089 1090 /* TODO: Also check completeDvdLayerDescriptor.Descriptor content (via IOCTL_SCSI_PASS_THROUGH_DIRECT ?) */ 1091 1092 /* Insufficient output buffer */ 1093 for(i=0; i<sizeof(DVD_DESCRIPTOR_HEADER); i++) 1094 { 1095 SetLastError(0xdeadbeef); 1096 1097 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), 1098 &completeDvdLayerDescriptor, i, &nbBytes, NULL); 1099 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,"IOCTL_DVD_READ_STRUCTURE should fail with small buffer\n"); 1100 } 1101 1102 SetLastError(0xdeadbeef); 1103 1104 /* On newer version, an output buffer of sizeof(DVD_READ_STRUCTURE) size fails. 1105 I think this is to force developers to realize that there is a header before the actual content */ 1106 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), 1107 &dvdLayerDescriptor, sizeof(DVD_LAYER_DESCRIPTOR), &nbBytes, NULL); 1108 ok( (!ret && GetLastError() == ERROR_INVALID_PARAMETER) || broken(ret) /* < Win7 */, 1109 "IOCTL_DVD_READ_STRUCTURE should have failed\n"); 1110 1111 SetLastError(0xdeadbeef); 1112 1113 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, NULL, sizeof(DVD_READ_STRUCTURE), 1114 &completeDvdLayerDescriptor, sizeof(struct COMPLETE_DVD_LAYER_DESCRIPTOR), &nbBytes, NULL); 1115 ok( (!ret && GetLastError() == ERROR_INVALID_PARAMETER), 1116 "IOCTL_DVD_READ_STRUCTURE should have failed\n"); 1117 1118 /* Test wrong input parameters */ 1119 for(i=0; i<sizeof(DVD_READ_STRUCTURE); i++) 1120 { 1121 SetLastError(0xdeadbeef); 1122 1123 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, i, 1124 &completeDvdLayerDescriptor, sizeof(struct COMPLETE_DVD_LAYER_DESCRIPTOR), &nbBytes, NULL); 1125 ok( (!ret && GetLastError() == ERROR_INVALID_PARAMETER), 1126 "IOCTL_DVD_READ_STRUCTURE should have failed\n"); 1127 } 1128 1129 1130 /* DvdCopyrightDescriptor */ 1131 dvdReadStructure.Format = 1; 1132 1133 SetLastError(0xdeadbeef); 1134 1135 /* Strangely, with NULL lpOutBuffer, last error is insufficient buffer, not invalid parameter as we could expect */ 1136 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), 1137 NULL, sizeof(DVD_COPYRIGHT_DESCRIPTOR), &nbBytes, NULL); 1138 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "IOCTL_DVD_READ_STRUCTURE should have failed %d %u\n", ret, GetLastError()); 1139 1140 for(i=0; i<sizeof(DVD_COPYRIGHT_DESCRIPTOR); i++) 1141 { 1142 SetLastError(0xdeadbeef); 1143 1144 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), 1145 &dvdCopyrightDescriptor, i, &nbBytes, NULL); 1146 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "IOCTL_DVD_READ_STRUCTURE should have failed %d %u\n", ret, GetLastError()); 1147 } 1148 1149 1150 /* DvdManufacturerDescriptor */ 1151 dvdReadStructure.Format = 4; 1152 1153 SetLastError(0xdeadbeef); 1154 1155 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), 1156 &completeDvdManufacturerDescriptor, sizeof(DVD_MANUFACTURER_DESCRIPTOR), &nbBytes, NULL); 1157 ok(ret || broken(GetLastError() == ERROR_NOT_READY), 1158 "IOCTL_DVD_READ_STRUCTURE (DvdManufacturerDescriptor) failed, last error = %u\n", GetLastError()); 1159 if(!ret) 1160 return; 1161 1162 /* Confirm there is always a header before the actual data */ 1163 ok( completeDvdManufacturerDescriptor.Header.Length == 0x0802, "Length is 0x%04x instead of 0x0802\n", completeDvdManufacturerDescriptor.Header.Length); 1164 ok( completeDvdManufacturerDescriptor.Header.Reserved[0] == 0, "Reserved[0] is %x instead of 0\n", completeDvdManufacturerDescriptor.Header.Reserved[0]); 1165 ok( completeDvdManufacturerDescriptor.Header.Reserved[1] == 0, "Reserved[1] is %x instead of 0\n", completeDvdManufacturerDescriptor.Header.Reserved[1]); 1166 1167 SetLastError(0xdeadbeef); 1168 1169 /* Basic parameter check */ 1170 ret = DeviceIoControl(handle, IOCTL_DVD_READ_STRUCTURE, &dvdReadStructure, sizeof(DVD_READ_STRUCTURE), 1171 NULL, sizeof(DVD_MANUFACTURER_DESCRIPTOR), &nbBytes, NULL); 1172 ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "IOCTL_DVD_READ_STRUCTURE should have failed %d %u\n", ret, GetLastError()); 1173 } 1174 1175 static void test_cdrom_ioctl(void) 1176 { 1177 char drive_letter, drive_path[] = "A:\\", drive_full_path[] = "\\\\.\\A:"; 1178 DWORD bitmask; 1179 HANDLE handle; 1180 1181 bitmask = GetLogicalDrives(); 1182 if(!bitmask) 1183 { 1184 trace("GetLogicalDrives failed : %u\n", GetLastError()); 1185 return; 1186 } 1187 1188 for(drive_letter='A'; drive_letter<='Z'; drive_letter++) 1189 { 1190 if(!(bitmask & (1 << (drive_letter-'A') ))) 1191 continue; 1192 1193 drive_path[0] = drive_letter; 1194 if(GetDriveTypeA(drive_path) != DRIVE_CDROM) 1195 { 1196 trace("Skipping %c:, not a CDROM drive.\n", drive_letter); 1197 continue; 1198 } 1199 1200 trace("Testing with %c:\n", drive_letter); 1201 1202 drive_full_path[4] = drive_letter; 1203 handle = CreateFileA(drive_full_path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); 1204 if(handle == INVALID_HANDLE_VALUE) 1205 { 1206 trace("Failed to open the device : %u\n", GetLastError()); 1207 continue; 1208 } 1209 1210 /* Add your tests here */ 1211 test_dvd_read_structure(handle); 1212 1213 CloseHandle(handle); 1214 } 1215 1216 } 1217 1218 START_TEST(volume) 1219 { 1220 hdll = GetModuleHandleA("kernel32.dll"); 1221 pGetVolumeNameForVolumeMountPointA = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointA"); 1222 pGetVolumeNameForVolumeMountPointW = (void *) GetProcAddress(hdll, "GetVolumeNameForVolumeMountPointW"); 1223 pFindFirstVolumeA = (void *) GetProcAddress(hdll, "FindFirstVolumeA"); 1224 pFindNextVolumeA = (void *) GetProcAddress(hdll, "FindNextVolumeA"); 1225 pFindVolumeClose = (void *) GetProcAddress(hdll, "FindVolumeClose"); 1226 pGetLogicalDriveStringsA = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsA"); 1227 pGetLogicalDriveStringsW = (void *) GetProcAddress(hdll, "GetLogicalDriveStringsW"); 1228 pGetVolumeInformationA = (void *) GetProcAddress(hdll, "GetVolumeInformationA"); 1229 pGetVolumePathNameA = (void *) GetProcAddress(hdll, "GetVolumePathNameA"); 1230 pGetVolumePathNameW = (void *) GetProcAddress(hdll, "GetVolumePathNameW"); 1231 pGetVolumePathNamesForVolumeNameA = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameA"); 1232 pGetVolumePathNamesForVolumeNameW = (void *) GetProcAddress(hdll, "GetVolumePathNamesForVolumeNameW"); 1233 1234 test_query_dos_deviceA(); 1235 test_define_dos_deviceA(); 1236 test_FindFirstVolume(); 1237 test_GetVolumePathNameA(); 1238 test_GetVolumePathNameW(); 1239 test_GetVolumeNameForVolumeMountPointA(); 1240 test_GetVolumeNameForVolumeMountPointW(); 1241 test_GetLogicalDriveStringsA(); 1242 test_GetLogicalDriveStringsW(); 1243 test_GetVolumeInformationA(); 1244 test_enum_vols(); 1245 test_disk_extents(); 1246 test_GetVolumePathNamesForVolumeNameA(); 1247 test_GetVolumePathNamesForVolumeNameW(); 1248 test_cdrom_ioctl(); 1249 } 1250