1 /* Unit test suite for Ntdll directory functions
3 * Copyright 2007 Jeff Latimer
4 * Copyright 2007 Andrey Turkin
5 * Copyright 2008 Jeff Zaroyko
6 * Copyright 2009 Dan Kegel
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.
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.
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
23 * We use function pointers here as there is no import library for NTDLL on
31 /* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro
32 * definition errors when we get to winnt.h
34 #define WIN32_NO_STATUS
36 #include "wine/test.h"
39 static NTSTATUS (WINAPI
*pNtClose
)( PHANDLE
);
40 static NTSTATUS (WINAPI
*pNtOpenFile
) ( PHANDLE
, ACCESS_MASK
, POBJECT_ATTRIBUTES
, PIO_STATUS_BLOCK
, ULONG
, ULONG
);
41 static NTSTATUS (WINAPI
*pNtQueryDirectoryFile
)(HANDLE
,HANDLE
,PIO_APC_ROUTINE
,PVOID
,PIO_STATUS_BLOCK
,
42 PVOID
,ULONG
,FILE_INFORMATION_CLASS
,BOOLEAN
,PUNICODE_STRING
,BOOLEAN
);
43 static BOOLEAN (WINAPI
*pRtlCreateUnicodeStringFromAsciiz
)(PUNICODE_STRING
,LPCSTR
);
44 static BOOL (WINAPI
*pRtlDosPathNameToNtPathName_U
)( LPCWSTR
, PUNICODE_STRING
, PWSTR
*, CURDIR
* );
45 static VOID (WINAPI
*pRtlInitUnicodeString
)( PUNICODE_STRING
, LPCWSTR
);
46 static VOID (WINAPI
*pRtlFreeUnicodeString
)( PUNICODE_STRING
);
47 static NTSTATUS (WINAPI
*pRtlMultiByteToUnicodeN
)( LPWSTR dst
, DWORD dstlen
, LPDWORD reslen
,
48 LPCSTR src
, DWORD srclen
);
49 static NTSTATUS (WINAPI
*pRtlWow64EnableFsRedirection
)( BOOLEAN enable
);
50 static NTSTATUS (WINAPI
*pRtlWow64EnableFsRedirectionEx
)( ULONG disable
, ULONG
*old_value
);
52 /* The attribute sets to test */
53 static struct testfile_s
{
54 BOOL todo
; /* set if it doesn't work on wine yet */
55 BOOL attr_done
; /* set if attributes were tested for this file already */
56 const DWORD attr
; /* desired attribute */
57 const char *name
; /* filename to use */
58 const char *target
; /* what to point to (only for reparse pts) */
59 const char *description
; /* for error messages */
60 int nfound
; /* How many were found (expect 1) */
61 WCHAR nameW
[20]; /* unicode version of name (filled in later) */
63 { 0, 0, FILE_ATTRIBUTE_NORMAL
, "longfilename.tmp", NULL
, "normal" },
64 { 0, 0, FILE_ATTRIBUTE_NORMAL
, "n.tmp", NULL
, "normal" },
65 { 1, 0, FILE_ATTRIBUTE_HIDDEN
, "h.tmp", NULL
, "hidden" },
66 { 1, 0, FILE_ATTRIBUTE_SYSTEM
, "s.tmp", NULL
, "system" },
67 { 0, 0, FILE_ATTRIBUTE_DIRECTORY
, "d.tmp", NULL
, "directory" },
68 { 0, 0, FILE_ATTRIBUTE_DIRECTORY
, ".", NULL
, ". directory" },
69 { 0, 0, FILE_ATTRIBUTE_DIRECTORY
, "..", NULL
, ".. directory" },
72 static const int max_test_dir_size
= 20; /* size of above plus some for .. etc */
74 /* Create a test directory full of attribute test files, clear counts */
75 static void set_up_attribute_test(const char *testdirA
)
80 ret
= CreateDirectoryA(testdirA
, NULL
);
81 ok(ret
, "couldn't create dir '%s', error %d\n", testdirA
, GetLastError());
83 for (i
=0; testfiles
[i
].name
; i
++) {
85 pRtlMultiByteToUnicodeN(testfiles
[i
].nameW
, sizeof(testfiles
[i
].nameW
), NULL
, testfiles
[i
].name
, strlen(testfiles
[i
].name
)+1);
87 if (strcmp(testfiles
[i
].name
, ".") == 0 || strcmp(testfiles
[i
].name
, "..") == 0)
89 sprintf(buf
, "%s\\%s", testdirA
, testfiles
[i
].name
);
90 if (testfiles
[i
].attr
& FILE_ATTRIBUTE_DIRECTORY
) {
91 ret
= CreateDirectoryA(buf
, NULL
);
92 ok(ret
, "couldn't create dir '%s', error %d\n", buf
, GetLastError());
94 HANDLE h
= CreateFileA(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", buf
);
104 static void reset_found_files(void)
108 for (i
= 0; testfiles
[i
].name
; i
++)
109 testfiles
[i
].nfound
= 0;
112 /* Remove the given test directory and the attribute test files, if any */
113 static void tear_down_attribute_test(const char *testdirA
)
117 for (i
=0; testfiles
[i
].name
; i
++) {
120 if (strcmp(testfiles
[i
].name
, ".") == 0 || strcmp(testfiles
[i
].name
, "..") == 0)
122 sprintf(buf
, "%s\\%s", testdirA
, testfiles
[i
].name
);
123 if (testfiles
[i
].attr
& FILE_ATTRIBUTE_DIRECTORY
) {
124 ret
= RemoveDirectoryA(buf
);
125 ok(ret
|| (GetLastError() == ERROR_PATH_NOT_FOUND
),
126 "Failed to rmdir %s, error %d\n", buf
, GetLastError());
128 ret
= DeleteFileA(buf
);
129 ok(ret
|| (GetLastError() == ERROR_PATH_NOT_FOUND
),
130 "Failed to rm %s, error %d\n", buf
, GetLastError());
133 RemoveDirectoryA(testdirA
);
136 /* Match one found file against testfiles[], increment count if found */
137 static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION
*dir_info
)
141 (FILE_ATTRIBUTE_SYSTEM
|FILE_ATTRIBUTE_HIDDEN
|FILE_ATTRIBUTE_DIRECTORY
|FILE_ATTRIBUTE_REPARSE_POINT
);
142 DWORD attrib
= dir_info
->FileAttributes
& attribmask
;
143 WCHAR
*nameW
= dir_info
->FileName
;
144 int namelen
= dir_info
->FileNameLength
/ sizeof(WCHAR
);
146 for (i
=0; testfiles
[i
].name
; i
++) {
147 int len
= strlen(testfiles
[i
].name
);
148 if (namelen
!= len
|| memcmp(nameW
, testfiles
[i
].nameW
, len
*sizeof(WCHAR
)))
150 if (!testfiles
[i
].attr_done
) {
151 todo_wine_if (testfiles
[i
].todo
)
152 ok (attrib
== (testfiles
[i
].attr
& attribmask
), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", testfiles
[i
].name
, testfiles
[i
].description
, testfiles
[i
].attr
, attrib
);
153 testfiles
[i
].attr_done
= TRUE
;
155 testfiles
[i
].nfound
++;
158 ok(testfiles
[i
].name
!= NULL
, "unexpected file found\n");
161 static void test_flags_NtQueryDirectoryFile(OBJECT_ATTRIBUTES
*attr
, const char *testdirA
,
162 UNICODE_STRING
*mask
,
163 BOOLEAN single_entry
, BOOLEAN restart_flag
)
167 UINT data_pos
, data_size
;
168 UINT data_len
; /* length of dir data */
169 BYTE data
[8192]; /* directory data */
170 FILE_BOTH_DIRECTORY_INFORMATION
*dir_info
;
177 data_size
= mask
? offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[256] ) : sizeof(data
);
179 /* Read the directory and note which files are found */
180 status
= pNtOpenFile( &dirh
, SYNCHRONIZE
| FILE_LIST_DIRECTORY
, attr
, &io
, FILE_SHARE_READ
,
181 FILE_SYNCHRONOUS_IO_NONALERT
|FILE_OPEN_FOR_BACKUP_INTENT
|FILE_DIRECTORY_FILE
);
182 ok (status
== STATUS_SUCCESS
, "failed to open dir '%s', ret 0x%x, error %d\n", testdirA
, status
, GetLastError());
183 if (status
!= STATUS_SUCCESS
) {
184 skip("can't test if we can't open the directory\n");
188 U(io
).Status
= 0xdeadbeef;
189 status
= pNtQueryDirectoryFile( dirh
, NULL
, NULL
, NULL
, &io
, data
, data_size
,
190 FileBothDirectoryInformation
, single_entry
, mask
, restart_flag
);
191 ok (status
== STATUS_SUCCESS
, "failed to query directory; status %x\n", status
);
192 ok (U(io
).Status
== STATUS_SUCCESS
, "failed to query directory; status %x\n", U(io
).Status
);
193 data_len
= io
.Information
;
194 ok (data_len
>= sizeof(FILE_BOTH_DIRECTORY_INFORMATION
), "not enough data in directory\n");
198 while ((data_pos
< data_len
) && (numfiles
< max_test_dir_size
)) {
199 dir_info
= (FILE_BOTH_DIRECTORY_INFORMATION
*)(data
+ data_pos
);
201 tally_test_file(dir_info
);
203 if (dir_info
->NextEntryOffset
== 0) {
204 U(io
).Status
= 0xdeadbeef;
205 status
= pNtQueryDirectoryFile( dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
206 FileBothDirectoryInformation
, single_entry
, mask
, FALSE
);
207 ok (U(io
).Status
== status
, "wrong status %x / %x\n", status
, U(io
).Status
);
208 if (status
== STATUS_NO_MORE_FILES
) break;
209 ok (status
== STATUS_SUCCESS
, "failed to query directory; status %x\n", status
);
210 data_len
= io
.Information
;
211 if (data_len
< sizeof(FILE_BOTH_DIRECTORY_INFORMATION
))
215 data_pos
+= dir_info
->NextEntryOffset
;
219 ok(numfiles
< max_test_dir_size
, "too many loops\n");
222 for (i
=0; testfiles
[i
].name
; i
++)
223 ok(testfiles
[i
].nfound
== (testfiles
[i
].nameW
== mask
->Buffer
),
224 "Wrong number %d of %s files found (single_entry=%d,mask=%s)\n",
225 testfiles
[i
].nfound
, testfiles
[i
].description
, single_entry
,
226 wine_dbgstr_wn(mask
->Buffer
, mask
->Length
/sizeof(WCHAR
) ));
228 for (i
=0; testfiles
[i
].name
; i
++)
229 ok(testfiles
[i
].nfound
== 1, "Wrong number %d of %s files found (single_entry=%d,restart=%d)\n",
230 testfiles
[i
].nfound
, testfiles
[i
].description
, single_entry
, restart_flag
);
234 static void test_NtQueryDirectoryFile(void)
236 OBJECT_ATTRIBUTES attr
;
237 UNICODE_STRING ntdirname
, mask
;
238 char testdirA
[MAX_PATH
];
239 WCHAR testdirW
[MAX_PATH
];
242 WCHAR short_name
[12];
245 FILE_BOTH_DIRECTORY_INFORMATION
*next
, *fbdi
= (FILE_BOTH_DIRECTORY_INFORMATION
*)data
;
246 const WCHAR
*filename
= fbdi
->FileName
;
250 /* Clean up from prior aborted run, if any, then set up test files */
251 ok(GetTempPathA(MAX_PATH
, testdirA
), "couldn't get temp dir\n");
252 strcat(testdirA
, "NtQueryDirectoryFile.tmp");
253 tear_down_attribute_test(testdirA
);
254 set_up_attribute_test(testdirA
);
256 pRtlMultiByteToUnicodeN(testdirW
, sizeof(testdirW
), NULL
, testdirA
, strlen(testdirA
)+1);
257 if (!pRtlDosPathNameToNtPathName_U(testdirW
, &ntdirname
, NULL
, NULL
))
259 ok(0, "RtlDosPathNametoNtPathName_U failed\n");
262 InitializeObjectAttributes(&attr
, &ntdirname
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
264 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, NULL
, FALSE
, TRUE
);
265 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, NULL
, FALSE
, FALSE
);
266 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, NULL
, TRUE
, TRUE
);
267 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, NULL
, TRUE
, FALSE
);
269 for (i
= 0; testfiles
[i
].name
; i
++)
271 if (testfiles
[i
].nameW
[0] == '.') continue; /* . and .. as masks are broken on Windows */
272 mask
.Buffer
= testfiles
[i
].nameW
;
273 mask
.Length
= mask
.MaximumLength
= lstrlenW(testfiles
[i
].nameW
) * sizeof(WCHAR
);
274 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, &mask
, FALSE
, TRUE
);
275 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, &mask
, FALSE
, FALSE
);
276 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, &mask
, TRUE
, TRUE
);
277 test_flags_NtQueryDirectoryFile(&attr
, testdirA
, &mask
, TRUE
, FALSE
);
280 /* short path passed as mask */
281 status
= pNtOpenFile(&dirh
, SYNCHRONIZE
| FILE_LIST_DIRECTORY
, &attr
, &io
, FILE_SHARE_READ
,
282 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE
);
283 ok(status
== STATUS_SUCCESS
, "failed to open dir '%s'\n", testdirA
);
284 if (status
!= STATUS_SUCCESS
) {
285 skip("can't test if we can't open the directory\n");
288 mask
.Buffer
= testfiles
[0].nameW
;
289 mask
.Length
= mask
.MaximumLength
= lstrlenW(testfiles
[0].nameW
) * sizeof(WCHAR
);
290 data_size
= offsetof(FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[256]);
291 U(io
).Status
= 0xdeadbeef;
292 status
= pNtQueryDirectoryFile(dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
293 FileBothDirectoryInformation
, TRUE
, &mask
, FALSE
);
294 ok(status
== STATUS_SUCCESS
, "failed to query directory; status %x\n", status
);
295 ok(U(io
).Status
== STATUS_SUCCESS
, "failed to query directory; status %x\n", U(io
).Status
);
296 ok(fbdi
->ShortName
[0], "ShortName is empty\n");
298 mask
.Length
= mask
.MaximumLength
= fbdi
->ShortNameLength
;
299 memcpy(short_name
, fbdi
->ShortName
, mask
.Length
);
300 mask
.Buffer
= short_name
;
301 U(io
).Status
= 0xdeadbeef;
302 U(io
).Information
= 0xdeadbeef;
303 status
= pNtQueryDirectoryFile(dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
304 FileBothDirectoryInformation
, TRUE
, &mask
, TRUE
);
305 ok(status
== STATUS_SUCCESS
, "failed to query directory status %x\n", status
);
306 ok(U(io
).Status
== STATUS_SUCCESS
, "failed to query directory status %x\n", U(io
).Status
);
308 ok(U(io
).Information
== offsetof(FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[strlen(testfiles
[0].name
)]),
309 "wrong info %lx\n", U(io
).Information
);
310 ok(fbdi
->FileNameLength
== strlen(testfiles
[0].name
)*sizeof(WCHAR
) &&
311 !memcmp(fbdi
->FileName
, testfiles
[0].nameW
, fbdi
->FileNameLength
),
312 "incorrect long file name: %s\n", wine_dbgstr_wn(fbdi
->FileName
,
313 fbdi
->FileNameLength
/sizeof(WCHAR
)));
315 /* tests with short buffer */
316 memset( data
, 0x55, data_size
);
317 U(io
).Status
= 0xdeadbeef;
318 U(io
).Information
= 0xdeadbeef;
319 data_size
= offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] );
320 status
= pNtQueryDirectoryFile(dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
321 FileBothDirectoryInformation
, TRUE
, &mask
, TRUE
);
322 ok( status
== STATUS_BUFFER_OVERFLOW
, "wrong status %x\n", status
);
323 ok( U(io
).Status
== STATUS_BUFFER_OVERFLOW
, "wrong status %x\n", U(io
).Status
);
324 ok( U(io
).Information
== offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] ),
325 "wrong info %lx\n", U(io
).Information
);
326 ok( fbdi
->NextEntryOffset
== 0, "wrong offset %x\n", fbdi
->NextEntryOffset
);
327 ok( fbdi
->FileNameLength
== strlen(testfiles
[0].name
) * sizeof(WCHAR
),
328 "wrong length %x\n", fbdi
->FileNameLength
);
329 ok( filename
[0] == testfiles
[0].nameW
[0], "incorrect long file name: %s\n",
330 wine_dbgstr_wn(fbdi
->FileName
, fbdi
->FileNameLength
/sizeof(WCHAR
)));
332 ok( filename
[1] == 0x5555, "incorrect long file name: %s\n",
333 wine_dbgstr_wn(fbdi
->FileName
, fbdi
->FileNameLength
/sizeof(WCHAR
)));
335 memset( data
, 0x55, data_size
);
336 U(io
).Status
= 0xdeadbeef;
337 U(io
).Information
= 0xdeadbeef;
338 data_size
= offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[0] );
339 status
= pNtQueryDirectoryFile(dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
340 FileBothDirectoryInformation
, FALSE
, &mask
, TRUE
);
341 ok( status
== STATUS_INFO_LENGTH_MISMATCH
, "weong status %x\n", status
);
342 ok( U(io
).Status
== 0xdeadbeef, "wrong status %x\n", U(io
).Status
);
343 ok( U(io
).Information
== 0xdeadbeef, "wrong info %lx\n", U(io
).Information
);
344 ok( fbdi
->NextEntryOffset
== 0x55555555, "wrong offset %x\n", fbdi
->NextEntryOffset
);
348 status
= pNtOpenFile(&dirh
, SYNCHRONIZE
| FILE_LIST_DIRECTORY
, &attr
, &io
, FILE_SHARE_READ
,
349 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE
);
350 ok(status
== STATUS_SUCCESS
, "failed to open dir '%s'\n", testdirA
);
352 memset( data
, 0x55, data_size
);
353 data_size
= sizeof(data
);
354 U(io
).Status
= 0xdeadbeef;
355 U(io
).Information
= 0xdeadbeef;
356 status
= pNtQueryDirectoryFile(dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
357 FileBothDirectoryInformation
, FALSE
, NULL
, TRUE
);
358 ok(status
== STATUS_SUCCESS
, "wrong status %x\n", status
);
359 ok(U(io
).Status
== STATUS_SUCCESS
, "wrong status %x\n", U(io
).Status
);
360 ok(U(io
).Information
> 0 && U(io
).Information
< data_size
, "wrong info %lx\n", U(io
).Information
);
361 ok( fbdi
->NextEntryOffset
== ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] ) + 7) & ~7),
362 "wrong offset %x\n", fbdi
->NextEntryOffset
);
363 ok( fbdi
->FileNameLength
== sizeof(WCHAR
), "wrong length %x\n", fbdi
->FileNameLength
);
364 ok( fbdi
->FileName
[0] == '.', "incorrect long file name: %s\n",
365 wine_dbgstr_wn(fbdi
->FileName
, fbdi
->FileNameLength
/sizeof(WCHAR
)));
366 next
= (FILE_BOTH_DIRECTORY_INFORMATION
*)(data
+ fbdi
->NextEntryOffset
);
367 ok( next
->NextEntryOffset
== ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[2] ) + 7) & ~7),
368 "wrong offset %x\n", next
->NextEntryOffset
);
369 ok( next
->FileNameLength
== 2 * sizeof(WCHAR
), "wrong length %x\n", next
->FileNameLength
);
370 filename
= next
->FileName
;
371 ok( filename
[0] == '.' && filename
[1] == '.', "incorrect long file name: %s\n",
372 wine_dbgstr_wn(next
->FileName
, next
->FileNameLength
/sizeof(WCHAR
)));
374 data_size
= fbdi
->NextEntryOffset
+ offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] ),
375 memset( data
, 0x55, data_size
);
376 U(io
).Status
= 0xdeadbeef;
377 U(io
).Information
= 0xdeadbeef;
378 status
= pNtQueryDirectoryFile( dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
379 FileBothDirectoryInformation
, FALSE
, NULL
, TRUE
);
380 ok( status
== STATUS_SUCCESS
, "wrong status %x\n", status
);
381 ok( U(io
).Status
== STATUS_SUCCESS
, "wrong status %x\n", U(io
).Status
);
382 ok( U(io
).Information
== offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] ),
383 "wrong info %lx\n", U(io
).Information
);
384 ok( fbdi
->NextEntryOffset
== 0, "wrong offset %x\n", fbdi
->NextEntryOffset
);
385 ok( fbdi
->FileNameLength
== sizeof(WCHAR
), "wrong length %x\n", fbdi
->FileNameLength
);
386 ok( fbdi
->FileName
[0] == '.', "incorrect long file name: %s\n",
387 wine_dbgstr_wn(fbdi
->FileName
, fbdi
->FileNameLength
/sizeof(WCHAR
)));
388 next
= (FILE_BOTH_DIRECTORY_INFORMATION
*)&fbdi
->FileName
[1];
389 ok( next
->NextEntryOffset
== 0x55555555, "wrong offset %x\n", next
->NextEntryOffset
);
391 data_size
= fbdi
->NextEntryOffset
+ offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[2] ),
392 memset( data
, 0x55, data_size
);
393 U(io
).Status
= 0xdeadbeef;
394 U(io
).Information
= 0xdeadbeef;
395 status
= pNtQueryDirectoryFile( dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
396 FileBothDirectoryInformation
, FALSE
, NULL
, TRUE
);
397 ok( status
== STATUS_SUCCESS
, "wrong status %x\n", status
);
398 ok( U(io
).Status
== STATUS_SUCCESS
, "wrong status %x\n", U(io
).Status
);
399 ok( U(io
).Information
== offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] ),
400 "wrong info %lx\n", U(io
).Information
);
401 ok( fbdi
->NextEntryOffset
== 0, "wrong offset %x\n", fbdi
->NextEntryOffset
);
403 data_size
= ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] ) + 7) & ~7) +
404 offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[2] );
405 memset( data
, 0x55, data_size
);
406 U(io
).Status
= 0xdeadbeef;
407 U(io
).Information
= 0xdeadbeef;
408 status
= pNtQueryDirectoryFile( dirh
, 0, NULL
, NULL
, &io
, data
, data_size
,
409 FileBothDirectoryInformation
, FALSE
, NULL
, TRUE
);
410 ok( status
== STATUS_SUCCESS
, "wrong status %x\n", status
);
411 ok( U(io
).Status
== STATUS_SUCCESS
, "wrong status %x\n", U(io
).Status
);
413 ok( U(io
).Information
== data_size
, "wrong info %lx / %x\n", U(io
).Information
, data_size
);
415 ok( fbdi
->NextEntryOffset
== ((offsetof( FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[1] ) + 7) & ~7),
416 "wrong offset %x\n", fbdi
->NextEntryOffset
);
417 ok( fbdi
->FileNameLength
== sizeof(WCHAR
), "wrong length %x\n", fbdi
->FileNameLength
);
418 ok( fbdi
->FileName
[0] == '.', "incorrect long file name: %s\n",
419 wine_dbgstr_wn(fbdi
->FileName
, fbdi
->FileNameLength
/sizeof(WCHAR
)));
420 next
= (FILE_BOTH_DIRECTORY_INFORMATION
*)(data
+ fbdi
->NextEntryOffset
);
421 ok( next
->NextEntryOffset
== 0, "wrong offset %x\n", next
->NextEntryOffset
);
423 ok( next
->FileNameLength
== 2 * sizeof(WCHAR
), "wrong length %x\n", next
->FileNameLength
);
424 filename
= next
->FileName
;
426 ok( filename
[0] == '.' && filename
[1] == '.', "incorrect long file name: %s\n",
427 wine_dbgstr_wn(next
->FileName
, next
->FileNameLength
/sizeof(WCHAR
)));
431 U(io
).Status
= 0xdeadbeef;
432 status
= pNtQueryDirectoryFile( (HANDLE
)0xbeef, 0, NULL
, NULL
, &io
, data
, data_size
,
433 FileBothDirectoryInformation
, TRUE
, NULL
, TRUE
);
434 ok(status
== STATUS_INVALID_HANDLE
, "wrong status %x\n", status
);
435 ok(U(io
).Status
== 0xdeadbeef, "wrong status %x\n", U(io
).Status
);
438 tear_down_attribute_test(testdirA
);
439 pRtlFreeUnicodeString(&ntdirname
);
442 static void set_up_case_test(const char *testdir
)
448 ret
= CreateDirectoryA(testdir
, NULL
);
449 ok(ret
, "couldn't create dir '%s', error %d\n", testdir
, GetLastError());
451 sprintf(buf
, "%s\\%s", testdir
, "TesT");
452 h
= CreateFileA(buf
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
,
453 FILE_ATTRIBUTE_NORMAL
, 0);
454 ok(h
!= INVALID_HANDLE_VALUE
, "failed to create temp file '%s'\n", buf
);
458 static void tear_down_case_test(const char *testdir
)
463 sprintf(buf
, "%s\\%s", testdir
, "TesT");
464 ret
= DeleteFileA(buf
);
465 ok(ret
|| (GetLastError() == ERROR_PATH_NOT_FOUND
),
466 "Failed to rm %s, error %d\n", buf
, GetLastError());
467 RemoveDirectoryA(testdir
);
470 static void test_NtQueryDirectoryFile_case(void)
472 static const char testfile
[] = "TesT";
473 static const WCHAR testfile_w
[] = {'T','e','s','T'};
474 static int testfile_len
= sizeof(testfile
) - 1;
475 static WCHAR testmask
[] = {'t','e','s','t'};
476 OBJECT_ATTRIBUTES attr
;
477 UNICODE_STRING ntdirname
;
478 char testdir
[MAX_PATH
];
479 WCHAR testdir_w
[MAX_PATH
];
483 UINT data_size
, data_len
;
485 FILE_BOTH_DIRECTORY_INFORMATION
*dir_info
= (FILE_BOTH_DIRECTORY_INFORMATION
*)data
;
490 /* Clean up from prior aborted run, if any, then set up test files */
491 ok(GetTempPathA(MAX_PATH
, testdir
), "couldn't get temp dir\n");
492 strcat(testdir
, "case.tmp");
493 tear_down_case_test(testdir
);
494 set_up_case_test(testdir
);
496 pRtlMultiByteToUnicodeN(testdir_w
, sizeof(testdir_w
), NULL
, testdir
, strlen(testdir
) + 1);
497 if (!pRtlDosPathNameToNtPathName_U(testdir_w
, &ntdirname
, NULL
, NULL
))
499 ok(0, "RtlDosPathNametoNtPathName_U failed\n");
502 InitializeObjectAttributes(&attr
, &ntdirname
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
504 data_size
= offsetof(FILE_BOTH_DIRECTORY_INFORMATION
, FileName
[256]);
506 status
= pNtOpenFile(&dirh
, SYNCHRONIZE
| FILE_LIST_DIRECTORY
, &attr
, &io
, FILE_SHARE_READ
,
507 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE
);
508 ok (status
== STATUS_SUCCESS
, "failed to open dir '%s', ret 0x%x, error %d\n", testdir
, status
, GetLastError());
509 if (status
!= STATUS_SUCCESS
)
511 skip("can't test if we can't open the directory\n");
515 mask
.Buffer
= testmask
;
516 mask
.Length
= mask
.MaximumLength
= sizeof(testmask
);
517 pNtQueryDirectoryFile(dirh
, NULL
, NULL
, NULL
, &io
, data
, data_size
,
518 FileBothDirectoryInformation
, TRUE
, &mask
, FALSE
);
519 ok(U(io
).Status
== STATUS_SUCCESS
, "failed to query directory; status %x\n", U(io
).Status
);
520 data_len
= io
.Information
;
521 ok(data_len
>= sizeof(FILE_BOTH_DIRECTORY_INFORMATION
), "not enough data in directory\n");
523 name
= dir_info
->FileName
;
524 name_len
= dir_info
->FileNameLength
/ sizeof(WCHAR
);
526 ok(name_len
== testfile_len
, "unexpected filename length %u\n", name_len
);
527 ok(!memcmp(name
, testfile_w
, testfile_len
* sizeof(WCHAR
)), "unexpected filename %s\n",
528 wine_dbgstr_wn(name
, name_len
));
533 tear_down_case_test(testdir
);
534 pRtlFreeUnicodeString(&ntdirname
);
537 static void test_redirection(void)
542 if (!pRtlWow64EnableFsRedirection
|| !pRtlWow64EnableFsRedirectionEx
)
544 skip( "Wow64 redirection not supported\n" );
547 status
= pRtlWow64EnableFsRedirectionEx( FALSE
, &old
);
548 if (status
== STATUS_NOT_IMPLEMENTED
)
550 skip( "Wow64 redirection not supported\n" );
553 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
555 status
= pRtlWow64EnableFsRedirectionEx( FALSE
, &cur
);
556 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
557 ok( !cur
, "RtlWow64EnableFsRedirectionEx got %u\n", cur
);
559 status
= pRtlWow64EnableFsRedirectionEx( TRUE
, &cur
);
560 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
561 status
= pRtlWow64EnableFsRedirectionEx( TRUE
, &cur
);
562 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
563 ok( cur
== 1, "RtlWow64EnableFsRedirectionEx got %u\n", cur
);
565 status
= pRtlWow64EnableFsRedirection( TRUE
);
566 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
567 status
= pRtlWow64EnableFsRedirectionEx( TRUE
, &cur
);
568 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
569 ok( !cur
, "RtlWow64EnableFsRedirectionEx got %u\n", cur
);
571 status
= pRtlWow64EnableFsRedirectionEx( TRUE
, NULL
);
572 ok( status
== STATUS_ACCESS_VIOLATION
, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status
);
573 status
= pRtlWow64EnableFsRedirectionEx( TRUE
, (void*)1 );
574 ok( status
== STATUS_ACCESS_VIOLATION
, "RtlWow64EnableFsRedirectionEx failed with status %x\n", status
);
576 status
= pRtlWow64EnableFsRedirection( FALSE
);
577 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
578 status
= pRtlWow64EnableFsRedirectionEx( FALSE
, &cur
);
579 ok( !status
, "RtlWow64EnableFsRedirectionEx failed status %x\n", status
);
580 ok( cur
== 1, "RtlWow64EnableFsRedirectionEx got %u\n", cur
);
582 pRtlWow64EnableFsRedirectionEx( old
, &cur
);
585 START_TEST(directory
)
587 HMODULE hntdll
= GetModuleHandleA("ntdll.dll");
590 skip("not running on NT, skipping test\n");
594 pNtClose
= (void *)GetProcAddress(hntdll
, "NtClose");
595 pNtOpenFile
= (void *)GetProcAddress(hntdll
, "NtOpenFile");
596 pNtQueryDirectoryFile
= (void *)GetProcAddress(hntdll
, "NtQueryDirectoryFile");
597 pRtlCreateUnicodeStringFromAsciiz
= (void *)GetProcAddress(hntdll
, "RtlCreateUnicodeStringFromAsciiz");
598 pRtlDosPathNameToNtPathName_U
= (void *)GetProcAddress(hntdll
, "RtlDosPathNameToNtPathName_U");
599 pRtlInitUnicodeString
= (void *)GetProcAddress(hntdll
, "RtlInitUnicodeString");
600 pRtlFreeUnicodeString
= (void *)GetProcAddress(hntdll
, "RtlFreeUnicodeString");
601 pRtlMultiByteToUnicodeN
= (void *)GetProcAddress(hntdll
,"RtlMultiByteToUnicodeN");
602 pRtlWow64EnableFsRedirection
= (void *)GetProcAddress(hntdll
,"RtlWow64EnableFsRedirection");
603 pRtlWow64EnableFsRedirectionEx
= (void *)GetProcAddress(hntdll
,"RtlWow64EnableFsRedirectionEx");
605 test_NtQueryDirectoryFile();
606 test_NtQueryDirectoryFile_case();