xref: /optee_os/core/tee/tee_ree_fs.c (revision c8016054915d2e5ec760128a309faebadf2716d6)
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/handle.h>
30 #include <kernel/mutex.h>
31 #include <kernel/panic.h>
32 #include <kernel/thread.h>
33 #include <mm/core_memprot.h>
34 #include <optee_msg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string_ext.h>
38 #include <string.h>
39 #include <sys/queue.h>
40 #include <tee/tee_cryp_provider.h>
41 #include <tee/tee_fs_defs.h>
42 #include <tee/tee_fs.h>
43 #include <tee/tee_fs_key_manager.h>
44 #include <tee/tee_fs_rpc.h>
45 #include <trace.h>
46 #include <utee_defines.h>
47 #include <util.h>
48 
49 #define BLOCK_FILE_SHIFT	12
50 
51 #define BLOCK_FILE_SIZE		(1 << BLOCK_FILE_SHIFT)
52 
53 #define MAX_NUM_CACHED_BLOCKS	1
54 
55 #define NUM_BLOCKS_PER_FILE	1024
56 
57 #define MAX_FILE_SIZE	(BLOCK_FILE_SIZE * NUM_BLOCKS_PER_FILE)
58 
59 struct tee_file_handle;
60 
61 struct tee_fs_file_info {
62 	size_t length;
63 	uint32_t backup_version_table[NUM_BLOCKS_PER_FILE / 32];
64 };
65 
66 struct tee_fs_file_meta {
67 	struct tee_fs_file_info info;
68 	uint8_t encrypted_fek[TEE_FS_KM_FEK_SIZE];
69 	uint8_t backup_version;
70 };
71 
72 TAILQ_HEAD(block_head, block);
73 
74 struct block {
75 	TAILQ_ENTRY(block) list;
76 	int block_num;
77 	uint8_t *data;
78 	size_t data_size;
79 };
80 
81 struct block_cache {
82 	struct block_head block_lru;
83 	uint8_t cached_block_num;
84 };
85 
86 struct tee_fs_fd {
87 	struct tee_fs_file_meta meta;
88 	tee_fs_off_t pos;
89 	uint32_t flags;
90 	bool is_new_file;
91 	char *filename;
92 	struct block_cache block_cache;
93 };
94 
95 static inline int pos_to_block_num(int position)
96 {
97 	return position >> BLOCK_FILE_SHIFT;
98 }
99 
100 static inline int get_last_block_num(size_t size)
101 {
102 	return pos_to_block_num(size - 1);
103 }
104 
105 static inline uint8_t get_backup_version_of_block(
106 		struct tee_fs_file_meta *meta,
107 		size_t block_num)
108 {
109 	uint32_t index = (block_num / 32);
110 	uint32_t block_mask = 1 << (block_num % 32);
111 
112 	return !!(meta->info.backup_version_table[index] & block_mask);
113 }
114 
115 static inline void toggle_backup_version_of_block(
116 		struct tee_fs_file_meta *meta,
117 		size_t block_num)
118 {
119 	uint32_t index = (block_num / 32);
120 	uint32_t block_mask = 1 << (block_num % 32);
121 
122 	meta->info.backup_version_table[index] ^= block_mask;
123 }
124 
125 struct block_operations {
126 
127 	/*
128 	 * Read a block from REE File System which is corresponding
129 	 * to the given block_num.
130 	 */
131 	struct block *(*read)(struct tee_fs_fd *fdp, int block_num);
132 
133 	/*
134 	 * Write the given block to REE File System
135 	 */
136 	int (*write)(struct tee_fs_fd *fdp, struct block *b,
137 			struct tee_fs_file_meta *new_meta);
138 };
139 
140 static struct handle_db fs_handle_db = HANDLE_DB_INITIALIZER;
141 
142 static struct mutex ree_fs_mutex = MUTEX_INITIALIZER;
143 
144 /*
145  * We split a TEE file into multiple blocks and store them
146  * on REE filesystem. A TEE file is represented by a REE file
147  * called meta and a number of REE files called blocks. Meta
148  * file is used for storing file information, e.g. file size
149  * and backup version of each block.
150  *
151  * REE files naming rule is as follows:
152  *
153  *   <tee_file_name>/meta.<backup_version>
154  *   <tee_file_name>/block0.<backup_version>
155  *   ...
156  *   <tee_file_name>/block15.<backup_version>
157  *
158  * Backup_version is used to support atomic update operation.
159  * Original file will not be updated, instead we create a new
160  * version of the same file and update the new file instead.
161  *
162  * The backup_version of each block file is stored in meta
163  * file, the meta file itself also has backup_version, the update is
164  * successful after new version of meta has been written.
165  */
166 #define REE_FS_NAME_MAX (TEE_FS_NAME_MAX + 20)
167 
168 
169 static int ree_fs_mkdir_rpc(const char *path, tee_fs_mode_t mode)
170 {
171 	return tee_fs_rpc_mkdir(OPTEE_MSG_RPC_CMD_FS, path, mode);
172 }
173 
174 static TEE_Result ree_fs_opendir_rpc(const char *name, struct tee_fs_dir **d)
175 
176 {
177 	struct tee_fs_dir *d2 = tee_fs_rpc_opendir(OPTEE_MSG_RPC_CMD_FS, name);
178 
179 	if (!d2)
180 		return TEE_ERROR_ITEM_NOT_FOUND;
181 
182 	*d = d2;
183 	return TEE_SUCCESS;
184 }
185 
186 static void ree_fs_closedir_rpc(struct tee_fs_dir *d)
187 {
188 	tee_fs_rpc_closedir(OPTEE_MSG_RPC_CMD_FS, d);
189 }
190 
191 static TEE_Result ree_fs_readdir_rpc(struct tee_fs_dir *d,
192 				     struct tee_fs_dirent **ent)
193 {
194 	struct tee_fs_dirent *e = tee_fs_rpc_readdir(OPTEE_MSG_RPC_CMD_FS, d);
195 
196 	if (!e)
197 		return TEE_ERROR_ITEM_NOT_FOUND;
198 
199 	*ent = e;
200 	return TEE_SUCCESS;
201 }
202 
203 static int ree_fs_rmdir_rpc(const char *name)
204 {
205 	return tee_fs_rpc_rmdir(OPTEE_MSG_RPC_CMD_FS, name);
206 }
207 
208 static int ree_fs_access_rpc(const char *name, int mode)
209 {
210 	return tee_fs_rpc_access(OPTEE_MSG_RPC_CMD_FS, name, mode);
211 }
212 
213 static void get_meta_filepath(const char *file, int version,
214 				char *meta_path)
215 {
216 	snprintf(meta_path, REE_FS_NAME_MAX, "%s/meta.%d",
217 			file, version);
218 }
219 
220 static void get_block_filepath(const char *file, size_t block_num,
221 				int version, char *meta_path)
222 {
223 	snprintf(meta_path, REE_FS_NAME_MAX, "%s/block%zu.%d",
224 			file, block_num, version);
225 }
226 
227 static int __remove_block_file(struct tee_fs_fd *fdp, size_t block_num,
228 				bool toggle)
229 {
230 	TEE_Result res;
231 	char block_path[REE_FS_NAME_MAX];
232 	uint8_t version = get_backup_version_of_block(&fdp->meta, block_num);
233 
234 	if (toggle)
235 		version = !version;
236 
237 	get_block_filepath(fdp->filename, block_num, version, block_path);
238 	DMSG("%s", block_path);
239 
240 	res = tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, block_path);
241 	if (res == TEE_SUCCESS || res == TEE_ERROR_ITEM_NOT_FOUND)
242 		return 0; /* ignore it if file not found */
243 	return -1;
244 }
245 
246 static int remove_block_file(struct tee_fs_fd *fdp, size_t block_num)
247 {
248 	DMSG("remove block%zd", block_num);
249 	return __remove_block_file(fdp, block_num, false);
250 }
251 
252 static int remove_outdated_block(struct tee_fs_fd *fdp, size_t block_num)
253 {
254 	DMSG("remove outdated block%zd", block_num);
255 	return __remove_block_file(fdp, block_num, true);
256 }
257 
258 /*
259  * encrypted_fek: as input for META_FILE and BLOCK_FILE
260  */
261 static TEE_Result encrypt_and_write_file(const char *file_name,
262 		enum tee_fs_file_type file_type,
263 		void *data_in, size_t data_in_size,
264 		uint8_t *encrypted_fek)
265 {
266 	TEE_Result res;
267 	TEE_Result res2;
268 	struct tee_fs_rpc_operation op;
269 	void *ciphertext;
270 	size_t header_size = tee_fs_get_header_size(file_type);
271 	size_t ciphertext_size = header_size + data_in_size;
272 	int fd;
273 
274 	res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, file_name, &fd);
275 	if (res != TEE_SUCCESS) {
276 		if (res != TEE_ERROR_ITEM_NOT_FOUND)
277 			return res;
278 		res = tee_fs_rpc_new_create(OPTEE_MSG_RPC_CMD_FS, file_name,
279 					    &fd);
280 		if (res != TEE_SUCCESS)
281 			return res;
282 	}
283 
284 	res = tee_fs_rpc_new_write_init(&op, OPTEE_MSG_RPC_CMD_FS, fd, 0,
285 					ciphertext_size, &ciphertext);
286 	if (res != TEE_SUCCESS)
287 		goto out;
288 
289 	res = tee_fs_encrypt_file(file_type, data_in, data_in_size,
290 				  ciphertext, &ciphertext_size, encrypted_fek);
291 	if (res != TEE_SUCCESS)
292 		goto out;
293 
294 	res = tee_fs_rpc_new_write_final(&op);
295 out:
296 	res2 = tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fd);
297 	if (res == TEE_SUCCESS)
298 		return res2;
299 	return res;
300 }
301 
302 /*
303  * encrypted_fek: as output for META_FILE
304  *                as input for BLOCK_FILE
305  */
306 static TEE_Result read_and_decrypt_file(const char *file_name,
307 		enum tee_fs_file_type file_type,
308 		void *data_out, size_t *data_out_size,
309 		uint8_t *encrypted_fek)
310 {
311 	TEE_Result res;
312 	TEE_Result res2;
313 	struct tee_fs_rpc_operation op;
314 	size_t bytes;
315 	void *ciphertext;
316 	int fd;
317 
318 	res = tee_fs_rpc_new_open(OPTEE_MSG_RPC_CMD_FS, file_name, &fd);
319 	if (res != TEE_SUCCESS)
320 		return res;
321 
322 	bytes = *data_out_size + tee_fs_get_header_size(file_type);
323 	res = tee_fs_rpc_new_read_init(&op, OPTEE_MSG_RPC_CMD_FS, fd, 0,
324 				       bytes, &ciphertext);
325 	if (res != TEE_SUCCESS)
326 		goto out;
327 
328 	res = tee_fs_rpc_new_read_final(&op, &bytes);
329 	if (res != TEE_SUCCESS)
330 		goto out;
331 
332 	res = tee_fs_decrypt_file(file_type, ciphertext, bytes, data_out,
333 				  data_out_size, encrypted_fek);
334 	if (res != TEE_SUCCESS)
335 		res = TEE_ERROR_CORRUPT_OBJECT;
336 out:
337 	res2 = tee_fs_rpc_new_close(OPTEE_MSG_RPC_CMD_FS, fd);
338 	if (res == TEE_SUCCESS)
339 		return res2;
340 	return res;
341 }
342 
343 static TEE_Result write_meta_file(const char *filename,
344 		struct tee_fs_file_meta *meta)
345 {
346 	char meta_path[REE_FS_NAME_MAX];
347 
348 	get_meta_filepath(filename, meta->backup_version, meta_path);
349 
350 	return encrypt_and_write_file(meta_path, META_FILE,
351 			(void *)&meta->info, sizeof(meta->info),
352 			meta->encrypted_fek);
353 }
354 
355 static TEE_Result create_meta(struct tee_fs_fd *fdp)
356 {
357 	TEE_Result res;
358 
359 	memset(fdp->meta.info.backup_version_table, 0xff,
360 		sizeof(fdp->meta.info.backup_version_table));
361 	fdp->meta.info.length = 0;
362 
363 	res = tee_fs_generate_fek(fdp->meta.encrypted_fek, TEE_FS_KM_FEK_SIZE);
364 	if (res != TEE_SUCCESS)
365 		return res;
366 
367 	fdp->meta.backup_version = 0;
368 
369 	return write_meta_file(fdp->filename, &fdp->meta);
370 }
371 
372 static TEE_Result commit_meta_file(struct tee_fs_fd *fdp,
373 				   struct tee_fs_file_meta *new_meta)
374 {
375 	TEE_Result res;
376 	uint8_t old_version;
377 	char meta_path[REE_FS_NAME_MAX];
378 
379 	old_version = new_meta->backup_version;
380 	new_meta->backup_version = !new_meta->backup_version;
381 
382 	res = write_meta_file(fdp->filename, new_meta);
383 	if (res != TEE_SUCCESS)
384 		return res;
385 
386 	/*
387 	 * From now on the new meta is successfully committed,
388 	 * change tee_fs_fd accordingly
389 	 */
390 	fdp->meta = *new_meta;
391 
392 	/*
393 	 * Remove outdated meta file, there is nothing we can
394 	 * do if we fail here, but that is OK because both
395 	 * new & old version of block files are kept. The context
396 	 * of the file is still consistent.
397 	 */
398 	get_meta_filepath(fdp->filename, old_version, meta_path);
399 	tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, meta_path);
400 
401 	return res;
402 }
403 
404 static TEE_Result read_meta_file(const char *meta_path,
405 		struct tee_fs_file_meta *meta)
406 {
407 	size_t meta_info_size = sizeof(struct tee_fs_file_info);
408 
409 	return read_and_decrypt_file(meta_path, META_FILE,
410 				     &meta->info, &meta_info_size,
411 				     meta->encrypted_fek);
412 }
413 
414 static TEE_Result read_meta(struct tee_fs_fd *fdp)
415 {
416 	TEE_Result res;
417 	char meta_path[REE_FS_NAME_MAX];
418 
419 	get_meta_filepath(fdp->filename, fdp->meta.backup_version, meta_path);
420 	res = read_meta_file(meta_path, &fdp->meta);
421 	if (res != TEE_SUCCESS) {
422 		TEE_Result res2;
423 
424 		fdp->meta.backup_version = !fdp->meta.backup_version;
425 		get_meta_filepath(fdp->filename, fdp->meta.backup_version,
426 				  meta_path);
427 		res2 = read_meta_file(meta_path, &fdp->meta);
428 		if (res2 != TEE_ERROR_ITEM_NOT_FOUND)
429 			return res2;
430 	}
431 
432 	return res;
433 }
434 
435 static bool is_block_file_exist(struct tee_fs_file_meta *meta,
436 					size_t block_num)
437 {
438 	size_t file_size = meta->info.length;
439 
440 	if (file_size == 0)
441 		return false;
442 
443 	return (block_num <= (size_t)get_last_block_num(file_size));
444 }
445 
446 static TEE_Result read_block_from_storage(struct tee_fs_fd *fdp,
447 					  struct block *b)
448 {
449 	TEE_Result res = TEE_SUCCESS;
450 	uint8_t *plaintext = b->data;
451 	char block_path[REE_FS_NAME_MAX];
452 	size_t block_file_size = BLOCK_FILE_SIZE;
453 	uint8_t version = get_backup_version_of_block(&fdp->meta, b->block_num);
454 
455 	if (!is_block_file_exist(&fdp->meta, b->block_num))
456 		goto exit;
457 
458 	get_block_filepath(fdp->filename, b->block_num, version,
459 			block_path);
460 
461 	res = read_and_decrypt_file(block_path, BLOCK_FILE,
462 			plaintext, &block_file_size,
463 			fdp->meta.encrypted_fek);
464 	if (res != TEE_SUCCESS) {
465 		EMSG("Failed to read and decrypt file");
466 		goto exit;
467 	}
468 	b->data_size = block_file_size;
469 	DMSG("Successfully read and decrypt block%d from storage, size=%zd",
470 		b->block_num, b->data_size);
471 exit:
472 	return res;
473 }
474 
475 static int flush_block_to_storage(struct tee_fs_fd *fdp, struct block *b,
476 					 struct tee_fs_file_meta *new_meta)
477 {
478 	TEE_Result res;
479 	size_t block_num = b->block_num;
480 	char block_path[REE_FS_NAME_MAX];
481 	uint8_t new_version =
482 		!get_backup_version_of_block(&fdp->meta, block_num);
483 
484 	get_block_filepath(fdp->filename, block_num, new_version, block_path);
485 
486 	res = encrypt_and_write_file(block_path, BLOCK_FILE, b->data,
487 				     b->data_size, new_meta->encrypted_fek);
488 	if (res != TEE_SUCCESS) {
489 		EMSG("Failed to encrypt and write block file");
490 		goto fail;
491 	}
492 
493 	DMSG("Successfully encrypt and write block%d to storage, size=%zd",
494 		b->block_num, b->data_size);
495 	toggle_backup_version_of_block(new_meta, block_num);
496 
497 	return 0;
498 fail:
499 	return -1;
500 }
501 
502 static struct block *alloc_block(void)
503 {
504 	struct block *c;
505 
506 	c = malloc(sizeof(struct block));
507 	if (!c)
508 		return NULL;
509 
510 	c->data = malloc(BLOCK_FILE_SIZE);
511 	if (!c->data) {
512 		EMSG("unable to alloc memory for block data");
513 		goto exit;
514 	}
515 
516 	c->block_num = -1;
517 	c->data_size = 0;
518 
519 	return c;
520 
521 exit:
522 	free(c);
523 	return NULL;
524 }
525 
526 #ifdef CFG_FS_BLOCK_CACHE
527 static void free_block(struct block *b)
528 {
529 	if (b) {
530 		free(b->data);
531 		free(b);
532 	}
533 }
534 
535 static inline bool is_block_data_invalid(struct block *b)
536 {
537 	return (b->data_size == 0);
538 }
539 
540 static void get_block_from_cache(struct block_cache *cache,
541 			int block_num, struct block **out_block)
542 {
543 	struct block *b, *found = NULL;
544 
545 	DMSG("Try to find block%d in cache", block_num);
546 	TAILQ_FOREACH(b, &cache->block_lru, list) {
547 		if (b->block_num == block_num) {
548 			DMSG("Found in cache");
549 			found = b;
550 			break;
551 		}
552 	}
553 
554 	if (found) {
555 		TAILQ_REMOVE(&cache->block_lru, found, list);
556 		TAILQ_INSERT_HEAD(&cache->block_lru, found, list);
557 		*out_block = found;
558 		return;
559 	}
560 
561 	DMSG("Not found, reuse oldest block on LRU list");
562 	b = TAILQ_LAST(&cache->block_lru, block_head);
563 	TAILQ_REMOVE(&cache->block_lru, b, list);
564 	TAILQ_INSERT_HEAD(&cache->block_lru, b, list);
565 	b->block_num = block_num;
566 	b->data_size = 0;
567 	*out_block = b;
568 }
569 
570 static int init_block_cache(struct block_cache *cache)
571 {
572 	struct block *b;
573 
574 	TAILQ_INIT(&cache->block_lru);
575 	cache->cached_block_num = 0;
576 
577 	while (cache->cached_block_num < MAX_NUM_CACHED_BLOCKS) {
578 
579 		b = alloc_block();
580 		if (!b) {
581 			EMSG("Failed to alloc block");
582 			goto fail;
583 		} else {
584 			TAILQ_INSERT_HEAD(&cache->block_lru, b, list);
585 			cache->cached_block_num++;
586 		}
587 	}
588 	return 0;
589 
590 fail:
591 	TAILQ_FOREACH(b, &cache->block_lru, list)
592 		free_block(b);
593 	return -1;
594 }
595 
596 static void destroy_block_cache(struct block_cache *cache)
597 {
598 	struct block *b, *next;
599 
600 	TAILQ_FOREACH_SAFE(b, &cache->block_lru, list, next) {
601 		TAILQ_REMOVE(&cache->block_lru, b, list);
602 		free_block(b);
603 	}
604 }
605 #else
606 static int init_block_cache(struct block_cache *cache __unused)
607 {
608 	return 0;
609 }
610 
611 static void destroy_block_cache(struct block_cache *cache __unused)
612 {
613 }
614 #endif
615 
616 static void write_data_to_block(struct block *b, int offset,
617 				void *buf, size_t len)
618 {
619 	DMSG("Write %zd bytes to block%d", len, b->block_num);
620 	memcpy(b->data + offset, buf, len);
621 	if (offset + len > b->data_size) {
622 		b->data_size = offset + len;
623 		DMSG("Extend block%d size to %zd bytes",
624 				b->block_num, b->data_size);
625 	}
626 }
627 
628 static void read_data_from_block(struct block *b, int offset,
629 				void *buf, size_t len)
630 {
631 	DMSG("Read %zd bytes from block%d", len, b->block_num);
632 	if (offset + len > b->data_size)
633 		panic("Exceeding block size");
634 	memcpy(buf, b->data + offset, len);
635 }
636 
637 #ifdef CFG_FS_BLOCK_CACHE
638 static struct block *read_block_with_cache(struct tee_fs_fd *fdp, int block_num)
639 {
640 	struct block *b;
641 
642 	get_block_from_cache(&fdp->block_cache, block_num, &b);
643 	if (is_block_data_invalid(b))
644 		if (read_block_from_storage(fdp, b)) {
645 			EMSG("Unable to read block%d from storage",
646 					block_num);
647 			return NULL;
648 		}
649 
650 	return b;
651 }
652 #else
653 
654 static struct block *read_block_no_cache(struct tee_fs_fd *fdp, int block_num)
655 {
656 	static struct block *b;
657 	TEE_Result res;
658 
659 	if (!b)
660 		b = alloc_block();
661 	b->block_num = block_num;
662 
663 	res = read_block_from_storage(fdp, b);
664 	if (res != TEE_SUCCESS)
665 		EMSG("Unable to read block%d from storage",
666 				block_num);
667 
668 	return res != TEE_SUCCESS ? NULL : b;
669 }
670 #endif
671 
672 static struct block_operations block_ops = {
673 #ifdef CFG_FS_BLOCK_CACHE
674 	.read = read_block_with_cache,
675 #else
676 	.read = read_block_no_cache,
677 #endif
678 	.write = flush_block_to_storage,
679 };
680 
681 static TEE_Result out_of_place_write(struct tee_fs_fd *fdp, const void *buf,
682 		size_t len, struct tee_fs_file_meta *new_meta)
683 {
684 	int start_block_num = pos_to_block_num(fdp->pos);
685 	int end_block_num = pos_to_block_num(fdp->pos + len - 1);
686 	size_t remain_bytes = len;
687 	uint8_t *data_ptr = (uint8_t *)buf;
688 	int orig_pos = fdp->pos;
689 
690 	while (start_block_num <= end_block_num) {
691 		int offset = fdp->pos % BLOCK_FILE_SIZE;
692 		struct block *b;
693 		size_t size_to_write = (remain_bytes > BLOCK_FILE_SIZE) ?
694 			BLOCK_FILE_SIZE : remain_bytes;
695 
696 		if (size_to_write + offset > BLOCK_FILE_SIZE)
697 			size_to_write = BLOCK_FILE_SIZE - offset;
698 
699 		b = block_ops.read(fdp, start_block_num);
700 		if (!b)
701 			goto failed;
702 
703 		DMSG("Write data, offset: %d, size_to_write: %zd",
704 			offset, size_to_write);
705 		write_data_to_block(b, offset, data_ptr, size_to_write);
706 
707 		if (block_ops.write(fdp, b, new_meta)) {
708 			EMSG("Unable to wrtie block%d to storage",
709 					b->block_num);
710 			goto failed;
711 		}
712 
713 		data_ptr += size_to_write;
714 		remain_bytes -= size_to_write;
715 		start_block_num++;
716 		fdp->pos += size_to_write;
717 	}
718 
719 	if (fdp->pos > (tee_fs_off_t)new_meta->info.length)
720 		new_meta->info.length = fdp->pos;
721 
722 	return TEE_SUCCESS;
723 failed:
724 	fdp->pos = orig_pos;
725 	return TEE_ERROR_GENERIC;
726 }
727 
728 static TEE_Result create_hard_link(const char *old_dir, const char *new_dir,
729 				   const char *filename)
730 {
731 	char old_path[REE_FS_NAME_MAX];
732 	char new_path[REE_FS_NAME_MAX];
733 
734 	snprintf(old_path, REE_FS_NAME_MAX, "%s/%s",
735 			old_dir, filename);
736 	snprintf(new_path, REE_FS_NAME_MAX, "%s/%s",
737 			new_dir, filename);
738 
739 	DMSG("%s -> %s", old_path, new_path);
740 	if (tee_fs_rpc_link(OPTEE_MSG_RPC_CMD_FS, old_path, new_path))
741 		return TEE_ERROR_GENERIC;
742 
743 	return TEE_SUCCESS;
744 }
745 
746 static TEE_Result unlink_tee_file(const char *file)
747 {
748 	TEE_Result res;
749 	size_t len = strlen(file) + 1;
750 	struct tee_fs_dirent *dirent;
751 	struct tee_fs_dir *dir;
752 
753 	DMSG("file=%s", file);
754 
755 	if (len > TEE_FS_NAME_MAX)
756 		return TEE_ERROR_GENERIC;
757 
758 	res = ree_fs_opendir_rpc(file, &dir);
759 	if (res != TEE_SUCCESS)
760 		return res;
761 
762 	res = ree_fs_readdir_rpc(dir, &dirent);
763 	while (res == TEE_SUCCESS) {
764 		char path[REE_FS_NAME_MAX];
765 
766 		snprintf(path, REE_FS_NAME_MAX, "%s/%s",
767 			file, dirent->d_name);
768 
769 		DMSG("unlink %s", path);
770 		res = tee_fs_rpc_new_remove(OPTEE_MSG_RPC_CMD_FS, path);
771 		if (res != TEE_SUCCESS) {
772 			ree_fs_closedir_rpc(dir);
773 			return res;
774 		}
775 		res = ree_fs_readdir_rpc(dir, &dirent);
776 	}
777 
778 	ree_fs_closedir_rpc(dir);
779 
780 	return ree_fs_rmdir_rpc(file);
781 }
782 
783 static TEE_Result open_internal(const char *file, bool create, bool overwrite,
784 				struct tee_file_handle **fh)
785 {
786 	TEE_Result res;
787 	size_t len;
788 	struct tee_fs_fd *fdp = NULL;
789 
790 	if (!file)
791 		return TEE_ERROR_BAD_PARAMETERS;
792 
793 	len = strlen(file) + 1;
794 	if (len > TEE_FS_NAME_MAX)
795 		return TEE_ERROR_BAD_PARAMETERS;
796 
797 	fdp = calloc(1, sizeof(struct tee_fs_fd));
798 	if (!fdp)
799 		return TEE_ERROR_OUT_OF_MEMORY;
800 
801 	mutex_lock(&ree_fs_mutex);
802 
803 	/* init internal status */
804 	if (init_block_cache(&fdp->block_cache)) {
805 		res = TEE_ERROR_OUT_OF_MEMORY;
806 		goto exit_free_fd;
807 	}
808 
809 	fdp->filename = strdup(file);
810 	if (!fdp->filename) {
811 		res = TEE_ERROR_OUT_OF_MEMORY;
812 		goto exit_destroy_block_cache;
813 	}
814 
815 	res = read_meta(fdp);
816 	if (res == TEE_SUCCESS) {
817 		if (overwrite) {
818 			res = TEE_ERROR_ACCESS_CONFLICT;
819 			goto exit_free_filename;
820 		}
821 	} else if (res == TEE_ERROR_ITEM_NOT_FOUND) {
822 		if (!create)
823 			goto exit_free_filename;
824 		res = create_meta(fdp);
825 		if (res != TEE_SUCCESS)
826 			goto exit_free_filename;
827 	} else {
828 		goto exit_free_filename;
829 	}
830 
831 	*fh = (struct tee_file_handle *)fdp;
832 	goto exit;
833 
834 exit_free_filename:
835 	free(fdp->filename);
836 exit_destroy_block_cache:
837 	destroy_block_cache(&fdp->block_cache);
838 exit_free_fd:
839 	free(fdp);
840 exit:
841 	mutex_unlock(&ree_fs_mutex);
842 	return res;
843 }
844 
845 static TEE_Result ree_fs_open(const char *file, struct tee_file_handle **fh)
846 {
847 	return open_internal(file, false, false, fh);
848 }
849 
850 static TEE_Result ree_fs_create(const char *file, bool overwrite,
851 				struct tee_file_handle **fh)
852 {
853 	return open_internal(file, true, overwrite, fh);
854 }
855 
856 static void ree_fs_close(struct tee_file_handle **fh)
857 {
858 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)*fh;
859 
860 	if (fdp) {
861 		destroy_block_cache(&fdp->block_cache);
862 		free(fdp->filename);
863 		free(fdp);
864 		*fh = NULL;
865 	}
866 }
867 
868 static TEE_Result ree_fs_seek(struct tee_file_handle *fh, int32_t offset,
869 			      TEE_Whence whence, int32_t *new_offs)
870 {
871 	TEE_Result res;
872 	tee_fs_off_t new_pos;
873 	size_t filelen;
874 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
875 
876 	mutex_lock(&ree_fs_mutex);
877 
878 	DMSG("offset=%d, whence=%d", (int)offset, whence);
879 
880 	filelen = fdp->meta.info.length;
881 
882 	switch (whence) {
883 	case TEE_DATA_SEEK_SET:
884 		new_pos = offset;
885 		break;
886 
887 	case TEE_DATA_SEEK_CUR:
888 		new_pos = fdp->pos + offset;
889 		break;
890 
891 	case TEE_DATA_SEEK_END:
892 		new_pos = filelen + offset;
893 		break;
894 
895 	default:
896 		res = TEE_ERROR_BAD_PARAMETERS;
897 		goto exit;
898 	}
899 
900 	if (new_pos < 0)
901 		new_pos = 0;
902 
903 	if (new_pos > TEE_DATA_MAX_POSITION) {
904 		EMSG("Position is beyond TEE_DATA_MAX_POSITION");
905 		res = TEE_ERROR_BAD_PARAMETERS;
906 		goto exit;
907 	}
908 
909 	fdp->pos = new_pos;
910 	if (new_offs)
911 		*new_offs = new_pos;
912 	res = TEE_SUCCESS;
913 exit:
914 	mutex_unlock(&ree_fs_mutex);
915 	return res;
916 }
917 
918 /*
919  * To ensure atomic truncate operation, we can:
920  *
921  *  - update file length to new length
922  *  - commit new meta
923  *  - free unused blocks
924  *
925  * To ensure atomic extend operation, we can:
926  *
927  *  - update file length to new length
928  *  - allocate and fill zero data to new blocks
929  *  - commit new meta
930  *
931  * Any failure before committing new meta is considered as
932  * update failed, and the file content will not be updated
933  */
934 static TEE_Result ree_fs_ftruncate_internal(struct tee_fs_fd *fdp,
935 					    tee_fs_off_t new_file_len)
936 {
937 	TEE_Result res;
938 	size_t old_file_len = fdp->meta.info.length;
939 	struct tee_fs_file_meta new_meta;
940 
941 	if ((size_t)new_file_len == old_file_len) {
942 		DMSG("Ignore due to file length does not changed");
943 		return TEE_SUCCESS;
944 	}
945 
946 	if (new_file_len > MAX_FILE_SIZE) {
947 		EMSG("Over maximum file size(%d)", MAX_FILE_SIZE);
948 		return TEE_ERROR_BAD_PARAMETERS;
949 	}
950 
951 	new_meta = fdp->meta;
952 	new_meta.info.length = new_file_len;
953 
954 	if ((size_t)new_file_len < old_file_len) {
955 		int old_block_num = get_last_block_num(old_file_len);
956 		int new_block_num = get_last_block_num(new_file_len);
957 
958 		DMSG("Truncate file length to %zu", (size_t)new_file_len);
959 
960 		res = commit_meta_file(fdp, &new_meta);
961 		if (res != TEE_SUCCESS)
962 			return res;
963 
964 		/* now we are safe to free unused blocks */
965 		while (old_block_num > new_block_num) {
966 			if (remove_block_file(fdp, old_block_num)) {
967 				IMSG("Warning: Failed to free block: %d",
968 						old_block_num);
969 			}
970 
971 			old_block_num--;
972 		}
973 
974 	} else {
975 		size_t ext_len = new_file_len - old_file_len;
976 		int orig_pos = fdp->pos;
977 		uint8_t *buf;
978 
979 		buf = calloc(1, BLOCK_FILE_SIZE);
980 		if (!buf) {
981 			EMSG("Failed to allocate buffer, size=%d",
982 					BLOCK_FILE_SIZE);
983 			return TEE_ERROR_OUT_OF_MEMORY;
984 		}
985 
986 		DMSG("Extend file length to %zu", (size_t)new_file_len);
987 
988 		fdp->pos = old_file_len;
989 
990 		res = TEE_SUCCESS;
991 		while (ext_len > 0) {
992 			size_t data_len = (ext_len > BLOCK_FILE_SIZE) ?
993 					BLOCK_FILE_SIZE : ext_len;
994 
995 			DMSG("fill len=%zu", data_len);
996 			res = out_of_place_write(fdp, buf, data_len, &new_meta);
997 			if (res != TEE_SUCCESS) {
998 				EMSG("Failed to fill data");
999 				break;
1000 			}
1001 
1002 			ext_len -= data_len;
1003 		}
1004 
1005 		free(buf);
1006 		fdp->pos = orig_pos;
1007 
1008 		if (res == TEE_SUCCESS) {
1009 			res = commit_meta_file(fdp, &new_meta);
1010 			if (res != TEE_SUCCESS)
1011 				EMSG("Failed to commit meta file");
1012 		}
1013 	}
1014 
1015 	return res;
1016 }
1017 
1018 static TEE_Result ree_fs_read(struct tee_file_handle *fh, void *buf,
1019 			      size_t *len)
1020 {
1021 	TEE_Result res;
1022 	int start_block_num;
1023 	int end_block_num;
1024 	size_t remain_bytes;
1025 	uint8_t *data_ptr = buf;
1026 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
1027 
1028 	mutex_lock(&ree_fs_mutex);
1029 
1030 	remain_bytes = *len;
1031 	if ((fdp->pos + remain_bytes) < remain_bytes ||
1032 	    fdp->pos > (tee_fs_off_t)fdp->meta.info.length)
1033 		remain_bytes = 0;
1034 	else if (fdp->pos + remain_bytes > fdp->meta.info.length)
1035 		remain_bytes = fdp->meta.info.length - fdp->pos;
1036 
1037 	*len = remain_bytes;
1038 
1039 	if (!remain_bytes) {
1040 		res = TEE_SUCCESS;
1041 		goto exit;
1042 	}
1043 
1044 	DMSG("%s, data len=%zu", fdp->filename, remain_bytes);
1045 
1046 	start_block_num = pos_to_block_num(fdp->pos);
1047 	end_block_num = pos_to_block_num(fdp->pos + remain_bytes - 1);
1048 	DMSG("start_block_num:%d, end_block_num:%d",
1049 		start_block_num, end_block_num);
1050 
1051 	while (start_block_num <= end_block_num) {
1052 		struct block *b;
1053 		int offset = fdp->pos % BLOCK_FILE_SIZE;
1054 		size_t size_to_read = remain_bytes > BLOCK_FILE_SIZE ?
1055 			BLOCK_FILE_SIZE : remain_bytes;
1056 
1057 		if (size_to_read + offset > BLOCK_FILE_SIZE)
1058 			size_to_read = BLOCK_FILE_SIZE - offset;
1059 
1060 		DMSG("block_num:%d, offset:%d, size_to_read: %zd",
1061 			start_block_num, offset, size_to_read);
1062 
1063 		b = block_ops.read(fdp, start_block_num);
1064 		if (!b) {
1065 			res = TEE_ERROR_CORRUPT_OBJECT;
1066 			goto exit;
1067 		}
1068 
1069 		read_data_from_block(b, offset, data_ptr, size_to_read);
1070 		data_ptr += size_to_read;
1071 		remain_bytes -= size_to_read;
1072 		fdp->pos += size_to_read;
1073 
1074 		start_block_num++;
1075 	}
1076 	res = TEE_SUCCESS;
1077 exit:
1078 	mutex_unlock(&ree_fs_mutex);
1079 	return res;
1080 }
1081 
1082 /*
1083  * To ensure atomicity of write operation, we need to
1084  * do the following steps:
1085  * (The sequence of operations is very important)
1086  *
1087  *  - Create a new backup version of meta file as a copy
1088  *    of current meta file.
1089  *  - For each blocks to write:
1090  *    - Create new backup version for current block.
1091  *    - Write data to new backup version.
1092  *    - Update the new meta file accordingly.
1093  *  - Write the new meta file.
1094  *
1095  * (Any failure in above steps is considered as update failed,
1096  *  and the file content will not be updated)
1097  *
1098  * After previous step the update is considered complete, but
1099  * we should do the following clean-up step(s):
1100  *
1101  *  - Delete old meta file.
1102  *  - Remove old block files.
1103  *
1104  * (Any failure in above steps is considered as a successfully
1105  *  update)
1106  */
1107 static TEE_Result ree_fs_write(struct tee_file_handle *fh, const void *buf,
1108 			       size_t len)
1109 {
1110 	TEE_Result res;
1111 	struct tee_fs_file_meta new_meta;
1112 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
1113 	size_t file_size;
1114 	tee_fs_off_t orig_pos;
1115 	int start_block_num;
1116 	int end_block_num;
1117 
1118 
1119 	if (!len)
1120 		return TEE_SUCCESS;
1121 
1122 	mutex_lock(&ree_fs_mutex);
1123 
1124 	file_size = fdp->meta.info.length;
1125 	orig_pos = fdp->pos;
1126 
1127 	if ((fdp->pos + len) > MAX_FILE_SIZE || (fdp->pos + len) < len) {
1128 		EMSG("Over maximum file size(%d)", MAX_FILE_SIZE);
1129 		res = TEE_ERROR_BAD_PARAMETERS;
1130 		goto exit;
1131 	}
1132 
1133 	DMSG("%s, data len=%zu", fdp->filename, len);
1134 	if (file_size < (size_t)fdp->pos) {
1135 		DMSG("File hole detected, try to extend file size");
1136 		res = ree_fs_ftruncate_internal(fdp, fdp->pos);
1137 		if (res != TEE_SUCCESS)
1138 			goto exit;
1139 	}
1140 
1141 	new_meta = fdp->meta;
1142 	res = out_of_place_write(fdp, buf, len, &new_meta);
1143 	if (res != TEE_SUCCESS)
1144 		goto exit;
1145 
1146 	res = commit_meta_file(fdp, &new_meta);
1147 	if (res != TEE_SUCCESS)
1148 		goto exit;
1149 
1150 	/* we are safe to free old blocks */
1151 	start_block_num = pos_to_block_num(orig_pos);
1152 	end_block_num = pos_to_block_num(fdp->pos - 1);
1153 	while (start_block_num <= end_block_num) {
1154 		if (remove_outdated_block(fdp, start_block_num))
1155 			IMSG("Warning: Failed to free old block: %d",
1156 				start_block_num);
1157 
1158 		start_block_num++;
1159 	}
1160 exit:
1161 	mutex_unlock(&ree_fs_mutex);
1162 	return res;
1163 }
1164 
1165 /*
1166  * To ensure atomicity of rename operation, we need to
1167  * do the following steps:
1168  *
1169  *  - Create a new folder that represents the renamed TEE file
1170  *  - For each REE block files, create a hard link under the just
1171  *    created folder (new TEE file)
1172  *  - Now we are ready to commit meta, create hard link for the
1173  *    meta file
1174  *
1175  * (Any failure in above steps is considered as update failed,
1176  *  and the file content will not be updated)
1177  *
1178  * After previous step the update is considered complete, but
1179  * we should do the following clean-up step(s):
1180  *
1181  *  - Unlink all REE files represents the old TEE file (including
1182  *    meta and block files)
1183  *
1184  * (Any failure in above steps is considered as a successfully
1185  *  update)
1186  */
1187 static TEE_Result ree_fs_rename_internal(const char *old, const char *new)
1188 {
1189 	TEE_Result res;
1190 	size_t old_len;
1191 	size_t new_len;
1192 	size_t meta_count = 0;
1193 	struct tee_fs_dir *old_dir;
1194 	struct tee_fs_dirent *dirent;
1195 	char *meta_filename = NULL;
1196 
1197 	DMSG("old=%s, new=%s", old, new);
1198 
1199 	old_len = strlen(old) + 1;
1200 	new_len = strlen(new) + 1;
1201 
1202 	if (old_len > TEE_FS_NAME_MAX || new_len > TEE_FS_NAME_MAX)
1203 		return TEE_ERROR_BAD_PARAMETERS;
1204 
1205 	if (ree_fs_mkdir_rpc(new, TEE_FS_S_IRUSR | TEE_FS_S_IWUSR))
1206 		return TEE_ERROR_GENERIC;
1207 
1208 	res = ree_fs_opendir_rpc(old, &old_dir);
1209 	if (res != TEE_SUCCESS)
1210 		return res;
1211 
1212 	res = ree_fs_readdir_rpc(old_dir, &dirent);
1213 	while (res == TEE_SUCCESS) {
1214 		if (!strncmp(dirent->d_name, "meta.", 5)) {
1215 			meta_filename = strdup(dirent->d_name);
1216 			meta_count++;
1217 		} else {
1218 			res = create_hard_link(old, new, dirent->d_name);
1219 			if (res != TEE_SUCCESS)
1220 				goto exit_close_old_dir;
1221 		}
1222 
1223 		res = ree_fs_readdir_rpc(old_dir, &dirent);
1224 	}
1225 
1226 	/* finally, link the meta file, rename operation completed */
1227 	if (!meta_filename)
1228 		panic("no meta file");
1229 
1230 	/*
1231 	 * TODO: This will cause memory leakage at previous strdup()
1232 	 * if we accidently have two meta files in a TEE file.
1233 	 *
1234 	 * It's not easy to handle the case above (e.g. Which meta file
1235 	 * should be linked first? What to do if a power cut happened
1236 	 * during creating links for the two meta files?)
1237 	 *
1238 	 * We will solve this issue using another approach: merging
1239 	 * both meta and block files into a single REE file. This approach
1240 	 * can completely remove ree_fs_rename(). We can simply
1241 	 * rename TEE file using REE rename() system call, which is also
1242 	 * atomic.
1243 	 */
1244 	if (meta_count > 1)
1245 		EMSG("Warning: more than one meta file in your TEE file\n"
1246 		     "This will cause memory leakage.");
1247 
1248 	res = create_hard_link(old, new, meta_filename);
1249 	if (res != TEE_SUCCESS)
1250 		goto exit_close_old_dir;
1251 
1252 	/* we are safe now, remove old TEE file */
1253 	unlink_tee_file(old);
1254 
1255 exit_close_old_dir:
1256 	ree_fs_closedir_rpc(old_dir);
1257 	free(meta_filename);
1258 	return res;
1259 }
1260 
1261 static TEE_Result ree_fs_rename(const char *old, const char *new)
1262 {
1263 	TEE_Result res;
1264 
1265 	mutex_lock(&ree_fs_mutex);
1266 	res = ree_fs_rename_internal(old, new);
1267 	mutex_unlock(&ree_fs_mutex);
1268 
1269 	return res;
1270 }
1271 
1272 /*
1273  * To ensure atomic unlink operation, we can simply
1274  * split the unlink operation into:
1275  *
1276  *  - rename("file", "file.trash");
1277  *
1278  * (Any failure in above steps is considered as update failed,
1279  *  and the file content will not be updated)
1280  *
1281  * After previous step the update is considered complete, but
1282  * we should do the following clean-up step(s):
1283  *
1284  *  - unlink("file.trash");
1285  *
1286  * (Any failure in above steps is considered as a successfully
1287  *  update)
1288  */
1289 static TEE_Result ree_fs_remove(const char *file)
1290 {
1291 	TEE_Result res;
1292 	char trash_file[TEE_FS_NAME_MAX + 6];
1293 
1294 	snprintf(trash_file, TEE_FS_NAME_MAX + 6, "%s.trash", file);
1295 
1296 	mutex_lock(&ree_fs_mutex);
1297 
1298 	res = ree_fs_rename_internal(file, trash_file);
1299 	if (res == TEE_SUCCESS)
1300 		unlink_tee_file(trash_file);
1301 
1302 	mutex_unlock(&ree_fs_mutex);
1303 	return res;
1304 }
1305 
1306 static TEE_Result ree_fs_truncate(struct tee_file_handle *fh, size_t len)
1307 {
1308 	TEE_Result res;
1309 	struct tee_fs_fd *fdp = (struct tee_fs_fd *)fh;
1310 
1311 	mutex_lock(&ree_fs_mutex);
1312 	res = ree_fs_ftruncate_internal(fdp, len);
1313 	mutex_unlock(&ree_fs_mutex);
1314 
1315 	return res;
1316 }
1317 
1318 static int ree_open_wrapper(TEE_Result *errno, const char *file, int flags, ...)
1319 {
1320 	TEE_Result res;
1321 	struct tee_file_handle *tfh = NULL;
1322 	int fd;
1323 
1324 	if (flags & TEE_FS_O_CREATE)
1325 		res = ree_fs_create(file, !!(flags & TEE_FS_O_EXCL), &tfh);
1326 	else
1327 		res = ree_fs_open(file, &tfh);
1328 
1329 	*errno = res;
1330 	if (res != TEE_SUCCESS)
1331 		return -1;
1332 
1333 	mutex_lock(&ree_fs_mutex);
1334 	fd = handle_get(&fs_handle_db, tfh);
1335 	mutex_unlock(&ree_fs_mutex);
1336 
1337 	if (fd == -1)
1338 		panic(); /* Temporary solution */
1339 
1340 	return fd;
1341 }
1342 
1343 static int ree_close_wrapper(int fd)
1344 {
1345 	struct tee_file_handle *tfh;
1346 
1347 	mutex_lock(&ree_fs_mutex);
1348 	tfh = handle_put(&fs_handle_db, fd);
1349 	mutex_unlock(&ree_fs_mutex);
1350 
1351 	if (tfh) {
1352 		ree_fs_close(&tfh);
1353 		return 0;
1354 	}
1355 	return -1;
1356 }
1357 
1358 static int ree_read_wrapper(TEE_Result *errno, int fd, void *buf, size_t len)
1359 {
1360 	TEE_Result res;
1361 	struct tee_file_handle *tfh;
1362 	size_t l;
1363 
1364 	mutex_lock(&ree_fs_mutex);
1365 	tfh = handle_lookup(&fs_handle_db, fd);
1366 	mutex_unlock(&ree_fs_mutex);
1367 
1368 	if (!tfh) {
1369 		*errno = TEE_ERROR_BAD_PARAMETERS;
1370 		return -1;
1371 	}
1372 
1373 	l = len;
1374 	res = ree_fs_read(tfh, buf, &l);
1375 	*errno = res;
1376 
1377 	if (res != TEE_SUCCESS)
1378 		return -1;
1379 	return l;
1380 }
1381 
1382 static int ree_write_wrapper(TEE_Result *errno, int fd, const void *buf,
1383 			     size_t len)
1384 {
1385 	TEE_Result res;
1386 	struct tee_file_handle *tfh;
1387 
1388 	mutex_lock(&ree_fs_mutex);
1389 	tfh = handle_lookup(&fs_handle_db, fd);
1390 	mutex_unlock(&ree_fs_mutex);
1391 
1392 	if (!tfh) {
1393 		*errno = TEE_ERROR_BAD_PARAMETERS;
1394 		return -1;
1395 	}
1396 
1397 	res = ree_fs_write(tfh, buf, len);
1398 	*errno = res;
1399 
1400 	if (res != TEE_SUCCESS)
1401 		return -1;
1402 	return len;
1403 }
1404 
1405 static tee_fs_off_t ree_lseek_wrapper(TEE_Result *errno, int fd,
1406 				      tee_fs_off_t offset, int whence)
1407 {
1408 	TEE_Result res;
1409 	struct tee_file_handle *tfh;
1410 	int32_t new_offs;
1411 
1412 	mutex_lock(&ree_fs_mutex);
1413 	tfh = handle_lookup(&fs_handle_db, fd);
1414 	mutex_unlock(&ree_fs_mutex);
1415 
1416 	if (!tfh) {
1417 		*errno = TEE_ERROR_BAD_PARAMETERS;
1418 		return -1;
1419 	}
1420 
1421 	switch (whence) {
1422 	case TEE_FS_SEEK_SET:
1423 		res = ree_fs_seek(tfh, offset, TEE_DATA_SEEK_SET, &new_offs);
1424 		break;
1425 	case TEE_FS_SEEK_CUR:
1426 		res = ree_fs_seek(tfh, offset, TEE_DATA_SEEK_CUR, &new_offs);
1427 		break;
1428 	case TEE_FS_SEEK_END:
1429 		res = ree_fs_seek(tfh, offset, TEE_DATA_SEEK_END, &new_offs);
1430 		break;
1431 	default:
1432 		res = TEE_ERROR_BAD_PARAMETERS;
1433 	}
1434 
1435 	*errno = res;
1436 	if (res != TEE_SUCCESS)
1437 		return -1;
1438 	return new_offs;
1439 }
1440 
1441 static int ree_rename_wrapper(const char *old, const char *new)
1442 {
1443 	if (ree_fs_rename(old, new) != TEE_SUCCESS)
1444 		return -1;
1445 	return 0;
1446 }
1447 
1448 static int ree_unlink_wrapper(const char *file)
1449 {
1450 	if (ree_fs_remove(file) != TEE_SUCCESS)
1451 		return -1;
1452 	return 0;
1453 }
1454 
1455 static int ree_ftruncate_wrapper(TEE_Result *errno, int fd,
1456 				  tee_fs_off_t length)
1457 {
1458 	TEE_Result res;
1459 	struct tee_file_handle *tfh;
1460 
1461 	mutex_lock(&ree_fs_mutex);
1462 	tfh = handle_lookup(&fs_handle_db, fd);
1463 	mutex_unlock(&ree_fs_mutex);
1464 
1465 	if (!tfh) {
1466 		*errno = TEE_ERROR_BAD_PARAMETERS;
1467 		return -1;
1468 	}
1469 
1470 	res = ree_fs_truncate(tfh, length);
1471 	*errno = res;
1472 
1473 	if (res != TEE_SUCCESS)
1474 		return -1;
1475 	return 0;
1476 }
1477 
1478 static struct tee_fs_dir *ree_opendir_wrapper(const char *name)
1479 {
1480 	struct tee_fs_dir *d;
1481 
1482 	if (ree_fs_opendir_rpc(name, &d) != TEE_SUCCESS)
1483 		return NULL;
1484 	return d;
1485 }
1486 
1487 static int ree_closedir_wrapper(struct tee_fs_dir *d)
1488 {
1489 	ree_fs_closedir_rpc(d);
1490 	return 0;
1491 }
1492 
1493 static struct tee_fs_dirent *ree_readdir_wrapper(struct tee_fs_dir *d)
1494 {
1495 	struct tee_fs_dirent *e;
1496 
1497 	if (ree_fs_readdir_rpc(d, &e) != TEE_SUCCESS)
1498 		return NULL;
1499 	return e;
1500 }
1501 
1502 const struct tee_file_operations ree_fs_ops = {
1503 	.open = ree_open_wrapper,
1504 	.close = ree_close_wrapper,
1505 	.read = ree_read_wrapper,
1506 	.write = ree_write_wrapper,
1507 	.lseek = ree_lseek_wrapper,
1508 	.ftruncate = ree_ftruncate_wrapper,
1509 	.rename = ree_rename_wrapper,
1510 	.unlink = ree_unlink_wrapper,
1511 	.mkdir = ree_fs_mkdir_rpc,
1512 	.opendir = ree_opendir_wrapper,
1513 	.closedir = ree_closedir_wrapper,
1514 	.readdir = ree_readdir_wrapper,
1515 	.rmdir = ree_fs_rmdir_rpc,
1516 	.access = ree_fs_access_rpc
1517 };
1518