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