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