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