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 } 401