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