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#define _FILE_OFFSET_BITS 64 18#define _LARGEFILE64_SOURCE 1 19 20#include <sys/types.h> 21#include <sys/stat.h> 22#include <sys/types.h> 23#include <sys/mman.h> 24#include <fcntl.h> 25#include <libgen.h> 26#include <unistd.h> 27 28#include <sparse/sparse.h> 29 30#include "ext4_utils.h" 31#include "make_ext4fs.h" 32#include "allocate.h" 33 34#if defined(__APPLE__) && defined(__MACH__) 35#define off64_t off_t 36#endif 37 38#ifndef USE_MINGW /* O_BINARY is windows-specific flag */ 39#define O_BINARY 0 40#endif 41 42extern struct fs_info info; 43 44static int verbose = 0; 45 46static void usage(char *path) 47{ 48 fprintf(stderr, "%s [ options ] <image or block device> <output image>\n", path); 49 fprintf(stderr, "\n"); 50 fprintf(stderr, " -c include CRC block\n"); 51 fprintf(stderr, " -v verbose output\n"); 52 fprintf(stderr, " -z gzip output\n"); 53 fprintf(stderr, " -S don't use sparse output format\n"); 54} 55 56static int build_sparse_ext(int fd, const char *filename) 57{ 58 unsigned int i; 59 unsigned int block; 60 int start_contiguous_block; 61 u8 *block_bitmap; 62 off64_t ret; 63 64 block_bitmap = malloc(info.block_size); 65 if (!block_bitmap) 66 critical_error("failed to allocate block bitmap"); 67 68 if (aux_info.first_data_block > 0) 69 sparse_file_add_file(ext4_sparse_file, filename, 0, 70 info.block_size * aux_info.first_data_block, 0); 71 72 for (i = 0; i < aux_info.groups; i++) { 73 u32 first_block = aux_info.first_data_block + i * info.blocks_per_group; 74 u32 last_block = min(info.blocks_per_group, aux_info.len_blocks - first_block); 75 76 ret = lseek64(fd, (u64)info.block_size * aux_info.bg_desc[i].bg_block_bitmap, 77 SEEK_SET); 78 if (ret < 0) 79 critical_error_errno("failed to seek to block group bitmap %d", i); 80 81 ret = read(fd, block_bitmap, info.block_size); 82 if (ret < 0) 83 critical_error_errno("failed to read block group bitmap %d", i); 84 if (ret != (int)info.block_size) 85 critical_error("failed to read all of block group bitmap %d", i); 86 87 start_contiguous_block = -1; 88 for (block = 0; block < last_block; block++) { 89 if (start_contiguous_block >= 0) { 90 if (!bitmap_get_bit(block_bitmap, block)) { 91 u32 start_block = first_block + start_contiguous_block; 92 u32 len_blocks = block - start_contiguous_block; 93 94 sparse_file_add_file(ext4_sparse_file, filename, 95 (u64)info.block_size * start_block, 96 info.block_size * len_blocks, start_block); 97 start_contiguous_block = -1; 98 } 99 } else { 100 if (bitmap_get_bit(block_bitmap, block)) 101 start_contiguous_block = block; 102 } 103 } 104 105 if (start_contiguous_block >= 0) { 106 u32 start_block = first_block + start_contiguous_block; 107 u32 len_blocks = last_block - start_contiguous_block; 108 sparse_file_add_file(ext4_sparse_file, filename, 109 (u64)info.block_size * start_block, 110 info.block_size * len_blocks, start_block); 111 } 112 } 113 114 return 0; 115} 116 117int main(int argc, char **argv) 118{ 119 int opt; 120 const char *in = NULL; 121 const char *out = NULL; 122 int gzip = 0; 123 int sparse = 1; 124 int infd, outfd; 125 int crc = 0; 126 127 while ((opt = getopt(argc, argv, "cvzS")) != -1) { 128 switch (opt) { 129 case 'c': 130 crc = 1; 131 break; 132 case 'v': 133 verbose = 1; 134 break; 135 case 'z': 136 gzip = 1; 137 break; 138 case 'S': 139 sparse = 0; 140 break; 141 } 142 } 143 144 if (optind >= argc) { 145 fprintf(stderr, "Expected image or block device after options\n"); 146 usage(argv[0]); 147 exit(EXIT_FAILURE); 148 } 149 150 in = argv[optind++]; 151 152 if (optind >= argc) { 153 fprintf(stderr, "Expected output image after input image\n"); 154 usage(argv[0]); 155 exit(EXIT_FAILURE); 156 } 157 158 out = argv[optind++]; 159 160 if (optind < argc) { 161 fprintf(stderr, "Unexpected argument: %s\n", argv[optind]); 162 usage(argv[0]); 163 exit(EXIT_FAILURE); 164 } 165 166 infd = open(in, O_RDONLY); 167 168 if (infd < 0) 169 critical_error_errno("failed to open input image"); 170 171 read_ext(infd, verbose); 172 173 ext4_sparse_file = sparse_file_new(info.block_size, info.len); 174 175 build_sparse_ext(infd, in); 176 177 close(infd); 178 179 if (strcmp(out, "-")) { 180 outfd = open(out, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); 181 if (outfd < 0) { 182 error_errno("open"); 183 return EXIT_FAILURE; 184 } 185 } else { 186 outfd = STDOUT_FILENO; 187 } 188 189 write_ext4_image(outfd, gzip, sparse, crc); 190 close(outfd); 191 192 sparse_file_destroy(ext4_sparse_file); 193 194 return 0; 195} 196