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