An attempt to write a tool for ext4 that will allow to change inode count of a filesystem

master
Vitaliy Filippov 2013-12-25 10:15:02 +00:00
commit 55f3fa2c01
2 changed files with 125 additions and 0 deletions

3
Makefile Normal file
View File

@ -0,0 +1,3 @@
all: realloc-inodes
realloc-inodes: realloc-inodes.c
gcc -o realloc-inodes -lcom_err -lext2fs realloc-inodes.c

122
realloc-inodes.c Normal file
View File

@ -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 <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#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);
}
}