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