f395962ec239102c3131014b37ad5ab10a78ba56
[reactos.git] / rostests / winetests / ntdll / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 U(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( U(iosb).Status == 1, "information wrong\n");
97 ok( iosb.Information == 1, "information wrong\n");
98
99 U(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( U(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 U(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( U(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( U(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 U(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(U(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(U(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(U(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 U(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(U(iosb).Status == STATUS_NOTIFY_ENUM_DIR, "status not successful\n");
267 ok(iosb.Information == 0, "info not set\n");
268
269 U(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(U(iosb).Status == STATUS_SUCCESS, "status not successful\n");
282 ok(iosb.Information == 0x12, "info not set\n");
283
284
285 U(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 U(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(U(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(U(iosb).Status == STATUS_SUCCESS, "status wrong\n");
305 ok(U(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 if (!hntdll)
320 {
321 win_skip("not running on NT, skipping test\n");
322 return;
323 }
324
325 pNtNotifyChangeDirectoryFile = (fnNtNotifyChangeDirectoryFile)
326 GetProcAddress(hntdll, "NtNotifyChangeDirectoryFile");
327 pNtCancelIoFile = (fnNtCancelIoFile)
328 GetProcAddress(hntdll, "NtCancelIoFile");
329
330 if (!pNtNotifyChangeDirectoryFile || !pNtCancelIoFile)
331 {
332 win_skip("missing functions, skipping test\n");
333 return;
334 }
335
336 test_ntncdf();
337 test_ntncdf_async();
338 }