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