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