From 72ed12648368b3f3ea14e8102e20bf5d3a3be6d3 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 12 Nov 2000 19:32:20 +0000 Subject: [PATCH] ChangeLog, Makefile.in, e2image.h, ext2_err.et.in, ext2fs.h, imager.c: imager.c (ext2fs_image_{inode,super,bitmap}_{read,write}, ext2_fs.h, Makefile.in: New file that has routines that save ext2fs metadata to a file. ext2_err.et.in (EXT2_ET_MAGIC_E2IMAGE): New error code assigned. e2image.h: New file which defines the file format for the ext2 image file. (Saved copy of ext2 metadata to a file as a saving throw against worst-case damage.) ChangeLog, Makefile.in, e2image.c: e2image.c, Makefile.in: New program which saves ext2 metadata to a file for people who need a last-ditch saving throw. --- lib/ext2fs/ChangeLog | 12 ++ lib/ext2fs/Makefile.in | 2 + lib/ext2fs/e2image.h | 49 ++++++ lib/ext2fs/ext2_err.et.in | 4 +- lib/ext2fs/ext2fs.h | 15 ++ lib/ext2fs/imager.c | 386 ++++++++++++++++++++++++++++++++++++++++++++++ misc/ChangeLog | 5 + misc/Makefile.in | 6 +- misc/e2image.c | 166 ++++++++++++++++++++ 9 files changed, 642 insertions(+), 3 deletions(-) create mode 100644 lib/ext2fs/e2image.h create mode 100644 lib/ext2fs/imager.c create mode 100644 misc/e2image.c diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 17f47fd..0ade399 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,15 @@ +2000-11-05 + + * imager.c (ext2fs_image_{inode,super,bitmap}_{read,write}, + ext2_fs.h, Makefile.in: New file that has routines that + save ext2fs metadata to a file. + + * ext2_err.et.in (EXT2_ET_MAGIC_E2IMAGE): New error code assigned. + + * e2image.h: New file which defines the file format for the ext2 + image file. (Saved copy of ext2 metadata to a file as a + saving throw against worst-case damage.) + 2000-11-01 * inode.c (ext2fs_flush_icache): Add new function diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in index 6d21d60..008e48a 100644 --- a/lib/ext2fs/Makefile.in +++ b/lib/ext2fs/Makefile.in @@ -32,6 +32,7 @@ OBJS= ext2_err.o \ get_pathname.o \ getsize.o \ icount.o \ + imager.o \ initialize.o \ inline.o \ inode.o \ @@ -82,6 +83,7 @@ SRCS= ext2_err.c \ $(srcdir)/get_pathname.c \ $(srcdir)/getsize.c \ $(srcdir)/icount.c \ + $(srcdir)/imager.o \ $(srcdir)/initialize.c \ $(srcdir)/inline.c \ $(srcdir)/inode.c \ diff --git a/lib/ext2fs/e2image.h b/lib/ext2fs/e2image.h new file mode 100644 index 0000000..c72c29d --- /dev/null +++ b/lib/ext2fs/e2image.h @@ -0,0 +1,49 @@ +/* + * e2image.h --- header file describing the ext2 image format + * + * Copyright (C) 2000 Theodore Ts'o. + * + * Note: this uses the POSIX IO interfaces, unlike most of the other + * functions in this library. So sue me. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + + +struct ext2_image_hdr { + __u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */ + char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */ + __u32 fs_hostname[64];/* Hostname of machine of image */ + char fs_netaddr[32]; /* Network address */ + __u32 fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */ + __u32 fs_device; /* Device number of image */ + char fs_uuid[16]; /* UUID of filesystem */ + __u32 fs_reserved[8]; + + __u32 image_device; /* Device number of image file */ + __u32 image_inode; /* Inode number of image file */ + __u32 image_time; /* Time of image creation */ + __u32 image_reserved[8]; + + __u32 offset_super; /* Byte offset of the sb and descriptors */ + __u32 offset_inode; /* Byte offset of the inode table */ + __u32 offset_inodemap; /* Byte offset of the inode bitmaps */ + __u32 offset_blockmap; /* Byte offset of the inode bitmaps */ + __u32 offset_reserved[8]; +}; + + + + + + + + + + + + + diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in index 41a439d..bc79a47 100644 --- a/lib/ext2fs/ext2_err.et.in +++ b/lib/ext2fs/ext2_err.et.in @@ -56,8 +56,8 @@ ec EXT2_ET_MAGIC_PQ_IO_CHANNEL, ec EXT2_ET_MAGIC_EXT2_FILE, "Wrong magic number for ext2 file structure" -ec EXT2_ET_MAGIC_RESERVED_7, - "Wrong magic number --- RESERVED_7" +ec EXT2_ET_MAGIC_E2IMAGE, + "Wrong magic number for Ext2 Image Header" ec EXT2_ET_MAGIC_RESERVED_8, "Wrong magic number --- RESERVED_8" diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 791bd3d..e579386 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -368,6 +368,12 @@ typedef struct ext2_icount *ext2_icount_t; #define BMAP_ALLOC 1 /* + * Flags for imager.c functions + */ +#define IMAGER_FLAG_INODEMAP 1 +#define IMAGER_FLAG_SPARSEWRITE 2 + +/* * For checking structure magic numbers... */ @@ -724,12 +730,21 @@ extern void ext2fs_badblocks_list_free(badblocks_list bb); extern errcode_t ext2fs_get_device_size(const char *file, int blocksize, blk_t *retblocks); +/* imager.c */ +extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags); + /* initialize.c */ extern errcode_t ext2fs_initialize(const char *name, int flags, struct ext2_super_block *param, io_manager manager, ext2_filsys *ret_fs); /* inode.c */ +extern errcode_t ext2fs_flush_icache(ext2_filsys fs); extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, ext2_inode_scan *ret_scan); extern void ext2fs_close_inode_scan(ext2_inode_scan scan); diff --git a/lib/ext2fs/imager.c b/lib/ext2fs/imager.c new file mode 100644 index 0000000..79b88ee --- /dev/null +++ b/lib/ext2fs/imager.c @@ -0,0 +1,386 @@ +/* + * image.c --- writes out the critical parts of the filesystem as a + * flat file. + * + * Copyright (C) 2000 Theodore Ts'o. + * + * Note: this uses the POSIX IO interfaces, unlike most of the other + * functions in this library. So sue me. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#if EXT2_FLAT_INCLUDES +#include "ext2_fs.h" +#else +#include +#endif + +#include "ext2fs.h" + +/* + * This function returns 1 if the specified block is all zeros + */ +static int check_zero_block(char *buf, int blocksize) +{ + char *cp = buf; + int left = blocksize; + + while (left > 0) { + if (*cp++) + return 0; + left--; + } + return 1; +} + +/* + * Write the inode table out as a single block. + */ +#define BUF_BLOCKS 32 + +errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags) +{ + unsigned int group, left, c, d; + char *buf, *cp; + blk_t blk; + ssize_t actual; + errcode_t retval; + + buf = malloc(fs->blocksize * BUF_BLOCKS); + if (!buf) + return ENOMEM; + + for (group = 0; group < fs->group_desc_count; group++) { + blk = fs->group_desc[(unsigned)group].bg_inode_table; + if (!blk) + return EXT2_ET_MISSING_INODE_TABLE; + left = fs->inode_blocks_per_group; + while (left) { + c = BUF_BLOCKS; + if (c > left) + c = left; + retval = io_channel_read_blk(fs->io, blk, c, buf); + if (retval) + goto errout; + cp = buf; + while (c) { + if (!(flags & IMAGER_FLAG_SPARSEWRITE)) { + d = c; + goto skip_sparse; + } + /* Skip zero blocks */ + if (check_zero_block(cp, fs->blocksize)) { + c--; + blk++; + left--; + cp += fs->blocksize; + lseek(fd, fs->blocksize, SEEK_CUR); + continue; + } + /* Find non-zero blocks */ + for (d=1; d < c; d++) { + if (check_zero_block(cp + d*fs->blocksize, fs->blocksize)) + break; + } + skip_sparse: + actual = write(fd, cp, fs->blocksize * d); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != fs->blocksize * d) { + retval = EXT2_ET_SHORT_WRITE; + goto errout; + } + blk += d; + left -= d; + cp += fs->blocksize * d; + c -= d; + } + } + } + retval = 0; + +errout: + free(buf); + return retval; +} + +/* + * Read in the inode table and stuff it into place + */ +errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags) +{ + unsigned int group, i, c, left; + char *buf; + blk_t blk; + ssize_t actual; + errcode_t retval; + + buf = malloc(fs->blocksize * BUF_BLOCKS); + if (!buf) + return ENOMEM; + + for (group = 0; group < fs->group_desc_count; group++) { + blk = fs->group_desc[(unsigned)group].bg_inode_table; + if (!blk) + return EXT2_ET_MISSING_INODE_TABLE; + left = fs->inode_blocks_per_group; + while (left) { + c = BUF_BLOCKS; + if (c > left) + c = left; + actual = read(fd, buf, fs->blocksize * c); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != fs->blocksize * c) { + retval = EXT2_ET_SHORT_READ; + goto errout; + } + retval = io_channel_write_blk(fs->io, blk, c, buf); + if (retval) + goto errout; + + blk += c; + left -= c; + } + } + retval = ext2fs_flush_icache(fs); + +errout: + free(buf); + return retval; +} + +/* + * Write out superblock and group descriptors + */ +errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags) +{ + unsigned int i; + char *buf, *cp; + blk_t blk; + ssize_t actual; + errcode_t retval; + + buf = malloc(fs->blocksize); + if (!buf) + return ENOMEM; + + /* + * Write out the superblock + */ + memset(buf, 0, fs->blocksize); + memcpy(buf, fs->super, SUPERBLOCK_SIZE); + actual = write(fd, buf, fs->blocksize); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != fs->blocksize) { + retval = EXT2_ET_SHORT_WRITE; + goto errout; + } + + /* + * Now write out the block group descriptors + */ + cp = (char *) fs->group_desc; + actual = write(fd, cp, fs->blocksize * fs->desc_blocks); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != fs->blocksize * fs->desc_blocks) { + retval = EXT2_ET_SHORT_WRITE; + goto errout; + } + + retval = 0; + +errout: + free(buf); + return retval; +} + +/* + * Read the superblock and group descriptors and overwrite them. + */ +errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags) +{ + unsigned int i; + char *buf, *cp; + blk_t blk; + ssize_t actual, size; + errcode_t retval; + + size = fs->blocksize * (fs->group_desc_count + 1); + buf = malloc(size); + if (!buf) + return ENOMEM; + + /* + * Read it all in. + */ + actual = read(fd, buf, size); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != size) { + retval = EXT2_ET_SHORT_READ; + goto errout; + } + + /* + * Now copy in the superblock and group descriptors + */ + memcpy(fs->super, buf, SUPERBLOCK_SIZE); + + memcpy(fs->group_desc, buf + fs->blocksize, + fs->blocksize * fs->group_desc_count); + + retval = 0; + +errout: + free(buf); + return retval; +} + +/* + * Write the block/inode bitmaps. + */ +errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) +{ + char *ptr; + int c, size; + char zero_buf[1024]; + ssize_t actual; + errcode_t retval; + + if (flags & IMAGER_FLAG_INODEMAP) { + if (!fs->inode_map) { + retval = ext2fs_read_inode_bitmap(fs); + if (retval) + return retval; + } + ptr = fs->inode_map->bitmap; + size = ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); + } else { + if (!fs->block_map) { + retval = ext2fs_read_block_bitmap(fs); + if (retval) + return retval; + } + ptr = fs->block_map->bitmap; + size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; + } + + actual = write(fd, ptr, size); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != size) { + retval = EXT2_ET_SHORT_WRITE; + goto errout; + } + size = size % fs->blocksize; + memset(zero_buf, 0, sizeof(zero_buf)); + if (size) { + size = fs->blocksize - size; + while (size) { + c = size; + if (c > sizeof(zero_buf)) + c = sizeof(zero_buf); + actual = write(fd, zero_buf, c); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != c) { + retval = EXT2_ET_SHORT_WRITE; + goto errout; + } + size -= c; + } + } + retval = 0; +errout: + return (retval); +} + + +/* + * Read the block/inode bitmaps. + */ +errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) +{ + char *ptr, *buf = 0; + int c, size; + char zero_buf[1024]; + ssize_t actual; + errcode_t retval; + + if (flags & IMAGER_FLAG_INODEMAP) { + if (!fs->inode_map) { + retval = ext2fs_read_inode_bitmap(fs); + if (retval) + return retval; + } + ptr = fs->inode_map->bitmap; + size = ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); + } else { + if (!fs->block_map) { + retval = ext2fs_read_block_bitmap(fs); + if (retval) + return retval; + } + ptr = fs->block_map->bitmap; + size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; + } + + buf = malloc(size); + if (!buf) + return ENOMEM; + + actual = read(fd, buf, size); + if (actual == -1) { + errno = retval; + goto errout; + } + if (actual != size) { + retval = EXT2_ET_SHORT_WRITE; + goto errout; + } + memcpy(ptr, buf, size); + + retval = 0; +errout: + if (buf) + free(buf); + return (retval); +} diff --git a/misc/ChangeLog b/misc/ChangeLog index 5da2e14..6985af1 100644 --- a/misc/ChangeLog +++ b/misc/ChangeLog @@ -1,3 +1,8 @@ +2000-11-05 + + * e2image.c, Makefile.in: New program which saves ext2 metadata to + a file for people who need a last-ditch saving throw. + 2000-10-24 * mke2fs.c (PRS): Applied Andreas Dilger's patch to make the -r -s diff --git a/misc/Makefile.in b/misc/Makefile.in index f196f46..a4d0e44 100644 --- a/misc/Makefile.in +++ b/misc/Makefile.in @@ -11,7 +11,7 @@ INSTALL = @INSTALL@ @MCONFIG@ -SPROGS= mke2fs badblocks tune2fs dumpe2fs e2label @FSCK_PROG@ +SPROGS= mke2fs badblocks tune2fs dumpe2fs e2label e2image @FSCK_PROG@ USPROGS= mklost+found SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \ e2label.8 @FSCK_MAN@ @@ -28,6 +28,7 @@ UUIDGEN_OBJS= uuidgen.o DUMPE2FS_OBJS= dumpe2fs.o BADBLOCKS_OBJS= badblocks.o E2LABEL_OBJS= e2label.o +E2IMAGE_OBJS= e2image.o FSCK_OBJS= fsck.o get_device_by_label.o SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c \ @@ -57,6 +58,9 @@ tune2fs: $(TUNE2FS_OBJS) $(DEPLIBS_E2P) $(DEPLIBUUID) e2label: $(E2LABEL_OBJS) $(CC) $(ALL_LDFLAGS) -o e2label $(E2LABEL_OBJS) +e2image: $(E2IMAGE_OBJS) $(DEPLIBS) + $(CC) $(ALL_LDFLAGS) -o e2image $(E2IMAGE_OBJS) $(LIBS) + mklost+found: $(MKLPF_OBJS) $(CC) $(ALL_LDFLAGS) -o mklost+found $(MKLPF_OBJS) diff --git a/misc/e2image.c b/misc/e2image.c new file mode 100644 index 0000000..2cdf2fe --- /dev/null +++ b/misc/e2image.c @@ -0,0 +1,166 @@ +/* + * e2image.c --- Program which writes an image file backing up + * critical metadata for the filesystem. + * + * Copyright 2000 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include +#include +#ifdef HAVE_GETOPT_H +#include +#else +extern char *optarg; +extern int optind; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ext2fs/ext2fs.h" +#include "et/com_err.h" +#include "uuid/uuid.h" +#include "e2p/e2p.h" +#include "ext2fs/e2image.h" + +#include "../version.h" +#include "nls-enable.h" + +const char * program_name = "e2label"; +char * device_name = NULL; + +static void usage(void) +{ + fprintf(stderr, _("Usage: %s device file\n"), program_name); + exit (1); +} + +static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n"); + +static void write_header(int fd, struct ext2_image_hdr *hdr) +{ + char header_buf[4096]; + int actual; + + if (lseek(fd, 0, SEEK_SET) < 0) { + perror("lseek while writing header"); + exit(1); + } + memset(header_buf, 0, sizeof(header_buf)); + + if (hdr) + memcpy(header_buf, hdr, sizeof(struct ext2_image_hdr)); + + actual = write(fd, header_buf, sizeof(header_buf)); + if (actual < 0) { + perror("write header"); + exit(1); + } + if (actual != sizeof(header_buf)) { + fprintf(stderr, _("short write (only %d bytes) for" + "writing image header"), actual); + exit(1); + } +} + + +int main (int argc, char ** argv) +{ + int c; + char * tmp; + errcode_t retval; + ext2_filsys fs; + struct ext2fs_sb *sb; + int open_flag = 0; + int raw_flag = 0; + int fd = 0; + char *features_cmd = 0; + struct ext2_image_hdr hdr; + +#ifdef ENABLE_NLS + setlocale(LC_MESSAGES, ""); + bindtextdomain(NLS_CAT_NAME, LOCALEDIR); + textdomain(NLS_CAT_NAME); +#endif + fprintf (stderr, _("e2image %s, %s for EXT2 FS %s, %s\n"), + E2FSPROGS_VERSION, E2FSPROGS_DATE, + EXT2FS_VERSION, EXT2FS_DATE); + if (argc && *argv) + program_name = *argv; + initialize_ext2_error_table(); + while ((c = getopt (argc, argv, "r")) != EOF) + switch (c) { + case 'r': + raw_flag++; + break; + default: + usage(); + } + if (optind != argc - 2 ) + usage(); + device_name = argv[optind]; + retval = ext2fs_open (device_name, open_flag, 0, 0, + unix_io_manager, &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); + } + sb = (struct ext2fs_sb *) fs->super; + + fd = open(argv[optind+1], O_CREAT|O_TRUNC|O_RDWR, 0600); + if (fd < 0) { + com_err(program_name, errno, _("while trying to open %s"), + argv[optind+1]); + exit(1); + } + + write_header(fd, NULL); + memset(&hdr, 0, sizeof(struct ext2_image_hdr)); + + hdr.offset_super = lseek(fd, 0, SEEK_CUR); + retval = ext2fs_image_super_write(fs, fd, 0); + if (retval) { + com_err(program_name, retval, _("while writing superblock")); + exit(1); + } + + hdr.offset_inode = lseek(fd, 0, SEEK_CUR); + retval = ext2fs_image_inode_write(fs, fd, IMAGER_FLAG_SPARSEWRITE); + if (retval) { + com_err(program_name, retval, _("while writing inode table")); + exit(1); + } + + hdr.offset_blockmap = lseek(fd, 0, SEEK_CUR); + retval = ext2fs_image_bitmap_write(fs, fd, 0); + if (retval) { + com_err(program_name, retval, _("while writing block bitmap")); + exit(1); + } + + hdr.offset_inodemap = lseek(fd, 0, SEEK_CUR); + retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP); + if (retval) { + com_err(program_name, retval, _("while writing inode bitmap")); + exit(1); + } + + ext2fs_close (fs); + exit (0); +} -- 1.8.3.1