Whamcloud - gitweb
e2fsck: do not change global variables
[tools/e2fsprogs.git] / misc / e2image.c
index bdadfe7..1ae0300 100644 (file)
  * %End-Header%
  */
 
+#ifndef _LARGEFILE_SOURCE
 #define _LARGEFILE_SOURCE
+#endif
+#ifndef _LARGEFILE64_SOURCE
 #define _LARGEFILE64_SOURCE
+#endif
 
 #include "config.h"
 #include <fcntl.h>
@@ -35,39 +39,50 @@ extern int optind;
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <assert.h>
+#include <signal.h>
 
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fs.h"
+#include "ext2fs/ext2fsP.h"
 #include "et/com_err.h"
 #include "uuid/uuid.h"
 #include "e2p/e2p.h"
 #include "ext2fs/e2image.h"
 #include "ext2fs/qcow2.h"
 
+#include "support/nls-enable.h"
+#include "support/plausible.h"
+#include "support/quotaio.h"
 #include "../version.h"
-#include "nls-enable.h"
 
-#define QCOW_OFLAG_COPIED     (1LL << 63)
+#define QCOW_OFLAG_COPIED     (1ULL << 63)
+#define NO_BLK ((blk64_t) -1)
 
+/* Image types */
+#define E2IMAGE_RAW    1
+#define E2IMAGE_QCOW2  2
+
+/* Image flags */
+#define E2IMAGE_INSTALL_FLAG   1
+#define E2IMAGE_SCRAMBLE_FLAG  2
+#define E2IMAGE_IS_QCOW2_FLAG  4
+#define E2IMAGE_CHECK_ZERO_FLAG        8
 
 static const char * program_name = "e2image";
 static char * device_name = NULL;
 static char all_data;
 static char output_is_blk;
+static char nop_flag;
 /* writing to blk device: don't skip zeroed blocks */
-blk64_t source_offset, dest_offset;
-char move_mode;
-char show_progress;
-
-static void lseek_error_and_exit(int errnum)
-{
-       fprintf(stderr, "seek: %s\n", error_message(errnum));
-       exit(1);
-}
+static blk64_t source_offset, dest_offset;
+static char move_mode;
+static char show_progress;
+static char *check_buf;
+static int skipped_blocks;
 
-static blk64_t align_offset(blk64_t offset, int n)
+static blk64_t align_offset(blk64_t offset, unsigned int n)
 {
-       return (offset + n - 1) & ~(n - 1);
+       return (offset + n - 1) & ~((blk64_t) n - 1);
 }
 
 static int get_bits_from_size(size_t size)
@@ -90,11 +105,62 @@ static int get_bits_from_size(size_t size)
 
 static void usage(void)
 {
-       fprintf(stderr, _("Usage: %s [-rsIQafp] [-o src_offset] [-O dest_offset] device image_file\n"),
+       fprintf(stderr, _("Usage: %s [ -r|-Q ] [ -f ] [ -b superblock ] [ -B blocksize ] "
+                         "device image-file\n"),
+               program_name);
+       fprintf(stderr, _("       %s -I device image-file\n"), program_name);
+       fprintf(stderr, _("       %s -ra [ -cfnp ] [ -o src_offset ] "
+                         "[ -O dest_offset ] src_fs [ dest_fs ]\n"),
                program_name);
        exit (1);
 }
 
+static ext2_loff_t seek_relative(int fd, int offset)
+{
+       ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_CUR);
+       if (ret < 0) {
+               perror("seek_relative");
+               exit(1);
+       }
+       return ret;
+}
+
+static ext2_loff_t seek_set(int fd, ext2_loff_t offset)
+{
+       ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_SET);
+       if (ret < 0) {
+               perror("seek_set");
+               exit(1);
+       }
+       return ret;
+}
+
+/*
+ * Returns true if the block we are about to write is identical to
+ * what is already on the disk.
+ */
+static int check_block(int fd, void *buf, void *cbuf, int blocksize)
+{
+       char *cp = cbuf;
+       int count = blocksize, ret;
+
+       if (cbuf == NULL)
+               return 0;
+
+       while (count > 0) {
+               ret = read(fd, cp, count);
+               if (ret < 0) {
+                       perror("check_block");
+                       exit(1);
+               }
+               count -= ret;
+               cp += ret;
+       }
+       ret = memcmp(buf, cbuf, blocksize);
+       seek_relative(fd, -blocksize);
+       return (ret == 0) ? 1 : 0;
+}
+
 static void generic_write(int fd, void *buf, int blocksize, blk64_t block)
 {
        int count, free_buf = 0;
@@ -107,11 +173,17 @@ static void generic_write(int fd, void *buf, int blocksize, blk64_t block)
                free_buf = 1;
                err = ext2fs_get_arrayzero(1, blocksize, &buf);
                if (err) {
-                       com_err(program_name, err, "while allocating buffer");
+                       com_err(program_name, err, "%s",
+                               _("while allocating buffer"));
                        exit(1);
                }
        }
-
+       if (nop_flag) {
+               printf(_("Writing block %llu\n"), (unsigned long long) block);
+               if (fd != 1)
+                       seek_relative(fd, blocksize);
+               goto free_and_return;
+       }
        count = write(fd, buf, blocksize);
        if (count != blocksize) {
                if (count == -1)
@@ -120,13 +192,16 @@ static void generic_write(int fd, void *buf, int blocksize, blk64_t block)
                        err = 0;
 
                if (block)
-                       com_err(program_name, err, "error writing block %llu",
-                               block);
+                       com_err(program_name, err,
+                               _("error writing block %llu"),
+                               (unsigned long long) block);
                else
-                       com_err(program_name, err, "error in write()");
+                       com_err(program_name, err, "%s",
+                               _("error in generic_write()"));
 
                exit(1);
        }
+free_and_return:
        if (free_buf)
                ext2fs_free_mem(&buf);
 }
@@ -148,16 +223,13 @@ static void write_header(int fd, void *hdr, int hdr_size, int wrt_size)
                exit(1);
        }
 
-       if (ext2fs_llseek(fd, 0, SEEK_SET) < 0) {
-               perror("ext2fs_llseek while writing header");
-               exit(1);
-       }
+       seek_set(fd, 0);
        memset(header_buf, 0, wrt_size);
 
        if (hdr)
                memcpy(header_buf, hdr, hdr_size);
 
-       generic_write(fd, header_buf, wrt_size, 0);
+       generic_write(fd, header_buf, wrt_size, NO_BLK);
 
        ext2fs_free_mem(&header_buf);
 }
@@ -171,7 +243,7 @@ static void write_image_file(ext2_filsys fs, int fd)
        write_header(fd, NULL, sizeof(struct ext2_image_hdr), fs->blocksize);
        memset(&hdr, 0, sizeof(struct ext2_image_hdr));
 
-       hdr.offset_super = ext2fs_llseek(fd, 0, SEEK_CUR);
+       hdr.offset_super = ext2fs_cpu_to_le32(seek_relative(fd, 0));
        retval = ext2fs_image_super_write(fs, fd, 0);
        if (retval) {
                com_err(program_name, retval, "%s",
@@ -179,7 +251,7 @@ static void write_image_file(ext2_filsys fs, int fd)
                exit(1);
        }
 
-       hdr.offset_inode = ext2fs_llseek(fd, 0, SEEK_CUR);
+       hdr.offset_inode = ext2fs_cpu_to_le32(seek_relative(fd, 0));
        retval = ext2fs_image_inode_write(fs, fd,
                                  (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
        if (retval) {
@@ -188,7 +260,7 @@ static void write_image_file(ext2_filsys fs, int fd)
                exit(1);
        }
 
-       hdr.offset_blockmap = ext2fs_llseek(fd, 0, SEEK_CUR);
+       hdr.offset_blockmap = ext2fs_cpu_to_le32(seek_relative(fd, 0));
        retval = ext2fs_image_bitmap_write(fs, fd, 0);
        if (retval) {
                com_err(program_name, retval, "%s",
@@ -196,7 +268,7 @@ static void write_image_file(ext2_filsys fs, int fd)
                exit(1);
        }
 
-       hdr.offset_inodemap = ext2fs_llseek(fd, 0, SEEK_CUR);
+       hdr.offset_inodemap = ext2fs_cpu_to_le32(seek_relative(fd, 0));
        retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP);
        if (retval) {
                com_err(program_name, retval, "%s",
@@ -204,23 +276,23 @@ static void write_image_file(ext2_filsys fs, int fd)
                exit(1);
        }
 
-       hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE;
+       hdr.magic_number = ext2fs_cpu_to_le32(EXT2_ET_MAGIC_E2IMAGE);
        strcpy(hdr.magic_descriptor, "Ext2 Image 1.0");
        gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname));
        strncpy(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)-1);
        hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0;
-       hdr.fs_blocksize = fs->blocksize;
+       hdr.fs_blocksize = ext2fs_cpu_to_le32(fs->blocksize);
 
        if (stat(device_name, &st) == 0)
-               hdr.fs_device = st.st_rdev;
+               hdr.fs_device = ext2fs_cpu_to_le32(st.st_rdev);
 
        if (fstat(fd, &st) == 0) {
-               hdr.image_device = st.st_dev;
-               hdr.image_inode = st.st_ino;
+               hdr.image_device = ext2fs_cpu_to_le32(st.st_dev);
+               hdr.image_inode = ext2fs_cpu_to_le32(st.st_ino);
        }
        memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid));
 
-       hdr.image_time = time(0);
+       hdr.image_time = ext2fs_cpu_to_le32(time(0));
        write_header(fd, &hdr, sizeof(struct ext2_image_hdr), fs->blocksize);
 }
 
@@ -242,7 +314,7 @@ struct process_block_struct {
  * structure, so there's no point in letting the ext2fs library read
  * the inode again.
  */
-static ino_t stashed_ino = 0;
+static ext2_ino_t stashed_ino = 0;
 static struct ext2_inode *stashed_inode;
 
 static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
@@ -347,6 +419,14 @@ static void mark_table_blocks(ext2_filsys fs)
        }
        meta_blocks_count += fs->desc_blocks;
 
+       /*
+        *  Mark MMP block
+        */
+       if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) {
+               ext2fs_mark_block_bitmap2(meta_block_map, fs->super->s_mmp_block);
+               meta_blocks_count++;
+       }
+
        for (i = 0; i < fs->group_desc_count; i++) {
                /*
                 * Mark the blocks used for the inode table
@@ -356,9 +436,7 @@ static void mark_table_blocks(ext2_filsys fs)
                    ext2fs_inode_table_loc(fs, i)) {
                        unsigned int end = (unsigned) fs->inode_blocks_per_group;
                        /* skip unused blocks */
-                       if (!output_is_blk &&
-                           EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                       if (!output_is_blk && ext2fs_has_group_desc_csum(fs))
                                end -= (ext2fs_bg_itable_unused(fs, i) /
                                        EXT2_INODES_PER_BLOCK(fs->super));
                        for (j = 0, b = ext2fs_inode_table_loc(fs, i);
@@ -409,19 +487,6 @@ static int check_zero_block(char *buf, int blocksize)
        return 1;
 }
 
-static void write_block(int fd, char *buf, int sparse_offset,
-                       int blocksize, blk64_t block)
-{
-       ext2_loff_t     ret = 0;
-
-       if (sparse_offset)
-               ret = ext2fs_llseek(fd, sparse_offset, SEEK_CUR);
-
-       if (ret < 0)
-               lseek_error_and_exit(errno);
-       generic_write(fd, buf, blocksize, block);
-}
-
 static int name_id[256];
 
 #define EXT4_MAX_REC_LEN               ((1<<16)-1)
@@ -449,9 +514,9 @@ static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf)
 #endif
                if (rec_len < 8 || (rec_len % 4) ||
                    (p+rec_len > end)) {
-                       printf("Corrupt directory block %lu: "
-                              "bad rec_len (%d)\n", (unsigned long) blk,
-                              rec_len);
+                       printf(_("Corrupt directory block %llu: "
+                                "bad rec_len (%d)\n"),
+                              (unsigned long long) blk, rec_len);
                        rec_len = end - p;
                        (void) ext2fs_set_rec_len(fs, rec_len,
                                        (struct ext2_dir_entry *) dirent);
@@ -461,9 +526,9 @@ static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf)
                        continue;
                }
                if (dirent->name_len + 8U > rec_len) {
-                       printf("Corrupt directory block %lu: "
-                              "bad name_len (%d)\n", (unsigned long) blk,
-                              dirent->name_len);
+                       printf(_("Corrupt directory block %llu: "
+                                "bad name_len (%d)\n"),
+                              (unsigned long long) blk, dirent->name_len);
                        dirent->name_len = rec_len - 8;
                        continue;
                }
@@ -488,7 +553,27 @@ static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf)
        }
 }
 
-static void output_meta_data_blocks(ext2_filsys fs, int fd)
+static char got_sigint;
+
+static void sigint_handler(int unused EXT2FS_ATTR((unused)))
+{
+       got_sigint = 1;
+       signal (SIGINT, SIG_DFL);
+}
+
+#define calc_percent(a, b) ((int) ((100.0 * (((float) (a)) / \
+                                            ((float) (b)))) + 0.5))
+#define calc_rate(t, b, d) (((float)(t) / ((float)(1024 * 1024) / (b))) / (d))
+
+static int print_progress(blk64_t num, blk64_t total)
+{
+       return fprintf(stderr, _("%llu / %llu blocks (%d%%)"),
+                      (unsigned long long) num,
+                      (unsigned long long) total,
+                      calc_percent(num, total));
+}
+
+static void output_meta_data_blocks(ext2_filsys fs, int fd, int flags)
 {
        errcode_t       retval;
        blk64_t         blk;
@@ -497,28 +582,27 @@ static void output_meta_data_blocks(ext2_filsys fs, int fd)
        blk64_t         start = 0;
        blk64_t         distance = 0;
        blk64_t         end = ext2fs_blocks_count(fs->super);
-       time_t          last_update;
-       time_t          start_time;
+       time_t          last_update = 0;
+       time_t          start_time = 0;
        blk64_t         total_written = 0;
-       int             bscount;
+       int             bscount = 0;
 
        retval = ext2fs_get_mem(fs->blocksize, &buf);
        if (retval) {
-               com_err(program_name, retval, "while allocating buffer");
+               com_err(program_name, retval, "%s",
+                       _("while allocating buffer"));
                exit(1);
        }
        retval = ext2fs_get_memzero(fs->blocksize, &zero_buf);
        if (retval) {
-               com_err(program_name, retval, "while allocating buffer");
+               com_err(program_name, retval, "%s",
+                       _("while allocating buffer"));
                exit(1);
        }
        if (show_progress) {
-               printf("Copying ");
-               bscount = printf("%llu / %llu blocks (%llu%%)",
-                                total_written,
-                                meta_blocks_count,
-                                (total_written + 50) / ((meta_blocks_count + 50) / 100));
-               fflush(stdout);
+               fprintf(stderr, "%s", _("Copying "));
+               bscount = print_progress(total_written, meta_blocks_count);
+               fflush(stderr);
                last_update = time(NULL);
                start_time = time(NULL);
        }
@@ -531,59 +615,95 @@ static void output_meta_data_blocks(ext2_filsys fs, int fd)
                if (distance < ext2fs_blocks_count(fs->super))
                        start = ext2fs_blocks_count(fs->super) - distance;
        }
+       if (move_mode)
+               signal (SIGINT, sigint_handler);
 more_blocks:
        if (distance)
-               ext2fs_llseek (fd, (start * fs->blocksize) + dest_offset, SEEK_SET);
+               seek_set(fd, (start * fs->blocksize) + dest_offset);
        for (blk = start; blk < end; blk++) {
+               if (got_sigint) {
+                       if (distance) {
+                               /* moving to the right */
+                               if (distance >= ext2fs_blocks_count(fs->super)||
+                                   start == ext2fs_blocks_count(fs->super) -
+                                               distance)
+                                       kill(getpid(), SIGINT);
+                       } else {
+                               /* moving to the left */
+                               if (blk < (source_offset - dest_offset) /
+                                   fs->blocksize)
+                                       kill(getpid(), SIGINT);
+                       }
+                       if (show_progress)
+                               fputc('\r', stderr);
+                       fprintf(stderr, "%s",
+                               _("Stopping now will destroy the filesystem, "
+                                "interrupt again if you are sure\n"));
+                       if (show_progress) {
+                               fprintf(stderr, "%s", _("Copying "));
+                               bscount = print_progress(total_written,
+                                                        meta_blocks_count);
+                               fflush(stderr);
+                       }
+
+                       got_sigint = 0;
+               }
                if (show_progress && last_update != time(NULL)) {
+                       time_t duration;
                        last_update = time(NULL);
                        while (bscount--)
-                               printf("\b");
-                       bscount = printf("%llu / %llu blocks (%llu%%)",
-                                        total_written,
-                                        meta_blocks_count,
-                                        (total_written + 50) /
-                                        ((meta_blocks_count + 50) / 100));
-                       time_t duration = time(NULL) - start_time;
-                       if (duration > 5) {
-                               time_t est = (duration *
-                                             meta_blocks_count / total_written) -
-                                       (duration);
+                               fputc('\b', stderr);
+                       bscount = print_progress(total_written,
+                                                meta_blocks_count);
+                       duration = time(NULL) - start_time;
+                       if (duration > 5 && total_written) {
+                               time_t est = (duration * meta_blocks_count /
+                                             total_written) - duration;
                                char buff[30];
                                strftime(buff, 30, "%T", gmtime(&est));
-                               bscount += printf(" %s remaining at %.2f MB/s",
-                                                 buff,
-                                                 ((float)total_written /
-                                                  ((1024 * 1024) / fs->blocksize)) /
-                                                 duration);
+                               bscount +=
+                                       fprintf(stderr,
+                                               _(" %s remaining at %.2f MB/s"),
+                                               buff, calc_rate(total_written,
+                                                               fs->blocksize,
+                                                               duration));
                        }
-                       fflush (stdout);
+                       fflush (stderr);
                }
                if ((blk >= fs->super->s_first_data_block) &&
                    ext2fs_test_block_bitmap2(meta_block_map, blk)) {
                        retval = io_channel_read_blk64(fs->io, blk, 1, buf);
                        if (retval) {
                                com_err(program_name, retval,
-                                       "error reading block %llu", blk);
+                                       _("error reading block %llu"),
+                                       (unsigned long long) blk);
                        }
                        total_written++;
                        if (scramble_block_map &&
                            ext2fs_test_block_bitmap2(scramble_block_map, blk))
                                scramble_dir_block(fs, blk, buf);
-                       if ((fd != 1) && check_zero_block(buf, fs->blocksize))
+                       if ((flags & E2IMAGE_CHECK_ZERO_FLAG) &&
+                           check_zero_block(buf, fs->blocksize))
                                goto sparse_write;
-                       write_block(fd, buf, sparse, fs->blocksize, blk);
+                       if (sparse)
+                               seek_relative(fd, sparse);
                        sparse = 0;
+                       if (check_block(fd, buf, check_buf, fs->blocksize)) {
+                               seek_relative(fd, fs->blocksize);
+                               skipped_blocks++;
+                       } else
+                               generic_write(fd, buf, fs->blocksize, blk);
                } else {
                sparse_write:
                        if (fd == 1) {
-                               write_block(fd, zero_buf, 0,
-                                           fs->blocksize, blk);
+                               if (!nop_flag)
+                                       generic_write(fd, zero_buf,
+                                                     fs->blocksize, blk);
                                continue;
                        }
                        sparse += fs->blocksize;
                        if (sparse > 1024*1024) {
-                               write_block(fd, 0, 1024*1024, 0, 0);
+                               seek_relative(fd, 1024*1024);
                                sparse -= 1024*1024;
                        }
                }
@@ -604,41 +724,40 @@ more_blocks:
                sparse = 0;
                goto more_blocks;
        }
+       signal (SIGINT, SIG_DFL);
        if (show_progress) {
-               while (bscount--)
-                       printf("\b");
                time_t duration = time(NULL) - start_time;
                char buff[30];
+               fputc('\r', stderr);
                strftime(buff, 30, "%T", gmtime(&duration));
-               printf("\b\b\b\b\b\b\b\bCopied %llu / %llu blocks (%llu%%) in "
-                      "%s at %.2f MB/s       \n",
-                      total_written,
-                      meta_blocks_count,
-                      (total_written + 50) / ((meta_blocks_count + 50) / 100),
-                      buff,
-                      ((float)total_written /
-                       ((1024 * 1024) / fs->blocksize)) /
-                      duration);
-
+               fprintf(stderr, _("Copied %llu / %llu blocks (%d%%) in %s "),
+                       (unsigned long long) total_written,
+                       (unsigned long long) meta_blocks_count,
+                       calc_percent(total_written, meta_blocks_count), buff);
+               if (duration)
+                       fprintf(stderr, _("at %.2f MB/s"),
+                               calc_rate(total_written, fs->blocksize, duration));
+               fputs("       \n", stderr);
        }
 #ifdef HAVE_FTRUNCATE64
        if (sparse) {
                ext2_loff_t offset;
                if (distance)
-                       offset = ext2fs_llseek(
-                               fd,
-                               fs->blocksize * ext2fs_blocks_count(fs->super) + dest_offset,
-                               SEEK_SET);
-               else offset = ext2fs_llseek(fd, sparse, SEEK_CUR);
+                       offset = seek_set(fd,
+                                         fs->blocksize * ext2fs_blocks_count(fs->super) + dest_offset);
+               else
+                       offset = seek_relative(fd, sparse);
 
-               if (offset < 0)
-                       lseek_error_and_exit(errno);
-               if (ftruncate64(fd, offset) < 0)
-                       write_block(fd, zero_buf, -1, 1, -1);
+               if (ftruncate64(fd, offset) < 0) {
+                       seek_relative(fd, -1);
+                       generic_write(fd, zero_buf, 1, NO_BLK);
+               }
        }
 #else
-       if (sparse && !distance)
-               write_block(fd, zero_buf, sparse-1, 1, -1);
+       if (sparse && !distance) {
+               seek_relative(fd, sparse-1);
+               generic_write(fd, zero_buf, 1, NO_BLK);
+       }
 #endif
        ext2fs_free_mem(&zero_buf);
        ext2fs_free_mem(&buf);
@@ -651,7 +770,8 @@ static void init_l1_table(struct ext2_qcow2_image *image)
 
        ret = ext2fs_get_arrayzero(image->l1_size, sizeof(__u64), &l1_table);
        if (ret) {
-               com_err(program_name, ret, "while allocating l1 table");
+               com_err(program_name, ret, "%s",
+                       _("while allocating l1 table"));
                exit(1);
        }
 
@@ -696,7 +816,7 @@ static void init_l2_cache(struct ext2_qcow2_image *image)
        return;
 
 alloc_err:
-       com_err(program_name, ret, "while allocating l2 cache");
+       com_err(program_name, ret, "%s", _("while allocating l2 cache"));
        exit(1);
 }
 
@@ -719,9 +839,10 @@ again:
        }
 
        if (cache->free != cache->count) {
-               fprintf(stderr, "Warning: There are still tables in the "
-                               "cache while putting the cache, data will "
-                               "be lost so the image may not be valid.\n");
+               fprintf(stderr, "%s", _("Warning: There are still tables in "
+                                       "the cache while putting the cache, "
+                                       "data will be lost so the image may "
+                                       "not be valid.\n"));
                table = cache->used_head;
                cache->used_head = NULL;
                goto again;
@@ -768,8 +889,8 @@ static int init_refcount(struct ext2_qcow2_image *img, blk64_t table_offset)
        return ret;
 }
 
-static int initialize_qcow2_image(int fd, ext2_filsys fs,
-                           struct ext2_qcow2_image *image)
+static errcode_t initialize_qcow2_image(int fd, ext2_filsys fs,
+                                       struct ext2_qcow2_image *image)
 {
        struct ext2_qcow2_hdr *header;
        blk64_t total_size, offset;
@@ -777,6 +898,10 @@ static int initialize_qcow2_image(int fd, ext2_filsys fs,
        int cluster_bits = get_bits_from_size(fs->blocksize);
        struct ext2_super_block *sb = fs->super;
 
+       /* Sbould never happen, but just in case... */
+       if (cluster_bits < 0)
+               return EXT2_FILSYS_CORRUPTED;
+
        /* Allocate header */
        ret = ext2fs_get_memzero(sizeof(struct ext2_qcow2_hdr), &header);
        if (ret)
@@ -818,7 +943,7 @@ static int initialize_qcow2_image(int fd, ext2_filsys fs,
        header->refcount_table_clusters =
                ext2fs_cpu_to_be32(image->refcount.refcount_table_clusters);
        offset += image->cluster_size;
-       offset += image->refcount.refcount_table_clusters <<
+       offset += (blk64_t) image->refcount.refcount_table_clusters <<
                image->cluster_bits;
 
        /* Make space for L2 tables */
@@ -893,25 +1018,23 @@ static void flush_l2_cache(struct ext2_qcow2_image *image)
        int fd = image->fd;
 
        /* Store current position */
-       if ((offset = ext2fs_llseek(fd, 0, SEEK_CUR)) < 0)
-               lseek_error_and_exit(errno);
+       offset = seek_relative(fd, 0);
 
        assert(table);
        while (cache->free < cache->count) {
                if (seek != table->offset) {
-                       if (ext2fs_llseek(fd, table->offset, SEEK_SET) < 0)
-                               lseek_error_and_exit(errno);
+                       seek_set(fd, table->offset);
                        seek = table->offset;
                }
 
-               generic_write(fd, (char *)table->data, image->cluster_size , 0);
+               generic_write(fd, (char *)table->data, image->cluster_size,
+                             NO_BLK);
                put_used_table(image, &table);
                seek += image->cluster_size;
        }
 
        /* Restore previous position */
-       if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
-               lseek_error_and_exit(errno);
+       seek_set(fd, offset);
 }
 
 /**
@@ -988,11 +1111,10 @@ static int update_refcount(int fd, struct ext2_qcow2_image *img,
         */
        if (table_index != ref->refcount_table_index) {
 
-               if (ext2fs_llseek(fd, ref->refcount_block_offset, SEEK_SET) < 0)
-                       lseek_error_and_exit(errno);
+               seek_set(fd, ref->refcount_block_offset);
 
                generic_write(fd, (char *)ref->refcount_block,
-                             img->cluster_size, 0);
+                             img->cluster_size, NO_BLK);
                memset(ref->refcount_block, 0, img->cluster_size);
 
                ref->refcount_table[ref->refcount_table_index] =
@@ -1006,7 +1128,7 @@ static int update_refcount(int fd, struct ext2_qcow2_image *img,
        /*
         * We are relying on the fact that we are creating the qcow2
         * image sequentially, hence we will always allocate refcount
-        * block items sequentialy.
+        * block items sequentially.
         */
        ref->refcount_block[ref->refcount_block_index] = ext2fs_cpu_to_be16(1);
        ref->refcount_block_index++;
@@ -1021,14 +1143,13 @@ static int sync_refcount(int fd, struct ext2_qcow2_image *img)
 
        ref->refcount_table[ref->refcount_table_index] =
                ext2fs_cpu_to_be64(ref->refcount_block_offset);
-       if (ext2fs_llseek(fd, ref->refcount_table_offset, SEEK_SET) < 0)
-               lseek_error_and_exit(errno);
+       seek_set(fd, ref->refcount_table_offset);
        generic_write(fd, (char *)ref->refcount_table,
-               ref->refcount_table_clusters << img->cluster_bits, 0);
+               ref->refcount_table_clusters << img->cluster_bits, NO_BLK);
 
-       if (ext2fs_llseek(fd, ref->refcount_block_offset, SEEK_SET) < 0)
-               lseek_error_and_exit(errno);
-       generic_write(fd, (char *)ref->refcount_block, img->cluster_size, 0);
+       seek_set(fd, ref->refcount_block_offset);
+       generic_write(fd, (char *)ref->refcount_block, img->cluster_size,
+                     NO_BLK);
        return 0;
 }
 
@@ -1043,15 +1164,15 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
        /* allocate  struct ext2_qcow2_image */
        retval = ext2fs_get_mem(sizeof(struct ext2_qcow2_image), &img);
        if (retval) {
-               com_err(program_name, retval,
-                       "while allocating ext2_qcow2_image");
+               com_err(program_name, retval, "%s",
+                       _("while allocating ext2_qcow2_image"));
                exit(1);
        }
 
        retval = initialize_qcow2_image(fd, fs, img);
        if (retval) {
-               com_err(program_name, retval,
-                       "while initializing ext2_qcow2_image");
+               com_err(program_name, retval, "%s",
+                       _("while initializing ext2_qcow2_image"));
                exit(1);
        }
        header_size = align_offset(sizeof(struct ext2_qcow2_hdr),
@@ -1060,8 +1181,7 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
 
        /* Refcount all qcow2 related metadata up to refcount_block_offset */
        end = img->refcount.refcount_block_offset;
-       if (ext2fs_llseek(fd, end, SEEK_SET) < 0)
-               lseek_error_and_exit(errno);
+       seek_set(fd, end);
        blk = end + img->cluster_size;
        for (offset = 0; offset <= end; offset += img->cluster_size) {
                if (update_refcount(fd, img, offset, blk)) {
@@ -1073,12 +1193,12 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
                        end += img->cluster_size;
                }
        }
-       if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
-               lseek_error_and_exit(errno);
+       seek_set(fd, offset);
 
        retval = ext2fs_get_mem(fs->blocksize, &buf);
        if (retval) {
-               com_err(program_name, retval, "while allocating buffer");
+               com_err(program_name, retval, "%s",
+                       _("while allocating buffer"));
                exit(1);
        }
        /* Write qcow2 data blocks */
@@ -1088,7 +1208,8 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
                        retval = io_channel_read_blk64(fs->io, blk, 1, buf);
                        if (retval) {
                                com_err(program_name, retval,
-                                       "error reading block %llu", blk);
+                                       _("error reading block %llu"),
+                                       (unsigned long long) blk);
                                continue;
                        }
                        if (scramble_block_map &&
@@ -1100,8 +1221,7 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
                        if (update_refcount(fd, img, offset, offset)) {
                                /* Make space for another refcount block */
                                offset += img->cluster_size;
-                               if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
-                                       lseek_error_and_exit(errno);
+                               seek_set(fd, offset);
                                /*
                                 * We have created the new refcount block, this
                                 * means that we need to refcount it as well.
@@ -1111,14 +1231,15 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
                                 * block should not be created!
                                 */
                                if (update_refcount(fd, img, offset, offset)) {
-                                       fprintf(stderr, "Programming error: "
-                                               "multiple sequential refcount "
-                                               "blocks created!\n");
+                                       fprintf(stderr, "%s",
+                                               _("Programming error: multiple "
+                                                 "sequential refcount blocks "
+                                                 "created!\n"));
                                        exit(1);
                                }
                        }
 
-                       generic_write(fd, buf, fs->blocksize, 0);
+                       generic_write(fd, buf, fs->blocksize, blk);
 
                        if (add_l2_item(img, blk, offset,
                                        offset + img->cluster_size)) {
@@ -1128,36 +1249,35 @@ static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
                                        offset += img->cluster_size;
                                        if (update_refcount(fd, img, offset,
                                                            offset)) {
-                                               fprintf(stderr,
-                       "Programming error: multiple sequential refcount "
-                       "blocks created!\n");
+                                               fprintf(stderr, "%s",
+                       _("Programming error: multiple sequential refcount "
+                         "blocks created!\n"));
                                                exit(1);
                                        }
                                }
                                offset += img->cluster_size;
-                               if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
-                                       lseek_error_and_exit(errno);
+                               seek_set(fd, offset);
                                continue;
                        }
 
                        offset += img->cluster_size;
                }
        }
-       update_refcount(fd, img, offset, offset);
+       (void) update_refcount(fd, img, offset, offset);
        flush_l2_cache(img);
        sync_refcount(fd, img);
 
        /* Write l1_table*/
-       if (ext2fs_llseek(fd, img->l1_offset, SEEK_SET) < 0)
-               lseek_error_and_exit(errno);
+       seek_set(fd, img->l1_offset);
        size = img->l1_size * sizeof(__u64);
-       generic_write(fd, (char *)img->l1_table, size, 0);
+       generic_write(fd, (char *)img->l1_table, size, NO_BLK);
 
        ext2fs_free_mem(&buf);
        free_qcow2_image(img);
 }
 
-static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
+static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags,
+                                blk64_t superblock)
 {
        struct process_block_struct     pb;
        struct ext2_inode               inode;
@@ -1167,10 +1287,11 @@ static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
        char *                          block_buf;
 
        meta_blocks_count = 0;
-       retval = ext2fs_allocate_block_bitmap(fs, "in-use block map",
+       retval = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
                                              &meta_block_map);
        if (retval) {
-               com_err(program_name, retval, "while allocating block bitmap");
+               com_err(program_name, retval, "%s",
+                       _("while allocating block bitmap"));
                exit(1);
        }
 
@@ -1178,19 +1299,35 @@ static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
                retval = ext2fs_allocate_block_bitmap(fs, "scramble block map",
                                                      &scramble_block_map);
                if (retval) {
-                       com_err(program_name, retval,
-                               "while allocating scramble block bitmap");
+                       com_err(program_name, retval, "%s",
+                               _("while allocating scramble block bitmap"));
                        exit(1);
                }
        }
 
+       if (superblock) {
+               unsigned int j;
+
+               ext2fs_mark_block_bitmap2(meta_block_map, superblock);
+               meta_blocks_count++;
+
+               /*
+                * Mark the backup superblock descriptors
+                */
+               for (j = 0; j < fs->desc_blocks; j++) {
+                       ext2fs_mark_block_bitmap2(meta_block_map,
+                       ext2fs_descriptor_block_loc2(fs, superblock, j));
+               }
+               meta_blocks_count += fs->desc_blocks;
+       }
+
        mark_table_blocks(fs);
        if (show_progress)
-               printf("Scanning inodes...\n");
+               fprintf(stderr, "%s", _("Scanning inodes...\n"));
 
        retval = ext2fs_open_inode_scan(fs, 0, &scan);
        if (retval) {
-               com_err(program_name, retval,"%s",
+               com_err(program_name, retval, "%s",
                        _("while opening inode scan"));
                exit(1);
        }
@@ -1229,15 +1366,18 @@ static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
                pb.ino = ino;
                pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
                if (LINUX_S_ISDIR(inode.i_mode) ||
-                   (LINUX_S_ISLNK(inode.i_mode) &&
-                    ext2fs_inode_has_valid_blocks2(fs, &inode)) ||
-                   ino == fs->super->s_journal_inum) {
+                   LINUX_S_ISLNK(inode.i_mode) ||
+                   ino == fs->super->s_journal_inum ||
+                   ino == quota_type2inum(USRQUOTA, fs->super) ||
+                   ino == quota_type2inum(GRPQUOTA, fs->super) ||
+                   ino == quota_type2inum(PRJQUOTA, fs->super) ||
+                   ino == fs->super->s_orphan_file_inum) {
                        retval = ext2fs_block_iterate3(fs, ino,
                                        BLOCK_FLAG_READ_ONLY, block_buf,
                                        process_dir_block, &pb);
                        if (retval) {
                                com_err(program_name, retval,
-                                       "while iterating over inode %u",
+                                       _("while iterating over inode %u"),
                                        ino);
                                exit(1);
                        }
@@ -1251,7 +1391,7 @@ static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
                                       process_file_block, &pb);
                                if (retval) {
                                        com_err(program_name, retval,
-                                       "while iterating over inode %u", ino);
+                                       _("while iterating over inode %u"), ino);
                                        exit(1);
                                }
                        }
@@ -1262,7 +1402,7 @@ static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
        if (type & E2IMAGE_QCOW2)
                output_qcow2_meta_data_blocks(fs, fd);
        else
-               output_meta_data_blocks(fs, fd);
+               output_meta_data_blocks(fs, fd, flags);
 
        ext2fs_free_mem(&block_buf);
        ext2fs_close_inode_scan(scan);
@@ -1275,14 +1415,15 @@ static void install_image(char *device, char *image_fn, int type)
 {
        errcode_t retval;
        ext2_filsys fs;
-       int open_flag = EXT2_FLAG_IMAGE_FILE | EXT2_FLAG_64BITS;
+       int open_flag = EXT2_FLAG_IMAGE_FILE | EXT2_FLAG_64BITS |
+                       EXT2_FLAG_IGNORE_CSUM_ERRORS;
        int fd = 0;
        io_manager      io_ptr;
        io_channel      io;
 
        if (type) {
-               com_err(program_name, 0, "Raw and qcow2 images cannot"
-                       "be installed");
+               com_err(program_name, 0, "%s",
+                       _("Raw and qcow2 images cannot be installed"));
                exit(1);
        }
 
@@ -1297,14 +1438,14 @@ static void install_image(char *device, char *image_fn, int type)
        retval = ext2fs_open (image_fn, open_flag, 0, 0,
                              io_ptr, &fs);
         if (retval) {
-               com_err (program_name, retval, _("while trying to open %s"),
-                        image_fn);
+               com_err(program_name, retval, _("while trying to open %s"),
+                       image_fn);
                exit(1);
        }
 
        retval = ext2fs_read_bitmaps (fs);
        if (retval) {
-               com_err(program_name, retval, "error reading bitmaps");
+               com_err(program_name, retval, "%s", _("error reading bitmaps"));
                exit(1);
        }
 
@@ -1316,25 +1457,23 @@ static void install_image(char *device, char *image_fn, int type)
 
        retval = io_ptr->open(device, IO_FLAG_RW, &io);
        if (retval) {
-               com_err(device, 0, "while opening device file");
+               com_err(device, 0, "%s", _("while opening device file"));
                exit(1);
        }
 
        ext2fs_rewrite_to_io(fs, io);
 
-       if (ext2fs_llseek(fd, fs->image_header->offset_inode, SEEK_SET) < 0) {
-               perror("ext2fs_llseek");
-               exit(1);
-       }
+       seek_set(fd, ext2fs_le32_to_cpu(fs->image_header->offset_inode));
 
        retval = ext2fs_image_inode_read(fs, fd, 0);
        if (retval) {
-               com_err(image_fn, 0, "while restoring the image table");
+               com_err(image_fn, 0, "%s",
+                       _("while restoring the image table"));
                exit(1);
        }
 
        close(fd);
-       ext2fs_close (fs);
+       ext2fs_close_free(&fs);
 }
 
 static struct ext2_qcow2_hdr *check_qcow2_image(int *fd, char *name)
@@ -1352,9 +1491,10 @@ int main (int argc, char ** argv)
        int c;
        errcode_t retval;
        ext2_filsys fs;
-       char *image_fn;
+       char *image_fn, offset_opt[64];
        struct ext2_qcow2_hdr *header = NULL;
-       int open_flag = EXT2_FLAG_64BITS;
+       int open_flag = EXT2_FLAG_64BITS | EXT2_FLAG_THREADS |
+               EXT2_FLAG_IGNORE_CSUM_ERRORS;
        int img_type = 0;
        int flags = 0;
        int mount_flags = 0;
@@ -1362,7 +1502,10 @@ int main (int argc, char ** argv)
        int fd = 0;
        int ret = 0;
        int ignore_rw_mount = 0;
+       int check = 0;
        struct stat st;
+       blk64_t superblock = 0;
+       int blocksize = 0;
 
 #ifdef ENABLE_NLS
        setlocale(LC_MESSAGES, "");
@@ -1375,9 +1518,17 @@ int main (int argc, char ** argv)
                 E2FSPROGS_DATE);
        if (argc && *argv)
                program_name = *argv;
+       else
+               usage();
        add_error_table(&et_ext2_error_table);
-       while ((c = getopt(argc, argv, "rsIQafo:O:p")) != EOF)
+       while ((c = getopt(argc, argv, "b:B:nrsIQafo:O:pc")) != EOF)
                switch (c) {
+               case 'b':
+                       superblock = strtoull(optarg, NULL, 0);
+                       break;
+               case 'B':
+                       blocksize = strtoul(optarg, NULL, 0);
+                       break;
                case 'I':
                        flags |= E2IMAGE_INSTALL_FLAG;
                        break;
@@ -1400,6 +1551,9 @@ int main (int argc, char ** argv)
                case 'f':
                        ignore_rw_mount = 1;
                        break;
+               case 'n':
+                       nop_flag = 1;
+                       break;
                case 'o':
                        source_offset = strtoull(optarg, NULL, 0);
                        break;
@@ -1409,6 +1563,9 @@ int main (int argc, char ** argv)
                case 'p':
                        show_progress = 1;
                        break;
+               case 'c':
+                       check = 1;
+                       break;
                default:
                        usage();
                }
@@ -1419,23 +1576,28 @@ int main (int argc, char ** argv)
                usage();
 
        if (all_data && !img_type) {
-               com_err(program_name, 0, "-a option can only be used "
-                                        "with raw or QCOW2 images.");
+               com_err(program_name, 0, "%s", _("-a option can only be used "
+                                                "with raw or QCOW2 images."));
+               exit(1);
+       }
+       if (superblock && !img_type) {
+               com_err(program_name, 0, "%s", _("-b option can only be used "
+                                                "with raw or QCOW2 images."));
                exit(1);
        }
        if ((source_offset || dest_offset) && img_type != E2IMAGE_RAW) {
-               com_err(program_name, 0,
-                       "Offsets are only allowed with raw images.");
+               com_err(program_name, 0, "%s",
+                       _("Offsets are only allowed with raw images."));
                exit(1);
        }
        if (move_mode && img_type != E2IMAGE_RAW) {
-               com_err(program_name, 0,
-                       "Move mode is only allowed with raw images.");
+               com_err(program_name, 0, "%s",
+                       _("Move mode is only allowed with raw images."));
                exit(1);
        }
        if (move_mode && !all_data) {
-               com_err(program_name, 0,
-                       "Move mode requires all data mode.");
+               com_err(program_name, 0, "%s",
+                       _("Move mode requires all data mode."));
                exit(1);
        }
        device_name = argv[optind];
@@ -1445,18 +1607,18 @@ int main (int argc, char ** argv)
 
        retval = ext2fs_check_if_mounted(device_name, &mount_flags);
        if (retval) {
-               com_err(program_name, retval, "checking if mounted");
+               com_err(program_name, retval, "%s", _("checking if mounted"));
                exit(1);
        }
 
        if (img_type && !ignore_rw_mount &&
            (mount_flags & EXT2_MF_MOUNTED) &&
           !(mount_flags & EXT2_MF_READONLY)) {
-               fprintf(stderr, "\nRunning e2image on a R/W mounted "
+               fprintf(stderr, "%s", _("\nRunning e2image on a R/W mounted "
                        "filesystem can result in an\n"
                        "inconsistent image which will not be useful "
                        "for debugging purposes.\n"
-                       "Use -f option if you really want to do that.\n");
+                       "Use -f option if you really want to do that.\n"));
                exit(1);
        }
 
@@ -1472,15 +1634,15 @@ int main (int argc, char ** argv)
                        goto skip_device;
                }
        }
-       char *options;
-       asprintf (&options, "offset=%llu", source_offset);
-       retval = ext2fs_open2 (device_name, options, open_flag, 0, 0,
-                              unix_io_manager, &fs);
-       free (options);
+       sprintf(offset_opt, "offset=%llu", (unsigned long long) source_offset);
+       retval = ext2fs_open2(device_name, offset_opt, open_flag,
+                             superblock, blocksize, unix_io_manager, &fs);
         if (retval) {
                com_err (program_name, retval, _("while trying to open %s"),
                         device_name);
                fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
+               if (retval == EXT2_ET_BAD_MAGIC)
+                       check_plausibility(device_name, CHECK_FS_EXIST, NULL);
                exit(1);
        }
 
@@ -1488,10 +1650,12 @@ skip_device:
        if (strcmp(image_fn, "-") == 0)
                fd = 1;
        else {
-               int o_flags = O_CREAT|O_WRONLY;
+               int o_flags = O_CREAT|O_RDWR;
 
                if (img_type != E2IMAGE_RAW)
                        o_flags |= O_TRUNC;
+               if (access(image_fn, F_OK) != 0)
+                       flags |= E2IMAGE_CHECK_ZERO_FLAG;
                fd = ext2fs_open_file(image_fn, o_flags, 0600);
                if (fd < 0) {
                        com_err(program_name, errno,
@@ -1500,48 +1664,77 @@ skip_device:
                }
        }
        if (dest_offset)
-               if (ext2fs_llseek (fd, dest_offset, SEEK_SET) < 0) {
-                       perror("ext2fs_llseek");
-                       exit(1);
-               }
+               seek_set(fd, dest_offset);
 
        if ((img_type & E2IMAGE_QCOW2) && (fd == 1)) {
-               com_err(program_name, 0, "QCOW2 image can not be written to "
-                                        "the stdout!\n");
+               com_err(program_name, 0, "%s",
+                       _("QCOW2 image can not be written to the stdout!\n"));
                exit(1);
        }
        if (fd != 1) {
                if (fstat(fd, &st)) {
-                       com_err(program_name, 0, "Can not stat output\n");
+                       com_err(program_name, 0, "%s",
+                               _("Can not stat output\n"));
                        exit(1);
                }
-               if (S_ISBLK(st.st_mode))
+               if (ext2fsP_is_disk_device(st.st_mode))
                        output_is_blk = 1;
        }
        if (flags & E2IMAGE_IS_QCOW2_FLAG) {
                ret = qcow2_write_raw_image(qcow2_fd, fd, header);
                if (ret) {
                        if (ret == -QCOW_COMPRESSED)
-                               fprintf(stderr, "Image (%s) is compressed\n",
+                               fprintf(stderr, _("Image (%s) is compressed\n"),
+                                       image_fn);
+                       else if (ret == -QCOW_ENCRYPTED)
+                               fprintf(stderr, _("Image (%s) is encrypted\n"),
                                        image_fn);
-                       if (ret == -QCOW_ENCRYPTED)
-                               fprintf(stderr, "Image (%s) is encrypted\n",
+                       else if (ret == -QCOW_CORRUPTED)
+                               fprintf(stderr, _("Image (%s) is corrupted\n"),
                                        image_fn);
-                       com_err(program_name, ret,
-                               _("while trying to convert qcow2 image"
-                               " (%s) into raw image (%s)"),
-                               device_name, image_fn);
+                       else
+                               com_err(program_name, ret,
+                                       _("while trying to convert qcow2 image"
+                                         " (%s) into raw image (%s)"),
+                                       image_fn, device_name);
+                       ret = 1;
                }
                goto out;
        }
 
-
+       if (check) {
+               if (img_type != E2IMAGE_RAW) {
+                       fprintf(stderr, "%s", _("The -c option only supported "
+                                               "in raw mode\n"));
+                       exit(1);
+               }
+               if (fd == 1) {
+                       fprintf(stderr, "%s", _("The -c option not supported "
+                                               "when writing to stdout\n"));
+                       exit(1);
+               }
+               retval = ext2fs_get_mem(fs->blocksize, &check_buf);
+               if (retval) {
+                       com_err(program_name, retval, "%s",
+                               _("while allocating check_buf"));
+                       exit(1);
+               }
+       }
+       if (show_progress && (img_type != E2IMAGE_RAW)) {
+               fprintf(stderr, "%s",
+                       _("The -p option only supported in raw mode\n"));
+               exit(1);
+       }
        if (img_type)
-               write_raw_image_file(fs, fd, img_type, flags);
+               write_raw_image_file(fs, fd, img_type, flags, superblock);
        else
                write_image_file(fs, fd);
 
-       ext2fs_close (fs);
+       ext2fs_close_free(&fs);
+       if (check)
+               printf(_("%d blocks already contained the data to be copied\n"),
+                      skipped_blocks);
+
 out:
        if (header)
                free(header);