option for patch_io_manager; clean the code
parent
d891ecbf1d
commit
a7bf43764f
4
Makefile
4
Makefile
|
@ -1,3 +1,5 @@
|
|||
all: realloc-inodes
|
||||
all: realloc-inodes e2patch
|
||||
realloc-inodes: realloc-inodes.c bmove.c ext2fsP.h Makefile patch_io.c patch_io.h
|
||||
gcc -g -Wsign-compare -Wall -o realloc-inodes -lcom_err -lext2fs realloc-inodes.c bmove.c patch_io.c
|
||||
e2patch: e2patch.c
|
||||
gcc -g -Wsign-compare -Wall -o e2patch -lcom_err -lext2fs e2patch.c
|
||||
|
|
66
patch_io.c
66
patch_io.c
|
@ -3,11 +3,10 @@
|
|||
* a separate sparse file to apply it later.
|
||||
*
|
||||
* Patch file format:
|
||||
* 1) sparse data blocks - same size as the filesystem image, but only changed blocks are written
|
||||
* 2) updated block bitmap - fs_size/block_size/8
|
||||
* 1) sparse data blocks - same size as the filesystem, but only changed blocks are written
|
||||
* 2) updated block bitmap - fs_size/block_size/8 bytes
|
||||
* 3) 4 byte FS block size
|
||||
* 4) 4 byte FS size in blocks
|
||||
* FIXME: should be 8 bytes! 4 bytes = sizeof(blk_t), from ext2fs_get_device_size()
|
||||
* 4) 8 byte FS size in blocks
|
||||
*
|
||||
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
|
||||
* License: GNU GPLv2 or later
|
||||
|
@ -35,10 +34,6 @@
|
|||
#define ATTR(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For checking structure magic numbers...
|
||||
*/
|
||||
|
||||
#define EXT2_CHECK_MAGIC(struct, code) if ((struct)->magic != (code)) return (code)
|
||||
|
||||
struct patch_private_data {
|
||||
|
@ -46,7 +41,7 @@ struct patch_private_data {
|
|||
char *patch_file;
|
||||
int patch_fd;
|
||||
int block_size;
|
||||
blk_t size;
|
||||
blk64_t size;
|
||||
ext2fs_generic_bitmap bmap;
|
||||
/* The backing io channel */
|
||||
io_channel real;
|
||||
|
@ -68,7 +63,7 @@ static errcode_t patch_get_stats(io_channel channel, io_stats *stats);
|
|||
|
||||
static struct struct_io_manager struct_patch_manager = {
|
||||
EXT2_ET_MAGIC_IO_MANAGER,
|
||||
"Undo I/O Manager",
|
||||
"Patch I/O Manager",
|
||||
patch_open,
|
||||
patch_close,
|
||||
patch_set_blksize,
|
||||
|
@ -98,18 +93,18 @@ errcode_t set_patch_io_patch_file(char *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void patch_read_bmap(struct patch_private_data *data)
|
||||
static void patch_read_bmap(struct patch_private_data *data, int fd)
|
||||
{
|
||||
int bufsize = 65536, r;
|
||||
ext2_loff_t i;
|
||||
int bufsize = 65536;
|
||||
blk64_t i, r;
|
||||
void *buf = malloc(bufsize);
|
||||
ext2fs_llseek(data->patch_fd, data->size*data->block_size, SEEK_SET);
|
||||
ext2fs_llseek(fd, data->size*data->block_size, SEEK_SET);
|
||||
for (i = 0; i < data->size/8; )
|
||||
{
|
||||
r = bufsize;
|
||||
if (data->size/8 - i < r)
|
||||
r = data->size/8 - i;
|
||||
r = read(data->patch_fd, buf, r);
|
||||
r = read(fd, buf, r);
|
||||
if (r < 0)
|
||||
{
|
||||
r = 0;
|
||||
|
@ -122,19 +117,19 @@ static void patch_read_bmap(struct patch_private_data *data)
|
|||
free(buf);
|
||||
}
|
||||
|
||||
static void patch_write_bmap(struct patch_private_data *data)
|
||||
static void patch_write_bmap(struct patch_private_data *data, int fd)
|
||||
{
|
||||
int bufsize = 65536, r;
|
||||
ext2_loff_t i;
|
||||
int bufsize = 65536;
|
||||
blk64_t i, r;
|
||||
void *buf = malloc(bufsize);
|
||||
ext2fs_llseek(data->patch_fd, data->size*data->block_size, SEEK_SET);
|
||||
ext2fs_llseek(fd, data->size*data->block_size, SEEK_SET);
|
||||
for (i = 0; i < data->size/8; )
|
||||
{
|
||||
r = bufsize;
|
||||
if (data->size/8 - i < r)
|
||||
r = data->size/8 - i;
|
||||
ext2fs_get_generic_bmap_range(data->bmap, i*8, r*8, buf);
|
||||
r = write(data->patch_fd, buf, r);
|
||||
r = write(fd, buf, r);
|
||||
if (r < 0)
|
||||
{
|
||||
r = 0;
|
||||
|
@ -144,8 +139,8 @@ static void patch_write_bmap(struct patch_private_data *data)
|
|||
i += r;
|
||||
}
|
||||
free(buf);
|
||||
write(data->patch_fd, &data->block_size, sizeof(int));
|
||||
write(data->patch_fd, &data->size, sizeof(blk_t));
|
||||
write(fd, &data->block_size, sizeof(int));
|
||||
write(fd, &data->size, sizeof(blk64_t));
|
||||
}
|
||||
|
||||
static errcode_t patch_open(const char *name, int flags, io_channel *channel)
|
||||
|
@ -203,16 +198,16 @@ static errcode_t patch_open(const char *name, int flags, io_channel *channel)
|
|||
retval = errno;
|
||||
goto cleanup;
|
||||
}
|
||||
if (size > sizeof(int)+sizeof(blk_t))
|
||||
if (size > sizeof(int)+sizeof(blk64_t))
|
||||
{
|
||||
ext2fs_llseek(data->patch_fd, size-sizeof(int)-sizeof(blk_t), 0);
|
||||
ext2fs_llseek(data->patch_fd, size-sizeof(int)-sizeof(blk64_t), 0);
|
||||
read(data->patch_fd, &data->block_size, sizeof(int));
|
||||
read(data->patch_fd, &data->size, sizeof(blk_t));
|
||||
read(data->patch_fd, &data->size, sizeof(blk64_t));
|
||||
retval = ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, NULL,
|
||||
0, data->size, data->size, "overwritten blocks", 0, &data->bmap);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
patch_read_bmap(data);
|
||||
patch_read_bmap(data, data->patch_fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,7 +219,7 @@ cleanup:
|
|||
{
|
||||
if (data->bmap)
|
||||
ext2fs_free_generic_bmap(data->bmap);
|
||||
if (data->patch_fd)
|
||||
if (data->patch_fd >= 0)
|
||||
close(data->patch_fd);
|
||||
if (data->patch_file)
|
||||
free(data->patch_file);
|
||||
|
@ -255,10 +250,11 @@ static errcode_t patch_close(io_channel channel)
|
|||
|
||||
if (data->bmap)
|
||||
{
|
||||
patch_write_bmap(data);
|
||||
if (data->patch_fd >= 0)
|
||||
patch_write_bmap(data, data->patch_fd);
|
||||
ext2fs_free_generic_bmap(data->bmap);
|
||||
}
|
||||
if (data->patch_fd)
|
||||
if (data->patch_fd >= 0)
|
||||
close(data->patch_fd);
|
||||
if (data->patch_file)
|
||||
free(data->patch_file);
|
||||
|
@ -357,13 +353,13 @@ static errcode_t patch_read_blk(io_channel channel, unsigned long block, int cou
|
|||
return patch_read_blk64(channel, block, count, buf);
|
||||
}
|
||||
|
||||
static errcode_t patch_check_bmap(struct patch_private_data *data, io_channel channel)
|
||||
static errcode_t patch_check_bmap_init(struct patch_private_data *data, io_channel channel)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
if (!data->bmap)
|
||||
{
|
||||
data->block_size = channel->block_size;
|
||||
retval = ext2fs_get_device_size(channel->name, data->block_size, &data->size);
|
||||
retval = ext2fs_get_device_size2(channel->name, data->block_size, &data->size);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, NULL,
|
||||
|
@ -384,7 +380,7 @@ static errcode_t patch_write_blk64(io_channel channel, unsigned long long block,
|
|||
|
||||
if ((unsigned)ext2fs_llseek(data->patch_fd, block*channel->block_size, SEEK_SET) != block*channel->block_size)
|
||||
return errno ? errno : EXT2_ET_LLSEEK_FAILED;
|
||||
retval = patch_check_bmap(data, channel);
|
||||
retval = patch_check_bmap_init(data, channel);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (count < 0)
|
||||
|
@ -451,10 +447,10 @@ static errcode_t patch_set_option(io_channel channel, const char *option, const
|
|||
* Need to support offset option to work with
|
||||
* Unix I/O manager
|
||||
*/
|
||||
if (data->real && data->real->manager->set_option) {
|
||||
if (data->real && data->real->manager->set_option)
|
||||
retval = data->real->manager->set_option(data->real, option, arg);
|
||||
}
|
||||
if (!retval && !strcmp(option, "offset")) {
|
||||
if (!retval && !strcmp(option, "offset"))
|
||||
{
|
||||
if (!arg)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
|
|
115
realloc-inodes.c
115
realloc-inodes.c
|
@ -63,7 +63,7 @@ typedef struct
|
|||
{
|
||||
ext2_filsys fs;
|
||||
int fs_fd;
|
||||
char *device_name, *io_options;
|
||||
char *device_name, *io_options, *patch_file;
|
||||
__u32 ig_old, ig_new; // old and new inodes-per-group count
|
||||
__u32 ibg_old, ibg_new; // old and new inode_blocks-per-group count
|
||||
__u32 new_inode_count;
|
||||
|
@ -646,99 +646,54 @@ __u32 atou(char *s)
|
|||
return x;
|
||||
}
|
||||
|
||||
static char *basename(char *name)
|
||||
{
|
||||
char *n1 = rindex(name, '/'), *n2 = rindex(name, '\\');
|
||||
if (!n1 && !n2)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
else if (n1 < n2)
|
||||
{
|
||||
return n1+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return n2+1;
|
||||
}
|
||||
}
|
||||
|
||||
const char *program_name = "realloc-inodes";
|
||||
|
||||
static int setup_tdb(char *name, io_manager *io_ptr)
|
||||
static int setup_patch_io(char *name, char *patch_file, io_manager *io_ptr)
|
||||
{
|
||||
set_patch_io_backing_manager(*io_ptr);
|
||||
set_patch_io_patch_file("./patch");
|
||||
set_patch_io_patch_file(patch_file);
|
||||
*io_ptr = patch_io_manager;
|
||||
printf(_(
|
||||
"To apply the inode change operation to the real filesystem"
|
||||
" please run the command\n e2patch apply %s %s\n"
|
||||
), name, patch_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_tdb_0(char *name, io_manager *io_ptr)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
const char *tdb_dir;
|
||||
char *tdb_file;
|
||||
char *dev_name;
|
||||
|
||||
dev_name = basename(name);
|
||||
|
||||
tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
|
||||
if (!tdb_dir)
|
||||
{
|
||||
tdb_dir = "/var/lib/e2fsprogs";
|
||||
}
|
||||
|
||||
if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0))
|
||||
{
|
||||
fprintf(stderr, "Can't save undo file to %s; specify different undo directory with E2FSPROGS_UNDO_DIR env variable\n", tdb_dir);
|
||||
return ENOENT;
|
||||
}
|
||||
if ((retval = access(tdb_dir, W_OK)))
|
||||
{
|
||||
fprintf(stderr, "Can't save undo file to %s; specify different undo directory with E2FSPROGS_UNDO_DIR env variable\n", tdb_dir);
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
tdb_file = malloc(strlen(tdb_dir) + 2 + 14 + strlen(dev_name) + 7 + 1);
|
||||
if (!tdb_file)
|
||||
{
|
||||
fprintf(stderr, "Bad alloc\n");
|
||||
return ENOMEM;
|
||||
}
|
||||
sprintf(tdb_file, "%s/realloc-inodes-%s.e2undo", tdb_dir, dev_name);
|
||||
|
||||
if (!access(tdb_file, F_OK) && (unlink(tdb_file) < 0))
|
||||
{
|
||||
retval = errno;
|
||||
com_err(program_name, retval,
|
||||
_("while trying to delete %s"),
|
||||
tdb_file);
|
||||
free(tdb_file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
set_undo_io_backing_manager(*io_ptr);
|
||||
*io_ptr = undo_io_manager;
|
||||
set_undo_io_backup_file(tdb_file);
|
||||
printf(_("To undo the %s operation please run the command\n e2undo %s %s\n\n"), program_name, tdb_file, name);
|
||||
free(tdb_file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int main(int narg, char **args)
|
||||
{
|
||||
realloc_data rd = { 0 };
|
||||
int optind, retval, io_flags = 0, force = 0;
|
||||
io_manager io_ptr = unix_io_manager;
|
||||
struct stat st_buf;
|
||||
if (narg < 3)
|
||||
for (optind = 1; optind < narg; optind++)
|
||||
{
|
||||
printf("USAGE: ./realloc-inodes <device> <new_inode_count>\n");
|
||||
if (!strcmp(args[optind], "--patch"))
|
||||
rd.patch_file = args[++optind];
|
||||
else if (args[optind][0] == '-' && args[optind][1] == '-')
|
||||
{
|
||||
if (strcmp(args[optind], "--help") != 0)
|
||||
printf("Unknown option: %s\n", args[optind]);
|
||||
break;
|
||||
}
|
||||
else if (!rd.device_name)
|
||||
rd.device_name = args[optind];
|
||||
else
|
||||
rd.new_inode_count = atou(args[optind++]);
|
||||
}
|
||||
if (!rd.device_name || !rd.new_inode_count)
|
||||
{
|
||||
printf(
|
||||
"Change inode count of an ext2/ext3/ext4 filesystem\n"
|
||||
"License: GNU GPLv2 or later\nCopyright (c) Vitaliy Filippov, 2013+\n\n"
|
||||
"USAGE: ./realloc-inodes [--patch <patch_file>] <device> <new_inode_count>\n\n"
|
||||
"If <patch_file> is specified, all modifications are written to it\n"
|
||||
"instead of directly modifying the filesystem. These modifications\n"
|
||||
"can then be applied and unapplied to the real filesystem in a safe way.\n"
|
||||
"<patch_file> should be on a filesystem supporting sparse files.\n"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
optind = 1;
|
||||
rd.device_name = args[optind++];
|
||||
rd.new_inode_count = atou(args[optind++]);
|
||||
add_error_table(&et_ext2_error_table);
|
||||
// Open FS
|
||||
rd.fs_fd = ext2fs_open_file(rd.device_name, O_RDWR, 0);
|
||||
|
@ -763,8 +718,10 @@ int main(int narg, char **args)
|
|||
{
|
||||
*rd.io_options++ = 0;
|
||||
}
|
||||
// undo_io_manager is very slow by now -- safe, but slow: it commits every transaction...
|
||||
setup_tdb(rd.device_name, &io_ptr);
|
||||
if (rd.patch_file)
|
||||
{
|
||||
setup_patch_io(rd.device_name, rd.patch_file, &io_ptr);
|
||||
}
|
||||
io_flags = EXT2_FLAG_64BITS | EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;
|
||||
retval = ext2fs_open2(rd.device_name, rd.io_options, io_flags, 0, 0, io_ptr, &rd.fs);
|
||||
if (retval)
|
||||
|
|
Loading…
Reference in New Issue