Clarify compile-time and run-time arithmetic safety assertions.
This is an experiment with a handful of macros for writing the
checks, most of which are compile-time:
MUL_OK(t, a, b) Does a*b avoid overflow in type t?
ADD_OK(t, a, b) Does a + b avoid overflow in type t?
TOOMANY(t, x, b, m) Are there more than m b-element blocks in x in type t?
(I.e., does ceiling(x/b) > m?)
Addenda that might make sense but are not needed here:
MUL(t, a, b, &p) Set p = a*b and return 0, or return ERANGE if overflow.
ADD(t, a, b, &s) Set s = a+b and return 0, or return ERANGE if overflow.
Example:
uint32_t a = ..., b = ..., y = ..., z = ..., x, w;
/* input validation */
error = MUL(size_t, a, b, &x);
if (error)
fail;
if (TOOMANY(uint32_t, x, BLKSIZ, MAX_NBLK))
fail;
y = HOWMANY(x, BLKSIZ);
if (z > Z_MAX)
fail;
...
/* internal computation */
__CTASSERT(MUL_OK(uint32_t, Z_MAX, MAX_NBLK));
w = z*y;
Obvious shortcomings:
1. Nothing checks your ctassert matches your subsequent arithmetic.
(Maybe we could have BOUNDED_MUL(t, x, xmax, y, ymax) with a
ctassert inside.)
2. Nothing flows the bounds needed by the arithmetic you use back
into candidate definitions of X_MAX/Y_MAX.
But at least the reviewer's job is only to make sure that (a) the
MUL_OK matches the *, and (b) the bounds in the assertion match the
bounds on the inputs -- in particular, the reviewer need not derive
the bounds from the context, only confirm they are supported by the
paths to it.
This is not meant to be a general-purpose proof assistant, or even a
special-purpose one like gfverif <http://gfverif.cryptojedi.org/>.
Rather, it is an experiment in adding a modicum of compile-time
verification with a simple C API change.
This also is not intended to serve as trapping arithmetic on
overflow. The goal here is to enable writing the program with
explicit checks on input and compile-time annotations on computation
to gain confident that overflow won't happen in the computation.
2017-07-30 00:04:07 +03:00
|
|
|
/* $NetBSD: vnduncompress.c,v 1.14 2017/07/29 21:04:07 riastradh Exp $ */
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2013 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Taylor R. Campbell.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
Clarify compile-time and run-time arithmetic safety assertions.
This is an experiment with a handful of macros for writing the
checks, most of which are compile-time:
MUL_OK(t, a, b) Does a*b avoid overflow in type t?
ADD_OK(t, a, b) Does a + b avoid overflow in type t?
TOOMANY(t, x, b, m) Are there more than m b-element blocks in x in type t?
(I.e., does ceiling(x/b) > m?)
Addenda that might make sense but are not needed here:
MUL(t, a, b, &p) Set p = a*b and return 0, or return ERANGE if overflow.
ADD(t, a, b, &s) Set s = a+b and return 0, or return ERANGE if overflow.
Example:
uint32_t a = ..., b = ..., y = ..., z = ..., x, w;
/* input validation */
error = MUL(size_t, a, b, &x);
if (error)
fail;
if (TOOMANY(uint32_t, x, BLKSIZ, MAX_NBLK))
fail;
y = HOWMANY(x, BLKSIZ);
if (z > Z_MAX)
fail;
...
/* internal computation */
__CTASSERT(MUL_OK(uint32_t, Z_MAX, MAX_NBLK));
w = z*y;
Obvious shortcomings:
1. Nothing checks your ctassert matches your subsequent arithmetic.
(Maybe we could have BOUNDED_MUL(t, x, xmax, y, ymax) with a
ctassert inside.)
2. Nothing flows the bounds needed by the arithmetic you use back
into candidate definitions of X_MAX/Y_MAX.
But at least the reviewer's job is only to make sure that (a) the
MUL_OK matches the *, and (b) the bounds in the assertion match the
bounds on the inputs -- in particular, the reviewer need not derive
the bounds from the context, only confirm they are supported by the
paths to it.
This is not meant to be a general-purpose proof assistant, or even a
special-purpose one like gfverif <http://gfverif.cryptojedi.org/>.
Rather, it is an experiment in adding a modicum of compile-time
verification with a simple C API change.
This also is not intended to serve as trapping arithmetic on
overflow. The goal here is to enable writing the program with
explicit checks on input and compile-time annotations on computation
to gain confident that overflow won't happen in the computation.
2017-07-30 00:04:07 +03:00
|
|
|
__RCSID("$NetBSD: vnduncompress.c,v 1.14 2017/07/29 21:04:07 riastradh Exp $");
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
#include <sys/endian.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <err.h>
|
2014-01-22 10:15:57 +04:00
|
|
|
#include <errno.h>
|
2013-05-04 03:28:15 +04:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <zlib.h>
|
|
|
|
|
|
|
|
#include "common.h"
|
2014-01-22 10:14:46 +04:00
|
|
|
#include "offtab.h"
|
2014-01-22 10:14:28 +04:00
|
|
|
#include "utils.h"
|
2013-05-04 03:28:15 +04:00
|
|
|
|
2014-01-22 10:17:34 +04:00
|
|
|
static void err1(const char *, ...) __printflike(1,2) __dead;
|
|
|
|
static void errx1(const char *, ...) __printflike(1,2) __dead;
|
2014-01-22 10:14:46 +04:00
|
|
|
|
2013-05-04 03:28:15 +04:00
|
|
|
int
|
|
|
|
vnduncompress(int argc, char **argv, const struct options *O __unused)
|
|
|
|
{
|
2014-01-22 10:14:46 +04:00
|
|
|
struct offtab offtab;
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
if (argc != 2)
|
|
|
|
usage();
|
|
|
|
|
|
|
|
const char *const cloop2_pathname = argv[0];
|
|
|
|
const char *const image_pathname = argv[1];
|
|
|
|
|
|
|
|
/* Open the cloop2 and image files. */
|
|
|
|
const int cloop2_fd = open(cloop2_pathname, O_RDONLY);
|
|
|
|
if (cloop2_fd == -1)
|
|
|
|
err(1, "open(%s)", cloop2_pathname);
|
|
|
|
|
|
|
|
const int image_fd = open(image_pathname,
|
|
|
|
(O_WRONLY | O_CREAT | O_TRUNC), 0777);
|
|
|
|
if (image_fd == -1)
|
|
|
|
err(1, "open(%s)", image_pathname);
|
|
|
|
|
|
|
|
/* Read the header. */
|
|
|
|
struct cloop2_header header;
|
2014-01-22 10:14:28 +04:00
|
|
|
const ssize_t h_read = read_block(cloop2_fd, &header, sizeof(header));
|
2013-05-04 03:28:15 +04:00
|
|
|
if (h_read == -1)
|
|
|
|
err(1, "read header");
|
|
|
|
assert(h_read >= 0);
|
|
|
|
if ((size_t)h_read != sizeof(header))
|
2013-05-07 02:53:24 +04:00
|
|
|
errx(1, "partial read of header: %zu != %zu",
|
|
|
|
(size_t)h_read, sizeof(header));
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
const uint32_t blocksize = be32toh(header.cl2h_blocksize);
|
|
|
|
const uint32_t n_blocks = be32toh(header.cl2h_n_blocks);
|
|
|
|
|
|
|
|
/* Sanity-check the header parameters. */
|
|
|
|
__CTASSERT(MIN_BLOCKSIZE <= UINT32_MAX);
|
|
|
|
if (blocksize < MIN_BLOCKSIZE)
|
|
|
|
errx(1, "blocksize too small: %"PRIu32
|
|
|
|
" (must be at least %"PRIu32")",
|
|
|
|
blocksize, (uint32_t)MIN_BLOCKSIZE);
|
|
|
|
__CTASSERT(MAX_BLOCKSIZE <= UINT32_MAX);
|
|
|
|
if (MAX_BLOCKSIZE < blocksize)
|
|
|
|
errx(1, "blocksize too large: %"PRIu32
|
|
|
|
" (must be at most %"PRIu32")",
|
|
|
|
blocksize, (uint32_t)MAX_BLOCKSIZE);
|
|
|
|
__CTASSERT(DEV_BSIZE <= UINT32_MAX);
|
|
|
|
if ((blocksize % DEV_BSIZE) != 0)
|
|
|
|
errx(1, "bad blocksize: %"PRIu32
|
|
|
|
" (not a multiple of %"PRIu32")",
|
|
|
|
blocksize, (uint32_t)DEV_BSIZE);
|
|
|
|
__CTASSERT(MAX_N_BLOCKS <= UINT32_MAX);
|
|
|
|
if (MAX_N_BLOCKS < n_blocks)
|
|
|
|
errx(1, "too many blocks: %"PRIu32" (max %"PRIu32")",
|
|
|
|
n_blocks, (uint32_t)MAX_N_BLOCKS);
|
|
|
|
|
2014-01-22 10:15:57 +04:00
|
|
|
/* Calculate the number of offsets we'll have to handle. */
|
2013-05-04 03:28:15 +04:00
|
|
|
__CTASSERT(MAX_N_BLOCKS <= (UINT32_MAX - 1));
|
|
|
|
__CTASSERT((MAX_N_BLOCKS + 1) == MAX_N_OFFSETS);
|
|
|
|
const uint32_t n_offsets = (n_blocks + 1);
|
2014-01-22 10:15:57 +04:00
|
|
|
|
2014-01-22 10:18:00 +04:00
|
|
|
/* Choose a working window size. */
|
|
|
|
uint32_t window_size;
|
|
|
|
if (ISSET(O->flags, FLAG_w) && (O->window_size < n_offsets)) {
|
2014-01-22 10:15:57 +04:00
|
|
|
if (lseek(cloop2_fd, 0, SEEK_CUR) == -1) {
|
|
|
|
if (errno == ESPIPE)
|
|
|
|
errx(1, "window too small, nonseekable input");
|
|
|
|
else
|
|
|
|
err(1, "window too small and lseek failed");
|
|
|
|
}
|
2014-01-22 10:18:00 +04:00
|
|
|
window_size = O->window_size;
|
|
|
|
} else {
|
|
|
|
if (lseek(cloop2_fd, 0, SEEK_CUR) == -1) {
|
|
|
|
if (errno != ESPIPE)
|
|
|
|
warn("lseek");
|
|
|
|
window_size = 0;
|
|
|
|
} else {
|
|
|
|
window_size = DEF_WINDOW_SIZE;
|
|
|
|
}
|
2014-01-22 10:15:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the offset table and start reading it in. */
|
2017-04-17 02:50:40 +03:00
|
|
|
__CTASSERT(CLOOP2_OFFSET_TABLE_OFFSET <= OFFTAB_MAX_FDPOS);
|
2014-01-22 10:18:00 +04:00
|
|
|
offtab_init(&offtab, n_offsets, window_size, cloop2_fd,
|
2014-01-22 10:15:22 +04:00
|
|
|
CLOOP2_OFFSET_TABLE_OFFSET);
|
2014-01-22 10:14:46 +04:00
|
|
|
offtab_reset_read(&offtab, &err1, &errx1);
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
/* Allocate compression buffers. */
|
|
|
|
/* XXX compression ratio bound */
|
Clarify compile-time and run-time arithmetic safety assertions.
This is an experiment with a handful of macros for writing the
checks, most of which are compile-time:
MUL_OK(t, a, b) Does a*b avoid overflow in type t?
ADD_OK(t, a, b) Does a + b avoid overflow in type t?
TOOMANY(t, x, b, m) Are there more than m b-element blocks in x in type t?
(I.e., does ceiling(x/b) > m?)
Addenda that might make sense but are not needed here:
MUL(t, a, b, &p) Set p = a*b and return 0, or return ERANGE if overflow.
ADD(t, a, b, &s) Set s = a+b and return 0, or return ERANGE if overflow.
Example:
uint32_t a = ..., b = ..., y = ..., z = ..., x, w;
/* input validation */
error = MUL(size_t, a, b, &x);
if (error)
fail;
if (TOOMANY(uint32_t, x, BLKSIZ, MAX_NBLK))
fail;
y = HOWMANY(x, BLKSIZ);
if (z > Z_MAX)
fail;
...
/* internal computation */
__CTASSERT(MUL_OK(uint32_t, Z_MAX, MAX_NBLK));
w = z*y;
Obvious shortcomings:
1. Nothing checks your ctassert matches your subsequent arithmetic.
(Maybe we could have BOUNDED_MUL(t, x, xmax, y, ymax) with a
ctassert inside.)
2. Nothing flows the bounds needed by the arithmetic you use back
into candidate definitions of X_MAX/Y_MAX.
But at least the reviewer's job is only to make sure that (a) the
MUL_OK matches the *, and (b) the bounds in the assertion match the
bounds on the inputs -- in particular, the reviewer need not derive
the bounds from the context, only confirm they are supported by the
paths to it.
This is not meant to be a general-purpose proof assistant, or even a
special-purpose one like gfverif <http://gfverif.cryptojedi.org/>.
Rather, it is an experiment in adding a modicum of compile-time
verification with a simple C API change.
This also is not intended to serve as trapping arithmetic on
overflow. The goal here is to enable writing the program with
explicit checks on input and compile-time annotations on computation
to gain confident that overflow won't happen in the computation.
2017-07-30 00:04:07 +03:00
|
|
|
__CTASSERT(MUL_OK(size_t, 2, MAX_BLOCKSIZE));
|
2013-05-04 03:28:15 +04:00
|
|
|
void *const compbuf = malloc(2 * (size_t)blocksize);
|
|
|
|
if (compbuf == NULL)
|
|
|
|
err(1, "malloc compressed buffer");
|
|
|
|
|
|
|
|
__CTASSERT(MAX_BLOCKSIZE <= SIZE_MAX);
|
|
|
|
void *const uncompbuf = malloc(blocksize);
|
|
|
|
if (uncompbuf == NULL)
|
|
|
|
err(1, "malloc uncompressed buffer");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Uncompress the blocks.
|
|
|
|
*/
|
Clarify compile-time and run-time arithmetic safety assertions.
This is an experiment with a handful of macros for writing the
checks, most of which are compile-time:
MUL_OK(t, a, b) Does a*b avoid overflow in type t?
ADD_OK(t, a, b) Does a + b avoid overflow in type t?
TOOMANY(t, x, b, m) Are there more than m b-element blocks in x in type t?
(I.e., does ceiling(x/b) > m?)
Addenda that might make sense but are not needed here:
MUL(t, a, b, &p) Set p = a*b and return 0, or return ERANGE if overflow.
ADD(t, a, b, &s) Set s = a+b and return 0, or return ERANGE if overflow.
Example:
uint32_t a = ..., b = ..., y = ..., z = ..., x, w;
/* input validation */
error = MUL(size_t, a, b, &x);
if (error)
fail;
if (TOOMANY(uint32_t, x, BLKSIZ, MAX_NBLK))
fail;
y = HOWMANY(x, BLKSIZ);
if (z > Z_MAX)
fail;
...
/* internal computation */
__CTASSERT(MUL_OK(uint32_t, Z_MAX, MAX_NBLK));
w = z*y;
Obvious shortcomings:
1. Nothing checks your ctassert matches your subsequent arithmetic.
(Maybe we could have BOUNDED_MUL(t, x, xmax, y, ymax) with a
ctassert inside.)
2. Nothing flows the bounds needed by the arithmetic you use back
into candidate definitions of X_MAX/Y_MAX.
But at least the reviewer's job is only to make sure that (a) the
MUL_OK matches the *, and (b) the bounds in the assertion match the
bounds on the inputs -- in particular, the reviewer need not derive
the bounds from the context, only confirm they are supported by the
paths to it.
This is not meant to be a general-purpose proof assistant, or even a
special-purpose one like gfverif <http://gfverif.cryptojedi.org/>.
Rather, it is an experiment in adding a modicum of compile-time
verification with a simple C API change.
This also is not intended to serve as trapping arithmetic on
overflow. The goal here is to enable writing the program with
explicit checks on input and compile-time annotations on computation
to gain confident that overflow won't happen in the computation.
2017-07-30 00:04:07 +03:00
|
|
|
__CTASSERT(MUL_OK(off_t, MAX_N_OFFSETS, sizeof(uint64_t)));
|
|
|
|
__CTASSERT(ADD_OK(off_t, sizeof(header),
|
|
|
|
(MAX_N_OFFSETS * sizeof(uint64_t))));
|
2013-05-04 03:28:15 +04:00
|
|
|
__CTASSERT(OFF_MAX <= UINT64_MAX);
|
2014-01-25 19:31:06 +04:00
|
|
|
uint64_t offset = (sizeof(header) +
|
|
|
|
((uint64_t)n_offsets * sizeof(uint64_t)));
|
2013-05-04 03:28:15 +04:00
|
|
|
uint32_t blkno;
|
2014-01-22 10:14:46 +04:00
|
|
|
(void)offtab_prepare_get(&offtab, 0);
|
|
|
|
uint64_t last = offtab_get(&offtab, 0);
|
2013-05-04 03:28:15 +04:00
|
|
|
for (blkno = 0; blkno < n_blocks; blkno++) {
|
2014-01-22 10:14:46 +04:00
|
|
|
(void)offtab_prepare_get(&offtab, (blkno + 1));
|
|
|
|
|
|
|
|
const uint64_t start = last;
|
|
|
|
const uint64_t end = offtab_get(&offtab, (blkno + 1));
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
/* Sanity-check the offsets. */
|
|
|
|
if (start != offset)
|
2014-01-22 10:15:12 +04:00
|
|
|
errx(1, "strange offset for block %"PRIu32
|
|
|
|
": 0x%"PRIx64,
|
2013-05-04 03:28:15 +04:00
|
|
|
blkno, start);
|
|
|
|
/* XXX compression ratio bound */
|
Clarify compile-time and run-time arithmetic safety assertions.
This is an experiment with a handful of macros for writing the
checks, most of which are compile-time:
MUL_OK(t, a, b) Does a*b avoid overflow in type t?
ADD_OK(t, a, b) Does a + b avoid overflow in type t?
TOOMANY(t, x, b, m) Are there more than m b-element blocks in x in type t?
(I.e., does ceiling(x/b) > m?)
Addenda that might make sense but are not needed here:
MUL(t, a, b, &p) Set p = a*b and return 0, or return ERANGE if overflow.
ADD(t, a, b, &s) Set s = a+b and return 0, or return ERANGE if overflow.
Example:
uint32_t a = ..., b = ..., y = ..., z = ..., x, w;
/* input validation */
error = MUL(size_t, a, b, &x);
if (error)
fail;
if (TOOMANY(uint32_t, x, BLKSIZ, MAX_NBLK))
fail;
y = HOWMANY(x, BLKSIZ);
if (z > Z_MAX)
fail;
...
/* internal computation */
__CTASSERT(MUL_OK(uint32_t, Z_MAX, MAX_NBLK));
w = z*y;
Obvious shortcomings:
1. Nothing checks your ctassert matches your subsequent arithmetic.
(Maybe we could have BOUNDED_MUL(t, x, xmax, y, ymax) with a
ctassert inside.)
2. Nothing flows the bounds needed by the arithmetic you use back
into candidate definitions of X_MAX/Y_MAX.
But at least the reviewer's job is only to make sure that (a) the
MUL_OK matches the *, and (b) the bounds in the assertion match the
bounds on the inputs -- in particular, the reviewer need not derive
the bounds from the context, only confirm they are supported by the
paths to it.
This is not meant to be a general-purpose proof assistant, or even a
special-purpose one like gfverif <http://gfverif.cryptojedi.org/>.
Rather, it is an experiment in adding a modicum of compile-time
verification with a simple C API change.
This also is not intended to serve as trapping arithmetic on
overflow. The goal here is to enable writing the program with
explicit checks on input and compile-time annotations on computation
to gain confident that overflow won't happen in the computation.
2017-07-30 00:04:07 +03:00
|
|
|
__CTASSERT(MUL_OK(size_t, 2, MAX_BLOCKSIZE));
|
2013-05-04 03:28:15 +04:00
|
|
|
if ((2 * (size_t)blocksize) <= (end - start))
|
2014-01-22 10:15:12 +04:00
|
|
|
errx(1, "block %"PRIu32" too large"
|
|
|
|
": %"PRIu64" bytes from 0x%"PRIx64" to 0x%"PRIx64,
|
|
|
|
blkno, (end - start), start, end);
|
2013-05-04 03:28:15 +04:00
|
|
|
assert(offset <= MIN(OFF_MAX, UINT64_MAX));
|
|
|
|
if ((MIN(OFF_MAX, UINT64_MAX) - offset) < (end - start))
|
|
|
|
errx(1, "block %"PRIu32" overflows offset:"
|
2014-01-22 10:15:12 +04:00
|
|
|
" 0x%"PRIx64" + %"PRIu64,
|
2013-05-04 03:28:15 +04:00
|
|
|
blkno, offset, (end - start));
|
|
|
|
|
|
|
|
/* Read the compressed block. */
|
2014-01-22 10:14:28 +04:00
|
|
|
const ssize_t n_read = read_block(cloop2_fd, compbuf,
|
|
|
|
(end - start));
|
2013-05-04 03:28:15 +04:00
|
|
|
if (n_read == -1)
|
|
|
|
err(1, "read block %"PRIu32, blkno);
|
|
|
|
assert(n_read >= 0);
|
|
|
|
if ((size_t)n_read != (end - start))
|
2013-05-07 02:53:24 +04:00
|
|
|
errx(1, "partial read of block %"PRIu32": %zu != %zu",
|
|
|
|
blkno, (size_t)n_read, (size_t)(end - start));
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
/* Uncompress the block. */
|
|
|
|
const unsigned long complen = (end - start);
|
|
|
|
unsigned long uncomplen = blocksize;
|
|
|
|
const int zerror = uncompress(uncompbuf, &uncomplen, compbuf,
|
|
|
|
complen);
|
|
|
|
if (zerror != Z_OK)
|
|
|
|
errx(1, "block %"PRIu32" decompression failure (%d)"
|
|
|
|
": %s", blkno, zerror, zError(zerror));
|
|
|
|
|
|
|
|
/* Sanity-check the uncompressed length. */
|
|
|
|
assert(uncomplen <= blocksize);
|
|
|
|
if (((blkno + 1) < n_blocks) && (uncomplen != blocksize))
|
|
|
|
errx(1, "truncated non-final block %"PRIu32
|
|
|
|
": %lu bytes", blkno, uncomplen);
|
|
|
|
|
|
|
|
/* Write the uncompressed block. */
|
|
|
|
const ssize_t n_written = write(image_fd, uncompbuf,
|
|
|
|
uncomplen);
|
|
|
|
if (n_written == -1)
|
|
|
|
err(1, "write block %"PRIu32, blkno);
|
|
|
|
assert(n_written >= 0);
|
|
|
|
if ((size_t)n_written != uncomplen)
|
2013-05-07 02:53:24 +04:00
|
|
|
errx(1, "partial write of block %"PRIu32": %zu != %lu",
|
|
|
|
blkno, (size_t)n_written, uncomplen);
|
2013-05-04 03:28:15 +04:00
|
|
|
|
|
|
|
/* Advance our position. */
|
|
|
|
assert((size_t)n_read <= (MIN(OFF_MAX, UINT64_MAX) - offset));
|
|
|
|
offset += (size_t)n_read;
|
2014-01-22 10:14:46 +04:00
|
|
|
last = end;
|
2013-05-04 03:28:15 +04:00
|
|
|
}
|
|
|
|
|
2014-01-22 10:14:46 +04:00
|
|
|
/* Destroy the offset table and free the compression buffers. */
|
|
|
|
offtab_destroy(&offtab);
|
2013-05-04 03:28:15 +04:00
|
|
|
free(uncompbuf);
|
|
|
|
free(compbuf);
|
|
|
|
|
|
|
|
/* Close the files. */
|
|
|
|
if (close(image_fd) == -1)
|
|
|
|
warn("close(image fd)");
|
|
|
|
if (close(cloop2_fd) == -1)
|
|
|
|
warn("close(cloop2 fd)");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2014-01-22 10:17:34 +04:00
|
|
|
|
|
|
|
static void __printflike(1,2) __dead
|
|
|
|
err1(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
va_start(va, fmt);
|
|
|
|
verr(1, fmt, va);
|
|
|
|
va_end(va);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __printflike(1,2) __dead
|
|
|
|
errx1(const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
|
|
|
|
va_start(va, fmt);
|
|
|
|
verrx(1, fmt, va);
|
|
|
|
va_end(va);
|
|
|
|
}
|