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