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"
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)
44 static const struct test tests
[] =
84 { "\\\\.\\CONIN$", 6 },
85 { "\\\\.\\CONOUT$", 6 },
89 const struct test
*test
;
90 WCHAR buffer
[MAX_PATH
];
93 if (!pRtlDetermineDosPathNameType_U
)
95 win_skip("RtlDetermineDosPathNameType_U is not available\n");
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)
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 },
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 },
138 { " . . . :", 0, 0 },
140 { "c:nul. . . :", 4, 6 },
141 { "c:nul . . :", 4, 6 },
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 */
150 { "c:com5:", 4, 8, TRUE
}, /* fails on win11 */
153 { "c:\\lpt0.txt", 0, 0 },
154 { "CONIN$", 0, 12, TRUE
}, /* fails on win7 */
155 { "CONOUT$", 0, 14, TRUE
}, /* fails on win7 */
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 */
173 const struct test
*test
;
177 if (!pRtlIsDosDeviceName_U
)
179 win_skip("RtlIsDosDeviceName_U is not available\n");
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)
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*/ },
229 const struct test
*test
;
231 OEM_STRING oem
, oem_ret
;
236 if (!pRtlIsNameLegalDOS8Dot3
)
238 win_skip("RtlIsNameLegalDOS8Dot3 is not available\n");
242 ustr
.MaximumLength
= sizeof(buffer
);
243 ustr
.Buffer
= buffer
;
244 for (test
= tests
; test
->path
; test
++)
247 strcpy(path
, test
->path
);
249 oem
.Length
= strlen(test
->path
);
250 oem
.MaximumLength
= oem
.Length
+ 1;
251 pRtlOemStringToUnicodeString( &ustr
, &oem
, FALSE
);
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)
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};
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"},
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
];
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
);
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
);
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
;
437 int file_offset
; /* offset to file part */
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
));
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
));
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
},
696 OBJECT_ATTRIBUTES attr
;
697 UNICODE_STRING nameW
;
702 InitializeObjectAttributes( &attr
, &nameW
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
704 for (i
= 0; i
< ARRAY_SIZE(tests
); i
++)
706 attr
.RootDirectory
= 0;
708 status
= STATUS_SUCCESS
;
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
));
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();