#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
+#include <signal.h>
#include "ext2fs/ext2_fs.h"
#include "ext2fs/ext2fs.h"
#include "nls-enable.h"
#define QCOW_OFLAG_COPIED (1LL << 63)
-
-
-const char * program_name = "e2image";
-char * device_name = NULL;
-char all_data;
-char output_is_blk;
+#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 */
+static blk64_t source_offset, dest_offset;
+static char move_mode;
+static char show_progress;
+static char *check_buf;
+static int skipped_blocks;
-static void lseek_error_and_exit(int errnum)
-{
- fprintf(stderr, "seek: %s\n", error_message(errnum));
- exit(1);
-}
-
-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)
static void usage(void)
{
- fprintf(stderr, _("Usage: %s [-rsIQaf] device image_file\n"),
+ fprintf(stderr, _("Usage: %s [-acfnprsIQ] [-o src_offset] "
+ "[-O dest_offset] \\\n\tdevice image_file\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;
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,
+ _("while allocating buffer"));
exit(1);
}
}
-
+ if (nop_flag) {
+ printf(_("Writing block %llu\n"), (unsigned long long) block);
+ seek_relative(fd, blocksize);
+ return;
+ }
count = write(fd, buf, blocksize);
if (count != blocksize) {
if (count == -1)
err = 0;
if (block)
- com_err(program_name, err, "error writing block %llu",
- block);
+ com_err(program_name, err,
+ _("error writing block %llu"), block);
else
- com_err(program_name, err, "error in write()");
+ com_err(program_name, err, _("error in write()"));
exit(1);
}
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);
}
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 = seek_relative(fd, 0);
retval = ext2fs_image_super_write(fs, fd, 0);
if (retval) {
com_err(program_name, retval, "%s",
exit(1);
}
- hdr.offset_inode = ext2fs_llseek(fd, 0, SEEK_CUR);
+ hdr.offset_inode = seek_relative(fd, 0);
retval = ext2fs_image_inode_write(fs, fd,
(fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
if (retval) {
exit(1);
}
- hdr.offset_blockmap = ext2fs_llseek(fd, 0, SEEK_CUR);
+ hdr.offset_blockmap = seek_relative(fd, 0);
retval = ext2fs_image_bitmap_write(fs, fd, 0);
if (retval) {
com_err(program_name, retval, "%s",
exit(1);
}
- hdr.offset_inodemap = ext2fs_llseek(fd, 0, SEEK_CUR);
+ hdr.offset_inodemap = seek_relative(fd, 0);
retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP);
if (retval) {
com_err(program_name, retval, "%s",
/*
* These set of functions are used to write a RAW image file.
*/
-ext2fs_block_bitmap meta_block_map;
-ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */
-blk64_t meta_blocks_count;
+static ext2fs_block_bitmap meta_block_map;
+static ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */
+static blk64_t meta_blocks_count;
struct process_block_struct {
ext2_ino_t ino;
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);
-}
-
-int name_id[256];
+static int name_id[256];
#define EXT4_MAX_REC_LEN ((1<<16)-1)
#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);
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;
}
}
}
-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);
+}
+
+static void output_meta_data_blocks(ext2_filsys fs, int fd, int flags)
{
errcode_t retval;
blk64_t blk;
char *buf, *zero_buf;
int sparse = 0;
+ blk64_t start = 0;
+ blk64_t distance = 0;
+ blk64_t end = ext2fs_blocks_count(fs->super);
+ time_t last_update = 0;
+ time_t start_time = 0;
+ blk64_t total_written = 0;
+ 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, _("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, _("while allocating buffer"));
exit(1);
}
- for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) {
+ 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);
+ last_update = time(NULL);
+ start_time = time(NULL);
+ }
+ /* when doing an in place move to the right, you can't start
+ at the beginning or you will overwrite data, so instead
+ divide the fs up into distance size chunks and write them
+ in reverse. */
+ if (move_mode && dest_offset > source_offset) {
+ distance = (dest_offset - source_offset) / fs->blocksize;
+ 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)
+ 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)
+ printf ("\r");
+ printf(_("Stopping now will destroy the filesystem, "
+ "interrupt again if you are sure\n"));
+ 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);
+ }
+
+ 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));
+ duration = time(NULL) - start_time;
+ if (duration > 5) {
+ 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);
+ }
+ fflush (stdout);
+ }
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"), 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);
+ 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;
}
}
}
+ if (distance && start) {
+ if (start < distance) {
+ end = start;
+ start = 0;
+ } else {
+ end -= distance;
+ start -= distance;
+ if (end < distance) {
+ /* past overlap, do rest in one go */
+ end = start;
+ start = 0;
+ }
+ }
+ sparse = 0;
+ goto more_blocks;
+ }
+ signal (SIGINT, SIG_DFL);
+ if (show_progress) {
+ time_t duration = time(NULL) - start_time;
+ char buff[30];
+ while (bscount--)
+ printf("\b");
+ 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);
+
+ }
#ifdef HAVE_FTRUNCATE64
if (sparse) {
- ext2_loff_t offset = ext2fs_llseek(fd, sparse, SEEK_CUR);
+ ext2_loff_t offset;
+ if (distance)
+ 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)
- 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);
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, _("while allocating l1 table"));
exit(1);
}
return;
alloc_err:
- com_err(program_name, ret, "while allocating l2 cache");
+ com_err(program_name, ret, _("while allocating l2 cache"));
exit(1);
}
}
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, _("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;
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);
}
/**
*/
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] =
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;
}
retval = ext2fs_get_mem(sizeof(struct ext2_qcow2_image), &img);
if (retval) {
com_err(program_name, retval,
- "while allocating ext2_qcow2_image");
+ _("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");
+ _("while initializing ext2_qcow2_image"));
exit(1);
}
header_size = align_offset(sizeof(struct ext2_qcow2_hdr),
/* 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)) {
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, _("while allocating buffer"));
exit(1);
}
/* Write qcow2 data blocks */
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"), blk);
continue;
}
if (scramble_block_map &&
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.
* block should not be created!
*/
if (update_refcount(fd, img, offset, offset)) {
- fprintf(stderr, "Programming error: "
+ fprintf(stderr, _("Programming error: "
"multiple sequential refcount "
- "blocks created!\n");
+ "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)) {
if (update_refcount(fd, img, offset,
offset)) {
fprintf(stderr,
- "Programming error: multiple sequential refcount "
- "blocks created!\n");
+ _("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;
}
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);
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,
+ _("while allocating block bitmap"));
exit(1);
}
&scramble_block_map);
if (retval) {
com_err(program_name, retval,
- "while allocating scramble block bitmap");
+ _("while allocating scramble block bitmap"));
exit(1);
}
}
mark_table_blocks(fs);
+ if (show_progress)
+ printf(_("Scanning inodes...\n"));
retval = ext2fs_open_inode_scan(fs, 0, &scan);
if (retval) {
process_dir_block, &pb);
if (retval) {
com_err(program_name, retval,
- "while iterating over inode %u",
+ _("while iterating over inode %u"),
ino);
exit(1);
}
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);
}
}
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);
io_channel io;
if (type) {
- com_err(program_name, 0, "Raw and qcow2 images cannot"
- "be installed");
+ com_err(program_name, 0, _("Raw and qcow2 images cannot"
+ "be installed"));
exit(1);
}
retval = ext2fs_read_bitmaps (fs);
if (retval) {
- com_err(program_name, retval, "error reading bitmaps");
+ com_err(program_name, retval, _("error reading bitmaps"));
exit(1);
}
retval = io_ptr->open(device, IO_FLAG_RW, &io);
if (retval) {
- com_err(device, 0, "while opening device file");
+ com_err(device, 0, _("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, fs->image_header->offset_inode);
retval = ext2fs_image_inode_read(fs, fd, 0);
if (retval) {
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 img_type = 0;
int fd = 0;
int ret = 0;
int ignore_rw_mount = 0;
+ int check = 0;
struct stat st;
#ifdef ENABLE_NLS
if (argc && *argv)
program_name = *argv;
add_error_table(&et_ext2_error_table);
- while ((c = getopt(argc, argv, "rsIQaf")) != EOF)
+ while ((c = getopt(argc, argv, "nrsIQafo:O:pc")) != EOF)
switch (c) {
case 'I':
flags |= E2IMAGE_INSTALL_FLAG;
case 'f':
ignore_rw_mount = 1;
break;
+ case 'n':
+ nop_flag = 1;
+ break;
+ case 'o':
+ source_offset = strtoull(optarg, NULL, 0);
+ break;
+ case 'O':
+ dest_offset = strtoull(optarg, NULL, 0);
+ break;
+ case 'p':
+ show_progress = 1;
+ break;
+ case 'c':
+ check = 1;
+ break;
default:
usage();
}
- if (optind != argc - 2 )
+ if (optind == argc - 1 &&
+ (source_offset || dest_offset))
+ move_mode = 1;
+ else if (optind != argc - 2 )
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, _("-a 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."));
+ exit(1);
+ }
+ if (move_mode && img_type != E2IMAGE_RAW) {
+ com_err(program_name, 0,
+ _("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."));
exit(1);
}
-
device_name = argv[optind];
- image_fn = argv[optind+1];
+ if (move_mode)
+ image_fn = device_name;
+ else image_fn = argv[optind+1];
retval = ext2fs_check_if_mounted(device_name, &mount_flags);
if (retval) {
- com_err(program_name, retval, "checking if mounted");
+ com_err(program_name, retval, _("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, _("\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);
}
goto skip_device;
}
}
-
- retval = ext2fs_open (device_name, open_flag, 0, 0,
+ sprintf(offset_opt, "offset=%llu", source_offset);
+ retval = ext2fs_open2(device_name, offset_opt, open_flag, 0, 0,
unix_io_manager, &fs);
if (retval) {
com_err (program_name, retval, _("while trying to open %s"),
if (strcmp(image_fn, "-") == 0)
fd = 1;
else {
- fd = ext2fs_open_file(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
+ 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,
- _("while trying to open %s"), argv[optind+1]);
+ _("while trying to open %s"), image_fn);
exit(1);
}
}
+ if (dest_offset)
+ 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, _("QCOW2 image can not be written to "
+ "the stdout!\n"));
exit(1);
}
if (fd != 1) {
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);
if (ret == -QCOW_ENCRYPTED)
- fprintf(stderr, "Image (%s) is encrypted\n",
+ fprintf(stderr, _("Image (%s) is encrypted\n"),
image_fn);
com_err(program_name, ret,
_("while trying to convert qcow2 image"
- " (%s) into raw image (%s)"),
+ " (%s) into raw image (%s)"),
device_name, image_fn);
}
goto out;
}
+ if (check) {
+ if (img_type != E2IMAGE_RAW) {
+ fprintf(stderr, _("The -c option only supported "
+ "in raw mode\n"));
+ exit(1);
+ }
+ if (fd == 1) {
+ fprintf(stderr, _("The -c option is not supported "
+ "when writing to stdout\n"));
+ exit(1);
+ }
+ retval = ext2fs_get_mem(fs->blocksize, &check_buf);
+ if (retval) {
+ com_err(program_name, retval,
+ _("while allocating check_buf"));
+ exit(1);
+ }
+ }
if (img_type)
write_raw_image_file(fs, fd, img_type, flags);
write_image_file(fs, fd);
ext2fs_close (fs);
+ if (check)
+ printf(_("%d blocks already contained the data to be copied.\n"),
+ skipped_blocks);
+
out:
if (header)
free(header);