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