e2image.c revision 0155e770218961f1ab0b39851e1fb4e832ff713d
1/* 2 * e2image.c --- Program which writes an image file backing up 3 * critical metadata for the filesystem. 4 * 5 * Copyright 2000, 2001 by Theodore Ts'o. 6 * 7 * %Begin-Header% 8 * This file may be redistributed under the terms of the GNU Public 9 * License. 10 * %End-Header% 11 */ 12 13#define _LARGEFILE_SOURCE 14#define _LARGEFILE64_SOURCE 15 16#include "config.h" 17#include <fcntl.h> 18#include <grp.h> 19#ifdef HAVE_GETOPT_H 20#include <getopt.h> 21#else 22extern char *optarg; 23extern int optind; 24#endif 25#include <pwd.h> 26#include <stdio.h> 27#ifdef HAVE_STDLIB_H 28#include <stdlib.h> 29#endif 30#include <string.h> 31#include <time.h> 32#include <unistd.h> 33#include <fcntl.h> 34#include <errno.h> 35#include <sys/stat.h> 36#include <sys/types.h> 37#include <assert.h> 38#include <signal.h> 39 40#include "ext2fs/ext2_fs.h" 41#include "ext2fs/ext2fs.h" 42#include "et/com_err.h" 43#include "uuid/uuid.h" 44#include "e2p/e2p.h" 45#include "ext2fs/e2image.h" 46#include "ext2fs/qcow2.h" 47 48#include "../version.h" 49#include "nls-enable.h" 50 51#define QCOW_OFLAG_COPIED (1LL << 63) 52#define NO_BLK ((blk64_t) -1) 53 54/* Image types */ 55#define E2IMAGE_RAW 1 56#define E2IMAGE_QCOW2 2 57 58/* Image flags */ 59#define E2IMAGE_INSTALL_FLAG 1 60#define E2IMAGE_SCRAMBLE_FLAG 2 61#define E2IMAGE_IS_QCOW2_FLAG 4 62#define E2IMAGE_CHECK_ZERO_FLAG 8 63 64static const char * program_name = "e2image"; 65static char * device_name = NULL; 66static char all_data; 67static char output_is_blk; 68static char nop_flag; 69/* writing to blk device: don't skip zeroed blocks */ 70static blk64_t source_offset, dest_offset; 71static char move_mode; 72static char show_progress; 73static char *check_buf; 74static int skipped_blocks; 75 76static blk64_t align_offset(blk64_t offset, unsigned int n) 77{ 78 return (offset + n - 1) & ~((blk64_t) n - 1); 79} 80 81static int get_bits_from_size(size_t size) 82{ 83 int res = 0; 84 85 if (size == 0) 86 return -1; 87 88 while (size != 1) { 89 /* Not a power of two */ 90 if (size & 1) 91 return -1; 92 93 size >>= 1; 94 res++; 95 } 96 return res; 97} 98 99static void usage(void) 100{ 101 fprintf(stderr, _("Usage: %s [-acfnprsIQ] [-o src_offset] " 102 "[-O dest_offset] \\\n\tdevice image_file\n"), 103 program_name); 104 exit (1); 105} 106 107static ext2_loff_t seek_relative(int fd, int offset) 108{ 109 ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_CUR); 110 if (ret < 0) { 111 perror("seek_relative"); 112 exit(1); 113 } 114 return ret; 115} 116 117static ext2_loff_t seek_set(int fd, ext2_loff_t offset) 118{ 119 ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_SET); 120 if (ret < 0) { 121 perror("seek_set"); 122 exit(1); 123 } 124 return ret; 125} 126 127/* 128 * Returns true if the block we are about to write is identical to 129 * what is already on the disk. 130 */ 131static int check_block(int fd, void *buf, void *cbuf, int blocksize) 132{ 133 char *cp = cbuf; 134 int count = blocksize, ret; 135 136 if (cbuf == NULL) 137 return 0; 138 139 while (count > 0) { 140 ret = read(fd, cp, count); 141 if (ret < 0) { 142 perror("check_block"); 143 exit(1); 144 } 145 count -= ret; 146 cp += ret; 147 } 148 ret = memcmp(buf, cbuf, blocksize); 149 seek_relative(fd, -blocksize); 150 return (ret == 0) ? 1 : 0; 151} 152 153static void generic_write(int fd, void *buf, int blocksize, blk64_t block) 154{ 155 int count, free_buf = 0; 156 errcode_t err; 157 158 if (!blocksize) 159 return; 160 161 if (!buf) { 162 free_buf = 1; 163 err = ext2fs_get_arrayzero(1, blocksize, &buf); 164 if (err) { 165 com_err(program_name, err, "while allocating buffer"); 166 exit(1); 167 } 168 } 169 if (nop_flag) { 170 printf("Writing block %llu\n", (unsigned long long) block); 171 seek_relative(fd, blocksize); 172 return; 173 } 174 count = write(fd, buf, blocksize); 175 if (count != blocksize) { 176 if (count == -1) 177 err = errno; 178 else 179 err = 0; 180 181 if (block) 182 com_err(program_name, err, "error writing block %llu", 183 block); 184 else 185 com_err(program_name, err, "error in write()"); 186 187 exit(1); 188 } 189 if (free_buf) 190 ext2fs_free_mem(&buf); 191} 192 193static void write_header(int fd, void *hdr, int hdr_size, int wrt_size) 194{ 195 char *header_buf; 196 int ret; 197 198 /* Sanity check */ 199 if (hdr_size > wrt_size) { 200 fprintf(stderr, "%s", 201 _("Error: header size is bigger than wrt_size\n")); 202 } 203 204 ret = ext2fs_get_mem(wrt_size, &header_buf); 205 if (ret) { 206 fputs(_("Couldn't allocate header buffer\n"), stderr); 207 exit(1); 208 } 209 210 seek_set(fd, 0); 211 memset(header_buf, 0, wrt_size); 212 213 if (hdr) 214 memcpy(header_buf, hdr, hdr_size); 215 216 generic_write(fd, header_buf, wrt_size, NO_BLK); 217 218 ext2fs_free_mem(&header_buf); 219} 220 221static void write_image_file(ext2_filsys fs, int fd) 222{ 223 struct ext2_image_hdr hdr; 224 struct stat st; 225 errcode_t retval; 226 227 write_header(fd, NULL, sizeof(struct ext2_image_hdr), fs->blocksize); 228 memset(&hdr, 0, sizeof(struct ext2_image_hdr)); 229 230 hdr.offset_super = seek_relative(fd, 0); 231 retval = ext2fs_image_super_write(fs, fd, 0); 232 if (retval) { 233 com_err(program_name, retval, "%s", 234 _("while writing superblock")); 235 exit(1); 236 } 237 238 hdr.offset_inode = seek_relative(fd, 0); 239 retval = ext2fs_image_inode_write(fs, fd, 240 (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0); 241 if (retval) { 242 com_err(program_name, retval, "%s", 243 _("while writing inode table")); 244 exit(1); 245 } 246 247 hdr.offset_blockmap = seek_relative(fd, 0); 248 retval = ext2fs_image_bitmap_write(fs, fd, 0); 249 if (retval) { 250 com_err(program_name, retval, "%s", 251 _("while writing block bitmap")); 252 exit(1); 253 } 254 255 hdr.offset_inodemap = seek_relative(fd, 0); 256 retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP); 257 if (retval) { 258 com_err(program_name, retval, "%s", 259 _("while writing inode bitmap")); 260 exit(1); 261 } 262 263 hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE; 264 strcpy(hdr.magic_descriptor, "Ext2 Image 1.0"); 265 gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname)); 266 strncpy(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)-1); 267 hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0; 268 hdr.fs_blocksize = fs->blocksize; 269 270 if (stat(device_name, &st) == 0) 271 hdr.fs_device = st.st_rdev; 272 273 if (fstat(fd, &st) == 0) { 274 hdr.image_device = st.st_dev; 275 hdr.image_inode = st.st_ino; 276 } 277 memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid)); 278 279 hdr.image_time = time(0); 280 write_header(fd, &hdr, sizeof(struct ext2_image_hdr), fs->blocksize); 281} 282 283/* 284 * These set of functions are used to write a RAW image file. 285 */ 286static ext2fs_block_bitmap meta_block_map; 287static ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */ 288static blk64_t meta_blocks_count; 289 290struct process_block_struct { 291 ext2_ino_t ino; 292 int is_dir; 293}; 294 295/* 296 * These subroutines short circuits ext2fs_get_blocks and 297 * ext2fs_check_directory; we use them since we already have the inode 298 * structure, so there's no point in letting the ext2fs library read 299 * the inode again. 300 */ 301static ino_t stashed_ino = 0; 302static struct ext2_inode *stashed_inode; 303 304static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)), 305 ext2_ino_t ino, 306 blk_t *blocks) 307{ 308 int i; 309 310 if ((ino != stashed_ino) || !stashed_inode) 311 return EXT2_ET_CALLBACK_NOTHANDLED; 312 313 for (i=0; i < EXT2_N_BLOCKS; i++) 314 blocks[i] = stashed_inode->i_block[i]; 315 return 0; 316} 317 318static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)), 319 ext2_ino_t ino) 320{ 321 if ((ino != stashed_ino) || !stashed_inode) 322 return EXT2_ET_CALLBACK_NOTHANDLED; 323 324 if (!LINUX_S_ISDIR(stashed_inode->i_mode)) 325 return EXT2_ET_NO_DIRECTORY; 326 return 0; 327} 328 329static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)), 330 ext2_ino_t ino, 331 struct ext2_inode *inode) 332{ 333 if ((ino != stashed_ino) || !stashed_inode) 334 return EXT2_ET_CALLBACK_NOTHANDLED; 335 *inode = *stashed_inode; 336 return 0; 337} 338 339static void use_inode_shortcuts(ext2_filsys fs, int use_shortcuts) 340{ 341 if (use_shortcuts) { 342 fs->get_blocks = meta_get_blocks; 343 fs->check_directory = meta_check_directory; 344 fs->read_inode = meta_read_inode; 345 stashed_ino = 0; 346 } else { 347 fs->get_blocks = 0; 348 fs->check_directory = 0; 349 fs->read_inode = 0; 350 } 351} 352 353static int process_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)), 354 blk64_t *block_nr, 355 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 356 blk64_t ref_block EXT2FS_ATTR((unused)), 357 int ref_offset EXT2FS_ATTR((unused)), 358 void *priv_data EXT2FS_ATTR((unused))) 359{ 360 struct process_block_struct *p; 361 362 p = (struct process_block_struct *) priv_data; 363 364 ext2fs_mark_block_bitmap2(meta_block_map, *block_nr); 365 meta_blocks_count++; 366 if (scramble_block_map && p->is_dir && blockcnt >= 0) 367 ext2fs_mark_block_bitmap2(scramble_block_map, *block_nr); 368 return 0; 369} 370 371static int process_file_block(ext2_filsys fs EXT2FS_ATTR((unused)), 372 blk64_t *block_nr, 373 e2_blkcnt_t blockcnt, 374 blk64_t ref_block EXT2FS_ATTR((unused)), 375 int ref_offset EXT2FS_ATTR((unused)), 376 void *priv_data EXT2FS_ATTR((unused))) 377{ 378 if (blockcnt < 0 || all_data) { 379 ext2fs_mark_block_bitmap2(meta_block_map, *block_nr); 380 meta_blocks_count++; 381 } 382 return 0; 383} 384 385static void mark_table_blocks(ext2_filsys fs) 386{ 387 blk64_t first_block, b; 388 unsigned int i,j; 389 390 first_block = fs->super->s_first_data_block; 391 /* 392 * Mark primary superblock 393 */ 394 ext2fs_mark_block_bitmap2(meta_block_map, first_block); 395 meta_blocks_count++; 396 397 /* 398 * Mark the primary superblock descriptors 399 */ 400 for (j = 0; j < fs->desc_blocks; j++) { 401 ext2fs_mark_block_bitmap2(meta_block_map, 402 ext2fs_descriptor_block_loc2(fs, first_block, j)); 403 } 404 meta_blocks_count += fs->desc_blocks; 405 406 for (i = 0; i < fs->group_desc_count; i++) { 407 /* 408 * Mark the blocks used for the inode table 409 */ 410 if ((output_is_blk || 411 !ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT)) && 412 ext2fs_inode_table_loc(fs, i)) { 413 unsigned int end = (unsigned) fs->inode_blocks_per_group; 414 /* skip unused blocks */ 415 if (!output_is_blk && 416 EXT2_HAS_RO_COMPAT_FEATURE(fs->super, 417 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) 418 end -= (ext2fs_bg_itable_unused(fs, i) / 419 EXT2_INODES_PER_BLOCK(fs->super)); 420 for (j = 0, b = ext2fs_inode_table_loc(fs, i); 421 j < end; 422 j++, b++) { 423 ext2fs_mark_block_bitmap2(meta_block_map, b); 424 meta_blocks_count++; 425 } 426 } 427 428 /* 429 * Mark block used for the block bitmap 430 */ 431 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && 432 ext2fs_block_bitmap_loc(fs, i)) { 433 ext2fs_mark_block_bitmap2(meta_block_map, 434 ext2fs_block_bitmap_loc(fs, i)); 435 meta_blocks_count++; 436 } 437 438 /* 439 * Mark block used for the inode bitmap 440 */ 441 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && 442 ext2fs_inode_bitmap_loc(fs, i)) { 443 ext2fs_mark_block_bitmap2(meta_block_map, 444 ext2fs_inode_bitmap_loc(fs, i)); 445 meta_blocks_count++; 446 } 447 } 448} 449 450/* 451 * This function returns 1 if the specified block is all zeros 452 */ 453static int check_zero_block(char *buf, int blocksize) 454{ 455 char *cp = buf; 456 int left = blocksize; 457 458 if (output_is_blk) 459 return 0; 460 while (left > 0) { 461 if (*cp++) 462 return 0; 463 left--; 464 } 465 return 1; 466} 467 468static int name_id[256]; 469 470#define EXT4_MAX_REC_LEN ((1<<16)-1) 471 472static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf) 473{ 474 char *p, *end, *cp; 475 struct ext2_dir_entry_2 *dirent; 476 unsigned int rec_len; 477 int id, len; 478 479 end = buf + fs->blocksize; 480 for (p = buf; p < end-8; p += rec_len) { 481 dirent = (struct ext2_dir_entry_2 *) p; 482 rec_len = dirent->rec_len; 483#ifdef WORDS_BIGENDIAN 484 rec_len = ext2fs_swab16(rec_len); 485#endif 486 if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0) 487 rec_len = fs->blocksize; 488 else 489 rec_len = (rec_len & 65532) | ((rec_len & 3) << 16); 490#if 0 491 printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len); 492#endif 493 if (rec_len < 8 || (rec_len % 4) || 494 (p+rec_len > end)) { 495 printf("Corrupt directory block %llu: " 496 "bad rec_len (%d)\n", (unsigned long long) blk, 497 rec_len); 498 rec_len = end - p; 499 (void) ext2fs_set_rec_len(fs, rec_len, 500 (struct ext2_dir_entry *) dirent); 501#ifdef WORDS_BIGENDIAN 502 dirent->rec_len = ext2fs_swab16(dirent->rec_len); 503#endif 504 continue; 505 } 506 if (dirent->name_len + 8U > rec_len) { 507 printf("Corrupt directory block %llu: " 508 "bad name_len (%d)\n", (unsigned long long) blk, 509 dirent->name_len); 510 dirent->name_len = rec_len - 8; 511 continue; 512 } 513 cp = p+8; 514 len = rec_len - dirent->name_len - 8; 515 if (len > 0) 516 memset(cp+dirent->name_len, 0, len); 517 if (dirent->name_len==1 && cp[0] == '.') 518 continue; 519 if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.') 520 continue; 521 522 memset(cp, 'A', dirent->name_len); 523 len = dirent->name_len; 524 id = name_id[len]++; 525 while ((len > 0) && (id > 0)) { 526 *cp += id % 26; 527 id = id / 26; 528 cp++; 529 len--; 530 } 531 } 532} 533 534static char got_sigint; 535 536static void sigint_handler(int unused EXT2FS_ATTR((unused))) 537{ 538 got_sigint = 1; 539 signal (SIGINT, SIG_DFL); 540} 541 542static void output_meta_data_blocks(ext2_filsys fs, int fd, int flags) 543{ 544 errcode_t retval; 545 blk64_t blk; 546 char *buf, *zero_buf; 547 int sparse = 0; 548 blk64_t start = 0; 549 blk64_t distance = 0; 550 blk64_t end = ext2fs_blocks_count(fs->super); 551 time_t last_update = 0; 552 time_t start_time = 0; 553 blk64_t total_written = 0; 554 int bscount = 0; 555 556 retval = ext2fs_get_mem(fs->blocksize, &buf); 557 if (retval) { 558 com_err(program_name, retval, "while allocating buffer"); 559 exit(1); 560 } 561 retval = ext2fs_get_memzero(fs->blocksize, &zero_buf); 562 if (retval) { 563 com_err(program_name, retval, "while allocating buffer"); 564 exit(1); 565 } 566 if (show_progress) { 567 printf("Copying "); 568 bscount = printf("%llu / %llu blocks (%llu%%)", 569 total_written, 570 meta_blocks_count, 571 (total_written + 50) / ((meta_blocks_count + 50) / 100)); 572 fflush(stdout); 573 last_update = time(NULL); 574 start_time = time(NULL); 575 } 576 /* when doing an in place move to the right, you can't start 577 at the beginning or you will overwrite data, so instead 578 divide the fs up into distance size chunks and write them 579 in reverse. */ 580 if (move_mode && dest_offset > source_offset) { 581 distance = (dest_offset - source_offset) / fs->blocksize; 582 if (distance < ext2fs_blocks_count(fs->super)) 583 start = ext2fs_blocks_count(fs->super) - distance; 584 } 585 if (move_mode) 586 signal (SIGINT, sigint_handler); 587more_blocks: 588 if (distance) 589 seek_set(fd, (start * fs->blocksize) + dest_offset); 590 for (blk = start; blk < end; blk++) { 591 if (got_sigint) { 592 if (distance) { 593 /* moving to the right */ 594 if (distance >= ext2fs_blocks_count(fs->super) || 595 start == ext2fs_blocks_count(fs->super) - distance) 596 kill (getpid(), SIGINT); 597 } else { 598 /* moving to the left */ 599 if (blk < (source_offset - dest_offset) / fs->blocksize) 600 kill (getpid(), SIGINT); 601 } 602 if (show_progress) 603 printf ("\r"); 604 printf ("Stopping now will destroy the filesystem, " 605 "interrupt again if you are sure\n"); 606 if (show_progress) { 607 printf("Copying "); 608 bscount = printf("%llu / %llu blocks (%llu%%)", 609 total_written, 610 meta_blocks_count, 611 (total_written + 50) / ((meta_blocks_count + 50) 612 / 100)); 613 fflush(stdout); 614 } 615 616 got_sigint = 0; 617 } 618 if (show_progress && last_update != time(NULL)) { 619 time_t duration; 620 last_update = time(NULL); 621 while (bscount--) 622 printf("\b"); 623 bscount = printf("%llu / %llu blocks (%llu%%)", 624 total_written, 625 meta_blocks_count, 626 (total_written + 50) / 627 ((meta_blocks_count + 50) / 100)); 628 duration = time(NULL) - start_time; 629 if (duration > 5) { 630 time_t est = (duration * 631 meta_blocks_count / total_written) - 632 (duration); 633 char buff[30]; 634 strftime(buff, 30, "%T", gmtime(&est)); 635 bscount += printf(" %s remaining at %.2f MB/s", 636 buff, 637 ((float)total_written / 638 ((1024 * 1024) / fs->blocksize)) / 639 duration); 640 } 641 fflush (stdout); 642 } 643 if ((blk >= fs->super->s_first_data_block) && 644 ext2fs_test_block_bitmap2(meta_block_map, blk)) { 645 retval = io_channel_read_blk64(fs->io, blk, 1, buf); 646 if (retval) { 647 com_err(program_name, retval, 648 "error reading block %llu", blk); 649 } 650 total_written++; 651 if (scramble_block_map && 652 ext2fs_test_block_bitmap2(scramble_block_map, blk)) 653 scramble_dir_block(fs, blk, buf); 654 if ((flags & E2IMAGE_CHECK_ZERO_FLAG) && 655 check_zero_block(buf, fs->blocksize)) 656 goto sparse_write; 657 if (sparse) 658 seek_relative(fd, sparse); 659 sparse = 0; 660 if (check_block(fd, buf, check_buf, fs->blocksize)) { 661 seek_relative(fd, fs->blocksize); 662 skipped_blocks++; 663 } else 664 generic_write(fd, buf, fs->blocksize, blk); 665 } else { 666 sparse_write: 667 if (fd == 1) { 668 generic_write(fd, zero_buf, fs->blocksize, blk); 669 continue; 670 } 671 sparse += fs->blocksize; 672 if (sparse > 1024*1024) { 673 seek_relative(fd, 1024*1024); 674 sparse -= 1024*1024; 675 } 676 } 677 } 678 if (distance && start) { 679 if (start < distance) { 680 end = start; 681 start = 0; 682 } else { 683 end -= distance; 684 start -= distance; 685 if (end < distance) { 686 /* past overlap, do rest in one go */ 687 end = start; 688 start = 0; 689 } 690 } 691 sparse = 0; 692 goto more_blocks; 693 } 694 signal (SIGINT, SIG_DFL); 695 if (show_progress) { 696 time_t duration = time(NULL) - start_time; 697 char buff[30]; 698 while (bscount--) 699 printf("\b"); 700 strftime(buff, 30, "%T", gmtime(&duration)); 701 printf("\b\b\b\b\b\b\b\bCopied %llu / %llu blocks (%llu%%) in " 702 "%s at %.2f MB/s \n", 703 total_written, 704 meta_blocks_count, 705 (total_written + 50) / ((meta_blocks_count + 50) / 100), 706 buff, 707 ((float)total_written / 708 ((1024 * 1024) / fs->blocksize)) / 709 duration); 710 711 } 712#ifdef HAVE_FTRUNCATE64 713 if (sparse) { 714 ext2_loff_t offset; 715 if (distance) 716 offset = seek_set(fd, 717 fs->blocksize * ext2fs_blocks_count(fs->super) + dest_offset); 718 else 719 offset = seek_relative(fd, sparse); 720 721 if (ftruncate64(fd, offset) < 0) { 722 seek_relative(fd, -1); 723 generic_write(fd, zero_buf, 1, NO_BLK); 724 } 725 } 726#else 727 if (sparse && !distance) { 728 seek_relative(fd, sparse-1); 729 generic_write(fd, zero_buf, 1, NO_BLK); 730 } 731#endif 732 ext2fs_free_mem(&zero_buf); 733 ext2fs_free_mem(&buf); 734} 735 736static void init_l1_table(struct ext2_qcow2_image *image) 737{ 738 __u64 *l1_table; 739 errcode_t ret; 740 741 ret = ext2fs_get_arrayzero(image->l1_size, sizeof(__u64), &l1_table); 742 if (ret) { 743 com_err(program_name, ret, "while allocating l1 table"); 744 exit(1); 745 } 746 747 image->l1_table = l1_table; 748} 749 750static void init_l2_cache(struct ext2_qcow2_image *image) 751{ 752 unsigned int count, i; 753 struct ext2_qcow2_l2_cache *cache; 754 struct ext2_qcow2_l2_table *table; 755 errcode_t ret; 756 757 ret = ext2fs_get_arrayzero(1, sizeof(struct ext2_qcow2_l2_cache), 758 &cache); 759 if (ret) 760 goto alloc_err; 761 762 count = (image->l1_size > L2_CACHE_PREALLOC) ? L2_CACHE_PREALLOC : 763 image->l1_size; 764 765 cache->count = count; 766 cache->free = count; 767 cache->next_offset = image->l2_offset; 768 769 for (i = 0; i < count; i++) { 770 ret = ext2fs_get_arrayzero(1, 771 sizeof(struct ext2_qcow2_l2_table), &table); 772 if (ret) 773 goto alloc_err; 774 775 ret = ext2fs_get_arrayzero(image->l2_size, 776 sizeof(__u64), &table->data); 777 if (ret) 778 goto alloc_err; 779 780 table->next = cache->free_head; 781 cache->free_head = table; 782 } 783 784 image->l2_cache = cache; 785 return; 786 787alloc_err: 788 com_err(program_name, ret, "while allocating l2 cache"); 789 exit(1); 790} 791 792static void put_l2_cache(struct ext2_qcow2_image *image) 793{ 794 struct ext2_qcow2_l2_cache *cache = image->l2_cache; 795 struct ext2_qcow2_l2_table *tmp, *table; 796 797 if (!cache) 798 return; 799 800 table = cache->free_head; 801 cache->free_head = NULL; 802again: 803 while (table) { 804 tmp = table; 805 table = table->next; 806 ext2fs_free_mem(&tmp->data); 807 ext2fs_free_mem(&tmp); 808 } 809 810 if (cache->free != cache->count) { 811 fprintf(stderr, "Warning: There are still tables in the " 812 "cache while putting the cache, data will " 813 "be lost so the image may not be valid.\n"); 814 table = cache->used_head; 815 cache->used_head = NULL; 816 goto again; 817 } 818 819 ext2fs_free_mem(&cache); 820} 821 822static int init_refcount(struct ext2_qcow2_image *img, blk64_t table_offset) 823{ 824 struct ext2_qcow2_refcount *ref; 825 blk64_t table_clusters; 826 errcode_t ret; 827 828 ref = &(img->refcount); 829 830 /* 831 * One refcount block addresses 2048 clusters, one refcount table 832 * addresses cluster/sizeof(__u64) refcount blocks, and we need 833 * to address meta_blocks_count clusters + qcow2 metadata clusters 834 * in the worst case. 835 */ 836 table_clusters = meta_blocks_count + (table_offset >> 837 img->cluster_bits); 838 table_clusters >>= (img->cluster_bits + 6 - 1); 839 table_clusters = (table_clusters == 0) ? 1 : table_clusters; 840 841 ref->refcount_table_offset = table_offset; 842 ref->refcount_table_clusters = table_clusters; 843 ref->refcount_table_index = 0; 844 ref->refcount_block_index = 0; 845 846 /* Allocate refcount table */ 847 ret = ext2fs_get_arrayzero(ref->refcount_table_clusters, 848 img->cluster_size, &ref->refcount_table); 849 if (ret) 850 return ret; 851 852 /* Allocate refcount block */ 853 ret = ext2fs_get_arrayzero(1, img->cluster_size, &ref->refcount_block); 854 if (ret) 855 ext2fs_free_mem(&ref->refcount_table); 856 857 return ret; 858} 859 860static int initialize_qcow2_image(int fd, ext2_filsys fs, 861 struct ext2_qcow2_image *image) 862{ 863 struct ext2_qcow2_hdr *header; 864 blk64_t total_size, offset; 865 int shift, l2_bits, header_size, l1_size, ret; 866 int cluster_bits = get_bits_from_size(fs->blocksize); 867 struct ext2_super_block *sb = fs->super; 868 869 /* Allocate header */ 870 ret = ext2fs_get_memzero(sizeof(struct ext2_qcow2_hdr), &header); 871 if (ret) 872 return ret; 873 874 total_size = ext2fs_blocks_count(sb) << cluster_bits; 875 image->cluster_size = fs->blocksize; 876 image->l2_size = 1 << (cluster_bits - 3); 877 image->cluster_bits = cluster_bits; 878 image->fd = fd; 879 880 header->magic = ext2fs_cpu_to_be32(QCOW_MAGIC); 881 header->version = ext2fs_cpu_to_be32(QCOW_VERSION); 882 header->size = ext2fs_cpu_to_be64(total_size); 883 header->cluster_bits = ext2fs_cpu_to_be32(cluster_bits); 884 885 header_size = (sizeof(struct ext2_qcow2_hdr) + 7) & ~7; 886 offset = align_offset(header_size, image->cluster_size); 887 888 header->l1_table_offset = ext2fs_cpu_to_be64(offset); 889 image->l1_offset = offset; 890 891 l2_bits = cluster_bits - 3; 892 shift = cluster_bits + l2_bits; 893 l1_size = ((total_size + (1LL << shift) - 1) >> shift); 894 header->l1_size = ext2fs_cpu_to_be32(l1_size); 895 image->l1_size = l1_size; 896 897 /* Make space for L1 table */ 898 offset += align_offset(l1_size * sizeof(blk64_t), image->cluster_size); 899 900 /* Initialize refcounting */ 901 ret = init_refcount(image, offset); 902 if (ret) { 903 ext2fs_free_mem(&header); 904 return ret; 905 } 906 header->refcount_table_offset = ext2fs_cpu_to_be64(offset); 907 header->refcount_table_clusters = 908 ext2fs_cpu_to_be32(image->refcount.refcount_table_clusters); 909 offset += image->cluster_size; 910 offset += image->refcount.refcount_table_clusters << 911 image->cluster_bits; 912 913 /* Make space for L2 tables */ 914 image->l2_offset = offset; 915 offset += image->cluster_size; 916 917 /* Make space for first refcount block */ 918 image->refcount.refcount_block_offset = offset; 919 920 image->hdr = header; 921 /* Initialize l1 and l2 tables */ 922 init_l1_table(image); 923 init_l2_cache(image); 924 925 return 0; 926} 927 928static void free_qcow2_image(struct ext2_qcow2_image *img) 929{ 930 if (!img) 931 return; 932 933 if (img->hdr) 934 ext2fs_free_mem(&img->hdr); 935 936 if (img->l1_table) 937 ext2fs_free_mem(&img->l1_table); 938 939 if (img->refcount.refcount_table) 940 ext2fs_free_mem(&img->refcount.refcount_table); 941 if (img->refcount.refcount_block) 942 ext2fs_free_mem(&img->refcount.refcount_block); 943 944 put_l2_cache(img); 945 946 ext2fs_free_mem(&img); 947} 948 949/** 950 * Put table from used list (used_head) into free list (free_head). 951 * l2_table is used to return pointer to the next used table (used_head). 952 */ 953static void put_used_table(struct ext2_qcow2_image *img, 954 struct ext2_qcow2_l2_table **l2_table) 955{ 956 struct ext2_qcow2_l2_cache *cache = img->l2_cache; 957 struct ext2_qcow2_l2_table *table; 958 959 table = cache->used_head; 960 cache->used_head = table->next; 961 962 assert(table); 963 if (!table->next) 964 cache->used_tail = NULL; 965 966 /* Clean the table for case we will need to use it again */ 967 memset(table->data, 0, img->cluster_size); 968 table->next = cache->free_head; 969 cache->free_head = table; 970 971 cache->free++; 972 973 *l2_table = cache->used_head; 974} 975 976static void flush_l2_cache(struct ext2_qcow2_image *image) 977{ 978 blk64_t seek = 0; 979 ext2_loff_t offset; 980 struct ext2_qcow2_l2_cache *cache = image->l2_cache; 981 struct ext2_qcow2_l2_table *table = cache->used_head; 982 int fd = image->fd; 983 984 /* Store current position */ 985 offset = seek_relative(fd, 0); 986 987 assert(table); 988 while (cache->free < cache->count) { 989 if (seek != table->offset) { 990 seek_set(fd, table->offset); 991 seek = table->offset; 992 } 993 994 generic_write(fd, (char *)table->data, image->cluster_size, 995 NO_BLK); 996 put_used_table(image, &table); 997 seek += image->cluster_size; 998 } 999 1000 /* Restore previous position */ 1001 seek_set(fd, offset); 1002} 1003 1004/** 1005 * Get first free table (from free_head) and put it into tail of used list 1006 * (to used_tail). 1007 * l2_table is used to return pointer to moved table. 1008 * Returns 1 if the cache is full, 0 otherwise. 1009 */ 1010static void get_free_table(struct ext2_qcow2_image *image, 1011 struct ext2_qcow2_l2_table **l2_table) 1012{ 1013 struct ext2_qcow2_l2_table *table; 1014 struct ext2_qcow2_l2_cache *cache = image->l2_cache; 1015 1016 if (0 == cache->free) 1017 flush_l2_cache(image); 1018 1019 table = cache->free_head; 1020 assert(table); 1021 cache->free_head = table->next; 1022 1023 if (cache->used_tail) 1024 cache->used_tail->next = table; 1025 else 1026 /* First item in the used list */ 1027 cache->used_head = table; 1028 1029 cache->used_tail = table; 1030 cache->free--; 1031 1032 *l2_table = table; 1033} 1034 1035static int add_l2_item(struct ext2_qcow2_image *img, blk64_t blk, 1036 blk64_t data, blk64_t next) 1037{ 1038 struct ext2_qcow2_l2_cache *cache = img->l2_cache; 1039 struct ext2_qcow2_l2_table *table = cache->used_tail; 1040 blk64_t l1_index = blk / img->l2_size; 1041 blk64_t l2_index = blk & (img->l2_size - 1); 1042 int ret = 0; 1043 1044 /* 1045 * Need to create new table if it does not exist, 1046 * or if it is full 1047 */ 1048 if (!table || (table->l1_index != l1_index)) { 1049 get_free_table(img, &table); 1050 table->l1_index = l1_index; 1051 table->offset = cache->next_offset; 1052 cache->next_offset = next; 1053 img->l1_table[l1_index] = 1054 ext2fs_cpu_to_be64(table->offset | QCOW_OFLAG_COPIED); 1055 ret++; 1056 } 1057 1058 table->data[l2_index] = ext2fs_cpu_to_be64(data | QCOW_OFLAG_COPIED); 1059 return ret; 1060} 1061 1062static int update_refcount(int fd, struct ext2_qcow2_image *img, 1063 blk64_t offset, blk64_t rfblk_pos) 1064{ 1065 struct ext2_qcow2_refcount *ref; 1066 __u32 table_index; 1067 int ret = 0; 1068 1069 ref = &(img->refcount); 1070 table_index = offset >> (2 * img->cluster_bits - 1); 1071 1072 /* 1073 * Need to create new refcount block when the offset addresses 1074 * another item in the refcount table 1075 */ 1076 if (table_index != ref->refcount_table_index) { 1077 1078 seek_set(fd, ref->refcount_block_offset); 1079 1080 generic_write(fd, (char *)ref->refcount_block, 1081 img->cluster_size, NO_BLK); 1082 memset(ref->refcount_block, 0, img->cluster_size); 1083 1084 ref->refcount_table[ref->refcount_table_index] = 1085 ext2fs_cpu_to_be64(ref->refcount_block_offset); 1086 ref->refcount_block_offset = rfblk_pos; 1087 ref->refcount_block_index = 0; 1088 ref->refcount_table_index = table_index; 1089 ret++; 1090 } 1091 1092 /* 1093 * We are relying on the fact that we are creating the qcow2 1094 * image sequentially, hence we will always allocate refcount 1095 * block items sequentialy. 1096 */ 1097 ref->refcount_block[ref->refcount_block_index] = ext2fs_cpu_to_be16(1); 1098 ref->refcount_block_index++; 1099 return ret; 1100} 1101 1102static int sync_refcount(int fd, struct ext2_qcow2_image *img) 1103{ 1104 struct ext2_qcow2_refcount *ref; 1105 1106 ref = &(img->refcount); 1107 1108 ref->refcount_table[ref->refcount_table_index] = 1109 ext2fs_cpu_to_be64(ref->refcount_block_offset); 1110 seek_set(fd, ref->refcount_table_offset); 1111 generic_write(fd, (char *)ref->refcount_table, 1112 ref->refcount_table_clusters << img->cluster_bits, NO_BLK); 1113 1114 seek_set(fd, ref->refcount_block_offset); 1115 generic_write(fd, (char *)ref->refcount_block, img->cluster_size, 1116 NO_BLK); 1117 return 0; 1118} 1119 1120static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd) 1121{ 1122 errcode_t retval; 1123 blk64_t blk, offset, size, end; 1124 char *buf; 1125 struct ext2_qcow2_image *img; 1126 unsigned int header_size; 1127 1128 /* allocate struct ext2_qcow2_image */ 1129 retval = ext2fs_get_mem(sizeof(struct ext2_qcow2_image), &img); 1130 if (retval) { 1131 com_err(program_name, retval, 1132 "while allocating ext2_qcow2_image"); 1133 exit(1); 1134 } 1135 1136 retval = initialize_qcow2_image(fd, fs, img); 1137 if (retval) { 1138 com_err(program_name, retval, 1139 "while initializing ext2_qcow2_image"); 1140 exit(1); 1141 } 1142 header_size = align_offset(sizeof(struct ext2_qcow2_hdr), 1143 img->cluster_size); 1144 write_header(fd, img->hdr, sizeof(struct ext2_qcow2_hdr), header_size); 1145 1146 /* Refcount all qcow2 related metadata up to refcount_block_offset */ 1147 end = img->refcount.refcount_block_offset; 1148 seek_set(fd, end); 1149 blk = end + img->cluster_size; 1150 for (offset = 0; offset <= end; offset += img->cluster_size) { 1151 if (update_refcount(fd, img, offset, blk)) { 1152 blk += img->cluster_size; 1153 /* 1154 * If we create new refcount block, we need to refcount 1155 * it as well. 1156 */ 1157 end += img->cluster_size; 1158 } 1159 } 1160 seek_set(fd, offset); 1161 1162 retval = ext2fs_get_mem(fs->blocksize, &buf); 1163 if (retval) { 1164 com_err(program_name, retval, "while allocating buffer"); 1165 exit(1); 1166 } 1167 /* Write qcow2 data blocks */ 1168 for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) { 1169 if ((blk >= fs->super->s_first_data_block) && 1170 ext2fs_test_block_bitmap2(meta_block_map, blk)) { 1171 retval = io_channel_read_blk64(fs->io, blk, 1, buf); 1172 if (retval) { 1173 com_err(program_name, retval, 1174 "error reading block %llu", blk); 1175 continue; 1176 } 1177 if (scramble_block_map && 1178 ext2fs_test_block_bitmap2(scramble_block_map, blk)) 1179 scramble_dir_block(fs, blk, buf); 1180 if (check_zero_block(buf, fs->blocksize)) 1181 continue; 1182 1183 if (update_refcount(fd, img, offset, offset)) { 1184 /* Make space for another refcount block */ 1185 offset += img->cluster_size; 1186 seek_set(fd, offset); 1187 /* 1188 * We have created the new refcount block, this 1189 * means that we need to refcount it as well. 1190 * So the previous update_refcount refcounted 1191 * the block itself and now we are going to 1192 * create refcount for data. New refcount 1193 * block should not be created! 1194 */ 1195 if (update_refcount(fd, img, offset, offset)) { 1196 fprintf(stderr, "Programming error: " 1197 "multiple sequential refcount " 1198 "blocks created!\n"); 1199 exit(1); 1200 } 1201 } 1202 1203 generic_write(fd, buf, fs->blocksize, blk); 1204 1205 if (add_l2_item(img, blk, offset, 1206 offset + img->cluster_size)) { 1207 offset += img->cluster_size; 1208 if (update_refcount(fd, img, offset, 1209 offset + img->cluster_size)) { 1210 offset += img->cluster_size; 1211 if (update_refcount(fd, img, offset, 1212 offset)) { 1213 fprintf(stderr, 1214 "Programming error: multiple sequential refcount " 1215 "blocks created!\n"); 1216 exit(1); 1217 } 1218 } 1219 offset += img->cluster_size; 1220 seek_set(fd, offset); 1221 continue; 1222 } 1223 1224 offset += img->cluster_size; 1225 } 1226 } 1227 update_refcount(fd, img, offset, offset); 1228 flush_l2_cache(img); 1229 sync_refcount(fd, img); 1230 1231 /* Write l1_table*/ 1232 seek_set(fd, img->l1_offset); 1233 size = img->l1_size * sizeof(__u64); 1234 generic_write(fd, (char *)img->l1_table, size, NO_BLK); 1235 1236 ext2fs_free_mem(&buf); 1237 free_qcow2_image(img); 1238} 1239 1240static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags) 1241{ 1242 struct process_block_struct pb; 1243 struct ext2_inode inode; 1244 ext2_inode_scan scan; 1245 ext2_ino_t ino; 1246 errcode_t retval; 1247 char * block_buf; 1248 1249 meta_blocks_count = 0; 1250 retval = ext2fs_allocate_block_bitmap(fs, "in-use block map", 1251 &meta_block_map); 1252 if (retval) { 1253 com_err(program_name, retval, "while allocating block bitmap"); 1254 exit(1); 1255 } 1256 1257 if (flags & E2IMAGE_SCRAMBLE_FLAG) { 1258 retval = ext2fs_allocate_block_bitmap(fs, "scramble block map", 1259 &scramble_block_map); 1260 if (retval) { 1261 com_err(program_name, retval, 1262 "while allocating scramble block bitmap"); 1263 exit(1); 1264 } 1265 } 1266 1267 mark_table_blocks(fs); 1268 if (show_progress) 1269 printf("Scanning inodes...\n"); 1270 1271 retval = ext2fs_open_inode_scan(fs, 0, &scan); 1272 if (retval) { 1273 com_err(program_name, retval,"%s", 1274 _("while opening inode scan")); 1275 exit(1); 1276 } 1277 1278 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf); 1279 if (retval) { 1280 com_err(program_name, 0, "%s", 1281 _("Can't allocate block buffer")); 1282 exit(1); 1283 } 1284 1285 use_inode_shortcuts(fs, 1); 1286 stashed_inode = &inode; 1287 while (1) { 1288 retval = ext2fs_get_next_inode(scan, &ino, &inode); 1289 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) 1290 continue; 1291 if (retval) { 1292 com_err(program_name, retval, "%s", 1293 _("while getting next inode")); 1294 exit(1); 1295 } 1296 if (ino == 0) 1297 break; 1298 if (!inode.i_links_count) 1299 continue; 1300 if (ext2fs_file_acl_block(fs, &inode)) { 1301 ext2fs_mark_block_bitmap2(meta_block_map, 1302 ext2fs_file_acl_block(fs, &inode)); 1303 meta_blocks_count++; 1304 } 1305 if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) 1306 continue; 1307 1308 stashed_ino = ino; 1309 pb.ino = ino; 1310 pb.is_dir = LINUX_S_ISDIR(inode.i_mode); 1311 if (LINUX_S_ISDIR(inode.i_mode) || 1312 (LINUX_S_ISLNK(inode.i_mode) && 1313 ext2fs_inode_has_valid_blocks2(fs, &inode)) || 1314 ino == fs->super->s_journal_inum) { 1315 retval = ext2fs_block_iterate3(fs, ino, 1316 BLOCK_FLAG_READ_ONLY, block_buf, 1317 process_dir_block, &pb); 1318 if (retval) { 1319 com_err(program_name, retval, 1320 "while iterating over inode %u", 1321 ino); 1322 exit(1); 1323 } 1324 } else { 1325 if ((inode.i_flags & EXT4_EXTENTS_FL) || 1326 inode.i_block[EXT2_IND_BLOCK] || 1327 inode.i_block[EXT2_DIND_BLOCK] || 1328 inode.i_block[EXT2_TIND_BLOCK] || all_data) { 1329 retval = ext2fs_block_iterate3(fs, 1330 ino, BLOCK_FLAG_READ_ONLY, block_buf, 1331 process_file_block, &pb); 1332 if (retval) { 1333 com_err(program_name, retval, 1334 "while iterating over inode %u", ino); 1335 exit(1); 1336 } 1337 } 1338 } 1339 } 1340 use_inode_shortcuts(fs, 0); 1341 1342 if (type & E2IMAGE_QCOW2) 1343 output_qcow2_meta_data_blocks(fs, fd); 1344 else 1345 output_meta_data_blocks(fs, fd, flags); 1346 1347 ext2fs_free_mem(&block_buf); 1348 ext2fs_close_inode_scan(scan); 1349 ext2fs_free_block_bitmap(meta_block_map); 1350 if (type & E2IMAGE_SCRAMBLE_FLAG) 1351 ext2fs_free_block_bitmap(scramble_block_map); 1352} 1353 1354static void install_image(char *device, char *image_fn, int type) 1355{ 1356 errcode_t retval; 1357 ext2_filsys fs; 1358 int open_flag = EXT2_FLAG_IMAGE_FILE | EXT2_FLAG_64BITS; 1359 int fd = 0; 1360 io_manager io_ptr; 1361 io_channel io; 1362 1363 if (type) { 1364 com_err(program_name, 0, "Raw and qcow2 images cannot" 1365 "be installed"); 1366 exit(1); 1367 } 1368 1369#ifdef CONFIG_TESTIO_DEBUG 1370 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { 1371 io_ptr = test_io_manager; 1372 test_io_backing_manager = unix_io_manager; 1373 } else 1374#endif 1375 io_ptr = unix_io_manager; 1376 1377 retval = ext2fs_open (image_fn, open_flag, 0, 0, 1378 io_ptr, &fs); 1379 if (retval) { 1380 com_err (program_name, retval, _("while trying to open %s"), 1381 image_fn); 1382 exit(1); 1383 } 1384 1385 retval = ext2fs_read_bitmaps (fs); 1386 if (retval) { 1387 com_err(program_name, retval, "error reading bitmaps"); 1388 exit(1); 1389 } 1390 1391 fd = ext2fs_open_file(image_fn, O_RDONLY, 0); 1392 if (fd < 0) { 1393 perror(image_fn); 1394 exit(1); 1395 } 1396 1397 retval = io_ptr->open(device, IO_FLAG_RW, &io); 1398 if (retval) { 1399 com_err(device, 0, "while opening device file"); 1400 exit(1); 1401 } 1402 1403 ext2fs_rewrite_to_io(fs, io); 1404 1405 seek_set(fd, fs->image_header->offset_inode); 1406 1407 retval = ext2fs_image_inode_read(fs, fd, 0); 1408 if (retval) { 1409 com_err(image_fn, 0, "while restoring the image table"); 1410 exit(1); 1411 } 1412 1413 close(fd); 1414 ext2fs_close (fs); 1415} 1416 1417static struct ext2_qcow2_hdr *check_qcow2_image(int *fd, char *name) 1418{ 1419 1420 *fd = ext2fs_open_file(name, O_RDONLY, 0600); 1421 if (*fd < 0) 1422 return NULL; 1423 1424 return qcow2_read_header(*fd); 1425} 1426 1427int main (int argc, char ** argv) 1428{ 1429 int c; 1430 errcode_t retval; 1431 ext2_filsys fs; 1432 char *image_fn, offset_opt[64]; 1433 struct ext2_qcow2_hdr *header = NULL; 1434 int open_flag = EXT2_FLAG_64BITS; 1435 int img_type = 0; 1436 int flags = 0; 1437 int mount_flags = 0; 1438 int qcow2_fd = 0; 1439 int fd = 0; 1440 int ret = 0; 1441 int ignore_rw_mount = 0; 1442 int check = 0; 1443 struct stat st; 1444 1445#ifdef ENABLE_NLS 1446 setlocale(LC_MESSAGES, ""); 1447 setlocale(LC_CTYPE, ""); 1448 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1449 textdomain(NLS_CAT_NAME); 1450 set_com_err_gettext(gettext); 1451#endif 1452 fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION, 1453 E2FSPROGS_DATE); 1454 if (argc && *argv) 1455 program_name = *argv; 1456 add_error_table(&et_ext2_error_table); 1457 while ((c = getopt(argc, argv, "nrsIQafo:O:pc")) != EOF) 1458 switch (c) { 1459 case 'I': 1460 flags |= E2IMAGE_INSTALL_FLAG; 1461 break; 1462 case 'Q': 1463 if (img_type) 1464 usage(); 1465 img_type |= E2IMAGE_QCOW2; 1466 break; 1467 case 'r': 1468 if (img_type) 1469 usage(); 1470 img_type |= E2IMAGE_RAW; 1471 break; 1472 case 's': 1473 flags |= E2IMAGE_SCRAMBLE_FLAG; 1474 break; 1475 case 'a': 1476 all_data = 1; 1477 break; 1478 case 'f': 1479 ignore_rw_mount = 1; 1480 break; 1481 case 'n': 1482 nop_flag = 1; 1483 break; 1484 case 'o': 1485 source_offset = strtoull(optarg, NULL, 0); 1486 break; 1487 case 'O': 1488 dest_offset = strtoull(optarg, NULL, 0); 1489 break; 1490 case 'p': 1491 show_progress = 1; 1492 break; 1493 case 'c': 1494 check = 1; 1495 break; 1496 default: 1497 usage(); 1498 } 1499 if (optind == argc - 1 && 1500 (source_offset || dest_offset)) 1501 move_mode = 1; 1502 else if (optind != argc - 2 ) 1503 usage(); 1504 1505 if (all_data && !img_type) { 1506 com_err(program_name, 0, "-a option can only be used " 1507 "with raw or QCOW2 images."); 1508 exit(1); 1509 } 1510 if ((source_offset || dest_offset) && img_type != E2IMAGE_RAW) { 1511 com_err(program_name, 0, 1512 "Offsets are only allowed with raw images."); 1513 exit(1); 1514 } 1515 if (move_mode && img_type != E2IMAGE_RAW) { 1516 com_err(program_name, 0, 1517 "Move mode is only allowed with raw images."); 1518 exit(1); 1519 } 1520 if (move_mode && !all_data) { 1521 com_err(program_name, 0, 1522 "Move mode requires all data mode."); 1523 exit(1); 1524 } 1525 device_name = argv[optind]; 1526 if (move_mode) 1527 image_fn = device_name; 1528 else image_fn = argv[optind+1]; 1529 1530 retval = ext2fs_check_if_mounted(device_name, &mount_flags); 1531 if (retval) { 1532 com_err(program_name, retval, "checking if mounted"); 1533 exit(1); 1534 } 1535 1536 if (img_type && !ignore_rw_mount && 1537 (mount_flags & EXT2_MF_MOUNTED) && 1538 !(mount_flags & EXT2_MF_READONLY)) { 1539 fprintf(stderr, "\nRunning e2image on a R/W mounted " 1540 "filesystem can result in an\n" 1541 "inconsistent image which will not be useful " 1542 "for debugging purposes.\n" 1543 "Use -f option if you really want to do that.\n"); 1544 exit(1); 1545 } 1546 1547 if (flags & E2IMAGE_INSTALL_FLAG) { 1548 install_image(device_name, image_fn, img_type); 1549 exit (0); 1550 } 1551 1552 if (img_type & E2IMAGE_RAW) { 1553 header = check_qcow2_image(&qcow2_fd, device_name); 1554 if (header) { 1555 flags |= E2IMAGE_IS_QCOW2_FLAG; 1556 goto skip_device; 1557 } 1558 } 1559 sprintf(offset_opt, "offset=%llu", source_offset); 1560 retval = ext2fs_open2(device_name, offset_opt, open_flag, 0, 0, 1561 unix_io_manager, &fs); 1562 if (retval) { 1563 com_err (program_name, retval, _("while trying to open %s"), 1564 device_name); 1565 fputs(_("Couldn't find valid filesystem superblock.\n"), stdout); 1566 exit(1); 1567 } 1568 1569skip_device: 1570 if (strcmp(image_fn, "-") == 0) 1571 fd = 1; 1572 else { 1573 int o_flags = O_CREAT|O_RDWR; 1574 1575 if (img_type != E2IMAGE_RAW) 1576 o_flags |= O_TRUNC; 1577 if (access(image_fn, F_OK) != 0) 1578 flags |= E2IMAGE_CHECK_ZERO_FLAG; 1579 fd = ext2fs_open_file(image_fn, o_flags, 0600); 1580 if (fd < 0) { 1581 com_err(program_name, errno, 1582 _("while trying to open %s"), image_fn); 1583 exit(1); 1584 } 1585 } 1586 if (dest_offset) 1587 seek_set(fd, dest_offset); 1588 1589 if ((img_type & E2IMAGE_QCOW2) && (fd == 1)) { 1590 com_err(program_name, 0, "QCOW2 image can not be written to " 1591 "the stdout!\n"); 1592 exit(1); 1593 } 1594 if (fd != 1) { 1595 if (fstat(fd, &st)) { 1596 com_err(program_name, 0, "Can not stat output\n"); 1597 exit(1); 1598 } 1599 if (S_ISBLK(st.st_mode)) 1600 output_is_blk = 1; 1601 } 1602 if (flags & E2IMAGE_IS_QCOW2_FLAG) { 1603 ret = qcow2_write_raw_image(qcow2_fd, fd, header); 1604 if (ret) { 1605 if (ret == -QCOW_COMPRESSED) 1606 fprintf(stderr, "Image (%s) is compressed\n", 1607 image_fn); 1608 if (ret == -QCOW_ENCRYPTED) 1609 fprintf(stderr, "Image (%s) is encrypted\n", 1610 image_fn); 1611 com_err(program_name, ret, 1612 _("while trying to convert qcow2 image" 1613 " (%s) into raw image (%s)"), 1614 device_name, image_fn); 1615 } 1616 goto out; 1617 } 1618 1619 if (check) { 1620 if (img_type != E2IMAGE_RAW) { 1621 fprintf(stderr, _("The -c option only supported " 1622 "in raw mode\n")); 1623 exit(1); 1624 } 1625 if (fd == 1) { 1626 fprintf(stderr, _("The -c option is not supported " 1627 "when writing to stdout\n")); 1628 exit(1); 1629 } 1630 retval = ext2fs_get_mem(fs->blocksize, &check_buf); 1631 if (retval) { 1632 com_err(program_name, retval, 1633 "while allocating check_buf"); 1634 exit(1); 1635 } 1636 } 1637 1638 if (img_type) 1639 write_raw_image_file(fs, fd, img_type, flags); 1640 else 1641 write_image_file(fs, fd); 1642 1643 ext2fs_close (fs); 1644 if (check) 1645 printf("%d blocks already contained the data to be copied.\n", 1646 skipped_blocks); 1647 1648out: 1649 if (header) 1650 free(header); 1651 if (qcow2_fd) 1652 close(qcow2_fd); 1653 remove_error_table(&et_ext2_error_table); 1654 return ret; 1655} 1656