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