xref: /xnu-12377.81.4/tests/vfs/getattrlist_fullpath.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /* compile: xcrun -sdk macosx.internal clang -ldarwintest -o getattrlist_fullpath getattrlist_fullpath.c -g -Weverything */
2 
3 #include <errno.h>
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/attr.h>
9 
10 #include <darwintest.h>
11 #include <darwintest_utils.h>
12 
13 #define MAXLONGPATHLEN 4096
14 
15 T_GLOBAL_META(
16 	T_META_NAMESPACE("xnu.vfs"),
17 	T_META_RADAR_COMPONENT_NAME("xnu"),
18 	T_META_RADAR_COMPONENT_VERSION("vfs"),
19 	T_META_ASROOT(false),
20 	T_META_CHECK_LEAKS(false));
21 
22 static char *
fast_realpath(const char * path,bool follow)23 fast_realpath(const char *path, bool follow)
24 {
25 	struct {
26 		uint32_t        size;
27 		attrreference_t fullPathAttr;
28 		char            fullPathBuf[MAXLONGPATHLEN];
29 	} __attribute__((aligned(4), packed)) buf;
30 
31 	struct attrlist al = {
32 		.bitmapcount = ATTR_BIT_MAP_COUNT,
33 		.commonattr = ATTR_CMN_FULLPATH,
34 	};
35 
36 	unsigned int options = FSOPT_ATTR_CMN_EXTENDED;
37 	if (!follow) {
38 		options |= FSOPT_NOFOLLOW;
39 	}
40 
41 	if (getattrlist(path, &al, &buf, sizeof(buf), options) < 0) {
42 		return NULL;
43 	}
44 
45 	return strdup((char *)&buf.fullPathAttr + buf.fullPathAttr.attr_dataoffset);
46 }
47 
48 static void
test_realpath(char * input,char * output)49 test_realpath(char *input, char *output)
50 {
51 	T_ASSERT_EQ_STR(fast_realpath(input, false), output, "Testing input '%s', output '%s'", input, output);
52 }
53 
54 T_DECL(getattrlist_fullpath,
55     "getattrlist ATTR_CMN_FULLPATH should preserve input path prefix in output")
56 {
57 	test_realpath("/private/etc/hosts", "/private/etc/hosts");
58 	test_realpath("/etc/hosts", "/private/etc/hosts");
59 
60 	/* Test for .nofollow prefix */
61 	test_realpath("/.nofollow/etc/hosts", NULL);
62 	test_realpath("/.nofollow/private/etc/hosts", "/.nofollow/private/etc/hosts");
63 
64 	/* Test for RESOLVE_NOFOLLOW_ANY resolve prefix */
65 	test_realpath("/.resolve/1/etc/hosts", NULL);
66 	test_realpath("/.resolve/1/private/etc/hosts", "/.resolve/1/private/etc/hosts");
67 }
68