[NTDLL_WINETEST] Add a PCH.
[reactos.git] / modules / rostests / winetests / ntdll / directory.c
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 }