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