]> git.saurik.com Git - apple/hfs.git/blob - tests/cases/test-set-protection-class.c
55751f3e7eda89521361ff23877c90de0bcdf1c7
[apple/hfs.git] / tests / cases / test-set-protection-class.c
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_IPHONE && !TARGET_OS_SIMULATOR)
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_IPHONE && !TARGET_OS_SIMULATOR)
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_IPHONE && !TARGET_OS_SIMULATOR)
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 assert_no_err(munmap(p, size));
163 }
164
165 unlink(path);
166 free(buf);
167 free(buf2);
168
169 return 0;
170 }