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