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