From 55f3fa2c0118cf3b6c1d512e0f0d45ed603380b5 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Wed, 25 Dec 2013 10:15:02 +0000 Subject: [PATCH] An attempt to write a tool for ext4 that will allow to change inode count of a filesystem --- Makefile | 3 ++ realloc-inodes.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 Makefile create mode 100644 realloc-inodes.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ec6e72b --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +all: realloc-inodes +realloc-inodes: realloc-inodes.c + gcc -o realloc-inodes -lcom_err -lext2fs realloc-inodes.c diff --git a/realloc-inodes.c b/realloc-inodes.c new file mode 100644 index 0000000..0292b46 --- /dev/null +++ b/realloc-inodes.c @@ -0,0 +1,122 @@ +/** + * An attempt to write a tool for ext4 that will allow to change inode count of a filesystem. + * + * In theory it shouldn't be that hard: + * 1) If shrinking: + * 1.1) move inodes so that the end of inode table is empty + * 1.2) mark some blocks that belonged to inode table as free + * 2) If growing: + * 2.1) move data blocks so there is enough space reserved for new inode table + * 2.2) mark some blocks that should belong to inode table as occupied + * 3) Change all inode numbers in directory entries so that + * new_num = (old_num/old_inodes_per_group)*new_inodes_per_group + (old_num%inodes_per_group) + * 4) Change superblock: s_inodes_count, s_free_inodes_count, s_inodes_per_group + * 5) Change block group descriptors: bg_inode_table_(lo,hi), bg_free_inodes_count_(lo,hi), + * bg_inode_bitmap_csum_(lo,hi), bg_itable_unused_(lo,hi) + * + * This is a destructive process involving metadata change so it would be good if + * we could first write a file containing all necessary changes, then backup all + * changed blocks, and then write new blocks to the disk. (maybe just use undo_io_manager?) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" + +#define _(a) (a) + +const char *program_name = "realloc-inodes"; + +// try to read out all directory inodes? +void test(ext2_filsys fs) +{ + int i, j, retval; + blk64_t blk; + void *buf; + struct ext2_inode *inode; + retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group, &buf); + for (i = 0; i < fs->group_desc_count; i++) + { + // read inode table of a group + blk = ext2fs_inode_table_loc(fs, i); + retval = io_channel_read_blk64(fs->io, blk, fs->inode_blocks_per_group, buf); + if (retval) + { + goto errout; + } + for (j = 0; j < fs->super->s_inodes_per_group; j++) + { + inode = (struct ext2_inode*)(buf + EXT2_INODE_SIZE(fs->super) * j); + if (inode->i_mode & S_IFDIR) + { + + } + } + } +errout: + ext2fs_free_mem(&buf); +} + +int main(int narg, char **args) +{ + ext2_filsys fs; + io_manager io_ptr = unix_io_manager; + int optind, fd, retval, io_flags = 0, force = 0; + ext2fs_struct_stat st_buf; + char *device_name, *io_options; + + optind = 1; + device_name = args[optind++]; + add_error_table(&et_ext2_error_table); + fd = ext2fs_open_file(device_name, O_RDWR, 0); + if (fd < 0) + { + com_err("open", errno, _("while opening %s"), device_name); + exit(1); + } + retval = ext2fs_fstat(fd, &st_buf); + if (retval < 0) + { + com_err("open", errno, _("while getting stat information for %s"), device_name); + exit(1); + } + if (!S_ISREG(st_buf.st_mode)) + { + close(fd); + fd = -1; + } + io_options = strchr(device_name, '?'); + if (io_options) + { + *io_options++ = 0; + } + //io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE; + io_flags |= EXT2_FLAG_64BITS; + retval = ext2fs_open2(device_name, io_options, io_flags, 0, 0, io_ptr, &fs); + if (retval) + { + com_err(program_name, retval, _("while trying to open %s"), device_name); + printf(_("Couldn't find valid filesystem superblock.\n")); + exit(1); + } + if (!force && ((fs->super->s_state & EXT2_ERROR_FS) || ((fs->super->s_state & EXT2_VALID_FS) == 0))) + { + fprintf(stderr, _("Please run 'e2fsck -f %s' first.\n\n"), device_name); + exit(1); + } + test(fs); + ext2fs_close(fs); + if (fd > 0) + { + close(fd); + } +}