ntdll: Add some more tests for NtNotifyChangeDirectoryFile.
[wine] / dlls / ntdll / tests / change.c
1 /*
2  * File change notification tests
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <ntstatus.h>
22 #define WIN32_NO_STATUS
23 #include <windows.h>
24 #include <winnt.h>
25 #include <winternl.h>
26 #include <winerror.h>
27 #include <stdio.h>
28 #include "wine/test.h"
29
30 typedef NTSTATUS (WINAPI *fnNtNotifyChangeDirectoryFile)(
31                           HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,
32                           PIO_STATUS_BLOCK,PVOID,ULONG,ULONG,BOOLEAN);
33 fnNtNotifyChangeDirectoryFile pNtNotifyChangeDirectoryFile;
34
35 typedef NTSTATUS (WINAPI *fnNtCancelIoFile)(HANDLE,PIO_STATUS_BLOCK);
36 fnNtCancelIoFile pNtCancelIoFile;
37
38
39 static void test_ntncdf(void)
40 {
41     NTSTATUS r;
42     HANDLE hdir, hEvent;
43     char buffer[0x1000];
44     DWORD fflags, filter = 0;
45     IO_STATUS_BLOCK iosb;
46     WCHAR path[MAX_PATH], subdir[MAX_PATH];
47     static const WCHAR szBoo[] = { '\\','b','o','o',0 };
48     static const WCHAR szHoo[] = { '\\','h','o','o',0 };
49     PFILE_NOTIFY_INFORMATION pfni;
50
51     r = GetTempPathW( MAX_PATH, path );
52     ok( r != 0, "temp path failed\n");
53     if (!r)
54         return;
55
56     lstrcatW( path, szBoo );
57     lstrcpyW( subdir, path );
58     lstrcatW( subdir, szHoo );
59
60     RemoveDirectoryW( subdir );
61     RemoveDirectoryW( path );
62     
63     r = CreateDirectoryW(path, NULL);
64     ok( r == TRUE, "failed to create directory\n");
65
66     r = pNtNotifyChangeDirectoryFile(NULL,NULL,NULL,NULL,NULL,NULL,0,0,0);
67     ok(r==STATUS_ACCESS_VIOLATION, "should return access violation\n");
68
69     fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
70     hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, 
71                         OPEN_EXISTING, fflags, NULL);
72     ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
73
74     hEvent = CreateEvent( NULL, 0, 0, NULL );
75
76     r = pNtNotifyChangeDirectoryFile(hdir,NULL,NULL,NULL,&iosb,NULL,0,0,0);
77     ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n");
78
79     r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,NULL,0,0,0);
80     ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n");
81
82     filter = FILE_NOTIFY_CHANGE_FILE_NAME;
83     filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
84     filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
85     filter |= FILE_NOTIFY_CHANGE_SIZE;
86     filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
87     filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
88     filter |= FILE_NOTIFY_CHANGE_CREATION;
89     filter |= FILE_NOTIFY_CHANGE_SECURITY;
90
91     iosb.Status = 1;
92     iosb.Information = 1;
93     r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,-1,0);
94     ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n");
95
96     ok( iosb.Status == 1, "information wrong\n");
97     ok( iosb.Information == 1, "information wrong\n");
98
99     iosb.Status = 1;
100     iosb.Information = 0;
101     r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
102     ok(r==STATUS_PENDING, "should return status pending\n");
103
104     r = WaitForSingleObject( hEvent, 0 );
105     ok( r == STATUS_TIMEOUT, "should timeout\n" );
106
107     r = WaitForSingleObject( hdir, 0 );
108     ok( r == STATUS_TIMEOUT, "should timeout\n" );
109
110     r = CreateDirectoryW( subdir, NULL );
111     ok( r == TRUE, "failed to create directory\n");
112
113     r = WaitForSingleObject( hdir, 0 );
114     ok( r == STATUS_TIMEOUT, "should timeout\n" );
115
116     r = WaitForSingleObject( hEvent, 0 );
117     ok( r == WAIT_OBJECT_0, "event should be ready\n" );
118
119     ok( iosb.Status == STATUS_SUCCESS, "information wrong\n");
120     ok( iosb.Information == 0x12, "information wrong\n");
121
122     pfni = (PFILE_NOTIFY_INFORMATION) buffer;
123     ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
124     ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
125     ok( pfni->FileNameLength == 6, "len wrong\n" );
126     ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" );
127
128     r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,0,0);
129     ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n");
130
131     r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,0,0);
132     ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n");
133
134     filter = FILE_NOTIFY_CHANGE_SIZE;
135
136     iosb.Status = 1;
137     iosb.Information = 1;
138     r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,NULL,0,filter,0);
139     ok(r==STATUS_PENDING, "should status pending\n");
140
141     ok( iosb.Status == 1, "information wrong\n");
142     ok( iosb.Information == 1, "information wrong\n");
143
144     r = WaitForSingleObject( hdir, 0 );
145     ok( r == STATUS_TIMEOUT, "should timeout\n" );
146
147     r = RemoveDirectoryW( subdir );
148     ok( r == TRUE, "failed to remove directory\n");
149
150     r = WaitForSingleObject( hdir, 100 );
151     ok( r == WAIT_OBJECT_0, "should be ready\n" );
152
153     r = WaitForSingleObject( hdir, 100 );
154     ok( r == WAIT_OBJECT_0, "should be ready\n" );
155
156     ok( iosb.Status == STATUS_NOTIFY_ENUM_DIR, "information wrong\n");
157     ok( iosb.Information == 0, "information wrong\n");
158
159     CloseHandle(hdir);
160     CloseHandle(hEvent);
161
162     r = RemoveDirectoryW( path );
163     ok( r == TRUE, "failed to remove directory\n");
164 }
165
166
167 static void test_ntncdf_async(void)
168 {
169     NTSTATUS r;
170     HANDLE hdir, hEvent;
171     char buffer[0x1000];
172     DWORD fflags, filter = 0;
173     IO_STATUS_BLOCK iosb, iosb2;
174     WCHAR path[MAX_PATH], subdir[MAX_PATH];
175     static const WCHAR szBoo[] = { '\\','b','o','o',0 };
176     static const WCHAR szHoo[] = { '\\','h','o','o',0 };
177     PFILE_NOTIFY_INFORMATION pfni;
178
179     r = GetTempPathW( MAX_PATH, path );
180     ok( r != 0, "temp path failed\n");
181     if (!r)
182         return;
183
184     lstrcatW( path, szBoo );
185     lstrcpyW( subdir, path );
186     lstrcatW( subdir, szHoo );
187
188     RemoveDirectoryW( subdir );
189     RemoveDirectoryW( path );
190     
191     r = CreateDirectoryW(path, NULL);
192     ok( r == TRUE, "failed to create directory\n");
193
194     r = pNtNotifyChangeDirectoryFile(NULL,NULL,NULL,NULL,NULL,NULL,0,0,0);
195     ok(r==STATUS_ACCESS_VIOLATION, "should return access violation\n");
196
197     fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED;
198     hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, 
199                         OPEN_EXISTING, fflags, NULL);
200     ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n");
201
202     hEvent = CreateEvent( NULL, 0, 0, NULL );
203
204     filter = FILE_NOTIFY_CHANGE_FILE_NAME;
205     filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
206     filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
207     filter |= FILE_NOTIFY_CHANGE_SIZE;
208     filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
209     filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
210     filter |= FILE_NOTIFY_CHANGE_CREATION;
211     filter |= FILE_NOTIFY_CHANGE_SECURITY;
212
213
214     iosb.Status      = 0x01234567;
215     iosb.Information = 0x12345678;
216     r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
217     ok(r==STATUS_PENDING, "should status pending\n");
218     ok(iosb.Status == 0x01234567, "status set too soon\n");
219     ok(iosb.Information == 0x12345678, "info set too soon\n");
220
221     r = CreateDirectoryW( subdir, NULL );
222     ok( r == TRUE, "failed to create directory\n");
223
224     r = WaitForSingleObject( hdir, 100 );
225     ok( r == WAIT_OBJECT_0, "should be ready\n" );
226
227     ok(iosb.Status == STATUS_SUCCESS, "status not successful\n");
228     ok(iosb.Information == 0x12, "info not set\n");
229
230     pfni = (PFILE_NOTIFY_INFORMATION) buffer;
231     ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
232     ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" );
233     ok( pfni->FileNameLength == 6, "len wrong\n" );
234     ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" );
235
236     r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
237     ok(r==STATUS_PENDING, "should status pending\n");
238
239     r = RemoveDirectoryW( subdir );
240     ok( r == TRUE, "failed to remove directory\n");
241
242     r = WaitForSingleObject( hdir, 0 );
243     ok( r == WAIT_OBJECT_0, "should be ready\n" );
244
245     ok(iosb.Status == STATUS_SUCCESS, "status not successful\n");
246     ok(iosb.Information == 0x12, "info not set\n");
247
248     ok( pfni->NextEntryOffset == 0, "offset wrong\n" );
249     ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" );
250     ok( pfni->FileNameLength == 6, "len wrong\n" );
251     ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" );
252
253     /* check APCs */
254     iosb.Status = 0;
255     iosb.Information = 0;
256
257     r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,NULL,0,filter,0);
258     ok(r==STATUS_PENDING, "should status pending\n");
259
260     r = CreateDirectoryW( subdir, NULL );
261     ok( r == TRUE, "failed to create directory\n");
262
263     r = WaitForSingleObject( hdir, 0 );
264     ok( r == WAIT_OBJECT_0, "should be ready\n" );
265
266     ok(iosb.Status == STATUS_NOTIFY_ENUM_DIR, "status not successful\n");
267     ok(iosb.Information == 0, "info not set\n");
268
269     iosb.Status = 0;
270     iosb.Information = 0;
271
272     r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
273     ok(r==STATUS_PENDING, "should status pending\n");
274
275     r = RemoveDirectoryW( subdir );
276     ok( r == TRUE, "failed to remove directory\n");
277
278     r = WaitForSingleObject( hEvent, 0 );
279     ok( r == WAIT_OBJECT_0, "should be ready\n" );
280
281     ok(iosb.Status == STATUS_SUCCESS, "status not successful\n");
282     ok(iosb.Information == 0x12, "info not set\n");
283
284
285     iosb.Status      = 0x01234567;
286     iosb.Information = 0x12345678;
287     r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0);
288     ok(r==STATUS_PENDING, "should status pending\n");
289
290     iosb2.Status      = 0x01234567;
291     iosb2.Information = 0x12345678;
292     r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb2,buffer,sizeof buffer,filter,0);
293     ok(r==STATUS_PENDING, "should status pending\n");
294
295     ok(iosb.Status == 0x01234567, "status set too soon\n");
296     ok(iosb.Information == 0x12345678, "info set too soon\n");
297
298     todo_wine {
299     r = pNtCancelIoFile(hdir, &iosb);
300     ok( r == STATUS_SUCCESS, "cancel failed\n");
301
302     CloseHandle(hdir);
303
304     ok(iosb.Status == STATUS_SUCCESS, "status wrong\n");
305     ok(iosb2.Status == STATUS_CANCELLED, "status wrong\n");
306     }
307     ok(iosb.Information == 0, "info wrong\n");
308     ok(iosb2.Information == 0, "info wrong\n");
309
310     r = RemoveDirectoryW( path );
311     ok( r == TRUE, "failed to remove directory\n");
312
313     CloseHandle(hEvent);
314 }
315
316 START_TEST(change)
317 {
318     HMODULE hntdll = GetModuleHandle("ntdll");
319
320     pNtNotifyChangeDirectoryFile = (fnNtNotifyChangeDirectoryFile) 
321         GetProcAddress(hntdll, "NtNotifyChangeDirectoryFile");
322     pNtCancelIoFile = (fnNtCancelIoFile)
323         GetProcAddress(hntdll, "NtCancelIoFile");
324
325     if (!pNtNotifyChangeDirectoryFile)
326         return;
327     if (!pNtCancelIoFile)
328         return;
329
330     test_ntncdf();
331     test_ntncdf_async();
332 }