175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall/* 275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * Copyright (C) 2010 The Android Open Source Project 375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * 475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * Licensed under the Apache License, Version 2.0 (the "License"); 575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * you may not use this file except in compliance with the License. 675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * You may obtain a copy of the License at 775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * 875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * http://www.apache.org/licenses/LICENSE-2.0 975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * 1075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * Unless required by applicable law or agreed to in writing, software 1175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * distributed under the License is distributed on an "AS IS" BASIS, 1275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * See the License for the specific language governing permissions and 1475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * limitations under the License. 1575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall */ 1633f96c66e9a1f2e266a75e5e84c091dffa6ef118Colin Cross 1733f96c66e9a1f2e266a75e5e84c091dffa6ef118Colin Cross#include "ext4_utils.h" 1833f96c66e9a1f2e266a75e5e84c091dffa6ef118Colin Cross#include "sparse_format.h" 1933f96c66e9a1f2e266a75e5e84c091dffa6ef118Colin Cross#include "sparse_crc32.h" 2075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 2175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#include <sys/types.h> 2275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#include <sys/stat.h> 2375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#include <sys/types.h> 2475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#include <sys/mman.h> 2575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#include <unistd.h> 2675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#include <fcntl.h> 2775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#include <stdio.h> 2875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 2975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#define COPY_BUF_SIZE (1024*1024) 3075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrallu8 *copybuf; 3175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 325a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall/* This will be malloc'ed with the size of blk_sz from the sparse file header */ 335a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrallu8* zerobuf; 345a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall 3575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#define SPARSE_HEADER_MAJOR_VER 1 3675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) 3775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall#define CHUNK_HEADER_LEN (sizeof(chunk_header_t)) 3875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 3975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrallvoid usage() 4075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall{ 4175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Usage: simg2img <sparse_image_file> <raw_image_file>\n"); 4275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall} 4375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 440b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Crossstatic int read_all(int fd, void *buf, size_t len) 450b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross{ 460b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross size_t total = 0; 470b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross int ret; 480b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross char *ptr = buf; 490b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 500b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross while (total < len) { 510b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret = read(fd, ptr, len - total); 520b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 530b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret < 0) 540b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross return ret; 550b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 560b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret == 0) 570b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross return total; 580b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 590b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ptr += ret; 600b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross total += ret; 610b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross } 620b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 630b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross return total; 640b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross} 650b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 660b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Crossstatic int write_all(int fd, void *buf, size_t len) 670b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross{ 680b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross size_t total = 0; 690b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross int ret; 700b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross char *ptr = buf; 710b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 720b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross while (total < len) { 730b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret = write(fd, ptr, len - total); 740b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 750b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret < 0) 760b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross return ret; 770b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 780b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret == 0) 790b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross return total; 800b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 810b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ptr += ret; 820b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross total += ret; 830b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross } 840b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 850b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross return total; 860b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross} 870b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 880b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Crossint process_raw_chunk(int in, int out, u32 blocks, u32 blk_sz, u32 *crc32) 8975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall{ 9075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall u64 len = (u64)blocks * blk_sz; 910b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross int ret; 9275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall int chunk; 9375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 9475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall while (len) { 9575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall chunk = (len > COPY_BUF_SIZE) ? COPY_BUF_SIZE : len; 960b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret = read_all(in, copybuf, chunk); 970b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret != chunk) { 980b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross fprintf(stderr, "read returned an error copying a raw chunk: %d %d\n", 990b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret, chunk); 1005a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall exit(-1); 1015a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall } 1025a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall *crc32 = sparse_crc32(*crc32, copybuf, chunk); 1030b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret = write_all(out, copybuf, chunk); 1040b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret != chunk) { 1050b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross fprintf(stderr, "write returned an error copying a raw chunk\n"); 1065a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall exit(-1); 1075a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall } 10875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall len -= chunk; 10975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 11075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 11175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall return blocks; 11275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall} 11375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 11475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 115dba332410528d11474ae9f878b6984755d55e299Ken Sumrallint process_fill_chunk(int in, int out, u32 blocks, u32 blk_sz, u32 *crc32) 116dba332410528d11474ae9f878b6984755d55e299Ken Sumrall{ 117dba332410528d11474ae9f878b6984755d55e299Ken Sumrall u64 len = (u64)blocks * blk_sz; 118dba332410528d11474ae9f878b6984755d55e299Ken Sumrall int ret; 119dba332410528d11474ae9f878b6984755d55e299Ken Sumrall int chunk; 120dba332410528d11474ae9f878b6984755d55e299Ken Sumrall u32 fill_val; 121dba332410528d11474ae9f878b6984755d55e299Ken Sumrall u32 *fillbuf; 122dba332410528d11474ae9f878b6984755d55e299Ken Sumrall unsigned int i; 123dba332410528d11474ae9f878b6984755d55e299Ken Sumrall 124dba332410528d11474ae9f878b6984755d55e299Ken Sumrall /* Fill copy_buf with the fill value */ 125dba332410528d11474ae9f878b6984755d55e299Ken Sumrall ret = read_all(in, &fill_val, sizeof(fill_val)); 126dba332410528d11474ae9f878b6984755d55e299Ken Sumrall fillbuf = (u32 *)copybuf; 127dba332410528d11474ae9f878b6984755d55e299Ken Sumrall for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) { 128dba332410528d11474ae9f878b6984755d55e299Ken Sumrall fillbuf[i] = fill_val; 129dba332410528d11474ae9f878b6984755d55e299Ken Sumrall } 130dba332410528d11474ae9f878b6984755d55e299Ken Sumrall 131dba332410528d11474ae9f878b6984755d55e299Ken Sumrall while (len) { 132dba332410528d11474ae9f878b6984755d55e299Ken Sumrall chunk = (len > COPY_BUF_SIZE) ? COPY_BUF_SIZE : len; 133dba332410528d11474ae9f878b6984755d55e299Ken Sumrall *crc32 = sparse_crc32(*crc32, copybuf, chunk); 134dba332410528d11474ae9f878b6984755d55e299Ken Sumrall ret = write_all(out, copybuf, chunk); 135dba332410528d11474ae9f878b6984755d55e299Ken Sumrall if (ret != chunk) { 136dba332410528d11474ae9f878b6984755d55e299Ken Sumrall fprintf(stderr, "write returned an error copying a raw chunk\n"); 137dba332410528d11474ae9f878b6984755d55e299Ken Sumrall exit(-1); 138dba332410528d11474ae9f878b6984755d55e299Ken Sumrall } 139dba332410528d11474ae9f878b6984755d55e299Ken Sumrall len -= chunk; 140dba332410528d11474ae9f878b6984755d55e299Ken Sumrall } 141dba332410528d11474ae9f878b6984755d55e299Ken Sumrall 142dba332410528d11474ae9f878b6984755d55e299Ken Sumrall return blocks; 143dba332410528d11474ae9f878b6984755d55e299Ken Sumrall} 144dba332410528d11474ae9f878b6984755d55e299Ken Sumrall 1450b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Crossint process_skip_chunk(int out, u32 blocks, u32 blk_sz, u32 *crc32) 14675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall{ 14775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall /* len needs to be 64 bits, as the sparse file specifies the skip amount 14875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * as a 32 bit value of blocks. 14975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall */ 15075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall u64 len = (u64)blocks * blk_sz; 15175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 1520b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross lseek64(out, len, SEEK_CUR); 15375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 15475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall return blocks; 15575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall} 15675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 1570b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Crossint process_crc32_chunk(int in, u32 crc32) 158757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross{ 159757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross u32 file_crc32; 1600b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross int ret; 1610b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross 1620b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret = read_all(in, &file_crc32, 4); 1630b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret != 4) { 1640b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross fprintf(stderr, "read returned an error copying a crc32 chunk\n"); 165757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross exit(-1); 166757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross } 167757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross 168757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross if (file_crc32 != crc32) { 169757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross fprintf(stderr, "computed crc32 of 0x%8.8x, expected 0x%8.8x\n", 170757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross crc32, file_crc32); 171757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross exit(-1); 172757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross } 173757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross 174757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross return 0; 175757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross} 176757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross 17775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrallint main(int argc, char *argv[]) 17875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall{ 1790b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross int in; 1800b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross int out; 18175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall unsigned int i; 18275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall sparse_header_t sparse_header; 18375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall chunk_header_t chunk_header; 18475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall u32 crc32 = 0; 18575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall u32 total_blocks = 0; 1860b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross int ret; 18775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 18875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (argc != 3) { 18975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall usage(); 19075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 19175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 19275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 19375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if ( (copybuf = malloc(COPY_BUF_SIZE)) == 0) { 19475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Cannot malloc copy buf\n"); 19575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 19675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 19775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 1980b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (strcmp(argv[1], "-") == 0) { 1990b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross in = STDIN_FILENO; 2000b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross } else { 2010b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if ((in = open(argv[1], O_RDONLY)) == 0) { 2020b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross fprintf(stderr, "Cannot open input file %s\n", argv[1]); 2030b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross exit(-1); 2040b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross } 20575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 20675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 2070b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (strcmp(argv[2], "-") == 0) { 2080b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross out = STDOUT_FILENO; 2090b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross } else { 210e246d8693582b3d952fa52c28cd2ea97e8a7aa14Ken Sumrall if ((out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666)) == 0) { 2110b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross fprintf(stderr, "Cannot open output file %s\n", argv[2]); 2120b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross exit(-1); 2130b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross } 21475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 21575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 2160b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret = read_all(in, &sparse_header, sizeof(sparse_header)); 2170b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret != sizeof(sparse_header)) { 21875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Error reading sparse file header\n"); 21975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 22075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 22175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 22275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (sparse_header.magic != SPARSE_HEADER_MAGIC) { 22375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Bad magic\n"); 22475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 22575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 22675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 22775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) { 22875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Unknown major version number\n"); 22975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 23075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 23175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 23275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) { 23375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall /* Skip the remaining bytes in a header that is longer than 23475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * we expected. 23575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall */ 2360b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross lseek64(in, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR); 23775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 23875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 2395a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall if ( (zerobuf = malloc(sparse_header.blk_sz)) == 0) { 2405a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall fprintf(stderr, "Cannot malloc zero buf\n"); 2415a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall exit(-1); 2425a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall } 2435a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall 24475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall for (i=0; i<sparse_header.total_chunks; i++) { 2450b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross ret = read_all(in, &chunk_header, sizeof(chunk_header)); 2460b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ret != sizeof(chunk_header)) { 24775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Error reading chunk header\n"); 24875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 24975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 25075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 25175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) { 25275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall /* Skip the remaining bytes in a header that is longer than 25375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * we expected. 25475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall */ 2550b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross lseek64(in, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR); 25675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 25775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 25875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall switch (chunk_header.chunk_type) { 25975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall case CHUNK_TYPE_RAW: 26075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (chunk_header.total_sz != (sparse_header.chunk_hdr_sz + 26175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall (chunk_header.chunk_sz * sparse_header.blk_sz)) ) { 26275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Bogus chunk size for chunk %d, type Raw\n", i); 26375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 26475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 26575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall total_blocks += process_raw_chunk(in, out, 26675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall chunk_header.chunk_sz, sparse_header.blk_sz, &crc32); 26775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall break; 268dba332410528d11474ae9f878b6984755d55e299Ken Sumrall case CHUNK_TYPE_FILL: 269dba332410528d11474ae9f878b6984755d55e299Ken Sumrall if (chunk_header.total_sz != (sparse_header.chunk_hdr_sz + sizeof(u32)) ) { 270dba332410528d11474ae9f878b6984755d55e299Ken Sumrall fprintf(stderr, "Bogus chunk size for chunk %d, type Fill\n", i); 271dba332410528d11474ae9f878b6984755d55e299Ken Sumrall exit(-1); 272dba332410528d11474ae9f878b6984755d55e299Ken Sumrall } 273dba332410528d11474ae9f878b6984755d55e299Ken Sumrall total_blocks += process_fill_chunk(in, out, 274dba332410528d11474ae9f878b6984755d55e299Ken Sumrall chunk_header.chunk_sz, sparse_header.blk_sz, &crc32); 275dba332410528d11474ae9f878b6984755d55e299Ken Sumrall break; 27675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall case CHUNK_TYPE_DONT_CARE: 27775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (chunk_header.total_sz != sparse_header.chunk_hdr_sz) { 27875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Bogus chunk size for chunk %d, type Dont Care\n", i); 27975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 28075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 28175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall total_blocks += process_skip_chunk(out, 28275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall chunk_header.chunk_sz, sparse_header.blk_sz, &crc32); 28375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall break; 284757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross case CHUNK_TYPE_CRC32: 285757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross process_crc32_chunk(in, crc32); 286757ace516d8e4350616b5fd10da0c982d3d5ec74Colin Cross break; 28775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall default: 28875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Unknown chunk type 0x%4.4x\n", chunk_header.chunk_type); 28975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 29075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 29175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 29275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 29375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall /* If the last chunk was a skip, then the code just did a seek, but 29475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * no write, and the file won't actually be the correct size. This 29575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * will make the file the correct size. Make sure the offset is 29675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall * computed in 64 bits, and the function called can handle 64 bits. 29775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall */ 2980b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross if (ftruncate64(out, (u64)total_blocks * sparse_header.blk_sz)) { 2995a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall fprintf(stderr, "Error calling ftruncate() to set the image size\n"); 3005a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall exit(-1); 3015a6181798de5c2d882c79b27406c330a6fa7da3eKen Sumrall } 30275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 3030b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross close(in); 3040b7cb80f7bcd8ef3fa0c79d2cb5e9c5f78a93250Colin Cross close(out); 30575249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 30675249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall if (sparse_header.total_blks != total_blocks) { 30775249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall fprintf(stderr, "Wrote %d blocks, expected to write %d blocks\n", 30875249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall total_blocks, sparse_header.total_blks); 30975249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(-1); 31075249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall } 31175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 31275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall exit(0); 31375249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall} 31475249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall 315