Beispiel #1
0
static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno)
{
    fsw_status_t    status;
    fsw_u32         groupno, ino_in_group, ino_bno, ino_index;
    fsw_u8          *buffer;

    if (dno->raw)
        return FSW_SUCCESS;

    FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_dnode_fill: inode %d\n"), dno->g.dnode_id));

    // read the inode block
    groupno = (fsw_u32) (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group;
    ino_in_group = (fsw_u32) (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group;
    ino_bno = vol->inotab_bno[groupno] +
        ino_in_group / (vol->g.phys_blocksize / vol->inode_size);
    ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size);
    status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer);
    if (status)
        return status;

    // keep our inode around
    status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size);
    fsw_block_release(vol, ino_bno, buffer);
    if (status)
        return status;

    // get info from the inode
    dno->g.size = dno->raw->i_size;
    // TODO: check docs for 64-bit sized files
    if (S_ISREG(dno->raw->i_mode))
        dno->g.type = FSW_DNODE_TYPE_FILE;
    else if (S_ISDIR(dno->raw->i_mode))
        dno->g.type = FSW_DNODE_TYPE_DIR;
    else if (S_ISLNK(dno->raw->i_mode))
        dno->g.type = FSW_DNODE_TYPE_SYMLINK;
    else
        dno->g.type = FSW_DNODE_TYPE_SPECIAL;

    return FSW_SUCCESS;
}
fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
{
    fsw_status_t    status;
    struct fsw_dnode *dno = shand->dnode;
    struct fsw_volume *vol = dno->vol;
    fsw_u8          *buffer, *block_buffer;
    fsw_u32         buflen, copylen, pos;
    fsw_u32         log_bno, pos_in_extent, phys_bno, pos_in_physblock;
    fsw_u32         cache_level;

    if (shand->pos >= dno->size) {   // already at EOF
        *buffer_size_inout = 0;
        return FSW_SUCCESS;
    }

    // initialize vars
    buffer = buffer_in;
    buflen = *buffer_size_inout;
    pos = (fsw_u32)shand->pos;
    cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0;
    // restrict read to file size
    if (buflen > dno->size - pos)
        buflen = (fsw_u32)(dno->size - pos);

    while (buflen > 0) {
        // get extent for the current logical block
        log_bno = pos / vol->log_blocksize;
        if (shand->extent.type == FSW_EXTENT_TYPE_INVALID ||
            log_bno < shand->extent.log_start ||
            log_bno >= shand->extent.log_start + shand->extent.log_count) {

            if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
                fsw_free(shand->extent.buffer);

            // ask the file system for the proper extent
            shand->extent.log_start = log_bno;
            status = vol->fstype_table->get_extent(vol, dno, &shand->extent);
            if (status) {
                shand->extent.type = FSW_EXTENT_TYPE_INVALID;
                return status;
            }
        }

        pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize;

        // dispatch by extent type
        if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) {
            // convert to physical block number and offset
            phys_bno = shand->extent.phys_start + pos_in_extent / vol->phys_blocksize;
            pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1);
            copylen = vol->phys_blocksize - pos_in_physblock;
            if (copylen > buflen)
                copylen = buflen;

            // get one physical block
            status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer);
            if (status)
                return status;

            // copy data from it
            fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen);
            fsw_block_release(vol, phys_bno, block_buffer);

        } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) {
            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
            if (copylen > buflen)
                copylen = buflen;
            fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen);

        } else {   // _SPARSE or _INVALID
            copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
            if (copylen > buflen)
                copylen = buflen;
            fsw_memzero(buffer, copylen);

        }

        buffer += copylen;
        buflen -= copylen;
        pos    += copylen;
    }

    *buffer_size_inout = (fsw_u32)(pos - shand->pos);
    shand->pos = pos;

    return FSW_SUCCESS;
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
0
static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
                                        struct fsw_extent *extent)
{
    fsw_status_t    status;
    fsw_u32         bno, release_bno, buf_bcnt, file_bcnt;
    fsw_u32         *buffer;
    int             path[5], i;

    // Preconditions: The caller has checked that the requested logical block
    //  is within the file's size. The dnode has complete information, i.e.
    //  fsw_ext2_dnode_read_info was called successfully on it.

    extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
    extent->log_count = 1;
    bno = extent->log_start;

    // try direct block pointers in the inode
    if (bno < EXT2_NDIR_BLOCKS) {
        path[0] = bno;
        path[1] = -1;
    } else {
        bno -= EXT2_NDIR_BLOCKS;

        // try indirect block
        if (bno < vol->ind_bcnt) {
            path[0] = EXT2_IND_BLOCK;
            path[1] = bno;
            path[2] = -1;
        } else {
            bno -= vol->ind_bcnt;

            // try double-indirect block
            if (bno < vol->dind_bcnt) {
                path[0] = EXT2_DIND_BLOCK;
                path[1] = bno / vol->ind_bcnt;
                path[2] = bno % vol->ind_bcnt;
                path[3] = -1;
            } else {
                bno -= vol->dind_bcnt;

                // use the triple-indirect block
                path[0] = EXT2_TIND_BLOCK;
                path[1] = bno / vol->dind_bcnt;
                path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt;
                path[3] = bno % vol->ind_bcnt;
                path[4] = -1;
            }
        }
    }

    // follow the indirection path
    buffer = dno->raw->i_block;
    buf_bcnt = EXT2_NDIR_BLOCKS;
    release_bno = 0;
    for (i = 0; ; i++) {
        bno = buffer[path[i]];
        if (bno == 0) {
            extent->type = FSW_EXTENT_TYPE_SPARSE;
            if (release_bno)
                fsw_block_release(vol, release_bno, buffer);
            return FSW_SUCCESS;
        }
        if (path[i+1] < 0)
            break;

        if (release_bno)
            fsw_block_release(vol, release_bno, buffer);
        status = fsw_block_get(vol, bno, 1, (void **)&buffer);
        if (status)
            return status;
        release_bno = bno;
        buf_bcnt = vol->ind_bcnt;
    }
    extent->phys_start = bno;

    // check if the following blocks can be aggregated into one extent
    file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
    while (path[i]           + extent->log_count < buf_bcnt &&    // indirect block has more block pointers
           extent->log_start + extent->log_count < file_bcnt) {   // file has more blocks
        if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
            extent->log_count++;
        else
            break;
    }

    if (release_bno)
        fsw_block_release(vol, release_bno, buffer);
    return FSW_SUCCESS;
}