ntdll/tests: Test NtCancelIoFile(Ex).
[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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * NOTES
22  * We use function pointers here as there is no import library for NTDLL on
23  * windows.
24  */
25
26 #include <stdio.h>
27 #include <stdarg.h>
28
29 #include "ntstatus.h"
30 /* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro
31  * definition errors when we get to winnt.h
32  */
33 #define WIN32_NO_STATUS
34
35 #include "wine/test.h"
36 #include "winternl.h"
37
38 #ifndef IO_COMPLETION_ALL_ACCESS
39 #define IO_COMPLETION_ALL_ACCESS 0x001F0003
40 #endif
41
42 static NTSTATUS (WINAPI *pRtlFreeUnicodeString)( PUNICODE_STRING );
43 static VOID     (WINAPI *pRtlInitUnicodeString)( PUNICODE_STRING, LPCWSTR );
44 static BOOL     (WINAPI *pRtlDosPathNameToNtPathName_U)( LPCWSTR, PUNICODE_STRING, PWSTR*, CURDIR* );
45 static NTSTATUS (WINAPI *pNtCreateMailslotFile)( PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
46                                        ULONG, ULONG, ULONG, PLARGE_INTEGER );
47 static NTSTATUS (WINAPI *pNtDeleteFile)(POBJECT_ATTRIBUTES ObjectAttributes);
48 static NTSTATUS (WINAPI *pNtReadFile)(HANDLE hFile, HANDLE hEvent,
49                                       PIO_APC_ROUTINE apc, void* apc_user,
50                                       PIO_STATUS_BLOCK io_status, void* buffer, ULONG length,
51                                       PLARGE_INTEGER offset, PULONG key);
52 static NTSTATUS (WINAPI *pNtWriteFile)(HANDLE hFile, HANDLE hEvent,
53                                        PIO_APC_ROUTINE apc, void* apc_user,
54                                        PIO_STATUS_BLOCK io_status,
55                                        const void* buffer, ULONG length,
56                                        PLARGE_INTEGER offset, PULONG key);
57 static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE hFile, PIO_STATUS_BLOCK io_status);
58 static NTSTATUS (WINAPI *pNtCancelIoFileEx)(HANDLE hFile, PIO_STATUS_BLOCK iosb, PIO_STATUS_BLOCK io_status);
59 static NTSTATUS (WINAPI *pNtClose)( PHANDLE );
60
61 static NTSTATUS (WINAPI *pNtCreateIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, ULONG);
62 static NTSTATUS (WINAPI *pNtOpenIoCompletion)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
63 static NTSTATUS (WINAPI *pNtQueryIoCompletion)(HANDLE, IO_COMPLETION_INFORMATION_CLASS, PVOID, ULONG, PULONG);
64 static NTSTATUS (WINAPI *pNtRemoveIoCompletion)(HANDLE, PULONG_PTR, PULONG_PTR, PIO_STATUS_BLOCK, PLARGE_INTEGER);
65 static NTSTATUS (WINAPI *pNtSetIoCompletion)(HANDLE, ULONG_PTR, ULONG_PTR, NTSTATUS, ULONG);
66 static NTSTATUS (WINAPI *pNtSetInformationFile)(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS);
67
68 static inline BOOL is_signaled( HANDLE obj )
69 {
70     return WaitForSingleObject( obj, 0 ) == 0;
71 }
72
73 #define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c"
74 #define TEST_BUF_LEN 3
75
76 static BOOL create_pipe( HANDLE *read, HANDLE *write, ULONG flags, ULONG size )
77 {
78     *read = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND | flags, PIPE_TYPE_BYTE | PIPE_WAIT,
79                             1, size, size, NMPWAIT_USE_DEFAULT_WAIT, NULL);
80     ok(*read != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n");
81
82     *write = CreateFileA(PIPENAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
83     ok(*write != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError());
84
85     return TRUE;
86 }
87
88 static HANDLE create_temp_file( ULONG flags )
89 {
90     char buffer[MAX_PATH];
91     HANDLE handle;
92
93     GetTempFileNameA( ".", "foo", 0, buffer );
94     handle = CreateFileA(buffer, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
95                          flags | FILE_FLAG_DELETE_ON_CLOSE, 0);
96     ok( handle != INVALID_HANDLE_VALUE, "failed to create temp file\n" );
97     return (handle == INVALID_HANDLE_VALUE) ? 0 : handle;
98 }
99
100 #define CVALUE_FIRST 0xfffabbcc
101 #define CKEY_FIRST 0x1030341
102 #define CKEY_SECOND 0x132E46
103
104 ULONG_PTR completionKey;
105 IO_STATUS_BLOCK ioSb;
106 ULONG_PTR completionValue;
107
108 static long get_pending_msgs(HANDLE h)
109 {
110     NTSTATUS res;
111     ULONG a, req;
112
113     res = pNtQueryIoCompletion( h, IoCompletionBasicInformation, &a, sizeof(a), &req );
114     ok( res == STATUS_SUCCESS, "NtQueryIoCompletion failed: %x\n", res );
115     if (res != STATUS_SUCCESS) return -1;
116     ok( req == sizeof(a), "Unexpected response size: %x\n", req );
117     return a;
118 }
119
120 static BOOL get_msg(HANDLE h)
121 {
122     LARGE_INTEGER timeout = {{-10000000*3}};
123     DWORD res = pNtRemoveIoCompletion( h, &completionKey, &completionValue, &ioSb, &timeout);
124     ok( res == STATUS_SUCCESS, "NtRemoveIoCompletion failed: %x\n", res );
125     if (res != STATUS_SUCCESS)
126     {
127         completionKey = completionValue = 0;
128         memset(&ioSb, 0, sizeof(ioSb));
129         return FALSE;
130     }
131     return TRUE;
132 }
133
134
135 static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
136 {
137     int *count = arg;
138
139     trace( "apc called block %p iosb.status %x iosb.info %lu\n",
140            iosb, U(*iosb).Status, iosb->Information );
141     (*count)++;
142     ok( !reserved, "reserved is not 0: %x\n", reserved );
143 }
144
145 static void delete_file_test(void)
146 {
147     NTSTATUS ret;
148     OBJECT_ATTRIBUTES attr;
149     UNICODE_STRING nameW;
150     WCHAR pathW[MAX_PATH];
151     WCHAR pathsubW[MAX_PATH];
152     static const WCHAR testdirW[] = {'n','t','d','e','l','e','t','e','f','i','l','e',0};
153     static const WCHAR subdirW[]  = {'\\','s','u','b',0};
154
155     ret = GetTempPathW(MAX_PATH, pathW);
156     if (!ret)
157     {
158         ok(0, "couldn't get temp dir\n");
159         return;
160     }
161     if (ret + sizeof(testdirW)/sizeof(WCHAR)-1 + sizeof(subdirW)/sizeof(WCHAR)-1 >= MAX_PATH)
162     {
163         ok(0, "MAX_PATH exceeded in constructing paths\n");
164         return;
165     }
166
167     lstrcatW(pathW, testdirW);
168     lstrcpyW(pathsubW, pathW);
169     lstrcatW(pathsubW, subdirW);
170
171     ret = CreateDirectoryW(pathW, NULL);
172     ok(ret == TRUE, "couldn't create directory ntdeletefile\n");
173     if (!pRtlDosPathNameToNtPathName_U(pathW, &nameW, NULL, NULL))
174     {
175         ok(0,"RtlDosPathNametoNtPathName_U failed\n");
176         return;
177     }
178
179     attr.Length = sizeof(attr);
180     attr.RootDirectory = 0;
181     attr.Attributes = OBJ_CASE_INSENSITIVE;
182     attr.ObjectName = &nameW;
183     attr.SecurityDescriptor = NULL;
184     attr.SecurityQualityOfService = NULL;
185
186     /* test NtDeleteFile on an empty directory */
187     ret = pNtDeleteFile(&attr);
188     ok(ret == STATUS_SUCCESS, "NtDeleteFile should succeed in removing an empty directory\n");
189     ret = RemoveDirectoryW(pathW);
190     ok(ret == FALSE, "expected to fail removing directory, NtDeleteFile should have removed it\n");
191
192     /* test NtDeleteFile on a non-empty directory */
193     ret = CreateDirectoryW(pathW, NULL);
194     ok(ret == TRUE, "couldn't create directory ntdeletefile ?!\n");
195     ret = CreateDirectoryW(pathsubW, NULL);
196     ok(ret == TRUE, "couldn't create directory subdir\n");
197     ret = pNtDeleteFile(&attr);
198     ok(ret == STATUS_SUCCESS, "expected NtDeleteFile to ret STATUS_SUCCESS\n");
199     ret = RemoveDirectoryW(pathsubW);
200     ok(ret == TRUE, "expected to remove directory ntdeletefile\\sub\n");
201     ret = RemoveDirectoryW(pathW);
202     ok(ret == TRUE, "expected to remove directory ntdeletefile, NtDeleteFile failed.\n");
203
204     pRtlFreeUnicodeString( &nameW );
205 }
206
207 static void read_file_test(void)
208 {
209     const char text[] = "foobar";
210     HANDLE handle, read, write;
211     NTSTATUS status;
212     IO_STATUS_BLOCK iosb, iosb2;
213     DWORD written;
214     int apc_count = 0;
215     char buffer[128];
216     LARGE_INTEGER offset;
217     HANDLE event = CreateEventA( NULL, TRUE, FALSE, NULL );
218
219     buffer[0] = 1;
220
221     if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
222
223     /* try read with no data */
224     U(iosb).Status = 0xdeadbabe;
225     iosb.Information = 0xdeadbeef;
226     ok( is_signaled( read ), "read handle is not signaled\n" );
227     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
228     ok( status == STATUS_PENDING, "wrong status %x\n", status );
229     ok( !is_signaled( read ), "read handle is signaled\n" );
230     ok( !is_signaled( event ), "event is signaled\n" );
231     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
232     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
233     ok( !apc_count, "apc was called\n" );
234     WriteFile( write, buffer, 1, &written, NULL );
235     /* iosb updated here by async i/o */
236     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
237     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
238     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
239     ok( !is_signaled( read ), "read handle is signaled\n" );
240     ok( is_signaled( event ), "event is not signaled\n" );
241     ok( !apc_count, "apc was called\n" );
242     apc_count = 0;
243     SleepEx( 1, FALSE ); /* non-alertable sleep */
244     ok( !apc_count, "apc was called\n" );
245     SleepEx( 1, TRUE ); /* alertable sleep */
246     ok( apc_count == 1, "apc not called\n" );
247
248     /* with no event, the pipe handle itself gets signaled */
249     apc_count = 0;
250     U(iosb).Status = 0xdeadbabe;
251     iosb.Information = 0xdeadbeef;
252     ok( !is_signaled( read ), "read handle is not signaled\n" );
253     status = pNtReadFile( read, 0, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
254     ok( status == STATUS_PENDING, "wrong status %x\n", status );
255     ok( !is_signaled( read ), "read handle is signaled\n" );
256     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
257     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
258     ok( !apc_count, "apc was called\n" );
259     WriteFile( write, buffer, 1, &written, NULL );
260     /* iosb updated here by async i/o */
261     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
262     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
263     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
264     ok( is_signaled( read ), "read handle is signaled\n" );
265     ok( !apc_count, "apc was called\n" );
266     apc_count = 0;
267     SleepEx( 1, FALSE ); /* non-alertable sleep */
268     ok( !apc_count, "apc was called\n" );
269     SleepEx( 1, TRUE ); /* alertable sleep */
270     ok( apc_count == 1, "apc not called\n" );
271
272     /* now read with data ready */
273     apc_count = 0;
274     U(iosb).Status = 0xdeadbabe;
275     iosb.Information = 0xdeadbeef;
276     ResetEvent( event );
277     WriteFile( write, buffer, 1, &written, NULL );
278     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
279     ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
280     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
281     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
282     ok( is_signaled( event ), "event is not signaled\n" );
283     ok( !apc_count, "apc was called\n" );
284     SleepEx( 1, FALSE ); /* non-alertable sleep */
285     ok( !apc_count, "apc was called\n" );
286     SleepEx( 1, TRUE ); /* alertable sleep */
287     ok( apc_count == 1, "apc not called\n" );
288
289     /* try read with no data */
290     apc_count = 0;
291     U(iosb).Status = 0xdeadbabe;
292     iosb.Information = 0xdeadbeef;
293     ok( is_signaled( event ), "event is not signaled\n" ); /* check that read resets the event */
294     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
295     ok( status == STATUS_PENDING, "wrong status %x\n", status );
296     ok( !is_signaled( event ), "event is signaled\n" );
297     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
298     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
299     ok( !apc_count, "apc was called\n" );
300     WriteFile( write, buffer, 1, &written, NULL );
301     /* partial read is good enough */
302     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
303     ok( is_signaled( event ), "event is signaled\n" );
304     ok( U(iosb).Status == 0, "wrong status %x\n", U(iosb).Status );
305     ok( iosb.Information == 1, "wrong info %lu\n", iosb.Information );
306     ok( !apc_count, "apc was called\n" );
307     SleepEx( 1, TRUE ); /* alertable sleep */
308     ok( apc_count == 1, "apc was not called\n" );
309
310     /* read from disconnected pipe */
311     apc_count = 0;
312     U(iosb).Status = 0xdeadbabe;
313     iosb.Information = 0xdeadbeef;
314     CloseHandle( write );
315     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
316     ok( status == STATUS_PIPE_BROKEN, "wrong status %x\n", status );
317     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
318     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
319     ok( !is_signaled( event ), "event is signaled\n" );
320     ok( !apc_count, "apc was called\n" );
321     SleepEx( 1, TRUE ); /* alertable sleep */
322     ok( !apc_count, "apc was called\n" );
323     CloseHandle( read );
324
325     /* read from closed handle */
326     apc_count = 0;
327     U(iosb).Status = 0xdeadbabe;
328     iosb.Information = 0xdeadbeef;
329     SetEvent( event );
330     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 1, NULL, NULL );
331     ok( status == STATUS_INVALID_HANDLE, "wrong status %x\n", status );
332     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
333     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
334     ok( is_signaled( event ), "event is signaled\n" );  /* not reset on invalid handle */
335     ok( !apc_count, "apc was called\n" );
336     SleepEx( 1, TRUE ); /* alertable sleep */
337     ok( !apc_count, "apc was called\n" );
338
339     /* disconnect while async read is in progress */
340     if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
341     apc_count = 0;
342     U(iosb).Status = 0xdeadbabe;
343     iosb.Information = 0xdeadbeef;
344     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
345     ok( status == STATUS_PENDING, "wrong status %x\n", status );
346     ok( !is_signaled( event ), "event is signaled\n" );
347     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
348     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
349     ok( !apc_count, "apc was called\n" );
350     CloseHandle( write );
351     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
352     ok( U(iosb).Status == STATUS_PIPE_BROKEN, "wrong status %x\n", U(iosb).Status );
353     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
354     ok( is_signaled( event ), "event is signaled\n" );
355     ok( !apc_count, "apc was called\n" );
356     SleepEx( 1, TRUE ); /* alertable sleep */
357     ok( apc_count == 1, "apc was not called\n" );
358     CloseHandle( read );
359
360     if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
361     ok(DuplicateHandle(GetCurrentProcess(), read, GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS),
362         "Failed to duplicate handle: %d\n", GetLastError());
363
364     apc_count = 0;
365     U(iosb).Status = 0xdeadbabe;
366     iosb.Information = 0xdeadbeef;
367     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
368     ok( status == STATUS_PENDING, "wrong status %x\n", status );
369     ok( !is_signaled( event ), "event is signaled\n" );
370     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
371     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
372     ok( !apc_count, "apc was called\n" );
373     /* Cancel by other handle */
374     status = pNtCancelIoFile( read, &iosb2 );
375     ok(status == STATUS_SUCCESS, "failed to cancel by different handle: %x\n", status);
376     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
377     ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
378     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
379     ok( is_signaled( event ), "event is signaled\n" );
380     todo_wine ok( !apc_count, "apc was called\n" );
381     SleepEx( 1, TRUE ); /* alertable sleep */
382     ok( apc_count == 1, "apc was not called\n" );
383
384     apc_count = 0;
385     U(iosb).Status = 0xdeadbabe;
386     iosb.Information = 0xdeadbeef;
387     status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
388     ok( status == STATUS_PENDING, "wrong status %x\n", status );
389     ok( !is_signaled( event ), "event is signaled\n" );
390     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
391     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
392     ok( !apc_count, "apc was called\n" );
393     /* Close queued handle */
394     CloseHandle( read );
395     SleepEx( 1, TRUE ); /* alertable sleep */
396     ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
397     ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
398     status = pNtCancelIoFile( read, &iosb2 );
399     ok(status == STATUS_INVALID_HANDLE, "cancelled by closed handle?\n");
400     status = pNtCancelIoFile( handle, &iosb2 );
401     ok(status == STATUS_SUCCESS, "failed to cancel: %x\n", status);
402     Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
403     ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
404     ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
405     ok( is_signaled( event ), "event is signaled\n" );
406     todo_wine ok( !apc_count, "apc was called\n" );
407     SleepEx( 1, TRUE ); /* alertable sleep */
408     ok( apc_count == 1, "apc was not called\n" );
409     CloseHandle( handle );
410     CloseHandle( write );
411
412     if (pNtCancelIoFileEx)
413     {
414         /* Basic Cancel Ex */
415         if (!create_pipe( &read, &write, FILE_FLAG_OVERLAPPED, 4096 )) return;
416
417         apc_count = 0;
418         U(iosb).Status = 0xdeadbabe;
419         iosb.Information = 0xdeadbeef;
420         status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
421         ok( status == STATUS_PENDING, "wrong status %x\n", status );
422         ok( !is_signaled( event ), "event is signaled\n" );
423         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
424         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
425         ok( !apc_count, "apc was called\n" );
426         status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
427         ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
428         Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
429         ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
430         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
431         ok( is_signaled( event ), "event is signaled\n" );
432         todo_wine ok( !apc_count, "apc was called\n" );
433         SleepEx( 1, TRUE ); /* alertable sleep */
434         ok( apc_count == 1, "apc was not called\n" );
435
436         /* Duplicate iosb */
437         apc_count = 0;
438         U(iosb).Status = 0xdeadbabe;
439         iosb.Information = 0xdeadbeef;
440         status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
441         ok( status == STATUS_PENDING, "wrong status %x\n", status );
442         ok( !is_signaled( event ), "event is signaled\n" );
443         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
444         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
445         ok( !apc_count, "apc was called\n" );
446         status = pNtReadFile( read, event, apc, &apc_count, &iosb, buffer, 2, NULL, NULL );
447         ok( status == STATUS_PENDING, "wrong status %x\n", status );
448         ok( !is_signaled( event ), "event is signaled\n" );
449         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
450         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
451         ok( !apc_count, "apc was called\n" );
452         status = pNtCancelIoFileEx( read, &iosb, &iosb2 );
453         ok(status == STATUS_SUCCESS, "Failed to cancel I/O\n");
454         Sleep(1);  /* FIXME: needed for wine to run the i/o apc  */
455         ok( U(iosb).Status == STATUS_CANCELLED, "wrong status %x\n", U(iosb).Status );
456         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
457         ok( is_signaled( event ), "event is signaled\n" );
458         todo_wine ok( !apc_count, "apc was called\n" );
459         SleepEx( 1, TRUE ); /* alertable sleep */
460         ok( apc_count == 2, "apc was not called\n" );
461
462         CloseHandle( read );
463         CloseHandle( write );
464     }
465
466     /* now try a real file */
467     if (!(handle = create_temp_file( FILE_FLAG_OVERLAPPED ))) return;
468     apc_count = 0;
469     U(iosb).Status = 0xdeadbabe;
470     iosb.Information = 0xdeadbeef;
471     offset.QuadPart = 0;
472     ResetEvent( event );
473     status = pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL );
474     ok( status == STATUS_SUCCESS || status == STATUS_PENDING, "wrong status %x\n", status );
475     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
476     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
477     ok( is_signaled( event ), "event is signaled\n" );
478     ok( !apc_count, "apc was called\n" );
479     SleepEx( 1, TRUE ); /* alertable sleep */
480     ok( apc_count == 1, "apc was not called\n" );
481
482     apc_count = 0;
483     U(iosb).Status = 0xdeadbabe;
484     iosb.Information = 0xdeadbeef;
485     offset.QuadPart = 0;
486     ResetEvent( event );
487     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL );
488     ok( status == STATUS_SUCCESS ||
489         status == STATUS_PENDING, /* vista */
490         "wrong status %x\n", status );
491     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
492     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
493     ok( is_signaled( event ), "event is signaled\n" );
494     ok( !apc_count, "apc was called\n" );
495     SleepEx( 1, TRUE ); /* alertable sleep */
496     ok( apc_count == 1, "apc was not called\n" );
497
498     /* read beyond eof */
499     apc_count = 0;
500     U(iosb).Status = 0xdeadbabe;
501     iosb.Information = 0xdeadbeef;
502     offset.QuadPart = strlen(text) + 2;
503     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL );
504     if (status == STATUS_PENDING)  /* vista */
505     {
506         ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status );
507         ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
508         ok( is_signaled( event ), "event is signaled\n" );
509         ok( !apc_count, "apc was called\n" );
510         SleepEx( 1, TRUE ); /* alertable sleep */
511         ok( apc_count == 1, "apc was not called\n" );
512     }
513     else
514     {
515         ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status );
516         ok( U(iosb).Status == 0xdeadbabe, "wrong status %x\n", U(iosb).Status );
517         ok( iosb.Information == 0xdeadbeef, "wrong info %lu\n", iosb.Information );
518         ok( !is_signaled( event ), "event is signaled\n" );
519         ok( !apc_count, "apc was called\n" );
520         SleepEx( 1, TRUE ); /* alertable sleep */
521         ok( !apc_count, "apc was called\n" );
522     }
523     CloseHandle( handle );
524
525     /* now a non-overlapped file */
526     if (!(handle = create_temp_file(0))) return;
527     apc_count = 0;
528     U(iosb).Status = 0xdeadbabe;
529     iosb.Information = 0xdeadbeef;
530     offset.QuadPart = 0;
531     status = pNtWriteFile( handle, event, apc, &apc_count, &iosb, text, strlen(text), &offset, NULL );
532     ok( status == STATUS_END_OF_FILE ||
533         status == STATUS_SUCCESS ||
534         status == STATUS_PENDING,  /* vista */
535         "wrong status %x\n", status );
536     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
537     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
538     ok( is_signaled( event ), "event is signaled\n" );
539     ok( !apc_count, "apc was called\n" );
540     SleepEx( 1, TRUE ); /* alertable sleep */
541     ok( apc_count == 1, "apc was not called\n" );
542
543     apc_count = 0;
544     U(iosb).Status = 0xdeadbabe;
545     iosb.Information = 0xdeadbeef;
546     offset.QuadPart = 0;
547     ResetEvent( event );
548     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, strlen(text) + 10, &offset, NULL );
549     ok( status == STATUS_SUCCESS, "wrong status %x\n", status );
550     ok( U(iosb).Status == STATUS_SUCCESS, "wrong status %x\n", U(iosb).Status );
551     ok( iosb.Information == strlen(text), "wrong info %lu\n", iosb.Information );
552     ok( is_signaled( event ), "event is signaled\n" );
553     ok( !apc_count, "apc was called\n" );
554     SleepEx( 1, TRUE ); /* alertable sleep */
555     todo_wine ok( !apc_count, "apc was called\n" );
556
557     /* read beyond eof */
558     apc_count = 0;
559     U(iosb).Status = 0xdeadbabe;
560     iosb.Information = 0xdeadbeef;
561     offset.QuadPart = strlen(text) + 2;
562     ResetEvent( event );
563     status = pNtReadFile( handle, event, apc, &apc_count, &iosb, buffer, 2, &offset, NULL );
564     ok( status == STATUS_END_OF_FILE, "wrong status %x\n", status );
565     todo_wine ok( U(iosb).Status == STATUS_END_OF_FILE, "wrong status %x\n", U(iosb).Status );
566     todo_wine ok( iosb.Information == 0, "wrong info %lu\n", iosb.Information );
567     todo_wine ok( is_signaled( event ), "event is not signaled\n" );
568     ok( !apc_count, "apc was called\n" );
569     SleepEx( 1, TRUE ); /* alertable sleep */
570     ok( !apc_count, "apc was called\n" );
571
572     CloseHandle( handle );
573
574     CloseHandle( event );
575 }
576
577 static void nt_mailslot_test(void)
578 {
579     HANDLE hslot;
580     ACCESS_MASK DesiredAccess;
581     OBJECT_ATTRIBUTES attr;
582
583     ULONG CreateOptions;
584     ULONG MailslotQuota;
585     ULONG MaxMessageSize;
586     LARGE_INTEGER TimeOut;
587     IO_STATUS_BLOCK IoStatusBlock;
588     NTSTATUS rc;
589     UNICODE_STRING str;
590     WCHAR buffer1[] = { '\\','?','?','\\','M','A','I','L','S','L','O','T','\\',
591                         'R',':','\\','F','R','E','D','\0' };
592
593     TimeOut.QuadPart = -1;
594
595     pRtlInitUnicodeString(&str, buffer1);
596     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
597     CreateOptions = MailslotQuota = MaxMessageSize = 0;
598     DesiredAccess = GENERIC_READ;
599
600     /*
601      * Check for NULL pointer handling
602      */
603     rc = pNtCreateMailslotFile(NULL, DesiredAccess,
604          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
605          &TimeOut);
606     ok( rc == STATUS_ACCESS_VIOLATION ||
607         rc == STATUS_INVALID_PARAMETER, /* win2k3 */
608         "rc = %x not STATUS_ACCESS_VIOLATION or STATUS_INVALID_PARAMETER\n", rc);
609
610     /*
611      * Test to see if the Timeout can be NULL
612      */
613     hslot = (HANDLE)0xdeadbeef;
614     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
615          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
616          NULL);
617     ok( rc == STATUS_SUCCESS ||
618         rc == STATUS_INVALID_PARAMETER, /* win2k3 */
619         "rc = %x not STATUS_SUCCESS or STATUS_INVALID_PARAMETER\n", rc);
620     ok( hslot != 0, "Handle is invalid\n");
621
622     if  ( rc == STATUS_SUCCESS ) rc = pNtClose(hslot);
623
624     /*
625      * Test that the length field is checked properly
626      */
627     attr.Length = 0;
628     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
629          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
630          &TimeOut);
631     todo_wine ok( rc == STATUS_INVALID_PARAMETER, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc);
632
633     if  (rc == STATUS_SUCCESS) pNtClose(hslot);
634
635     attr.Length = sizeof(OBJECT_ATTRIBUTES)+1;
636     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
637          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
638          &TimeOut);
639     todo_wine ok( rc == STATUS_INVALID_PARAMETER, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc);
640
641     if  (rc == STATUS_SUCCESS) pNtClose(hslot);
642
643     /*
644      * Test handling of a NULL unicode string in ObjectName
645      */
646     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
647     attr.ObjectName = NULL;
648     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
649          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
650          &TimeOut);
651     ok( rc == STATUS_OBJECT_PATH_SYNTAX_BAD ||
652         rc == STATUS_INVALID_PARAMETER,
653         "rc = %x not STATUS_OBJECT_PATH_SYNTAX_BAD or STATUS_INVALID_PARAMETER\n", rc);
654
655     if  (rc == STATUS_SUCCESS) pNtClose(hslot);
656
657     /*
658      * Test a valid call
659      */
660     InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL);
661     rc = pNtCreateMailslotFile(&hslot, DesiredAccess,
662          &attr, &IoStatusBlock, CreateOptions, MailslotQuota, MaxMessageSize,
663          &TimeOut);
664     ok( rc == STATUS_SUCCESS, "Create MailslotFile failed rc = %x\n", rc);
665     ok( hslot != 0, "Handle is invalid\n");
666
667     rc = pNtClose(hslot);
668     ok( rc == STATUS_SUCCESS, "NtClose failed\n");
669 }
670
671 static void test_iocp_setcompletion(HANDLE h)
672 {
673     NTSTATUS res;
674     long count;
675
676     res = pNtSetIoCompletion( h, CKEY_FIRST, CVALUE_FIRST, STATUS_INVALID_DEVICE_REQUEST, 3 );
677     ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %x\n", res );
678
679     count = get_pending_msgs(h);
680     ok( count == 1, "Unexpected msg count: %ld\n", count );
681
682     if (get_msg(h))
683     {
684         ok( completionKey == CKEY_FIRST, "Invalid completion key: %lx\n", completionKey );
685         ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information );
686         ok( U(ioSb).Status == STATUS_INVALID_DEVICE_REQUEST, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
687         ok( completionValue == CVALUE_FIRST, "Invalid completion value: %lx\n", completionValue );
688     }
689
690     count = get_pending_msgs(h);
691     ok( !count, "Unexpected msg count: %ld\n", count );
692 }
693
694 static void test_iocp_fileio(HANDLE h)
695 {
696     static const char pipe_name[] = "\\\\.\\pipe\\iocompletiontestnamedpipe";
697
698     IO_STATUS_BLOCK iosb;
699     FILE_COMPLETION_INFORMATION fci = {h, CKEY_SECOND};
700     HANDLE hPipeSrv, hPipeClt;
701     NTSTATUS res;
702
703     hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL );
704     ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" );
705     if (hPipeSrv != INVALID_HANDLE_VALUE )
706     {
707         hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
708         ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" );
709         if (hPipeClt != INVALID_HANDLE_VALUE)
710         {
711             res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation );
712             ok( res == STATUS_INVALID_PARAMETER, "Unexpected NtSetInformationFile on non-overlapped handle: %x\n", res );
713             CloseHandle(hPipeClt);
714         }
715         CloseHandle( hPipeSrv );
716     }
717
718     hPipeSrv = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 4, 1024, 1024, 1000, NULL );
719     ok( hPipeSrv != INVALID_HANDLE_VALUE, "Cannot create named pipe\n" );
720     if (hPipeSrv == INVALID_HANDLE_VALUE )
721         return;
722
723     hPipeClt = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
724     ok( hPipeClt != INVALID_HANDLE_VALUE, "Cannot connect to pipe\n" );
725     if (hPipeClt != INVALID_HANDLE_VALUE)
726     {
727         OVERLAPPED o = {0,};
728         BYTE send_buf[TEST_BUF_LEN], recv_buf[TEST_BUF_LEN];
729         DWORD read;
730         long count;
731
732         NTSTATUS res = pNtSetInformationFile( hPipeSrv, &iosb, &fci, sizeof(fci), FileCompletionInformation );
733         ok( res == STATUS_SUCCESS, "NtSetInformationFile failed: %x\n", res );
734         ok( U(iosb).Status == STATUS_SUCCESS, "iosb.Status invalid: %x\n", U(iosb).Status );
735
736         memset( send_buf, 0, TEST_BUF_LEN );
737         memset( recv_buf, 0xde, TEST_BUF_LEN );
738         count = get_pending_msgs(h);
739         ok( !count, "Unexpected msg count: %ld\n", count );
740         ReadFile( hPipeSrv, recv_buf, TEST_BUF_LEN, &read, &o);
741         count = get_pending_msgs(h);
742         ok( !count, "Unexpected msg count: %ld\n", count );
743         WriteFile( hPipeClt, send_buf, TEST_BUF_LEN, &read, NULL );
744
745         if (get_msg(h))
746         {
747             ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey );
748             ok( ioSb.Information == 3, "Invalid ioSb.Information: %ld\n", ioSb.Information );
749             ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
750             ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue );
751             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] );
752         }
753         count = get_pending_msgs(h);
754         ok( !count, "Unexpected msg count: %ld\n", count );
755
756         memset( send_buf, 0, TEST_BUF_LEN );
757         memset( recv_buf, 0xde, TEST_BUF_LEN );
758         WriteFile( hPipeClt, send_buf, 2, &read, NULL );
759         count = get_pending_msgs(h);
760         ok( !count, "Unexpected msg count: %ld\n", count );
761         ReadFile( hPipeSrv, recv_buf, 2, &read, &o);
762         count = get_pending_msgs(h);
763         ok( count == 1, "Unexpected msg count: %ld\n", count );
764         if (get_msg(h))
765         {
766             ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey );
767             ok( ioSb.Information == 2, "Invalid ioSb.Information: %ld\n", ioSb.Information );
768             ok( U(ioSb).Status == STATUS_SUCCESS, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
769             ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue );
770             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] );
771         }
772
773         ReadFile( hPipeSrv, recv_buf, TEST_BUF_LEN, &read, &o);
774         CloseHandle( hPipeSrv );
775         count = get_pending_msgs(h);
776         ok( count == 1, "Unexpected msg count: %ld\n", count );
777         if (get_msg(h))
778         {
779             ok( completionKey == CKEY_SECOND, "Invalid completion key: %lx\n", completionKey );
780             ok( ioSb.Information == 0, "Invalid ioSb.Information: %ld\n", ioSb.Information );
781             /* wine sends wrong status here */
782             todo_wine ok( U(ioSb).Status == STATUS_PIPE_BROKEN, "Invalid ioSb.Status: %x\n", U(ioSb).Status);
783             ok( completionValue == (ULONG_PTR)&o, "Invalid completion value: %lx\n", completionValue );
784         }
785     }
786
787     CloseHandle( hPipeClt );
788 }
789
790 static void test_iocompletion(void)
791 {
792     HANDLE h = INVALID_HANDLE_VALUE;
793     NTSTATUS res;
794
795     res = pNtCreateIoCompletion( &h, IO_COMPLETION_ALL_ACCESS, NULL, 0);
796
797     ok( res == 0, "NtCreateIoCompletion anonymous failed: %x\n", res );
798     ok( h && h != INVALID_HANDLE_VALUE, "Invalid handle returned\n" );
799
800     if ( h && h != INVALID_HANDLE_VALUE)
801     {
802         test_iocp_setcompletion(h);
803         test_iocp_fileio(h);
804         pNtClose(h);
805     }
806 }
807
808 START_TEST(file)
809 {
810     HMODULE hntdll = GetModuleHandleA("ntdll.dll");
811     if (!hntdll)
812     {
813         skip("not running on NT, skipping test\n");
814         return;
815     }
816
817     pRtlFreeUnicodeString   = (void *)GetProcAddress(hntdll, "RtlFreeUnicodeString");
818     pRtlInitUnicodeString   = (void *)GetProcAddress(hntdll, "RtlInitUnicodeString");
819     pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(hntdll, "RtlDosPathNameToNtPathName_U");
820     pNtCreateMailslotFile   = (void *)GetProcAddress(hntdll, "NtCreateMailslotFile");
821     pNtDeleteFile           = (void *)GetProcAddress(hntdll, "NtDeleteFile");
822     pNtReadFile             = (void *)GetProcAddress(hntdll, "NtReadFile");
823     pNtWriteFile            = (void *)GetProcAddress(hntdll, "NtWriteFile");
824     pNtCancelIoFile         = (void *)GetProcAddress(hntdll, "NtCancelIoFile");
825     pNtCancelIoFileEx       = (void *)GetProcAddress(hntdll, "NtCancelIoFileEx");
826     pNtClose                = (void *)GetProcAddress(hntdll, "NtClose");
827     pNtCreateIoCompletion   = (void *)GetProcAddress(hntdll, "NtCreateIoCompletion");
828     pNtOpenIoCompletion     = (void *)GetProcAddress(hntdll, "NtOpenIoCompletion");
829     pNtQueryIoCompletion    = (void *)GetProcAddress(hntdll, "NtQueryIoCompletion");
830     pNtRemoveIoCompletion   = (void *)GetProcAddress(hntdll, "NtRemoveIoCompletion");
831     pNtSetIoCompletion      = (void *)GetProcAddress(hntdll, "NtSetIoCompletion");
832     pNtSetInformationFile   = (void *)GetProcAddress(hntdll, "NtSetInformationFile");
833
834     delete_file_test();
835     read_file_test();
836     nt_mailslot_test();
837     test_iocompletion();
838 }