shell32: Add a stub SHGetKnownFolderIDList.
[wine] / dlls / ntdll / tests / file.c
1 /* Unit test suite for Ntdll file functions
2  *
3  * Copyright 2007 Jeff Latimer
4  * Copyright 2007 Andrey Turkin
5  * Copyright 2008 Jeff Zaroyko
6  * Copyright 2011 Dmitry Timoshkov
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 <stdio.h>
28 #include <stdarg.h>
29
30 #include "ntstatus.h"
31 /* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro
32  * definition errors when we get to winnt.h
33  */
34 #define WIN32_NO_STATUS
35
36 #include "wine/test.h"
37 #include "winternl.h"
38 #include "winuser.h"
39 #include "winioctl.h"
40
41 #ifndef IO_COMPLETION_ALL_ACCESS
42 #define IO_COMPLETION_ALL_ACCESS 0x001F0003
43 #endif
44
45 static BOOL     (WINAPI * pGetVolumePathNameW)(LPCWSTR, LPWSTR, DWORD);
46 static UINT     (WINAPI *pGetSystemWow64DirectoryW)( LPWSTR, UINT );
47
48 static VOID     (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING );
49 static VOID     (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR );
50 static BOOL     (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* );
51 static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG, ULONG * );
52
53 static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
54                                        ULONG, ULONG, ULONG, PLARGE_INTEGER );
55 static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
56 static NTSTATUS (WINAPI *pNtOpenFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG);
57 static NTSTATUS (WINAPI *pNtDeleteFile)(POBJECT_ATTRIBUTES ObjectAttributes);
58 static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent,
59                                       PIO_APC_ROUTINE apc, void* apc_user,
60                                       PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
61                                       PLARGE_INTEGER offset, PULONG key);
62 static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
63                                        PIO_APC_ROUTINE apc, void* apc_user,
64                                        PIO_STATUS_BLOCK io_status,
65                                        const void* buffer, ULONG length,
66                                        PLARGE_INTEGER offset, PULONG key);
67 static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE hFile, PIO_STATUS_BLOCK io_status);
68 static NTSTATUS (WINAPI *pNtCancelIoFileEx)(HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status);
69 static NTSTATUS (WINAPI *pNtClose)( PHANDLE );
70
71 static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG);
72 static NTSTATUS (WINAPI *pNtOpenIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
73 static NTSTATUS (WINAPI *pNtQueryIoCompletion)(HANDLE, IO_COMPLETION_INFORMATION_CLASS, PVOID, ULONG, PULONG);
74 static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER);
75 static NTSTATUS (WINAPI *pNtSetIoCompletion)(HANDLE, ULONG_PTR, ULONG_PTR, NTSTATUS, ULONG);
76 static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS);
77 static NTSTATUS (WINAPI *pNtQueryInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS);
78 static NTSTATUS (WINAPI *pNtQueryDirectoryFile)(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,
79                                                 PVOID,ULONG,FILE_INFORMATION_CLASS,BOOLEAN,PUNICODE_STRING,BOOLEAN);
80 static NTSTATUS (WINAPI *pNtQueryVolumeInformationFile)(HANDLE,PIO_STATUS_BLOCK,PVOID,ULONG,FS_INFORMATION_CLASS);
81
82 static inline BOOL is_signaled( HANDLE obj )
83 {
84     return WaitForSingleObject( obj, 0 ) == 0;
85 }
86
87 #define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c"
88 #define TEST_BUF_LEN 3
89
90 static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size )
91 {
92     *read = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT,
93                             1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
94     ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
95
96     *write = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
97     ok(*write != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
98
99     return TRUE;
100 }
101
102 static HANDLE create_temp_file( ULONG flags )
103 {
104     char buffer[MAX_PATH];
105     HANDLE handle;
106
107     GetTempFileNameA( ".", "foo", 0, buffer );
108     handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
109                          flags | FILE_FLAG_DELETE_ON_CLOSE, 0);
110     ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
111     return (handle == INVALID_HANDLE_VALUE) ? 0 : handle;
112 }
113
114 #define CVALUE_FIRST 0xfffabbcc
115 #define CKEY_FIRST 0x1030341
116 #define CKEY_SECOND 0x132E46
117
118 static ULONG_PTR completionKey;
119 static IO_STATUS_BLOCK ioSb;
120 static ULONG_PTR completionValue;
121
122 static ULONG get_pending_msgs(HANDLE h)
123 {
124     NTSTATUS res;
125     ULONG a, req;
126
127     res = pNtQueryIoCompletion( h, IoCompletionBasicInformation, &a, sizeof(a), &req );
128     ok( res == STATUS_SUCCESS, "NtQueryIoCompletion failed: %x\n", res );
129     if (res != STATUS_SUCCESS) return -1;
130     ok( req == sizeof(a), "Unexpected response size: %x\n", req );
131     return a;
132 }
133
134 static BOOL get_msg(HANDLE h)
135 {
136     LARGE_INTEGER timeout = {{-10000000*3}};
137     DWORD res = pNtRemoveIoCompletion( h, &completionKey, &completionValue, &ioSb, &timeout);
138     ok( res == STATUS_SUCCESS, "NtRemoveIoCompletion failed: %x\n", res );
139     if (res != STATUS_SUCCESS)
140     {
141         completionKey = completionValue = 0;
142         memset(&ioSb, 0, sizeof(ioSb));
143         return FALSE;
144     }
145     return TRUE;
146 }
147
148
149 static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
150 {
151     int *count = arg;
152
153     trace( "apc called block %p iosb.status %x iosb.info %lu\n",
154            iosb, U(*iosb).Status, iosb->Information );
155     (*count)++;
156     ok( !reserved, "reserved is not 0: %x\n", reserved );
157 }
158
159 static void create_file_test(void)
160 {
161     static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t',
162                                         '\\','f','a','i','l','i','n','g',0};
163     static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0};
164     static const WCHAR pipeInvalidNameW[]  = {'a','|','b',0};
165     NTSTATUS status;
166     HANDLE dir, file;
167     WCHAR path[MAX_PATH];
168     OBJECT_ATTRIBUTES attr;
169     IO_STATUS_BLOCK io;
170     UNICODE_STRING nameW;
171
172     GetCurrentDirectoryW( MAX_PATH, path );
173     pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
174     attr.Length = sizeof(attr);
175     attr.RootDirectory = 0;
176     attr.ObjectName = &nameW;
177     attr.Attributes = OBJ_CASE_INSENSITIVE;
178     attr.SecurityDescriptor = NULL;
179     attr.SecurityQualityOfService = NULL;
180
181     /* try various open modes and options on directories */
182     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
183                             FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0 );
184     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
185     CloseHandle( dir );
186
187     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
188                             FILE_CREATE, FILE_DIRECTORY_FILE, NULL, 0 );
189     ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED,
190         "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
191
192     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
193                             FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0 );
194     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
195     CloseHandle( dir );
196
197     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
198                             FILE_SUPERSEDE, FILE_DIRECTORY_FILE, NULL, 0 );
199     ok( status == STATUS_INVALID_PARAMETER, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
200
201     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
202                             FILE_OVERWRITE, FILE_DIRECTORY_FILE, NULL, 0 );
203     ok( status == STATUS_INVALID_PARAMETER, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
204
205     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
206                             FILE_OVERWRITE_IF, FILE_DIRECTORY_FILE, NULL, 0 );
207     ok( status == STATUS_INVALID_PARAMETER, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
208
209     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
210                             FILE_OPEN, 0, NULL, 0 );
211     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
212     CloseHandle( dir );
213
214     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
215                             FILE_CREATE, 0, NULL, 0 );
216     ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED,
217         "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
218
219     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
220                             FILE_OPEN_IF, 0, NULL, 0 );
221     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
222     CloseHandle( dir );
223
224     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
225                             FILE_SUPERSEDE, 0, NULL, 0 );
226     ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED,
227         "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
228
229     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
230                             FILE_OVERWRITE, 0, NULL, 0 );
231     ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED,
232         "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
233
234     status = pNtCreateFile( &dir, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
235                             FILE_OVERWRITE_IF, 0, NULL, 0 );
236     ok( status == STATUS_OBJECT_NAME_COLLISION || status == STATUS_ACCESS_DENIED,
237         "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
238
239     pRtlFreeUnicodeString( &nameW );
240
241     pRtlInitUnicodeString( &nameW, systemrootW );
242     attr.Length = sizeof(attr);
243     attr.RootDirectory = NULL;
244     attr.ObjectName = &nameW;
245     attr.Attributes = OBJ_CASE_INSENSITIVE;
246     attr.SecurityDescriptor = NULL;
247     attr.SecurityQualityOfService = NULL;
248     dir = NULL;
249     status = pNtCreateFile( &dir, FILE_APPEND_DATA, &attr, &io, NULL, FILE_ATTRIBUTE_NORMAL, 0,
250                             FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
251     todo_wine
252     ok( status == STATUS_INVALID_PARAMETER,
253         "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
254
255     /* Invalid chars in file/dirnames */
256     pRtlDosPathNameToNtPathName_U(questionmarkInvalidNameW, &nameW, NULL, NULL);
257     attr.ObjectName = &nameW;
258     status = pNtCreateFile(&dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0,
259                            FILE_SHARE_READ, FILE_CREATE,
260                            FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
261     ok(status == STATUS_OBJECT_NAME_INVALID,
262        "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status);
263
264     status = pNtCreateFile(&file, GENERIC_WRITE|SYNCHRONIZE, &attr, &io, NULL, 0,
265                            0, FILE_CREATE,
266                            FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
267     ok(status == STATUS_OBJECT_NAME_INVALID,
268        "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status);
269
270     pRtlDosPathNameToNtPathName_U(pipeInvalidNameW, &nameW, NULL, NULL);
271     attr.ObjectName = &nameW;
272     status = pNtCreateFile(&dir, GENERIC_READ|SYNCHRONIZE, &attr, &io, NULL, 0,
273                            FILE_SHARE_READ, FILE_CREATE,
274                            FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
275     ok(status == STATUS_OBJECT_NAME_INVALID,
276        "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status);
277
278     status = pNtCreateFile(&file, GENERIC_WRITE|SYNCHRONIZE, &attr, &io, NULL, 0,
279                            0, FILE_CREATE,
280                            FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
281     ok(status == STATUS_OBJECT_NAME_INVALID,
282        "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status);
283 }
284
285 static void open_file_test(void)
286 {
287     NTSTATUS status;
288     HANDLE dir, root, handle;
289     WCHAR path[MAX_PATH];
290     BYTE data[1024];
291     OBJECT_ATTRIBUTES attr;
292     IO_STATUS_BLOCK io;
293     UNICODE_STRING nameW;
294     UINT i, len;
295     BOOL restart = TRUE;
296
297     len = GetWindowsDirectoryW( path, MAX_PATH );
298     pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
299     attr.Length = sizeof(attr);
300     attr.RootDirectory = 0;
301     attr.ObjectName = &nameW;
302     attr.Attributes = OBJ_CASE_INSENSITIVE;
303     attr.SecurityDescriptor = NULL;
304     attr.SecurityQualityOfService = NULL;
305     status = pNtOpenFile( &dir, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io,
306                           FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT );
307     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
308     pRtlFreeUnicodeString( &nameW );
309
310     path[3] = 0;  /* root of the drive */
311     pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
312     status = pNtOpenFile( &root, GENERIC_READ, &attr, &io,
313                           FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE );
314     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
315     pRtlFreeUnicodeString( &nameW );
316
317     /* test opening system dir with RootDirectory set to windows dir */
318     GetSystemDirectoryW( path, MAX_PATH );
319     while (path[len] == '\\') len++;
320     nameW.Buffer = path + len;
321     nameW.Length = lstrlenW(path + len) * sizeof(WCHAR);
322     attr.RootDirectory = dir;
323     status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io,
324                           FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE );
325     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
326     CloseHandle( handle );
327
328     /* try uppercase name */
329     for (i = len; path[i]; i++) if (path[i] >= 'a' && path[i] <= 'z') path[i] -= 'a' - 'A';
330     status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io,
331                           FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE );
332     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
333     CloseHandle( handle );
334
335     /* try with leading backslash */
336     nameW.Buffer--;
337     nameW.Length += sizeof(WCHAR);
338     status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io,
339                           FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE );
340     ok( status == STATUS_INVALID_PARAMETER ||
341         status == STATUS_OBJECT_NAME_INVALID ||
342         status == STATUS_OBJECT_PATH_SYNTAX_BAD,
343         "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
344     if (!status) CloseHandle( handle );
345
346     /* try with empty name */
347     nameW.Length = 0;
348     status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io,
349                           FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE );
350     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
351     CloseHandle( handle );
352
353     /* try open by file id */
354
355     while (!pNtQueryDirectoryFile( dir, NULL, NULL, NULL, &io, data, sizeof(data),
356                                    FileIdBothDirectoryInformation, TRUE, NULL, restart ))
357     {
358         FILE_ID_BOTH_DIRECTORY_INFORMATION *info = (FILE_ID_BOTH_DIRECTORY_INFORMATION *)data;
359
360         restart = FALSE;
361
362         if (!info->FileId.QuadPart) continue;
363
364         nameW.Buffer = (WCHAR *)&info->FileId;
365         nameW.Length = sizeof(info->FileId);
366         info->FileName[info->FileNameLength/sizeof(WCHAR)] = 0;
367         attr.RootDirectory = dir;
368         /* We skip 'open' files by not specifying FILE_SHARE_WRITE */
369         status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io,
370                               FILE_SHARE_READ,
371                               FILE_OPEN_BY_FILE_ID |
372                               ((info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_DIRECTORY_FILE : 0) );
373         ok( status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED || status == STATUS_NOT_IMPLEMENTED || status == STATUS_SHARING_VIOLATION,
374             "open %s failed %x\n", wine_dbgstr_w(info->FileName), status );
375         if (status == STATUS_NOT_IMPLEMENTED)
376         {
377             win_skip( "FILE_OPEN_BY_FILE_ID not supported\n" );
378             break;
379         }
380         if (status == STATUS_SHARING_VIOLATION)
381             trace( "%s is currently open\n", wine_dbgstr_w(info->FileName) );
382         if (!status)
383         {
384             BYTE buf[sizeof(FILE_ALL_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
385
386             if (!pNtQueryInformationFile( handle, &io, buf, sizeof(buf), FileAllInformation ))
387             {
388                 FILE_ALL_INFORMATION *fai = (FILE_ALL_INFORMATION *)buf;
389
390                 /* check that it's the same file/directory */
391
392                 /* don't check the size for directories */
393                 if (!(info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
394                     ok( info->EndOfFile.QuadPart == fai->StandardInformation.EndOfFile.QuadPart,
395                         "mismatched file size for %s\n", wine_dbgstr_w(info->FileName));
396
397                 ok( info->CreationTime.QuadPart == fai->BasicInformation.CreationTime.QuadPart,
398                     "mismatched creation time for %s\n", wine_dbgstr_w(info->FileName));
399             }
400             CloseHandle( handle );
401
402             /* try same thing from drive root */
403             attr.RootDirectory = root;
404             status = pNtOpenFile( &handle, GENERIC_READ, &attr, &io,
405                                   FILE_SHARE_READ|FILE_SHARE_WRITE,
406                                   FILE_OPEN_BY_FILE_ID |
407                                   ((info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_DIRECTORY_FILE : 0) );
408             ok( status == STATUS_SUCCESS || status == STATUS_NOT_IMPLEMENTED,
409                 "open %s failed %x\n", wine_dbgstr_w(info->FileName), status );
410             if (!status) CloseHandle( handle );
411         }
412     }
413
414     CloseHandle( dir );
415     CloseHandle( root );
416 }
417
418 static void delete_file_test(void)
419 {
420     NTSTATUS ret;
421     OBJECT_ATTRIBUTES attr;
422     UNICODE_STRING nameW;
423     WCHAR pathW[MAX_PATH];
424     WCHAR pathsubW[MAX_PATH];
425     static const WCHAR testdirW[] = {'n','t','d','e','l','e','t','e','f','i','l','e',0};
426     static const WCHAR subdirW[]  = {'\\','s','u','b',0};
427
428     ret = GetTempPathW(MAX_PATH, pathW);
429     if (!ret)
430     {
431         ok(0, "couldn't get temp dir\n");
432         return;
433     }
434     if (ret + sizeof(testdirW)/sizeof(WCHAR)-1 + sizeof(subdirW)/sizeof(WCHAR)-1 >= MAX_PATH)
435     {
436         ok(0, "MAX_PATH exceeded in constructing paths\n");
437         return;
438     }
439
440     lstrcatW(pathW, testdirW);
441     lstrcpyW(pathsubW, pathW);
442     lstrcatW(pathsubW, subdirW);
443
444     ret = CreateDirectoryW(pathW, NULL);
445     ok(ret == TRUE, "couldn't create directory ntdeletefile\n");
446     if (!pRtlDosPathNameToNtPathName_U(pathW, &nameW, NULL, NULL))
447     {
448         ok(0,"RtlDosPathNametoNtPathName_U failed\n");
449         return;
450     }
451
452     attr.Length = sizeof(attr);
453     attr.RootDirectory = 0;
454     attr.Attributes = OBJ_CASE_INSENSITIVE;
455     attr.ObjectName = &nameW;
456     attr.SecurityDescriptor = NULL;
457     attr.SecurityQualityOfService = NULL;
458
459     /* test NtDeleteFile on an empty directory */
460     ret = pNtDeleteFile(&attr);
461     ok(ret == STATUS_SUCCESS, "NtDeleteFile should succeed in removing an empty directory\n");
462     ret = RemoveDirectoryW(pathW);
463     ok(ret == FALSE, "expected to fail removing directory, NtDeleteFile should have removed it\n");
464
465     /* test NtDeleteFile on a non-empty directory */
466     ret = CreateDirectoryW(pathW, NULL);
467     ok(ret == TRUE, "couldn't create directory ntdeletefile ?!\n");
468     ret = CreateDirectoryW(pathsubW, NULL);
469     ok(ret == TRUE, "couldn't create directory subdir\n");
470     ret = pNtDeleteFile(&attr);
471     ok(ret == STATUS_SUCCESS, "expected NtDeleteFile to ret STATUS_SUCCESS\n");
472     ret = RemoveDirectoryW(pathsubW);
473     ok(ret == TRUE, "expected to remove directory ntdeletefile\\sub\n");
474     ret = RemoveDirectoryW(pathW);
475     ok(ret == TRUE, "expected to remove directory ntdeletefile, NtDeleteFile failed.\n");
476
477     pRtlFreeUnicodeString( &nameW );
478 }
479
480 static void read_file_test(void)
481 {
482     const char text[] = "foobar";
483     HANDLE handle, read, write;
484     NTSTATUS status;
485     IO_STATUS_BLOCK iosb, iosb2;
486     DWORD written;
487     int apc_count = 0;
488     char buffer[128];
489     LARGE_INTEGER offset;
490     HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
491     BOOL ret;
492
493     buffer[0] = 1;
494
495     if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
496
497     /* try read with no data */
498     U(iosb).Status = 0xdeadbabe;
499     iosb.Information = 0xdeadbeef;
500     ok( is_signaled( read ), "read handle is not signaled\n" );
501     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
502     ok( status == STATUS_PENDING, "wrong status %x\n", status );
503     ok( !is_signaled( read ), "read handle is signaled\n" );
504     ok( !is_signaled( event ), "event is signaled\n" );
505     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
506     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
507     ok( !apc_count, "apc was called\n" );
508     WriteFile( write, buffer, 1, &written, NULL );
509     /* iosb updated here by async i/o */
510     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
511     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
512     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
513     ok( !is_signaled( read ), "read handle is signaled\n" );
514     ok( is_signaled( event ), "event is not signaled\n" );
515     ok( !apc_count, "apc was called\n" );
516     apc_count = 0;
517     SleepEx( 1, FALSE ); /* non-alertable sleep */
518     ok( !apc_count, "apc was called\n" );
519     SleepEx( 1, TRUE ); /* alertable sleep */
520     ok( apc_count == 1, "apc not called\n" );
521
522     /* with no event, the pipe handle itself gets signaled */
523     apc_count = 0;
524     U(iosb).Status = 0xdeadbabe;
525     iosb.Information = 0xdeadbeef;
526     ok( !is_signaled( read ), "read handle is not signaled\n" );
527     status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
528     ok( status == STATUS_PENDING, "wrong status %x\n", status );
529     ok( !is_signaled( read ), "read handle is signaled\n" );
530     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
531     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
532     ok( !apc_count, "apc was called\n" );
533     WriteFile( write, buffer, 1, &written, NULL );
534     /* iosb updated here by async i/o */
535     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
536     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
537     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
538     ok( is_signaled( read ), "read handle is signaled\n" );
539     ok( !apc_count, "apc was called\n" );
540     apc_count = 0;
541     SleepEx( 1, FALSE ); /* non-alertable sleep */
542     ok( !apc_count, "apc was called\n" );
543     SleepEx( 1, TRUE ); /* alertable sleep */
544     ok( apc_count == 1, "apc not called\n" );
545
546     /* now read with data ready */
547     apc_count = 0;
548     U(iosb).Status = 0xdeadbabe;
549     iosb.Information = 0xdeadbeef;
550     ResetEvent( event );
551     WriteFile( write, buffer, 1, &written, NULL );
552     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
553     ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
554     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
555     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
556     ok( is_signaled( event ), "event is not signaled\n" );
557     ok( !apc_count, "apc was called\n" );
558     SleepEx( 1, FALSE ); /* non-alertable sleep */
559     ok( !apc_count, "apc was called\n" );
560     SleepEx( 1, TRUE ); /* alertable sleep */
561     ok( apc_count == 1, "apc not called\n" );
562
563     /* try read with no data */
564     apc_count = 0;
565     U(iosb).Status = 0xdeadbabe;
566     iosb.Information = 0xdeadbeef;
567     ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */
568     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
569     ok( status == STATUS_PENDING, "wrong status %x\n", status );
570     ok( !is_signaled( event ), "event is signaled\n" );
571     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
572     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
573     ok( !apc_count, "apc was called\n" );
574     WriteFile( write, buffer, 1, &written, NULL );
575     /* partial read is good enough */
576     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
577     ok( is_signaled( event ), "event is signaled\n" );
578     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
579     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
580     ok( !apc_count, "apc was called\n" );
581     SleepEx( 1, TRUE ); /* alertable sleep */
582     ok( apc_count == 1, "apc was not called\n" );
583
584     /* read from disconnected pipe */
585     apc_count = 0;
586     U(iosb).Status = 0xdeadbabe;
587     iosb.Information = 0xdeadbeef;
588     CloseHandle( write );
589     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
590     ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status );
591     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
592     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
593     ok( !is_signaled( event ), "event is signaled\n" );
594     ok( !apc_count, "apc was called\n" );
595     SleepEx( 1, TRUE ); /* alertable sleep */
596     ok( !apc_count, "apc was called\n" );
597     CloseHandle( read );
598
599     /* read from closed handle */
600     apc_count = 0;
601     U(iosb).Status = 0xdeadbabe;
602     iosb.Information = 0xdeadbeef;
603     SetEvent( event );
604     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
605     ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
606     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
607     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
608     ok( is_signaled( event ), "event is signaled\n" );  /* not reset on invalid handle */
609     ok( !apc_count, "apc was called\n" );
610     SleepEx( 1, TRUE ); /* alertable sleep */
611     ok( !apc_count, "apc was called\n" );
612
613     /* disconnect while async read is in progress */
614     if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
615     apc_count = 0;
616     U(iosb).Status = 0xdeadbabe;
617     iosb.Information = 0xdeadbeef;
618     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
619     ok( status == STATUS_PENDING, "wrong status %x\n", status );
620     ok( !is_signaled( event ), "event is signaled\n" );
621     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
622     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
623     ok( !apc_count, "apc was called\n" );
624     CloseHandle( write );
625     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
626     ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status );
627     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
628     ok( is_signaled( event ), "event is signaled\n" );
629     ok( !apc_count, "apc was called\n" );
630     SleepEx( 1, TRUE ); /* alertable sleep */
631     ok( apc_count == 1, "apc was not called\n" );
632     CloseHandle( read );
633
634     if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
635     ret = DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS);
636     ok(ret, "Failed to duplicate handle: %d\n", GetLastError());
637
638     apc_count = 0;
639     U(iosb).Status = 0xdeadbabe;
640     iosb.Information = 0xdeadbeef;
641     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
642     ok( status == STATUS_PENDING, "wrong status %x\n", status );
643     ok( !is_signaled( event ), "event is signaled\n" );
644     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
645     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
646     ok( !apc_count, "apc was called\n" );
647     /* Cancel by other handle */
648     status = pNtCancelIoFile( read, &iosb2 );
649     ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status);
650     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
651     ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
652     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
653     ok( is_signaled( event ), "event is signaled\n" );
654     todo_wine ok( !apc_count, "apc was called\n" );
655     SleepEx( 1, TRUE ); /* alertable sleep */
656     ok( apc_count == 1, "apc was not called\n" );
657
658     apc_count = 0;
659     U(iosb).Status = 0xdeadbabe;
660     iosb.Information = 0xdeadbeef;
661     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
662     ok( status == STATUS_PENDING, "wrong status %x\n", status );
663     ok( !is_signaled( event ), "event is signaled\n" );
664     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
665     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
666     ok( !apc_count, "apc was called\n" );
667     /* Close queued handle */
668     CloseHandle( read );
669     SleepEx( 1, TRUE ); /* alertable sleep */
670     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
671     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
672     status = pNtCancelIoFile( read, &iosb2 );
673     ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n");
674     status = pNtCancelIoFile( handle, &iosb2 );
675     ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status);
676     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
677     ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
678     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
679     ok( is_signaled( event ), "event is signaled\n" );
680     todo_wine ok( !apc_count, "apc was called\n" );
681     SleepEx( 1, TRUE ); /* alertable sleep */
682     ok( apc_count == 1, "apc was not called\n" );
683     CloseHandle( handle );
684     CloseHandle( write );
685
686     if (pNtCancelIoFileEx)
687     {
688         /* Basic Cancel Ex */
689         if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
690
691         apc_count = 0;
692         U(iosb).Status = 0xdeadbabe;
693         iosb.Information = 0xdeadbeef;
694         status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
695         ok( status == STATUS_PENDING, "wrong status %x\n", status );
696         ok( !is_signaled( event ), "event is signaled\n" );
697         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
698         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
699         ok( !apc_count, "apc was called\n" );
700         status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
701         ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
702         Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
703         ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
704         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
705         ok( is_signaled( event ), "event is signaled\n" );
706         todo_wine ok( !apc_count, "apc was called\n" );
707         SleepEx( 1, TRUE ); /* alertable sleep */
708         ok( apc_count == 1, "apc was not called\n" );
709
710         /* Duplicate iosb */
711         apc_count = 0;
712         U(iosb).Status = 0xdeadbabe;
713         iosb.Information = 0xdeadbeef;
714         status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
715         ok( status == STATUS_PENDING, "wrong status %x\n", status );
716         ok( !is_signaled( event ), "event is signaled\n" );
717         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
718         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
719         ok( !apc_count, "apc was called\n" );
720         status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
721         ok( status == STATUS_PENDING, "wrong status %x\n", status );
722         ok( !is_signaled( event ), "event is signaled\n" );
723         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
724         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
725         ok( !apc_count, "apc was called\n" );
726         status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
727         ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
728         Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
729         ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
730         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
731         ok( is_signaled( event ), "event is signaled\n" );
732         todo_wine ok( !apc_count, "apc was called\n" );
733         SleepEx( 1, TRUE ); /* alertable sleep */
734         ok( apc_count == 2, "apc was not called\n" );
735
736         CloseHandle( read );
737         CloseHandle( write );
738     }
739
740     /* now try a real file */
741     if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return;
742     apc_count = 0;
743     U(iosb).Status = 0xdeadbabe;
744     iosb.Information = 0xdeadbeef;
745     offset.QuadPart = 0;
746     ResetEvent( event );
747     status = pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL );
748     ok( status == STATUS_SUCCESS || status == STATUS_PENDING, "wrong status %x\n", status );
749     if (status == STATUS_PENDING) WaitForSingleObject( event, 1000 );
750     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
751     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
752     ok( is_signaled( event ), "event is signaled\n" );
753     ok( !apc_count, "apc was called\n" );
754     SleepEx( 1, TRUE ); /* alertable sleep */
755     ok( apc_count == 1, "apc was not called\n" );
756
757     apc_count = 0;
758     U(iosb).Status = 0xdeadbabe;
759     iosb.Information = 0xdeadbeef;
760     offset.QuadPart = 0;
761     ResetEvent( event );
762     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL );
763     ok( status == STATUS_SUCCESS ||
764         status == STATUS_PENDING, /* vista */
765         "wrong status %x\n", status );
766     if (status == STATUS_PENDING) WaitForSingleObject( event, 1000 );
767     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
768     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
769     ok( is_signaled( event ), "event is signaled\n" );
770     ok( !apc_count, "apc was called\n" );
771     SleepEx( 1, TRUE ); /* alertable sleep */
772     ok( apc_count == 1, "apc was not called\n" );
773
774     /* read beyond eof */
775     apc_count = 0;
776     U(iosb).Status = 0xdeadbabe;
777     iosb.Information = 0xdeadbeef;
778     offset.QuadPart = strlen(text) + 2;
779     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL );
780     if (status == STATUS_PENDING)  /* vista */
781     {
782         WaitForSingleObject( event, 1000 );
783         ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status );
784         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
785         ok( is_signaled( event ), "event is signaled\n" );
786         ok( !apc_count, "apc was called\n" );
787         SleepEx( 1, TRUE ); /* alertable sleep */
788         ok( apc_count == 1, "apc was not called\n" );
789     }
790     else
791     {
792         ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status );
793         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
794         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
795         ok( !is_signaled( event ), "event is signaled\n" );
796         ok( !apc_count, "apc was called\n" );
797         SleepEx( 1, TRUE ); /* alertable sleep */
798         ok( !apc_count, "apc was called\n" );
799     }
800     CloseHandle( handle );
801
802     /* now a non-overlapped file */
803     if (!(handle = create_temp_file(0))) return;
804     apc_count = 0;
805     U(iosb).Status = 0xdeadbabe;
806     iosb.Information = 0xdeadbeef;
807     offset.QuadPart = 0;
808     status = pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL );
809     ok( status == STATUS_END_OF_FILE ||
810         status == STATUS_SUCCESS ||
811         status == STATUS_PENDING,  /* vista */
812         "wrong status %x\n", status );
813     if (status == STATUS_PENDING) WaitForSingleObject( event, 1000 );
814     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
815     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
816     ok( is_signaled( event ), "event is signaled\n" );
817     ok( !apc_count, "apc was called\n" );
818     SleepEx( 1, TRUE ); /* alertable sleep */
819     ok( apc_count == 1, "apc was not called\n" );
820
821     apc_count = 0;
822     U(iosb).Status = 0xdeadbabe;
823     iosb.Information = 0xdeadbeef;
824     offset.QuadPart = 0;
825     ResetEvent( event );
826     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL );
827     ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
828     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
829     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
830     ok( is_signaled( event ), "event is signaled\n" );
831     ok( !apc_count, "apc was called\n" );
832     SleepEx( 1, TRUE ); /* alertable sleep */
833     todo_wine ok( !apc_count, "apc was called\n" );
834
835     /* read beyond eof */
836     apc_count = 0;
837     U(iosb).Status = 0xdeadbabe;
838     iosb.Information = 0xdeadbeef;
839     offset.QuadPart = strlen(text) + 2;
840     ResetEvent( event );
841     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL );
842     ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status );
843     todo_wine ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status );
844     todo_wine ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
845     todo_wine ok( is_signaled( event ), "event is not signaled\n" );
846     ok( !apc_count, "apc was called\n" );
847     SleepEx( 1, TRUE ); /* alertable sleep */
848     ok( !apc_count, "apc was called\n" );
849
850     CloseHandle( handle );
851
852     CloseHandle( event );
853 }
854
855 static void append_file_test(void)
856 {
857     const char text[] = "foobar";
858     HANDLE handle;
859     NTSTATUS status;
860     IO_STATUS_BLOCK iosb;
861     DWORD written;
862     char buffer[128];
863
864     GetTempFileNameA( ".", "foo", 0, buffer );
865     /* It is possible to open a file with only FILE_APPEND_DATA access flags.
866        It matches the O_WRONLY|O_APPEND open() posix behavior */
867     handle = CreateFileA(buffer, FILE_APPEND_DATA, 0, NULL, CREATE_ALWAYS,
868                          FILE_FLAG_DELETE_ON_CLOSE, 0);
869     ok( handle != INVALID_HANDLE_VALUE, "Failed to create a temp file in FILE_APPEND_DATA mode.\n" );
870     if(handle == INVALID_HANDLE_VALUE)
871     {
872         skip("Couldn't create a temporary file, skipping FILE_APPEND_DATA test\n");
873         return;
874     }
875
876     U(iosb).Status = STATUS_PENDING;
877     iosb.Information = 0;
878
879     status = pNtWriteFile(handle, NULL, NULL, NULL, &iosb,
880                           text, sizeof(text), NULL, NULL);
881
882     if (status == STATUS_PENDING)
883     {
884         WaitForSingleObject( handle, 1000 );
885         status = U(iosb).Status;
886     }
887     written = iosb.Information;
888
889     todo_wine
890     ok(status == STATUS_SUCCESS && written == sizeof(text), "FILE_APPEND_DATA NtWriteFile failed\n");
891
892     CloseHandle(handle);
893 }
894
895 static void nt_mailslot_test(void)
896 {
897     HANDLE hslot;
898     ACCESS_MASK DesiredAccess;
899     OBJECT_ATTRIBUTES attr;
900
901     ULONG CreateOptions;
902     ULONG MailslotQuota;
903     ULONG MaxMessageSize;
904     LARGE_INTEGER TimeOut;
905     IO_STATUS_BLOCK IoStatusBlock;
906     NTSTATUS rc;
907     UNICODE_STRING str;
908     WCHAR buffer1[] = { '\\','?','?','\\','M','A','I','L','S','L','O','T','\\',
909                         'R',':','\\','F','R','E','D','\0' };
910
911     TimeOut.QuadPart = -1;
912
913     pRtlInitUnicodeString(&str, buffer1);
914     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
915     CreateOptions = MailslotQuota = MaxMessageSize = 0;
916     DesiredAccess = GENERIC_READ;
917
918     /*
919      * Check for NULL pointer handling
920      */
921     rc = pNtCreateMailslotFile(NULL, DesiredAccess,
922          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
923          &TimeOut);
924     ok( rc == STATUS_ACCESS_VIOLATION ||
925         rc == STATUS_INVALID_PARAMETER, /* win2k3 */
926         "rc = %x not STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER\n", rc);
927
928     /*
929      * Test to see if the Timeout can be NULL
930      */
931     hslot = (HANDLE)0xdeadbeef;
932     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
933          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
934          NULL);
935     ok( rc == STATUS_SUCCESS ||
936         rc == STATUS_INVALID_PARAMETER, /* win2k3 */
937         "rc = %x not STATUS_SUCCESS or STATUS_INVALID_PARAMETER\n", rc);
938     ok( hslot != 0, "Handle is invalid\n");
939
940     if  ( rc == STATUS_SUCCESS ) pNtClose(hslot);
941
942     /*
943      * Test that the length field is checked properly
944      */
945     attr.Length = 0;
946     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
947          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
948          &TimeOut);
949     todo_wine ok( rc == STATUS_INVALID_PARAMETER, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc);
950
951     if  (rc == STATUS_SUCCESS) pNtClose(hslot);
952
953     attr.Length = sizeof(OBJECT_ATTRIBUTES)+1;
954     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
955          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
956          &TimeOut);
957     todo_wine ok( rc == STATUS_INVALID_PARAMETER, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc);
958
959     if  (rc == STATUS_SUCCESS) pNtClose(hslot);
960
961     /*
962      * Test handling of a NULL unicode string in ObjectName
963      */
964     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
965     attr.ObjectName = NULL;
966     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
967          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
968          &TimeOut);
969     ok( rc == STATUS_OBJECT_PATH_SYNTAX_BAD ||
970         rc == STATUS_INVALID_PARAMETER,
971         "rc = %x not STATUS_OBJECT_PATH_SYNTAX_BAD or STATUS_INVALID_PARAMETER\n", rc);
972
973     if  (rc == STATUS_SUCCESS) pNtClose(hslot);
974
975     /*
976      * Test a valid call
977      */
978     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
979     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
980          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
981          &TimeOut);
982     ok( rc == STATUS_SUCCESS, "Create MailslotFile failed rc = %x\n", rc);
983     ok( hslot != 0, "Handle is invalid\n");
984
985     rc = pNtClose(hslot);
986     ok( rc == STATUS_SUCCESS, "NtClose failed\n");
987 }
988
989 static void test_iocp_setcompletion(HANDLE h)
990 {
991     NTSTATUS res;
992     ULONG count;
993
994     res = pNtSetIoCompletion( h, CKEY_FIRST, CVALUE_FIRST, STATUS_INVALID_DEVICE_REQUEST, 3 );
995     ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %x\n", res );
996
997     count = get_pending_msgs(h);
998     ok( count == 1, "Unexpected msg count: %d\n", count );
999
1000     if (get_msg(h))
1001     {
1002         ok( completionKey == CKEY_FIRST, "Invalid completion key: %lx\n", completionKey );
1003         ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information );
1004         ok( U(ioSb).Status == STATUS_INVALID_DEVICE_REQUEST, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
1005         ok( completionValue == CVALUE_FIRST, "Invalid completion value: %lx\n", completionValue );
1006     }
1007
1008     count = get_pending_msgs(h);
1009     ok( !count, "Unexpected msg count: %d\n", count );
1010 }
1011
1012 static void test_iocp_fileio(HANDLE h)
1013 {
1014     static const char pipe_name[] = "\\\\.\\pipe\\iocompletiontestnamedpipe";
1015
1016     IO_STATUS_BLOCK iosb;
1017     FILE_COMPLETION_INFORMATION fci = {h, CKEY_SECOND};
1018     HANDLE hPipeSrv, hPipeClt;
1019     NTSTATUS res;
1020
1021     hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL );
1022     ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" );
1023     if (hPipeSrv != INVALID_HANDLE_VALUE )
1024     {
1025         hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
1026         ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" );
1027         if (hPipeClt != INVALID_HANDLE_VALUE)
1028         {
1029             U(iosb).Status = 0xdeadbeef;
1030             res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation );
1031             ok( res == STATUS_INVALID_PARAMETER, "Unexpected NtSetInformationFile on non-overlapped handle: %x\n", res );
1032             ok( U(iosb).Status == STATUS_INVALID_PARAMETER /* 98 */ || U(iosb).Status == 0xdeadbeef /* NT4+ */,
1033                 "Unexpected iosb.Status on non-overlapped handle: %x\n", U(iosb).Status );
1034             CloseHandle(hPipeClt);
1035         }
1036         CloseHandle( hPipeSrv );
1037     }
1038
1039     hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL );
1040     ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" );
1041     if (hPipeSrv == INVALID_HANDLE_VALUE )
1042         return;
1043
1044     hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
1045     ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" );
1046     if (hPipeClt != INVALID_HANDLE_VALUE)
1047     {
1048         OVERLAPPED o = {0,};
1049         BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN];
1050         DWORD read;
1051         long count;
1052
1053         U(iosb).Status = 0xdeadbeef;
1054         res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation );
1055         ok( res == STATUS_SUCCESS, "NtSetInformationFile failed: %x\n", res );
1056         ok( U(iosb).Status == STATUS_SUCCESS, "iosb.Status invalid: %x\n", U(iosb).Status );
1057
1058         memset( send_buf, 0, TEST_BUF_LEN );
1059         memset( recv_buf, 0xde, TEST_BUF_LEN );
1060         count = get_pending_msgs(h);
1061         ok( !count, "Unexpected msg count: %ld\n", count );
1062         ReadFile( hPipeSrv, recv_buf, TEST_BUF_LEN, &read, &o);
1063         count = get_pending_msgs(h);
1064         ok( !count, "Unexpected msg count: %ld\n", count );
1065         WriteFile( hPipeClt, send_buf, TEST_BUF_LEN, &read, NULL );
1066
1067         if (get_msg(h))
1068         {
1069             ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey );
1070             ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information );
1071             ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
1072             ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue );
1073             ok( !memcmp( send_buf, recv_buf, TEST_BUF_LEN ), "Receive buffer (%x %x %x) did not match send buffer (%x %x %x)\n", recv_buf[0], recv_buf[1], recv_buf[2], send_buf[0], send_buf[1], send_buf[2] );
1074         }
1075         count = get_pending_msgs(h);
1076         ok( !count, "Unexpected msg count: %ld\n", count );
1077
1078         memset( send_buf, 0, TEST_BUF_LEN );
1079         memset( recv_buf, 0xde, TEST_BUF_LEN );
1080         WriteFile( hPipeClt, send_buf, 2, &read, NULL );
1081         count = get_pending_msgs(h);
1082         ok( !count, "Unexpected msg count: %ld\n", count );
1083         ReadFile( hPipeSrv, recv_buf, 2, &read, &o);
1084         count = get_pending_msgs(h);
1085         ok( count == 1, "Unexpected msg count: %ld\n", count );
1086         if (get_msg(h))
1087         {
1088             ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey );
1089             ok( ioSb.Information == 2, "Invalid ioSb.Information: %ld\n", ioSb.Information );
1090             ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
1091             ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue );
1092             ok( !memcmp( send_buf, recv_buf, 2 ), "Receive buffer (%x %x) did not match send buffer (%x %x)\n", recv_buf[0], recv_buf[1], send_buf[0], send_buf[1] );
1093         }
1094
1095         ReadFile( hPipeSrv, recv_buf, TEST_BUF_LEN, &read, &o);
1096         CloseHandle( hPipeSrv );
1097         count = get_pending_msgs(h);
1098         ok( count == 1, "Unexpected msg count: %ld\n", count );
1099         if (get_msg(h))
1100         {
1101             ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey );
1102             ok( ioSb.Information == 0, "Invalid ioSb.Information: %ld\n", ioSb.Information );
1103             /* wine sends wrong status here */
1104             todo_wine ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
1105             ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue );
1106         }
1107     }
1108
1109     CloseHandle( hPipeClt );
1110 }
1111
1112 static void test_file_basic_information(void)
1113 {
1114     IO_STATUS_BLOCK io;
1115     FILE_BASIC_INFORMATION fbi;
1116     HANDLE h;
1117     int res;
1118     int attrib_mask = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL;
1119
1120     if (!(h = create_temp_file(0))) return;
1121
1122     /* Check default first */
1123     memset(&fbi, 0, sizeof(fbi));
1124     res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
1125     ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res);
1126     ok ( (fbi.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE,
1127          "attribute %x not expected\n", fbi.FileAttributes );
1128
1129     /* Then SYSTEM */
1130     /* Clear fbi to avoid setting times */
1131     memset(&fbi, 0, sizeof(fbi));
1132     fbi.FileAttributes = FILE_ATTRIBUTE_SYSTEM;
1133     U(io).Status = 0xdeadbeef;
1134     res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
1135     ok ( res == STATUS_SUCCESS, "can't set system attribute, NtSetInformationFile returned %x\n", res );
1136     ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status is %x\n", U(io).Status );
1137
1138     memset(&fbi, 0, sizeof(fbi));
1139     res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
1140     ok ( res == STATUS_SUCCESS, "can't get attributes\n");
1141     todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes );
1142
1143     /* Then HIDDEN */
1144     memset(&fbi, 0, sizeof(fbi));
1145     fbi.FileAttributes = FILE_ATTRIBUTE_HIDDEN;
1146     U(io).Status = 0xdeadbeef;
1147     res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
1148     ok ( res == STATUS_SUCCESS, "can't set system attribute, NtSetInformationFile returned %x\n", res );
1149     ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status is %x\n", U(io).Status );
1150
1151     memset(&fbi, 0, sizeof(fbi));
1152     res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
1153     ok ( res == STATUS_SUCCESS, "can't get attributes\n");
1154     todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes );
1155
1156     /* Check NORMAL last of all (to make sure we can clear attributes) */
1157     memset(&fbi, 0, sizeof(fbi));
1158     fbi.FileAttributes = FILE_ATTRIBUTE_NORMAL;
1159     U(io).Status = 0xdeadbeef;
1160     res = pNtSetInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
1161     ok ( res == STATUS_SUCCESS, "can't set normal attribute, NtSetInformationFile returned %x\n", res );
1162     ok ( U(io).Status == STATUS_SUCCESS, "can't set normal attribute, io.Status is %x\n", U(io).Status );
1163
1164     memset(&fbi, 0, sizeof(fbi));
1165     res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation);
1166     ok ( res == STATUS_SUCCESS, "can't get attributes\n");
1167     todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_NORMAL, "attribute %x not 0\n", fbi.FileAttributes );
1168
1169     CloseHandle( h );
1170 }
1171
1172 static void test_file_all_information(void)
1173 {
1174     IO_STATUS_BLOCK io;
1175     /* FileAllInformation, like FileNameInformation, has a variable-length pathname
1176      * buffer at the end.  Vista objects with STATUS_BUFFER_OVERFLOW if you
1177      * don't leave enough room there.
1178      */
1179     struct {
1180       FILE_ALL_INFORMATION fai;
1181       WCHAR buf[256];
1182     } fai_buf;
1183     HANDLE h;
1184     int res;
1185     int attrib_mask = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL;
1186
1187     if (!(h = create_temp_file(0))) return;
1188
1189     /* Check default first */
1190     res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
1191     ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res);
1192     ok ( (fai_buf.fai.BasicInformation.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == FILE_ATTRIBUTE_ARCHIVE,
1193          "attribute %x not expected\n", fai_buf.fai.BasicInformation.FileAttributes );
1194
1195     /* Then SYSTEM */
1196     /* Clear fbi to avoid setting times */
1197     memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
1198     fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_SYSTEM;
1199     U(io).Status = 0xdeadbeef;
1200     res = pNtSetInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
1201     ok ( res == STATUS_INVALID_INFO_CLASS || broken(res == STATUS_NOT_IMPLEMENTED), "shouldn't be able to set FileAllInformation, res %x\n", res);
1202     todo_wine ok ( U(io).Status == 0xdeadbeef, "shouldn't be able to set FileAllInformation, io.Status is %x\n", U(io).Status);
1203     U(io).Status = 0xdeadbeef;
1204     res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation);
1205     ok ( res == STATUS_SUCCESS, "can't set system attribute, res: %x\n", res );
1206     ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status: %x\n", U(io).Status );
1207
1208     memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
1209     res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
1210     ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res);
1211     todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes );
1212
1213     /* Then HIDDEN */
1214     memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
1215     fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_HIDDEN;
1216     U(io).Status = 0xdeadbeef;
1217     res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation);
1218     ok ( res == STATUS_SUCCESS, "can't set system attribute, res: %x\n", res );
1219     ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status: %x\n", U(io).Status );
1220
1221     memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
1222     res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
1223     ok ( res == STATUS_SUCCESS, "can't get attributes\n");
1224     todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes );
1225
1226     /* Check NORMAL last of all (to make sure we can clear attributes) */
1227     memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation));
1228     fai_buf.fai.BasicInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
1229     U(io).Status = 0xdeadbeef;
1230     res = pNtSetInformationFile(h, &io, &fai_buf.fai.BasicInformation, sizeof fai_buf.fai.BasicInformation, FileBasicInformation);
1231     ok ( res == STATUS_SUCCESS, "can't set system attribute, res: %x\n", res );
1232     ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status: %x\n", U(io).Status );
1233
1234     memset(&fai_buf.fai, 0, sizeof(fai_buf.fai));
1235     res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation);
1236     ok ( res == STATUS_SUCCESS, "can't get attributes\n");
1237     todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_NORMAL, "attribute %x not FILE_ATTRIBUTE_NORMAL\n", fai_buf.fai.BasicInformation.FileAttributes );
1238
1239     CloseHandle( h );
1240 }
1241
1242 static void test_file_both_information(void)
1243 {
1244     IO_STATUS_BLOCK io;
1245     FILE_BOTH_DIR_INFORMATION fbi;
1246     HANDLE h;
1247     int res;
1248
1249     if (!(h = create_temp_file(0))) return;
1250
1251     memset(&fbi, 0, sizeof(fbi));
1252     res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBothDirectoryInformation);
1253     ok ( res == STATUS_INVALID_INFO_CLASS || res == STATUS_NOT_IMPLEMENTED, "shouldn't be able to query FileBothDirectoryInformation, res %x\n", res);
1254
1255     CloseHandle( h );
1256 }
1257
1258 static void test_iocompletion(void)
1259 {
1260     HANDLE h = INVALID_HANDLE_VALUE;
1261     NTSTATUS res;
1262
1263     res = pNtCreateIoCompletion( &h, IO_COMPLETION_ALL_ACCESS, NULL, 0);
1264
1265     ok( res == 0, "NtCreateIoCompletion anonymous failed: %x\n", res );
1266     ok( h && h != INVALID_HANDLE_VALUE, "Invalid handle returned\n" );
1267
1268     if ( h && h != INVALID_HANDLE_VALUE)
1269     {
1270         test_iocp_setcompletion(h);
1271         test_iocp_fileio(h);
1272         pNtClose(h);
1273     }
1274 }
1275
1276 static void test_file_name_information(void)
1277 {
1278     WCHAR *file_name, *volume_prefix, *expected;
1279     FILE_NAME_INFORMATION *info;
1280     ULONG old_redir = 1, tmp;
1281     UINT file_name_size;
1282     IO_STATUS_BLOCK io;
1283     UINT info_size;
1284     HRESULT hr;
1285     HANDLE h;
1286     UINT len;
1287
1288     /* GetVolumePathName is not present before w2k */
1289     if (!pGetVolumePathNameW) {
1290         win_skip("GetVolumePathNameW not found\n");
1291         return;
1292     }
1293
1294     file_name_size = GetSystemDirectoryW( NULL, 0 );
1295     file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) );
1296     volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) );
1297     expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) );
1298
1299     len = GetSystemDirectoryW( file_name, file_name_size );
1300     ok(len == file_name_size - 1,
1301             "GetSystemDirectoryW returned %u, expected %u.\n",
1302             len, file_name_size - 1);
1303
1304     len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size );
1305     ok(len, "GetVolumePathNameW failed.\n");
1306
1307     len = lstrlenW( volume_prefix );
1308     if (len && volume_prefix[len - 1] == '\\') --len;
1309     memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) );
1310     expected[file_name_size - len - 1] = '\0';
1311
1312     /* A bit more than we actually need, but it keeps the calculation simple. */
1313     info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR));
1314     info = HeapAlloc( GetProcessHeap(), 0, info_size );
1315
1316     if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( TRUE, &old_redir );
1317     h = CreateFileW( file_name, GENERIC_READ,
1318             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1319             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
1320     if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( old_redir, &tmp );
1321     ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n");
1322
1323     hr = pNtQueryInformationFile( h, &io, info, sizeof(*info) - 1, FileNameInformation );
1324     ok(hr == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationFile returned %#x.\n", hr);
1325
1326     memset( info, 0xcc, info_size );
1327     hr = pNtQueryInformationFile( h, &io, info, sizeof(*info), FileNameInformation );
1328     ok(hr == STATUS_BUFFER_OVERFLOW, "NtQueryInformationFile returned %#x, expected %#x.\n",
1329             hr, STATUS_BUFFER_OVERFLOW);
1330     ok(U(io).Status == STATUS_BUFFER_OVERFLOW, "io.Status is %#x, expected %#x.\n",
1331             U(io).Status, STATUS_BUFFER_OVERFLOW);
1332     ok(info->FileNameLength == lstrlenW( expected ) * sizeof(WCHAR), "info->FileNameLength is %u\n", info->FileNameLength);
1333     ok(info->FileName[2] == 0xcccc, "info->FileName[2] is %#x, expected 0xcccc.\n", info->FileName[2]);
1334     ok(CharLowerW((LPWSTR)(UINT_PTR)info->FileName[1]) == CharLowerW((LPWSTR)(UINT_PTR)expected[1]),
1335             "info->FileName[1] is %p, expected %p.\n",
1336             CharLowerW((LPWSTR)(UINT_PTR)info->FileName[1]), CharLowerW((LPWSTR)(UINT_PTR)expected[1]));
1337     ok(io.Information == sizeof(*info), "io.Information is %lu\n", io.Information);
1338
1339     memset( info, 0xcc, info_size );
1340     hr = pNtQueryInformationFile( h, &io, info, info_size, FileNameInformation );
1341     ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS);
1342     ok(U(io).Status == STATUS_SUCCESS, "io.Status is %#x, expected %#x.\n", U(io).Status, STATUS_SUCCESS);
1343     ok(info->FileNameLength == lstrlenW( expected ) * sizeof(WCHAR), "info->FileNameLength is %u\n", info->FileNameLength);
1344     ok(info->FileName[info->FileNameLength / sizeof(WCHAR)] == 0xcccc, "info->FileName[len] is %#x, expected 0xcccc.\n",
1345        info->FileName[info->FileNameLength / sizeof(WCHAR)]);
1346     info->FileName[info->FileNameLength / sizeof(WCHAR)] = '\0';
1347     ok(!lstrcmpiW( info->FileName, expected ), "info->FileName is %s, expected %s.\n",
1348             wine_dbgstr_w( info->FileName ), wine_dbgstr_w( expected ));
1349     ok(io.Information == FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + info->FileNameLength,
1350             "io.Information is %lu, expected %u.\n",
1351             io.Information, FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) + info->FileNameLength);
1352
1353     CloseHandle( h );
1354     HeapFree( GetProcessHeap(), 0, info );
1355     HeapFree( GetProcessHeap(), 0, expected );
1356     HeapFree( GetProcessHeap(), 0, volume_prefix );
1357
1358     if (old_redir || !pGetSystemWow64DirectoryW || !(file_name_size = pGetSystemWow64DirectoryW( NULL, 0 )))
1359     {
1360         skip("Not running on WoW64, skipping test.\n");
1361         HeapFree( GetProcessHeap(), 0, file_name );
1362         return;
1363     }
1364
1365     h = CreateFileW( file_name, GENERIC_READ,
1366             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1367             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
1368     ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n");
1369     HeapFree( GetProcessHeap(), 0, file_name );
1370
1371     file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) );
1372     volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) );
1373     expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*expected) );
1374
1375     len = pGetSystemWow64DirectoryW( file_name, file_name_size );
1376     ok(len == file_name_size - 1,
1377             "GetSystemWow64DirectoryW returned %u, expected %u.\n",
1378             len, file_name_size - 1);
1379
1380     len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size );
1381     ok(len, "GetVolumePathNameW failed.\n");
1382
1383     len = lstrlenW( volume_prefix );
1384     if (len && volume_prefix[len - 1] == '\\') --len;
1385     memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) );
1386     expected[file_name_size - len - 1] = '\0';
1387
1388     info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR));
1389     info = HeapAlloc( GetProcessHeap(), 0, info_size );
1390
1391     memset( info, 0xcc, info_size );
1392     hr = pNtQueryInformationFile( h, &io, info, info_size, FileNameInformation );
1393     ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS);
1394     info->FileName[info->FileNameLength / sizeof(WCHAR)] = '\0';
1395     ok(!lstrcmpiW( info->FileName, expected ), "info->FileName is %s, expected %s.\n",
1396             wine_dbgstr_w( info->FileName ), wine_dbgstr_w( expected ));
1397
1398     CloseHandle( h );
1399     HeapFree( GetProcessHeap(), 0, info );
1400     HeapFree( GetProcessHeap(), 0, expected );
1401     HeapFree( GetProcessHeap(), 0, volume_prefix );
1402     HeapFree( GetProcessHeap(), 0, file_name );
1403 }
1404
1405 static void test_file_all_name_information(void)
1406 {
1407     WCHAR *file_name, *volume_prefix, *expected;
1408     FILE_ALL_INFORMATION *info;
1409     ULONG old_redir = 1, tmp;
1410     UINT file_name_size;
1411     IO_STATUS_BLOCK io;
1412     UINT info_size;
1413     HRESULT hr;
1414     HANDLE h;
1415     UINT len;
1416
1417     /* GetVolumePathName is not present before w2k */
1418     if (!pGetVolumePathNameW) {
1419         win_skip("GetVolumePathNameW not found\n");
1420         return;
1421     }
1422
1423     file_name_size = GetSystemDirectoryW( NULL, 0 );
1424     file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) );
1425     volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) );
1426     expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) );
1427
1428     len = GetSystemDirectoryW( file_name, file_name_size );
1429     ok(len == file_name_size - 1,
1430             "GetSystemDirectoryW returned %u, expected %u.\n",
1431             len, file_name_size - 1);
1432
1433     len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size );
1434     ok(len, "GetVolumePathNameW failed.\n");
1435
1436     len = lstrlenW( volume_prefix );
1437     if (len && volume_prefix[len - 1] == '\\') --len;
1438     memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) );
1439     expected[file_name_size - len - 1] = '\0';
1440
1441     /* A bit more than we actually need, but it keeps the calculation simple. */
1442     info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR));
1443     info = HeapAlloc( GetProcessHeap(), 0, info_size );
1444
1445     if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( TRUE, &old_redir );
1446     h = CreateFileW( file_name, GENERIC_READ,
1447             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1448             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
1449     if (pRtlWow64EnableFsRedirectionEx) pRtlWow64EnableFsRedirectionEx( old_redir, &tmp );
1450     ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n");
1451
1452     hr = pNtQueryInformationFile( h, &io, info, sizeof(*info) - 1, FileAllInformation );
1453     ok(hr == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationFile returned %#x, expected %#x.\n",
1454             hr, STATUS_INFO_LENGTH_MISMATCH);
1455
1456     memset( info, 0xcc, info_size );
1457     hr = pNtQueryInformationFile( h, &io, info, sizeof(*info), FileAllInformation );
1458     ok(hr == STATUS_BUFFER_OVERFLOW, "NtQueryInformationFile returned %#x, expected %#x.\n",
1459             hr, STATUS_BUFFER_OVERFLOW);
1460     ok(U(io).Status == STATUS_BUFFER_OVERFLOW, "io.Status is %#x, expected %#x.\n",
1461             U(io).Status, STATUS_BUFFER_OVERFLOW);
1462     ok(info->NameInformation.FileNameLength == lstrlenW( expected ) * sizeof(WCHAR),
1463        "info->NameInformation.FileNameLength is %u\n", info->NameInformation.FileNameLength );
1464     ok(info->NameInformation.FileName[2] == 0xcccc,
1465             "info->NameInformation.FileName[2] is %#x, expected 0xcccc.\n", info->NameInformation.FileName[2]);
1466     ok(CharLowerW((LPWSTR)(UINT_PTR)info->NameInformation.FileName[1]) == CharLowerW((LPWSTR)(UINT_PTR)expected[1]),
1467             "info->NameInformation.FileName[1] is %p, expected %p.\n",
1468             CharLowerW((LPWSTR)(UINT_PTR)info->NameInformation.FileName[1]), CharLowerW((LPWSTR)(UINT_PTR)expected[1]));
1469     ok(io.Information == sizeof(*info), "io.Information is %lu\n", io.Information);
1470
1471     memset( info, 0xcc, info_size );
1472     hr = pNtQueryInformationFile( h, &io, info, info_size, FileAllInformation );
1473     ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS);
1474     ok(U(io).Status == STATUS_SUCCESS, "io.Status is %#x, expected %#x.\n", U(io).Status, STATUS_SUCCESS);
1475     ok(info->NameInformation.FileNameLength == lstrlenW( expected ) * sizeof(WCHAR),
1476        "info->NameInformation.FileNameLength is %u\n", info->NameInformation.FileNameLength );
1477     ok(info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)] == 0xcccc,
1478        "info->NameInformation.FileName[len] is %#x, expected 0xcccc.\n",
1479        info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)]);
1480     info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)] = '\0';
1481     ok(!lstrcmpiW( info->NameInformation.FileName, expected ),
1482             "info->NameInformation.FileName is %s, expected %s.\n",
1483             wine_dbgstr_w( info->NameInformation.FileName ), wine_dbgstr_w( expected ));
1484     ok(io.Information == FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName)
1485             + info->NameInformation.FileNameLength,
1486             "io.Information is %lu\n", io.Information );
1487
1488     CloseHandle( h );
1489     HeapFree( GetProcessHeap(), 0, info );
1490     HeapFree( GetProcessHeap(), 0, expected );
1491     HeapFree( GetProcessHeap(), 0, volume_prefix );
1492
1493     if (old_redir || !pGetSystemWow64DirectoryW || !(file_name_size = pGetSystemWow64DirectoryW( NULL, 0 )))
1494     {
1495         skip("Not running on WoW64, skipping test.\n");
1496         HeapFree( GetProcessHeap(), 0, file_name );
1497         return;
1498     }
1499
1500     h = CreateFileW( file_name, GENERIC_READ,
1501             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1502             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
1503     ok(h != INVALID_HANDLE_VALUE, "Failed to open file.\n");
1504     HeapFree( GetProcessHeap(), 0, file_name );
1505
1506     file_name = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*file_name) );
1507     volume_prefix = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*volume_prefix) );
1508     expected = HeapAlloc( GetProcessHeap(), 0, file_name_size * sizeof(*expected) );
1509
1510     len = pGetSystemWow64DirectoryW( file_name, file_name_size );
1511     ok(len == file_name_size - 1,
1512             "GetSystemWow64DirectoryW returned %u, expected %u.\n",
1513             len, file_name_size - 1);
1514
1515     len = pGetVolumePathNameW( file_name, volume_prefix, file_name_size );
1516     ok(len, "GetVolumePathNameW failed.\n");
1517
1518     len = lstrlenW( volume_prefix );
1519     if (len && volume_prefix[len - 1] == '\\') --len;
1520     memcpy( expected, file_name + len, (file_name_size - len - 1) * sizeof(WCHAR) );
1521     expected[file_name_size - len - 1] = '\0';
1522
1523     info_size = sizeof(*info) + (file_name_size * sizeof(WCHAR));
1524     info = HeapAlloc( GetProcessHeap(), 0, info_size );
1525
1526     memset( info, 0xcc, info_size );
1527     hr = pNtQueryInformationFile( h, &io, info, info_size, FileAllInformation );
1528     ok(hr == STATUS_SUCCESS, "NtQueryInformationFile returned %#x, expected %#x.\n", hr, STATUS_SUCCESS);
1529     info->NameInformation.FileName[info->NameInformation.FileNameLength / sizeof(WCHAR)] = '\0';
1530     ok(!lstrcmpiW( info->NameInformation.FileName, expected ), "info->NameInformation.FileName is %s, expected %s.\n",
1531             wine_dbgstr_w( info->NameInformation.FileName ), wine_dbgstr_w( expected ));
1532
1533     CloseHandle( h );
1534     HeapFree( GetProcessHeap(), 0, info );
1535     HeapFree( GetProcessHeap(), 0, expected );
1536     HeapFree( GetProcessHeap(), 0, volume_prefix );
1537     HeapFree( GetProcessHeap(), 0, file_name );
1538 }
1539
1540 static void test_query_volume_information_file(void)
1541 {
1542     NTSTATUS status;
1543     HANDLE dir;
1544     WCHAR path[MAX_PATH];
1545     OBJECT_ATTRIBUTES attr;
1546     IO_STATUS_BLOCK io;
1547     UNICODE_STRING nameW;
1548     FILE_FS_VOLUME_INFORMATION *ffvi;
1549     BYTE buf[sizeof(FILE_FS_VOLUME_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
1550
1551     GetWindowsDirectoryW( path, MAX_PATH );
1552     pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
1553     attr.Length = sizeof(attr);
1554     attr.RootDirectory = 0;
1555     attr.ObjectName = &nameW;
1556     attr.Attributes = OBJ_CASE_INSENSITIVE;
1557     attr.SecurityDescriptor = NULL;
1558     attr.SecurityQualityOfService = NULL;
1559
1560     status = pNtOpenFile( &dir, SYNCHRONIZE|FILE_LIST_DIRECTORY, &attr, &io,
1561                           FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT );
1562     ok( !status, "open %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
1563     pRtlFreeUnicodeString( &nameW );
1564
1565     ZeroMemory( buf, sizeof(buf) );
1566     U(io).Status = 0xdadadada;
1567     io.Information = 0xcacacaca;
1568
1569     status = pNtQueryVolumeInformationFile( dir, &io, buf, sizeof(buf), FileFsVolumeInformation );
1570
1571     ffvi = (FILE_FS_VOLUME_INFORMATION *)buf;
1572
1573 todo_wine
1574 {
1575     ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", status);
1576     ok(U(io).Status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %d\n", U(io).Status);
1577
1578     ok(io.Information == (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength),
1579     "expected %d, got %lu\n", (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength),
1580      io.Information);
1581
1582     ok(ffvi->VolumeCreationTime.QuadPart != 0, "Missing VolumeCreationTime\n");
1583     ok(ffvi->VolumeSerialNumber != 0, "Missing VolumeSerialNumber\n");
1584     ok(ffvi->SupportsObjects == 1,"expected 1, got %d\n", ffvi->SupportsObjects);
1585 }
1586     ok(ffvi->VolumeLabelLength == lstrlenW(ffvi->VolumeLabel) * sizeof(WCHAR), "got %d\n", ffvi->VolumeLabelLength);
1587
1588     trace("VolumeSerialNumber: %x VolumeLabelName: %s\n", ffvi->VolumeSerialNumber, wine_dbgstr_w(ffvi->VolumeLabel));
1589
1590     CloseHandle( dir );
1591 }
1592
1593 static void test_NtCreateFile(void)
1594 {
1595     static const struct test_data
1596     {
1597         DWORD disposition, attrib_in, status, result, attrib_out, needs_cleanup;
1598     } td[] =
1599     {
1600     /* 0*/{ FILE_CREATE, FILE_ATTRIBUTE_READONLY, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE },
1601     /* 1*/{ FILE_CREATE, 0, STATUS_OBJECT_NAME_COLLISION, 0, 0, TRUE },
1602     /* 2*/{ FILE_CREATE, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE },
1603     /* 3*/{ FILE_OPEN, FILE_ATTRIBUTE_READONLY, 0, FILE_OPENED, FILE_ATTRIBUTE_ARCHIVE, TRUE },
1604     /* 4*/{ FILE_OPEN, FILE_ATTRIBUTE_READONLY, STATUS_OBJECT_NAME_NOT_FOUND, 0, 0, FALSE },
1605     /* 5*/{ FILE_OPEN_IF, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE },
1606     /* 6*/{ FILE_OPEN_IF, FILE_ATTRIBUTE_READONLY, 0, FILE_OPENED, FILE_ATTRIBUTE_ARCHIVE, TRUE },
1607     /* 7*/{ FILE_OPEN_IF, FILE_ATTRIBUTE_READONLY, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE },
1608     /* 8*/{ FILE_OPEN_IF, 0, 0, FILE_OPENED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE },
1609     /* 9*/{ FILE_OVERWRITE, 0, STATUS_ACCESS_DENIED, 0, 0, TRUE },
1610     /*10*/{ FILE_OVERWRITE, 0, STATUS_OBJECT_NAME_NOT_FOUND, 0, 0, FALSE },
1611     /*11*/{ FILE_CREATE, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE },
1612     /*12*/{ FILE_OVERWRITE, FILE_ATTRIBUTE_READONLY, 0, FILE_OVERWRITTEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE },
1613     /*13*/{ FILE_OVERWRITE_IF, 0, STATUS_ACCESS_DENIED, 0, 0, TRUE },
1614     /*14*/{ FILE_OVERWRITE_IF, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, FALSE },
1615     /*15*/{ FILE_OVERWRITE_IF, FILE_ATTRIBUTE_READONLY, 0, FILE_OVERWRITTEN, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, FALSE },
1616     /*16*/{ FILE_SUPERSEDE, 0, 0, FILE_SUPERSEDED, FILE_ATTRIBUTE_ARCHIVE, FALSE },
1617     /*17*/{ FILE_SUPERSEDE, FILE_ATTRIBUTE_READONLY, 0, FILE_SUPERSEDED, FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY, TRUE },
1618     /*18*/{ FILE_SUPERSEDE, 0, 0, FILE_CREATED, FILE_ATTRIBUTE_ARCHIVE, TRUE }
1619     };
1620     static const WCHAR fooW[] = {'f','o','o',0};
1621     static const WCHAR dotW[] = {'.',0};
1622     NTSTATUS status;
1623     HANDLE handle;
1624     WCHAR path[MAX_PATH];
1625     OBJECT_ATTRIBUTES attr;
1626     IO_STATUS_BLOCK io;
1627     UNICODE_STRING nameW;
1628     DWORD ret, i;
1629
1630     GetTempFileNameW(dotW, fooW, 0, path);
1631     DeleteFileW(path);
1632     pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
1633
1634     attr.Length = sizeof(attr);
1635     attr.RootDirectory = NULL;
1636     attr.ObjectName = &nameW;
1637     attr.Attributes = OBJ_CASE_INSENSITIVE;
1638     attr.SecurityDescriptor = NULL;
1639     attr.SecurityQualityOfService = NULL;
1640
1641     for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
1642     {
1643         status = pNtCreateFile(&handle, GENERIC_READ, &attr, &io, NULL,
1644                                td[i].attrib_in, FILE_SHARE_READ|FILE_SHARE_WRITE,
1645                                td[i].disposition, 0, NULL, 0);
1646
1647         ok(status == td[i].status, "%d: expected %#x got %#x\n", i, td[i].status, status);
1648
1649         if (!status)
1650         {
1651             ok(io.Information == td[i].result,"%d: expected %#x got %#lx\n", i, td[i].result, io.Information);
1652
1653             ret = GetFileAttributesW(path);
1654             ret &= ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
1655             /* FIXME: leave only 'else' case below once Wine is fixed */
1656             if (ret != td[i].attrib_out)
1657             {
1658             todo_wine
1659                 ok(ret == td[i].attrib_out, "%d: expected %#x got %#x\n", i, td[i].attrib_out, ret);
1660                 SetFileAttributesW(path, td[i].attrib_out);
1661             }
1662             else
1663                 ok(ret == td[i].attrib_out, "%d: expected %#x got %#x\n", i, td[i].attrib_out, ret);
1664
1665             CloseHandle(handle);
1666         }
1667
1668         if (td[i].needs_cleanup)
1669         {
1670             SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE);
1671             DeleteFileW(path);
1672         }
1673     }
1674
1675     SetFileAttributesW(path, FILE_ATTRIBUTE_ARCHIVE);
1676     DeleteFileW( path );
1677 }
1678
1679 START_TEST(file)
1680 {
1681     HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
1682     HMODULE hntdll = GetModuleHandleA("ntdll.dll");
1683     if (!hntdll)
1684     {
1685         skip("not running on NT, skipping test\n");
1686         return;
1687     }
1688
1689     pGetVolumePathNameW = (void *)GetProcAddress(hkernel32, "GetVolumePathNameW");
1690     pGetSystemWow64DirectoryW = (void *)GetProcAddress(hkernel32, "GetSystemWow64DirectoryW");
1691
1692     pRtlFreeUnicodeString   = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
1693     pRtlInitUnicodeString   = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
1694     pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U");
1695     pRtlWow64EnableFsRedirectionEx = (void *)GetProcAddress(hntdll, "RtlWow64EnableFsRedirectionEx");
1696     pNtCreateMailslotFile   = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile");
1697     pNtCreateFile           = (void *)GetProcAddress(hntdll, "NtCreateFile");
1698     pNtOpenFile             = (void *)GetProcAddress(hntdll, "NtOpenFile");
1699     pNtDeleteFile           = (void *)GetProcAddress(hntdll, "NtDeleteFile");
1700     pNtReadFile             = (void *)GetProcAddress(hntdll, "NtReadFile");
1701     pNtWriteFile            = (void *)GetProcAddress(hntdll, "NtWriteFile");
1702     pNtCancelIoFile         = (void *)GetProcAddress(hntdll, "NtCancelIoFile");
1703     pNtCancelIoFileEx       = (void *)GetProcAddress(hntdll, "NtCancelIoFileEx");
1704     pNtClose                = (void *)GetProcAddress(hntdll, "NtClose");
1705     pNtCreateIoCompletion   = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion");
1706     pNtOpenIoCompletion     = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion");
1707     pNtQueryIoCompletion    = (void *)GetProcAddress(hntdll, "NtQueryIoCompletion");
1708     pNtRemoveIoCompletion   = (void *)GetProcAddress(hntdll, "NtRemoveIoCompletion");
1709     pNtSetIoCompletion      = (void *)GetProcAddress(hntdll, "NtSetIoCompletion");
1710     pNtSetInformationFile   = (void *)GetProcAddress(hntdll, "NtSetInformationFile");
1711     pNtQueryInformationFile = (void *)GetProcAddress(hntdll, "NtQueryInformationFile");
1712     pNtQueryDirectoryFile   = (void *)GetProcAddress(hntdll, "NtQueryDirectoryFile");
1713     pNtQueryVolumeInformationFile = (void *)GetProcAddress(hntdll, "NtQueryVolumeInformationFile");
1714
1715     test_NtCreateFile();
1716     create_file_test();
1717     open_file_test();
1718     delete_file_test();
1719     read_file_test();
1720     append_file_test();
1721     nt_mailslot_test();
1722     test_iocompletion();
1723     test_file_basic_information();
1724     test_file_all_information();
1725     test_file_both_information();
1726     test_file_name_information();
1727     test_file_all_name_information();
1728     test_query_volume_information_file();
1729 }