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