ReactOS  0.4.14-dev-114-gc8cbd56
RtlDosPathNameToNtPathName_U.c
Go to the documentation of this file.
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;
59  PWSTR Buffer;
61 
62 typedef struct _RTLP_CURDIR_REF
63 {
64  LONG RefCount;
65  HANDLE Handle;
67 
68 typedef struct RTL_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];
210  char szCurDrive[3];
211  char reserved1;
213  char szParentDir[512];
217  const char* pszPD; // parent dir
218  const char* pszPDPlusSlash;
219 } DirComponents;
220 
221 
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  }
315  (RtlDosPathNameToNtPathName_U_t)GetProcAddress(hDll, "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
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 
350  char szTmp[518];
351 
352 #ifndef COMPILE_AS_ROSTEST
353  InitFunctionPointer();
354 #endif
355 
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 
struct _RTLP_CURDIR_REF RTLP_CURDIR_REF
const uint16_t * PCWSTR
Definition: typedefs.h:55
struct DirComponents DirComponents
PPEB Peb
Definition: dllmain.c:27
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
#define LoadLibrary
Definition: winbase.h:3686
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define START_TEST(x)
Definition: atltest.h:75
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
uint16_t * PWSTR
Definition: typedefs.h:54
int main(int argc, char *argv[])
Definition: atactl.cpp:1685
HANDLE ContainingDirectory
Definition: rtltypes.h:1375
sprintf(szTmp, "%s%s", cd.szCDPlusSlash, "foo")
#define HIBYTE(W)
Definition: jmemdos.c:486
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
char szTmp[518]
#define DWORD
Definition: nt_native.h:44
DWORD WINAPI GetVersion(VOID)
Definition: version.c:22
struct _RTL_RELATIVE_NAME_U * PRTL_RELATIVE_NAME_U
static void test2(LPCWSTR pwsz, LPCWSTR pwszExpected, LPCWSTR pwszExpectedPartName)
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define GetCurrentDirectory
Definition: winbase.h:3629
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define swprintf(buf, format,...)
Definition: sprintf.c:56
unsigned long DWORD
Definition: ntddk_ex.h:95
InitDirComponents & cd
#define __stdcall
Definition: typedefs.h:25
static const WCHAR L[]
Definition: oid.c:1250
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
unsigned char BYTE
Definition: mem.h:68
struct _RTLP_CURDIR_REF * PRTLP_CURDIR_REF
static void InitDirComponents(DirComponents *p)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
ULONG OSMinorVersion
Definition: ntddk_ex.h:301
#define NtCurrentPeb()
Definition: FLS.c:20
unsigned short USHORT
Definition: pedump.c:61
#define ok(value,...)
Definition: atltest.h:57
struct _RTL_RELATIVE_NAME_U RTL_RELATIVE_NAME_U
UNICODE_STRING * PUNICODE_STRING
Definition: env_spec_w32.h:373
struct _UNICODE_STRING UNICODE_STRING
#define BOOLEAN
Definition: pedump.c:73
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define GetProcAddress(x, y)
Definition: compat.h:410
UNICODE_STRING RelativeName
Definition: rtltypes.h:1374
static void test(const char *psz, const char *pszExpected, const char *pszExpectedPartName)
ULONG OSMajorVersion
Definition: ntddk_ex.h:300
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
#define LOWORD(l)
Definition: pedump.c:82
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
PRTLP_CURDIR_REF CurDirRef
Definition: rtltypes.h:1376
static void check_result(BOOLEAN bOK, const char *pszErr)
NTSYSAPI BOOLEAN NTAPI RtlDosPathNameToNtPathName_U(_In_opt_z_ PCWSTR DosPathName, _Out_ PUNICODE_STRING NtPathName, _Out_opt_ PCWSTR *NtFileNamePart, _Out_opt_ PRTL_RELATIVE_NAME_U DirectoryInfo)
#define printf
Definition: config.h:203