Home | History | Annotate | Download | only in ext4_utils
      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 extern struct fs_info info;
     32 
     33 static int verbose = 0;
     34 
     35 static 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 
     45 static 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 
     98 static 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 
    106 static 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 
    165 int 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