struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize) { struct buffer_head *bh; int bufsize = sizeof(*bh) + kdev->k_fs->blocksize - sizeof(bh->b_data); errcode_t retval; retval = ext2fs_get_memzero(bufsize, &bh); if (retval) return NULL; #ifdef CONFIG_JBD_DEBUG if (journal_enable_debug >= 3) bh_count++; #endif jfs_debug(4, "getblk for block %llu (%d bytes)(total %d)\n", (unsigned long long) blocknr, blocksize, bh_count); bh->b_fs = kdev->k_fs; if (kdev->k_dev == K_DEV_FS) bh->b_io = kdev->k_fs->io; else bh->b_io = kdev->k_fs->journal_io; bh->b_size = blocksize; bh->b_blocknr = blocknr; return bh; }
static int qcow2_read_l1_table(struct ext2_qcow2_image *img) { int fd = img->fd; size_t size, l1_size = img->l1_size * sizeof(blk64_t); blk64_t *table; errcode_t ret; ret = ext2fs_get_memzero(l1_size, &table); if (ret) return ret; if (ext2fs_llseek(fd, img->l1_offset, SEEK_SET) < 0) { ext2fs_free_mem(&table); return errno; } size = read(fd, table, l1_size); if (size != l1_size) { ext2fs_free_mem(&table); return errno; } img->l1_table = table; return 0; }
static errcode_t ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, char *buf, size_t size) { errcode_t retval; blk64_t blk; char *blk_buf; retval = ext2fs_get_memzero(fs->blocksize, &blk_buf); if (retval) return retval; #ifdef WORDS_BIGENDIAN retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE, size, 0); if (retval) goto errout; #endif /* Adjust the rec_len */ retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size); if (retval) goto errout; /* Allocate a new block */ retval = ext2fs_new_block2(fs, 0, 0, &blk); if (retval) goto errout; retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino); if (retval) goto errout; /* Update inode */ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS)) inode->i_flags |= EXT4_EXTENTS_FL; inode->i_flags &= ~EXT4_INLINE_DATA_FL; retval = ext2fs_iblk_add_blocks(fs, inode, 1); if (retval) goto errout; inode->i_size = fs->blocksize; retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk); if (retval) goto errout; retval = ext2fs_write_inode(fs, ino, inode); if (retval) goto errout; ext2fs_block_alloc_stats(fs, blk, +1); errout: ext2fs_free_mem(&blk_buf); return retval; }
int qcow2_write_raw_image(int qcow2_fd, int raw_fd, struct ext2_qcow2_hdr *hdr) { struct ext2_qcow2_image img; errcode_t ret = 0; unsigned int l1_index, l2_index; ext2_off64_t offset; blk64_t *l1_table, *l2_table = 0; void *copy_buf = NULL; size_t size; if (hdr->crypt_method) return -QCOW_ENCRYPTED; img.fd = qcow2_fd; img.hdr = hdr; img.l2_cache = NULL; img.l1_table = NULL; img.cluster_bits = ext2fs_be32_to_cpu(hdr->cluster_bits); img.cluster_size = 1 << img.cluster_bits; img.l1_size = ext2fs_be32_to_cpu(hdr->l1_size); img.l1_offset = ext2fs_be64_to_cpu(hdr->l1_table_offset); img.l2_size = 1 << (img.cluster_bits - 3); img.image_size = ext2fs_be64_to_cpu(hdr->size); ret = ext2fs_get_memzero(img.cluster_size, &l2_table); if (ret) goto out; ret = ext2fs_get_memzero(1 << img.cluster_bits, ©_buf); if (ret) goto out; if (ext2fs_llseek(raw_fd, 0, SEEK_SET) < 0) { ret = errno; goto out; } ret = qcow2_read_l1_table(&img); if (ret) goto out; l1_table = img.l1_table; /* Walk through l1 table */ for (l1_index = 0; l1_index < img.l1_size; l1_index++) { ext2_off64_t off_out; offset = ext2fs_be64_to_cpu(l1_table[l1_index]) & ~QCOW_OFLAG_COPIED; if ((offset > img.image_size) || (offset <= 0)) continue; if (offset & QCOW_OFLAG_COMPRESSED) { ret = -QCOW_COMPRESSED; goto out; } ret = qcow2_read_l2_table(&img, offset, &l2_table); if (ret) break; /* Walk through l2 table and copy data blocks into raw image */ for (l2_index = 0; l2_index < img.l2_size; l2_index++) { offset = ext2fs_be64_to_cpu(l2_table[l2_index]) & ~QCOW_OFLAG_COPIED; if (offset == 0) continue; off_out = (l1_index * img.l2_size) + l2_index; off_out <<= img.cluster_bits; ret = qcow2_copy_data(qcow2_fd, raw_fd, offset, off_out, copy_buf, img.cluster_size); if (ret) goto out; } } /* Resize the output image to the filesystem size */ if (ext2fs_llseek(raw_fd, img.image_size - 1, SEEK_SET) < 0) return errno; ((char *)copy_buf)[0] = 0; size = write(raw_fd, copy_buf, 1); if (size != 1) return errno; out: if (copy_buf) ext2fs_free_mem(©_buf); if (img.l1_table) ext2fs_free_mem(&img.l1_table); if (l2_table) ext2fs_free_mem(&l2_table); return ret; }
errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, int type, __u64 start, __u64 end, __u64 real_end, const char *descr, ext2fs_generic_bitmap *ret) { ext2fs_generic_bitmap bitmap; struct ext2_bitmap_ops *ops; ext2_ino_t num_dirs; errcode_t retval; if (!type) type = EXT2FS_BMAP64_BITARRAY; switch (type) { case EXT2FS_BMAP64_BITARRAY: ops = &ext2fs_blkmap64_bitarray; break; case EXT2FS_BMAP64_RBTREE: ops = &ext2fs_blkmap64_rbtree; break; case EXT2FS_BMAP64_AUTODIR: retval = ext2fs_get_num_dirs(fs, &num_dirs); if (retval || num_dirs > (fs->super->s_inodes_count / 320)) ops = &ext2fs_blkmap64_bitarray; else ops = &ext2fs_blkmap64_rbtree; break; default: return EINVAL; } retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), &bitmap); if (retval) return retval; #ifdef BMAP_STATS if (gettimeofday(&bitmap->stats.created, (struct timezone *) NULL) == -1) { perror("gettimeofday"); return 1; } bitmap->stats.type = type; #endif /* XXX factor out, repeated in copy_bmap */ bitmap->magic = magic; bitmap->fs = fs; bitmap->start = start; bitmap->end = end; bitmap->real_end = real_end; bitmap->bitmap_ops = ops; bitmap->cluster_bits = 0; switch (magic) { case EXT2_ET_MAGIC_INODE_BITMAP64: bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; break; case EXT2_ET_MAGIC_BLOCK_BITMAP64: bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; bitmap->cluster_bits = fs->cluster_ratio_bits; break; default: bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; } if (descr) { retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); if (retval) { ext2fs_free_mem(&bitmap); return retval; } strcpy(bitmap->description, descr); } else bitmap->description = 0; retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); if (retval) { ext2fs_free_mem(&bitmap->description); ext2fs_free_mem(&bitmap); return retval; } *ret = bitmap; return 0; }
errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, ext2fs_generic_bitmap *dest) { char *descr, *new_descr; ext2fs_generic_bitmap new_bmap; errcode_t retval; if (!src) return EINVAL; if (EXT2FS_IS_32_BITMAP(src)) return ext2fs_copy_generic_bitmap(src, dest); if (!EXT2FS_IS_64_BITMAP(src)) return EINVAL; /* Allocate a new bitmap struct */ retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), &new_bmap); if (retval) return retval; #ifdef BMAP_STATS_OPS src->stats.copy_count++; #endif #ifdef BMAP_STATS if (gettimeofday(&new_bmap->stats.created, (struct timezone *) NULL) == -1) { perror("gettimeofday"); return 1; } new_bmap->stats.type = src->stats.type; #endif /* Copy all the high-level parts over */ new_bmap->magic = src->magic; new_bmap->fs = src->fs; new_bmap->start = src->start; new_bmap->end = src->end; new_bmap->real_end = src->real_end; new_bmap->bitmap_ops = src->bitmap_ops; new_bmap->base_error_code = src->base_error_code; new_bmap->cluster_bits = src->cluster_bits; descr = src->description; if (descr) { retval = ext2fs_get_mem(strlen(descr)+10, &new_descr); if (retval) { ext2fs_free_mem(&new_bmap); return retval; } sprintf(new_descr, "copy of %s", descr); new_bmap->description = new_descr; } retval = src->bitmap_ops->copy_bmap(src, new_bmap); if (retval) { ext2fs_free_mem(&new_bmap->description); ext2fs_free_mem(&new_bmap); return retval; } *dest = new_bmap; return 0; }
static errcode_t ext2fs_get_journal(ext2_filsys fs, journal_t **ret_journal) { struct process_block_struct pb; struct ext2_super_block *sb = fs->super; struct ext2_super_block jsuper; struct buffer_head *bh; struct inode *j_inode = NULL; struct kdev_s *dev_fs = NULL, *dev_journal; const char *journal_name = 0; journal_t *journal = NULL; errcode_t retval = 0; io_manager io_ptr = 0; unsigned long long start = 0; int ext_journal = 0; int tried_backup_jnl = 0; retval = ext2fs_get_memzero(sizeof(journal_t), &journal); if (retval) return retval; retval = ext2fs_get_memzero(2 * sizeof(struct kdev_s), &dev_fs); if (retval) goto errout; dev_journal = dev_fs+1; dev_fs->k_fs = dev_journal->k_fs = fs; dev_fs->k_dev = K_DEV_FS; dev_journal->k_dev = K_DEV_JOURNAL; journal->j_dev = dev_journal; journal->j_fs_dev = dev_fs; journal->j_inode = NULL; journal->j_blocksize = fs->blocksize; if (uuid_is_null(sb->s_journal_uuid)) { if (!sb->s_journal_inum) { retval = EXT2_ET_BAD_INODE_NUM; goto errout; } retval = ext2fs_get_memzero(sizeof(*j_inode), &j_inode); if (retval) goto errout; j_inode->i_fs = fs; j_inode->i_ino = sb->s_journal_inum; retval = ext2fs_read_inode(fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) { try_backup_journal: if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || tried_backup_jnl) goto errout; memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, EXT2_N_BLOCKS*4); j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15]; j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; j_inode->i_ext2.i_links_count = 1; j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; tried_backup_jnl++; } if (!j_inode->i_ext2.i_links_count || !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { retval = EXT2_ET_NO_JOURNAL; goto try_backup_journal; } if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize < JFS_MIN_JOURNAL_BLOCKS) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } pb.last_block = -1; retval = ext2fs_block_iterate3(fs, j_inode->i_ino, BLOCK_FLAG_HOLE, 0, process_journal_block, &pb); if ((pb.last_block + 1) * fs->blocksize < (int) EXT2_I_SIZE(&j_inode->i_ext2)) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } if (tried_backup_jnl && (fs->flags & EXT2_FLAG_RW)) { retval = ext2fs_write_inode(fs, sb->s_journal_inum, &j_inode->i_ext2); if (retval) goto errout; } journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize; #ifdef USE_INODE_IO retval = ext2fs_inode_io_intern2(fs, sb->s_journal_inum, &j_inode->i_ext2, &journal_name); if (retval) goto errout; io_ptr = inode_io_manager; #else journal->j_inode = j_inode; fs->journal_io = fs->io; retval = (errcode_t)journal_bmap(journal, 0, &start); if (retval) goto errout; #endif } else { ext_journal = 1; if (!fs->journal_name) { char uuid[37]; blkid_cache blkid; blkid_get_cache(&blkid, NULL); uuid_unparse(sb->s_journal_uuid, uuid); fs->journal_name = blkid_get_devname(blkid, "UUID", uuid); if (!fs->journal_name) fs->journal_name = blkid_devno_to_devname(sb->s_journal_dev); blkid_put_cache(blkid); } journal_name = fs->journal_name; if (!journal_name) { retval = EXT2_ET_LOAD_EXT_JOURNAL; goto errout; } jfs_debug(1, "Using journal file %s\n", journal_name); io_ptr = unix_io_manager; } #if 0 test_io_backing_manager = io_ptr; io_ptr = test_io_manager; #endif #ifndef USE_INODE_IO if (ext_journal) #endif { retval = io_ptr->open(journal_name, fs->flags & EXT2_FLAG_RW, &fs->journal_io); } if (retval) goto errout; io_channel_set_blksize(fs->journal_io, fs->blocksize); if (ext_journal) { blk64_t maxlen; start = ext2fs_journal_sb_start(fs->blocksize) - 1; bh = getblk(dev_journal, start, fs->blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } ll_rw_block(READ, 1, &bh); retval = bh->b_err; if (retval) { brelse(bh); goto errout; } memcpy(&jsuper, start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET, sizeof(jsuper)); #ifdef WORDS_BIGENDIAN if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ext2fs_swap_super(&jsuper); #endif if (jsuper.s_magic != EXT2_SUPER_MAGIC || !ext2fs_has_feature_journal_dev(&jsuper)) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } /* Make sure the journal UUID is correct */ if (memcmp(jsuper.s_uuid, fs->super->s_journal_uuid, sizeof(jsuper.s_uuid))) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } /* Check the superblock checksum */ if (ext2fs_has_feature_metadata_csum(&jsuper)) { struct struct_ext2_filsys fsx; struct ext2_super_block superx; void *p; p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET; memcpy(&fsx, fs, sizeof(fsx)); memcpy(&superx, fs->super, sizeof(superx)); fsx.super = &superx; ext2fs_set_feature_metadata_csum(fsx.super); if (!ext2fs_superblock_csum_verify(&fsx, p)) { retval = EXT2_ET_LOAD_EXT_JOURNAL; brelse(bh); goto errout; } } brelse(bh); maxlen = ext2fs_blocks_count(&jsuper); journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : (1ULL << 32) - 1; start++; } bh = getblk(dev_journal, start, journal->j_blocksize); if (!bh) { retval = EXT2_ET_NO_MEMORY; goto errout; } journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; #ifdef USE_INODE_IO if (j_inode) ext2fs_free_mem(&j_inode); #endif *ret_journal = journal; return 0; errout: if (dev_fs) ext2fs_free_mem(&dev_fs); if (j_inode) ext2fs_free_mem(&j_inode); if (journal) ext2fs_free_mem(&journal); return retval; }
errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, ext2_extent_handle_t *ret_handle) { struct ext2_extent_handle *handle; errcode_t retval; int i; struct ext3_extent_header *eh; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (!inode) if ((ino == 0) || (ino > fs->super->s_inodes_count)) return EXT2_ET_BAD_INODE_NUM; retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle); if (retval) return retval; memset(handle, 0, sizeof(struct ext2_extent_handle)); handle->ino = ino; handle->fs = fs; if (inode) { handle->inode = inode; } else { handle->inode = &handle->inodebuf; retval = ext2fs_read_inode(fs, ino, handle->inode); if (retval) goto errout; } eh = (struct ext3_extent_header *) &handle->inode->i_block[0]; for (i=0; i < EXT2_N_BLOCKS; i++) if (handle->inode->i_block[i]) break; if (i >= EXT2_N_BLOCKS) { eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC); eh->eh_depth = 0; eh->eh_entries = 0; i = (sizeof(handle->inode->i_block) - sizeof(*eh)) / sizeof(struct ext3_extent); eh->eh_max = ext2fs_cpu_to_le16(i); handle->inode->i_flags |= EXT4_EXTENTS_FL; } if (!(handle->inode->i_flags & EXT4_EXTENTS_FL)) { retval = EXT2_ET_INODE_NOT_EXTENT; goto errout; } retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block)); if (retval) goto errout; handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth); handle->type = ext2fs_le16_to_cpu(eh->eh_magic); handle->max_paths = handle->max_depth + 1; retval = ext2fs_get_memzero(handle->max_paths * sizeof(struct extent_path), &handle->path); handle->path[0].buf = (char *) handle->inode->i_block; handle->path[0].left = handle->path[0].entries = ext2fs_le16_to_cpu(eh->eh_entries); handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max); handle->path[0].curr = 0; handle->path[0].end_blk = (EXT2_I_SIZE(handle->inode) + fs->blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(fs->super); handle->path[0].visit_num = 1; handle->level = 0; handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE; *ret_handle = handle; return 0; errout: ext2fs_extent_free(handle); return retval; }
static errcode_t copy_file(ext2_filsys fs, int fd, ext2_ino_t newfile, int bufsize, int make_holes) { ext2_file_t e2_file; errcode_t retval, close_ret; int got; unsigned int written; char *buf; char *ptr; char *zero_buf; int cmp; retval = ext2fs_file_open(fs, newfile, EXT2_FILE_WRITE, &e2_file); if (retval) return retval; retval = ext2fs_get_mem(bufsize, &buf); if (retval) { com_err("copy_file", retval, "can't allocate buffer\n"); goto out_close; } /* This is used for checking whether the whole block is zero */ retval = ext2fs_get_memzero(bufsize, &zero_buf); if (retval) { com_err("copy_file", retval, "can't allocate zero buffer\n"); goto out_free_buf; } while (1) { got = read(fd, buf, bufsize); if (got == 0) break; if (got < 0) { retval = errno; goto fail; } ptr = buf; /* Sparse copy */ if (make_holes) { /* Check whether all is zero */ cmp = memcmp(ptr, zero_buf, got); if (cmp == 0) { /* The whole block is zero, make a hole */ retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL); if (retval) goto fail; got = 0; } } /* Normal copy */ while (got > 0) { retval = ext2fs_file_write(e2_file, ptr, got, &written); if (retval) goto fail; got -= written; ptr += written; } } fail: ext2fs_free_mem(&zero_buf); out_free_buf: ext2fs_free_mem(&buf); out_close: close_ret = ext2fs_file_close(e2_file); if (retval == 0) retval = close_ret; return retval; }