1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2020 CTERA Networks. All Rights Reserved.
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci * Started by Amir Goldstein <amir73il@gmail.com>
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci/*\
9f08c3bdfSopenharmony_ci * [Description]
10f08c3bdfSopenharmony_ci * Check fanotify directory entry modification events, events on child and
11f08c3bdfSopenharmony_ci * on self with group init flags:
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * - FAN_REPORT_DFID_NAME (dir fid + name)
14f08c3bdfSopenharmony_ci * - FAN_REPORT_DIR_FID   (dir fid)
15f08c3bdfSopenharmony_ci * - FAN_REPORT_DIR_FID | FAN_REPORT_FID   (dir fid + child fid)
16f08c3bdfSopenharmony_ci * - FAN_REPORT_DFID_NAME | FAN_REPORT_FID (dir fid + name + child fid)
17f08c3bdfSopenharmony_ci * - FAN_REPORT_DFID_NAME_TARGET (dir fid + name + created/deleted file fid)
18f08c3bdfSopenharmony_ci */
19f08c3bdfSopenharmony_ci
20f08c3bdfSopenharmony_ci#define _GNU_SOURCE
21f08c3bdfSopenharmony_ci#include "config.h"
22f08c3bdfSopenharmony_ci
23f08c3bdfSopenharmony_ci#include <stdio.h>
24f08c3bdfSopenharmony_ci#include <sys/stat.h>
25f08c3bdfSopenharmony_ci#include <sys/types.h>
26f08c3bdfSopenharmony_ci#include <errno.h>
27f08c3bdfSopenharmony_ci#include <string.h>
28f08c3bdfSopenharmony_ci#include <sys/mount.h>
29f08c3bdfSopenharmony_ci#include <sys/syscall.h>
30f08c3bdfSopenharmony_ci#include "tst_test.h"
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H
33f08c3bdfSopenharmony_ci#include "fanotify.h"
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_ci#define EVENT_MAX 20
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci/* Size of the event structure, not including file handle */
38f08c3bdfSopenharmony_ci#define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \
39f08c3bdfSopenharmony_ci		    sizeof(struct fanotify_event_info_fid))
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci/* Tripple events buffer size to account for file handles and names */
42f08c3bdfSopenharmony_ci#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 3)
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci#define BUF_SIZE 256
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci#ifdef HAVE_NAME_TO_HANDLE_AT
47f08c3bdfSopenharmony_cistruct event_t {
48f08c3bdfSopenharmony_ci	unsigned long long mask;
49f08c3bdfSopenharmony_ci	struct fanotify_fid_t *fid;
50f08c3bdfSopenharmony_ci	struct fanotify_fid_t *child_fid;
51f08c3bdfSopenharmony_ci	char name[BUF_SIZE];
52f08c3bdfSopenharmony_ci	char name2[BUF_SIZE];
53f08c3bdfSopenharmony_ci	char *old_name;
54f08c3bdfSopenharmony_ci	char *new_name;
55f08c3bdfSopenharmony_ci};
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_cistatic char fname1[BUF_SIZE + 11], fname2[BUF_SIZE + 11];
58f08c3bdfSopenharmony_cistatic char dname1[BUF_SIZE], dname2[BUF_SIZE], tmpdir[BUF_SIZE];
59f08c3bdfSopenharmony_cistatic int fd_notify;
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_cistatic struct event_t event_set[EVENT_MAX];
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_cistatic char event_buf[EVENT_BUF_LEN];
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci#define DIR_NAME1 "test_dir1"
66f08c3bdfSopenharmony_ci#define DIR_NAME2 "test_dir2"
67f08c3bdfSopenharmony_ci#define FILE_NAME1 "test_file1"
68f08c3bdfSopenharmony_ci#define FILE_NAME2 "test_file2"
69f08c3bdfSopenharmony_ci#define MOUNT_PATH "fs_mnt"
70f08c3bdfSopenharmony_ci#define TEMP_DIR MOUNT_PATH "/temp_dir"
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_cistatic int fan_report_target_fid_unsupported;
73f08c3bdfSopenharmony_cistatic int rename_events_unsupported;
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_cistatic struct test_case_t {
76f08c3bdfSopenharmony_ci	const char *tname;
77f08c3bdfSopenharmony_ci	struct fanotify_group_type group;
78f08c3bdfSopenharmony_ci	struct fanotify_mark_type mark;
79f08c3bdfSopenharmony_ci	unsigned long mask;
80f08c3bdfSopenharmony_ci	struct fanotify_mark_type sub_mark;
81f08c3bdfSopenharmony_ci	unsigned long sub_mask;
82f08c3bdfSopenharmony_ci	unsigned long tmpdir_ignored_mask;
83f08c3bdfSopenharmony_ci} test_cases[] = {
84f08c3bdfSopenharmony_ci	{
85f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME monitor filesystem for create/delete/move/open/close",
86f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
87f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
88f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
89f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
90f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
91f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
92f08c3bdfSopenharmony_ci		0,
93f08c3bdfSopenharmony_ci	},
94f08c3bdfSopenharmony_ci	{
95f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME monitor directories for create/delete/move/open/close",
96f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
97f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
98f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
99f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
100f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
101f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
102f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
103f08c3bdfSopenharmony_ci		0,
104f08c3bdfSopenharmony_ci	},
105f08c3bdfSopenharmony_ci	{
106f08c3bdfSopenharmony_ci		"FAN_REPORT_DIR_FID monitor filesystem for create/delete/move/open/close",
107f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
108f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
109f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
110f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
111f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
112f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
113f08c3bdfSopenharmony_ci		0,
114f08c3bdfSopenharmony_ci	},
115f08c3bdfSopenharmony_ci	{
116f08c3bdfSopenharmony_ci		"FAN_REPORT_DIR_FID monitor directories for create/delete/move/open/close",
117f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
118f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
119f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
120f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
121f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
122f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
123f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
124f08c3bdfSopenharmony_ci		0,
125f08c3bdfSopenharmony_ci	},
126f08c3bdfSopenharmony_ci	{
127f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_FID monitor filesystem for create/delete/move/open/close",
128f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
129f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
130f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
131f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
132f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
133f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
134f08c3bdfSopenharmony_ci		0,
135f08c3bdfSopenharmony_ci	},
136f08c3bdfSopenharmony_ci	{
137f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_FID monitor directories for create/delete/move/open/close",
138f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
139f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
140f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
141f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
142f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
143f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
144f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
145f08c3bdfSopenharmony_ci		0,
146f08c3bdfSopenharmony_ci	},
147f08c3bdfSopenharmony_ci	{
148f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/open/close",
149f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
150f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
151f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
152f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
153f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
154f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
155f08c3bdfSopenharmony_ci		0,
156f08c3bdfSopenharmony_ci	},
157f08c3bdfSopenharmony_ci	{
158f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/open/close",
159f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
160f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
161f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
162f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
163f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
164f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
165f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
166f08c3bdfSopenharmony_ci		0,
167f08c3bdfSopenharmony_ci	},
168f08c3bdfSopenharmony_ci	{
169f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/open/close",
170f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
171f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
172f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
173f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
174f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
175f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
176f08c3bdfSopenharmony_ci		0,
177f08c3bdfSopenharmony_ci	},
178f08c3bdfSopenharmony_ci	{
179f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/open/close",
180f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
181f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
182f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
183f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
184f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
185f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
186f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
187f08c3bdfSopenharmony_ci		0,
188f08c3bdfSopenharmony_ci	},
189f08c3bdfSopenharmony_ci	{
190f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/rename/open/close",
191f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
192f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
193f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
194f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
195f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
196f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
197f08c3bdfSopenharmony_ci		0,
198f08c3bdfSopenharmony_ci	},
199f08c3bdfSopenharmony_ci	{
200f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/rename/open/close",
201f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
202f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
203f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
204f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
205f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
206f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
207f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
208f08c3bdfSopenharmony_ci		0,
209f08c3bdfSopenharmony_ci	},
210f08c3bdfSopenharmony_ci	{
211f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/rename/open/close",
212f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
213f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
214f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
215f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
216f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
217f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
218f08c3bdfSopenharmony_ci		0,
219f08c3bdfSopenharmony_ci	},
220f08c3bdfSopenharmony_ci	{
221f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/rename/open/close",
222f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
223f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
224f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
225f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
226f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
227f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
228f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
229f08c3bdfSopenharmony_ci		0,
230f08c3bdfSopenharmony_ci	},
231f08c3bdfSopenharmony_ci	{
232f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_FID monitor directories and ignore FAN_RENAME events to/from temp directory",
233f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
234f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
235f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
236f08c3bdfSopenharmony_ci		/* Watches for self events on subdir and events on subdir's children */
237f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(INODE),
238f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
239f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
240f08c3bdfSopenharmony_ci		/* Ignore FAN_RENAME to/from tmpdir */
241f08c3bdfSopenharmony_ci		FAN_MOVE | FAN_RENAME,
242f08c3bdfSopenharmony_ci	},
243f08c3bdfSopenharmony_ci	{
244f08c3bdfSopenharmony_ci		"FAN_REPORT_DFID_NAME_FID monitor filesystem and ignore FAN_RENAME events to/from temp directory",
245f08c3bdfSopenharmony_ci		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
246f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
247f08c3bdfSopenharmony_ci		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
248f08c3bdfSopenharmony_ci		/* Mount watch for events possible on children */
249f08c3bdfSopenharmony_ci		INIT_FANOTIFY_MARK_TYPE(MOUNT),
250f08c3bdfSopenharmony_ci		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
251f08c3bdfSopenharmony_ci		/* Ignore FAN_RENAME to/from tmpdir */
252f08c3bdfSopenharmony_ci		FAN_MOVE | FAN_RENAME,
253f08c3bdfSopenharmony_ci	},
254f08c3bdfSopenharmony_ci};
255f08c3bdfSopenharmony_ci
256f08c3bdfSopenharmony_cistatic void do_test(unsigned int number)
257f08c3bdfSopenharmony_ci{
258f08c3bdfSopenharmony_ci	int fd, dirfd, len = 0, i = 0, test_num = 0, tst_count = 0;
259f08c3bdfSopenharmony_ci	struct test_case_t *tc = &test_cases[number];
260f08c3bdfSopenharmony_ci	struct fanotify_group_type *group = &tc->group;
261f08c3bdfSopenharmony_ci	struct fanotify_mark_type *mark = &tc->mark;
262f08c3bdfSopenharmony_ci	struct fanotify_mark_type *sub_mark = &tc->sub_mark;
263f08c3bdfSopenharmony_ci	struct fanotify_fid_t root_fid, dir_fid, file_fid;
264f08c3bdfSopenharmony_ci	struct fanotify_fid_t *child_fid = NULL, *subdir_fid = NULL;
265f08c3bdfSopenharmony_ci	int report_name = (group->flag & FAN_REPORT_NAME);
266f08c3bdfSopenharmony_ci	int report_target_fid = (group->flag & FAN_REPORT_TARGET_FID);
267f08c3bdfSopenharmony_ci	int report_rename = (tc->mask & FAN_RENAME);
268f08c3bdfSopenharmony_ci	int fs_mark = (mark->flag == FAN_MARK_FILESYSTEM);
269f08c3bdfSopenharmony_ci	int rename_ignored = (tc->tmpdir_ignored_mask & FAN_RENAME);
270f08c3bdfSopenharmony_ci
271f08c3bdfSopenharmony_ci	tst_res(TINFO, "Test #%d: %s", number, tc->tname);
272f08c3bdfSopenharmony_ci
273f08c3bdfSopenharmony_ci	if (report_rename && rename_events_unsupported) {
274f08c3bdfSopenharmony_ci		tst_res(TCONF, "FAN_RENAME not supported in kernel?");
275f08c3bdfSopenharmony_ci		return;
276f08c3bdfSopenharmony_ci	}
277f08c3bdfSopenharmony_ci
278f08c3bdfSopenharmony_ci	if (fan_report_target_fid_unsupported && report_target_fid) {
279f08c3bdfSopenharmony_ci		FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID,
280f08c3bdfSopenharmony_ci					    fan_report_target_fid_unsupported);
281f08c3bdfSopenharmony_ci		return;
282f08c3bdfSopenharmony_ci	}
283f08c3bdfSopenharmony_ci
284f08c3bdfSopenharmony_ci	fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0);
285f08c3bdfSopenharmony_ci
286f08c3bdfSopenharmony_ci	/*
287f08c3bdfSopenharmony_ci	 * Watch dir modify events with name in filesystem/dir
288f08c3bdfSopenharmony_ci	 */
289f08c3bdfSopenharmony_ci	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag, tc->mask,
290f08c3bdfSopenharmony_ci			   AT_FDCWD, MOUNT_PATH);
291f08c3bdfSopenharmony_ci
292f08c3bdfSopenharmony_ci	/* Save the mount root fid */
293f08c3bdfSopenharmony_ci	fanotify_save_fid(MOUNT_PATH, &root_fid);
294f08c3bdfSopenharmony_ci
295f08c3bdfSopenharmony_ci	/*
296f08c3bdfSopenharmony_ci	 * Create subdir and watch open events "on children" with name.
297f08c3bdfSopenharmony_ci	 * Make it a mount root.
298f08c3bdfSopenharmony_ci	 */
299f08c3bdfSopenharmony_ci	SAFE_MKDIR(dname1, 0755);
300f08c3bdfSopenharmony_ci	SAFE_MOUNT(dname1, dname1, "none", MS_BIND, NULL);
301f08c3bdfSopenharmony_ci
302f08c3bdfSopenharmony_ci	/* Save the subdir fid */
303f08c3bdfSopenharmony_ci	fanotify_save_fid(dname1, &dir_fid);
304f08c3bdfSopenharmony_ci	/* With FAN_REPORT_TARGET_FID, report subdir fid also for dirent events */
305f08c3bdfSopenharmony_ci	if (report_target_fid)
306f08c3bdfSopenharmony_ci		subdir_fid = &dir_fid;
307f08c3bdfSopenharmony_ci
308f08c3bdfSopenharmony_ci	if (tc->sub_mask)
309f08c3bdfSopenharmony_ci		SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | sub_mark->flag,
310f08c3bdfSopenharmony_ci				   tc->sub_mask, AT_FDCWD, dname1);
311f08c3bdfSopenharmony_ci	/*
312f08c3bdfSopenharmony_ci	 * ignore FAN_RENAME to/from tmpdir, so we won't get the FAN_RENAME events
313f08c3bdfSopenharmony_ci	 * when subdir is moved via tmpdir.
314f08c3bdfSopenharmony_ci	 * FAN_MOVE is also set in ignored mark of tmpdir, but it will have no effect
315f08c3bdfSopenharmony_ci	 * and the MOVED_FROM/TO events will still be reported.
316f08c3bdfSopenharmony_ci	 */
317f08c3bdfSopenharmony_ci	if (tc->tmpdir_ignored_mask)
318f08c3bdfSopenharmony_ci		SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD |
319f08c3bdfSopenharmony_ci				   FAN_MARK_IGNORED_MASK |
320f08c3bdfSopenharmony_ci				   FAN_MARK_IGNORED_SURV_MODIFY,
321f08c3bdfSopenharmony_ci				   tc->tmpdir_ignored_mask, AT_FDCWD, TEMP_DIR);
322f08c3bdfSopenharmony_ci
323f08c3bdfSopenharmony_ci	memset(event_set, 0, sizeof(event_set));
324f08c3bdfSopenharmony_ci	event_set[tst_count].mask = FAN_CREATE | FAN_ONDIR;
325f08c3bdfSopenharmony_ci	event_set[tst_count].fid = &root_fid;
326f08c3bdfSopenharmony_ci	event_set[tst_count].child_fid = subdir_fid;
327f08c3bdfSopenharmony_ci	strcpy(event_set[tst_count].name, DIR_NAME1);
328f08c3bdfSopenharmony_ci	tst_count++;
329f08c3bdfSopenharmony_ci
330f08c3bdfSopenharmony_ci	/* Generate modify events "on child" */
331f08c3bdfSopenharmony_ci	fd = SAFE_CREAT(fname1, 0755);
332f08c3bdfSopenharmony_ci
333f08c3bdfSopenharmony_ci	/* Save the file fid */
334f08c3bdfSopenharmony_ci	fanotify_save_fid(fname1, &file_fid);
335f08c3bdfSopenharmony_ci	/* With FAN_REPORT_TARGET_FID, report child fid also for dirent events */
336f08c3bdfSopenharmony_ci	if (report_target_fid)
337f08c3bdfSopenharmony_ci		child_fid = &file_fid;
338f08c3bdfSopenharmony_ci
339f08c3bdfSopenharmony_ci	SAFE_WRITE(SAFE_WRITE_ALL, fd, "1", 1);
340f08c3bdfSopenharmony_ci	SAFE_RENAME(fname1, fname2);
341f08c3bdfSopenharmony_ci
342f08c3bdfSopenharmony_ci	SAFE_CLOSE(fd);
343f08c3bdfSopenharmony_ci
344f08c3bdfSopenharmony_ci	/* Generate delete events with fname2 */
345f08c3bdfSopenharmony_ci	SAFE_UNLINK(fname2);
346f08c3bdfSopenharmony_ci
347f08c3bdfSopenharmony_ci	/* Read events on files in subdir */
348f08c3bdfSopenharmony_ci	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
349f08c3bdfSopenharmony_ci
350f08c3bdfSopenharmony_ci	/*
351f08c3bdfSopenharmony_ci	 * FAN_CREATE|FAN_DELETE|FAN_MOVE events with the same name are merged.
352f08c3bdfSopenharmony_ci	 */
353f08c3bdfSopenharmony_ci	event_set[tst_count].mask = FAN_CREATE | FAN_MOVED_FROM;
354f08c3bdfSopenharmony_ci	event_set[tst_count].fid = &dir_fid;
355f08c3bdfSopenharmony_ci	event_set[tst_count].child_fid = child_fid;
356f08c3bdfSopenharmony_ci	strcpy(event_set[tst_count].name, FILE_NAME1);
357f08c3bdfSopenharmony_ci	tst_count++;
358f08c3bdfSopenharmony_ci	/*
359f08c3bdfSopenharmony_ci	 * Event on non-dir child with the same name may be merged with the
360f08c3bdfSopenharmony_ci	 * directory entry modification events above, unless FAN_REPORT_FID is
361f08c3bdfSopenharmony_ci	 * set and child fid is reported. If FAN_REPORT_FID is set but
362f08c3bdfSopenharmony_ci	 * FAN_REPORT_NAME is not set, then FAN_CREATE above is merged with
363f08c3bdfSopenharmony_ci	 * FAN_DELETE below and FAN_OPEN will be merged with FAN_CLOSE.
364f08c3bdfSopenharmony_ci	 */
365f08c3bdfSopenharmony_ci	if (report_name) {
366f08c3bdfSopenharmony_ci		event_set[tst_count].mask = FAN_OPEN;
367f08c3bdfSopenharmony_ci		event_set[tst_count].fid = &dir_fid;
368f08c3bdfSopenharmony_ci		event_set[tst_count].child_fid = &file_fid;
369f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name, FILE_NAME1);
370f08c3bdfSopenharmony_ci		tst_count++;
371f08c3bdfSopenharmony_ci	}
372f08c3bdfSopenharmony_ci	/*
373f08c3bdfSopenharmony_ci	 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged
374f08c3bdfSopenharmony_ci	 * with any other event because it has different info records.
375f08c3bdfSopenharmony_ci	 */
376f08c3bdfSopenharmony_ci	if (report_rename) {
377f08c3bdfSopenharmony_ci		event_set[tst_count].mask = FAN_RENAME;
378f08c3bdfSopenharmony_ci		event_set[tst_count].fid = &dir_fid;
379f08c3bdfSopenharmony_ci		event_set[tst_count].child_fid = child_fid;
380f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name, FILE_NAME1);
381f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name2, FILE_NAME2);
382f08c3bdfSopenharmony_ci		event_set[tst_count].old_name = event_set[tst_count].name;
383f08c3bdfSopenharmony_ci		event_set[tst_count].new_name = event_set[tst_count].name2;
384f08c3bdfSopenharmony_ci		tst_count++;
385f08c3bdfSopenharmony_ci	}
386f08c3bdfSopenharmony_ci
387f08c3bdfSopenharmony_ci	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO;
388f08c3bdfSopenharmony_ci	/*
389f08c3bdfSopenharmony_ci	 * With FAN_REPORT_TARGET_FID, close of FILE_NAME2 is merged with
390f08c3bdfSopenharmony_ci	 * moved_to and delete events, because they all have parent and
391f08c3bdfSopenharmony_ci	 * child fid records.
392f08c3bdfSopenharmony_ci	 */
393f08c3bdfSopenharmony_ci	if (report_target_fid)
394f08c3bdfSopenharmony_ci		event_set[tst_count].mask |= FAN_CLOSE_WRITE;
395f08c3bdfSopenharmony_ci	event_set[tst_count].fid = &dir_fid;
396f08c3bdfSopenharmony_ci	event_set[tst_count].child_fid = child_fid;
397f08c3bdfSopenharmony_ci	strcpy(event_set[tst_count].name, FILE_NAME2);
398f08c3bdfSopenharmony_ci	tst_count++;
399f08c3bdfSopenharmony_ci	/*
400f08c3bdfSopenharmony_ci	 * When not reporting name, open of FILE_NAME1 is merged
401f08c3bdfSopenharmony_ci	 * with close of FILE_NAME2.
402f08c3bdfSopenharmony_ci	 */
403f08c3bdfSopenharmony_ci	if (!report_name) {
404f08c3bdfSopenharmony_ci		event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_WRITE;
405f08c3bdfSopenharmony_ci		event_set[tst_count].fid = &dir_fid;
406f08c3bdfSopenharmony_ci		event_set[tst_count].child_fid = &file_fid;
407f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name, "");
408f08c3bdfSopenharmony_ci		tst_count++;
409f08c3bdfSopenharmony_ci	}
410f08c3bdfSopenharmony_ci	/*
411f08c3bdfSopenharmony_ci	 * Directory watch does not get self events on children.
412f08c3bdfSopenharmony_ci	 * Filesystem watch gets self event w/o name info if FAN_REPORT_FID
413f08c3bdfSopenharmony_ci	 * is set.
414f08c3bdfSopenharmony_ci	 */
415f08c3bdfSopenharmony_ci	if (fs_mark && (group->flag & FAN_REPORT_FID)) {
416f08c3bdfSopenharmony_ci		event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF;
417f08c3bdfSopenharmony_ci		event_set[tst_count].fid = &file_fid;
418f08c3bdfSopenharmony_ci		event_set[tst_count].child_fid = NULL;
419f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name, "");
420f08c3bdfSopenharmony_ci		tst_count++;
421f08c3bdfSopenharmony_ci	}
422f08c3bdfSopenharmony_ci	/*
423f08c3bdfSopenharmony_ci	 * Without FAN_REPORT_TARGET_FID, close of FILE_NAME2 is not merged with
424f08c3bdfSopenharmony_ci	 * open of FILE_NAME1 and it is received after the merged self events.
425f08c3bdfSopenharmony_ci	 */
426f08c3bdfSopenharmony_ci	if (report_name && !report_target_fid) {
427f08c3bdfSopenharmony_ci		event_set[tst_count].mask = FAN_CLOSE_WRITE;
428f08c3bdfSopenharmony_ci		event_set[tst_count].fid = &dir_fid;
429f08c3bdfSopenharmony_ci		event_set[tst_count].child_fid = &file_fid;
430f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name, FILE_NAME2);
431f08c3bdfSopenharmony_ci		tst_count++;
432f08c3bdfSopenharmony_ci	}
433f08c3bdfSopenharmony_ci
434f08c3bdfSopenharmony_ci	dirfd = SAFE_OPEN(dname1, O_RDONLY | O_DIRECTORY);
435f08c3bdfSopenharmony_ci	SAFE_CLOSE(dirfd);
436f08c3bdfSopenharmony_ci
437f08c3bdfSopenharmony_ci	SAFE_UMOUNT(dname1);
438f08c3bdfSopenharmony_ci
439f08c3bdfSopenharmony_ci	/*
440f08c3bdfSopenharmony_ci	 * Directory watch gets open/close events on itself and on its subdirs.
441f08c3bdfSopenharmony_ci	 * Filesystem watch gets open/close event on all directories with name ".".
442f08c3bdfSopenharmony_ci	 */
443f08c3bdfSopenharmony_ci	event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR;
444f08c3bdfSopenharmony_ci	event_set[tst_count].fid = &dir_fid;
445f08c3bdfSopenharmony_ci	event_set[tst_count].child_fid = NULL;
446f08c3bdfSopenharmony_ci	strcpy(event_set[tst_count].name, ".");
447f08c3bdfSopenharmony_ci	tst_count++;
448f08c3bdfSopenharmony_ci	/*
449f08c3bdfSopenharmony_ci	 * Directory watch gets self event on itself and filesystem watch gets
450f08c3bdfSopenharmony_ci	 * self event on all directories with name ".".
451f08c3bdfSopenharmony_ci	 */
452f08c3bdfSopenharmony_ci	event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR;
453f08c3bdfSopenharmony_ci	event_set[tst_count].fid = &dir_fid;
454f08c3bdfSopenharmony_ci	event_set[tst_count].child_fid = NULL;
455f08c3bdfSopenharmony_ci	strcpy(event_set[tst_count].name, ".");
456f08c3bdfSopenharmony_ci	tst_count++;
457f08c3bdfSopenharmony_ci
458f08c3bdfSopenharmony_ci	/*
459f08c3bdfSopenharmony_ci	 * If only root dir and subdir are watched, a rename via an unwatched tmpdir
460f08c3bdfSopenharmony_ci	 * will observe the same MOVED_FROM/MOVED_TO events as a direct rename,
461f08c3bdfSopenharmony_ci	 * but will observe 2 FAN_RENAME events with 1 info dir+name record each
462f08c3bdfSopenharmony_ci	 * instead of 1 FAN_RENAME event with 2 dir+name info records.
463f08c3bdfSopenharmony_ci	 *
464f08c3bdfSopenharmony_ci	 * If tmpdir is ignoring FAN_RENAME, we will get the MOVED_FROM/MOVED_TO
465f08c3bdfSopenharmony_ci	 * events and will not get the FAN_RENAME event for rename via tmpdir.
466f08c3bdfSopenharmony_ci	 */
467f08c3bdfSopenharmony_ci	if (!fs_mark || rename_ignored) {
468f08c3bdfSopenharmony_ci		SAFE_RENAME(dname1, tmpdir);
469f08c3bdfSopenharmony_ci		SAFE_RENAME(tmpdir, dname2);
470f08c3bdfSopenharmony_ci	} else {
471f08c3bdfSopenharmony_ci		SAFE_RENAME(dname1, dname2);
472f08c3bdfSopenharmony_ci	}
473f08c3bdfSopenharmony_ci	SAFE_RMDIR(dname2);
474f08c3bdfSopenharmony_ci
475f08c3bdfSopenharmony_ci	/* Read more events on dirs */
476f08c3bdfSopenharmony_ci	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
477f08c3bdfSopenharmony_ci
478f08c3bdfSopenharmony_ci	/*
479f08c3bdfSopenharmony_ci	 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged
480f08c3bdfSopenharmony_ci	 * with any other event because it has different info records.
481f08c3bdfSopenharmony_ci	 * When renamed via an unwatched tmpdir, the 1st FAN_RENAME event has the
482f08c3bdfSopenharmony_ci	 * info record of root_fid+DIR_NAME1 and the 2nd FAN_RENAME event has the
483f08c3bdfSopenharmony_ci	 * info record of root_fid+DIR_NAME2.
484f08c3bdfSopenharmony_ci	 * If tmpdir is ignoring FAN_RENAME, we get no FAN_RENAME events at all.
485f08c3bdfSopenharmony_ci	 */
486f08c3bdfSopenharmony_ci	if (report_rename && !rename_ignored) {
487f08c3bdfSopenharmony_ci		event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR;
488f08c3bdfSopenharmony_ci		event_set[tst_count].fid = &root_fid;
489f08c3bdfSopenharmony_ci		event_set[tst_count].child_fid = subdir_fid;
490f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name, DIR_NAME1);
491f08c3bdfSopenharmony_ci		event_set[tst_count].old_name = event_set[tst_count].name;
492f08c3bdfSopenharmony_ci		if (fs_mark) {
493f08c3bdfSopenharmony_ci			strcpy(event_set[tst_count].name2, DIR_NAME2);
494f08c3bdfSopenharmony_ci			event_set[tst_count].new_name = event_set[tst_count].name2;
495f08c3bdfSopenharmony_ci		}
496f08c3bdfSopenharmony_ci		tst_count++;
497f08c3bdfSopenharmony_ci	}
498f08c3bdfSopenharmony_ci	event_set[tst_count].mask = FAN_MOVED_FROM | FAN_ONDIR;
499f08c3bdfSopenharmony_ci	event_set[tst_count].fid = &root_fid;
500f08c3bdfSopenharmony_ci	event_set[tst_count].child_fid = subdir_fid;
501f08c3bdfSopenharmony_ci	strcpy(event_set[tst_count].name, DIR_NAME1);
502f08c3bdfSopenharmony_ci	tst_count++;
503f08c3bdfSopenharmony_ci	if (report_rename && !fs_mark && !rename_ignored) {
504f08c3bdfSopenharmony_ci		event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR;
505f08c3bdfSopenharmony_ci		event_set[tst_count].fid = &root_fid;
506f08c3bdfSopenharmony_ci		event_set[tst_count].child_fid = subdir_fid;
507f08c3bdfSopenharmony_ci		strcpy(event_set[tst_count].name, DIR_NAME2);
508f08c3bdfSopenharmony_ci		event_set[tst_count].new_name = event_set[tst_count].name;
509f08c3bdfSopenharmony_ci		tst_count++;
510f08c3bdfSopenharmony_ci	}
511f08c3bdfSopenharmony_ci	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO | FAN_ONDIR;
512f08c3bdfSopenharmony_ci	event_set[tst_count].fid = &root_fid;
513f08c3bdfSopenharmony_ci	event_set[tst_count].child_fid = subdir_fid;
514f08c3bdfSopenharmony_ci	strcpy(event_set[tst_count].name, DIR_NAME2);
515f08c3bdfSopenharmony_ci	tst_count++;
516f08c3bdfSopenharmony_ci	/* Expect no more events */
517f08c3bdfSopenharmony_ci	event_set[tst_count].mask = 0;
518f08c3bdfSopenharmony_ci
519f08c3bdfSopenharmony_ci	/*
520f08c3bdfSopenharmony_ci	 * Cleanup the marks
521f08c3bdfSopenharmony_ci	 */
522f08c3bdfSopenharmony_ci	SAFE_CLOSE(fd_notify);
523f08c3bdfSopenharmony_ci	fd_notify = -1;
524f08c3bdfSopenharmony_ci
525f08c3bdfSopenharmony_ci	while (i < len) {
526f08c3bdfSopenharmony_ci		struct event_t *expected = &event_set[test_num];
527f08c3bdfSopenharmony_ci		struct fanotify_event_metadata *event;
528f08c3bdfSopenharmony_ci		struct fanotify_event_info_fid *event_fid;
529f08c3bdfSopenharmony_ci		struct fanotify_event_info_fid *child_fid;
530f08c3bdfSopenharmony_ci		struct fanotify_fid_t *expected_fid = expected->fid;
531f08c3bdfSopenharmony_ci		struct fanotify_fid_t *expected_child_fid = expected->child_fid;
532f08c3bdfSopenharmony_ci		struct file_handle *file_handle;
533f08c3bdfSopenharmony_ci		unsigned int fhlen;
534f08c3bdfSopenharmony_ci		const char *filename;
535f08c3bdfSopenharmony_ci		int namelen, info_type, mask_match, info_id = 0;
536f08c3bdfSopenharmony_ci
537f08c3bdfSopenharmony_ci		event = (struct fanotify_event_metadata *)&event_buf[i];
538f08c3bdfSopenharmony_ci		event_fid = (struct fanotify_event_info_fid *)(event + 1);
539f08c3bdfSopenharmony_ci		file_handle = (struct file_handle *)event_fid->handle;
540f08c3bdfSopenharmony_ci		fhlen = file_handle->handle_bytes;
541f08c3bdfSopenharmony_ci		filename = (char *)file_handle->f_handle + fhlen;
542f08c3bdfSopenharmony_ci		child_fid = (void *)((char *)event_fid + event_fid->hdr.len);
543f08c3bdfSopenharmony_ci		namelen = (char *)child_fid - (char *)filename;
544f08c3bdfSopenharmony_ci		/* End of event_fid could have name, zero padding, both or none */
545f08c3bdfSopenharmony_ci		if (namelen > 0) {
546f08c3bdfSopenharmony_ci			namelen = strlen(filename);
547f08c3bdfSopenharmony_ci		} else {
548f08c3bdfSopenharmony_ci			filename = "";
549f08c3bdfSopenharmony_ci			namelen = 0;
550f08c3bdfSopenharmony_ci		}
551f08c3bdfSopenharmony_ci		/* Is there a child fid after first fid record? */
552f08c3bdfSopenharmony_ci		if (((char *)child_fid - (char *)event) >= event->event_len)
553f08c3bdfSopenharmony_ci			child_fid = NULL;
554f08c3bdfSopenharmony_ci
555f08c3bdfSopenharmony_ci		if (!(group->flag & FAN_REPORT_FID))
556f08c3bdfSopenharmony_ci			expected_child_fid = NULL;
557f08c3bdfSopenharmony_ci
558f08c3bdfSopenharmony_ci		if (!report_name)
559f08c3bdfSopenharmony_ci			expected->name[0] = 0;
560f08c3bdfSopenharmony_ci
561f08c3bdfSopenharmony_ci		if (expected->mask & FAN_RENAME) {
562f08c3bdfSopenharmony_ci			/* If old name is not reported, first record is new name */
563f08c3bdfSopenharmony_ci			info_type = expected->old_name ?
564f08c3bdfSopenharmony_ci				FAN_EVENT_INFO_TYPE_OLD_DFID_NAME :
565f08c3bdfSopenharmony_ci				FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
566f08c3bdfSopenharmony_ci			/* The 2nd fid is same as 1st becaue we rename in same parent */
567f08c3bdfSopenharmony_ci			if (expected->name2[0])
568f08c3bdfSopenharmony_ci				expected_child_fid = expected_fid;
569f08c3bdfSopenharmony_ci		} else if (expected->name[0]) {
570f08c3bdfSopenharmony_ci			info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
571f08c3bdfSopenharmony_ci		} else if (expected->mask & FAN_ONDIR) {
572f08c3bdfSopenharmony_ci			info_type = FAN_EVENT_INFO_TYPE_DFID;
573f08c3bdfSopenharmony_ci		} else if (expected->mask & (FAN_DELETE_SELF | FAN_MOVE_SELF)) {
574f08c3bdfSopenharmony_ci			/* Self event on non-dir has only child fid */
575f08c3bdfSopenharmony_ci			info_type = FAN_EVENT_INFO_TYPE_FID;
576f08c3bdfSopenharmony_ci		} else {
577f08c3bdfSopenharmony_ci			info_type = FAN_EVENT_INFO_TYPE_DFID;
578f08c3bdfSopenharmony_ci		}
579f08c3bdfSopenharmony_ci
580f08c3bdfSopenharmony_ci		/*
581f08c3bdfSopenharmony_ci		 * Event may contain more than the expected mask, but it must
582f08c3bdfSopenharmony_ci		 * have all the bits in expected mask.
583f08c3bdfSopenharmony_ci		 * Expected event on dir must not get event on non dir and the
584f08c3bdfSopenharmony_ci		 * other way around.
585f08c3bdfSopenharmony_ci		 */
586f08c3bdfSopenharmony_ci		mask_match = ((event->mask & expected->mask) &&
587f08c3bdfSopenharmony_ci			      !(expected->mask & ~event->mask) &&
588f08c3bdfSopenharmony_ci			      !((event->mask ^ expected->mask) & FAN_ONDIR));
589f08c3bdfSopenharmony_ci
590f08c3bdfSopenharmony_cicheck_match:
591f08c3bdfSopenharmony_ci		if (test_num >= tst_count) {
592f08c3bdfSopenharmony_ci			tst_res(TFAIL,
593f08c3bdfSopenharmony_ci				"got unnecessary event: mask=%llx "
594f08c3bdfSopenharmony_ci				"pid=%u fd=%d name='%s' "
595f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d",
596f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
597f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd, filename,
598f08c3bdfSopenharmony_ci				event->event_len, event_fid->hdr.info_type,
599f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
600f08c3bdfSopenharmony_ci		} else if (!fhlen || namelen < 0) {
601f08c3bdfSopenharmony_ci			tst_res(TFAIL,
602f08c3bdfSopenharmony_ci				"got event without fid: mask=%llx pid=%u fd=%d, "
603f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d",
604f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
605f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd,
606f08c3bdfSopenharmony_ci				event->event_len, event_fid->hdr.info_type,
607f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
608f08c3bdfSopenharmony_ci		} else if (!mask_match) {
609f08c3bdfSopenharmony_ci			tst_res(TFAIL,
610f08c3bdfSopenharmony_ci				"got event: mask=%llx (expected %llx) "
611f08c3bdfSopenharmony_ci				"pid=%u fd=%d name='%s' "
612f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d",
613f08c3bdfSopenharmony_ci				(unsigned long long)event->mask, expected->mask,
614f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd, filename,
615f08c3bdfSopenharmony_ci				event->event_len, event_fid->hdr.info_type,
616f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
617f08c3bdfSopenharmony_ci		} else if (info_type != event_fid->hdr.info_type) {
618f08c3bdfSopenharmony_ci			tst_res(TFAIL,
619f08c3bdfSopenharmony_ci				"got event: mask=%llx pid=%u fd=%d, "
620f08c3bdfSopenharmony_ci				"len=%d info_type=%d expected(%d) info_len=%d fh_len=%d",
621f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
622f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd,
623f08c3bdfSopenharmony_ci				event->event_len, event_fid->hdr.info_type,
624f08c3bdfSopenharmony_ci				info_type, event_fid->hdr.len, fhlen);
625f08c3bdfSopenharmony_ci		} else if (fhlen != expected_fid->handle.handle_bytes) {
626f08c3bdfSopenharmony_ci			tst_res(TFAIL,
627f08c3bdfSopenharmony_ci				"got event: mask=%llx pid=%u fd=%d name='%s' "
628f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d expected(%d) "
629f08c3bdfSopenharmony_ci				"fh_type=%d",
630f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
631f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd, filename,
632f08c3bdfSopenharmony_ci				event->event_len, info_type,
633f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen,
634f08c3bdfSopenharmony_ci				expected_fid->handle.handle_bytes,
635f08c3bdfSopenharmony_ci				file_handle->handle_type);
636f08c3bdfSopenharmony_ci		} else if (file_handle->handle_type !=
637f08c3bdfSopenharmony_ci			   expected_fid->handle.handle_type) {
638f08c3bdfSopenharmony_ci			tst_res(TFAIL,
639f08c3bdfSopenharmony_ci				"got event: mask=%llx pid=%u fd=%d name='%s' "
640f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d "
641f08c3bdfSopenharmony_ci				"fh_type=%d expected(%x)",
642f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
643f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd, filename,
644f08c3bdfSopenharmony_ci				event->event_len, info_type,
645f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen,
646f08c3bdfSopenharmony_ci				file_handle->handle_type,
647f08c3bdfSopenharmony_ci				expected_fid->handle.handle_type);
648f08c3bdfSopenharmony_ci		} else if (memcmp(file_handle->f_handle,
649f08c3bdfSopenharmony_ci				  expected_fid->handle.f_handle, fhlen)) {
650f08c3bdfSopenharmony_ci			tst_res(TFAIL,
651f08c3bdfSopenharmony_ci				"got event: mask=%llx pid=%u fd=%d name='%s' "
652f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d "
653f08c3bdfSopenharmony_ci				"fh_type=%d unexpected file handle (%x...)",
654f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
655f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd, filename,
656f08c3bdfSopenharmony_ci				event->event_len, info_type,
657f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen,
658f08c3bdfSopenharmony_ci				file_handle->handle_type,
659f08c3bdfSopenharmony_ci				*(int *)(file_handle->f_handle));
660f08c3bdfSopenharmony_ci		} else if (memcmp(&event_fid->fsid, &expected_fid->fsid,
661f08c3bdfSopenharmony_ci				  sizeof(event_fid->fsid)) != 0) {
662f08c3bdfSopenharmony_ci			tst_res(TFAIL,
663f08c3bdfSopenharmony_ci				"got event: mask=%llx pid=%u fd=%d name='%s' "
664f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d "
665f08c3bdfSopenharmony_ci				"fsid=%x.%x (expected %x.%x)",
666f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
667f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd, filename,
668f08c3bdfSopenharmony_ci				event->event_len, info_type,
669f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen,
670f08c3bdfSopenharmony_ci				FSID_VAL_MEMBER(event_fid->fsid, 0),
671f08c3bdfSopenharmony_ci				FSID_VAL_MEMBER(event_fid->fsid, 1),
672f08c3bdfSopenharmony_ci				expected_fid->fsid.val[0],
673f08c3bdfSopenharmony_ci				expected_fid->fsid.val[1]);
674f08c3bdfSopenharmony_ci		} else if (strcmp(expected->name, filename)) {
675f08c3bdfSopenharmony_ci			tst_res(TFAIL,
676f08c3bdfSopenharmony_ci				"got event: mask=%llx "
677f08c3bdfSopenharmony_ci				"pid=%u fd=%d name='%s' expected('%s') "
678f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d",
679f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
680f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd,
681f08c3bdfSopenharmony_ci				filename, expected->name,
682f08c3bdfSopenharmony_ci				event->event_len, event_fid->hdr.info_type,
683f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
684f08c3bdfSopenharmony_ci		} else if (event->pid != getpid()) {
685f08c3bdfSopenharmony_ci			tst_res(TFAIL,
686f08c3bdfSopenharmony_ci				"got event: mask=%llx pid=%u "
687f08c3bdfSopenharmony_ci				"(expected %u) fd=%d name='%s' "
688f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d",
689f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
690f08c3bdfSopenharmony_ci				(unsigned int)event->pid,
691f08c3bdfSopenharmony_ci				(unsigned int)getpid(),
692f08c3bdfSopenharmony_ci				event->fd, filename,
693f08c3bdfSopenharmony_ci				event->event_len, event_fid->hdr.info_type,
694f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
695f08c3bdfSopenharmony_ci		} else if (!!child_fid != !!expected_child_fid) {
696f08c3bdfSopenharmony_ci			tst_res(TFAIL,
697f08c3bdfSopenharmony_ci				"got event: mask=%llx "
698f08c3bdfSopenharmony_ci				"pid=%u fd=%d name='%s' num_info=%d (expected %d) "
699f08c3bdfSopenharmony_ci				"len=%d info_type=%d info_len=%d fh_len=%d",
700f08c3bdfSopenharmony_ci				(unsigned long long)event->mask,
701f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd,
702f08c3bdfSopenharmony_ci				filename, 1 + !!child_fid, 1 + !!expected_child_fid,
703f08c3bdfSopenharmony_ci				event->event_len, event_fid->hdr.info_type,
704f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
705f08c3bdfSopenharmony_ci		} else if (child_fid) {
706f08c3bdfSopenharmony_ci			tst_res(TINFO,
707f08c3bdfSopenharmony_ci				"got event #%d: info #%d: info_type=%d info_len=%d fh_len=%d",
708f08c3bdfSopenharmony_ci				test_num, info_id, event_fid->hdr.info_type,
709f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
710f08c3bdfSopenharmony_ci
711f08c3bdfSopenharmony_ci			/* Recheck event_fid match with child_fid */
712f08c3bdfSopenharmony_ci			event_fid = child_fid;
713f08c3bdfSopenharmony_ci			expected_fid = expected->child_fid;
714f08c3bdfSopenharmony_ci			info_id = 1;
715f08c3bdfSopenharmony_ci			info_type = FAN_EVENT_INFO_TYPE_FID;
716f08c3bdfSopenharmony_ci			/*
717f08c3bdfSopenharmony_ci			 * With FAN_RENAME event, expect a second record of
718f08c3bdfSopenharmony_ci			 * type NEW_DFID_NAME, which in our case
719f08c3bdfSopenharmony_ci			 * has the same fid as the source dir in 1st record.
720f08c3bdfSopenharmony_ci			 * TODO: check the 2nd name and the 3rd child fid record.
721f08c3bdfSopenharmony_ci			 */
722f08c3bdfSopenharmony_ci			if (event->mask & FAN_RENAME && expected->name2[0]) {
723f08c3bdfSopenharmony_ci				info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
724f08c3bdfSopenharmony_ci				expected_fid = expected->fid;
725f08c3bdfSopenharmony_ci			}
726f08c3bdfSopenharmony_ci			file_handle = (struct file_handle *)event_fid->handle;
727f08c3bdfSopenharmony_ci			fhlen = file_handle->handle_bytes;
728f08c3bdfSopenharmony_ci			child_fid = NULL;
729f08c3bdfSopenharmony_ci			expected_child_fid = NULL;
730f08c3bdfSopenharmony_ci			goto check_match;
731f08c3bdfSopenharmony_ci		} else {
732f08c3bdfSopenharmony_ci			tst_res(TPASS,
733f08c3bdfSopenharmony_ci				"got event #%d: mask=%llx pid=%u fd=%d name='%s' "
734f08c3bdfSopenharmony_ci				"len=%d; info #%d: info_type=%d info_len=%d fh_len=%d",
735f08c3bdfSopenharmony_ci				test_num, (unsigned long long)event->mask,
736f08c3bdfSopenharmony_ci				(unsigned int)event->pid, event->fd, filename,
737f08c3bdfSopenharmony_ci				event->event_len, info_id, event_fid->hdr.info_type,
738f08c3bdfSopenharmony_ci				event_fid->hdr.len, fhlen);
739f08c3bdfSopenharmony_ci		}
740f08c3bdfSopenharmony_ci
741f08c3bdfSopenharmony_ci		if (test_num < tst_count)
742f08c3bdfSopenharmony_ci			test_num++;
743f08c3bdfSopenharmony_ci
744f08c3bdfSopenharmony_ci		if (mask_match) {
745f08c3bdfSopenharmony_ci			/* In case of merged event match next expected mask */
746f08c3bdfSopenharmony_ci			event->mask &= ~expected->mask | FAN_ONDIR;
747f08c3bdfSopenharmony_ci			if (event->mask & ~FAN_ONDIR)
748f08c3bdfSopenharmony_ci				continue;
749f08c3bdfSopenharmony_ci		}
750f08c3bdfSopenharmony_ci
751f08c3bdfSopenharmony_ci		i += event->event_len;
752f08c3bdfSopenharmony_ci		if (event->fd > 0)
753f08c3bdfSopenharmony_ci			SAFE_CLOSE(event->fd);
754f08c3bdfSopenharmony_ci	}
755f08c3bdfSopenharmony_ci
756f08c3bdfSopenharmony_ci	for (; test_num < tst_count; test_num++) {
757f08c3bdfSopenharmony_ci		tst_res(TFAIL, "didn't get event: mask=%llx, name='%s'",
758f08c3bdfSopenharmony_ci			 event_set[test_num].mask, event_set[test_num].name);
759f08c3bdfSopenharmony_ci
760f08c3bdfSopenharmony_ci	}
761f08c3bdfSopenharmony_ci}
762f08c3bdfSopenharmony_ci
763f08c3bdfSopenharmony_cistatic void setup(void)
764f08c3bdfSopenharmony_ci{
765f08c3bdfSopenharmony_ci	REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH);
766f08c3bdfSopenharmony_ci	fan_report_target_fid_unsupported =
767f08c3bdfSopenharmony_ci		fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MOUNT_PATH);
768f08c3bdfSopenharmony_ci	rename_events_unsupported =
769f08c3bdfSopenharmony_ci		fanotify_events_supported_by_kernel(FAN_RENAME, FAN_REPORT_DFID_NAME, 0);
770f08c3bdfSopenharmony_ci
771f08c3bdfSopenharmony_ci	SAFE_MKDIR(TEMP_DIR, 0755);
772f08c3bdfSopenharmony_ci	sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1);
773f08c3bdfSopenharmony_ci	sprintf(dname2, "%s/%s", MOUNT_PATH, DIR_NAME2);
774f08c3bdfSopenharmony_ci	sprintf(tmpdir, "%s/%s", TEMP_DIR, DIR_NAME2);
775f08c3bdfSopenharmony_ci	sprintf(fname1, "%s/%s", dname1, FILE_NAME1);
776f08c3bdfSopenharmony_ci	sprintf(fname2, "%s/%s", dname1, FILE_NAME2);
777f08c3bdfSopenharmony_ci}
778f08c3bdfSopenharmony_ci
779f08c3bdfSopenharmony_cistatic void cleanup(void)
780f08c3bdfSopenharmony_ci{
781f08c3bdfSopenharmony_ci	if (fd_notify > 0)
782f08c3bdfSopenharmony_ci		SAFE_CLOSE(fd_notify);
783f08c3bdfSopenharmony_ci}
784f08c3bdfSopenharmony_ci
785f08c3bdfSopenharmony_cistatic struct tst_test test = {
786f08c3bdfSopenharmony_ci	.test = do_test,
787f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(test_cases),
788f08c3bdfSopenharmony_ci	.setup = setup,
789f08c3bdfSopenharmony_ci	.cleanup = cleanup,
790f08c3bdfSopenharmony_ci	.mount_device = 1,
791f08c3bdfSopenharmony_ci	.mntpoint = MOUNT_PATH,
792f08c3bdfSopenharmony_ci	.all_filesystems = 1,
793f08c3bdfSopenharmony_ci	.needs_root = 1
794f08c3bdfSopenharmony_ci};
795f08c3bdfSopenharmony_ci
796f08c3bdfSopenharmony_ci#else
797f08c3bdfSopenharmony_ci	TST_TEST_TCONF("system does not have required name_to_handle_at() support");
798f08c3bdfSopenharmony_ci#endif
799f08c3bdfSopenharmony_ci#else
800f08c3bdfSopenharmony_ci	TST_TEST_TCONF("system doesn't have required fanotify support");
801f08c3bdfSopenharmony_ci#endif
802