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