1 /* 2 * PROJECT: ReactOS api tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Test for RtlDosPathNameToNtPathName_U 5 * PROGRAMMER: Mike "tamlin" Nordell 6 */ 7 /* TODO: 8 * - Make the code UNICODE aware. If a user is inside a directory with 9 * non-ANSI characters somewhere in the path, all bets are currently off. 10 * - Remove hard-coded path size limits. 11 * - Un-tabify to match style of other code. 12 * - Clean up cruft. Probably remove the option of running it stand-alone. 13 */ 14 15 /* Test to see that ntdll.RtlDosPathNameToNtPathName_U behaves _exactly_ 16 * like Windows with all possible input to it. 17 * - relative path. 18 * - absolute paths 19 * - \\.\C:\foo 20 * - \\.\C:\foo\ 21 * - \\?\C:\foo 22 * - \\?\C:\foo\ 23 * - \??\C: 24 * - \??\C:\ 25 * 26 * Caveat: The "\??\*" form behaves different depending on Windows version. 27 * Some tests will fail if there is no C: volume. 28 * 29 * Code is assumed to be compiled as 32-bit "ANSI" (i.e. with _UNICODE) undefined. 30 */ 31 32 // Enable this define to compile the test as a ReactOS auto-test. 33 // Disable it to compile on plain Win32, to test-run and get info. 34 #define COMPILE_AS_ROSTEST 35 36 #ifndef COMPILE_AS_ROSTEST 37 # define PRINT_INFO // Also print, in addition to testing 38 # include <windows.h> 39 # include <stdio.h> 40 # include <stddef.h> 41 #else /* Compile for ReactOS or wine */ 42 # include <apitest.h> 43 # define WIN32_NO_STATUS 44 # include <stdio.h> 45 # include <ndk/rtlfuncs.h> 46 #endif 47 48 /* 49 BOOLEAN 50 NTAPI 51 RtlDosPathNameToNtPathName_U(IN PCWSTR DosName, 52 OUT PUNICODE_STRING NtName, 53 OUT PCWSTR *PartName, 54 OUT PRTL_RELATIVE_NAME_U RelativeName) 55 */ 56 57 #ifndef COMPILE_AS_ROSTEST 58 59 typedef struct UNICODE_STRING { 60 USHORT Length; 61 USHORT MaximumLength; 62 PWSTR Buffer; 63 } UNICODE_STRING, *PUNICODE_STRING; 64 65 typedef struct _RTLP_CURDIR_REF 66 { 67 LONG RefCount; 68 HANDLE Handle; 69 } RTLP_CURDIR_REF, *PRTLP_CURDIR_REF; 70 71 typedef struct RTL_RELATIVE_NAME_U { 72 UNICODE_STRING RelativeName; 73 HANDLE ContainingDirectory; 74 PRTLP_CURDIR_REF CurDirRef; 75 } RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; 76 77 typedef BOOLEAN (__stdcall *RtlDosPathNameToNtPathName_U_t)(PCWSTR,PUNICODE_STRING,PCWSTR*,PRTL_RELATIVE_NAME_U); 78 79 static RtlDosPathNameToNtPathName_U_t RtlDosPathNameToNtPathName_U; 80 81 #endif // !COMPILE_AS_ROSTEST 82 83 84 static void check_result(BOOLEAN bOK, const char* pszErr) 85 { 86 #ifdef COMPILE_AS_ROSTEST 87 ok(bOK, "%s.\n", pszErr); 88 #else 89 if (!bOK) { 90 printf("\a** %s.\n", pszErr); 91 } 92 #endif 93 } 94 95 96 #ifndef COMPILE_AS_ROSTEST 97 static void prucs(const char* pszDesc, UNICODE_STRING* pucs) 98 { 99 WCHAR wszTmp[512]; 100 memcpy(wszTmp, pucs->Buffer, pucs->Length); 101 wszTmp[pucs->Length/2] = 0; 102 printf("%-12s: \"%S\"\n", pszDesc, wszTmp); 103 } 104 #endif 105 106 // Test RtlDosPathNameToNtPathName_U . 107 // pwszExpected shall contain the expected result for NtName 108 // *without* the leading "\??\". 109 // pwszExpectedPartName shall contain the expected result for PartName. 110 // NULL Expected means result is expected to be NULL too. 111 static void test2(LPCWSTR pwsz, LPCWSTR pwszExpected, LPCWSTR pwszExpectedPartName) 112 { 113 UNICODE_STRING NtName; 114 PWSTR PartName; 115 RTL_RELATIVE_NAME_U RelativeName; 116 BOOLEAN bOK; 117 118 bOK = RtlDosPathNameToNtPathName_U(pwsz, &NtName, (PCWSTR*)&PartName, &RelativeName); 119 120 check_result(bOK, "RtlDosPathNameToNtPathName_U failed"); 121 if (!bOK) { 122 printf("input: \"%S\"\n", pwsz); 123 return; 124 } 125 126 #if !defined(COMPILE_AS_ROSTEST) && defined(PRINT_INFO) 127 printf("--------------------------\n"); 128 printf("in : \"%S\"\n", pwsz); 129 prucs("NtName", &NtName); 130 printf("PartName : \"%S\"\n", PartName ? PartName : L"(null)"); 131 // prucs("RelativeName", &RelativeName.RelativeName); 132 #endif 133 134 // Disregarding input, output (NtName) shall always start with "\??\". 135 bOK = NtName.Length >= 8 && 136 memcmp(NtName.Buffer, L"\\??\\", 8) == 0; 137 check_result(bOK, "NtName does not start with \"\\??\\\""); 138 if (!bOK) { 139 return; 140 } 141 142 if (pwszExpected) { 143 PWSTR pwszActual = NtName.Buffer + 4; 144 const size_t lenExp = wcslen(pwszExpected); 145 const size_t lenAct = (NtName.Length - 8) / 2; 146 bOK = (lenExp == lenAct) && 147 memcmp(pwszActual, pwszExpected, lenExp * 2) == 0; 148 check_result(bOK, "NtName does not match expected"); 149 if (!bOK) 150 { 151 printf("input: : %2u chars \"%S\"\n", wcslen(pwsz), pwsz); 152 printf("Expected: %2u chars \"%S\"\n", lenExp, pwszExpected); 153 printf("Actual : %2u chars \"%S\"\n", lenAct, lenAct ? pwszActual : L"(null)"); 154 return; 155 } 156 } else 157 if (NtName.Length) 158 { 159 PWSTR pwszActual = NtName.Buffer + 4; 160 const size_t lenAct = (NtName.Length - 8) / 2; 161 check_result(FALSE, "Unexpected NtName (expected NULL)"); 162 printf("input: : %2u chars \"%S\"\n", wcslen(pwsz), pwsz); 163 printf("Actual : %2u chars \"%S\"\n", lenAct, pwszActual); 164 } 165 166 if (pwszExpectedPartName) { 167 const size_t lenExp = wcslen(pwszExpectedPartName); 168 const size_t lenAct = PartName ? wcslen(PartName) : 0; 169 bOK = (lenExp == lenAct) && 170 wcscmp(PartName, pwszExpectedPartName) == 0; 171 check_result(bOK, "PartName does not match expected"); 172 if (!bOK) { 173 printf("input: : %2u chars \"%S\"\n", wcslen(pwsz), pwsz); 174 printf("Expected: %2u chars \"%S\"\n", lenExp, pwszExpectedPartName); 175 printf("Actual : %2u chars \"%S\"\n", lenAct, lenAct ? PartName : L"(null)"); 176 return; 177 } 178 } else 179 if (PartName) 180 { 181 check_result(FALSE, "Unexpected PartName (expected NULL)."); 182 printf("input: : %2u chars \"%S\"\n", wcslen(pwsz), pwsz); 183 printf("Actual : %2u chars %S\n", wcslen(PartName), PartName); 184 } 185 } 186 187 // NULL Expected means result is expected to be NULL too. 188 static void test(const char* psz, const char* pszExpected, const char* pszExpectedPartName) 189 { 190 WCHAR wszTmp1[512]; 191 WCHAR wszTmp2[512]; 192 WCHAR wszTmp3[512]; 193 LPCWSTR p2 = 0; 194 LPCWSTR p3 = 0; 195 swprintf(wszTmp1, L"%S", psz); 196 if (pszExpected) { 197 swprintf(wszTmp2, L"%S", pszExpected); 198 p2 = wszTmp2; 199 } 200 if (pszExpectedPartName) { 201 swprintf(wszTmp3, L"%S", pszExpectedPartName); 202 p3 = wszTmp3; 203 } 204 test2(wszTmp1, p2, p3); 205 } 206 207 208 typedef struct DirComponents 209 { 210 char szCD[512]; 211 char szCDPlusSlash[512]; 212 char* pszLastCDComponent; 213 char szCurDrive[4]; 214 char szCurDriveSlash[4]; 215 char szParentDir[512]; 216 char szParentDirPlusSlash[512]; 217 char szNextLastCDComponent[260]; 218 const char* pszNextLastCDComponent; 219 const char* pszPD; // parent dir 220 const char* pszPDPlusSlash; 221 } DirComponents; 222 223 224 static void InitDirComponents(DirComponents* p) 225 { 226 /* While the following code seems to work, it's an unholy mess 227 * and should probably be cleaned up. 228 */ 229 BOOLEAN bOK; 230 231 p->pszNextLastCDComponent = 0; 232 p->pszPD = 0; 233 p->pszPDPlusSlash = 0; 234 235 GetCurrentDirectory(sizeof(p->szCD) / sizeof(*p->szCD), p->szCD); 236 237 bOK = strlen(p->szCD) >= 2 && p->szCD[1] == ':'; 238 check_result(bOK, "Expected curdir to be a drive letter. It's not"); 239 240 if (!bOK) { 241 printf("Curdir is \"%s\"\n", p->szCD); 242 exit(1); 243 } 244 245 bOK = p->szCD[2] == '\\'; 246 check_result(bOK, "CD is missing a slash as its third character"); 247 if (!bOK) { 248 printf("CD is \"%s\"\n", p->szCD); 249 exit(1); 250 } 251 252 // Note that if executed from the root directory, a backslash is 253 // already appended. 254 strcpy(p->szCDPlusSlash, p->szCD); 255 if (strlen(p->szCD) > 3) { 256 // Append trailing backslash 257 strcat(p->szCDPlusSlash, "\\"); 258 } 259 260 memcpy(p->szCurDrive, p->szCD, 2); 261 p->szCurDrive[2] = 0; 262 sprintf(p->szCurDriveSlash, "%s\\", p->szCurDrive); 263 264 p->pszLastCDComponent = strrchr(p->szCD, '\\'); 265 if (p->pszLastCDComponent) 266 { 267 // We have a parent directory 268 memcpy(p->szParentDir, p->szCD, p->pszLastCDComponent - p->szCD); 269 p->szParentDir[p->pszLastCDComponent - p->szCD] = 0; 270 p->pszPD = p->szParentDir; 271 if (strlen(p->szParentDir) == 2 && p->szParentDir[1] == ':') { 272 // When run from root directory, this is expected to 273 // have a trailing backslash 274 strcat(p->szParentDir, "\\"); 275 } 276 strcpy(p->szParentDirPlusSlash, p->szParentDir); 277 if (p->szParentDirPlusSlash[strlen(p->szParentDirPlusSlash)-1] != '\\') { 278 strcat(p->szParentDirPlusSlash, "\\"); 279 } 280 p->pszPDPlusSlash = p->szParentDirPlusSlash; 281 282 // Check if we have a directory above that too. 283 *p->pszLastCDComponent = 0; 284 p->pszNextLastCDComponent = strrchr(p->szCD, '\\'); 285 *p->pszLastCDComponent = '\\'; 286 if (p->pszNextLastCDComponent) { 287 ++p->pszNextLastCDComponent; // skip the leading slash 288 if (p->pszNextLastCDComponent + 1 >= p->pszLastCDComponent) { 289 p->pszNextLastCDComponent = 0; 290 } else { 291 const size_t siz = p->pszLastCDComponent - p->pszNextLastCDComponent; 292 memcpy(p->szNextLastCDComponent, p->pszNextLastCDComponent, siz); 293 p->szNextLastCDComponent[siz] = 0; 294 p->pszNextLastCDComponent = p->szNextLastCDComponent; 295 } 296 } 297 } 298 if (p->pszLastCDComponent && p->pszLastCDComponent[1] == 0) { 299 // If the backslash is the last character in the path, 300 // this is a NULL-component. 301 p->pszLastCDComponent = 0; 302 } else { 303 ++p->pszLastCDComponent; // skip the leading slash 304 } 305 } 306 307 308 #ifndef COMPILE_AS_ROSTEST 309 static void InitFunctionPointer() 310 { 311 HINSTANCE hDll = LoadLibrary("ntdll"); 312 if (!hDll) { 313 printf("Major failure. Couldn't even load ntdll!\n"); 314 exit(1); 315 } 316 RtlDosPathNameToNtPathName_U = 317 (RtlDosPathNameToNtPathName_U_t)GetProcAddress(hDll, "RtlDosPathNameToNtPathName_U"); 318 if (!RtlDosPathNameToNtPathName_U) { 319 printf("Major failure. Couldn't get RtlDosPathNameToNtPathName_U!\n"); 320 exit(1); 321 } 322 } 323 324 # if defined(PRINT_INFO) 325 static DWORD get_win_ver() 326 { 327 # ifdef COMPILE_AS_ROSTEST 328 PPEB Peb = NtCurrentPeb(); 329 const DWORD dwWinVer = (DWORD)(Peb->OSMinorVersion << 8) | Peb->OSMajorVersion; 330 # else 331 const DWORD dwWinVer = GetVersion(); 332 # endif 333 return dwWinVer; 334 } 335 # endif /* PRINT_INFO */ 336 #endif /* !COMPILE_AS_ROSTEST */ 337 338 339 #ifdef COMPILE_AS_ROSTEST 340 START_TEST(RtlDosPathNameToNtPathName_U) 341 #else 342 int main() 343 #endif 344 { 345 #if defined(PRINT_INFO) 346 const DWORD dwWinVer = get_win_ver(); 347 const BYTE WinVerMaj = (BYTE)dwWinVer; 348 const BYTE WinVerMin = HIBYTE(LOWORD(dwWinVer)); 349 #endif // PRINT_INFO 350 351 DirComponents cd; 352 char szTmp[512]; 353 354 #ifndef COMPILE_AS_ROSTEST 355 InitFunctionPointer(); 356 #endif 357 358 InitDirComponents(&cd); 359 360 #if defined(PRINT_INFO) 361 printf("WinVer: %d.%d\n", WinVerMaj, WinVerMin); 362 printf("pszLastCDComponent \"%s\"\n", cd.pszLastCDComponent); 363 printf("pszNextLastCDComponent \"%s\"\n", cd.pszNextLastCDComponent); 364 printf("pszParentDir \"%s\"\n", cd.pszPD); 365 printf("pszParentDirPlusSlash \"%s\"\n", cd.pszPDPlusSlash); 366 #endif 367 368 #define PREP0 /* The normal Win32 namespace. Fully parsed. */ 369 #define PREP1 "\\\\.\\" /* The Win32 Device Namespace. Only partially parsed. */ 370 #define PREP2 "\\\\?\\" /* The Win32 File Namespace. Only partially parsed. */ 371 372 // input name NtName PartName 373 // volume-absolute paths 374 test(PREP1 "C:" , "C:" , "C:"); 375 test(PREP2 "C:" , "C:" , "C:"); 376 test(PREP0 "C:\\" , "C:\\" , NULL); 377 test(PREP1 "C:\\" , "C:\\" , NULL); 378 test(PREP2 "C:\\" , "C:\\" , NULL); 379 test(PREP0 "C:\\foo" , "C:\\foo" , "foo"); 380 test(PREP1 "C:\\foo" , "C:\\foo" , "foo"); 381 test(PREP2 "C:\\foo" , "C:\\foo" , "foo"); 382 test(PREP0 "C:\\foo\\" , "C:\\foo\\" , NULL); 383 test(PREP1 "C:\\foo\\" , "C:\\foo\\" , NULL); 384 test(PREP2 "C:\\foo\\" , "C:\\foo\\" , NULL); 385 test(PREP0 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar"); 386 test(PREP1 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar"); 387 test(PREP2 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar"); 388 test(PREP0 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL); 389 test(PREP1 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL); 390 test(PREP2 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL); 391 test(PREP0 "C:\\foo\\.." , "C:\\" , NULL); 392 test(PREP1 "C:\\foo\\.." , "C:" , "C:"); 393 test(PREP2 "C:\\foo\\.." , "C:\\foo\\.." , ".."); 394 test(PREP0 "C:\\foo\\..\\" , "C:\\" , NULL); 395 test(PREP1 "C:\\foo\\..\\" , "C:\\" , NULL); 396 test(PREP2 "C:\\foo\\..\\" , "C:\\foo\\..\\" , NULL); 397 test(PREP0 "C:\\foo." , "C:\\foo" , "foo"); 398 test(PREP1 "C:\\foo." , "C:\\foo" , "foo"); 399 test(PREP2 "C:\\foo." , "C:\\foo." , "foo."); 400 401 test(PREP0 "C:\\f\\b\\.." , "C:\\f" , "f"); 402 test(PREP1 "C:\\f\\b\\.." , "C:\\f" , "f"); 403 test(PREP2 "C:\\f\\b\\.." , "C:\\f\\b\\.." , ".."); 404 test(PREP0 "C:\\f\\b\\..\\", "C:\\f\\" , NULL); 405 test(PREP1 "C:\\f\\b\\..\\", "C:\\f\\" , NULL); 406 test(PREP2 "C:\\f\\b\\..\\", "C:\\f\\b\\..\\" , NULL); 407 408 // CD-relative paths 409 410 // RtlDosPathNameToNtPathName_U makes no distinction for 411 // special device names, such as "PhysicalDisk0", "HarddiskVolume0" 412 // or "Global??". They all follow the same pattern as a named 413 // filesystem entry, why they implicitly tested by the following 414 // "foo" and "foo\" cases. 415 sprintf(szTmp, "%s%s", cd.szCDPlusSlash, "foo"); 416 test(PREP0 "foo" , szTmp , "foo"); 417 test(PREP1 "foo" , "foo" , "foo"); 418 test(PREP2 "foo" , "foo" , "foo"); 419 420 sprintf(szTmp, "%s%s", cd.szCDPlusSlash , "foo\\"); 421 test(PREP0 "foo\\" , szTmp , NULL); 422 test(PREP1 "foo\\" , "foo\\" , NULL); 423 test(PREP2 "foo\\" , "foo\\" , NULL); 424 425 test(PREP0 "." , cd.szCD , cd.pszLastCDComponent); 426 test(PREP1 "." , "" , NULL); 427 test(PREP2 "." , "." , "."); 428 test(PREP0 ".\\" , cd.szCDPlusSlash , NULL); 429 test(PREP1 ".\\" , "" , NULL); 430 test(PREP2 ".\\" , ".\\" , NULL); 431 test(PREP0 ".\\." , cd.szCD , cd.pszLastCDComponent); 432 test(PREP1 ".\\." , "" , NULL); 433 test(PREP2 ".\\." , ".\\." , "."); 434 test(PREP0 ".\\.." , cd.pszPD , cd.pszNextLastCDComponent); 435 test(PREP1 ".\\.." , "" , NULL); 436 test(PREP2 ".\\.." , ".\\.." , ".."); 437 test(PREP0 ".." , cd.pszPD , cd.pszNextLastCDComponent); 438 test(PREP1 ".." , "" , NULL); 439 test(PREP2 ".." , ".." , ".."); 440 test(PREP0 "..\\" , cd.pszPDPlusSlash , NULL); 441 test(PREP1 "..\\" , "" , NULL); 442 test(PREP2 "..\\" , "..\\" , NULL); 443 // malformed 444 test(PREP0 "..." , cd.szCDPlusSlash , NULL); 445 test(PREP1 "..." , "" , NULL); 446 test(PREP2 "..." , "..." , "..."); 447 448 // Test well-known "special" DOS device names. 449 test(PREP0 "NUL" , "NUL" , NULL); 450 test(PREP1 "NUL" , "NUL" , "NUL"); 451 test(PREP2 "NUL" , "NUL" , "NUL"); 452 test(PREP0 "NUL:" , "NUL" , NULL); 453 test(PREP1 "NUL:" , "NUL:" , "NUL:"); 454 test(PREP2 "NUL:" , "NUL:" , "NUL:"); 455 test(PREP0 "CON" , "CON" , NULL); 456 // NOTE: RtlDosPathNameToNtPathName_U (as currently tested) fails for 457 // the input "\\.\CON" on two widely different Windows versions. 458 // test(PREP1 "CON" , "CON" , "CON"); 459 test(PREP2 "CON" , "CON" , "CON"); 460 test(PREP0 "CON:" , "CON" , NULL); 461 test(PREP1 "CON:" , "CON:" , "CON:"); 462 test(PREP2 "CON:" , "CON:" , "CON:"); 463 464 sprintf(szTmp, "%s\\%s", cd.szCD, "NUL:\\"); 465 test(PREP0 "NUL:\\" , szTmp , NULL); 466 test(PREP1 "NUL:\\" , "NUL:\\" , NULL); 467 test(PREP2 "NUL:\\" , "NUL:\\" , NULL); 468 test(PREP0 "C:NUL" , "NUL" , NULL); 469 test(PREP1 "C:NUL" , "C:NUL" , "C:NUL"); 470 test(PREP2 "C:NUL" , "C:NUL" , "C:NUL"); 471 test(PREP0 "C:\\NUL" , "NUL" , NULL); 472 test(PREP1 "C:\\NUL" , "C:\\NUL" , "NUL"); 473 test(PREP2 "C:\\NUL" , "C:\\NUL" , "NUL"); 474 test(PREP0 "C:\\NUL\\" , "C:\\NUL\\" , NULL); 475 test(PREP1 "C:\\NUL\\" , "C:\\NUL\\" , NULL); 476 test(PREP2 "C:\\NUL\\" , "C:\\NUL\\" , NULL); 477 478 // root-paths 479 test(PREP0 "\\" , cd.szCurDriveSlash, NULL); 480 test(PREP1 "\\" , "" , NULL); 481 test(PREP2 "\\" , "\\" , NULL); 482 483 test(PREP0 "\\." , cd.szCurDriveSlash, NULL); 484 test(PREP1 "\\." , "" , NULL); 485 test(PREP2 "\\." , "\\." , "."); 486 487 test(PREP0 "\\.." , cd.szCurDriveSlash, NULL); 488 test(PREP1 "\\.." , "" , NULL); 489 test(PREP2 "\\.." , "\\.." , ".."); 490 491 test(PREP0 "\\..." , cd.szCurDriveSlash, NULL); 492 test(PREP1 "\\..." , "" , NULL); 493 test(PREP2 "\\..." , "\\..." , "..."); 494 495 // malformed 496 sprintf(szTmp, "%s%s", cd.szCurDrive, "\\C:"); 497 test(PREP0 "\\C:" , szTmp , "C:"); 498 test(PREP1 "\\C:" , "C:" , "C:"); 499 test(PREP2 "\\C:" , "\\C:" , "C:"); 500 501 sprintf(szTmp, "%s%s", cd.szCurDrive, "\\C:\\"); 502 test(PREP0 "\\C:\\" , szTmp , NULL); 503 test(PREP1 "\\C:\\" , "C:\\" , NULL); 504 test(PREP2 "\\C:\\" , "\\C:\\" , NULL); 505 506 // UNC paths 507 test(PREP0 "\\\\" , "UNC\\" , NULL); 508 test(PREP1 "\\\\" , "" , NULL); 509 test(PREP2 "\\\\" , "\\\\" , NULL); 510 test(PREP0 "\\\\\\" , "UNC\\\\" , NULL); 511 test(PREP1 "\\\\\\" , "" , NULL); 512 test(PREP2 "\\\\\\" , "\\\\\\" , NULL); 513 test(PREP0 "\\\\foo" , "UNC\\foo" , NULL); 514 test(PREP1 "\\\\foo" , "foo" , "foo"); 515 test(PREP2 "\\\\foo" , "\\\\foo" , "foo"); 516 517 test(PREP0 "\\\\foo\\.." , "UNC\\foo\\" , NULL); 518 test(PREP1 "\\\\foo\\.." , "" , NULL); 519 test(PREP2 "\\\\foo\\.." , "\\\\foo\\.." , ".."); 520 521 test(PREP0 "\\\\foo\\" , "UNC\\foo\\" , NULL); 522 test(PREP1 "\\\\foo\\" , "foo\\" , NULL); 523 test(PREP2 "\\\\foo\\" , "\\\\foo\\" , NULL); 524 test(PREP0 "\\\\f\\b" , "UNC\\f\\b" , NULL); 525 test(PREP1 "\\\\f\\b" , "f\\b" , "b"); 526 test(PREP2 "\\\\f\\b" , "\\\\f\\b" , "b"); 527 test(PREP0 "\\\\f\\b\\" , "UNC\\f\\b\\" , NULL); 528 test(PREP1 "\\\\f\\b\\" , "f\\b\\" , NULL); 529 test(PREP2 "\\\\f\\b\\" , "\\\\f\\b\\" , NULL); 530 531 test(PREP0 "\\\\f\\b\\.." , "UNC\\f\\b" , NULL); 532 test(PREP1 "\\\\f\\b\\.." , "f" , "f"); 533 test(PREP2 "\\\\f\\b\\.." , "\\\\f\\b\\.." , ".."); 534 535 // strange UNC-paths 536 test(PREP0 "\\\\C:" , "UNC\\C:" , NULL); 537 test(PREP1 "\\\\C:" , "C:" , "C:"); 538 test(PREP2 "\\\\C:" , "\\\\C:" , "C:"); 539 test(PREP0 "\\\\C:\\" , "UNC\\C:\\" , NULL); 540 test(PREP1 "\\\\C:\\" , "C:\\" , NULL); 541 test(PREP2 "\\\\C:\\" , "\\\\C:\\" , NULL); 542 test(PREP0 "\\\\NUL" , "UNC\\NUL" , NULL); 543 test(PREP1 "\\\\NUL" , "NUL" , "NUL"); 544 test(PREP2 "\\\\NUL" , "\\\\NUL" , "NUL"); 545 test(PREP0 "\\\\NUL:" , "UNC\\NUL:" , NULL); 546 test(PREP1 "\\\\NUL:" , "NUL:" , "NUL:"); 547 test(PREP2 "\\\\NUL:" , "\\\\NUL:" , "NUL:"); 548 test(PREP0 "\\\\NUL:\\" , "UNC\\NUL:\\" , NULL); 549 test(PREP1 "\\\\NUL:\\" , "NUL:\\" , NULL); 550 test(PREP2 "\\\\NUL:\\" , "\\\\NUL:\\" , NULL); 551 552 // UNC + forward slashes 553 test(PREP0 "//" , "UNC\\" , NULL); 554 test(PREP1 "//" , "" , NULL); 555 test(PREP2 "//" , "//" , "//"); 556 test(PREP0 "//C:" , "UNC\\C:" , NULL); 557 test(PREP1 "//C:" , "C:" , "C:"); 558 test(PREP2 "//C:" , "//C:" , "//C:"); 559 test(PREP0 "//C:/" , "UNC\\C:\\" , NULL); 560 test(PREP1 "//C:/" , "C:\\" , NULL); 561 test(PREP2 "//C:/" , "//C:/" , "//C:/"); 562 test(PREP0 "//." , "" , NULL); 563 test(PREP1 "//." , "" , NULL); 564 test(PREP2 "//." , "//." , "//."); 565 test(PREP0 "//.." , "UNC\\" , NULL); 566 test(PREP1 "//.." , "" , NULL); 567 test(PREP2 "//.." , "//.." , "//.."); 568 test(PREP0 "/./" , cd.szCurDriveSlash, NULL); 569 test(PREP1 "/./" , "" , NULL); 570 test(PREP2 "/./" , "/./" , "/./"); 571 test(PREP0 "//./" , "" , NULL); 572 test(PREP1 "//./" , "" , NULL); 573 test(PREP2 "//./" , "//./" , "//./"); 574 575 test(cd.szCD , cd.szCD , cd.pszLastCDComponent); 576 test(cd.szCDPlusSlash , cd.szCDPlusSlash , NULL); 577 578 #if 0 579 // The following tests are "problematic", as they return results based on 580 // what your CD on C: is, whether or not you actually run the program 581 // from C:. For that reason, they are currently disabled. 582 test(PREP0 "C:" , "C:\\"+C_curdir , C_curdir); 583 test(PREP0 "C:NUL\\" , "C:\\"+C_curdir+"\\NUL\\" , NULL); 584 #endif 585 586 #if 0 // Disabled due to... see the comment inside the block. 587 { 588 char szExp[32]; 589 BOOL bValid = FALSE; 590 char szPrepend[32]; 591 szPrepend[0] = 0; 592 // Strictly speaking, this "Should Never Happen(tm)", calling 593 // RtlDosPathNameToNtPathName_U with a source already formed as 594 // a full NT name ("\??\"), why it's not the end of the world 595 // that this test is currently disabled. 596 // 597 // Some versions of Windows prepends driveletter + colon 598 // for the process' current volume. 599 // Prepending curdrive is most likely a bug that got fixed in 600 // later versions of Windows, but for compatibility it may 601 // become a requirement to "shim" this. 602 // 603 // Known operating systems prepending "Z:\??\" (assuming the 604 // process' CD is on the volume Z:): 605 // - XP sp2. 606 // 607 // Known operating systems not prepending: 608 // - Win7 64 (as 32-bit) 609 if (WinVerMaj == 5) { 610 sprintf(szPrepend, "%s\\??\\", cd.szCurDrive); 611 } 612 613 sprintf(szExp, "%s%s", szPrepend, "C:"); 614 test("\\??\\C:", szExp, "C:"); 615 616 sprintf(szExp, "%s%s", szPrepend, "C:\\"); 617 test("\\??\\C:\\", szExp, NULL); 618 619 } 620 #endif 621 622 #ifndef COMPILE_AS_ROSTEST 623 return 0; 624 #endif 625 } 626 627