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: : %2Iu chars \"%S\"\n", wcslen(pwsz), pwsz); 149 printf("Expected: %2Iu chars \"%S\"\n", lenExp, pwszExpected); 150 printf("Actual : %2Iu 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: : %2Iu chars \"%S\"\n", wcslen(pwsz), pwsz); 160 printf("Actual : %2Iu 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: : %2Iu chars \"%S\"\n", wcslen(pwsz), pwsz); 171 printf("Expected: %2Iu chars \"%S\"\n", lenExp, pwszExpectedPartName); 172 printf("Actual : %2Iu 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: : %2Iu chars \"%S\"\n", wcslen(pwsz), pwsz); 180 printf("Actual : %2Iu 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[3]; 211 char reserved1; 212 char szCurDriveSlash[4]; 213 char szParentDir[512]; 214 char szParentDirPlusSlash[512]; 215 char szNextLastCDComponent[260]; 216 const char* pszNextLastCDComponent; 217 const char* pszPD; // parent dir 218 const char* pszPDPlusSlash; 219 } DirComponents; 220 221 222 static void InitDirComponents(DirComponents* p) 223 { 224 /* While the following code seems to work, it's an unholy mess 225 * and should probably be cleaned up. 226 */ 227 BOOLEAN bOK; 228 229 p->pszNextLastCDComponent = 0; 230 p->pszPD = 0; 231 p->pszPDPlusSlash = 0; 232 233 GetCurrentDirectory(sizeof(p->szCD) / sizeof(*p->szCD), p->szCD); 234 235 bOK = strlen(p->szCD) >= 2 && p->szCD[1] == ':'; 236 check_result(bOK, "Expected curdir to be a drive letter. It's not"); 237 238 if (!bOK) { 239 printf("Curdir is \"%s\"\n", p->szCD); 240 exit(1); 241 } 242 243 bOK = p->szCD[2] == '\\'; 244 check_result(bOK, "CD is missing a slash as its third character"); 245 if (!bOK) { 246 printf("CD is \"%s\"\n", p->szCD); 247 exit(1); 248 } 249 250 // Note that if executed from the root directory, a backslash is 251 // already appended. 252 strcpy(p->szCDPlusSlash, p->szCD); 253 if (strlen(p->szCD) > 3) { 254 // Append trailing backslash 255 strcat(p->szCDPlusSlash, "\\"); 256 } 257 258 memcpy(p->szCurDrive, p->szCD, 2); 259 p->szCurDrive[2] = 0; 260 sprintf(p->szCurDriveSlash, "%s\\", p->szCurDrive); 261 262 p->pszLastCDComponent = strrchr(p->szCD, '\\'); 263 if (p->pszLastCDComponent) 264 { 265 // We have a parent directory 266 memcpy(p->szParentDir, p->szCD, p->pszLastCDComponent - p->szCD); 267 p->szParentDir[p->pszLastCDComponent - p->szCD] = 0; 268 p->pszPD = p->szParentDir; 269 if (strlen(p->szParentDir) == 2 && p->szParentDir[1] == ':') { 270 // When run from root directory, this is expected to 271 // have a trailing backslash 272 strcat(p->szParentDir, "\\"); 273 } 274 strcpy(p->szParentDirPlusSlash, p->szParentDir); 275 if (p->szParentDirPlusSlash[strlen(p->szParentDirPlusSlash)-1] != '\\') { 276 strcat(p->szParentDirPlusSlash, "\\"); 277 } 278 p->pszPDPlusSlash = p->szParentDirPlusSlash; 279 280 // Check if we have a directory above that too. 281 *p->pszLastCDComponent = 0; 282 p->pszNextLastCDComponent = strrchr(p->szCD, '\\'); 283 *p->pszLastCDComponent = '\\'; 284 if (p->pszNextLastCDComponent) { 285 ++p->pszNextLastCDComponent; // skip the leading slash 286 if (p->pszNextLastCDComponent + 1 >= p->pszLastCDComponent) { 287 p->pszNextLastCDComponent = 0; 288 } else { 289 const size_t siz = p->pszLastCDComponent - p->pszNextLastCDComponent; 290 memcpy(p->szNextLastCDComponent, p->pszNextLastCDComponent, siz); 291 p->szNextLastCDComponent[siz] = 0; 292 p->pszNextLastCDComponent = p->szNextLastCDComponent; 293 } 294 } 295 } 296 if (p->pszLastCDComponent && p->pszLastCDComponent[1] == 0) { 297 // If the backslash is the last character in the path, 298 // this is a NULL-component. 299 p->pszLastCDComponent = 0; 300 } else { 301 ++p->pszLastCDComponent; // skip the leading slash 302 } 303 } 304 305 306 #ifndef COMPILE_AS_ROSTEST 307 static void InitFunctionPointer() 308 { 309 HINSTANCE hDll = LoadLibrary("ntdll"); 310 if (!hDll) { 311 printf("Major failure. Couldn't even load ntdll!\n"); 312 exit(1); 313 } 314 RtlDosPathNameToNtPathName_U = 315 (RtlDosPathNameToNtPathName_U_t)GetProcAddress(hDll, "RtlDosPathNameToNtPathName_U"); 316 if (!RtlDosPathNameToNtPathName_U) { 317 printf("Major failure. Couldn't get RtlDosPathNameToNtPathName_U!\n"); 318 exit(1); 319 } 320 } 321 322 # if defined(PRINT_INFO) 323 static DWORD get_win_ver() 324 { 325 # ifdef COMPILE_AS_ROSTEST 326 PPEB Peb = NtCurrentPeb(); 327 const DWORD dwWinVer = (DWORD)(Peb->OSMinorVersion << 8) | Peb->OSMajorVersion; 328 # else 329 const DWORD dwWinVer = GetVersion(); 330 # endif 331 return dwWinVer; 332 } 333 # endif /* PRINT_INFO */ 334 #endif /* !COMPILE_AS_ROSTEST */ 335 336 337 #ifdef COMPILE_AS_ROSTEST 338 START_TEST(RtlDosPathNameToNtPathName_U) 339 #else 340 int main() 341 #endif 342 { 343 #if defined(PRINT_INFO) 344 const DWORD dwWinVer = get_win_ver(); 345 const BYTE WinVerMaj = (BYTE)dwWinVer; 346 const BYTE WinVerMin = HIBYTE(LOWORD(dwWinVer)); 347 #endif // PRINT_INFO 348 349 DirComponents cd; 350 char szTmp[518]; 351 352 #ifndef COMPILE_AS_ROSTEST 353 InitFunctionPointer(); 354 #endif 355 356 InitDirComponents(&cd); 357 358 #if defined(PRINT_INFO) 359 printf("WinVer: %d.%d\n", WinVerMaj, WinVerMin); 360 printf("pszLastCDComponent \"%s\"\n", cd.pszLastCDComponent); 361 printf("pszNextLastCDComponent \"%s\"\n", cd.pszNextLastCDComponent); 362 printf("pszParentDir \"%s\"\n", cd.pszPD); 363 printf("pszParentDirPlusSlash \"%s\"\n", cd.pszPDPlusSlash); 364 #endif 365 366 #define PREP0 /* The normal Win32 namespace. Fully parsed. */ 367 #define PREP1 "\\\\.\\" /* The Win32 Device Namespace. Only partially parsed. */ 368 #define PREP2 "\\\\?\\" /* The Win32 File Namespace. Only partially parsed. */ 369 370 // input name NtName PartName 371 // volume-absolute paths 372 test(PREP1 "C:" , "C:" , "C:"); 373 test(PREP2 "C:" , "C:" , "C:"); 374 test(PREP0 "C:\\" , "C:\\" , NULL); 375 test(PREP1 "C:\\" , "C:\\" , NULL); 376 test(PREP2 "C:\\" , "C:\\" , NULL); 377 test(PREP0 "C:\\foo" , "C:\\foo" , "foo"); 378 test(PREP1 "C:\\foo" , "C:\\foo" , "foo"); 379 test(PREP2 "C:\\foo" , "C:\\foo" , "foo"); 380 test(PREP0 "C:\\foo\\" , "C:\\foo\\" , NULL); 381 test(PREP1 "C:\\foo\\" , "C:\\foo\\" , NULL); 382 test(PREP2 "C:\\foo\\" , "C:\\foo\\" , NULL); 383 test(PREP0 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar"); 384 test(PREP1 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar"); 385 test(PREP2 "C:\\foo\\bar" , "C:\\foo\\bar" , "bar"); 386 test(PREP0 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL); 387 test(PREP1 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL); 388 test(PREP2 "C:\\foo\\bar\\", "C:\\foo\\bar\\" , NULL); 389 test(PREP0 "C:\\foo\\.." , "C:\\" , NULL); 390 test(PREP1 "C:\\foo\\.." , "C:" , "C:"); 391 test(PREP2 "C:\\foo\\.." , "C:\\foo\\.." , ".."); 392 test(PREP0 "C:\\foo\\..\\" , "C:\\" , NULL); 393 test(PREP1 "C:\\foo\\..\\" , "C:\\" , NULL); 394 test(PREP2 "C:\\foo\\..\\" , "C:\\foo\\..\\" , NULL); 395 test(PREP0 "C:\\foo." , "C:\\foo" , "foo"); 396 test(PREP1 "C:\\foo." , "C:\\foo" , "foo"); 397 test(PREP2 "C:\\foo." , "C:\\foo." , "foo."); 398 399 test(PREP0 "C:\\f\\b\\.." , "C:\\f" , "f"); 400 test(PREP1 "C:\\f\\b\\.." , "C:\\f" , "f"); 401 test(PREP2 "C:\\f\\b\\.." , "C:\\f\\b\\.." , ".."); 402 test(PREP0 "C:\\f\\b\\..\\", "C:\\f\\" , NULL); 403 test(PREP1 "C:\\f\\b\\..\\", "C:\\f\\" , NULL); 404 test(PREP2 "C:\\f\\b\\..\\", "C:\\f\\b\\..\\" , NULL); 405 406 // CD-relative paths 407 408 // RtlDosPathNameToNtPathName_U makes no distinction for 409 // special device names, such as "PhysicalDisk0", "HarddiskVolume0" 410 // or "Global??". They all follow the same pattern as a named 411 // filesystem entry, why they implicitly tested by the following 412 // "foo" and "foo\" cases. 413 sprintf(szTmp, "%s%s", cd.szCDPlusSlash, "foo"); 414 test(PREP0 "foo" , szTmp , "foo"); 415 test(PREP1 "foo" , "foo" , "foo"); 416 test(PREP2 "foo" , "foo" , "foo"); 417 418 sprintf(szTmp, "%s%s", cd.szCDPlusSlash , "foo\\"); 419 test(PREP0 "foo\\" , szTmp , NULL); 420 test(PREP1 "foo\\" , "foo\\" , NULL); 421 test(PREP2 "foo\\" , "foo\\" , NULL); 422 423 test(PREP0 "." , cd.szCD , cd.pszLastCDComponent); 424 test(PREP1 "." , "" , NULL); 425 test(PREP2 "." , "." , "."); 426 test(PREP0 ".\\" , cd.szCDPlusSlash , NULL); 427 test(PREP1 ".\\" , "" , NULL); 428 test(PREP2 ".\\" , ".\\" , NULL); 429 test(PREP0 ".\\." , cd.szCD , cd.pszLastCDComponent); 430 test(PREP1 ".\\." , "" , NULL); 431 test(PREP2 ".\\." , ".\\." , "."); 432 test(PREP0 ".\\.." , cd.pszPD , cd.pszNextLastCDComponent); 433 test(PREP1 ".\\.." , "" , NULL); 434 test(PREP2 ".\\.." , ".\\.." , ".."); 435 test(PREP0 ".." , cd.pszPD , cd.pszNextLastCDComponent); 436 test(PREP1 ".." , "" , NULL); 437 test(PREP2 ".." , ".." , ".."); 438 test(PREP0 "..\\" , cd.pszPDPlusSlash , NULL); 439 test(PREP1 "..\\" , "" , NULL); 440 test(PREP2 "..\\" , "..\\" , NULL); 441 // malformed 442 test(PREP0 "..." , cd.szCDPlusSlash , NULL); 443 test(PREP1 "..." , "" , NULL); 444 test(PREP2 "..." , "..." , "..."); 445 446 // Test well-known "special" DOS device names. 447 test(PREP0 "NUL" , "NUL" , NULL); 448 test(PREP1 "NUL" , "NUL" , "NUL"); 449 test(PREP2 "NUL" , "NUL" , "NUL"); 450 test(PREP0 "NUL:" , "NUL" , NULL); 451 test(PREP1 "NUL:" , "NUL:" , "NUL:"); 452 test(PREP2 "NUL:" , "NUL:" , "NUL:"); 453 test(PREP0 "CON" , "CON" , NULL); 454 // NOTE: RtlDosPathNameToNtPathName_U (as currently tested) fails for 455 // the input "\\.\CON" on two widely different Windows versions. 456 // test(PREP1 "CON" , "CON" , "CON"); 457 test(PREP2 "CON" , "CON" , "CON"); 458 test(PREP0 "CON:" , "CON" , NULL); 459 test(PREP1 "CON:" , "CON:" , "CON:"); 460 test(PREP2 "CON:" , "CON:" , "CON:"); 461 462 sprintf(szTmp, "%s\\%s", cd.szCD, "NUL:\\"); 463 test(PREP0 "NUL:\\" , szTmp , NULL); 464 test(PREP1 "NUL:\\" , "NUL:\\" , NULL); 465 test(PREP2 "NUL:\\" , "NUL:\\" , NULL); 466 test(PREP0 "C:NUL" , "NUL" , NULL); 467 test(PREP1 "C:NUL" , "C:NUL" , "C:NUL"); 468 test(PREP2 "C:NUL" , "C:NUL" , "C:NUL"); 469 test(PREP0 "C:\\NUL" , "NUL" , NULL); 470 test(PREP1 "C:\\NUL" , "C:\\NUL" , "NUL"); 471 test(PREP2 "C:\\NUL" , "C:\\NUL" , "NUL"); 472 test(PREP0 "C:\\NUL\\" , "C:\\NUL\\" , NULL); 473 test(PREP1 "C:\\NUL\\" , "C:\\NUL\\" , NULL); 474 test(PREP2 "C:\\NUL\\" , "C:\\NUL\\" , NULL); 475 476 // root-paths 477 test(PREP0 "\\" , cd.szCurDriveSlash, NULL); 478 test(PREP1 "\\" , "" , NULL); 479 test(PREP2 "\\" , "\\" , NULL); 480 481 test(PREP0 "\\." , cd.szCurDriveSlash, NULL); 482 test(PREP1 "\\." , "" , NULL); 483 test(PREP2 "\\." , "\\." , "."); 484 485 test(PREP0 "\\.." , cd.szCurDriveSlash, NULL); 486 test(PREP1 "\\.." , "" , NULL); 487 test(PREP2 "\\.." , "\\.." , ".."); 488 489 test(PREP0 "\\..." , cd.szCurDriveSlash, NULL); 490 test(PREP1 "\\..." , "" , NULL); 491 test(PREP2 "\\..." , "\\..." , "..."); 492 493 // malformed 494 sprintf(szTmp, "%s%s", cd.szCurDrive, "\\C:"); 495 test(PREP0 "\\C:" , szTmp , "C:"); 496 test(PREP1 "\\C:" , "C:" , "C:"); 497 test(PREP2 "\\C:" , "\\C:" , "C:"); 498 499 sprintf(szTmp, "%s%s", cd.szCurDrive, "\\C:\\"); 500 test(PREP0 "\\C:\\" , szTmp , NULL); 501 test(PREP1 "\\C:\\" , "C:\\" , NULL); 502 test(PREP2 "\\C:\\" , "\\C:\\" , NULL); 503 504 // UNC paths 505 test(PREP0 "\\\\" , "UNC\\" , NULL); 506 test(PREP1 "\\\\" , "" , NULL); 507 test(PREP2 "\\\\" , "\\\\" , NULL); 508 test(PREP0 "\\\\\\" , "UNC\\\\" , NULL); 509 test(PREP1 "\\\\\\" , "" , NULL); 510 test(PREP2 "\\\\\\" , "\\\\\\" , NULL); 511 test(PREP0 "\\\\foo" , "UNC\\foo" , NULL); 512 test(PREP1 "\\\\foo" , "foo" , "foo"); 513 test(PREP2 "\\\\foo" , "\\\\foo" , "foo"); 514 515 test(PREP0 "\\\\foo\\.." , "UNC\\foo\\" , NULL); 516 test(PREP1 "\\\\foo\\.." , "" , NULL); 517 test(PREP2 "\\\\foo\\.." , "\\\\foo\\.." , ".."); 518 519 test(PREP0 "\\\\foo\\" , "UNC\\foo\\" , NULL); 520 test(PREP1 "\\\\foo\\" , "foo\\" , NULL); 521 test(PREP2 "\\\\foo\\" , "\\\\foo\\" , NULL); 522 test(PREP0 "\\\\f\\b" , "UNC\\f\\b" , NULL); 523 test(PREP1 "\\\\f\\b" , "f\\b" , "b"); 524 test(PREP2 "\\\\f\\b" , "\\\\f\\b" , "b"); 525 test(PREP0 "\\\\f\\b\\" , "UNC\\f\\b\\" , NULL); 526 test(PREP1 "\\\\f\\b\\" , "f\\b\\" , NULL); 527 test(PREP2 "\\\\f\\b\\" , "\\\\f\\b\\" , NULL); 528 529 test(PREP0 "\\\\f\\b\\.." , "UNC\\f\\b" , NULL); 530 test(PREP1 "\\\\f\\b\\.." , "f" , "f"); 531 test(PREP2 "\\\\f\\b\\.." , "\\\\f\\b\\.." , ".."); 532 533 // strange UNC-paths 534 test(PREP0 "\\\\C:" , "UNC\\C:" , NULL); 535 test(PREP1 "\\\\C:" , "C:" , "C:"); 536 test(PREP2 "\\\\C:" , "\\\\C:" , "C:"); 537 test(PREP0 "\\\\C:\\" , "UNC\\C:\\" , NULL); 538 test(PREP1 "\\\\C:\\" , "C:\\" , NULL); 539 test(PREP2 "\\\\C:\\" , "\\\\C:\\" , NULL); 540 test(PREP0 "\\\\NUL" , "UNC\\NUL" , NULL); 541 test(PREP1 "\\\\NUL" , "NUL" , "NUL"); 542 test(PREP2 "\\\\NUL" , "\\\\NUL" , "NUL"); 543 test(PREP0 "\\\\NUL:" , "UNC\\NUL:" , NULL); 544 test(PREP1 "\\\\NUL:" , "NUL:" , "NUL:"); 545 test(PREP2 "\\\\NUL:" , "\\\\NUL:" , "NUL:"); 546 test(PREP0 "\\\\NUL:\\" , "UNC\\NUL:\\" , NULL); 547 test(PREP1 "\\\\NUL:\\" , "NUL:\\" , NULL); 548 test(PREP2 "\\\\NUL:\\" , "\\\\NUL:\\" , NULL); 549 550 // UNC + forward slashes 551 test(PREP0 "//" , "UNC\\" , NULL); 552 test(PREP1 "//" , "" , NULL); 553 test(PREP2 "//" , "//" , "//"); 554 test(PREP0 "//C:" , "UNC\\C:" , NULL); 555 test(PREP1 "//C:" , "C:" , "C:"); 556 test(PREP2 "//C:" , "//C:" , "//C:"); 557 test(PREP0 "//C:/" , "UNC\\C:\\" , NULL); 558 test(PREP1 "//C:/" , "C:\\" , NULL); 559 test(PREP2 "//C:/" , "//C:/" , "//C:/"); 560 test(PREP0 "//." , "" , NULL); 561 test(PREP1 "//." , "" , NULL); 562 test(PREP2 "//." , "//." , "//."); 563 test(PREP0 "//.." , "UNC\\" , NULL); 564 test(PREP1 "//.." , "" , NULL); 565 test(PREP2 "//.." , "//.." , "//.."); 566 test(PREP0 "/./" , cd.szCurDriveSlash, NULL); 567 test(PREP1 "/./" , "" , NULL); 568 test(PREP2 "/./" , "/./" , "/./"); 569 test(PREP0 "//./" , "" , NULL); 570 test(PREP1 "//./" , "" , NULL); 571 test(PREP2 "//./" , "//./" , "//./"); 572 573 test(cd.szCD , cd.szCD , cd.pszLastCDComponent); 574 test(cd.szCDPlusSlash , cd.szCDPlusSlash , NULL); 575 576 #if 0 577 // The following tests are "problematic", as they return results based on 578 // what your CD on C: is, whether or not you actually run the program 579 // from C:. For that reason, they are currently disabled. 580 test(PREP0 "C:" , "C:\\"+C_curdir , C_curdir); 581 test(PREP0 "C:NUL\\" , "C:\\"+C_curdir+"\\NUL\\" , NULL); 582 #endif 583 584 #if 0 // Disabled due to... see the comment inside the block. 585 { 586 char szExp[32]; 587 BOOL bValid = FALSE; 588 char szPrepend[32]; 589 szPrepend[0] = 0; 590 // Strictly speaking, this "Should Never Happen(tm)", calling 591 // RtlDosPathNameToNtPathName_U with a source already formed as 592 // a full NT name ("\??\"), why it's not the end of the world 593 // that this test is currently disabled. 594 // 595 // Some versions of Windows prepends driveletter + colon 596 // for the process' current volume. 597 // Prepending curdrive is most likely a bug that got fixed in 598 // later versions of Windows, but for compatibility it may 599 // become a requirement to "shim" this. 600 // 601 // Known operating systems prepending "Z:\??\" (assuming the 602 // process' CD is on the volume Z:): 603 // - XP sp2. 604 // 605 // Known operating systems not prepending: 606 // - Win7 64 (as 32-bit) 607 if (WinVerMaj == 5) { 608 sprintf(szPrepend, "%s\\??\\", cd.szCurDrive); 609 } 610 611 sprintf(szExp, "%s%s", szPrepend, "C:"); 612 test("\\??\\C:", szExp, "C:"); 613 614 sprintf(szExp, "%s%s", szPrepend, "C:\\"); 615 test("\\??\\C:\\", szExp, NULL); 616 617 } 618 #endif 619 620 #ifndef COMPILE_AS_ROSTEST 621 return 0; 622 #endif 623 } 624 625