Changes in uspace/srv/fs/cdfs/cdfs_ops.c [fc22069:44ecf89] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/fs/cdfs/cdfs_ops.c
rfc22069 r44ecf89 39 39 #include "cdfs_ops.h" 40 40 #include <stdbool.h> 41 #include <adt/list.h>42 41 #include <adt/hash_table.h> 43 42 #include <adt/hash.h> … … 48 47 #include <errno.h> 49 48 #include <block.h> 50 #include <scsi/mmc.h>51 49 #include <str.h> 52 50 #include <byteorder.h> … … 67 65 68 66 #define CDFS_STANDARD_IDENT "CD001" 69 70 enum {71 CDFS_NAME_CURDIR = '\x00',72 CDFS_NAME_PARENTDIR = '\x01'73 };74 67 75 68 typedef enum { … … 133 126 134 127 typedef struct { 135 uint8_t flags; /* reserved in primary */128 uint8_t res0; 136 129 137 130 uint8_t system_ident[32]; … … 141 134 uint32_t_lb lba_size; 142 135 143 uint8_t esc_seq[32]; /* reserved in primary */136 uint8_t res2[32]; 144 137 uint16_t_lb set_size; 145 138 uint16_t_lb sequence_nr; … … 171 164 172 165 uint8_t fs_version; 173 } __attribute__((packed)) cdfs_vol_desc_pri sec_t;166 } __attribute__((packed)) cdfs_vol_desc_primary_t; 174 167 175 168 typedef struct { … … 179 172 union { 180 173 cdfs_vol_desc_boot_t boot; 181 cdfs_vol_desc_pri sec_t prisec;174 cdfs_vol_desc_primary_t primary; 182 175 } data; 183 176 } __attribute__((packed)) cdfs_vol_desc_t; 184 185 typedef enum {186 /** ASCII character set / encoding (base ISO 9660) */187 enc_ascii,188 /** UCS-2 character set / encoding (Joliet) */189 enc_ucs2190 } cdfs_enc_t;191 177 192 178 typedef enum { … … 205 191 206 192 typedef struct { 207 link_t link; /**< Link to list of all instances */208 service_id_t service_id; /**< Service ID of block device */209 cdfs_enc_t enc; /**< Filesystem string encoding */210 } cdfs_t;211 212 typedef struct {213 193 fs_node_t *fs_node; /**< FS node */ 214 194 fs_index_t index; /**< Node index */ 215 cdfs_t *fs; /**< File system*/195 service_id_t service_id; /**< Service ID of block device */ 216 196 217 197 ht_link_t nh_link; /**< Nodes hash table link */ … … 227 207 } cdfs_node_t; 228 208 229 /** String encoding */230 enum {231 /** ASCII - standard ISO 9660 */232 ucs2_esc_seq_no = 3,233 /** USC-2 - Joliet */234 ucs2_esc_seq_len = 3235 };236 237 /** Joliet SVD UCS-2 escape sequences */238 static uint8_t ucs2_esc_seq[ucs2_esc_seq_no][ucs2_esc_seq_len] = {239 { 0x25, 0x2f, 0x40 },240 { 0x25, 0x2f, 0x43 },241 { 0x25, 0x2f, 0x45 }242 };243 244 /** List of all instances */245 static LIST_INITIALIZE(cdfs_instances);246 247 209 /** Shared index of nodes */ 248 210 static fs_index_t cdfs_index = 1; … … 272 234 { 273 235 cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link); 274 return hash_combine(node-> fs->service_id, node->index);236 return hash_combine(node->service_id, node->index); 275 237 } 276 238 … … 280 242 ht_key_t *key = (ht_key_t*)k; 281 243 282 return key->service_id == node-> fs->service_id && key->index == node->index;244 return key->service_id == node->service_id && key->index == node->index; 283 245 } 284 246 … … 287 249 cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link); 288 250 289 if (node->type == CDFS_DIRECTORY) {290 link_t *link;291 while ((link = list_first(&node->cs_list)) != NULL) {292 cdfs_dentry_t *dentry = list_get_instance(link, cdfs_dentry_t, link);293 list_remove(&dentry->link);294 free(dentry);295 }251 assert(node->type == CDFS_DIRECTORY); 252 253 link_t *link; 254 while ((link = list_first(&node->cs_list)) != NULL) { 255 cdfs_dentry_t *dentry = list_get_instance(link, cdfs_dentry_t, link); 256 list_remove(&dentry->link); 257 free(dentry); 296 258 } 297 259 … … 338 300 node->fs_node = NULL; 339 301 node->index = 0; 340 node-> fs = NULL;302 node->service_id = 0; 341 303 node->type = CDFS_NONE; 342 304 node->lnkcnt = 0; … … 349 311 } 350 312 351 static int create_node(fs_node_t **rfn, cdfs_t *fs, int lflag,313 static int create_node(fs_node_t **rfn, service_id_t service_id, int lflag, 352 314 fs_index_t index) 353 315 { … … 370 332 371 333 fs_node_t *rootfn; 372 int rc = cdfs_root_get(&rootfn, fs->service_id);334 int rc = cdfs_root_get(&rootfn, service_id); 373 335 374 336 assert(rc == EOK); … … 379 341 node->index = index; 380 342 381 node-> fs = fs;343 node->service_id = service_id; 382 344 383 345 if (lflag & L_DIRECTORY) … … 403 365 404 366 /* Check for duplicate entries */ 405 list_foreach(parent->cs_list, link, cdfs_dentry_t, dentry) { 367 list_foreach(parent->cs_list, link) { 368 cdfs_dentry_t *dentry = 369 list_get_instance(link, cdfs_dentry_t, link); 370 406 371 if (str_cmp(dentry->name, name) == 0) 407 372 return EEXIST; … … 429 394 } 430 395 431 /** Decode CDFS string. 432 * 433 * @param data Pointer to string data 434 * @param dsize Size of data in bytes 435 * @param enc String encoding 436 * @return Decoded string 437 */ 438 static char *cdfs_decode_str(void *data, size_t dsize, cdfs_enc_t enc) 439 { 440 int rc; 441 char *str; 442 uint16_t *buf; 443 444 switch (enc) { 445 case enc_ascii: 446 str = malloc(dsize + 1); 447 if (str == NULL) 448 return NULL; 449 memcpy(str, data, dsize); 450 str[dsize] = '\0'; 451 break; 452 case enc_ucs2: 453 buf = calloc(dsize + 2, 1); 454 if (buf == NULL) 455 return NULL; 456 457 size_t i; 458 for (i = 0; i < dsize / sizeof(uint16_t); i++) { 459 buf[i] = uint16_t_be2host(((uint16_t *)data)[i]); 460 } 461 462 size_t dstr_size = dsize / sizeof(uint16_t) * 4 + 1; 463 str = malloc(dstr_size); 464 if (str == NULL) 465 return NULL; 466 467 rc = utf16_to_str(str, dstr_size, buf); 468 free(buf); 469 470 if (rc != EOK) 471 return NULL; 472 break; 473 default: 474 assert(false); 475 str = NULL; 476 } 477 478 return str; 479 } 480 481 /** Decode file name. 482 * 483 * @param data File name buffer 484 * @param dsize Fine name buffer size 485 * @param dtype Directory entry type 486 * @return Decoded file name (allocated string) 487 */ 488 static char *cdfs_decode_name(void *data, size_t dsize, cdfs_enc_t enc, 489 cdfs_dentry_type_t dtype) 490 { 491 char *name; 492 char *dot; 493 char *scolon; 494 495 name = cdfs_decode_str(data, dsize, enc); 496 if (name == NULL) 497 return NULL; 498 499 if (dtype == CDFS_DIRECTORY) 500 return name; 501 502 dot = str_chr(name, '.'); 503 504 if (dot != NULL) { 505 scolon = str_chr(dot, ';'); 506 if (scolon != NULL) { 507 /* Trim version part */ 508 *scolon = '\0'; 509 } 510 511 /* If the extension is an empty string, trim the dot separator. */ 512 if (dot[1] == '\0') 513 *dot = '\0'; 514 } 515 516 return name; 517 } 518 519 static bool cdfs_readdir(cdfs_t *fs, fs_node_t *fs_node) 396 static bool cdfs_readdir(service_id_t service_id, fs_node_t *fs_node) 520 397 { 521 398 cdfs_node_t *node = CDFS_NODE(fs_node); … … 531 408 for (uint32_t i = 0; i < blocks; i++) { 532 409 block_t *block; 533 int rc = block_get(&block, fs->service_id, node->lba + i, BLOCK_FLAGS_NONE);410 int rc = block_get(&block, service_id, node->lba + i, BLOCK_FLAGS_NONE); 534 411 if (rc != EOK) 535 412 return false; 536 413 537 cdfs_dir_t *dir; 538 539 for (size_t offset = 0; offset < BLOCK_SIZE; 414 cdfs_dir_t *dir = (cdfs_dir_t *) block->data; 415 416 // FIXME: skip '.' and '..' 417 418 for (size_t offset = 0; 419 (dir->length != 0) && (offset < BLOCK_SIZE); 540 420 offset += dir->length) { 541 421 dir = (cdfs_dir_t *) (block->data + offset); 542 if (dir->length == 0)543 break;544 if (offset + dir->length > BLOCK_SIZE) {545 /* XXX Incorrect FS structure */546 break;547 }548 422 549 423 cdfs_dentry_type_t dentry_type; … … 553 427 dentry_type = CDFS_FILE; 554 428 555 /* Skip special entries */556 557 if (dir->name_length == 1 &&558 dir->name[0] == CDFS_NAME_CURDIR)559 continue;560 if (dir->name_length == 1 &&561 dir->name[0] == CDFS_NAME_PARENTDIR)562 continue;563 564 429 // FIXME: hack - indexing by dentry byte offset on disc 565 430 566 431 fs_node_t *fn; 567 int rc = create_node(&fn, fs, dentry_type,432 int rc = create_node(&fn, service_id, dentry_type, 568 433 (node->lba + i) * BLOCK_SIZE + offset); 569 434 if ((rc != EOK) || (fn == NULL)) … … 574 439 cur->size = uint32_lb(dir->size); 575 440 576 char *name = cdfs_decode_name(dir->name, 577 dir->name_length, node->fs->enc, dentry_type); 441 char *name = (char *) malloc(dir->name_length + 1); 578 442 if (name == NULL) 579 443 return false; 444 445 memcpy(name, dir->name, dir->name_length); 446 name[dir->name_length] = 0; 580 447 581 448 // FIXME: check return value … … 595 462 } 596 463 597 static fs_node_t *get_uncached_node( cdfs_t *fs, fs_index_t index)464 static fs_node_t *get_uncached_node(service_id_t service_id, fs_index_t index) 598 465 { 599 466 cdfs_lba_t lba = index / BLOCK_SIZE; … … 601 468 602 469 block_t *block; 603 int rc = block_get(&block, fs->service_id, lba, BLOCK_FLAGS_NONE);470 int rc = block_get(&block, service_id, lba, BLOCK_FLAGS_NONE); 604 471 if (rc != EOK) 605 472 return NULL; … … 614 481 615 482 fs_node_t *fn; 616 rc = create_node(&fn, fs, dentry_type, index);483 rc = create_node(&fn, service_id, dentry_type, index); 617 484 if ((rc != EOK) || (fn == NULL)) 618 485 return NULL; … … 630 497 } 631 498 632 static fs_node_t *get_cached_node( cdfs_t *fs, fs_index_t index)499 static fs_node_t *get_cached_node(service_id_t service_id, fs_index_t index) 633 500 { 634 501 ht_key_t key = { 635 502 .index = index, 636 .service_id = fs->service_id503 .service_id = service_id 637 504 }; 638 505 … … 644 511 } 645 512 646 return get_uncached_node( fs, index);513 return get_uncached_node(service_id, index); 647 514 } 648 515 … … 652 519 653 520 if (!parent->processed) { 654 int rc = cdfs_readdir(parent-> fs, pfn);521 int rc = cdfs_readdir(parent->service_id, pfn); 655 522 if (rc != EOK) 656 523 return rc; 657 524 } 658 525 659 list_foreach(parent->cs_list, link, cdfs_dentry_t, dentry) { 526 list_foreach(parent->cs_list, link) { 527 cdfs_dentry_t *dentry = 528 list_get_instance(link, cdfs_dentry_t, link); 529 660 530 if (str_cmp(dentry->name, component) == 0) { 661 *fn = get_cached_node(parent-> fs, dentry->index);531 *fn = get_cached_node(parent->service_id, dentry->index); 662 532 return EOK; 663 533 } … … 673 543 674 544 if (!node->processed) 675 cdfs_readdir(node-> fs, fn);545 cdfs_readdir(node->service_id, fn); 676 546 677 547 node->opened++; … … 714 584 715 585 if ((node->type == CDFS_DIRECTORY) && (!node->processed)) 716 cdfs_readdir(node-> fs, fn);586 cdfs_readdir(node->service_id, fn); 717 587 718 588 *has_children = !list_empty(&node->cs_list); … … 753 623 { 754 624 return 0; 755 }756 757 static int cdfs_size_block(service_id_t service_id, uint32_t *size)758 {759 *size = BLOCK_SIZE;760 761 return EOK;762 }763 764 static int cdfs_total_block_count(service_id_t service_id, uint64_t *count)765 {766 *count = 0;767 768 return EOK;769 }770 771 static int cdfs_free_block_count(service_id_t service_id, uint64_t *count)772 {773 *count = 0;774 775 return EOK;776 625 } 777 626 … … 792 641 .is_directory = cdfs_is_directory, 793 642 .is_file = cdfs_is_file, 794 .service_get = cdfs_service_get, 795 .size_block = cdfs_size_block, 796 .total_block_count = cdfs_total_block_count, 797 .free_block_count = cdfs_free_block_count 643 .service_get = cdfs_service_get 798 644 }; 799 645 800 /** Verify that escape sequence corresonds to one of the allowed encoding 801 * escape sequences allowed for Joliet. */ 802 static int cdfs_verify_joliet_esc_seq(uint8_t *seq) 803 { 804 size_t i, j, k; 805 bool match; 806 807 i = 0; 808 while (i + ucs2_esc_seq_len <= 32) { 809 if (seq[i] == 0) 810 break; 811 812 for (j = 0; j < ucs2_esc_seq_no; j++) { 813 match = true; 814 for (k = 0; k < ucs2_esc_seq_len; k++) 815 if (seq[i + k] != ucs2_esc_seq[j][k]) 816 match = false; 817 if (match) { 818 break; 819 } 820 } 821 822 if (!match) 823 return EINVAL; 824 825 i += ucs2_esc_seq_len; 826 } 827 828 while (i < 32) { 829 if (seq[i] != 0) 830 return EINVAL; 831 ++i; 832 } 833 834 return EOK; 835 } 836 837 /** Find Joliet supplementary volume descriptor. 838 * 839 * @param sid Block device service ID 840 * @param altroot First filesystem block 841 * @param rlba Place to store LBA of root dir 842 * @param rsize Place to store size of root dir 843 * @return EOK if found, ENOENT if not 844 */ 845 static int cdfs_find_joliet_svd(service_id_t sid, cdfs_lba_t altroot, 846 uint32_t *rlba, uint32_t *rsize) 847 { 848 cdfs_lba_t bi; 849 850 for (bi = altroot + 17; ; bi++) { 851 block_t *block; 852 int rc = block_get(&block, sid, bi, BLOCK_FLAGS_NONE); 853 if (rc != EOK) 854 break; 855 856 cdfs_vol_desc_t *vol_desc = (cdfs_vol_desc_t *) block->data; 857 858 if (vol_desc->type == VOL_DESC_SET_TERMINATOR) { 859 block_put(block); 860 break; 861 } 862 863 if ((vol_desc->type != VOL_DESC_SUPPLEMENTARY) || 864 (memcmp(vol_desc->standard_ident, CDFS_STANDARD_IDENT, 5) != 0) || 865 (vol_desc->version != 1)) { 866 block_put(block); 867 continue; 868 } 869 870 uint16_t set_size = uint16_lb(vol_desc->data.prisec.set_size); 871 if (set_size > 1) { 872 /* 873 * Technically, we don't support multi-disc sets. 874 * But one can encounter erroneously mastered 875 * images in the wild and it might actually work 876 * for the first disc in the set. 877 */ 878 } 879 880 uint16_t sequence_nr = uint16_lb(vol_desc->data.prisec.sequence_nr); 881 if (sequence_nr != 1) { 882 /* 883 * We only support the first disc 884 * in multi-disc sets. 885 */ 886 block_put(block); 887 continue; 888 } 889 890 uint16_t block_size = uint16_lb(vol_desc->data.prisec.block_size); 891 if (block_size != BLOCK_SIZE) { 892 block_put(block); 893 continue; 894 } 895 896 rc = cdfs_verify_joliet_esc_seq(vol_desc->data.prisec.esc_seq); 897 if (rc != EOK) 898 continue; 899 *rlba = uint32_lb(vol_desc->data.prisec.root_dir.lba); 900 *rsize = uint32_lb(vol_desc->data.prisec.root_dir.size); 901 block_put(block); 902 return EOK; 903 } 904 905 return ENOENT; 906 } 907 908 static bool iso_readfs(cdfs_t *fs, fs_node_t *rfn, 646 static bool iso_readfs(service_id_t service_id, fs_node_t *rfn, 909 647 cdfs_lba_t altroot) 910 648 { 911 649 /* First 16 blocks of isofs are empty */ 912 650 block_t *block; 913 int rc = block_get(&block, fs->service_id, altroot + 16, BLOCK_FLAGS_NONE);651 int rc = block_get(&block, service_id, altroot + 16, BLOCK_FLAGS_NONE); 914 652 if (rc != EOK) 915 653 return false; … … 928 666 } 929 667 930 uint16_t set_size = uint16_lb(vol_desc->data.pri sec.set_size);668 uint16_t set_size = uint16_lb(vol_desc->data.primary.set_size); 931 669 if (set_size > 1) { 932 670 /* … … 938 676 } 939 677 940 uint16_t sequence_nr = uint16_lb(vol_desc->data.pri sec.sequence_nr);678 uint16_t sequence_nr = uint16_lb(vol_desc->data.primary.sequence_nr); 941 679 if (sequence_nr != 1) { 942 680 /* … … 948 686 } 949 687 950 uint16_t block_size = uint16_lb(vol_desc->data.pri sec.block_size);688 uint16_t block_size = uint16_lb(vol_desc->data.primary.block_size); 951 689 if (block_size != BLOCK_SIZE) { 952 690 block_put(block); … … 957 695 958 696 cdfs_node_t *node = CDFS_NODE(rfn); 959 960 /* Search for Joliet SVD */ 961 962 uint32_t jrlba; 963 uint32_t jrsize; 964 965 rc = cdfs_find_joliet_svd(fs->service_id, altroot, &jrlba, &jrsize); 966 if (rc == EOK) { 967 /* Found */ 968 node->lba = jrlba; 969 node->size = jrsize; 970 fs->enc = enc_ucs2; 971 } else { 972 node->lba = uint32_lb(vol_desc->data.prisec.root_dir.lba); 973 node->size = uint32_lb(vol_desc->data.prisec.root_dir.size); 974 fs->enc = enc_ascii; 975 } 976 977 if (!cdfs_readdir(fs, rfn)) { 697 node->lba = uint32_lb(vol_desc->data.primary.root_dir.lba); 698 node->size = uint32_lb(vol_desc->data.primary.root_dir.size); 699 700 if (!cdfs_readdir(service_id, rfn)) { 978 701 block_put(block); 979 702 return false; … … 987 710 * 988 711 */ 989 static cdfs_t *cdfs_fs_create(service_id_t sid, cdfs_lba_t altroot) 990 { 991 cdfs_t *fs = NULL; 992 fs_node_t *rfn = NULL; 993 994 fs = calloc(1, sizeof(cdfs_t)); 995 if (fs == NULL) 996 goto error; 997 998 fs->service_id = sid; 999 712 static bool cdfs_instance_init(service_id_t service_id, cdfs_lba_t altroot) 713 { 1000 714 /* Create root node */ 1001 int rc = create_node(&rfn, fs, L_DIRECTORY, cdfs_index++); 715 fs_node_t *rfn; 716 int rc = create_node(&rfn, service_id, L_DIRECTORY, cdfs_index++); 1002 717 1003 718 if ((rc != EOK) || (!rfn)) 1004 goto error;719 return false; 1005 720 1006 721 /* FS root is not linked */ … … 1010 725 1011 726 /* Check if there is cdfs in given session */ 1012 if (!iso_readfs(fs, rfn, altroot)) 1013 goto error; 1014 1015 list_append(&fs->link, &cdfs_instances); 1016 return fs; 1017 error: 1018 // XXX destroy node 1019 free(fs); 1020 return NULL; 727 if (!iso_readfs(service_id, rfn, altroot)) { 728 // XXX destroy node 729 return false; 730 } 731 732 return true; 1021 733 } 1022 734 … … 1025 737 { 1026 738 /* Initialize the block layer */ 1027 int rc = block_init( service_id, BLOCK_SIZE);739 int rc = block_init(EXCHANGE_SERIALIZE, service_id, BLOCK_SIZE); 1028 740 if (rc != EOK) 1029 741 return rc; … … 1036 748 altroot = 0; 1037 749 } else { 1038 /* 1039 * Read TOC multisession information and get the start address 1040 * of the first track in the last session 1041 */ 1042 scsi_toc_multisess_data_t toc; 1043 1044 rc = block_read_toc(service_id, 1, &toc, sizeof(toc)); 1045 if (rc == EOK && (uint16_t_be2host(toc.toc_len) == 10)) 1046 altroot = uint32_t_be2host(toc.ftrack_lsess.start_addr); 750 /* Read TOC and find the last session */ 751 toc_block_t *toc = block_get_toc(service_id, 1); 752 if ((toc != NULL) && (uint16_t_be2host(toc->size) == 10)) { 753 altroot = uint32_t_be2host(toc->first_lba); 754 free(toc); 755 } 1047 756 } 1048 757 … … 1065 774 } 1066 775 1067 /* Create cdfs instance */1068 if ( cdfs_fs_create(service_id, altroot) == NULL) {776 /* Initialize cdfs instance */ 777 if (!cdfs_instance_init(service_id, altroot)) { 1069 778 block_cache_fini(service_id); 1070 779 block_fini(service_id); … … 1089 798 cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link); 1090 799 1091 if (node-> fs->service_id == service_id) {800 if (node->service_id == service_id) { 1092 801 hash_table_remove_item(&nodes, &node->nh_link); 1093 802 } … … 1096 805 } 1097 806 1098 static void cdfs_fs_destroy(cdfs_t *fs) 1099 { 1100 list_remove(&fs->link); 1101 hash_table_apply(&nodes, rm_service_id_nodes, &fs->service_id); 1102 block_cache_fini(fs->service_id); 1103 block_fini(fs->service_id); 1104 free(fs); 1105 } 1106 1107 static cdfs_t *cdfs_find_by_sid(service_id_t service_id) 1108 { 1109 list_foreach(cdfs_instances, link, cdfs_t, fs) { 1110 if (fs->service_id == service_id) 1111 return fs; 1112 } 1113 1114 return NULL; 807 static void cdfs_instance_done(service_id_t service_id) 808 { 809 hash_table_apply(&nodes, rm_service_id_nodes, &service_id); 810 block_cache_fini(service_id); 811 block_fini(service_id); 1115 812 } 1116 813 1117 814 static int cdfs_unmounted(service_id_t service_id) 1118 815 { 1119 cdfs_t *fs; 1120 1121 fs = cdfs_find_by_sid(service_id); 1122 if (fs == NULL) 1123 return ENOENT; 1124 1125 cdfs_fs_destroy(fs); 816 cdfs_instance_done(service_id); 1126 817 return EOK; 1127 818 } … … 1143 834 1144 835 if (!node->processed) { 1145 int rc = cdfs_readdir( node->fs, FS_NODE(node));836 int rc = cdfs_readdir(service_id, FS_NODE(node)); 1146 837 if (rc != EOK) 1147 838 return rc; … … 1226 917 /* Some nodes were requested to be removed from the cache. */ 1227 918 if (0 < *premove_cnt) { 1228 cdfs_node_t *node = 919 cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link); 1229 920 1230 921 if (!node->opened) {
Note:
See TracChangeset
for help on using the changeset viewer.