]>
Commit | Line | Data |
---|---|---|
558d2836 A |
1 | #include <TargetConditionals.h> |
2 | ||
de8ee011 | 3 | #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) |
558d2836 A |
4 | |
5 | #include <unistd.h> | |
6 | #include <fcntl.h> | |
7 | #include <stdio.h> | |
8 | #include <sys/mman.h> | |
9 | #include <string.h> | |
10 | #include <sys/attr.h> | |
11 | #include <sys/stat.h> | |
12 | #include <sys/sysctl.h> | |
13 | #include <System/sys/fsgetpath.h> | |
14 | #include <hfs/hfs_fsctl.h> | |
de8ee011 A |
15 | #include <sys/mount.h> |
16 | #include <sys/param.h> | |
558d2836 A |
17 | |
18 | #include "hfs-tests.h" | |
19 | #include "test-utils.h" | |
20 | ||
21 | TEST(list_ids, .run_as_root = true) | |
22 | ||
23 | #define MAX_FILES 100 | |
24 | #define KB *1024 | |
25 | #define F_RECYCLE 84 | |
26 | ||
27 | static struct attrs { | |
28 | uint32_t len; | |
29 | uint64_t file_id; | |
30 | uint32_t dp_flags; | |
31 | } __attribute__((aligned(4), packed)) attrs[MAX_FILES]; | |
32 | ||
33 | static char *path[MAX_FILES]; | |
34 | static int fd[MAX_FILES]; | |
35 | ||
36 | static uint32_t max_ids = 1000000; | |
37 | static uint32_t max_ids_per_iter = 262144; | |
38 | ||
39 | int run_list_ids(__unused test_ctx_t *ctx) | |
40 | { | |
41 | // The data partition needs to be HFS | |
42 | struct statfs sfs; | |
43 | ||
44 | assert(statfs("/private/var", &sfs) == 0); | |
45 | if (strcmp(sfs.f_fstypename, "hfs")) { | |
46 | printf("list_ids needs hfs on the data partition.\n"); | |
47 | return 0; | |
48 | } | |
49 | ||
50 | unsigned i; | |
51 | uint32_t *file_ids = malloc(4 * max_ids); | |
52 | uint32_t count = 0; | |
53 | ||
54 | bzero(file_ids, 4 * max_ids); | |
55 | ||
56 | struct listxattrid_cp listxattrid_file_ids = { | |
57 | .flags = (LSXCP_PROT_CLASS_A | LSXCP_PROT_CLASS_B | |
58 | | LSXCP_PROT_CLASS_C | LSXCP_UNROLLED_KEYS), | |
59 | }; | |
60 | ||
61 | do { | |
62 | listxattrid_file_ids.count = max_ids_per_iter; | |
63 | listxattrid_file_ids.fileid = file_ids + count; | |
64 | ||
65 | assert_no_err(fsctl("/private/var", HFSIOC_LISTXATTRID_CP, &listxattrid_file_ids, 0)); | |
66 | ||
67 | count += listxattrid_file_ids.count; | |
68 | assert(count < max_ids); | |
69 | } while (count == max_ids_per_iter); | |
70 | ||
71 | void *buf = malloc(1 KB); | |
72 | memset(buf, 0x25, 1 KB); | |
73 | ||
74 | for (unsigned i = 0; i < MAX_FILES; i ++) { | |
75 | ||
76 | asprintf(&path[i], "/private/var/get-matched_listid.data.%u", getpid()+i); | |
77 | unlink(path[i]); | |
78 | ||
79 | assert_with_errno((fd[i] = open(path[i], O_RDWR | O_TRUNC | O_CREAT, 0666)) >= 0); | |
80 | ||
81 | // Write 1 kB | |
82 | check_io(write(fd[i], buf, 1 KB), 1 KB); | |
83 | ||
84 | // Change file to class B | |
85 | assert_no_err(fcntl(fd[i], F_SETPROTECTIONCLASS, 2)); | |
86 | ||
87 | struct attrlist attrlist = { | |
88 | .bitmapcount = ATTR_BIT_MAP_COUNT, | |
89 | .commonattr = ATTR_CMN_FILEID | ATTR_CMN_DATA_PROTECT_FLAGS, | |
90 | }; | |
91 | ||
92 | assert_no_err(fgetattrlist(fd[i], &attrlist, &attrs[i], sizeof(attrs), 0)); | |
93 | assert((attrs[i].dp_flags & 0x1f) == 2); | |
94 | ||
95 | } | |
96 | ||
97 | bool release_build = false; | |
98 | ||
99 | if (fcntl(fd[0], F_RECYCLE)) { | |
100 | assert_equal_int(errno, ENOTTY); | |
101 | release_build = true; | |
102 | } | |
103 | ||
104 | // HFS_KR_OP_SET_INFO doesn't run in releae build. | |
105 | if (release_build) | |
106 | goto exit; | |
107 | ||
108 | for (unsigned i = 0; i < MAX_FILES; i ++) { | |
109 | ||
110 | hfs_key_roll_args_t args; | |
111 | ||
112 | // Change the revision and os version | |
113 | args.api_version = HFS_KR_API_LATEST_VERSION; | |
114 | args.operation = HFS_KR_OP_SET_INFO; | |
115 | args.key_revision = 0x0200; | |
116 | args.key_os_version = CP_OS_VERS_PRE_71; | |
117 | assert_no_err(ffsctl(fd[i], HFSIOC_KEY_ROLL, &args, 0)); | |
118 | ||
119 | args.operation = HFS_KR_OP_STATUS; | |
120 | assert_no_err(ffsctl(fd[i], HFSIOC_KEY_ROLL, &args, 0)); | |
121 | ||
122 | assert(args.done == -1 | |
123 | && args.key_revision == 0x0200 | |
124 | && args.key_os_version == CP_OS_VERS_PRE_71); | |
125 | ||
126 | } | |
127 | ||
128 | max_ids_per_iter = 48; | |
129 | count = 0; | |
130 | bzero(file_ids, 4 * max_ids); | |
131 | ||
132 | struct cp_listids list_file_ids = { | |
133 | .api_version = CPLIDS_API_VERSION_1, | |
134 | .flags = CPLID_MAX_OS_VERSION | CPLID_PROT_CLASS_B, | |
135 | .max_key_os_version = CP_OS_VERS_71, | |
136 | }; | |
137 | ||
138 | do { | |
139 | list_file_ids.count = max_ids_per_iter; | |
140 | list_file_ids.file_ids = file_ids + count; | |
141 | ||
142 | if (fsctl("/private/var", HFSIOC_CP_LIST_IDS, &list_file_ids, 0) < 0) { | |
143 | assert_with_errno(errno == EINTR); | |
144 | count = 0; | |
145 | bzero(list_file_ids.state, sizeof(list_file_ids.state)); | |
146 | continue; | |
147 | } | |
148 | count += list_file_ids.count; | |
149 | ||
150 | assert(count < max_ids); | |
151 | ||
152 | } while (list_file_ids.count == max_ids_per_iter); | |
153 | ||
154 | assert(count == MAX_FILES); | |
155 | ||
156 | statfs("/private/var", &sfs); | |
157 | ||
158 | for (i = 0; i < count; i++) { | |
159 | char path_name[PATH_MAX]; | |
160 | ||
161 | if (fsgetpath(path_name, sizeof(path), &sfs.f_fsid, | |
162 | (uint64_t)file_ids[i]) < 0) { | |
163 | assert_with_errno(errno == ENOENT); | |
164 | continue; | |
165 | } | |
166 | assert(file_ids[i] == attrs[i].file_id); | |
167 | } | |
168 | ||
169 | exit: | |
170 | ||
171 | free(buf); | |
172 | free(file_ids); | |
173 | ||
174 | for (i = 0; i < MAX_FILES; i++) { | |
175 | assert_no_err(close(fd[i])); | |
176 | if (path[i]) { | |
177 | unlink(path[i]); | |
178 | free(path[i]); | |
179 | } | |
180 | } | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
de8ee011 | 185 | #endif // (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) |