libarchive: import changes from upstream

Libarchive 3.6.0

New features:
PR #1614: tar: new option "--no-read-sparse"
PR #1503: RAR reader: filter support
PR #1585: RAR5 reader: self-extracting archive support

New features (not used in FreeBSD base):
PR #1567: tar: threads support for zstd (#1567)
PR #1518: ZIP reader: zstd decompression support

Security Fixes:
PR #1491, #1492, #1493, CVE-2021-36976:
   fix invalid memory access and out of bounds read in RAR5 reader
PR #1566, #1618, CVE-2021-31566:
   extended fix for following symlinks when processing the fixup list

Other notable bugfixes and improvements:
PR #1620: tar: respect "--ignore-zeros" in c, r and u modes
PR #1625: reduced size of application binaries

MFC after:	2 weeks
Relnotes:	yes
This commit is contained in:
Martin Matuska 2022-02-10 00:35:42 +01:00
commit 833a452e9f
92 changed files with 36977 additions and 832 deletions

View file

@ -0,0 +1,18 @@
# To use this config on you editor, follow the instructions at:
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[*.sh]
indent_style = space
indent_size = 4
[CMakeLists.txt]
indent_style = space
indent_size = 2

View file

@ -0,0 +1,24 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'libarchive'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'libarchive'
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

View file

@ -1,3 +1,7 @@
Feb 09, 2022: libarchive 3.6.0 released
Feb 08, 2022: libarchive 3.5.3 released
Aug 22, 2021: libarchive 3.5.2 released
Dec 26, 2020: libarchive 3.5.1 released

View file

@ -0,0 +1,115 @@
# ============================================================================
# https://www.gnu.org/software/autoconf-archive/ax_compile_check_sizeof.html
# ============================================================================
#
# SYNOPSIS
#
# AX_COMPILE_CHECK_SIZEOF(TYPE [, HEADERS [, EXTRA_SIZES...]])
#
# DESCRIPTION
#
# This macro checks for the size of TYPE using compile checks, not run
# checks. You can supply extra HEADERS to look into. the check will cycle
# through 1 2 4 8 16 and any EXTRA_SIZES the user supplies. If a match is
# found, it will #define SIZEOF_`TYPE' to that value. Otherwise it will
# emit a configure time error indicating the size of the type could not be
# determined.
#
# The trick is that C will not allow duplicate case labels. While this is
# valid C code:
#
# switch (0) case 0: case 1:;
#
# The following is not:
#
# switch (0) case 0: case 0:;
#
# Thus, the AC_COMPILE_IFELSE will fail if the currently tried size does
# not match.
#
# Here is an example skeleton configure.in script, demonstrating the
# macro's usage:
#
# AC_PROG_CC
# AC_CHECK_HEADERS(stddef.h unistd.h)
# AC_TYPE_SIZE_T
# AC_CHECK_TYPE(ssize_t, int)
#
# headers='#ifdef HAVE_STDDEF_H
# #include <stddef.h>
# #endif
# #ifdef HAVE_UNISTD_H
# #include <unistd.h>
# #endif
# '
#
# AX_COMPILE_CHECK_SIZEOF(char)
# AX_COMPILE_CHECK_SIZEOF(short)
# AX_COMPILE_CHECK_SIZEOF(int)
# AX_COMPILE_CHECK_SIZEOF(long)
# AX_COMPILE_CHECK_SIZEOF(unsigned char *)
# AX_COMPILE_CHECK_SIZEOF(void *)
# AX_COMPILE_CHECK_SIZEOF(size_t, $headers)
# AX_COMPILE_CHECK_SIZEOF(ssize_t, $headers)
# AX_COMPILE_CHECK_SIZEOF(ptrdiff_t, $headers)
# AX_COMPILE_CHECK_SIZEOF(off_t, $headers)
#
# LICENSE
#
# Copyright (c) 2008 Kaveh Ghazi <ghazi@caip.rutgers.edu>
# Copyright (c) 2017 Reini Urban <rurban@cpan.org>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 8
AU_ALIAS([AC_COMPILE_CHECK_SIZEOF], [AX_COMPILE_CHECK_SIZEOF])
AC_DEFUN([AX_COMPILE_CHECK_SIZEOF],
[changequote(<<, >>)dnl
dnl The name to #define.
define(<<AC_TYPE_NAME>>, translit(sizeof_$1, [a-z *], [A-Z_P]))dnl
dnl The cache variable name.
define(<<AC_CV_NAME>>, translit(ac_cv_sizeof_$1, [ *], [_p]))dnl
changequote([, ])dnl
AC_MSG_CHECKING(size of $1)
AC_CACHE_VAL(AC_CV_NAME,
[for ac_size in 4 8 1 2 16 $3 ; do # List sizes in rough order of prevalence.
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <sys/types.h>
$2
]], [[switch (0) case 0: case (sizeof ($1) == $ac_size):;]])], [AC_CV_NAME=$ac_size])
if test x$AC_CV_NAME != x ; then break; fi
done
])
if test x$AC_CV_NAME = x ; then
AC_MSG_ERROR([cannot determine a size for $1])
fi
AC_MSG_RESULT($AC_CV_NAME)
AC_DEFINE_UNQUOTED(AC_TYPE_NAME, $AC_CV_NAME, [The number of bytes in type $1])
undefine([AC_TYPE_NAME])dnl
undefine([AC_CV_NAME])dnl
])

View file

@ -36,7 +36,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3005002
#define ARCHIVE_VERSION_NUMBER 3006000
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
@ -97,7 +97,7 @@ typedef ssize_t la_ssize_t;
#endif
/* Large file support for Android */
#ifdef __ANDROID__
#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)
#include "android_lf.h"
#endif
@ -155,7 +155,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
#define ARCHIVE_VERSION_ONLY_STRING "3.5.2"
#define ARCHIVE_VERSION_ONLY_STRING "3.6.0"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
@ -1024,6 +1024,8 @@ __LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
#define ARCHIVE_READDISK_NO_ACL (0x0020)
/* Default: File flags are read from disk. */
#define ARCHIVE_READDISK_NO_FFLAGS (0x0040)
/* Default: Sparse file information is read from disk. */
#define ARCHIVE_READDISK_NO_SPARSE (0x0080)
__LA_DECL int archive_read_disk_set_behavior(struct archive *,
int flags);

View file

@ -21,8 +21,10 @@
#if defined(_MSC_VER)
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
#else
#elif defined(__GNUC__)
#define BLAKE2_PACKED(x) x __attribute__((packed))
#else
#define BLAKE2_PACKED(x) _Pragma("pack 1") x _Pragma("pack 0")
#endif
#if defined(__cplusplus)

View file

@ -154,7 +154,7 @@ static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
/* prevents compiler optimizing out memset() */
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
{
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
static void *(__LA_LIBC_CC *const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);
}

View file

@ -17,6 +17,7 @@
#include <string.h>
#include <stdio.h>
#include "archive_platform.h"
#include "archive_blake2.h"
#include "archive_blake2_impl.h"

View file

@ -21,6 +21,7 @@
#include <omp.h>
#endif
#include "archive_platform.h"
#include "archive_blake2.h"
#include "archive_blake2_impl.h"

View file

@ -401,14 +401,6 @@ aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
memcpy(ctx->key, key, key_len);
memset(ctx->nonce, 0, sizeof(ctx->nonce));
ctx->encr_pos = AES_BLOCK_SIZE;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
if (!EVP_CIPHER_CTX_reset(ctx->ctx)) {
EVP_CIPHER_CTX_free(ctx->ctx);
ctx->ctx = NULL;
}
#else
EVP_CIPHER_CTX_init(ctx->ctx);
#endif
return 0;
}

View file

@ -30,7 +30,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
#define ARCHIVE_VERSION_NUMBER 3005002
#define ARCHIVE_VERSION_NUMBER 3006000
/*
* Note: archive_entry.h is for use outside of libarchive; the
@ -99,7 +99,7 @@ typedef ssize_t la_ssize_t;
#endif
/* Large file support for Android */
#ifdef __ANDROID__
#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)
#include "android_lf.h"
#endif

View file

@ -714,7 +714,7 @@ Convert(time_t Month, time_t Day, time_t Year,
? 29 : 28;
/* Checking for 2038 bogusly assumes that time_t is 32 bits. But
I'm too lazy to try to check for time_t overflow in another way. */
if (Year < EPOCH || Year > 2038
if (Year < EPOCH || Year >= 2038
|| Month < 1 || Month > 12
/* Lint fluff: "conversion from long may lose accuracy" */
|| Day < 1 || Day > DaysInMonth[(int)--Month]

View file

@ -77,7 +77,7 @@ static pack_t pack_12_20;
static pack_t pack_14_18;
static pack_t pack_8_24;
static pack_t pack_bsdos;
static int compare_format(const void *, const void *);
static int __LA_LIBC_CC compare_format(const void *, const void *);
static const char iMajorError[] = "invalid major number";
static const char iMinorError[] = "invalid minor number";
@ -310,6 +310,7 @@ static const struct format {
};
static int
__LA_LIBC_CC
compare_format(const void *key, const void *element)
{
const char *name;

View file

@ -69,8 +69,16 @@
* either Windows or Posix APIs. */
#if (defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
#include "archive_windows.h"
/* The C library on Windows specifies a calling convention for callback
* functions and exports; when we interact with them (capture pointers,
* call and pass function pointers) we need to match their calling
* convention.
* This only matters when libarchive is built with /Gr, /Gz or /Gv
* (which change the default calling convention.) */
#define __LA_LIBC_CC __cdecl
#else
#define la_stat(path,stref) stat(path,stref)
#define __LA_LIBC_CC
#endif
/*
@ -155,6 +163,28 @@
#define INTMAX_MIN ((intmax_t)(~INTMAX_MAX))
#endif
/* Some platforms lack the standard PRIxN/PRIdN definitions. */
#if !HAVE_INTTYPES_H || !defined(PRIx32) || !defined(PRId32)
#ifndef PRIx32
#if SIZEOF_INT == 4
#define PRIx32 "x"
#elif SIZEOF_LONG == 4
#define PRIx32 "lx"
#else
#error No suitable 32-bit unsigned integer type found for this platform
#endif
#endif // PRIx32
#ifndef PRId32
#if SIZEOF_INT == 4
#define PRId32 "d"
#elif SIZEOF_LONG == 4
#define PRId32 "ld"
#else
#error No suitable 32-bit signed integer type found for this platform
#endif
#endif // PRId32
#endif // !HAVE_INTTYPES_H || !defined(PRIx32) || !defined(PRId32)
/*
* If we can't restore metadata using a file descriptor, then
* for compatibility's sake, close files before trying to restore metadata.

View file

@ -107,14 +107,11 @@ struct archive {
* Some public API functions depend on the "real" type of the
* archive object.
*/
struct archive_vtable *vtable;
const struct archive_vtable *vtable;
int archive_format;
const char *archive_format_name;
int compression_code; /* Currently active compression. */
const char *compression_name;
/* Number of file entries processed. */
int file_count;

View file

@ -58,7 +58,6 @@ __FBSDID("$FreeBSD$");
static int choose_filters(struct archive_read *);
static int choose_format(struct archive_read *);
static int close_filters(struct archive_read *);
static struct archive_vtable *archive_read_vtable(void);
static int64_t _archive_filter_bytes(struct archive *, int);
static int _archive_filter_code(struct archive *, int);
static const char *_archive_filter_name(struct archive *, int);
@ -73,26 +72,18 @@ static int _archive_read_next_header2(struct archive *,
struct archive_entry *);
static int64_t advance_file_pointer(struct archive_read_filter *, int64_t);
static struct archive_vtable *
archive_read_vtable(void)
{
static struct archive_vtable av;
static int inited = 0;
if (!inited) {
av.archive_filter_bytes = _archive_filter_bytes;
av.archive_filter_code = _archive_filter_code;
av.archive_filter_name = _archive_filter_name;
av.archive_filter_count = _archive_filter_count;
av.archive_read_data_block = _archive_read_data_block;
av.archive_read_next_header = _archive_read_next_header;
av.archive_read_next_header2 = _archive_read_next_header2;
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
inited = 1;
}
return (&av);
}
static const struct archive_vtable
archive_read_vtable = {
.archive_filter_bytes = _archive_filter_bytes,
.archive_filter_code = _archive_filter_code,
.archive_filter_name = _archive_filter_name,
.archive_filter_count = _archive_filter_count,
.archive_read_data_block = _archive_read_data_block,
.archive_read_next_header = _archive_read_next_header,
.archive_read_next_header2 = _archive_read_next_header2,
.archive_free = _archive_read_free,
.archive_close = _archive_read_close,
};
/*
* Allocate, initialize and return a struct archive object.
@ -109,7 +100,7 @@ archive_read_new(void)
a->archive.state = ARCHIVE_STATE_NEW;
a->entry = archive_entry_new2(&a->archive);
a->archive.vtable = archive_read_vtable();
a->archive.vtable = &archive_read_vtable;
a->passphrases.last = &a->passphrases.first;
@ -245,24 +236,29 @@ client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
}
static int
client_close_proxy(struct archive_read_filter *self)
read_client_close_proxy(struct archive_read *a)
{
int r = ARCHIVE_OK, r2;
unsigned int i;
if (self->archive->client.closer == NULL)
if (a->client.closer == NULL)
return (r);
for (i = 0; i < self->archive->client.nodes; i++)
for (i = 0; i < a->client.nodes; i++)
{
r2 = (self->archive->client.closer)
((struct archive *)self->archive,
self->archive->client.dataset[i].data);
r2 = (a->client.closer)
((struct archive *)a, a->client.dataset[i].data);
if (r > r2)
r = r2;
}
return (r);
}
static int
client_close_proxy(struct archive_read_filter *self)
{
return read_client_close_proxy(self->archive);
}
static int
client_open_proxy(struct archive_read_filter *self)
{
@ -298,9 +294,7 @@ client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)
r1 = (self->archive->client.closer)
((struct archive *)self->archive, self->data);
self->data = data2;
if (self->archive->client.opener != NULL)
r2 = (self->archive->client.opener)
((struct archive *)self->archive, self->data);
r2 = client_open_proxy(self);
}
return (r1 < r2) ? r1 : r2;
}
@ -457,13 +451,18 @@ archive_read_prepend_callback_data(struct archive *_a, void *client_data)
return archive_read_add_callback_data(_a, client_data, 0);
}
static const struct archive_read_filter_vtable
none_reader_vtable = {
.read = client_read_proxy,
.close = client_close_proxy,
};
int
archive_read_open1(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter, *tmp;
int slot, e = ARCHIVE_OK;
unsigned int i;
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"archive_read_open");
@ -481,11 +480,7 @@ archive_read_open1(struct archive *_a)
e = (a->client.opener)(&a->archive, a->client.dataset[0].data);
if (e != 0) {
/* If the open failed, call the closer to clean up. */
if (a->client.closer) {
for (i = 0; i < a->client.nodes; i++)
(a->client.closer)(&a->archive,
a->client.dataset[i].data);
}
read_client_close_proxy(a);
return (e);
}
}
@ -497,14 +492,11 @@ archive_read_open1(struct archive *_a)
filter->upstream = NULL;
filter->archive = a;
filter->data = a->client.dataset[0].data;
filter->open = client_open_proxy;
filter->read = client_read_proxy;
filter->skip = client_skip_proxy;
filter->seek = client_seek_proxy;
filter->close = client_close_proxy;
filter->sswitch = client_switch_proxy;
filter->vtable = &none_reader_vtable;
filter->name = "none";
filter->code = ARCHIVE_FILTER_NONE;
filter->can_skip = 1;
filter->can_seek = 1;
a->client.dataset[0].begin_position = 0;
if (!a->filter || !a->bypass_filter_bidding)
@ -570,12 +562,12 @@ choose_filters(struct archive_read *a)
bidder = a->bidders;
for (i = 0; i < number_bidders; i++, bidder++) {
if (bidder->bid != NULL) {
bid = (bidder->bid)(bidder, a->filter);
if (bid > best_bid) {
best_bid = bid;
best_bidder = bidder;
}
if (bidder->vtable == NULL)
continue;
bid = (bidder->vtable->bid)(bidder, a->filter);
if (bid > best_bid) {
best_bid = bid;
best_bidder = bidder;
}
}
@ -587,8 +579,6 @@ choose_filters(struct archive_read *a)
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
a->archive.compression_name = a->filter->name;
a->archive.compression_code = a->filter->code;
return (ARCHIVE_OK);
}
@ -600,7 +590,7 @@ choose_filters(struct archive_read *a)
filter->archive = a;
filter->upstream = a->filter;
a->filter = filter;
r = (best_bidder->init)(a->filter);
r = (best_bidder->vtable->init)(a->filter);
if (r != ARCHIVE_OK) {
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
@ -614,10 +604,9 @@ choose_filters(struct archive_read *a)
int
__archive_read_header(struct archive_read *a, struct archive_entry *entry)
{
if (a->filter->read_header)
return a->filter->read_header(a->filter, entry);
else
if (!a->filter->vtable->read_header)
return (ARCHIVE_OK);
return a->filter->vtable->read_header(a->filter, entry);
}
/*
@ -1006,8 +995,8 @@ close_filters(struct archive_read *a)
/* Close each filter in the pipeline. */
while (f != NULL) {
struct archive_read_filter *t = f->upstream;
if (!f->closed && f->close != NULL) {
int r1 = (f->close)(f);
if (!f->closed && f->vtable != NULL) {
int r1 = (f->vtable->close)(f);
f->closed = 1;
if (r1 < r)
r = r1;
@ -1112,11 +1101,10 @@ _archive_read_free(struct archive *_a)
/* Release the bidder objects. */
n = sizeof(a->bidders)/sizeof(a->bidders[0]);
for (i = 0; i < n; i++) {
if (a->bidders[i].free != NULL) {
int r1 = (a->bidders[i].free)(&a->bidders[i]);
if (r1 < r)
r = r1;
}
if (a->bidders[i].vtable == NULL ||
a->bidders[i].vtable->free == NULL)
continue;
(a->bidders[i].vtable->free)(&a->bidders[i]);
}
/* Release passphrase list. */
@ -1241,19 +1229,35 @@ __archive_read_register_format(struct archive_read *a,
* initialization functions.
*/
int
__archive_read_get_bidder(struct archive_read *a,
struct archive_read_filter_bidder **bidder)
__archive_read_register_bidder(struct archive_read *a,
void *bidder_data,
const char *name,
const struct archive_read_filter_bidder_vtable *vtable)
{
struct archive_read_filter_bidder *bidder;
int i, number_slots;
archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "__archive_read_register_bidder");
number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]);
for (i = 0; i < number_slots; i++) {
if (a->bidders[i].bid == NULL) {
memset(a->bidders + i, 0, sizeof(a->bidders[0]));
*bidder = (a->bidders + i);
return (ARCHIVE_OK);
if (a->bidders[i].vtable != NULL)
continue;
memset(a->bidders + i, 0, sizeof(a->bidders[0]));
bidder = (a->bidders + i);
bidder->data = bidder_data;
bidder->name = name;
bidder->vtable = vtable;
if (bidder->vtable->bid == NULL || bidder->vtable->init == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: "
"no bid/init for filter bidder");
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
archive_set_error(&a->archive, ENOMEM,
@ -1382,7 +1386,7 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
*avail = 0;
return (NULL);
}
bytes_read = (filter->read)(filter,
bytes_read = (filter->vtable->read)(filter,
&filter->client_buff);
if (bytes_read < 0) { /* Read error. */
filter->client_total = filter->client_avail = 0;
@ -1561,8 +1565,8 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
return (total_bytes_skipped);
/* If there's an optimized skip function, use it. */
if (filter->skip != NULL) {
bytes_skipped = (filter->skip)(filter, request);
if (filter->can_skip != 0) {
bytes_skipped = client_skip_proxy(filter, request);
if (bytes_skipped < 0) { /* error */
filter->fatal = 1;
return (bytes_skipped);
@ -1576,7 +1580,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
/* Use ordinary reads as necessary to complete the request. */
for (;;) {
bytes_read = (filter->read)(filter, &filter->client_buff);
bytes_read = (filter->vtable->read)(filter, &filter->client_buff);
if (bytes_read < 0) {
filter->client_buff = NULL;
filter->fatal = 1;
@ -1631,7 +1635,7 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
if (filter->closed || filter->fatal)
return (ARCHIVE_FATAL);
if (filter->seek == NULL)
if (filter->can_seek == 0)
return (ARCHIVE_FAILED);
client = &(filter->archive->client);

View file

@ -135,7 +135,7 @@ archive_read_append_filter(struct archive *_a, int code)
filter->archive = a;
filter->upstream = a->filter;
a->filter = filter;
r2 = (bidder->init)(a->filter);
r2 = (bidder->vtable->init)(a->filter);
if (r2 != ARCHIVE_OK) {
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
@ -192,7 +192,7 @@ archive_read_append_filter_program_signature(struct archive *_a,
filter->archive = a;
filter->upstream = a->filter;
a->filter = filter;
r = (bidder->init)(a->filter);
r = (bidder->vtable->init)(a->filter);
if (r != ARCHIVE_OK) {
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);

View file

@ -29,6 +29,8 @@
.Os
.Sh NAME
.Nm archive_read_disk_new ,
.Nm archive_read_disk_open ,
.Nm archive_read_disk_open_w ,
.Nm archive_read_disk_set_behavior ,
.Nm archive_read_disk_set_symlink_logical ,
.Nm archive_read_disk_set_symlink_physical ,
@ -38,7 +40,14 @@
.Nm archive_read_disk_uname ,
.Nm archive_read_disk_set_uname_lookup ,
.Nm archive_read_disk_set_gname_lookup ,
.Nm archive_read_disk_set_standard_lookup
.Nm archive_read_disk_set_standard_lookup ,
.Nm archive_read_disk_descend ,
.Nm archive_read_disk_can_descend ,
.Nm archive_read_disk_current_filesystem ,
.Nm archive_read_disk_current_filesystem_is_synthetic ,
.Nm archive_read_disk_current_filesystem_is_remote ,
.Nm archive_read_disk_set_matching ,
.Nm archive_read_disk_set_metadata_filter_callback ,
.Nd functions for reading objects from disk
.Sh LIBRARY
Streaming Archive Library (libarchive, -larchive)
@ -47,6 +56,10 @@ Streaming Archive Library (libarchive, -larchive)
.Ft struct archive *
.Fn archive_read_disk_new "void"
.Ft int
.Fn archive_read_disk_open "struct archive *" "const char *"
.Ft int
.Fn archive_read_disk_open_w "struct archive *" "const wchar_t *"
.Ft int
.Fn archive_read_disk_set_behavior "struct archive *" "int"
.Ft int
.Fn archive_read_disk_set_symlink_logical "struct archive *"
@ -81,6 +94,29 @@ Streaming Archive Library (libarchive, -larchive)
.Fa "int fd"
.Fa "const struct stat *"
.Fc
.Ft int
.Fn archive_read_disk_descend "struct archive *"
.Ft int
.Fn archive_read_disk_can_descend "struct archive *"
.Ft int
.Fn archive_read_disk_current_filesystem "struct archive *"
.Ft int
.Fn archive_read_disk_current_filesystem_is_synthetic "struct archive *"
.Ft int
.Fn archive_read_disk_current_filesystem_is_remote "struct archive *"
.Ft int
.Fo archive_read_disk_set_matching
.Fa "struct archive *"
.Fa "struct archive *"
.Fa "void (*excluded_func)(struct archive *, void *, struct archive entry *)"
.Fa "void *"
.Fc
.Ft int
.Fo archive_read_disk_set_metadata_filter_callback
.Fa "struct archive *"
.Fa "int (*metadata_filter_func)(struct archive *, void*, struct archive_entry *)"
.Fa "void *"
.Fc
.Sh DESCRIPTION
These functions provide an API for reading information about
objects on disk.
@ -92,6 +128,14 @@ objects.
Allocates and initializes a
.Tn struct archive
object suitable for reading object information from disk.
.It Fn archive_read_disk_open
Opens the file or directory from the given path and prepares the
.Tn struct archive
to read it from disk.
.It Fn archive_read_disk_open_w
Opens the file or directory from the given path as a wide character string and prepares the
.Tn struct archive
to read it from disk.
.It Fn archive_read_disk_set_behavior
Configures various behavior options when reading entries from disk.
The flags field consists of a bitwise OR of one or more of the
@ -137,6 +181,9 @@ for more information on extended file attributes.
.It Cm ARCHIVE_READDISK_RESTORE_ATIME
Restore access time of traversed files.
By default, access time of traversed files is not restored.
.It Cm ARCHIVE_READDISK_NO_SPARSE
Do not read sparse file information.
By default, sparse file information is read from disk.
.El
.It Xo
.Fn archive_read_disk_set_symlink_logical ,
@ -221,6 +268,37 @@ using the currently-registered lookup functions above.
This affects the file ownership fields and ACL values in the
.Tn struct archive_entry
object.
.It Fn archive_read_disk_descend
If the current entry can be descended, this function will mark the directory as the next entry for
.Xr archive_read_header 3
to visit.
.It Fn archive_read_disk_can_descend
Returns 1 if the current entry is an unvisited directory and 0 otherwise.
.It Fn archive_read_disk_current_filesystem
Returns the index of the most recent filesystem entry that has been visited through archive_read_disk
.It Fn archive_read_disk_current_filesystem_is_synthetic
Returns 1 if the current filesystem is a virtual filesystem. Returns 0 if the current filesystem is not a virtual filesystem. Returns -1 if it is unknown.
.It Fn archive_read_disk_current_filesystem_is_remote
Returns 1 if the current filesystem is a remote filesystem. Returns 0 if the current filesystem is not a remote filesystem. Returns -1 if it is unknown.
.It Fn archive_read_disk_set_matching
Allows the caller to set
.Tn struct archive
*_ma to compare each entry during
.Xr archive_read_header 3
calls. If matched based on calls to
.Tn archive_match_path_excluded ,
.Tn archive_match_time_excluded ,
or
.Tn archive_match_owner_excluded ,
then the callback function specified by the _excluded_func parameter will execute. This function will recieve data provided to the fourth parameter, void *_client_data.
.It Fn archive_read_disk_set_metadata_filter_callback
Allows the caller to set a callback function during calls to
.Xr archive_read_header 3
to filter out metadata for each entry. The callback function recieves the
.Tn struct archive
object, void* custom filter data, and the
.Tn struct archive_entry .
If the callback function returns an error, ARCHIVE_RETRY will be returned and the entry will not be further processed.
.El
More information about the
.Va struct archive

View file

@ -303,9 +303,11 @@ archive_read_disk_entry_from_file(struct archive *_a,
if (r1 < r)
r = r1;
}
r1 = setup_sparse(a, entry, &fd);
if (r1 < r)
r = r1;
if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) {
r1 = setup_sparse(a, entry, &fd);
if (r1 < r)
r = r1;
}
/* If we opened the file earlier in this function, close it. */
if (initial_fd != fd)

View file

@ -369,22 +369,14 @@ static int open_on_current_dir(struct tree *, const char *, int);
static int tree_dup(int);
static struct archive_vtable *
archive_read_disk_vtable(void)
{
static struct archive_vtable av;
static int inited = 0;
if (!inited) {
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
av.archive_read_data_block = _archive_read_data_block;
av.archive_read_next_header = _archive_read_next_header;
av.archive_read_next_header2 = _archive_read_next_header2;
inited = 1;
}
return (&av);
}
static const struct archive_vtable
archive_read_disk_vtable = {
.archive_free = _archive_read_free,
.archive_close = _archive_read_close,
.archive_read_data_block = _archive_read_data_block,
.archive_read_next_header = _archive_read_next_header,
.archive_read_next_header2 = _archive_read_next_header2,
};
const char *
archive_read_disk_gname(struct archive *_a, la_int64_t gid)
@ -461,7 +453,7 @@ archive_read_disk_new(void)
return (NULL);
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_read_disk_vtable();
a->archive.vtable = &archive_read_disk_vtable;
a->entry = archive_entry_new2(&a->archive);
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
@ -1290,7 +1282,7 @@ archive_read_disk_descend(struct archive *_a)
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_read_disk_descend");
if (t->visit_type != TREE_REGULAR || !t->descend)
if (!archive_read_disk_can_descend(_a))
return (ARCHIVE_OK);
/*

View file

@ -42,6 +42,16 @@ struct archive_read;
struct archive_read_filter_bidder;
struct archive_read_filter;
struct archive_read_filter_bidder_vtable {
/* Taste the upstream filter to see if we handle this. */
int (*bid)(struct archive_read_filter_bidder *,
struct archive_read_filter *);
/* Initialize a newly-created filter. */
int (*init)(struct archive_read_filter *);
/* Release the bidder's configuration data. */
void (*free)(struct archive_read_filter_bidder *);
};
/*
* How bidding works for filters:
* * The bid manager initializes the client-provided reader as the
@ -62,16 +72,16 @@ struct archive_read_filter_bidder {
void *data;
/* Name of the filter */
const char *name;
/* Taste the upstream filter to see if we handle this. */
int (*bid)(struct archive_read_filter_bidder *,
struct archive_read_filter *);
/* Initialize a newly-created filter. */
int (*init)(struct archive_read_filter *);
/* Set an option for the filter bidder. */
int (*options)(struct archive_read_filter_bidder *,
const char *key, const char *value);
/* Release the bidder's configuration data. */
int (*free)(struct archive_read_filter_bidder *);
const struct archive_read_filter_bidder_vtable *vtable;
};
struct archive_read_filter_vtable {
/* Return next block. */
ssize_t (*read)(struct archive_read_filter *, const void **);
/* Close (just this filter) and free(self). */
int (*close)(struct archive_read_filter *self);
/* Read any header metadata if available. */
int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);
};
/*
@ -86,25 +96,14 @@ struct archive_read_filter {
struct archive_read_filter_bidder *bidder; /* My bidder. */
struct archive_read_filter *upstream; /* Who I read from. */
struct archive_read *archive; /* Associated archive. */
/* Open a block for reading */
int (*open)(struct archive_read_filter *self);
/* Return next block. */
ssize_t (*read)(struct archive_read_filter *, const void **);
/* Skip forward this many bytes. */
int64_t (*skip)(struct archive_read_filter *self, int64_t request);
/* Seek to an absolute location. */
int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence);
/* Close (just this filter) and free(self). */
int (*close)(struct archive_read_filter *self);
/* Function that handles switching from reading one block to the next/prev */
int (*sswitch)(struct archive_read_filter *self, unsigned int iindex);
/* Read any header metadata if available. */
int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);
const struct archive_read_filter_vtable *vtable;
/* My private data. */
void *data;
const char *name;
int code;
int can_skip;
int can_seek;
/* Used by reblocking logic. */
char *buffer;
@ -242,8 +241,10 @@ int __archive_read_register_format(struct archive_read *a,
int (*format_capabilities)(struct archive_read *),
int (*has_encrypted_entries)(struct archive_read *));
int __archive_read_get_bidder(struct archive_read *a,
struct archive_read_filter_bidder **bidder);
int __archive_read_register_bidder(struct archive_read *a,
void *bidder_data,
const char *name,
const struct archive_read_filter_bidder_vtable *vtable);
const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *);
const void *__archive_read_filter_ahead(struct archive_read_filter *,

View file

@ -112,37 +112,15 @@ static int
archive_set_filter_option(struct archive *_a, const char *m, const char *o,
const char *v)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter;
struct archive_read_filter_bidder *bidder;
int r, rv = ARCHIVE_WARN, matched_modules = 0;
(void)_a; /* UNUSED */
(void)o; /* UNUSED */
(void)v; /* UNUSED */
for (filter = a->filter; filter != NULL; filter = filter->upstream) {
bidder = filter->bidder;
if (bidder == NULL)
continue;
if (bidder->options == NULL)
/* This bidder does not support option */
continue;
if (m != NULL) {
if (strcmp(filter->name, m) != 0)
continue;
++matched_modules;
}
r = bidder->options(bidder, o, v);
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
/* If the filter name didn't match, return a special code for
* _archive_set_option[s]. */
if (m != NULL && matched_modules == 0)
if (m != NULL)
return ARCHIVE_WARN - 1;
return (rv);
return ARCHIVE_WARN;
}
static int

View file

@ -70,7 +70,6 @@ static int bzip2_filter_close(struct archive_read_filter *);
*/
static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
static int bzip2_reader_init(struct archive_read_filter *);
static int bzip2_reader_free(struct archive_read_filter_bidder *);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
@ -81,24 +80,21 @@ archive_read_support_compression_bzip2(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
bzip2_bidder_vtable = {
.bid = bzip2_reader_bid,
.init = bzip2_reader_init,
};
int
archive_read_support_filter_bzip2(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_bzip2");
if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "bzip2",
&bzip2_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
reader->data = NULL;
reader->name = "bzip2";
reader->bid = bzip2_reader_bid;
reader->init = bzip2_reader_init;
reader->options = NULL;
reader->free = bzip2_reader_free;
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
return (ARCHIVE_OK);
#else
@ -108,12 +104,6 @@ archive_read_support_filter_bzip2(struct archive *_a)
#endif
}
static int
bzip2_reader_free(struct archive_read_filter_bidder *self){
(void)self; /* UNUSED */
return (ARCHIVE_OK);
}
/*
* Test whether we can handle this data.
*
@ -183,6 +173,12 @@ bzip2_reader_init(struct archive_read_filter *self)
#else
static const struct archive_read_filter_vtable
bzip2_reader_vtable = {
.read = bzip2_filter_read,
.close = bzip2_filter_close,
};
/*
* Setup the callbacks.
*/
@ -209,9 +205,7 @@ bzip2_reader_init(struct archive_read_filter *self)
self->data = state;
state->out_block_size = out_block_size;
state->out_block = out_block;
self->read = bzip2_filter_read;
self->skip = NULL; /* not supported */
self->close = bzip2_filter_close;
self->vtable = &bzip2_reader_vtable;
return (ARCHIVE_OK);
}

View file

@ -133,7 +133,6 @@ struct private_data {
static int compress_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
static int compress_bidder_init(struct archive_read_filter *);
static int compress_bidder_free(struct archive_read_filter_bidder *);
static ssize_t compress_filter_read(struct archive_read_filter *, const void **);
static int compress_filter_close(struct archive_read_filter *);
@ -150,25 +149,19 @@ archive_read_support_compression_compress(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
compress_bidder_vtable = {
.bid = compress_bidder_bid,
.init = compress_bidder_init,
};
int
archive_read_support_filter_compress(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_compress");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "compress (.Z)";
bidder->bid = compress_bidder_bid;
bidder->init = compress_bidder_init;
bidder->options = NULL;
bidder->free = compress_bidder_free;
return (ARCHIVE_OK);
return __archive_read_register_bidder(a, NULL, "compress (.Z)",
&compress_bidder_vtable);
}
/*
@ -205,6 +198,12 @@ compress_bidder_bid(struct archive_read_filter_bidder *self,
return (bits_checked);
}
static const struct archive_read_filter_vtable
compress_reader_vtable = {
.read = compress_filter_read,
.close = compress_filter_close,
};
/*
* Setup the callbacks.
*/
@ -233,9 +232,7 @@ compress_bidder_init(struct archive_read_filter *self)
self->data = state;
state->out_block_size = out_block_size;
state->out_block = out_block;
self->read = compress_filter_read;
self->skip = NULL; /* not supported */
self->close = compress_filter_close;
self->vtable = &compress_reader_vtable;
/* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */
@ -305,16 +302,6 @@ compress_filter_read(struct archive_read_filter *self, const void **pblock)
return (p - start);
}
/*
* Clean up the reader.
*/
static int
compress_bidder_free(struct archive_read_filter_bidder *self)
{
self->data = NULL;
return (ARCHIVE_OK);
}
/*
* Close and release the filter.
*/

View file

@ -54,30 +54,21 @@ static int grzip_bidder_bid(struct archive_read_filter_bidder *,
static int grzip_bidder_init(struct archive_read_filter *);
static int
grzip_reader_free(struct archive_read_filter_bidder *self)
{
(void)self; /* UNUSED */
return (ARCHIVE_OK);
}
static const struct archive_read_filter_bidder_vtable
grzip_bidder_vtable = {
.bid = grzip_bidder_bid,
.init = grzip_bidder_init,
};
int
archive_read_support_filter_grzip(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_grzip");
if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, NULL,
&grzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
reader->data = NULL;
reader->bid = grzip_bidder_bid;
reader->init = grzip_bidder_init;
reader->options = NULL;
reader->free = grzip_reader_free;
/* This filter always uses an external program. */
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external grzip program for grzip decompression");

View file

@ -94,24 +94,21 @@ archive_read_support_compression_gzip(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
gzip_bidder_vtable = {
.bid = gzip_bidder_bid,
.init = gzip_bidder_init,
};
int
archive_read_support_filter_gzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_gzip");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "gzip",
&gzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "gzip";
bidder->bid = gzip_bidder_bid;
bidder->init = gzip_bidder_init;
bidder->options = NULL;
bidder->free = NULL; /* No data, so no cleanup necessary. */
/* Signal the extent of gzip support with the return value here. */
#if HAVE_ZLIB_H
return (ARCHIVE_OK);
@ -291,6 +288,15 @@ gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry)
return (ARCHIVE_OK);
}
static const struct archive_read_filter_vtable
gzip_reader_vtable = {
.read = gzip_filter_read,
.close = gzip_filter_close,
#ifdef HAVE_ZLIB_H
.read_header = gzip_read_header,
#endif
};
/*
* Initialize the filter object.
*/
@ -317,12 +323,7 @@ gzip_bidder_init(struct archive_read_filter *self)
self->data = state;
state->out_block_size = out_block_size;
state->out_block = out_block;
self->read = gzip_filter_read;
self->skip = NULL; /* not supported */
self->close = gzip_filter_close;
#ifdef HAVE_ZLIB_H
self->read_header = gzip_read_header;
#endif
self->vtable = &gzip_reader_vtable;
state->in_stream = 0; /* We're not actually within a stream yet. */

View file

@ -53,31 +53,21 @@ static int lrzip_bidder_bid(struct archive_read_filter_bidder *,
static int lrzip_bidder_init(struct archive_read_filter *);
static int
lrzip_reader_free(struct archive_read_filter_bidder *self)
{
(void)self; /* UNUSED */
return (ARCHIVE_OK);
}
static const struct archive_read_filter_bidder_vtable
lrzip_bidder_vtable = {
.bid = lrzip_bidder_bid,
.init = lrzip_bidder_init,
};
int
archive_read_support_filter_lrzip(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_lrzip");
if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "lrzip",
&lrzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
reader->data = NULL;
reader->name = "lrzip";
reader->bid = lrzip_bidder_bid;
reader->init = lrzip_bidder_init;
reader->options = NULL;
reader->free = lrzip_reader_free;
/* This filter always uses an external program. */
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external lrzip program for lrzip decompression");

View file

@ -99,7 +99,6 @@ static int lz4_filter_close(struct archive_read_filter *);
*/
static int lz4_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
static int lz4_reader_init(struct archive_read_filter *);
static int lz4_reader_free(struct archive_read_filter_bidder *);
#if defined(HAVE_LIBLZ4)
static ssize_t lz4_filter_read_default_stream(struct archive_read_filter *,
const void **);
@ -107,24 +106,21 @@ static ssize_t lz4_filter_read_legacy_stream(struct archive_read_filter *,
const void **);
#endif
static const struct archive_read_filter_bidder_vtable
lz4_bidder_vtable = {
.bid = lz4_reader_bid,
.init = lz4_reader_init,
};
int
archive_read_support_filter_lz4(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_lz4");
if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "lz4",
&lz4_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
reader->data = NULL;
reader->name = "lz4";
reader->bid = lz4_reader_bid;
reader->init = lz4_reader_init;
reader->options = NULL;
reader->free = lz4_reader_free;
#if defined(HAVE_LIBLZ4)
return (ARCHIVE_OK);
#else
@ -134,12 +130,6 @@ archive_read_support_filter_lz4(struct archive *_a)
#endif
}
static int
lz4_reader_free(struct archive_read_filter_bidder *self){
(void)self; /* UNUSED */
return (ARCHIVE_OK);
}
/*
* Test whether we can handle this data.
*
@ -218,6 +208,12 @@ lz4_reader_init(struct archive_read_filter *self)
#else
static const struct archive_read_filter_vtable
lz4_reader_vtable = {
.read = lz4_filter_read,
.close = lz4_filter_close,
};
/*
* Setup the callbacks.
*/
@ -238,9 +234,7 @@ lz4_reader_init(struct archive_read_filter *self)
self->data = state;
state->stage = SELECT_STREAM;
self->read = lz4_filter_read;
self->skip = NULL; /* not supported */
self->close = lz4_filter_close;
self->vtable = &lz4_reader_vtable;
return (ARCHIVE_OK);
}

View file

@ -101,23 +101,21 @@ static int lzop_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *);
static int lzop_bidder_init(struct archive_read_filter *);
static const struct archive_read_filter_bidder_vtable
lzop_bidder_vtable = {
.bid = lzop_bidder_bid,
.init = lzop_bidder_init,
};
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)
if (__archive_read_register_bidder(a, NULL, NULL,
&lzop_bidder_vtable) != 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);
@ -171,6 +169,13 @@ lzop_bidder_init(struct archive_read_filter *self)
return (r);
}
#else
static const struct archive_read_filter_vtable
lzop_reader_vtable = {
.read = lzop_filter_read,
.close = lzop_filter_close
};
/*
* Initialize the filter object.
*/
@ -190,9 +195,7 @@ lzop_bidder_init(struct archive_read_filter *self)
}
self->data = state;
self->read = lzop_filter_read;
self->skip = NULL; /* not supported */
self->close = lzop_filter_close;
self->vtable = &lzop_reader_vtable;
return (ARCHIVE_OK);
}

View file

@ -98,7 +98,7 @@ struct program_bidder {
static int program_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *upstream);
static int program_bidder_init(struct archive_read_filter *);
static int program_bidder_free(struct archive_read_filter_bidder *);
static void program_bidder_free(struct archive_read_filter_bidder *);
/*
* The actual filter needs to track input and output data.
@ -123,42 +123,20 @@ static ssize_t program_filter_read(struct archive_read_filter *,
static int program_filter_close(struct archive_read_filter *);
static void free_state(struct program_bidder *);
static int
set_bidder_signature(struct archive_read_filter_bidder *bidder,
struct program_bidder *state, const void *signature, size_t signature_len)
{
if (signature != NULL && signature_len > 0) {
state->signature_len = signature_len;
state->signature = malloc(signature_len);
memcpy(state->signature, signature, signature_len);
}
/*
* Fill in the bidder object.
*/
bidder->data = state;
bidder->bid = program_bidder_bid;
bidder->init = program_bidder_init;
bidder->options = NULL;
bidder->free = program_bidder_free;
return (ARCHIVE_OK);
}
static const struct archive_read_filter_bidder_vtable
program_bidder_vtable = {
.bid = program_bidder_bid,
.init = program_bidder_init,
.free = program_bidder_free,
};
int
archive_read_support_filter_program_signature(struct archive *_a,
const char *cmd, const void *signature, size_t signature_len)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
struct program_bidder *state;
/*
* Get a bidder object from the read core.
*/
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
/*
* Allocate our private state.
*/
@ -169,20 +147,31 @@ archive_read_support_filter_program_signature(struct archive *_a,
if (state->cmd == NULL)
goto memerr;
return set_bidder_signature(bidder, state, signature, signature_len);
if (signature != NULL && signature_len > 0) {
state->signature_len = signature_len;
state->signature = malloc(signature_len);
memcpy(state->signature, signature, signature_len);
}
if (__archive_read_register_bidder(a, state, NULL,
&program_bidder_vtable) != ARCHIVE_OK) {
free_state(state);
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
memerr:
free_state(state);
archive_set_error(_a, ENOMEM, "Can't allocate memory");
return (ARCHIVE_FATAL);
}
static int
static void
program_bidder_free(struct archive_read_filter_bidder *self)
{
struct program_bidder *state = (struct program_bidder *)self->data;
free_state(state);
return (ARCHIVE_OK);
}
static void
@ -393,6 +382,12 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
}
}
static const struct archive_read_filter_vtable
program_reader_vtable = {
.read = program_filter_read,
.close = program_filter_close,
};
int
__archive_read_program(struct archive_read_filter *self, const char *cmd)
{
@ -439,9 +434,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
}
self->data = state;
self->read = program_filter_read;
self->skip = NULL;
self->close = program_filter_close;
self->vtable = &program_reader_vtable;
/* XXX Check that we can read at least one byte? */
return (ARCHIVE_OK);

View file

@ -72,25 +72,19 @@ archive_read_support_compression_rpm(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
rpm_bidder_vtable = {
.bid = rpm_bidder_bid,
.init = rpm_bidder_init,
};
int
archive_read_support_filter_rpm(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_rpm");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "rpm";
bidder->bid = rpm_bidder_bid;
bidder->init = rpm_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
return (ARCHIVE_OK);
return __archive_read_register_bidder(a, NULL, "rpm",
&rpm_bidder_vtable);
}
static int
@ -133,6 +127,12 @@ rpm_bidder_bid(struct archive_read_filter_bidder *self,
return (bits_checked);
}
static const struct archive_read_filter_vtable
rpm_reader_vtable = {
.read = rpm_filter_read,
.close = rpm_filter_close,
};
static int
rpm_bidder_init(struct archive_read_filter *self)
{
@ -140,9 +140,6 @@ rpm_bidder_init(struct archive_read_filter *self)
self->code = ARCHIVE_FILTER_RPM;
self->name = "rpm";
self->read = rpm_filter_read;
self->skip = NULL; /* not supported */
self->close = rpm_filter_close;
rpm = (struct rpm *)calloc(sizeof(*rpm), 1);
if (rpm == NULL) {
@ -153,6 +150,7 @@ rpm_bidder_init(struct archive_read_filter *self)
self->data = rpm;
rpm->state = ST_LEAD;
self->vtable = &rpm_reader_vtable;
return (ARCHIVE_OK);
}

View file

@ -76,25 +76,19 @@ archive_read_support_compression_uu(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
uudecode_bidder_vtable = {
.bid = uudecode_bidder_bid,
.init = uudecode_bidder_init,
};
int
archive_read_support_filter_uu(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_uu");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "uu";
bidder->bid = uudecode_bidder_bid;
bidder->init = uudecode_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
return (ARCHIVE_OK);
return __archive_read_register_bidder(a, NULL, "uu",
&uudecode_bidder_vtable);
}
static const unsigned char ascii[256] = {
@ -357,6 +351,12 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
return (0);
}
static const struct archive_read_filter_vtable
uudecode_reader_vtable = {
.read = uudecode_filter_read,
.close = uudecode_filter_close,
};
static int
uudecode_bidder_init(struct archive_read_filter *self)
{
@ -366,9 +366,6 @@ uudecode_bidder_init(struct archive_read_filter *self)
self->code = ARCHIVE_FILTER_UU;
self->name = "uu";
self->read = uudecode_filter_read;
self->skip = NULL; /* not supported */
self->close = uudecode_filter_close;
uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1);
out_buff = malloc(OUT_BUFF_SIZE);
@ -388,6 +385,7 @@ uudecode_bidder_init(struct archive_read_filter *self)
uudecode->in_allocated = IN_BUFF_SIZE;
uudecode->out_buff = out_buff;
uudecode->state = ST_FIND_HEAD;
self->vtable = &uudecode_reader_vtable;
return (ARCHIVE_OK);
}

View file

@ -108,24 +108,21 @@ archive_read_support_compression_xz(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
xz_bidder_vtable = {
.bid = xz_bidder_bid,
.init = xz_bidder_init,
};
int
archive_read_support_filter_xz(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_xz");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "xz",
&xz_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "xz";
bidder->bid = xz_bidder_bid;
bidder->init = xz_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
#else
@ -143,24 +140,21 @@ archive_read_support_compression_lzma(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
lzma_bidder_vtable = {
.bid = lzma_bidder_bid,
.init = lzma_bidder_init,
};
int
archive_read_support_filter_lzma(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_lzma");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "lzma",
&lzma_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "lzma";
bidder->bid = lzma_bidder_bid;
bidder->init = lzma_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
#else
@ -179,24 +173,21 @@ archive_read_support_compression_lzip(struct archive *a)
}
#endif
static const struct archive_read_filter_bidder_vtable
lzip_bidder_vtable = {
.bid = lzip_bidder_bid,
.init = lzip_bidder_init,
};
int
archive_read_support_filter_lzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_lzip");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "lzip",
&lzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "lzip";
bidder->bid = lzip_bidder_bid;
bidder->init = lzip_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
#else
@ -293,8 +284,8 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self,
/* Second through fifth bytes are dictionary size, stored in
* little-endian order. The minimum dictionary size is
* 1 << 12(4KiB) which the lzma of LZMA SDK uses with option
* -d12 and the maximum dictionary size is 1 << 27(128MiB)
* which the one uses with option -d27.
* -d12 and the maximum dictionary size is 1 << 29(512MiB)
* which the one uses with option -d29.
* NOTE: A comment of LZMA SDK source code says this dictionary
* range is from 1 << 12 to 1 << 30. */
dicsize = archive_le32dec(buffer+1);
@ -377,7 +368,7 @@ lzip_has_member(struct archive_read_filter *filter)
/* Dictionary size. */
log2dic = buffer[5] & 0x1f;
if (log2dic < 12 || log2dic > 27)
if (log2dic < 12 || log2dic > 29)
return (0);
bits_checked += 8;
@ -470,6 +461,12 @@ set_error(struct archive_read_filter *self, int ret)
}
}
static const struct archive_read_filter_vtable
xz_lzma_reader_vtable = {
.read = xz_filter_read,
.close = xz_filter_close,
};
/*
* Setup the callbacks.
*/
@ -494,9 +491,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
self->data = state;
state->out_block_size = out_block_size;
state->out_block = out_block;
self->read = xz_filter_read;
self->skip = NULL; /* not supported */
self->close = xz_filter_close;
self->vtable = &xz_lzma_reader_vtable;
state->stream.avail_in = 0;
@ -562,7 +557,7 @@ lzip_init(struct archive_read_filter *self)
/* Get dictionary size. */
log2dic = h[5] & 0x1f;
if (log2dic < 12 || log2dic > 27)
if (log2dic < 12 || log2dic > 29)
return (ARCHIVE_FATAL);
dicsize = 1U << log2dic;
if (log2dic > 12)

View file

@ -79,24 +79,21 @@ static int zstd_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *);
static int zstd_bidder_init(struct archive_read_filter *);
static const struct archive_read_filter_bidder_vtable
zstd_bidder_vtable = {
.bid = zstd_bidder_bid,
.init = zstd_bidder_init,
};
int
archive_read_support_filter_zstd(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_zstd");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
if (__archive_read_register_bidder(a, NULL, "zstd",
&zstd_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->name = "zstd";
bidder->bid = zstd_bidder_bid;
bidder->init = zstd_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#if HAVE_ZSTD_H && HAVE_LIBZSTD
return (ARCHIVE_OK);
#else
@ -160,6 +157,12 @@ zstd_bidder_init(struct archive_read_filter *self)
#else
static const struct archive_read_filter_vtable
zstd_reader_vtable = {
.read = zstd_filter_read,
.close = zstd_filter_close,
};
/*
* Initialize the filter object
*/
@ -192,9 +195,7 @@ zstd_bidder_init(struct archive_read_filter *self)
state->out_block_size = out_block_size;
state->out_block = out_block;
state->dstream = dstream;
self->read = zstd_filter_read;
self->skip = NULL; /* not supported */
self->close = zstd_filter_close;
self->vtable = &zstd_reader_vtable;
state->eof = 0;
state->in_frame = 0;

View file

@ -1629,11 +1629,11 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
|| strcmp(key, "contents") == 0) {
parse_escapes(val, NULL);
archive_strcpy(&mtree->contents_name, val);
break;
return (ARCHIVE_OK);
}
if (strcmp(key, "cksum") == 0)
break;
__LA_FALLTHROUGH;
return (ARCHIVE_OK);
break;
case 'd':
if (strcmp(key, "device") == 0) {
/* stat(2) st_rdev field, e.g. the major/minor IDs
@ -1647,65 +1647,64 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
archive_entry_set_rdev(entry, dev);
return r;
}
__LA_FALLTHROUGH;
break;
case 'f':
if (strcmp(key, "flags") == 0) {
*parsed_kws |= MTREE_HAS_FFLAGS;
archive_entry_copy_fflags_text(entry, val);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'g':
if (strcmp(key, "gid") == 0) {
*parsed_kws |= MTREE_HAS_GID;
archive_entry_set_gid(entry, mtree_atol(&val, 10));
break;
return (ARCHIVE_OK);
}
if (strcmp(key, "gname") == 0) {
*parsed_kws |= MTREE_HAS_GNAME;
archive_entry_copy_gname(entry, val);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'i':
if (strcmp(key, "inode") == 0) {
archive_entry_set_ino(entry, mtree_atol(&val, 10));
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'l':
if (strcmp(key, "link") == 0) {
parse_escapes(val, NULL);
archive_entry_copy_symlink(entry, val);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'm':
if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) {
return parse_digest(a, entry, val,
ARCHIVE_ENTRY_DIGEST_MD5);
}
if (strcmp(key, "mode") == 0) {
if (val[0] >= '0' && val[0] <= '7') {
*parsed_kws |= MTREE_HAS_PERM;
archive_entry_set_perm(entry,
(mode_t)mtree_atol(&val, 8));
} else {
if (val[0] < '0' || val[0] > '7') {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Symbolic or non-octal mode \"%s\" unsupported", val);
return ARCHIVE_WARN;
return (ARCHIVE_WARN);
}
break;
*parsed_kws |= MTREE_HAS_PERM;
archive_entry_set_perm(entry, (mode_t)mtree_atol(&val, 8));
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'n':
if (strcmp(key, "nlink") == 0) {
*parsed_kws |= MTREE_HAS_NLINK;
archive_entry_set_nlink(entry,
(unsigned int)mtree_atol(&val, 10));
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'r':
if (strcmp(key, "resdevice") == 0) {
/* stat(2) st_dev field, e.g. the device ID where the
@ -1723,7 +1722,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
return parse_digest(a, entry, val,
ARCHIVE_ENTRY_DIGEST_RMD160);
}
__LA_FALLTHROUGH;
break;
case 's':
if (strcmp(key, "sha1") == 0 ||
strcmp(key, "sha1digest") == 0) {
@ -1747,9 +1746,9 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
}
if (strcmp(key, "size") == 0) {
archive_entry_set_size(entry, mtree_atol(&val, 10));
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 't':
if (strcmp(key, "tags") == 0) {
/*
@ -1757,7 +1756,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
* Ignore the tags for now, but the interface
* should be extended to allow inclusion/exclusion.
*/
break;
return (ARCHIVE_OK);
}
if (strcmp(key, "time") == 0) {
int64_t m;
@ -1783,79 +1782,85 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
else if (m < my_time_t_min)
m = my_time_t_min;
archive_entry_set_mtime(entry, (time_t)m, ns);
break;
return (ARCHIVE_OK);
}
if (strcmp(key, "type") == 0) {
switch (val[0]) {
case 'b':
if (strcmp(val, "block") == 0) {
archive_entry_set_filetype(entry, AE_IFBLK);
break;
*parsed_kws |= MTREE_HAS_TYPE;
archive_entry_set_filetype(entry,
AE_IFBLK);
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'c':
if (strcmp(val, "char") == 0) {
*parsed_kws |= MTREE_HAS_TYPE;
archive_entry_set_filetype(entry,
AE_IFCHR);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'd':
if (strcmp(val, "dir") == 0) {
*parsed_kws |= MTREE_HAS_TYPE;
archive_entry_set_filetype(entry,
AE_IFDIR);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'f':
if (strcmp(val, "fifo") == 0) {
*parsed_kws |= MTREE_HAS_TYPE;
archive_entry_set_filetype(entry,
AE_IFIFO);
break;
return (ARCHIVE_OK);
}
if (strcmp(val, "file") == 0) {
*parsed_kws |= MTREE_HAS_TYPE;
archive_entry_set_filetype(entry,
AE_IFREG);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
case 'l':
if (strcmp(val, "link") == 0) {
*parsed_kws |= MTREE_HAS_TYPE;
archive_entry_set_filetype(entry,
AE_IFLNK);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized file type \"%s\"; "
"assuming \"file\"", val);
archive_entry_set_filetype(entry, AE_IFREG);
return (ARCHIVE_WARN);
break;
}
*parsed_kws |= MTREE_HAS_TYPE;
break;
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized file type \"%s\"; "
"assuming \"file\"", val);
archive_entry_set_filetype(entry, AE_IFREG);
return (ARCHIVE_WARN);
}
__LA_FALLTHROUGH;
break;
case 'u':
if (strcmp(key, "uid") == 0) {
*parsed_kws |= MTREE_HAS_UID;
archive_entry_set_uid(entry, mtree_atol(&val, 10));
break;
return (ARCHIVE_OK);
}
if (strcmp(key, "uname") == 0) {
*parsed_kws |= MTREE_HAS_UNAME;
archive_entry_copy_uname(entry, val);
break;
return (ARCHIVE_OK);
}
__LA_FALLTHROUGH;
break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized key %s=%s", key, val);
return (ARCHIVE_WARN);
break;
}
return (ARCHIVE_OK);
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized key %s=%s", key, val);
return (ARCHIVE_WARN);
}
static int

View file

@ -135,6 +135,16 @@
#define MAX_SYMBOL_LENGTH 0xF
#define MAX_SYMBOLS 20
/* Virtual Machine Properties */
#define VM_MEMORY_SIZE 0x40000
#define VM_MEMORY_MASK (VM_MEMORY_SIZE - 1)
#define PROGRAM_WORK_SIZE 0x3C000
#define PROGRAM_GLOBAL_SIZE 0x2000
#define PROGRAM_SYSTEM_GLOBAL_ADDRESS PROGRAM_WORK_SIZE
#define PROGRAM_SYSTEM_GLOBAL_SIZE 0x40
#define PROGRAM_USER_GLOBAL_ADDRESS (PROGRAM_SYSTEM_GLOBAL_ADDRESS + PROGRAM_SYSTEM_GLOBAL_SIZE)
#define PROGRAM_USER_GLOBAL_SIZE (PROGRAM_GLOBAL_SIZE - PROGRAM_SYSTEM_GLOBAL_SIZE)
/*
* Considering L1,L2 cache miss and a calling of write system-call,
* the best size of the output buffer(uncompressed buffer) is 128K.
@ -213,6 +223,69 @@ struct data_block_offsets
int64_t end_offset;
};
struct rar_program_code
{
uint8_t *staticdata;
uint32_t staticdatalen;
uint8_t *globalbackup;
uint32_t globalbackuplen;
uint64_t fingerprint;
uint32_t usagecount;
uint32_t oldfilterlength;
struct rar_program_code *next;
};
struct rar_filter
{
struct rar_program_code *prog;
uint32_t initialregisters[8];
uint8_t *globaldata;
uint32_t globaldatalen;
size_t blockstartpos;
uint32_t blocklength;
uint32_t filteredblockaddress;
uint32_t filteredblocklength;
struct rar_filter *next;
};
struct memory_bit_reader
{
const uint8_t *bytes;
size_t length;
size_t offset;
uint64_t bits;
int available;
int at_eof;
};
struct rar_virtual_machine
{
uint32_t registers[8];
uint8_t memory[VM_MEMORY_SIZE + sizeof(uint32_t)];
};
struct rar_filters
{
struct rar_virtual_machine *vm;
struct rar_program_code *progs;
struct rar_filter *stack;
int64_t filterstart;
uint32_t lastfilternum;
int64_t lastend;
uint8_t *bytes;
size_t bytes_ready;
};
struct audio_state
{
int8_t weight[5];
int16_t delta[4];
int8_t lastdelta;
int error[11];
int count;
uint8_t lastbyte;
};
struct rar
{
/* Entries from main RAR header */
@ -273,15 +346,16 @@ struct rar
struct huffman_code lengthcode;
unsigned char lengthtable[HUFFMAN_TABLE_SIZE];
struct lzss lzss;
char output_last_match;
unsigned int lastlength;
unsigned int lastoffset;
unsigned int oldoffset[4];
unsigned int lastlowoffset;
unsigned int numlowoffsetrepeats;
int64_t filterstart;
char start_new_table;
/* Filters */
struct rar_filters filters;
/* PPMd Variant H members */
char ppmd_valid;
char ppmd_eod;
@ -343,13 +417,13 @@ static int read_symlink_stored(struct archive_read *, struct archive_entry *,
static int read_data_stored(struct archive_read *, const void **, size_t *,
int64_t *);
static int read_data_compressed(struct archive_read *, const void **, size_t *,
int64_t *, size_t);
int64_t *, size_t);
static int rar_br_preparation(struct archive_read *, struct rar_br *);
static int parse_codes(struct archive_read *);
static void free_codes(struct archive_read *);
static int read_next_symbol(struct archive_read *, struct huffman_code *);
static int create_code(struct archive_read *, struct huffman_code *,
unsigned char *, int, char);
unsigned char *, int, char);
static int add_value(struct archive_read *, struct huffman_code *, int, int,
int);
static int new_node(struct huffman_code *);
@ -357,9 +431,29 @@ static int make_table(struct archive_read *, struct huffman_code *);
static int make_table_recurse(struct archive_read *, struct huffman_code *, int,
struct huffman_table_entry *, int, int);
static int64_t expand(struct archive_read *, int64_t);
static int copy_from_lzss_window(struct archive_read *, const void **,
int64_t, int);
static int copy_from_lzss_window_to_unp(struct archive_read *, const void **,
int64_t, int);
static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *);
static int parse_filter(struct archive_read *, const uint8_t *, uint16_t,
uint8_t);
static int run_filters(struct archive_read *);
static void clear_filters(struct rar_filters *);
static struct rar_filter *create_filter(struct rar_program_code *,
const uint8_t *, uint32_t,
uint32_t[8], size_t, uint32_t);
static void delete_filter(struct rar_filter *filter);
static struct rar_program_code *compile_program(const uint8_t *, size_t);
static void delete_program_code(struct rar_program_code *prog);
static uint32_t membr_next_rarvm_number(struct memory_bit_reader *br);
static inline uint32_t membr_bits(struct memory_bit_reader *br, int bits);
static int membr_fill(struct memory_bit_reader *br, int bits);
static int read_filter(struct archive_read *, int64_t *);
static int rar_decode_byte(struct archive_read*, uint8_t *);
static int execute_filter(struct archive_read*, struct rar_filter *,
struct rar_virtual_machine *, size_t);
static int copy_from_lzss_window(struct archive_read *, void *, int64_t, int);
static inline void vm_write_32(struct rar_virtual_machine*, size_t, uint32_t);
static inline uint32_t vm_read_32(struct rar_virtual_machine*, size_t);
/*
* Bit stream reader.
@ -1244,6 +1338,7 @@ archive_read_format_rar_cleanup(struct archive_read *a)
rar = (struct rar *)(a->format->data);
free_codes(a);
clear_filters(&rar->filters);
free(rar->filename);
free(rar->filename_save);
free(rar->dbo);
@ -1662,6 +1757,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
__archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
rar->ppmd_valid = rar->ppmd_eod = 0;
rar->filters.filterstart = INT64_MAX;
/* Don't set any archive entries for non-file header types */
if (head_type == NEWSUB_HEAD)
@ -1886,7 +1982,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
static int
read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
int64_t *offset, size_t looper)
int64_t *offset, size_t looper)
{
if (looper++ > MAX_COMPRESS_DEPTH)
return (ARCHIVE_FATAL);
@ -1901,6 +1997,33 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
do {
if (!rar->valid)
return (ARCHIVE_FATAL);
if (rar->filters.bytes_ready > 0)
{
/* Flush unp_buffer first */
if (rar->unp_offset > 0)
{
*buff = rar->unp_buffer;
*size = rar->unp_offset;
rar->unp_offset = 0;
*offset = rar->offset_outgoing;
rar->offset_outgoing += *size;
}
else
{
*buff = rar->filters.bytes;
*size = rar->filters.bytes_ready;
rar->offset += *size;
*offset = rar->offset_outgoing;
rar->offset_outgoing += *size;
rar->filters.bytes_ready -= *size;
rar->filters.bytes += *size;
}
goto ending_block;
}
if (rar->ppmd_eod ||
(rar->dictionary_size && rar->offset >= rar->unp_size))
{
@ -1936,7 +2059,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
bs = rar->unp_buffer_size - rar->unp_offset;
else
bs = (size_t)rar->bytes_uncopied;
ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs);
if (ret != ARCHIVE_OK)
return (ret);
rar->offset += bs;
@ -1954,6 +2077,13 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
continue;
}
if (rar->filters.lastend == rar->filters.filterstart)
{
if (!run_filters(a))
return (ARCHIVE_FATAL);
continue;
}
if (!rar->br.next_in &&
(ret = rar_br_preparation(a, &(rar->br))) < ARCHIVE_WARN)
return (ret);
@ -2045,13 +2175,16 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
{
start = rar->offset;
end = start + rar->dictionary_size;
rar->filterstart = INT64_MAX;
if (rar->filters.filterstart < end) {
end = rar->filters.filterstart;
}
if ((actualend = expand(a, end)) < 0)
return ((int)actualend);
rar->bytes_uncopied = actualend - start;
if (rar->bytes_uncopied == 0) {
rar->filters.lastend = actualend;
if (rar->filters.lastend != rar->filters.filterstart && rar->bytes_uncopied == 0) {
/* Broken RAR files cause this case.
* NOTE: If this case were possible on a normal RAR file
* we would find out where it was actually bad and
@ -2065,7 +2198,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
bs = rar->unp_buffer_size - rar->unp_offset;
else
bs = (size_t)rar->bytes_uncopied;
ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs);
ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs);
if (ret != ARCHIVE_OK)
return (ret);
rar->offset += bs;
@ -2080,6 +2213,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
*size = rar->unp_buffer_size;
*offset = rar->offset_outgoing;
rar->offset_outgoing += *size;
ending_block:
/* Calculate File CRC. */
rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size);
return ret;
@ -2739,25 +2873,19 @@ expand(struct archive_read *a, int64_t end)
struct rar *rar = (struct rar *)(a->format->data);
struct rar_br *br = &(rar->br);
if (rar->filterstart < end)
end = rar->filterstart;
if (rar->filters.filterstart < end)
end = rar->filters.filterstart;
while (1)
{
if (rar->output_last_match &&
lzss_position(&rar->lzss) + rar->lastlength <= end)
{
lzss_emit_match(rar, rar->lastoffset, rar->lastlength);
rar->output_last_match = 0;
}
if(lzss_position(&rar->lzss) >= end)
return end;
if(rar->is_ppmd_block || rar->output_last_match ||
lzss_position(&rar->lzss) >= end)
if(rar->is_ppmd_block)
return lzss_position(&rar->lzss);
if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
return (ARCHIVE_FATAL);
rar->output_last_match = 0;
if (symbol < 256)
{
@ -2789,9 +2917,9 @@ expand(struct archive_read *a, int64_t end)
}
else if(symbol==257)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Parsing filters is unsupported.");
return (ARCHIVE_FAILED);
if (!read_filter(a, &end))
return (ARCHIVE_FATAL);
continue;
}
else if(symbol==258)
{
@ -2864,7 +2992,7 @@ expand(struct archive_read *a, int64_t end)
goto truncated_data;
offs += rar_br_bits(br, offsetbits[offssymbol] - 4) << 4;
rar_br_consume(br, offsetbits[offssymbol] - 4);
}
}
if(rar->numlowoffsetrepeats > 0)
{
@ -2908,7 +3036,8 @@ expand(struct archive_read *a, int64_t end)
rar->lastoffset = offs;
rar->lastlength = len;
rar->output_last_match = 1;
lzss_emit_match(rar, rar->lastoffset, rar->lastlength);
}
truncated_data:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@ -2922,8 +3051,31 @@ expand(struct archive_read *a, int64_t end)
}
static int
copy_from_lzss_window(struct archive_read *a, const void **buffer,
int64_t startpos, int length)
copy_from_lzss_window(struct archive_read *a, void *buffer,
int64_t startpos, int length)
{
int windowoffs, firstpart;
struct rar *rar = (struct rar *)(a->format->data);
windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
firstpart = lzss_size(&rar->lzss) - windowoffs;
if (firstpart < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data");
return (ARCHIVE_FATAL);
}
if (firstpart < length) {
memcpy(buffer, &rar->lzss.window[windowoffs], firstpart);
memcpy(buffer, &rar->lzss.window[0], length - firstpart);
} else {
memcpy(buffer, &rar->lzss.window[windowoffs], length);
}
return (ARCHIVE_OK);
}
static int
copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
int64_t startpos, int length)
{
int windowoffs, firstpart;
struct rar *rar = (struct rar *)(a->format->data);
@ -3003,3 +3155,599 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
}
return h;
}
static int
parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint8_t flags)
{
struct rar *rar = (struct rar *)(a->format->data);
struct rar_filters *filters = &rar->filters;
struct memory_bit_reader br = { 0 };
struct rar_program_code *prog;
struct rar_filter *filter, **nextfilter;
uint32_t numprogs, num, blocklength, globaldatalen;
uint8_t *globaldata;
size_t blockstartpos;
uint32_t registers[8] = { 0 };
uint32_t i;
br.bytes = bytes;
br.length = length;
numprogs = 0;
for (prog = filters->progs; prog; prog = prog->next)
numprogs++;
if ((flags & 0x80))
{
num = membr_next_rarvm_number(&br);
if (num == 0)
{
delete_filter(filters->stack);
filters->stack = NULL;
delete_program_code(filters->progs);
filters->progs = NULL;
}
else
num--;
if (num > numprogs) {
return 0;
}
filters->lastfilternum = num;
}
else
num = filters->lastfilternum;
prog = filters->progs;
for (i = 0; i < num; i++)
prog = prog->next;
if (prog)
prog->usagecount++;
blockstartpos = membr_next_rarvm_number(&br) + (size_t)lzss_position(&rar->lzss);
if ((flags & 0x40))
blockstartpos += 258;
if ((flags & 0x20))
blocklength = membr_next_rarvm_number(&br);
else
blocklength = prog ? prog->oldfilterlength : 0;
registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS;
registers[4] = blocklength;
registers[5] = prog ? prog->usagecount : 0;
registers[7] = VM_MEMORY_SIZE;
if ((flags & 0x10))
{
uint8_t mask = (uint8_t)membr_bits(&br, 7);
for (i = 0; i < 7; i++)
if ((mask & (1 << i)))
registers[i] = membr_next_rarvm_number(&br);
}
if (!prog)
{
uint32_t len = membr_next_rarvm_number(&br);
uint8_t *bytecode;
struct rar_program_code **next;
if (len == 0 || len > 0x10000)
return 0;
bytecode = malloc(len);
if (!bytecode)
return 0;
for (i = 0; i < len; i++)
bytecode[i] = (uint8_t)membr_bits(&br, 8);
prog = compile_program(bytecode, len);
if (!prog) {
free(bytecode);
return 0;
}
free(bytecode);
next = &filters->progs;
while (*next)
next = &(*next)->next;
*next = prog;
}
prog->oldfilterlength = blocklength;
globaldata = NULL;
globaldatalen = 0;
if ((flags & 0x08))
{
globaldatalen = membr_next_rarvm_number(&br);
if (globaldatalen > PROGRAM_USER_GLOBAL_SIZE)
return 0;
globaldata = malloc(globaldatalen + PROGRAM_SYSTEM_GLOBAL_SIZE);
if (!globaldata)
return 0;
for (i = 0; i < globaldatalen; i++)
globaldata[i + PROGRAM_SYSTEM_GLOBAL_SIZE] = (uint8_t)membr_bits(&br, 8);
}
if (br.at_eof)
{
free(globaldata);
return 0;
}
filter = create_filter(prog, globaldata, globaldatalen, registers, blockstartpos, blocklength);
free(globaldata);
if (!filter)
return 0;
for (i = 0; i < 7; i++)
archive_le32enc(&filter->globaldata[i * 4], registers[i]);
archive_le32enc(&filter->globaldata[0x1C], blocklength);
archive_le32enc(&filter->globaldata[0x20], 0);
archive_le32enc(&filter->globaldata[0x2C], prog->usagecount);
nextfilter = &filters->stack;
while (*nextfilter)
nextfilter = &(*nextfilter)->next;
*nextfilter = filter;
if (!filters->stack->next)
filters->filterstart = blockstartpos;
return 1;
}
static struct rar_filter *
create_filter(struct rar_program_code *prog, const uint8_t *globaldata, uint32_t globaldatalen, uint32_t registers[8], size_t startpos, uint32_t length)
{
struct rar_filter *filter;
filter = calloc(1, sizeof(*filter));
if (!filter)
return NULL;
filter->prog = prog;
filter->globaldatalen = globaldatalen > PROGRAM_SYSTEM_GLOBAL_SIZE ? globaldatalen : PROGRAM_SYSTEM_GLOBAL_SIZE;
filter->globaldata = calloc(1, filter->globaldatalen);
if (!filter->globaldata)
return NULL;
if (globaldata)
memcpy(filter->globaldata, globaldata, globaldatalen);
if (registers)
memcpy(filter->initialregisters, registers, sizeof(filter->initialregisters));
filter->blockstartpos = startpos;
filter->blocklength = length;
return filter;
}
static int
run_filters(struct archive_read *a)
{
struct rar *rar = (struct rar *)(a->format->data);
struct rar_filters *filters = &rar->filters;
struct rar_filter *filter = filters->stack;
size_t start = filters->filterstart;
size_t end = start + filter->blocklength;
uint32_t lastfilteraddress;
uint32_t lastfilterlength;
int ret;
filters->filterstart = INT64_MAX;
end = (size_t)expand(a, end);
if (end != start + filter->blocklength)
return 0;
if (!filters->vm)
{
filters->vm = calloc(1, sizeof(*filters->vm));
if (!filters->vm)
return 0;
}
ret = copy_from_lzss_window(a, filters->vm->memory, start, filter->blocklength);
if (ret != ARCHIVE_OK)
return 0;
if (!execute_filter(a, filter, filters->vm, rar->offset))
return 0;
lastfilteraddress = filter->filteredblockaddress;
lastfilterlength = filter->filteredblocklength;
filters->stack = filter->next;
filter->next = NULL;
delete_filter(filter);
while ((filter = filters->stack) != NULL && (int64_t)filter->blockstartpos == filters->filterstart && filter->blocklength == lastfilterlength)
{
memmove(&filters->vm->memory[0], &filters->vm->memory[lastfilteraddress], lastfilterlength);
if (!execute_filter(a, filter, filters->vm, rar->offset))
return 0;
lastfilteraddress = filter->filteredblockaddress;
lastfilterlength = filter->filteredblocklength;
filters->stack = filter->next;
filter->next = NULL;
delete_filter(filter);
}
if (filters->stack)
{
if (filters->stack->blockstartpos < end)
return 0;
filters->filterstart = filters->stack->blockstartpos;
}
filters->lastend = end;
filters->bytes = &filters->vm->memory[lastfilteraddress];
filters->bytes_ready = lastfilterlength;
return 1;
}
static struct rar_program_code *
compile_program(const uint8_t *bytes, size_t length)
{
struct memory_bit_reader br = { 0 };
struct rar_program_code *prog;
// uint32_t instrcount = 0;
uint8_t xor;
size_t i;
xor = 0;
for (i = 1; i < length; i++)
xor ^= bytes[i];
if (!length || xor != bytes[0])
return NULL;
br.bytes = bytes;
br.length = length;
br.offset = 1;
prog = calloc(1, sizeof(*prog));
if (!prog)
return NULL;
prog->fingerprint = crc32(0, bytes, length) | ((uint64_t)length << 32);
if (membr_bits(&br, 1))
{
prog->staticdatalen = membr_next_rarvm_number(&br) + 1;
prog->staticdata = malloc(prog->staticdatalen);
if (!prog->staticdata)
{
delete_program_code(prog);
return NULL;
}
for (i = 0; i < prog->staticdatalen; i++)
prog->staticdata[i] = (uint8_t)membr_bits(&br, 8);
}
return prog;
}
static void
delete_filter(struct rar_filter *filter)
{
while (filter)
{
struct rar_filter *next = filter->next;
free(filter->globaldata);
free(filter);
filter = next;
}
}
static void
clear_filters(struct rar_filters *filters)
{
delete_filter(filters->stack);
delete_program_code(filters->progs);
free(filters->vm);
}
static void
delete_program_code(struct rar_program_code *prog)
{
while (prog)
{
struct rar_program_code *next = prog->next;
free(prog->staticdata);
free(prog->globalbackup);
free(prog);
prog = next;
}
}
static uint32_t
membr_next_rarvm_number(struct memory_bit_reader *br)
{
uint32_t val;
switch (membr_bits(br, 2))
{
case 0:
return membr_bits(br, 4);
case 1:
val = membr_bits(br, 8);
if (val >= 16)
return val;
return 0xFFFFFF00 | (val << 4) | membr_bits(br, 4);
case 2:
return membr_bits(br, 16);
default:
return membr_bits(br, 32);
}
}
static inline uint32_t
membr_bits(struct memory_bit_reader *br, int bits)
{
if (bits > br->available && (br->at_eof || !membr_fill(br, bits)))
return 0;
return (uint32_t)((br->bits >> (br->available -= bits)) & (((uint64_t)1 << bits) - 1));
}
static int
membr_fill(struct memory_bit_reader *br, int bits)
{
while (br->available < bits && br->offset < br->length)
{
br->bits = (br->bits << 8) | br->bytes[br->offset++];
br->available += 8;
}
if (bits > br->available)
{
br->at_eof = 1;
return 0;
}
return 1;
}
static int
read_filter(struct archive_read *a, int64_t *end)
{
struct rar *rar = (struct rar *)(a->format->data);
uint8_t flags, val, *code;
uint16_t length, i;
if (!rar_decode_byte(a, &flags))
return 0;
length = (flags & 0x07) + 1;
if (length == 7)
{
if (!rar_decode_byte(a, &val))
return 0;
length = val + 7;
}
else if (length == 8)
{
if (!rar_decode_byte(a, &val))
return 0;
length = val << 8;
if (!rar_decode_byte(a, &val))
return 0;
length |= val;
}
code = malloc(length);
if (!code)
return 0;
for (i = 0; i < length; i++)
{
if (!rar_decode_byte(a, &code[i]))
{
free(code);
return 0;
}
}
if (!parse_filter(a, code, length, flags))
{
free(code);
return 0;
}
free(code);
if (rar->filters.filterstart < *end)
*end = rar->filters.filterstart;
return 1;
}
static int
execute_filter_delta(struct rar_filter *filter, struct rar_virtual_machine *vm)
{
uint32_t length = filter->initialregisters[4];
uint32_t numchannels = filter->initialregisters[0];
uint8_t *src, *dst;
uint32_t i, idx;
if (length > PROGRAM_WORK_SIZE / 2)
return 0;
src = &vm->memory[0];
dst = &vm->memory[length];
for (i = 0; i < numchannels; i++)
{
uint8_t lastbyte = 0;
for (idx = i; idx < length; idx += numchannels)
lastbyte = dst[idx] = lastbyte - *src++;
}
filter->filteredblockaddress = length;
filter->filteredblocklength = length;
return 1;
}
static int
execute_filter_e8(struct rar_filter *filter, struct rar_virtual_machine *vm, size_t pos, int e9also)
{
uint32_t length = filter->initialregisters[4];
uint32_t filesize = 0x1000000;
uint32_t i;
if (length > PROGRAM_WORK_SIZE || length < 4)
return 0;
for (i = 0; i <= length - 5; i++)
{
if (vm->memory[i] == 0xE8 || (e9also && vm->memory[i] == 0xE9))
{
uint32_t currpos = (uint32_t)pos + i + 1;
int32_t address = (int32_t)vm_read_32(vm, i + 1);
if (address < 0 && currpos >= (uint32_t)-address)
vm_write_32(vm, i + 1, address + filesize);
else if (address >= 0 && (uint32_t)address < filesize)
vm_write_32(vm, i + 1, address - currpos);
i += 4;
}
}
filter->filteredblockaddress = 0;
filter->filteredblocklength = length;
return 1;
}
static int
execute_filter_rgb(struct rar_filter *filter, struct rar_virtual_machine *vm)
{
uint32_t stride = filter->initialregisters[0];
uint32_t byteoffset = filter->initialregisters[1];
uint32_t blocklength = filter->initialregisters[4];
uint8_t *src, *dst;
uint32_t i, j;
if (blocklength > PROGRAM_WORK_SIZE / 2 || stride > blocklength)
return 0;
src = &vm->memory[0];
dst = &vm->memory[blocklength];
for (i = 0; i < 3; i++) {
uint8_t byte = 0;
uint8_t *prev = dst + i - stride;
for (j = i; j < blocklength; j += 3)
{
if (prev >= dst)
{
uint32_t delta1 = abs(prev[3] - prev[0]);
uint32_t delta2 = abs(byte - prev[0]);
uint32_t delta3 = abs(prev[3] - prev[0] + byte - prev[0]);
if (delta1 > delta2 || delta1 > delta3)
byte = delta2 <= delta3 ? prev[3] : prev[0];
}
byte -= *src++;
dst[j] = byte;
prev += 3;
}
}
for (i = byteoffset; i < blocklength - 2; i += 3)
{
dst[i] += dst[i + 1];
dst[i + 2] += dst[i + 1];
}
filter->filteredblockaddress = blocklength;
filter->filteredblocklength = blocklength;
return 1;
}
static int
execute_filter_audio(struct rar_filter *filter, struct rar_virtual_machine *vm)
{
uint32_t length = filter->initialregisters[4];
uint32_t numchannels = filter->initialregisters[0];
uint8_t *src, *dst;
uint32_t i, j;
if (length > PROGRAM_WORK_SIZE / 2)
return 0;
src = &vm->memory[0];
dst = &vm->memory[length];
for (i = 0; i < numchannels; i++)
{
struct audio_state state;
memset(&state, 0, sizeof(state));
for (j = i; j < length; j += numchannels)
{
int8_t delta = (int8_t)*src++;
uint8_t predbyte, byte;
int prederror;
state.delta[2] = state.delta[1];
state.delta[1] = state.lastdelta - state.delta[0];
state.delta[0] = state.lastdelta;
predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF;
byte = (predbyte - delta) & 0xFF;
prederror = delta << 3;
state.error[0] += abs(prederror);
state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]);
state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]);
state.error[5] += abs(prederror - state.delta[2]); state.error[6] += abs(prederror + state.delta[2]);
state.lastdelta = (int8_t)(byte - state.lastbyte);
dst[j] = state.lastbyte = byte;
if (!(state.count++ & 0x1F))
{
uint8_t k, idx = 0;
for (k = 1; k < 7; k++)
{
if (state.error[k] < state.error[idx])
idx = k;
}
memset(state.error, 0, sizeof(state.error));
switch (idx)
{
case 1: if (state.weight[0] >= -16) state.weight[0]--; break;
case 2: if (state.weight[0] < 16) state.weight[0]++; break;
case 3: if (state.weight[1] >= -16) state.weight[1]--; break;
case 4: if (state.weight[1] < 16) state.weight[1]++; break;
case 5: if (state.weight[2] >= -16) state.weight[2]--; break;
case 6: if (state.weight[2] < 16) state.weight[2]++; break;
}
}
}
}
filter->filteredblockaddress = length;
filter->filteredblocklength = length;
return 1;
}
static int
execute_filter(struct archive_read *a, struct rar_filter *filter, struct rar_virtual_machine *vm, size_t pos)
{
if (filter->prog->fingerprint == 0x1D0E06077D)
return execute_filter_delta(filter, vm);
if (filter->prog->fingerprint == 0x35AD576887)
return execute_filter_e8(filter, vm, pos, 0);
if (filter->prog->fingerprint == 0x393CD7E57E)
return execute_filter_e8(filter, vm, pos, 1);
if (filter->prog->fingerprint == 0x951C2C5DC8)
return execute_filter_rgb(filter, vm);
if (filter->prog->fingerprint == 0xD8BC85E701)
return execute_filter_audio(filter, vm);
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "No support for RAR VM program filter");
return 0;
}
static int
rar_decode_byte(struct archive_read *a, uint8_t *byte)
{
struct rar *rar = (struct rar *)(a->format->data);
struct rar_br *br = &(rar->br);
if (!rar_br_read_ahead(a, br, 8))
return 0;
*byte = (uint8_t)rar_br_bits(br, 8);
rar_br_consume(br, 8);
return 1;
}
static inline void
vm_write_32(struct rar_virtual_machine* vm, size_t offset, uint32_t u32)
{
archive_le32enc(vm->memory + offset, u32);
}
static inline uint32_t
vm_read_32(struct rar_virtual_machine* vm, size_t offset)
{
return archive_le32dec(vm->memory + offset);
}

View file

@ -632,7 +632,7 @@ static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {
/* 0xEB = ARM's BL (branch + link) instruction. */
offset = read_filter_data(rar,
(rar->cstate.solid_offset + flt->block_start + i) &
rar->cstate.window_mask) & 0x00ffffff;
(uint32_t)rar->cstate.window_mask) & 0x00ffffff;
offset -= (uint32_t) ((i + flt->block_start) / 4);
offset = (offset & 0x00ffffff) | 0xeb000000;
@ -1012,7 +1012,16 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
return ret;
}
static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
static int read_bits_32(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint32_t* value)
{
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Premature end of stream during extraction of data (#1)");
return ARCHIVE_FATAL;
}
uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24;
bits |= p[rar->bits.in_addr + 1] << 16;
bits |= p[rar->bits.in_addr + 2] << 8;
@ -1023,7 +1032,16 @@ static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
return ARCHIVE_OK;
}
static int read_bits_16(struct rar5* rar, const uint8_t* p, uint16_t* value) {
static int read_bits_16(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint16_t* value)
{
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_PROGRAMMER,
"Premature end of stream during extraction of data (#2)");
return ARCHIVE_FATAL;
}
int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16;
bits |= (int) p[rar->bits.in_addr + 1] << 8;
bits |= (int) p[rar->bits.in_addr + 2];
@ -1039,8 +1057,8 @@ static void skip_bits(struct rar5* rar, int bits) {
}
/* n = up to 16 */
static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
int* value)
static int read_consume_bits(struct archive_read* a, struct rar5* rar,
const uint8_t* p, int n, int* value)
{
uint16_t v;
int ret, num;
@ -1051,7 +1069,7 @@ static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
return ARCHIVE_FATAL;
}
ret = read_bits_16(rar, p, &v);
ret = read_bits_16(a, rar, p, &v);
if(ret != ARCHIVE_OK)
return ret;
@ -1099,6 +1117,44 @@ static int bid_standard(struct archive_read* a) {
return -1;
}
static int bid_sfx(struct archive_read *a)
{
const char *p;
if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
return -1;
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
/* This is a PE file */
char signature[sizeof(rar5_signature_xor)];
ssize_t offset = 0x10000;
ssize_t window = 4096;
ssize_t bytes_avail;
rar5_signature(signature);
while (offset + window <= (1024 * 512)) {
const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail);
if (buff == NULL) {
/* Remaining bytes are less than window. */
window >>= 1;
if (window < 0x40)
return 0;
continue;
}
p = buff + offset;
while (p + 8 < buff + bytes_avail) {
if (memcmp(p, signature, sizeof(signature)) == 0)
return 30;
p += 0x10;
}
offset = p - buff;
}
}
return 0;
}
static int rar5_bid(struct archive_read* a, int best_bid) {
int my_bid;
@ -1109,6 +1165,10 @@ static int rar5_bid(struct archive_read* a, int best_bid) {
if(my_bid > -1) {
return my_bid;
}
my_bid = bid_sfx(a);
if (my_bid > -1) {
return my_bid;
}
return -1;
}
@ -1712,14 +1772,29 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
}
}
/* If we're currently switching volumes, ignore the new definition of
* window_size. */
if(rar->cstate.switch_multivolume == 0) {
/* Values up to 64M should fit into ssize_t on every
* architecture. */
rar->cstate.window_size = (ssize_t) window_size;
if(rar->cstate.window_size < (ssize_t) window_size &&
rar->cstate.window_buf)
{
/* If window_buf has been allocated before, reallocate it, so
* that its size will match new window_size. */
uint8_t* new_window_buf =
realloc(rar->cstate.window_buf, window_size);
if(!new_window_buf) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Not enough memory when trying to realloc the window "
"buffer.");
return ARCHIVE_FATAL;
}
rar->cstate.window_buf = new_window_buf;
}
/* Values up to 64M should fit into ssize_t on every
* architecture. */
rar->cstate.window_size = (ssize_t) window_size;
if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {
/* Solid files have to have the same window_size across
whole archive. Remember the window_size parameter
@ -2273,6 +2348,62 @@ static int skip_base_block(struct archive_read* a) {
return ret;
}
static int try_skip_sfx(struct archive_read *a)
{
const char *p;
if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
return ARCHIVE_EOF;
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0)
{
char signature[sizeof(rar5_signature_xor)];
const void *h;
const char *q;
size_t skip, total = 0;
ssize_t bytes, window = 4096;
rar5_signature(signature);
while (total + window <= (1024 * 512)) {
h = __archive_read_ahead(a, window, &bytes);
if (h == NULL) {
/* Remaining bytes are less than window. */
window >>= 1;
if (window < 0x40)
goto fatal;
continue;
}
if (bytes < 0x40)
goto fatal;
p = h;
q = p + bytes;
/*
* Scan ahead until we find something that looks
* like the RAR header.
*/
while (p + 8 < q) {
if (memcmp(p, signature, sizeof(signature)) == 0) {
skip = p - (const char *)h;
__archive_read_consume(a, skip);
return (ARCHIVE_OK);
}
p += 0x10;
}
skip = p - (const char *)h;
__archive_read_consume(a, skip);
total += skip;
}
}
return ARCHIVE_OK;
fatal:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Couldn't find out RAR header");
return (ARCHIVE_FATAL);
}
static int rar5_read_header(struct archive_read *a,
struct archive_entry *entry)
{
@ -2281,6 +2412,8 @@ static int rar5_read_header(struct archive_read *a,
if(rar->header_initialized == 0) {
init_header(a);
if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)
return ret;
rar->header_initialized = 1;
}
@ -2425,13 +2558,13 @@ static int create_decode_tables(uint8_t* bit_length,
static int decode_number(struct archive_read* a, struct decode_table* table,
const uint8_t* p, uint16_t* num)
{
int i, bits, dist;
int i, bits, dist, ret;
uint16_t bitfield;
uint32_t pos;
struct rar5* rar = get_context(a);
if(ARCHIVE_OK != read_bits_16(rar, p, &bitfield)) {
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {
return ret;
}
bitfield &= 0xfffe;
@ -2537,14 +2670,6 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
for(i = 0; i < HUFF_TABLE_SIZE;) {
uint16_t num;
if((rar->bits.in_addr + 6) >= rar->cstate.cur_block_size) {
/* Truncated data, can't continue. */
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated data in huffman tables (#2)");
return ARCHIVE_FATAL;
}
ret = decode_number(a, &rar->cstate.bd, p, &num);
if(ret != ARCHIVE_OK) {
archive_set_error(&a->archive,
@ -2561,8 +2686,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
/* 16..17: repeat previous code */
uint16_t n;
if(ARCHIVE_OK != read_bits_16(rar, p, &n))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
return ret;
if(num == 16) {
n >>= 13;
@ -2590,8 +2715,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
/* other codes: fill with zeroes `n` times */
uint16_t n;
if(ARCHIVE_OK != read_bits_16(rar, p, &n))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
return ret;
if(num == 18) {
n >>= 13;
@ -2707,22 +2832,22 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
}
/* Convenience function used during filter processing. */
static int parse_filter_data(struct rar5* rar, const uint8_t* p,
uint32_t* filter_data)
static int parse_filter_data(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint32_t* filter_data)
{
int i, bytes;
int i, bytes, ret;
uint32_t data = 0;
if(ARCHIVE_OK != read_consume_bits(rar, p, 2, &bytes))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))
return ret;
bytes++;
for(i = 0; i < bytes; i++) {
uint16_t byte;
if(ARCHIVE_OK != read_bits_16(rar, p, &byte)) {
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {
return ret;
}
/* Cast to uint32_t will ensure the shift operation will not
@ -2765,16 +2890,17 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
uint16_t filter_type;
struct filter_info* filt = NULL;
struct rar5* rar = get_context(ar);
int ret;
/* Read the parameters from the input stream. */
if(ARCHIVE_OK != parse_filter_data(rar, p, &block_start))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))
return ret;
if(ARCHIVE_OK != parse_filter_data(rar, p, &block_length))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))
return ret;
if(ARCHIVE_OK != read_bits_16(rar, p, &filter_type))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))
return ret;
filter_type >>= 13;
skip_bits(rar, 3);
@ -2814,8 +2940,8 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
if(filter_type == FILTER_DELTA) {
int channels;
if(ARCHIVE_OK != read_consume_bits(rar, p, 5, &channels))
return ARCHIVE_EOF;
if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))
return ret;
filt->channels = channels + 1;
}
@ -2823,10 +2949,11 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
return ARCHIVE_OK;
}
static int decode_code_length(struct rar5* rar, const uint8_t* p,
uint16_t code)
static int decode_code_length(struct archive_read* a, struct rar5* rar,
const uint8_t* p, uint16_t code)
{
int lbits, length = 2;
if(code < 8) {
lbits = 0;
length += code;
@ -2838,7 +2965,7 @@ static int decode_code_length(struct rar5* rar, const uint8_t* p,
if(lbits > 0) {
int add;
if(ARCHIVE_OK != read_consume_bits(rar, p, lbits, &add))
if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))
return -1;
length += add;
@ -2933,7 +3060,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
continue;
} else if(num >= 262) {
uint16_t dist_slot;
int len = decode_code_length(rar, p, num - 262),
int len = decode_code_length(a, rar, p, num - 262),
dbits,
dist = 1;
@ -2975,12 +3102,12 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
uint16_t low_dist;
if(dbits > 4) {
if(ARCHIVE_OK != read_bits_32(
rar, p, &add)) {
if(ARCHIVE_OK != (ret = read_bits_32(
a, rar, p, &add))) {
/* Return EOF if we
* can't read more
* data. */
return ARCHIVE_EOF;
return ret;
}
skip_bits(rar, dbits - 4);
@ -3015,11 +3142,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
/* dbits is one of [0,1,2,3] */
int add;
if(ARCHIVE_OK != read_consume_bits(rar,
p, dbits, &add)) {
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,
p, dbits, &add))) {
/* Return EOF if we can't read
* more data. */
return ARCHIVE_EOF;
return ret;
}
dist += add;
@ -3076,7 +3203,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
return ARCHIVE_FATAL;
}
len = decode_code_length(rar, p, len_slot);
len = decode_code_length(a, rar, p, len_slot);
if (len == -1) {
return ARCHIVE_FATAL;
}
rar->cstate.last_len = len;
if(ARCHIVE_OK != copy_string(a, len, dist))
@ -3600,6 +3731,16 @@ static int do_uncompress_file(struct archive_read* a) {
rar->cstate.initialized = 1;
}
/* Don't allow extraction if window_size is invalid. */
if(rar->cstate.window_size == 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid window size declaration in this file");
/* This should never happen in valid files. */
return ARCHIVE_FATAL;
}
if(rar->cstate.all_filters_applied == 1) {
/* We use while(1) here, but standard case allows for just 1
* iteration. The loop will iterate if process_block() didn't

View file

@ -573,11 +573,15 @@ archive_read_format_tar_read_header(struct archive_read *a,
l = wcslen(wp);
if (l > 0 && wp[l - 1] == L'/') {
archive_entry_set_filetype(entry, AE_IFDIR);
tar->entry_bytes_remaining = 0;
tar->entry_padding = 0;
}
} else if ((p = archive_entry_pathname(entry)) != NULL) {
l = strlen(p);
if (l > 0 && p[l - 1] == '/') {
archive_entry_set_filetype(entry, AE_IFDIR);
tar->entry_bytes_remaining = 0;
tar->entry_padding = 0;
}
}
}
@ -1396,6 +1400,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
{
int64_t size;
size_t msize;
const void *data;
const char *p, *name;
const wchar_t *wp, *wname;
@ -1434,6 +1439,11 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
/* Read the body as a Mac OS metadata blob. */
size = archive_entry_size(entry);
msize = (size_t)size;
if (size < 0 || (uintmax_t)msize != (uintmax_t)size) {
*unconsumed = 0;
return (ARCHIVE_FATAL);
}
/*
* TODO: Look beyond the body here to peek at the next header.
@ -1447,13 +1457,13 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
* Q: Is the above idea really possible? Even
* when there are GNU or pax extension entries?
*/
data = __archive_read_ahead(a, (size_t)size, NULL);
data = __archive_read_ahead(a, msize, NULL);
if (data == NULL) {
*unconsumed = 0;
return (ARCHIVE_FATAL);
}
archive_entry_copy_mac_metadata(entry, data, (size_t)size);
*unconsumed = (size_t)((size + 511) & ~ 511);
archive_entry_copy_mac_metadata(entry, data, msize);
*unconsumed = (msize + 511) & ~ 511;
tar_flush_unconsumed(a, unconsumed);
return (tar_read_header(a, tar, entry, unconsumed));
}

View file

@ -58,6 +58,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_LZMA_H
#include <lzma.h>
#endif
#ifdef HAVE_ZSTD_H
#include <zstd.h>
#endif
#include "archive.h"
#include "archive_digest_private.h"
@ -191,6 +194,11 @@ struct zip {
char bzstream_valid;
#endif
#if HAVE_ZSTD_H && HAVE_LIBZSTD
ZSTD_DStream *zstdstream;
char zstdstream_valid;
#endif
IByteIn zipx_ppmd_stream;
ssize_t zipx_ppmd_read_compressed;
CPpmd8 ppmd8;
@ -435,6 +443,7 @@ static const struct {
{17, "reserved"}, /* Reserved by PKWARE */
{18, "ibm-terse-new"}, /* File is compressed using IBM TERSE (new) */
{19, "ibm-lz777"},/* IBM LZ77 z Architecture (PFS) */
{93, "zstd"}, /* Zstandard (zstd) Compression */
{95, "xz"}, /* XZ compressed data */
{96, "jpeg"}, /* JPEG compressed data */
{97, "wav-pack"}, /* WavPack compressed data */
@ -1144,7 +1153,8 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
(intmax_t)zip_entry->compressed_size);
ret = ARCHIVE_WARN;
}
if (zip_entry->uncompressed_size == 0) {
if (zip_entry->uncompressed_size == 0 ||
zip_entry->uncompressed_size == 0xffffffff) {
zip_entry->uncompressed_size
= zip_entry_central_dir.uncompressed_size;
} else if (zip_entry->uncompressed_size
@ -1186,7 +1196,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
{
// symlink target string appeared to be compressed
int status = ARCHIVE_FATAL;
const void *uncompressed_buffer;
const void *uncompressed_buffer = NULL;
switch (zip->entry->compression)
{
@ -2238,6 +2248,140 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
#endif
#if HAVE_ZSTD_H && HAVE_LIBZSTD
static int
zipx_zstd_init(struct archive_read *a, struct zip *zip)
{
size_t r;
/* Deallocate already existing Zstd decompression context if it
* exists. */
if(zip->zstdstream_valid) {
ZSTD_freeDStream(zip->zstdstream);
zip->zstdstream_valid = 0;
}
/* Allocate a new Zstd decompression context. */
zip->zstdstream = ZSTD_createDStream();
r = ZSTD_initDStream(zip->zstdstream);
if (ZSTD_isError(r)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Error initializing zstd decompressor: %s",
ZSTD_getErrorName(r));
return ARCHIVE_FAILED;
}
/* Mark the zstdstream field to be released in cleanup phase. */
zip->zstdstream_valid = 1;
/* (Re)allocate the buffer that will contain decompressed bytes. */
free(zip->uncompressed_buffer);
zip->uncompressed_buffer_size = ZSTD_DStreamOutSize();
zip->uncompressed_buffer =
(uint8_t*) malloc(zip->uncompressed_buffer_size);
if (zip->uncompressed_buffer == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory for Zstd decompression");
return ARCHIVE_FATAL;
}
/* Initialization done. */
zip->decompress_init = 1;
return ARCHIVE_OK;
}
static int
zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
struct zip *zip = (struct zip *)(a->format->data);
ssize_t bytes_avail = 0, in_bytes, to_consume;
const void *compressed_buff;
int r;
size_t ret;
uint64_t total_out;
ZSTD_outBuffer out;
ZSTD_inBuffer in;
(void) offset; /* UNUSED */
/* Initialize decompression context if we're here for the first time. */
if(!zip->decompress_init) {
r = zipx_zstd_init(a, zip);
if(r != ARCHIVE_OK)
return r;
}
/* Fetch more compressed bytes */
compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
if(bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated zstd file body");
return (ARCHIVE_FATAL);
}
in_bytes = zipmin(zip->entry_bytes_remaining, bytes_avail);
if(in_bytes < 1) {
/* zstd doesn't complain when caller feeds avail_in == 0.
* It will actually return success in this case, which is
* undesirable. This is why we need to make this check
* manually. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated zstd file body");
return (ARCHIVE_FATAL);
}
/* Setup buffer boundaries */
in.src = compressed_buff;
in.size = in_bytes;
in.pos = 0;
out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 };
/* Perform the decompression. */
ret = ZSTD_decompressStream(zip->zstdstream, &out, &in);
if (ZSTD_isError(ret)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Error during zstd decompression: %s",
ZSTD_getErrorName(ret));
return (ARCHIVE_FATAL);
}
/* Check end of the stream. */
if (ret == 0) {
if ((in.pos == in.size) && (out.pos < out.size)) {
zip->end_of_entry = 1;
ZSTD_freeDStream(zip->zstdstream);
zip->zstdstream_valid = 0;
}
}
/* Update the pointers so decompressor can continue decoding. */
to_consume = in.pos;
__archive_read_consume(a, to_consume);
total_out = out.pos;
zip->entry_bytes_remaining -= to_consume;
zip->entry_compressed_bytes_read += to_consume;
zip->entry_uncompressed_bytes_read += total_out;
/* Give libarchive its due. */
*size = total_out;
*buff = zip->uncompressed_buffer;
/* Seek for optional marker, like in other entries. */
r = consume_optional_marker(a, zip);
if(r != ARCHIVE_OK)
return r;
return ARCHIVE_OK;
}
#endif
#ifdef HAVE_ZLIB_H
static int
zip_deflate_init(struct archive_read *a, struct zip *zip)
@ -2857,6 +3001,11 @@ archive_read_format_zip_read_data(struct archive_read *a,
case 95: /* ZIPx XZ compression. */
r = zip_read_data_zipx_xz(a, buff, size, offset);
break;
#endif
#if HAVE_ZSTD_H && HAVE_LIBZSTD
case 93: /* ZIPx Zstd compression. */
r = zip_read_data_zipx_zstd(a, buff, size, offset);
break;
#endif
/* PPMd support is built-in, so we don't need any #if guards. */
case 98: /* ZIPx PPMd compression. */
@ -2948,6 +3097,12 @@ archive_read_format_zip_cleanup(struct archive_read *a)
}
#endif
#if HAVE_ZSTD_H && HAVE_LIBZSTD
if (zip->zstdstream_valid) {
ZSTD_freeDStream(zip->zstdstream);
}
#endif
free(zip->uncompressed_buffer);
if (zip->ppmd8_valid)

View file

@ -745,7 +745,7 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
dp = &defchar_used;
count = WideCharToMultiByte(to_cp, 0, ws, wslen,
as->s + as->length,
(int)as->buffer_length - as->length - 1, NULL, dp);
(int)as->buffer_length - (int)as->length - 1, NULL, dp);
if (count == 0 &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
/* Expand the MBS buffer and retry. */

View file

@ -60,8 +60,6 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h"
#include "archive_write_private.h"
static struct archive_vtable *archive_write_vtable(void);
static int _archive_filter_code(struct archive *, int);
static const char *_archive_filter_name(struct archive *, int);
static int64_t _archive_filter_bytes(struct archive *, int);
@ -79,26 +77,18 @@ struct archive_none {
char *next;
};
static struct archive_vtable *
archive_write_vtable(void)
{
static struct archive_vtable av;
static int inited = 0;
if (!inited) {
av.archive_close = _archive_write_close;
av.archive_filter_bytes = _archive_filter_bytes;
av.archive_filter_code = _archive_filter_code;
av.archive_filter_name = _archive_filter_name;
av.archive_filter_count = _archive_write_filter_count;
av.archive_free = _archive_write_free;
av.archive_write_header = _archive_write_header;
av.archive_write_finish_entry = _archive_write_finish_entry;
av.archive_write_data = _archive_write_data;
inited = 1;
}
return (&av);
}
static const struct archive_vtable
archive_write_vtable = {
.archive_close = _archive_write_close,
.archive_filter_bytes = _archive_filter_bytes,
.archive_filter_code = _archive_filter_code,
.archive_filter_name = _archive_filter_name,
.archive_filter_count = _archive_write_filter_count,
.archive_free = _archive_write_free,
.archive_write_header = _archive_write_header,
.archive_write_finish_entry = _archive_write_finish_entry,
.archive_write_data = _archive_write_data,
};
/*
* Allocate, initialize and return an archive object.
@ -114,7 +104,7 @@ archive_write_new(void)
return (NULL);
a->archive.magic = ARCHIVE_WRITE_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_write_vtable();
a->archive.vtable = &archive_write_vtable;
/*
* The value 10240 here matches the traditional tar default,
* but is otherwise arbitrary.

View file

@ -251,13 +251,13 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f,
int ds, log2dic, wedges;
/* Calculate a coded dictionary size */
if (dict_size < (1 << 12) || dict_size > (1 << 27)) {
if (dict_size < (1 << 12) || dict_size > (1 << 29)) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
"Unacceptable dictionary size for lzip: %d",
dict_size);
return (ARCHIVE_FATAL);
}
for (log2dic = 27; log2dic >= 12; log2dic--) {
for (log2dic = 29; log2dic >= 12; log2dic--) {
if (dict_size & (1 << log2dic))
break;
}

View file

@ -50,7 +50,8 @@ __FBSDID("$FreeBSD$");
struct private_data {
int compression_level;
#if HAVE_ZSTD_H && HAVE_LIBZSTD
int threads;
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
ZSTD_CStream *cstream;
int64_t total_in;
ZSTD_outBuffer out;
@ -76,7 +77,7 @@ static int archive_compressor_zstd_write(struct archive_write_filter *,
const void *, size_t);
static int archive_compressor_zstd_close(struct archive_write_filter *);
static int archive_compressor_zstd_free(struct archive_write_filter *);
#if HAVE_ZSTD_H && HAVE_LIBZSTD
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
static int drive_compressor(struct archive_write_filter *,
struct private_data *, int, const void *, size_t);
#endif
@ -107,7 +108,8 @@ archive_write_add_filter_zstd(struct archive *_a)
f->code = ARCHIVE_FILTER_ZSTD;
f->name = "zstd";
data->compression_level = CLEVEL_DEFAULT;
#if HAVE_ZSTD_H && HAVE_LIBZSTD
data->threads = 0;
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
data->cstream = ZSTD_createCStream();
if (data->cstream == NULL) {
free(data);
@ -134,7 +136,7 @@ static int
archive_compressor_zstd_free(struct archive_write_filter *f)
{
struct private_data *data = (struct private_data *)f->data;
#if HAVE_ZSTD_H && HAVE_LIBZSTD
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
ZSTD_freeCStream(data->cstream);
free(data->out.dst);
#else
@ -187,7 +189,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
if (string_is_numeric(value) != ARCHIVE_OK) {
return (ARCHIVE_WARN);
}
#if HAVE_ZSTD_H && HAVE_LIBZSTD
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
maximum = ZSTD_maxCLevel();
#if ZSTD_VERSION_NUMBER >= MINVER_MINCLEVEL
if (ZSTD_versionNumber() >= MINVER_MINCLEVEL) {
@ -204,6 +206,20 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
}
data->compression_level = level;
return (ARCHIVE_OK);
} else if (strcmp(key, "threads") == 0) {
int threads = atoi(value);
if (string_is_numeric(value) != ARCHIVE_OK) {
return (ARCHIVE_WARN);
}
int minimum = 0;
if (threads < minimum) {
return (ARCHIVE_WARN);
}
data->threads = threads;
return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
@ -212,7 +228,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
return (ARCHIVE_WARN);
}
#if HAVE_ZSTD_H && HAVE_LIBZSTD
#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
/*
* Setup callback.
*/
@ -252,6 +268,8 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
return (ARCHIVE_FATAL);
}
ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads);
return (ARCHIVE_OK);
}
@ -335,7 +353,7 @@ drive_compressor(struct archive_write_filter *f,
}
}
#else /* HAVE_ZSTD_H && HAVE_LIBZSTD */
#else /* HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR */
static int
archive_compressor_zstd_open(struct archive_write_filter *f)
@ -366,6 +384,14 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
archive_strcat(&as, " --ultra");
}
if (data->threads != 0) {
struct archive_string as2;
archive_string_init(&as2);
archive_string_sprintf(&as2, " --threads=%d", data->threads);
archive_string_concat(&as, &as2);
archive_string_free(&as2);
}
f->write = archive_compressor_zstd_write;
r = __archive_write_program_open(f, data->pdata, as.s);
archive_string_free(&as);
@ -389,4 +415,4 @@ archive_compressor_zstd_close(struct archive_write_filter *f)
return __archive_write_program_close(f, data->pdata);
}
#endif /* HAVE_ZSTD_H && HAVE_LIBZSTD */
#endif /* HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR */

View file

@ -163,14 +163,14 @@ caused by archives that (deliberately or otherwise) extract
files outside of the current directory.
The default is not to perform this check.
If
.It Cm ARCHIVE_EXTRACT_SPARSE
Scan data for blocks of NUL bytes and try to recreate them with holes.
This results in sparse files, independent of whether the archive format
supports or uses them.
.Cm ARCHIVE_EXTRACT_UNLINK
is specified together with this option, the library will
remove any intermediate symlinks it finds and return an
error only if such symlink could not be removed.
.It Cm ARCHIVE_EXTRACT_SPARSE
Scan data for blocks of NUL bytes and try to recreate them with holes.
This results in sparse files, independent of whether the archive format
supports or uses them.
.It Cm ARCHIVE_EXTRACT_TIME
The timestamps (mtime, ctime, and atime) should be restored.
By default, they are ignored.

View file

@ -398,8 +398,6 @@ static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
static ssize_t write_data_block(struct archive_write_disk *,
const char *, size_t);
static struct archive_vtable *archive_write_disk_vtable(void);
static int _archive_write_disk_close(struct archive *);
static int _archive_write_disk_free(struct archive *);
static int _archive_write_disk_header(struct archive *,
@ -524,25 +522,16 @@ lazy_stat(struct archive_write_disk *a)
return (ARCHIVE_WARN);
}
static struct archive_vtable *
archive_write_disk_vtable(void)
{
static struct archive_vtable av;
static int inited = 0;
if (!inited) {
av.archive_close = _archive_write_disk_close;
av.archive_filter_bytes = _archive_write_disk_filter_bytes;
av.archive_free = _archive_write_disk_free;
av.archive_write_header = _archive_write_disk_header;
av.archive_write_finish_entry
= _archive_write_disk_finish_entry;
av.archive_write_data = _archive_write_disk_data;
av.archive_write_data_block = _archive_write_disk_data_block;
inited = 1;
}
return (&av);
}
static const struct archive_vtable
archive_write_disk_vtable = {
.archive_close = _archive_write_disk_close,
.archive_filter_bytes = _archive_write_disk_filter_bytes,
.archive_free = _archive_write_disk_free,
.archive_write_header = _archive_write_disk_header,
.archive_write_finish_entry = _archive_write_disk_finish_entry,
.archive_write_data = _archive_write_disk_data,
.archive_write_data_block = _archive_write_disk_data_block,
};
static int64_t
_archive_write_disk_filter_bytes(struct archive *_a, int n)
@ -1996,7 +1985,7 @@ archive_write_disk_new(void)
a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
/* We're ready to write a header immediately. */
a->archive.state = ARCHIVE_STATE_HEADER;
a->archive.vtable = archive_write_disk_vtable();
a->archive.vtable = &archive_write_disk_vtable;
a->start_time = time(NULL);
/* Query and restore the umask. */
umask(a->user_umask = umask(0));

View file

@ -1,3 +1,4 @@
#include "archive_platform.h"
#include "archive.h"
/*

View file

@ -124,7 +124,7 @@ PACKED(struct cpio_binary_header {
* ...but it feels a little better to do it like this:
*/
static uint16_t swap16(uint16_t in) {
static uint16_t la_swap16(uint16_t in) {
union {
uint16_t s[2];
uint8_t c[4];
@ -141,7 +141,7 @@ static uint16_t swap16(uint16_t in) {
/* NOTREACHED */
}
static uint32_t swap32(uint32_t in) {
static uint32_t la_swap32(uint32_t in) {
union {
uint32_t l;
uint16_t s[2];
@ -156,8 +156,8 @@ static uint32_t swap32(uint32_t in) {
U.s[1] = t;
} else if (U.c[3]) { /* Big-endian */
U.l = in;
U.s[0] = swap16(U.s[0]);
U.s[1] = swap16(U.s[1]);
U.s[0] = la_swap16(U.s[0]);
U.s[1] = la_swap16(U.s[1]);
} else { /* PDP-endian */
U.l = in;
}
@ -426,8 +426,8 @@ write_header(struct archive_write *a, struct archive_entry *entry)
/* Include trailing null */
pathlength = (int)len + 1;
h.h_magic = swap16(070707);
h.h_dev = swap16(archive_entry_dev(entry));
h.h_magic = la_swap16(070707);
h.h_dev = la_swap16(archive_entry_dev(entry));
ino = synthesize_ino_value(cpio, entry);
if (ino < 0) {
@ -441,7 +441,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
ret_final = ARCHIVE_FATAL;
goto exit_write_header;
}
h.h_ino = swap16(ino);
h.h_ino = la_swap16((uint16_t)ino);
h.h_mode = archive_entry_mode(entry);
if (((h.h_mode & AE_IFMT) == AE_IFSOCK) || ((h.h_mode & AE_IFMT) == AE_IFIFO)) {
@ -460,20 +460,20 @@ write_header(struct archive_write *a, struct archive_entry *entry)
/* we could turn off AE_IFREG here, but it does no harm, */
/* and allows v7 cpio to read the entry without confusion */
}
h.h_mode = swap16(h.h_mode);
h.h_mode = la_swap16(h.h_mode);
h.h_uid = swap16(archive_entry_uid(entry));
h.h_gid = swap16(archive_entry_gid(entry));
h.h_nlink = swap16(archive_entry_nlink(entry));
h.h_uid = la_swap16((uint16_t)archive_entry_uid(entry));
h.h_gid = la_swap16((uint16_t)archive_entry_gid(entry));
h.h_nlink = la_swap16((uint16_t)archive_entry_nlink(entry));
if (archive_entry_filetype(entry) == AE_IFBLK
|| archive_entry_filetype(entry) == AE_IFCHR)
h.h_majmin = swap16(archive_entry_rdev(entry));
h.h_majmin = la_swap16(archive_entry_rdev(entry));
else
h.h_majmin = 0;
h.h_mtime = swap32(archive_entry_mtime(entry));
h.h_namesize = swap16(pathlength);
h.h_mtime = la_swap32((uint32_t)archive_entry_mtime(entry));
h.h_namesize = la_swap16(pathlength);
/* Non-regular files don't store bodies. */
if (archive_entry_filetype(entry) != AE_IFREG)
@ -502,7 +502,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
ret_final = ARCHIVE_FATAL;
goto exit_write_header;
}
h.h_filesize = swap32(strlen(p)); /* symlink */
h.h_filesize = la_swap32((uint32_t)strlen(p)); /* symlink */
} else {
if ((a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) &&
(archive_entry_size(entry) > 256*256*256-1)) {
@ -516,7 +516,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
ret_final = ARCHIVE_FAILED;
goto exit_write_header;
}
h.h_filesize = swap32(archive_entry_size(entry)); /* file */
h.h_filesize = la_swap32((uint32_t)archive_entry_size(entry)); /* file */
}
ret = __archive_write_output(a, &h, HSIZE);

View file

@ -6802,6 +6802,7 @@ isoent_rr_move(struct archive_write *a)
* This comparing rule is according to ISO9660 Standard 6.9.1
*/
static int
__LA_LIBC_CC
_compare_path_table(const void *v1, const void *v2)
{
const struct isoent *p1, *p2;
@ -6844,6 +6845,7 @@ _compare_path_table(const void *v1, const void *v2)
}
static int
__LA_LIBC_CC
_compare_path_table_joliet(const void *v1, const void *v2)
{
const struct isoent *p1, *p2;

View file

@ -1028,10 +1028,8 @@ archive_write_pax_header(struct archive_write *a,
archive_string_init(&entry_name);
archive_strcpy(&entry_name, archive_entry_pathname(entry_main));
/* If file size is too large, add 'size' to pax extended attrs. */
/* If file size is too large, we need pax extended attrs. */
if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) {
add_pax_attr_int(&(pax->pax_header), "size",
archive_entry_size(entry_main));
need_extension = 1;
}
@ -1347,6 +1345,12 @@ archive_write_pax_header(struct archive_write *a,
mapsize + pax->sparse_map_padding + sparse_total);
}
/* If file size is too large, add 'size' to pax extended attrs. */
if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) {
add_pax_attr_int(&(pax->pax_header), "size",
archive_entry_size(entry_main));
}
/* Format 'ustar' header for main entry.
*
* The trouble with file size: If the reader can't understand

View file

@ -740,12 +740,16 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
/* We may know the size, but never the CRC. */
zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END;
} else {
/* We don't know the size. In this case, we prefer
* deflate (it has a clear end-of-data marker which
* makes length-at-end more reliable) and will
* enable Zip64 extensions unless we're told not to.
/* We don't know the size. Use the default
* compression unless specified otherwise.
* We enable Zip64 extensions unless we're told not to.
*/
zip->entry_compression = COMPRESSION_DEFAULT;
zip->entry_compression = zip->requested_compression;
if(zip->entry_compression == COMPRESSION_UNSPECIFIED){
zip->entry_compression = COMPRESSION_DEFAULT;
}
zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END;
if ((zip->flags & ZIP_FLAG_AVOID_ZIP64) == 0) {
zip->entry_uses_zip64 = 1;

View file

@ -62,30 +62,40 @@ GNU-format tar archives,
.It
most common cpio archive formats,
.It
ISO9660 CD images (including RockRidge and Joliet extensions),
.It
Zip archives,
7-Zip archives,
.It
ar archives (including GNU/SysV and BSD extensions),
.It
Microsoft CAB archives,
.It
ISO9660 CD images (including RockRidge and Joliet extensions),
.It
LHA archives,
.It
mtree file tree descriptions,
.It
RAR archives,
RAR and most RAR5 archives,
.It
XAR archives.
WARC archives,
.It
XAR archives,
.It
Zip archives.
.El
The library automatically detects archives compressed with
.Xr gzip 1 ,
.Xr compress 1 ,
.Xr bzip2 1 ,
.Xr xz 1 ,
.Xr grzip 1 ,
.Xr gzip 1 ,
.Xr lrzip 1 ,
.Xr lz4 1 ,
.Xr lzip 1 ,
.Xr lzop 1 ,
.Xr xz 1 ,
or
.Xr compress 1
and decompresses them transparently.
.Xr zstd 1
and decompresses them transparently. Decompression of some formats
requires external decompressor utilities.
It can similarly detect and decode archives processed with
.Xr uuencode 1
or which have an
@ -107,19 +117,19 @@ archives,
.It
cpio archives,
.It
Zip archive,
7-Zip archives,
.It
ar archives,
.It
two different variants of shar archives,
.It
ISO9660 CD images,
.It
7-Zip archives,
.It
ar archives,
.It
mtree file tree descriptions,
.It
XAR archives.
XAR archives,
.It
Zip archive.
.El
Pax interchange format is an extension of the tar archive format that
eliminates essentially all of the limitations of historic tar formats

View file

@ -142,12 +142,6 @@ canAlways(void)
return 1;
}
static int
cannot(void)
{
return 0;
}
DEFINE_TEST(test_archive_write_add_filter_by_name_b64encode)
{
test_filter_by_name("b64encode", ARCHIVE_FILTER_UU, canAlways);
@ -185,12 +179,12 @@ DEFINE_TEST(test_archive_write_add_filter_by_name_lz4)
DEFINE_TEST(test_archive_write_add_filter_by_name_lzip)
{
test_filter_by_name("lzip", ARCHIVE_FILTER_LZIP, cannot);
test_filter_by_name("lzip", ARCHIVE_FILTER_LZIP, canLzip);
}
DEFINE_TEST(test_archive_write_add_filter_by_name_lzma)
{
test_filter_by_name("lzma", ARCHIVE_FILTER_LZMA, cannot);
test_filter_by_name("lzma", ARCHIVE_FILTER_LZMA, canLzma);
}
DEFINE_TEST(test_archive_write_add_filter_by_name_lzop)
@ -205,7 +199,7 @@ DEFINE_TEST(test_archive_write_add_filter_by_name_uuencode)
DEFINE_TEST(test_archive_write_add_filter_by_name_xz)
{
test_filter_by_name("xz", ARCHIVE_FILTER_XZ, cannot);
test_filter_by_name("xz", ARCHIVE_FILTER_XZ, canXz);
}
DEFINE_TEST(test_archive_write_add_filter_by_name_zstd)

View file

@ -0,0 +1,77 @@
/*-
* Copyright (c) 2021 Samanta Navarro
* 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 "test.h"
__FBSDID("$FreeBSD$");
/*
* Background: Original tar file format did not use its linkflag to
* specify directories. Instead regular files simply have a slash
* appended to their names. No data blocks follow directories in
* archives. This means that a possibly specified file size must not
* be used to determine the amount of data blocks to skip.
*/
static void
test_compat_tar_directory_1(void)
{
char name[] = "test_compat_tar_directory_1.tar";
struct archive_entry *ae;
struct archive *a;
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
extract_reference_file(name);
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));
/* Read first entry, which is a directory in a regular file header. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("directory1/", archive_entry_pathname(ae));
assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
assertEqualInt(1, archive_entry_size(ae));
/* Read second entry, which is a ustar directory entry. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("directory2/", archive_entry_pathname(ae));
assertEqualInt(AE_IFDIR, archive_entry_filetype(ae));
assertEqualInt(0, archive_entry_size(ae));
/* Verify the end-of-archive. */
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
/* Verify that the format detection worked. */
assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR);
assertEqualInt(ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_compat_tar_directory)
{
test_compat_tar_directory_1();
}

View file

@ -0,0 +1,50 @@
$FreeBSD$
begin 644 test_compat_tar_directory_1.tar
M9&ER96-T;W)Y,2\`````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M`````````````#`P,#`W,#``,#`P,#`P,``P,#`P,#`P`#`P,#`P,#`P,#`Q
M`#`P,#`P,#`P,#`P`#`P-C4Q-0`@````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M``````````````````````!D:7)E8W1O<GDR+P``````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````,#`P,#<P,``P,#`P,#`P`#`P
M,#`P,#``,#`P,#`P,#`P,#``,#`P,#`P,#`P,#``,#`V-3$U`"``````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
7````````````````````````````````
`
end

View file

@ -428,6 +428,10 @@ DEFINE_TEST(test_fuzz_tar)
NULL
};
#endif
static const char *fileset11[] = {
"test_compat_tar_directory_1.tar",
NULL
};
static const struct files filesets[] = {
{0, fileset1}, /* Exercise bzip2 decompressor. */
{1, fileset1},
@ -444,6 +448,7 @@ DEFINE_TEST(test_fuzz_tar)
#if HAVE_ZSTD_H && HAVE_LIBZSTD
{0, fileset10}, /* Exercise zstd decompressor. */
#endif
{0, fileset11},
{1, NULL}
};
test_fuzz(filesets);

View file

@ -49,7 +49,6 @@ DEFINE_TEST(test_read_data_large)
char tmpfilename[] = "largefile";
int tmpfilefd;
FILE *f;
unsigned int i;
size_t used;
/* Create a new archive in memory. */
@ -64,8 +63,7 @@ DEFINE_TEST(test_read_data_large)
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
for (i = 0; i < sizeof(buff2); i++)
buff2[i] = (unsigned char)rand();
fill_with_pseudorandom_data(buff2, sizeof(buff2));
archive_entry_set_size(ae, sizeof(buff2));
assertA(0 == archive_write_header(a, ae));
archive_entry_free(ae);

View file

@ -59,8 +59,7 @@ DEFINE_TEST(test_read_extract)
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
for (i = 0; i < FILE_BUFF_SIZE; i++)
file_buff[i] = (unsigned char)rand();
fill_with_pseudorandom_data(file_buff, FILE_BUFF_SIZE);
archive_entry_set_size(ae, FILE_BUFF_SIZE);
assertA(0 == archive_write_header(a, ae));
assertA(FILE_BUFF_SIZE == archive_write_data(a, file_buff, FILE_BUFF_SIZE));

View file

@ -1206,6 +1206,23 @@ DEFINE_TEST(test_read_format_rar5_different_window_size)
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_window_buf_and_size_desync)
{
/* oss fuzz 30442 */
char buf[4096];
PROLOGUE("test_read_format_rar5_window_buf_and_size_desync.rar");
/* Return codes of those calls are ignored, because this sample file
* is invalid. However, the unpacker shouldn't produce any SIGSEGV
* errors during processing. */
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, 46)) {}
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_arm_filter_on_window_boundary)
{
char buf[4096];
@ -1271,3 +1288,62 @@ DEFINE_TEST(test_read_format_rar5_block_size_is_too_small)
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_sfx)
{
struct archive *a;
struct archive_entry *ae;
int bs = 10240;
char buff[32];
const char reffile[] = "test_read_format_rar5_sfx.exe";
const char test_txt[] = "123";
int size = sizeof(test_txt) - 1;
extract_reference_file(reffile);
assert((a = archive_read_new()) != NULL);
assertA(0 == archive_read_support_filter_all(a));
assertA(0 == archive_read_support_format_all(a));
assertA(0 == archive_read_open_filename(a, reffile, bs));
assertA(0 == archive_read_next_header(a, &ae));
assertEqualString("test.txt.txt", archive_entry_pathname(ae));
assertA(size == archive_read_data(a, buff, size));
assertEqualMem(buff, test_txt, size);
}
DEFINE_TEST(test_read_format_rar5_decode_number_out_of_bounds_read)
{
/* oss fuzz 30448 */
char buf[4096];
PROLOGUE("test_read_format_rar5_decode_number_out_of_bounds_read.rar");
/* Return codes of those calls are ignored, because this sample file
* is invalid. However, the unpacker shouldn't produce any SIGSEGV
* errors during processing. */
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, sizeof(buf))) {}
EPILOGUE();
}
DEFINE_TEST(test_read_format_rar5_bad_window_size_in_multiarchive_file)
{
/* oss fuzz 30459 */
char buf[4096];
PROLOGUE("test_read_format_rar5_bad_window_sz_in_mltarc_file.rar");
/* This file is damaged, so those functions should return failure.
* Additionally, SIGSEGV shouldn't be raised during execution
* of those functions. */
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, sizeof(buf))) {}
(void) archive_read_next_header(a, &ae);
while(0 < archive_read_data(a, buf, sizeof(buf))) {}
EPILOGUE();
}

View file

@ -0,0 +1,7 @@
begin 644 test_read_format_rar5_bad_window_size_in_multiarchive_file.rar
M4F%R(1H'`0`]/-[E`@$`_R`@1#[Z5P("`PL`("`@@"(`"?\@("#___\@("`@
M("`@("`@("`@4X`J]`,"YR(#$($@("`@``$@("`@@<L0("`@("`@("`@("`@
M("`@(""LCTJA`P$%`B`@`2!3@"KT`P+G(@,@("`@_P,!!B`@(/___R`@(('+
5$"`OX2`@[.SL[.S_("`@("`@("`@
`
end

View file

@ -0,0 +1,10 @@
begin 644 test_read_format_rar5_decode_number_out_of_bounds_read.rar
M4F%R(1H'`0!3@"KT`P+G(@(0("`@@`L!!"`@("`@(($D_[BJ2"!::7!)210V
M+0#ZF#)Q!`+>YPW_("`@("``_R````````````````````````````!__P``
M``````!T72`@/EW_(/\@("`@("`@("`@("`@("`@("`@("`@("`@(/\@("`@
M("`@("#_("`@("`@("`@("`@("`@("`@("`@("`@("#_("`@("`@("`@_R`@
M("`@("`@("`@("`@("`@("`@("`@("`@_R`@("`@("`@(/\@("`@("`@("`@
M("`@("`@("`@("`@("`@(/\@("`@("`@("#_("`@("`@("`@("`@("`@("`@
E("`@("`@("#_("`@("`@("`@_R`@("`@("`@("`@("`@("`@(```
`
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
begin 644 test_read_format_rar5_window_buf_and_size_desync.rar
M4F%R(1H'`0`]/-[E`@$`_P$`1#[Z5P("`PL``BXB"?\`!(@B@0`)6.-AF?_1
M^0DI&0GG(F%R(0<:)`!3@"KT`P+G(@O_X[\``#&``(?!!0$$[:L``$.M*E)A
M<B$`O<\>P0";/P1%``A*2DI*2DYQ<6TN9'%*2DI*2DI*``!D<F--``````"Z
MNC*ZNKJZNFYO=&%I;+JZNKJZNKJZOKJZ.KJZNKJZNKKZU@4%````0$!`0$!`
M0$!`0$!`0$!`0$#_________/T#`0$!`0$!`-UM`0$!`0$!`0$!`0$!`0$!`
M0$!`0'!,J+:O!IZ-WN4'@`!3*F0`````````````````````````````````
M``````````````#T`P)287(A&@<!`%.`*O0#`N<B`_,F@`'[__\``(`4`01S
J'`/H/O\H@?\D`#O9GIZ>GN<B"_]%``(``&1RGIZ>GIZ>8_^>GE/_``!.
`
end

View file

@ -0,0 +1,57 @@
/*-
* Copyright (c) 2003-2021 Wei-Cheng Pan
* 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 "test.h"
__FBSDID("$FreeBSD$");
DEFINE_TEST(test_read_format_rar_filter)
{
const char *refname = "test_read_format_rar_filter.rar";
struct archive *a;
struct archive_entry *ae;
char *buff[12];
const char signature[12] = {
0xff, 0xd8, 0xff, 0xe0,
0x00, 0x10, 0x4a, 0x46,
0x49, 0x46, 0x00, 0x01,
};
extract_reference_file(refname);
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 10240));
assertA(0 == archive_read_next_header(a, &ae));
assertEqualString("013.jpg", archive_entry_pathname(ae));
assertA((int)archive_entry_mtime(ae));
assertEqualInt(1215721, archive_entry_size(ae));
assertA(12 == archive_read_data(a, buff, 12));
assertEqualMem(buff, signature, 12);
assertA(1 == archive_read_next_header(a, &ae));
assertEqualInt(1, archive_file_count(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}

File diff suppressed because it is too large Load diff

View file

@ -736,6 +736,130 @@ DEFINE_TEST(test_read_format_zip_bzip2_multi_blockread)
assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_read_format_zip_zstd_one_file)
{
const char *refname = "test_read_format_zip_zstd.zipx";
struct archive *a;
struct archive_entry *ae;
assert((a = archive_read_new()) != NULL);
if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) {
skipping("zstd is not fully supported on this platform");
archive_read_close(a);
return;
}
extract_reference_file(refname);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 37));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("vimrc", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one(a, ae, 0xBA8E3BAA));
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_read_format_zip_zstd_one_file_blockread)
{
const char *refname = "test_read_format_zip_zstd.zipx";
struct archive *a;
struct archive_entry *ae;
assert((a = archive_read_new()) != NULL);
if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) {
skipping("zstd is not fully supported on this platform");
archive_read_close(a);
return;
}
extract_reference_file(refname);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 37));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("vimrc", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one_using_blocks(a, 13, 0xBA8E3BAA));
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_read_format_zip_zstd_multi)
{
const char *refname = "test_read_format_zip_zstd_multi.zipx";
struct archive *a;
struct archive_entry *ae;
assert((a = archive_read_new()) != NULL);
if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) {
skipping("zstd is not fully supported on this platform");
archive_read_close(a);
return;
}
extract_reference_file(refname);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 37));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("smartd.conf", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one(a, ae, 0x8DD7379E));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("ts.conf", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one(a, ae, 0x7AE59B31));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("vimrc", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one(a, ae, 0xBA8E3BAA));
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_read_format_zip_zstd_multi_blockread)
{
const char *refname = "test_read_format_zip_zstd_multi.zipx";
struct archive *a;
struct archive_entry *ae;
assert((a = archive_read_new()) != NULL);
if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) {
skipping("zstd is not fully supported on this platform");
archive_read_close(a);
return;
}
extract_reference_file(refname);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname, 37));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("smartd.conf", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one_using_blocks(a, 12, 0x8DD7379E));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("ts.conf", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one_using_blocks(a, 13, 0x7AE59B31));
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString("ZIP 2.0 (zstd)", archive_format_name(a));
assertEqualString("vimrc", archive_entry_pathname(ae));
assertEqualIntA(a, 0, extract_one_using_blocks(a, 14, 0xBA8E3BAA));
assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
}
DEFINE_TEST(test_read_format_zip_xz_multi)
{
const char *refname = "test_read_format_zip_xz_multi.zipx";

View file

@ -0,0 +1,18 @@
begin 644 test_read_format_zip_zstd.zipx
M4$L#!!0```!=`#TQD4VJ.XZZ&P(``)`#```%````=FEM<F,HM2_]`%B5$``F
M*&PC(&_;!LR_L%[])MU@R?]OORW$@9`DQ+<"F#-&'$Y6"9""0&%E`%\`7@"1
M7?FX:LJ\X?*WT9.43+L]A_#MKX7+T^E'CZM<W%N^:O@!SJ4,4TAA"BGIT&'%
M\5.>I.97\6@M?/P$SA1R6+RFRUD<*@L-#!$.$A`-#!,!;_I.?CH\]WK(I'HJ
MC1"P;([X:RD\"4NZL[X9?H=*YI9Q^9SUG`U"%GS.%'JF0M<\[PV?3#MR">63
MU+);7<0EM,_'U]+(<VG*;PPLCBFD+)V*P',I<U:G]:N>)+7>.MS@IFGS.GUF
M'S5\-@V=Y=MW6",,P^\(`,FALG&E(V`ZX;1&#G$;^?8[^=%R^:Q[GB1^JPZA
M-SI]3O>XY5O/>)70LG3/QWO;L^DZJQ/Q)"5'6^UGS\CUT,:'[<)XDMY"B%WV
MPK<V35TV@^>$('N2MJ]2M61L`\D@@2E$0?$HA-^YDM0T959VUCN4BS.J<-=[
M6P)HFD)TO47V[FWT;?<:9=HN25KX&K(SA?9*P8'"=&]T1G?9G8^[AR>)P11R
MY'H86B0%XTKA&U$O;*N]M,>LJ)E`K77)I'N2E`(B(!!&C.+TY**V^BU(V9R8
M!ZLXW)6;"!YPP'E,4_F\OB!T"4Z:6/#"Z823+@5V#BNHGHC-+4@`)>?""C,)
M2+G'/1,#D-1'B&&R288:'(KD,I>"_/85<Z&-7Q#VF647!5!+`0(_`Q0```!=
M`#TQD4VJ.XZZ&P(``)`#```%``````````````"D@0````!V:6UR8U!+!08`
1`````0`!`#,````^`@``````
`
end

View file

@ -0,0 +1,94 @@
begin 644 test_read_format_zip_zstd_multi.zipx
M4$L#!!0```!=`)$XD4V>-]>-'@L``"L:```+````<VUA<G1D+F-O;F8HM2_]
M`%BM6`!*H%`;+\!*JCH'T([11*/??O?P6[0UJ(DJ\IZ.MT=7AH2`T3TTL21)
M?PF4\HC]-T6!X+H9E@&@`;X!3=-$%[_M&;V:'^Q'/9A5[%W4UN0[+H9)Z@YJ
M\N+S7-;>+!_^R$5-5D[3>O4AU,N^VP>S3+^79Y-P+W?;_&!3.]_D3K-7OY*9
MR]UN$D)9?2_/*/9(FB13Q!*YTT"H42F^;(9P^_V^L)?+=AI^5S^^6_'%I]C.
M9Z)^65,*(B*9*!+I`,KD;LHM>DSQNK>@Y,P6C^]6?!12PCM-YG)LFS/\J<G,
MH_Q./5/P<W=3KU_4N[9GJM=QW7L&0M58>U3JFDR`5XNOHZ0N^P8+&#R!1]OO
MVOBBS4MIQG>:9>T9Q:[)S%W4/VZGC-8[OR,X![]8K^OG=J7OBK4\VOC@YV9W
MFHWR5[_MCQ4?:Y^R7Y3899^7>IAUK^2;'[3VLMQI&JC1>GRGD9AHN)X7\Y;:
M^7ZOWM5WNA/:>0C?=J=I`+@#PY2O0,.QX&@L(&@\@0,*@`$E-!B.,QP-R!><
M!,"=IK&FC!A*V5%BT;9MB\5"UGU]@=_7TNR+R88[31-545)1L>].?^1Z*L:?
MLOK"5SW*USHUZU514E^883K="9+:RYTFHYC6C\_OLCR*\G4F;]#*=Y#!]VJW
MEJ6P^EZ<)N[5?Y^;47@$2V0Z@!QU6F17TJ,I0O;UK)^Z6:84_%S$)!55+`'Q
M84Z/04]X!7I"PI,`>2!?`)UZ<<\[-?BTBO+P*787=[K31`@)!V\)`U,VM1,#
M;ELI":%NY97\:E`QW[3R^)R&'\@5#-#:Y4[S($`4&@>WW*T##RHV96P(0GL(
MO0'Z!:+0Z&RIBGU\3D-!Z6Q+PNF/)1T^Y9R4A[76YELJD8?):1J$!V.!8!$Y
M/.!@+*)H,1V<)^A17D)7Z.IX@5FW<)H(4PCTX(RZJ;5.=YI;4<+K,7U`CL?=
MK=TS<S'[YFVH@LOO*2^^OJ<VWVD6HQQYHGQ-+822NK:Z;WPPRE.O%9.M*;QH
MW#^\K5W>[-9#J%-D6DSYB"4R+2*6R)OG8[C3-`E?`)TK%%O$ASD-:X_A2IYP
M!0.<UXIZ497*IO-0JY:U[Y38%2Y!;SP<EZ!#%!J7H#M-9$G(&7Y\=QKN*;.=
MYZG)ZU%"<S>93:UU;H9M7_:M^+J7OYC7&N<VC-P)#OKO-$XS.4@1"V5",2`B
M<8C(`Z7!<@IE.F6*4!PD[C01Q4%B.$2$9(E4)@R0&"`B))^D!LLK$0R?*`=(
M%@FE(DW.$''+)#D\\DDZI4)I@#@@3M-32CQ(?#'E[]6.A\,M&D]GE[O33*1(
MI9>"DI5W?%+BLEY#!KH'Y2X'Y2Z6#/5,,>7VQ(C%-+[J49OQ!=/B$7K*[.!.
M\V2F,B^U\2WC^=T`(N(1;]+%MP`C+XOI!.'6[L+@&'%61I@BTUO&@T?#P="M
M#X$>=U&S($RF`G8GPY^#*SB-@@/R>#@<C8=B/"[*2VX\C-WZ4S+<:2*GVQS?
MYS:E4R_J$+OU\L0?32B6B(12D:!,SN].LY16<SN^(_#POKE\N'$NQ1%$CE=H
M\3E8\2U0+!$0?P($^0.!'G\>D.,/0]%<S)ON%145%=#V^%[-VEP(Y60P&`$L
M$BP0?*=NCS>U,4KJ#&DP%@DN`306CS/TQQ3?05=,[X`:49NP+`&$@#>Z77!V
MZ^)VQ4Y_Y#11J=;KZD=R:\8GH#,NH9:5^C[J75Q^:P7<:1@^K:Z&NE<&QH@_
MHJ#VHMYQX>/?:2+NN%B4\V'B7L(0F:8H%PM-Y'8^7G>GB=Q&K?JSXIO-E]AM
MQ\469MA[!CY`=_%Q$(RJ2AZ+4^LSKF#NM?V9D$!.DY#@N`(!/I&N0(`W/M>"
MBCUJW?7\G&;C<UC@T7K<7Y#<^;_)B_\\R]H7N)=W9J>@Q;PYD;"BQICRGXTR
M3K6T"S9?]>4)A@`4&I^`GD"A<4D%O6&_T%#3:B<*8<4']Z+PO*]Z3C[<,CT0
MQU"OWT20_.F'/?@J(DA_EHH[MZH>PN221WHF7]#4SBFI.!$Q(><Z`$49WU&3
MU&_%Y^)*O./.J4E>/8E426\BW5*!/N4UZ$\&3:17\LPP\G\B?6I0!EVV8I[6
M`*4UB!OLE#"H9,P[LXK]5*A9.\][4:W8M]4MXEX;Q0!*Y;R69GSP*1]&K[UD
MJN<>*NAI@#YE)7OJ]LDD<HP-UE*>,'@FZM2FK*IGLXSECRP)H=OJ30UO@'[W
M_F0N+FKSGVP7\I^YF.4G(4Z91#P\3@A5)1=1'E257'A1?FY!^1TB!UPNYC$_
M;&[V9Z&2WRBCSH6RV0*Q>%@X/!#/L_"B&(GM_`/A8J9B?QYM_<)FF?Y.IT@D
M8'F!P:@Q,5/(S(B(B$B2)!D.<02$&,6<Q'(/$F``NA8F(6/(R,C(B$B2,E(H
M#&O$"QQS],*]JCT+'3I2_1>>IE2R*7%*T&;?1.FK+IYT!&_5B-5DP39XE!D%
MU4I&#GB2.ZRXY2=4I)"45?,9GE*1:>%CGS]Y$T?]!<.L!XW0S]DV[J]^RZUO
MU-$)H:Y^.=7_&D-=/U?:N2=I9478#(<R"2HH/$YR04$9EKH6#AV.N\01E!!$
MCT@CL0Q$I<1@%U#C&*.3C%#@^WE8'I3<^\`&&Q:4_EWAAKY):0YA.D5</(D5
M4Z4)CK][0*J#O3_U?<+8>(F??EK=-I1S/+>G(J&!8#8Z!:SN/"0W!8-Q[JFX
MM_*65-,=T<$H_5R>$A*!B@?!QDT)A2&MH8F637:F%R6%";@](C+4@\6'16DZ
MU_HU?%3PJE\R1U+@1W,+`-#RU%+^+.>.!"M\UT,*C&33WQRGB1G26U$9^L)A
M)I%").6%$Y@_%NBBIU(1:BFRY39*=(')Z1KA$&)]OJ(+#I`/%M!VE>6H1^\D
M,#X7\>\,NQ2.]95_3<MOBK4C;TJ.QS*25;V],MW9R7H)$V)[J:&_5#ZC'[L+
M8_Q:OK78)07M$="OP%8;S;"#0LS#>M#!#:N(IC^E6(GHYRO+<3#5PU)A=@0#
M%[=9[_H%";U],PMX`<<#,:#K?!05",0@;1R(1:[N>SE]`N+W-AW20?"87U?W
MK[3+[+`]MO)(%2XN0H\@:S$OM_]EM=8!3:[TE;@FRJNCP6'V]PP'1<*B?KO!
MU0BW]X&T&QIBOH<8K/(#;Z@8%W[DDI%8F[B.+3D$C,J"\(`6XIX"'LOA0+`7
MB)&X$P@K>MMV>X/MQ8*7P8-UY,(L_Q?%H5JB#>I4V^NXD34"X,<3K.RIA,_`
M?(#'XE!-6,8R!_)8X4;0H%5C7*"G;B"^H.GQJA^21KE)P!?PA)KD#RQ&%K(I
MX\:E'<Z?+C&G1R\@)2.Q+))K#7G=[\8B6TP41T=PKOD)=`%"$%P0HW@`6[4]
M_51][H+HV+!("9>!D\^5@D'RPX,&RVW'G!BHTTI-]S<P%=6HD;2E//_3BQ>4
MD8845O$($J+3Q-60RN",_F/"AL>>K)JT2M]0$E`:/I!9&4\N/KB'Y^@,IEH'
M24"9!VN@A)H:Q?\A<MHG<3,_-H/HJ^APHYA3G`4%78G`2HP/LW.0>`.0A848
M(`]O]_OU)'H%IJ@(?-M*9'K)&RCLM@T%=-)*31^"9Z1TS:;@S5]#J4..*-FE
M,/B;48CTK8-ZC76,F34<-<K#[6N]QHC%>E(M:`YL4:7L>Q<M6?[+L2F3*ND4
MRY&-"/:?`V:6X:/,MP._DUCO@M"8[(SP`(P2#08EY;7]HD=`#^I3SVX4YJ,9
MOS]5J.8I@[Y+.[`T9(0_32]M2;Z]AURZ*7BL>H0(`<:3R#$LW-\-LR\E^AG;
MI)[_`WT'-5!+`P04````70"(.)%-,9OE>IH!``!4`P``!P```'1S+F-O;F8H
MM2_]`%B-#`#6G$T?4$W3!D_TVC/9!E7:MTFZHMQL#\'FCNWU"^^36;A/#48`
M00!&`.H\A"5RGEETHH(5QQ%1V?#T(&R.*[7D]R#N_$0E[^.<6>(Y2SZSOC[&
M-:,6X0<GO)CWWC2H'(,5QZ$X]*SQ),>J5Q0$*P+/1^N-MYBU7C&((R<N1D?_
M+9)DM>=%@NK,V;$'M>)X8I2EYSU^EO7):4J]6LF)7DU;\IOL>*,<7S5>#A4!
MW:L#`DX$ID628(-DP6F6,+#@0UNE<O&";IPQB]BHGQAU-VY!PJQSY"M#;_0/
MYNAB7",$"4K(-#B8R%?N0<;16>-8G\PZSD?UZ3A'UL]2XVSW:@7X5C(LE=*@
M!P0),F$$.4@0"6:1X42K292OO'F(,_2?/@ZHC*Z015*;CIS?-8<C7PW/"P$D
M25RE%JM6(2!`PJ#3'DLK_$X$^.PYRH!LVVR)JHMC$3U^)%O7B":QA50+5+(#
MOED%P(\)_/A*]1"6#,,TU?`)-;R!Z)6N/_$>,)D!W9=FT'5M;6,=/5CUA)1X
M;1VP`U!+`P04````70`],9%-JCN.NAL"``"0`P``!0```'9I;7)C*+4O_0!8
ME1``)BAL(R!OVP;,O[!>_2;=8,G_;[\MQ(&0),2W`I@S1AQ.5@F0@D!A90!?
M`%X`D5WYN&K*O.'RM]&3E$R[/8?P[:^%R]/I1X^K7-Q;OFKX`<ZE#%-(80HI
MZ=!AQ?%3GJ3F5_%H+7S\!,X4<EB\ILM9'"H+#0P1#A(0#0P3`6_Z3GXZ//=Z
MR*1Z*HT0L&R.^&LI/`E+NK.^&7Z'2N:6<?F<]9P-0A9\SA1ZID+7/.\-GTP[
M<@GED]2R6UW$);3/Q]?2R'-IRF\,+(XII"R=BL!S*7-6I_6KGB2UWCK<X*9I
M\SI]9A\U?#8-G>7;=U@C#,/O"`#)H;)QI2-@.N&T1@YQ&_GV._G1<OFL>YXD
M?JL.H3<Z?4[WN.5;SWB5T+)TS\=[V[/I.JL3\20E1UOM9\_(]=#&A^W">)+>
M0HA=]L*W-DU=-H/GA"![DK:O4K5D;`/)(($I1$'Q*(3?N9+4-&56=M8[E(LS
MJG#7>UL":)I"=+U%]NYM]&WW&F7:+DE:^!JR,X7V2L&!PG1O=$9WV9V/NX<G
MB<$4<N1Z&%HD!>-*X1M1+VRKO;3'K*B90*UUR:1[DI0"(B`01HSB].2BMOHM
M2-F<F`>K.-R5FP@><,!Y3%/YO+X@=`E.FECPPNF$DRX%=@XKJ)Z(S2U(`"7G
MP@HS"4BYQST3`Y#41XAALDF&&AR*Y#*7@OSV%7.AC5\0]IEE%P502P$"/P,4
M````70"1.)%-GC?7C1X+```K&@``"P``````````````I($`````<VUA<G1D
M+F-O;F902P$"/P,4````70"(.)%-,9OE>IH!``!4`P``!P``````````````
MI(%'"P``=',N8V]N9E!+`0(_`Q0```!=`#TQD4VJ.XZZ&P(``)`#```%````
I``````````"D@08-``!V:6UR8U!+!08``````P`#`*$```!$#P``````
`
end

View file

@ -37,7 +37,6 @@ static unsigned char buff[11 * 1024 * 1024];
/* Check correct behavior on large reads. */
DEFINE_TEST(test_read_large)
{
unsigned int i;
int tmpfilefd;
char tmpfilename[] = "test-read_large.XXXXXX";
size_t used;
@ -45,8 +44,7 @@ DEFINE_TEST(test_read_large)
struct archive_entry *entry;
FILE *f;
for (i = 0; i < sizeof(testdata); i++)
testdata[i] = (unsigned char)(rand());
fill_with_pseudorandom_data(testdata, sizeof(testdata));
assert(NULL != (a = archive_write_new()));
assertA(0 == archive_write_set_format_ustar(a));

View file

@ -48,8 +48,8 @@ DEFINE_TEST(test_read_pax_truncated)
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
for (i = 0; i < filedata_size; i++)
filedata[i] = (unsigned char)rand();
fill_with_pseudorandom_data(filedata, filedata_size);
archive_entry_set_atime(ae, 1, 2);
archive_entry_set_ctime(ae, 3, 4);
archive_entry_set_mtime(ae, 5, 6);

View file

@ -47,8 +47,7 @@ DEFINE_TEST(test_read_truncated)
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
for (i = 0; i < sizeof(buff2); i++)
buff2[i] = (unsigned char)rand();
fill_with_pseudorandom_data(buff2, sizeof(buff2));
archive_entry_set_size(ae, sizeof(buff2));
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
archive_entry_free(ae);

View file

@ -41,7 +41,7 @@ test_truncation(const char *compression,
char path[16];
char *buff, *data;
size_t buffsize, datasize, used1;
int i, j, r, use_prog;
int i, r, use_prog;
buffsize = 2000000;
assert(NULL != (buff = (char *)malloc(buffsize)));
@ -91,9 +91,7 @@ test_truncation(const char *compression,
free(buff);
return;
}
for (j = 0; j < (int)datasize; ++j) {
data[j] = (char)(rand() % 256);
}
fill_with_pseudorandom_data(data, datasize);
failure("%s", path);
if (!assertEqualIntA(a, datasize,
archive_write_data(a, data, datasize))) {
@ -111,8 +109,13 @@ test_truncation(const char *compression,
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_read_open_memory(a, buff, used1 - used1/64));
r = archive_read_open_memory(a, buff, used1 - used1/64);
if (r != ARCHIVE_OK) {
assertEqualStringA(a, "truncated bzip2 input",
archive_error_string(a));
goto out;
}
for (i = 0; i < 100; i++) {
if (ARCHIVE_OK != archive_read_next_header(a, &ae)) {
failure("Should have non-NULL error message for %s",
@ -133,6 +136,7 @@ test_truncation(const char *compression,
archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
out:
free(data);
free(buff);
}
@ -154,12 +158,12 @@ DEFINE_TEST(test_read_truncated_filter_gzip)
DEFINE_TEST(test_read_truncated_filter_lzip)
{
test_truncation("lzip", archive_write_add_filter_lzip, 0);
test_truncation("lzip", archive_write_add_filter_lzip, canLzip());
}
DEFINE_TEST(test_read_truncated_filter_lzma)
{
test_truncation("lzma", archive_write_add_filter_lzma, 0);
test_truncation("lzma", archive_write_add_filter_lzma, canLzma());
}
DEFINE_TEST(test_read_truncated_filter_lzop)
@ -169,5 +173,5 @@ DEFINE_TEST(test_read_truncated_filter_lzop)
DEFINE_TEST(test_read_truncated_filter_xz)
{
test_truncation("xz", archive_write_add_filter_xz, 0);
test_truncation("xz", archive_write_add_filter_xz, canXz());
}

View file

@ -364,9 +364,10 @@ verify_sparse_file(struct archive *a, const char *path,
#if DEBUG
fprintf(stderr, " overlapping hole expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
/* Must be a hole, overlap must be filled with '\0' */
if (assert(sparse->type == HOLE)) {
if (sparse->type == HOLE) {
assertMemoryFilledWith(start, end - start, '\0');
} else if (assert(sparse->type == DATA)) {
assertMemoryFilledWith(start, end - start, ' ');
}
start = end;
expected_offset += sparse->size;
@ -410,9 +411,10 @@ verify_sparse_file(struct archive *a, const char *path,
#if DEBUG
fprintf(stderr, " trailing overlap expected_offset=%d, size=%d\n", (int)expected_offset, (int)sparse->size);
#endif
/* Must be a hole, overlap must be filled with '\0' */
if (assert(sparse->type == HOLE)) {
if (sparse->type == HOLE) {
assertMemoryFilledWith(start, end - start, '\0');
} else if (assert(sparse->type == DATA)) {
assertMemoryFilledWith(start, end - start, ' ');
}
}
last_offset = offset + bytes_read;
@ -614,6 +616,33 @@ DEFINE_TEST(test_sparse_basic)
verify_sparse_file2(a, "file0", sparse_file0, 5, 0);
verify_sparse_file2(a, "file0", sparse_file0, 5, 1);
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
/*
* Test that setting ARCHIVE_READDISK_NO_SPARSE
* creates no sparse entries.
*/
assert((a = archive_read_disk_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
ARCHIVE_READDISK_NO_SPARSE));
verify_sparse_file(a, "file0", sparse_file0, 0);
verify_sparse_file(a, "file1", sparse_file1, 0);
verify_sparse_file(a, "file2", sparse_file2, 0);
verify_sparse_file(a, "file3", sparse_file3, 0);
verify_sparse_file(a, "file4", sparse_file4, 0);
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
assert((a = archive_read_disk_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
ARCHIVE_READDISK_NO_SPARSE));
verify_sparse_file2(a, "file0", sparse_file0, 0, 0);
verify_sparse_file2(a, "file0", sparse_file0, 0, 1);
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
free(cwd);
}

View file

@ -39,9 +39,6 @@ __FBSDID("$FreeBSD$");
*/
DEFINE_TEST(test_write_disk_secure746a)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
skipping("archive_write_disk security checks not supported on Windows");
#else
struct archive *a;
struct archive_entry *ae;
@ -75,7 +72,6 @@ DEFINE_TEST(test_write_disk_secure746a)
assertEqualIntA(a, ARCHIVE_FATAL, archive_write_close(a));
archive_write_free(a);
#endif
}
/*

View file

@ -129,6 +129,10 @@ DEFINE_TEST(test_write_filter_zstd)
archive_write_set_filter_option(a, NULL, "compression-level", "-1")); */
assertEqualIntA(a, ARCHIVE_OK,
archive_write_set_filter_option(a, NULL, "compression-level", "7"));
assertEqualIntA(a, ARCHIVE_FAILED,
archive_write_set_filter_option(a, NULL, "threads", "-1")); /* negative */
assertEqualIntA(a, ARCHIVE_OK,
archive_write_set_filter_option(a, NULL, "threads", "4"));
assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2));
for (i = 0; i < 100; i++) {
sprintf(path, "file%03d", i);

View file

@ -27,7 +27,7 @@
#include "test.h"
__FBSDID("$FreeBSD$");
#define LARGE_SIZE (16*1024*1024)
#define LARGE_SIZE (1*1024*1024)
static void
test_large(const char *compression_type)
{
@ -37,7 +37,6 @@ test_large(const char *compression_type)
size_t buffsize = LARGE_SIZE + 1024 * 256;
size_t datasize = LARGE_SIZE;
char *buff, *filedata, *filedata2;
unsigned i;
assert((buff = malloc(buffsize)) != NULL);
assert((filedata = malloc(datasize)) != NULL);
@ -87,8 +86,7 @@ test_large(const char *compression_type)
/* NOTE: PPMd cannot handle random data correctly.*/
memset(filedata, 'a', datasize);
} else {
for (i = 0; i < datasize; i++)
filedata[i] = (char)rand();
fill_with_pseudorandom_data(filedata, datasize);
}
assertEqualInt(datasize, archive_write_data(a, filedata, datasize));

View file

@ -0,0 +1,321 @@
/*-
* Copyright (c) 2021 Jia Cheong Tan
* 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
* in this position and unchanged.
* 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 "test.h"
__FBSDID("$FreeBSD$");
/* File data */
static const char file_name[] = "file";
static const char file_data1[] = {'a', 'b', 'c', 'd', 'e'};
static const char file_data2[] = {'f', 'g', 'h', 'i', 'j'};
static const int file_perm = 00644;
static const short file_uid = 10;
static const short file_gid = 20;
/* Folder data */
static const char folder_name[] = "folder/";
static const int folder_perm = 00755;
static const short folder_uid = 30;
static const short folder_gid = 40;
#define ZIP_ENTRY_FLAG_LENGTH_AT_END (1 << 3)
/* Quick and dirty: Read 2-byte and 4-byte integers from Zip file. */
static unsigned i2(const char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); }
static unsigned i4(const char *p) { return (i2(p) | (i2(p + 2) << 16)); }
static unsigned long
bitcrc32(unsigned long c, const void *_p, size_t s)
{
/* This is a drop-in replacement for crc32() from zlib.
* Libarchive should be able to correctly generate
* uncompressed zip archives (including correct CRCs) even
* when zlib is unavailable, and this function helps us verify
* that. Yes, this is very, very slow and unsuitable for
* production use, but it's correct, compact, and works well
* enough for this particular usage. Libarchive internally
* uses a much more efficient implementation. */
const unsigned char *p = _p;
int bitctr;
if (p == NULL)
return (0);
for (; s > 0; --s)
{
c ^= *p++;
for (bitctr = 8; bitctr > 0; --bitctr)
{
if (c & 1)
c = (c >> 1);
else
c = (c >> 1) ^ 0xedb88320;
c ^= 0x80000000;
}
}
return (c);
}
static void write_archive(struct archive *a)
{
struct archive_entry *entry = archive_entry_new();
assert(entry != NULL);
/* Does not set size for file entry */
archive_entry_set_pathname(entry, file_name);
archive_entry_set_mode(entry, S_IFREG | 0644);
archive_entry_set_uid(entry, file_uid);
archive_entry_set_gid(entry, file_gid);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
assertEqualIntA(a, sizeof(file_data1), archive_write_data(a, file_data1, sizeof(file_data1)));
assertEqualIntA(a, sizeof(file_data2), archive_write_data(a, file_data2, sizeof(file_data2)));
archive_entry_free(entry);
/* Folder */
assert((entry = archive_entry_new()) != NULL);
archive_entry_set_pathname(entry, folder_name);
archive_entry_set_mode(entry, S_IFDIR | folder_perm);
archive_entry_set_size(entry, 0);
archive_entry_set_uid(entry, folder_uid);
archive_entry_set_gid(entry, folder_gid);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, entry));
archive_entry_free(entry);
}
static void verify_contents(const char *zip_buff, size_t size)
{
unsigned long crc = bitcrc32(0, file_data1, sizeof(file_data1));
crc = bitcrc32(crc, file_data2, sizeof(file_data2));
const char *zip_end = zip_buff + size;
/* Since there are no comments, the end of central directory
* is 22 bytes from the end of content */
const char *end_of_central_dir = zip_end - 22;
/* Check for end of central directory signature */
assertEqualMem(end_of_central_dir, "PK\x5\x6", 4);
/* Check for number of disk */
assertEqualInt(i2(end_of_central_dir + 4), 0);
/* Check for disk where central directory starts */
assertEqualInt(i2(end_of_central_dir + 6), 0);
/* Check for number of central directory records on disk */
assertEqualInt(i2(end_of_central_dir + 8), 2);
/* Check for total number of central directory records */
assertEqualInt(i2(end_of_central_dir + 10), 2);
/* Check for size of central directory and offset
* The size + offset must equal the end of the central directory */
assertEqualInt(i4(end_of_central_dir + 12) + i4(end_of_central_dir + 16), end_of_central_dir - zip_buff);
/* Check for empty comment length */
assertEqualInt(i2(end_of_central_dir + 20), 0);
/* Get address of central directory */
const char *central_directory = zip_buff + i4(end_of_central_dir + 16);
/* Check for entry in central directory signature */
assertEqualMem(central_directory, "PK\x1\x2", 4);
/* Check for version used to write entry */
assertEqualInt(i2(central_directory + 4), 3 * 256 + 10);
/* Check for version needed to extract entry */
assertEqualInt(i2(central_directory + 6), 10);
/* Check flags */
assertEqualInt(i2(central_directory + 8), ZIP_ENTRY_FLAG_LENGTH_AT_END);
/* Check compression method */
assertEqualInt(i2(central_directory + 10), 0);
/* Check crc value */
assertEqualInt(i4(central_directory + 16), crc);
/* Check compressed size*/
assertEqualInt(i4(central_directory + 20), sizeof(file_data1) + sizeof(file_data2));
/* Check uncompressed size */
assertEqualInt(i4(central_directory + 24), sizeof(file_data1) + sizeof(file_data2));
/* Check file name length */
assertEqualInt(i2(central_directory + 28), strlen(file_name));
/* Check extra field length */
assertEqualInt(i2(central_directory + 30), 20);
/* Check file comment length */
assertEqualInt(i2(central_directory + 32), 0);
/* Check disk number where file starts */
assertEqualInt(i2(central_directory + 34), 0);
/* Check internal file attrs */
assertEqualInt(i2(central_directory + 36), 0);
/* Check external file attrs */
assertEqualInt(i4(central_directory + 38) >> 16 & 01777, file_perm);
/* Check offset of local header */
assertEqualInt(i4(central_directory + 42), 0);
/* Check for file name contents */
assertEqualMem(central_directory + 46, file_name, strlen(file_name));
/* Get address of local file entry */
const char *local_file_header = zip_buff;
/* Check local file header signature */
assertEqualMem(local_file_header, "PK\x3\x4", 4);
/* Check version needed to extract */
assertEqualInt(i2(local_file_header + 4), 10);
/* Check flags */
assertEqualInt(i2(local_file_header + 6), 8);
/* Check compression method */
assertEqualInt(i2(local_file_header + 8), 0);
/* Check crc */
assertEqualInt(i4(local_file_header + 14), 0);
/* Check compressed size
* 0 because it was unknown at time of writing */
assertEqualInt(i4(local_file_header + 18), 0);
/* Check uncompressed size
* 0 because it was unknown at time of writing */
assertEqualInt(i4(local_file_header + 22), 0);
/* Check pathname length */
assertEqualInt(i2(local_file_header + 26), strlen(file_name));
/* Check extra field length */
assertEqualInt(i2(local_file_header + 28), 20);
/* Check path name match */
assertEqualMem(local_file_header + 30, file_name, strlen(file_name));
/* Start of data */
const char *data = local_file_header + i2(local_file_header + 28) + strlen(file_name) + 30;
/* Check for file data match */
assertEqualMem(data, file_data1, sizeof(file_data1));
assertEqualMem(data + sizeof(file_data1), file_data2, sizeof(file_data2));
/* Start of data descriptor */
const char *data_descriptor = data + sizeof(file_data1) + sizeof(file_data2);
/* Check data descriptor signature */
assertEqualMem(data_descriptor, "PK\x7\x8", 4);
/* Check crc value */
assertEqualInt(i4(data_descriptor + 4), crc);
/* Check compressed size */
assertEqualInt(i4(data_descriptor + 8), sizeof(file_data1) + sizeof(file_data2));
/* Chcek uncompresed size */
assertEqualInt(i4(data_descriptor + 12), sizeof(file_data1) + sizeof(file_data2));
/* Get folder entry in central directory */
const char *central_directory_folder_entry = central_directory + 46 + 20 + strlen(file_name);
/* Get start of folder entry */
const char *local_folder_header = data_descriptor + 16;
/* Check for entry in central directory signature */
assertEqualMem(central_directory_folder_entry, "PK\x1\x2", 4);
/* Check version made by */
assertEqualInt(i2(central_directory_folder_entry + 4), 3 * 256 + 20);
/* Check version needed to extract */
assertEqualInt(i2(central_directory_folder_entry + 6), 20);
/* Check flags */
assertEqualInt(i2(central_directory_folder_entry + 8), 0);
/* Check compression method */
assertEqualInt(i2(central_directory_folder_entry + 10), 0);
/* Check crc */
assertEqualInt(i2(central_directory_folder_entry + 16), 0);
/* Check compressed size */
assertEqualInt(i4(central_directory_folder_entry + 20), 0);
/* Check uncompressed size */
assertEqualInt(i4(central_directory_folder_entry + 24), 0);
/* Check path name length */
assertEqualInt(i2(central_directory_folder_entry + 28), strlen(folder_name));
/* Check extra field length */
assertEqualInt(i2(central_directory_folder_entry + 30), 20);
/* Check file comment length */
assertEqualInt(i2(central_directory_folder_entry + 32), 0);
/* Check disk number start */
assertEqualInt(i2(central_directory_folder_entry + 34), 0);
/* Check internal file attrs */
assertEqualInt(i2(central_directory_folder_entry + 36), 0);
/* Check external file attrs */
assertEqualInt(i4(central_directory_folder_entry + 38) >> 16 & 01777, folder_perm);
/* Check offset of local header*/
assertEqualInt(i4(central_directory_folder_entry + 42), local_folder_header - zip_buff);
/* Check path name */
assertEqualMem(central_directory_folder_entry + 46, folder_name, strlen(folder_name));
/* Check local header */
assertEqualMem(local_folder_header, "PK\x3\x4", 4);
/* Check version to extract */
assertEqualInt(i2(local_folder_header + 4), 20);
/* Check flags */
assertEqualInt(i2(local_folder_header + 6), 0);
/* Check compression method */
assertEqualInt(i2(local_folder_header + 8), 0);
/* Check crc */
assertEqualInt(i4(local_folder_header + 14), 0);
/* Check compressed size */
assertEqualInt(i2(local_folder_header + 18), 0);
/* Check uncompressed size */
assertEqualInt(i4(local_folder_header + 22), 0);
/* Check path name length */
assertEqualInt(i2(local_folder_header + 26), strlen(folder_name));
/* Check extra field length */
assertEqualInt(i2(local_folder_header + 28), 20);
/* Check path name */
assertEqualMem(local_folder_header + 30, folder_name, strlen(folder_name));
const char *post_local_folder = local_folder_header + 30 + strlen(folder_name) + 20;
assertEqualMem(post_local_folder, central_directory, 4);
}
DEFINE_TEST(test_write_format_zip_size_unset)
{
struct archive *a;
char zip_buffer[100000];
size_t size;
/* Use compression=store to disable compression. */
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "zip:compression=store"));
/* Disable zip64 explicitly since it is automatically enabled if no size is set */
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "zip:zip64="));
assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1));
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1));
assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, zip_buffer, sizeof(zip_buffer), &size));
write_archive(a);
/* Close the archive . */
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
dumpfile("constructed_size_unset.zip", zip_buffer, size);
verify_contents(zip_buffer, size);
/* Use compression-level=0 to disable compression. */
assert((a = archive_write_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a));
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "zip:compression-level=0"));
/* Disable zip64 explicitly since it is automatically enabled if no size is set */
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_options(a, "zip:zip64="));
assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a));
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_per_block(a, 1));
assertEqualIntA(a, ARCHIVE_OK, archive_write_set_bytes_in_last_block(a, 1));
assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, zip_buffer, sizeof(zip_buffer), &size));
write_archive(a);
/* Close the archive . */
assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
assertEqualInt(ARCHIVE_OK, archive_write_free(a));
dumpfile("constructed_size_unset.zip", zip_buffer, size);
verify_contents(zip_buffer, size);
}

View file

@ -470,6 +470,11 @@ This is the reverse of
and the default behavior if
.Nm
is run as non-root in x mode.
.It Fl Fl no-read-sparse
(c, r, u modes only)
Do not read sparse file information from disk.
This is the reverse of
.Fl Fl read-sparse .
.It Fl Fl no-safe-writes
(x mode only)
Do not create temporary files and use
@ -633,10 +638,20 @@ a compression dictionary to improve compression ratio.
.It Cm zstd:compression-level
A decimal integer specifying the zstd compression level. Supported values depend
on the library version, common values are from 1 to 22.
.It Cm zstd:threads
Specify the number of worker threads to use.
Setting threads to a special value 0 makes
.Xr zstd 1
use as many threads as there are CPU cores on the system.
.It Cm lzop:compression-level
A decimal integer from 1 to 9 specifying the lzop compression level.
.It Cm xz:compression-level
A decimal integer from 0 to 9 specifying the xz compression level.
.It Cm xz:threads
Specify the number of worker threads to use.
Setting threads to a special value 0 makes
.Xr xz 1
use as many threads as there are CPU cores on the system.
.It Cm mtree: Ns Ar keyword
The mtree writer module allows you to specify which mtree keywords
will be included in the output.
@ -730,6 +745,12 @@ By default, the archive is always read to the very end, since
there can be multiple entries with the same name and, by convention,
later entries overwrite earlier entries.
This option is provided as a performance optimization.
.It Fl Fl read-sparse
(c, r, u modes only)
Read sparse file information from disk.
This is the reverse of
.Fl Fl no-read-sparse
and the default behavior.
.It Fl S
(x mode only)
Extract files as sparse files.

View file

@ -70,24 +70,20 @@ __FBSDID("$FreeBSD$");
#include "bsdtar.h"
#include "err.h"
/*
* Per POSIX.1-1988, tar defaults to reading/writing archives to/from
* the default tape device for the system. Pick something reasonable here.
*/
#ifdef __linux
#define _PATH_DEFTAPE "/dev/st0"
#if ARCHIVE_VERSION_NUMBER < 4000000 && !defined(_PATH_DEFTAPE)
// Libarchive 4.0 and later will NOT define _PATH_DEFTAPE
// but will honor it if it's set in the build.
// Until then, we'll continue to set it by default on certain platforms:
#if defined(__linux)
#define _PATH_DEFTAPE "/dev/st0"
#elif defined(_WIN32) && !defined(__CYGWIN__)
#define _PATH_DEFTAPE "\\\\.\\tape0"
#elif !defined(__APPLE__)
#define _PATH_DEFTAPE "/dev/tape"
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
#define _PATH_DEFTAPE "\\\\.\\tape0"
#endif
#if defined(__APPLE__)
#undef _PATH_DEFTAPE
#define _PATH_DEFTAPE "-" /* Mac OS has no tape support, default to stdio. */
#endif
#ifndef _PATH_DEFTAPE
#define _PATH_DEFTAPE "/dev/tape"
#endif
#define _PATH_STDIO "-"
#ifdef __MINGW32__
int _CRT_glob = 0; /* Disable broken CRT globbing. */
@ -217,8 +213,21 @@ main(int argc, char **argv)
/* Default: open tape drive. */
bsdtar->filename = getenv("TAPE");
if (bsdtar->filename == NULL)
bsdtar->filename = _PATH_DEFTAPE;
#if defined(_PATH_DEFTAPE)
if (bsdtar->filename == NULL) {
#if defined(_WIN32) && !defined(__CYGWIN__)
int tapeExists = !_access(_PATH_DEFTAPE, 0);
#else
int tapeExists = !access(_PATH_DEFTAPE, F_OK);
#endif
if (tapeExists) {
bsdtar->filename = _PATH_DEFTAPE;
}
}
#endif
if (bsdtar->filename == NULL) {
bsdtar->filename = _PATH_STDIO;
}
/* Default block size settings. */
bsdtar->bytes_per_block = DEFAULT_BYTES_PER_BLOCK;
@ -542,6 +551,10 @@ main(int argc, char **argv)
bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_MAC_METADATA;
bsdtar->flags |= OPTFLAG_NO_MAC_METADATA;
break;
case OPTION_NO_READ_SPARSE:
bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_SPARSE;
bsdtar->flags |= OPTFLAG_NO_READ_SPARSE;
break;
case OPTION_NO_SAFE_WRITES:
bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_SAFE_WRITES;
break;
@ -649,6 +662,10 @@ main(int argc, char **argv)
case 'r': /* SUSv2 */
set_mode(bsdtar, opt);
break;
case OPTION_READ_SPARSE:
bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_SPARSE;
bsdtar->flags |= OPTFLAG_READ_SPARSE;
break;
case 'S': /* NetBSD pax-as-tar */
bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE;
break;
@ -796,8 +813,14 @@ main(int argc, char **argv)
"Must specify one of -c, -r, -t, -u, -x");
/* Check boolean options only permitted in certain modes. */
if (bsdtar->flags & OPTFLAG_AUTO_COMPRESS)
only_mode(bsdtar, "-a", "c");
if (bsdtar->flags & OPTFLAG_AUTO_COMPRESS) {
only_mode(bsdtar, "-a", "cx");
if (bsdtar->mode == 'x') {
bsdtar->flags &= ~OPTFLAG_AUTO_COMPRESS;
lafe_warnc(0,
"Ignoring option -a in mode -x");
}
}
if (bsdtar->readdisk_flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
only_mode(bsdtar, "--one-file-system", "cru");
if (bsdtar->flags & OPTFLAG_FAST_READ)

View file

@ -129,6 +129,8 @@ struct bsdtar {
#define OPTFLAG_FFLAGS (0x00100000) /* --fflags */
#define OPTFLAG_NO_MAC_METADATA (0x00200000) /* --no-mac-metadata */
#define OPTFLAG_MAC_METADATA (0x00400000) /* --mac-metadata */
#define OPTFLAG_NO_READ_SPARSE (0x00800000) /* --no-read-sparse */
#define OPTFLAG_READ_SPARSE (0x01000000) /* --read-sparse */
/* Fake short equivalents for long options that otherwise lack them. */
enum {
@ -164,6 +166,7 @@ enum {
OPTION_NO_ACLS,
OPTION_NO_FFLAGS,
OPTION_NO_MAC_METADATA,
OPTION_NO_READ_SPARSE,
OPTION_NO_SAFE_WRITES,
OPTION_NO_SAME_OWNER,
OPTION_NO_SAME_PERMISSIONS,
@ -178,6 +181,7 @@ enum {
OPTION_OPTIONS,
OPTION_PASSPHRASE,
OPTION_POSIX,
OPTION_READ_SPARSE,
OPTION_SAFE_WRITES,
OPTION_SAME_OWNER,
OPTION_STRIP_COMPONENTS,

View file

@ -122,6 +122,7 @@ static const struct bsdtar_option {
{ "no-acls", 0, OPTION_NO_ACLS },
{ "no-fflags", 0, OPTION_NO_FFLAGS },
{ "no-mac-metadata", 0, OPTION_NO_MAC_METADATA },
{ "no-read-sparse", 0, OPTION_NO_READ_SPARSE },
{ "no-recursion", 0, 'n' },
{ "no-safe-writes", 0, OPTION_NO_SAFE_WRITES },
{ "no-same-owner", 0, OPTION_NO_SAME_OWNER },
@ -145,6 +146,7 @@ static const struct bsdtar_option {
{ "posix", 0, OPTION_POSIX },
{ "preserve-permissions", 0, 'p' },
{ "read-full-blocks", 0, 'B' },
{ "read-sparse", 0, OPTION_READ_SPARSE },
{ "safe-writes", 0, OPTION_SAFE_WRITES },
{ "same-owner", 0, OPTION_SAME_OWNER },
{ "same-permissions", 0, 'p' },

View file

@ -95,7 +95,7 @@ get_format_code(const char *suffix)
{ ".7z", "7zip" },
{ ".ar", "arbsd" },
{ ".cpio", "cpio" },
{ ".iso", "iso9960" },
{ ".iso", "iso9660" },
{ ".mtree", "mtree" },
{ ".shar", "shar" },
{ ".tar", "paxr" },

View file

@ -371,10 +371,9 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer)
r = archive_read_extract2(a, entry, writer);
if (r != ARCHIVE_OK) {
if (!bsdtar->verbose)
safe_fprintf(stderr, "%s",
archive_entry_pathname(entry));
safe_fprintf(stderr, ": %s",
archive_error_string(a));
safe_fprintf(stderr, "%s", archive_entry_pathname(entry));
fprintf(stderr, ": %s: ", archive_error_string(a));
fprintf(stderr, "%s", strerror(errno));
if (!bsdtar->verbose)
fprintf(stderr, "\n");
bsdtar->return_value = 1;

View file

@ -0,0 +1,147 @@
/*-
* Copyright (c) 2021 Ryan Libby
* 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
* in this position and unchanged.
* 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 "test.h"
__FBSDID("$FreeBSD$");
static int
make_files(void)
{
int ret;
assertMakeDir("in", 0755);
assertMakeDir("out", 0755);
assertMakeFile("in/a", 0644, "a");
assertMakeFile("in/b", 0644, "b");
assertMakeFile("in/c", 0644, "c");
assertEqualInt(0, systemf("%s cf a.tar -C in a", testprog));
assertEqualInt(0, systemf("%s cf b.tar -C in b", testprog));
/* An archive formed with cat, and readable with --ignore-zeros. */
ret = systemf("cat a.tar b.tar > ab-cat.tar");
if (ret != 0) {
skipping("This test requires a `cat` program");
return (ret);
}
return (0);
}
DEFINE_TEST(test_option_ignore_zeros_mode_t)
{
if (make_files())
return;
/* Generate expected t-mode output. */
assertEqualInt(0, systemf(
"%s cf ab-norm.tar -C in a b > norm-c.out 2> norm-c.err",
testprog));
assertEmptyFile("norm-c.err");
assertEmptyFile("norm-c.out");
assertEqualInt(0, systemf(
"%s tf ab-norm.tar > norm-t.out 2> norm-t.err",
testprog));
assertEmptyFile("norm-t.err");
/* Test output. */
assertEqualInt(0, systemf(
"%s tf ab-cat.tar --ignore-zeros > test.out 2> test.err",
testprog));
assertEmptyFile("test.err");
assertEqualFile("test.out", "norm-t.out");
}
DEFINE_TEST(test_option_ignore_zeros_mode_x)
{
if (make_files())
return;
assertEqualInt(0, systemf(
"%s xf ab-cat.tar --ignore-zeros -C out > test.out 2> test.err",
testprog));
assertEmptyFile("test.err");
assertEmptyFile("test.out");
assertEqualFile("out/a", "in/a");
assertEqualFile("out/b", "in/b");
}
DEFINE_TEST(test_option_ignore_zeros_mode_c)
{
if (make_files())
return;
assertEqualInt(0, systemf(
"%s cf abc.tar --ignore-zeros @ab-cat.tar -C in c "
"> test-c.out 2> test-c.err",
testprog));
assertEmptyFile("test-c.err");
assertEmptyFile("test-c.out");
assertEqualInt(0, systemf(
"%s xf abc.tar -C out > test-x.out 2> test-x.err",
testprog));
assertEmptyFile("test-x.err");
assertEmptyFile("test-x.out");
assertEqualFile("out/a", "in/a");
assertEqualFile("out/b", "in/b");
assertEqualFile("out/c", "in/c");
}
static void
test_option_ignore_zeros_mode_ru(const char *mode)
{
if (make_files())
return;
assertEqualInt(0, systemf(
"%s %sf ab-cat.tar --ignore-zeros -C in c "
"> test-ru.out 2> test-ru.err",
testprog, mode));
assertEmptyFile("test-ru.err");
assertEmptyFile("test-ru.out");
assertEqualInt(0, systemf(
"%s xf ab-cat.tar --ignore-zeros -C out "
"> test-x.out 2> test-x.err",
testprog));
assertEmptyFile("test-x.err");
assertEmptyFile("test-x.out");
assertEqualFile("out/a", "in/a");
assertEqualFile("out/b", "in/b");
assertEqualFile("out/c", "in/c");
}
DEFINE_TEST(test_option_ignore_zeros_mode_r)
{
test_option_ignore_zeros_mode_ru("r");
}
DEFINE_TEST(test_option_ignore_zeros_mode_u)
{
test_option_ignore_zeros_mode_ru("u");
}

View file

@ -196,6 +196,10 @@ set_reader_options(struct bsdtar *bsdtar, struct archive *a)
else
archive_clear_error(a);
}
if (bsdtar->flags & OPTFLAG_IGNORE_ZEROS)
if (archive_read_set_options(a,
"read_concatenated_archives") != ARCHIVE_OK)
lafe_errc(1, 0, "%s", archive_error_string(a));
}
void

View file

@ -471,4 +471,6 @@ void assertVersion(const char *prog, const char *base);
#include <dmalloc.h>
#endif
#include "test_utils.h"
#endif /* TEST_COMMON_H */

View file

@ -2610,7 +2610,7 @@ canLzma(void)
static int tested = 0, value = 0;
if (!tested) {
tested = 1;
if (systemf("lzma %s", redirectArgs) == 0)
if (systemf("lzma --help %s", redirectArgs) == 0)
value = 1;
}
return (value);
@ -3462,6 +3462,12 @@ assertion_entry_compare_acls(const char *file, int line,
* DEFINE_TEST(test_function)
* for each test.
*/
struct test_list_t
{
void (*func)(void);
const char *name;
int failures;
};
/* Use "list.h" to declare all of the test functions. */
#undef DEFINE_TEST
@ -3753,6 +3759,100 @@ get_refdir(const char *d)
return p;
}
/* Filter tests against a glob pattern. Returns non-zero if test matches
* pattern, zero otherwise. A '^' at the beginning of the pattern negates
* the return values (i.e. returns zero for a match, non-zero otherwise.
*/
static int
test_filter(const char *pattern, const char *test)
{
int retval = 0;
int negate = 0;
const char *p = pattern;
const char *t = test;
if (p[0] == '^')
{
negate = 1;
p++;
}
while (1)
{
if (p[0] == '\\')
p++;
else if (p[0] == '*')
{
while (p[0] == '*')
p++;
if (p[0] == '\\')
p++;
if ((t = strchr(t, p[0])) == 0)
break;
}
if (p[0] != t[0])
break;
if (p[0] == '\0') {
retval = 1;
break;
}
p++;
t++;
}
return (negate) ? !retval : retval;
}
static int
get_test_set(int *test_set, int limit, const char *test)
{
int start, end;
int idx = 0;
if (test == NULL) {
/* Default: Run all tests. */
for (;idx < limit; idx++)
test_set[idx] = idx;
return (limit);
}
if (*test >= '0' && *test <= '9') {
const char *vp = test;
start = 0;
while (*vp >= '0' && *vp <= '9') {
start *= 10;
start += *vp - '0';
++vp;
}
if (*vp == '\0') {
end = start;
} else if (*vp == '-') {
++vp;
if (*vp == '\0') {
end = limit - 1;
} else {
end = 0;
while (*vp >= '0' && *vp <= '9') {
end *= 10;
end += *vp - '0';
++vp;
}
}
} else
return (-1);
if (start < 0 || end >= limit || start > end)
return (-1);
while (start <= end)
test_set[idx++] = start++;
} else {
for (start = 0; start < limit; ++start) {
const char *name = tests[start].name;
if (test_filter(test, name))
test_set[idx++] = start;
}
}
return ((idx == 0)?-1:idx);
}
int
main(int argc, char **argv)
{
@ -4049,7 +4149,7 @@ main(int argc, char **argv)
do {
int test_num;
test_num = get_test_set(test_set, limit, *argv, tests);
test_num = get_test_set(test_set, limit, *argv);
if (test_num < 0) {
printf("*** INVALID Test %s\n", *argv);
free(refdir_alloc);

View file

@ -26,99 +26,86 @@
#include "test_utils.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
/* Filter tests against a glob pattern. Returns non-zero if test matches
* pattern, zero otherwise. A '^' at the beginning of the pattern negates
* the return values (i.e. returns zero for a match, non-zero otherwise.
static inline uint64_t
xorshift64(uint64_t *state)
{
uint64_t x = *state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
*state = x;
return (x);
}
/*
* Fill a buffer with reproducible pseudo-random data using a simple xorshift
* algorithm. Originally, most tests filled buffers with a loop that calls
* rand() once for each byte. However, this initialization can be extremely
* slow when running on emulated platforms such as QEMU where 16M calls to
* rand() take a long time: Before the test_write_format_7zip_large_copy test
* took ~22 seconds, whereas using a xorshift random number generator (that can
* be inlined) reduces it to ~17 seconds on QEMU RISC-V.
*/
static int
test_filter(const char *pattern, const char *test)
static void
fill_with_pseudorandom_data_seed(uint64_t seed, void *buffer, size_t size)
{
int retval = 0;
int negate = 0;
const char *p = pattern;
const char *t = test;
if (p[0] == '^')
{
negate = 1;
p++;
}
while (1)
{
if (p[0] == '\\')
p++;
else if (p[0] == '*')
{
while (p[0] == '*')
p++;
if (p[0] == '\\')
p++;
if ((t = strchr(t, p[0])) == 0)
break;
}
if (p[0] != t[0])
break;
if (p[0] == '\0') {
retval = 1;
break;
}
p++;
t++;
}
return (negate) ? !retval : retval;
}
int get_test_set(int *test_set, int limit, const char *test,
struct test_list_t *tests)
{
int start, end;
int idx = 0;
if (test == NULL) {
/* Default: Run all tests. */
for (;idx < limit; idx++)
test_set[idx] = idx;
return (limit);
}
if (*test >= '0' && *test <= '9') {
const char *vp = test;
start = 0;
while (*vp >= '0' && *vp <= '9') {
start *= 10;
start += *vp - '0';
++vp;
}
if (*vp == '\0') {
end = start;
} else if (*vp == '-') {
++vp;
if (*vp == '\0') {
end = limit - 1;
} else {
end = 0;
while (*vp >= '0' && *vp <= '9') {
end *= 10;
end += *vp - '0';
++vp;
}
}
} else
return (-1);
if (start < 0 || end >= limit || start > end)
return (-1);
while (start <= end)
test_set[idx++] = start++;
uint64_t *aligned_buffer;
size_t num_values;
size_t i;
size_t unaligned_suffix;
size_t unaligned_prefix = 0;
/*
* To avoid unaligned stores we only fill the aligned part of the buffer
* with pseudo-random data and fill the unaligned prefix with 0xab and
* the suffix with 0xcd.
*/
if ((uintptr_t)buffer % sizeof(uint64_t)) {
unaligned_prefix =
sizeof(uint64_t) - (uintptr_t)buffer % sizeof(uint64_t);
aligned_buffer =
(uint64_t *)((char *)buffer + unaligned_prefix);
memset(buffer, 0xab, unaligned_prefix);
} else {
for (start = 0; start < limit; ++start) {
const char *name = tests[start].name;
if (test_filter(test, name))
test_set[idx++] = start;
}
aligned_buffer = (uint64_t *)buffer;
}
assert((uintptr_t)aligned_buffer % sizeof(uint64_t) == 0);
num_values = (size - unaligned_prefix) / sizeof(uint64_t);
unaligned_suffix =
size - unaligned_prefix - num_values * sizeof(uint64_t);
for (i = 0; i < num_values; i++) {
aligned_buffer[i] = xorshift64(&seed);
}
if (unaligned_suffix) {
memset((char *)buffer + size - unaligned_suffix, 0xcd,
unaligned_suffix);
}
return ((idx == 0)?-1:idx);
}
void
fill_with_pseudorandom_data(void *buffer, size_t size)
{
uint64_t seed;
const char* seed_str;
/*
* Check if a seed has been specified in the environment, otherwise fall
* back to using rand() as a seed.
*/
if ((seed_str = getenv("TEST_RANDOM_SEED")) != NULL) {
errno = 0;
seed = strtoull(seed_str, NULL, 10);
if (errno != 0) {
fprintf(stderr, "strtoull(%s) failed: %s", seed_str,
strerror(errno));
seed = rand();
}
} else {
seed = rand();
}
fill_with_pseudorandom_data_seed(seed, buffer, size);
}

View file

@ -27,13 +27,10 @@
#ifndef TEST_UTILS_H
#define TEST_UTILS_H
struct test_list_t
{
void (*func)(void);
const char *name;
int failures;
};
#include <stddef.h>
#include <stdint.h>
int get_test_set(int *, int, const char *, struct test_list_t *);
/* Fill a buffer with pseudorandom data */
void fill_with_pseudorandom_data(void* buffer, size_t size);
#endif /* TEST_UTILS_H */

View file

@ -19,6 +19,8 @@ CFLAGS+= -I${.CURDIR} -I${.CURDIR:H} -I${.OBJDIR}
CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive -I${_LIBARCHIVEDIR}/libarchive/test
CFLAGS+= -I${_LIBARCHIVEDIR}/test_utils
CFLAGS.test_utils.c+= -Wno-cast-align
# Uncomment to link against dmalloc
#LDADD+= -L/usr/local/lib -ldmalloc
#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC
@ -79,6 +81,7 @@ TESTS_SRCS= \
test_compat_solaris_tar_acl.c \
test_compat_solaris_pax_sparse.c \
test_compat_star_acl.c \
test_compat_tar_directory.c \
test_compat_tar_hardlink.c \
test_compat_uudecode.c \
test_compat_uudecode_large.c \
@ -167,6 +170,7 @@ TESTS_SRCS= \
test_read_format_rar_encryption_data.c \
test_read_format_rar_encryption_header.c \
test_read_format_rar_encryption_partially.c \
test_read_format_rar_filter.c \
test_read_format_rar_invalid1.c \
test_read_format_raw.c \
test_read_format_tar.c \
@ -291,6 +295,7 @@ TESTS_SRCS= \
test_write_format_zip_compression_store.c \
test_write_format_zip_empty.c \
test_write_format_zip_empty_zip64.c \
test_write_format_zip_entry_size_unset.c \
test_write_format_zip_file.c \
test_write_format_zip_file_zip64.c \
test_write_format_zip_large.c \
@ -380,6 +385,7 @@ ${PACKAGE}FILES+= test_compat_solaris_pax_sparse_2.pax.Z.uu
${PACKAGE}FILES+= test_compat_solaris_tar_acl.tar.uu
${PACKAGE}FILES+= test_compat_star_acl_nfs4.tar.uu
${PACKAGE}FILES+= test_compat_star_acl_posix1e.tar.uu
${PACKAGE}FILES+= test_compat_tar_directory_1.tar.uu
${PACKAGE}FILES+= test_compat_tar_hardlink_1.tar.uu
${PACKAGE}FILES+= test_compat_uudecode_large.tar.Z.uu
${PACKAGE}FILES+= test_compat_xz_1.txz.uu
@ -517,6 +523,7 @@ ${PACKAGE}FILES+= test_read_format_rar_compress_normal.rar.uu
${PACKAGE}FILES+= test_read_format_rar_encryption_data.rar.uu
${PACKAGE}FILES+= test_read_format_rar_encryption_header.rar.uu
${PACKAGE}FILES+= test_read_format_rar_encryption_partially.rar.uu
${PACKAGE}FILES+= test_read_format_rar_filter.rar.uu
${PACKAGE}FILES+= test_read_format_rar_invalid1.rar.uu
${PACKAGE}FILES+= test_read_format_rar_multi_lzss_blocks.rar.uu
${PACKAGE}FILES+= test_read_format_rar_multivolume.part0001.rar.uu
@ -533,9 +540,11 @@ ${PACKAGE}FILES+= test_read_format_rar_unicode.rar.uu
${PACKAGE}FILES+= test_read_format_rar_windows.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_arm.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_arm_filter_on_window_boundary.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_bad_window_sz_in_mltarc_file.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_blake2.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_block_size_is_too_small.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_compressed.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_decode_number_out_of_bounds_read.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_different_solid_window_size.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_different_window_size.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_different_winsize_on_merge.rar.uu
@ -563,12 +572,14 @@ ${PACKAGE}FILES+= test_read_format_rar5_multiple_files_solid.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_nonempty_dir_stream.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_owner.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_readtables_overflow.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_sfx.exe.uu
${PACKAGE}FILES+= test_read_format_rar5_solid.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_stored.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_stored_manyfiles.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_symlink.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_truncated_huff.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_win32.rar.uu
${PACKAGE}FILES+= test_read_format_rar5_window_buf_and_size_desync.rar.uu
${PACKAGE}FILES+= test_read_format_raw.bufr.uu
${PACKAGE}FILES+= test_read_format_raw.data.Z.uu
${PACKAGE}FILES+= test_read_format_raw.data.gz.uu
@ -632,6 +643,8 @@ ${PACKAGE}FILES+= test_read_format_zip_winzip_aes256_stored.zip.uu
${PACKAGE}FILES+= test_read_format_zip_xz_multi.zipx.uu
${PACKAGE}FILES+= test_read_format_zip_zip64a.zip.uu
${PACKAGE}FILES+= test_read_format_zip_zip64b.zip.uu
${PACKAGE}FILES+= test_read_format_zip_zstd.zipx.uu
${PACKAGE}FILES+= test_read_format_zip_zstd_multi.zipx.uu
${PACKAGE}FILES+= test_read_large_splitted_rar_aa.uu
${PACKAGE}FILES+= test_read_large_splitted_rar_ab.uu
${PACKAGE}FILES+= test_read_large_splitted_rar_ac.uu

View file

@ -18,6 +18,8 @@ CFLAGS+= -I${_LIBARCHIVEDIR}/cat -I${_LIBARCHIVEDIR}/cat/test
CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive
CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive_fe -I${_LIBARCHIVEDIR}/test_utils
CFLAGS.test_utils.c+= -Wno-cast-align
# Uncomment to link against dmalloc
#LDADD+= -L/usr/local/lib -ldmalloc
#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC

View file

@ -22,6 +22,8 @@ CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive_fe -I${_LIBARCHIVEDIR}/test_utils
#LDADD+= -L/usr/local/lib -ldmalloc
#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC
CFLAGS.test_utils.c+= -Wno-cast-align
.PATH: ${_LIBARCHIVEDIR}/cpio
CPIO_SRCS= cmdline.c

View file

@ -16,6 +16,8 @@ CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive
CFLAGS+= -I${_LIBARCHIVEDIR}/tar -I${_LIBARCHIVEDIR}/tar/test
CFLAGS+= -I${_LIBARCHIVEDIR}/test_utils
CFLAGS.test_utils.c+= -Wno-cast-align
# Uncomment to link against dmalloc
#LDADD+= -L/usr/local/lib -ldmalloc
#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC
@ -59,6 +61,7 @@ TESTS_SRCS= \
test_option_fflags.c \
test_option_gid_gname.c \
test_option_grzip.c \
test_option_ignore_zeros.c \
test_option_j.c \
test_option_k.c \
test_option_keep_newer_files.c \