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