xref: /xnu-12377.61.12/tests/vfs/longpaths.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8) !
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 		free(cwd);
429 		return;
430 	}
431 
432 	char *testrelpath = createpath(pathlen - cwdlen - 1, false, NULL); // -1 for the slash
433 	char *inpath = NULL;
434 	asprintf(&inpath, "%s/%s", cwd, testrelpath);
435 	free(cwd);
436 	free(testrelpath);
437 	T_QUIET; T_ASSERT_EQ(strlen(inpath), pathlen, CTXSTR);
438 
439 	struct {
440 		uint32_t size;
441 		attrreference_t attr;
442 		char path[MAXLONGPATHLEN];
443 	} __attribute__((aligned(4), packed)) buf;
444 
445 	struct attrlist al = {
446 		.bitmapcount = ATTR_BIT_MAP_COUNT,
447 		.commonattr = ATTR_CMN_FULLPATH,
448 	};
449 
450 	int rc = getattrlist(inpath, &al, &buf, sizeof(buf), FSOPT_ATTR_CMN_EXTENDED);
451 
452 	if (expected_errno == 0) {
453 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
454 
455 		char *retpath = (char *)&buf.attr + buf.attr.attr_dataoffset;
456 		T_QUIET; T_ASSERT_LT(retpath, (char *)&buf + buf.size, CTXSTR);
457 		T_QUIET; T_ASSERT_LE(retpath + buf.attr.attr_length, (char *)&buf + buf.size, CTXSTR);
458 		T_QUIET; T_ASSERT_EQ(strcmp(retpath, inpath), 0, CTXSTR);
459 	} else {
460 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
461 	}
462 	free(inpath);
463 }
464 
465 static void
test_getattrlist_relpath(size_t pathlen,bool policy,int expected_errno)466 test_getattrlist_relpath(size_t pathlen, bool policy, int expected_errno)
467 {
468 	char *cwd = getcwd(NULL, 0);
469 	size_t cwdlen = strlen(cwd);
470 
471 	if (pathlen + 1 <= cwdlen) {
472 		// Test dir is longer than pathlen + slash, no sense running the test
473 		free(cwd);
474 		return;
475 	}
476 
477 	struct stat st;
478 	char *testrelpath = createpath(pathlen - cwdlen - 1, false, &st); // -1 for the slash
479 	char *inpath = NULL;
480 	asprintf(&inpath, "%s/%s", cwd, testrelpath);
481 	free(cwd);
482 	free(testrelpath);
483 	T_QUIET; T_ASSERT_EQ(strlen(inpath), pathlen, NULL);
484 
485 	struct {
486 		uint32_t size;
487 		dev_t dev;
488 		uint64_t fileID;
489 		attrreference_t attr;
490 		char path[MAXLONGPATHLEN];
491 	} __attribute__((aligned(4), packed)) buf;
492 
493 	struct attrlist al = {
494 		.bitmapcount = ATTR_BIT_MAP_COUNT,
495 		.commonattr = ATTR_CMN_DEVID | ATTR_CMN_FILEID,
496 		.forkattr = ATTR_CMNEXT_RELPATH,
497 	};
498 
499 	int rc = getattrlist(inpath, &al, &buf, sizeof(buf), FSOPT_ATTR_CMN_EXTENDED);
500 
501 	if (expected_errno == 0) {
502 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
503 
504 		char *retpath = (char *)&buf.attr + buf.attr.attr_dataoffset;
505 		T_QUIET; T_ASSERT_LT(retpath, (char *)&buf + buf.size, CTXSTR);
506 		T_QUIET; T_ASSERT_LE(retpath + buf.attr.attr_length, (char *)&buf + buf.size, CTXSTR);
507 		T_QUIET; T_ASSERT_TRUE(buf.dev == st.st_dev && buf.fileID == st.st_ino, CTXSTR);
508 	} else {
509 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
510 	}
511 	free(inpath);
512 }
513 
514 static void
test_getattrlist_nofirmlinkpath(size_t pathlen,bool policy,int expected_errno)515 test_getattrlist_nofirmlinkpath(size_t pathlen, bool policy, int expected_errno)
516 {
517 #if !TARGET_OS_OSX
518 	T_QUIET; T_PASS(NULL);
519 	return;
520 #else
521 	char *cwd = getcwd(NULL, 0);
522 	size_t cwdlen = strlen(cwd);
523 
524 	struct {
525 		uint32_t size;
526 		attrreference_t attr;
527 		char mtpt[MAXPATHLEN];
528 	} __attribute__((aligned(4), packed)) mtptbuf;
529 
530 	struct attrlist mtptal = {
531 		.bitmapcount = ATTR_BIT_MAP_COUNT,
532 		.volattr = ATTR_VOL_MOUNTPOINT,
533 	};
534 	T_QUIET; T_ASSERT_POSIX_SUCCESS(getattrlist(cwd, &mtptal, &mtptbuf, sizeof(mtptbuf), 0), NULL);
535 
536 	char *mtpt = (char *)&mtptbuf.attr + mtptbuf.attr.attr_dataoffset;
537 	size_t mtptlen = strlen(mtpt);
538 
539 	if (pathlen + 1 <= mtptlen + cwdlen) {
540 		// Test dir + mount point is longer than pathlen + slash, no sense running the test
541 		free(cwd);
542 		return;
543 	}
544 
545 	/*
546 	 * cwd already has a leading slash, so the -1 below is for the slash that will be put
547 	 * after cwd when build inpath
548 	 */
549 	char *testrelpath = createpath(pathlen - mtptlen - cwdlen - 1, false, NULL);
550 	char *inpath = NULL;
551 	asprintf(&inpath, "%s%s/%s", mtpt, cwd, testrelpath);
552 	free(cwd);
553 	free(testrelpath);
554 	T_QUIET; T_ASSERT_EQ(strlen(inpath), pathlen, CTXSTR);
555 
556 	struct {
557 		uint32_t size;
558 		attrreference_t attr;
559 		char path[MAXLONGPATHLEN];
560 	} __attribute__((aligned(4), packed)) buf;
561 
562 	struct attrlist al = {
563 		.bitmapcount = ATTR_BIT_MAP_COUNT,
564 		.forkattr = ATTR_CMNEXT_NOFIRMLINKPATH,
565 	};
566 
567 	int rc = getattrlist(inpath, &al, &buf, sizeof(buf), FSOPT_ATTR_CMN_EXTENDED);
568 
569 	if (expected_errno == 0) {
570 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
571 
572 		char *retpath = (char *)&buf.attr + buf.attr.attr_dataoffset;
573 		T_QUIET; T_ASSERT_LT(retpath, (char *)&buf + buf.size, CTXSTR);
574 		T_QUIET; T_ASSERT_LE(retpath + buf.attr.attr_length, (char *)&buf + buf.size, CTXSTR);
575 		T_QUIET; T_ASSERT_EQ(strcmp(retpath, inpath), 0, CTXSTR);
576 	} else {
577 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
578 	}
579 	free(inpath);
580 #endif /* !TARGET_OS_OSX */
581 }
582 
583 static void
test_lstat(size_t pathlen,bool policy,int expected_errno)584 test_lstat(size_t pathlen, bool policy, int expected_errno)
585 {
586 	struct stat st;
587 	char *path = createpath(pathlen, false, NULL);
588 	int rc = lstat(path, &st);
589 	free(path);
590 
591 	if (expected_errno == 0) {
592 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
593 	} else {
594 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
595 	}
596 }
597 
598 static void
test_mkdirat(size_t pathlen,bool policy,int expected_errno)599 test_mkdirat(size_t pathlen, bool policy, int expected_errno)
600 {
601 	char *name = "newdir";
602 	size_t parentlen = pathlen - strlen(name) - 1;
603 	char *parent = createpath(parentlen, true, NULL);
604 	char *path = NULL;
605 	asprintf(&path, "%s/%s", parent, name);
606 
607 	int rc = mkdirat(AT_FDCWD, path, 0700);
608 	free(parent);
609 	free(path);
610 
611 	if (expected_errno == 0) {
612 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
613 	} else {
614 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
615 	}
616 }
617 
618 static void
test_open(size_t pathlen,bool policy,int expected_errno)619 test_open(size_t pathlen, bool policy, int expected_errno)
620 {
621 	char *path = createpath(pathlen, false, NULL);
622 	int fd = open(path, O_EVTONLY);
623 	free(path);
624 
625 	if (expected_errno == 0) {
626 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
627 	} else {
628 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
629 	}
630 	if (fd >= 0) {
631 		close(fd);
632 	}
633 }
634 
635 static void
test_open_create(size_t pathlen,bool policy,int expected_errno)636 test_open_create(size_t pathlen, bool policy, int expected_errno)
637 {
638 	char *name = "newfile";
639 	size_t parentlen = pathlen - strlen(name) - 1;
640 	char *parent = createpath(parentlen, true, NULL);
641 	char *path = NULL;
642 	asprintf(&path, "%s/%s", parent, name);
643 
644 	int fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
645 	free(parent);
646 	free(path);
647 
648 	if (expected_errno == 0) {
649 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
650 	} else {
651 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
652 	}
653 	if (fd >= 0) {
654 		close(fd);
655 	}
656 }
657 
658 static void
test_open_volfs(size_t pathlen,bool policy,int expected_errno)659 test_open_volfs(size_t pathlen, bool policy, int expected_errno)
660 {
661 #if !TARGET_OS_OSX
662 	T_QUIET; T_PASS(NULL);
663 	return;
664 #else
665 	char *cwd = getcwd(NULL, 0);
666 	size_t cwdlen = strlen(cwd);
667 	free(cwd);
668 
669 	if (pathlen + 1 <= cwdlen) {
670 		// Test dir is longer than pathlen + slash, no sense running the test
671 		return;
672 	}
673 	size_t relpathlen = pathlen - cwdlen - 1; // -1 for the slash
674 
675 	struct stat st, volst;
676 	free(createpath(relpathlen, false, &st));
677 
678 	char *path = NULL;
679 	asprintf(&path, "/.vol/%d/%llu", st.st_dev, st.st_ino);
680 	int fd = open(path, O_EVTONLY);
681 	free(path);
682 
683 	if (expected_errno == 0) {
684 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
685 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fstat(fd, &volst), CTXSTR);
686 		T_QUIET; T_ASSERT_TRUE(volst.st_dev == st.st_dev && volst.st_ino == st.st_ino,
687 		    CTXFMT " dev %d != %d, ino %llu != %llu",
688 		    CTXARGS, volst.st_dev, st.st_dev, volst.st_ino, st.st_ino);
689 	} else {
690 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
691 	}
692 	if (fd >= 0) {
693 		close(fd);
694 	}
695 #endif /* !TARGET_OS_OSX */
696 }
697 
698 static void
test_openat(size_t pathlen,bool policy,int expected_errno)699 test_openat(size_t pathlen, bool policy, int expected_errno)
700 {
701 	char *path = createpath(pathlen, false, NULL);
702 	int fd = openat(AT_FDCWD, path, O_EVTONLY);
703 	free(path);
704 
705 	if (expected_errno == 0) {
706 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
707 	} else {
708 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
709 	}
710 	if (fd >= 0) {
711 		close(fd);
712 	}
713 }
714 
715 static void
test_openat_create(size_t pathlen,bool policy,int expected_errno)716 test_openat_create(size_t pathlen, bool policy, int expected_errno)
717 {
718 	char *name = "newfile";
719 	size_t parentlen = pathlen - strlen(name) - 1;
720 	char *parent = createpath(parentlen, true, NULL);
721 	char *path = NULL;
722 	asprintf(&path, "%s/%s", parent, name);
723 
724 	int fd = openat(AT_FDCWD, path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
725 	free(parent);
726 	free(path);
727 
728 	if (expected_errno == 0) {
729 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
730 	} else {
731 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
732 	}
733 	if (fd >= 0) {
734 		close(fd);
735 	}
736 }
737 
738 static int openbyid_errno_off[] = {
739 	/* 64 */ 0,
740 	/* NAME_MAX */ 0,
741 	/* MAXPATHLEN - 1 */ ENAMETOOLONG,
742 	/* MAXPATHLEN */ ENAMETOOLONG,
743 	/* MAXPATHLEN + 1 */ ENAMETOOLONG,
744 	/* 2 * MAXPATHLEN */ ENAMETOOLONG,
745 	/* 2 * MAXPATHLEN + 64 */ ENAMETOOLONG,
746 	/* MAXLONGPATHLEN - 1 */ EINVAL,
747 	/* MAXLONGPATHLEN */ EINVAL,
748 	/* MAXLONGPATHLEN + 1 */ EINVAL,
749 	/* MAXLONGPATHLEN + MAXPATHLEN */ EINVAL,
750 };
751 
752 static int openbyid_errno_on[] = {
753 	/* 64 */ 0,
754 	/* NAME_MAX */ 0,
755 	/* MAXPATHLEN - 1 */ 0,
756 	/* MAXPATHLEN */ 0,
757 	/* MAXPATHLEN + 1 */ 0,
758 	/* 2 * MAXPATHLEN */ 0,
759 	/* 2 * MAXPATHLEN + 64 */ 0,
760 	/* MAXLONGPATHLEN - 1 */ EINVAL,
761 	/* MAXLONGPATHLEN */ EINVAL,
762 	/* MAXLONGPATHLEN + 1 */ EINVAL,
763 	/* MAXLONGPATHLEN + MAXPATHLEN */ EINVAL,
764 };
765 
766 static void
test_openbyid_np(size_t pathlen,bool policy,int expected_errno)767 test_openbyid_np(size_t pathlen, bool policy, int expected_errno)
768 {
769 	struct stat st;
770 	char *path = createpath(pathlen, false, &st);
771 	free(path);
772 
773 	fsid_t fsid = {st.st_dev, 0};
774 	uint64_t fsobjid = st.st_ino;
775 	int fd = openbyid_np(&fsid, (fsobj_id_t *)&fsobjid, O_EVTONLY);
776 
777 	if (expected_errno == 0) {
778 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
779 	} else {
780 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
781 	}
782 	if (fd >= 0) {
783 		close(fd);
784 	}
785 }
786 
787 /*
788  * The full paths here are length + strlen("link/") = length + 5
789  */
790 static int path_after_link_errno_off[] = {
791 	/* 64 */ 0,
792 	/* NAME_MAX */ 0,
793 	/* MAXPATHLEN - 1 */ ENAMETOOLONG,
794 	/* MAXPATHLEN */ ENAMETOOLONG,
795 	/* MAXPATHLEN + 1 */ ENAMETOOLONG,
796 	/* 2 * MAXPATHLEN */ ENAMETOOLONG,
797 	/* 2 * MAXPATHLEN + 64 */ ENAMETOOLONG,
798 	/* MAXLONGPATHLEN - 1 */ ENAMETOOLONG,
799 	/* MAXLONGPATHLEN */ ENAMETOOLONG,
800 	/* MAXLONGPATHLEN + 1 */ ENAMETOOLONG,
801 	/* MAXLONGPATHLEN + MAXPATHLEN */ ENAMETOOLONG,
802 };
803 
804 static int path_after_link_errno_on[] = {
805 	/* 64 */ 0,
806 	/* NAME_MAX */ 0,
807 	/* MAXPATHLEN - 1 */ 0,
808 	/* MAXPATHLEN */ 0,
809 	/* MAXPATHLEN + 1 */ 0,
810 	/* 2 * MAXPATHLEN */ 0,
811 	/* 2 * MAXPATHLEN + 64 */ 0,
812 	/* MAXLONGPATHLEN - 1 */ ENAMETOOLONG,
813 	/* MAXLONGPATHLEN */ ENAMETOOLONG,
814 	/* MAXLONGPATHLEN + 1 */ ENAMETOOLONG,
815 	/* MAXLONGPATHLEN + MAXPATHLEN */ ENAMETOOLONG,
816 };
817 
818 static void
test_path_after_link(size_t remaininglen,bool policy,int expected_errno)819 test_path_after_link(size_t remaininglen, bool policy, int expected_errno)
820 {
821 	/*
822 	 * Create path of the form link/... where ... has remaininglen length.
823 	 */
824 
825 	T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir("base", 0700), CTXFMT, remaininglen, onoffstr(policy));
826 	T_QUIET; T_ASSERT_POSIX_SUCCESS(symlink("base", "link"), CTXFMT, remaininglen, onoffstr(policy));
827 
828 	chdir("base");
829 	struct stat origst;
830 	char *remainingpath = createpath(remaininglen - 1, false, &origst); // -1 for the slash
831 	chdir("..");
832 
833 	char *path = NULL;
834 	asprintf(&path, "link/%s", remainingpath);
835 	free(remainingpath);
836 
837 	struct stat st;
838 	int rc = fstatat(AT_FDCWD, path, &st, 0);
839 	free(path);
840 
841 	if (expected_errno == 0) {
842 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXFMT, remaininglen, onoffstr(policy));
843 		T_QUIET; T_ASSERT_TRUE(st.st_dev == origst.st_dev && st.st_ino == origst.st_ino,
844 		    CTXFMT, remaininglen, onoffstr(policy));
845 	} else {
846 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXFMT, remaininglen, onoffstr(policy));
847 	}
848 }
849 
850 static void
test_renameatx_np(size_t pathlen,bool policy,int expected_errno)851 test_renameatx_np(size_t pathlen, bool policy, int expected_errno)
852 {
853 	char *src = createpath(pathlen, false, NULL);
854 	char *dst = strdup(src);
855 
856 	// Change last character in name
857 	dst[pathlen - 1] = '9';
858 
859 	int rc = renameatx_np(AT_FDCWD, src, AT_FDCWD, dst, 0);
860 	free(src);
861 	free(dst);
862 
863 	if (expected_errno == 0) {
864 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
865 	} else {
866 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
867 	}
868 }
869 
870 static void
test_symlink_long2long(size_t pathlen,bool policy,int expected_errno)871 test_symlink_long2long(size_t pathlen, bool policy, int expected_errno)
872 {
873 	char *linkname = "link";
874 	size_t parentlen = pathlen - strlen(linkname) - 1;
875 	char *parent = createpath(parentlen, true, NULL);
876 	char *linkpath = NULL;
877 	asprintf(&linkpath, "%s/%s", parent, linkname);
878 	char *targetpath = NULL;
879 	asprintf(&targetpath, "%s/xpto", parent);
880 	size_t targetlen = strlen(targetpath);
881 
882 	int rc = symlink(targetpath, linkpath);
883 	free(parent);
884 
885 	if (expected_errno == 0) {
886 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
887 
888 		char *buf = emalloc(targetlen + 1);
889 		ssize_t linklen;
890 
891 		T_QUIET; T_ASSERT_POSIX_SUCCESS((linklen = readlink(linkpath, buf, targetlen)), CTXSTR);
892 		T_QUIET; T_ASSERT_EQ((size_t)linklen, targetlen,
893 		    CTXFMT " linklen %zd", CTXARGS, (size_t)linklen);
894 		buf[linklen] = '\0';
895 
896 		T_QUIET; T_ASSERT_EQ(strcmp(buf, targetpath), 0, CTXSTR);
897 		free(targetpath);
898 		free(linkpath);
899 		free(buf);
900 	} else {
901 		free(targetpath);
902 		free(linkpath);
903 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
904 	}
905 }
906 
907 static void
test_symlink_long2short(size_t pathlen,bool policy,int expected_errno)908 test_symlink_long2short(size_t pathlen, bool policy, int expected_errno)
909 {
910 	char *name = "long-link";
911 	size_t parentlen = pathlen - strlen(name) - 1;
912 	char *parent = createpath(parentlen, true, NULL);
913 	char *path = NULL;
914 	asprintf(&path, "%s/%s", parent, name);
915 
916 	char *targetname = "destination.txt";
917 	size_t targetlen = strlen(targetname);
918 	int rc = symlink(targetname, path);
919 	free(parent);
920 
921 	if (expected_errno == 0) {
922 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
923 
924 		char *buf = emalloc(targetlen + 1);
925 		ssize_t linklen;
926 
927 		T_QUIET; T_ASSERT_POSIX_SUCCESS((linklen = readlink(path, buf, targetlen)), CTXSTR);
928 		T_QUIET; T_ASSERT_EQ((size_t)linklen, targetlen,
929 		    CTXFMT " linklen %zd", CTXARGS, (size_t)linklen);
930 		buf[linklen] = '\0';
931 
932 		T_QUIET; T_ASSERT_EQ(strcmp(buf, targetname), 0, CTXSTR);
933 		free(path);
934 		free(buf);
935 	} else {
936 		free(path);
937 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
938 	}
939 }
940 
941 static void
test_symlink_short2long(size_t pathlen,bool policy,int expected_errno)942 test_symlink_short2long(size_t pathlen, bool policy, int expected_errno)
943 {
944 	char *path = createpath(pathlen, false, NULL);
945 	int rc = symlink(path, "short-link");
946 
947 	if (expected_errno == 0) {
948 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
949 
950 		char *buf = emalloc(pathlen + 1);
951 		ssize_t linklen;
952 
953 		T_QUIET; T_ASSERT_POSIX_SUCCESS((linklen = readlink("short-link", buf, pathlen)), CTXSTR);
954 		T_QUIET; T_ASSERT_EQ((size_t)linklen, pathlen,
955 		    CTXFMT " linklen %zd", CTXARGS, (size_t)linklen);
956 		buf[linklen] = '\0';
957 
958 		T_QUIET; T_ASSERT_EQ(strcmp(buf, path), 0, CTXSTR);
959 		free(path);
960 		free(buf);
961 	} else {
962 		free(path);
963 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
964 	}
965 }
966 
967 static void
test_symlink_intermediate(size_t pathlen,bool policy,int expected_errno)968 test_symlink_intermediate(size_t pathlen, bool policy, int expected_errno)
969 {
970 	/*
971 	 * Create path with intermediate symlinks so that linked and original paths
972 	 * are of the same length.
973 	 */
974 	char *path = createpath(pathlen, false, NULL);
975 
976 	// Find parent of path
977 	char *lastslash = strrchr(path, '/');
978 	if (lastslash == NULL || lastslash == path) {
979 		free(path);
980 		return;
981 	}
982 
983 	size_t leaflen = strlen(lastslash + 1);
984 
985 	char *p = lastslash - 1;
986 	while (p - 1 != path && *(p - 1) != '/') {
987 		p--;
988 	}
989 
990 	size_t parentlen = (uintptr_t)(lastslash - p);
991 	char *parentname = emalloc(parentlen + 1);
992 	memmove(parentname, p, parentlen);
993 	parentname[parentlen] = '\0';
994 
995 	// Find grandparent of path, which will be the base path where to create a symlink
996 	size_t baselen = pathlen - parentlen - 1 - 1 - leaflen;
997 	char *basepath = emalloc(baselen + 1);
998 	memmove(basepath, path, baselen);
999 	basepath[baselen] = '\0';
1000 
1001 	// Create symlink
1002 	char *linkname = emalloc(parentlen + 1);
1003 	size_t n = generatename(linkname, parentlen, 49); // repeating Xs
1004 	linkname[n] = '\0';
1005 
1006 	char *linkpath = NULL;
1007 	asprintf(&linkpath, "%s/%s", basepath, linkname);
1008 	free(linkname);
1009 
1010 	T_QUIET; T_ASSERT_EQ(strlen(linkpath) + 1 + leaflen, pathlen, NULL);
1011 
1012 	int rc = symlink(parentname, linkpath);
1013 	free(parentname);
1014 
1015 	if (!policy) {
1016 		if (strlen(linkpath) < MAXPATHLEN) {
1017 			T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1018 		} else {
1019 			T_QUIET; T_ASSERT_POSIX_FAILURE(rc, ENAMETOOLONG, CTXSTR);
1020 		}
1021 	} else {
1022 		if (strlen(linkpath) < MAXLONGPATHLEN) {
1023 			T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1024 		} else {
1025 			T_QUIET; T_ASSERT_POSIX_FAILURE(rc, ENAMETOOLONG, CTXSTR);
1026 		}
1027 	}
1028 
1029 	char *linkedpath = NULL;
1030 	asprintf(&linkedpath, "%s/%s", linkpath, lastslash + 1);
1031 	T_QUIET; T_ASSERT_EQ(strlen(linkedpath), pathlen, NULL);
1032 	free(linkpath);
1033 
1034 	int fd = open(linkedpath, O_EVTONLY);
1035 	free(linkedpath);
1036 
1037 	if (expected_errno == 0) {
1038 		T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, CTXSTR);
1039 	} else {
1040 		T_QUIET; T_ASSERT_POSIX_FAILURE(fd, expected_errno, CTXSTR);
1041 	}
1042 	if (fd >= 0) {
1043 		close(fd);
1044 	}
1045 	free(basepath);
1046 	free(path);
1047 }
1048 
1049 static void
test_unlinkat(size_t pathlen,bool policy,int expected_errno)1050 test_unlinkat(size_t pathlen, bool policy, int expected_errno)
1051 {
1052 	char *path = createpath(pathlen, false, NULL);
1053 	int rc = unlinkat(AT_FDCWD, path, 0);
1054 	free(path);
1055 
1056 	if (expected_errno == 0) {
1057 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1058 	} else {
1059 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
1060 	}
1061 }
1062 
1063 static void
test_xattr(size_t pathlen,bool policy,int expected_errno)1064 test_xattr(size_t pathlen, bool policy, int expected_errno)
1065 {
1066 	char *path = createpath(pathlen, false, NULL);
1067 	char *name = "lpattr";
1068 	char *value = "xpto";
1069 	ssize_t valuelen = strlen(value);
1070 
1071 	int rc = setxattr(path, name, value, valuelen, 0, XATTR_CREATE);
1072 	if (expected_errno == 0) {
1073 		T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, CTXSTR);
1074 	} else {
1075 		T_QUIET; T_ASSERT_POSIX_FAILURE(rc, expected_errno, CTXSTR);
1076 	}
1077 
1078 	char *buf = emalloc(valuelen);
1079 	ssize_t attrlen = getxattr(path, name, buf, valuelen, 0, XATTR_CREATE);
1080 	free(path);
1081 	if (expected_errno == 0) {
1082 		T_QUIET; T_ASSERT_POSIX_SUCCESS(attrlen, CTXSTR);
1083 		T_QUIET; T_ASSERT_EQ(attrlen, valuelen, CTXSTR);
1084 		T_QUIET; T_ASSERT_EQ(0, memcmp(buf, value, valuelen), CTXSTR);
1085 	} else {
1086 		T_QUIET; T_ASSERT_POSIX_FAILURE(attrlen, expected_errno, CTXSTR);
1087 	}
1088 	free(buf);
1089 }
1090 
1091 #define SYSCALL_TEST(name, expected_errno_off, expected_errno_on) \
1092 T_DECL(longpaths_ ## name ## _test, "Test " #name " with long paths") \
1093 {\
1094 	char *testdir = setup_test_dir(#name);\
1095 \
1096 	disable_policy();\
1097 	bool policy = false;\
1098 	for (size_t i = 0; i < nelem(pathlengths); i++) {\
1099 	        size_t pathlen = pathlengths[i];\
1100 	        setup_case_dir(pathlen, policy);\
1101 	        test_ ## name (pathlen, policy, (expected_errno_off)[i]);\
1102 	        chdir("..");\
1103 	}\
1104 \
1105 	enable_policy();\
1106 	policy = true;\
1107 	for (size_t i = 0; i < nelem(pathlengths); i++) {\
1108 	        size_t pathlen = pathlengths[i];\
1109 	        setup_case_dir(pathlen, policy);\
1110 	        test_ ##name (pathlen, policy, (expected_errno_on)[i]);\
1111 	        chdir("..");\
1112 	}\
1113 \
1114 	removefile(testdir, NULL, REMOVEFILE_RECURSIVE | REMOVEFILE_ALLOW_LONG_PATHS);\
1115 	free(testdir);\
1116 }
1117 
1118 SYSCALL_TEST(access, common_errno_off, common_errno_on)
1119 SYSCALL_TEST(faccessat, common_errno_off, common_errno_on)
1120 SYSCALL_TEST(fstatat, common_errno_off, common_errno_on)
1121 SYSCALL_TEST(F_GETPATH, F_GETPATH_errno, F_GETPATH_errno)
1122 
1123 SYSCALL_TEST(getattrlist_fileID, common_errno_off, common_errno_on)
1124 SYSCALL_TEST(getattrlist_nofirmlinkpath, common_errno_off, common_errno_on)
1125 SYSCALL_TEST(getattrlist_fullpath, common_errno_off, common_errno_on)
1126 SYSCALL_TEST(getattrlist_relpath, common_errno_off, common_errno_on)
1127 
1128 SYSCALL_TEST(lstat, common_errno_off, common_errno_on)
1129 SYSCALL_TEST(mkdirat, common_errno_off, common_errno_on)
1130 
1131 SYSCALL_TEST(open, common_errno_off, common_errno_on)
1132 SYSCALL_TEST(open_create, common_errno_off, common_errno_on)
1133 SYSCALL_TEST(open_volfs, common_errno_on, common_errno_on)
1134 
1135 SYSCALL_TEST(openat, common_errno_off, common_errno_on)
1136 SYSCALL_TEST(openat_create, common_errno_off, common_errno_on)
1137 
1138 SYSCALL_TEST(openbyid_np, openbyid_errno_off, openbyid_errno_on)
1139 SYSCALL_TEST(path_after_link, path_after_link_errno_off, path_after_link_errno_on)
1140 SYSCALL_TEST(renameatx_np, common_errno_off, common_errno_on)
1141 
1142 SYSCALL_TEST(symlink_intermediate, common_errno_off, common_errno_on)
1143 // Even with the policy on, we should fail when symlinks target long paths
1144 SYSCALL_TEST(symlink_long2long, common_errno_off, common_errno_off)
1145 SYSCALL_TEST(symlink_long2short, common_errno_off, common_errno_on)
1146 SYSCALL_TEST(symlink_short2long, common_errno_off, common_errno_off)
1147 
1148 SYSCALL_TEST(unlinkat, common_errno_off, common_errno_on)
1149 SYSCALL_TEST(xattr, common_errno_off, common_errno_on)
1150