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