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