ext2simg.c revision dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7
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 <sparse/sparse.h> 18 19#include "ext4_utils.h" 20#include "make_ext4fs.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 35extern struct fs_info info; 36 37static int verbose = 0; 38 39static 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 49static 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 102static 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 110static 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 169int 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); 240 close(outfd); 241 242 return 0; 243} 244