xref: /freebsd/contrib/netbsd-tests/kernel/kqueue/t_vnode.c (revision 1a36faad54665288ed4eb839d2a4699ae2ead45e)
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 
16 static const char *dir_target = "foo";
17 static const char *dir_inside1 = "foo/bar1";
18 static const char *dir_inside2 = "foo/bar2";
19 static const char *dir_outside = "bar";
20 static const char *file_inside1 = "foo/baz1";
21 static const char *file_inside2 = "foo/baz2";
22 static const char *file_outside = "qux";
23 static const struct timespec ts = {0, 0};
24 static int kq = -1;
25 static int target = -1;
26 
27 int init_target(void);
28 int init_kqueue(void);
29 int create_file(const char *);
30 void cleanup(void);
31 
32 int
init_target(void)33 init_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 
42 int
init_kqueue(void)43 init_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 
58 int
create_file(const char * file)59 create_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 
70 void
cleanup(void)71 cleanup(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 
84 ATF_TC_WITH_CLEANUP(dir_no_note_link_create_file_in);
ATF_TC_HEAD(dir_no_note_link_create_file_in,tc)85 ATF_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 }
ATF_TC_BODY(dir_no_note_link_create_file_in,tc)91 ATF_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 }
ATF_TC_CLEANUP(dir_no_note_link_create_file_in,tc)102 ATF_TC_CLEANUP(dir_no_note_link_create_file_in, tc)
103 {
104 	cleanup();
105 }
106 
107 ATF_TC_WITH_CLEANUP(dir_no_note_link_delete_file_in);
ATF_TC_HEAD(dir_no_note_link_delete_file_in,tc)108 ATF_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 }
ATF_TC_BODY(dir_no_note_link_delete_file_in,tc)114 ATF_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 }
ATF_TC_CLEANUP(dir_no_note_link_delete_file_in,tc)126 ATF_TC_CLEANUP(dir_no_note_link_delete_file_in, tc)
127 {
128 	cleanup();
129 }
130 
131 ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_dir_within);
ATF_TC_HEAD(dir_no_note_link_mv_dir_within,tc)132 ATF_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 }
ATF_TC_BODY(dir_no_note_link_mv_dir_within,tc)138 ATF_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 }
ATF_TC_CLEANUP(dir_no_note_link_mv_dir_within,tc)150 ATF_TC_CLEANUP(dir_no_note_link_mv_dir_within, tc)
151 {
152 	cleanup();
153 }
154 
155 ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_file_within);
ATF_TC_HEAD(dir_no_note_link_mv_file_within,tc)156 ATF_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 }
ATF_TC_BODY(dir_no_note_link_mv_file_within,tc)162 ATF_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 }
ATF_TC_CLEANUP(dir_no_note_link_mv_file_within,tc)174 ATF_TC_CLEANUP(dir_no_note_link_mv_file_within, tc)
175 {
176 	cleanup();
177 }
178 
179 ATF_TC_WITH_CLEANUP(dir_note_link_create_dir_in);
ATF_TC_HEAD(dir_note_link_create_dir_in,tc)180 ATF_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 }
ATF_TC_BODY(dir_note_link_create_dir_in,tc)186 ATF_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 }
ATF_TC_CLEANUP(dir_note_link_create_dir_in,tc)197 ATF_TC_CLEANUP(dir_note_link_create_dir_in, tc)
198 {
199 	cleanup();
200 }
201 
202 ATF_TC_WITH_CLEANUP(dir_note_link_delete_dir_in);
ATF_TC_HEAD(dir_note_link_delete_dir_in,tc)203 ATF_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 }
ATF_TC_BODY(dir_note_link_delete_dir_in,tc)209 ATF_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 }
ATF_TC_CLEANUP(dir_note_link_delete_dir_in,tc)221 ATF_TC_CLEANUP(dir_note_link_delete_dir_in, tc)
222 {
223 	cleanup();
224 }
225 
226 ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_in);
ATF_TC_HEAD(dir_note_link_mv_dir_in,tc)227 ATF_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 }
ATF_TC_BODY(dir_note_link_mv_dir_in,tc)233 ATF_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 }
ATF_TC_CLEANUP(dir_note_link_mv_dir_in,tc)245 ATF_TC_CLEANUP(dir_note_link_mv_dir_in, tc)
246 {
247 	cleanup();
248 }
249 
250 ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_out);
ATF_TC_HEAD(dir_note_link_mv_dir_out,tc)251 ATF_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 }
ATF_TC_BODY(dir_note_link_mv_dir_out,tc)257 ATF_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 }
ATF_TC_CLEANUP(dir_note_link_mv_dir_out,tc)269 ATF_TC_CLEANUP(dir_note_link_mv_dir_out, tc)
270 {
271 	cleanup();
272 }
273 
274 ATF_TC_WITH_CLEANUP(dir_note_write_create_dir_in);
ATF_TC_HEAD(dir_note_write_create_dir_in,tc)275 ATF_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 }
ATF_TC_BODY(dir_note_write_create_dir_in,tc)281 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_create_dir_in,tc)292 ATF_TC_CLEANUP(dir_note_write_create_dir_in, tc)
293 {
294 	cleanup();
295 }
296 
297 ATF_TC_WITH_CLEANUP(dir_note_write_create_file_in);
ATF_TC_HEAD(dir_note_write_create_file_in,tc)298 ATF_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 }
ATF_TC_BODY(dir_note_write_create_file_in,tc)304 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_create_file_in,tc)315 ATF_TC_CLEANUP(dir_note_write_create_file_in, tc)
316 {
317 	cleanup();
318 }
319 
320 ATF_TC_WITH_CLEANUP(dir_note_write_delete_dir_in);
ATF_TC_HEAD(dir_note_write_delete_dir_in,tc)321 ATF_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 }
ATF_TC_BODY(dir_note_write_delete_dir_in,tc)327 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_delete_dir_in,tc)339 ATF_TC_CLEANUP(dir_note_write_delete_dir_in, tc)
340 {
341 	cleanup();
342 }
343 
344 ATF_TC_WITH_CLEANUP(dir_note_write_delete_file_in);
ATF_TC_HEAD(dir_note_write_delete_file_in,tc)345 ATF_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 }
ATF_TC_BODY(dir_note_write_delete_file_in,tc)351 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_delete_file_in,tc)363 ATF_TC_CLEANUP(dir_note_write_delete_file_in, tc)
364 {
365 	cleanup();
366 }
367 
368 ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_in);
ATF_TC_HEAD(dir_note_write_mv_dir_in,tc)369 ATF_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 }
ATF_TC_BODY(dir_note_write_mv_dir_in,tc)375 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_mv_dir_in,tc)387 ATF_TC_CLEANUP(dir_note_write_mv_dir_in, tc)
388 {
389 	cleanup();
390 }
391 
392 ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_out);
ATF_TC_HEAD(dir_note_write_mv_dir_out,tc)393 ATF_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 }
ATF_TC_BODY(dir_note_write_mv_dir_out,tc)399 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_mv_dir_out,tc)411 ATF_TC_CLEANUP(dir_note_write_mv_dir_out, tc)
412 {
413 	cleanup();
414 }
415 
416 ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_within);
ATF_TC_HEAD(dir_note_write_mv_dir_within,tc)417 ATF_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 }
ATF_TC_BODY(dir_note_write_mv_dir_within,tc)423 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_mv_dir_within,tc)435 ATF_TC_CLEANUP(dir_note_write_mv_dir_within, tc)
436 {
437 	cleanup();
438 }
439 
440 ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_in);
ATF_TC_HEAD(dir_note_write_mv_file_in,tc)441 ATF_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 }
ATF_TC_BODY(dir_note_write_mv_file_in,tc)447 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_mv_file_in,tc)459 ATF_TC_CLEANUP(dir_note_write_mv_file_in, tc)
460 {
461 	cleanup();
462 }
463 
464 ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_out);
ATF_TC_HEAD(dir_note_write_mv_file_out,tc)465 ATF_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 }
ATF_TC_BODY(dir_note_write_mv_file_out,tc)471 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_mv_file_out,tc)483 ATF_TC_CLEANUP(dir_note_write_mv_file_out, tc)
484 {
485 	cleanup();
486 }
487 
488 ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_within);
ATF_TC_HEAD(dir_note_write_mv_file_within,tc)489 ATF_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 }
ATF_TC_BODY(dir_note_write_mv_file_within,tc)495 ATF_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 }
ATF_TC_CLEANUP(dir_note_write_mv_file_within,tc)507 ATF_TC_CLEANUP(dir_note_write_mv_file_within, tc)
508 {
509 	cleanup();
510 }
511 
ATF_TP_ADD_TCS(tp)512 ATF_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