summaryrefslogtreecommitdiff
path: root/lib/ext2fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2000-11-12 19:32:20 +0000
committerTheodore Ts'o <tytso@mit.edu>2000-11-12 19:32:20 +0000
commit72ed12648368b3f3ea14e8102e20bf5d3a3be6d3 (patch)
tree8cfc855fc826c968d5a43efcbc12b4406ee21346 /lib/ext2fs
parent6a7f455bb129e867407fe1961328931ff704b3d2 (diff)
downloade2fsprogs-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/ChangeLog12
-rw-r--r--lib/ext2fs/Makefile.in2
-rw-r--r--lib/ext2fs/e2image.h49
-rw-r--r--lib/ext2fs/ext2_err.et.in4
-rw-r--r--lib/ext2fs/ext2fs.h15
-rw-r--r--lib/ext2fs/imager.c386
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);
+}