2013-02-09 21:17:57 +04:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2003-2007 Tim Kientzle
|
|
|
|
* Copyright (c) 2012 Michihiro NAKAJIMA
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* 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 AUTHOR(S) ``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 AUTHOR(S) 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 "archive_platform.h"
|
|
|
|
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ERRNO_H
|
|
|
|
#include <errno.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
|
|
#include <stdlib.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
#include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_LZO_LZOCONF_H
|
|
|
|
#include <lzo/lzoconf.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_LZO_LZO1X_H
|
|
|
|
#include <lzo/lzo1x.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ZLIB_H
|
2013-07-27 00:22:48 +04:00
|
|
|
#include <cm_zlib.h> /* for crc32 and adler32 */
|
2013-02-09 21:17:57 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "archive.h"
|
|
|
|
#if !defined(HAVE_ZLIB_H) &&\
|
|
|
|
defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
|
|
|
#include "archive_crc32.h"
|
|
|
|
#endif
|
|
|
|
#include "archive_endian.h"
|
|
|
|
#include "archive_private.h"
|
|
|
|
#include "archive_read_private.h"
|
|
|
|
|
|
|
|
#ifndef HAVE_ZLIB_H
|
|
|
|
#define adler32 lzo_adler32
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define LZOP_HEADER_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
|
|
|
|
#define LZOP_HEADER_MAGIC_LEN 9
|
|
|
|
|
|
|
|
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
|
|
|
struct read_lzop {
|
|
|
|
unsigned char *out_block;
|
|
|
|
size_t out_block_size;
|
|
|
|
int64_t total_out;
|
|
|
|
int flags;
|
|
|
|
uint32_t compressed_cksum;
|
|
|
|
uint32_t uncompressed_cksum;
|
|
|
|
size_t compressed_size;
|
|
|
|
size_t uncompressed_size;
|
|
|
|
size_t unconsumed_bytes;
|
|
|
|
char in_stream;
|
|
|
|
char eof; /* True = found end of compressed data. */
|
|
|
|
};
|
|
|
|
|
|
|
|
#define FILTER 0x0800
|
|
|
|
#define CRC32_HEADER 0x1000
|
|
|
|
#define EXTRA_FIELD 0x0040
|
|
|
|
#define ADLER32_UNCOMPRESSED 0x0001
|
|
|
|
#define ADLER32_COMPRESSED 0x0002
|
|
|
|
#define CRC32_UNCOMPRESSED 0x0100
|
|
|
|
#define CRC32_COMPRESSED 0x0200
|
|
|
|
#define MAX_BLOCK_SIZE (64 * 1024 * 1024)
|
|
|
|
|
|
|
|
static ssize_t lzop_filter_read(struct archive_read_filter *, const void **);
|
|
|
|
static int lzop_filter_close(struct archive_read_filter *);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int lzop_bidder_bid(struct archive_read_filter_bidder *,
|
|
|
|
struct archive_read_filter *);
|
|
|
|
static int lzop_bidder_init(struct archive_read_filter *);
|
|
|
|
|
|
|
|
int
|
|
|
|
archive_read_support_filter_lzop(struct archive *_a)
|
|
|
|
{
|
|
|
|
struct archive_read *a = (struct archive_read *)_a;
|
|
|
|
struct archive_read_filter_bidder *reader;
|
|
|
|
|
|
|
|
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
|
|
|
|
ARCHIVE_STATE_NEW, "archive_read_support_filter_lzop");
|
|
|
|
|
|
|
|
if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
|
|
|
|
reader->data = NULL;
|
|
|
|
reader->bid = lzop_bidder_bid;
|
|
|
|
reader->init = lzop_bidder_init;
|
|
|
|
reader->options = NULL;
|
|
|
|
reader->free = NULL;
|
|
|
|
/* Signal the extent of lzop support with the return value here. */
|
|
|
|
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
|
|
|
return (ARCHIVE_OK);
|
|
|
|
#else
|
|
|
|
/* Return ARCHIVE_WARN since this always uses an external program. */
|
|
|
|
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
|
|
|
|
"Using external lzop program for lzop decompression");
|
|
|
|
return (ARCHIVE_WARN);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Bidder just verifies the header and returns the number of verified bits.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
lzop_bidder_bid(struct archive_read_filter_bidder *self,
|
|
|
|
struct archive_read_filter *filter)
|
|
|
|
{
|
|
|
|
const unsigned char *p;
|
|
|
|
ssize_t avail;
|
|
|
|
|
|
|
|
(void)self; /* UNUSED */
|
|
|
|
|
|
|
|
p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
|
|
|
|
if (p == NULL || avail == 0)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
return (LZOP_HEADER_MAGIC_LEN * 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(HAVE_LZO_LZOCONF_H) || !defined(HAVE_LZO_LZO1X_H)
|
|
|
|
/*
|
|
|
|
* If we don't have the library on this system, we can't do the
|
|
|
|
* decompression directly. We can, however, try to run "lzop -d"
|
|
|
|
* in case that's available.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
lzop_bidder_init(struct archive_read_filter *self)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = __archive_read_program(self, "lzop -d");
|
|
|
|
/* Note: We set the format here even if __archive_read_program()
|
|
|
|
* above fails. We do, after all, know what the format is
|
|
|
|
* even if we weren't able to read it. */
|
|
|
|
self->code = ARCHIVE_FILTER_LZOP;
|
|
|
|
self->name = "lzop";
|
|
|
|
return (r);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* Initialize the filter object.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
lzop_bidder_init(struct archive_read_filter *self)
|
|
|
|
{
|
|
|
|
struct read_lzop *state;
|
|
|
|
|
|
|
|
self->code = ARCHIVE_FILTER_LZOP;
|
|
|
|
self->name = "lzop";
|
|
|
|
|
|
|
|
state = (struct read_lzop *)calloc(sizeof(*state), 1);
|
|
|
|
if (state == NULL) {
|
|
|
|
archive_set_error(&self->archive->archive, ENOMEM,
|
|
|
|
"Can't allocate data for lzop decompression");
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
self->data = state;
|
|
|
|
self->read = lzop_filter_read;
|
|
|
|
self->skip = NULL; /* not supported */
|
|
|
|
self->close = lzop_filter_close;
|
|
|
|
|
|
|
|
return (ARCHIVE_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
consume_header(struct archive_read_filter *self)
|
|
|
|
{
|
|
|
|
struct read_lzop *state = (struct read_lzop *)self->data;
|
|
|
|
const unsigned char *p, *_p;
|
|
|
|
unsigned checksum, flags, len, method, version;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check LZOP magic code.
|
|
|
|
*/
|
|
|
|
p = __archive_read_filter_ahead(self->upstream,
|
|
|
|
LZOP_HEADER_MAGIC_LEN, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
return (ARCHIVE_EOF);
|
|
|
|
|
|
|
|
if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
|
|
|
|
return (ARCHIVE_EOF);
|
|
|
|
__archive_read_filter_consume(self->upstream,
|
|
|
|
LZOP_HEADER_MAGIC_LEN);
|
|
|
|
|
|
|
|
p = __archive_read_filter_ahead(self->upstream, 29, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
goto truncated;
|
|
|
|
_p = p;
|
|
|
|
version = archive_be16dec(p);
|
|
|
|
p += 4;/* version(2 bytes) + library version(2 bytes) */
|
|
|
|
|
|
|
|
if (version >= 0x940) {
|
|
|
|
unsigned reqversion = archive_be16dec(p); p += 2;
|
|
|
|
if (reqversion < 0x900) {
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_MISC, "Invalid required version");
|
|
|
|
return (ARCHIVE_FAILED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
method = *p++;
|
|
|
|
if (method < 1 || method > 3) {
|
|
|
|
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
|
|
|
"Unsupported method");
|
|
|
|
return (ARCHIVE_FAILED);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version >= 0x940) {
|
|
|
|
unsigned level = *p++;
|
2015-10-21 11:47:34 +03:00
|
|
|
#if 0
|
2014-03-18 07:43:07 +04:00
|
|
|
unsigned default_level[] = {0, 3, 1, 9};
|
2015-10-21 11:47:34 +03:00
|
|
|
#endif
|
2014-03-18 07:43:07 +04:00
|
|
|
if (level == 0)
|
|
|
|
/* Method is 1..3 here due to check above. */
|
2015-10-21 11:47:34 +03:00
|
|
|
#if 0 /* Avoid an error Clang Static Analyzer claims
|
|
|
|
"Value stored to 'level' is never read". */
|
2014-03-18 07:43:07 +04:00
|
|
|
level = default_level[method];
|
2015-10-21 11:47:34 +03:00
|
|
|
#else
|
|
|
|
;/* NOP */
|
|
|
|
#endif
|
2014-03-18 07:43:07 +04:00
|
|
|
else if (level > 9) {
|
2013-02-09 21:17:57 +04:00
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_MISC, "Invalid level");
|
|
|
|
return (ARCHIVE_FAILED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
flags = archive_be32dec(p); p += 4;
|
|
|
|
|
|
|
|
if (flags & FILTER)
|
|
|
|
p += 4; /* Skip filter */
|
|
|
|
p += 4; /* Skip mode */
|
|
|
|
if (version >= 0x940)
|
|
|
|
p += 8; /* Skip mtime */
|
|
|
|
else
|
|
|
|
p += 4; /* Skip mtime */
|
|
|
|
len = *p++; /* Read filename length */
|
|
|
|
len += p - _p;
|
|
|
|
/* Make sure we have all bytes we need to calculate checksum. */
|
|
|
|
p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
goto truncated;
|
|
|
|
if (flags & CRC32_HEADER)
|
|
|
|
checksum = crc32(crc32(0, NULL, 0), p, len);
|
|
|
|
else
|
|
|
|
checksum = adler32(adler32(0, NULL, 0), p, len);
|
|
|
|
if (archive_be32dec(p + len) != checksum)
|
|
|
|
goto corrupted;
|
|
|
|
__archive_read_filter_consume(self->upstream, len + 4);
|
|
|
|
if (flags & EXTRA_FIELD) {
|
|
|
|
/* Skip extra field */
|
|
|
|
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
goto truncated;
|
|
|
|
len = archive_be32dec(p);
|
|
|
|
__archive_read_filter_consume(self->upstream, len + 4 + 4);
|
|
|
|
}
|
|
|
|
state->flags = flags;
|
|
|
|
state->in_stream = 1;
|
|
|
|
return (ARCHIVE_OK);
|
|
|
|
truncated:
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
|
|
|
|
return (ARCHIVE_FAILED);
|
|
|
|
corrupted:
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
|
|
|
|
return (ARCHIVE_FAILED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
consume_block_info(struct archive_read_filter *self)
|
|
|
|
{
|
|
|
|
struct read_lzop *state = (struct read_lzop *)self->data;
|
|
|
|
const unsigned char *p;
|
|
|
|
unsigned flags = state->flags;
|
|
|
|
|
|
|
|
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
goto truncated;
|
|
|
|
state->uncompressed_size = archive_be32dec(p);
|
|
|
|
__archive_read_filter_consume(self->upstream, 4);
|
|
|
|
if (state->uncompressed_size == 0)
|
|
|
|
return (ARCHIVE_EOF);
|
|
|
|
if (state->uncompressed_size > MAX_BLOCK_SIZE)
|
|
|
|
goto corrupted;
|
|
|
|
|
|
|
|
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
goto truncated;
|
|
|
|
state->compressed_size = archive_be32dec(p);
|
|
|
|
__archive_read_filter_consume(self->upstream, 4);
|
|
|
|
if (state->compressed_size > state->uncompressed_size)
|
|
|
|
goto corrupted;
|
|
|
|
|
|
|
|
if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
|
|
|
|
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
goto truncated;
|
|
|
|
state->compressed_cksum = state->uncompressed_cksum =
|
|
|
|
archive_be32dec(p);
|
|
|
|
__archive_read_filter_consume(self->upstream, 4);
|
|
|
|
}
|
|
|
|
if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
|
|
|
|
state->compressed_size < state->uncompressed_size) {
|
|
|
|
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
|
|
|
if (p == NULL)
|
|
|
|
goto truncated;
|
|
|
|
state->compressed_cksum = archive_be32dec(p);
|
|
|
|
__archive_read_filter_consume(self->upstream, 4);
|
|
|
|
}
|
|
|
|
return (ARCHIVE_OK);
|
|
|
|
truncated:
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
|
|
|
|
return (ARCHIVE_FAILED);
|
|
|
|
corrupted:
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
|
|
|
|
return (ARCHIVE_FAILED);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
lzop_filter_read(struct archive_read_filter *self, const void **p)
|
|
|
|
{
|
|
|
|
struct read_lzop *state = (struct read_lzop *)self->data;
|
|
|
|
const void *b;
|
|
|
|
lzo_uint out_size;
|
|
|
|
uint32_t cksum;
|
|
|
|
int ret, r;
|
|
|
|
|
|
|
|
if (state->unconsumed_bytes) {
|
|
|
|
__archive_read_filter_consume(self->upstream,
|
|
|
|
state->unconsumed_bytes);
|
|
|
|
state->unconsumed_bytes = 0;
|
|
|
|
}
|
|
|
|
if (state->eof)
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (!state->in_stream) {
|
|
|
|
ret = consume_header(self);
|
|
|
|
if (ret < ARCHIVE_OK)
|
|
|
|
return (ret);
|
|
|
|
if (ret == ARCHIVE_EOF) {
|
|
|
|
state->eof = 1;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = consume_block_info(self);
|
|
|
|
if (ret < ARCHIVE_OK)
|
|
|
|
return (ret);
|
|
|
|
if (ret == ARCHIVE_EOF)
|
|
|
|
state->in_stream = 0;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->out_block == NULL ||
|
|
|
|
state->out_block_size < state->uncompressed_size) {
|
|
|
|
void *new_block;
|
|
|
|
|
|
|
|
new_block = realloc(state->out_block, state->uncompressed_size);
|
|
|
|
if (new_block == NULL) {
|
|
|
|
archive_set_error(&self->archive->archive, ENOMEM,
|
|
|
|
"Can't allocate data for lzop decompression");
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
}
|
|
|
|
state->out_block = new_block;
|
|
|
|
state->out_block_size = state->uncompressed_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
b = __archive_read_filter_ahead(self->upstream,
|
|
|
|
state->compressed_size, NULL);
|
|
|
|
if (b == NULL) {
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
}
|
|
|
|
if (state->flags & CRC32_COMPRESSED)
|
|
|
|
cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
|
|
|
|
else if (state->flags & ADLER32_COMPRESSED)
|
|
|
|
cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
|
|
|
|
else
|
|
|
|
cksum = state->compressed_cksum;
|
|
|
|
if (cksum != state->compressed_cksum) {
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_MISC, "Corrupted data");
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the both uncompressed size and compressed size are the same,
|
|
|
|
* we do not decompress this block.
|
|
|
|
*/
|
|
|
|
if (state->uncompressed_size == state->compressed_size) {
|
|
|
|
*p = b;
|
|
|
|
state->total_out += state->compressed_size;
|
|
|
|
state->unconsumed_bytes = state->compressed_size;
|
|
|
|
return ((ssize_t)state->uncompressed_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Drive lzo uncompresison.
|
|
|
|
*/
|
|
|
|
out_size = (lzo_uint)state->uncompressed_size;
|
|
|
|
r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
|
|
|
|
state->out_block, &out_size, NULL);
|
|
|
|
switch (r) {
|
|
|
|
case LZO_E_OK:
|
|
|
|
if (out_size == state->uncompressed_size)
|
|
|
|
break;
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_MISC, "Corrupted data");
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
case LZO_E_OUT_OF_MEMORY:
|
|
|
|
archive_set_error(&self->archive->archive, ENOMEM,
|
|
|
|
"lzop decompression failed: out of memory");
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
default:
|
|
|
|
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
|
|
|
"lzop decompression failed: %d", r);
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->flags & CRC32_UNCOMPRESSED)
|
|
|
|
cksum = crc32(crc32(0, NULL, 0), state->out_block,
|
|
|
|
state->uncompressed_size);
|
|
|
|
else if (state->flags & ADLER32_UNCOMPRESSED)
|
|
|
|
cksum = adler32(adler32(0, NULL, 0), state->out_block,
|
|
|
|
state->uncompressed_size);
|
|
|
|
else
|
|
|
|
cksum = state->uncompressed_cksum;
|
|
|
|
if (cksum != state->uncompressed_cksum) {
|
|
|
|
archive_set_error(&self->archive->archive,
|
|
|
|
ARCHIVE_ERRNO_MISC, "Corrupted data");
|
|
|
|
return (ARCHIVE_FATAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
__archive_read_filter_consume(self->upstream, state->compressed_size);
|
|
|
|
*p = state->out_block;
|
|
|
|
state->total_out += out_size;
|
|
|
|
return ((ssize_t)out_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean up the decompressor.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
lzop_filter_close(struct archive_read_filter *self)
|
|
|
|
{
|
|
|
|
struct read_lzop *state = (struct read_lzop *)self->data;
|
|
|
|
|
|
|
|
free(state->out_block);
|
|
|
|
free(state);
|
|
|
|
return (ARCHIVE_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|