Whamcloud - gitweb
a32df00597abe7646a322910db39b029a8ffc561
[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 &&
423                             EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
424                                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
425                                 end -= (ext2fs_bg_itable_unused(fs, i) /
426                                         EXT2_INODES_PER_BLOCK(fs->super));
427                         for (j = 0, b = ext2fs_inode_table_loc(fs, i);
428                              j < end;
429                              j++, b++) {
430                                 ext2fs_mark_block_bitmap2(meta_block_map, b);
431                                 meta_blocks_count++;
432                         }
433                 }
434
435                 /*
436                  * Mark block used for the block bitmap
437                  */
438                 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) &&
439                     ext2fs_block_bitmap_loc(fs, i)) {
440                         ext2fs_mark_block_bitmap2(meta_block_map,
441                                      ext2fs_block_bitmap_loc(fs, i));
442                         meta_blocks_count++;
443                 }
444
445                 /*
446                  * Mark block used for the inode bitmap
447                  */
448                 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
449                     ext2fs_inode_bitmap_loc(fs, i)) {
450                         ext2fs_mark_block_bitmap2(meta_block_map,
451                                  ext2fs_inode_bitmap_loc(fs, i));
452                         meta_blocks_count++;
453                 }
454         }
455 }
456
457 /*
458  * This function returns 1 if the specified block is all zeros
459  */
460 static int check_zero_block(char *buf, int blocksize)
461 {
462         char    *cp = buf;
463         int     left = blocksize;
464
465         if (output_is_blk)
466                 return 0;
467         while (left > 0) {
468                 if (*cp++)
469                         return 0;
470                 left--;
471         }
472         return 1;
473 }
474
475 static int name_id[256];
476
477 #define EXT4_MAX_REC_LEN                ((1<<16)-1)
478
479 static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf)
480 {
481         char *p, *end, *cp;
482         struct ext2_dir_entry_2 *dirent;
483         unsigned int rec_len;
484         int id, len;
485
486         end = buf + fs->blocksize;
487         for (p = buf; p < end-8; p += rec_len) {
488                 dirent = (struct ext2_dir_entry_2 *) p;
489                 rec_len = dirent->rec_len;
490 #ifdef WORDS_BIGENDIAN
491                 rec_len = ext2fs_swab16(rec_len);
492 #endif
493                 if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0)
494                         rec_len = fs->blocksize;
495                 else 
496                         rec_len = (rec_len & 65532) | ((rec_len & 3) << 16);
497 #if 0
498                 printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
499 #endif
500                 if (rec_len < 8 || (rec_len % 4) ||
501                     (p+rec_len > end)) {
502                         printf(_("Corrupt directory block %llu: "
503                                  "bad rec_len (%d)\n"),
504                                (unsigned long long) blk, rec_len);
505                         rec_len = end - p;
506                         (void) ext2fs_set_rec_len(fs, rec_len,
507                                         (struct ext2_dir_entry *) dirent);
508 #ifdef WORDS_BIGENDIAN
509                         dirent->rec_len = ext2fs_swab16(dirent->rec_len);
510 #endif
511                         continue;
512                 }
513                 if (dirent->name_len + 8U > rec_len) {
514                         printf(_("Corrupt directory block %llu: "
515                                  "bad name_len (%d)\n"),
516                                (unsigned long long) blk, dirent->name_len);
517                         dirent->name_len = rec_len - 8;
518                         continue;
519                 }
520                 cp = p+8;
521                 len = rec_len - dirent->name_len - 8;
522                 if (len > 0)
523                         memset(cp+dirent->name_len, 0, len);
524                 if (dirent->name_len==1 && cp[0] == '.')
525                         continue;
526                 if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.')
527                         continue;
528
529                 memset(cp, 'A', dirent->name_len);
530                 len = dirent->name_len;
531                 id = name_id[len]++;
532                 while ((len > 0) && (id > 0)) {
533                         *cp += id % 26;
534                         id = id / 26;
535                         cp++;
536                         len--;
537                 }
538         }
539 }
540
541 static char got_sigint;
542
543 static void sigint_handler(int unused EXT2FS_ATTR((unused)))
544 {
545         got_sigint = 1;
546         signal (SIGINT, SIG_DFL);
547 }
548
549 #define calc_percent(a, b) ((int) ((100.0 * (((float) (a)) / \
550                                              ((float) (b)))) + 0.5))
551 #define calc_rate(t, b, d) (((float)(t) / ((1024 * 1024) / (b))) / (d))
552
553 static int print_progress(blk64_t num, blk64_t total)
554 {
555         return fprintf(stderr, _("%llu / %llu blocks (%d%%)"), num, total,
556                       calc_percent(num, total));
557 }
558
559 static void output_meta_data_blocks(ext2_filsys fs, int fd, int flags)
560 {
561         errcode_t       retval;
562         blk64_t         blk;
563         char            *buf, *zero_buf;
564         int             sparse = 0;
565         blk64_t         start = 0;
566         blk64_t         distance = 0;
567         blk64_t         end = ext2fs_blocks_count(fs->super);
568         time_t          last_update = 0;
569         time_t          start_time = 0;
570         blk64_t         total_written = 0;
571         int             bscount = 0;
572
573         retval = ext2fs_get_mem(fs->blocksize, &buf);
574         if (retval) {
575                 com_err(program_name, retval, "%s",
576                         _("while allocating buffer"));
577                 exit(1);
578         }
579         retval = ext2fs_get_memzero(fs->blocksize, &zero_buf);
580         if (retval) {
581                 com_err(program_name, retval, "%s",
582                         _("while allocating buffer"));
583                 exit(1);
584         }
585         if (show_progress) {
586                 fprintf(stderr, "%s", _("Copying "));
587                 bscount = print_progress(total_written, meta_blocks_count);
588                 fflush(stderr);
589                 last_update = time(NULL);
590                 start_time = time(NULL);
591         }
592         /* when doing an in place move to the right, you can't start
593            at the beginning or you will overwrite data, so instead
594            divide the fs up into distance size chunks and write them
595            in reverse. */
596         if (move_mode && dest_offset > source_offset) {
597                 distance = (dest_offset - source_offset) / fs->blocksize;
598                 if (distance < ext2fs_blocks_count(fs->super))
599                         start = ext2fs_blocks_count(fs->super) - distance;
600         }
601         if (move_mode)
602                 signal (SIGINT, sigint_handler);
603 more_blocks:
604         if (distance)
605                 seek_set(fd, (start * fs->blocksize) + dest_offset);
606         for (blk = start; blk < end; blk++) {
607                 if (got_sigint) {
608                         if (distance) {
609                                 /* moving to the right */
610                                 if (distance >= ext2fs_blocks_count(fs->super)||
611                                     start == ext2fs_blocks_count(fs->super) -
612                                                 distance)
613                                         kill(getpid(), SIGINT);
614                         } else {
615                                 /* moving to the left */
616                                 if (blk < (source_offset - dest_offset) /
617                                     fs->blocksize)
618                                         kill(getpid(), SIGINT);
619                         }
620                         if (show_progress)
621                                 fputc('\r', stderr);
622                         fprintf(stderr, "%s",
623                                 _("Stopping now will destroy the filesystem, "
624                                  "interrupt again if you are sure\n"));
625                         if (show_progress) {
626                                 fprintf(stderr, "%s", _("Copying "));
627                                 bscount = print_progress(total_written,
628                                                          meta_blocks_count);
629                                 fflush(stderr);
630                         }
631
632                         got_sigint = 0;
633                 }
634                 if (show_progress && last_update != time(NULL)) {
635                         time_t duration;
636                         last_update = time(NULL);
637                         while (bscount--)
638                                 fputc('\b', stderr);
639                         bscount = print_progress(total_written,
640                                                  meta_blocks_count);
641                         duration = time(NULL) - start_time;
642                         if (duration > 5 && total_written) {
643                                 time_t est = (duration * meta_blocks_count /
644                                               total_written) - duration;
645                                 char buff[30];
646                                 strftime(buff, 30, "%T", gmtime(&est));
647                                 bscount +=
648                                         fprintf(stderr,
649                                                 _(" %s remaining at %.2f MB/s"),
650                                                 buff, calc_rate(total_written,
651                                                                 fs->blocksize,
652                                                                 duration));
653                         }
654                         fflush (stderr);
655                 }
656                 if ((blk >= fs->super->s_first_data_block) &&
657                     ext2fs_test_block_bitmap2(meta_block_map, blk)) {
658                         retval = io_channel_read_blk64(fs->io, blk, 1, buf);
659                         if (retval) {
660                                 com_err(program_name, retval,
661                                         _("error reading block %llu"), blk);
662                         }
663                         total_written++;
664                         if (scramble_block_map &&
665                             ext2fs_test_block_bitmap2(scramble_block_map, blk))
666                                 scramble_dir_block(fs, blk, buf);
667                         if ((flags & E2IMAGE_CHECK_ZERO_FLAG) &&
668                             check_zero_block(buf, fs->blocksize))
669                                 goto sparse_write;
670                         if (sparse)
671                                 seek_relative(fd, sparse);
672                         sparse = 0;
673                         if (check_block(fd, buf, check_buf, fs->blocksize)) {
674                                 seek_relative(fd, fs->blocksize);
675                                 skipped_blocks++;
676                         } else
677                                 generic_write(fd, buf, fs->blocksize, blk);
678                 } else {
679                 sparse_write:
680                         if (fd == 1) {
681                                 if (!nop_flag)
682                                         generic_write(fd, zero_buf,
683                                                       fs->blocksize, blk);
684                                 continue;
685                         }
686                         sparse += fs->blocksize;
687                         if (sparse > 1024*1024) {
688                                 seek_relative(fd, 1024*1024);
689                                 sparse -= 1024*1024;
690                         }
691                 }
692         }
693         if (distance && start) {
694                 if (start < distance) {
695                         end = start;
696                         start = 0;
697                 } else {
698                         end -= distance;
699                         start -= distance;
700                         if (end < distance) {
701                                 /* past overlap, do rest in one go */
702                                 end = start;
703                                 start = 0;
704                         }
705                 }
706                 sparse = 0;
707                 goto more_blocks;
708         }
709         signal (SIGINT, SIG_DFL);
710         if (show_progress) {
711                 time_t duration = time(NULL) - start_time;
712                 char buff[30];
713                 fputc('\r', stderr);
714                 strftime(buff, 30, "%T", gmtime(&duration));
715                 fprintf(stderr, _("Copied %llu / %llu blocks (%d%%) in %s "),
716                         total_written, meta_blocks_count,
717                         calc_percent(total_written, meta_blocks_count), buff);
718                 if (duration)
719                         fprintf(stderr, _("at %.2f MB/s"),
720                                 calc_rate(total_written, fs->blocksize, duration));
721                 fputs("       \n", stderr);
722         }
723 #ifdef HAVE_FTRUNCATE64
724         if (sparse) {
725                 ext2_loff_t offset;
726                 if (distance)
727                         offset = seek_set(fd,
728                                           fs->blocksize * ext2fs_blocks_count(fs->super) + dest_offset);
729                 else
730                         offset = seek_relative(fd, sparse);
731
732                 if (ftruncate64(fd, offset) < 0) {
733                         seek_relative(fd, -1);
734                         generic_write(fd, zero_buf, 1, NO_BLK);
735                 }
736         }
737 #else
738         if (sparse && !distance) {
739                 seek_relative(fd, sparse-1);
740                 generic_write(fd, zero_buf, 1, NO_BLK);
741         }
742 #endif
743         ext2fs_free_mem(&zero_buf);
744         ext2fs_free_mem(&buf);
745 }
746
747 static void init_l1_table(struct ext2_qcow2_image *image)
748 {
749         __u64 *l1_table;
750         errcode_t ret;
751
752         ret = ext2fs_get_arrayzero(image->l1_size, sizeof(__u64), &l1_table);
753         if (ret) {
754                 com_err(program_name, ret, "%s",
755                         _("while allocating l1 table"));
756                 exit(1);
757         }
758
759         image->l1_table = l1_table;
760 }
761
762 static void init_l2_cache(struct ext2_qcow2_image *image)
763 {
764         unsigned int count, i;
765         struct ext2_qcow2_l2_cache *cache;
766         struct ext2_qcow2_l2_table *table;
767         errcode_t ret;
768
769         ret = ext2fs_get_arrayzero(1, sizeof(struct ext2_qcow2_l2_cache),
770                                    &cache);
771         if (ret)
772                 goto alloc_err;
773
774         count = (image->l1_size > L2_CACHE_PREALLOC) ? L2_CACHE_PREALLOC :
775                  image->l1_size;
776
777         cache->count = count;
778         cache->free = count;
779         cache->next_offset = image->l2_offset;
780
781         for (i = 0; i < count; i++) {
782                 ret = ext2fs_get_arrayzero(1,
783                                 sizeof(struct ext2_qcow2_l2_table), &table);
784                 if (ret)
785                         goto alloc_err;
786
787                 ret = ext2fs_get_arrayzero(image->l2_size,
788                                                    sizeof(__u64), &table->data);
789                 if (ret)
790                         goto alloc_err;
791
792                 table->next = cache->free_head;
793                 cache->free_head = table;
794         }
795
796         image->l2_cache = cache;
797         return;
798
799 alloc_err:
800         com_err(program_name, ret, "%s", _("while allocating l2 cache"));
801         exit(1);
802 }
803
804 static void put_l2_cache(struct ext2_qcow2_image *image)
805 {
806         struct ext2_qcow2_l2_cache *cache = image->l2_cache;
807         struct ext2_qcow2_l2_table *tmp, *table;
808
809         if (!cache)
810                 return;
811
812         table = cache->free_head;
813         cache->free_head = NULL;
814 again:
815         while (table) {
816                 tmp = table;
817                 table = table->next;
818                 ext2fs_free_mem(&tmp->data);
819                 ext2fs_free_mem(&tmp);
820         }
821
822         if (cache->free != cache->count) {
823                 fprintf(stderr, "%s", _("Warning: There are still tables in "
824                                         "the cache while putting the cache, "
825                                         "data will be lost so the image may "
826                                         "not be valid.\n"));
827                 table = cache->used_head;
828                 cache->used_head = NULL;
829                 goto again;
830         }
831
832         ext2fs_free_mem(&cache);
833 }
834
835 static int init_refcount(struct ext2_qcow2_image *img, blk64_t table_offset)
836 {
837         struct  ext2_qcow2_refcount     *ref;
838         blk64_t table_clusters;
839         errcode_t ret;
840
841         ref = &(img->refcount);
842
843         /*
844          * One refcount block addresses 2048 clusters, one refcount table
845          * addresses cluster/sizeof(__u64) refcount blocks, and we need
846          * to address meta_blocks_count clusters + qcow2 metadata clusters
847          * in the worst case.
848          */
849         table_clusters = meta_blocks_count + (table_offset >>
850                                               img->cluster_bits);
851         table_clusters >>= (img->cluster_bits + 6 - 1);
852         table_clusters = (table_clusters == 0) ? 1 : table_clusters;
853
854         ref->refcount_table_offset = table_offset;
855         ref->refcount_table_clusters = table_clusters;
856         ref->refcount_table_index = 0;
857         ref->refcount_block_index = 0;
858
859         /* Allocate refcount table */
860         ret = ext2fs_get_arrayzero(ref->refcount_table_clusters,
861                                    img->cluster_size, &ref->refcount_table);
862         if (ret)
863                 return ret;
864
865         /* Allocate refcount block */
866         ret = ext2fs_get_arrayzero(1, img->cluster_size, &ref->refcount_block);
867         if (ret)
868                 ext2fs_free_mem(&ref->refcount_table);
869
870         return ret;
871 }
872
873 static int initialize_qcow2_image(int fd, ext2_filsys fs,
874                             struct ext2_qcow2_image *image)
875 {
876         struct ext2_qcow2_hdr *header;
877         blk64_t total_size, offset;
878         int shift, l2_bits, header_size, l1_size, ret;
879         int cluster_bits = get_bits_from_size(fs->blocksize);
880         struct ext2_super_block *sb = fs->super;
881
882         /* Allocate header */
883         ret = ext2fs_get_memzero(sizeof(struct ext2_qcow2_hdr), &header);
884         if (ret)
885                 return ret;
886
887         total_size = ext2fs_blocks_count(sb) << cluster_bits;
888         image->cluster_size = fs->blocksize;
889         image->l2_size = 1 << (cluster_bits - 3);
890         image->cluster_bits = cluster_bits;
891         image->fd = fd;
892
893         header->magic = ext2fs_cpu_to_be32(QCOW_MAGIC);
894         header->version = ext2fs_cpu_to_be32(QCOW_VERSION);
895         header->size = ext2fs_cpu_to_be64(total_size);
896         header->cluster_bits = ext2fs_cpu_to_be32(cluster_bits);
897
898         header_size = (sizeof(struct ext2_qcow2_hdr) + 7) & ~7;
899         offset = align_offset(header_size, image->cluster_size);
900
901         header->l1_table_offset = ext2fs_cpu_to_be64(offset);
902         image->l1_offset = offset;
903
904         l2_bits = cluster_bits - 3;
905         shift = cluster_bits + l2_bits;
906         l1_size = ((total_size + (1LL << shift) - 1) >> shift);
907         header->l1_size = ext2fs_cpu_to_be32(l1_size);
908         image->l1_size = l1_size;
909
910         /* Make space for L1 table */
911         offset += align_offset(l1_size * sizeof(blk64_t), image->cluster_size);
912
913         /* Initialize refcounting */
914         ret = init_refcount(image, offset);
915         if (ret) {
916                 ext2fs_free_mem(&header);
917                 return ret;
918         }
919         header->refcount_table_offset = ext2fs_cpu_to_be64(offset);
920         header->refcount_table_clusters =
921                 ext2fs_cpu_to_be32(image->refcount.refcount_table_clusters);
922         offset += image->cluster_size;
923         offset += image->refcount.refcount_table_clusters <<
924                 image->cluster_bits;
925
926         /* Make space for L2 tables */
927         image->l2_offset = offset;
928         offset += image->cluster_size;
929
930         /* Make space for first refcount block */
931         image->refcount.refcount_block_offset = offset;
932
933         image->hdr = header;
934         /* Initialize l1 and l2 tables */
935         init_l1_table(image);
936         init_l2_cache(image);
937
938         return 0;
939 }
940
941 static void free_qcow2_image(struct ext2_qcow2_image *img)
942 {
943         if (!img)
944                 return;
945
946         if (img->hdr)
947                 ext2fs_free_mem(&img->hdr);
948
949         if (img->l1_table)
950                 ext2fs_free_mem(&img->l1_table);
951
952         if (img->refcount.refcount_table)
953                 ext2fs_free_mem(&img->refcount.refcount_table);
954         if (img->refcount.refcount_block)
955                 ext2fs_free_mem(&img->refcount.refcount_block);
956
957         put_l2_cache(img);
958
959         ext2fs_free_mem(&img);
960 }
961
962 /**
963  * Put table from used list (used_head) into free list (free_head).
964  * l2_table is used to return pointer to the next used table (used_head).
965  */
966 static void put_used_table(struct ext2_qcow2_image *img,
967                           struct ext2_qcow2_l2_table **l2_table)
968 {
969         struct ext2_qcow2_l2_cache *cache = img->l2_cache;
970         struct ext2_qcow2_l2_table *table;
971
972         table = cache->used_head;
973         cache->used_head = table->next;
974
975         assert(table);
976         if (!table->next)
977                 cache->used_tail = NULL;
978
979         /* Clean the table for case we will need to use it again */
980         memset(table->data, 0, img->cluster_size);
981         table->next = cache->free_head;
982         cache->free_head = table;
983
984         cache->free++;
985
986         *l2_table = cache->used_head;
987 }
988
989 static void flush_l2_cache(struct ext2_qcow2_image *image)
990 {
991         blk64_t seek = 0;
992         ext2_loff_t offset;
993         struct ext2_qcow2_l2_cache *cache = image->l2_cache;
994         struct ext2_qcow2_l2_table *table = cache->used_head;
995         int fd = image->fd;
996
997         /* Store current position */
998         offset = seek_relative(fd, 0);
999
1000         assert(table);
1001         while (cache->free < cache->count) {
1002                 if (seek != table->offset) {
1003                         seek_set(fd, table->offset);
1004                         seek = table->offset;
1005                 }
1006
1007                 generic_write(fd, (char *)table->data, image->cluster_size,
1008                               NO_BLK);
1009                 put_used_table(image, &table);
1010                 seek += image->cluster_size;
1011         }
1012
1013         /* Restore previous position */
1014         seek_set(fd, offset);
1015 }
1016
1017 /**
1018  * Get first free table (from free_head) and put it into tail of used list
1019  * (to used_tail).
1020  * l2_table is used to return pointer to moved table.
1021  * Returns 1 if the cache is full, 0 otherwise.
1022  */
1023 static void get_free_table(struct ext2_qcow2_image *image,
1024                           struct ext2_qcow2_l2_table **l2_table)
1025 {
1026         struct ext2_qcow2_l2_table *table;
1027         struct ext2_qcow2_l2_cache *cache = image->l2_cache;
1028
1029         if (0 == cache->free)
1030                 flush_l2_cache(image);
1031
1032         table = cache->free_head;
1033         assert(table);
1034         cache->free_head = table->next;
1035
1036         if (cache->used_tail)
1037                 cache->used_tail->next = table;
1038         else
1039                 /* First item in the used list */
1040                 cache->used_head = table;
1041
1042         cache->used_tail = table;
1043         cache->free--;
1044
1045         *l2_table = table;
1046 }
1047
1048 static int add_l2_item(struct ext2_qcow2_image *img, blk64_t blk,
1049                        blk64_t data, blk64_t next)
1050 {
1051         struct ext2_qcow2_l2_cache *cache = img->l2_cache;
1052         struct ext2_qcow2_l2_table *table = cache->used_tail;
1053         blk64_t l1_index = blk / img->l2_size;
1054         blk64_t l2_index = blk & (img->l2_size - 1);
1055         int ret = 0;
1056
1057         /*
1058          * Need to create new table if it does not exist,
1059          * or if it is full
1060          */
1061         if (!table || (table->l1_index != l1_index)) {
1062                 get_free_table(img, &table);
1063                 table->l1_index = l1_index;
1064                 table->offset = cache->next_offset;
1065                 cache->next_offset = next;
1066                 img->l1_table[l1_index] =
1067                         ext2fs_cpu_to_be64(table->offset | QCOW_OFLAG_COPIED);
1068                 ret++;
1069         }
1070
1071         table->data[l2_index] = ext2fs_cpu_to_be64(data | QCOW_OFLAG_COPIED);
1072         return ret;
1073 }
1074
1075 static int update_refcount(int fd, struct ext2_qcow2_image *img,
1076                            blk64_t offset, blk64_t rfblk_pos)
1077 {
1078         struct  ext2_qcow2_refcount     *ref;
1079         __u32   table_index;
1080         int ret = 0;
1081
1082         ref = &(img->refcount);
1083         table_index = offset >> (2 * img->cluster_bits - 1);
1084
1085         /*
1086          * Need to create new refcount block when the offset addresses
1087          * another item in the refcount table
1088          */
1089         if (table_index != ref->refcount_table_index) {
1090
1091                 seek_set(fd, ref->refcount_block_offset);
1092
1093                 generic_write(fd, (char *)ref->refcount_block,
1094                               img->cluster_size, NO_BLK);
1095                 memset(ref->refcount_block, 0, img->cluster_size);
1096
1097                 ref->refcount_table[ref->refcount_table_index] =
1098                         ext2fs_cpu_to_be64(ref->refcount_block_offset);
1099                 ref->refcount_block_offset = rfblk_pos;
1100                 ref->refcount_block_index = 0;
1101                 ref->refcount_table_index = table_index;
1102                 ret++;
1103         }
1104
1105         /*
1106          * We are relying on the fact that we are creating the qcow2
1107          * image sequentially, hence we will always allocate refcount
1108          * block items sequentialy.
1109          */
1110         ref->refcount_block[ref->refcount_block_index] = ext2fs_cpu_to_be16(1);
1111         ref->refcount_block_index++;
1112         return ret;
1113 }
1114
1115 static int sync_refcount(int fd, struct ext2_qcow2_image *img)
1116 {
1117         struct  ext2_qcow2_refcount     *ref;
1118
1119         ref = &(img->refcount);
1120
1121         ref->refcount_table[ref->refcount_table_index] =
1122                 ext2fs_cpu_to_be64(ref->refcount_block_offset);
1123         seek_set(fd, ref->refcount_table_offset);
1124         generic_write(fd, (char *)ref->refcount_table,
1125                 ref->refcount_table_clusters << img->cluster_bits, NO_BLK);
1126
1127         seek_set(fd, ref->refcount_block_offset);
1128         generic_write(fd, (char *)ref->refcount_block, img->cluster_size,
1129                       NO_BLK);
1130         return 0;
1131 }
1132
1133 static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
1134 {
1135         errcode_t               retval;
1136         blk64_t                 blk, offset, size, end;
1137         char                    *buf;
1138         struct ext2_qcow2_image *img;
1139         unsigned int            header_size;
1140
1141         /* allocate  struct ext2_qcow2_image */
1142         retval = ext2fs_get_mem(sizeof(struct ext2_qcow2_image), &img);
1143         if (retval) {
1144                 com_err(program_name, retval, "%s",
1145                         _("while allocating ext2_qcow2_image"));
1146                 exit(1);
1147         }
1148
1149         retval = initialize_qcow2_image(fd, fs, img);
1150         if (retval) {
1151                 com_err(program_name, retval, "%s",
1152                         _("while initializing ext2_qcow2_image"));
1153                 exit(1);
1154         }
1155         header_size = align_offset(sizeof(struct ext2_qcow2_hdr),
1156                                    img->cluster_size);
1157         write_header(fd, img->hdr, sizeof(struct ext2_qcow2_hdr), header_size);
1158
1159         /* Refcount all qcow2 related metadata up to refcount_block_offset */
1160         end = img->refcount.refcount_block_offset;
1161         seek_set(fd, end);
1162         blk = end + img->cluster_size;
1163         for (offset = 0; offset <= end; offset += img->cluster_size) {
1164                 if (update_refcount(fd, img, offset, blk)) {
1165                         blk += img->cluster_size;
1166                         /*
1167                          * If we create new refcount block, we need to refcount
1168                          * it as well.
1169                          */
1170                         end += img->cluster_size;
1171                 }
1172         }
1173         seek_set(fd, offset);
1174
1175         retval = ext2fs_get_mem(fs->blocksize, &buf);
1176         if (retval) {
1177                 com_err(program_name, retval, "%s",
1178                         _("while allocating buffer"));
1179                 exit(1);
1180         }
1181         /* Write qcow2 data blocks */
1182         for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) {
1183                 if ((blk >= fs->super->s_first_data_block) &&
1184                     ext2fs_test_block_bitmap2(meta_block_map, blk)) {
1185                         retval = io_channel_read_blk64(fs->io, blk, 1, buf);
1186                         if (retval) {
1187                                 com_err(program_name, retval,
1188                                         _("error reading block %llu"), blk);
1189                                 continue;
1190                         }
1191                         if (scramble_block_map &&
1192                             ext2fs_test_block_bitmap2(scramble_block_map, blk))
1193                                 scramble_dir_block(fs, blk, buf);
1194                         if (check_zero_block(buf, fs->blocksize))
1195                                 continue;
1196
1197                         if (update_refcount(fd, img, offset, offset)) {
1198                                 /* Make space for another refcount block */
1199                                 offset += img->cluster_size;
1200                                 seek_set(fd, offset);
1201                                 /*
1202                                  * We have created the new refcount block, this
1203                                  * means that we need to refcount it as well.
1204                                  * So the previous update_refcount refcounted
1205                                  * the block itself and now we are going to
1206                                  * create refcount for data. New refcount
1207                                  * block should not be created!
1208                                  */
1209                                 if (update_refcount(fd, img, offset, offset)) {
1210                                         fprintf(stderr, "%s",
1211                                                 _("Programming error: multiple "
1212                                                   "sequential refcount blocks "
1213                                                   "created!\n"));
1214                                         exit(1);
1215                                 }
1216                         }
1217
1218                         generic_write(fd, buf, fs->blocksize, blk);
1219
1220                         if (add_l2_item(img, blk, offset,
1221                                         offset + img->cluster_size)) {
1222                                 offset += img->cluster_size;
1223                                 if (update_refcount(fd, img, offset,
1224                                         offset + img->cluster_size)) {
1225                                         offset += img->cluster_size;
1226                                         if (update_refcount(fd, img, offset,
1227                                                             offset)) {
1228                                                 fprintf(stderr, "%s",
1229                         _("Programming error: multiple sequential refcount "
1230                           "blocks created!\n"));
1231                                                 exit(1);
1232                                         }
1233                                 }
1234                                 offset += img->cluster_size;
1235                                 seek_set(fd, offset);
1236                                 continue;
1237                         }
1238
1239                         offset += img->cluster_size;
1240                 }
1241         }
1242         update_refcount(fd, img, offset, offset);
1243         flush_l2_cache(img);
1244         sync_refcount(fd, img);
1245
1246         /* Write l1_table*/
1247         seek_set(fd, img->l1_offset);
1248         size = img->l1_size * sizeof(__u64);
1249         generic_write(fd, (char *)img->l1_table, size, NO_BLK);
1250
1251         ext2fs_free_mem(&buf);
1252         free_qcow2_image(img);
1253 }
1254
1255 static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
1256 {
1257         struct process_block_struct     pb;
1258         struct ext2_inode               inode;
1259         ext2_inode_scan                 scan;
1260         ext2_ino_t                      ino;
1261         errcode_t                       retval;
1262         char *                          block_buf;
1263
1264         meta_blocks_count = 0;
1265         retval = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
1266                                               &meta_block_map);
1267         if (retval) {
1268                 com_err(program_name, retval, "%s",
1269                         _("while allocating block bitmap"));
1270                 exit(1);
1271         }
1272
1273         if (flags & E2IMAGE_SCRAMBLE_FLAG) {
1274                 retval = ext2fs_allocate_block_bitmap(fs, "scramble block map",
1275                                                       &scramble_block_map);
1276                 if (retval) {
1277                         com_err(program_name, retval, "%s",
1278                                 _("while allocating scramble block bitmap"));
1279                         exit(1);
1280                 }
1281         }
1282
1283         mark_table_blocks(fs);
1284         if (show_progress)
1285                 fprintf(stderr, "%s", _("Scanning inodes...\n"));
1286
1287         retval = ext2fs_open_inode_scan(fs, 0, &scan);
1288         if (retval) {
1289                 com_err(program_name, retval, "%s",
1290                         _("while opening inode scan"));
1291                 exit(1);
1292         }
1293
1294         retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
1295         if (retval) {
1296                 com_err(program_name, 0, "%s",
1297                         _("Can't allocate block buffer"));
1298                 exit(1);
1299         }
1300
1301         use_inode_shortcuts(fs, 1);
1302         stashed_inode = &inode;
1303         while (1) {
1304                 retval = ext2fs_get_next_inode(scan, &ino, &inode);
1305                 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
1306                         continue;
1307                 if (retval) {
1308                         com_err(program_name, retval, "%s",
1309                                 _("while getting next inode"));
1310                         exit(1);
1311                 }
1312                 if (ino == 0)
1313                         break;
1314                 if (!inode.i_links_count)
1315                         continue;
1316                 if (ext2fs_file_acl_block(fs, &inode)) {
1317                         ext2fs_mark_block_bitmap2(meta_block_map,
1318                                         ext2fs_file_acl_block(fs, &inode));
1319                         meta_blocks_count++;
1320                 }
1321                 if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
1322                         continue;
1323
1324                 stashed_ino = ino;
1325                 pb.ino = ino;
1326                 pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
1327                 if (LINUX_S_ISDIR(inode.i_mode) ||
1328                     (LINUX_S_ISLNK(inode.i_mode) &&
1329                      ext2fs_inode_has_valid_blocks2(fs, &inode)) ||
1330                     ino == fs->super->s_journal_inum) {
1331                         retval = ext2fs_block_iterate3(fs, ino,
1332                                         BLOCK_FLAG_READ_ONLY, block_buf,
1333                                         process_dir_block, &pb);
1334                         if (retval) {
1335                                 com_err(program_name, retval,
1336                                         _("while iterating over inode %u"),
1337                                         ino);
1338                                 exit(1);
1339                         }
1340                 } else {
1341                         if ((inode.i_flags & EXT4_EXTENTS_FL) ||
1342                             inode.i_block[EXT2_IND_BLOCK] ||
1343                             inode.i_block[EXT2_DIND_BLOCK] ||
1344                             inode.i_block[EXT2_TIND_BLOCK] || all_data) {
1345                                 retval = ext2fs_block_iterate3(fs,
1346                                        ino, BLOCK_FLAG_READ_ONLY, block_buf,
1347                                        process_file_block, &pb);
1348                                 if (retval) {
1349                                         com_err(program_name, retval,
1350                                         _("while iterating over inode %u"), ino);
1351                                         exit(1);
1352                                 }
1353                         }
1354                 }
1355         }
1356         use_inode_shortcuts(fs, 0);
1357
1358         if (type & E2IMAGE_QCOW2)
1359                 output_qcow2_meta_data_blocks(fs, fd);
1360         else
1361                 output_meta_data_blocks(fs, fd, flags);
1362
1363         ext2fs_free_mem(&block_buf);
1364         ext2fs_close_inode_scan(scan);
1365         ext2fs_free_block_bitmap(meta_block_map);
1366         if (type & E2IMAGE_SCRAMBLE_FLAG)
1367                 ext2fs_free_block_bitmap(scramble_block_map);
1368 }
1369
1370 static void install_image(char *device, char *image_fn, int type)
1371 {
1372         errcode_t retval;
1373         ext2_filsys fs;
1374         int open_flag = EXT2_FLAG_IMAGE_FILE | EXT2_FLAG_64BITS;
1375         int fd = 0;
1376         io_manager      io_ptr;
1377         io_channel      io;
1378
1379         if (type) {
1380                 com_err(program_name, 0, "%s",
1381                         _("Raw and qcow2 images cannot be installed"));
1382                 exit(1);
1383         }
1384
1385 #ifdef CONFIG_TESTIO_DEBUG
1386         if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1387                 io_ptr = test_io_manager;
1388                 test_io_backing_manager = unix_io_manager;
1389         } else
1390 #endif
1391                 io_ptr = unix_io_manager;
1392
1393         retval = ext2fs_open (image_fn, open_flag, 0, 0,
1394                               io_ptr, &fs);
1395         if (retval) {
1396                 com_err(program_name, retval, _("while trying to open %s"),
1397                         image_fn);
1398                 exit(1);
1399         }
1400
1401         retval = ext2fs_read_bitmaps (fs);
1402         if (retval) {
1403                 com_err(program_name, retval, "%s", _("error reading bitmaps"));
1404                 exit(1);
1405         }
1406
1407         fd = ext2fs_open_file(image_fn, O_RDONLY, 0);
1408         if (fd < 0) {
1409                 perror(image_fn);
1410                 exit(1);
1411         }
1412
1413         retval = io_ptr->open(device, IO_FLAG_RW, &io);
1414         if (retval) {
1415                 com_err(device, 0, "%s", _("while opening device file"));
1416                 exit(1);
1417         }
1418
1419         ext2fs_rewrite_to_io(fs, io);
1420
1421         seek_set(fd, fs->image_header->offset_inode);
1422
1423         retval = ext2fs_image_inode_read(fs, fd, 0);
1424         if (retval) {
1425                 com_err(image_fn, 0, "%s",
1426                         _("while restoring the image table"));
1427                 exit(1);
1428         }
1429
1430         close(fd);
1431         ext2fs_close_free(&fs);
1432 }
1433
1434 static struct ext2_qcow2_hdr *check_qcow2_image(int *fd, char *name)
1435 {
1436
1437         *fd = ext2fs_open_file(name, O_RDONLY, 0600);
1438         if (*fd < 0)
1439                 return NULL;
1440
1441         return qcow2_read_header(*fd);
1442 }
1443
1444 int main (int argc, char ** argv)
1445 {
1446         int c;
1447         errcode_t retval;
1448         ext2_filsys fs;
1449         char *image_fn, offset_opt[64];
1450         struct ext2_qcow2_hdr *header = NULL;
1451         int open_flag = EXT2_FLAG_64BITS;
1452         int img_type = 0;
1453         int flags = 0;
1454         int mount_flags = 0;
1455         int qcow2_fd = 0;
1456         int fd = 0;
1457         int ret = 0;
1458         int ignore_rw_mount = 0;
1459         int check = 0;
1460         struct stat st;
1461
1462 #ifdef ENABLE_NLS
1463         setlocale(LC_MESSAGES, "");
1464         setlocale(LC_CTYPE, "");
1465         bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1466         textdomain(NLS_CAT_NAME);
1467         set_com_err_gettext(gettext);
1468 #endif
1469         fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
1470                  E2FSPROGS_DATE);
1471         if (argc && *argv)
1472                 program_name = *argv;
1473         add_error_table(&et_ext2_error_table);
1474         while ((c = getopt(argc, argv, "nrsIQafo:O:pc")) != EOF)
1475                 switch (c) {
1476                 case 'I':
1477                         flags |= E2IMAGE_INSTALL_FLAG;
1478                         break;
1479                 case 'Q':
1480                         if (img_type)
1481                                 usage();
1482                         img_type |= E2IMAGE_QCOW2;
1483                         break;
1484                 case 'r':
1485                         if (img_type)
1486                                 usage();
1487                         img_type |= E2IMAGE_RAW;
1488                         break;
1489                 case 's':
1490                         flags |= E2IMAGE_SCRAMBLE_FLAG;
1491                         break;
1492                 case 'a':
1493                         all_data = 1;
1494                         break;
1495                 case 'f':
1496                         ignore_rw_mount = 1;
1497                         break;
1498                 case 'n':
1499                         nop_flag = 1;
1500                         break;
1501                 case 'o':
1502                         source_offset = strtoull(optarg, NULL, 0);
1503                         break;
1504                 case 'O':
1505                         dest_offset = strtoull(optarg, NULL, 0);
1506                         break;
1507                 case 'p':
1508                         show_progress = 1;
1509                         break;
1510                 case 'c':
1511                         check = 1;
1512                         break;
1513                 default:
1514                         usage();
1515                 }
1516         if (optind == argc - 1 &&
1517             (source_offset || dest_offset))
1518                     move_mode = 1;
1519         else if (optind != argc - 2 )
1520                 usage();
1521
1522         if (all_data && !img_type) {
1523                 com_err(program_name, 0, "%s", _("-a option can only be used "
1524                                                  "with raw or QCOW2 images."));
1525                 exit(1);
1526         }
1527         if ((source_offset || dest_offset) && img_type != E2IMAGE_RAW) {
1528                 com_err(program_name, 0, "%s",
1529                         _("Offsets are only allowed with raw images."));
1530                 exit(1);
1531         }
1532         if (move_mode && img_type != E2IMAGE_RAW) {
1533                 com_err(program_name, 0, "%s",
1534                         _("Move mode is only allowed with raw images."));
1535                 exit(1);
1536         }
1537         if (move_mode && !all_data) {
1538                 com_err(program_name, 0, "%s",
1539                         _("Move mode requires all data mode."));
1540                 exit(1);
1541         }
1542         device_name = argv[optind];
1543         if (move_mode)
1544                 image_fn = device_name;
1545         else image_fn = argv[optind+1];
1546
1547         retval = ext2fs_check_if_mounted(device_name, &mount_flags);
1548         if (retval) {
1549                 com_err(program_name, retval, "%s", _("checking if mounted"));
1550                 exit(1);
1551         }
1552
1553         if (img_type && !ignore_rw_mount &&
1554             (mount_flags & EXT2_MF_MOUNTED) &&
1555            !(mount_flags & EXT2_MF_READONLY)) {
1556                 fprintf(stderr, "%s", _("\nRunning e2image on a R/W mounted "
1557                         "filesystem can result in an\n"
1558                         "inconsistent image which will not be useful "
1559                         "for debugging purposes.\n"
1560                         "Use -f option if you really want to do that.\n"));
1561                 exit(1);
1562         }
1563
1564         if (flags & E2IMAGE_INSTALL_FLAG) {
1565                 install_image(device_name, image_fn, img_type);
1566                 exit (0);
1567         }
1568
1569         if (img_type & E2IMAGE_RAW) {
1570                 header = check_qcow2_image(&qcow2_fd, device_name);
1571                 if (header) {
1572                         flags |= E2IMAGE_IS_QCOW2_FLAG;
1573                         goto skip_device;
1574                 }
1575         }
1576         sprintf(offset_opt, "offset=%llu", source_offset);
1577         retval = ext2fs_open2(device_name, offset_opt, open_flag, 0, 0,
1578                               unix_io_manager, &fs);
1579         if (retval) {
1580                 com_err (program_name, retval, _("while trying to open %s"),
1581                          device_name);
1582                 fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
1583                 exit(1);
1584         }
1585
1586 skip_device:
1587         if (strcmp(image_fn, "-") == 0)
1588                 fd = 1;
1589         else {
1590                 int o_flags = O_CREAT|O_RDWR;
1591
1592                 if (img_type != E2IMAGE_RAW)
1593                         o_flags |= O_TRUNC;
1594                 if (access(image_fn, F_OK) != 0)
1595                         flags |= E2IMAGE_CHECK_ZERO_FLAG;
1596                 fd = ext2fs_open_file(image_fn, o_flags, 0600);
1597                 if (fd < 0) {
1598                         com_err(program_name, errno,
1599                                 _("while trying to open %s"), image_fn);
1600                         exit(1);
1601                 }
1602         }
1603         if (dest_offset)
1604                 seek_set(fd, dest_offset);
1605
1606         if ((img_type & E2IMAGE_QCOW2) && (fd == 1)) {
1607                 com_err(program_name, 0, "%s",
1608                         _("QCOW2 image can not be written to the stdout!\n"));
1609                 exit(1);
1610         }
1611         if (fd != 1) {
1612                 if (fstat(fd, &st)) {
1613                         com_err(program_name, 0, "%s",
1614                                 _("Can not stat output\n"));
1615                         exit(1);
1616                 }
1617                 if (S_ISBLK(st.st_mode))
1618                         output_is_blk = 1;
1619         }
1620         if (flags & E2IMAGE_IS_QCOW2_FLAG) {
1621                 ret = qcow2_write_raw_image(qcow2_fd, fd, header);
1622                 if (ret) {
1623                         if (ret == -QCOW_COMPRESSED)
1624                                 fprintf(stderr, _("Image (%s) is compressed\n"),
1625                                         image_fn);
1626                         if (ret == -QCOW_ENCRYPTED)
1627                                 fprintf(stderr, _("Image (%s) is encrypted\n"),
1628                                         image_fn);
1629                         com_err(program_name, ret,
1630                                 _("while trying to convert qcow2 image"
1631                                   " (%s) into raw image (%s)"),
1632                                 device_name, image_fn);
1633                 }
1634                 goto out;
1635         }
1636
1637         if (check) {
1638                 if (img_type != E2IMAGE_RAW) {
1639                         fprintf(stderr, "%s", _("The -c option only supported "
1640                                                 "in raw mode\n"));
1641                         exit(1);
1642                 }
1643                 if (fd == 1) {
1644                         fprintf(stderr, "%s", _("The -c option not supported "
1645                                                 "when writing to stdout\n"));
1646                         exit(1);
1647                 }
1648                 retval = ext2fs_get_mem(fs->blocksize, &check_buf);
1649                 if (retval) {
1650                         com_err(program_name, retval, "%s",
1651                                 _("while allocating check_buf"));
1652                         exit(1);
1653                 }
1654         }
1655         if (show_progress && (img_type != E2IMAGE_RAW)) {
1656                 fprintf(stderr, "%s",
1657                         _("The -p option only supported in raw mode\n"));
1658                 exit(1);
1659         }
1660         if (img_type)
1661                 write_raw_image_file(fs, fd, img_type, flags);
1662         else
1663                 write_image_file(fs, fd);
1664
1665         ext2fs_close_free(&fs);
1666         if (check)
1667                 printf(_("%d blocks already contained the data to be copied\n"),
1668                        skipped_blocks);
1669
1670 out:
1671         if (header)
1672                 free(header);
1673         if (qcow2_fd)
1674                 close(qcow2_fd);
1675         remove_error_table(&et_ext2_error_table);
1676         return ret;
1677 }