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