static char output_is_blk;
/* writing to blk device: don't skip zeroed blocks */
blk64_t source_offset, dest_offset;
+char move_mode;
static void lseek_error_and_exit(int errnum)
{
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);
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval) {
com_err(program_name, retval, "while allocating buffer");
exit(1);
}
- for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) {
+ /* 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;
+ }
+more_blocks:
+ if (distance)
+ ext2fs_llseek (fd, (start * fs->blocksize) + dest_offset, SEEK_SET);
+ for (blk = start; blk < end; blk++) {
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 (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;
+ }
#ifdef HAVE_FTRUNCATE64
if (sparse) {
- ext2_loff_t offset = ext2fs_llseek(fd, sparse, SEEK_CUR);
+ 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);
if (offset < 0)
lseek_error_and_exit(errno);
write_block(fd, zero_buf, -1, 1, -1);
}
#else
- if (sparse)
+ if (sparse && !distance)
write_block(fd, zero_buf, sparse-1, 1, -1);
#endif
ext2fs_free_mem(&zero_buf);
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) {
"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) {
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_WRONLY;
+
+ if (img_type != E2IMAGE_RAW)
+ o_flags |= O_TRUNC;
+ 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);
}
}