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