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