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