]>
Commit | Line | Data |
---|---|---|
1 | // See <rdar://16977080> | |
2 | ||
3 | #include <unistd.h> | |
4 | #include <sys/fcntl.h> | |
5 | #include <stdio.h> | |
6 | #include <stdbool.h> | |
7 | #include <stdarg.h> | |
8 | #include <stdlib.h> | |
9 | #include <string.h> | |
10 | #include <sys/errno.h> | |
11 | #include <sys/mman.h> | |
12 | #include <sys/xattr.h> | |
13 | #include <sys/mount.h> | |
14 | #include <sys/param.h> | |
15 | #include <TargetConditionals.h> | |
16 | ||
17 | #include "hfs-tests.h" | |
18 | #include "test-utils.h" | |
19 | #include "disk-image.h" | |
20 | ||
21 | TEST(set_protection_class) | |
22 | ||
23 | static char *path; | |
24 | static int pass; | |
25 | ||
26 | int run_set_protection_class(__unused test_ctx_t *ctx) | |
27 | { | |
28 | const char *tstdir; | |
29 | ||
30 | #if TARGET_OS_EMBEDDED | |
31 | // The root file system needs to be HFS | |
32 | struct statfs sfs; | |
33 | ||
34 | assert(statfs("/tmp", &sfs) == 0); | |
35 | if (strcmp(sfs.f_fstypename, "hfs")) { | |
36 | printf("set_protection_class needs hfs as root file system - skipping.\n"); | |
37 | return 0; | |
38 | } | |
39 | ||
40 | tstdir = "/tmp"; | |
41 | #else // !TARGET_OS_EMBEDDED | |
42 | disk_image_t *di = disk_image_get(); | |
43 | tstdir = di->mount_point; | |
44 | #endif | |
45 | ||
46 | asprintf(&path, "%s/set-protection-class.data.%u", tstdir, getpid()); | |
47 | ||
48 | const size_t size = 16 * 1024 * 1024; | |
49 | ||
50 | void *buf = valloc(size), *buf2 = valloc(size); | |
51 | memset(buf, 0x1f, size); | |
52 | ||
53 | /* | |
54 | * Pass 0: Write files using write and then call | |
55 | * F_SETPROTECTIONCLASS while the file is still referenced | |
56 | * i.e. file won't go through inactive. | |
57 | * | |
58 | * Pass 1: Like pass 0 but file should go through inactive. | |
59 | * | |
60 | * Pass 2: Like pass 0 but using resource fork to reference file. | |
61 | * | |
62 | * Pass 3: Like pass 0 but use mmap to write the data. | |
63 | * | |
64 | * Pass 4: Like pass 3 but we close the file after mmap which will | |
65 | * mean the file goes through inactive when we do the | |
66 | * munmap. | |
67 | * | |
68 | */ | |
69 | ||
70 | for (pass = 0; pass < 5; ++pass) { | |
71 | unlink(path); | |
72 | int fd; | |
73 | assert_with_errno((fd = open(path, O_RDWR | O_TRUNC | O_CREAT, 0666)) >= 0); | |
74 | ||
75 | switch (pass) { | |
76 | default: | |
77 | { | |
78 | size_t done = 0; | |
79 | while (done < size) { | |
80 | size_t todo = random() % 1024 + 1; | |
81 | if (todo > size - done) | |
82 | todo = size - done; | |
83 | ||
84 | check_io(write(fd, buf + done, todo), todo); | |
85 | ||
86 | done += todo; | |
87 | } | |
88 | } | |
89 | break; | |
90 | case 3: | |
91 | case 4: | |
92 | { | |
93 | void *p; | |
94 | ||
95 | assert_no_err(ftruncate(fd, size)); | |
96 | assert_with_errno((p = mmap(NULL, size, PROT_READ | PROT_WRITE, | |
97 | MAP_SHARED, fd, 0)) != MAP_FAILED); | |
98 | ||
99 | if (pass == 4) | |
100 | assert_no_err(close(fd)); | |
101 | ||
102 | size_t done = 0; | |
103 | while (done < size) { | |
104 | size_t todo = random() % 1024 + 1; | |
105 | if (todo > size - done) | |
106 | todo = size - done; | |
107 | ||
108 | memcpy(p + done, buf + done, todo); | |
109 | ||
110 | done += todo; | |
111 | } | |
112 | ||
113 | assert_no_err(msync(p, size, MS_ASYNC)); | |
114 | ||
115 | assert_no_err(munmap(p, size)); | |
116 | } | |
117 | break; | |
118 | } | |
119 | ||
120 | int fd2 = -1; | |
121 | switch (pass) { | |
122 | default: | |
123 | assert_with_errno((fd2 = open(path, O_RDONLY)) >= 0); | |
124 | break; | |
125 | case 1: | |
126 | break; | |
127 | case 2: | |
128 | { | |
129 | // Force the rsrc fork vnode to be created | |
130 | static const char val[] = "set-protection-class-test"; | |
131 | assert_with_errno(!setxattr(path, XATTR_RESOURCEFORK_NAME, val, | |
132 | sizeof(val) - 1, 0, 0)); | |
133 | break; | |
134 | } | |
135 | } | |
136 | ||
137 | if (pass != 4) | |
138 | assert_no_err(close(fd)); | |
139 | ||
140 | assert_with_errno((fd = open(path, O_RDWR)) >= 0); | |
141 | ||
142 | #if TARGET_OS_EMBEDDED | |
143 | assert_no_err(fcntl(fd, F_SETPROTECTIONCLASS, 2)); | |
144 | #endif | |
145 | ||
146 | void *p; | |
147 | ||
148 | assert_with_errno((p = mmap(NULL, size, PROT_WRITE, MAP_SHARED, | |
149 | fd, 0)) != MAP_FAILED); | |
150 | ||
151 | assert_no_err(msync(p, size, MS_INVALIDATE)); | |
152 | ||
153 | bzero(buf2, size); | |
154 | check_io(pread(fd, buf2, size, 0), size); | |
155 | ||
156 | assert(!memcmp(buf2, buf, size)); | |
157 | ||
158 | assert_no_err(close(fd)); | |
159 | if (fd2 != -1) | |
160 | assert_no_err(close(fd2)); | |
161 | } | |
162 | ||
163 | unlink(path); | |
164 | ||
165 | return 0; | |
166 | } |