e299560eb301ad0c031d3c4b84d773ceb458b189
[reactos.git] / rostests / winetests / ntdll / 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 }