ntoskrnl.exe: Add Ex[p]InterlockedFlushSList.
[wine.git] / dlls / ntdll / tests / path.c
blob195dea37e88381601a60fe61ab75b349466335e0
1 /*
2 * Unit test suite for ntdll path functions
4 * Copyright 2002 Alexandre Julliard
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.
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.
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
21 #include "ntdll_test.h"
22 #include "winnls.h"
24 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
25 LPCSTR src, DWORD srclen );
26 static NTSTATUS (WINAPI *pRtlUnicodeToMultiByteN)(LPSTR,DWORD,LPDWORD,LPCWSTR,DWORD);
27 static UINT (WINAPI *pRtlDetermineDosPathNameType_U)( PCWSTR path );
28 static ULONG (WINAPI *pRtlIsDosDeviceName_U)( PCWSTR dos_name );
29 static NTSTATUS (WINAPI *pRtlOemStringToUnicodeString)(UNICODE_STRING *, const STRING *, BOOLEAN );
30 static BOOLEAN (WINAPI *pRtlIsNameLegalDOS8Dot3)(const UNICODE_STRING*,POEM_STRING,PBOOLEAN);
31 static DWORD (WINAPI *pRtlGetFullPathName_U)(const WCHAR*,ULONG,WCHAR*,WCHAR**);
32 static BOOLEAN (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
33 static NTSTATUS (WINAPI *pRtlDosPathNameToNtPathName_U_WithStatus)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
35 static void test_RtlDetermineDosPathNameType_U(void)
37 struct test
39 const char *path;
40 UINT ret;
43 static const struct test tests[] =
45 { "\\\\foo", 1 },
46 { "//foo", 1 },
47 { "\\/foo", 1 },
48 { "/\\foo", 1 },
49 { "\\\\", 1 },
50 { "//", 1 },
51 { "c:\\foo", 2 },
52 { "c:/foo", 2 },
53 { "c://foo", 2 },
54 { "c:\\", 2 },
55 { "c:/", 2 },
56 { "c:foo", 3 },
57 { "c:f\\oo", 3 },
58 { "c:foo/bar", 3 },
59 { "\\foo", 4 },
60 { "/foo", 4 },
61 { "\\", 4 },
62 { "/", 4 },
63 { "foo", 5 },
64 { "", 5 },
65 { "\0:foo", 5 },
66 { "\\\\.\\foo", 6 },
67 { "//./foo", 6 },
68 { "/\\./foo", 6 },
69 { "\\\\.foo", 1 },
70 { "//.foo", 1 },
71 { "\\\\.", 7 },
72 { "//.", 7 },
73 { "\\\\?\\foo", 6 },
74 { "//?/foo", 6 },
75 { "/\\?/foo", 6 },
76 { "\\\\?foo", 1 },
77 { "//?foo", 1 },
78 { "\\\\?", 7 },
79 { "//?", 7 },
80 { NULL, 0 }
83 const struct test *test;
84 WCHAR buffer[MAX_PATH];
85 UINT ret;
87 if (!pRtlDetermineDosPathNameType_U)
89 win_skip("RtlDetermineDosPathNameType_U is not available\n");
90 return;
93 for (test = tests; test->path; test++)
95 pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 );
96 ret = pRtlDetermineDosPathNameType_U( buffer );
97 ok( ret == test->ret, "Wrong result %d/%d for %s\n", ret, test->ret, test->path );
102 static void test_RtlIsDosDeviceName_U(void)
104 struct test
106 const char *path;
107 WORD pos;
108 WORD len;
109 BOOL fails;
112 static const struct test tests[] =
114 { "\\\\.\\CON", 8, 6, TRUE }, /* fails on win8 */
115 { "\\\\.\\con", 8, 6, TRUE }, /* fails on win8 */
116 { "\\\\.\\CON2", 0, 0 },
117 { "", 0, 0 },
118 { "\\\\foo\\nul", 0, 0 },
119 { "c:\\nul:", 6, 6 },
120 { "c:\\nul\\", 0, 0 },
121 { "c:\\nul\\foo", 0, 0 },
122 { "c:\\nul::", 6, 6, TRUE }, /* fails on nt4 */
123 { "c:\\nul::::::", 6, 6, TRUE }, /* fails on nt4 */
124 { "c:prn ", 4, 6 },
125 { "c:prn.......", 4, 6 },
126 { "c:prn... ...", 4, 6 },
127 { "c:NUL .... ", 4, 6, TRUE }, /* fails on nt4 */
128 { "c: . . .", 0, 0 },
129 { "c:", 0, 0 },
130 { " . . . :", 0, 0 },
131 { ":", 0, 0 },
132 { "c:nul. . . :", 4, 6 },
133 { "c:nul . . :", 4, 6, TRUE }, /* fails on nt4 */
134 { "c:nul0", 0, 0 },
135 { "c:prn:aaa", 4, 6, TRUE }, /* fails on win9x */
136 { "c:PRN:.txt", 4, 6 },
137 { "c:aux:.txt...", 4, 6 },
138 { "c:prn:.txt:", 4, 6 },
139 { "c:nul:aaa", 4, 6, TRUE }, /* fails on win9x */
140 { "con:", 0, 6 },
141 { "lpt1:", 0, 8 },
142 { "c:com5:", 4, 8 },
143 { "CoM4:", 0, 8 },
144 { "lpt9:", 0, 8 },
145 { "c:\\lpt0.txt", 0, 0 },
146 { "c:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
147 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
148 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
149 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
150 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
151 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
152 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\nul.txt", 1000, 6 },
153 { NULL, 0 }
156 const struct test *test;
157 WCHAR buffer[2000];
158 ULONG ret;
160 if (!pRtlIsDosDeviceName_U)
162 win_skip("RtlIsDosDeviceName_U is not available\n");
163 return;
166 for (test = tests; test->path; test++)
168 pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 );
169 ret = pRtlIsDosDeviceName_U( buffer );
170 ok( ret == MAKELONG( test->len, test->pos ) ||
171 (test->fails && broken( ret == 0 )),
172 "Wrong result (%d,%d)/(%d,%d) for %s\n",
173 HIWORD(ret), LOWORD(ret), test->pos, test->len, test->path );
177 static void test_RtlIsNameLegalDOS8Dot3(void)
179 struct test
181 const char *path;
182 BOOLEAN result;
183 BOOLEAN spaces;
186 static const struct test tests[] =
188 { "12345678", TRUE, FALSE },
189 { "123 5678", TRUE, TRUE },
190 { "12345678.", FALSE, 2 /*not set*/ },
191 { "1234 678.", FALSE, 2 /*not set*/ },
192 { "12345678.a", TRUE, FALSE },
193 { "12345678.a ", FALSE, 2 /*not set*/ },
194 { "12345678.a c", TRUE, TRUE },
195 { " 2345678.a ", FALSE, 2 /*not set*/ },
196 { "1 345678.abc", TRUE, TRUE },
197 { "1 8.a c", TRUE, TRUE },
198 { "1 3 5 7 .abc", FALSE, 2 /*not set*/ },
199 { "12345678. c", TRUE, TRUE },
200 { "123456789.a", FALSE, 2 /*not set*/ },
201 { "12345.abcd", FALSE, 2 /*not set*/ },
202 { "12345.ab d", FALSE, 2 /*not set*/ },
203 { ".abc", FALSE, 2 /*not set*/ },
204 { "12.abc.d", FALSE, 2 /*not set*/ },
205 { ".", TRUE, FALSE },
206 { "..", TRUE, FALSE },
207 { "...", FALSE, 2 /*not set*/ },
208 { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", FALSE, 2 /*not set*/ },
209 { NULL, 0 }
212 const struct test *test;
213 UNICODE_STRING ustr;
214 OEM_STRING oem, oem_ret;
215 WCHAR buffer[200];
216 char buff2[12];
217 BOOLEAN ret, spaces;
219 if (!pRtlIsNameLegalDOS8Dot3)
221 win_skip("RtlIsNameLegalDOS8Dot3 is not available\n");
222 return;
225 ustr.MaximumLength = sizeof(buffer);
226 ustr.Buffer = buffer;
227 for (test = tests; test->path; test++)
229 char path[100];
230 strcpy(path, test->path);
231 oem.Buffer = path;
232 oem.Length = strlen(test->path);
233 oem.MaximumLength = oem.Length + 1;
234 pRtlOemStringToUnicodeString( &ustr, &oem, FALSE );
235 spaces = 2;
236 oem_ret.Length = oem_ret.MaximumLength = sizeof(buff2);
237 oem_ret.Buffer = buff2;
238 ret = pRtlIsNameLegalDOS8Dot3( &ustr, &oem_ret, &spaces );
239 ok( ret == test->result, "Wrong result %d/%d for '%s'\n", ret, test->result, test->path );
240 ok( spaces == test->spaces, "Wrong spaces value %d/%d for '%s'\n", spaces, test->spaces, test->path );
241 if (strlen(test->path) <= 12)
243 STRING test_str;
244 char str[13];
245 strcpy( str, test->path );
246 RtlInitString( &test_str, str );
247 RtlUpperString( &test_str, &test_str );
248 ok( !RtlCompareString(&oem_ret, &test_str, FALSE),
249 "Wrong string '%.*s'/'%s'\n", oem_ret.Length, oem_ret.Buffer, test->path );
253 static void test_RtlGetFullPathName_U(void)
255 static const WCHAR emptyW[] = {0};
256 static const WCHAR deadbeefW[] = {'d','e','a','d','b','e','e','f',0};
258 struct test
260 const char *path;
261 const char *rname;
262 const char *rfile;
263 const char *alt_rname;
264 const char *alt_rfile;
267 static const struct test tests[] =
269 { "c:/test", "c:\\test", "test"},
270 { "c:/test/", "c:\\test\\", NULL},
271 { "c:/test ", "c:\\test", "test"},
272 { "c:/test.", "c:\\test", "test"},
273 { "c:/test .... .. ", "c:\\test", "test"},
274 { "c:/test/ .... .. ", "c:\\test\\", NULL},
275 { "c:/test/..", "c:\\", NULL},
276 { "c:/test/.. ", "c:\\test\\", NULL},
277 { "c:/TEST", "c:\\TEST", "TEST"},
278 { "c:/test/file", "c:\\test\\file", "file"},
279 { "c:/test./file", "c:\\test\\file", "file"},
280 { "c:/test.. /file", "c:\\test.. \\file","file"},
281 { "c:/test/././file", "c:\\test\\file", "file"},
282 { "c:/test\\.\\.\\file", "c:\\test\\file", "file"},
283 { "c:/test/\\.\\.\\file", "c:\\test\\file", "file"},
284 { "c:/test\\\\.\\.\\file", "c:\\test\\file", "file"},
285 { "c:/test\\test1\\..\\.\\file", "c:\\test\\file", "file"},
286 { "c:///test\\.\\.\\file//", "c:\\test\\file\\", NULL,
287 "c:\\test\\file", "file"}, /* nt4 */
288 { "c:///test\\..\\file\\..\\//", "c:\\", NULL},
289 { "c:/test../file", "c:\\test.\\file", "file",
290 "c:\\test..\\file", "file"}, /* vista */
291 { "c:\\test", "c:\\test", "test"},
292 { "C:\\test", "C:\\test", "test"},
293 { "c:/", "c:\\", NULL},
294 { "c:.", "C:\\windows", "windows"},
295 { "c:foo", "C:\\windows\\foo", "foo"},
296 { "c:foo/bar", "C:\\windows\\foo\\bar", "bar"},
297 { "c:./foo", "C:\\windows\\foo", "foo"},
298 { "\\foo", "C:\\foo", "foo"},
299 { "foo", "C:\\windows\\foo", "foo"},
300 { ".", "C:\\windows", "windows"},
301 { "..", "C:\\", NULL},
302 { "...", "C:\\windows\\", NULL},
303 { "./foo", "C:\\windows\\foo", "foo"},
304 { "foo/..", "C:\\windows", "windows"},
305 { "AUX", "\\\\.\\AUX", NULL},
306 { "COM1", "\\\\.\\COM1", NULL},
307 { "?<>*\"|:", "C:\\windows\\?<>*\"|:", "?<>*\"|:"},
309 { "\\\\foo", "\\\\foo", NULL},
310 { "//foo", "\\\\foo", NULL},
311 { "\\/foo", "\\\\foo", NULL},
312 { "//", "\\\\", NULL},
313 { "//foo/", "\\\\foo\\", NULL},
315 { "//.", "\\\\.\\", NULL},
316 { "//./", "\\\\.\\", NULL},
317 { "//.//", "\\\\.\\", NULL},
318 { "//./foo", "\\\\.\\foo", "foo"},
319 { "//./foo/", "\\\\.\\foo\\", NULL},
320 { "//./foo/bar", "\\\\.\\foo\\bar", "bar"},
321 { "//./foo/.", "\\\\.\\foo", "foo"},
322 { "//./foo/..", "\\\\.\\", NULL},
324 { "//?/", "\\\\?\\", NULL},
325 { "//?//", "\\\\?\\", NULL},
326 { "//?/foo", "\\\\?\\foo", "foo"},
327 { "//?/foo/", "\\\\?\\foo\\", NULL},
328 { "//?/foo/bar", "\\\\?\\foo\\bar", "bar"},
329 { "//?/foo/.", "\\\\?\\foo", "foo"},
330 { "//?/foo/..", "\\\\?\\", NULL},
332 /* RtlGetFullPathName_U() can't understand the global namespace prefix */
333 { "\\??\\foo", "C:\\??\\foo", "foo"},
334 { 0 }
337 const struct test *test;
338 WCHAR pathbufW[2*MAX_PATH], rbufferW[MAX_PATH];
339 char rbufferA[MAX_PATH], rfileA[MAX_PATH], curdir[MAX_PATH];
340 ULONG ret;
341 WCHAR *file_part;
342 DWORD reslen;
343 UINT len;
345 GetCurrentDirectoryA(sizeof(curdir), curdir);
346 SetCurrentDirectoryA("C:\\windows\\");
348 file_part = (WCHAR *)0xdeadbeef;
349 lstrcpyW(rbufferW, deadbeefW);
350 ret = pRtlGetFullPathName_U(NULL, MAX_PATH, rbufferW, &file_part);
351 ok(!ret, "Expected RtlGetFullPathName_U to return 0, got %u\n", ret);
352 ok(!lstrcmpW(rbufferW, deadbeefW),
353 "Expected the output buffer to be untouched, got %s\n", wine_dbgstr_w(rbufferW));
354 ok(file_part == (WCHAR *)0xdeadbeef ||
355 file_part == NULL, /* Win7 */
356 "Expected file part pointer to be untouched, got %p\n", file_part);
358 file_part = (WCHAR *)0xdeadbeef;
359 lstrcpyW(rbufferW, deadbeefW);
360 ret = pRtlGetFullPathName_U(emptyW, MAX_PATH, rbufferW, &file_part);
361 ok(!ret, "Expected RtlGetFullPathName_U to return 0, got %u\n", ret);
362 ok(!lstrcmpW(rbufferW, deadbeefW),
363 "Expected the output buffer to be untouched, got %s\n", wine_dbgstr_w(rbufferW));
364 ok(file_part == (WCHAR *)0xdeadbeef ||
365 file_part == NULL, /* Win7 */
366 "Expected file part pointer to be untouched, got %p\n", file_part);
368 for (test = tests; test->path; test++)
370 len= strlen(test->rname) * sizeof(WCHAR);
371 pRtlMultiByteToUnicodeN(pathbufW , sizeof(pathbufW), NULL, test->path, strlen(test->path)+1 );
372 ret = pRtlGetFullPathName_U( pathbufW,MAX_PATH, rbufferW, &file_part);
373 ok( ret == len || (test->alt_rname && ret == strlen(test->alt_rname)*sizeof(WCHAR)),
374 "Wrong result %d/%d for \"%s\"\n", ret, len, test->path );
375 ok(pRtlUnicodeToMultiByteN(rbufferA,MAX_PATH,&reslen,rbufferW,(lstrlenW(rbufferW) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
376 "RtlUnicodeToMultiByteN failed\n");
377 ok(!lstrcmpA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpA(rbufferA,test->alt_rname)),
378 "Got \"%s\" expected \"%s\"\n",rbufferA,test->rname);
379 if (file_part)
381 ok(pRtlUnicodeToMultiByteN(rfileA,MAX_PATH,&reslen,file_part,(lstrlenW(file_part) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
382 "RtlUnicodeToMultiByteN failed\n");
383 ok((test->rfile && !lstrcmpA(rfileA,test->rfile)) ||
384 (test->alt_rfile && !lstrcmpA(rfileA,test->alt_rfile)),
385 "Got \"%s\" expected \"%s\"\n",rfileA,test->rfile);
387 else
389 ok( !test->rfile, "Got NULL expected \"%s\"\n", test->rfile );
393 SetCurrentDirectoryA(curdir);
396 static void test_RtlDosPathNameToNtPathName_U(void)
398 static const WCHAR broken_global_prefix[] = {'\\','?','?','\\','C',':','\\','?','?'};
400 char curdir[MAX_PATH];
401 WCHAR path[MAX_PATH];
402 UNICODE_STRING nameW;
403 WCHAR *file_part;
404 NTSTATUS status;
405 BOOL ret, expect;
406 int i;
408 static const struct
410 const char *dos;
411 const char *nt;
412 int file_offset; /* offset to file part */
413 NTSTATUS status;
414 NTSTATUS alt_status;
415 int broken;
417 tests[] =
419 { "c:\\", "\\??\\c:\\", -1, STATUS_SUCCESS },
420 { "c:/", "\\??\\c:\\", -1, STATUS_SUCCESS },
421 { "c:/foo", "\\??\\c:\\foo", 7, STATUS_SUCCESS },
422 { "c:/foo.", "\\??\\c:\\foo", 7, STATUS_SUCCESS },
423 { "c:/foo/", "\\??\\c:\\foo\\", -1, STATUS_SUCCESS },
424 { "c:/foo//", "\\??\\c:\\foo\\", -1, STATUS_SUCCESS },
425 { "C:/foo", "\\??\\C:\\foo", 7, STATUS_SUCCESS },
426 { "C:/foo/bar", "\\??\\C:\\foo\\bar", 11, STATUS_SUCCESS },
427 { "C:/foo/bar", "\\??\\C:\\foo\\bar", 11, STATUS_SUCCESS },
428 { "c:.", "\\??\\C:\\windows", 7, STATUS_SUCCESS },
429 { "c:foo", "\\??\\C:\\windows\\foo", 15, STATUS_SUCCESS },
430 { "c:foo/bar", "\\??\\C:\\windows\\foo\\bar", 19, STATUS_SUCCESS },
431 { "c:./foo", "\\??\\C:\\windows\\foo", 15, STATUS_SUCCESS },
432 { "c:/./foo", "\\??\\c:\\foo", 7, STATUS_SUCCESS },
433 { "c:/foo/.", "\\??\\c:\\foo", 7, STATUS_SUCCESS },
434 { "c:/foo/./bar", "\\??\\c:\\foo\\bar", 11, STATUS_SUCCESS },
435 { "c:/foo/../bar", "\\??\\c:\\bar", 7, STATUS_SUCCESS },
436 { "\\foo", "\\??\\C:\\foo", 7, STATUS_SUCCESS },
437 { "foo", "\\??\\C:\\windows\\foo", 15, STATUS_SUCCESS },
438 { ".", "\\??\\C:\\windows", 7, STATUS_SUCCESS },
439 { "./", "\\??\\C:\\windows\\", -1, STATUS_SUCCESS },
440 { "..", "\\??\\C:\\", -1, STATUS_SUCCESS },
441 { "...", "\\??\\C:\\windows\\", -1, STATUS_SUCCESS },
442 { "./foo", "\\??\\C:\\windows\\foo", 15, STATUS_SUCCESS },
443 { "foo/..", "\\??\\C:\\windows", 7, STATUS_SUCCESS },
444 { "AUX" , "\\??\\AUX", -1, STATUS_SUCCESS },
445 { "COM1" , "\\??\\COM1", -1, STATUS_SUCCESS },
446 { "?<>*\"|:", "\\??\\C:\\windows\\?<>*\"|:", 15, STATUS_SUCCESS },
448 { "", NULL, -1, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND },
449 { NULL, NULL, -1, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND },
450 { " ", NULL, -1, STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND },
452 { "\\\\foo", "\\??\\UNC\\foo", -1, STATUS_SUCCESS },
453 { "//foo", "\\??\\UNC\\foo", -1, STATUS_SUCCESS },
454 { "\\/foo", "\\??\\UNC\\foo", -1, STATUS_SUCCESS },
455 { "//", "\\??\\UNC\\", -1, STATUS_SUCCESS },
456 { "//foo/", "\\??\\UNC\\foo\\", -1, STATUS_SUCCESS },
458 { "//.", "\\??\\", -1, STATUS_SUCCESS },
459 { "//./", "\\??\\", -1, STATUS_SUCCESS },
460 { "//.//", "\\??\\", -1, STATUS_SUCCESS },
461 { "//./foo", "\\??\\foo", 4, STATUS_SUCCESS },
462 { "//./foo/", "\\??\\foo\\", -1, STATUS_SUCCESS },
463 { "//./foo/bar", "\\??\\foo\\bar", 8, STATUS_SUCCESS },
464 { "//./foo/.", "\\??\\foo", 4, STATUS_SUCCESS },
465 { "//./foo/..", "\\??\\", -1, STATUS_SUCCESS },
467 { "//?", "\\??\\", -1, STATUS_SUCCESS },
468 { "//?/", "\\??\\", -1, STATUS_SUCCESS },
469 { "//?//", "\\??\\", -1, STATUS_SUCCESS },
470 { "//?/foo", "\\??\\foo", 4, STATUS_SUCCESS },
471 { "//?/foo/", "\\??\\foo\\", -1, STATUS_SUCCESS },
472 { "//?/foo/bar", "\\??\\foo\\bar", 8, STATUS_SUCCESS },
473 { "//?/foo/.", "\\??\\foo", 4, STATUS_SUCCESS },
474 { "//?/foo/..", "\\??\\", -1, STATUS_SUCCESS },
476 { "\\\\?", "\\??\\", -1, STATUS_SUCCESS },
477 { "\\\\?\\", "\\??\\", -1, STATUS_SUCCESS },
479 { "\\\\?\\/", "\\??\\/", 4, STATUS_SUCCESS },
480 { "\\\\?\\foo", "\\??\\foo", 4, STATUS_SUCCESS },
481 { "\\\\?\\foo/", "\\??\\foo/", 4, STATUS_SUCCESS },
482 { "\\\\?\\foo/bar", "\\??\\foo/bar", 4, STATUS_SUCCESS },
483 { "\\\\?\\foo/.", "\\??\\foo/.", 4, STATUS_SUCCESS },
484 { "\\\\?\\foo/..", "\\??\\foo/..", 4, STATUS_SUCCESS },
485 { "\\\\?\\\\", "\\??\\\\", -1, STATUS_SUCCESS },
486 { "\\\\?\\\\\\", "\\??\\\\\\", -1, STATUS_SUCCESS },
487 { "\\\\?\\foo\\", "\\??\\foo\\", -1, STATUS_SUCCESS },
488 { "\\\\?\\foo\\bar", "\\??\\foo\\bar", 8, STATUS_SUCCESS },
489 { "\\\\?\\foo\\.", "\\??\\foo\\.", 8, STATUS_SUCCESS },
490 { "\\\\?\\foo\\..", "\\??\\foo\\..", 8, STATUS_SUCCESS },
492 { "\\??", "\\??\\C:\\??", 7, STATUS_SUCCESS },
493 { "\\??\\", "\\??\\C:\\??\\", -1, STATUS_SUCCESS },
495 { "\\??\\/", "\\??\\/", 4, STATUS_SUCCESS },
496 { "\\??\\foo", "\\??\\foo", 4, STATUS_SUCCESS },
497 { "\\??\\foo/", "\\??\\foo/", 4, STATUS_SUCCESS },
498 { "\\??\\foo/bar", "\\??\\foo/bar", 4, STATUS_SUCCESS },
499 { "\\??\\foo/.", "\\??\\foo/.", 4, STATUS_SUCCESS },
500 { "\\??\\foo/..", "\\??\\foo/..", 4, STATUS_SUCCESS },
501 { "\\??\\\\", "\\??\\\\", -1, STATUS_SUCCESS },
502 { "\\??\\\\\\", "\\??\\\\\\", -1, STATUS_SUCCESS },
503 { "\\??\\foo\\", "\\??\\foo\\", -1, STATUS_SUCCESS },
504 { "\\??\\foo\\bar", "\\??\\foo\\bar", 8, STATUS_SUCCESS },
505 { "\\??\\foo\\.", "\\??\\foo\\.", 8, STATUS_SUCCESS },
506 { "\\??\\foo\\..", "\\??\\foo\\..", 8, STATUS_SUCCESS },
509 GetCurrentDirectoryA(sizeof(curdir), curdir);
510 SetCurrentDirectoryA("C:\\windows\\");
512 for (i = 0; i < ARRAY_SIZE(tests); ++i)
514 MultiByteToWideChar(CP_ACP, 0, tests[i].dos, -1, path, ARRAY_SIZE(path));
515 ret = pRtlDosPathNameToNtPathName_U(path, &nameW, &file_part, NULL);
517 if (pRtlDosPathNameToNtPathName_U_WithStatus)
519 RtlFreeUnicodeString(&nameW);
520 status = pRtlDosPathNameToNtPathName_U_WithStatus(path, &nameW, &file_part, NULL);
521 ok(status == tests[i].status || status == tests[i].alt_status,
522 "%s: Expected status %#x, got %#x.\n", tests[i].dos, tests[i].status, status);
525 expect = (tests[i].status == STATUS_SUCCESS);
526 ok(ret == expect, "%s: Expected %#x, got %#x.\n", tests[i].dos, expect, ret);
528 if (ret != TRUE) continue;
530 if (!strncmp(tests[i].dos, "\\??\\", 4) && tests[i].dos[4] &&
531 broken(!memcmp(nameW.Buffer, broken_global_prefix, sizeof(broken_global_prefix))))
533 /* Windows version prior to 2003 don't interpret the \??\ prefix */
534 continue;
537 MultiByteToWideChar(CP_ACP, 0, tests[i].nt, -1, path, ARRAY_SIZE(path));
538 ok(!lstrcmpW(nameW.Buffer, path), "%s: Expected %s, got %s.\n",
539 tests[i].dos, tests[i].nt, wine_dbgstr_w(nameW.Buffer));
541 if (tests[i].file_offset > 0)
542 ok(file_part == nameW.Buffer + tests[i].file_offset,
543 "%s: Expected file part %s, got %s.\n", tests[i].dos,
544 wine_dbgstr_w(nameW.Buffer + tests[i].file_offset), wine_dbgstr_w(file_part));
545 else
546 ok(file_part == NULL, "%s: Expected NULL file part, got %s.\n",
547 tests[i].dos, wine_dbgstr_w(file_part));
549 RtlFreeUnicodeString(&nameW);
552 SetCurrentDirectoryA(curdir);
555 START_TEST(path)
557 HMODULE mod = GetModuleHandleA("ntdll.dll");
558 if (!mod)
560 win_skip("Not running on NT, skipping tests\n");
561 return;
564 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN");
565 pRtlUnicodeToMultiByteN = (void *)GetProcAddress(mod,"RtlUnicodeToMultiByteN");
566 pRtlDetermineDosPathNameType_U = (void *)GetProcAddress(mod,"RtlDetermineDosPathNameType_U");
567 pRtlIsDosDeviceName_U = (void *)GetProcAddress(mod,"RtlIsDosDeviceName_U");
568 pRtlOemStringToUnicodeString = (void *)GetProcAddress(mod,"RtlOemStringToUnicodeString");
569 pRtlIsNameLegalDOS8Dot3 = (void *)GetProcAddress(mod,"RtlIsNameLegalDOS8Dot3");
570 pRtlGetFullPathName_U = (void *)GetProcAddress(mod,"RtlGetFullPathName_U");
571 pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U");
572 pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus");
574 test_RtlDetermineDosPathNameType_U();
575 test_RtlIsDosDeviceName_U();
576 test_RtlIsNameLegalDOS8Dot3();
577 test_RtlGetFullPathName_U();
578 test_RtlDosPathNameToNtPathName_U();