t_vnode.c revision 314817
1#include <sys/event.h> 2#include <sys/stat.h> 3#include <sys/time.h> 4#include <fcntl.h> 5#include <stdio.h> 6#include <unistd.h> 7 8#include <atf-c.h> 9 10/* 11 * Test cases for events triggered by manipulating a target directory 12 * content. Using EVFILT_VNODE filter on the target directory descriptor. 13 * 14 */ 15 16static const char *dir_target = "foo"; 17static const char *dir_inside1 = "foo/bar1"; 18static const char *dir_inside2 = "foo/bar2"; 19static const char *dir_outside = "bar"; 20static const char *file_inside1 = "foo/baz1"; 21static const char *file_inside2 = "foo/baz2"; 22static const char *file_outside = "qux"; 23static const struct timespec ts = {0, 0}; 24static int kq = -1; 25static int target = -1; 26 27int init_target(void); 28int init_kqueue(void); 29int create_file(const char *); 30void cleanup(void); 31 32int 33init_target(void) 34{ 35 if (mkdir(dir_target, S_IRWXU) < 0) { 36 return -1; 37 } 38 target = open(dir_target, O_RDONLY, 0); 39 return target; 40} 41 42int 43init_kqueue(void) 44{ 45 struct kevent eventlist[1]; 46 47 kq = kqueue(); 48 if (kq < 0) { 49 return -1; 50 } 51 EV_SET(&eventlist[0], (uintptr_t)target, EVFILT_VNODE, 52 EV_ADD | EV_ONESHOT, NOTE_DELETE | 53 NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | 54 NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, 0); 55 return kevent(kq, eventlist, 1, NULL, 0, NULL); 56} 57 58int 59create_file(const char *file) 60{ 61 int fd; 62 63 fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); 64 if (fd < 0) { 65 return -1; 66 } 67 return close(fd); 68} 69 70void 71cleanup(void) 72{ 73 (void)unlink(file_inside1); 74 (void)unlink(file_inside2); 75 (void)unlink(file_outside); 76 (void)rmdir(dir_inside1); 77 (void)rmdir(dir_inside2); 78 (void)rmdir(dir_outside); 79 (void)rmdir(dir_target); 80 (void)close(kq); 81 (void)close(target); 82} 83 84ATF_TC_WITH_CLEANUP(dir_no_note_link_create_file_in); 85ATF_TC_HEAD(dir_no_note_link_create_file_in, tc) 86{ 87 atf_tc_set_md_var(tc, "descr", "This test case ensures " 88 "that kevent(2) does not return NOTE_LINK for the directory " 89 "'foo' if a file 'foo/baz' is created."); 90} 91ATF_TC_BODY(dir_no_note_link_create_file_in, tc) 92{ 93 struct kevent changelist[1]; 94 95 ATF_REQUIRE(init_target() != -1); 96 ATF_REQUIRE(init_kqueue() != -1); 97 98 ATF_REQUIRE(create_file(file_inside1) != -1); 99 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 100 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0); 101} 102ATF_TC_CLEANUP(dir_no_note_link_create_file_in, tc) 103{ 104 cleanup(); 105} 106 107ATF_TC_WITH_CLEANUP(dir_no_note_link_delete_file_in); 108ATF_TC_HEAD(dir_no_note_link_delete_file_in, tc) 109{ 110 atf_tc_set_md_var(tc, "descr", "This test case ensures " 111 "that kevent(2) does not return NOTE_LINK for the directory " 112 "'foo' if a file 'foo/baz' is deleted."); 113} 114ATF_TC_BODY(dir_no_note_link_delete_file_in, tc) 115{ 116 struct kevent changelist[1]; 117 118 ATF_REQUIRE(init_target() != -1); 119 ATF_REQUIRE(create_file(file_inside1) != -1); 120 ATF_REQUIRE(init_kqueue() != -1); 121 122 ATF_REQUIRE(unlink(file_inside1) != -1); 123 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 124 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0); 125} 126ATF_TC_CLEANUP(dir_no_note_link_delete_file_in, tc) 127{ 128 cleanup(); 129} 130 131ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_dir_within); 132ATF_TC_HEAD(dir_no_note_link_mv_dir_within, tc) 133{ 134 atf_tc_set_md_var(tc, "descr", "This test case ensures " 135 "that kevent(2) does not return NOTE_LINK for the directory " 136 "'foo' if a directory 'foo/bar' is renamed to 'foo/baz'."); 137} 138ATF_TC_BODY(dir_no_note_link_mv_dir_within, tc) 139{ 140 struct kevent changelist[1]; 141 142 ATF_REQUIRE(init_target() != -1); 143 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 144 ATF_REQUIRE(init_kqueue() != -1); 145 146 ATF_REQUIRE(rename(dir_inside1, dir_inside2) != -1); 147 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 148 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0); 149} 150ATF_TC_CLEANUP(dir_no_note_link_mv_dir_within, tc) 151{ 152 cleanup(); 153} 154 155ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_file_within); 156ATF_TC_HEAD(dir_no_note_link_mv_file_within, tc) 157{ 158 atf_tc_set_md_var(tc, "descr", "This test case ensures " 159 "that kevent(2) does not return NOTE_LINK for the directory " 160 "'foo' if a file 'foo/baz' is renamed to 'foo/qux'."); 161} 162ATF_TC_BODY(dir_no_note_link_mv_file_within, tc) 163{ 164 struct kevent changelist[1]; 165 166 ATF_REQUIRE(init_target() != -1); 167 ATF_REQUIRE(create_file(file_inside1) != -1); 168 ATF_REQUIRE(init_kqueue() != -1); 169 170 ATF_REQUIRE(rename(file_inside1, file_inside2) != -1); 171 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 172 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0); 173} 174ATF_TC_CLEANUP(dir_no_note_link_mv_file_within, tc) 175{ 176 cleanup(); 177} 178 179ATF_TC_WITH_CLEANUP(dir_note_link_create_dir_in); 180ATF_TC_HEAD(dir_note_link_create_dir_in, tc) 181{ 182 atf_tc_set_md_var(tc, "descr", "This test case ensures " 183 "that kevent(2) returns NOTE_LINK for the directory " 184 "'foo' if a directory 'foo/bar' is created."); 185} 186ATF_TC_BODY(dir_note_link_create_dir_in, tc) 187{ 188 struct kevent changelist[1]; 189 190 ATF_REQUIRE(init_target() != -1); 191 ATF_REQUIRE(init_kqueue() != -1); 192 193 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 194 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 195 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK); 196} 197ATF_TC_CLEANUP(dir_note_link_create_dir_in, tc) 198{ 199 cleanup(); 200} 201 202ATF_TC_WITH_CLEANUP(dir_note_link_delete_dir_in); 203ATF_TC_HEAD(dir_note_link_delete_dir_in, tc) 204{ 205 atf_tc_set_md_var(tc, "descr", "This test case ensures " 206 "that kevent(2) returns NOTE_LINK for the directory " 207 "'foo' if a directory 'foo/bar' is deleted."); 208} 209ATF_TC_BODY(dir_note_link_delete_dir_in, tc) 210{ 211 struct kevent changelist[1]; 212 213 ATF_REQUIRE(init_target() != -1); 214 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 215 ATF_REQUIRE(init_kqueue() != -1); 216 217 ATF_REQUIRE(rmdir(dir_inside1) != -1); 218 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 219 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK); 220} 221ATF_TC_CLEANUP(dir_note_link_delete_dir_in, tc) 222{ 223 cleanup(); 224} 225 226ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_in); 227ATF_TC_HEAD(dir_note_link_mv_dir_in, tc) 228{ 229 atf_tc_set_md_var(tc, "descr", "This test case ensures " 230 "that kevent(2) returns NOTE_LINK for the directory " 231 "'foo' if a directory 'bar' is renamed to 'foo/bar'."); 232} 233ATF_TC_BODY(dir_note_link_mv_dir_in, tc) 234{ 235 struct kevent changelist[1]; 236 237 ATF_REQUIRE(init_target() != -1); 238 ATF_REQUIRE(mkdir(dir_outside, S_IRWXU) != -1); 239 ATF_REQUIRE(init_kqueue() != -1); 240 241 ATF_REQUIRE(rename(dir_outside, dir_inside1) != -1); 242 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 243 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK); 244} 245ATF_TC_CLEANUP(dir_note_link_mv_dir_in, tc) 246{ 247 cleanup(); 248} 249 250ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_out); 251ATF_TC_HEAD(dir_note_link_mv_dir_out, tc) 252{ 253 atf_tc_set_md_var(tc, "descr", "This test case ensures " 254 "that kevent(2) returns NOTE_LINK for the directory " 255 "'foo' if a directory 'foo/bar' is renamed to 'bar'."); 256} 257ATF_TC_BODY(dir_note_link_mv_dir_out, tc) 258{ 259 struct kevent changelist[1]; 260 261 ATF_REQUIRE(init_target() != -1); 262 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 263 ATF_REQUIRE(init_kqueue() != -1); 264 265 ATF_REQUIRE(rename(dir_inside1, dir_outside) != -1); 266 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 267 ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK); 268} 269ATF_TC_CLEANUP(dir_note_link_mv_dir_out, tc) 270{ 271 cleanup(); 272} 273 274ATF_TC_WITH_CLEANUP(dir_note_write_create_dir_in); 275ATF_TC_HEAD(dir_note_write_create_dir_in, tc) 276{ 277 atf_tc_set_md_var(tc, "descr", "This test case ensures " 278 "that kevent(2) returns NOTE_WRITE for the directory " 279 "'foo' if a directory 'foo/bar' is created."); 280} 281ATF_TC_BODY(dir_note_write_create_dir_in, tc) 282{ 283 struct kevent changelist[1]; 284 285 ATF_REQUIRE(init_target() != -1); 286 ATF_REQUIRE(init_kqueue() != -1); 287 288 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 289 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 290 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 291} 292ATF_TC_CLEANUP(dir_note_write_create_dir_in, tc) 293{ 294 cleanup(); 295} 296 297ATF_TC_WITH_CLEANUP(dir_note_write_create_file_in); 298ATF_TC_HEAD(dir_note_write_create_file_in, tc) 299{ 300 atf_tc_set_md_var(tc, "descr", "This test case ensures " 301 "that kevent(2) returns NOTE_WRITE for the directory " 302 "'foo' if a file 'foo/baz' is created."); 303} 304ATF_TC_BODY(dir_note_write_create_file_in, tc) 305{ 306 struct kevent changelist[1]; 307 308 ATF_REQUIRE(init_target() != -1); 309 ATF_REQUIRE(init_kqueue() != -1); 310 311 ATF_REQUIRE(create_file(file_inside1) != -1); 312 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 313 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 314} 315ATF_TC_CLEANUP(dir_note_write_create_file_in, tc) 316{ 317 cleanup(); 318} 319 320ATF_TC_WITH_CLEANUP(dir_note_write_delete_dir_in); 321ATF_TC_HEAD(dir_note_write_delete_dir_in, tc) 322{ 323 atf_tc_set_md_var(tc, "descr", "This test case ensures " 324 "that kevent(2) returns NOTE_WRITE for the directory " 325 "'foo' if a directory 'foo/bar' is deleted."); 326} 327ATF_TC_BODY(dir_note_write_delete_dir_in, tc) 328{ 329 struct kevent changelist[1]; 330 331 ATF_REQUIRE(init_target() != -1); 332 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 333 ATF_REQUIRE(init_kqueue() != -1); 334 335 ATF_REQUIRE(rmdir(dir_inside1) != -1); 336 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 337 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 338} 339ATF_TC_CLEANUP(dir_note_write_delete_dir_in, tc) 340{ 341 cleanup(); 342} 343 344ATF_TC_WITH_CLEANUP(dir_note_write_delete_file_in); 345ATF_TC_HEAD(dir_note_write_delete_file_in, tc) 346{ 347 atf_tc_set_md_var(tc, "descr", "This test case ensures " 348 "that kevent(2) returns NOTE_WRITE for the directory " 349 "'foo' if a file 'foo/baz' is deleted."); 350} 351ATF_TC_BODY(dir_note_write_delete_file_in, tc) 352{ 353 struct kevent changelist[1]; 354 355 ATF_REQUIRE(init_target() != -1); 356 ATF_REQUIRE(create_file(file_inside1) != -1); 357 ATF_REQUIRE(init_kqueue() != -1); 358 359 ATF_REQUIRE(unlink(file_inside1) != -1); 360 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 361 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 362} 363ATF_TC_CLEANUP(dir_note_write_delete_file_in, tc) 364{ 365 cleanup(); 366} 367 368ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_in); 369ATF_TC_HEAD(dir_note_write_mv_dir_in, tc) 370{ 371 atf_tc_set_md_var(tc, "descr", "This test case ensures " 372 "that kevent(2) returns NOTE_WRITE for the directory " 373 "'foo' if a directory 'bar' is renamed to 'foo/bar'."); 374} 375ATF_TC_BODY(dir_note_write_mv_dir_in, tc) 376{ 377 struct kevent changelist[1]; 378 379 ATF_REQUIRE(init_target() != -1); 380 ATF_REQUIRE(mkdir(dir_outside, S_IRWXU) != -1); 381 ATF_REQUIRE(init_kqueue() != -1); 382 383 ATF_REQUIRE(rename(dir_outside, dir_inside1) != -1); 384 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 385 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 386} 387ATF_TC_CLEANUP(dir_note_write_mv_dir_in, tc) 388{ 389 cleanup(); 390} 391 392ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_out); 393ATF_TC_HEAD(dir_note_write_mv_dir_out, tc) 394{ 395 atf_tc_set_md_var(tc, "descr", "This test case ensures " 396 "that kevent(2) returns NOTE_WRITE for the directory " 397 "'foo' if a directory 'foo/bar' is renamed to 'bar'."); 398} 399ATF_TC_BODY(dir_note_write_mv_dir_out, tc) 400{ 401 struct kevent changelist[1]; 402 403 ATF_REQUIRE(init_target() != -1); 404 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 405 ATF_REQUIRE(init_kqueue() != -1); 406 407 ATF_REQUIRE(rename(dir_inside1, dir_outside) != -1); 408 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 409 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 410} 411ATF_TC_CLEANUP(dir_note_write_mv_dir_out, tc) 412{ 413 cleanup(); 414} 415 416ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_within); 417ATF_TC_HEAD(dir_note_write_mv_dir_within, tc) 418{ 419 atf_tc_set_md_var(tc, "descr", "This test case ensures " 420 "that kevent(2) returns NOTE_WRITE for the directory " 421 "'foo' if a directory 'foo/bar' is renamed to 'foo/baz'."); 422} 423ATF_TC_BODY(dir_note_write_mv_dir_within, tc) 424{ 425 struct kevent changelist[1]; 426 427 ATF_REQUIRE(init_target() != -1); 428 ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1); 429 ATF_REQUIRE(init_kqueue() != -1); 430 431 ATF_REQUIRE(rename(dir_inside1, dir_inside2) != -1); 432 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 433 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 434} 435ATF_TC_CLEANUP(dir_note_write_mv_dir_within, tc) 436{ 437 cleanup(); 438} 439 440ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_in); 441ATF_TC_HEAD(dir_note_write_mv_file_in, tc) 442{ 443 atf_tc_set_md_var(tc, "descr", "This test case ensures " 444 "that kevent(2) returns NOTE_WRITE for the directory " 445 "'foo' if a file 'qux' is renamed to 'foo/baz'."); 446} 447ATF_TC_BODY(dir_note_write_mv_file_in, tc) 448{ 449 struct kevent changelist[1]; 450 451 ATF_REQUIRE(init_target() != -1); 452 ATF_REQUIRE(create_file(file_outside) != -1); 453 ATF_REQUIRE(init_kqueue() != -1); 454 455 ATF_REQUIRE(rename(file_outside, file_inside1) != -1); 456 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 457 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 458} 459ATF_TC_CLEANUP(dir_note_write_mv_file_in, tc) 460{ 461 cleanup(); 462} 463 464ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_out); 465ATF_TC_HEAD(dir_note_write_mv_file_out, tc) 466{ 467 atf_tc_set_md_var(tc, "descr", "This test case ensures " 468 "that kevent(2) returns NOTE_WRITE for the directory " 469 "'foo' if a file 'foo/baz' is renamed to 'qux'."); 470} 471ATF_TC_BODY(dir_note_write_mv_file_out, tc) 472{ 473 struct kevent changelist[1]; 474 475 ATF_REQUIRE(init_target() != -1); 476 ATF_REQUIRE(create_file(file_inside1) != -1); 477 ATF_REQUIRE(init_kqueue() != -1); 478 479 ATF_REQUIRE(rename(file_inside1, file_outside) != -1); 480 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 481 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 482} 483ATF_TC_CLEANUP(dir_note_write_mv_file_out, tc) 484{ 485 cleanup(); 486} 487 488ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_within); 489ATF_TC_HEAD(dir_note_write_mv_file_within, tc) 490{ 491 atf_tc_set_md_var(tc, "descr", "This test case ensures " 492 "that kevent(2) returns NOTE_WRITE for the directory " 493 "'foo' if a file 'foo/baz' is renamed to 'foo/qux'."); 494} 495ATF_TC_BODY(dir_note_write_mv_file_within, tc) 496{ 497 struct kevent changelist[1]; 498 499 ATF_REQUIRE(init_target() != -1); 500 ATF_REQUIRE(create_file(file_inside1) != -1); 501 ATF_REQUIRE(init_kqueue() != -1); 502 503 ATF_REQUIRE(rename(file_inside1, file_inside2) != -1); 504 ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1); 505 ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE); 506} 507ATF_TC_CLEANUP(dir_note_write_mv_file_within, tc) 508{ 509 cleanup(); 510} 511 512ATF_TP_ADD_TCS(tp) 513{ 514 ATF_TP_ADD_TC(tp, dir_no_note_link_create_file_in); 515 ATF_TP_ADD_TC(tp, dir_no_note_link_delete_file_in); 516 ATF_TP_ADD_TC(tp, dir_no_note_link_mv_dir_within); 517 ATF_TP_ADD_TC(tp, dir_no_note_link_mv_file_within); 518 ATF_TP_ADD_TC(tp, dir_note_link_create_dir_in); 519 ATF_TP_ADD_TC(tp, dir_note_link_delete_dir_in); 520 ATF_TP_ADD_TC(tp, dir_note_link_mv_dir_in); 521 ATF_TP_ADD_TC(tp, dir_note_link_mv_dir_out); 522 ATF_TP_ADD_TC(tp, dir_note_write_create_dir_in); 523 ATF_TP_ADD_TC(tp, dir_note_write_create_file_in); 524 ATF_TP_ADD_TC(tp, dir_note_write_delete_dir_in); 525 ATF_TP_ADD_TC(tp, dir_note_write_delete_file_in); 526 ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_in); 527 ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_out); 528 ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_within); 529 ATF_TP_ADD_TC(tp, dir_note_write_mv_file_in); 530 ATF_TP_ADD_TC(tp, dir_note_write_mv_file_out); 531 ATF_TP_ADD_TC(tp, dir_note_write_mv_file_within); 532 return atf_no_error(); 533} 534