1f7afbc7fSchristos #include <sys/event.h>
2f7afbc7fSchristos #include <sys/stat.h>
3f7afbc7fSchristos #include <sys/time.h>
4f7afbc7fSchristos #include <fcntl.h>
5f7afbc7fSchristos #include <stdio.h>
6f7afbc7fSchristos #include <unistd.h>
7f7afbc7fSchristos
8f7afbc7fSchristos #include <atf-c.h>
9f7afbc7fSchristos
10f7afbc7fSchristos /*
11f7afbc7fSchristos * Test cases for events triggered by manipulating a target directory
12f7afbc7fSchristos * content. Using EVFILT_VNODE filter on the target directory descriptor.
13f7afbc7fSchristos *
14f7afbc7fSchristos */
15f7afbc7fSchristos
16f7afbc7fSchristos static const char *dir_target = "foo";
17f7afbc7fSchristos static const char *dir_inside1 = "foo/bar1";
18f7afbc7fSchristos static const char *dir_inside2 = "foo/bar2";
19f7afbc7fSchristos static const char *dir_outside = "bar";
20f7afbc7fSchristos static const char *file_inside1 = "foo/baz1";
21f7afbc7fSchristos static const char *file_inside2 = "foo/baz2";
22f7afbc7fSchristos static const char *file_outside = "qux";
23f7afbc7fSchristos static const struct timespec ts = {0, 0};
24f7afbc7fSchristos static int kq = -1;
25f7afbc7fSchristos static int target = -1;
26f7afbc7fSchristos
27f7afbc7fSchristos int init_target(void);
28f7afbc7fSchristos int init_kqueue(void);
29f7afbc7fSchristos int create_file(const char *);
30f7afbc7fSchristos void cleanup(void);
31f7afbc7fSchristos
32f7afbc7fSchristos int
init_target(void)33f7afbc7fSchristos init_target(void)
34f7afbc7fSchristos {
35f7afbc7fSchristos if (mkdir(dir_target, S_IRWXU) < 0) {
36f7afbc7fSchristos return -1;
37f7afbc7fSchristos }
38f7afbc7fSchristos target = open(dir_target, O_RDONLY, 0);
39f7afbc7fSchristos return target;
40f7afbc7fSchristos }
41f7afbc7fSchristos
42f7afbc7fSchristos int
init_kqueue(void)43f7afbc7fSchristos init_kqueue(void)
44f7afbc7fSchristos {
45f7afbc7fSchristos struct kevent eventlist[1];
46f7afbc7fSchristos
47f7afbc7fSchristos kq = kqueue();
48f7afbc7fSchristos if (kq < 0) {
49f7afbc7fSchristos return -1;
50f7afbc7fSchristos }
51f7afbc7fSchristos EV_SET(&eventlist[0], (uintptr_t)target, EVFILT_VNODE,
52f7afbc7fSchristos EV_ADD | EV_ONESHOT, NOTE_DELETE |
53f7afbc7fSchristos NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
54f7afbc7fSchristos NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, 0);
55f7afbc7fSchristos return kevent(kq, eventlist, 1, NULL, 0, NULL);
56f7afbc7fSchristos }
57f7afbc7fSchristos
58f7afbc7fSchristos int
create_file(const char * file)59f7afbc7fSchristos create_file(const char *file)
60f7afbc7fSchristos {
61f7afbc7fSchristos int fd;
62f7afbc7fSchristos
63f7afbc7fSchristos fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
64f7afbc7fSchristos if (fd < 0) {
65f7afbc7fSchristos return -1;
66f7afbc7fSchristos }
67f7afbc7fSchristos return close(fd);
68f7afbc7fSchristos }
69f7afbc7fSchristos
70f7afbc7fSchristos void
cleanup(void)71f7afbc7fSchristos cleanup(void)
72f7afbc7fSchristos {
73f7afbc7fSchristos (void)unlink(file_inside1);
74f7afbc7fSchristos (void)unlink(file_inside2);
75f7afbc7fSchristos (void)unlink(file_outside);
76f7afbc7fSchristos (void)rmdir(dir_inside1);
77f7afbc7fSchristos (void)rmdir(dir_inside2);
78f7afbc7fSchristos (void)rmdir(dir_outside);
79f7afbc7fSchristos (void)rmdir(dir_target);
80f7afbc7fSchristos (void)close(kq);
81f7afbc7fSchristos (void)close(target);
82f7afbc7fSchristos }
83f7afbc7fSchristos
84f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_no_note_link_create_file_in);
ATF_TC_HEAD(dir_no_note_link_create_file_in,tc)85f7afbc7fSchristos ATF_TC_HEAD(dir_no_note_link_create_file_in, tc)
86f7afbc7fSchristos {
87f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
88f7afbc7fSchristos "that kevent(2) does not return NOTE_LINK for the directory "
89f7afbc7fSchristos "'foo' if a file 'foo/baz' is created.");
90f7afbc7fSchristos }
ATF_TC_BODY(dir_no_note_link_create_file_in,tc)91f7afbc7fSchristos ATF_TC_BODY(dir_no_note_link_create_file_in, tc)
92f7afbc7fSchristos {
93f7afbc7fSchristos struct kevent changelist[1];
94f7afbc7fSchristos
95f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
96f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
97f7afbc7fSchristos
98f7afbc7fSchristos ATF_REQUIRE(create_file(file_inside1) != -1);
99f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
100f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
101f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_no_note_link_create_file_in,tc)102f7afbc7fSchristos ATF_TC_CLEANUP(dir_no_note_link_create_file_in, tc)
103f7afbc7fSchristos {
104f7afbc7fSchristos cleanup();
105f7afbc7fSchristos }
106f7afbc7fSchristos
107f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_no_note_link_delete_file_in);
ATF_TC_HEAD(dir_no_note_link_delete_file_in,tc)108f7afbc7fSchristos ATF_TC_HEAD(dir_no_note_link_delete_file_in, tc)
109f7afbc7fSchristos {
110f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
111f7afbc7fSchristos "that kevent(2) does not return NOTE_LINK for the directory "
112f7afbc7fSchristos "'foo' if a file 'foo/baz' is deleted.");
113f7afbc7fSchristos }
ATF_TC_BODY(dir_no_note_link_delete_file_in,tc)114f7afbc7fSchristos ATF_TC_BODY(dir_no_note_link_delete_file_in, tc)
115f7afbc7fSchristos {
116f7afbc7fSchristos struct kevent changelist[1];
117f7afbc7fSchristos
118f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
119f7afbc7fSchristos ATF_REQUIRE(create_file(file_inside1) != -1);
120f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
121f7afbc7fSchristos
122f7afbc7fSchristos ATF_REQUIRE(unlink(file_inside1) != -1);
123f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
124f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
125f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_no_note_link_delete_file_in,tc)126f7afbc7fSchristos ATF_TC_CLEANUP(dir_no_note_link_delete_file_in, tc)
127f7afbc7fSchristos {
128f7afbc7fSchristos cleanup();
129f7afbc7fSchristos }
130f7afbc7fSchristos
131f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_dir_within);
ATF_TC_HEAD(dir_no_note_link_mv_dir_within,tc)132f7afbc7fSchristos ATF_TC_HEAD(dir_no_note_link_mv_dir_within, tc)
133f7afbc7fSchristos {
134f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
135f7afbc7fSchristos "that kevent(2) does not return NOTE_LINK for the directory "
136f7afbc7fSchristos "'foo' if a directory 'foo/bar' is renamed to 'foo/baz'.");
137f7afbc7fSchristos }
ATF_TC_BODY(dir_no_note_link_mv_dir_within,tc)138f7afbc7fSchristos ATF_TC_BODY(dir_no_note_link_mv_dir_within, tc)
139f7afbc7fSchristos {
140f7afbc7fSchristos struct kevent changelist[1];
141f7afbc7fSchristos
142f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
143f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
144f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
145f7afbc7fSchristos
146f7afbc7fSchristos ATF_REQUIRE(rename(dir_inside1, dir_inside2) != -1);
147f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
148f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
149f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_no_note_link_mv_dir_within,tc)150f7afbc7fSchristos ATF_TC_CLEANUP(dir_no_note_link_mv_dir_within, tc)
151f7afbc7fSchristos {
152f7afbc7fSchristos cleanup();
153f7afbc7fSchristos }
154f7afbc7fSchristos
155f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_file_within);
ATF_TC_HEAD(dir_no_note_link_mv_file_within,tc)156f7afbc7fSchristos ATF_TC_HEAD(dir_no_note_link_mv_file_within, tc)
157f7afbc7fSchristos {
158f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
159f7afbc7fSchristos "that kevent(2) does not return NOTE_LINK for the directory "
160f7afbc7fSchristos "'foo' if a file 'foo/baz' is renamed to 'foo/qux'.");
161f7afbc7fSchristos }
ATF_TC_BODY(dir_no_note_link_mv_file_within,tc)162f7afbc7fSchristos ATF_TC_BODY(dir_no_note_link_mv_file_within, tc)
163f7afbc7fSchristos {
164f7afbc7fSchristos struct kevent changelist[1];
165f7afbc7fSchristos
166f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
167f7afbc7fSchristos ATF_REQUIRE(create_file(file_inside1) != -1);
168f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
169f7afbc7fSchristos
170f7afbc7fSchristos ATF_REQUIRE(rename(file_inside1, file_inside2) != -1);
171f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
172f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
173f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_no_note_link_mv_file_within,tc)174f7afbc7fSchristos ATF_TC_CLEANUP(dir_no_note_link_mv_file_within, tc)
175f7afbc7fSchristos {
176f7afbc7fSchristos cleanup();
177f7afbc7fSchristos }
178f7afbc7fSchristos
179f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_link_create_dir_in);
ATF_TC_HEAD(dir_note_link_create_dir_in,tc)180f7afbc7fSchristos ATF_TC_HEAD(dir_note_link_create_dir_in, tc)
181f7afbc7fSchristos {
182f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
183f7afbc7fSchristos "that kevent(2) returns NOTE_LINK for the directory "
184f7afbc7fSchristos "'foo' if a directory 'foo/bar' is created.");
185f7afbc7fSchristos }
ATF_TC_BODY(dir_note_link_create_dir_in,tc)186f7afbc7fSchristos ATF_TC_BODY(dir_note_link_create_dir_in, tc)
187f7afbc7fSchristos {
188f7afbc7fSchristos struct kevent changelist[1];
189f7afbc7fSchristos
190f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
191f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
192f7afbc7fSchristos
193f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
194f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
195f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
196f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_link_create_dir_in,tc)197f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_link_create_dir_in, tc)
198f7afbc7fSchristos {
199f7afbc7fSchristos cleanup();
200f7afbc7fSchristos }
201f7afbc7fSchristos
202f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_link_delete_dir_in);
ATF_TC_HEAD(dir_note_link_delete_dir_in,tc)203f7afbc7fSchristos ATF_TC_HEAD(dir_note_link_delete_dir_in, tc)
204f7afbc7fSchristos {
205f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
206f7afbc7fSchristos "that kevent(2) returns NOTE_LINK for the directory "
207f7afbc7fSchristos "'foo' if a directory 'foo/bar' is deleted.");
208f7afbc7fSchristos }
ATF_TC_BODY(dir_note_link_delete_dir_in,tc)209f7afbc7fSchristos ATF_TC_BODY(dir_note_link_delete_dir_in, tc)
210f7afbc7fSchristos {
211f7afbc7fSchristos struct kevent changelist[1];
212f7afbc7fSchristos
213f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
214f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
215f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
216f7afbc7fSchristos
217f7afbc7fSchristos ATF_REQUIRE(rmdir(dir_inside1) != -1);
218f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
219f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
220f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_link_delete_dir_in,tc)221f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_link_delete_dir_in, tc)
222f7afbc7fSchristos {
223f7afbc7fSchristos cleanup();
224f7afbc7fSchristos }
225f7afbc7fSchristos
226f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_in);
ATF_TC_HEAD(dir_note_link_mv_dir_in,tc)227f7afbc7fSchristos ATF_TC_HEAD(dir_note_link_mv_dir_in, tc)
228f7afbc7fSchristos {
229f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
230f7afbc7fSchristos "that kevent(2) returns NOTE_LINK for the directory "
231f7afbc7fSchristos "'foo' if a directory 'bar' is renamed to 'foo/bar'.");
232f7afbc7fSchristos }
ATF_TC_BODY(dir_note_link_mv_dir_in,tc)233f7afbc7fSchristos ATF_TC_BODY(dir_note_link_mv_dir_in, tc)
234f7afbc7fSchristos {
235f7afbc7fSchristos struct kevent changelist[1];
236f7afbc7fSchristos
237f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
238f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_outside, S_IRWXU) != -1);
239f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
240f7afbc7fSchristos
241f7afbc7fSchristos ATF_REQUIRE(rename(dir_outside, dir_inside1) != -1);
242f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
243f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
244f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_link_mv_dir_in,tc)245f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_link_mv_dir_in, tc)
246f7afbc7fSchristos {
247f7afbc7fSchristos cleanup();
248f7afbc7fSchristos }
249f7afbc7fSchristos
250f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_out);
ATF_TC_HEAD(dir_note_link_mv_dir_out,tc)251f7afbc7fSchristos ATF_TC_HEAD(dir_note_link_mv_dir_out, tc)
252f7afbc7fSchristos {
253f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
254f7afbc7fSchristos "that kevent(2) returns NOTE_LINK for the directory "
255f7afbc7fSchristos "'foo' if a directory 'foo/bar' is renamed to 'bar'.");
256f7afbc7fSchristos }
ATF_TC_BODY(dir_note_link_mv_dir_out,tc)257f7afbc7fSchristos ATF_TC_BODY(dir_note_link_mv_dir_out, tc)
258f7afbc7fSchristos {
259f7afbc7fSchristos struct kevent changelist[1];
260f7afbc7fSchristos
261f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
262f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
263f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
264f7afbc7fSchristos
265f7afbc7fSchristos ATF_REQUIRE(rename(dir_inside1, dir_outside) != -1);
266f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
267f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
268f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_link_mv_dir_out,tc)269f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_link_mv_dir_out, tc)
270f7afbc7fSchristos {
271f7afbc7fSchristos cleanup();
272f7afbc7fSchristos }
273f7afbc7fSchristos
274f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_create_dir_in);
ATF_TC_HEAD(dir_note_write_create_dir_in,tc)275f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_create_dir_in, tc)
276f7afbc7fSchristos {
277f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
278f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
279f7afbc7fSchristos "'foo' if a directory 'foo/bar' is created.");
280f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_create_dir_in,tc)281f7afbc7fSchristos ATF_TC_BODY(dir_note_write_create_dir_in, tc)
282f7afbc7fSchristos {
283f7afbc7fSchristos struct kevent changelist[1];
284f7afbc7fSchristos
285f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
286f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
287f7afbc7fSchristos
288f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
289f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
290f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
291f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_create_dir_in,tc)292f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_create_dir_in, tc)
293f7afbc7fSchristos {
294f7afbc7fSchristos cleanup();
295f7afbc7fSchristos }
296f7afbc7fSchristos
297f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_create_file_in);
ATF_TC_HEAD(dir_note_write_create_file_in,tc)298f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_create_file_in, tc)
299f7afbc7fSchristos {
300f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
301f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
302f7afbc7fSchristos "'foo' if a file 'foo/baz' is created.");
303f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_create_file_in,tc)304f7afbc7fSchristos ATF_TC_BODY(dir_note_write_create_file_in, tc)
305f7afbc7fSchristos {
306f7afbc7fSchristos struct kevent changelist[1];
307f7afbc7fSchristos
308f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
309f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
310f7afbc7fSchristos
311f7afbc7fSchristos ATF_REQUIRE(create_file(file_inside1) != -1);
312f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
313f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
314f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_create_file_in,tc)315f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_create_file_in, tc)
316f7afbc7fSchristos {
317f7afbc7fSchristos cleanup();
318f7afbc7fSchristos }
319f7afbc7fSchristos
320f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_delete_dir_in);
ATF_TC_HEAD(dir_note_write_delete_dir_in,tc)321f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_delete_dir_in, tc)
322f7afbc7fSchristos {
323f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
324f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
325f7afbc7fSchristos "'foo' if a directory 'foo/bar' is deleted.");
326f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_delete_dir_in,tc)327f7afbc7fSchristos ATF_TC_BODY(dir_note_write_delete_dir_in, tc)
328f7afbc7fSchristos {
329f7afbc7fSchristos struct kevent changelist[1];
330f7afbc7fSchristos
331f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
332f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
333f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
334f7afbc7fSchristos
335f7afbc7fSchristos ATF_REQUIRE(rmdir(dir_inside1) != -1);
336f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
337f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
338f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_delete_dir_in,tc)339f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_delete_dir_in, tc)
340f7afbc7fSchristos {
341f7afbc7fSchristos cleanup();
342f7afbc7fSchristos }
343f7afbc7fSchristos
344f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_delete_file_in);
ATF_TC_HEAD(dir_note_write_delete_file_in,tc)345f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_delete_file_in, tc)
346f7afbc7fSchristos {
347f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
348f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
349f7afbc7fSchristos "'foo' if a file 'foo/baz' is deleted.");
350f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_delete_file_in,tc)351f7afbc7fSchristos ATF_TC_BODY(dir_note_write_delete_file_in, tc)
352f7afbc7fSchristos {
353f7afbc7fSchristos struct kevent changelist[1];
354f7afbc7fSchristos
355f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
356f7afbc7fSchristos ATF_REQUIRE(create_file(file_inside1) != -1);
357f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
358f7afbc7fSchristos
359f7afbc7fSchristos ATF_REQUIRE(unlink(file_inside1) != -1);
360f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
361f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
362f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_delete_file_in,tc)363f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_delete_file_in, tc)
364f7afbc7fSchristos {
365f7afbc7fSchristos cleanup();
366f7afbc7fSchristos }
367f7afbc7fSchristos
368f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_in);
ATF_TC_HEAD(dir_note_write_mv_dir_in,tc)369f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_mv_dir_in, tc)
370f7afbc7fSchristos {
371f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
372f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
373f7afbc7fSchristos "'foo' if a directory 'bar' is renamed to 'foo/bar'.");
374f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_mv_dir_in,tc)375f7afbc7fSchristos ATF_TC_BODY(dir_note_write_mv_dir_in, tc)
376f7afbc7fSchristos {
377f7afbc7fSchristos struct kevent changelist[1];
378f7afbc7fSchristos
379f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
380f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_outside, S_IRWXU) != -1);
381f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
382f7afbc7fSchristos
383f7afbc7fSchristos ATF_REQUIRE(rename(dir_outside, dir_inside1) != -1);
384f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
385f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
386f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_mv_dir_in,tc)387f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_mv_dir_in, tc)
388f7afbc7fSchristos {
389f7afbc7fSchristos cleanup();
390f7afbc7fSchristos }
391f7afbc7fSchristos
392f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_out);
ATF_TC_HEAD(dir_note_write_mv_dir_out,tc)393f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_mv_dir_out, tc)
394f7afbc7fSchristos {
395f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
396f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
397f7afbc7fSchristos "'foo' if a directory 'foo/bar' is renamed to 'bar'.");
398f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_mv_dir_out,tc)399f7afbc7fSchristos ATF_TC_BODY(dir_note_write_mv_dir_out, tc)
400f7afbc7fSchristos {
401f7afbc7fSchristos struct kevent changelist[1];
402f7afbc7fSchristos
403f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
404f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
405f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
406f7afbc7fSchristos
407f7afbc7fSchristos ATF_REQUIRE(rename(dir_inside1, dir_outside) != -1);
408f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
409f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
410f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_mv_dir_out,tc)411f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_mv_dir_out, tc)
412f7afbc7fSchristos {
413f7afbc7fSchristos cleanup();
414f7afbc7fSchristos }
415f7afbc7fSchristos
416f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_within);
ATF_TC_HEAD(dir_note_write_mv_dir_within,tc)417f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_mv_dir_within, tc)
418f7afbc7fSchristos {
419f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
420f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
421f7afbc7fSchristos "'foo' if a directory 'foo/bar' is renamed to 'foo/baz'.");
422f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_mv_dir_within,tc)423f7afbc7fSchristos ATF_TC_BODY(dir_note_write_mv_dir_within, tc)
424f7afbc7fSchristos {
425f7afbc7fSchristos struct kevent changelist[1];
426f7afbc7fSchristos
427f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
428f7afbc7fSchristos ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
429f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
430f7afbc7fSchristos
431f7afbc7fSchristos ATF_REQUIRE(rename(dir_inside1, dir_inside2) != -1);
432f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
433f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
434f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_mv_dir_within,tc)435f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_mv_dir_within, tc)
436f7afbc7fSchristos {
437f7afbc7fSchristos cleanup();
438f7afbc7fSchristos }
439f7afbc7fSchristos
440f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_in);
ATF_TC_HEAD(dir_note_write_mv_file_in,tc)441f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_mv_file_in, tc)
442f7afbc7fSchristos {
443f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
444f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
445f7afbc7fSchristos "'foo' if a file 'qux' is renamed to 'foo/baz'.");
446f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_mv_file_in,tc)447f7afbc7fSchristos ATF_TC_BODY(dir_note_write_mv_file_in, tc)
448f7afbc7fSchristos {
449f7afbc7fSchristos struct kevent changelist[1];
450f7afbc7fSchristos
451f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
452f7afbc7fSchristos ATF_REQUIRE(create_file(file_outside) != -1);
453f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
454f7afbc7fSchristos
455f7afbc7fSchristos ATF_REQUIRE(rename(file_outside, file_inside1) != -1);
456f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
457f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
458f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_mv_file_in,tc)459f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_mv_file_in, tc)
460f7afbc7fSchristos {
461f7afbc7fSchristos cleanup();
462f7afbc7fSchristos }
463f7afbc7fSchristos
464f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_out);
ATF_TC_HEAD(dir_note_write_mv_file_out,tc)465f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_mv_file_out, tc)
466f7afbc7fSchristos {
467f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
468f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
469f7afbc7fSchristos "'foo' if a file 'foo/baz' is renamed to 'qux'.");
470f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_mv_file_out,tc)471f7afbc7fSchristos ATF_TC_BODY(dir_note_write_mv_file_out, tc)
472f7afbc7fSchristos {
473f7afbc7fSchristos struct kevent changelist[1];
474f7afbc7fSchristos
475f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
476f7afbc7fSchristos ATF_REQUIRE(create_file(file_inside1) != -1);
477f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
478f7afbc7fSchristos
479f7afbc7fSchristos ATF_REQUIRE(rename(file_inside1, file_outside) != -1);
480f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
481f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
482f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_mv_file_out,tc)483f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_mv_file_out, tc)
484f7afbc7fSchristos {
485f7afbc7fSchristos cleanup();
486f7afbc7fSchristos }
487f7afbc7fSchristos
488f7afbc7fSchristos ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_within);
ATF_TC_HEAD(dir_note_write_mv_file_within,tc)489f7afbc7fSchristos ATF_TC_HEAD(dir_note_write_mv_file_within, tc)
490f7afbc7fSchristos {
491f7afbc7fSchristos atf_tc_set_md_var(tc, "descr", "This test case ensures "
492f7afbc7fSchristos "that kevent(2) returns NOTE_WRITE for the directory "
493f7afbc7fSchristos "'foo' if a file 'foo/baz' is renamed to 'foo/qux'.");
494f7afbc7fSchristos }
ATF_TC_BODY(dir_note_write_mv_file_within,tc)495f7afbc7fSchristos ATF_TC_BODY(dir_note_write_mv_file_within, tc)
496f7afbc7fSchristos {
497f7afbc7fSchristos struct kevent changelist[1];
498f7afbc7fSchristos
499f7afbc7fSchristos ATF_REQUIRE(init_target() != -1);
500f7afbc7fSchristos ATF_REQUIRE(create_file(file_inside1) != -1);
501f7afbc7fSchristos ATF_REQUIRE(init_kqueue() != -1);
502f7afbc7fSchristos
503f7afbc7fSchristos ATF_REQUIRE(rename(file_inside1, file_inside2) != -1);
504f7afbc7fSchristos ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
505f7afbc7fSchristos ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
506f7afbc7fSchristos }
ATF_TC_CLEANUP(dir_note_write_mv_file_within,tc)507f7afbc7fSchristos ATF_TC_CLEANUP(dir_note_write_mv_file_within, tc)
508f7afbc7fSchristos {
509f7afbc7fSchristos cleanup();
510f7afbc7fSchristos }
511f7afbc7fSchristos
512982ae832Sthorpej static const char testfile[] = "testfile";
513982ae832Sthorpej
514982ae832Sthorpej ATF_TC_WITH_CLEANUP(open_write_read_close);
ATF_TC_HEAD(open_write_read_close,tc)515982ae832Sthorpej ATF_TC_HEAD(open_write_read_close, tc)
516982ae832Sthorpej {
517982ae832Sthorpej atf_tc_set_md_var(tc, "descr", "This test case exercises "
518982ae832Sthorpej "that kevent(2) returns NOTE_OPEN, NOTE_READ, NOTE_WRITE, "
519982ae832Sthorpej "NOTE_CLOSE, and NOTE_CLOSE_WRITE.");
520982ae832Sthorpej }
ATF_TC_BODY(open_write_read_close,tc)521982ae832Sthorpej ATF_TC_BODY(open_write_read_close, tc)
522982ae832Sthorpej {
523982ae832Sthorpej struct kevent event[1];
524982ae832Sthorpej char buf[sizeof(testfile)];
525982ae832Sthorpej int fd;
526982ae832Sthorpej
527982ae832Sthorpej ATF_REQUIRE((kq = kqueue()) != -1);
528982ae832Sthorpej
529982ae832Sthorpej /*
530982ae832Sthorpej * Create the test file and register an event on it. We need
531982ae832Sthorpej * to keep the fd open to keep receiving events, so we'll just
532982ae832Sthorpej * leak it and re-use the fd variable.
533982ae832Sthorpej */
534982ae832Sthorpej ATF_REQUIRE((fd = open(testfile,
535982ae832Sthorpej O_RDWR | O_CREAT | O_TRUNC, 0600)) != -1);
536982ae832Sthorpej EV_SET(&event[0], fd, EVFILT_VNODE, EV_ADD | EV_CLEAR,
537982ae832Sthorpej NOTE_OPEN | NOTE_READ | NOTE_WRITE |
538982ae832Sthorpej NOTE_CLOSE | NOTE_CLOSE_WRITE, 0, NULL);
539982ae832Sthorpej ATF_REQUIRE(kevent(kq, event, 1, NULL, 0, NULL) == 0);
540982ae832Sthorpej
541982ae832Sthorpej /*
542982ae832Sthorpej * Open the file for writing, check for NOTE_OPEN.
543982ae832Sthorpej * Write to the file, check for NOTE_WRITE | NOTE_EXTEND.
544982ae832Sthorpej * Re-write the file, check for NOTE_WRITE and !NOTE_EXTEND.
545982ae832Sthorpej * Write one additional byte, check for NOTE_WRITE | NOTE_EXTEND.
546982ae832Sthorpej * Close the file, check for NOTE_CLOSE_WRITE.
547982ae832Sthorpej */
548982ae832Sthorpej ATF_REQUIRE((fd = open(testfile, O_RDWR)) != -1);
549982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
550982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_OPEN);
551982ae832Sthorpej
552982ae832Sthorpej ATF_REQUIRE((pwrite(fd, testfile,
553982ae832Sthorpej sizeof(testfile), 0)) == sizeof(testfile));
554982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
555982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_WRITE);
556982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_EXTEND);
557982ae832Sthorpej
558982ae832Sthorpej ATF_REQUIRE((pwrite(fd, testfile,
559982ae832Sthorpej sizeof(testfile), 0)) == sizeof(testfile));
560982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
561982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_WRITE);
562982ae832Sthorpej ATF_REQUIRE((event[0].fflags & NOTE_EXTEND) == 0);
563982ae832Sthorpej
564982ae832Sthorpej ATF_REQUIRE((pwrite(fd, testfile,
565982ae832Sthorpej 1, sizeof(testfile))) == 1);
566982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
567982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_WRITE);
568982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_EXTEND);
569982ae832Sthorpej
570982ae832Sthorpej (void)close(fd);
571982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
572982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_CLOSE_WRITE);
573982ae832Sthorpej ATF_REQUIRE((event[0].fflags & NOTE_CLOSE) == 0);
574982ae832Sthorpej
575982ae832Sthorpej /*
576982ae832Sthorpej * Open the file for reading, check for NOTE_OPEN.
577982ae832Sthorpej * Read from the file, check for NOTE_READ.
578982ae832Sthorpej * Close the file., check for NOTE_CLOSE.
579982ae832Sthorpej */
580982ae832Sthorpej ATF_REQUIRE((fd = open(testfile, O_RDONLY)) != -1);
581982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
582982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_OPEN);
583982ae832Sthorpej
584982ae832Sthorpej ATF_REQUIRE((read(fd, buf, sizeof(buf))) == sizeof(buf));
585982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
586982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_READ);
587982ae832Sthorpej
588982ae832Sthorpej (void)close(fd);
589982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
590982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_CLOSE);
591982ae832Sthorpej ATF_REQUIRE((event[0].fflags & NOTE_CLOSE_WRITE) == 0);
592982ae832Sthorpej }
ATF_TC_CLEANUP(open_write_read_close,tc)593982ae832Sthorpej ATF_TC_CLEANUP(open_write_read_close, tc)
594982ae832Sthorpej {
595982ae832Sthorpej (void)unlink(testfile);
596982ae832Sthorpej }
597982ae832Sthorpej
598982ae832Sthorpej ATF_TC_WITH_CLEANUP(interest);
ATF_TC_HEAD(interest,tc)599982ae832Sthorpej ATF_TC_HEAD(interest, tc)
600982ae832Sthorpej {
601982ae832Sthorpej atf_tc_set_md_var(tc, "descr", "This test case exercises "
602982ae832Sthorpej "the kernel code that computes vnode kevent interest");
603982ae832Sthorpej }
ATF_TC_BODY(interest,tc)604982ae832Sthorpej ATF_TC_BODY(interest, tc)
605982ae832Sthorpej {
606982ae832Sthorpej struct kevent event[3];
607982ae832Sthorpej int open_ev_fd, write_ev_fd, close_ev_fd;
608982ae832Sthorpej int fd;
609982ae832Sthorpej
610982ae832Sthorpej /*
611982ae832Sthorpej * This test cases exercises some implementation details
612982ae832Sthorpej * regarding how "kevent interest" is computed for a vnode.
613982ae832Sthorpej *
614982ae832Sthorpej * We are going to add events, one at a time, in a specific
615982ae832Sthorpej * order, and then remove one of them, with the knowledge that
616982ae832Sthorpej * a specific code path in vfs_vnops.c:vn_knote_detach() will
617982ae832Sthorpej * be taken. There are several KASSERT()s in this code path
618982ae832Sthorpej * that will be validated.
619982ae832Sthorpej *
620982ae832Sthorpej * In order to ensure distinct knotes are attached to the vnodes,
621982ae832Sthorpej * we must use a different file descriptor to register interest
622982ae832Sthorpej * in each kind of event.
623982ae832Sthorpej */
624982ae832Sthorpej
625982ae832Sthorpej ATF_REQUIRE((kq = kqueue()) != -1);
626982ae832Sthorpej
627982ae832Sthorpej /*
628982ae832Sthorpej * Create the test file and register an event on it. We need
629982ae832Sthorpej * to keep the fd open to keep receiving events, so we'll just
630982ae832Sthorpej * leak it and re-use the fd variable.
631982ae832Sthorpej */
632982ae832Sthorpej ATF_REQUIRE((open_ev_fd = open(testfile,
633982ae832Sthorpej O_RDWR | O_CREAT | O_TRUNC, 0600)) != -1);
634982ae832Sthorpej ATF_REQUIRE((write_ev_fd = dup(open_ev_fd)) != -1);
635982ae832Sthorpej ATF_REQUIRE((close_ev_fd = dup(open_ev_fd)) != -1);
636982ae832Sthorpej
637982ae832Sthorpej EV_SET(&event[0], open_ev_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR,
638982ae832Sthorpej NOTE_OPEN, 0, NULL);
639982ae832Sthorpej EV_SET(&event[1], write_ev_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR,
640982ae832Sthorpej NOTE_WRITE, 0, NULL);
641982ae832Sthorpej EV_SET(&event[2], close_ev_fd, EVFILT_VNODE, EV_ADD | EV_CLEAR,
642982ae832Sthorpej NOTE_CLOSE | NOTE_CLOSE_WRITE, 0, NULL);
643982ae832Sthorpej ATF_REQUIRE(kevent(kq, event, 3, NULL, 0, NULL) == 0);
644982ae832Sthorpej
645982ae832Sthorpej /*
646982ae832Sthorpej * The testfile vnode now has 3 knotes attached, in "LIFO"
647982ae832Sthorpej * order:
648982ae832Sthorpej *
649982ae832Sthorpej * NOTE_CLOSE -> NOTE_WRITE -> NOTE_OPEN
650982ae832Sthorpej *
651982ae832Sthorpej * We will now remove the NOTE_WRITE knote.
652982ae832Sthorpej */
653982ae832Sthorpej (void)close(write_ev_fd);
654982ae832Sthorpej
655982ae832Sthorpej ATF_REQUIRE((fd = open(testfile, O_RDWR)) != -1);
656982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
657982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_OPEN);
658982ae832Sthorpej
659982ae832Sthorpej ATF_REQUIRE((pwrite(fd, testfile,
660982ae832Sthorpej sizeof(testfile), 0)) == sizeof(testfile));
661982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 0);
662982ae832Sthorpej
663982ae832Sthorpej (void)close(fd);
664982ae832Sthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
665982ae832Sthorpej ATF_REQUIRE(event[0].fflags & NOTE_CLOSE_WRITE);
666982ae832Sthorpej ATF_REQUIRE((event[0].fflags & NOTE_CLOSE) == 0);
667982ae832Sthorpej
668982ae832Sthorpej }
ATF_TC_CLEANUP(interest,tc)669982ae832Sthorpej ATF_TC_CLEANUP(interest, tc)
670982ae832Sthorpej {
671982ae832Sthorpej (void)unlink(testfile);
672982ae832Sthorpej }
673982ae832Sthorpej
674*c1cb8abdSthorpej ATF_TC_WITH_CLEANUP(rename_over_self_hardlink);
ATF_TC_HEAD(rename_over_self_hardlink,tc)675*c1cb8abdSthorpej ATF_TC_HEAD(rename_over_self_hardlink, tc)
676*c1cb8abdSthorpej {
677*c1cb8abdSthorpej atf_tc_set_md_var(tc, "descr", "This test case tests "
678*c1cb8abdSthorpej "renaming a file over a hard-link to itself");
679*c1cb8abdSthorpej }
ATF_TC_BODY(rename_over_self_hardlink,tc)680*c1cb8abdSthorpej ATF_TC_BODY(rename_over_self_hardlink, tc)
681*c1cb8abdSthorpej {
682*c1cb8abdSthorpej struct kevent event[2], *dir_ev, *file_ev;
683*c1cb8abdSthorpej int dir_fd, file_fd;
684*c1cb8abdSthorpej
685*c1cb8abdSthorpej ATF_REQUIRE((kq = kqueue()) != -1);
686*c1cb8abdSthorpej
687*c1cb8abdSthorpej ATF_REQUIRE((mkdir(dir_target, 0700)) == 0);
688*c1cb8abdSthorpej ATF_REQUIRE((dir_fd = open(dir_target, O_RDONLY)) != -1);
689*c1cb8abdSthorpej
690*c1cb8abdSthorpej ATF_REQUIRE((file_fd = open(file_inside1, O_RDONLY | O_CREAT,
691*c1cb8abdSthorpej 0600)) != -1);
692*c1cb8abdSthorpej ATF_REQUIRE(link(file_inside1, file_inside2) == 0);
693*c1cb8abdSthorpej
694*c1cb8abdSthorpej EV_SET(&event[0], dir_fd, EVFILT_VNODE, EV_ADD,
695*c1cb8abdSthorpej NOTE_WRITE | NOTE_EXTEND | NOTE_LINK, 0, NULL);
696*c1cb8abdSthorpej EV_SET(&event[1], file_fd, EVFILT_VNODE, EV_ADD,
697*c1cb8abdSthorpej NOTE_LINK | NOTE_DELETE, 0, NULL);
698*c1cb8abdSthorpej ATF_REQUIRE(kevent(kq, event, 2, NULL, 0, NULL) == 0);
699*c1cb8abdSthorpej
700*c1cb8abdSthorpej ATF_REQUIRE(rename(file_inside1, file_inside2) == 0);
701*c1cb8abdSthorpej
702*c1cb8abdSthorpej ATF_REQUIRE(kevent(kq, NULL, 0, event, 2, &ts) == 2);
703*c1cb8abdSthorpej ATF_REQUIRE(event[0].ident == (uintptr_t)dir_fd ||
704*c1cb8abdSthorpej event[0].ident == (uintptr_t)file_fd);
705*c1cb8abdSthorpej ATF_REQUIRE(event[1].ident == (uintptr_t)dir_fd ||
706*c1cb8abdSthorpej event[1].ident == (uintptr_t)file_fd);
707*c1cb8abdSthorpej if (event[0].ident == (uintptr_t)dir_fd) {
708*c1cb8abdSthorpej dir_ev = &event[0];
709*c1cb8abdSthorpej file_ev = &event[1];
710*c1cb8abdSthorpej } else {
711*c1cb8abdSthorpej dir_ev = &event[1];
712*c1cb8abdSthorpej file_ev = &event[0];
713*c1cb8abdSthorpej }
714*c1cb8abdSthorpej ATF_REQUIRE(dir_ev->fflags == NOTE_WRITE);
715*c1cb8abdSthorpej ATF_REQUIRE(file_ev->fflags == NOTE_LINK);
716*c1cb8abdSthorpej }
ATF_TC_CLEANUP(rename_over_self_hardlink,tc)717*c1cb8abdSthorpej ATF_TC_CLEANUP(rename_over_self_hardlink, tc)
718*c1cb8abdSthorpej {
719*c1cb8abdSthorpej cleanup();
720*c1cb8abdSthorpej }
721982ae832Sthorpej
ATF_TP_ADD_TCS(tp)722f7afbc7fSchristos ATF_TP_ADD_TCS(tp)
723f7afbc7fSchristos {
724f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_no_note_link_create_file_in);
725f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_no_note_link_delete_file_in);
726982ae832Sthorpej
727f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_no_note_link_mv_dir_within);
728f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_no_note_link_mv_file_within);
729982ae832Sthorpej
730f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_link_create_dir_in);
731f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_link_delete_dir_in);
732982ae832Sthorpej
733f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_link_mv_dir_in);
734f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_link_mv_dir_out);
735982ae832Sthorpej
736f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_create_dir_in);
737f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_create_file_in);
738982ae832Sthorpej
739f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_delete_dir_in);
740f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_delete_file_in);
741982ae832Sthorpej
742f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_in);
743f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_out);
744f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_within);
745f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_mv_file_in);
746f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_mv_file_out);
747f7afbc7fSchristos ATF_TP_ADD_TC(tp, dir_note_write_mv_file_within);
748982ae832Sthorpej
749*c1cb8abdSthorpej ATF_TP_ADD_TC(tp, rename_over_self_hardlink);
750*c1cb8abdSthorpej
751982ae832Sthorpej ATF_TP_ADD_TC(tp, open_write_read_close);
752982ae832Sthorpej ATF_TP_ADD_TC(tp, interest);
753982ae832Sthorpej
754f7afbc7fSchristos return atf_no_error();
755f7afbc7fSchristos }
756