Whamcloud - gitweb
Merge branch 'maint' into next
[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         int fd = 0;
1379         io_manager      io_ptr;
1380         io_channel      io;
1381
1382         if (type) {
1383                 com_err(program_name, 0, "%s",
1384                         _("Raw and qcow2 images cannot be installed"));
1385                 exit(1);
1386         }
1387
1388 #ifdef CONFIG_TESTIO_DEBUG
1389         if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1390                 io_ptr = test_io_manager;
1391                 test_io_backing_manager = unix_io_manager;
1392         } else
1393 #endif
1394                 io_ptr = unix_io_manager;
1395
1396         retval = ext2fs_open (image_fn, open_flag, 0, 0,
1397                               io_ptr, &fs);
1398         if (retval) {
1399                 com_err(program_name, retval, _("while trying to open %s"),
1400                         image_fn);
1401                 exit(1);
1402         }
1403
1404         retval = ext2fs_read_bitmaps (fs);
1405         if (retval) {
1406                 com_err(program_name, retval, "%s", _("error reading bitmaps"));
1407                 exit(1);
1408         }
1409
1410         fd = ext2fs_open_file(image_fn, O_RDONLY, 0);
1411         if (fd < 0) {
1412                 perror(image_fn);
1413                 exit(1);
1414         }
1415
1416         retval = io_ptr->open(device, IO_FLAG_RW, &io);
1417         if (retval) {
1418                 com_err(device, 0, "%s", _("while opening device file"));
1419                 exit(1);
1420         }
1421
1422         ext2fs_rewrite_to_io(fs, io);
1423
1424         seek_set(fd, fs->image_header->offset_inode);
1425
1426         retval = ext2fs_image_inode_read(fs, fd, 0);
1427         if (retval) {
1428                 com_err(image_fn, 0, "%s",
1429                         _("while restoring the image table"));
1430                 exit(1);
1431         }
1432
1433         close(fd);
1434         ext2fs_close_free(&fs);
1435 }
1436
1437 static struct ext2_qcow2_hdr *check_qcow2_image(int *fd, char *name)
1438 {
1439
1440         *fd = ext2fs_open_file(name, O_RDONLY, 0600);
1441         if (*fd < 0)
1442                 return NULL;
1443
1444         return qcow2_read_header(*fd);
1445 }
1446
1447 int main (int argc, char ** argv)
1448 {
1449         int c;
1450         errcode_t retval;
1451         ext2_filsys fs;
1452         char *image_fn, offset_opt[64];
1453         struct ext2_qcow2_hdr *header = NULL;
1454         int open_flag = EXT2_FLAG_64BITS;
1455         int img_type = 0;
1456         int flags = 0;
1457         int mount_flags = 0;
1458         int qcow2_fd = 0;
1459         int fd = 0;
1460         int ret = 0;
1461         int ignore_rw_mount = 0;
1462         int check = 0;
1463         struct stat st;
1464
1465 #ifdef ENABLE_NLS
1466         setlocale(LC_MESSAGES, "");
1467         setlocale(LC_CTYPE, "");
1468         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1469         textdomain(NLS_CAT_NAME);
1470         set_com_err_gettext(gettext);
1471 #endif
1472         fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
1473                  E2FSPROGS_DATE);
1474         if (argc && *argv)
1475                 program_name = *argv;
1476         add_error_table(&et_ext2_error_table);
1477         while ((c = getopt(argc, argv, "nrsIQafo:O:pc")) != EOF)
1478                 switch (c) {
1479                 case 'I':
1480                         flags |= E2IMAGE_INSTALL_FLAG;
1481                         break;
1482                 case 'Q':
1483                         if (img_type)
1484                                 usage();
1485                         img_type |= E2IMAGE_QCOW2;
1486                         break;
1487                 case 'r':
1488                         if (img_type)
1489                                 usage();
1490                         img_type |= E2IMAGE_RAW;
1491                         break;
1492                 case 's':
1493                         flags |= E2IMAGE_SCRAMBLE_FLAG;
1494                         break;
1495                 case 'a':
1496                         all_data = 1;
1497                         break;
1498                 case 'f':
1499                         ignore_rw_mount = 1;
1500                         break;
1501                 case 'n':
1502                         nop_flag = 1;
1503                         break;
1504                 case 'o':
1505                         source_offset = strtoull(optarg, NULL, 0);
1506                         break;
1507                 case 'O':
1508                         dest_offset = strtoull(optarg, NULL, 0);
1509                         break;
1510                 case 'p':
1511                         show_progress = 1;
1512                         break;
1513                 case 'c':
1514                         check = 1;
1515                         break;
1516                 default:
1517                         usage();
1518                 }
1519         if (optind == argc - 1 &&
1520             (source_offset || dest_offset))
1521                     move_mode = 1;
1522         else if (optind != argc - 2 )
1523                 usage();
1524
1525         if (all_data && !img_type) {
1526                 com_err(program_name, 0, "%s", _("-a option can only be used "
1527                                                  "with raw or QCOW2 images."));
1528                 exit(1);
1529         }
1530         if ((source_offset || dest_offset) && img_type != E2IMAGE_RAW) {
1531                 com_err(program_name, 0, "%s",
1532                         _("Offsets are only allowed with raw images."));
1533                 exit(1);
1534         }
1535         if (move_mode && img_type != E2IMAGE_RAW) {
1536                 com_err(program_name, 0, "%s",
1537                         _("Move mode is only allowed with raw images."));
1538                 exit(1);
1539         }
1540         if (move_mode && !all_data) {
1541                 com_err(program_name, 0, "%s",
1542                         _("Move mode requires all data mode."));
1543                 exit(1);
1544         }
1545         device_name = argv[optind];
1546         if (move_mode)
1547                 image_fn = device_name;
1548         else image_fn = argv[optind+1];
1549
1550         retval = ext2fs_check_if_mounted(device_name, &mount_flags);
1551         if (retval) {
1552                 com_err(program_name, retval, "%s", _("checking if mounted"));
1553                 exit(1);
1554         }
1555
1556         if (img_type && !ignore_rw_mount &&
1557             (mount_flags & EXT2_MF_MOUNTED) &&
1558            !(mount_flags & EXT2_MF_READONLY)) {
1559                 fprintf(stderr, "%s", _("\nRunning e2image on a R/W mounted "
1560                         "filesystem can result in an\n"
1561                         "inconsistent image which will not be useful "
1562                         "for debugging purposes.\n"
1563                         "Use -f option if you really want to do that.\n"));
1564                 exit(1);
1565         }
1566
1567         if (flags & E2IMAGE_INSTALL_FLAG) {
1568                 install_image(device_name, image_fn, img_type);
1569                 exit (0);
1570         }
1571
1572         if (img_type & E2IMAGE_RAW) {
1573                 header = check_qcow2_image(&qcow2_fd, device_name);
1574                 if (header) {
1575                         flags |= E2IMAGE_IS_QCOW2_FLAG;
1576                         goto skip_device;
1577                 }
1578         }
1579         sprintf(offset_opt, "offset=%llu", source_offset);
1580         retval = ext2fs_open2(device_name, offset_opt, open_flag, 0, 0,
1581                               unix_io_manager, &fs);
1582         if (retval) {
1583                 com_err (program_name, retval, _("while trying to open %s"),
1584                          device_name);
1585                 fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
1586                 if (retval == EXT2_ET_BAD_MAGIC)
1587                         check_plausibility(device_name, CHECK_FS_EXIST, NULL);
1588                 exit(1);
1589         }
1590
1591 skip_device:
1592         if (strcmp(image_fn, "-") == 0)
1593                 fd = 1;
1594         else {
1595                 int o_flags = O_CREAT|O_RDWR;
1596
1597                 if (img_type != E2IMAGE_RAW)
1598                         o_flags |= O_TRUNC;
1599                 if (access(image_fn, F_OK) != 0)
1600                         flags |= E2IMAGE_CHECK_ZERO_FLAG;
1601                 fd = ext2fs_open_file(image_fn, o_flags, 0600);
1602                 if (fd < 0) {
1603                         com_err(program_name, errno,
1604                                 _("while trying to open %s"), image_fn);
1605                         exit(1);
1606                 }
1607         }
1608         if (dest_offset)
1609                 seek_set(fd, dest_offset);
1610
1611         if ((img_type & E2IMAGE_QCOW2) && (fd == 1)) {
1612                 com_err(program_name, 0, "%s",
1613                         _("QCOW2 image can not be written to the stdout!\n"));
1614                 exit(1);
1615         }
1616         if (fd != 1) {
1617                 if (fstat(fd, &st)) {
1618                         com_err(program_name, 0, "%s",
1619                                 _("Can not stat output\n"));
1620                         exit(1);
1621                 }
1622                 if (S_ISBLK(st.st_mode))
1623                         output_is_blk = 1;
1624         }
1625         if (flags & E2IMAGE_IS_QCOW2_FLAG) {
1626                 ret = qcow2_write_raw_image(qcow2_fd, fd, header);
1627                 if (ret) {
1628                         if (ret == -QCOW_COMPRESSED)
1629                                 fprintf(stderr, _("Image (%s) is compressed\n"),
1630                                         image_fn);
1631                         if (ret == -QCOW_ENCRYPTED)
1632                                 fprintf(stderr, _("Image (%s) is encrypted\n"),
1633                                         image_fn);
1634                         com_err(program_name, ret,
1635                                 _("while trying to convert qcow2 image"
1636                                   " (%s) into raw image (%s)"),
1637                                 device_name, image_fn);
1638                 }
1639                 goto out;
1640         }
1641
1642         if (check) {
1643                 if (img_type != E2IMAGE_RAW) {
1644                         fprintf(stderr, "%s", _("The -c option only supported "
1645                                                 "in raw mode\n"));
1646                         exit(1);
1647                 }
1648                 if (fd == 1) {
1649                         fprintf(stderr, "%s", _("The -c option not supported "
1650                                                 "when writing to stdout\n"));
1651                         exit(1);
1652                 }
1653                 retval = ext2fs_get_mem(fs->blocksize, &check_buf);
1654                 if (retval) {
1655                         com_err(program_name, retval, "%s",
1656                                 _("while allocating check_buf"));
1657                         exit(1);
1658                 }
1659         }
1660         if (show_progress && (img_type != E2IMAGE_RAW)) {
1661                 fprintf(stderr, "%s",
1662                         _("The -p option only supported in raw mode\n"));
1663                 exit(1);
1664         }
1665         if (img_type)
1666                 write_raw_image_file(fs, fd, img_type, flags);
1667         else
1668                 write_image_file(fs, fd);
1669
1670         ext2fs_close_free(&fs);
1671         if (check)
1672                 printf(_("%d blocks already contained the data to be copied\n"),
1673                        skipped_blocks);
1674
1675 out:
1676         if (header)
1677                 free(header);
1678         if (qcow2_fd)
1679                 close(qcow2_fd);
1680         remove_error_table(&et_ext2_error_table);
1681         return ret;
1682 }