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