1 /* Unit test suite for Ntdll file functions
3 * Copyright 2007 Jeff Latimer
4 * Copyright 2007 Andrey Turkin
5 * Copyright 2008 Jeff Zaroyko
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.
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.
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
22 * We use function pointers here as there is no import library for NTDLL on
30 /* Define WIN32_NO_STATUS so MSVC does not give us duplicate macro
31 * definition errors when we get to winnt.h
33 #define WIN32_NO_STATUS
35 #include "wine/test.h"
38 #ifndef IO_COMPLETION_ALL_ACCESS
39 #define IO_COMPLETION_ALL_ACCESS 0x001F0003
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
);
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
);
68 static inline BOOL
is_signaled( HANDLE obj
)
70 return WaitForSingleObject( obj
, 0 ) == 0;
73 #define PIPENAME "\\\\.\\pipe\\ntdll_tests_file.c"
74 #define TEST_BUF_LEN 3
76 static BOOL
create_pipe( HANDLE
*read
, HANDLE
*write
, ULONG flags
, ULONG size
)
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");
82 *write
= CreateFileA(PIPENAME
, GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, 0);
83 ok(*write
!= INVALID_HANDLE_VALUE
, "CreateFile failed (%d)\n", GetLastError());
88 static HANDLE
create_temp_file( ULONG flags
)
90 char buffer
[MAX_PATH
];
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
;
100 #define CVALUE_FIRST 0xfffabbcc
101 #define CKEY_FIRST 0x1030341
102 #define CKEY_SECOND 0x132E46
104 ULONG_PTR completionKey
;
105 IO_STATUS_BLOCK ioSb
;
106 ULONG_PTR completionValue
;
108 static long get_pending_msgs(HANDLE h
)
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
);
120 static BOOL
get_msg(HANDLE h
)
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
)
127 completionKey
= completionValue
= 0;
128 memset(&ioSb
, 0, sizeof(ioSb
));
135 static void WINAPI
apc( void *arg
, IO_STATUS_BLOCK
*iosb
, ULONG reserved
)
139 trace( "apc called block %p iosb.status %x iosb.info %lu\n",
140 iosb
, U(*iosb
).Status
, iosb
->Information
);
142 ok( !reserved
, "reserved is not 0: %x\n", reserved
);
145 static void delete_file_test(void)
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};
155 ret
= GetTempPathW(MAX_PATH
, pathW
);
158 ok(0, "couldn't get temp dir\n");
161 if (ret
+ sizeof(testdirW
)/sizeof(WCHAR
)-1 + sizeof(subdirW
)/sizeof(WCHAR
)-1 >= MAX_PATH
)
163 ok(0, "MAX_PATH exceeded in constructing paths\n");
167 lstrcatW(pathW
, testdirW
);
168 lstrcpyW(pathsubW
, pathW
);
169 lstrcatW(pathsubW
, subdirW
);
171 ret
= CreateDirectoryW(pathW
, NULL
);
172 ok(ret
== TRUE
, "couldn't create directory ntdeletefile\n");
173 if (!pRtlDosPathNameToNtPathName_U(pathW
, &nameW
, NULL
, NULL
))
175 ok(0,"RtlDosPathNametoNtPathName_U failed\n");
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
;
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");
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");
204 pRtlFreeUnicodeString( &nameW
);
207 static void read_file_test(void)
209 const char text
[] = "foobar";
210 HANDLE handle
, read
, write
;
212 IO_STATUS_BLOCK iosb
, iosb2
;
216 LARGE_INTEGER offset
;
217 HANDLE event
= CreateEventA( NULL
, TRUE
, FALSE
, NULL
);
221 if (!create_pipe( &read
, &write
, FILE_FLAG_OVERLAPPED
, 4096 )) return;
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" );
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" );
248 /* with no event, the pipe handle itself gets signaled */
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" );
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" );
272 /* now read with data ready */
274 U(iosb
).Status
= 0xdeadbabe;
275 iosb
.Information
= 0xdeadbeef;
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" );
289 /* try read with no data */
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" );
310 /* read from disconnected pipe */
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" );
325 /* read from closed handle */
327 U(iosb
).Status
= 0xdeadbabe;
328 iosb
.Information
= 0xdeadbeef;
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" );
339 /* disconnect while async read is in progress */
340 if (!create_pipe( &read
, &write
, FILE_FLAG_OVERLAPPED
, 4096 )) return;
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" );
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());
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" );
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 */
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
);
412 if (pNtCancelIoFileEx
)
414 /* Basic Cancel Ex */
415 if (!create_pipe( &read
, &write
, FILE_FLAG_OVERLAPPED
, 4096 )) return;
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" );
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" );
463 CloseHandle( write
);
466 /* now try a real file */
467 if (!(handle
= create_temp_file( FILE_FLAG_OVERLAPPED
))) return;
469 U(iosb
).Status
= 0xdeadbabe;
470 iosb
.Information
= 0xdeadbeef;
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" );
483 U(iosb
).Status
= 0xdeadbabe;
484 iosb
.Information
= 0xdeadbeef;
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" );
498 /* read beyond eof */
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 */
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" );
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" );
523 CloseHandle( handle
);
525 /* now a non-overlapped file */
526 if (!(handle
= create_temp_file(0))) return;
528 U(iosb
).Status
= 0xdeadbabe;
529 iosb
.Information
= 0xdeadbeef;
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" );
544 U(iosb
).Status
= 0xdeadbabe;
545 iosb
.Information
= 0xdeadbeef;
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" );
557 /* read beyond eof */
559 U(iosb
).Status
= 0xdeadbabe;
560 iosb
.Information
= 0xdeadbeef;
561 offset
.QuadPart
= strlen(text
) + 2;
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" );
572 CloseHandle( handle
);
574 CloseHandle( event
);
577 static void nt_mailslot_test(void)
580 ACCESS_MASK DesiredAccess
;
581 OBJECT_ATTRIBUTES attr
;
585 ULONG MaxMessageSize
;
586 LARGE_INTEGER TimeOut
;
587 IO_STATUS_BLOCK IoStatusBlock
;
590 WCHAR buffer1
[] = { '\\','?','?','\\','M','A','I','L','S','L','O','T','\\',
591 'R',':','\\','F','R','E','D','\0' };
593 TimeOut
.QuadPart
= -1;
595 pRtlInitUnicodeString(&str
, buffer1
);
596 InitializeObjectAttributes(&attr
, &str
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
597 CreateOptions
= MailslotQuota
= MaxMessageSize
= 0;
598 DesiredAccess
= GENERIC_READ
;
601 * Check for NULL pointer handling
603 rc
= pNtCreateMailslotFile(NULL
, DesiredAccess
,
604 &attr
, &IoStatusBlock
, CreateOptions
, MailslotQuota
, MaxMessageSize
,
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
);
611 * Test to see if the Timeout can be NULL
613 hslot
= (HANDLE
)0xdeadbeef;
614 rc
= pNtCreateMailslotFile(&hslot
, DesiredAccess
,
615 &attr
, &IoStatusBlock
, CreateOptions
, MailslotQuota
, MaxMessageSize
,
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");
622 if ( rc
== STATUS_SUCCESS
) rc
= pNtClose(hslot
);
625 * Test that the length field is checked properly
628 rc
= pNtCreateMailslotFile(&hslot
, DesiredAccess
,
629 &attr
, &IoStatusBlock
, CreateOptions
, MailslotQuota
, MaxMessageSize
,
631 todo_wine
ok( rc
== STATUS_INVALID_PARAMETER
, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc
);
633 if (rc
== STATUS_SUCCESS
) pNtClose(hslot
);
635 attr
.Length
= sizeof(OBJECT_ATTRIBUTES
)+1;
636 rc
= pNtCreateMailslotFile(&hslot
, DesiredAccess
,
637 &attr
, &IoStatusBlock
, CreateOptions
, MailslotQuota
, MaxMessageSize
,
639 todo_wine
ok( rc
== STATUS_INVALID_PARAMETER
, "rc = %x not c000000d STATUS_INVALID_PARAMETER\n", rc
);
641 if (rc
== STATUS_SUCCESS
) pNtClose(hslot
);
644 * Test handling of a NULL unicode string in ObjectName
646 InitializeObjectAttributes(&attr
, &str
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
647 attr
.ObjectName
= NULL
;
648 rc
= pNtCreateMailslotFile(&hslot
, DesiredAccess
,
649 &attr
, &IoStatusBlock
, CreateOptions
, MailslotQuota
, MaxMessageSize
,
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
);
655 if (rc
== STATUS_SUCCESS
) pNtClose(hslot
);
660 InitializeObjectAttributes(&attr
, &str
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
661 rc
= pNtCreateMailslotFile(&hslot
, DesiredAccess
,
662 &attr
, &IoStatusBlock
, CreateOptions
, MailslotQuota
, MaxMessageSize
,
664 ok( rc
== STATUS_SUCCESS
, "Create MailslotFile failed rc = %x\n", rc
);
665 ok( hslot
!= 0, "Handle is invalid\n");
667 rc
= pNtClose(hslot
);
668 ok( rc
== STATUS_SUCCESS
, "NtClose failed\n");
671 static void test_iocp_setcompletion(HANDLE h
)
676 res
= pNtSetIoCompletion( h
, CKEY_FIRST
, CVALUE_FIRST
, STATUS_INVALID_DEVICE_REQUEST
, 3 );
677 ok( res
== STATUS_SUCCESS
, "NtSetIoCompletion failed: %x\n", res
);
679 count
= get_pending_msgs(h
);
680 ok( count
== 1, "Unexpected msg count: %ld\n", count
);
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
);
690 count
= get_pending_msgs(h
);
691 ok( !count
, "Unexpected msg count: %ld\n", count
);
694 static void test_iocp_fileio(HANDLE h
)
696 static const char pipe_name
[] = "\\\\.\\pipe\\iocompletiontestnamedpipe";
698 IO_STATUS_BLOCK iosb
;
699 FILE_COMPLETION_INFORMATION fci
= {h
, CKEY_SECOND
};
700 HANDLE hPipeSrv
, hPipeClt
;
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
)
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
)
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
);
715 CloseHandle( hPipeSrv
);
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
)
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
)
728 BYTE send_buf
[TEST_BUF_LEN
], recv_buf
[TEST_BUF_LEN
];
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
);
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
);
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] );
753 count
= get_pending_msgs(h
);
754 ok( !count
, "Unexpected msg count: %ld\n", count
);
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
);
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] );
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
);
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
);
787 CloseHandle( hPipeClt
);
790 static void test_iocompletion(void)
792 HANDLE h
= INVALID_HANDLE_VALUE
;
795 res
= pNtCreateIoCompletion( &h
, IO_COMPLETION_ALL_ACCESS
, NULL
, 0);
797 ok( res
== 0, "NtCreateIoCompletion anonymous failed: %x\n", res
);
798 ok( h
&& h
!= INVALID_HANDLE_VALUE
, "Invalid handle returned\n" );
800 if ( h
&& h
!= INVALID_HANDLE_VALUE
)
802 test_iocp_setcompletion(h
);
810 HMODULE hntdll
= GetModuleHandleA("ntdll.dll");
813 skip("not running on NT, skipping test\n");
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");