fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
{
    fsw_status_t    status;
    struct fsw_shandle shand;
    fsw_u32         buffer_size;
    char            buffer[FSW_PATH_MAX];

    struct fsw_string s;

    if (dno->size > FSW_PATH_MAX)
        return FSW_VOLUME_CORRUPTED;

    s.type = FSW_STRING_TYPE_ISO88591;
    s.size = s.len = (int)dno->size;
    s.data = buffer;

    // open shandle and read the data
    status = fsw_shandle_open(dno, &shand);
    if (status)
        return status;
    buffer_size = (fsw_u32)s.size;
    status = fsw_shandle_read(&shand, &buffer_size, buffer);
    fsw_shandle_close(&shand);
    if (status)
        return status;
    if ((int)buffer_size < s.size)
        return FSW_VOLUME_CORRUPTED;

    status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s);
    return status;
}
Exemplo n.º 2
0
static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
                                      struct fsw_string *link_target)
{
    fsw_status_t    status;
    int             ea_blocks;
    struct fsw_string s;

    if (dno->g.size > FSW_PATH_MAX)
        return FSW_VOLUME_CORRUPTED;

    ea_blocks = dno->raw->i_file_acl ? (vol->g.log_blocksize >> 9) : 0;

    if (dno->raw->i_blocks - ea_blocks == 0) {
        // "fast" symlink, path is stored inside the inode
        s.type = FSW_STRING_TYPE_ISO88591;
        s.size = s.len = (int)dno->g.size;
        s.data = dno->raw->i_block;
        status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s);
    } else {
        // "slow" symlink, path is stored in normal inode data
        status = fsw_dnode_readlink_data(dno, link_target);
    }

    return status;
}
Exemplo n.º 3
0
fsw_status_t fsw_dnode_create_with_tree(struct fsw_dnode *parent_dno, fsw_u64 tree_id, fsw_u64 dnode_id, int type,
                              struct fsw_string *name, struct fsw_dnode **dno_out)
{
    fsw_status_t    status;
    struct fsw_volume *vol = parent_dno->vol;
    struct fsw_dnode *dno;

    // check if we already have a dnode with the same id
    for (dno = vol->dnode_head; dno; dno = dno->next) {
        if (dno->dnode_id == dnode_id && dno->tree_id == tree_id) {
            fsw_dnode_retain(dno);
            *dno_out = dno;
            return FSW_SUCCESS;
        }
    }

    // allocate memory for the structure
    status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
    if (status)
        return status;

    // fill the structure
    dno->vol = vol;
    dno->parent = parent_dno;
    fsw_dnode_retain(dno->parent);
    dno->tree_id = tree_id;
    dno->dnode_id = dnode_id;
    dno->type = type;
    dno->refcount = 1;
    status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
    if (status) {
        fsw_free(dno);
        return status;
    }

    fsw_dnode_register(vol, dno);

    *dno_out = dno;
    return FSW_SUCCESS;
}
Exemplo n.º 4
0
static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol)
{
    fsw_status_t    status;
    void            *buffer;
    fsw_u32         blockno;
    struct iso9660_volume_descriptor *voldesc;
    struct iso9660_primary_volume_descriptor *pvoldesc;
    fsw_u32         voldesc_type;
    int             i;
    struct fsw_string s;
    struct iso9660_dirrec rootdir;
    int sua_pos;
    char *sig;
    int skip;
    struct fsw_rock_ridge_susp_entry *entry;

    // read through the Volume Descriptor Set
    fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE);
    blockno = ISO9660_SUPERBLOCK_BLOCKNO;

    do {
        status = fsw_block_get(vol, blockno, 0, &buffer);
        if (status)
            return status;

        voldesc = (struct iso9660_volume_descriptor *)buffer;
        voldesc_type = voldesc->volume_descriptor_type;
        if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) {
            // descriptor follows ISO 9660 standard
            if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) {
                // suitable Primary Volume Descriptor found
                if (vol->primary_voldesc) {
                    fsw_free(vol->primary_voldesc);
                    vol->primary_voldesc = NULL;
                }
                status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE);
            }
        } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) {
            // completely alien standard identifier, stop reading
            voldesc_type = 255;
        }

        fsw_block_release(vol, blockno, buffer);
        blockno++;
    } while (!status && voldesc_type != 255);
    if (status)
        return status;

    // get information from Primary Volume Descriptor
    if (vol->primary_voldesc == NULL)
        return FSW_UNSUPPORTED;
    pvoldesc = vol->primary_voldesc;
    if (ISOINT(pvoldesc->logical_block_size) != 2048)
        return FSW_UNSUPPORTED;

    // get volume name
    for (i = 32; i > 0; i--)
        if (pvoldesc->volume_identifier[i-1] != ' ')
            break;
    s.type = FSW_STRING_TYPE_ISO88591;
    s.size = s.len = i;
    s.data = pvoldesc->volume_identifier;
    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
    if (status)
        return status;

    // setup the root dnode
    status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root);
    if (status)
        return status;
    fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec));

    if (   pvoldesc->escape[0] == 0x25
        && pvoldesc->escape[1] == 0x2f
        && (   pvoldesc->escape[2] == 0x40
            || pvoldesc->escape[2] == 0x43
            || pvoldesc->escape[2] == 0x45))
    {
        FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
        vol->fJoliet = 1;
    }


    fsw_memcpy(&rootdir, &pvoldesc->root_directory, sizeof(rootdir));
    sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2;
    //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
    //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));

#if 1
    status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer);
    sig = (char *)buffer + sua_pos;
    skip = 0;
    entry = (struct fsw_rock_ridge_susp_entry *)sig;
    if (   entry->sig[0] == 'S'
        && entry->sig[1] == 'P')
    {
        struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry;
        if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef)
        {
            vol->fRockRidge = 1;
        } else {
            FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
        }
        skip = sp->skip;
    }
#endif
    // release volume descriptors
    fsw_free(vol->primary_voldesc);
    vol->primary_voldesc = NULL;


    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));

    return FSW_SUCCESS;
}
Exemplo n.º 5
0
static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol)
{
    fsw_status_t    status;
    void            *buffer;
    fsw_u32         blocksize;
    fsw_u32         groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index;
    struct ext2_group_desc *gdesc;
    int             i;
    struct fsw_string s;

    // allocate memory to keep the superblock around
    status = fsw_alloc(sizeof(struct ext2_super_block), &vol->sb);
    if (status)
        return status;

    // read the superblock into its buffer
    fsw_set_blocksize(vol, EXT2_SUPERBLOCK_BLOCKSIZE, EXT2_SUPERBLOCK_BLOCKSIZE);
    status = fsw_block_get(vol, EXT2_SUPERBLOCK_BLOCKNO, 0, &buffer);
    if (status)
        return status;
    fsw_memcpy(vol->sb, buffer, sizeof(struct ext2_super_block));
    fsw_block_release(vol, EXT2_SUPERBLOCK_BLOCKNO, buffer);

    // check the superblock
    if (vol->sb->s_magic != EXT2_SUPER_MAGIC)
        return FSW_UNSUPPORTED;
    if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
        vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
        return FSW_UNSUPPORTED;
    if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
        (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
        return FSW_UNSUPPORTED;

    /*
     if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
         (vol->sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER))
     Print(L"Ext2 WARNING: This ext3 file system needs recovery, trying to use it anyway.\n");
     */

    // set real blocksize
    blocksize = EXT2_BLOCK_SIZE(vol->sb);
    fsw_set_blocksize(vol, blocksize, blocksize);

    // get other info from superblock
    vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
    vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
    vol->inode_size = EXT2_INODE_SIZE(vol->sb);

    for (i = 0; i < 16; i++)
        if (vol->sb->s_volume_name[i] == 0)
            break;
    s.type = FSW_STRING_TYPE_ISO88591;
    s.size = s.len = i;
    s.data = vol->sb->s_volume_name;
    status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
    if (status)
        return status;

    // read the group descriptors to get inode table offsets
    groupcnt = ((vol->sb->s_inodes_count - 2) / vol->sb->s_inodes_per_group) + 1;
    gdesc_per_block = (vol->g.phys_blocksize / sizeof(struct ext2_group_desc));

    status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno);
    if (status)
        return status;
    for (groupno = 0; groupno < groupcnt; groupno++) {
        // get the block group descriptor
        gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block;
        gdesc_index = groupno % gdesc_per_block;
        status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer);
        if (status)
            return status;
        gdesc = ((struct ext2_group_desc *)(buffer)) + gdesc_index;
        vol->inotab_bno[groupno] = gdesc->bg_inode_table;
        fsw_block_release(vol, gdesc_bno, buffer);
    }

    // setup the root dnode
    status = fsw_dnode_create_root(vol, EXT2_ROOT_INO, &vol->g.root);
    if (status)
        return status;

    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_volume_mount: success, blocksize %d\n"), blocksize));

    return FSW_SUCCESS;
}