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