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