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