xref: /optee_os/core/tee/tee_ree_fs.c (revision fd108c3e6609cc545dd1d53ea40042bcb28d500e)
1 /*
2  * Copyright (c) 2015, 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 <kernel/mutex.h>
30 #include <kernel/panic.h>
31 #include <kernel/thread.h>
32 #include <mm/core_memprot.h>
33 #include <optee_msg_supplicant.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string_ext.h>
37 #include <string.h>
38 #include <sys/queue.h>
39 #include <tee/fs_dirfile.h>
40 #include <tee/fs_htree.h>
41 #include <tee/tee_cryp_provider.h>
42 #include <tee/tee_fs.h>
43 #include <tee/tee_fs_rpc.h>
44 #include <tee/tee_pobj.h>
45 #include <trace.h>
46 #include <utee_defines.h>
47 #include <util.h>
48 
49 #define BLOCK_SHIFT	12
50 
51 #define BLOCK_SIZE	(1 << BLOCK_SHIFT)
52 
53 struct tee_fs_fd {
54 	struct tee_fs_htree *ht;
55 	int fd;
56 	struct tee_fs_dirfile_fileh dfh;
57 	const TEE_UUID *uuid;
58 };
59 
60 struct tee_fs_dir {
61 	struct tee_fs_dirfile_dirh *dirh;
62 	int idx;
63 	struct tee_fs_dirent d;
64 	const TEE_UUID *uuid;
65 };
66 
67 static int pos_to_block_num(int position)
68 {
69 	return position >> BLOCK_SHIFT;
70 }
71 
72 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
73 
74 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, size_t pos,
75 				     const void *buf, size_t len)
76 {
77 	TEE_Result res;
78 	size_t start_block_num = pos_to_block_num(pos);
79 	size_t end_block_num = pos_to_block_num(pos + len - 1);
80 	size_t remain_bytes = len;
81 	uint8_t *data_ptr = (uint8_t *)buf;
82 	uint8_t *block;
83 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
84 
85 	block = malloc(BLOCK_SIZE);
86 	if (!block)
87 		return TEE_ERROR_OUT_OF_MEMORY;
88 
89 	while (start_block_num <= end_block_num) {
90 		size_t offset = pos % BLOCK_SIZE;
91 		size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE);
92 
93 		if (size_to_write + offset > BLOCK_SIZE)
94 			size_to_write = BLOCK_SIZE - offset;
95 
96 		if (start_block_num * BLOCK_SIZE <
97 		    ROUNDUP(meta->length, BLOCK_SIZE)) {
98 			res = tee_fs_htree_read_block(&fdp->ht,
99 						      start_block_num, block);
100 			if (res != TEE_SUCCESS)
101 				goto exit;
102 		} else {
103 			memset(block, 0, BLOCK_SIZE);
104 		}
105 
106 		if (data_ptr)
107 			memcpy(block + offset, data_ptr, size_to_write);
108 		else
109 			memset(block + offset, 0, size_to_write);
110 
111 		res = tee_fs_htree_write_block(&fdp->ht, start_block_num,
112 					       block);
113 		if (res != TEE_SUCCESS)
114 			goto exit;
115 
116 		if (data_ptr)
117 			data_ptr += size_to_write;
118 		remain_bytes -= size_to_write;
119 		start_block_num++;
120 		pos += size_to_write;
121 	}
122 
123 	if (pos > meta->length)
124 		meta->length = pos;
125 
126 exit:
127 	free(block);
128 	return res;
129 }
130 
131 static TEE_Result get_offs_size(enum tee_fs_htree_type type, size_t idx,
132 				uint8_t vers, size_t *offs, size_t *size)
133 {
134 	const size_t node_size = sizeof(struct tee_fs_htree_node_image);
135 	const size_t block_nodes = BLOCK_SIZE / (node_size * 2);
136 	size_t pbn;
137 	size_t bidx;
138 
139 	assert(vers == 0 || vers == 1);
140 
141 	/*
142 	 * File layout
143 	 *
144 	 * phys block 0:
145 	 * tee_fs_htree_image vers 0 @ offs = 0
146 	 * tee_fs_htree_image vers 1 @ offs = sizeof(tee_fs_htree_image)
147 	 *
148 	 * phys block 1:
149 	 * tee_fs_htree_node_image 0  vers 0 @ offs = 0
150 	 * tee_fs_htree_node_image 0  vers 1 @ offs = node_size
151 	 * tee_fs_htree_node_image 1  vers 0 @ offs = node_size * 2
152 	 * tee_fs_htree_node_image 1  vers 1 @ offs = node_size * 3
153 	 * ...
154 	 * tee_fs_htree_node_image 61 vers 0 @ offs = node_size * 122
155 	 * tee_fs_htree_node_image 61 vers 1 @ offs = node_size * 123
156 	 *
157 	 * phys block 2:
158 	 * data block 0 vers 0
159 	 *
160 	 * phys block 3:
161 	 * data block 0 vers 1
162 	 *
163 	 * ...
164 	 * phys block 63:
165 	 * data block 61 vers 0
166 	 *
167 	 * phys block 64:
168 	 * data block 61 vers 1
169 	 *
170 	 * phys block 65:
171 	 * tee_fs_htree_node_image 62  vers 0 @ offs = 0
172 	 * tee_fs_htree_node_image 62  vers 1 @ offs = node_size
173 	 * tee_fs_htree_node_image 63  vers 0 @ offs = node_size * 2
174 	 * tee_fs_htree_node_image 63  vers 1 @ offs = node_size * 3
175 	 * ...
176 	 * tee_fs_htree_node_image 121 vers 0 @ offs = node_size * 122
177 	 * tee_fs_htree_node_image 121 vers 1 @ offs = node_size * 123
178 	 *
179 	 * ...
180 	 */
181 
182 	switch (type) {
183 	case TEE_FS_HTREE_TYPE_HEAD:
184 		*offs = sizeof(struct tee_fs_htree_image) * vers;
185 		*size = sizeof(struct tee_fs_htree_image);
186 		return TEE_SUCCESS;
187 	case TEE_FS_HTREE_TYPE_NODE:
188 		pbn = 1 + ((idx / block_nodes) * block_nodes * 2);
189 		*offs = pbn * BLOCK_SIZE +
190 			2 * node_size * (idx % block_nodes) +
191 			node_size * vers;
192 		*size = node_size;
193 		return TEE_SUCCESS;
194 	case TEE_FS_HTREE_TYPE_BLOCK:
195 		bidx = 2 * idx + vers;
196 		pbn = 2 + bidx + bidx / (block_nodes * 2 - 1);
197 		*offs = pbn * BLOCK_SIZE;
198 		*size = BLOCK_SIZE;
199 		return TEE_SUCCESS;
200 	default:
201 		return TEE_ERROR_GENERIC;
202 	}
203 }
204 
205 static TEE_Result ree_fs_rpc_read_init(void *aux,
206 				       struct tee_fs_rpc_operation *op,
207 				       enum tee_fs_htree_type type, size_t idx,
208 				       uint8_t vers, void **data)
209 {
210 	struct tee_fs_fd *fdp = aux;
211 	TEE_Result res;
212 	size_t offs;
213 	size_t size;
214 
215 	res = get_offs_size(type, idx, vers, &offs, &size);
216 	if (res != TEE_SUCCESS)
217 		return res;
218 
219 	return tee_fs_rpc_read_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
220 				    offs, size, data);
221 }
222 
223 static TEE_Result ree_fs_rpc_write_init(void *aux,
224 					struct tee_fs_rpc_operation *op,
225 					enum tee_fs_htree_type type, size_t idx,
226 					uint8_t vers, void **data)
227 {
228 	struct tee_fs_fd *fdp = aux;
229 	TEE_Result res;
230 	size_t offs;
231 	size_t size;
232 
233 	res = get_offs_size(type, idx, vers, &offs, &size);
234 	if (res != TEE_SUCCESS)
235 		return res;
236 
237 	return tee_fs_rpc_write_init(op, OPTEE_MSG_RPC_CMD_FS, fdp->fd,
238 				     offs, size, data);
239 }
240 
241 static const struct tee_fs_htree_storage ree_fs_storage_ops = {
242 	.block_size = BLOCK_SIZE,
243 	.rpc_read_init = ree_fs_rpc_read_init,
244 	.rpc_read_final = tee_fs_rpc_read_final,
245 	.rpc_write_init = ree_fs_rpc_write_init,
246 	.rpc_write_final = tee_fs_rpc_write_final,
247 };
248 
249 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
250 					    tee_fs_off_t new_file_len)
251 {
252 	TEE_Result res;
253 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
254 
255 	if ((size_t)new_file_len > meta->length) {
256 		size_t ext_len = new_file_len - meta->length;
257 
258 		res = out_of_place_write(fdp, meta->length, NULL, ext_len);
259 		if (res != TEE_SUCCESS)
260 			return res;
261 	} else {
262 		size_t offs;
263 		size_t sz;
264 
265 		res = get_offs_size(TEE_FS_HTREE_TYPE_BLOCK,
266 				    ROUNDUP(new_file_len, BLOCK_SIZE) /
267 					BLOCK_SIZE, 1, &offs, &sz);
268 		if (res != TEE_SUCCESS)
269 			return res;
270 
271 		res = tee_fs_htree_truncate(&fdp->ht,
272 					    new_file_len / BLOCK_SIZE);
273 		if (res != TEE_SUCCESS)
274 			return res;
275 
276 		res = tee_fs_rpc_truncate(OPTEE_MSG_RPC_CMD_FS, fdp->fd,
277 					  offs + sz);
278 		if (res != TEE_SUCCESS)
279 			return res;
280 
281 		meta->length = new_file_len;
282 	}
283 
284 	return TEE_SUCCESS;
285 }
286 
287 static TEE_Result ree_fs_read_primitive(struct tee_file_handle *fh, size_t pos,
288 					void *buf, size_t *len)
289 {
290 	TEE_Result res;
291 	int start_block_num;
292 	int end_block_num;
293 	size_t remain_bytes;
294 	uint8_t *data_ptr = buf;
295 	uint8_t *block = NULL;
296 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
297 	struct tee_fs_htree_meta *meta = tee_fs_htree_get_meta(fdp->ht);
298 
299 	remain_bytes = *len;
300 	if ((pos + remain_bytes) < remain_bytes || pos > meta->length)
301 		remain_bytes = 0;
302 	else if (pos + remain_bytes > meta->length)
303 		remain_bytes = meta->length - pos;
304 
305 	*len = remain_bytes;
306 
307 	if (!remain_bytes) {
308 		res = TEE_SUCCESS;
309 		goto exit;
310 	}
311 
312 	start_block_num = pos_to_block_num(pos);
313 	end_block_num = pos_to_block_num(pos + remain_bytes - 1);
314 
315 	block = malloc(BLOCK_SIZE);
316 	if (!block) {
317 		res = TEE_ERROR_OUT_OF_MEMORY;
318 		goto exit;
319 	}
320 
321 	while (start_block_num <= end_block_num) {
322 		size_t offset = pos % BLOCK_SIZE;
323 		size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE);
324 
325 		if (size_to_read + offset > BLOCK_SIZE)
326 			size_to_read = BLOCK_SIZE - offset;
327 
328 		res = tee_fs_htree_read_block(&fdp->ht, start_block_num, block);
329 		if (res != TEE_SUCCESS)
330 			goto exit;
331 
332 		memcpy(data_ptr, block + offset, size_to_read);
333 
334 		data_ptr += size_to_read;
335 		remain_bytes -= size_to_read;
336 		pos += size_to_read;
337 
338 		start_block_num++;
339 	}
340 	res = TEE_SUCCESS;
341 exit:
342 	free(block);
343 	return res;
344 }
345 
346 static TEE_Result ree_fs_read(struct tee_file_handle *fh, size_t pos,
347 			      void *buf, size_t *len)
348 {
349 	TEE_Result res;
350 
351 	mutex_lock(&ree_fs_mutex);
352 	res = ree_fs_read_primitive(fh, pos, buf, len);
353 	mutex_unlock(&ree_fs_mutex);
354 
355 	return res;
356 }
357 
358 static TEE_Result ree_fs_write_primitive(struct tee_file_handle *fh, size_t pos,
359 					 const void *buf, size_t len)
360 {
361 	TEE_Result res;
362 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
363 	size_t file_size;
364 
365 	if (!len)
366 		return TEE_SUCCESS;
367 
368 	file_size = tee_fs_htree_get_meta(fdp->ht)->length;
369 
370 	if ((pos + len) < len)
371 		return TEE_ERROR_BAD_PARAMETERS;
372 
373 	if (file_size < pos) {
374 		res = ree_fs_ftruncate_internal(fdp, pos);
375 		if (res != TEE_SUCCESS)
376 			return res;
377 	}
378 
379 	return out_of_place_write(fdp, pos, buf, len);
380 }
381 
382 static TEE_Result ree_fs_open_primitive(bool create, const TEE_UUID *uuid,
383 					struct tee_fs_dirfile_fileh *dfh,
384 					struct tee_file_handle **fh)
385 {
386 	TEE_Result res;
387 	struct tee_fs_fd *fdp;
388 	uint8_t *hash = NULL;
389 
390 	fdp = calloc(1, sizeof(struct tee_fs_fd));
391 	if (!fdp)
392 		return TEE_ERROR_OUT_OF_MEMORY;
393 	fdp->fd = -1;
394 	fdp->uuid = uuid;
395 
396 	if (create)
397 		res = tee_fs_rpc_create_dfh(OPTEE_MSG_RPC_CMD_FS,
398 					    dfh, &fdp->fd);
399 	else
400 		res = tee_fs_rpc_open_dfh(OPTEE_MSG_RPC_CMD_FS, dfh, &fdp->fd);
401 
402 	if (res != TEE_SUCCESS)
403 		goto out;
404 
405 	if (dfh)
406 		hash = dfh->hash;
407 	res = tee_fs_htree_open(create, hash, uuid, &ree_fs_storage_ops,
408 				fdp, &fdp->ht);
409 out:
410 	if (res == TEE_SUCCESS) {
411 		if (dfh)
412 			fdp->dfh = *dfh;
413 		else
414 			fdp->dfh.idx = -1;
415 		*fh = (struct tee_file_handle *)fdp;
416 	} else {
417 		if (fdp->fd != -1)
418 			tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
419 		if (create)
420 			tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, dfh);
421 		free(fdp);
422 	}
423 
424 	return res;
425 }
426 
427 static void ree_fs_close_primitive(struct tee_file_handle *fh)
428 {
429 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
430 
431 	if (fdp) {
432 		tee_fs_htree_close(&fdp->ht);
433 		tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_FS, fdp->fd);
434 		free(fdp);
435 	}
436 }
437 
438 static TEE_Result ree_dirf_commit_writes(struct tee_file_handle *fh,
439 					 uint8_t *hash)
440 {
441 	TEE_Result res;
442 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
443 
444 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
445 
446 	if (!res && hash)
447 		memcpy(hash, fdp->dfh.hash, sizeof(fdp->dfh.hash));
448 
449 	return res;
450 }
451 
452 static const struct tee_fs_dirfile_operations ree_dirf_ops = {
453 	.open = ree_fs_open_primitive,
454 	.close = ree_fs_close_primitive,
455 	.read = ree_fs_read_primitive,
456 	.write = ree_fs_write_primitive,
457 	.commit_writes = ree_dirf_commit_writes,
458 };
459 
460 static TEE_Result ree_fs_open(struct tee_pobj *po, size_t *size,
461 			      struct tee_file_handle **fh)
462 {
463 	TEE_Result res;
464 	struct tee_fs_dirfile_dirh *dirh = NULL;
465 	struct tee_fs_dirfile_fileh dfh;
466 
467 	mutex_lock(&ree_fs_mutex);
468 
469 	res = tee_fs_dirfile_open(&ree_dirf_ops, &dirh);
470 	if (res != TEE_SUCCESS)
471 		goto out;
472 
473 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
474 				  &dfh);
475 	if (res != TEE_SUCCESS)
476 		goto out;
477 
478 	res = ree_fs_open_primitive(false, &po->uuid, &dfh, fh);
479 	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
480 		/*
481 		 * If the object isn't found someone has tampered with it,
482 		 * treat it as corrupt.
483 		 */
484 		res = TEE_ERROR_CORRUPT_OBJECT;
485 	} else if (!res && size) {
486 		struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
487 
488 		*size = tee_fs_htree_get_meta(fdp->ht)->length;
489 	}
490 
491 out:
492 	tee_fs_dirfile_close(dirh);
493 	mutex_unlock(&ree_fs_mutex);
494 
495 	return res;
496 }
497 
498 static TEE_Result set_name(struct tee_fs_dirfile_dirh *dirh,
499 			   struct tee_fs_fd *fdp, struct tee_pobj *po,
500 			   bool overwrite)
501 {
502 	TEE_Result res;
503 	bool have_old_dfh = false;
504 	struct tee_fs_dirfile_fileh old_dfh = { .idx = -1 };
505 
506 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
507 				  &old_dfh);
508 	if (!overwrite && !res)
509 		return TEE_ERROR_ACCESS_CONFLICT;
510 
511 	if (!res)
512 		have_old_dfh = true;
513 
514 	/*
515 	 * If old_dfh wasn't found, the idx will be -1 and
516 	 * tee_fs_dirfile_rename() will allocate a new index.
517 	 */
518 	fdp->dfh.idx = old_dfh.idx;
519 	old_dfh.idx = -1;
520 	res = tee_fs_dirfile_rename(dirh, &po->uuid, &fdp->dfh,
521 				    po->obj_id, po->obj_id_len);
522 	if (res)
523 		return res;
524 
525 	res = tee_fs_dirfile_commit_writes(dirh);
526 	if (res)
527 		return res;
528 
529 	if (have_old_dfh)
530 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &old_dfh);
531 
532 	return TEE_SUCCESS;
533 }
534 
535 static void ree_fs_close(struct tee_file_handle **fh)
536 {
537 	ree_fs_close_primitive(*fh);
538 	*fh = NULL;
539 }
540 
541 static TEE_Result ree_fs_create(struct tee_pobj *po, bool overwrite,
542 				const void *head, size_t head_size,
543 				const void *attr, size_t attr_size,
544 				const void *data, size_t data_size,
545 				struct tee_file_handle **fh)
546 {
547 	struct tee_fs_fd *fdp;
548 	struct tee_fs_dirfile_dirh *dirh = NULL;
549 	struct tee_fs_dirfile_fileh dfh;
550 	TEE_Result res;
551 	size_t pos = 0;
552 
553 	*fh = NULL;
554 	mutex_lock(&ree_fs_mutex);
555 
556 	res = tee_fs_dirfile_open(&ree_dirf_ops, &dirh);
557 	if (res)
558 		goto out;
559 
560 	res = tee_fs_dirfile_get_tmp(dirh, &dfh);
561 	if (res)
562 		goto out;
563 
564 	res = ree_fs_open_primitive(true, &po->uuid, &dfh, fh);
565 	if (res)
566 		goto out;
567 
568 	if (head && head_size) {
569 		res = ree_fs_write_primitive(*fh, pos, head, head_size);
570 		if (res)
571 			goto out;
572 		pos += head_size;
573 	}
574 
575 	if (attr && attr_size) {
576 		res = ree_fs_write_primitive(*fh, pos, attr, attr_size);
577 		if (res)
578 			goto out;
579 		pos += attr_size;
580 	}
581 
582 	if (data && data_size) {
583 		res = ree_fs_write_primitive(*fh, pos, data, data_size);
584 		if (res)
585 			goto out;
586 	}
587 
588 	fdp = (struct tee_fs_fd *)*fh;
589 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
590 	if (res)
591 		goto out;
592 
593 	res = set_name(dirh, fdp, po, overwrite);
594 out:
595 	if (res && *fh) {
596 		ree_fs_close(fh);
597 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh);
598 	}
599 	tee_fs_dirfile_close(dirh);
600 	mutex_unlock(&ree_fs_mutex);
601 
602 	return res;
603 }
604 
605 static TEE_Result ree_fs_write(struct tee_file_handle *fh, size_t pos,
606 			       const void *buf, size_t len)
607 {
608 	TEE_Result res;
609 	struct tee_fs_dirfile_dirh *dirh = NULL;
610 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
611 
612 	mutex_lock(&ree_fs_mutex);
613 
614 	res = tee_fs_dirfile_open(&ree_dirf_ops, &dirh);
615 	if (res)
616 		goto out;
617 
618 	res = ree_fs_write_primitive(fh, pos, buf, len);
619 	if (res)
620 		goto out;
621 
622 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
623 	if (res)
624 		goto out;
625 
626 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
627 	if (res)
628 		goto out;
629 	res = tee_fs_dirfile_commit_writes(dirh);
630 out:
631 	tee_fs_dirfile_close(dirh);
632 	mutex_unlock(&ree_fs_mutex);
633 
634 	return res;
635 }
636 
637 static TEE_Result ree_fs_rename(struct tee_pobj *old, struct tee_pobj *new,
638 				bool overwrite)
639 {
640 	TEE_Result res;
641 	struct tee_fs_dirfile_dirh *dirh = NULL;
642 	struct tee_fs_dirfile_fileh dfh;
643 	struct tee_fs_dirfile_fileh remove_dfh = { .idx = -1 };
644 
645 	if (!new)
646 		return TEE_ERROR_BAD_PARAMETERS;
647 
648 	mutex_lock(&ree_fs_mutex);
649 	res = tee_fs_dirfile_open(&ree_dirf_ops, &dirh);
650 	if (res)
651 		goto out;
652 
653 	res = tee_fs_dirfile_find(dirh, &new->uuid, new->obj_id,
654 				  new->obj_id_len, &remove_dfh);
655 	if (!res && !overwrite) {
656 		res = TEE_ERROR_ACCESS_CONFLICT;
657 		goto out;
658 	}
659 
660 	res = tee_fs_dirfile_find(dirh, &old->uuid, old->obj_id,
661 				  old->obj_id_len, &dfh);
662 	if (res)
663 		goto out;
664 
665 	res = tee_fs_dirfile_rename(dirh, &new->uuid, &dfh, new->obj_id,
666 				    new->obj_id_len);
667 	if (res)
668 		goto out;
669 
670 	if (remove_dfh.idx != -1) {
671 		res = tee_fs_dirfile_remove(dirh, &remove_dfh);
672 		if (res)
673 			goto out;
674 	}
675 
676 	res = tee_fs_dirfile_commit_writes(dirh);
677 	if (res)
678 		goto out;
679 
680 	if (remove_dfh.idx != -1)
681 		tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &remove_dfh);
682 
683 out:
684 	tee_fs_dirfile_close(dirh);
685 	mutex_unlock(&ree_fs_mutex);
686 
687 	return res;
688 
689 }
690 
691 static TEE_Result ree_fs_remove(struct tee_pobj *po)
692 {
693 	TEE_Result res;
694 	struct tee_fs_dirfile_dirh *dirh = NULL;
695 	struct tee_fs_dirfile_fileh dfh;
696 
697 	mutex_lock(&ree_fs_mutex);
698 	res = tee_fs_dirfile_open(&ree_dirf_ops, &dirh);
699 	if (res)
700 		goto out;
701 
702 	res = tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
703 				  &dfh);
704 	if (res)
705 		goto out;
706 
707 	res = tee_fs_dirfile_remove(dirh, &dfh);
708 	if (res)
709 		goto out;
710 
711 	res = tee_fs_dirfile_commit_writes(dirh);
712 	if (res)
713 		goto out;
714 
715 	tee_fs_rpc_remove_dfh(OPTEE_MSG_RPC_CMD_FS, &dfh);
716 
717 	assert(tee_fs_dirfile_find(dirh, &po->uuid, po->obj_id, po->obj_id_len,
718 				   &dfh));
719 out:
720 	tee_fs_dirfile_close(dirh);
721 	mutex_unlock(&ree_fs_mutex);
722 
723 	return res;
724 }
725 
726 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
727 {
728 	TEE_Result res;
729 	struct tee_fs_dirfile_dirh *dirh = NULL;
730 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
731 
732 	mutex_lock(&ree_fs_mutex);
733 
734 	res = tee_fs_dirfile_open(&ree_dirf_ops, &dirh);
735 	if (res != TEE_SUCCESS)
736 		goto out;
737 
738 	res = ree_fs_ftruncate_internal(fdp, len);
739 	if (!res)
740 		goto out;
741 
742 	res = tee_fs_htree_sync_to_storage(&fdp->ht, fdp->dfh.hash);
743 	if (!res)
744 		goto out;
745 
746 	res = tee_fs_dirfile_update_hash(dirh, &fdp->dfh);
747 
748 out:
749 	tee_fs_dirfile_close(dirh);
750 	mutex_unlock(&ree_fs_mutex);
751 
752 	return res;
753 }
754 
755 static TEE_Result ree_fs_opendir_rpc(const TEE_UUID *uuid,
756 				     struct tee_fs_dir **dir)
757 
758 {
759 	TEE_Result res;
760 	struct tee_fs_dir *d = calloc(1, sizeof(*d));
761 
762 	if (!d)
763 		return TEE_ERROR_OUT_OF_MEMORY;
764 
765 	d->uuid = uuid;
766 
767 	mutex_lock(&ree_fs_mutex);
768 
769 	res = tee_fs_dirfile_open(&ree_dirf_ops, &d->dirh);
770 	if (res)
771 		goto out;
772 
773 	/* See that there's at least one file */
774 	d->idx = -1;
775 	d->d.oidlen = sizeof(d->d.oid);
776 	res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid,
777 				      &d->d.oidlen);
778 	d->idx = -1;
779 
780 out:
781 	if (!res) {
782 		*dir = d;
783 	} else {
784 		if (d)
785 			tee_fs_dirfile_close(d->dirh);
786 		free(d);
787 	}
788 	mutex_unlock(&ree_fs_mutex);
789 
790 	return res;
791 }
792 
793 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
794 {
795 	if (d) {
796 		mutex_lock(&ree_fs_mutex);
797 
798 		tee_fs_dirfile_close(d->dirh);
799 		free(d);
800 
801 		mutex_unlock(&ree_fs_mutex);
802 	}
803 }
804 
805 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
806 				     struct tee_fs_dirent **ent)
807 {
808 	TEE_Result res;
809 
810 	mutex_lock(&ree_fs_mutex);
811 
812 	d->d.oidlen = sizeof(d->d.oid);
813 	res = tee_fs_dirfile_get_next(d->dirh, d->uuid, &d->idx, d->d.oid,
814 				      &d->d.oidlen);
815 	if (res == TEE_SUCCESS)
816 		*ent = &d->d;
817 
818 	mutex_unlock(&ree_fs_mutex);
819 
820 	return res;
821 }
822 
823 const struct tee_file_operations ree_fs_ops = {
824 	.open = ree_fs_open,
825 	.create = ree_fs_create,
826 	.close = ree_fs_close,
827 	.read = ree_fs_read,
828 	.write = ree_fs_write,
829 	.truncate = ree_fs_truncate,
830 	.rename = ree_fs_rename,
831 	.remove = ree_fs_remove,
832 	.opendir = ree_fs_opendir_rpc,
833 	.closedir = ree_fs_closedir_rpc,
834 	.readdir = ree_fs_readdir_rpc,
835 };
836