[NTDLL_WINETEST] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / modules / rostests / winetests / ntdll / path.c
1 /*
2 * Unit test suite for ntdll path functions
3 *
4 * Copyright 2002 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "ntdll_test.h"
22
23 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
24 LPCSTR src, DWORD srclen );
25 static NTSTATUS (WINAPI *pRtlUnicodeToMultiByteN)(LPSTR,DWORD,LPDWORD,LPCWSTR,DWORD);
26 static UINT (WINAPI *pRtlDetermineDosPathNameType_U)( PCWSTR path );
27 static ULONG (WINAPI *pRtlIsDosDeviceName_U)( PCWSTR dos_name );
28 static NTSTATUS (WINAPI *pRtlOemStringToUnicodeString)(UNICODE_STRING *, const STRING *, BOOLEAN );
29 static BOOLEAN (WINAPI *pRtlIsNameLegalDOS8Dot3)(const UNICODE_STRING*,POEM_STRING,PBOOLEAN);
30 static DWORD (WINAPI *pRtlGetFullPathName_U)(const WCHAR*,ULONG,WCHAR*,WCHAR**);
31 static NTSTATUS (WINAPI *pRtlDosPathNameToNtPathName_U_WithStatus)(const WCHAR*, UNICODE_STRING*, WCHAR**, CURDIR*);
32
33 static void test_RtlDetermineDosPathNameType_U(void)
34 {
35 struct test
36 {
37 const char *path;
38 UINT ret;
39 };
40
41 static const struct test tests[] =
42 {
43 { "\\\\foo", 1 },
44 { "//foo", 1 },
45 { "\\/foo", 1 },
46 { "/\\foo", 1 },
47 { "\\\\", 1 },
48 { "//", 1 },
49 { "c:\\foo", 2 },
50 { "c:/foo", 2 },
51 { "c://foo", 2 },
52 { "c:\\", 2 },
53 { "c:/", 2 },
54 { "c:foo", 3 },
55 { "c:f\\oo", 3 },
56 { "c:foo/bar", 3 },
57 { "\\foo", 4 },
58 { "/foo", 4 },
59 { "\\", 4 },
60 { "/", 4 },
61 { "foo", 5 },
62 { "", 5 },
63 { "\0:foo", 5 },
64 { "\\\\.\\foo", 6 },
65 { "//./foo", 6 },
66 { "/\\./foo", 6 },
67 { "\\\\.foo", 1 },
68 { "//.foo", 1 },
69 { "\\\\.", 7 },
70 { "//.", 7 },
71 { NULL, 0 }
72 };
73
74 const struct test *test;
75 WCHAR buffer[MAX_PATH];
76 UINT ret;
77
78 if (!pRtlDetermineDosPathNameType_U)
79 {
80 win_skip("RtlDetermineDosPathNameType_U is not available\n");
81 return;
82 }
83
84 for (test = tests; test->path; test++)
85 {
86 pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 );
87 ret = pRtlDetermineDosPathNameType_U( buffer );
88 ok( ret == test->ret, "Wrong result %d/%d for %s\n", ret, test->ret, test->path );
89 }
90 }
91
92
93 static void test_RtlIsDosDeviceName_U(void)
94 {
95 struct test
96 {
97 const char *path;
98 WORD pos;
99 WORD len;
100 BOOL fails;
101 };
102
103 static const struct test tests[] =
104 {
105 { "\\\\.\\CON", 8, 6, TRUE }, /* fails on win8 */
106 { "\\\\.\\con", 8, 6, TRUE }, /* fails on win8 */
107 { "\\\\.\\CON2", 0, 0 },
108 { "", 0, 0 },
109 { "\\\\foo\\nul", 0, 0 },
110 { "c:\\nul:", 6, 6 },
111 { "c:\\nul\\", 0, 0 },
112 { "c:\\nul\\foo", 0, 0 },
113 { "c:\\nul::", 6, 6, TRUE }, /* fails on nt4 */
114 { "c:\\nul::::::", 6, 6, TRUE }, /* fails on nt4 */
115 { "c:prn ", 4, 6 },
116 { "c:prn.......", 4, 6 },
117 { "c:prn... ...", 4, 6 },
118 { "c:NUL .... ", 4, 6, TRUE }, /* fails on nt4 */
119 { "c: . . .", 0, 0 },
120 { "c:", 0, 0 },
121 { " . . . :", 0, 0 },
122 { ":", 0, 0 },
123 { "c:nul. . . :", 4, 6 },
124 { "c:nul . . :", 4, 6, TRUE }, /* fails on nt4 */
125 { "c:nul0", 0, 0 },
126 { "c:prn:aaa", 4, 6, TRUE }, /* fails on win9x */
127 { "c:PRN:.txt", 4, 6 },
128 { "c:aux:.txt...", 4, 6 },
129 { "c:prn:.txt:", 4, 6 },
130 { "c:nul:aaa", 4, 6, TRUE }, /* fails on win9x */
131 { "con:", 0, 6 },
132 { "lpt1:", 0, 8 },
133 { "c:com5:", 4, 8 },
134 { "CoM4:", 0, 8 },
135 { "lpt9:", 0, 8 },
136 { "c:\\lpt0.txt", 0, 0 },
137 { "c:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
138 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
139 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
140 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
141 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
142 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
143 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\nul.txt", 1000, 6 },
144 // ReactOS r54114
145 { "c:\\nul", 6, 6 },
146 { NULL, 0 }
147 };
148
149 const struct test *test;
150 WCHAR buffer[2000];
151 ULONG ret;
152
153 if (!pRtlIsDosDeviceName_U)
154 {
155 win_skip("RtlIsDosDeviceName_U is not available\n");
156 return;
157 }
158
159 for (test = tests; test->path; test++)
160 {
161 pRtlMultiByteToUnicodeN( buffer, sizeof(buffer), NULL, test->path, strlen(test->path)+1 );
162 ret = pRtlIsDosDeviceName_U( buffer );
163 ok( ret == MAKELONG( test->len, test->pos ) ||
164 (test->fails && broken( ret == 0 )),
165 "Wrong result (%d,%d)/(%d,%d) for %s\n",
166 HIWORD(ret), LOWORD(ret), test->pos, test->len, test->path );
167 }
168 }
169
170 static void test_RtlIsNameLegalDOS8Dot3(void)
171 {
172 struct test
173 {
174 const char *path;
175 BOOLEAN result;
176 BOOLEAN spaces;
177 };
178
179 static const struct test tests[] =
180 {
181 { "12345678", TRUE, FALSE },
182 { "123 5678", TRUE, TRUE },
183 { "12345678.", FALSE, 2 /*not set*/ },
184 { "1234 678.", FALSE, 2 /*not set*/ },
185 { "12345678.a", TRUE, FALSE },
186 { "12345678.a ", FALSE, 2 /*not set*/ },
187 { "12345678.a c", TRUE, TRUE },
188 { " 2345678.a ", FALSE, 2 /*not set*/ },
189 { "1 345678.abc", TRUE, TRUE },
190 { "1 8.a c", TRUE, TRUE },
191 { "1 3 5 7 .abc", FALSE, 2 /*not set*/ },
192 { "12345678. c", TRUE, TRUE },
193 { "123456789.a", FALSE, 2 /*not set*/ },
194 { "12345.abcd", FALSE, 2 /*not set*/ },
195 { "12345.ab d", FALSE, 2 /*not set*/ },
196 { ".abc", FALSE, 2 /*not set*/ },
197 { "12.abc.d", FALSE, 2 /*not set*/ },
198 { ".", TRUE, FALSE },
199 { "..", TRUE, FALSE },
200 { "...", FALSE, 2 /*not set*/ },
201 { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", FALSE, 2 /*not set*/ },
202 { NULL, 0 }
203 };
204
205 const struct test *test;
206 UNICODE_STRING ustr;
207 OEM_STRING oem, oem_ret;
208 WCHAR buffer[200];
209 char buff2[12];
210 BOOLEAN ret, spaces;
211
212 if (!pRtlIsNameLegalDOS8Dot3)
213 {
214 win_skip("RtlIsNameLegalDOS8Dot3 is not available\n");
215 return;
216 }
217
218 ustr.MaximumLength = sizeof(buffer);
219 ustr.Buffer = buffer;
220 for (test = tests; test->path; test++)
221 {
222 char path[100];
223 strcpy(path, test->path);
224 oem.Buffer = path;
225 oem.Length = strlen(test->path);
226 oem.MaximumLength = oem.Length + 1;
227 pRtlOemStringToUnicodeString( &ustr, &oem, FALSE );
228 spaces = 2;
229 oem_ret.Length = oem_ret.MaximumLength = sizeof(buff2);
230 oem_ret.Buffer = buff2;
231 ret = pRtlIsNameLegalDOS8Dot3( &ustr, &oem_ret, &spaces );
232 ok( ret == test->result, "Wrong result %d/%d for '%s'\n", ret, test->result, test->path );
233 ok( spaces == test->spaces, "Wrong spaces value %d/%d for '%s'\n", spaces, test->spaces, test->path );
234 if (strlen(test->path) <= 12)
235 {
236 char str[13];
237 int i;
238 strcpy( str, test->path );
239 for (i = 0; str[i]; i++) str[i] = toupper(str[i]);
240 ok( oem_ret.Length == strlen(test->path), "Wrong length %d/%d for '%s'\n",
241 oem_ret.Length, lstrlenA(test->path), test->path );
242 ok( !memcmp( oem_ret.Buffer, str, oem_ret.Length ),
243 "Wrong string '%.*s'/'%s'\n", oem_ret.Length, oem_ret.Buffer, str );
244 }
245 }
246 }
247 static void test_RtlGetFullPathName_U(void)
248 {
249 static const WCHAR emptyW[] = {0};
250 static const WCHAR deadbeefW[] = {'d','e','a','d','b','e','e','f',0};
251
252 struct test
253 {
254 const char *path;
255 const char *rname;
256 const char *rfile;
257 const char *alt_rname;
258 const char *alt_rfile;
259 };
260
261 static const struct test tests[] =
262 {
263 { "c:/test", "c:\\test", "test"},
264 { "c:/test ", "c:\\test", "test"},
265 { "c:/test.", "c:\\test", "test"},
266 { "c:/test .... .. ", "c:\\test", "test"},
267 { "c:/test/ .... .. ", "c:\\test\\", NULL},
268 { "c:/test/..", "c:\\", NULL},
269 { "c:/test/.. ", "c:\\test\\", NULL},
270 { "c:/TEST", "c:\\TEST", "TEST"},
271 { "c:/test/file", "c:\\test\\file", "file"},
272 { "c:/test./file", "c:\\test\\file", "file"},
273 { "c:/test.. /file", "c:\\test.. \\file","file"},
274 { "c:/test/././file", "c:\\test\\file", "file"},
275 { "c:/test\\.\\.\\file", "c:\\test\\file", "file"},
276 { "c:/test/\\.\\.\\file", "c:\\test\\file", "file"},
277 { "c:/test\\\\.\\.\\file", "c:\\test\\file", "file"},
278 { "c:/test\\test1\\..\\.\\file", "c:\\test\\file", "file"},
279 { "c:///test\\.\\.\\file//", "c:\\test\\file\\", NULL,
280 "c:\\test\\file", "file"}, /* nt4 */
281 { "c:///test\\..\\file\\..\\//", "c:\\", NULL},
282 { "c:/test../file", "c:\\test.\\file", "file",
283 "c:\\test..\\file", "file"}, /* vista */
284 { "c:\\test", "c:\\test", "test"},
285 { NULL, NULL, NULL}
286 };
287
288 const struct test *test;
289 WCHAR pathbufW[2*MAX_PATH], rbufferW[MAX_PATH];
290 CHAR rbufferA[MAX_PATH], rfileA[MAX_PATH];
291 ULONG ret;
292 WCHAR *file_part;
293 DWORD reslen;
294 UINT len;
295
296 if (!pRtlGetFullPathName_U)
297 {
298 win_skip("RtlGetFullPathName_U is not available\n");
299 return;
300 }
301
302 file_part = (WCHAR *)0xdeadbeef;
303 lstrcpyW(rbufferW, deadbeefW);
304 ret = pRtlGetFullPathName_U(NULL, MAX_PATH, rbufferW, &file_part);
305 ok(!ret, "Expected RtlGetFullPathName_U to return 0, got %u\n", ret);
306 ok(!lstrcmpW(rbufferW, deadbeefW),
307 "Expected the output buffer to be untouched, got %s\n", wine_dbgstr_w(rbufferW));
308 ok(file_part == (WCHAR *)0xdeadbeef ||
309 file_part == NULL, /* Win7 */
310 "Expected file part pointer to be untouched, got %p\n", file_part);
311
312 file_part = (WCHAR *)0xdeadbeef;
313 lstrcpyW(rbufferW, deadbeefW);
314 ret = pRtlGetFullPathName_U(emptyW, MAX_PATH, rbufferW, &file_part);
315 ok(!ret, "Expected RtlGetFullPathName_U to return 0, got %u\n", ret);
316 ok(!lstrcmpW(rbufferW, deadbeefW),
317 "Expected the output buffer to be untouched, got %s\n", wine_dbgstr_w(rbufferW));
318 ok(file_part == (WCHAR *)0xdeadbeef ||
319 file_part == NULL, /* Win7 */
320 "Expected file part pointer to be untouched, got %p\n", file_part);
321
322 for (test = tests; test->path; test++)
323 {
324 len= strlen(test->rname) * sizeof(WCHAR);
325 pRtlMultiByteToUnicodeN(pathbufW , sizeof(pathbufW), NULL, test->path, strlen(test->path)+1 );
326 ret = pRtlGetFullPathName_U( pathbufW,MAX_PATH, rbufferW, &file_part);
327 ok( ret == len || (test->alt_rname && ret == strlen(test->alt_rname)*sizeof(WCHAR)),
328 "Wrong result %d/%d for \"%s\"\n", ret, len, test->path );
329 ok(pRtlUnicodeToMultiByteN(rbufferA,MAX_PATH,&reslen,rbufferW,(lstrlenW(rbufferW) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
330 "RtlUnicodeToMultiByteN failed\n");
331 ok(!lstrcmpA(rbufferA,test->rname) || (test->alt_rname && !lstrcmpA(rbufferA,test->alt_rname)),
332 "Got \"%s\" expected \"%s\"\n",rbufferA,test->rname);
333 if (file_part)
334 {
335 ok(pRtlUnicodeToMultiByteN(rfileA,MAX_PATH,&reslen,file_part,(lstrlenW(file_part) + 1) * sizeof(WCHAR)) == STATUS_SUCCESS,
336 "RtlUnicodeToMultiByteN failed\n");
337 ok((test->rfile && !lstrcmpA(rfileA,test->rfile)) ||
338 (test->alt_rfile && !lstrcmpA(rfileA,test->alt_rfile)),
339 "Got \"%s\" expected \"%s\"\n",rfileA,test->rfile);
340 }
341 else
342 {
343 ok( !test->rfile, "Got NULL expected \"%s\"\n", test->rfile );
344 }
345 }
346 }
347
348 static void test_RtlDosPathNameToNtPathName_U_WithStatus(void)
349 {
350 static const WCHAR emptyW[] = { 0 };
351 WCHAR path[MAX_PATH];
352 UNICODE_STRING nameW;
353 NTSTATUS status;
354
355 if (!pRtlDosPathNameToNtPathName_U_WithStatus)
356 {
357 win_skip("RtlDosPathNameToNtPathName_U_WithStatus() is not supported.\n");
358 return;
359 }
360
361 GetCurrentDirectoryW( MAX_PATH, path );
362
363 status = pRtlDosPathNameToNtPathName_U_WithStatus( path, &nameW, NULL, NULL );
364 ok(!status, "Failed convert to nt path, %#x.\n", status);
365
366 status = pRtlDosPathNameToNtPathName_U_WithStatus( NULL, &nameW, NULL, NULL );
367 ok(status == STATUS_OBJECT_NAME_INVALID || broken(status == STATUS_OBJECT_PATH_NOT_FOUND) /* W2k3 */,
368 "Unexpected status %#x.\n", status);
369
370 status = pRtlDosPathNameToNtPathName_U_WithStatus( emptyW, &nameW, NULL, NULL );
371 ok(status == STATUS_OBJECT_NAME_INVALID || broken(status == STATUS_OBJECT_PATH_NOT_FOUND) /* W2k3 */,
372 "Unexpected status %#x.\n", status);
373
374 RtlFreeUnicodeString( &nameW );
375 }
376
377 START_TEST(path)
378 {
379 HMODULE mod = GetModuleHandleA("ntdll.dll");
380 if (!mod)
381 {
382 win_skip("Not running on NT, skipping tests\n");
383 return;
384 }
385
386 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(mod,"RtlMultiByteToUnicodeN");
387 pRtlUnicodeToMultiByteN = (void *)GetProcAddress(mod,"RtlUnicodeToMultiByteN");
388 pRtlDetermineDosPathNameType_U = (void *)GetProcAddress(mod,"RtlDetermineDosPathNameType_U");
389 pRtlIsDosDeviceName_U = (void *)GetProcAddress(mod,"RtlIsDosDeviceName_U");
390 pRtlOemStringToUnicodeString = (void *)GetProcAddress(mod,"RtlOemStringToUnicodeString");
391 pRtlIsNameLegalDOS8Dot3 = (void *)GetProcAddress(mod,"RtlIsNameLegalDOS8Dot3");
392 pRtlGetFullPathName_U = (void *)GetProcAddress(mod,"RtlGetFullPathName_U");
393 pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus");
394
395 test_RtlDetermineDosPathNameType_U();
396 test_RtlIsDosDeviceName_U();
397 test_RtlIsNameLegalDOS8Dot3();
398 test_RtlGetFullPathName_U();
399 test_RtlDosPathNameToNtPathName_U_WithStatus();
400 }