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