1 /* Unit test suite for Ntdll directory functions 2 * 3 * Copyright 2007 Jeff Latimer 4 * Copyright 2007 Andrey Turkin 5 * Copyright 2008 Jeff Zaroyko 6 * Copyright 2009 Dan Kegel 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 * 22 * NOTES 23 * We use function pointers here as there is no import library for NTDLL on 24 * windows. 25 */ 26 27 #include "ntdll_test.h" 28 29 static NTSTATUS (WINAPI *pNtClose)( PHANDLE ); 30 static NTSTATUS (WINAPI *pNtOpenFile) ( PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG ); 31 static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK, 32 PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN); 33 static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,LONG,FILE_INFORMATION_CLASS); 34 static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FILE_INFORMATION_CLASS); 35 static BOOLEAN (WINAPI *pRtlCreateUnicodeStringFromAsciiz)(PUNICODE_STRING,LPCSTR); 36 static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* ); 37 static VOID (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR ); 38 static VOID (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING ); 39 static LONG (WINAPI *pRtlCompareUnicodeString)( const UNICODE_STRING*, const UNICODE_STRING*,BOOLEAN ); 40 static NTSTATUS (WINAPI *pRtlMultiByteToUnicodeN)( LPWSTR dst, DWORD dstlen, LPDWORD reslen, 41 LPCSTR src, DWORD srclen ); 42 static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirection)( BOOLEAN enable ); 43 static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG *old_value ); 44 45 /* The attribute sets to test */ 46 static struct testfile_s { 47 BOOL attr_done; /* set if attributes were tested for this file already */ 48 const DWORD attr; /* desired attribute */ 49 WCHAR name[20]; /* filename to use */ 50 const char *target; /* what to point to (only for reparse pts) */ 51 const char *description; /* for error messages */ 52 int nfound; /* How many were found (expect 1) */ 53 } testfiles[] = { 54 { 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, 55 { 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, 56 { 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, 57 { 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, 58 { 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, 59 { 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, 60 { 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, 61 { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, 62 { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, 63 { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } 64 }; 65 static const int test_dir_count = sizeof(testfiles) / sizeof(testfiles[0]); 66 static const int max_test_dir_size = sizeof(testfiles) / sizeof(testfiles[0]) + 5; /* size of above plus some for .. etc */ 67 68 static const WCHAR dummyW[] = {'d','u','m','m','y',0}; 69 static const WCHAR dotW[] = {'.',0}; 70 static const WCHAR dotdotW[] = {'.','.',0}; 71 static const WCHAR backslashW[] = {'\\',0}; 72 73 /* Create a test directory full of attribute test files, clear counts */ 74 static void set_up_attribute_test(const WCHAR *testdir) 75 { 76 int i; 77 BOOL ret; 78 79 ret = CreateDirectoryW(testdir, NULL); 80 ok(ret, "couldn't create dir %s, error %d\n", wine_dbgstr_w(testdir), GetLastError()); 81 82 for (i=0; i < test_dir_count; i++) { 83 WCHAR buf[MAX_PATH]; 84 85 if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0) 86 continue; 87 lstrcpyW( buf, testdir ); 88 lstrcatW( buf, backslashW ); 89 lstrcatW( buf, testfiles[i].name ); 90 if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { 91 ret = CreateDirectoryW(buf, NULL); 92 ok(ret, "couldn't create dir %s, error %d\n", wine_dbgstr_w(buf), GetLastError()); 93 } else { 94 HANDLE h = CreateFileW(buf, 95 GENERIC_READ|GENERIC_WRITE, 96 0, NULL, CREATE_ALWAYS, 97 testfiles[i].attr, 0); 98 ok( h != INVALID_HANDLE_VALUE, "failed to create temp file %s\n", wine_dbgstr_w(buf) ); 99 CloseHandle(h); 100 } 101 } 102 } 103 104 static void reset_found_files(void) 105 { 106 int i; 107 108 for (i = 0; i < test_dir_count; i++) 109 testfiles[i].nfound = 0; 110 } 111 112 /* Remove the given test directory and the attribute test files, if any */ 113 static void tear_down_attribute_test(const WCHAR *testdir) 114 { 115 int i; 116 117 for (i = 0; i < test_dir_count; i++) { 118 int ret; 119 WCHAR buf[MAX_PATH]; 120 if (lstrcmpW(testfiles[i].name, dotW) == 0 || lstrcmpW(testfiles[i].name, dotdotW) == 0) 121 continue; 122 lstrcpyW( buf, testdir ); 123 lstrcatW( buf, backslashW ); 124 lstrcatW( buf, testfiles[i].name ); 125 if (testfiles[i].attr & FILE_ATTRIBUTE_DIRECTORY) { 126 ret = RemoveDirectoryW(buf); 127 ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), 128 "Failed to rmdir %s, error %d\n", wine_dbgstr_w(buf), GetLastError()); 129 } else { 130 ret = DeleteFileW(buf); 131 ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), 132 "Failed to rm %s, error %d\n", wine_dbgstr_w(buf), GetLastError()); 133 } 134 } 135 RemoveDirectoryW(testdir); 136 } 137 138 /* Match one found file against testfiles[], increment count if found */ 139 static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) 140 { 141 int i; 142 DWORD attribmask = 143 (FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT); 144 DWORD attrib = dir_info->FileAttributes & attribmask; 145 WCHAR *nameW = dir_info->FileName; 146 int namelen = dir_info->FileNameLength / sizeof(WCHAR); 147 148 for (i = 0; i < test_dir_count; i++) { 149 int len = lstrlenW(testfiles[i].name); 150 if (namelen != len || memcmp(nameW, testfiles[i].name, len*sizeof(WCHAR))) 151 continue; 152 if (!testfiles[i].attr_done) { 153 ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); 154 testfiles[i].attr_done = TRUE; 155 } 156 testfiles[i].nfound++; 157 break; 158 } 159 ok(i < test_dir_count, "unexpected file found %s\n", wine_dbgstr_wn(dir_info->FileName, namelen)); 160 } 161 162 static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES *attr, const char *testdirA, 163 UNICODE_STRING *mask, 164 BOOLEAN single_entry, BOOLEAN restart_flag) 165 { 166 UNICODE_STRING dummy_mask; 167 HANDLE dirh, new_dirh; 168 IO_STATUS_BLOCK io; 169 UINT data_pos, data_size; 170 UINT data_len; /* length of dir data */ 171 BYTE data[8192]; /* directory data */ 172 FILE_BOTH_DIRECTORY_INFORMATION *dir_info; 173 NTSTATUS status; 174 int numfiles; 175 int i; 176 177 reset_found_files(); 178 pRtlInitUnicodeString( &dummy_mask, dummyW ); 179 180 data_size = mask ? offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] ) : sizeof(data); 181 182 /* Read the directory and note which files are found */ 183 status = pNtOpenFile( &dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, attr, &io, FILE_SHARE_READ, 184 FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_DIRECTORY_FILE); 185 ok (status == STATUS_SUCCESS, "failed to open dir '%s', ret 0x%x, error %d\n", testdirA, status, GetLastError()); 186 if (status != STATUS_SUCCESS) { 187 skip("can't test if we can't open the directory\n"); 188 return; 189 } 190 191 U(io).Status = 0xdeadbeef; 192 status = pNtQueryDirectoryFile( dirh, NULL, NULL, NULL, &io, data, data_size, 193 FileBothDirectoryInformation, single_entry, mask, restart_flag ); 194 ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status); 195 ok (U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status); 196 data_len = io.Information; 197 ok (data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n"); 198 199 DuplicateHandle( GetCurrentProcess(), dirh, GetCurrentProcess(), &new_dirh, 200 0, FALSE, DUPLICATE_SAME_ACCESS ); 201 pNtClose(dirh); 202 203 data_pos = 0; 204 numfiles = 0; 205 while ((data_pos < data_len) && (numfiles < max_test_dir_size)) { 206 dir_info = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + data_pos); 207 208 tally_test_file(dir_info); 209 210 if (dir_info->NextEntryOffset == 0) { 211 U(io).Status = 0xdeadbeef; 212 status = pNtQueryDirectoryFile( new_dirh, 0, NULL, NULL, &io, data, data_size, 213 FileBothDirectoryInformation, single_entry, &dummy_mask, FALSE ); 214 ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status); 215 if (status == STATUS_NO_MORE_FILES) break; 216 ok (status == STATUS_SUCCESS, "failed to query directory; status %x\n", status); 217 data_len = io.Information; 218 if (data_len < sizeof(FILE_BOTH_DIRECTORY_INFORMATION)) 219 break; 220 data_pos = 0; 221 } else { 222 data_pos += dir_info->NextEntryOffset; 223 } 224 numfiles++; 225 } 226 ok(numfiles < max_test_dir_size, "too many loops\n"); 227 228 if (mask) 229 for (i = 0; i < test_dir_count; i++) 230 ok(testfiles[i].nfound == (testfiles[i].name == mask->Buffer), 231 "Wrong number %d of %s files found (single_entry=%d,mask=%s)\n", 232 testfiles[i].nfound, testfiles[i].description, single_entry, 233 wine_dbgstr_wn(mask->Buffer, mask->Length/sizeof(WCHAR) )); 234 else 235 for (i = 0; i < test_dir_count; i++) 236 ok(testfiles[i].nfound == 1, "Wrong number %d of %s files found (single_entry=%d,restart=%d)\n", 237 testfiles[i].nfound, testfiles[i].description, single_entry, restart_flag); 238 pNtClose(new_dirh); 239 } 240 241 static void test_directory_sort( const WCHAR *testdir ) 242 { 243 OBJECT_ATTRIBUTES attr; 244 UNICODE_STRING ntdirname; 245 IO_STATUS_BLOCK io; 246 UINT data_pos, data_len, count; 247 BYTE data[8192]; 248 WCHAR prev[MAX_PATH], name[MAX_PATH]; 249 UNICODE_STRING prev_str, name_str; 250 FILE_BOTH_DIRECTORY_INFORMATION *info; 251 NTSTATUS status; 252 HANDLE handle; 253 int res; 254 255 if (!pRtlDosPathNameToNtPathName_U( testdir, &ntdirname, NULL, NULL )) 256 { 257 ok(0, "RtlDosPathNametoNtPathName_U failed\n"); 258 return; 259 } 260 InitializeObjectAttributes( &attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL ); 261 status = pNtOpenFile( &handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, 262 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE ); 263 ok(status == STATUS_SUCCESS, "failed to open dir %s\n", wine_dbgstr_w(testdir) ); 264 265 U(io).Status = 0xdeadbeef; 266 status = pNtQueryDirectoryFile( handle, NULL, NULL, NULL, &io, data, sizeof(data), 267 FileBothDirectoryInformation, FALSE, NULL, TRUE ); 268 ok( status == STATUS_SUCCESS, "failed to query directory; status %x\n", status ); 269 ok( U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status ); 270 data_len = io.Information; 271 ok( data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n" ); 272 data_pos = 0; 273 count = 0; 274 275 while (data_pos < data_len) 276 { 277 info = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + data_pos); 278 279 memcpy( name, info->FileName, info->FileNameLength ); 280 name[info->FileNameLength / sizeof(WCHAR)] = 0; 281 switch (count) 282 { 283 case 0: /* first entry must be '.' */ 284 ok( !lstrcmpW( name, dotW ), "wrong name %s\n", wine_dbgstr_w( name )); 285 break; 286 case 1: /* second entry must be '..' */ 287 ok( !lstrcmpW( name, dotdotW ), "wrong name %s\n", wine_dbgstr_w( name )); 288 break; 289 case 2: /* nothing to compare against */ 290 break; 291 default: 292 pRtlInitUnicodeString( &prev_str, prev ); 293 pRtlInitUnicodeString( &name_str, name ); 294 res = pRtlCompareUnicodeString( &prev_str, &name_str, TRUE ); 295 ok( res < 0, "wrong result %d %s %s\n", res, wine_dbgstr_w( prev ), wine_dbgstr_w( name )); 296 break; 297 } 298 count++; 299 lstrcpyW( prev, name ); 300 301 if (info->NextEntryOffset == 0) 302 { 303 U(io).Status = 0xdeadbeef; 304 status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, sizeof(data), 305 FileBothDirectoryInformation, FALSE, NULL, FALSE ); 306 ok (U(io).Status == status, "wrong status %x / %x\n", status, U(io).Status); 307 if (status == STATUS_NO_MORE_FILES) break; 308 ok( status == STATUS_SUCCESS, "failed to query directory; status %x\n", status ); 309 data_len = io.Information; 310 data_pos = 0; 311 } 312 else data_pos += info->NextEntryOffset; 313 } 314 315 pNtClose( handle ); 316 pRtlFreeUnicodeString( &ntdirname ); 317 } 318 319 static void test_NtQueryDirectoryFile_classes( HANDLE handle, UNICODE_STRING *mask ) 320 { 321 IO_STATUS_BLOCK io; 322 UINT data_size; 323 ULONG data[256]; 324 NTSTATUS status; 325 int class; 326 327 for (class = 0; class < FileMaximumInformation; class++) 328 { 329 U(io).Status = 0xdeadbeef; 330 U(io).Information = 0xdeadbeef; 331 data_size = 0; 332 memset( data, 0x55, sizeof(data) ); 333 334 status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, data_size, 335 class, FALSE, mask, TRUE ); 336 ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class, U(io).Status ); 337 ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n", class, U(io).Information ); 338 ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class, data[0] ); 339 340 switch (class) 341 { 342 case FileIdGlobalTxDirectoryInformation: 343 case FileIdExtdDirectoryInformation: 344 case FileIdExtdBothDirectoryInformation: 345 if (status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED) continue; 346 /* fall through */ 347 case FileDirectoryInformation: 348 case FileFullDirectoryInformation: 349 case FileBothDirectoryInformation: 350 case FileNamesInformation: 351 case FileIdBothDirectoryInformation: 352 case FileIdFullDirectoryInformation: 353 case FileObjectIdInformation: 354 case FileQuotaInformation: 355 case FileReparsePointInformation: 356 ok( status == STATUS_INFO_LENGTH_MISMATCH, "%u: wrong status %x\n", class, status ); 357 break; 358 default: 359 ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_NOT_IMPLEMENTED, 360 "%u: wrong status %x\n", class, status ); 361 continue; 362 } 363 364 for (data_size = 1; data_size < sizeof(data); data_size++) 365 { 366 status = pNtQueryDirectoryFile( handle, 0, NULL, NULL, &io, data, data_size, 367 class, FALSE, mask, TRUE ); 368 if (status == STATUS_BUFFER_OVERFLOW) 369 { 370 ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, U(io).Status ); 371 ok( U(io).Information == data_size, "%u: wrong info %lx\n", class, U(io).Information ); 372 ok(data[0] == 0, "%u: wrong offset %x\n", class, data[0] ); 373 } 374 else 375 { 376 ok( U(io).Status == 0xdeadbeef, "%u: wrong status %x\n", class, U(io).Status ); 377 ok( U(io).Information == 0xdeadbeef, "%u: wrong info %lx\n", class, U(io).Information ); 378 ok(data[0] == 0x55555555, "%u: wrong offset %x\n", class, data[0] ); 379 } 380 if (status != STATUS_INFO_LENGTH_MISMATCH) break; 381 } 382 383 switch (class) 384 { 385 case FileDirectoryInformation: 386 ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); 387 ok( data_size == ((offsetof( FILE_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), 388 "%u: wrong size %u\n", class, data_size ); 389 break; 390 case FileFullDirectoryInformation: 391 ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); 392 ok( data_size == ((offsetof( FILE_FULL_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), 393 "%u: wrong size %u\n", class, data_size ); 394 break; 395 case FileBothDirectoryInformation: 396 ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); 397 ok( data_size == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), 398 "%u: wrong size %u\n", class, data_size ); 399 break; 400 case FileNamesInformation: 401 ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); 402 ok( data_size == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7), 403 "%u: wrong size %u\n", class, data_size ); 404 break; 405 case FileIdBothDirectoryInformation: 406 ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); 407 ok( data_size == ((offsetof( FILE_ID_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), 408 "%u: wrong size %u\n", class, data_size ); 409 break; 410 case FileIdFullDirectoryInformation: 411 ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); 412 ok( data_size == ((offsetof( FILE_ID_FULL_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), 413 "%u: wrong size %u\n", class, data_size ); 414 break; 415 case FileIdGlobalTxDirectoryInformation: 416 ok( status == STATUS_BUFFER_OVERFLOW, "%u: wrong status %x\n", class, status ); 417 ok( data_size == ((offsetof( FILE_ID_GLOBAL_TX_DIR_INFORMATION, FileName[1] ) + 7) & ~7), 418 "%u: wrong size %u\n", class, data_size ); 419 break; 420 case FileObjectIdInformation: 421 ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status ); 422 ok( data_size == sizeof(FILE_OBJECTID_INFORMATION), "%u: wrong size %u\n", class, data_size ); 423 break; 424 case FileQuotaInformation: 425 ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status ); 426 ok( data_size == sizeof(FILE_QUOTA_INFORMATION), "%u: wrong size %u\n", class, data_size ); 427 break; 428 case FileReparsePointInformation: 429 ok( status == STATUS_INVALID_INFO_CLASS, "%u: wrong status %x\n", class, status ); 430 ok( data_size == sizeof(FILE_REPARSE_POINT_INFORMATION), "%u: wrong size %u\n", class, data_size ); 431 break; 432 } 433 } 434 } 435 436 static void test_NtQueryDirectoryFile(void) 437 { 438 OBJECT_ATTRIBUTES attr; 439 UNICODE_STRING ntdirname, mask; 440 char testdirA[MAX_PATH]; 441 WCHAR testdirW[MAX_PATH]; 442 int i; 443 IO_STATUS_BLOCK io; 444 WCHAR short_name[12]; 445 UINT data_size; 446 BYTE data[8192]; 447 FILE_BOTH_DIRECTORY_INFORMATION *next, *fbdi = (FILE_BOTH_DIRECTORY_INFORMATION*)data; 448 FILE_POSITION_INFORMATION pos_info; 449 FILE_NAMES_INFORMATION *names; 450 const WCHAR *filename = fbdi->FileName; 451 NTSTATUS status; 452 HANDLE dirh; 453 454 /* Clean up from prior aborted run, if any, then set up test files */ 455 ok(GetTempPathA(MAX_PATH, testdirA), "couldn't get temp dir\n"); 456 strcat(testdirA, "NtQueryDirectoryFile.tmp"); 457 pRtlMultiByteToUnicodeN(testdirW, sizeof(testdirW), NULL, testdirA, strlen(testdirA)+1); 458 tear_down_attribute_test(testdirW); 459 set_up_attribute_test(testdirW); 460 461 if (!pRtlDosPathNameToNtPathName_U(testdirW, &ntdirname, NULL, NULL)) 462 { 463 ok(0, "RtlDosPathNametoNtPathName_U failed\n"); 464 goto done; 465 } 466 InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); 467 468 test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, FALSE, TRUE); 469 test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, FALSE, FALSE); 470 test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, TRUE); 471 test_flags_NtQueryDirectoryFile(&attr, testdirA, NULL, TRUE, FALSE); 472 473 for (i = 0; i < test_dir_count; i++) 474 { 475 if (testfiles[i].name[0] == '.') continue; /* . and .. as masks are broken on Windows */ 476 mask.Buffer = testfiles[i].name; 477 mask.Length = mask.MaximumLength = lstrlenW(testfiles[i].name) * sizeof(WCHAR); 478 test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, TRUE); 479 test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, FALSE, FALSE); 480 test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, TRUE); 481 test_flags_NtQueryDirectoryFile(&attr, testdirA, &mask, TRUE, FALSE); 482 } 483 484 /* short path passed as mask */ 485 status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, 486 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); 487 ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA); 488 if (status != STATUS_SUCCESS) { 489 skip("can't test if we can't open the directory\n"); 490 return; 491 } 492 status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); 493 ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); 494 ok( pos_info.CurrentByteOffset.QuadPart == 0, "wrong pos %s\n", 495 wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart)); 496 497 pos_info.CurrentByteOffset.QuadPart = 0xbeef; 498 status = pNtSetInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); 499 ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); 500 501 status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); 502 ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); 503 ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n", 504 wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart)); 505 506 mask.Buffer = testfiles[0].name; 507 mask.Length = mask.MaximumLength = lstrlenW(testfiles[0].name) * sizeof(WCHAR); 508 data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]); 509 U(io).Status = 0xdeadbeef; 510 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 511 FileBothDirectoryInformation, TRUE, &mask, FALSE); 512 ok(status == STATUS_SUCCESS, "failed to query directory; status %x\n", status); 513 ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status); 514 ok(fbdi->ShortName[0], "ShortName is empty\n"); 515 516 status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); 517 ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); 518 ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n", 519 wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) ); 520 521 mask.Length = mask.MaximumLength = fbdi->ShortNameLength; 522 memcpy(short_name, fbdi->ShortName, mask.Length); 523 mask.Buffer = short_name; 524 U(io).Status = 0xdeadbeef; 525 U(io).Information = 0xdeadbeef; 526 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 527 FileBothDirectoryInformation, TRUE, &mask, TRUE); 528 ok(status == STATUS_SUCCESS, "failed to query directory status %x\n", status); 529 ok(U(io).Status == STATUS_SUCCESS, "failed to query directory status %x\n", U(io).Status); 530 ok(U(io).Information == offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[lstrlenW(testfiles[0].name)]), 531 "wrong info %lx\n", U(io).Information); 532 ok(fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR) && 533 !memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength), 534 "incorrect long file name: %s\n", wine_dbgstr_wn(fbdi->FileName, 535 fbdi->FileNameLength/sizeof(WCHAR))); 536 537 status = pNtQueryInformationFile( dirh, &io, &pos_info, sizeof(pos_info), FilePositionInformation ); 538 ok( status == STATUS_SUCCESS, "NtQueryInformationFile failed %x\n", status ); 539 ok( pos_info.CurrentByteOffset.QuadPart == 0xbeef, "wrong pos %s\n", 540 wine_dbgstr_longlong(pos_info.CurrentByteOffset.QuadPart) ); 541 542 /* tests with short buffer */ 543 memset( data, 0x55, data_size ); 544 U(io).Status = 0xdeadbeef; 545 U(io).Information = 0xdeadbeef; 546 data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ); 547 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 548 FileBothDirectoryInformation, TRUE, &mask, TRUE); 549 ok( status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", status ); 550 ok( U(io).Status == STATUS_BUFFER_OVERFLOW, "wrong status %x\n", U(io).Status ); 551 ok( U(io).Information == data_size || broken( U(io).Information == 0), 552 "wrong info %lx\n", U(io).Information ); 553 ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset ); 554 ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name) * sizeof(WCHAR), 555 "wrong length %x\n", fbdi->FileNameLength ); 556 ok( filename[0] == testfiles[0].name[0], "incorrect long file name: %s\n", 557 wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); 558 ok( filename[1] == 0x5555, "incorrect long file name: %s\n", 559 wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); 560 561 test_NtQueryDirectoryFile_classes( dirh, &mask ); 562 563 /* mask may or may not be ignored when restarting the search */ 564 pRtlInitUnicodeString( &mask, dummyW ); 565 U(io).Status = 0xdeadbeef; 566 data_size = offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[256] ); 567 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 568 FileBothDirectoryInformation, TRUE, &mask, TRUE); 569 ok( status == STATUS_SUCCESS || status == STATUS_NO_MORE_FILES, "wrong status %x\n", status ); 570 ok( U(io).Status == status, "wrong status %x / %x\n", U(io).Status, status ); 571 if (!status) 572 ok( fbdi->FileNameLength == lstrlenW(testfiles[0].name)*sizeof(WCHAR) && 573 !memcmp(fbdi->FileName, testfiles[0].name, fbdi->FileNameLength), 574 "incorrect long file name: %s\n", 575 wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); 576 577 pNtClose(dirh); 578 579 status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, 580 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); 581 ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA); 582 583 memset( data, 0x55, data_size ); 584 data_size = sizeof(data); 585 U(io).Status = 0xdeadbeef; 586 U(io).Information = 0xdeadbeef; 587 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 588 FileBothDirectoryInformation, FALSE, NULL, TRUE); 589 ok(status == STATUS_SUCCESS, "wrong status %x\n", status); 590 ok(U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status); 591 ok(U(io).Information > 0 && U(io).Information < data_size, "wrong info %lx\n", U(io).Information); 592 ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), 593 "wrong offset %x\n", fbdi->NextEntryOffset ); 594 ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength ); 595 ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n", 596 wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); 597 next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset); 598 ok( next->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ) + 7) & ~7), 599 "wrong offset %x\n", next->NextEntryOffset ); 600 ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength ); 601 filename = next->FileName; 602 ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n", 603 wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR))); 604 605 data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ), 606 memset( data, 0x55, data_size ); 607 U(io).Status = 0xdeadbeef; 608 U(io).Information = 0xdeadbeef; 609 status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, 610 FileBothDirectoryInformation, FALSE, NULL, TRUE ); 611 ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); 612 ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); 613 ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ), 614 "wrong info %lx\n", U(io).Information ); 615 ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset ); 616 ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength ); 617 ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n", 618 wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); 619 next = (FILE_BOTH_DIRECTORY_INFORMATION *)&fbdi->FileName[1]; 620 ok( next->NextEntryOffset == 0x55555555, "wrong offset %x\n", next->NextEntryOffset ); 621 622 data_size = fbdi->NextEntryOffset + offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ), 623 memset( data, 0x55, data_size ); 624 U(io).Status = 0xdeadbeef; 625 U(io).Information = 0xdeadbeef; 626 status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, 627 FileBothDirectoryInformation, FALSE, NULL, TRUE ); 628 ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); 629 ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); 630 ok( U(io).Information == offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ), 631 "wrong info %lx\n", U(io).Information ); 632 ok( fbdi->NextEntryOffset == 0, "wrong offset %x\n", fbdi->NextEntryOffset ); 633 634 data_size = ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7) + 635 offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[2] ); 636 memset( data, 0x55, data_size ); 637 U(io).Status = 0xdeadbeef; 638 U(io).Information = 0xdeadbeef; 639 status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, 640 FileBothDirectoryInformation, FALSE, NULL, TRUE ); 641 ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); 642 ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); 643 ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size ); 644 ok( fbdi->NextEntryOffset == ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION, FileName[1] ) + 7) & ~7), 645 "wrong offset %x\n", fbdi->NextEntryOffset ); 646 ok( fbdi->FileNameLength == sizeof(WCHAR), "wrong length %x\n", fbdi->FileNameLength ); 647 ok( fbdi->FileName[0] == '.', "incorrect long file name: %s\n", 648 wine_dbgstr_wn(fbdi->FileName, fbdi->FileNameLength/sizeof(WCHAR))); 649 next = (FILE_BOTH_DIRECTORY_INFORMATION *)(data + fbdi->NextEntryOffset); 650 ok( next->NextEntryOffset == 0, "wrong offset %x\n", next->NextEntryOffset ); 651 ok( next->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", next->FileNameLength ); 652 filename = next->FileName; 653 ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n", 654 wine_dbgstr_wn(next->FileName, next->FileNameLength/sizeof(WCHAR))); 655 656 data_size = ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7) + 657 offsetof( FILE_NAMES_INFORMATION, FileName[2] ); 658 memset( data, 0x55, data_size ); 659 U(io).Status = 0xdeadbeef; 660 U(io).Information = 0xdeadbeef; 661 status = pNtQueryDirectoryFile( dirh, 0, NULL, NULL, &io, data, data_size, 662 FileNamesInformation, FALSE, NULL, TRUE ); 663 ok( status == STATUS_SUCCESS, "wrong status %x\n", status ); 664 ok( U(io).Status == STATUS_SUCCESS, "wrong status %x\n", U(io).Status ); 665 ok( U(io).Information == data_size, "wrong info %lx / %x\n", U(io).Information, data_size ); 666 names = (FILE_NAMES_INFORMATION *)data; 667 ok( names->NextEntryOffset == ((offsetof( FILE_NAMES_INFORMATION, FileName[1] ) + 7) & ~7), 668 "wrong offset %x\n", names->NextEntryOffset ); 669 ok( names->FileNameLength == sizeof(WCHAR), "wrong length %x\n", names->FileNameLength ); 670 ok( names->FileName[0] == '.', "incorrect long file name: %s\n", 671 wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR))); 672 names = (FILE_NAMES_INFORMATION *)(data + names->NextEntryOffset); 673 ok( names->NextEntryOffset == 0, "wrong offset %x\n", names->NextEntryOffset ); 674 ok( names->FileNameLength == 2 * sizeof(WCHAR), "wrong length %x\n", names->FileNameLength ); 675 filename = names->FileName; 676 ok( filename[0] == '.' && filename[1] == '.', "incorrect long file name: %s\n", 677 wine_dbgstr_wn(names->FileName, names->FileNameLength/sizeof(WCHAR))); 678 679 pNtClose(dirh); 680 681 /* create new handle to change mask */ 682 status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, 683 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); 684 ok(status == STATUS_SUCCESS, "failed to open dir '%s'\n", testdirA); 685 686 pRtlInitUnicodeString( &mask, dummyW ); 687 U(io).Status = 0xdeadbeef; 688 data_size = sizeof(data); 689 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 690 FileBothDirectoryInformation, TRUE, &mask, TRUE); 691 ok(status == STATUS_NO_SUCH_FILE, "wrong status %x\n", status); 692 ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status); 693 694 U(io).Status = 0xdeadbeef; 695 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 696 FileBothDirectoryInformation, TRUE, NULL, FALSE); 697 ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status); 698 ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n", U(io).Status); 699 700 U(io).Status = 0xdeadbeef; 701 status = pNtQueryDirectoryFile(dirh, 0, NULL, NULL, &io, data, data_size, 702 FileBothDirectoryInformation, TRUE, NULL, TRUE); 703 ok(status == STATUS_NO_MORE_FILES, "wrong status %x\n", status); 704 ok(U(io).Status == STATUS_NO_MORE_FILES, "wrong status %x\n", U(io).Status); 705 706 pNtClose(dirh); 707 708 U(io).Status = 0xdeadbeef; 709 status = pNtQueryDirectoryFile( (HANDLE)0xbeef, 0, NULL, NULL, &io, data, data_size, 710 FileBothDirectoryInformation, TRUE, NULL, TRUE ); 711 ok(status == STATUS_INVALID_HANDLE, "wrong status %x\n", status); 712 ok(U(io).Status == 0xdeadbeef, "wrong status %x\n", U(io).Status); 713 714 done: 715 test_directory_sort( testdirW ); 716 tear_down_attribute_test( testdirW ); 717 pRtlFreeUnicodeString(&ntdirname); 718 } 719 720 static void set_up_case_test(const char *testdir) 721 { 722 BOOL ret; 723 char buf[MAX_PATH]; 724 HANDLE h; 725 726 ret = CreateDirectoryA(testdir, NULL); 727 ok(ret, "couldn't create dir '%s', error %d\n", testdir, GetLastError()); 728 729 sprintf(buf, "%s\\%s", testdir, "TesT"); 730 h = CreateFileA(buf, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 731 FILE_ATTRIBUTE_NORMAL, 0); 732 ok(h != INVALID_HANDLE_VALUE, "failed to create temp file '%s'\n", buf); 733 CloseHandle(h); 734 } 735 736 static void tear_down_case_test(const char *testdir) 737 { 738 int ret; 739 char buf[MAX_PATH]; 740 741 sprintf(buf, "%s\\%s", testdir, "TesT"); 742 ret = DeleteFileA(buf); 743 ok(ret || (GetLastError() == ERROR_PATH_NOT_FOUND), 744 "Failed to rm %s, error %d\n", buf, GetLastError()); 745 RemoveDirectoryA(testdir); 746 } 747 748 static void test_NtQueryDirectoryFile_case(void) 749 { 750 static const char testfile[] = "TesT"; 751 static const WCHAR testfile_w[] = {'T','e','s','T'}; 752 static int testfile_len = sizeof(testfile) - 1; 753 static WCHAR testmask[] = {'t','e','s','t'}; 754 OBJECT_ATTRIBUTES attr; 755 UNICODE_STRING ntdirname; 756 char testdir[MAX_PATH]; 757 WCHAR testdir_w[MAX_PATH]; 758 HANDLE dirh; 759 UNICODE_STRING mask; 760 IO_STATUS_BLOCK io; 761 UINT data_size, data_len; 762 BYTE data[8192]; 763 FILE_BOTH_DIRECTORY_INFORMATION *dir_info = (FILE_BOTH_DIRECTORY_INFORMATION *)data; 764 DWORD status; 765 WCHAR *name; 766 ULONG name_len; 767 768 /* Clean up from prior aborted run, if any, then set up test files */ 769 ok(GetTempPathA(MAX_PATH, testdir), "couldn't get temp dir\n"); 770 strcat(testdir, "case.tmp"); 771 tear_down_case_test(testdir); 772 set_up_case_test(testdir); 773 774 pRtlMultiByteToUnicodeN(testdir_w, sizeof(testdir_w), NULL, testdir, strlen(testdir) + 1); 775 if (!pRtlDosPathNameToNtPathName_U(testdir_w, &ntdirname, NULL, NULL)) 776 { 777 ok(0, "RtlDosPathNametoNtPathName_U failed\n"); 778 goto done; 779 } 780 InitializeObjectAttributes(&attr, &ntdirname, OBJ_CASE_INSENSITIVE, 0, NULL); 781 782 data_size = offsetof(FILE_BOTH_DIRECTORY_INFORMATION, FileName[256]); 783 784 status = pNtOpenFile(&dirh, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_READ, 785 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE); 786 ok (status == STATUS_SUCCESS, "failed to open dir '%s', ret 0x%x, error %d\n", testdir, status, GetLastError()); 787 if (status != STATUS_SUCCESS) 788 { 789 skip("can't test if we can't open the directory\n"); 790 return; 791 } 792 793 mask.Buffer = testmask; 794 mask.Length = mask.MaximumLength = sizeof(testmask); 795 pNtQueryDirectoryFile(dirh, NULL, NULL, NULL, &io, data, data_size, 796 FileBothDirectoryInformation, TRUE, &mask, FALSE); 797 ok(U(io).Status == STATUS_SUCCESS, "failed to query directory; status %x\n", U(io).Status); 798 data_len = io.Information; 799 ok(data_len >= sizeof(FILE_BOTH_DIRECTORY_INFORMATION), "not enough data in directory\n"); 800 801 name = dir_info->FileName; 802 name_len = dir_info->FileNameLength / sizeof(WCHAR); 803 804 ok(name_len == testfile_len, "unexpected filename length %u\n", name_len); 805 ok(!memcmp(name, testfile_w, testfile_len * sizeof(WCHAR)), "unexpected filename %s\n", 806 wine_dbgstr_wn(name, name_len)); 807 808 pNtClose(dirh); 809 810 done: 811 tear_down_case_test(testdir); 812 pRtlFreeUnicodeString(&ntdirname); 813 } 814 815 static void test_redirection(void) 816 { 817 ULONG old, cur; 818 NTSTATUS status; 819 820 if (!pRtlWow64EnableFsRedirection || !pRtlWow64EnableFsRedirectionEx) 821 { 822 skip( "Wow64 redirection not supported\n" ); 823 return; 824 } 825 status = pRtlWow64EnableFsRedirectionEx( FALSE, &old ); 826 if (status == STATUS_NOT_IMPLEMENTED) 827 { 828 skip( "Wow64 redirection not supported\n" ); 829 return; 830 } 831 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 832 833 status = pRtlWow64EnableFsRedirectionEx( FALSE, &cur ); 834 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 835 ok( !cur, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); 836 837 status = pRtlWow64EnableFsRedirectionEx( TRUE, &cur ); 838 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 839 status = pRtlWow64EnableFsRedirectionEx( TRUE, &cur ); 840 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 841 ok( cur == 1, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); 842 843 status = pRtlWow64EnableFsRedirection( TRUE ); 844 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 845 status = pRtlWow64EnableFsRedirectionEx( TRUE, &cur ); 846 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 847 ok( !cur, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); 848 849 status = pRtlWow64EnableFsRedirectionEx( TRUE, NULL ); 850 ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status ); 851 status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)1 ); 852 ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status ); 853 status = pRtlWow64EnableFsRedirectionEx( TRUE, (void*)0xDEADBEEF ); 854 ok( status == STATUS_ACCESS_VIOLATION, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status ); 855 856 status = pRtlWow64EnableFsRedirection( FALSE ); 857 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 858 status = pRtlWow64EnableFsRedirectionEx( FALSE, &cur ); 859 ok( !status, "RtlWow64EnableFsRedirectionEx failed status %x\n", status ); 860 ok( cur == 1, "RtlWow64EnableFsRedirectionEx got %u\n", cur ); 861 862 pRtlWow64EnableFsRedirectionEx( old, &cur ); 863 } 864 865 START_TEST(directory) 866 { 867 WCHAR sysdir[MAX_PATH]; 868 HMODULE hntdll = GetModuleHandleA("ntdll.dll"); 869 if (!hntdll) 870 { 871 skip("not running on NT, skipping test\n"); 872 return; 873 } 874 875 pNtClose = (void *)GetProcAddress(hntdll, "NtClose"); 876 pNtOpenFile = (void *)GetProcAddress(hntdll, "NtOpenFile"); 877 pNtQueryDirectoryFile = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile"); 878 pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile"); 879 pNtSetInformationFile = (void *)GetProcAddress(hntdll, "NtSetInformationFile"); 880 pRtlCreateUnicodeStringFromAsciiz = (void *)GetProcAddress(hntdll, "RtlCreateUnicodeStringFromAsciiz"); 881 pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U"); 882 pRtlInitUnicodeString = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString"); 883 pRtlFreeUnicodeString = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString"); 884 pRtlCompareUnicodeString = (void *)GetProcAddress(hntdll, "RtlCompareUnicodeString"); 885 pRtlMultiByteToUnicodeN = (void *)GetProcAddress(hntdll,"RtlMultiByteToUnicodeN"); 886 pRtlWow64EnableFsRedirection = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirection"); 887 pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll,"RtlWow64EnableFsRedirectionEx"); 888 889 GetSystemDirectoryW( sysdir, MAX_PATH ); 890 test_directory_sort( sysdir ); 891 test_NtQueryDirectoryFile(); 892 test_NtQueryDirectoryFile_case(); 893 test_redirection(); 894 } 895