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 static NTSTATUS (WINAPI *pNtNotifyChangeDirectoryFile)( 31 HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID, 32 PIO_STATUS_BLOCK,PVOID,ULONG,ULONG,BOOLEAN); 33 34 static NTSTATUS (WINAPI *pNtCancelIoFile)(HANDLE,PIO_STATUS_BLOCK); 35 36 37 static void test_ntncdf(void) 38 { 39 NTSTATUS r; 40 HANDLE hdir, hEvent; 41 char buffer[0x1000]; 42 DWORD fflags, filter = 0; 43 IO_STATUS_BLOCK iosb; 44 WCHAR path[MAX_PATH], subdir[MAX_PATH]; 45 static const WCHAR szBoo[] = { '\\','b','o','o',0 }; 46 static const WCHAR szHoo[] = { '\\','h','o','o',0 }; 47 PFILE_NOTIFY_INFORMATION pfni; 48 49 r = GetTempPathW( MAX_PATH, path ); 50 ok( r != 0, "temp path failed\n"); 51 if (!r) 52 return; 53 54 lstrcatW( path, szBoo ); 55 lstrcpyW( subdir, path ); 56 lstrcatW( subdir, szHoo ); 57 58 RemoveDirectoryW( subdir ); 59 RemoveDirectoryW( path ); 60 61 r = CreateDirectoryW(path, NULL); 62 ok( r == TRUE, "failed to create directory\n"); 63 64 r = pNtNotifyChangeDirectoryFile(NULL,NULL,NULL,NULL,NULL,NULL,0,0,0); 65 ok(r==STATUS_ACCESS_VIOLATION, "should return access violation\n"); 66 67 fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED; 68 hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, 69 OPEN_EXISTING, fflags, NULL); 70 ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n"); 71 72 hEvent = CreateEventA( NULL, 0, 0, NULL ); 73 74 r = pNtNotifyChangeDirectoryFile(hdir,NULL,NULL,NULL,&iosb,NULL,0,0,0); 75 ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n"); 76 77 r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,NULL,0,0,0); 78 ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n"); 79 80 filter = FILE_NOTIFY_CHANGE_FILE_NAME; 81 filter |= FILE_NOTIFY_CHANGE_DIR_NAME; 82 filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; 83 filter |= FILE_NOTIFY_CHANGE_SIZE; 84 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE; 85 filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; 86 filter |= FILE_NOTIFY_CHANGE_CREATION; 87 filter |= FILE_NOTIFY_CHANGE_SECURITY; 88 89 U(iosb).Status = 1; 90 iosb.Information = 1; 91 r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,-1,0); 92 ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n"); 93 94 ok( U(iosb).Status == 1, "information wrong\n"); 95 ok( iosb.Information == 1, "information wrong\n"); 96 97 U(iosb).Status = 1; 98 iosb.Information = 0; 99 r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0); 100 ok(r==STATUS_PENDING, "should return status pending\n"); 101 102 r = WaitForSingleObject( hEvent, 100 ); 103 ok( r == STATUS_TIMEOUT, "should timeout\n" ); 104 105 r = WaitForSingleObject( hdir, 100 ); 106 ok( r == STATUS_TIMEOUT, "should timeout\n" ); 107 108 r = CreateDirectoryW( subdir, NULL ); 109 ok( r == TRUE, "failed to create directory\n"); 110 111 r = WaitForSingleObject( hdir, 100 ); 112 ok( r == STATUS_TIMEOUT, "should timeout\n" ); 113 114 r = WaitForSingleObject( hEvent, 100 ); 115 ok( r == WAIT_OBJECT_0, "event should be ready\n" ); 116 117 ok( U(iosb).Status == STATUS_SUCCESS, "information wrong\n"); 118 ok( iosb.Information == 0x12, "information wrong\n"); 119 120 pfni = (PFILE_NOTIFY_INFORMATION) buffer; 121 ok( pfni->NextEntryOffset == 0, "offset wrong\n" ); 122 ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" ); 123 ok( pfni->FileNameLength == 6, "len wrong\n" ); 124 ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" ); 125 126 r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,0,0); 127 ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n"); 128 129 r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,0,0); 130 ok(r==STATUS_INVALID_PARAMETER, "should return invalid parameter\n"); 131 132 filter = FILE_NOTIFY_CHANGE_SIZE; 133 134 U(iosb).Status = 1; 135 iosb.Information = 1; 136 r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,NULL,0,filter,0); 137 ok(r==STATUS_PENDING, "should status pending\n"); 138 139 ok( U(iosb).Status == 1, "information wrong\n"); 140 ok( iosb.Information == 1, "information wrong\n"); 141 142 r = WaitForSingleObject( hdir, 0 ); 143 ok( r == STATUS_TIMEOUT, "should timeout\n" ); 144 145 r = RemoveDirectoryW( subdir ); 146 ok( r == TRUE, "failed to remove directory\n"); 147 148 r = WaitForSingleObject( hdir, 100 ); 149 ok( r == WAIT_OBJECT_0, "should be ready\n" ); 150 151 r = WaitForSingleObject( hdir, 100 ); 152 ok( r == WAIT_OBJECT_0, "should be ready\n" ); 153 154 ok( U(iosb).Status == STATUS_NOTIFY_ENUM_DIR, "information wrong\n"); 155 ok( iosb.Information == 0, "information wrong\n"); 156 157 CloseHandle(hdir); 158 CloseHandle(hEvent); 159 160 r = RemoveDirectoryW( path ); 161 ok( r == TRUE, "failed to remove directory\n"); 162 } 163 164 165 static void test_ntncdf_async(void) 166 { 167 NTSTATUS r; 168 HANDLE hdir, hEvent; 169 char buffer[0x1000]; 170 DWORD fflags, filter = 0; 171 IO_STATUS_BLOCK iosb, iosb2; 172 WCHAR path[MAX_PATH], subdir[MAX_PATH]; 173 static const WCHAR szBoo[] = { '\\','b','o','o',0 }; 174 static const WCHAR szHoo[] = { '\\','h','o','o',0 }; 175 PFILE_NOTIFY_INFORMATION pfni; 176 177 r = GetTempPathW( MAX_PATH, path ); 178 ok( r != 0, "temp path failed\n"); 179 if (!r) 180 return; 181 182 lstrcatW( path, szBoo ); 183 lstrcpyW( subdir, path ); 184 lstrcatW( subdir, szHoo ); 185 186 RemoveDirectoryW( subdir ); 187 RemoveDirectoryW( path ); 188 189 r = CreateDirectoryW(path, NULL); 190 ok( r == TRUE, "failed to create directory\n"); 191 192 r = pNtNotifyChangeDirectoryFile(NULL,NULL,NULL,NULL,NULL,NULL,0,0,0); 193 ok(r==STATUS_ACCESS_VIOLATION, "should return access violation\n"); 194 195 fflags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED; 196 hdir = CreateFileW(path, GENERIC_READ|SYNCHRONIZE, FILE_SHARE_READ, NULL, 197 OPEN_EXISTING, fflags, NULL); 198 ok( hdir != INVALID_HANDLE_VALUE, "failed to open directory\n"); 199 200 hEvent = CreateEventA( NULL, 0, 0, NULL ); 201 202 filter = FILE_NOTIFY_CHANGE_FILE_NAME; 203 filter |= FILE_NOTIFY_CHANGE_DIR_NAME; 204 filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; 205 filter |= FILE_NOTIFY_CHANGE_SIZE; 206 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE; 207 filter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; 208 filter |= FILE_NOTIFY_CHANGE_CREATION; 209 filter |= FILE_NOTIFY_CHANGE_SECURITY; 210 211 212 U(iosb).Status = 0x01234567; 213 iosb.Information = 0x12345678; 214 r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0); 215 ok(r==STATUS_PENDING, "should status pending\n"); 216 ok(U(iosb).Status == 0x01234567, "status set too soon\n"); 217 ok(iosb.Information == 0x12345678, "info set too soon\n"); 218 219 r = CreateDirectoryW( subdir, NULL ); 220 ok( r == TRUE, "failed to create directory\n"); 221 222 r = WaitForSingleObject( hdir, 100 ); 223 ok( r == WAIT_OBJECT_0, "should be ready\n" ); 224 225 ok(U(iosb).Status == STATUS_SUCCESS, "status not successful\n"); 226 ok(iosb.Information == 0x12, "info not set\n"); 227 228 pfni = (PFILE_NOTIFY_INFORMATION) buffer; 229 ok( pfni->NextEntryOffset == 0, "offset wrong\n" ); 230 ok( pfni->Action == FILE_ACTION_ADDED, "action wrong\n" ); 231 ok( pfni->FileNameLength == 6, "len wrong\n" ); 232 ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" ); 233 234 r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0); 235 ok(r==STATUS_PENDING, "should status pending\n"); 236 237 r = RemoveDirectoryW( subdir ); 238 ok( r == TRUE, "failed to remove directory\n"); 239 240 r = WaitForSingleObject( hdir, 0 ); 241 ok( r == WAIT_OBJECT_0, "should be ready\n" ); 242 243 ok(U(iosb).Status == STATUS_SUCCESS, "status not successful\n"); 244 ok(iosb.Information == 0x12, "info not set\n"); 245 246 ok( pfni->NextEntryOffset == 0, "offset wrong\n" ); 247 ok( pfni->Action == FILE_ACTION_REMOVED, "action wrong\n" ); 248 ok( pfni->FileNameLength == 6, "len wrong\n" ); 249 ok( !memcmp(pfni->FileName,&szHoo[1],6), "name wrong\n" ); 250 251 /* check APCs */ 252 U(iosb).Status = 0; 253 iosb.Information = 0; 254 255 r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,NULL,0,filter,0); 256 ok(r==STATUS_PENDING, "should status pending\n"); 257 258 r = CreateDirectoryW( subdir, NULL ); 259 ok( r == TRUE, "failed to create directory\n"); 260 261 r = WaitForSingleObject( hdir, 0 ); 262 ok( r == WAIT_OBJECT_0, "should be ready\n" ); 263 264 ok(U(iosb).Status == STATUS_NOTIFY_ENUM_DIR, "status not successful\n"); 265 ok(iosb.Information == 0, "info not set\n"); 266 267 U(iosb).Status = 0; 268 iosb.Information = 0; 269 270 r = pNtNotifyChangeDirectoryFile(hdir,hEvent,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0); 271 ok(r==STATUS_PENDING, "should status pending\n"); 272 273 r = RemoveDirectoryW( subdir ); 274 ok( r == TRUE, "failed to remove directory\n"); 275 276 r = WaitForSingleObject( hEvent, 0 ); 277 ok( r == WAIT_OBJECT_0, "should be ready\n" ); 278 279 ok(U(iosb).Status == STATUS_SUCCESS, "status not successful\n"); 280 ok(iosb.Information == 0x12, "info not set\n"); 281 282 283 U(iosb).Status = 0x01234567; 284 iosb.Information = 0x12345678; 285 r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb,buffer,sizeof buffer,filter,0); 286 ok(r==STATUS_PENDING, "should status pending\n"); 287 288 U(iosb2).Status = 0x01234567; 289 iosb2.Information = 0x12345678; 290 r = pNtNotifyChangeDirectoryFile(hdir,0,NULL,NULL,&iosb2,buffer,sizeof buffer,filter,0); 291 ok(r==STATUS_PENDING, "should status pending\n"); 292 293 ok(U(iosb).Status == 0x01234567, "status set too soon\n"); 294 ok(iosb.Information == 0x12345678, "info set too soon\n"); 295 296 r = pNtCancelIoFile(hdir, &iosb); 297 ok( r == STATUS_SUCCESS, "cancel failed\n"); 298 299 CloseHandle(hdir); 300 301 ok(U(iosb).Status == STATUS_SUCCESS, "status wrong\n"); 302 ok(U(iosb2).Status == STATUS_CANCELLED, "status wrong %x\n",U(iosb2).Status); 303 304 ok(iosb.Information == 0, "info wrong\n"); 305 ok(iosb2.Information == 0, "info wrong\n"); 306 307 r = RemoveDirectoryW( path ); 308 ok( r == TRUE, "failed to remove directory\n"); 309 310 CloseHandle(hEvent); 311 } 312 313 START_TEST(change) 314 { 315 HMODULE hntdll = GetModuleHandleA("ntdll"); 316 if (!hntdll) 317 { 318 win_skip("not running on NT, skipping test\n"); 319 return; 320 } 321 322 pNtNotifyChangeDirectoryFile = (void *)GetProcAddress(hntdll, "NtNotifyChangeDirectoryFile"); 323 pNtCancelIoFile = (void *)GetProcAddress(hntdll, "NtCancelIoFile"); 324 325 if (!pNtNotifyChangeDirectoryFile || !pNtCancelIoFile) 326 { 327 win_skip("missing functions, skipping test\n"); 328 return; 329 } 330 331 test_ntncdf(); 332 test_ntncdf_async(); 333 } 334