/* * Initialize new quotafile */ static int v2_new_io(struct quota_handle *h) { int file_magics[] = INITQMAGICS; struct v2_disk_dqheader ddqheader; struct v2_disk_dqinfo ddqinfo; if (h->qh_fmt != QFMT_VFS_V1) return -1; /* Write basic quota header */ ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != sizeof(ddqheader)) return -1; /* Write information about quotafile */ h->qh_info.dqi_bgrace = MAX_DQ_TIME; h->qh_info.dqi_igrace = MAX_IQ_TIME; h->qh_info.u.v2_mdqi.dqi_flags = 0; h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = sizeof(struct v2r1_disk_dqblk); h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != sizeof(ddqinfo)) return -1; return 0; }
int fuse_to_ext4_acl(const acl_ea_header *facl, size_t facl_sz, ext4_acl_header **eacl, size_t *eacl_sz) { int i, facl_count; ext4_acl_header *h; size_t h_sz; ext4_acl_entry *e; acl_ea_entry *a; unsigned char *hptr; int err = 0; facl_count = acl_ea_count(facl_sz); h_sz = ext4_acl_size(facl_count); if (facl_count < 0 || facl->a_version != ACL_EA_VERSION) return -EINVAL; h = malloc(h_sz); if (!h) return -ENOMEM; h->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION); hptr = (unsigned char *) (h + 1); for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) { e = (ext4_acl_entry *) hptr; e->e_tag = ext2fs_cpu_to_le16(a->e_tag); e->e_perm = ext2fs_cpu_to_le16(a->e_perm); switch (a->e_tag) { case ACL_USER: case ACL_GROUP: e->e_id = ext2fs_cpu_to_le32(a->e_id); hptr += sizeof(ext4_acl_entry); break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: hptr += sizeof(ext4_acl_entry_short); break; default: err = -EINVAL; goto out; } } *eacl = h; *eacl_sz = h_sz; return err; out: free(h); return err; }
/* * Create new directory on inline data */ errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino, ext2_ino_t parent_ino, __u32 *iblock) { struct ext2_dir_entry *dir = NULL; errcode_t retval; int rec_len; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); iblock[0] = ext2fs_cpu_to_le32(parent_ino); dir = (struct ext2_dir_entry *)((char *)iblock + EXT4_INLINE_DATA_DOTDOT_SIZE); dir->inode = 0; rec_len = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; retval = ext2fs_set_rec_len(fs, rec_len, dir); if (retval) goto errout; #ifdef WORDS_BIGENDIAN retval = ext2fs_dirent_swab_out2(fs, (char *)dir, rec_len, 0); if (retval) goto errout; #endif errout: return retval; }
errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, int flags EXT2FS_ATTR((unused)), struct ext2fs_extent *extent) { struct extent_path *path; struct ext3_extent_idx *ix; struct ext3_extent *ex; EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); if (!(handle->fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; if (!handle->path) return EXT2_ET_NO_CURRENT_NODE; path = handle->path + handle->level; if (!path->curr) return EXT2_ET_NO_CURRENT_NODE; #ifdef DEBUG printf("extent replace: %u ", handle->ino); dbg_print_extent(0, extent); #endif if (handle->level == handle->max_depth) { ex = path->curr; ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk); ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF); ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32); if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) { if (extent->e_len > EXT_UNINIT_MAX_LEN) return EXT2_ET_EXTENT_INVALID_LENGTH; ex->ee_len = ext2fs_cpu_to_le16(extent->e_len + EXT_INIT_MAX_LEN); } else { if (extent->e_len > EXT_INIT_MAX_LEN) return EXT2_ET_EXTENT_INVALID_LENGTH; ex->ee_len = ext2fs_cpu_to_le16(extent->e_len); } } else {
int ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz, const ext4_acl_header *eacl, size_t eacl_sz) { int i, eacl_count; acl_ea_header *f; ext4_acl_entry *e; acl_ea_entry *a; size_t f_sz; unsigned char *hptr; int err = 0; eacl_count = ext4_acl_count(eacl_sz); f_sz = acl_ea_size(eacl_count); if (eacl_count < 0 || eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)) return -EINVAL; f = malloc(f_sz); if (!f) return -ENOMEM; f->a_version = ACL_EA_VERSION; hptr = (unsigned char *) (eacl + 1); for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) { e = (ext4_acl_entry *) hptr; a->e_tag = ext2fs_le16_to_cpu(e->e_tag); a->e_perm = ext2fs_le16_to_cpu(e->e_perm); switch (a->e_tag) { case ACL_USER: case ACL_GROUP: a->e_id = ext2fs_le32_to_cpu(e->e_id); hptr += sizeof(ext4_acl_entry); break; case ACL_USER_OBJ: case ACL_GROUP_OBJ: case ACL_MASK: case ACL_OTHER: hptr += sizeof(ext4_acl_entry_short); break; default: err = -EINVAL; goto out; } } *facl = f; *facl_sz = f_sz; return err; out: free(f); return err; }
static errcode_t undo_setup_tdb(struct undo_private_data *data) { int i; errcode_t retval; if (data->tdb_written == 1) return 0; data->tdb_written = 1; /* Make a bitmap to track what we've written */ memset(&data->fake_fs, 0, sizeof(data->fake_fs)); data->fake_fs.blocksize = data->tdb_data_size; retval = ext2fs_alloc_generic_bmap(&data->fake_fs, EXT2_ET_MAGIC_BLOCK_BITMAP64, EXT2FS_BMAP64_RBTREE, 0, ~1ULL, ~1ULL, "undo block map", &data->written_block_map); if (retval) return retval; /* Allocate key block */ retval = ext2fs_get_mem(data->tdb_data_size, &data->keyb); if (retval) return retval; data->key_blk_num = data->first_key_blk; /* Record block size */ dbg_printf("Undo block size %llu\n", data->tdb_data_size); dbg_printf("Keys per block %llu\n", KEYS_PER_BLOCK(data)); data->hdr.block_size = ext2fs_cpu_to_le32(data->tdb_data_size); io_channel_set_blksize(data->undo_file, data->tdb_data_size); /* Ensure that we have space for header blocks */ for (i = 0; i <= 2; i++) { retval = io_channel_read_blk64(data->undo_file, i, 1, data->keyb); if (retval) memset(data->keyb, 0, data->tdb_data_size); retval = io_channel_write_blk64(data->undo_file, i, 1, data->keyb); if (retval) return retval; retval = io_channel_flush(data->undo_file); if (retval) return retval; } memset(data->keyb, 0, data->tdb_data_size); return 0; }
/* * Copy dquot from memory to disk */ static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) { struct util_dqblk *m = &dquot->dq_dqb; struct v2r1_disk_dqblk *d = dp; d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit); d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit); d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit); d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit); d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes); d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace); d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime); d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime); d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id); if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) d->dqb_itime = ext2fs_cpu_to_le64(1); }
/* * Copy dqinfo from memory to disk */ static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, struct util_dqinfo *m) { d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace); d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace); d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); d->dqi_free_blk = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); d->dqi_free_entry = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); }
/* * This function takes the leaf nodes which have been written in * outdir, and populates the root node and any necessary interior nodes. */ static errcode_t calculate_tree(ext2_filsys fs, struct out_dir *outdir, ext2_ino_t ino, ext2_ino_t parent) { struct ext2_dx_root_info *root_info; struct ext2_dx_entry *root, *dx_ent = 0; struct ext2_dx_countlimit *root_limit, *limit; errcode_t retval; char * block_start; int i, c1, c2, nblks; int limit_offset, root_offset; root_info = set_root_node(fs, outdir->buf, ino, parent); root_offset = limit_offset = ((char *) root_info - outdir->buf) + root_info->info_length; root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset); c1 = root_limit->limit; nblks = outdir->num; /* Write out the pointer blocks */ if (nblks-1 <= c1) { /* Just write out the root block, and we're done */ root = (struct ext2_dx_entry *) (outdir->buf + root_offset); for (i=1; i < nblks; i++) { root->block = ext2fs_cpu_to_le32(i); if (i != 1) root->hash = ext2fs_cpu_to_le32(outdir->hashes[i]); root++; c1--; } } else { c2 = 0; limit = 0; root_info->indirect_levels = 1; for (i=1; i < nblks; i++) { if (c1 == 0) return ENOSPC; if (c2 == 0) { if (limit) limit->limit = limit->count = ext2fs_cpu_to_le16(limit->limit); root = (struct ext2_dx_entry *) (outdir->buf + root_offset); root->block = ext2fs_cpu_to_le32(outdir->num); if (i != 1) root->hash = ext2fs_cpu_to_le32(outdir->hashes[i]); if ((retval = get_next_block(fs, outdir, &block_start))) return retval; dx_ent = set_int_node(fs, block_start); limit = (struct ext2_dx_countlimit *) dx_ent; c2 = limit->limit; root_offset += sizeof(struct ext2_dx_entry); c1--; } dx_ent->block = ext2fs_cpu_to_le32(i); if (c2 != limit->limit) dx_ent->hash = ext2fs_cpu_to_le32(outdir->hashes[i]); dx_ent++; c2--; } limit->count = ext2fs_cpu_to_le16(limit->limit - c2); limit->limit = ext2fs_cpu_to_le16(limit->limit); } root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset); root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1); root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit); return 0; }
int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino, void *priv_data) { struct dir_context *ctx; struct ext2_inode inode; struct ext2_dir_entry dirent; struct ext2_inline_data data; int ret = BLOCK_ABORT; e2_blkcnt_t blockcnt = 0; char *old_buf; unsigned int old_buflen; int old_flags; ctx = (struct dir_context *)priv_data; old_buf = ctx->buf; old_buflen = ctx->buflen; old_flags = ctx->flags; ctx->flags |= DIRENT_FLAG_INCLUDE_INLINE_DATA; ctx->errcode = ext2fs_read_inode(fs, ino, &inode); if (ctx->errcode) goto out; if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) { ctx->errcode = EXT2_ET_NO_INLINE_DATA; goto out; } if (!LINUX_S_ISDIR(inode.i_mode)) { ctx->errcode = EXT2_ET_NO_DIRECTORY; goto out; } ret = 0; /* we first check '.' and '..' dir */ dirent.inode = ino; dirent.name_len = 1; ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent); dirent.name[0] = '.'; dirent.name[1] = '\0'; ctx->buf = (char *)&dirent; ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_ABORT) goto out; dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]); dirent.name_len = 2; ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent); dirent.name[0] = '.'; dirent.name[1] = '.'; dirent.name[2] = '\0'; ctx->buf = (char *)&dirent; ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_INLINE_DATA_CHANGED) { errcode_t err; inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode); err = ext2fs_write_inode(fs, ino, &inode); if (err) goto out; ret &= ~BLOCK_INLINE_DATA_CHANGED; } if (ret & BLOCK_ABORT) goto out; ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE; ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; #ifdef WORDS_BIGENDIAN ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out; } #endif ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_INLINE_DATA_CHANGED) { #ifdef WORDS_BIGENDIAN ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, ctx->buflen, 0); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out; } #endif ctx->errcode = ext2fs_write_inode(fs, ino, &inode); if (ctx->errcode) ret |= BLOCK_ABORT; ret &= ~BLOCK_INLINE_DATA_CHANGED; } if (ret & BLOCK_ABORT) goto out; data.fs = fs; data.ino = ino; ctx->errcode = ext2fs_inline_data_ea_get(&data); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out; } if (data.ea_size <= 0) goto out1; ctx->buf = data.ea_data; ctx->buflen = data.ea_size; #ifdef WORDS_BIGENDIAN ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out1; } #endif ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); if (ret & BLOCK_INLINE_DATA_CHANGED) { #ifdef WORDS_BIGENDIAN ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, ctx->buflen, 0); if (ctx->errcode) { ret |= BLOCK_ABORT; goto out1; } #endif ctx->errcode = ext2fs_inline_data_ea_set(&data); if (ctx->errcode) ret |= BLOCK_ABORT; } out1: ext2fs_free_mem(&data.ea_data); out: ctx->buf = old_buf; ctx->buflen = old_buflen; ctx->flags = old_flags; ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED); return ret; }
static errcode_t undo_write_tdb(io_channel channel, unsigned long long block, int count) { int size, sz; unsigned long long block_num, backing_blk_num; errcode_t retval = 0; ext2_loff_t offset; struct undo_private_data *data; unsigned char *read_ptr; unsigned long long end_block; unsigned long long data_size; void *data_ptr; struct undo_key *key; __u32 blk_crc; data = (struct undo_private_data *) channel->private_data; if (data->undo_file == NULL) { /* * Transaction database not initialized */ return 0; } if (count == 1) size = channel->block_size; else { if (count < 0) size = -count; else size = count * channel->block_size; } retval = undo_setup_tdb(data); if (retval) return retval; /* * Data is stored in tdb database as blocks of tdb_data_size size * This helps in efficient lookup further. * * We divide the disk to blocks of tdb_data_size. */ offset = (block * channel->block_size) + data->offset ; block_num = offset / data->tdb_data_size; end_block = (offset + size - 1) / data->tdb_data_size; while (block_num <= end_block) { __u32 keysz; /* * Check if we have the record already */ if (ext2fs_test_block_bitmap2(data->written_block_map, block_num)) { /* Try the next block */ block_num++; continue; } ext2fs_mark_block_bitmap2(data->written_block_map, block_num); /* * Read one block using the backing I/O manager * The backing I/O manager block size may be * different from the tdb_data_size. * Also we need to recalcuate the block number with respect * to the backing I/O manager. */ offset = block_num * data->tdb_data_size; backing_blk_num = (offset - data->offset) / channel->block_size; count = data->tdb_data_size + ((offset - data->offset) % channel->block_size); retval = ext2fs_get_mem(count, &read_ptr); if (retval) { return retval; } memset(read_ptr, 0, count); actual_size = 0; if ((count % channel->block_size) == 0) sz = count / channel->block_size; else sz = -count; retval = io_channel_read_blk64(data->real, backing_blk_num, sz, read_ptr); if (retval) { if (retval != EXT2_ET_SHORT_READ) { free(read_ptr); return retval; } /* * short read so update the record size * accordingly */ data_size = actual_size; } else { data_size = data->tdb_data_size; } if (data_size == 0) { free(read_ptr); block_num++; continue; } dbg_printf("Read %llu bytes from FS block %llu (blk=%llu cnt=%u)\n", data_size, backing_blk_num, block, count); if ((data_size % data->undo_file->block_size) == 0) sz = data_size / data->undo_file->block_size; else sz = -actual_size; data_ptr = read_ptr + ((offset - data->offset) % data->undo_file->block_size); /* extend this key? */ if (data->keys_in_block) { key = data->keyb->keys + data->keys_in_block - 1; keysz = ext2fs_le32_to_cpu(key->size); } else { key = NULL; keysz = 0; } if (key != NULL && ext2fs_le64_to_cpu(key->fsblk) + ((keysz + data->tdb_data_size - 1) / data->tdb_data_size) == backing_blk_num && E2UNDO_MAX_EXTENT_BLOCKS * data->tdb_data_size > keysz + sz) { blk_crc = ext2fs_le32_to_cpu(key->blk_crc); blk_crc = ext2fs_crc32c_le(blk_crc, (unsigned char *)data_ptr, data_size); key->blk_crc = ext2fs_cpu_to_le32(blk_crc); key->size = ext2fs_cpu_to_le32(keysz + data_size); } else { data->num_keys++; key = data->keyb->keys + data->keys_in_block; data->keys_in_block++; key->fsblk = ext2fs_cpu_to_le64(backing_blk_num); blk_crc = ext2fs_crc32c_le(~0, (unsigned char *)data_ptr, data_size); key->blk_crc = ext2fs_cpu_to_le32(blk_crc); key->size = ext2fs_cpu_to_le32(data_size); } dbg_printf("Writing block %llu to offset %llu size %d key %zu\n", block_num, data->undo_blk_num, sz, data->num_keys - 1); retval = io_channel_write_blk64(data->undo_file, data->undo_blk_num, sz, data_ptr); if (retval) { free(read_ptr); return retval; } data->undo_blk_num++; free(read_ptr); /* Write out the key block */ retval = write_undo_indexes(data, 0); if (retval) return retval; /* Next block */ block_num++; } return retval; }
static errcode_t write_undo_indexes(struct undo_private_data *data, int flush) { errcode_t retval; struct ext2_super_block super; io_channel channel; int block_size; __u32 sb_crc, hdr_crc; /* Spit out a key block, if there's any data */ if (data->keys_in_block) { data->keyb->magic = ext2fs_cpu_to_le32(KEYBLOCK_MAGIC); data->keyb->crc = 0; data->keyb->crc = ext2fs_cpu_to_le32( ext2fs_crc32c_le(~0, (unsigned char *)data->keyb, data->tdb_data_size)); dbg_printf("Writing keyblock to blk %llu\n", data->key_blk_num); retval = io_channel_write_blk64(data->undo_file, data->key_blk_num, 1, data->keyb); if (retval) return retval; /* Move on to the next key block if it's full. */ if (data->keys_in_block == KEYS_PER_BLOCK(data)) { memset(data->keyb, 0, data->tdb_data_size); data->keys_in_block = 0; data->key_blk_num = data->undo_blk_num; data->undo_blk_num++; } } /* Prepare superblock for write */ channel = data->real; block_size = channel->block_size; io_channel_set_blksize(channel, SUPERBLOCK_OFFSET); retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super); if (retval) goto err_out; sb_crc = ext2fs_crc32c_le(~0, (unsigned char *)&super, SUPERBLOCK_SIZE); super.s_magic = ~super.s_magic; /* Write the undo header to disk. */ memcpy(data->hdr.magic, E2UNDO_MAGIC, sizeof(data->hdr.magic)); data->hdr.num_keys = ext2fs_cpu_to_le64(data->num_keys); data->hdr.super_offset = ext2fs_cpu_to_le64(data->super_blk_num); data->hdr.key_offset = ext2fs_cpu_to_le64(data->first_key_blk); data->hdr.fs_block_size = ext2fs_cpu_to_le32(block_size); data->hdr.sb_crc = ext2fs_cpu_to_le32(sb_crc); hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&data->hdr, sizeof(data->hdr) - sizeof(data->hdr.header_crc)); data->hdr.header_crc = ext2fs_cpu_to_le32(hdr_crc); retval = io_channel_write_blk64(data->undo_file, 0, -(int)sizeof(data->hdr), &data->hdr); if (retval) goto err_out; /* * Record the entire superblock (in FS byte order) so that we can't * apply e2undo files to the wrong FS or out of order. */ dbg_printf("Writing superblock to block %llu\n", data->super_blk_num); retval = io_channel_write_blk64(data->undo_file, data->super_blk_num, -SUPERBLOCK_SIZE, &super); if (retval) goto err_out; if (flush) retval = io_channel_flush(data->undo_file); err_out: io_channel_set_blksize(channel, block_size); return retval; }
int do_create (ext2_filsys e2fs, const char *path, mode_t mode, dev_t dev, const char *fastsymlink) { int rt; time_t tm; errcode_t rc; char *p_path; char *r_path; ext2_ino_t ino; struct ext2_inode inode; ext2_ino_t n_ino; struct fuse_context *ctx; debugf("enter"); debugf("path = %s, mode: 0%o", path, mode); rt=do_check_split(path, &p_path, &r_path); debugf("parent: %s, child: %s", p_path, r_path); rt = do_readinode(e2fs, p_path, &ino, &inode); if (rt) { debugf("do_readinode(%s, &ino, &inode); failed", p_path); free_split(p_path, r_path); return rt; } rc = ext2fs_new_inode(e2fs, ino, mode, 0, &n_ino); if (rc) { debugf("ext2fs_new_inode(ep.fs, ino, mode, 0, &n_ino); failed"); return -ENOMEM; } do { debugf("calling ext2fs_link(e2fs, %d, %s, %d, %d);", ino, r_path, n_ino, do_modetoext2lag(mode)); rc = ext2fs_link(e2fs, ino, r_path, n_ino, do_modetoext2lag(mode)); if (rc == EXT2_ET_DIR_NO_SPACE) { debugf("calling ext2fs_expand_dir(e2fs, &d)", ino); if (ext2fs_expand_dir(e2fs, ino)) { debugf("error while expanding directory %s (%d)", p_path, ino); free_split(p_path, r_path); return -ENOSPC; } } } while (rc == EXT2_ET_DIR_NO_SPACE); if (rc) { debugf("ext2fs_link(e2fs, %d, %s, %d, %d); failed", ino, r_path, n_ino, do_modetoext2lag(mode)); free_split(p_path, r_path); return -EIO; } if (ext2fs_test_inode_bitmap(e2fs->inode_map, n_ino)) { debugf("inode already set"); } ext2fs_inode_alloc_stats2(e2fs, n_ino, +1, 0); memset(&inode, 0, sizeof(inode)); tm = e2fs->now ? e2fs->now : time(NULL); inode.i_mode = mode; inode.i_atime = inode.i_ctime = inode.i_mtime = tm; inode.i_links_count = 1; inode.i_size = 0; ctx = fuse_get_context(); if (ctx) { inode.i_uid = ctx->uid; inode.i_gid = ctx->gid; } if (S_ISCHR(mode) || S_ISBLK(mode)) { if (old_valid_dev(dev)) inode.i_block[0]= ext2fs_cpu_to_le32(old_encode_dev(dev)); else inode.i_block[1]= ext2fs_cpu_to_le32(new_encode_dev(dev)); } if (S_ISLNK(mode) && fastsymlink != NULL) { inode.i_size = strlen(fastsymlink); strncpy((char *)&(inode.i_block[0]),fastsymlink, (EXT2_N_BLOCKS * sizeof(inode.i_block[0]))); } rc = ext2fs_write_new_inode(e2fs, n_ino, &inode); if (rc) { debugf("ext2fs_write_new_inode(e2fs, n_ino, &inode);"); free_split(p_path, r_path); return -EIO; } /* update parent dir */ rt = do_readinode(e2fs, p_path, &ino, &inode); if (rt) { debugf("do_readinode(%s, &ino, &inode); dailed", p_path); free_split(p_path, r_path); return -EIO; } inode.i_ctime = inode.i_mtime = tm; rc = ext2fs_write_inode(e2fs, ino, &inode); if (rc) { debugf("ext2fs_write_inode(e2fs, ino, &inode); failed"); free_split(p_path, r_path); return -EIO; } free_split(p_path, r_path); debugf("leave"); return 0; }