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