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