xref: /xnu-11417.121.6/tests/vfs/longpaths.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650) !
1 #include <sys/param.h>
2 #include <sys/stat.h>
3 #include <sys/resource.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <assert.h>
13 #include <err.h>
14 #include <removefile.h>
15 
16 #include <sys/xattr.h>
17 #include <sys/attr.h>
18 #include <sys/fsgetpath.h>
19 #include <sys/fsgetpath_private.h>
20 
21 #include <darwintest.h>
22 #include <darwintest_utils.h>
23 
24 #define MAXLONGPATHLEN 8192 /* From sys/syslimits.h */
25 
26 #define nelem(x) (sizeof((x))/sizeof((x)[0]))
27 
28 #define DEBUG 1
29 #define DPRINT(fmt, ...) do {\
30 	if (DEBUG) fprintf(stderr, "%s | " fmt "\n", __func__, ## __VA_ARGS__);\
31 }while(0)
32 
33 #define onoffstr(x) ((x) ? "on" : "off")
34 
35 // helpers for printing test context on errors
36 #define CTXFMT    "[len: %zd, pol: %s]"
37 #define CTXARGS   pathlen, onoffstr(policy)
38 #define CTXSTR    CTXFMT, CTXARGS
39 
40 T_GLOBAL_META(
41 	T_META_NAMESPACE("xnu.vfs"),
42 	T_META_RADAR_COMPONENT_NAME("xnu"),
43 	T_META_RADAR_COMPONENT_VERSION("vfs"));
44 
45 static void *
emalloc(size_t n)46 emalloc(size_t n)
47 {
48 	void *p = malloc(n);
49 	T_QUIET; T_ASSERT_NE(p, NULL, "malloced %zd bytes", n);
50 	return p;
51 }
52 
53 static size_t
generatename(char * outstr,size_t maxlen,size_t depth)54 generatename(char *outstr, size_t maxlen, size_t depth)
55 {
56 	static char letters[] = {
57 		'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
58 		'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
59 		'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
60 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
61 	};
62 
63 	T_QUIET; T_ASSERT_TRUE(depth >= 0 && depth < sizeof(letters),
64 	    "0 <= %zd < %zd", depth, sizeof(letters));
65 
66 	size_t len = MIN(NAME_MAX, maxlen);
67 	memset(outstr, letters[depth], len);
68 	return len;
69 }
70 
71 static char *
createpath(size_t pathlen,bool leafisdir,struct stat * st)72 createpath(size_t pathlen, bool leafisdir, struct stat *st)
73 {
74 	// If we generate names exactly NAME_MAX long, the only difference between
75 	// paths of e.g. length 1023 and 1024 are the trailing slash.
76 	// NAME_MAX - 1 avoids that.
77 	enum {
78 		MAXINTERLEN = NAME_MAX - 1
79 	};
80 
81 	char *path = emalloc(pathlen + 1);
82 	char *p = path;
83 	int dirfd = AT_FDCWD;
84 	size_t depth = 0;
85 
86 	// Plus one below to account for the slash
87 	size_t intermediaries = pathlen / (MAXINTERLEN + 1);
88 	size_t leaflen = pathlen % (MAXINTERLEN + 1);
89 	if (leaflen == 0) {
90 		// Prevent trying to create an empty leaf when pathlen is an
91 		// exact divisor of MAXINTERLEN + 1
92 		leaflen = pathlen;
93 		intermediaries--;
94 	}
95 
96 	// leaflen > MAXINTERLEN when pathlen is an exact divisor MAXINTERLEN + 1
97 	char name[MAX(MAXINTERLEN, leaflen) + 1];
98 
99 	while (intermediaries-- > 0) {
100 		size_t n = generatename(name, MAXINTERLEN, depth);
101 		name[n] = '\0';
102 		memmove(p, name, n);
103 		p += n;
104 		*p++ = '/';
105 		depth++;
106 
107 		T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdirat(dirfd, name, 0700),
108 		    "[len: %zd] failed to create dir '%s' at %.*s",
109 		    pathlen, name, (int)MAXINTERLEN, path);
110 
111 		int fd = openat(dirfd, name, O_RDONLY | O_DIRECTORY);
112 		T_QUIET; T_ASSERT_GE(fd, 0,
113 		    "[len: %zd] failed to open dir %s: %s", pathlen, name, strerror(errno));
114 		if (dirfd != AT_FDCWD) {
115 			close(dirfd);
116 		}
117 		dirfd = fd;
118 	}
119 
120 	size_t n = generatename(name, leaflen, depth);
121 	name[n] = '\0';
122 	memmove(p, name, n);
123 	p += n;
124 	*p = '\0';
125 
126 	T_QUIET; T_ASSERT_TRUE(strlen(path) == pathlen, "%zd != %zd", strlen(path), pathlen);
127 
128 	if (leafisdir) {
129 		T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdirat(dirfd, name, 0700),
130 		    "[len: %zd] failed to create leaf dir '%s' at '%s'", pathlen, name, path);
131 
132 		if (st != NULL) {
133 			T_QUIET; T_ASSERT_POSIX_SUCCESS(fstatat(dirfd, name, st, 0),
134 			    "[len: %zd] failed to stat leaf dir '%s' at '%s'", pathlen, name, path);
135 		}
136 	} else {
137 		int fd = openat(dirfd, name, O_CREAT | O_TRUNC | O_WRONLY, 0600);
138 		T_QUIET; T_ASSERT_GE(fd, 0,
139 		    "[len: %zd] failed to create file '%s' leaf at '%s'", pathlen, name, path);
140 
141 		if (st != NULL) {
142 			T_QUIET; T_ASSERT_POSIX_SUCCESS(fstat(fd, st),
143 			    "[len: %zd] failed to stat leaf file '%s' at '%s'", pathlen, name, path);
144 		}
145 		close(fd);
146 	}
147 
148 	if (dirfd != AT_FDCWD) {
149 		close(dirfd);
150 	}
151 	return path;
152 }
153 
154 static int
openlongpath(const char * path,int flag)155 openlongpath(const char *path, int flag)
156 {
157 	const char *p = path;
158 	int dirfd = AT_FDCWD;
159 	int fd = -1;
160 	char *sep;
161 
162 	while (p != NULL && *p != '\0' && (sep = strchr(p, '/')) != NULL) {
163 		size_t namelen = (size_t)(sep - p);
164 		T_QUIET; T_ASSERT_LT(namelen, (size_t)NAME_MAX, "%zd >= NAME_MAX", namelen);
165 		char name[NAME_MAX];
166 		strlcpy(name, p, namelen + 1);
167 
168 		fd = openat(dirfd, name, O_EVTONLY);
169 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "failed to open intermediate %s", name);
170 		close(dirfd);
171 		dirfd = fd;
172 		p = sep + 1;
173 	}
174 
175 	fd = openat(dirfd, p, flag);
176 	T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "failed to open final component %s", p);
177 	close(dirfd);
178 	return fd;
179 }
180 
181 static char *
setup_test_dir(char * name)182 setup_test_dir(char *name)
183 {
184 	char *dir = NULL;
185 	asprintf(&dir, "%s/longpaths-%s-XXXXXX", dt_tmpdir(), name);
186 	T_QUIET; T_ASSERT_NOTNULL(mkdtemp(dir), NULL);
187 	T_LOG("test dir: %s", dir);
188 	chdir(dir);
189 	return dir;
190 }
191 
192 static void
setup_case_dir(size_t pathlen,bool policy)193 setup_case_dir(size_t pathlen, bool policy)
194 {
195 	char casedir[64];
196 	snprintf(casedir, sizeof(casedir), "len-%zd-policy-%s",
197 	    pathlen, onoffstr(policy));
198 
199 	T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(casedir, 0700),
200 	    "failed to create case dir %s", casedir);
201 	chdir(casedir);
202 }
203 
204 #ifndef IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS
205 #define IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS 13
206 #define IOPOL_VFS_SUPPORT_LONG_PATHS_DEFAULT 0
207 #define IOPOL_VFS_SUPPORT_LONG_PATHS_ON 1
208 #endif
209 
210 T_DECL(longpaths_set_policy_test, "Test combinations of policy settings in process and thread")
211 {
212 	char *testdir = setup_test_dir("set_policy_test");
213 
214 	char *path = createpath(MAXPATHLEN + 10, false, NULL);
215 	int fd = -1;
216 
217 	// Enable policy for thread
218 	T_ASSERT_POSIX_SUCCESS(setiopolicy_np(IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS,
219 	    IOPOL_SCOPE_THREAD, IOPOL_VFS_SUPPORT_LONG_PATHS_ON),
220 	    "[thread: on, proc: off]");
221 
222 	T_ASSERT_POSIX_SUCCESS(fd = open(path, O_EVTONLY), "open long path");
223 	close(fd);
224 
225 	// Enable policy for process
226 	T_ASSERT_POSIX_SUCCESS(setiopolicy_np(IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS,
227 	    IOPOL_SCOPE_PROCESS, IOPOL_VFS_SUPPORT_LONG_PATHS_ON),
228 	    "[thread: on, proc: on]");
229 
230 	T_ASSERT_POSIX_SUCCESS(fd = open(path, O_EVTONLY), "open long path");
231 	close(fd);
232 
233 	// Disable policy for thread
234 	T_ASSERT_POSIX_SUCCESS(setiopolicy_np(IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS,
235 	    IOPOL_SCOPE_THREAD, IOPOL_VFS_SUPPORT_LONG_PATHS_DEFAULT),
236 	    "[thread: off, proc: on]");
237 
238 	T_ASSERT_POSIX_SUCCESS(fd = open(path, O_EVTONLY), "open long path");
239 	close(fd);
240 
241 	// Disable policy for process
242 	T_ASSERT_POSIX_SUCCESS(setiopolicy_np(IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS,
243 	    IOPOL_SCOPE_PROCESS, IOPOL_VFS_SUPPORT_LONG_PATHS_DEFAULT),
244 	    "[thread: off, proc: off]");
245 
246 	T_ASSERT_POSIX_FAILURE(fd = open(path, O_EVTONLY), ENAMETOOLONG,
247 	    "ENAMETOOLONG when opening long path");
248 
249 	free(path);
250 	removefile(testdir, NULL, REMOVEFILE_RECURSIVE | REMOVEFILE_ALLOW_LONG_PATHS);
251 	free(testdir);
252 }
253 
254 static void
enable_policy(void)255 enable_policy(void)
256 {
257 	T_QUIET;
258 	T_ASSERT_POSIX_SUCCESS(setiopolicy_np(IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS,
259 	    IOPOL_SCOPE_PROCESS, IOPOL_VFS_SUPPORT_LONG_PATHS_ON),
260 	    "failed to enable i/o policy");
261 }
262 
263 static void
disable_policy(void)264 disable_policy(void)
265 {
266 	T_QUIET;
267 	T_ASSERT_POSIX_SUCCESS(setiopolicy_np(IOPOL_TYPE_VFS_SUPPORT_LONG_PATHS,
268 	    IOPOL_SCOPE_PROCESS, IOPOL_VFS_SUPPORT_LONG_PATHS_DEFAULT),
269 	    "failed to disable i/o policy");
270 }
271 
272 static size_t pathlengths[] = {
273 	64,
274 	NAME_MAX,
275 	MAXPATHLEN - 1,
276 	MAXPATHLEN,
277 	MAXPATHLEN + 1,
278 	2 * MAXPATHLEN,
279 	2 * MAXPATHLEN + 64,
280 	MAXLONGPATHLEN - 1,
281 	MAXLONGPATHLEN,
282 	MAXLONGPATHLEN + 1,
283 	MAXLONGPATHLEN + MAXPATHLEN,
284 };
285 
286 // Expected results for syscalls that return status code (0 or < 0)
287 static int common_errno_off[] = {
288 	/* 64 */ 0,
289 	/* NAME_MAX */ 0,
290 	/* MAXPATHLEN - 1 */ 0,
291 	/* MAXPATHLEN */ ENAMETOOLONG,
292 	/* MAXPATHLEN + 1 */ ENAMETOOLONG,
293 	/* 2 * MAXPATHLEN */ ENAMETOOLONG,
294 	/* 2 * MAXPATHLEN + 64 */ ENAMETOOLONG,
295 	/* MAXLONGPATHLEN - 1 */ ENAMETOOLONG,
296 	/* MAXLONGPATHLEN */ ENAMETOOLONG,
297 	/* MAXLONGPATHLEN + 1 */ ENAMETOOLONG,
298 	/* MAXLONGPATHLEN + MAXPATHLEN */ ENAMETOOLONG,
299 };
300 
301 static int common_errno_on[] = {
302 	/* 64 */ 0,
303 	/* NAME_MAX */ 0,
304 	/* MAXPATHLEN - 1 */ 0,
305 	/* MAXPATHLEN */ 0,
306 	/* MAXPATHLEN + 1 */ 0,
307 	/* 2 * MAXPATHLEN */ 0,
308 	/* 2 * MAXPATHLEN + 64 */ 0,
309 	/* MAXLONGPATHLEN - 1 */ 0,
310 	/* MAXLONGPATHLEN */ ENAMETOOLONG,
311 	/* MAXLONGPATHLEN + 1 */ ENAMETOOLONG,
312 	/* MAXLONGPATHLEN + MAXPATHLEN */ ENAMETOOLONG,
313 };
314 
315 static void
test_access(size_t pathlen,bool policy,int expected_errno)316 test_access(size_t pathlen, bool policy, int expected_errno)
317 {
318 	char *path = createpath(pathlen, false, NULL);
319 	int rc = access(path, F_OK);
320 	free(path);
321 
322 	if (expected_errno == 0) {
323 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
324 	} else {
325 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
326 	}
327 }
328 
329 static void
test_faccessat(size_t pathlen,bool policy,int expected_errno)330 test_faccessat(size_t pathlen, bool policy, int expected_errno)
331 {
332 	char *path = createpath(pathlen, false, NULL);
333 	int rc = faccessat(AT_FDCWD, path, F_OK, 0);
334 	free(path);
335 
336 	if (expected_errno == 0) {
337 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
338 	} else {
339 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
340 	}
341 }
342 
343 // F_GETPATH must *not* consider the i/o policy
344 static int F_GETPATH_errno[] = {
345 	/* 64 */ 0,
346 	/* NAME_MAX */ 0,
347 	/* MAXPATHLEN - 1 */ ENOSPC,
348 	/* MAXPATHLEN */ ENOSPC,
349 	/* MAXPATHLEN + 1 */ ENOSPC,
350 	/* 2 * MAXPATHLEN */ ENOSPC,
351 	/* 2 * MAXPATHLEN + 64 */ ENOSPC,
352 	/* MAXLONGPATHLEN - 1 */ ENOSPC,
353 	/* MAXLONGPATHLEN */ ENOSPC,
354 	/* MAXLONGPATHLEN + 1 */ ENOSPC,
355 	/* MAXLONGPATHLEN + MAXPATHLEN */ ENOSPC,
356 };
357 
358 static void
test_F_GETPATH(size_t pathlen,bool policy,int expected_errno)359 test_F_GETPATH(size_t pathlen, bool policy, int expected_errno)
360 {
361 	struct stat st;
362 	char *path = createpath(pathlen, false, &st);
363 
364 	int fd = openlongpath(path, O_EVTONLY);
365 	T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "failed to open path %s", path);
366 	free(path);
367 
368 	char buf[PATH_MAX];
369 	int rc = fcntl(fd, F_GETPATH, buf);
370 	close(fd);
371 
372 	if (expected_errno == 0) {
373 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
374 	} else {
375 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
376 	}
377 }
378 
379 static void
test_fstatat(size_t pathlen,bool policy,int expected_errno)380 test_fstatat(size_t pathlen, bool policy, int expected_errno)
381 {
382 	struct stat st;
383 	char *path = createpath(pathlen, false, NULL);
384 	int rc = fstatat(AT_FDCWD, path, &st, 0);
385 	free(path);
386 
387 	if (expected_errno == 0) {
388 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
389 	} else {
390 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
391 	}
392 }
393 
394 static void
test_getattrlist_fileID(size_t pathlen,bool policy,int expected_errno)395 test_getattrlist_fileID(size_t pathlen, bool policy, int expected_errno)
396 {
397 	struct stat st;
398 	char *path = createpath(pathlen, false, &st);
399 
400 	struct {
401 		uint32_t size;
402 		uint64_t fileID;
403 	} __attribute__((aligned(4), packed)) buf;
404 
405 	struct attrlist al = {
406 		.bitmapcount = ATTR_BIT_MAP_COUNT,
407 		.commonattr = ATTR_CMN_FILEID,
408 	};
409 
410 	int rc = getattrlist(path, &al, &buf, sizeof(buf), FSOPT_ATTR_CMN_EXTENDED);
411 	free(path);
412 
413 	if (expected_errno == 0) {
414 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
415 	} else {
416 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
417 	}
418 }
419 
420 static void
test_getattrlist_fullpath(size_t pathlen,bool policy,int expected_errno)421 test_getattrlist_fullpath(size_t pathlen, bool policy, int expected_errno)
422 {
423 	char *cwd = getcwd(NULL, 0);
424 	size_t cwdlen = strlen(cwd);
425 
426 	if (pathlen + 1 <= cwdlen) {
427 		// Test dir is longer than pathlen + slash, no sense running the test
428 		return;
429 	}
430 
431 	char *testrelpath = createpath(pathlen - cwdlen - 1, false, NULL); // -1 for the slash
432 	char *inpath = NULL;
433 	asprintf(&inpath, "%s/%s", cwd, testrelpath);
434 	free(cwd);
435 	free(testrelpath);
436 	T_QUIET; T_ASSERT_EQ(strlen(inpath), pathlen, CTXSTR);
437 
438 	struct {
439 		uint32_t size;
440 		attrreference_t attr;
441 		char path[MAXLONGPATHLEN];
442 	} __attribute__((aligned(4), packed)) buf;
443 
444 	struct attrlist al = {
445 		.bitmapcount = ATTR_BIT_MAP_COUNT,
446 		.commonattr = ATTR_CMN_FULLPATH,
447 	};
448 
449 	int rc = getattrlist(inpath, &al, &buf, sizeof(buf), FSOPT_ATTR_CMN_EXTENDED);
450 
451 	if (expected_errno == 0) {
452 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
453 
454 		char *retpath = (char *)&buf.attr + buf.attr.attr_dataoffset;
455 		T_QUIET; T_ASSERT_LT(retpath, (char *)&buf + buf.size, CTXSTR);
456 		T_QUIET; T_ASSERT_LE(retpath + buf.attr.attr_length, (char *)&buf + buf.size, CTXSTR);
457 		T_QUIET; T_ASSERT_EQ(strcmp(retpath, inpath), 0, CTXSTR);
458 	} else {
459 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
460 	}
461 	free(inpath);
462 }
463 
464 static void
test_getattrlist_relpath(size_t pathlen,bool policy,int expected_errno)465 test_getattrlist_relpath(size_t pathlen, bool policy, int expected_errno)
466 {
467 	char *cwd = getcwd(NULL, 0);
468 	size_t cwdlen = strlen(cwd);
469 
470 	if (pathlen + 1 <= cwdlen) {
471 		// Test dir is longer than pathlen + slash, no sense running the test
472 		return;
473 	}
474 
475 	struct stat st;
476 	char *testrelpath = createpath(pathlen - cwdlen - 1, false, &st); // -1 for the slash
477 	char *inpath = NULL;
478 	asprintf(&inpath, "%s/%s", cwd, testrelpath);
479 	free(cwd);
480 	free(testrelpath);
481 	T_QUIET; T_ASSERT_EQ(strlen(inpath), pathlen, NULL);
482 
483 	struct {
484 		uint32_t size;
485 		dev_t dev;
486 		uint64_t fileID;
487 		attrreference_t attr;
488 		char path[MAXLONGPATHLEN];
489 	} __attribute__((aligned(4), packed)) buf;
490 
491 	struct attrlist al = {
492 		.bitmapcount = ATTR_BIT_MAP_COUNT,
493 		.commonattr = ATTR_CMN_DEVID | ATTR_CMN_FILEID,
494 		.forkattr = ATTR_CMNEXT_RELPATH,
495 	};
496 
497 	int rc = getattrlist(inpath, &al, &buf, sizeof(buf), FSOPT_ATTR_CMN_EXTENDED);
498 
499 	if (expected_errno == 0) {
500 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
501 
502 		char *retpath = (char *)&buf.attr + buf.attr.attr_dataoffset;
503 		T_QUIET; T_ASSERT_LT(retpath, (char *)&buf + buf.size, CTXSTR);
504 		T_QUIET; T_ASSERT_LE(retpath + buf.attr.attr_length, (char *)&buf + buf.size, CTXSTR);
505 		T_QUIET; T_ASSERT_TRUE(buf.dev == st.st_dev && buf.fileID == st.st_ino, CTXSTR);
506 	} else {
507 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
508 	}
509 	free(inpath);
510 }
511 
512 static void
test_getattrlist_nofirmlinkpath(size_t pathlen,bool policy,int expected_errno)513 test_getattrlist_nofirmlinkpath(size_t pathlen, bool policy, int expected_errno)
514 {
515 #if !TARGET_OS_OSX
516 	T_QUIET; T_PASS(NULL);
517 	return;
518 #else
519 	char *cwd = getcwd(NULL, 0);
520 	size_t cwdlen = strlen(cwd);
521 
522 	struct {
523 		uint32_t size;
524 		attrreference_t attr;
525 		char mtpt[MAXPATHLEN];
526 	} __attribute__((aligned(4), packed)) mtptbuf;
527 
528 	struct attrlist mtptal = {
529 		.bitmapcount = ATTR_BIT_MAP_COUNT,
530 		.volattr = ATTR_VOL_MOUNTPOINT,
531 	};
532 	T_QUIET; T_ASSERT_POSIX_SUCCESS(getattrlist(cwd, &mtptal, &mtptbuf, sizeof(mtptbuf), 0), NULL);
533 
534 	char *mtpt = (char *)&mtptbuf.attr + mtptbuf.attr.attr_dataoffset;
535 	size_t mtptlen = strlen(mtpt);
536 
537 	if (pathlen + 1 <= mtptlen + cwdlen) {
538 		// Test dir + mount point is longer than pathlen + slash, no sense running the test
539 		return;
540 	}
541 
542 	/*
543 	 * cwd already has a leading slash, so the -1 below is for the slash that will be put
544 	 * after cwd when build inpath
545 	 */
546 	char *testrelpath = createpath(pathlen - mtptlen - cwdlen - 1, false, NULL);
547 	char *inpath = NULL;
548 	asprintf(&inpath, "%s%s/%s", mtpt, cwd, testrelpath);
549 	free(cwd);
550 	free(testrelpath);
551 	T_QUIET; T_ASSERT_EQ(strlen(inpath), pathlen, CTXSTR);
552 
553 	struct {
554 		uint32_t size;
555 		attrreference_t attr;
556 		char path[MAXLONGPATHLEN];
557 	} __attribute__((aligned(4), packed)) buf;
558 
559 	struct attrlist al = {
560 		.bitmapcount = ATTR_BIT_MAP_COUNT,
561 		.forkattr = ATTR_CMNEXT_NOFIRMLINKPATH,
562 	};
563 
564 	int rc = getattrlist(inpath, &al, &buf, sizeof(buf), FSOPT_ATTR_CMN_EXTENDED);
565 
566 	if (expected_errno == 0) {
567 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
568 
569 		char *retpath = (char *)&buf.attr + buf.attr.attr_dataoffset;
570 		T_QUIET; T_ASSERT_LT(retpath, (char *)&buf + buf.size, CTXSTR);
571 		T_QUIET; T_ASSERT_LE(retpath + buf.attr.attr_length, (char *)&buf + buf.size, CTXSTR);
572 		T_QUIET; T_ASSERT_EQ(strcmp(retpath, inpath), 0, CTXSTR);
573 	} else {
574 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
575 	}
576 	free(inpath);
577 #endif /* !TARGET_OS_OSX */
578 }
579 
580 static void
test_lstat(size_t pathlen,bool policy,int expected_errno)581 test_lstat(size_t pathlen, bool policy, int expected_errno)
582 {
583 	struct stat st;
584 	char *path = createpath(pathlen, false, NULL);
585 	int rc = lstat(path, &st);
586 	free(path);
587 
588 	if (expected_errno == 0) {
589 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
590 	} else {
591 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
592 	}
593 }
594 
595 static void
test_mkdirat(size_t pathlen,bool policy,int expected_errno)596 test_mkdirat(size_t pathlen, bool policy, int expected_errno)
597 {
598 	char *name = "newdir";
599 	size_t parentlen = pathlen - strlen(name) - 1;
600 	char *parent = createpath(parentlen, true, NULL);
601 	char *path = NULL;
602 	asprintf(&path, "%s/%s", parent, name);
603 
604 	int rc = mkdirat(AT_FDCWD, path, 0700);
605 	free(parent);
606 	free(path);
607 
608 	if (expected_errno == 0) {
609 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
610 	} else {
611 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
612 	}
613 }
614 
615 static void
test_open(size_t pathlen,bool policy,int expected_errno)616 test_open(size_t pathlen, bool policy, int expected_errno)
617 {
618 	char *path = createpath(pathlen, false, NULL);
619 	int fd = open(path, O_EVTONLY);
620 	free(path);
621 
622 	if (expected_errno == 0) {
623 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
624 	} else {
625 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
626 	}
627 	if (fd >= 0) {
628 		close(fd);
629 	}
630 }
631 
632 static void
test_open_create(size_t pathlen,bool policy,int expected_errno)633 test_open_create(size_t pathlen, bool policy, int expected_errno)
634 {
635 	char *name = "newfile";
636 	size_t parentlen = pathlen - strlen(name) - 1;
637 	char *parent = createpath(parentlen, true, NULL);
638 	char *path = NULL;
639 	asprintf(&path, "%s/%s", parent, name);
640 
641 	int fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
642 	free(parent);
643 	free(path);
644 
645 	if (expected_errno == 0) {
646 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
647 	} else {
648 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
649 	}
650 	if (fd >= 0) {
651 		close(fd);
652 	}
653 }
654 
655 static void
test_open_volfs(size_t pathlen,bool policy,int expected_errno)656 test_open_volfs(size_t pathlen, bool policy, int expected_errno)
657 {
658 #if !TARGET_OS_OSX
659 	T_QUIET; T_PASS(NULL);
660 	return;
661 #else
662 	char *cwd = getcwd(NULL, 0);
663 	size_t cwdlen = strlen(cwd);
664 	free(cwd);
665 
666 	if (pathlen + 1 <= cwdlen) {
667 		// Test dir is longer than pathlen + slash, no sense running the test
668 		return;
669 	}
670 	size_t relpathlen = pathlen - cwdlen - 1; // -1 for the slash
671 
672 	struct stat st, volst;
673 	free(createpath(relpathlen, false, &st));
674 
675 	char *path = NULL;
676 	asprintf(&path, "/.vol/%d/%llu", st.st_dev, st.st_ino);
677 	int fd = open(path, O_EVTONLY);
678 	free(path);
679 
680 	if (expected_errno == 0) {
681 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
682 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fstat(fd, &volst), CTXSTR);
683 		T_QUIET; T_ASSERT_TRUE(volst.st_dev == st.st_dev && volst.st_ino == st.st_ino,
684 		    CTXFMT " dev %d != %d, ino %llu != %llu",
685 		    CTXARGS, volst.st_dev, st.st_dev, volst.st_ino, st.st_ino);
686 	} else {
687 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
688 	}
689 	if (fd >= 0) {
690 		close(fd);
691 	}
692 #endif /* !TARGET_OS_OSX */
693 }
694 
695 static void
test_openat(size_t pathlen,bool policy,int expected_errno)696 test_openat(size_t pathlen, bool policy, int expected_errno)
697 {
698 	char *path = createpath(pathlen, false, NULL);
699 	int fd = openat(AT_FDCWD, path, O_EVTONLY);
700 	free(path);
701 
702 	if (expected_errno == 0) {
703 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
704 	} else {
705 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
706 	}
707 	if (fd >= 0) {
708 		close(fd);
709 	}
710 }
711 
712 static void
test_openat_create(size_t pathlen,bool policy,int expected_errno)713 test_openat_create(size_t pathlen, bool policy, int expected_errno)
714 {
715 	char *name = "newfile";
716 	size_t parentlen = pathlen - strlen(name) - 1;
717 	char *parent = createpath(parentlen, true, NULL);
718 	char *path = NULL;
719 	asprintf(&path, "%s/%s", parent, name);
720 
721 	int fd = openat(AT_FDCWD, path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
722 	free(parent);
723 	free(path);
724 
725 	if (expected_errno == 0) {
726 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
727 	} else {
728 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
729 	}
730 	if (fd >= 0) {
731 		close(fd);
732 	}
733 }
734 
735 static int openbyid_errno_off[] = {
736 	/* 64 */ 0,
737 	/* NAME_MAX */ 0,
738 	/* MAXPATHLEN - 1 */ ENAMETOOLONG,
739 	/* MAXPATHLEN */ ENAMETOOLONG,
740 	/* MAXPATHLEN + 1 */ ENAMETOOLONG,
741 	/* 2 * MAXPATHLEN */ ENAMETOOLONG,
742 	/* 2 * MAXPATHLEN + 64 */ ENAMETOOLONG,
743 	/* MAXLONGPATHLEN - 1 */ EINVAL,
744 	/* MAXLONGPATHLEN */ EINVAL,
745 	/* MAXLONGPATHLEN + 1 */ EINVAL,
746 	/* MAXLONGPATHLEN + MAXPATHLEN */ EINVAL,
747 };
748 
749 static int openbyid_errno_on[] = {
750 	/* 64 */ 0,
751 	/* NAME_MAX */ 0,
752 	/* MAXPATHLEN - 1 */ 0,
753 	/* MAXPATHLEN */ 0,
754 	/* MAXPATHLEN + 1 */ 0,
755 	/* 2 * MAXPATHLEN */ 0,
756 	/* 2 * MAXPATHLEN + 64 */ 0,
757 	/* MAXLONGPATHLEN - 1 */ EINVAL,
758 	/* MAXLONGPATHLEN */ EINVAL,
759 	/* MAXLONGPATHLEN + 1 */ EINVAL,
760 	/* MAXLONGPATHLEN + MAXPATHLEN */ EINVAL,
761 };
762 
763 static void
test_openbyid_np(size_t pathlen,bool policy,int expected_errno)764 test_openbyid_np(size_t pathlen, bool policy, int expected_errno)
765 {
766 	struct stat st;
767 	char *path = createpath(pathlen, false, &st);
768 	free(path);
769 
770 	fsid_t fsid = {st.st_dev, 0};
771 	uint64_t fsobjid = st.st_ino;
772 	int fd = openbyid_np(&fsid, (fsobj_id_t *)&fsobjid, O_EVTONLY);
773 
774 	if (expected_errno == 0) {
775 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
776 	} else {
777 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
778 	}
779 	if (fd >= 0) {
780 		close(fd);
781 	}
782 }
783 
784 /*
785  * The full paths here are length + strlen("link/") = length + 5
786  */
787 static int path_after_link_errno_off[] = {
788 	/* 64 */ 0,
789 	/* NAME_MAX */ 0,
790 	/* MAXPATHLEN - 1 */ ENAMETOOLONG,
791 	/* MAXPATHLEN */ ENAMETOOLONG,
792 	/* MAXPATHLEN + 1 */ ENAMETOOLONG,
793 	/* 2 * MAXPATHLEN */ ENAMETOOLONG,
794 	/* 2 * MAXPATHLEN + 64 */ ENAMETOOLONG,
795 	/* MAXLONGPATHLEN - 1 */ ENAMETOOLONG,
796 	/* MAXLONGPATHLEN */ ENAMETOOLONG,
797 	/* MAXLONGPATHLEN + 1 */ ENAMETOOLONG,
798 	/* MAXLONGPATHLEN + MAXPATHLEN */ ENAMETOOLONG,
799 };
800 
801 static int path_after_link_errno_on[] = {
802 	/* 64 */ 0,
803 	/* NAME_MAX */ 0,
804 	/* MAXPATHLEN - 1 */ 0,
805 	/* MAXPATHLEN */ 0,
806 	/* MAXPATHLEN + 1 */ 0,
807 	/* 2 * MAXPATHLEN */ 0,
808 	/* 2 * MAXPATHLEN + 64 */ 0,
809 	/* MAXLONGPATHLEN - 1 */ ENAMETOOLONG,
810 	/* MAXLONGPATHLEN */ ENAMETOOLONG,
811 	/* MAXLONGPATHLEN + 1 */ ENAMETOOLONG,
812 	/* MAXLONGPATHLEN + MAXPATHLEN */ ENAMETOOLONG,
813 };
814 
815 static void
test_path_after_link(size_t remaininglen,bool policy,int expected_errno)816 test_path_after_link(size_t remaininglen, bool policy, int expected_errno)
817 {
818 	/*
819 	 * Create path of the form link/... where ... has remaininglen length.
820 	 */
821 
822 	T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir("base", 0700), CTXFMT, remaininglen, onoffstr(policy));
823 	T_QUIET; T_ASSERT_POSIX_SUCCESS(symlink("base", "link"), CTXFMT, remaininglen, onoffstr(policy));
824 
825 	chdir("base");
826 	struct stat origst;
827 	char *remainingpath = createpath(remaininglen - 1, false, &origst); // -1 for the slash
828 	chdir("..");
829 
830 	char *path = NULL;
831 	asprintf(&path, "link/%s", remainingpath);
832 	free(remainingpath);
833 
834 	struct stat st;
835 	int rc = fstatat(AT_FDCWD, path, &st, 0);
836 	free(path);
837 
838 	if (expected_errno == 0) {
839 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXFMT, remaininglen, onoffstr(policy));
840 		T_QUIET; T_ASSERT_TRUE(st.st_dev == origst.st_dev && st.st_ino == origst.st_ino,
841 		    CTXFMT, remaininglen, onoffstr(policy));
842 	} else {
843 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXFMT, remaininglen, onoffstr(policy));
844 	}
845 }
846 
847 static void
test_renameatx_np(size_t pathlen,bool policy,int expected_errno)848 test_renameatx_np(size_t pathlen, bool policy, int expected_errno)
849 {
850 	char *src = createpath(pathlen, false, NULL);
851 	char *dst = strdup(src);
852 
853 	// Change last character in name
854 	dst[pathlen - 1] = '9';
855 
856 	int rc = renameatx_np(AT_FDCWD, src, AT_FDCWD, dst, 0);
857 	free(src);
858 	free(dst);
859 
860 	if (expected_errno == 0) {
861 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
862 	} else {
863 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
864 	}
865 }
866 
867 static void
test_symlink_long2long(size_t pathlen,bool policy,int expected_errno)868 test_symlink_long2long(size_t pathlen, bool policy, int expected_errno)
869 {
870 	char *linkname = "link";
871 	size_t parentlen = pathlen - strlen(linkname) - 1;
872 	char *parent = createpath(parentlen, true, NULL);
873 	char *linkpath = NULL;
874 	asprintf(&linkpath, "%s/%s", parent, linkname);
875 	char *targetpath = NULL;
876 	asprintf(&targetpath, "%s/xpto", parent);
877 	size_t targetlen = strlen(targetpath);
878 
879 	int rc = symlink(targetpath, linkpath);
880 	free(parent);
881 
882 	if (expected_errno == 0) {
883 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
884 
885 		char *buf = emalloc(targetlen + 1);
886 		ssize_t linklen;
887 
888 		T_QUIET; T_ASSERT_POSIX_SUCCESS((linklen = readlink(linkpath, buf, targetlen)), CTXSTR);
889 		T_QUIET; T_ASSERT_EQ((size_t)linklen, targetlen,
890 		    CTXFMT " linklen %zd", CTXARGS, (size_t)linklen);
891 		buf[linklen] = '\0';
892 
893 		T_QUIET; T_ASSERT_EQ(strcmp(buf, targetpath), 0, CTXSTR);
894 		free(targetpath);
895 		free(linkpath);
896 		free(buf);
897 	} else {
898 		free(targetpath);
899 		free(linkpath);
900 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
901 	}
902 }
903 
904 static void
test_symlink_long2short(size_t pathlen,bool policy,int expected_errno)905 test_symlink_long2short(size_t pathlen, bool policy, int expected_errno)
906 {
907 	char *name = "long-link";
908 	size_t parentlen = pathlen - strlen(name) - 1;
909 	char *parent = createpath(parentlen, true, NULL);
910 	char *path = NULL;
911 	asprintf(&path, "%s/%s", parent, name);
912 
913 	char *targetname = "destination.txt";
914 	size_t targetlen = strlen(targetname);
915 	int rc = symlink(targetname, path);
916 	free(parent);
917 
918 	if (expected_errno == 0) {
919 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
920 
921 		char *buf = emalloc(targetlen + 1);
922 		ssize_t linklen;
923 
924 		T_QUIET; T_ASSERT_POSIX_SUCCESS((linklen = readlink(path, buf, targetlen)), CTXSTR);
925 		T_QUIET; T_ASSERT_EQ((size_t)linklen, targetlen,
926 		    CTXFMT " linklen %zd", CTXARGS, (size_t)linklen);
927 		buf[linklen] = '\0';
928 
929 		T_QUIET; T_ASSERT_EQ(strcmp(buf, targetname), 0, CTXSTR);
930 		free(path);
931 		free(buf);
932 	} else {
933 		free(path);
934 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
935 	}
936 }
937 
938 static void
test_symlink_short2long(size_t pathlen,bool policy,int expected_errno)939 test_symlink_short2long(size_t pathlen, bool policy, int expected_errno)
940 {
941 	char *path = createpath(pathlen, false, NULL);
942 	int rc = symlink(path, "short-link");
943 
944 	if (expected_errno == 0) {
945 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
946 
947 		char *buf = emalloc(pathlen + 1);
948 		ssize_t linklen;
949 
950 		T_QUIET; T_ASSERT_POSIX_SUCCESS((linklen = readlink("short-link", buf, pathlen)), CTXSTR);
951 		T_QUIET; T_ASSERT_EQ((size_t)linklen, pathlen,
952 		    CTXFMT " linklen %zd", CTXARGS, (size_t)linklen);
953 		buf[linklen] = '\0';
954 
955 		T_QUIET; T_ASSERT_EQ(strcmp(buf, path), 0, CTXSTR);
956 		free(path);
957 		free(buf);
958 	} else {
959 		free(path);
960 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
961 	}
962 }
963 
964 static void
test_symlink_intermediate(size_t pathlen,bool policy,int expected_errno)965 test_symlink_intermediate(size_t pathlen, bool policy, int expected_errno)
966 {
967 	/*
968 	 * Create path with intermediate symlinks so that linked and original paths
969 	 * are of the same length.
970 	 */
971 	char *path = createpath(pathlen, false, NULL);
972 
973 	// Find parent of path
974 	char *lastslash = strrchr(path, '/');
975 	if (lastslash == NULL || lastslash == path) {
976 		return;
977 	}
978 
979 	size_t leaflen = strlen(lastslash + 1);
980 
981 	char *p = lastslash - 1;
982 	while (p - 1 != path && *(p - 1) != '/') {
983 		p--;
984 	}
985 
986 	size_t parentlen = (uintptr_t)(lastslash - p);
987 	char *parentname = emalloc(parentlen + 1);
988 	memmove(parentname, p, parentlen);
989 	parentname[parentlen] = '\0';
990 
991 	// Find grandparent of path, which will be the base path where to create a symlink
992 	size_t baselen = pathlen - parentlen - 1 - 1 - leaflen;
993 	char *basepath = emalloc(baselen + 1);
994 	memmove(basepath, path, baselen);
995 	basepath[baselen] = '\0';
996 
997 	// Create symlink
998 	char *linkname = emalloc(parentlen + 1);
999 	size_t n = generatename(linkname, parentlen, 49); // repeating Xs
1000 	linkname[n] = '\0';
1001 
1002 	char *linkpath = NULL;
1003 	asprintf(&linkpath, "%s/%s", basepath, linkname);
1004 	free(linkname);
1005 
1006 	T_QUIET; T_ASSERT_EQ(strlen(linkpath) + 1 + leaflen, pathlen, NULL);
1007 
1008 	int rc = symlink(parentname, linkpath);
1009 	free(parentname);
1010 
1011 	if (!policy) {
1012 		if (strlen(linkpath) < MAXPATHLEN) {
1013 			T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1014 		} else {
1015 			T_QUIET; T_ASSERT_POSIX_FAILURE(rc, ENAMETOOLONG, CTXSTR);
1016 		}
1017 	} else {
1018 		if (strlen(linkpath) < MAXLONGPATHLEN) {
1019 			T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1020 		} else {
1021 			T_QUIET; T_ASSERT_POSIX_FAILURE(rc, ENAMETOOLONG, CTXSTR);
1022 		}
1023 	}
1024 
1025 	char *linkedpath = NULL;
1026 	asprintf(&linkedpath, "%s/%s", linkpath, lastslash + 1);
1027 	T_QUIET; T_ASSERT_EQ(strlen(linkedpath), pathlen, NULL);
1028 	free(linkpath);
1029 
1030 	int fd = open(linkedpath, O_EVTONLY);
1031 	free(linkedpath);
1032 
1033 	if (expected_errno == 0) {
1034 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
1035 	} else {
1036 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
1037 	}
1038 	if (fd >= 0) {
1039 		close(fd);
1040 	}
1041 }
1042 
1043 static void
test_unlinkat(size_t pathlen,bool policy,int expected_errno)1044 test_unlinkat(size_t pathlen, bool policy, int expected_errno)
1045 {
1046 	char *path = createpath(pathlen, false, NULL);
1047 	int rc = unlinkat(AT_FDCWD, path, 0);
1048 	free(path);
1049 
1050 	if (expected_errno == 0) {
1051 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1052 	} else {
1053 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
1054 	}
1055 }
1056 
1057 static void
test_xattr(size_t pathlen,bool policy,int expected_errno)1058 test_xattr(size_t pathlen, bool policy, int expected_errno)
1059 {
1060 	char *path = createpath(pathlen, false, NULL);
1061 	char *name = "lpattr";
1062 	char *value = "xpto";
1063 	ssize_t valuelen = strlen(value);
1064 
1065 	int rc = setxattr(path, name, value, valuelen, 0, XATTR_CREATE);
1066 	if (expected_errno == 0) {
1067 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1068 	} else {
1069 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
1070 	}
1071 
1072 	char *buf = emalloc(valuelen);
1073 	ssize_t attrlen = getxattr(path, name, buf, valuelen, 0, XATTR_CREATE);
1074 	free(path);
1075 	if (expected_errno == 0) {
1076 		T_QUIET; T_ASSERT_POSIX_SUCCESS(attrlen, CTXSTR);
1077 		T_QUIET; T_ASSERT_EQ(attrlen, valuelen, CTXSTR);
1078 		T_QUIET; T_ASSERT_EQ(0, memcmp(buf, value, valuelen), CTXSTR);
1079 	} else {
1080 		T_QUIET; T_ASSERT_POSIX_FAILURE(attrlen, expected_errno, CTXSTR);
1081 	}
1082 	free(buf);
1083 }
1084 
1085 #define SYSCALL_TEST(name, expected_errno_off, expected_errno_on) \
1086 T_DECL(longpaths_ ## name ## _test, "Test " #name " with long paths") \
1087 {\
1088 	char *testdir = setup_test_dir(#name);\
1089 \
1090 	disable_policy();\
1091 	bool policy = false;\
1092 	for (size_t i = 0; i < nelem(pathlengths); i++) {\
1093 	        size_t pathlen = pathlengths[i];\
1094 	        setup_case_dir(pathlen, policy);\
1095 	        test_ ## name (pathlen, policy, (expected_errno_off)[i]);\
1096 	        chdir("..");\
1097 	}\
1098 \
1099 	enable_policy();\
1100 	policy = true;\
1101 	for (size_t i = 0; i < nelem(pathlengths); i++) {\
1102 	        size_t pathlen = pathlengths[i];\
1103 	        setup_case_dir(pathlen, policy);\
1104 	        test_ ##name (pathlen, policy, (expected_errno_on)[i]);\
1105 	        chdir("..");\
1106 	}\
1107 \
1108 	removefile(testdir, NULL, REMOVEFILE_RECURSIVE | REMOVEFILE_ALLOW_LONG_PATHS);\
1109 	free(testdir);\
1110 }
1111 
1112 SYSCALL_TEST(access, common_errno_off, common_errno_on)
1113 SYSCALL_TEST(faccessat, common_errno_off, common_errno_on)
1114 SYSCALL_TEST(fstatat, common_errno_off, common_errno_on)
1115 SYSCALL_TEST(F_GETPATH, F_GETPATH_errno, F_GETPATH_errno)
1116 
1117 SYSCALL_TEST(getattrlist_fileID, common_errno_off, common_errno_on)
1118 SYSCALL_TEST(getattrlist_nofirmlinkpath, common_errno_off, common_errno_on)
1119 SYSCALL_TEST(getattrlist_fullpath, common_errno_off, common_errno_on)
1120 SYSCALL_TEST(getattrlist_relpath, common_errno_off, common_errno_on)
1121 
1122 SYSCALL_TEST(lstat, common_errno_off, common_errno_on)
1123 SYSCALL_TEST(mkdirat, common_errno_off, common_errno_on)
1124 
1125 SYSCALL_TEST(open, common_errno_off, common_errno_on)
1126 SYSCALL_TEST(open_create, common_errno_off, common_errno_on)
1127 SYSCALL_TEST(open_volfs, common_errno_on, common_errno_on)
1128 
1129 SYSCALL_TEST(openat, common_errno_off, common_errno_on)
1130 SYSCALL_TEST(openat_create, common_errno_off, common_errno_on)
1131 
1132 SYSCALL_TEST(openbyid_np, openbyid_errno_off, openbyid_errno_on)
1133 SYSCALL_TEST(path_after_link, path_after_link_errno_off, path_after_link_errno_on)
1134 SYSCALL_TEST(renameatx_np, common_errno_off, common_errno_on)
1135 
1136 SYSCALL_TEST(symlink_intermediate, common_errno_off, common_errno_on)
1137 // Even with the policy on, we should fail when symlinks target long paths
1138 SYSCALL_TEST(symlink_long2long, common_errno_off, common_errno_off)
1139 SYSCALL_TEST(symlink_long2short, common_errno_off, common_errno_on)
1140 SYSCALL_TEST(symlink_short2long, common_errno_off, common_errno_off)
1141 
1142 SYSCALL_TEST(unlinkat, common_errno_off, common_errno_on)
1143 SYSCALL_TEST(xattr, common_errno_off, common_errno_on)
1144