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