diff options
author | Theodore Ts'o <tytso@mit.edu> | 2000-11-12 19:32:20 +0000 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2000-11-12 19:32:20 +0000 |
commit | 72ed12648368b3f3ea14e8102e20bf5d3a3be6d3 (patch) | |
tree | 8cfc855fc826c968d5a43efcbc12b4406ee21346 /lib/ext2fs | |
parent | 6a7f455bb129e867407fe1961328931ff704b3d2 (diff) | |
download | e2fsprogs-72ed12648368b3f3ea14e8102e20bf5d3a3be6d3.tar.gz |
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.
Diffstat (limited to 'lib/ext2fs')
-rw-r--r-- | lib/ext2fs/ChangeLog | 12 | ||||
-rw-r--r-- | lib/ext2fs/Makefile.in | 2 | ||||
-rw-r--r-- | lib/ext2fs/e2image.h | 49 | ||||
-rw-r--r-- | lib/ext2fs/ext2_err.et.in | 4 | ||||
-rw-r--r-- | lib/ext2fs/ext2fs.h | 15 | ||||
-rw-r--r-- | lib/ext2fs/imager.c | 386 |
6 files changed, 466 insertions, 2 deletions
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 17f47fd4..0ade399f 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,15 @@ +2000-11-05 <tytso@snap.thunk.org> + + * 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 <tytso@snap.thunk.org> * inode.c (ext2fs_flush_icache): Add new function diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in index 6d21d608..008e48a5 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 00000000..c72c29dd --- /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 41a439d4..bc79a47d 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 791bd3de..e5793860 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 00000000..79b88ee6 --- /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 <stdio.h> +#include <string.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#include <fcntl.h> +#include <time.h> +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#if EXT2_FLAT_INCLUDES +#include "ext2_fs.h" +#else +#include <linux/ext2_fs.h> +#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); +} |