Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 993d608 in mainline


Ignore:
Timestamp:
2014-08-07T21:29:31Z (6 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
238869ca
Parents:
0003e0f5
Message:

Add Joliet extension support to CDFS.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/fs/cdfs/cdfs_ops.c

    r0003e0f5 r993d608  
    132132
    133133typedef struct {
    134         uint8_t res0;
     134        uint8_t flags; /* reserved in primary */
    135135       
    136136        uint8_t system_ident[32];
     
    140140        uint32_t_lb lba_size;
    141141       
    142         uint8_t res2[32];
     142        uint8_t esc_seq[32]; /* reserved in primary */
    143143        uint16_t_lb set_size;
    144144        uint16_t_lb sequence_nr;
     
    170170       
    171171        uint8_t fs_version;
    172 } __attribute__((packed)) cdfs_vol_desc_primary_t;
     172} __attribute__((packed)) cdfs_vol_desc_prisec_t;
    173173
    174174typedef struct {
     
    178178        union {
    179179                cdfs_vol_desc_boot_t boot;
    180                 cdfs_vol_desc_primary_t primary;
     180                cdfs_vol_desc_prisec_t prisec;
    181181        } data;
    182182} __attribute__((packed)) cdfs_vol_desc_t;
     183
     184typedef enum {
     185        /** ASCII character set / encoding (base ISO 9660) */
     186        enc_ascii,
     187        /** UCS-2 character set / encoding (Joliet) */
     188        enc_ucs2
     189} cdfs_enc_t;
    183190
    184191typedef enum {
     
    196203typedef uint32_t cdfs_lba_t;
    197204
    198 /** Mounted CDFS filesystem */
    199205typedef struct {
    200         link_t link;
     206        link_t link;              /**< Link to list of all instances */
    201207        service_id_t service_id;  /**< Service ID of block device */
     208        cdfs_enc_t enc;           /**< Filesystem string encoding */
    202209} cdfs_t;
    203210
     
    218225        unsigned int opened;      /**< Opened count */
    219226} cdfs_node_t;
     227
     228/** String encoding */
     229enum {
     230        /** ASCII - standard ISO 9660 */
     231        ucs2_esc_seq_no = 3,
     232        /** USC-2 - Joliet */
     233        ucs2_esc_seq_len = 3
     234};
     235
     236/** Joliet SVD UCS-2 escape sequences */
     237static uint8_t ucs2_esc_seq[ucs2_esc_seq_no][ucs2_esc_seq_len] = {
     238        { 0x25, 0x2f, 0x40 },
     239        { 0x25, 0x2f, 0x43 },
     240        { 0x25, 0x2f, 0x45 }
     241};
    220242
    221243/** List of all instances */
     
    406428}
    407429
     430/** Decode CDFS string.
     431 *
     432 * @param data  Pointer to string data
     433 * @param dsize Size of data in bytes
     434 * @param enc   String encoding
     435 * @return      Decoded string
     436 */
     437static char *cdfs_decode_str(void *data, size_t dsize, cdfs_enc_t enc)
     438{
     439        int rc;
     440        char *str;
     441        uint16_t *buf;
     442       
     443        switch (enc) {
     444        case enc_ascii:
     445                str = malloc(dsize + 1);
     446                if (str == NULL)
     447                        return NULL;
     448                memcpy(str, data, dsize);
     449                str[dsize] = '\0';
     450                break;
     451        case enc_ucs2:
     452                buf = calloc(dsize + 2, 1);
     453                if (buf == NULL)
     454                        return NULL;
     455               
     456                size_t i;
     457                for (i = 0; i < dsize / sizeof(uint16_t); i++) {
     458                        buf[i] = uint16_t_be2host(((uint16_t *)data)[i]);
     459                }
     460               
     461                size_t dstr_size = dsize / sizeof(uint16_t) * 4 + 1;
     462                str = malloc(dstr_size);
     463                if (str == NULL)
     464                        return NULL;
     465               
     466                rc = utf16_to_str(str, dstr_size, buf);
     467                free(buf);
     468               
     469                if (rc != EOK)
     470                        return NULL;
     471                break;
     472        default:
     473                assert(false);
     474                str = NULL;
     475        }
     476       
     477        return str;
     478}
     479
    408480/** Decode file name.
    409481 *
     
    413485 * @return      Decoded file name (allocated string)
    414486 */
    415 static char *cdfs_decode_name(void *data, size_t dsize,
     487static char *cdfs_decode_name(void *data, size_t dsize, cdfs_enc_t enc,
    416488    cdfs_dentry_type_t dtype)
    417489{
     
    419491        char *dot;
    420492        char *scolon;
    421 
    422         name = malloc(dsize + 1);
     493       
     494        name = cdfs_decode_str(data, dsize, enc);
    423495        if (name == NULL)
    424496                return NULL;
    425         memcpy(name, data, dsize);
    426         name[dsize] = '\0';
    427 
     497       
    428498        if (dtype == CDFS_DIRECTORY)
    429499                return name;
    430 
     500       
    431501        dot = str_chr(name, '.');
    432         if (dot == NULL)
    433                 return NULL;
    434         scolon = str_chr(dot, ';');
    435         if (scolon == NULL)
    436                 return NULL;
    437 
    438         /* Trim version part */
    439         *scolon = '\0';
    440 
    441         /* If the extension is an empty string, trim the dot separator. */
    442         if (dot[1] == '\0')
    443                 *dot = '\0';
    444 
     502       
     503        if (dot != NULL) {
     504                scolon = str_chr(dot, ';');
     505                if (scolon != NULL) {
     506                        /* Trim version part */
     507                        *scolon = '\0';
     508                }
     509       
     510                /* If the extension is an empty string, trim the dot separator. */
     511                if (dot[1] == '\0')
     512                        *dot = '\0';
     513        }
     514       
    445515        return name;
    446516}
     
    504574                       
    505575                        char *name = cdfs_decode_name(dir->name,
    506                             dir->name_length, dentry_type);
     576                            dir->name_length, node->fs->enc, dentry_type);
    507577                        if (name == NULL)
    508578                                return false;
     
    687757{
    688758        *size = BLOCK_SIZE;
    689 
     759       
    690760        return EOK;
    691761}
     
    727797};
    728798
     799/** Verify that escape sequence corresonds to one of the allowed encoding
     800 * escape sequences allowed for Joliet. */
     801static int cdfs_verify_joliet_esc_seq(uint8_t *seq)
     802{
     803        size_t i, j, k;
     804        bool match;
     805       
     806        i = 0;
     807        while (i + ucs2_esc_seq_len <= 32) {
     808                if (seq[i] == 0)
     809                        break;
     810               
     811                for (j = 0; j < ucs2_esc_seq_no; j++) {
     812                        match = true;
     813                        for (k = 0; k < ucs2_esc_seq_len; k++)
     814                                if (seq[i + k] != ucs2_esc_seq[j][k])
     815                                        match = false;
     816                        if (match) {
     817                                break;
     818                        }
     819                }
     820               
     821                if (!match)
     822                        return EINVAL;
     823               
     824                i += ucs2_esc_seq_len;
     825        }
     826       
     827        while (i < 32) {
     828                if (seq[i] != 0)
     829                        return EINVAL;
     830                ++i;
     831        }
     832       
     833        return EOK;
     834}
     835
     836/** Find Joliet supplementary volume descriptor.
     837 *
     838 * @param sid           Block device service ID
     839 * @param altroot       First filesystem block
     840 * @param rlba          Place to store LBA of root dir
     841 * @param rsize         Place to store size of root dir
     842 * @return              EOK if found, ENOENT if not
     843 */
     844static int cdfs_find_joliet_svd(service_id_t sid, cdfs_lba_t altroot,
     845    uint32_t *rlba, uint32_t *rsize)
     846{
     847        cdfs_lba_t bi;
     848
     849        for (bi = altroot + 17; ; bi++) {
     850                block_t *block;
     851                int rc = block_get(&block, sid, bi, BLOCK_FLAGS_NONE);
     852                if (rc != EOK)
     853                        break;
     854               
     855                cdfs_vol_desc_t *vol_desc = (cdfs_vol_desc_t *) block->data;
     856               
     857                if (vol_desc->type == VOL_DESC_SET_TERMINATOR) {
     858                        block_put(block);
     859                        break;
     860                }
     861               
     862                if ((vol_desc->type != VOL_DESC_SUPPLEMENTARY) ||
     863                    (memcmp(vol_desc->standard_ident, CDFS_STANDARD_IDENT, 5) != 0) ||
     864                    (vol_desc->version != 1)) {
     865                        block_put(block);
     866                        continue;
     867                }
     868               
     869                uint16_t set_size = uint16_lb(vol_desc->data.prisec.set_size);
     870                if (set_size > 1) {
     871                        /*
     872                         * Technically, we don't support multi-disc sets.
     873                         * But one can encounter erroneously mastered
     874                         * images in the wild and it might actually work
     875                         * for the first disc in the set.
     876                         */
     877                }
     878               
     879                uint16_t sequence_nr = uint16_lb(vol_desc->data.prisec.sequence_nr);
     880                if (sequence_nr != 1) {
     881                        /*
     882                         * We only support the first disc
     883                         * in multi-disc sets.
     884                         */
     885                        block_put(block);
     886                        continue;
     887                }
     888               
     889                uint16_t block_size = uint16_lb(vol_desc->data.prisec.block_size);
     890                if (block_size != BLOCK_SIZE) {
     891                        block_put(block);
     892                        continue;
     893                }
     894               
     895                rc = cdfs_verify_joliet_esc_seq(vol_desc->data.prisec.esc_seq);
     896                if (rc != EOK)
     897                        continue;
     898                *rlba = uint32_lb(vol_desc->data.prisec.root_dir.lba);
     899                *rsize = uint32_lb(vol_desc->data.prisec.root_dir.size);
     900                block_put(block);
     901                return EOK;
     902        }
     903       
     904        return ENOENT;
     905}
     906
    729907static bool iso_readfs(cdfs_t *fs, fs_node_t *rfn,
    730908    cdfs_lba_t altroot)
     
    749927        }
    750928       
    751         uint16_t set_size = uint16_lb(vol_desc->data.primary.set_size);
     929        uint16_t set_size = uint16_lb(vol_desc->data.prisec.set_size);
    752930        if (set_size > 1) {
    753931                /*
     
    759937        }
    760938       
    761         uint16_t sequence_nr = uint16_lb(vol_desc->data.primary.sequence_nr);
     939        uint16_t sequence_nr = uint16_lb(vol_desc->data.prisec.sequence_nr);
    762940        if (sequence_nr != 1) {
    763941                /*
     
    769947        }
    770948       
    771         uint16_t block_size = uint16_lb(vol_desc->data.primary.block_size);
     949        uint16_t block_size = uint16_lb(vol_desc->data.prisec.block_size);
    772950        if (block_size != BLOCK_SIZE) {
    773951                block_put(block);
     
    778956       
    779957        cdfs_node_t *node = CDFS_NODE(rfn);
    780         node->lba = uint32_lb(vol_desc->data.primary.root_dir.lba);
    781         node->size = uint32_lb(vol_desc->data.primary.root_dir.size);
     958       
     959        /* Search for Joliet SVD */
     960       
     961        uint32_t jrlba;
     962        uint32_t jrsize;
     963       
     964        rc = cdfs_find_joliet_svd(fs->service_id, altroot, &jrlba, &jrsize);
     965        if (rc == EOK) {
     966                /* Found */
     967                node->lba = jrlba;
     968                node->size = jrsize;
     969                fs->enc = enc_ucs2;
     970        } else {
     971                node->lba = uint32_lb(vol_desc->data.prisec.root_dir.lba);
     972                node->size = uint32_lb(vol_desc->data.prisec.root_dir.size);
     973                fs->enc = enc_ascii;
     974        }
    782975       
    783976        if (!cdfs_readdir(fs, rfn)) {
     
    801994        if (fs == NULL)
    802995                goto error;
    803 
     996       
    804997        fs->service_id = sid;
    805 
     998       
    806999        /* Create root node */
    8071000        int rc = create_node(&rfn, fs, L_DIRECTORY, cdfs_index++);
     
    9251118        if (fs == NULL)
    9261119                return ENOENT;
    927 
     1120       
    9281121        cdfs_fs_destroy(fs);
    9291122        return EOK;
     
    10291222        /* Some nodes were requested to be removed from the cache. */
    10301223        if (0 < *premove_cnt) {
    1031                 cdfs_node_t *node =     hash_table_get_inst(item, cdfs_node_t, nh_link);
     1224                cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
    10321225
    10331226                if (!node->opened) {
Note: See TracChangeset for help on using the changeset viewer.