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