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:
commit
833a452e9f
18
contrib/libarchive/.editorconfig
Normal file
18
contrib/libarchive/.editorconfig
Normal 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
|
24
contrib/libarchive/.github/workflows/cifuzz.yml
vendored
Normal file
24
contrib/libarchive/.github/workflows/cifuzz.yml
vendored
Normal 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
|
@ -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
|
||||
|
115
contrib/libarchive/build/autoconf/m4_ax_compile_check_sizeof.m4
Normal file
115
contrib/libarchive/build/autoconf/m4_ax_compile_check_sizeof.m4
Normal 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
|
||||
])
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "archive_platform.h"
|
||||
#include "archive_blake2.h"
|
||||
#include "archive_blake2_impl.h"
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "archive_platform.h"
|
||||
#include "archive_blake2.h"
|
||||
#include "archive_blake2_impl.h"
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,14 +562,14 @@ 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 (bidder->vtable == NULL)
|
||||
continue;
|
||||
bid = (bidder->vtable->bid)(bidder, a->filter);
|
||||
if (bid > best_bid) {
|
||||
best_bid = bid;
|
||||
best_bidder = bidder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If no bidder, we're done. */
|
||||
if (best_bidder == NULL) {
|
||||
@ -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) {
|
||||
if (a->bidders[i].vtable != NULL)
|
||||
continue;
|
||||
memset(a->bidders + i, 0, sizeof(a->bidders[0]));
|
||||
*bidder = (a->bidders + i);
|
||||
return (ARCHIVE_OK);
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -303,9 +303,11 @@ archive_read_disk_entry_from_file(struct archive *_a,
|
||||
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)
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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 *,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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");
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
return (ARCHIVE_OK);
|
||||
break;
|
||||
__LA_FALLTHROUGH;
|
||||
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);
|
||||
}
|
||||
*parsed_kws |= MTREE_HAS_PERM;
|
||||
archive_entry_set_perm(entry, (mode_t)mtree_atol(&val, 8));
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
__LA_FALLTHROUGH;
|
||||
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,50 +1782,59 @@ 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);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
__LA_FALLTHROUGH;
|
||||
default:
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unrecognized file type \"%s\"; "
|
||||
@ -1834,28 +1842,25 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
*parsed_kws |= MTREE_HAS_TYPE;
|
||||
break;
|
||||
}
|
||||
__LA_FALLTHROUGH;
|
||||
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);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
__LA_FALLTHROUGH;
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unrecognized key %s=%s", key, val);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -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;
|
||||
@ -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 **,
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
@ -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,7 +3051,30 @@ expand(struct archive_read *a, int64_t end)
|
||||
}
|
||||
|
||||
static int
|
||||
copy_from_lzss_window(struct archive_read *a, const void **buffer,
|
||||
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;
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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,13 +1772,28 @@ 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) {
|
||||
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
|
||||
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "archive_platform.h"
|
||||
#include "archive.h"
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 = 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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
}
|
@ -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
|
@ -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
|
7048
contrib/libarchive/libarchive/test/test_read_format_rar5_sfx.exe.uu
Normal file
7048
contrib/libarchive/libarchive/test/test_read_format_rar5_sfx.exe.uu
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
@ -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));
|
||||
}
|
26650
contrib/libarchive/libarchive/test/test_read_format_rar_filter.rar.uu
Normal file
26650
contrib/libarchive/libarchive/test/test_read_format_rar_filter.rar.uu
Normal file
File diff suppressed because it is too large
Load Diff
@ -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";
|
||||
|
@ -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
|
@ -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
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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.
|
||||
|
@ -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
|
||||
#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"
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#elif 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
|
||||
#elif !defined(__APPLE__)
|
||||
#define _PATH_DEFTAPE "/dev/tape"
|
||||
#endif
|
||||
#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)
|
||||
#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)
|
||||
|
@ -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,
|
||||
|
@ -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' },
|
||||
|
@ -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" },
|
||||
|
@ -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;
|
||||
|
147
contrib/libarchive/tar/test/test_option_ignore_zeros.c
Normal file
147
contrib/libarchive/tar/test/test_option_ignore_zeros.c
Normal 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");
|
||||
}
|
@ -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
|
||||
|
@ -471,4 +471,6 @@ void assertVersion(const char *prog, const char *base);
|
||||
#include <dmalloc.h>
|
||||
#endif
|
||||
|
||||
#include "test_utils.h"
|
||||
|
||||
#endif /* TEST_COMMON_H */
|
||||
|
@ -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);
|
||||
|
@ -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++;
|
||||
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 {
|
||||
aligned_buffer = (uint64_t *)buffer;
|
||||
}
|
||||
|
||||
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;
|
||||
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 (p[0] != t[0])
|
||||
break;
|
||||
if (p[0] == '\0') {
|
||||
retval = 1;
|
||||
break;
|
||||
if (unaligned_suffix) {
|
||||
memset((char *)buffer + size - unaligned_suffix, 0xcd,
|
||||
unaligned_suffix);
|
||||
}
|
||||
p++;
|
||||
t++;
|
||||
}
|
||||
|
||||
return (negate) ? !retval : retval;
|
||||
}
|
||||
|
||||
int get_test_set(int *test_set, int limit, const char *test,
|
||||
struct test_list_t *tests)
|
||||
void
|
||||
fill_with_pseudorandom_data(void *buffer, size_t size)
|
||||
{
|
||||
int start, end;
|
||||
int idx = 0;
|
||||
|
||||
if (test == NULL) {
|
||||
/* Default: Run all tests. */
|
||||
for (;idx < limit; idx++)
|
||||
test_set[idx] = idx;
|
||||
return (limit);
|
||||
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();
|
||||
}
|
||||
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;
|
||||
seed = rand();
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
fill_with_pseudorandom_data_seed(seed, buffer, size);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user