dmsynth: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / ntdll / tests / path.c
blob9210cfb8843f1c03ff4d9469ee3ec95e0a2bb4b0
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*);
34 static NTSTATUS (WINAPI *pNtOpenFile)( HANDLE*, ACCESS_MASK, OBJECT_ATTRIBUTES*, IO_STATUS_BLOCK*, ULONG, ULONG );
36 static void test_RtlDetermineDosPathNameType_U(void)
38 struct test
40 const char *path;
41 UINT ret;
44 static const struct test tests[] =
46 { "\\\\foo", 1 },
47 { "//foo", 1 },
48 { "\\/foo", 1 },
49 { "/\\foo", 1 },
50 { "\\\\", 1 },
51 { "//", 1 },
52 { "c:\\foo", 2 },
53 { "c:/foo", 2 },
54 { "c://foo", 2 },
55 { "c:\\", 2 },
56 { "c:/", 2 },
57 { "c:foo", 3 },
58 { "c:f\\oo", 3 },
59 { "c:foo/bar", 3 },
60 { "\\foo", 4 },
61 { "/foo", 4 },
62 { "\\", 4 },
63 { "/", 4 },
64 { "foo", 5 },
65 { "", 5 },
66 { "\0:foo", 5 },
67 { "\\\\.\\foo", 6 },
68 { "//./foo", 6 },
69 { "/\\./foo", 6 },
70 { "\\\\.foo", 1 },
71 { "//.foo", 1 },
72 { "\\\\.", 7 },
73 { "//.", 7 },
74 { "\\\\?\\foo", 6 },
75 { "//?/foo", 6 },
76 { "/\\?/foo", 6 },
77 { "\\\\?foo", 1 },
78 { "//?foo", 1 },
79 { "\\\\?", 7 },
80 { "//?", 7 },
81 { "CONIN$", 5 },
82 { "CONOUT$", 5 },
83 { "CONERR$", 5 },
84 { "\\\\.\\CONIN$", 6 },
85 { "\\\\.\\CONOUT$", 6 },
86 { NULL, 0 }
89 const struct test *test;
90 WCHAR buffer[MAX_PATH];
91 UINT ret;
93 if (!pRtlDetermineDosPathNameType_U)
95 win_skip("RtlDetermineDosPathNameType_U is not available\n");
96 return;
99 for (test = tests; test->path; test++)
101 pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 );
102 ret = pRtlDetermineDosPathNameType_U( buffer );
103 ok( ret == test->ret, "Wrong result %d/%d for %s\n", ret, test->ret, test->path );
108 static void test_RtlIsDosDeviceName_U(void)
110 struct test
112 const char *path;
113 WORD pos;
114 WORD len;
115 BOOL fails;
118 static const struct test tests[] =
120 { "\\\\.\\CON", 8, 6, TRUE }, /* fails on win8 */
121 { "\\\\.\\con", 8, 6, TRUE }, /* fails on win8 */
122 { "\\\\.\\CON2", 0, 0 },
123 { "\\\\.\\CONIN$", 0, 0 },
124 { "\\\\.\\CONOUT$",0, 0 },
125 { "", 0, 0 },
126 { "\\\\foo\\nul", 0, 0 },
127 { "c:\\nul:", 6, 6 },
128 { "c:\\nul\\", 0, 0 },
129 { "c:\\nul\\foo", 0, 0 },
130 { "c:\\nul::", 6, 6 },
131 { "c:\\nul::::::", 6, 6, TRUE }, /* fails on win11 */
132 { "c:prn ", 4, 6, TRUE }, /* fails on win11 */
133 { "c:prn.......", 4, 6, TRUE }, /* fails on win11 */
134 { "c:prn... ...", 4, 6, TRUE }, /* fails on win11 */
135 { "c:NUL .... ", 4, 6 },
136 { "c: . . .", 0, 0 },
137 { "c:", 0, 0 },
138 { " . . . :", 0, 0 },
139 { ":", 0, 0 },
140 { "c:nul. . . :", 4, 6 },
141 { "c:nul . . :", 4, 6 },
142 { "c:nul0", 0, 0 },
143 { "c:prn:aaa", 4, 6, TRUE }, /* fails on win11 */
144 { "c:PRN:.txt", 4, 6, TRUE }, /* fails on win11 */
145 { "c:aux:.txt...", 4, 6, TRUE }, /* fails on win11 */
146 { "c:prn:.txt:", 4, 6, TRUE }, /* fails on win11 */
147 { "c:nul:aaa", 4, 6, TRUE }, /* fails on win11 */
148 { "con:", 0, 6 },
149 { "lpt1:", 0, 8 },
150 { "c:com5:", 4, 8, TRUE }, /* fails on win11 */
151 { "CoM4:", 0, 8 },
152 { "lpt9:", 0, 8 },
153 { "c:\\lpt0.txt", 0, 0 },
154 { "CONIN$", 0, 12, TRUE }, /* fails on win7 */
155 { "CONOUT$", 0, 14, TRUE }, /* fails on win7 */
156 { "CONERR$", 0, 0 },
157 { "CON", 0, 6 },
158 { "PIPE", 0, 0 },
159 { "\\??\\CONIN$", 8, 12, TRUE }, /* fails on win7 */
160 { "\\??\\CONOUT$", 8, 14, TRUE }, /* fails on win7 */
161 { "\\??\\CONERR$", 0, 0 },
162 { "\\??\\CON", 8, 6, TRUE }, /* fails on win11 */
163 { "c:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
164 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
165 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
166 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
167 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
168 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
169 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\nul.txt", 1000, 6, TRUE }, /* fails on win11 */
170 { NULL, 0 }
173 const struct test *test;
174 WCHAR buffer[2000];
175 ULONG ret;
177 if (!pRtlIsDosDeviceName_U)
179 win_skip("RtlIsDosDeviceName_U is not available\n");
180 return;
183 for (test = tests; test->path; test++)
185 pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 );
186 ret = pRtlIsDosDeviceName_U( buffer );
187 ok( ret == MAKELONG( test->len, test->pos ) ||
188 (test->fails && broken( ret == 0 )),
189 "Wrong result (%d,%d)/(%d,%d) for %s\n",
190 HIWORD(ret), LOWORD(ret), test->pos, test->len, test->path );
194 static void test_RtlIsNameLegalDOS8Dot3(void)
196 struct test
198 const char *path;
199 BOOLEAN result;
200 BOOLEAN spaces;
203 static const struct test tests[] =
205 { "12345678", TRUE, FALSE },
206 { "123 5678", TRUE, TRUE },
207 { "12345678.", FALSE, 2 /*not set*/ },
208 { "1234 678.", FALSE, 2 /*not set*/ },
209 { "12345678.a", TRUE, FALSE },
210 { "12345678.a ", FALSE, 2 /*not set*/ },
211 { "12345678.a c", TRUE, TRUE },
212 { " 2345678.a ", FALSE, 2 /*not set*/ },
213 { "1 345678.abc", TRUE, TRUE },
214 { "1 8.a c", TRUE, TRUE },
215 { "1 3 5 7 .abc", FALSE, 2 /*not set*/ },
216 { "12345678. c", TRUE, TRUE },
217 { "123456789.a", FALSE, 2 /*not set*/ },
218 { "12345.abcd", FALSE, 2 /*not set*/ },
219 { "12345.ab d", FALSE, 2 /*not set*/ },
220 { ".abc", FALSE, 2 /*not set*/ },
221 { "12.abc.d", FALSE, 2 /*not set*/ },
222 { ".", TRUE, FALSE },
223 { "..", TRUE, FALSE },
224 { "...", FALSE, 2 /*not set*/ },
225 { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", FALSE, 2 /*not set*/ },
226 { NULL, 0 }
229 const struct test *test;
230 UNICODE_STRING ustr;
231 OEM_STRING oem, oem_ret;
232 WCHAR buffer[200];
233 char buff2[12];
234 BOOLEAN ret, spaces;
236 if (!pRtlIsNameLegalDOS8Dot3)
238 win_skip("RtlIsNameLegalDOS8Dot3 is not available\n");
239 return;
242 ustr.MaximumLength = sizeof(buffer);
243 ustr.Buffer = buffer;
244 for (test = tests; test->path; test++)
246 char path[100];
247 strcpy(path, test->path);
248 oem.Buffer = path;
249 oem.Length = strlen(test->path);
250 oem.MaximumLength = oem.Length + 1;
251 pRtlOemStringToUnicodeString( &ustr, &oem, FALSE );
252 spaces = 2;
253 oem_ret.Length = oem_ret.MaximumLength = sizeof(buff2);
254 oem_ret.Buffer = buff2;
255 ret = pRtlIsNameLegalDOS8Dot3( &ustr, &oem_ret, &spaces );
256 ok( ret == test->result, "Wrong result %d/%d for '%s'\n", ret, test->result, test->path );
257 ok( spaces == test->spaces, "Wrong spaces value %d/%d for '%s'\n", spaces, test->spaces, test->path );
258 if (strlen(test->path) <= 12)
260 STRING test_str;
261 char str[13];
262 strcpy( str, test->path );
263 RtlInitString( &test_str, str );
264 RtlUpperString( &test_str, &test_str );
265 ok( !RtlCompareString(&oem_ret, &test_str, FALSE),
266 "Wrong string '%.*s'/'%s'\n", oem_ret.Length, oem_ret.Buffer, test->path );
270 static void test_RtlGetFullPathName_U(void)
272 static const WCHAR emptyW[] = {0};
273 static const WCHAR deadbeefW[] = {'d','e','a','d','b','e','e','f',0};
275 struct test
277 const char *path;
278 const char *rname;
279 const char *rfile;
280 const char *alt_rname;
281 const char *alt_rfile;
284 static const struct test tests[] =
286 { "c:/test", "c:\\test", "test"},
287 { "c:/test/", "c:\\test\\", NULL},
288 { "c:/test ", "c:\\test", "test"},
289 { "c:/test.", "c:\\test", "test"},
290 { "c:/test .... .. ", "c:\\test", "test"},
291 { "c:/test/ .... .. ", "c:\\test\\", NULL},
292 { "c:/test/..", "c:\\", NULL},
293 { "c:/test/.. ", "c:\\test\\", NULL},
294 { "c:/TEST", "c:\\TEST", "TEST"},
295 { "c:/test/file", "c:\\test\\file", "file"},
296 { "c:/test./file", "c:\\test\\file", "file"},
297 { "c:/test.. /file", "c:\\test.. \\file","file"},
298 { "c:/test/././file", "c:\\test\\file", "file"},
299 { "c:/test\\.\\.\\file", "c:\\test\\file", "file"},
300 { "c:/test/\\.\\.\\file", "c:\\test\\file", "file"},
301 { "c:/test\\\\.\\.\\file", "c:\\test\\file", "file"},
302 { "c:/test\\test1\\..\\.\\file", "c:\\test\\file", "file"},
303 { "c:///test\\.\\.\\file//", "c:\\test\\file\\", NULL,
304 "c:\\test\\file", "file"}, /* nt4 */
305 { "c:///test\\..\\file\\..\\//", "c:\\", NULL},
306 { "c:/test../file", "c:\\test.\\file", "file",
307 "c:\\test..\\file", "file"}, /* vista */
308 { "c:\\test", "c:\\test", "test"},
309 { "C:\\test", "C:\\test", "test"},
310 { "c:/", "c:\\", NULL},
311 { "c:.", "C:\\windows", "windows"},
312 { "c:foo", "C:\\windows\\foo", "foo"},
313 { "c:foo/bar", "C:\\windows\\foo\\bar", "bar"},
314 { "c:./foo", "C:\\windows\\foo", "foo"},
315 { "\\foo", "C:\\foo", "foo"},
316 { "foo", "C:\\windows\\foo", "foo"},
317 { ".", "C:\\windows", "windows"},
318 { "..", "C:\\", NULL},
319 { "...", "C:\\windows\\", NULL},
320 { "./foo", "C:\\windows\\foo", "foo"},
321 { "foo/..", "C:\\windows", "windows"},
322 { "\\windows\\nul", "\\\\.\\nul", NULL},
323 { "C:\\nonexistent\\nul", "\\\\.\\nul", NULL},
324 { "C:\\con\\con", "\\\\.\\con", NULL,
325 "C:\\con\\con", "con"}, /* win11 */
326 { "C:NUL.", "\\\\.\\NUL", NULL},
327 { "C:NUL", "\\\\.\\NUL", NULL},
328 { "AUX", "\\\\.\\AUX", NULL},
329 { "COM1", "\\\\.\\COM1", NULL},
330 { "?<>*\"|:", "C:\\windows\\?<>*\"|:", "?<>*\"|:"},
332 { "\\\\foo", "\\\\foo", NULL},
333 { "//foo", "\\\\foo", NULL},
334 { "\\/foo", "\\\\foo", NULL},
335 { "//", "\\\\", NULL},
336 { "//foo/", "\\\\foo\\", NULL},
338 { "//.", "\\\\.\\", NULL},
339 { "//./", "\\\\.\\", NULL},
340 { "//.//", "\\\\.\\", NULL},
341 { "//./foo", "\\\\.\\foo", "foo"},
342 { "//./foo/", "\\\\.\\foo\\", NULL},
343 { "//./foo/bar", "\\\\.\\foo\\bar", "bar"},
344 { "//./foo/.", "\\\\.\\foo", "foo"},
345 { "//./foo/..", "\\\\.\\", NULL},
347 { "//?/", "\\\\?\\", NULL},
348 { "//?//", "\\\\?\\", NULL},
349 { "//?/foo", "\\\\?\\foo", "foo"},
350 { "//?/foo/", "\\\\?\\foo\\", NULL},
351 { "//?/foo/bar", "\\\\?\\foo\\bar", "bar"},
352 { "//?/foo/.", "\\\\?\\foo", "foo"},
353 { "//?/foo/..", "\\\\?\\", NULL},
355 { "CONIN$", "\\\\.\\CONIN$", NULL,
356 "C:\\windows\\CONIN$", "CONIN$"},
357 { "CONOUT$", "\\\\.\\CONOUT$", NULL,
358 "C:\\windows\\CONOUT$", "CONOUT$"},
360 /* RtlGetFullPathName_U() can't understand the global namespace prefix */
361 { "\\??\\foo", "C:\\??\\foo", "foo"},
362 { 0 }
365 const struct test *test;
366 WCHAR pathbufW[2*MAX_PATH], rbufferW[MAX_PATH];
367 char rbufferA[MAX_PATH], rfileA[MAX_PATH], curdir[MAX_PATH];
368 ULONG ret;
369 WCHAR *file_part;
370 DWORD reslen;
371 UINT len;
373 GetCurrentDirectoryA(sizeof(curdir), curdir);
374 SetCurrentDirectoryA("C:\\windows\\");
376 file_part = (WCHAR *)0xdeadbeef;
377 lstrcpyW(rbufferW, deadbeefW);
378 ret = pRtlGetFullPathName_U(NULL, MAX_PATH, rbufferW, &file_part);
379 ok(!ret, "Expected RtlGetFullPathName_U to return 0, got %lu\n", ret);
380 ok(!lstrcmpW(rbufferW, deadbeefW),
381 "Expected the output buffer to be untouched, got %s\n", wine_dbgstr_w(rbufferW));
382 ok(file_part == (WCHAR *)0xdeadbeef ||
383 file_part == NULL, /* Win7 */
384 "Expected file part pointer to be untouched, got %p\n", file_part);
386 file_part = (WCHAR *)0xdeadbeef;
387 lstrcpyW(rbufferW, deadbeefW);
388 ret = pRtlGetFullPathName_U(emptyW, MAX_PATH, rbufferW, &file_part);
389 ok(!ret, "Expected RtlGetFullPathName_U to return 0, got %lu\n", ret);
390 ok(!lstrcmpW(rbufferW, deadbeefW),
391 "Expected the output buffer to be untouched, got %s\n", wine_dbgstr_w(rbufferW));
392 ok(file_part == (WCHAR *)0xdeadbeef ||
393 file_part == NULL, /* Win7 */
394 "Expected file part pointer to be untouched, got %p\n", file_part);
396 for (test = tests; test->path; test++)
398 len= strlen(test->rname) * sizeof(WCHAR);
399 pRtlMultiByteToUnicodeN(pathbufW , sizeof(pathbufW), NULL, test->path, strlen(test->path)+1 );
400 ret = pRtlGetFullPathName_U( pathbufW,MAX_PATH, rbufferW, &file_part);
401 ok( ret == len || (test->alt_rname && ret == strlen(test->alt_rname)*sizeof(WCHAR)),
402 "Wrong result %ld/%d for \"%s\"\n", ret, len, test->path );
403 ok(pRtlUnicodeToMultiByteN(rbufferA,MAX_PATH,&reslen,rbufferW,(lstrlenW(rbufferW) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
404 "RtlUnicodeToMultiByteN failed\n");
405 ok(!lstrcmpA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpA(rbufferA,test->alt_rname)),
406 "Got \"%s\" expected \"%s\"\n",rbufferA,test->rname);
407 if (file_part)
409 ok(pRtlUnicodeToMultiByteN(rfileA,MAX_PATH,&reslen,file_part,(lstrlenW(file_part) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
410 "RtlUnicodeToMultiByteN failed\n");
411 ok((test->rfile && !lstrcmpA(rfileA,test->rfile)) ||
412 (test->alt_rfile && !lstrcmpA(rfileA,test->alt_rfile)),
413 "Got \"%s\" expected \"%s\"\n",rfileA,test->rfile);
415 else
417 ok( !test->rfile, "Got NULL expected \"%s\"\n", test->rfile );
421 SetCurrentDirectoryA(curdir);
424 static void test_RtlDosPathNameToNtPathName_U(void)
426 char curdir[MAX_PATH];
427 UNICODE_STRING nameW;
428 WCHAR *file_part;
429 NTSTATUS status;
430 BOOL ret;
431 int i;
433 static const struct
435 const WCHAR *dos;
436 const WCHAR *nt;
437 int file_offset; /* offset to file part */
438 const WCHAR *alt_nt;
439 BOOL may_fail;
441 tests[] =
443 {L"c:\\", L"\\??\\c:\\", -1},
444 {L"c:/", L"\\??\\c:\\", -1},
445 {L"c:/foo", L"\\??\\c:\\foo", 7},
446 {L"c:/foo.", L"\\??\\c:\\foo", 7},
447 {L"c:/foo ", L"\\??\\c:\\foo", 7},
448 {L"c:/foo . .", L"\\??\\c:\\foo", 7},
449 {L"c:/foo.a", L"\\??\\c:\\foo.a", 7},
450 {L"c:/foo a", L"\\??\\c:\\foo a", 7},
451 {L"c:/foo*", L"\\??\\c:\\foo*", 7},
452 {L"c:/foo*a", L"\\??\\c:\\foo*a", 7},
453 {L"c:/foo?", L"\\??\\c:\\foo?", 7},
454 {L"c:/foo?a", L"\\??\\c:\\foo?a", 7},
455 {L"c:/foo<", L"\\??\\c:\\foo<", 7},
456 {L"c:/foo<a", L"\\??\\c:\\foo<a", 7},
457 {L"c:/foo>", L"\\??\\c:\\foo>", 7},
458 {L"c:/foo>a", L"\\??\\c:\\foo>a", 7},
459 {L"c:/foo/", L"\\??\\c:\\foo\\", -1},
460 {L"c:/foo//", L"\\??\\c:\\foo\\", -1},
461 {L"C:/foo", L"\\??\\C:\\foo", 7},
462 {L"C:/foo/bar", L"\\??\\C:\\foo\\bar", 11},
463 {L"C:/foo/bar", L"\\??\\C:\\foo\\bar", 11},
464 {L"c:.", L"\\??\\C:\\windows", 7},
465 {L"c:foo", L"\\??\\C:\\windows\\foo", 15},
466 {L"c:foo/bar", L"\\??\\C:\\windows\\foo\\bar", 19},
467 {L"c:./foo", L"\\??\\C:\\windows\\foo", 15},
468 {L"c:/./foo", L"\\??\\c:\\foo", 7},
469 {L"c:/..", L"\\??\\c:\\", -1},
470 {L"c:/foo/.", L"\\??\\c:\\foo", 7},
471 {L"c:/foo/./bar", L"\\??\\c:\\foo\\bar", 11},
472 {L"c:/foo/../bar", L"\\??\\c:\\bar", 7},
473 {L"\\foo", L"\\??\\C:\\foo", 7},
474 {L"foo", L"\\??\\C:\\windows\\foo", 15},
475 {L".", L"\\??\\C:\\windows", 7},
476 {L"./", L"\\??\\C:\\windows\\", -1},
477 {L"..", L"\\??\\C:\\", -1},
478 {L"...", L"\\??\\C:\\windows\\", -1},
479 {L"./foo", L"\\??\\C:\\windows\\foo", 15},
480 {L"foo/..", L"\\??\\C:\\windows", 7},
481 {L"\\windows\\nul", L"\\??\\nul", -1},
482 {L"C:NUL.", L"\\??\\NUL", -1},
483 {L"C:NUL", L"\\??\\NUL", -1},
484 {L"AUX" , L"\\??\\AUX", -1},
485 {L"COM1" , L"\\??\\COM1", -1},
486 {L"?<>*\"|:", L"\\??\\C:\\windows\\?<>*\"|:", 15},
487 {L"?:", L"\\??\\?:\\", -1},
489 {L"\\\\foo", L"\\??\\UNC\\foo", -1},
490 {L"//foo", L"\\??\\UNC\\foo", -1},
491 {L"\\/foo", L"\\??\\UNC\\foo", -1},
492 {L"//", L"\\??\\UNC\\", -1},
493 {L"//foo/", L"\\??\\UNC\\foo\\", -1},
495 {L"//.", L"\\??\\", -1},
496 {L"//./", L"\\??\\", -1},
497 {L"//.//", L"\\??\\", -1},
498 {L"//./foo", L"\\??\\foo", 4},
499 {L"//./foo/", L"\\??\\foo\\", -1},
500 {L"//./foo/bar", L"\\??\\foo\\bar", 8},
501 {L"//./foo/.", L"\\??\\foo", 4},
502 {L"//./foo/..", L"\\??\\", -1},
503 {L"//./foo. . ", L"\\??\\foo", 4},
505 {L"//?", L"\\??\\", -1},
506 {L"//?/", L"\\??\\", -1},
507 {L"//?//", L"\\??\\", -1},
508 {L"//?/foo", L"\\??\\foo", 4},
509 {L"//?/foo/", L"\\??\\foo\\", -1},
510 {L"//?/foo/bar", L"\\??\\foo\\bar", 8},
511 {L"//?/foo/.", L"\\??\\foo", 4},
512 {L"//?/foo/..", L"\\??\\", -1},
513 {L"//?/foo. . ", L"\\??\\foo", 4},
515 {L"\\\\.", L"\\??\\", -1},
516 {L"\\\\.\\", L"\\??\\", -1},
517 {L"\\\\.\\/", L"\\??\\", -1},
518 {L"\\\\.\\foo", L"\\??\\foo", 4},
519 {L"\\\\.\\foo/", L"\\??\\foo\\", -1},
520 {L"\\\\.\\foo/bar", L"\\??\\foo\\bar", 8},
521 {L"\\\\.\\foo/.", L"\\??\\foo", 4},
522 {L"\\\\.\\foo/..", L"\\??\\", -1},
523 {L"\\\\.\\foo. . ", L"\\??\\foo", 4},
524 {L"\\\\.\\CON", L"\\??\\CON", 4, NULL, TRUE}, /* broken on win7 */
525 {L"\\\\.\\CONIN$", L"\\??\\CONIN$", 4},
526 {L"\\\\.\\CONOUT$", L"\\??\\CONOUT$", 4},
528 {L"\\\\?", L"\\??\\", -1},
529 {L"\\\\?\\", L"\\??\\", -1},
531 {L"\\\\?\\/", L"\\??\\/", 4},
532 {L"\\\\?\\foo", L"\\??\\foo", 4},
533 {L"\\\\?\\foo/", L"\\??\\foo/", 4},
534 {L"\\\\?\\foo/bar", L"\\??\\foo/bar", 4},
535 {L"\\\\?\\foo/.", L"\\??\\foo/.", 4},
536 {L"\\\\?\\foo/..", L"\\??\\foo/..", 4},
537 {L"\\\\?\\\\", L"\\??\\\\", -1},
538 {L"\\\\?\\\\\\", L"\\??\\\\\\", -1},
539 {L"\\\\?\\foo\\", L"\\??\\foo\\", -1},
540 {L"\\\\?\\foo\\bar",L"\\??\\foo\\bar", 8},
541 {L"\\\\?\\foo\\.", L"\\??\\foo\\.", 8},
542 {L"\\\\?\\foo\\..", L"\\??\\foo\\..", 8},
543 {L"\\\\?\\foo. . ", L"\\??\\foo. . ", 4},
545 {L"\\??", L"\\??\\C:\\??", 7},
546 {L"\\??\\", L"\\??\\C:\\??\\", -1},
548 {L"\\??\\/", L"\\??\\/", 4},
549 {L"\\??\\foo", L"\\??\\foo", 4},
550 {L"\\??\\foo/", L"\\??\\foo/", 4},
551 {L"\\??\\foo/bar", L"\\??\\foo/bar", 4},
552 {L"\\??\\foo/.", L"\\??\\foo/.", 4},
553 {L"\\??\\foo/..", L"\\??\\foo/..", 4},
554 {L"\\??\\\\", L"\\??\\\\", -1},
555 {L"\\??\\\\\\", L"\\??\\\\\\", -1},
556 {L"\\??\\foo\\", L"\\??\\foo\\", -1},
557 {L"\\??\\foo\\bar", L"\\??\\foo\\bar", 8},
558 {L"\\??\\foo\\.", L"\\??\\foo\\.", 8},
559 {L"\\??\\foo\\..", L"\\??\\foo\\..", 8},
560 {L"\\??\\foo. . ", L"\\??\\foo. . ", 4},
562 {L"CONIN$", L"\\??\\CONIN$", -1, L"\\??\\C:\\windows\\CONIN$" /* win7 */ },
563 {L"CONOUT$", L"\\??\\CONOUT$", -1, L"\\??\\C:\\windows\\CONOUT$" /* win7 */ },
564 {L"cOnOuT$", L"\\??\\cOnOuT$", -1, L"\\??\\C:\\windows\\cOnOuT$" /* win7 */ },
565 {L"CONERR$", L"\\??\\C:\\windows\\CONERR$", 15},
567 static const WCHAR *error_paths[] = {
568 NULL, L"", L" ", L"C:\\nonexistent\\nul"
571 GetCurrentDirectoryA(sizeof(curdir), curdir);
572 SetCurrentDirectoryA("C:\\windows\\");
574 for (i = 0; i < ARRAY_SIZE(error_paths); ++i)
576 winetest_push_context("%s", debugstr_w(error_paths[i]));
578 ret = pRtlDosPathNameToNtPathName_U(error_paths[i], &nameW, &file_part, NULL);
579 ok(!ret, "Got %d.\n", ret);
581 if (pRtlDosPathNameToNtPathName_U_WithStatus)
583 status = pRtlDosPathNameToNtPathName_U_WithStatus(error_paths[i], &nameW, &file_part, NULL);
584 ok(status == STATUS_OBJECT_NAME_INVALID, "Got status %#lx.\n", status);
587 winetest_pop_context();
590 for (i = 0; i < ARRAY_SIZE(tests); ++i)
592 ret = pRtlDosPathNameToNtPathName_U(tests[i].dos, &nameW, &file_part, NULL);
593 if (!ret && tests[i].may_fail)
595 win_skip("skipping broken %s\n", debugstr_w(tests[i].dos));
596 continue;
598 ok(ret == TRUE, "%s: Got %d.\n", debugstr_w(tests[i].dos), ret);
600 if (pRtlDosPathNameToNtPathName_U_WithStatus)
602 RtlFreeUnicodeString(&nameW);
603 status = pRtlDosPathNameToNtPathName_U_WithStatus(tests[i].dos, &nameW, &file_part, NULL);
604 ok(status == STATUS_SUCCESS, "%s: Got status %#lx.\n", debugstr_w(tests[i].dos), status);
607 ok(!wcscmp(nameW.Buffer, tests[i].nt)
608 || (tests[i].alt_nt && broken(!wcscmp(nameW.Buffer, tests[i].alt_nt))),
609 "%s: Expected %s, got %s.\n", debugstr_w(tests[i].dos),
610 debugstr_w(tests[i].nt), debugstr_w(nameW.Buffer));
612 if (!wcscmp(nameW.Buffer, tests[i].nt))
614 if (tests[i].file_offset > 0)
615 ok(file_part == nameW.Buffer + tests[i].file_offset,
616 "%s: Expected file part %s, got %s.\n", debugstr_w(tests[i].dos),
617 debugstr_w(nameW.Buffer + tests[i].file_offset), debugstr_w(file_part));
618 else
619 ok(file_part == NULL, "%s: Expected NULL file part, got %s.\n",
620 debugstr_w(tests[i].dos), debugstr_w(file_part));
623 RtlFreeUnicodeString(&nameW);
626 SetCurrentDirectoryA(curdir);
629 static void test_nt_names(void)
631 static const struct { const WCHAR *root, *name; NTSTATUS expect, broken; } tests[] =
633 { NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll", STATUS_SUCCESS },
634 { NULL, L"\\??\\C:\\\\windows\\system32\\kernel32.dll", STATUS_SUCCESS, STATUS_OBJECT_NAME_INVALID },
635 { NULL, L"\\??\\C:\\windows\\system32\\", STATUS_FILE_IS_A_DIRECTORY },
636 { NULL, L"\\??\\C:\\\\\\windows\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
637 { NULL, L"\\??\\C:\\windows\\\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
638 { NULL, L"\\??\\C:\\windows\\system32\\.\\kernel32.dll", STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND },
639 { NULL, L"\\??\\C:\\windows\\system32\\..\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
640 { NULL, L"\\??\\C:\\.\\windows\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND },
641 { NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll ", STATUS_OBJECT_NAME_NOT_FOUND },
642 { NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll..", STATUS_OBJECT_NAME_NOT_FOUND },
643 { NULL, L"\\??\\C:\\windows \\system32 \\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
644 { NULL, L"\\??\\C:\\windows.\\system32.\\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
645 { NULL, L"\\??\\C:\\windows/system32/kernel32.dll", STATUS_OBJECT_NAME_INVALID },
646 { NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll*", STATUS_OBJECT_NAME_INVALID },
647 { NULL, L"\\??\\C:\\windows\\system32?\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
648 { NULL, L"C:\\windows\\system32?\\kernel32.dll", STATUS_OBJECT_PATH_SYNTAX_BAD },
649 { NULL, L"/??\\C:\\windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_SYNTAX_BAD },
650 { NULL, L"\\??" L"/C:\\windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
651 { NULL, L"\\??\\C:/windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_NOT_FOUND },
652 { NULL, L"\\??\\C:\\windows\\system32\\", STATUS_FILE_IS_A_DIRECTORY },
653 { NULL, L"\\??\\C:\\windows\\SyStEm32\\", STATUS_FILE_IS_A_DIRECTORY },
654 { NULL, L"\\??\\C:\\windows\\system32\\\\", STATUS_OBJECT_NAME_INVALID },
655 { NULL, L"\\??\\C:\\windows\\system32\\foobar\\", STATUS_OBJECT_NAME_NOT_FOUND },
656 { NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll\\", STATUS_OBJECT_NAME_INVALID },
657 { NULL, L"\\??\\C:\\windows\\system32\\kernel32.dll\\foo", STATUS_OBJECT_PATH_NOT_FOUND },
658 { NULL, L"\\??\\C:\\windows\\system32\\Kernel32.Dll\\", STATUS_OBJECT_NAME_INVALID },
659 { NULL, L"\\??\\C:\\windows\\system32\\Kernel32.Dll\\foo", STATUS_OBJECT_PATH_NOT_FOUND },
660 { NULL, L"\\??\\C:\\windows\\sys\001", STATUS_OBJECT_NAME_INVALID },
661 { L"\\??\\", NULL, STATUS_OBJECT_NAME_INVALID },
662 { L"\\??\\C:\\", NULL, STATUS_SUCCESS },
663 { L"\\??\\C:\\\\", NULL, STATUS_SUCCESS, STATUS_OBJECT_NAME_INVALID },
664 { L"/??\\C:\\", NULL, STATUS_OBJECT_PATH_SYNTAX_BAD },
665 { L"\\??\\C:/", NULL, STATUS_OBJECT_NAME_NOT_FOUND },
666 { L"\\??" L"/C:", NULL, STATUS_OBJECT_NAME_NOT_FOUND },
667 { L"\\??" L"/C:\\", NULL, STATUS_OBJECT_PATH_NOT_FOUND },
668 { L"\\??\\C:\\windows", NULL, STATUS_SUCCESS },
669 { L"\\??\\C:\\windows\\", NULL, STATUS_SUCCESS },
670 { L"\\??\\C:\\windows\\.", NULL, STATUS_OBJECT_NAME_INVALID },
671 { L"\\??\\C:\\windows\\.\\", NULL, STATUS_OBJECT_NAME_INVALID },
672 { L"\\??\\C:\\windows\\..", NULL, STATUS_OBJECT_NAME_INVALID },
673 { L"\\??\\C:\\windows\\..\\", NULL, STATUS_OBJECT_NAME_INVALID },
674 { L"\\??\\C:\\", L"windows\\system32\\kernel32.dll", STATUS_SUCCESS },
675 { L"\\??\\C:\\\\", L"windows\\system32\\kernel32.dll", STATUS_SUCCESS, STATUS_OBJECT_NAME_INVALID },
676 { L"\\??\\C:\\windows", L"system32\\kernel32.dll", STATUS_SUCCESS },
677 { L"\\??\\C:\\windows\\", L"system32\\kernel32.dll", STATUS_SUCCESS },
678 { L"\\??\\C:\\windows\\", L"system32\\", STATUS_FILE_IS_A_DIRECTORY },
679 { L"\\??\\C:\\windows\\", L"SyStEm32\\", STATUS_FILE_IS_A_DIRECTORY },
680 { L"\\??\\C:\\windows\\", L"system32\\\\", STATUS_OBJECT_NAME_INVALID },
681 { L"\\??\\C:\\windows\\", L"system32\\foobar\\", STATUS_OBJECT_NAME_NOT_FOUND },
682 { L"\\??\\C:\\windows\\", L"system32\\kernel32.dll\\", STATUS_OBJECT_NAME_INVALID },
683 { L"\\??\\C:\\windows\\", L"system32\\kernel32.dll\\foo", STATUS_OBJECT_PATH_NOT_FOUND },
684 { L"\\??\\C:\\windows\\", L"system32\\Kernel32.Dll\\", STATUS_OBJECT_NAME_INVALID },
685 { L"\\??\\C:\\windows\\", L"system32\\Kernel32.Dll\\foo", STATUS_OBJECT_PATH_NOT_FOUND },
686 { L"\\??\\C:\\windows\\", L"\\system32\\kernel32.dll", STATUS_INVALID_PARAMETER },
687 { L"\\??\\C:\\windows\\", L"/system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
688 { L"\\??\\C:\\windows\\", L".\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_PATH_NOT_FOUND },
689 { L"\\??\\C:\\windows\\", L"..\\windows\\system32\\kernel32.dll", STATUS_OBJECT_NAME_INVALID },
690 { L"\\??\\C:\\windows\\", L".", STATUS_OBJECT_NAME_INVALID },
691 { L"\\??\\C:\\windows\\", L"..", STATUS_OBJECT_NAME_INVALID },
692 { L"\\??\\C:\\windows\\", L"sys\001", STATUS_OBJECT_NAME_INVALID },
693 { L"C:\\", L"windows\\system32\\kernel32.dll", STATUS_OBJECT_PATH_SYNTAX_BAD },
695 unsigned int i;
696 OBJECT_ATTRIBUTES attr;
697 UNICODE_STRING nameW;
698 IO_STATUS_BLOCK io;
699 NTSTATUS status;
700 HANDLE handle;
702 InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
704 for (i = 0; i < ARRAY_SIZE(tests); i++)
706 attr.RootDirectory = 0;
707 handle = 0;
708 status = STATUS_SUCCESS;
709 if (tests[i].root)
711 RtlInitUnicodeString( &nameW, tests[i].root );
712 status = pNtOpenFile( &attr.RootDirectory, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io,
713 FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT |
714 FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE );
716 if (!status && tests[i].name)
718 RtlInitUnicodeString( &nameW, tests[i].name );
719 status = pNtOpenFile( &handle, FILE_GENERIC_READ, &attr, &io, FILE_SHARE_READ,
720 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE );
722 if (attr.RootDirectory) NtClose( attr.RootDirectory );
723 if (handle) NtClose( handle );
724 ok( status == tests[i].expect || broken( tests[i].broken && status == tests[i].broken ),
725 "%u: got %lx / %lx for %s + %s\n", i, status, tests[i].expect,
726 debugstr_w( tests[i].root ), debugstr_w( tests[i].name ));
731 START_TEST(path)
733 HMODULE mod = GetModuleHandleA("ntdll.dll");
735 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN");
736 pRtlUnicodeToMultiByteN = (void *)GetProcAddress(mod,"RtlUnicodeToMultiByteN");
737 pRtlDetermineDosPathNameType_U = (void *)GetProcAddress(mod,"RtlDetermineDosPathNameType_U");
738 pRtlIsDosDeviceName_U = (void *)GetProcAddress(mod,"RtlIsDosDeviceName_U");
739 pRtlOemStringToUnicodeString = (void *)GetProcAddress(mod,"RtlOemStringToUnicodeString");
740 pRtlIsNameLegalDOS8Dot3 = (void *)GetProcAddress(mod,"RtlIsNameLegalDOS8Dot3");
741 pRtlGetFullPathName_U = (void *)GetProcAddress(mod,"RtlGetFullPathName_U");
742 pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U");
743 pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus");
744 pNtOpenFile = (void *)GetProcAddress(mod, "NtOpenFile");
746 test_RtlDetermineDosPathNameType_U();
747 test_RtlIsDosDeviceName_U();
748 test_RtlIsNameLegalDOS8Dot3();
749 test_RtlGetFullPathName_U();
750 test_RtlDosPathNameToNtPathName_U();
751 test_nt_names();