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