img2simg.c revision 28fa5bc347390480fe190294c6c385b6a9f0d68b
128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross/* 228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Copyright (C) 2010-2012 The Android Open Source Project 328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * 428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Licensed under the Apache License, Version 2.0 (the "License"); 528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * you may not use this file except in compliance with the License. 628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * You may obtain a copy of the License at 728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * 828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * http://www.apache.org/licenses/LICENSE-2.0 928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * 1028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Unless required by applicable law or agreed to in writing, software 1128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * distributed under the License is distributed on an "AS IS" BASIS, 1228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * See the License for the specific language governing permissions and 1428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * limitations under the License. 1528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross */ 1628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 1728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define DEFAULT_BLOCK_SIZE "4K" 1828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define DEFAULT_CHUNK_SIZE "64M" 1928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define DEFAULT_SUFFIX "%03d" 2028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 2128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include "sparse_format.h" 2228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#if 0 /* endian.h is not on all platforms */ 2328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross# include <endian.h> 2428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#else 2528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* For now, just assume we're going to run on little-endian. */ 2628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross# define my_htole32(h) (h) 2728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross# define my_htole16(h) (h) 2828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#endif 2928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <errno.h> 3028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <fcntl.h> 3128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <limits.h> 3228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdarg.h> 3328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stddef.h> 3428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdio.h> 3528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <stdlib.h> 3628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <string.h> 3728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <unistd.h> 3828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/stat.h> 3928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#include <sys/types.h> 4028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 4128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross#define COPY_BUF_SIZE (1024*1024) 4228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic char *copy_buf; 4328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 4428fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic const char *progname(const char *argv0) 4528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 4628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross const char *prog_name; 4728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if ((prog_name = strrchr(argv0, '/'))) 4828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return(prog_name + 1); /* Advance beyond '/'. */ 4928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return(argv0); /* No '/' in argv0, use it as is. */ 5028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 5128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 5228fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void error_exit(const char *fmt, ...) 5328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 5428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross va_list ap; 5528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross va_start(ap, fmt); 5628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross vfprintf(stderr, fmt, ap); 5728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fputc('\n', stderr); 5828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross va_end(ap); 5928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross exit(EXIT_FAILURE); 6128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 6228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 6328fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void usage(const char *argv0, const char *error_fmt, ...) 6428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 6528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, 6628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross "Usage: %s [OPTIONS] <raw_image_file>\n", 6728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross progname(argv0)); 6828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "The <raw_image_file> will be split into as many sparse\n"); 6928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "files as needed. Each sparse file will contain a single\n"); 7028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "DONT CARE chunk to offset to the correct block and then\n"); 7128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "a single RAW chunk containing a portion of the data from\n"); 7228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "the raw image file. The sparse files will be named by\n"); 7328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "appending a number to the name of the raw image file.\n"); 7428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "\n"); 7528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "OPTIONS (Defaults are enclosed by square brackets):\n"); 7628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " -s SUFFIX Format appended number with SUFFIX [%s]\n", 7728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross DEFAULT_SUFFIX); 7828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " -B SIZE Use a block size of SIZE [%s]\n", 7928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross DEFAULT_BLOCK_SIZE); 8028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " -C SIZE Use a chunk size of SIZE [%s]\n", 8128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross DEFAULT_CHUNK_SIZE); 8228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "SIZE is a decimal integer that may optionally be\n"); 8328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "followed by a suffix that specifies a multiplier for\n"); 8428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "the integer:\n"); 8528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " c 1 byte (the default when omitted)\n"); 8628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " w 2 bytes\n"); 8728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " b 512 bytes\n"); 8828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " kB 1000 bytes\n"); 8928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " K 1024 bytes\n"); 9028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " MB 1000*1000 bytes\n"); 9128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " M 1024*1024 bytes\n"); 9228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " GB 1000*1000*1000 bytes\n"); 9328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, " G 1024*1024*1024 bytes\n"); 9428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 9528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (error_fmt && *error_fmt) 9628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross { 9728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "\n"); 9828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross va_list ap; 9928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross va_start(ap, error_fmt); 10028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross vfprintf(stderr, error_fmt, ap); 10128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross va_end(ap); 10228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross fprintf(stderr, "\n"); 10328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 10428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 10528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross exit(EXIT_FAILURE); 10628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 10728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 10828fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic void cpy_file(int out_fd, char *out_path, int in_fd, char *in_path, 10928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross size_t len) 11028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 11128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ssize_t s, cpy_len = COPY_BUF_SIZE; 11228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 11328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross while (len) { 11428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (len < COPY_BUF_SIZE) 11528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross cpy_len = len; 11628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 11728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross s = read(in_fd, copy_buf, cpy_len); 11828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (s < 0) 11928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("\"%s\": %s", in_path, strerror(errno)); 12028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!s) 12128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("\"%s\": Unexpected EOF", in_path); 12228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross cpy_len = s; 12428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 12528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross s = write(out_fd, copy_buf, cpy_len); 12628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (s < 0) 12728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("\"%s\": %s", out_path, strerror(errno)); 12828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (s != cpy_len) 12928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("\"%s\": Short data write (%lu)", out_path, 13028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross (unsigned long)s); 13128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 13228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross len -= cpy_len; 13328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 13428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 13528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 13628fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossstatic int parse_size(const char *size_str, size_t *size) 13728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 13828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross static const size_t MAX_SIZE_T = ~(size_t)0; 13928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross size_t mult; 14028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned long long int value; 14128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross const char *end; 14228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross errno = 0; 14328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross value = strtoull(size_str, (char **)&end, 10); 14428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (errno != 0 || end == size_str || value > MAX_SIZE_T) 14528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 14628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (*end == '\0') { 14728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross *size = value; 14828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 14928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 15028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (!strcmp(end, "c")) 15128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = 1; 15228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "w")) 15328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = 2; 15428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "b")) 15528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = 512; 15628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "kB")) 15728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = 1000; 15828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "K")) 15928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = 1024; 16028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "MB")) 16128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = (size_t)1000*1000; 16228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "M")) 16328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = (size_t)1024*1024; 16428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "GB")) 16528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = (size_t)1000*1000*1000; 16628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else if (!strcmp(end, "G")) 16728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross mult = (size_t)1024*1024*1024; 16828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross else 16928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 17028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 17128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (value > MAX_SIZE_T / mult) 17228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return -1; 17328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross *size = value * mult; 17428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross return 0; 17528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 17628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 17728fa5bc347390480fe190294c6c385b6a9f0d68bColin Crossint main(int argc, char *argv[]) 17828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross{ 17928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross char *suffix = DEFAULT_SUFFIX; 18028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross char *block_size_str = DEFAULT_BLOCK_SIZE; 18128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross char *chunk_size_str = DEFAULT_CHUNK_SIZE; 18228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross size_t block_size, chunk_size, blocks_per_chunk, to_write; 18328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross char *in_path, *out_path, *out_fmt; 18428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int in_fd, out_fd; 18528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct stat in_st; 18628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross off_t left_to_write; 18728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross struct { 18828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sparse_header_t sparse_hdr; 18928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t dont_care_hdr; 19028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_header_t raw_hdr; 19128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } file_hdr; 19228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross unsigned int file_count; 19328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross ssize_t s; 19428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross int i; 19528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 19628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Parse the command line. */ 19728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross while ((i = getopt(argc, argv, "s:B:C:")) != -1) 19828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross { 19928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross switch (i) { 20028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross case 's': 20128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross suffix = optarg; 20228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross break; 20328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross case 'B': 20428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross block_size_str = optarg; 20528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross break; 20628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross case 'C': 20728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_size_str = optarg; 20828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross break; 20928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross default: 21028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross usage(argv[0], NULL); 21128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross break; 21228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 21328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 21428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 21528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (parse_size(block_size_str, &block_size)) 21628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross usage(argv[0], "Can not parse \"%s\" as a block size.", 21728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross block_size_str); 21828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (block_size % 4096) 21928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross usage(argv[0], "Block size is not a multiple of 4096."); 22028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 22128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (parse_size(chunk_size_str, &chunk_size)) 22228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross usage(argv[0], "Can not parse \"%s\" as a chunk size.", 22328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross chunk_size_str); 22428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (chunk_size % block_size) 22528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross usage(argv[0], "Chunk size is not a multiple of the block size."); 22628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross blocks_per_chunk = chunk_size / block_size; 22728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 22828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if ((argc - optind) != 1) 22928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross usage(argv[0], "Missing or extra arguments."); 23028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross in_path = argv[optind]; 23128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 23228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Open the input file and validate it. */ 23328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if ((in_fd = open(in_path, O_RDONLY)) < 0) 23428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("open \"%s\": %s", in_path, strerror(errno)); 23528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (fstat(in_fd, &in_st)) 23628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("fstat \"%s\": %s", in_path, strerror(errno)); 23728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross left_to_write = in_st.st_size; 23828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (left_to_write % block_size) 23928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit( 24028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross "\"%s\" size (%llu) is not a multiple of the block size (%llu).\n", 24128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross in_path, 24228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross (unsigned long long)left_to_write, (unsigned long long)block_size); 24328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 24428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Get a buffer for copying the chunks. */ 24528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if ((copy_buf = malloc(COPY_BUF_SIZE)) == 0) 24628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("malloc copy buffer: %s", strerror(errno)); 24728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 24828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Get a buffer for a sprintf format to form output paths. */ 24928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if ((out_fmt = malloc(sizeof("%s") + strlen(suffix))) == 0) 25028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("malloc format buffer: %s", strerror(errno)); 25128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out_fmt[0] = '%'; 25228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross out_fmt[1] = 's'; 25328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross strcpy(out_fmt + 2, suffix); 25428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 25528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Get a buffer for an output path. */ 25628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross i = snprintf(copy_buf, COPY_BUF_SIZE, out_fmt, in_path, UINT_MAX); 25728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (i >= COPY_BUF_SIZE) 25828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("Ridulously long suffix: %s", suffix); 25928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if ((out_path = malloc(i + 1)) == 0) 26028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("malloc output path buffer: %s", strerror(errno)); 26128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 26228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* 26328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * Each file gets a sparse_header, a Don't Care chunk to offset to 26428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross * where the data belongs and then a Raw chunk with the actual data. 26528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross */ 26628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross memset((void *)&file_hdr.sparse_hdr, 0, sizeof(file_hdr.sparse_hdr)); 26728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.magic = my_htole32(SPARSE_HEADER_MAGIC); 26828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.major_version = my_htole16(1); 26928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.minor_version = my_htole16(0); 27028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.file_hdr_sz = my_htole16(sizeof(sparse_header_t)); 27128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.chunk_hdr_sz = my_htole16(sizeof(chunk_header_t)); 27228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.blk_sz = my_htole32(block_size); 27328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* The total_blks will be set in the file loop below. */ 27428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.total_chunks = my_htole32(2); 27528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.image_checksum = my_htole32(0); /* Typically unused. */ 27628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 27728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross memset((void *)&file_hdr.dont_care_hdr, 0, sizeof(file_hdr.dont_care_hdr)); 27828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.dont_care_hdr.chunk_type = my_htole16(CHUNK_TYPE_DONT_CARE); 27928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* The Don't Care's chunk_sz will be set in the file loop below. */ 28028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.dont_care_hdr.total_sz = my_htole32(sizeof(chunk_header_t)); 28128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 28228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross memset((void *)&file_hdr.raw_hdr, 0, sizeof(file_hdr.raw_hdr)); 28328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.raw_hdr.chunk_type = my_htole16(CHUNK_TYPE_RAW); 28428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.raw_hdr.chunk_sz = my_htole32(blocks_per_chunk); 28528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.raw_hdr.total_sz = my_htole32(chunk_size + sizeof(chunk_header_t)); 28628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 28728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Loop through writing chunk_size to each of the output files. */ 28828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross to_write = chunk_size; 28928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross for (file_count = 1; left_to_write ; file_count++) { 29028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Fix up the headers on the last block. */ 29128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (left_to_write < (off_t)chunk_size) { 29228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross to_write = left_to_write; 29328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.raw_hdr.chunk_sz = my_htole32(left_to_write / block_size); 29428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.raw_hdr.total_sz = my_htole32(left_to_write 29528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross + sizeof(chunk_header_t)); 29628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 29728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 29828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Form the pathname for this output file and open it. */ 29928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross sprintf(out_path, out_fmt, in_path, file_count); 30028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if ((out_fd = creat(out_path, 0666)) < 0) 30128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("\"%s\": %s", out_path, strerror(errno)); 30228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 30328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Update and write the headers to this output file. */ 30428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross s = (file_count-1) * blocks_per_chunk; 30528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.dont_care_hdr.chunk_sz = my_htole32(s); 30628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross file_hdr.sparse_hdr.total_blks = my_htole32(s 30728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross + (to_write / block_size)); 30828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross s = write(out_fd, (void *)&file_hdr, sizeof(file_hdr)); 30928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (s < 0) 31028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("\"%s\": %s", out_path, strerror(errno)); 31128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (s != sizeof(file_hdr)) 31228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("\"%s\": Short write (%lu)", out_path, (unsigned long)s); 31328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 31428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Copy this chunk from the input file to the output file. */ 31528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross cpy_file(out_fd, out_path, in_fd, in_path, to_write); 31628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 31728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross /* Close this output file and update the amount left to write. */ 31828fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (close(out_fd)) 31928fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("close \"%s\": %s", out_path, strerror(errno)); 32028fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross left_to_write -= to_write; 32128fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross } 32228fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 32328fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross if (close(in_fd)) 32428fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross error_exit("close \"%s\": %s", in_path, strerror(errno)); 32528fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross 32628fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross exit(EXIT_SUCCESS); 32728fa5bc347390480fe190294c6c385b6a9f0d68bColin Cross} 328