fsw_status_t fsw_memdup(void **dest_out, void *src, int len) { fsw_status_t status; status = fsw_alloc(len, dest_out); if (status) return status; fsw_memcpy(*dest_out, src, len); return FSW_SUCCESS; }
fsw_status_t fsw_alloc_zero(int len, void **ptr_out) { fsw_status_t status; status = fsw_alloc(len, ptr_out); if (status) return status; fsw_memzero(*ptr_out, len); return FSW_SUCCESS; }
struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path) { fsw_status_t status; struct fsw_posix_dir *dir; // allocate file structure status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir); if (status) return NULL; dir->pvol = pvol; // open the directory status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand); if (status) { fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status); fsw_free(dir); return NULL; } return dir; }
fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src) { fsw_status_t status; if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) { dest->type = type; dest->size = dest->len = 0; dest->data = NULL; return FSW_SUCCESS; } if (src->type == type) { dest->type = type; dest->len = src->len; dest->size = src->size; status = fsw_alloc(dest->size, &dest->data); if (status) return status; fsw_memcpy(dest->data, src->data, dest->size); return FSW_SUCCESS; } // dispatch to type-specific functions #define STRCOERCE_DISPATCH(type1, type2) \ if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \ return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest); STRCOERCE_DISPATCH(UTF8, ISO88591); STRCOERCE_DISPATCH(UTF16, ISO88591); STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591); STRCOERCE_DISPATCH(ISO88591, UTF8); STRCOERCE_DISPATCH(UTF16, UTF8); STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8); STRCOERCE_DISPATCH(ISO88591, UTF16); STRCOERCE_DISPATCH(UTF8, UTF16); STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16); return FSW_UNSUPPORTED; }
struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode) { fsw_status_t status; struct fsw_posix_file *file; // TODO: check flags for unwanted values // allocate file structure status = fsw_alloc(sizeof(struct fsw_posix_file), &file); if (status) return NULL; file->pvol = pvol; // open the file status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand); if (status) { fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status); fsw_free(file); return NULL; } return file; }
fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out) { fsw_status_t status; fsw_u32 i, discard_level, new_bcache_size; struct fsw_blockcache *new_bcache; /// @todo allow the host driver to do its own caching; just call through if // the appropriate function pointers are set if (cache_level > MAX_CACHE_LEVEL) cache_level = MAX_CACHE_LEVEL; // check block cache for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].phys_bno == phys_bno) { // cache hit! if (vol->bcache[i].cache_level < cache_level) vol->bcache[i].cache_level = cache_level; // promote the entry vol->bcache[i].refcount++; *buffer_out = vol->bcache[i].data; return FSW_SUCCESS; } } // find a free entry in the cache table for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].phys_bno == FSW_INVALID_BNO) break; } if (i >= vol->bcache_size) { for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) { for (i = 0; i < vol->bcache_size; i++) { if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level) break; } if (i < vol->bcache_size) break; } } if (i >= vol->bcache_size) { // enlarge / create the cache if (vol->bcache_size < 16) new_bcache_size = 16; else new_bcache_size = vol->bcache_size << 1; status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache); if (status) return status; if (vol->bcache_size > 0) fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache)); for (i = vol->bcache_size; i < new_bcache_size; i++) { new_bcache[i].refcount = 0; new_bcache[i].cache_level = 0; new_bcache[i].phys_bno = FSW_INVALID_BNO; new_bcache[i].data = NULL; } i = vol->bcache_size; // switch caches if (vol->bcache != NULL) fsw_free(vol->bcache); vol->bcache = new_bcache; vol->bcache_size = new_bcache_size; } vol->bcache[i].phys_bno = FSW_INVALID_BNO; // read the data if (vol->bcache[i].data == NULL) { status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data); if (status) return status; } status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data); if (status) return status; vol->bcache[i].phys_bno = phys_bno; vol->bcache[i].cache_level = cache_level; vol->bcache[i].refcount = 1; *buffer_out = vol->bcache[i].data; return FSW_SUCCESS; }
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; }