Add e2patch utility

master
Vitaliy Filippov 2016-09-16 11:13:36 +03:00
parent 460c0af190
commit b3782b2e5b
6 changed files with 229 additions and 5 deletions

2
.gitignore vendored
View File

@ -161,6 +161,8 @@ misc/e2initrd_helper
misc/e2label.8
misc/e2undo
misc/e2undo.8
misc/e2patch
misc/e2patch.8
misc/e4defrag
misc/e4defrag.8
misc/ext4.5

View File

@ -117,6 +117,7 @@ exit 0
%{_root_sbindir}/e2image
%{_root_sbindir}/e2label
%{_root_sbindir}/e2undo
%{_root_sbindir}/e2patch
%{_root_sbindir}/findfs
%{_root_sbindir}/fsck
%{_root_sbindir}/fsck.ext2
@ -168,6 +169,7 @@ exit 0
%{_mandir}/man8/e2image.8*
%{_mandir}/man8/e2label.8*
%{_mandir}/man8/e2undo.8*
%{_mandir}/man8/e2patch.8*
%{_mandir}/man8/fsck.8*
%{_mandir}/man8/logsave.8*
%{_mandir}/man8/mke2fs.8*

View File

@ -33,12 +33,12 @@ INSTALL = @INSTALL@
@FUSE_CMT@FUSE_PROG= fuse2fs
SPROGS= mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
$(E2IMAGE_PROG) @FSCK_PROG@ e2undo e2patch
USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) \
$(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG)
SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \
logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \
logsave.8 filefrag.8 e2freefrag.8 e2undo.8 e2patch.8 \
$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@
FMANPAGES= mke2fs.conf.5 ext4.5
@ -63,6 +63,7 @@ FSCK_OBJS= fsck.o base_device.o ismounted.o
BLKID_OBJS= blkid.o
FILEFRAG_OBJS= filefrag.o
E2UNDO_OBJS= e2undo.o
E2PATCH_OBJS= e2patch.o
E4DEFRAG_OBJS= e4defrag.o
E4CRYPT_OBJS= e4crypt.o
E2FREEFRAG_OBJS= e2freefrag.o
@ -88,6 +89,7 @@ PROFILED_BLKID_OBJS= profiled/blkid.o
PROFILED_FILEFRAG_OBJS= profiled/filefrag.o
PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
PROFILED_E2UNDO_OBJS= profiled/e2undo.o
PROFILED_E2PATCH_OBJS= profiled/e2patch.o
PROFILED_E4DEFRAG_OBJS= profiled/e4defrag.o
PROFILED_E4CRYPT_OBJS= profiled/e4crypt.o
PROFILED_FUSE2FS_OJBS= profiled/fuse2fs.o profiled/journal.o \
@ -98,7 +100,7 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
$(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
$(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
$(srcdir)/filefrag.c $(srcdir)/base_device.c \
$(srcdir)/ismounted.c $(srcdir)/e2undo.c \
$(srcdir)/ismounted.c $(srcdir)/e2undo.c $(srcdir)/e2patch.c \
$(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \
$(srcdir)/fuse2fs.c \
$(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \
@ -133,7 +135,7 @@ all:: profiled $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES) \
$(FMANPAGES) $(LPROGS) $(E4DEFRAG_PROG) $(E4CRYPT_PROGS) e2fuzz
@PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \
e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
logsave.profiled filefrag.profiled uuidgen.profiled $(UUIDD_PROFILED) \
e2image.profiled e4defrag.profiled e4crypt.profiled \
e2freefrag.profiled
@ -226,6 +228,16 @@ e2undo.profiled: $(E2UNDO_OBJS) $(PROFILED_DEPLIBS)
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2undo.profiled \
$(PROFILED_E2UNDO_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS)
e2patch: $(E2PATCH_OBJS) $(DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -o e2patch $(E2PATCH_OBJS) $(LIBS) \
$(LIBINTL) $(SYSLIBS)
e2patch.profiled: $(E2PATCH_OBJS) $(PROFILED_DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2patch.profiled \
$(PROFILED_E2PATCH_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS)
e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS) \
@ -439,6 +451,10 @@ e2undo.8: $(DEP_SUBSTITUTE) $(srcdir)/e2undo.8.in
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2undo.8.in e2undo.8
e2patch.8: $(DEP_SUBSTITUTE) $(srcdir)/e2patch.8.in
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2patch.8.in e2patch.8
findfs.8: $(DEP_SUBSTITUTE) $(srcdir)/findfs.8.in
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/findfs.8.in findfs.8
@ -669,7 +685,7 @@ clean::
e2initrd_helper partinfo prof_err.[ch] default_profile.c \
uuidd e2image tune2fs.static tst_ismounted fsck.profiled \
blkid.profiled tune2fs.profiled e2image.profiled \
e2undo.profiled mke2fs.profiled dumpe2fs.profiled \
e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled \
logsave.profiled filefrag.profiled uuidgen.profiled \
uuidd.profiled e2image.profiled e2fuzz mke2fs.conf \
profiled/*.o \#* *.s *.o *.a *~ core gmon.out
@ -792,6 +808,12 @@ e2undo.o: $(srcdir)/e2undo.c $(top_builddir)/lib/config.h \
$(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
$(top_srcdir)/lib/support/nls-enable.h
e2patch.o: $(srcdir)/e2patch.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
e2freefrag.o: $(srcdir)/e2freefrag.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \

31
misc/e2patch.8.in Normal file
View File

@ -0,0 +1,31 @@
.TH E2PATCH 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
.SH NAME
e2patch \- patch tool for safely applying libext2fs patch files to block devices
.SH SYNOPSIS
.B e2patch backup \fI<device>\fR \fI<patch_file>\fR \fI<backup_file>\fR
.br
.B e2patch apply \fI<device>\fR \fI<patch_file>\fR
.SH DESCRIPTION
.B e2patch
applies and restores "patches" produced by e2fsprogs with patch file option
(\fBresize2fs -T <patch_file>\fR) to block devices.
.PP
"Patch files" are sparse files containing overwritten device blocks and
a block bitmap.
.PP
"Patch files" are faster, safer and simpler to use than "undo files"
(\fBe2undo\fR and \fBresize2fs -z <undo_file>\fR), even though their original
design goal is similar.
.SH COMMANDS
.TP
.B e2patch backup \fI<device>\fR \fI<patch_file>\fR \fI<backup_file>\fR
Creates a backup in <backup_file> for restoring after bad patch <patch_file>.
Backup can then also be applied with \fBe2patch apply\fR
.TP
.B e2patch apply \fI<device>\fR \fI<patch_file>\fR
Apply <patch_file> to <device>.
.SH AUTHOR
Written by Vitaliy Filippov <vitalif@mail.ru>
.SH SEE ALSO
.BR resize2fs (8),
.BR e2undo (8).

166
misc/e2patch.c Normal file
View File

@ -0,0 +1,166 @@
/**
* e2patch.c --- Utility to apply/restore patches created by patch_io_manager.
*
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
* License: GNU GPLv2 or later
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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"
#include "ext2fs/patch.h"
#define BUF 0x10000
#define _(a) (a)
errcode_t make_backup_patch(char *device, char *io_options, char *patch_file, char *backup_file)
{
io_manager mgr = unix_io_manager;
io_channel io;
errcode_t retval;
blk64_t blk, start, buf_blocks;
int eq;
void *buf = NULL;
struct ext2fs_patch_file patch = { 0 }, backup = { 0 };
retval = mgr->open(device, IO_FLAG_EXCLUSIVE, &io);
if (retval) goto out;
if (io_options &&
(retval = io_channel_set_options(io, io_options)))
goto out;
retval = ext2fs_patch_open(&patch, patch_file, 0);
if (retval) goto out;
retval = ext2fs_patch_open(&backup, backup_file, O_CREAT);
if (retval) goto out;
backup.block_size = patch.block_size;
backup.size = patch.size;
ext2fs_patch_init_bmap(&backup, NULL);
buf_blocks = BUF/patch.block_size;
retval = mgr->set_blksize(io, patch.block_size);
if (retval) goto out;
buf = malloc(BUF);
for (start = 0, blk = 0; blk <= patch.size; blk++)
{
if ((eq = !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks)
{
if (start != blk)
{
retval = io_channel_read_blk64(io, start, blk-start, buf);
if (retval) goto out;
retval = ext2fs_patch_write_blk64(&backup, start, blk-start, buf);
if (retval) goto out;
}
start = blk+eq;
}
}
out:
if (buf)
free(buf);
ext2fs_patch_close(&backup);
ext2fs_patch_close(&patch);
mgr->close(io);
return retval;
}
errcode_t apply_patch(char *device, char *io_options, char *patch_file)
{
io_manager mgr = unix_io_manager;
io_channel io;
errcode_t retval;
blk64_t blk, start, buf_blocks;
int eq;
void *buf = NULL;
struct ext2fs_patch_file patch = { 0 };
retval = mgr->open(device, IO_FLAG_EXCLUSIVE|IO_FLAG_RW, &io);
if (retval) goto out;
if (io_options &&
(retval = io_channel_set_options(io, io_options)))
goto out;
retval = ext2fs_patch_open(&patch, patch_file, 0);
if (retval) goto out;
buf_blocks = BUF/patch.block_size;
retval = mgr->set_blksize(io, patch.block_size);
if (retval) goto out;
buf = malloc(BUF);
for (start = 0, blk = 0; blk <= patch.size; blk++)
{
if ((eq = blk < patch.size && !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks)
{
if (start != blk)
{
retval = ext2fs_patch_retry_read_at(patch.patch_fd, patch.offset + start*patch.block_size, (blk-start)*patch.block_size, buf);
if (retval) goto out;
retval = io_channel_write_blk64(io, start, blk-start, buf);
if (retval) goto out;
}
start = blk+eq;
}
}
out:
if (buf)
free(buf);
ext2fs_patch_close(&patch);
mgr->close(io);
return retval;
}
int main(int narg, char **args)
{
errcode_t retval;
char *io_options = NULL;
if (narg >= 5 && !strcmp(args[1], "backup"))
{
io_options = strchr(args[2], '?');
if (io_options)
*io_options++ = 0;
retval = make_backup_patch(args[2], io_options, args[3], args[4]);
}
else if (narg >= 4 && !strcmp(args[1], "apply"))
{
io_options = strchr(args[2], '?');
if (io_options)
*io_options++ = 0;
retval = apply_patch(args[2], io_options, args[3]);
}
else
{
printf(
"Patch tool for safely applying changes to block devices\n"
"License: GNU GPLv2 or later\n"
"Copyright (c) Vitaliy Filippov, 2014\n\n"
"To create a backup for restoring after bad patch:\n"
" e2patch backup <filesystem> <patch_file> <backup_file>\n"
"To apply a patch:\n"
" e2patch apply <filesystem> <patch_file>\n"
);
return 0;
}
if (retval)
{
com_err("e2patch", retval, _("while trying to %s"), args[1]);
}
return 0;
}

View File

@ -43,6 +43,7 @@ misc/e2image.c
misc/e2initrd_helper.c
misc/e2label.c
misc/e2undo.c
misc/e2patch.c
misc/e4crypt.c
misc/e4defrag.c
misc/filefrag.c