xref: /optee_os/core/tee/fs_dirfile.c (revision b1469ba0bfd0371eb52bd50f5c52eeda7a8f5f1e)
1 /*
2  * Copyright (c) 2017, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <assert.h>
29 #include <bitstring.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <tee/fs_dirfile.h>
34 #include <types_ext.h>
35 
36 struct tee_fs_dirfile_dirh {
37 	const struct tee_fs_dirfile_operations *fops;
38 	struct tee_file_handle *fh;
39 	int nbits;
40 	bitstr_t *files;
41 	size_t ndents;
42 };
43 
44 struct dirfile_entry {
45 	TEE_UUID uuid;
46 	uint8_t oid[TEE_OBJECT_ID_MAX_LEN];
47 	uint32_t oidlen;
48 	uint8_t hash[TEE_FS_HTREE_HASH_SIZE];
49 	uint32_t file_number;
50 };
51 
52 /*
53  * File layout
54  *
55  * dirfile_entry.0
56  * ...
57  * dirfile_entry.n
58  *
59  * where n the index is disconnected from file_number in struct dirfile_entry
60  */
61 
62 static TEE_Result maybe_grow_files(struct tee_fs_dirfile_dirh *dirh, int idx)
63 {
64 	void *p;
65 
66 	if (idx < dirh->nbits)
67 		return TEE_SUCCESS;
68 
69 	p = realloc(dirh->files, bitstr_size(idx + 1));
70 	if (!p)
71 		return TEE_ERROR_OUT_OF_MEMORY;
72 	dirh->files = p;
73 
74 	bit_nclear(dirh->files, dirh->nbits, idx);
75 	dirh->nbits = idx + 1;
76 
77 	return TEE_SUCCESS;
78 }
79 
80 static TEE_Result set_file(struct tee_fs_dirfile_dirh *dirh, int idx)
81 {
82 	TEE_Result res = maybe_grow_files(dirh, idx);
83 
84 	if (!res)
85 		bit_set(dirh->files, idx);
86 
87 	return res;
88 }
89 
90 static void clear_file(struct tee_fs_dirfile_dirh *dirh, int idx)
91 {
92 	if (idx < dirh->nbits)
93 		bit_clear(dirh->files, idx);
94 }
95 
96 static bool test_file(struct tee_fs_dirfile_dirh *dirh, int idx)
97 {
98 	if (idx < dirh->nbits)
99 		return bit_test(dirh->files, idx);
100 
101 	return false;
102 }
103 
104 static TEE_Result read_dent(struct tee_fs_dirfile_dirh *dirh, int idx,
105 			    struct dirfile_entry *dent)
106 {
107 	TEE_Result res;
108 	size_t l;
109 
110 	l = sizeof(*dent);
111 	res = dirh->fops->read(dirh->fh, sizeof(struct dirfile_entry) * idx,
112 			       dent, &l);
113 	if (!res && l != sizeof(*dent))
114 		res = TEE_ERROR_ITEM_NOT_FOUND;
115 
116 	return res;
117 }
118 
119 static TEE_Result write_dent(struct tee_fs_dirfile_dirh *dirh, size_t n,
120 			     struct dirfile_entry *dent)
121 {
122 	TEE_Result res;
123 
124 	res = dirh->fops->write(dirh->fh, sizeof(*dent) * n,
125 				dent, sizeof(*dent));
126 	if (!res && n >= dirh->ndents)
127 		dirh->ndents = n + 1;
128 
129 	return res;
130 }
131 
132 TEE_Result tee_fs_dirfile_open(bool create, uint8_t *hash,
133 			       const struct tee_fs_dirfile_operations *fops,
134 			       struct tee_fs_dirfile_dirh **dirh_ret)
135 {
136 	TEE_Result res;
137 	struct tee_fs_dirfile_dirh *dirh = calloc(1, sizeof(*dirh));
138 	size_t n;
139 
140 	if (!dirh)
141 		return TEE_ERROR_OUT_OF_MEMORY;
142 
143 	dirh->fops = fops;
144 	res = fops->open(create, hash, NULL, NULL, &dirh->fh);
145 	if (res)
146 		goto out;
147 
148 	for (n = 0;; n++) {
149 		struct dirfile_entry dent;
150 
151 		res = read_dent(dirh, n, &dent);
152 		if (res) {
153 			if (res == TEE_ERROR_ITEM_NOT_FOUND)
154 				res = TEE_SUCCESS;
155 			goto out;
156 		}
157 
158 		if (!dent.oidlen)
159 			continue;
160 
161 		if (test_file(dirh, dent.file_number)) {
162 			DMSG("clearing duplicate file number %" PRIu32,
163 			     dent.file_number);
164 			memset(&dent, 0, sizeof(dent));
165 			res = write_dent(dirh, n, &dent);
166 			if (res)
167 				goto out;
168 			continue;
169 		}
170 
171 		res = set_file(dirh, dent.file_number);
172 		if (res != TEE_SUCCESS)
173 			goto out;
174 	}
175 out:
176 	if (!res) {
177 		dirh->ndents = n;
178 		*dirh_ret = dirh;
179 	} else {
180 		tee_fs_dirfile_close(dirh);
181 	}
182 	return res;
183 }
184 
185 void tee_fs_dirfile_close(struct tee_fs_dirfile_dirh *dirh)
186 {
187 	if (dirh) {
188 		dirh->fops->close(dirh->fh);
189 		free(dirh->files);
190 		free(dirh);
191 	}
192 }
193 
194 TEE_Result tee_fs_dirfile_commit_writes(struct tee_fs_dirfile_dirh *dirh,
195 					uint8_t *hash)
196 {
197 	return dirh->fops->commit_writes(dirh->fh, hash);
198 }
199 
200 TEE_Result tee_fs_dirfile_get_tmp(struct tee_fs_dirfile_dirh *dirh,
201 				  struct tee_fs_dirfile_fileh *dfh)
202 {
203 	TEE_Result res;
204 	int i = 0;
205 
206 	if (dirh->files) {
207 		bit_ffc(dirh->files, dirh->nbits, &i);
208 		if (i == -1)
209 			i = dirh->nbits;
210 	}
211 
212 	res = set_file(dirh, i);
213 	if (!res)
214 		dfh->file_number = i;
215 
216 	return res;
217 }
218 
219 TEE_Result tee_fs_dirfile_find(struct tee_fs_dirfile_dirh *dirh,
220 			       const TEE_UUID *uuid, const void *oid,
221 			       size_t oidlen, struct tee_fs_dirfile_fileh *dfh)
222 {
223 	TEE_Result res;
224 	struct dirfile_entry dent;
225 	int n;
226 	int first_free = -1;
227 
228 	for (n = 0;; n++) {
229 		res = read_dent(dirh, n, &dent);
230 		if (res == TEE_ERROR_ITEM_NOT_FOUND && !oidlen) {
231 			memset(&dent, 0, sizeof(dent));
232 			if (first_free != -1)
233 				n = first_free;
234 			break;
235 		}
236 		if (res)
237 			return res;
238 
239 		/* TODO check this loop when oidlen == 0 */
240 
241 		if (!dent.oidlen && first_free == -1)
242 			first_free = n;
243 		if (dent.oidlen != oidlen)
244 			continue;
245 
246 		assert(!oidlen || !dent.oidlen ||
247 		       test_file(dirh, dent.file_number));
248 
249 		if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) &&
250 		    !memcmp(&dent.oid, oid, oidlen))
251 			break;
252 	}
253 
254 	if (dfh) {
255 		dfh->idx = n;
256 		dfh->file_number = dent.file_number;
257 		memcpy(dfh->hash, dent.hash, sizeof(dent.hash));
258 	}
259 
260 	return TEE_SUCCESS;
261 }
262 
263 TEE_Result tee_fs_dirfile_fileh_to_fname(const struct tee_fs_dirfile_fileh *dfh,
264 					 char *fname, size_t *fnlen)
265 {
266 	int r;
267 	size_t l = *fnlen;
268 
269 	if (dfh)
270 		r = snprintf(fname, l, "%" PRIx32, dfh->file_number);
271 	else
272 		r = snprintf(fname, l, "dirf.db");
273 
274 	if (r < 0)
275 		return TEE_ERROR_GENERIC;
276 
277 	*fnlen = r + 1;
278 	if ((size_t)r >= l)
279 		return TEE_ERROR_SHORT_BUFFER;
280 
281 	return TEE_SUCCESS;
282 }
283 
284 TEE_Result tee_fs_dirfile_rename(struct tee_fs_dirfile_dirh *dirh,
285 				 const TEE_UUID *uuid,
286 				 struct tee_fs_dirfile_fileh *dfh,
287 				 const void *oid, size_t oidlen)
288 {
289 	TEE_Result res;
290 	struct dirfile_entry dent;
291 
292 	if (!oidlen || oidlen > sizeof(dent.oid))
293 		return TEE_ERROR_BAD_PARAMETERS;
294 	memset(&dent, 0, sizeof(dent));
295 	dent.uuid = *uuid;
296 	memcpy(dent.oid, oid, oidlen);
297 	dent.oidlen = oidlen;
298 	memcpy(dent.hash, dfh->hash, sizeof(dent.hash));
299 	dent.file_number = dfh->file_number;
300 
301 	if (dfh->idx < 0) {
302 		struct tee_fs_dirfile_fileh dfh2;
303 
304 		res = tee_fs_dirfile_find(dirh, uuid, oid, oidlen, &dfh2);
305 		if (res) {
306 			if (res == TEE_ERROR_ITEM_NOT_FOUND)
307 				res = tee_fs_dirfile_find(dirh, uuid, NULL, 0,
308 							  &dfh2);
309 			if (res)
310 				return res;
311 		}
312 		dfh->idx = dfh2.idx;
313 	}
314 
315 	return write_dent(dirh, dfh->idx, &dent);
316 }
317 
318 TEE_Result tee_fs_dirfile_remove(struct tee_fs_dirfile_dirh *dirh,
319 				 const struct tee_fs_dirfile_fileh *dfh)
320 {
321 	TEE_Result res;
322 	struct dirfile_entry dent;
323 	uint32_t file_number;
324 
325 	res = read_dent(dirh, dfh->idx, &dent);
326 	if (res)
327 		return res;
328 
329 	if (!dent.oidlen)
330 		return TEE_SUCCESS;
331 
332 	file_number = dent.file_number;
333 	assert(dfh->file_number == file_number);
334 	assert(test_file(dirh, file_number));
335 
336 	memset(&dent, 0, sizeof(dent));
337 	res = write_dent(dirh, dfh->idx, &dent);
338 	if (!res)
339 		clear_file(dirh, file_number);
340 
341 	return res;
342 }
343 
344 TEE_Result tee_fs_dirfile_update_hash(struct tee_fs_dirfile_dirh *dirh,
345 				      const struct tee_fs_dirfile_fileh *dfh)
346 {
347 	TEE_Result res;
348 	struct dirfile_entry dent;
349 
350 	res = read_dent(dirh, dfh->idx, &dent);
351 	if (res)
352 		return res;
353 	assert(dent.file_number == dfh->file_number);
354 	assert(test_file(dirh, dent.file_number));
355 
356 	memcpy(&dent.hash, dfh->hash, sizeof(dent.hash));
357 
358 	return write_dent(dirh, dfh->idx, &dent);
359 }
360 
361 TEE_Result tee_fs_dirfile_get_next(struct tee_fs_dirfile_dirh *dirh,
362 				   const TEE_UUID *uuid, int *idx, void *oid,
363 				   size_t *oidlen)
364 {
365 	TEE_Result res;
366 	int i = *idx + 1;
367 	struct dirfile_entry dent;
368 
369 	if (i < 0)
370 		i = 0;
371 
372 	for (;; i++) {
373 		res = read_dent(dirh, i, &dent);
374 		if (res)
375 			return res;
376 		if (!memcmp(&dent.uuid, uuid, sizeof(dent.uuid)) &&
377 		    dent.oidlen)
378 			break;
379 	}
380 
381 	if (*oidlen < dent.oidlen)
382 		return TEE_ERROR_SHORT_BUFFER;
383 
384 	memcpy(oid, dent.oid, dent.oidlen);
385 	*oidlen = dent.oidlen;
386 	*idx = i;
387 
388 	return TEE_SUCCESS;
389 }
390