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/imager.c | |
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/imager.c')
-rw-r--r-- | lib/ext2fs/imager.c | 386 |
1 files changed, 386 insertions, 0 deletions
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); +} |