1a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross/*
2a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * Copyright (C) 2010 The Android Open Source Project
3a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross *
4a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * Licensed under the Apache License, Version 2.0 (the "License");
5a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * you may not use this file except in compliance with the License.
6a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * You may obtain a copy of the License at
7a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross *
8a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross *      http://www.apache.org/licenses/LICENSE-2.0
9a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross *
10a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * Unless required by applicable law or agreed to in writing, software
11a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * distributed under the License is distributed on an "AS IS" BASIS,
12a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * See the License for the specific language governing permissions and
14a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross * limitations under the License.
15a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross */
16a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
17f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#define _FILE_OFFSET_BITS 64
18f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#define _LARGEFILE64_SOURCE 1
19a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
20a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/types.h>
21a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/stat.h>
22a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/types.h>
23a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/mman.h>
24a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <fcntl.h>
25a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <libgen.h>
26a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <unistd.h>
27a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
28f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#include <sparse/sparse.h>
29f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross
30f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#include "ext4_utils.h"
31f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#include "make_ext4fs.h"
32f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#include "allocate.h"
33f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross
34f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#if defined(__APPLE__) && defined(__MACH__)
35f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#define off64_t off_t
36f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross#endif
37f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross
380349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
390349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#define O_BINARY 0
400349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#endif
410349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau
42a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossextern struct fs_info info;
43a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
44a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int verbose = 0;
45a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
46a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic void usage(char *path)
47a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
48a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "%s [ options ] <image or block device> <output image>\n", path);
49a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "\n");
50a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -c include CRC block\n");
51a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -v verbose output\n");
52a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -z gzip output\n");
53a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -S don't use sparse output format\n");
54a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
55a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
56a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int read_ext(int fd)
57a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
58a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	off64_t ret;
59a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	struct ext4_super_block sb;
60a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	unsigned int i;
61a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
62a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = lseek64(fd, 1024, SEEK_SET);
63a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
64a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to seek to superblock");
65a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
66a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = read(fd, &sb, sizeof(sb));
67a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
68a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to read superblock");
69a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret != sizeof(sb))
70a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error("failed to read all of superblock");
71a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
72a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ext4_parse_sb(&sb);
73a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
74a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = lseek64(fd, info.len, SEEK_SET);
75a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
76a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to seek to end of input image");
77a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
78a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
79a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
80a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to seek to block group descriptors");
81a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
82a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
83a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
84a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to read block group descriptors");
85a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
86a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error("failed to read all of block group descriptors");
87a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
88a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (verbose) {
89a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("Found filesystem with parameters:\n");
90a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Size: %llu\n", info.len);
91a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Block size: %d\n", info.block_size);
92a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Blocks per group: %d\n", info.blocks_per_group);
93a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Inodes per group: %d\n", info.inodes_per_group);
94a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Inode size: %d\n", info.inode_size);
95a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Label: %s\n", info.label);
96a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Blocks: %llu\n", aux_info.len_blocks);
97a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Block groups: %d\n", aux_info.groups);
98a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
99a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Used %d/%d inodes and %d/%d blocks\n",
100a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
101a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_inodes_count,
102a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
103a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_blocks_count_lo);
104a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
105a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
106a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
107a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
108a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
109a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int bitmap_get_bit(u8 *bitmap, u32 bit)
110a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
111a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (bitmap[bit / 8] & 1 << (bit % 8))
112a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		return 1;
113a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
114a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
115a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
116a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
117a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int build_sparse_ext(int fd, const char *filename)
118a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
119a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	unsigned int i;
120a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	unsigned int block;
121a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int start_contiguous_block;
122a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	u8 *block_bitmap;
123a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	off64_t ret;
124a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
125a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	block_bitmap = malloc(info.block_size);
126a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (!block_bitmap)
127a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error("failed to allocate block bitmap");
128a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
129a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (aux_info.first_data_block > 0)
130f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross		sparse_file_add_file(info.sparse_file, filename, 0,
131a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				info.block_size * aux_info.first_data_block, 0);
132a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
133a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	for (i = 0; i < aux_info.groups; i++) {
134a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		u32 first_block = aux_info.first_data_block + i * info.blocks_per_group;
135a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		u32 last_block = min(info.blocks_per_group, aux_info.len_blocks - first_block);
136a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
137a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		ret = lseek64(fd, (u64)info.block_size * aux_info.bg_desc[i].bg_block_bitmap,
138a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				SEEK_SET);
139a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (ret < 0)
140a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			critical_error_errno("failed to seek to block group bitmap %d", i);
141a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
142a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		ret = read(fd, block_bitmap, info.block_size);
143a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (ret < 0)
144a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			critical_error_errno("failed to read block group bitmap %d", i);
145a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (ret != (int)info.block_size)
146a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			critical_error("failed to read all of block group bitmap %d", i);
147a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
148a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		start_contiguous_block = -1;
149a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		for (block = 0; block < last_block; block++) {
150a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			if (start_contiguous_block >= 0) {
151a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				if (!bitmap_get_bit(block_bitmap, block)) {
152a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					u32 start_block = first_block + start_contiguous_block;
153a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					u32 len_blocks = block - start_contiguous_block;
154a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
155f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross					sparse_file_add_file(info.sparse_file, filename,
156f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross							(u64)info.block_size * start_block,
157a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross							info.block_size * len_blocks, start_block);
158a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					start_contiguous_block = -1;
159a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				}
160a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			} else {
161a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				if (bitmap_get_bit(block_bitmap, block))
162a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					start_contiguous_block = block;
163a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			}
164a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		}
165a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
166a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (start_contiguous_block >= 0) {
167a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			u32 start_block = first_block + start_contiguous_block;
168a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			u32 len_blocks = last_block - start_contiguous_block;
169f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross			sparse_file_add_file(info.sparse_file, filename,
170f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross					(u64)info.block_size * start_block,
171a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					info.block_size * len_blocks, start_block);
172a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		}
173a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
174a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
175a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
176a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
177a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
178a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossint main(int argc, char **argv)
179a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
180a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int opt;
181a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	const char *in = NULL;
182a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	const char *out = NULL;
183a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int gzip = 0;
184a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int sparse = 1;
1850349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	int infd, outfd;
186a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int crc = 0;
187a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
188a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	while ((opt = getopt(argc, argv, "cvzS")) != -1) {
189a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		switch (opt) {
190a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'c':
191a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			crc = 1;
192a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
193a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'v':
194a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			verbose = 1;
195a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
196a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'z':
197a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			gzip = 1;
198a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
199a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'S':
200a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			sparse = 0;
201a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
202a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		}
203a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
204a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
205a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (optind >= argc) {
206a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		fprintf(stderr, "Expected image or block device after options\n");
207a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		usage(argv[0]);
208a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		exit(EXIT_FAILURE);
209a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
210a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
211a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	in = argv[optind++];
212a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
213a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (optind >= argc) {
214a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		fprintf(stderr, "Expected output image after input image\n");
215a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		usage(argv[0]);
216a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		exit(EXIT_FAILURE);
217a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
218a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
219a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	out = argv[optind++];
220a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
221a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (optind < argc) {
222a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
223a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		usage(argv[0]);
224a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		exit(EXIT_FAILURE);
225a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
226a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2270349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	infd = open(in, O_RDONLY);
228a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2290349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	if (infd < 0)
230a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to open input image");
231a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2320349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	read_ext(infd);
2330349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau
234f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross	info.sparse_file = sparse_file_new(info.block_size, info.len);
235f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross
2360349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	build_sparse_ext(infd, in);
237a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2380349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	close(infd);
239a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2400349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	if (strcmp(out, "-")) {
2410349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		outfd = open(out, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
2420349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		if (outfd < 0) {
2430349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau			error_errno("open");
2440349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau			return EXIT_FAILURE;
2450349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		}
2460349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	} else {
2470349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		outfd = STDOUT_FILENO;
2480349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	}
249a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
250dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross	write_ext4_image(outfd, gzip, sparse, crc);
2510349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	close(outfd);
252a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
253f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross	sparse_file_destroy(info.sparse_file);
254f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross
255a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
256a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
257