ext2simg.c revision dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7
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
17dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross#include <sparse/sparse.h>
18dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross
19a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include "ext4_utils.h"
20a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include "make_ext4fs.h"
21a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include "allocate.h"
22a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
23a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/types.h>
24a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/stat.h>
25a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/types.h>
26a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <sys/mman.h>
27a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <fcntl.h>
28a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <libgen.h>
29a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross#include <unistd.h>
30a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
310349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
320349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#define O_BINARY 0
330349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#endif
340349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau
35a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossextern struct fs_info info;
36a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
37a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int verbose = 0;
38a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
39a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic void usage(char *path)
40a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
41a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "%s [ options ] <image or block device> <output image>\n", path);
42a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "\n");
43a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -c include CRC block\n");
44a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -v verbose output\n");
45a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -z gzip output\n");
46a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	fprintf(stderr, "  -S don't use sparse output format\n");
47a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
48a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
49a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int read_ext(int fd)
50a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
51a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	off64_t ret;
52a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	struct ext4_super_block sb;
53a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	unsigned int i;
54a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
55a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = lseek64(fd, 1024, SEEK_SET);
56a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
57a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to seek to superblock");
58a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
59a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = read(fd, &sb, sizeof(sb));
60a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
61a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to read superblock");
62a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret != sizeof(sb))
63a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error("failed to read all of superblock");
64a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
65a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ext4_parse_sb(&sb);
66a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
67a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = lseek64(fd, info.len, SEEK_SET);
68a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
69a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to seek to end of input image");
70a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
71a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
72a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
73a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to seek to block group descriptors");
74a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
75a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
76a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret < 0)
77a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to read block group descriptors");
78a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
79a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error("failed to read all of block group descriptors");
80a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
81a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (verbose) {
82a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("Found filesystem with parameters:\n");
83a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Size: %llu\n", info.len);
84a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Block size: %d\n", info.block_size);
85a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Blocks per group: %d\n", info.blocks_per_group);
86a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Inodes per group: %d\n", info.inodes_per_group);
87a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Inode size: %d\n", info.inode_size);
88a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Label: %s\n", info.label);
89a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Blocks: %llu\n", aux_info.len_blocks);
90a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Block groups: %d\n", aux_info.groups);
91a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
92a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		printf("    Used %d/%d inodes and %d/%d blocks\n",
93a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
94a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_inodes_count,
95a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
96a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				aux_info.sb->s_blocks_count_lo);
97a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
98a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
99a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
100a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
101a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
102a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int bitmap_get_bit(u8 *bitmap, u32 bit)
103a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
104a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (bitmap[bit / 8] & 1 << (bit % 8))
105a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		return 1;
106a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
107a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
108a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
109a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
110a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossstatic int build_sparse_ext(int fd, const char *filename)
111a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
112a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	unsigned int i;
113a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	unsigned int block;
114a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int start_contiguous_block;
115a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	u8 *block_bitmap;
116a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	off64_t ret;
117a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
118a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	block_bitmap = malloc(info.block_size);
119a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (!block_bitmap)
120a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error("failed to allocate block bitmap");
121a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
122a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (aux_info.first_data_block > 0)
123a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		queue_data_file(filename, 0,
124a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				info.block_size * aux_info.first_data_block, 0);
125a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
126a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	for (i = 0; i < aux_info.groups; i++) {
127a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		u32 first_block = aux_info.first_data_block + i * info.blocks_per_group;
128a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		u32 last_block = min(info.blocks_per_group, aux_info.len_blocks - first_block);
129a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
130a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		ret = lseek64(fd, (u64)info.block_size * aux_info.bg_desc[i].bg_block_bitmap,
131a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				SEEK_SET);
132a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (ret < 0)
133a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			critical_error_errno("failed to seek to block group bitmap %d", i);
134a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
135a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		ret = read(fd, block_bitmap, info.block_size);
136a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (ret < 0)
137a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			critical_error_errno("failed to read block group bitmap %d", i);
138a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (ret != (int)info.block_size)
139a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			critical_error("failed to read all of block group bitmap %d", i);
140a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
141a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		start_contiguous_block = -1;
142a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		for (block = 0; block < last_block; block++) {
143a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			if (start_contiguous_block >= 0) {
144a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				if (!bitmap_get_bit(block_bitmap, block)) {
145a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					u32 start_block = first_block + start_contiguous_block;
146a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					u32 len_blocks = block - start_contiguous_block;
147a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
148a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					queue_data_file(filename, (u64)info.block_size * start_block,
149a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross							info.block_size * len_blocks, start_block);
150a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					start_contiguous_block = -1;
151a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				}
152a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			} else {
153a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross				if (bitmap_get_bit(block_bitmap, block))
154a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					start_contiguous_block = block;
155a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			}
156a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		}
157a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
158a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		if (start_contiguous_block >= 0) {
159a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			u32 start_block = first_block + start_contiguous_block;
160a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			u32 len_blocks = last_block - start_contiguous_block;
161a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			queue_data_file(filename, (u64)info.block_size * start_block,
162a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross					info.block_size * len_blocks, start_block);
163a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		}
164a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
165a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
166a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
167a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
168a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
169a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Crossint main(int argc, char **argv)
170a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross{
171a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int opt;
172a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	const char *in = NULL;
173a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	const char *out = NULL;
174a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int gzip = 0;
175a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int sparse = 1;
1760349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	int infd, outfd;
177a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	int crc = 0;
178a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
179a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	while ((opt = getopt(argc, argv, "cvzS")) != -1) {
180a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		switch (opt) {
181a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'c':
182a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			crc = 1;
183a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
184a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'v':
185a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			verbose = 1;
186a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
187a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'z':
188a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			gzip = 1;
189a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
190a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		case 'S':
191a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			sparse = 0;
192a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross			break;
193a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		}
194a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
195a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
196a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (optind >= argc) {
197a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		fprintf(stderr, "Expected image or block device after options\n");
198a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		usage(argv[0]);
199a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		exit(EXIT_FAILURE);
200a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
201a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
202a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	in = argv[optind++];
203a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
204a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (optind >= argc) {
205a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		fprintf(stderr, "Expected output image after input image\n");
206a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		usage(argv[0]);
207a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		exit(EXIT_FAILURE);
208a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
209a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
210a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	out = argv[optind++];
211a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
212a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	if (optind < argc) {
213a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
214a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		usage(argv[0]);
215a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		exit(EXIT_FAILURE);
216a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	}
217a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2180349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	infd = open(in, O_RDONLY);
219a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2200349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	if (infd < 0)
221a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross		critical_error_errno("failed to open input image");
222a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2230349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	read_ext(infd);
2240349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau
2250349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	build_sparse_ext(infd, in);
226a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2270349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	close(infd);
228a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
2290349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	if (strcmp(out, "-")) {
2300349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		outfd = open(out, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
2310349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		if (outfd < 0) {
2320349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau			error_errno("open");
2330349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau			return EXIT_FAILURE;
2340349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		}
2350349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	} else {
2360349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		outfd = STDOUT_FILENO;
2370349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	}
238a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
239dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross	write_ext4_image(outfd, gzip, sparse, crc);
2400349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	close(outfd);
241a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross
242a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross	return 0;
243a7ed433f2dc0116627a93b18fbb260f0665ca0cbColin Cross}
244