libarchive: merge from vendor branch

libarchive 3.8.10

ChangeLog:
https://github.com/libarchive/libarchive/compare/v3.8.9...v3.8.10

Obtained from:	libarchive
Vendor commit:	0c48412be2d94afe1859a807ea7896a18d8900bd
MFC after:	3 days
This commit is contained in:
Martin Matuska committed 2026-10-26 22:47:32 +01:00
commit 61c70dc16a
290 files changed
+14057 -2764

No files matched your search

+2
View File
@@ -1,3 +1,5 @@
Oct 14, 2026: libarchive 3.8.10 released
Jul 28, 2026: libarchive 3.8.9 released
Jun 23, 2026: libarchive 3.8.8 released
@@ -0,0 +1,84 @@
# visibility.m4
# serial 9
dnl Copyright (C) 2005, 2008, 2010-2026 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
dnl This file is offered as-is, without any warranty.
dnl From Bruno Haible.
dnl Tests whether the compiler supports the command-line option
dnl -fvisibility=hidden and the function and variable attributes
dnl __attribute__((__visibility__("hidden"))) and
dnl __attribute__((__visibility__("default"))).
dnl Does *not* test for __visibility__("protected") - which has tricky
dnl semantics (see the 'vismain' test in glibc) and does not exist e.g. on
dnl Mac OS X.
dnl Does *not* test for __visibility__("internal") - which has processor
dnl dependent semantics.
dnl Does *not* test for #pragma GCC visibility push(hidden) - which is
dnl "really only recommended for legacy code".
dnl Set the variable CFLAG_VISIBILITY.
dnl Defines and sets the variable HAVE_VISIBILITY.
AC_DEFUN([gl_VISIBILITY],
[
AC_REQUIRE([AC_PROG_CC])
CFLAG_VISIBILITY=
HAVE_VISIBILITY=0
if test -n "$GCC"; then
dnl First, check whether -Werror can be added to the command line, or
dnl whether it leads to an error because of some other option that the
dnl user has put into $CC $CFLAGS $CPPFLAGS.
AC_CACHE_CHECK([whether the -Werror option is usable],
[gl_cv_cc_vis_werror],
[gl_saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[]], [[]])],
[gl_cv_cc_vis_werror=yes],
[gl_cv_cc_vis_werror=no])
CFLAGS="$gl_saved_CFLAGS"
])
dnl Now check whether visibility declarations are supported.
AC_CACHE_CHECK([for simple visibility declarations],
[gl_cv_cc_visibility],
[gl_saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fvisibility=hidden"
dnl We use the option -Werror and a function dummyfunc, because on some
dnl platforms (Cygwin 1.7) the use of -fvisibility triggers a warning
dnl "visibility attribute not supported in this configuration; ignored"
dnl at the first function definition in every compilation unit, and we
dnl don't want to use the option in this case.
if test $gl_cv_cc_vis_werror = yes; then
CFLAGS="$CFLAGS -Werror"
fi
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[extern __attribute__((__visibility__("hidden"))) int hiddenvar;
extern __attribute__((__visibility__("default"))) int exportedvar;
extern __attribute__((__visibility__("hidden"))) int hiddenfunc (void);
extern __attribute__((__visibility__("default"))) int exportedfunc (void);
void dummyfunc (void);
int hiddenvar;
int exportedvar;
int hiddenfunc (void) { return 51; }
int exportedfunc (void) { return 1225736919; }
void dummyfunc (void) {}
]],
[[]])],
[gl_cv_cc_visibility=yes],
[gl_cv_cc_visibility=no])
CFLAGS="$gl_saved_CFLAGS"
])
if test $gl_cv_cc_visibility = yes; then
CFLAG_VISIBILITY="-fvisibility=hidden"
HAVE_VISIBILITY=1
fi
fi
AC_SUBST([CFLAG_VISIBILITY])
AC_SUBST([HAVE_VISIBILITY])
AC_DEFINE_UNQUOTED([HAVE_VISIBILITY], [$HAVE_VISIBILITY],
[Define to 1 or 0, depending whether the compiler supports simple visibility declarations.])
])
+24 -1
View File
@@ -79,6 +79,14 @@ Reset access times on files after they are read.
.It Fl B
(o mode only)
Block output to records of 5120 bytes.
.It Fl Fl b64encode
(o mode only)
Encode the archive with base64, after any compression.
In input mode, this option is ignored; base64-encoded archives are
recognized automatically on input.
If both this option and
.Fl Fl uuencode
are given, the last one specified is used.
.It Fl C Ar size
(o mode only)
Block output to records of
@@ -154,7 +162,7 @@ automatically on input.
.It Fl j
Synonym for
.Fl y .
.It Fl L
.It Fl L , Fl Fl dereference
(o and p modes)
All symbolic links will be followed.
Normally, symbolic links are archived and copied as symbolic links.
@@ -163,6 +171,11 @@ With this option, the target of the link will be archived or copied instead.
(p mode only)
Create links from the target directory to the original files,
instead of copying.
.It Fl Fl grzip
(o mode only)
Compress the resulting archive with
.Xr grzip 1 .
In input mode, this option is ignored.
.It Fl Fl lrzip
(o mode only)
Compress the resulting archive with
@@ -265,6 +278,16 @@ do not restore the contents to disk.
(i and p modes)
Unconditionally overwrite existing files.
Ordinarily, an older file will not overwrite a newer file on disk.
.It Fl Fl uuencode
(o mode only)
Encode the archive with
.Xr uuencode 1 ,
after any compression.
In input mode, this option is ignored; uuencoded archives are
recognized automatically on input.
If both this option and
.Fl Fl b64encode
are given, the last one specified is used.
.It Fl V , Fl Fl dot
Print a dot to stderr for each file as it is processed.
Superseded by
+35 -45
View File
@@ -66,6 +66,7 @@
#include "cpio.h"
#include "lafe_err.h"
#include "lafe_explicit_bzero.h"
#include "line_reader.h"
#include "passphrase.h"
@@ -77,8 +78,6 @@
#endif
struct name_cache {
int probes;
int hits;
size_t size;
struct {
id_t id;
@@ -87,7 +86,6 @@ struct name_cache {
};
static int extract_data(struct archive *, struct archive *);
const char * cpio_i64toa(int64_t);
static void cpio_rename(struct archive_entry *);
static int entry_to_archive(struct cpio *, struct archive_entry *);
static int file_to_archive(struct cpio *, const char *);
@@ -409,6 +407,10 @@ main(int argc, char *argv[])
else
cpio->format = "cpio";
}
if (cpio->argc > 0)
lafe_errc(1, 0,
"Too many arguments for -o mode (got %d, expected 0)",
cpio->argc);
mode_out(cpio);
break;
case 'i':
@@ -429,6 +431,10 @@ main(int argc, char *argv[])
if (*cpio->argv == NULL || **cpio->argv == '\0')
lafe_errc(1, 0,
"-p mode requires a target directory");
if (cpio->argc > 1)
lafe_errc(1, 0,
"Too many arguments for -p mode (got %d, expected 1)",
cpio->argc);
mode_pass(cpio, *cpio->argv);
break;
default:
@@ -728,12 +734,16 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
return (r);
}
if (cpio->uid_override >= 0)
if (cpio->uid_override >= 0) {
archive_entry_set_uid(entry, cpio->uid_override);
archive_entry_set_uname(entry, NULL);
}
if (cpio->uname_override != NULL)
archive_entry_set_uname(entry, cpio->uname_override);
if (cpio->gid_override >= 0)
if (cpio->gid_override >= 0) {
archive_entry_set_gid(entry, cpio->gid_override);
archive_entry_set_gname(entry, NULL);
}
if (cpio->gname_override != NULL)
archive_entry_set_gname(entry, cpio->gname_override);
@@ -842,7 +852,11 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
lafe_warnc(0, "Copying file instead");
} else
#endif
return (0);
{
if (r != ARCHIVE_OK)
cpio->return_value = 1;
return (0);
}
}
/*
@@ -1160,6 +1174,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
const char *uname, *gname;
FILE *out = stdout;
const char *fmt;
double age;
time_t mtime;
static time_t now;
struct tm *ltime;
@@ -1172,9 +1187,11 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
if (cpio->option_numeric_uid_gid) {
/* Format numeric uid/gid for display. */
strcpy(uids, cpio_i64toa(archive_entry_uid(entry)));
snprintf(uids, sizeof(uids), "%lld",
(long long)archive_entry_uid(entry));
uname = uids;
strcpy(gids, cpio_i64toa(archive_entry_gid(entry)));
snprintf(gids, sizeof(gids), "%lld",
(long long)archive_entry_gid(entry));
gname = gids;
} else {
/* Use uname if it's present, else lookup name from uid. */
@@ -1194,21 +1211,21 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
(unsigned long)archive_entry_rdevmajor(entry),
(unsigned long)archive_entry_rdevminor(entry));
} else {
strcpy(size, cpio_i64toa(archive_entry_size(entry)));
snprintf(size, sizeof(size), "%lld",
(long long)archive_entry_size(entry));
}
/* Format the time using 'ls -l' conventions. */
mtime = archive_entry_mtime(entry);
age = difftime(mtime, now);
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Windows' strftime function does not support %e format. */
if (mtime - now > 365*86400/2
|| mtime - now < -365*86400/2)
if (age > 365.0 * 86400 / 2 || age < -365.0 * 86400 / 2)
fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y";
else
fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M";
#else
if (mtime - now > 365*86400/2
|| mtime - now < -365*86400/2)
if (age > 365.0 * 86400 / 2 || age < -365.0 * 86400 / 2)
fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y";
else
fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M";
@@ -1392,12 +1409,10 @@ lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable,
}
cache = *name_cache_variable;
cache->probes++;
slot = id % cache->size;
if (cache->cache[slot].name != NULL) {
if (cache->cache[slot].id == id) {
cache->hits++;
return (cache->cache[slot].name);
}
free(cache->cache[slot].name);
@@ -1442,8 +1457,8 @@ lookup_uname_helper(struct cpio *cpio, const char **name, id_t id)
pwent = getpwuid((uid_t)id);
if (pwent == NULL) {
if (errno && errno != ENOENT)
lafe_warnc(errno, "getpwuid(%s) failed",
cpio_i64toa((int64_t)id));
lafe_warnc(errno, "getpwuid(%lld) failed",
(long long)id);
return 1;
}
@@ -1469,8 +1484,8 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id)
grent = getgrgid((gid_t)id);
if (grent == NULL) {
if (errno && errno != ENOENT)
lafe_warnc(errno, "getgrgid(%s) failed",
cpio_i64toa((int64_t)id));
lafe_warnc(errno, "getgrgid(%lld) failed",
(long long)id);
return 1;
}
@@ -1478,31 +1493,6 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id)
return 0;
}
/*
* It would be nice to just use printf() for formatting large numbers,
* but the compatibility problems are a big headache. Hence the
* following simple utility function.
*/
const char *
cpio_i64toa(int64_t n0)
{
/* 2^64 =~ 1.8 * 10^19, so 20 decimal digits suffice.
* We also need 1 byte for '-' and 1 for '\0'.
*/
static char buff[22];
int64_t n = n0 < 0 ? -n0 : n0;
char *p = buff + sizeof(buff);
*--p = '\0';
do {
*--p = '0' + (int)(n % 10);
n /= 10;
} while (n > 0);
if (n0 < 0)
*--p = '-';
return p;
}
#define PPBUFF_SIZE 1024
static const char *
passphrase_callback(struct archive *a, void *_client_data)
@@ -1523,7 +1513,7 @@ static void
passphrase_free(char *ppbuff)
{
if (ppbuff != NULL) {
memset(ppbuff, 0, PPBUFF_SIZE);
explicit_bzero(ppbuff, PPBUFF_SIZE);
free(ppbuff);
}
}
-1
View File
@@ -34,7 +34,6 @@ struct cpio {
int dot; /* -V */
int quiet; /* --quiet */
int extract_flags; /* Flags for extract operation */
const char *compress_program;
int option_append; /* -A, only relevant for -o */
int option_atime_restore; /* -a */
int option_follow_links; /* -L */
+8 -66
View File
@@ -45,7 +45,7 @@ static void
basic_cpio(const char *target,
const char *pack_options,
const char *unpack_options,
const char *se, const char *se2)
const char *se)
{
int r;
@@ -74,7 +74,7 @@ basic_cpio(const char *target,
/* Verify stderr. */
failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target);
assertTextFileContents(se2, "unpack.err");
assertTextFileContents(se, "unpack.err");
verify_files(pack_options);
@@ -112,7 +112,6 @@ DEFINE_TEST(test_basic)
{
FILE *filelist;
const char *msg;
char result[1024];
assertUmask(0);
@@ -120,85 +119,28 @@ DEFINE_TEST(test_basic)
* Create an assortment of files on disk.
*/
filelist = fopen("filelist", "w");
memset(result, 0, sizeof(result));
/* File with 10 bytes content. */
assertMakeFile("file", 0644, "1234567890");
fprintf(filelist, "file\n");
if (is_LargeInode("file")) {
strncat(result,
"bsdcpio: file: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result,
strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result,
"\n",
sizeof(result) - strlen(result) -1);
}
/* hardlink to above file. */
assertMakeHardlink("linkfile", "file");
fprintf(filelist, "linkfile\n");
if (is_LargeInode("linkfile")) {
strncat(result,
"bsdcpio: linkfile: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result,
strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result,
"\n",
sizeof(result) - strlen(result) -1);
}
/* Symlink to above file. */
if (canSymlink()) {
assertMakeSymlink("symlink", "file", 0);
fprintf(filelist, "symlink\n");
if (is_LargeInode("symlink")) {
strncat(result,
"bsdcpio: symlink: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result,
strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result,
"\n",
sizeof(result) - strlen(result) -1);
}
}
/* Another file with different permissions. */
assertMakeFile("file2", 0777, "1234567890");
fprintf(filelist, "file2\n");
if (is_LargeInode("file2")) {
strncat(result,
"bsdcpio: file2: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result,
strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result,
"\n",
sizeof(result) - strlen(result) -1);
}
/* Directory. */
assertMakeDir("dir", 0775);
fprintf(filelist, "dir\n");
if (is_LargeInode("dir")) {
strncat(result,
"bsdcpio: dir: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result,
strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result,
"\n",
sizeof(result) - strlen(result) -1);
}
strncat(result, "2 blocks\n", sizeof(result) - strlen(result) -1);
/* All done. */
fclose(filelist);
@@ -207,14 +149,14 @@ DEFINE_TEST(test_basic)
/* Archive/dearchive with a variety of options. */
msg = canSymlink() ? "2 blocks\n" : "1 block\n";
basic_cpio("copy", "", "", msg, msg);
basic_cpio("copy_odc", "--format=odc", "", msg, msg);
basic_cpio("copy_newc", "-H newc", "", result, "2 blocks\n");
basic_cpio("copy_cpio", "-H odc", "", msg, msg);
basic_cpio("copy", "", "", msg);
basic_cpio("copy_odc", "--format=odc", "", msg);
basic_cpio("copy_newc", "-H newc", "", "2 blocks\n");
basic_cpio("copy_cpio", "-H odc", "", msg);
msg = "1 block\n";
basic_cpio("copy_bin", "-H bin", "", msg, msg);
basic_cpio("copy_bin", "-H bin", "", msg);
msg = canSymlink() ? "9 blocks\n" : "8 blocks\n";
basic_cpio("copy_ustar", "-H ustar", "", msg, msg);
basic_cpio("copy_ustar", "-H ustar", "", msg);
/* Copy in one step using -p */
passthrough("passthrough");
+9 -1
View File
@@ -82,7 +82,15 @@ DEFINE_TEST(test_cmdline)
assert(0 != systemf("%s -p -o <empty >16.out 2>16.err", testprog));
assertEmptyFile("16.out");
failure("-p with empty input should fail");
failure("-p with missing directory should fail");
assert(0 != systemf("%s -p <empty >17.out 2>17.err", testprog));
assertEmptyFile("17.out");
failure("-p with more than one argument should fail");
assert(0 != systemf("%s -p out abc <empty >18.out 2>18.err", testprog));
assertEmptyFile("18.out");
failure("-o with arguments should fail");
assert(0 != systemf("%s -o abc <empty >19.out 2>19.err", testprog));
assertEmptyFile("19.out");
}
@@ -113,42 +113,6 @@ DEFINE_TEST(test_format_newc)
/* Setup result message. */
memset(result, 0, sizeof(result));
if (is_LargeInode("file1")) {
strncat(result,
"bsdcpio: file1: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result, strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result, "\n",
sizeof(result) - strlen(result) -1);
}
if (canSymlink() && is_LargeInode("symlink")) {
strncat(result,
"bsdcpio: symlink: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result, strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result, "\n",
sizeof(result) - strlen(result) -1);
}
if (is_LargeInode("dir")) {
strncat(result,
"bsdcpio: dir: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result, strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result, "\n",
sizeof(result) - strlen(result) -1);
}
if (is_LargeInode("hardlink")) {
strncat(result,
"bsdcpio: hardlink: large inode number truncated: ",
sizeof(result) - strlen(result) -1);
strncat(result, strerror(ERANGE),
sizeof(result) - strlen(result) -1);
strncat(result, "\n",
sizeof(result) - strlen(result) -1);
}
/* Record some facts about what we just created: */
now = time(NULL); /* They were all created w/in last two seconds. */
@@ -225,7 +189,7 @@ DEFINE_TEST(test_format_newc)
/* "symlink" pointing to "file1" */
assert(is_hex(e, 110));
assertEqualMem(e + 0, "070701", 6); /* Magic */
assert(is_hex(e + 6, 8)); /* ino */
assert(ino != from_hex(e + 6, 8)); /* ino */
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Mode: Group members bits and others bits do not work. */
assertEqualInt(0xa180, from_hex(e + 14, 8) & 0xffc0);
@@ -258,7 +222,7 @@ DEFINE_TEST(test_format_newc)
/* "dir" */
assert(is_hex(e, 110));
assertEqualMem(e + 0, "070701", 6); /* Magic */
assert(is_hex(e + 6, 8)); /* ino */
assert(ino != from_hex(e + 6, 8)); /* ino */
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Group members bits and others bits do not work. */
assertEqualInt(0x41c0, from_hex(e + 14, 8) & 0xffc0); /* Mode */
@@ -28,4 +28,11 @@ DEFINE_TEST(test_option_l)
/* Check that this is a link and not a copy. */
assertIsHardlink("f", "link/f");
/* A failed hard link must make pass mode fail. */
r = systemf("echo f | %s -pl missing/parent >invalid.out 2>invalid.err",
testprog);
assert(r != 0);
assertFileNotExists("missing/parent/f");
assertNonEmptyFile("invalid.err");
}
+6 -4
View File
@@ -34,7 +34,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3008009
#define ARCHIVE_VERSION_NUMBER 3008010
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
@@ -177,7 +177,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
#define ARCHIVE_VERSION_ONLY_STRING "3.8.9"
#define ARCHIVE_VERSION_ONLY_STRING "3.8.10"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
@@ -204,6 +204,7 @@ __LA_DECL const char * archive_liblzo2_version(void);
__LA_DECL const char * archive_libexpat_version(void);
__LA_DECL const char * archive_libbsdxml_version(void);
__LA_DECL const char * archive_libxml2_version(void);
__LA_DECL const char * archive_xmllite_version(void);
__LA_DECL const char * archive_mbedtls_version(void);
__LA_DECL const char * archive_nettle_version(void);
__LA_DECL const char * archive_openssl_version(void);
@@ -273,7 +274,8 @@ typedef la_int64_t archive_skip_callback(struct archive *,
/* Seeks to specified location in the file and returns the position.
* Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h.
* Return ARCHIVE_FATAL if the seek fails for any reason.
* Return ARCHIVE_FAILED if the seek failed in a way that keeps its
* current read position, ARCHIVE_FATAL for any other error reason.
*/
typedef la_int64_t archive_seek_callback(struct archive *,
void *_client_data, la_int64_t offset, int whence);
@@ -647,7 +649,7 @@ __LA_DECL la_int64_t archive_seek_data(struct archive *, la_int64_t, int);
* A zero-copy version of archive_read_data that also exposes the file offset
* of each returned block. Note that the client has no way to specify
* the desired size of the block. The API does guarantee that offsets will
* be strictly increasing and that returned blocks will not overlap.
* be increasing and that returned blocks will not overlap.
*/
__LA_DECL int archive_read_data_block(struct archive *a,
const void **buff, size_t *size, la_int64_t *offset);
@@ -19,6 +19,19 @@
#include <stddef.h>
#include <stdint.h>
// Rename functions for libarchive namespacing.
#define blake2s __archive_blake2s
#define blake2s_final __archive_blake2s_final
#define blake2s_init __archive_blake2s_init
#define blake2s_init_key __archive_blake2s_init_key
#define blake2s_init_param __archive_blake2s_init_param
#define blake2sp __archive_blake2sp
#define blake2sp_final __archive_blake2sp_final
#define blake2sp_init __archive_blake2sp_init
#define blake2sp_init_key __archive_blake2sp_init_key
#define blake2sp_update __archive_blake2sp_update
#define blake2s_update __archive_blake2s_update
#if defined(_MSC_VER)
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
#elif defined(__GNUC__)
@@ -83,6 +83,7 @@ state_name(unsigned s)
{
switch (s) {
case ARCHIVE_STATE_NEW: return ("new");
case ARCHIVE_STATE_OPEN: return ("open");
case ARCHIVE_STATE_HEADER: return ("header");
case ARCHIVE_STATE_DATA: return ("data");
case ARCHIVE_STATE_DATA_RECOVERY: return ("data_recovery");
@@ -0,0 +1,192 @@
/*-
* Copyright (c) 2009 Joerg Sonnenberger
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "archive_platform.h"
#include "archive_private.h"
#if defined(HAVE_ZLIB_H)
#include <zlib.h>
#endif
#if (defined(__aarch64__) || defined(_M_ARM64)) && \
defined(__ARM_FEATURE_CRC32) && !defined(__ARM_BIG_ENDIAN) && \
!defined(__AARCH64EB__)
/*
* Implementation 1: Hardware-accelerated CRC32 using ARMv8 ACLE instructions.
* Only use this when the compiler target guarantees CRC extension support.
* The extension is optional in ARMv8.0, so enabling it here without runtime
* detection would make generic AArch64 binaries unsafe on older CPUs.
*/
#if defined(_MSC_VER)
#include <arm64_acle.h>
#elif defined(__GNUC__) || defined(__clang__)
#include <arm_acle.h>
#endif
#include <stdint.h>
unsigned long
__archive_crc32(unsigned long crc, const void *_p, size_t len)
{
const unsigned char *p = (const unsigned char *)_p;
uint32_t c = (uint32_t)crc ^ 0xffffffffU;
if (p == NULL)
return (0);
/* Align to 8 bytes */
while (len > 0 && ((uintptr_t)p & 7)) {
c = __crc32b(c, *p++);
len--;
}
/* 8-way unrolled 64-bit loop */
while (len >= 64) {
c = __crc32d(c, *(const uint64_t *)p); p += 8;
c = __crc32d(c, *(const uint64_t *)p); p += 8;
c = __crc32d(c, *(const uint64_t *)p); p += 8;
c = __crc32d(c, *(const uint64_t *)p); p += 8;
c = __crc32d(c, *(const uint64_t *)p); p += 8;
c = __crc32d(c, *(const uint64_t *)p); p += 8;
c = __crc32d(c, *(const uint64_t *)p); p += 8;
c = __crc32d(c, *(const uint64_t *)p); p += 8;
len -= 64;
}
while (len >= 8) {
c = __crc32d(c, *(const uint64_t *)p);
p += 8;
len -= 8;
}
/* Trailing bytes */
while (len > 0) {
c = __crc32b(c, *p++);
len--;
}
return (c ^ 0xffffffffU);
}
#elif defined(HAVE_ZLIB_H)
/*
* Implementation 2: zlib crc32().
* zlib provides a highly-optimized CRC32 implementation across many platforms.
*/
unsigned long
__archive_crc32(unsigned long crc, const void *_p, size_t len)
{
if (_p == NULL)
return (0);
return crc32(crc, _p, (uInt)len);
}
#else
/*
* Implementation 3: Portable 256-entry table fallback.
* Used when neither hardware CRC32 nor zlib is available.
* Key feature: Reasonably fast and requires no platform-specific support.
*/
unsigned long
__archive_crc32(unsigned long crc, const void *_p, size_t len)
{
const unsigned char *p = (const unsigned char *)_p;
static const unsigned long crc_tbl[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d
};
if (_p == NULL)
return (0);
crc = crc ^ 0xffffffffUL;
for (;len >= 8; len -= 8) {
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
}
while (len--)
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
return (crc ^ 0xffffffffUL);
}
#endif
@@ -31,19 +31,6 @@
#include "archive.h"
#include "archive_cryptor_private.h"
/*
* On systems that do not support any recognized crypto libraries,
* this file will normally define no usable symbols.
*
* But some compilers and linkers choke on empty object files, so
* define a public symbol that will always exist. This could
* be removed someday if this file gains another always-present
* symbol definition.
*/
int __libarchive_cryptor_build_hack(void) {
return 0;
}
#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto
static int
@@ -57,7 +44,7 @@ pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
return 0;
}
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(ARCHIVE_CRYPTO_WIN)
#ifdef _MSC_VER
#pragma comment(lib, "Bcrypt.lib")
#endif
@@ -197,7 +184,7 @@ aes_ctr_release(archive_crypto_ctx *ctx)
return 0;
}
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(ARCHIVE_CRYPTO_WIN)
static int
aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
@@ -29,16 +29,6 @@
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
/*
* On systems that do not support any recognized crypto libraries,
* the archive_cryptor.c file will normally define no usable symbols.
*
* But some compilers and linkers choke on empty object files, so
* define a public symbol that will always exist. This could
* be removed someday if this file gains another always-present
* symbol definition.
*/
int __libarchive_cryptor_build_hack(void);
#ifdef __APPLE__
# include <AvailabilityMacros.h>
@@ -62,7 +52,7 @@ typedef struct {
size_t encr_pos;
} archive_crypto_ctx;
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(ARCHIVE_CRYPTO_WIN)
#include <bcrypt.h>
#define ARCHIVE_CRYPTOR_USE_CNG 1
+44 -20
View File
@@ -44,7 +44,7 @@
/*
* Message digest functions for Windows platform.
*/
#if defined(HAVE_BCRYPT_H)
#if defined(ARCHIVE_CRYPTO_WIN)
/*
* Initialize a Message digest.
@@ -97,7 +97,7 @@ win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
return (ARCHIVE_OK);
}
#endif /* defined(HAVE_BCRYPT_H) */
#endif /* defined(ARCHIVE_CRYPTO_WIN) */
/* MD5 implementations */
@@ -211,7 +211,7 @@ static int
__archive_md5init(archive_md5_ctx *ctx)
{
mbedtls_md5_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_md5_starts(ctx) == 0)
#else
if (mbedtls_md5_starts_ret(ctx) == 0)
@@ -225,7 +225,7 @@ static int
__archive_md5update(archive_md5_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_md5_update(ctx, indata, insize) == 0)
#else
if (mbedtls_md5_update_ret(ctx, indata, insize) == 0)
@@ -238,7 +238,7 @@ __archive_md5update(archive_md5_ctx *ctx, const void *indata,
static int
__archive_md5final(archive_md5_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_md5_finish(ctx, md) == 0) {
#else
if (mbedtls_md5_finish_ret(ctx, md) == 0) {
@@ -271,7 +271,11 @@ __archive_md5update(archive_md5_ctx *ctx, const void *indata,
static int
__archive_md5final(archive_md5_ctx *ctx, void *md)
{
#if NETTLE_VERSION_MAJOR < 4
md5_digest(ctx, MD5_DIGEST_SIZE, md);
#else
md5_digest(ctx, md);
#endif
return (ARCHIVE_OK);
}
@@ -394,7 +398,7 @@ static int
__archive_ripemd160init(archive_rmd160_ctx *ctx)
{
mbedtls_ripemd160_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_ripemd160_starts(ctx) == 0)
#else
if (mbedtls_ripemd160_starts_ret(ctx) == 0)
@@ -408,7 +412,7 @@ static int
__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_ripemd160_update(ctx, indata, insize) == 0)
#else
if (mbedtls_ripemd160_update_ret(ctx, indata, insize) == 0)
@@ -421,7 +425,7 @@ __archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
static int
__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_ripemd160_finish(ctx, md) == 0) {
#else
if (mbedtls_ripemd160_finish_ret(ctx, md) == 0) {
@@ -454,7 +458,11 @@ __archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
static int
__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
{
#if NETTLE_VERSION_MAJOR < 4
ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, md);
#else
ripemd160_digest(ctx, md);
#endif
return (ARCHIVE_OK);
}
@@ -618,7 +626,7 @@ static int
__archive_sha1init(archive_sha1_ctx *ctx)
{
mbedtls_sha1_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha1_starts(ctx) == 0)
#else
if (mbedtls_sha1_starts_ret(ctx) == 0)
@@ -632,7 +640,7 @@ static int
__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha1_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha1_update_ret(ctx, indata, insize) == 0)
@@ -645,7 +653,7 @@ __archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
static int
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha1_finish(ctx, md) == 0) {
#else
if (mbedtls_sha1_finish_ret(ctx, md) == 0) {
@@ -678,7 +686,11 @@ __archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
static int
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
{
#if NETTLE_VERSION_MAJOR < 4
sha1_digest(ctx, SHA1_DIGEST_SIZE, md);
#else
sha1_digest(ctx, md);
#endif
return (ARCHIVE_OK);
}
@@ -894,7 +906,7 @@ static int
__archive_sha256init(archive_sha256_ctx *ctx)
{
mbedtls_sha256_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha256_starts(ctx, 0) == 0)
#else
if (mbedtls_sha256_starts_ret(ctx, 0) == 0)
@@ -908,7 +920,7 @@ static int
__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha256_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha256_update_ret(ctx, indata, insize) == 0)
@@ -921,7 +933,7 @@ __archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
static int
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha256_finish(ctx, md) == 0) {
#else
if (mbedtls_sha256_finish_ret(ctx, md) == 0) {
@@ -954,7 +966,11 @@ __archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
static int
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
{
#if NETTLE_VERSION_MAJOR < 4
sha256_digest(ctx, SHA256_DIGEST_SIZE, md);
#else
sha256_digest(ctx, md);
#endif
return (ARCHIVE_OK);
}
@@ -1142,7 +1158,7 @@ static int
__archive_sha384init(archive_sha384_ctx *ctx)
{
mbedtls_sha512_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha512_starts(ctx, 1) == 0)
#else
if (mbedtls_sha512_starts_ret(ctx, 1) == 0)
@@ -1156,7 +1172,7 @@ static int
__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha512_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
@@ -1169,7 +1185,7 @@ __archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
static int
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha512_finish(ctx, md) == 0) {
#else
if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
@@ -1202,7 +1218,11 @@ __archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
static int
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
{
#if NETTLE_VERSION_MAJOR < 4
sha384_digest(ctx, SHA384_DIGEST_SIZE, md);
#else
sha384_digest(ctx, md);
#endif
return (ARCHIVE_OK);
}
@@ -1414,7 +1434,7 @@ static int
__archive_sha512init(archive_sha512_ctx *ctx)
{
mbedtls_sha512_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha512_starts(ctx, 0) == 0)
#else
if (mbedtls_sha512_starts_ret(ctx, 0) == 0)
@@ -1428,7 +1448,7 @@ static int
__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha512_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
@@ -1441,7 +1461,7 @@ __archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
static int
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
if (mbedtls_sha512_finish(ctx, md) == 0) {
#else
if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
@@ -1474,7 +1494,11 @@ __archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
static int
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
{
#if NETTLE_VERSION_MAJOR < 4
sha512_digest(ctx, SHA512_DIGEST_SIZE, md);
#else
sha512_digest(ctx, md);
#endif
return (ARCHIVE_OK);
}
@@ -135,6 +135,9 @@
#endif
/* Nettle crypto headers */
#if defined(HAVE_NETTLE_VERSION_H)
#include <nettle/version.h>
#endif
#if defined(ARCHIVE_CRYPTO_MD5_NETTLE)
#include <nettle/md5.h>
#endif
@@ -145,8 +148,19 @@
defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
#if NETTLE_VERSION_MAJOR < 4
#if defined(HAVE_NETTLE_SHA_H)
#include <nettle/sha.h>
#endif
#else
#if defined(HAVE_NETTLE_SHA1_H)
#include <nettle/sha1.h>
#endif
#if defined(HAVE_NETTLE_SHA2_H)
#include <nettle/sha2.h>
#endif
#endif
#endif
/* OpenSSL crypto headers */
#if defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
@@ -165,7 +179,6 @@
defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
#if defined(HAVE_BCRYPT_H)
#include <bcrypt.h>
#define ARCHIVE_CRYPTO_CNG 1
typedef struct {
@@ -174,7 +187,6 @@ typedef struct {
BCRYPT_HASH_HANDLE hHash;
} Digest_CTX;
#endif
#endif
/* typedefs */
#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
@@ -80,7 +80,7 @@ Allocate and return a blank
object.
.El
.Ss Function groups
Due to high number of functions, the accessor functions can be found in
Due to the high number of functions, the accessor functions can be found in
man pages grouped by the purpose.
.Bl -tag -width ".Xr archive_entry_perms 3"
.It Xr archive_entry_acl 3
+14 -23
View File
@@ -121,15 +121,6 @@ static const wchar_t *ae_wcstofflags(const wchar_t *stringp,
static const char *ae_strtofflags(const char *stringp, size_t length,
unsigned long *setp, unsigned long *clrp);
#ifndef HAVE_WCSCPY
static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
{
wchar_t *dest = s1;
while ((*s1 = *s2) != L'\0')
++s1, ++s2;
return dest;
}
#endif
#ifndef HAVE_WCSLEN
static size_t wcslen(const wchar_t *s)
{
@@ -469,7 +460,7 @@ archive_entry_gname_w(struct archive_entry *entry)
}
int
_archive_entry_gname_l(struct archive_entry *entry,
archive_entry_gname_l(struct archive_entry *entry,
const char **p, size_t *len, struct archive_string_conv *sc)
{
return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_gname, p, len, sc));
@@ -533,7 +524,7 @@ archive_entry_hardlink_is_set(struct archive_entry *entry)
}
int
_archive_entry_hardlink_l(struct archive_entry *entry,
archive_entry_hardlink_l(struct archive_entry *entry,
const char **p, size_t *len, struct archive_string_conv *sc)
{
if ((entry->ae_set & AE_SET_HARDLINK) == 0) {
@@ -643,7 +634,7 @@ archive_entry_pathname_w(struct archive_entry *entry)
}
int
_archive_entry_pathname_l(struct archive_entry *entry,
archive_entry_pathname_l(struct archive_entry *entry,
const char **p, size_t *len, struct archive_string_conv *sc)
{
return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_pathname, p, len, sc));
@@ -799,7 +790,7 @@ archive_entry_symlink_w(struct archive_entry *entry)
}
int
_archive_entry_symlink_l(struct archive_entry *entry,
archive_entry_symlink_l(struct archive_entry *entry,
const char **p, size_t *len, struct archive_string_conv *sc)
{
if ((entry->ae_set & AE_SET_SYMLINK) == 0) {
@@ -856,7 +847,7 @@ archive_entry_uname_w(struct archive_entry *entry)
}
int
_archive_entry_uname_l(struct archive_entry *entry,
archive_entry_uname_l(struct archive_entry *entry,
const char **p, size_t *len, struct archive_string_conv *sc)
{
return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_uname, p, len, sc));
@@ -974,7 +965,7 @@ archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name)
}
int
_archive_entry_copy_gname_l(struct archive_entry *entry,
archive_entry_copy_gname_l(struct archive_entry *entry,
const char *name, size_t len, struct archive_string_conv *sc)
{
return (archive_mstring_copy_mbs_len_l(&entry->ae_gname, name, len, sc));
@@ -1075,7 +1066,7 @@ archive_entry_update_hardlink_utf8(struct archive_entry *entry, const char *targ
}
int
_archive_entry_copy_hardlink_l(struct archive_entry *entry,
archive_entry_copy_hardlink_l(struct archive_entry *entry,
const char *target, size_t len, struct archive_string_conv *sc)
{
int r;
@@ -1225,7 +1216,7 @@ archive_entry_update_link_utf8(struct archive_entry *entry, const char *target)
}
int
_archive_entry_copy_link_l(struct archive_entry *entry,
archive_entry_copy_link_l(struct archive_entry *entry,
const char *target, size_t len, struct archive_string_conv *sc)
{
int r;
@@ -1306,7 +1297,7 @@ archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name
}
int
_archive_entry_copy_pathname_l(struct archive_entry *entry,
archive_entry_copy_pathname_l(struct archive_entry *entry,
const char *name, size_t len, struct archive_string_conv *sc)
{
return (archive_mstring_copy_mbs_len_l(&entry->ae_pathname,
@@ -1460,7 +1451,7 @@ archive_entry_update_symlink_utf8(struct archive_entry *entry, const char *linkn
}
int
_archive_entry_copy_symlink_l(struct archive_entry *entry,
archive_entry_copy_symlink_l(struct archive_entry *entry,
const char *linkname, size_t len, struct archive_string_conv *sc)
{
int r;
@@ -1544,7 +1535,7 @@ archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_enc
}
int
_archive_entry_copy_uname_l(struct archive_entry *entry,
archive_entry_copy_uname_l(struct archive_entry *entry,
const char *name, size_t len, struct archive_string_conv *sc)
{
return (archive_mstring_copy_mbs_len_l(&entry->ae_uname,
@@ -1748,7 +1739,7 @@ archive_entry_acl_to_text(struct archive_entry *entry, la_ssize_t *len,
}
char *
_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
int flags, struct archive_string_conv *sc)
{
return (archive_acl_to_text_l(&entry->acl, len, flags, sc));
@@ -1772,7 +1763,7 @@ archive_entry_acl_from_text(struct archive_entry *entry,
}
int
_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
int type, struct archive_string_conv *sc)
{
return (archive_acl_from_text_l(&entry->acl, text, type, sc));
@@ -1825,7 +1816,7 @@ archive_entry_acl_text(struct archive_entry *entry, int flags)
/* Deprecated */
int
_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
archive_entry_acl_text_l(struct archive_entry *entry, int flags,
const char **acl_text, size_t *len, struct archive_string_conv *sc)
{
free(entry->acl.acl_text);
@@ -28,7 +28,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
#define ARCHIVE_VERSION_NUMBER 3008009
#define ARCHIVE_VERSION_NUMBER 3008010
/*
* Note: archive_entry.h is for use outside of libarchive; the
@@ -161,11 +161,11 @@ Directories have an additional ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
which controls the initial access ACL for newly-created directory entries.
.Ss NFSv4 Access Control Lists
A NFSv4 ACL consists of multiple individual entries called Access Control
An NFSv4 ACL consists of multiple individual entries called Access Control
Entries (ACEs).
.Pp
There are four possible types of a NFSv4 ACE:
.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYE_ALLOW"
There are four possible types of an NFSv4 ACE:
.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_ALLOW"
.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALLOW
Allow principal to perform actions requiring given permissions.
.It Dv ARCHIVE_ENTRY_ACL_TYPE_DENY
@@ -338,13 +338,13 @@ character
are skipped.
.Pp
.Fn archive_entry_acl_next
return the next entry of the ACL list.
This functions may only be called after
returns the next entry of the ACL list.
This function may only be called after
.Fn archive_entry_acl_reset
has indicated the presence of extended ACL entries.
.Pp
.Fn archive_entry_acl_reset
prepare reading the list of ACL entries with
prepares reading the list of ACL entries with
.Fn archive_entry_acl_next .
The function returns 0 if no non-extended ACLs are found.
In this case, the access permissions should be obtained by
@@ -380,7 +380,7 @@ Output POSIX.1e default ACLs.
Prefix each default ACL entry with the word
.Dq default: .
.It Dv ARCHIVE_ENTRY_ACL_STYLE_SOLARIS
The mask and other ACLs don not contain a double colon.
The mask and other ACLs do not contain a double colon.
.El
.Pp
The following flags are effective only on NFSv4 ACL:
@@ -399,7 +399,7 @@ Separate ACL entries with comma instead of newline.
.El
.Pp
If the archive entry contains NFSv4 ACLs, all types of NFSv4 ACLs are returned.
It the entry contains POSIX.1e ACLs and none of the flags
If the entry contains POSIX.1e ACLs and none of the flags
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
or
.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
@@ -408,7 +408,7 @@ are prefixed with
.Dq default: .
.Pp
.Fn archive_entry_acl_types
get ACL entry types contained in an archive entry's ACL.
gets ACL entry types contained in an archive entry's ACL.
As POSIX.1e and NFSv4
ACL entries cannot be mixed, this function is a very efficient way to detect if
an ACL already contains POSIX.1e or NFSv4 ACL entries.
@@ -416,7 +416,7 @@ an ACL already contains POSIX.1e or NFSv4 ACL entries.
.Fn archive_entry_acl_count
and
.Fn archive_entry_acl_reset
returns the number of ACL entries that match the given type mask.
return the number of ACL entries that match the given type mask.
For POSIX.1e ACLS if the type mask includes
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
and at least one extended ACL entry exists, the three classic Unix
@@ -69,15 +69,15 @@ Store the body the last time an inode is seen (new cpio).
The
.Nm
functions help by providing a unified interface and handling the complexity
behind the scene.
behind the scenes.
.Pp
The
.Nm
functions assume that
.Vt archive_entry
instances have valid nlinks, inode and device values.
The inode and device value is used to match entries.
The nlinks value is used to determined if all references have been found and
The inode and device values are used to match entries.
The nlinks value is used to determine if all references have been found and
if the internal references can be recycled.
.Pp
The
@@ -100,7 +100,7 @@ The
function is the core of
.Nm .
The
.Fn entry
.Fa entry
argument points to the
.Vt archive_entry
that should be written.
@@ -44,47 +44,47 @@ struct archive_string_conv;
* Return -1 if the string conversion failed.
*/
#define archive_entry_gname_l _archive_entry_gname_l
int _archive_entry_gname_l(struct archive_entry *,
#define archive_entry_gname_l __archive_entry_gname_l
int archive_entry_gname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_hardlink_l _archive_entry_hardlink_l
int _archive_entry_hardlink_l(struct archive_entry *,
#define archive_entry_hardlink_l __archive_entry_hardlink_l
int archive_entry_hardlink_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_pathname_l _archive_entry_pathname_l
int _archive_entry_pathname_l(struct archive_entry *,
#define archive_entry_pathname_l __archive_entry_pathname_l
int archive_entry_pathname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_symlink_l _archive_entry_symlink_l
int _archive_entry_symlink_l(struct archive_entry *,
#define archive_entry_symlink_l __archive_entry_symlink_l
int archive_entry_symlink_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_uname_l _archive_entry_uname_l
int _archive_entry_uname_l(struct archive_entry *,
#define archive_entry_uname_l __archive_entry_uname_l
int archive_entry_uname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_acl_text_l _archive_entry_acl_text_l
int _archive_entry_acl_text_l(struct archive_entry *, int,
const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED;
#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l
char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int,
#define archive_entry_acl_text_l __archive_entry_acl_text_l
int archive_entry_acl_text_l(struct archive_entry *, int,
const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED;
#define archive_entry_acl_to_text_l __archive_entry_acl_to_text_l
char *archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int,
struct archive_string_conv *);
#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l
int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text,
#define archive_entry_acl_from_text_l __archive_entry_acl_from_text_l
int archive_entry_acl_from_text_l(struct archive_entry *, const char* text,
int type, struct archive_string_conv *);
#define archive_entry_copy_gname_l _archive_entry_copy_gname_l
int _archive_entry_copy_gname_l(struct archive_entry *,
#define archive_entry_copy_gname_l __archive_entry_copy_gname_l
int archive_entry_copy_gname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_hardlink_l _archive_entry_copy_hardlink_l
int _archive_entry_copy_hardlink_l(struct archive_entry *,
#define archive_entry_copy_hardlink_l __archive_entry_copy_hardlink_l
int archive_entry_copy_hardlink_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_link_l _archive_entry_copy_link_l
int _archive_entry_copy_link_l(struct archive_entry *,
#define archive_entry_copy_link_l __archive_entry_copy_link_l
int archive_entry_copy_link_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_pathname_l _archive_entry_copy_pathname_l
int _archive_entry_copy_pathname_l(struct archive_entry *,
#define archive_entry_copy_pathname_l __archive_entry_copy_pathname_l
int archive_entry_copy_pathname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_symlink_l _archive_entry_copy_symlink_l
int _archive_entry_copy_symlink_l(struct archive_entry *,
#define archive_entry_copy_symlink_l __archive_entry_copy_symlink_l
int archive_entry_copy_symlink_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_uname_l _archive_entry_copy_uname_l
int _archive_entry_copy_uname_l(struct archive_entry *,
#define archive_entry_copy_uname_l __archive_entry_copy_uname_l
int archive_entry_copy_uname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#endif /* !ARCHIVE_ENTRY_LOCALE_H_INCLUDED */
@@ -205,6 +205,6 @@ The platform types
.Vt uid_t
and
.Vt gid_t
are often 16 or 32 bit wide.
are often 16 or 32 bits wide.
In this case it is possible that the ids can not be correctly restored
from archives and get truncated.
@@ -251,18 +251,18 @@ is the preferred interface.
Block and character devices are characterised either using a device number
or a pair of major and minor number.
The combined device number can be obtained with
.Fn archive_device_rdev
.Fn archive_entry_rdev
and set with
.Fn archive_device_set_rdev .
.Fn archive_entry_set_rdev .
The major and minor numbers are accessed by
.Fn archive_device_rdevmajor ,
.Fn archive_device_rdevminor
.Fn archive_device_set_rdevmajor
.Fn archive_entry_rdevmajor ,
.Fn archive_entry_rdevminor
.Fn archive_entry_set_rdevmajor
and
.Fn archive_device_set_rdevminor .
.Fn archive_entry_set_rdevminor .
.Pp
The process of splitting the combined device number into major and
minor number and the reverse process of combing them differs between
minor number and the reverse process of combining them differs between
platforms.
Some archive formats use the combined form, while other formats use
the split form.
+1 -15
View File
@@ -31,20 +31,6 @@
#include "archive.h"
#include "archive_hmac_private.h"
/*
* On systems that do not support any recognized crypto libraries,
* the archive_hmac.c file is expected to define no usable symbols.
*
* But some compilers and linkers choke on empty object files, so
* define a public symbol that will always exist. This could
* be removed someday if this file gains another always-present
* symbol definition.
*/
int __libarchive_hmac_build_hack(void) {
return 0;
}
#ifdef ARCHIVE_HMAC_USE_Apple_CommonCrypto
static int
@@ -74,7 +60,7 @@ __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
memset(ctx, 0, sizeof(*ctx));
}
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(ARCHIVE_CRYPTO_WIN)
#ifndef BCRYPT_HASH_REUSABLE_FLAG
# define BCRYPT_HASH_REUSABLE_FLAG 0x00000020
@@ -29,16 +29,6 @@
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
/*
* On systems that do not support any recognized crypto libraries,
* the archive_hmac.c file is expected to define no usable symbols.
*
* But some compilers and linkers choke on empty object files, so
* define a public symbol that will always exist. This could
* be removed someday if this file gains another always-present
* symbol definition.
*/
int __libarchive_hmac_build_hack(void);
#ifdef __APPLE__
# include <AvailabilityMacros.h>
@@ -52,7 +42,7 @@ int __libarchive_hmac_build_hack(void);
typedef CCHmacContext archive_hmac_sha1_ctx;
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(ARCHIVE_CRYPTO_WIN)
#include <bcrypt.h>
typedef struct {
@@ -269,6 +269,7 @@ archive_match_free(struct archive *_a)
free(a->inclusion_gids.ids);
match_list_free(&(a->inclusion_unames));
match_list_free(&(a->inclusion_gnames));
archive_string_free(&a->archive.error_string);
free(a);
return (ARCHIVE_OK);
}
@@ -1172,8 +1173,8 @@ set_timefilter_find_data(struct archive_match *a, int timetype,
time_t ctime_sec, mtime_sec;
uint32_t ctime_ns, mtime_ns;
ntfs_to_unix(FILETIME_to_ntfs(ftLastWriteTime), &mtime_sec, &mtime_ns);
ntfs_to_unix(FILETIME_to_ntfs(ftCreationTime), &ctime_sec, &ctime_ns);
__archive_ntfs_to_unix(__archive_FILETIME_to_ntfs(ftLastWriteTime), &mtime_sec, &mtime_ns);
__archive_ntfs_to_unix(__archive_FILETIME_to_ntfs(ftCreationTime), &ctime_sec, &ctime_ns);
return set_timefilter(a, timetype,
mtime_sec, mtime_ns, ctime_sec, ctime_ns);
}
@@ -101,8 +101,7 @@ static const char tooManyFields[] = "too many fields for format";
#define apd_makedev(maj, min) makedev((maj), (min))
#endif
/* exported */
dev_t
static dev_t
pack_native(int n, unsigned long numbers[], const char **error)
{
dev_t dev = 0;
@@ -317,7 +316,7 @@ compare_format(const void *key, const void *element)
pack_t *
pack_find(const char *name)
__archive_pack_find(const char *name)
{
const struct format *format;
@@ -36,8 +36,7 @@
typedef dev_t pack_t(int, unsigned long [], const char **);
pack_t *pack_find(const char *);
pack_t pack_native;
pack_t *__archive_pack_find(const char *);
#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))
#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \
@@ -72,23 +72,25 @@
* Generally checked via `__archive_check_magic()`.
*/
/* Newly created archive object, not yet opened */
#define ARCHIVE_STATE_NEW 1U
/* Newly created archive object, not yet opened. */
#define ARCHIVE_STATE_NEW 0x01U
/* Archive is opened. */
#define ARCHIVE_STATE_OPEN 0x02U
/* Archive is ready to read a header. */
#define ARCHIVE_STATE_HEADER 2U
#define ARCHIVE_STATE_HEADER 0x04U
/* A header has been read: client can ask for data
* or they can ask for the next header and
* we'll automatically skip the remaining data. */
#define ARCHIVE_STATE_DATA 4U
#define ARCHIVE_STATE_DATA 0x08U
/* Similar to STATE_DATA but after a FAILED header:
* the client may not read data, but they may ask
* for the next header and we'll recover. */
#define ARCHIVE_STATE_DATA_RECOVERY 8U
#define ARCHIVE_STATE_DATA_RECOVERY 0x10U
/* End-of-archive has been reached. Client can only
* close or free the archive. */
#define ARCHIVE_STATE_EOF 0x10U
#define ARCHIVE_STATE_EOF 0x20U
/* Archive is closed; client is only allowed to free the archive. */
#define ARCHIVE_STATE_CLOSED 0x20U
#define ARCHIVE_STATE_CLOSED 0x40U
/* Archive is in a FATAL error state: a close request
* is permitted but ignored. */
#define ARCHIVE_STATE_FATAL 0x8000U
@@ -206,4 +208,6 @@ void __archive_reset_read_data(struct archive *);
# define ARCHIVE_LITERAL_ULL(x) x##ull
#endif
unsigned long __archive_crc32(unsigned long crc, const void *p, size_t len);
#endif
@@ -83,12 +83,16 @@ archive_random(void *buf, size_t nbytes)
BCRYPT_ALG_HANDLE hAlg;
status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
if (!BCRYPT_SUCCESS(status))
if (!BCRYPT_SUCCESS(status)) {
la_dosmaperr(GetLastError());
return ARCHIVE_FAILED;
}
status = BCryptGenRandom(hAlg, buf, (ULONG)nbytes, 0);
BCryptCloseAlgorithmProvider(hAlg, 0);
if (!BCRYPT_SUCCESS(status))
if (!BCRYPT_SUCCESS(status)) {
la_dosmaperr(GetLastError());
return ARCHIVE_FAILED;
}
return ARCHIVE_OK;
#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
+5 -5
View File
@@ -152,7 +152,7 @@ __archive_rb_tree_find_node_leq(struct archive_rb_tree *rbt, const void *key)
return last;
}
int
__archive_rb_tree_insert_node(struct archive_rb_tree *rbt,
struct archive_rb_node *self)
@@ -218,7 +218,7 @@ __archive_rb_tree_insert_node(struct archive_rb_tree *rbt,
return T;
}
/*
* Swap the location and colors of 'self' and its child @ which. The child
* can not be a sentinel node. This is our rotation function. However,
@@ -268,7 +268,7 @@ __archive_rb_tree_reparent_nodes(
}
}
static void
__archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt,
struct archive_rb_node *self)
@@ -343,7 +343,7 @@ __archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt,
*/
RB_MARK_BLACK(rbt->rbt_root);
}
static void
__archive_rb_tree_prune_node(struct archive_rb_tree *rbt,
struct archive_rb_node *self, int rebalance)
@@ -363,7 +363,7 @@ __archive_rb_tree_prune_node(struct archive_rb_tree *rbt,
if (rebalance)
__archive_rb_tree_removal_rebalance(rbt, father, which);
}
/*
* When deleting an interior node
*/
+1 -1
View File
@@ -170,7 +170,7 @@ list_archive(const char *name)
struct archive *a;
struct archive_entry *entry;
mydata = malloc(sizeof(struct mydata));
mydata = malloc(sizeof(*mydata));
a = archive_read_new();
mydata->name = name;
archive_read_support_filter_all(a);
+269 -234
View File
@@ -58,6 +58,7 @@
#define minimum(a, b) (a < b ? a : b)
static int bid_format(struct archive_read *, int);
static int choose_filters(struct archive_read *);
static int choose_format(struct archive_read *);
static int close_filters(struct archive_read *);
@@ -175,100 +176,6 @@ archive_read_open2(struct archive *a, void *client_data,
return archive_read_open1(a);
}
static ssize_t
client_read_proxy(struct archive_read_filter *f, const void **buff)
{
ssize_t r;
r = (f->archive->client.reader)(&f->archive->archive,
f->data, buff);
return (r);
}
static int64_t
client_skip_proxy(struct archive_read_filter *f, int64_t request)
{
if (request < 0)
__archive_errx(1, "Negative skip requested");
if (request == 0)
return 0;
if (f->archive->client.skipper != NULL) {
int64_t total = 0;
for (;;) {
int64_t get, ask = request;
get = (f->archive->client.skipper)
(&f->archive->archive, f->data, ask);
total += get;
if (get == 0 || get == request)
return (total);
if (get > request)
return ARCHIVE_FATAL;
request -= get;
}
} else if (f->archive->client.seeker != NULL
&& request > 64 * 1024) {
/* If the client provided a seeker but not a skipper,
* we can use the seeker to skip forward.
*
* Note: This isn't always a good idea. The client
* skipper is allowed to skip by less than requested
* if it needs to maintain block alignment. The
* seeker is not allowed to play such games, so using
* the seeker here may be a performance loss compared
* to just reading and discarding. That's why we
* only do this for skips of over 64k.
*/
int64_t before = f->position;
int64_t after = (f->archive->client.seeker)
(&f->archive->archive, f->data, request, SEEK_CUR);
if (after != before + request)
return ARCHIVE_FATAL;
return after - before;
}
return 0;
}
static int64_t
client_seek_proxy(struct archive_read_filter *f, int64_t offset, int whence)
{
/* DO NOT use the skipper here! If we transparently handled
* forward seek here by using the skipper, that will break
* other libarchive code that assumes a successful forward
* seek means it can also seek backwards.
*/
if (f->archive->client.seeker == NULL) {
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
"Current client reader does not support seeking a device");
return (ARCHIVE_FAILED);
}
return (f->archive->client.seeker)(&f->archive->archive,
f->data, offset, whence);
}
static int
read_client_close_proxy(struct archive_read *a)
{
int r = ARCHIVE_OK, r2;
unsigned int i;
if (a->client.closer == NULL)
return (r);
for (i = 0; i < a->client.nodes; i++)
{
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 *f)
{
return read_client_close_proxy(f->archive);
}
static int
client_switch_proxy(struct archive_read_filter *f, unsigned int iindex)
{
@@ -276,8 +183,6 @@ client_switch_proxy(struct archive_read_filter *f, unsigned int iindex)
int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
void *data2;
while (f->upstream != NULL)
f = f->upstream;
a = f->archive;
/* Don't do anything if already in the specified data node */
@@ -303,9 +208,76 @@ client_switch_proxy(struct archive_read_filter *f, unsigned int iindex)
r2 = (a->client.opener)
((struct archive *)a, f->data);
}
f->client_total = f->client_avail = 0;
return (r1 < r2) ? r1 : r2;
}
/*
* Reads data from client.
*
* Automatically switches clients if end of file of a client is reached.
* This simplifies handling of multi volume archives for readers.
*/
static ssize_t
client_read_proxy(struct archive_read_filter *f, const void **buff)
{
ssize_t bytes_read = 0;
for (;;) {
bytes_read = (f->archive->client.reader)(&f->archive->archive,
f->data, buff);
if (bytes_read == 0) {
unsigned int cursor = f->archive->client.cursor;
/* Continue with next client object if available. */
if (cursor != f->archive->client.nodes - 1 &&
client_switch_proxy(f, cursor + 1) == ARCHIVE_OK)
continue;
}
break;
}
return (bytes_read);
}
static int64_t
client_skip_proxy(struct archive_read_filter *f, int64_t request)
{
return (f->archive->client.skipper)(&f->archive->archive,
f->data, request);
}
static int64_t
client_seek_proxy(struct archive_read_filter *f, int64_t offset, int whence)
{
/* DO NOT use the skipper here! If we transparently handled
* forward seek here by using the skipper, that will break
* other libarchive code that assumes a successful forward
* seek means it can also seek backwards.
*/
return (f->archive->client.seeker)(&f->archive->archive,
f->data, offset, whence);
}
static int
client_close_proxy(struct archive_read_filter *f)
{
struct archive_read *a = f->archive;
int r = ARCHIVE_OK, r2;
unsigned int i;
if (a->client.closer == NULL)
return (r);
for (i = 0; i < a->client.nodes; i++)
{
r2 = (a->client.closer)
((struct archive *)a, a->client.dataset[i].data);
if (r > r2)
r = r2;
}
return (r);
}
int
archive_read_set_open_callback(struct archive *_a,
archive_open_callback *client_opener)
@@ -496,19 +468,13 @@ archive_read_open1(struct archive *_a)
return (ARCHIVE_FATAL);
}
/* Open data source. */
if (a->client.opener != NULL) {
e = (a->client.opener)(&a->archive, a->client.dataset[0].data);
if (e != 0) {
/* If the open failed, call the closer to clean up. */
read_client_close_proxy(a);
return (e);
}
}
a->archive.state = ARCHIVE_STATE_OPEN;
f = calloc(1, sizeof(*f));
if (f == NULL)
if (f == NULL) {
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
f->bidder = NULL;
f->upstream = NULL;
f->archive = a;
@@ -516,8 +482,20 @@ archive_read_open1(struct archive *_a)
f->vtable = &none_reader_vtable;
f->name = "none";
f->code = ARCHIVE_FILTER_NONE;
f->can_skip = 1;
f->can_seek = 1;
f->can_skip = a->client.skipper != NULL;
f->can_seek = a->client.seeker != NULL;
/* Open data source. */
if (a->client.opener != NULL) {
e = (a->client.opener)(&a->archive, a->client.dataset[0].data);
if (e != ARCHIVE_OK) {
/* If the open failed, call the closer to clean up. */
client_close_proxy(f);
free(f);
a->archive.state = ARCHIVE_STATE_FATAL;
return (e);
}
}
a->client.dataset[0].begin_position = 0;
if (!a->filter || !a->bypass_filter_bidding)
@@ -549,11 +527,22 @@ archive_read_open1(struct archive *_a)
}
a->format = &(a->formats[slot]);
}
else if (a->format->bid != NULL)
{
if (bid_format(a, -1) < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Registered format does not match");
close_filters(a);
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
}
a->archive.state = ARCHIVE_STATE_HEADER;
/* Ensure libarchive starts from the first node in a multivolume set */
client_switch_proxy(a->filter, 0);
client_switch_proxy(f, 0);
return (e);
}
@@ -714,7 +703,6 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
__archive_reset_read_data(&a->archive);
a->data_start_node = a->client.cursor;
/* EOF always wins; otherwise return the worst error. */
return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
}
@@ -730,6 +718,21 @@ _archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
return ret;
}
static int
bid_format(struct archive_read *a, int best_bid)
{
int bid;
bid = (a->format->bid)(a, best_bid);
if (bid == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (a->filter->position != 0 &&
__archive_read_seek(a, 0, SEEK_SET) < 0)
return (ARCHIVE_FATAL);
return (bid);
}
/*
* Allow each registered format to bid on whether it wants to handle
* the next entry. Return index of winning bidder.
@@ -750,11 +753,9 @@ choose_format(struct archive_read *a)
a->format = &(a->formats[0]);
for (i = 0; i < slots; i++, a->format++) {
if (a->format->bid) {
bid = (a->format->bid)(a, best_bid);
bid = bid_format(a, best_bid);
if (bid == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (a->filter->position != 0)
__archive_read_seek(a, 0, SEEK_SET);
if ((bid > best_bid) || (best_bid_slot < 0)) {
best_bid = bid;
best_bid_slot = i;
@@ -1290,7 +1291,6 @@ __archive_read_register_format(struct archive_read *a,
int
__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;
@@ -1307,7 +1307,6 @@ __archive_read_register_bidder(struct archive_read *a,
memset(a->bidders + i, 0, sizeof(a->bidders[0]));
bidder = (a->bidders + i);
bidder->data = bidder_data;
bidder->name = name;
bidder->vtable = vtable;
if (bidder->vtable->bid == NULL || bidder->vtable->init == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
@@ -1358,6 +1357,38 @@ __archive_read_register_bidder(struct archive_read *a,
* code that has uncertain look-ahead needs.
*/
/*
* Reads data into client buffer.
*
* In case of error or end of file, filter flags are set.
* Client buffer related fields are updated.
*/
static ssize_t
read_client_data(struct archive_read_filter *f)
{
ssize_t bytes_read;
if (f->end_of_file)
return (0);
bytes_read = (f->vtable->read)(f, &f->client_buff);
if (bytes_read < 0) {
f->client_total = f->client_avail = 0;
f->client_next = f->client_buff = NULL;
f->fatal = 1;
} else if (bytes_read == 0) {
f->client_total = f->client_avail = 0;
f->client_next = f->client_buff = NULL;
f->end_of_file = 1;
} else {
f->client_total = bytes_read;
f->client_avail = f->client_total;
f->client_next = f->client_buff;
}
return (bytes_read);
}
/*
* Looks ahead in the input stream:
* * If 'avail' pointer is provided, that returns number of bytes available
@@ -1383,34 +1414,24 @@ __archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
const void *
__archive_read_filter_ahead(struct archive_read_filter *f,
size_t min, ssize_t *avail)
size_t request, ssize_t *avail)
{
ssize_t bytes_read;
size_t tocopy;
size_t min, tocopy;
if (f->fatal) {
if (avail)
*avail = ARCHIVE_FATAL;
return (NULL);
}
/* request == 0 is perfectly well-defined.*/
min = request == 0 ? 1 : request;
/*
* Keep pulling more data until we can satisfy the request.
*/
for (;;) {
/*
* If we can satisfy from the copy buffer (and the
* copy buffer isn't empty), we're done. In particular,
* note that min == 0 is a perfectly well-defined
* request.
*/
if (f->avail >= min && f->avail > 0) {
if (avail != NULL)
*avail = f->avail;
return (f->next);
}
/*
* We can satisfy directly from client buffer if everything
* currently in the copy buffer is still in the client buffer.
@@ -1429,55 +1450,36 @@ __archive_read_filter_ahead(struct archive_read_filter *f,
return (f->client_next);
}
/* Move data forward in copy buffer if necessary. */
if (f->next > f->buffer &&
min > f->buffer_size - (f->next - f->buffer)) {
if (f->avail > 0)
memmove(f->buffer, f->next,
f->avail);
f->next = f->buffer;
/* If we can satisfy from the copy buffer, we're done. */
if (f->avail >= min) {
if (avail != NULL)
*avail = f->avail;
return (f->next);
}
/* If we've used up the client data, get more. */
if (f->client_avail <= 0) {
if (f->end_of_file) {
if (avail != NULL)
*avail = f->avail;
return (NULL);
}
bytes_read = (f->vtable->read)(f,
&f->client_buff);
if (bytes_read < 0) { /* Read error. */
f->client_total = f->client_avail = 0;
f->client_next =
f->client_buff = NULL;
f->fatal = 1;
bytes_read = read_client_data(f);
if (bytes_read < 0) {
/* Read error. */
if (avail != NULL)
*avail = ARCHIVE_FATAL;
return (NULL);
}
if (bytes_read == 0) {
/* Check for another client object first */
if (f->archive->client.cursor !=
f->archive->client.nodes - 1) {
if (client_switch_proxy(f,
f->archive->client.cursor + 1)
== ARCHIVE_OK)
continue;
}
/* Premature end-of-file. */
f->client_total = f->client_avail = 0;
f->client_next =
f->client_buff = NULL;
f->end_of_file = 1;
/* Return whatever we do have. */
static const char *empty = "";
const char *eof;
/* Premature end-of-file.
* Return whatever we do have. */
if (avail != NULL)
*avail = f->avail;
return (NULL);
if (request == 0)
eof = f->avail == 0 ? empty : f->next;
else
eof = NULL;
return (eof);
}
f->client_total = bytes_read;
f->client_avail = f->client_total;
f->client_next = f->client_buff;
} else {
/*
* We can't satisfy the request from the copy
@@ -1523,19 +1525,23 @@ __archive_read_filter_ahead(struct archive_read_filter *f,
}
/* Move data into newly-enlarged buffer. */
if (f->avail > 0)
memmove(p, f->next, f->avail);
memcpy(p, f->next, f->avail);
free(f->buffer);
f->next = f->buffer = p;
f->buffer_size = s;
} else if (f->next > f->buffer &&
min > f->buffer_size - (f->next - f->buffer)) {
/* Move data forward in copy buffer
* if necessary. */
if (f->avail > 0)
memmove(f->buffer, f->next,
f->avail);
f->next = f->buffer;
}
/* We can add client data to copy buffer. */
/* First estimate: copy to fill rest of buffer. */
tocopy = (f->buffer + f->buffer_size)
- (f->next + f->avail);
/* Don't waste time buffering more than we need to. */
if (tocopy + f->avail > min)
tocopy = min - f->avail;
tocopy = min - f->avail;
/* Don't copy more than is available. */
if (tocopy > f->client_avail)
tocopy = f->client_avail;
@@ -1593,16 +1599,14 @@ __archive_read_filter_consume(struct archive_read_filter *f,
static int64_t
advance_file_pointer(struct archive_read_filter *f, int64_t request)
{
int64_t bytes_skipped, total_bytes_skipped = 0;
ssize_t bytes_read;
size_t min;
int64_t total_bytes_skipped = 0;
if (f->fatal)
return (-1);
/* Use up the copy buffer first. */
if (f->avail > 0) {
min = (size_t)minimum(request, (int64_t)f->avail);
size_t min = (size_t)minimum(request, (int64_t)f->avail);
f->next += min;
f->avail -= min;
request -= min;
@@ -1612,7 +1616,7 @@ advance_file_pointer(struct archive_read_filter *f, int64_t request)
/* Then use up the client buffer. */
if (f->client_avail > 0) {
min = (size_t)minimum(request, (int64_t)f->client_avail);
size_t min = (size_t)minimum(request, (int64_t)f->client_avail);
f->client_next += min;
f->client_avail -= min;
request -= min;
@@ -1624,12 +1628,41 @@ advance_file_pointer(struct archive_read_filter *f, int64_t request)
/* If there's an optimized skip function, use it. */
if (f->can_skip != 0) {
bytes_skipped = client_skip_proxy(f, request);
if (bytes_skipped < 0) { /* error */
f->fatal = 1;
return (bytes_skipped);
while (request > 0) {
int64_t get = client_skip_proxy(f, request);
if (get < 0 || get > request) {
f->fatal = 1;
return (ARCHIVE_FATAL);
}
if (get == 0)
break;
f->position += get;
total_bytes_skipped += get;
request -= get;
}
f->position += bytes_skipped;
if (request == 0)
return (total_bytes_skipped);
} else if (f->can_seek != 0 && request > 64 * 1024) {
/* If the client provided a seeker but not a skipper,
* we can use the seeker to skip forward.
*
* Note: This isn't always a good idea. The client
* skipper is allowed to skip by less than requested
* if it needs to maintain block alignment. The
* seeker is not allowed to play such games, so using
* the seeker here may be a performance loss compared
* to just reading and discarding. That's why we
* only do this for skips of over 64k.
*/
int64_t bytes_skipped;
int64_t before = f->position;
int64_t after = __archive_read_filter_seek(f,
request, SEEK_CUR);
if (after != before + request) {
f->fatal = 1;
return (ARCHIVE_FATAL);
}
bytes_skipped = after - before;
total_bytes_skipped += bytes_skipped;
request -= bytes_skipped;
if (request == 0)
@@ -1638,31 +1671,16 @@ advance_file_pointer(struct archive_read_filter *f, int64_t request)
/* Use ordinary reads as necessary to complete the request. */
for (;;) {
bytes_read = (f->vtable->read)(f, &f->client_buff);
if (bytes_read < 0) {
f->client_buff = NULL;
f->fatal = 1;
ssize_t bytes_read = read_client_data(f);
if (bytes_read < 0)
return (bytes_read);
}
if (bytes_read == 0) {
if (f->archive->client.cursor !=
f->archive->client.nodes - 1) {
if (client_switch_proxy(f,
f->archive->client.cursor + 1)
== ARCHIVE_OK)
continue;
}
f->client_buff = NULL;
f->end_of_file = 1;
if (bytes_read == 0)
return (total_bytes_skipped);
}
if (bytes_read >= request) {
f->client_next =
((const char *)f->client_buff) + request;
f->client_avail = (size_t)(bytes_read - request);
f->client_total = bytes_read;
f->client_next += request;
f->client_avail -= request;
total_bytes_skipped += request;
f->position += request;
return (total_bytes_skipped);
@@ -1689,7 +1707,8 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
{
struct archive_read_client *client;
int64_t r;
unsigned int cursor;
unsigned int cursor, old_cursor;
int sought = 0;
if (f->closed || f->fatal)
return (ARCHIVE_FATAL);
@@ -1697,6 +1716,8 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
return (ARCHIVE_FAILED);
client = &(f->archive->client);
old_cursor = client->cursor;
switch (whence) {
case SEEK_CUR:
/* Adjust the offset and use SEEK_SET instead */
@@ -1709,7 +1730,7 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
if (client->dataset[cursor].begin_position < 0 ||
client->dataset[cursor].total_size < 0 ||
client->dataset[cursor].begin_position +
client->dataset[cursor].total_size - 1 > offset ||
client->dataset[cursor].total_size > offset ||
cursor + 1 >= client->nodes)
break;
r = client->dataset[cursor].begin_position +
@@ -1719,12 +1740,13 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
while (1) {
r = client_switch_proxy(f, cursor);
if (r != ARCHIVE_OK)
return r;
goto clear_buffer;
if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
return r;
goto clear_buffer;
sought = 1;
client->dataset[cursor].total_size = r;
if (client->dataset[cursor].begin_position +
client->dataset[cursor].total_size - 1 > offset ||
client->dataset[cursor].total_size > offset ||
cursor + 1 >= client->nodes)
break;
r = client->dataset[cursor].begin_position +
@@ -1733,10 +1755,13 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
}
offset -= client->dataset[cursor].begin_position;
if (offset < 0
|| offset > client->dataset[cursor].total_size)
return ARCHIVE_FATAL;
|| offset > client->dataset[cursor].total_size) {
r = ARCHIVE_FATAL;
goto clear_buffer;
}
if ((r = client_seek_proxy(f, offset, SEEK_SET)) < 0)
return r;
goto clear_buffer;
sought = 1;
break;
case SEEK_END:
@@ -1753,9 +1778,10 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
while (1) {
r = client_switch_proxy(f, cursor);
if (r != ARCHIVE_OK)
return r;
goto clear_buffer;
if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
return r;
goto clear_buffer;
sought = 1;
client->dataset[cursor].total_size = r;
r = client->dataset[cursor].begin_position +
client->dataset[cursor].total_size;
@@ -1776,10 +1802,11 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
}
offset = (r + offset) - client->dataset[cursor].begin_position;
if ((r = client_switch_proxy(f, cursor)) != ARCHIVE_OK)
return r;
goto clear_buffer;
r = client_seek_proxy(f, offset, SEEK_SET);
if (r < ARCHIVE_OK)
return r;
goto clear_buffer;
sought = 1;
break;
default:
@@ -1787,28 +1814,36 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
}
r += client->dataset[cursor].begin_position;
clear_buffer:
if (r == ARCHIVE_FAILED && !sought && old_cursor == client->cursor) {
/* Seek failed without moving position: keep buffer */
return (r);
}
/*
* Ouch. Clearing the buffer like this hurts, especially
* at bid time. A lot of our efficiency at bid time comes
* from having bidders reuse the data we've already read.
*
* TODO: If the seek request is in data we already
* have, then don't call the seek callback.
*
* TODO: Zip seeks to end-of-file at bid time. If
* other formats also start doing this, we may need to
* find a way for clients to fudge the seek offset to
* a block boundary.
*
* Hmmm... If whence was SEEK_END, we know the file
* size is (r - offset). Can we use that to simplify
* the TODO items above?
*/
f->avail = f->client_avail = 0;
f->next = f->buffer;
if (r >= 0) {
/*
* Ouch. Clearing the buffer like this hurts, especially
* at bid time. A lot of our efficiency at bid time comes
* from having bidders reuse the data we've already read.
*
* TODO: If the seek request is in data we already
* have, then don't call the seek callback.
*
* TODO: Zip seeks to end-of-file at bid time. If
* other formats also start doing this, we may need to
* find a way for clients to fudge the seek offset to
* a block boundary.
*
* Hmmm... If whence was SEEK_END, we know the file
* size is (r - offset). Can we use that to simplify
* the TODO items above?
*/
f->avail = f->client_avail = 0;
f->next = f->buffer;
f->position = r;
f->end_of_file = 0;
}
} else
f->fatal = 1;
return r;
}
@@ -47,7 +47,7 @@ Streaming Archive Library (libarchive, -larchive)
.Sh DESCRIPTION
.Bl -tag -width indent
.It Fn archive_read_add_passphrase
Register passphrases for reading an encryption archive.
Register passphrases for reading an encrypted archive.
If
.Ar passphrase
is
@@ -59,7 +59,7 @@ Otherwise,
.Cm ARCHIVE_OK
will be returned.
.It Fn archive_read_set_passphrase_callback
Register a callback function that will be invoked to get a passphrase
Register a callback function that will be invoked to get a passphrase
for decryption after trying all the passphrases registered by the
.Fn archive_read_add_passphrase
function failed.
@@ -33,14 +33,25 @@
#include "archive_private.h"
#include "archive_read_private.h"
static struct archive_read_filter_bidder *
get_last_bidder(struct archive_read *a)
{
size_t i;
for (i = 0; i < sizeof(a->bidders) / sizeof(a->bidders[0]); i++)
{
if (a->bidders[i].vtable == NULL)
break;
}
return a->bidders + (i - 1);
}
int
archive_read_append_filter(struct archive *_a, int code)
{
int r1, r2, number_bidders, i;
const char *str;
struct archive_read_filter_bidder *b;
struct archive_read_filter *f;
struct archive_read *a = (struct archive_read *)_a;
int r1, r2;
r2 = (ARCHIVE_OK);
switch (code)
@@ -53,15 +64,12 @@ archive_read_append_filter(struct archive *_a, int code)
r1 = (ARCHIVE_OK);
break;
case ARCHIVE_FILTER_GZIP:
str = "gzip";
r1 = archive_read_support_filter_gzip(_a);
break;
case ARCHIVE_FILTER_BZIP2:
str = "bzip2";
r1 = archive_read_support_filter_bzip2(_a);
break;
case ARCHIVE_FILTER_COMPRESS:
str = "compress (.Z)";
r1 = archive_read_support_filter_compress(_a);
break;
case ARCHIVE_FILTER_PROGRAM:
@@ -69,43 +77,33 @@ archive_read_append_filter(struct archive *_a, int code)
"Cannot append program filter using archive_read_append_filter");
return (ARCHIVE_FATAL);
case ARCHIVE_FILTER_LZMA:
str = "lzma";
r1 = archive_read_support_filter_lzma(_a);
break;
case ARCHIVE_FILTER_XZ:
str = "xz";
r1 = archive_read_support_filter_xz(_a);
break;
case ARCHIVE_FILTER_UU:
str = "uu";
r1 = archive_read_support_filter_uu(_a);
break;
case ARCHIVE_FILTER_RPM:
str = "rpm";
r1 = archive_read_support_filter_rpm(_a);
break;
case ARCHIVE_FILTER_LZ4:
str = "lz4";
r1 = archive_read_support_filter_lz4(_a);
break;
case ARCHIVE_FILTER_ZSTD:
str = "zstd";
r1 = archive_read_support_filter_zstd(_a);
break;
case ARCHIVE_FILTER_LZIP:
str = "lzip";
r1 = archive_read_support_filter_lzip(_a);
break;
case ARCHIVE_FILTER_LZOP:
str = "lzop";
r1 = archive_read_support_filter_lzop(_a);
break;
case ARCHIVE_FILTER_LRZIP:
str = "lrzip";
r1 = archive_read_support_filter_lrzip(_a);
break;
case ARCHIVE_FILTER_GRZIP:
str = "grzip";
r1 = archive_read_support_filter_grzip(_a);
break;
default:
@@ -114,22 +112,10 @@ archive_read_append_filter(struct archive *_a, int code)
return (ARCHIVE_FATAL);
}
if (code != ARCHIVE_FILTER_NONE)
if (r1 > ARCHIVE_FATAL && code != ARCHIVE_FILTER_NONE)
{
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
b = a->bidders;
for (i = 1; i < number_bidders; i++, b++)
{
if (!b->name || !strcmp(b->name, str))
break;
}
if (!b->name || strcmp(b->name, str))
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: Unable to append filter");
return (ARCHIVE_FATAL);
}
struct archive_read_filter_bidder *b;
struct archive_read_filter *f;
f = calloc(1, sizeof(*f));
if (f == NULL)
@@ -137,6 +123,7 @@ archive_read_append_filter(struct archive *_a, int code)
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
b = get_last_bidder(a);
f->bidder = b;
f->archive = a;
f->upstream = a->filter;
@@ -162,37 +149,22 @@ int
archive_read_append_filter_program_signature(struct archive *_a,
const char *cmd, const void *signature, size_t signature_len)
{
int r, number_bidders, i;
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *b;
struct archive_read_filter *f;
struct archive_read *a = (struct archive_read *)_a;
int r;
if (archive_read_support_filter_program_signature(_a, cmd, signature,
signature_len) != (ARCHIVE_OK))
return (ARCHIVE_FATAL);
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
b = a->bidders;
for (i = 0; i < number_bidders; i++, b++)
{
/* Program bidder name set to filter name after initialization */
if (b->data && !b->name)
break;
}
if (!b->data)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: Unable to append program filter");
return (ARCHIVE_FATAL);
}
f = calloc(1, sizeof(*f));
if (f == NULL)
{
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
b = get_last_bidder(a);
f->bidder = b;
f->archive = a;
f->upstream = a->filter;
@@ -202,7 +174,6 @@ archive_read_append_filter_program_signature(struct archive *_a,
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
b->name = a->filter->name;
a->bypass_filter_bidding = 1;
return r;
@@ -70,6 +70,21 @@ will not overlap.
Note that the blocks returned from this function can be much larger
than the block size read from disk, due to compression
and internal buffer optimizations.
All three of
.Fa buff ,
.Fa len
and
.Fa offset
are written whenever the function returns
.Cm ARCHIVE_OK
or
.Cm ARCHIVE_EOF .
At the end of an entry
.Fa len
is zero and
.Fa offset
is the end of the entry's data, which is how a trailing sparse hole is
reported.
.It Fn archive_read_data_skip
A convenience function that repeatedly calls
.Fn archive_read_data_block
@@ -96,7 +96,7 @@ archive_read_data_into_fd(struct archive *a, int fd)
size_t size, bytes_to_write;
ssize_t bytes_written;
int64_t fd_offset;
int64_t target_offset;
int64_t target_offset = 0;
int64_t actual_offset = 0;
int64_t declared_size;
int can_lseek;
@@ -56,7 +56,7 @@ Streaming Archive Library (libarchive, -larchive)
.Ft int
.Fn archive_read_disk_open "struct archive *" "const char *"
.Ft int
.Fn archive_read_disk_open_w "struct archive *" "const wchar_t *"
.Fn archive_read_disk_open_w "struct archive *" "const wchar_t *"
.Ft int
.Fn archive_read_disk_set_behavior "struct archive *" "int"
.Ft int
@@ -109,7 +109,7 @@ Streaming Archive Library (libarchive, -larchive)
.Fa "void (*excluded_func)(struct archive *, void *, struct archive entry *)"
.Fa "void *"
.Fc
.Ft int
.Ft int
.Fo archive_read_disk_set_metadata_filter_callback
.Fa "struct archive *"
.Fa "int (*metadata_filter_func)(struct archive *, void*, struct archive_entry *)"
@@ -191,15 +191,19 @@ By default, sparse file information is read from disk.
This sets the mode used for handling symbolic links.
The
.Dq logical
mode follows all symbolic links.
mode follows all symbolic links, except that a symbolic link whose
target is an ancestor directory of the link is archived as a symbolic
link rather than being followed, to avoid loops.
The
.Dq physical
mode does not follow any symbolic links.
The
.Dq hybrid
mode currently behaves identically to the
.Dq logical
mode.
mode follows symbolic links specified as the target of
.Fn archive_read_disk_open
or
.Fn archive_read_disk_open_w
but does not follow symbolic links anywhere else.
.It Xo
.Fn archive_read_disk_gname ,
.Fn archive_read_disk_uname
@@ -267,13 +271,13 @@ 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
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
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
@@ -294,7 +298,7 @@ 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 receives the
.Tn struct archive
object, void* custom filter data, and the
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
@@ -316,12 +320,12 @@ file_to_archive(struct archive *a, const char *name)
struct archive_entry *entry;
int fd;
fd = open(name, O_RDONLY);
if (fd < 0)
return;
ard = archive_read_disk_new();
archive_read_disk_set_standard_lookup(ard);
entry = archive_entry_new();
fd = open(name, O_RDONLY);
if (fd < 0)
return;
archive_entry_copy_pathname(entry, name);
archive_read_disk_entry_from_file(ard, entry, fd, NULL);
archive_write_header(a, entry);
@@ -97,9 +97,6 @@
#include "archive_private.h"
#include "archive_read_disk_private.h"
#ifndef HAVE_FCHDIR
#error fchdir function required.
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -114,6 +111,18 @@
#define HAVE_DIRFD
#endif
#ifndef HAVE_FCHDIR
/*
* Stub function for platforms that do not support fchdir. This is OK on
* platforms with newer *at functions as fchdir isn't used there (e.g. WASI).
*/
static int fchdir(int fd)
{
errno = ENOSYS;
return -1;
}
#endif
/*-
* This is a new directory-walking system that addresses a number
* of problems I've had with fts(3). In particular, it has no
@@ -47,11 +47,11 @@
#include "archive.h"
#include "archive_integer.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
#if defined(_WIN32) && !defined(__CYGWIN__) || defined(__wasi__)
int
archive_read_disk_set_standard_lookup(struct archive *a)
{
archive_set_error(a, -1, "Standard lookups not available on Windows");
archive_set_error(a, -1, "Standard lookups not available on this platform");
return (ARCHIVE_FATAL);
}
#else /* ! (_WIN32 && !__CYGWIN__) */
@@ -312,4 +312,4 @@ lookup_gname_helper(struct name_cache *cache, id_t id)
}
#endif
#endif /* ! (_WIN32 && !__CYGWIN__) */
#endif /* ! (_WIN32 && !__CYGWIN__ || __wasi__) */
@@ -59,7 +59,7 @@ than 2013.
.It Fn archive_read_free
Invokes
.Fn archive_read_close
if it was not invoked manually, then release all resources.
if it was not invoked manually, then releases all resources.
Note: In libarchive 1.x, this function was declared to return
.Ft void ,
which made it impossible to detect certain errors when
@@ -166,7 +166,7 @@ The callback functions must match the following prototypes:
.El
.Pp
The open callback is invoked by
.Fn archive_open .
.Fn archive_read_open .
It should return
.Cm ARCHIVE_OK
if the underlying file or data source is successfully
@@ -210,7 +210,7 @@ performance gains when reading uncompressed
archives from slow disk drives or other media
that can skip quickly.
.Pp
The close callback is invoked by archive_close when
The close callback is invoked by archive_read_close when
the archive processing is complete.
The callback should return
.Cm ARCHIVE_OK
@@ -109,8 +109,11 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
archive_read_set_seek_callback(a, file_seek);
archive_read_set_close_callback(a, file_close);
r = archive_read_set_callback_data(a, mine);
if (r < 0)
if (r < 0) {
free(mine->buffer);
free(mine);
return (r);
}
return (archive_read_open1(a));
}
@@ -106,8 +106,11 @@ archive_read_open_FILE(struct archive *a, FILE *f)
archive_read_set_seek_callback(a, FILE_seek);
archive_read_set_close_callback(a, FILE_close);
r = archive_read_set_callback_data(a, mine);
if (r < 0)
if (r < 0) {
free(mine->buffer);
free(mine);
return (r);
}
return (archive_read_open1(a));
}
@@ -84,8 +84,10 @@ archive_read_open_memory2(struct archive *a, const void *buff,
archive_read_set_skip_callback(a, memory_read_skip);
archive_read_set_close_callback(a, memory_read_close);
r = archive_read_set_callback_data(a, mine);
if (r < 0)
if (r < 0) {
free(mine);
return (r);
}
return (archive_read_open1(a));
}
@@ -149,29 +151,27 @@ static int64_t
memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence)
{
struct read_memory_data *mine = (struct read_memory_data *)client_data;
const unsigned char *p;
(void)a; /* UNUSED */
switch (whence) {
case SEEK_SET:
mine->p = mine->start + offset;
p = mine->start + offset;
break;
case SEEK_CUR:
mine->p += offset;
p = mine->p + offset;
break;
case SEEK_END:
mine->p = mine->end + offset;
p = mine->end + offset;
break;
default:
return ARCHIVE_FATAL;
}
if (mine->p < mine->start) {
mine->p = mine->start;
return ARCHIVE_FAILED;
}
if (mine->p > mine->end) {
mine->p = mine->end;
if (p < mine->start)
return ARCHIVE_FAILED;
}
if (p > mine->end)
return ARCHIVE_FAILED;
mine->p = p;
return (mine->p - mine->start);
}
@@ -68,8 +68,6 @@ struct archive_read_filter_bidder_vtable {
struct archive_read_filter_bidder {
/* Configuration data for the bidder. */
void *data;
/* Name of the filter */
const char *name;
const struct archive_read_filter_bidder_vtable *vtable;
};
@@ -189,10 +187,6 @@ struct archive_read {
*/
int64_t entry_bytes_declared;
/* Nodes and offsets of compressed data block */
unsigned int data_start_node;
unsigned int data_end_node;
/*
* Format detection is mostly the same as compression
* detection, with one significant difference: The bidders
@@ -250,7 +244,6 @@ int __archive_read_register_format(struct archive_read *a,
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 *);
@@ -134,7 +134,7 @@ If either function returns
.Cm ARCHIVE_FATAL
will be returned
immediately.
Otherwise, greater of the two values will be returned.
Otherwise, the greater of the two values will be returned.
.\"
.It Xo
.Fn archive_read_set_options
@@ -91,7 +91,7 @@ archive_read_support_filter_bzip2(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "bzip2",
if (__archive_read_register_bidder(a, NULL,
&bzip2_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -160,7 +160,7 @@ archive_read_support_filter_compress(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
return __archive_read_register_bidder(a, NULL, "compress (.Z)",
return __archive_read_register_bidder(a, NULL,
&compress_bidder_vtable);
}
@@ -62,7 +62,7 @@ archive_read_support_filter_grzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "grzip",
if (__archive_read_register_bidder(a, NULL,
&grzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -96,7 +96,7 @@ archive_read_support_filter_gzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "gzip",
if (__archive_read_register_bidder(a, NULL,
&gzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -344,7 +344,7 @@ consume_header(struct archive_read_filter *f)
__archive_read_filter_consume(f->upstream, len);
/* Initialize CRC accumulator. */
gzip->crc = crc32(0L, NULL, 0);
gzip->crc = __archive_crc32(0L, NULL, 0);
/* Initialize compression library. */
gzip->stream.next_in = (unsigned char *)(uintptr_t)
@@ -416,8 +416,12 @@ consume_trailer(struct archive_read_filter *f)
/* GZip trailer is a fixed 8 byte structure. */
p = __archive_read_filter_ahead(f->upstream, 8, NULL);
if (p == NULL)
if (p == NULL) {
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Truncated gzip input");
return (ARCHIVE_FATAL);
}
/* XXX TODO: Verify the length and CRC. */
@@ -61,7 +61,7 @@ archive_read_support_filter_lrzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "lrzip",
if (__archive_read_register_bidder(a, NULL,
&lrzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -79,14 +79,12 @@ lrzip_bidder_bid(struct archive_read_filter_bidder *b,
struct archive_read_filter *f)
{
const unsigned char *p;
ssize_t len;
int i;
(void)b; /* UNUSED */
/* Start by looking at the first six bytes of the header, which
* is all fixed layout. */
len = 6;
p = __archive_read_filter_ahead(f, len, NULL);
p = __archive_read_filter_ahead(f, 6, NULL);
if (p == NULL)
return (0);
@@ -101,7 +99,7 @@ lrzip_bidder_bid(struct archive_read_filter_bidder *b,
if ((i < 6) || (i > 10))
return 0;
return (int)len;
return (48);
}
static int
@@ -73,7 +73,6 @@ struct lz4 {
int block_maximum_size;
} flags;
int64_t stream_size;
uint32_t dict_id;
char *out_block;
size_t out_block_size;
@@ -82,7 +81,6 @@ struct lz4 {
size_t decoded_size;
void *xxh32_state;
char valid; /* True = decompressor is initialized */
char eof; /* True = found end of compressed data. */
};
@@ -118,7 +116,7 @@ archive_read_support_filter_lz4(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "lz4",
if (__archive_read_register_bidder(a, NULL,
&lz4_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -180,6 +178,7 @@ lz4_reader_bid(struct archive_read_filter_bidder *b,
uint32_t frame_data_size;
/* Skip over the magic number */
bits_checked += 28;
offset_in_buffer += 4;
/* Ensure that we can read another 4 bytes. */
@@ -205,13 +204,11 @@ lz4_reader_bid(struct archive_read_filter_bidder *b,
* if this is LZ4 data.
*/
if (archive_ckd_add_size(&min,
offset_in_buffer, min_lz4_frame_size))
offset_in_buffer, min_lz4_frame_size) ||
min > max_lookahead)
return (0);
/* TODO: should this be >= ? */
if (min > (size_t)avail) {
if (min > max_lookahead)
return (0);
buffer = __archive_read_filter_ahead(f,
min, &avail);
if (buffer == NULL)
@@ -226,7 +223,6 @@ lz4_reader_bid(struct archive_read_filter_bidder *b,
* follows, or this isn't LZ4 data.
*/
bits_checked = offset_in_buffer;
buffer = buffer + offset_in_buffer;
if (magic_number == LZ4_MAGICNUMBER) {
@@ -109,7 +109,7 @@ archive_read_support_filter_lzop(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "lzop",
if (__archive_read_register_bidder(a, NULL,
&lzop_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -274,7 +274,7 @@ consume_header(struct archive_read_filter *f)
if (p == NULL)
goto truncated;
if (flags & CRC32_HEADER)
checksum = crc32(crc32(0, NULL, 0), p, len);
checksum = __archive_crc32(__archive_crc32(0, NULL, 0), p, len);
else
checksum = adler32(adler32(0, NULL, 0), p, len);
#ifndef DONT_FAIL_ON_CRC_ERROR
@@ -414,7 +414,7 @@ lzop_filter_read(struct archive_read_filter *f, const void **p)
return (ARCHIVE_FATAL);
}
if (lzop->flags & CRC32_COMPRESSED)
cksum = crc32(crc32(0, NULL, 0), b, lzop->compressed_size);
cksum = __archive_crc32(__archive_crc32(0, NULL, 0), b, lzop->compressed_size);
else if (lzop->flags & ADLER32_COMPRESSED)
cksum = adler32(adler32(0, NULL, 0), b, lzop->compressed_size);
else
@@ -459,7 +459,7 @@ lzop_filter_read(struct archive_read_filter *f, const void **p)
}
if (lzop->flags & CRC32_UNCOMPRESSED)
cksum = crc32(crc32(0, NULL, 0), lzop->out_block,
cksum = __archive_crc32(__archive_crc32(0, NULL, 0), lzop->out_block,
lzop->uncompressed_size);
else if (lzop->flags & ADLER32_UNCOMPRESSED)
cksum = adler32(adler32(0, NULL, 0), lzop->out_block,
@@ -81,6 +81,8 @@ archive_read_support_filter_program(struct archive *a, const char *cmd)
return (archive_read_support_filter_program_signature(a, cmd, NULL, 0));
}
#ifdef HAVE_WAITPID
/*
* The bidder object stores the command and the signature to watch for.
* The 'inhibit' entry here is used to ensure that unchecked filters never
@@ -149,6 +151,11 @@ archive_read_support_filter_program_signature(struct archive *_a,
archive_strcat(&state->description, cmd);
if (signature != NULL && signature_len > 0) {
if (signature_len > (size_t)INT_MAX / 8) {
free_state(state);
archive_set_error(_a, EINVAL, "Signature too large");
return (ARCHIVE_FATAL);
}
state->signature_len = signature_len;
state->signature = malloc(signature_len);
if (state->signature == NULL)
@@ -156,7 +163,7 @@ archive_read_support_filter_program_signature(struct archive *_a,
memcpy(state->signature, signature, signature_len);
}
if (__archive_read_register_bidder(a, state, NULL,
if (__archive_read_register_bidder(a, state,
&program_bidder_vtable) != ARCHIVE_OK) {
free_state(state);
return (ARCHIVE_FATAL);
@@ -257,7 +264,7 @@ child_stop(struct archive_read_filter *f, struct program *program)
return (ARCHIVE_WARN);
}
#if !defined(_WIN32) || defined(__CYGWIN__)
#ifdef WIFSIGNALED
if (WIFSIGNALED(program->exit_status)) {
#ifdef SIGPIPE
/* If the child died because we stopped reading before
@@ -274,7 +281,7 @@ child_stop(struct archive_read_filter *f, struct program *program)
WTERMSIG(program->exit_status));
return (ARCHIVE_WARN);
}
#endif /* !_WIN32 || __CYGWIN__ */
#endif /* WIFSIGNALED */
if (WIFEXITED(program->exit_status)) {
if (WEXITSTATUS(program->exit_status) == 0)
@@ -495,3 +502,26 @@ program_filter_close(struct archive_read_filter *f)
return (e);
}
#else
int
archive_read_support_filter_program_signature(struct archive *a,
const char *cmd, const void *signature, size_t signature_len)
{
(void)cmd; /* UNUSED */
(void)signature; /* UNUSED */
(void)signature_len; /* UNUSED */
archive_set_error(a, ENOSYS, "Processes not supported");
return (ARCHIVE_FATAL);
}
int
__archive_read_program(struct archive_read_filter *f, const char *cmd)
{
(void)f; /* UNUSED */
(void)cmd; /* UNUSED */
return (ARCHIVE_FATAL);
}
#endif
@@ -71,7 +71,7 @@ archive_read_support_filter_rpm(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
return __archive_read_register_bidder(a, NULL, "rpm",
return __archive_read_register_bidder(a, NULL,
&rpm_bidder_vtable);
}
@@ -37,18 +37,14 @@
#include "archive.h"
#include "archive_entry.h"
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
/* Maximum lookahead during bid phase */
#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
#define MAX_LINE_LENGTH 128*1024 /* in bytes */
struct uu {
int64_t total;
unsigned char *in_buff;
#define IN_BUFF_SIZE (1024)
ssize_t in_cnt;
size_t in_allocated;
unsigned char *out_buff;
#define OUT_BUFF_SIZE (64 * 1024)
int state;
@@ -92,29 +88,10 @@ archive_read_support_filter_uu(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
return __archive_read_register_bidder(a, NULL, "uu",
return __archive_read_register_bidder(a, NULL,
&uudecode_bidder_vtable);
}
static const unsigned char ascii[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\n', 0, 0, '\r', 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
};
static const unsigned char uuchar[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
@@ -172,143 +149,157 @@ static const int base64num[128] = {
49, 50, 51, 0, 0, 0, 0, 0, /* 70 - 7F */
};
static ssize_t
get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
/*
* Read the next line from upstream beginning at given offset. No more than
* MAX_LINE_LENGTH bytes will be read into stream. Bytes won't be consumed.
* The length of the line excluding the newline is stored in len.
*
* If parsed is non-zero, only already available bytes are considered.
* This option is supposed to be used with a 0 offset.
*
* Amount of unconsumed bytes, including newline character(s), or up to
* MAX_LINE_LENGTH if no newline was found, is stored in unconsumed.
*
* If a line is found, pointer to beginning of line is returned.
*/
static const unsigned char *
read_line_ahead(struct archive_read_filter *f, ssize_t parsed,
size_t offset, size_t *len, ssize_t *unconsumed)
{
ssize_t len;
/* Read approximately two new lines each iteration. */
size_t step = 160;
const unsigned char *line;
ssize_t avail;
size_t request, start;
len = 0;
while (len < avail) {
switch (ascii[*b]) {
case 0: /* Non-ascii character or control character. */
if (nlsize != NULL)
*nlsize = 0;
return (-1);
case '\r':
if (avail-len > 1 && b[1] == '\n') {
if (nlsize != NULL)
*nlsize = 2;
return (len+2);
start = offset;
line = NULL;
*len = 0;
*unconsumed = 0;
request = offset == 0 ? 1 : offset + step;
do {
size_t remaining, nl = 1;
const unsigned char *b, *p;
/* Read bytes from upstream filter. */
b = __archive_read_filter_ahead(f, request, &avail);
if (avail > MAX_LINE_LENGTH)
avail = MAX_LINE_LENGTH;
*unconsumed = avail;
if (b == NULL) {
if (avail > 0 && (size_t)avail > offset)
b = __archive_read_filter_ahead(f, avail,
&avail);
if (b == NULL)
break;
}
remaining = avail - offset;
/* Locate end of line (\r, \n, \r\n). */
p = memchr(b + offset, '\n', remaining);
if (p == NULL) {
p = memchr(b + offset, '\r', remaining);
if (p == b + avail - 1 && step > 1) {
/* Is it \r or \r\n, missing one byte? */
p = NULL;
step = 1;
}
/* FALL THROUGH */
case '\n':
if (nlsize != NULL)
*nlsize = 1;
return (len+1);
case 1:
b++;
len++;
break;
} else if (p > b + start && p[-1] == '\r') {
/* "\r\n" takes two bytes. */
nl++;
--p;
}
}
if (nlsize != NULL)
*nlsize = 0;
return (avail);
}
static ssize_t
bid_get_line(struct archive_read_filter *f,
const unsigned char **b, ssize_t *avail, ssize_t *ravail,
ssize_t *nl, size_t* nbytes_read)
{
ssize_t len;
int quit;
quit = 0;
if (*avail == 0) {
*nl = 0;
len = 0;
} else
len = get_line(*b, *avail, nl);
/*
* Read more bytes while it does not reach the end of line.
*/
while (*nl == 0 && len == *avail && !quit &&
*nbytes_read < UUENCODE_BID_MAX_READ) {
ssize_t diff = *ravail - *avail;
size_t nbytes_req = (*ravail+1023) & ~1023U;
ssize_t tested;
/* Increase reading bytes if it is not enough for at least
* two new lines. */
if (nbytes_req < (size_t)*ravail + 160)
nbytes_req <<= 1;
*b = __archive_read_filter_ahead(f, nbytes_req, avail);
if (*b == NULL) {
if (*ravail >= *avail)
return (0);
/* Reading bytes reaches the end of a stream. */
*b = __archive_read_filter_ahead(f, *avail, avail);
quit = 1;
/* Return line or prepare to read more bytes. */
if (p != NULL) {
line = b + start;
*len = p - line;
*unconsumed = *len + nl;
} else {
/* Keep offset for check of possibly missing \n in \r\n. */
if (step != 1)
offset = avail;
if (archive_ckd_add_size(&request, avail, step))
break;
if (request > MAX_LINE_LENGTH)
request = MAX_LINE_LENGTH;
}
*nbytes_read = *avail;
*ravail = *avail;
*b += diff;
*avail -= diff;
tested = len;/* Skip some bytes we already determined. */
len = get_line(*b + tested, *avail - tested, nl);
if (len >= 0)
len += tested;
}
return (len);
} while (line == NULL && avail < MAX_LINE_LENGTH && !parsed);
return line;
}
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
/*
* Parses the header line of a uuencoded file, "begin <mode> <name>", or of
* a base64 encoded file, "begin-base64 <mode> <name>". The mode is a
* sequence of at least three octal digits: encoders don't all write the same
* number of them, for example 644, 0644 or 4755 for the same kind of file.
*
* Returns the length of the "begin " or "begin-base64 " prefix, or 0 if the
* line is not a header. Stores the permission bits of the mode in *mode and
* the offset of the name in *name_offset, unless they are NULL.
*/
static size_t
parse_header(const unsigned char *p, size_t len, mode_t *mode,
size_t *name_offset)
{
size_t i, l;
mode_t m;
if (len >= 6 && memcmp(p, "begin ", 6) == 0)
l = 6;
else if (len >= 13 && memcmp(p, "begin-base64 ", 13) == 0)
l = 13;
else
return (0);
m = 0;
for (i = l; i < len && p[i] >= '0' && p[i] <= '7'; i++)
m = ((m << 3) | (p[i] - '0')) & 0777;
/*
* Need at least three digits, as too lenient a check would have
* the bidder take other kinds of data for a header. Then a space and
* a one character name.
*/
if (i - l < 3 || i + 1 >= len || p[i] != ' ')
return (0);
if (mode != NULL)
*mode = m;
if (name_offset != NULL)
*name_offset = i + 1;
return (l);
}
static int
uudecode_bidder_bid(struct archive_read_filter_bidder *b,
struct archive_read_filter *f)
{
const unsigned char *p;
ssize_t avail, ravail;
ssize_t len, nl;
int l;
size_t l;
int firstline;
size_t nbytes_read;
size_t len, offset;
ssize_t unconsumed;
(void)b; /* UNUSED */
p = __archive_read_filter_ahead(f, 1, &avail);
if (p == NULL)
return (0);
offset = 0;
firstline = 20;
ravail = avail;
nbytes_read = avail;
for (;;) {
len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read);
if (len < 0 || nl == 0)
p = read_line_ahead(f, 0, offset, &len, &unconsumed);
if (p == NULL)
return (0); /* No match found. */
if (len - nl >= 11 && memcmp(p, "begin ", 6) == 0)
l = 6;
else if (len -nl >= 18 && memcmp(p, "begin-base64 ", 13) == 0)
l = 13;
else
l = 0;
offset += unconsumed;
if (l > 0 && (p[l] < '0' || p[l] > '7' ||
p[l+1] < '0' || p[l+1] > '7' ||
p[l+2] < '0' || p[l+2] > '7' || p[l+3] != ' '))
l = 0;
p += len;
avail -= len;
if (l)
l = parse_header(p, len, NULL, NULL);
if (l != 0)
break;
firstline = 0;
/* Do not read more than UUENCODE_BID_MAX_READ bytes */
if (nbytes_read >= UUENCODE_BID_MAX_READ)
return (0);
}
if (!avail)
return (0);
len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read);
if (len < 0 || nl == 0)
return (0);/* There are non-ascii characters. */
avail -= len;
p = read_line_ahead(f, 0, offset, &len, &unconsumed);
if (p == NULL)
return (0); /* No match found. */
if (l == 6) {
/* "begin " */
@@ -316,10 +307,13 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *b,
return (0);
/* Get a length of decoded bytes. */
l = UUDECODE(*p++); len--;
if (l == 0)
/* empty encoded file */
return (firstline+30);
if (l > 45)
/* Normally, maximum length is 45(character 'M'). */
return (0);
if (l > len - nl)
if (l > len)
return (0); /* Line too short. */
while (l) {
if (!uuchar[*p++])
@@ -327,30 +321,27 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *b,
--len;
--l;
}
if (len-nl == 1 &&
if (len == 1 &&
(uuchar[*p] || /* Check sum. */
(*p >= 'a' && *p <= 'z'))) {/* Padding data(MINIX). */
++p;
--len;
}
p += nl;
if (avail && uuchar[*p])
offset += unconsumed;
p = read_line_ahead(f, 0, offset, &len, &unconsumed);
if (p != NULL && uuchar[*p])
return (firstline+30);
} else if (l == 13) {
/* "begin-base64 " */
while (len-nl > 0) {
while (len > 0) {
if (!base64[*p++])
return (0);
--len;
len--;
}
p += nl;
if (avail >= 5 && memcmp(p, "====\n", 5) == 0)
return (firstline+40);
if (avail >= 6 && memcmp(p, "====\r\n", 6) == 0)
return (firstline+40);
if (avail > 0 && base64[*p])
if (len == 0)
return (firstline+30);
if (len == 4 && memcmp(p, "====", 4) == 0)
return (firstline+40);
}
return (0);
@@ -366,29 +357,23 @@ uudecode_reader_vtable = {
static int
uudecode_bidder_init(struct archive_read_filter *f)
{
struct uu *uu;
struct uu *uu;
void *out_buff;
void *in_buff;
f->code = ARCHIVE_FILTER_UU;
f->name = "uu";
uu = calloc(1, sizeof(*uu));
out_buff = malloc(OUT_BUFF_SIZE);
in_buff = malloc(IN_BUFF_SIZE);
if (uu == NULL || out_buff == NULL || in_buff == NULL) {
if (uu == NULL || out_buff == NULL) {
archive_set_error(&f->archive->archive, ENOMEM,
"Can't allocate data for uudecode");
free(uu);
free(out_buff);
free(in_buff);
return (ARCHIVE_FATAL);
}
f->data = uu;
uu->in_buff = in_buff;
uu->in_cnt = 0;
uu->in_allocated = IN_BUFF_SIZE;
uu->out_buff = out_buff;
uu->state = ST_FIND_HEAD;
uu->mode_set = 0;
@@ -398,45 +383,6 @@ uudecode_bidder_init(struct archive_read_filter *f)
return (ARCHIVE_OK);
}
static int
ensure_in_buff_size(struct archive_read_filter *f,
struct uu *uu, size_t size)
{
if (size > uu->in_allocated) {
unsigned char *ptr;
size_t newsize;
/*
* Calculate a new buffer size for in_buff.
* Increase its value until it is enough for our needs.
*/
newsize = uu->in_allocated;
do {
if (newsize < IN_BUFF_SIZE*32)
newsize <<= 1;
else
newsize += IN_BUFF_SIZE;
} while (size > newsize);
/* Allocate the new buffer. */
ptr = malloc(newsize);
if (ptr == NULL) {
archive_set_error(&f->archive->archive,
ENOMEM,
"Can't allocate data for uudecode");
return (ARCHIVE_FATAL);
}
/* Move the remaining data in in_buff into the new buffer. */
if (uu->in_cnt)
memmove(ptr, uu->in_buff, uu->in_cnt);
/* Replace in_buff with the new buffer. */
free(uu->in_buff);
uu->in_buff = ptr;
uu->in_allocated = newsize;
}
return (ARCHIVE_OK);
}
static int
uudecode_read_header(struct archive_read_filter *f, struct archive_entry *entry)
{
@@ -455,138 +401,59 @@ static ssize_t
uudecode_filter_read(struct archive_read_filter *f, const void **buff)
{
struct uu *uu = f->data;
const unsigned char *b, *d;
unsigned char *out;
ssize_t avail_in, ravail;
ssize_t used;
ssize_t total;
ssize_t len, llen, nl, namelen;
read_more:
d = __archive_read_filter_ahead(f->upstream, 1, &avail_in);
if (d == NULL && avail_in < 0)
return (ARCHIVE_FATAL);
/* Quiet a code analyzer; make sure avail_in must be zero
* when d is NULL. */
if (d == NULL)
avail_in = 0;
used = 0;
total = 0;
out = uu->out_buff;
if (avail_in > 2 * UUENCODE_BID_MAX_READ)
avail_in = 2 * UUENCODE_BID_MAX_READ;
ravail = avail_in;
if (uu->state == ST_IGNORE) {
used = avail_in;
goto finish;
}
if (uu->in_cnt) {
if (uu->in_cnt > UUENCODE_BID_MAX_READ) {
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid format data");
return (ARCHIVE_FATAL);
}
/*
* If there is remaining data which is saved by
* a previous call, use it first.
*/
if (ensure_in_buff_size(f, uu,
avail_in + uu->in_cnt) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (avail_in > 0)
memcpy(uu->in_buff + uu->in_cnt,
d, avail_in);
d = uu->in_buff;
avail_in += uu->in_cnt;
uu->in_cnt = 0;
}
for (;used < avail_in; d += llen, used += llen) {
ssize_t l, body;
total = 0;
b = d;
len = get_line(b, avail_in - used, &nl);
if (len < 0) {
/* Non-ascii character is found. */
if (uu->state == ST_FIND_HEAD &&
(uu->total > 0 || total > 0)) {
uu->state = ST_IGNORE;
used = avail_in;
goto finish;
}
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
if (len > UUENCODE_BID_MAX_READ) {
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid format data");
return (ARCHIVE_FATAL);
}
llen = len;
if ((nl == 0) && (uu->state != ST_UUEND)) {
if (total == 0 && ravail <= 0) {
/* There is nothing more to read, fail */
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Missing format data");
while (uu->state != ST_IGNORE) {
const unsigned char *b;
ssize_t unconsumed;
ssize_t l, body;
ssize_t namelen;
size_t len, name_offset;
mode_t mode;
b = read_line_ahead(f->upstream, total, 0,
&len, &unconsumed);
if (b == NULL) {
if (unconsumed < 0)
return (ARCHIVE_FATAL);
}
/*
* Save remaining data which does not contain
* NL('\n','\r').
*/
if (ensure_in_buff_size(f, uu, len)
!= ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (uu->in_buff != b)
memmove(uu->in_buff, b, len);
uu->in_cnt = len;
if (total == 0) {
/* Do not return 0; it means end-of-file.
* We should try to read more bytes. */
__archive_read_filter_consume(
f->upstream, ravail);
goto read_more;
}
used += len;
break;
}
switch (uu->state) {
default:
case ST_FIND_HEAD:
/* Do not read more than UUENCODE_BID_MAX_READ bytes */
if (total + len >= UUENCODE_BID_MAX_READ) {
if (unconsumed == MAX_LINE_LENGTH) {
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid format data");
return (ARCHIVE_FATAL);
}
if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
l = 6;
else if (len - nl >= 18 &&
memcmp(b, "begin-base64 ", 13) == 0)
l = 13;
else
l = 0;
if (l != 0 && b[l] >= '0' && b[l] <= '7' &&
b[l+1] >= '0' && b[l+1] <= '7' &&
b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
if (total != 0)
break;
if (uu->state != ST_FIND_HEAD) {
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
/* Non-ascii character or end of stream is found. */
uu->state = ST_IGNORE;
}
switch (uu->state) {
case ST_IGNORE:
default:
break;
case ST_FIND_HEAD:
l = parse_header(b, len, &mode, &name_offset);
if (l != 0) {
if (l == 6)
uu->state = ST_READ_UU;
else
uu->state = ST_READ_BASE64;
uu->mode = (mode_t)(
((int)(b[l] - '0') * 64) +
((int)(b[l+1] - '0') * 8) +
(int)(b[l+2] - '0'));
uu->mode = mode;
uu->mode_set = 1;
namelen = len - nl - 4 - l;
namelen = len - name_offset;
if (namelen > 1) {
if (uu->name != NULL)
free(uu->name);
free(uu->name);
uu->name = malloc(namelen + 1);
if (uu->name == NULL) {
archive_set_error(
@@ -596,7 +463,7 @@ read_more:
return (ARCHIVE_FATAL);
}
strncpy(uu->name,
(const char *)(b + l + 4),
(const char *)(b + name_offset),
namelen);
uu->name[namelen] = '\0';
}
@@ -605,7 +472,7 @@ read_more:
case ST_READ_UU:
if (total + len * 2 > OUT_BUFF_SIZE)
goto finish;
body = len - nl;
body = len;
if (!uuchar[*b] || body <= 0) {
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
@@ -658,8 +525,8 @@ read_more:
}
break;
case ST_UUEND:
if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
uu->state = ST_FIND_HEAD;
if (len == 3 && memcmp(b, "end", 3) == 0)
uu->state = ST_IGNORE;
else {
archive_set_error(&f->archive->archive,
ARCHIVE_ERRNO_MISC,
@@ -670,10 +537,10 @@ read_more:
case ST_READ_BASE64:
if (total + len * 2 > OUT_BUFF_SIZE)
goto finish;
l = len - nl;
l = len;
if (l >= 3 && b[0] == '=' && b[1] == '=' &&
b[2] == '=') {
uu->state = ST_FIND_HEAD;
uu->state = ST_IGNORE;
break;
}
while (l > 0) {
@@ -713,14 +580,10 @@ read_more:
}
break;
}
__archive_read_filter_consume(f->upstream, unconsumed);
}
finish:
if (ravail < avail_in)
used -= avail_in - ravail;
__archive_read_filter_consume(f->upstream, used);
*buff = uu->out_buff;
uu->total += total;
return (total);
}
@@ -729,7 +592,6 @@ uudecode_filter_close(struct archive_read_filter *f)
{
struct uu *uu = f->data;
free(uu->in_buff);
free(uu->out_buff);
free(uu->name);
free(uu);
@@ -115,7 +115,7 @@ archive_read_support_filter_xz(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "xz",
if (__archive_read_register_bidder(a, NULL,
&xz_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -147,7 +147,7 @@ archive_read_support_filter_lzma(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "lzma",
if (__archive_read_register_bidder(a, NULL,
&lzma_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -180,7 +180,7 @@ archive_read_support_filter_lzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "lzip",
if (__archive_read_register_bidder(a, NULL,
&lzip_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -25,10 +25,6 @@
#include "archive_platform.h"
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -87,7 +83,7 @@ archive_read_support_filter_zstd(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
if (__archive_read_register_bidder(a, NULL, "zstd",
if (__archive_read_register_bidder(a, NULL,
&zstd_bidder_vtable) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -109,6 +105,7 @@ zstd_bidder_bid(struct archive_read_filter_bidder *b,
{
const unsigned char *buffer;
ssize_t avail;
int bits_checked = 0;
/*
* Zstandard skippable frames contain a 4 byte magic number followed
* by a 4 byte frame data size, then that number of bytes of data.
@@ -147,6 +144,7 @@ zstd_bidder_bid(struct archive_read_filter_bidder *b,
uint32_t frame_data_size;
/* Skip over the magic number */
bits_checked += 28;
offset_in_buffer += 4;
/* Ensure that we can read another 4 bytes. */
@@ -172,12 +170,10 @@ zstd_bidder_bid(struct archive_read_filter_bidder *b,
* if this is zstd data.
*/
if (archive_ckd_add_size(&min,
offset_in_buffer, min_zstd_frame_size))
offset_in_buffer, min_zstd_frame_size) ||
min > max_lookahead)
return (0);
if (min > (size_t)avail) {
if (min > max_lookahead)
return (0);
buffer = __archive_read_filter_ahead(f,
min, &avail);
if (buffer == NULL)
@@ -193,7 +189,7 @@ zstd_bidder_bid(struct archive_read_filter_bidder *b,
*/
if (magic_number == zstd_magic)
return (offset_in_buffer + 4);
return (bits_checked + 32);
return (0);
}
@@ -60,13 +60,11 @@
#include "archive_time_private.h"
#include "archive_endian.h"
#ifndef HAVE_ZLIB_H
#include "archive_crc32.h"
#endif
#define _7ZIP_SIGNATURE "7z\xBC\xAF\x27\x1C"
#define SFX_MIN_ADDR 0x27000
#define SFX_MAX_ADDR 0x60000
#define SFX_MAX_ADDR 0x80000
#define SFX_MAX_OFFSET (SFX_MAX_ADDR - SFX_MIN_ADDR)
#define SFX_MAX_SEEK 0x800000
@@ -353,13 +351,21 @@ struct _7zip {
/* Decoding BCJ and BCJ2 data. */
uint32_t bcj_state;
size_t odd_bcj_size;
unsigned char odd_bcj[4];
size_t odd_bcj_size; /* Number of bytes currently stashed in odd_bcj. */
/* Bytes that a filter didn't have enough lookahead to transform yet.
* Big enough to hold the largest lookahead (IA64). */
unsigned char odd_bcj[16];
/* Decoding BCJ data. */
size_t bcj_prevPosT;
uint32_t bcj_prevMask;
uint32_t bcj_ip;
/* Decoding Delta data. */
unsigned delta_dist;
uint8_t delta_pos;
uint8_t delta_history[256];
/* Decoding BCJ2 data. */
int64_t main_stream_bytes_remaining;
unsigned char *sub_stream_buff[3];
@@ -459,10 +465,17 @@ static void x86_Init(struct _7zip *);
static size_t x86_Convert(struct _7zip *, uint8_t *, size_t);
static void arm_Init(struct _7zip *);
static size_t arm_Convert(struct _7zip *, uint8_t *, size_t);
static void armthumb_Init(struct _7zip *);
static size_t armthumb_Convert(struct _7zip *, uint8_t *, size_t);
static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);
static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t);
static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t);
static size_t riscv_Convert(struct _7zip *, uint8_t *, size_t);
static size_t ia64_Convert(struct _7zip *, uint8_t *, size_t);
static void delta_Init(struct _7zip *, unsigned);
static void delta_Decode(struct _7zip *, uint8_t *, size_t);
static size_t bcj_lookahead(int64_t);
static int64_t seek_compat(struct archive_read *, int64_t, int, int);
@@ -478,8 +491,7 @@ archive_read_support_format_7zip(struct archive *_a)
zip = calloc(1, sizeof(*zip));
if (zip == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate 7zip data");
archive_set_error(_a, ENOMEM, "Can't allocate 7zip data");
return (ARCHIVE_FATAL);
}
@@ -489,7 +501,6 @@ archive_read_support_format_7zip(struct archive *_a)
*/
zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
r = __archive_read_register_format(a,
zip,
"7zip",
@@ -505,7 +516,7 @@ archive_read_support_format_7zip(struct archive *_a)
if (r != ARCHIVE_OK)
free(zip);
return (ARCHIVE_OK);
return (r);
}
static int
@@ -531,11 +542,11 @@ archive_read_format_7zip_has_encrypted_entries(struct archive_read *a)
static int
get_data_offset(struct archive_read *a, int64_t *data_offset, int compat)
{
const unsigned char *p;
const unsigned char *h;
int64_t offset, sfx_offset;
int r, window;
if ((p = __archive_read_ahead(a, 6, NULL)) == NULL) {
if ((h = __archive_read_ahead(a, 6, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated 7-Zip file body");
return (ARCHIVE_FATAL);
@@ -543,7 +554,7 @@ get_data_offset(struct archive_read *a, int64_t *data_offset, int compat)
/* If first six bytes are the 7-Zip signature,
* return the offset right now. */
if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0) {
if (memcmp(h, _7ZIP_SIGNATURE, 6) == 0) {
*data_offset = 0;
return (ARCHIVE_OK);
}
@@ -556,9 +567,9 @@ get_data_offset(struct archive_read *a, int64_t *data_offset, int compat)
* performing a seek, get_elf_sfx_offset requires one,
* thus a performance difference between the two is expected.
*/
if ((p[0] == 'M' && p[1] == 'Z'))
if ((h[0] == 'M' && h[1] == 'Z'))
r = get_pe_sfx_offset(a, &sfx_offset);
else if (memcmp(p, "\x7F\x45LF", 4) == 0)
else if (memcmp(h, "\x7F\x45LF", 4) == 0)
r = get_elf_sfx_offset(a, &sfx_offset, compat);
else
r = ARCHIVE_FATAL;
@@ -567,27 +578,29 @@ get_data_offset(struct archive_read *a, int64_t *data_offset, int compat)
offset = sfx_offset;
window = 4096;
while (offset + window <= (sfx_offset + SFX_MAX_OFFSET)) {
#define SFX_MAX_READAHEAD (sfx_offset + SFX_MAX_OFFSET)
while (offset + window <= SFX_MAX_READAHEAD) {
ssize_t bytes_avail;
const unsigned char *buff = __archive_read_ahead(a,
offset + window, &bytes_avail);
if (buff == NULL) {
/* Remaining bytes are less than window. */
window >>= 1;
if (window < 0x40)
goto fail;
continue;
h = __archive_read_ahead(a, offset + window, &bytes_avail);
if (h == NULL) {
if (bytes_avail >= offset + 32) {
/* Remaining bytes are less than window. */
window = bytes_avail - offset;
continue;
}
goto fail;
}
p = buff + offset;
while (buff + bytes_avail - p >= 32) {
size_t step = check_7zip_header_in_sfx(p);
if (bytes_avail > SFX_MAX_READAHEAD)
bytes_avail = SFX_MAX_READAHEAD;
while (offset <= bytes_avail - 32) {
size_t step = check_7zip_header_in_sfx(h + offset);
if (step == 0) {
*data_offset = p - buff;
*data_offset = offset;
return (ARCHIVE_OK);
}
p += step;
offset += step;
}
offset = p - buff;
}
fail:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -600,9 +613,9 @@ archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
{
int64_t data_offset;
/* If someone has already bid more than 32, then avoid
/* If someone has already bid more than 48, then avoid
trashing the look-ahead buffers with a seek. */
if (best_bid > 32)
if (best_bid > 48)
return (-1);
if (get_data_offset(a, &data_offset, 0) < 0)
@@ -623,7 +636,7 @@ check_7zip_header_in_sfx(const unsigned char *p)
* Magic Code, so we should do this in order not to
* make a mis-detection.
*/
if (crc32(0, p + 12, 20) != archive_le32dec(p + 8))
if (__archive_crc32(0, p + 12, 20) != archive_le32dec(p + 8))
return (6);
/* Hit the header! */
return (0);
@@ -965,7 +978,13 @@ archive_read_format_7zip_read_header(struct archive_read *a,
}
}
if (archive_entry_copy_pathname_l(entry,
if (zip_entry->utf16name == NULL) {
/*
* No kName property (eg from`7z a -si`): 7-Zip derives the
* name from the archive filename, which we don't know.
*/
archive_entry_set_pathname(entry, "data");
} else if (archive_entry_copy_pathname_l(entry,
(const char *)zip_entry->utf16name,
zip_entry->name_len, zip->sconv) != 0) {
if (errno == ENOMEM) {
@@ -1135,7 +1154,7 @@ archive_read_format_7zip_read_data(struct archive_read *a,
/* Update checksum */
if ((zip->entry->flg & CRC32_IS_SET) && bytes)
zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
zip->entry_crc32 = __archive_crc32(zip->entry_crc32, *buff,
(unsigned)bytes);
/* If we hit the end, swallow any end-of-data marker. */
@@ -1302,6 +1321,15 @@ ppmd_read(void *p)
* and we are on boundary;
* last resort to read using __archive_read_ahead.
*/
if (zip->pack_stream_inbytes_remaining <= 0 ||
zip->ppstream.stream_in >=
(uint64_t)zip->pack_stream_inbytes_remaining) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated 7z file data");
zip->ppstream.overconsumed = 1;
return (0);
}
const uint8_t *data = __archive_read_ahead(a,
zip->ppstream.stream_in + 1, NULL);
if (data == NULL) {
@@ -1339,9 +1367,13 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
if (coder2->codec != _7Z_X86 &&
coder2->codec != _7Z_X86_BCJ2 &&
coder2->codec != _7Z_ARM &&
coder2->codec != _7Z_ARMTHUMB &&
coder2->codec != _7Z_ARM64 &&
coder2->codec != _7Z_IA64 &&
coder2->codec != _7Z_POWERPC &&
coder2->codec != _7Z_SPARC) {
coder2->codec != _7Z_RISCV &&
coder2->codec != _7Z_SPARC &&
coder2->codec != _7Z_DELTA) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Unsupported filter %jx for %jx",
@@ -1349,12 +1381,29 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
(uintmax_t)coder1->codec);
return (ARCHIVE_FAILED);
}
if (coder2->codec == _7Z_DELTA &&
coder2->propertiesSize != 1) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Delta parameter");
return (ARCHIVE_FAILED);
}
zip->codec2 = coder2->codec;
zip->bcj_state = 0;
if (coder2->codec == _7Z_X86)
x86_Init(zip);
else if (coder2->codec == _7Z_ARM)
arm_Init(zip);
else if (coder2->codec == _7Z_ARMTHUMB)
armthumb_Init(zip);
else if (coder2->codec == _7Z_ARM64 ||
coder2->codec == _7Z_IA64 ||
coder2->codec == _7Z_POWERPC ||
coder2->codec == _7Z_RISCV ||
coder2->codec == _7Z_SPARC)
zip->bcj_ip = 0;
else if (coder2->codec == _7Z_DELTA)
delta_Init(zip, coder2->properties[0] + 1);
}
break;
default:
@@ -1407,73 +1456,86 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
zip->codec2 = coder2->codec;
filters[fi].options = NULL;
switch (zip->codec2) {
case _7Z_X86:
if (zip->codec == _7Z_LZMA2) {
/*
* Only LZMA2 gets liblzma's branch filters; for LZMA1
* we run our own instead, for the reason given above.
*/
if (zip->codec != _7Z_LZMA2 &&
bcj_lookahead(zip->codec2) != 0) {
/* Use our filter. */
if (zip->codec2 == _7Z_X86)
x86_Init(zip);
else if (zip->codec2 == _7Z_ARM)
arm_Init(zip);
else if (zip->codec2 == _7Z_ARMTHUMB)
armthumb_Init(zip);
else /* ARM64, IA64, POWERPC, RISCV, SPARC. */
zip->bcj_ip = 0;
} else {
switch (zip->codec2) {
case _7Z_X86:
filters[fi].id = LZMA_FILTER_X86;
fi++;
} else
break;
case _7Z_X86_BCJ2:
/* Use our filter. */
x86_Init(zip);
break;
case _7Z_X86_BCJ2:
/* Use our filter. */
zip->bcj_state = 0;
break;
case _7Z_DELTA:
if (coder2->propertiesSize != 1) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Delta parameter");
return (ARCHIVE_FAILED);
}
filters[fi].id = LZMA_FILTER_DELTA;
memset(&delta_opt, 0, sizeof(delta_opt));
delta_opt.type = LZMA_DELTA_TYPE_BYTE;
delta_opt.dist =
coder2->properties[0] + 1;
filters[fi].options = &delta_opt;
fi++;
break;
/* Following filters have not been tested yet. */
case _7Z_POWERPC:
filters[fi].id = LZMA_FILTER_POWERPC;
fi++;
break;
case _7Z_IA64:
filters[fi].id = LZMA_FILTER_IA64;
fi++;
break;
case _7Z_ARM:
filters[fi].id = LZMA_FILTER_ARM;
fi++;
break;
case _7Z_ARMTHUMB:
filters[fi].id = LZMA_FILTER_ARMTHUMB;
fi++;
break;
zip->bcj_state = 0;
break;
case _7Z_DELTA:
if (coder2->propertiesSize != 1) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Delta parameter");
return (ARCHIVE_FAILED);
}
filters[fi].id = LZMA_FILTER_DELTA;
memset(&delta_opt, 0, sizeof(delta_opt));
delta_opt.type = LZMA_DELTA_TYPE_BYTE;
delta_opt.dist =
coder2->properties[0] + 1;
filters[fi].options = &delta_opt;
fi++;
break;
/* Following filters have not been tested yet. */
case _7Z_POWERPC:
filters[fi].id = LZMA_FILTER_POWERPC;
fi++;
break;
case _7Z_IA64:
filters[fi].id = LZMA_FILTER_IA64;
fi++;
break;
case _7Z_ARM:
filters[fi].id = LZMA_FILTER_ARM;
fi++;
break;
case _7Z_ARMTHUMB:
filters[fi].id = LZMA_FILTER_ARMTHUMB;
fi++;
break;
#ifdef LZMA_FILTER_ARM64
case _7Z_ARM64:
filters[fi].id = LZMA_FILTER_ARM64;
fi++;
break;
case _7Z_ARM64:
filters[fi].id = LZMA_FILTER_ARM64;
fi++;
break;
#endif
#ifdef LZMA_FILTER_RISCV
case _7Z_RISCV:
filters[fi].id = LZMA_FILTER_RISCV;
fi++;
break;
case _7Z_RISCV:
filters[fi].id = LZMA_FILTER_RISCV;
fi++;
break;
#endif
case _7Z_SPARC:
filters[fi].id = LZMA_FILTER_SPARC;
fi++;
break;
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Unexpected codec ID: %jX",
(uintmax_t)zip->codec2);
return (ARCHIVE_FAILED);
case _7Z_SPARC:
filters[fi].id = LZMA_FILTER_SPARC;
fi++;
break;
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Unexpected codec ID: %jX",
(uintmax_t)zip->codec2);
return (ARCHIVE_FAILED);
}
}
}
@@ -1672,6 +1734,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
size_t t_avail_in, t_avail_out;
uint8_t *bcj2_next_out;
size_t bcj2_avail_out;
size_t odd_bcj_out = 0;
int r, ret = ARCHIVE_OK;
t_avail_in = o_avail_in = *used;
@@ -1679,12 +1742,14 @@ decompress(struct archive_read *a, struct _7zip *zip,
t_next_in = b;
t_next_out = buff;
if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) {
if (zip->codec != _7Z_LZMA2 && bcj_lookahead(zip->codec2) != 0) {
int i;
size_t min_out = bcj_lookahead(zip->codec2);
/* Do not copy out the BCJ remaining bytes when the output
* buffer size is less than five bytes. */
if (o_avail_in != 0 && t_avail_out < 5 && zip->odd_bcj_size) {
* buffer size is less than the filter's lookahead size. */
if (o_avail_in != 0 && t_avail_out < min_out &&
zip->odd_bcj_size) {
*used = 0;
*outbytes = 0;
return (ret);
@@ -1693,8 +1758,17 @@ decompress(struct archive_read *a, struct _7zip *zip,
*t_next_out++ = zip->odd_bcj[i];
t_avail_out--;
zip->odd_bcj_size--;
odd_bcj_out++;
}
if (o_avail_in == 0 || t_avail_out == 0) {
/*
* PPMd is the only codec which can still produce output
* after its packed stream has been consumed: it is asked
* to flush the rest of the folder when called with no
* input. Returning here would skip that flush and leave
* the folder short, so let it through.
*/
if ((o_avail_in == 0 && zip->codec != _7Z_PPMD) ||
t_avail_out == 0) {
*used = o_avail_in - t_avail_in;
*outbytes = o_avail_out - t_avail_out;
if (o_avail_in == 0)
@@ -1898,10 +1972,20 @@ decompress(struct archive_read *a, struct _7zip *zip,
zip->ppmd7_stat = 1;
}
if (t_avail_in == 0)
/* XXX Flush out remaining decoded data XXX */
flush_bytes = zip->folder_outbytes_remaining;
else
if (t_avail_in == 0) {
/* XXX Flush out remaining decoded data XXX
*
* The bytes a BCJ filter parked on the previous call
* have just been written to the output buffer, and
* count towards what the folder still owes. Asking
* PPMd to decode them a second time would run the
* range decoder off the end of the packed stream. */
flush_bytes = zip->folder_outbytes_remaining -
(int64_t)odd_bcj_out;
/* Those bytes were all that was left of the folder. */
if (flush_bytes <= 0)
break;
} else
flush_bytes = 0;
do {
@@ -1939,34 +2023,64 @@ decompress(struct archive_read *a, struct _7zip *zip,
if (ret != ARCHIVE_OK && ret != ARCHIVE_EOF)
return (ret);
*used = o_avail_in - t_avail_in;
if (zip->codec == _7Z_PPMD)
*used = zip->ppstream.stream_in;
else
*used = o_avail_in - t_avail_in;
*outbytes = o_avail_out - t_avail_out;
/*
* Decode BCJ.
*/
if (zip->codec != _7Z_LZMA2) {
if (zip->codec2 == _7Z_X86) {
size_t l = x86_Convert(zip, buff, *outbytes);
if (zip->codec != _7Z_LZMA2 && bcj_lookahead(zip->codec2) != 0) {
size_t l;
zip->odd_bcj_size = *outbytes - l;
if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&
o_avail_in && ret != ARCHIVE_EOF) {
memcpy(zip->odd_bcj,
((unsigned char *)buff) + l,
zip->odd_bcj_size);
*outbytes = l;
} else
zip->odd_bcj_size = 0;
} else if (zip->codec2 == _7Z_ARM) {
*outbytes = arm_Convert(zip, buff, *outbytes);
} else if (zip->codec2 == _7Z_ARM64) {
*outbytes = arm64_Convert(zip, buff, *outbytes);
} else if (zip->codec2 == _7Z_SPARC) {
*outbytes = sparc_Convert(zip, buff, *outbytes);
} else if (zip->codec2 == _7Z_POWERPC) {
*outbytes = powerpc_Convert(zip, buff, *outbytes);
switch (zip->codec2) {
case _7Z_X86:
l = x86_Convert(zip, buff, *outbytes);
break;
case _7Z_ARM:
l = arm_Convert(zip, buff, *outbytes);
break;
case _7Z_ARMTHUMB:
l = armthumb_Convert(zip, buff, *outbytes);
break;
case _7Z_ARM64:
l = arm64_Convert(zip, buff, *outbytes);
break;
case _7Z_SPARC:
l = sparc_Convert(zip, buff, *outbytes);
break;
case _7Z_POWERPC:
l = powerpc_Convert(zip, buff, *outbytes);
break;
case _7Z_RISCV:
l = riscv_Convert(zip, buff, *outbytes);
break;
case _7Z_IA64:
l = ia64_Convert(zip, buff, *outbytes);
break;
default:
/* Unreachable: bcj_lookahead() returns non-zero only
* for the codecs handled above. Guards against the two
* lists drifting apart. */
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
"BCJ filter internal error");
return (ARCHIVE_FAILED);
}
/* Keep the bytes which could not be converted yet, they are
* prepended to the output buffer on the next call. */
zip->odd_bcj_size = *outbytes - l;
if (zip->odd_bcj_size > 0 &&
zip->odd_bcj_size <= sizeof(zip->odd_bcj) &&
o_avail_in && ret != ARCHIVE_EOF) {
memcpy(zip->odd_bcj,
((unsigned char *)buff) + l,
zip->odd_bcj_size);
*outbytes = l;
} else
zip->odd_bcj_size = 0;
}
/*
@@ -1995,6 +2109,13 @@ decompress(struct archive_read *a, struct _7zip *zip,
*outbytes = o_avail_out - bcj2_avail_out;
}
/*
* Decode Delta. LZMA1 and LZMA2 use liblzma's Delta filter instead.
*/
if (zip->codec2 == _7Z_DELTA &&
zip->codec != _7Z_LZMA && zip->codec != _7Z_LZMA2)
delta_Decode(zip, buff, *outbytes);
return (ret);
}
@@ -3176,19 +3297,19 @@ read_Times(struct archive_read *a, int type)
goto failed;
switch (type) {
case kCTime:
ntfs_to_unix(archive_le64dec(p),
__archive_ntfs_to_unix(archive_le64dec(p),
&(entries[i].ctime),
&(entries[i].ctime_ns));
entries[i].flg |= CTIME_IS_SET;
break;
case kATime:
ntfs_to_unix(archive_le64dec(p),
__archive_ntfs_to_unix(archive_le64dec(p),
&(entries[i].atime),
&(entries[i].atime_ns));
entries[i].flg |= ATIME_IS_SET;
break;
case kMTime:
ntfs_to_unix(archive_le64dec(p),
__archive_ntfs_to_unix(archive_le64dec(p),
&(entries[i].mtime),
&(entries[i].mtime_ns));
entries[i].flg |= MTIME_IS_SET;
@@ -3267,7 +3388,7 @@ header_bytes(struct archive_read *a, size_t rbytes)
}
/* Update checksum */
zip->header_crc32 = crc32(zip->header_crc32, p, (unsigned)rbytes);
zip->header_crc32 = __archive_crc32(zip->header_crc32, p, (unsigned)rbytes);
return (p);
}
@@ -3306,7 +3427,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
}
/* CRC check. */
if (crc32(0, p + 12, 20)
if (__archive_crc32(0, p + 12, 20)
!= archive_le32dec(p + 8)) {
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive, -1, "Header CRC error");
@@ -3650,8 +3771,9 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
if (zip->uncompressed_buffer_bytes_remaining ==
zip->uncompressed_buffer_size)
break;
if (zip->codec2 == _7Z_X86 && zip->odd_bcj_size &&
zip->uncompressed_buffer_bytes_remaining + 5 >
if (zip->odd_bcj_size &&
zip->uncompressed_buffer_bytes_remaining +
bcj_lookahead(zip->codec2) >
zip->uncompressed_buffer_size)
break;
if (zip->pack_stream_inbytes_remaining == 0 &&
@@ -4280,6 +4402,54 @@ arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
return i;
}
static void
armthumb_Init(struct _7zip *zip)
{
zip->bcj_ip = 4;
}
static size_t
armthumb_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
{
// This function was adapted from
// static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
// in https://git.tukaani.org/xz-embedded.git
/*
* Branch/Call/Jump (BCJ) filter decoders
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <https://7-zip.org/>
*
* SPDX-License-Identifier: 0BSD
*/
size_t i;
uint32_t addr;
for (i = 0; i + 4 <= size; i += 2) {
if ((buf[i + 1] & 0xF8) == 0xF0
&& (buf[i + 3] & 0xF8) == 0xF8) {
addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
| ((uint32_t)buf[i] << 11)
| (((uint32_t)buf[i + 3] & 0x07) << 8)
| (uint32_t)buf[i + 2];
addr <<= 1;
addr -= zip->bcj_ip + (uint32_t)i;
addr >>= 1;
buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
buf[i] = (uint8_t)(addr >> 11);
buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
buf[i + 2] = (uint8_t)addr;
i += 2;
}
}
zip->bcj_ip += (uint32_t)i;
return i;
}
static size_t
arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
{
@@ -4443,6 +4613,260 @@ powerpc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
return i;
}
static size_t
riscv_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
{
// This function was adapted from
// static size_t bcj_riscv(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
// in https://git.tukaani.org/xz-embedded.git
/*
* Branch/Call/Jump (BCJ) filter decoders
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <https://7-zip.org/>
*
* SPDX-License-Identifier: 0BSD
*/
if (size < 8)
return 0;
size -= 8;
size_t i;
for (i = 0; i <= size; i += 2) {
uint32_t inst = buf[i];
if (inst == 0xEF) {
// JAL. Only filter rd=x1(ra) and rd=x5(t0).
const uint32_t b1 = buf[i + 1];
if ((b1 & 0x0D) != 0)
continue;
const uint32_t b2 = buf[i + 2];
const uint32_t b3 = buf[i + 3];
uint32_t addr = ((b1 & 0xF0) << 13)
| (b2 << 9) | (b3 << 1);
addr -= zip->bcj_ip + (uint32_t)i;
buf[i + 1] = (uint8_t)((b1 & 0x0F)
| ((addr >> 8) & 0xF0));
buf[i + 2] = (uint8_t)(((addr >> 16) & 0x0F)
| ((addr >> 7) & 0x10)
| ((addr << 4) & 0xE0));
buf[i + 3] = (uint8_t)(((addr >> 4) & 0x7F)
| ((addr >> 13) & 0x80));
i += 4 - 2;
} else if ((inst & 0x7F) == 0x17) {
// AUIPC, paired with a second instruction (inst2)
// that is within the next four bytes.
uint32_t inst2;
inst |= (uint32_t)buf[i + 1] << 8;
inst |= (uint32_t)buf[i + 2] << 16;
inst |= (uint32_t)buf[i + 3] << 24;
if (inst & 0xE80) {
// AUIPC's rd doesn't equal x0 or x2.
inst2 = archive_le32dec(buf + i + 4);
if (((inst << 8) ^ (inst2 - 3)) & 0xF8003) {
i += 6 - 2;
continue;
}
uint32_t addr = (inst & 0xFFFFF000)
+ (inst2 >> 20);
inst = 0x17 | (2 << 7) | (inst2 << 12);
inst2 = addr;
} else {
// AUIPC's rd equals x0 or x2.
const uint32_t inst2_rs1 = inst >> 27;
if ((uint32_t)((inst - 0x3117) << 18)
>= (inst2_rs1 & 0x1D)) {
i += 4 - 2;
continue;
}
uint32_t addr = archive_be32dec(buf + i + 4);
addr -= zip->bcj_ip + (uint32_t)i;
inst2 = (inst >> 12) | (addr << 20);
inst = 0x17 | (inst2_rs1 << 7)
| ((addr + 0x800) & 0xFFFFF000);
}
archive_le32enc(buf + i, inst);
archive_le32enc(buf + i + 4, inst2);
i += 8 - 2;
}
}
zip->bcj_ip += (uint32_t)i;
return i;
}
static size_t
ia64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
{
// This function was adapted from
// static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
// in https://git.tukaani.org/xz-embedded.git
/*
* Branch/Call/Jump (BCJ) filter decoders
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <https://7-zip.org/>
*
* SPDX-License-Identifier: 0BSD
*/
static const uint8_t branch_table[32] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 6, 6, 0, 0, 7, 7,
4, 4, 0, 0, 4, 4, 0, 0
};
/* Loop counters */
size_t i;
size_t j;
/* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
uint32_t slot;
/* Bitwise offset of the instruction indicated by slot */
uint32_t bit_pos;
/* bit_pos split into byte and bit parts */
uint32_t byte_pos;
uint32_t bit_res;
/* Address part of an instruction */
uint32_t addr;
/* Mask used to detect which instructions to convert */
uint32_t mask;
/* 41-bit instruction stored somewhere in the lowest 48 bits */
uint64_t instr;
/* Instruction normalized with bit_res for easier manipulation */
uint64_t norm;
size &= ~(size_t)15;
for (i = 0; i < size; i += 16) {
mask = branch_table[buf[i] & 0x1F];
for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
if (((mask >> slot) & 1) == 0)
continue;
byte_pos = bit_pos >> 3;
bit_res = bit_pos & 7;
instr = 0;
for (j = 0; j < 6; ++j)
instr |= (uint64_t)(buf[i + j + byte_pos])
<< (8 * j);
norm = instr >> bit_res;
if (((norm >> 37) & 0x0F) == 0x05
&& ((norm >> 9) & 0x07) == 0) {
addr = (norm >> 13) & 0x0FFFFF;
addr |= ((uint32_t)(norm >> 36) & 1) << 20;
addr <<= 4;
addr -= zip->bcj_ip + (uint32_t)i;
addr >>= 4;
norm &= ~((uint64_t)0x8FFFFF << 13);
norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
norm |= (uint64_t)(addr & 0x100000)
<< (36 - 20);
instr &= (1U << bit_res) - 1;
instr |= norm << bit_res;
for (j = 0; j < 6; j++)
buf[i + j + byte_pos]
= (uint8_t)(instr >> (8 * j));
}
}
}
zip->bcj_ip += (uint32_t)i;
return i;
}
static void
delta_Init(struct _7zip *zip, unsigned dist)
{
zip->delta_dist = dist;
zip->delta_pos = 0;
memset(zip->delta_history, 0, sizeof(zip->delta_history));
}
static void
delta_Decode(struct _7zip *zip, uint8_t *buf, size_t size)
{
// This was adapted from src/liblzma/delta/delta_decoder.c's
// static void decode_buffer(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
// function in https://github.com/tukaani-project/xz.git
/*
* Delta filter decoder
*
* Author: Lasse Collin
*
* SPDX-License-Identifier: 0BSD
*/
size_t i;
for (i = 0; i < size; i++) {
buf[i] += zip->delta_history[
(zip->delta_dist + zip->delta_pos) & 0xFF];
zip->delta_history[zip->delta_pos--] = buf[i];
}
}
/*
* The widest instruction the BCJ filters rewrite, and the smallest output
* buffer that those filters can make progress with. Filters leave up to one
* byte less than this unconverted at the end of a buffer (when they don't
* have enough data to continue). Returns 0 for codecs we do not filter
* ourselves.
*/
static size_t
bcj_lookahead(int64_t codec2)
{
switch (codec2) {
case _7Z_X86:
return (5);
case _7Z_RISCV:
return (8);
case _7Z_IA64:
return (16);
case _7Z_ARM:
case _7Z_ARMTHUMB:
case _7Z_ARM64:
case _7Z_POWERPC:
case _7Z_SPARC:
return (4);
default:
return (0);
}
}
/*
* Brought from LZMA SDK.
*
@@ -106,8 +106,7 @@ archive_read_support_format_ar(struct archive *_a)
ar = calloc(1, sizeof(*ar));
if (ar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate ar data");
archive_set_error(_a, ENOMEM, "Can't allocate ar data");
return (ARCHIVE_FATAL);
}
ar->strtab = NULL;
@@ -125,11 +124,9 @@ archive_read_support_format_ar(struct archive *_a)
NULL,
NULL);
if (r != ARCHIVE_OK) {
if (r != ARCHIVE_OK)
free(ar);
return (r);
}
return (ARCHIVE_OK);
return (r);
}
static int
@@ -251,56 +248,66 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
*/
ar_parse_common_header(ar, entry, h);
/*
* '/' is the ranlib index.
* Ignore it since it contains linker information.
*/
if (strcmp(filename, "/") == 0) {
/* This is not a file entry. Ignore. */
archive_entry_copy_pathname(entry, NULL);
/* Skip special file entry. */
return (archive_read_format_ar_skip(a));
}
/*
* '//' is the GNU filename table.
* Later entries can refer to names in this table.
*/
if (strcmp(filename, "//") == 0) {
char *st;
size_t entry_size;
int64_t entry_size;
size_t strtab_size;
/* This is not a file entry. Ignore. */
archive_entry_copy_pathname(entry, NULL);
archive_entry_copy_pathname(entry, filename);
/* Get the size of the filename table. */
number = ar_atol10(h + AR_size_offset, AR_size_size);
if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {
entry_size = archive_entry_size(entry);
if (entry_size == 0 || entry_size > 1024 * 1024 * 1024) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Filename table too large");
return (ARCHIVE_FATAL);
}
entry_size = (size_t)number;
if (entry_size == 0) {
archive_set_error(&a->archive, EINVAL,
"Invalid string table");
"Invalid filename table size");
return (ARCHIVE_FATAL);
}
strtab_size = (size_t)entry_size;
if (ar->strtab != NULL) {
archive_set_error(&a->archive, EINVAL,
"More than one string table exists");
"More than one filename table exists");
return (ARCHIVE_FATAL);
}
/* Read the filename table into memory. */
st = malloc(entry_size);
st = malloc(strtab_size);
if (st == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate filename table buffer");
return (ARCHIVE_FATAL);
}
ar->strtab = st;
ar->strtab_size = entry_size;
ar->strtab_size = strtab_size;
if (*unconsumed) {
__archive_read_consume(a, *unconsumed);
*unconsumed = 0;
}
if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL)
if ((b = __archive_read_ahead(a, strtab_size, NULL)) == NULL)
return (ARCHIVE_FATAL);
memcpy(st, b, strtab_size);
/* Skip special file entry. */
if (archive_read_format_ar_skip(a) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
memcpy(st, b, entry_size);
__archive_read_consume(a, entry_size);
/* All contents are consumed. */
ar->entry_bytes_remaining = 0;
archive_entry_set_size(entry, ar->entry_bytes_remaining);
/* Parse the filename table. */
return (ar_parse_gnu_filename_table(a));
@@ -415,17 +422,20 @@ archive_read_format_ar_read_header(struct archive_read *a,
a->archive.archive_format = ARCHIVE_FORMAT_AR;
}
/* Read the header for the next file entry. */
if ((header_data = __archive_read_ahead(a, 60, NULL)) == NULL)
/* Broken header. */
return (ARCHIVE_EOF);
do {
/* Read the header for the next file entry. */
if ((header_data = __archive_read_ahead(a, 60, NULL)) == NULL)
/* Broken header. */
return (ARCHIVE_EOF);
unconsumed = 60;
unconsumed = 60;
ret = _ar_read_header(a, entry, ar, (const char *)header_data, &unconsumed);
ret = _ar_read_header(a, entry, ar, (const char *)header_data,
&unconsumed);
if (unconsumed)
__archive_read_consume(a, unconsumed);
if (unconsumed)
__archive_read_consume(a, unconsumed);
} while (ret == ARCHIVE_OK && archive_entry_pathname(entry) == NULL);
return ret;
}
@@ -522,18 +532,20 @@ ar_parse_gnu_filename_table(struct archive_read *a)
size = ar->strtab_size;
for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {
if (*p == '/') {
/* Normalize backslash, even before separator check. */
if (*p == '\\')
*p = '/';
if (*p == '/' && *(p + 1) == '\n') {
*p++ = '\0';
if (*p != '\n')
goto bad_string_table;
*p = '\0';
}
}
/*
* GNU ar always pads the table to an even size.
* The pad character is either '\n' or '`'.
* For Windows Archive files, the pad character can be '\0'.
*/
if (p != ar->strtab + size && *p != '\n' && *p != '`')
if (p != ar->strtab + size && *p != '\n' && *p != '`' && *p != '\0')
goto bad_string_table;
/* Enforce zero termination. */
@@ -187,6 +187,8 @@ struct lzx_dec {
uint8_t *w_buff;
/* The insert position to the window. */
size_t w_pos;
/* The number of initialized bytes in the window. */
size_t w_filled;
/* The position where we can copy decoded code from the window. */
size_t copy_pos;
/* The length how many bytes we can copy decoded code from
@@ -284,6 +286,7 @@ struct lzx_stream {
#define MAX_UNCOMPRESS_SIZE 0x8000
#define MAX_FILE_SIZE (UINT16_MAX * MAX_UNCOMPRESS_SIZE)
#define MAX_E8_TRANSLATION (0x8000 * MAX_UNCOMPRESS_SIZE)
#define SFX_MAX_READAHEAD (1024 * 512)
static const char * const compression_name[] = {
"NONE",
@@ -459,14 +462,13 @@ archive_read_support_format_cab(struct archive *_a)
cab = calloc(1, sizeof(*cab));
if (cab == NULL) {
archive_set_error(&a->archive, ENOMEM,
archive_set_error(_a, ENOMEM,
"Can't allocate CAB data");
return (ARCHIVE_FATAL);
}
archive_string_init(&cab->ws);
if (archive_wstring_ensure(&cab->ws, 256) == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory");
archive_set_error(_a, ENOMEM, "Can't allocate memory");
free(cab);
return (ARCHIVE_FATAL);
}
@@ -488,10 +490,10 @@ archive_read_support_format_cab(struct archive *_a)
archive_wstring_free(&cab->ws);
free(cab);
}
return (ARCHIVE_OK);
return (r);
}
static int
static size_t
find_cab_magic(const char *p)
{
switch (p[4]) {
@@ -517,46 +519,54 @@ find_cab_magic(const char *p)
static int
archive_read_format_cab_bid(struct archive_read *a, int best_bid)
{
const char *p;
ssize_t bytes_avail, offset, window;
const char *h;
/* If there's already a better bid than we can ever
make, don't bother testing. */
if (best_bid > 64)
return (-1);
if ((p = __archive_read_ahead(a, 8, NULL)) == NULL)
if ((h = __archive_read_ahead(a, 16, NULL)) == NULL)
return (-1);
if (memcmp(p, "MSCF\0\0\0\0", 8) == 0)
return (64);
if (memcmp(h, "MSCF", 4) == 0) {
if (memcmp(h + 4, "\0\0\0\0", 4) == 0)
return (64);
/* Some archives do not have all reserved bits set to zero. */
if (memcmp(h + 12, "\0\0\0\0", 4) == 0)
return (32);
}
/*
* Attempt to handle self-extracting archives
* by noting a PE header and searching forward
* up to 128k for an 'MSCF' marker.
*/
if (p[0] == 'M' && p[1] == 'Z') {
if (h[0] == 'M' && h[1] == 'Z') {
ssize_t bytes_avail;
ssize_t offset, window;
offset = 0;
window = 4096;
while (offset < (1024 * 128)) {
const char *h = __archive_read_ahead(a, offset + window,
while (offset + window <= SFX_MAX_READAHEAD) {
h = __archive_read_ahead(a, offset + window,
&bytes_avail);
if (h == NULL) {
/* Remaining bytes are less than window. */
window >>= 1;
if (window < 128)
return (0);
continue;
if (bytes_avail >= offset + 8) {
/* Remaining bytes are less than window. */
window = bytes_avail - offset;
continue;
}
return (0);
}
p = h + offset;
while (p + 8 < h + bytes_avail) {
int next;
if ((next = find_cab_magic(p)) == 0)
if (bytes_avail > SFX_MAX_READAHEAD)
bytes_avail = SFX_MAX_READAHEAD;
while (offset <= bytes_avail - 8) {
size_t next = find_cab_magic(h + offset);
if (next == 0)
return (64);
p += next;
offset += next;
}
offset = p - h;
}
}
return (0);
@@ -619,8 +629,8 @@ cab_skip_sfx(struct archive_read *a)
* like the cab header.
*/
while (p + 8 < q) {
int next;
if ((next = find_cab_magic(p)) == 0) {
size_t next = find_cab_magic(p);
if (next == 0) {
skip = p - h;
__archive_read_consume(a, skip);
return (ARCHIVE_OK);
@@ -1048,8 +1058,16 @@ archive_read_format_cab_read_header(struct archive_read *a,
}
/* If a cffolder of this file is changed, reset a cfdata to read
* file contents from next cfdata. */
if (prev_folder != cab->entry_cffolder)
if (prev_folder != cab->entry_cffolder) {
cab->entry_cfdata = NULL;
/*
* Bytes of files we skipped so far belong to folders we
* are done with; reading this file will seek directly to
* the data of the new folder, so we must not charge the
* skipped bytes against the new folder's data.
*/
cab->bytes_skipped = 0;
}
/* If a pathname is UTF-8, prepare a string conversion object
* for UTF-8 and use it. */
@@ -2252,6 +2270,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
}
ds->w_pos = 0;
ds->w_filled = 0;
ds->state = ST_RD_TRANSLATION;
ds->br.cache_buffer = 0;
ds->br.cache_avail = 0;
@@ -2707,6 +2726,11 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
strm->avail_out -= l;
strm->total_out += l;
ds->w_pos = (ds->w_pos + l) & ds->w_mask;
if (ds->w_filled < ds->w_size) {
ds->w_filled += l;
if (ds->w_filled > ds->w_size)
ds->w_filled = ds->w_size;
}
ds->block_bytes_avail -= l;
}
/* FALL THROUGH */
@@ -2753,7 +2777,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Pre-tree for first 256 elements of main tree.
*/
if (lzx_read_pre_tree(strm) < 0) {
if (lzx_read_pre_tree(strm) == ARCHIVE_EOF) {
ds->state = ST_RD_PRE_MAIN_TREE_256;
if (last)
goto failed;
@@ -2781,7 +2805,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Pre-tree for remaining elements of main tree.
*/
if (lzx_read_pre_tree(strm) < 0) {
if (lzx_read_pre_tree(strm) == ARCHIVE_EOF) {
ds->state = ST_RD_PRE_MAIN_TREE_REM;
if (last)
goto failed;
@@ -2811,7 +2835,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Pre-tree for remaining elements of main tree.
*/
if (lzx_read_pre_tree(strm) < 0) {
if (lzx_read_pre_tree(strm) == ARCHIVE_EOF) {
ds->state = ST_RD_PRE_LENGTH_TREE;
if (last)
goto failed;
@@ -2862,6 +2886,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
uint8_t mt_lookup_bits = mt->lookup_bits;
size_t copy_len = ds->copy_len, copy_pos = ds->copy_pos;
size_t w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
size_t w_filled = ds->w_filled;
uint8_t length_header = ds->length_header;
uint8_t offset_bits = ds->offset_bits;
uint16_t position_slot = ds->position_slot;
@@ -2886,6 +2911,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
ds->position_slot = position_slot;
ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
ds->w_pos = w_pos;
ds->w_filled = w_filled;
strm->avail_out = endp - noutp;
return (ARCHIVE_EOF);
}
@@ -2922,6 +2948,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
* afterward. */
w_buff[w_pos] = c;
w_pos = (w_pos + 1) & w_mask;
if (w_filled < w_size)
w_filled++;
/* Store the decoded code to output buffer. */
*noutp++ = c;
block_bytes_avail--;
@@ -3049,6 +3077,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
/*
* Compute a real position in window.
*/
if (copy_pos == 0 || copy_pos > w_filled)
goto failed;
copy_pos = (w_pos - copy_pos) & w_mask;
/* FALL THROUGH */
case ST_COPY:
@@ -3086,6 +3116,11 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
noutp += l;
copy_pos = (copy_pos + l) & w_mask;
w_pos = (w_pos + l) & w_mask;
if (w_filled < w_size) {
w_filled += l;
if (w_filled > w_size)
w_filled = w_size;
}
block_bytes_avail -= l;
if (copy_len <= l)
/* A copy of current pattern ended. */
@@ -3114,6 +3149,7 @@ next_data:
ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
ds->state = state;
ds->w_pos = w_pos;
ds->w_filled = w_filled;
strm->avail_out = endp - noutp;
return (ARCHIVE_OK);
}
@@ -3240,7 +3276,8 @@ lzx_huffman_init(struct huffman *hf, uint16_t symbol_count, uint8_t tbl_bits)
return (ARCHIVE_FATAL);
hf->tbl_bits = tbl_bits;
} else
memset(hf->tbl, 0, tbl_size * sizeof(hf->bitlen[0]));
memset(hf->tbl, 0,
((size_t)1 << hf->tbl_bits) * sizeof(hf->tbl[0]));
return (ARCHIVE_OK);
}
@@ -173,9 +173,7 @@ struct links_entry {
char *name;
};
#define CPIO_MAGIC 0x13141516
struct cpio {
int magic;
int (*read_header)(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *);
struct links_entry *links_head;
@@ -234,10 +232,9 @@ archive_read_support_format_cpio(struct archive *_a)
cpio = calloc(1, sizeof(*cpio));
if (cpio == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
archive_set_error(_a, ENOMEM, "Can't allocate cpio data");
return (ARCHIVE_FATAL);
}
cpio->magic = CPIO_MAGIC;
r = __archive_read_register_format(a,
cpio,
@@ -254,7 +251,7 @@ archive_read_support_format_cpio(struct archive *_a)
if (r != ARCHIVE_OK)
free(cpio);
return (ARCHIVE_OK);
return (r);
}
@@ -262,16 +259,16 @@ static int
archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
{
struct cpio *cpio = a->format->data;
const unsigned char *p;
const void *h;
int bid;
(void)best_bid; /* UNUSED */
if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
if ((h = __archive_read_ahead(a, 6, NULL)) == NULL)
return (-1);
bid = 0;
if (memcmp(p, "070707", 6) == 0) {
if (memcmp(h, "070707", 6) == 0) {
/* ASCII cpio archive (odc, POSIX.1) */
cpio->read_header = header_odc;
bid += 48;
@@ -279,7 +276,7 @@ archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
* XXX TODO: More verification; Could check that only octal
* digits appear in appropriate header locations. XXX
*/
} else if (memcmp(p, "070727", 6) == 0) {
} else if (memcmp(h, "070727", 6) == 0) {
/* afio large ASCII cpio archive */
cpio->read_header = header_odc;
bid += 48;
@@ -287,7 +284,7 @@ archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
* XXX TODO: More verification; Could check that almost hex
* digits appear in appropriate header locations. XXX
*/
} else if (memcmp(p, "070701", 6) == 0) {
} else if (memcmp(h, "070701", 6) == 0) {
/* ASCII cpio archive (SVR4 without CRC) */
cpio->read_header = header_newc;
bid += 48;
@@ -295,7 +292,7 @@ archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
* XXX TODO: More verification; Could check that only hex
* digits appear in appropriate header locations. XXX
*/
} else if (memcmp(p, "070702", 6) == 0) {
} else if (memcmp(h, "070702", 6) == 0) {
/* ASCII cpio archive (SVR4 with CRC) */
/* XXX TODO: Flag that we should check the CRC. XXX */
cpio->read_header = header_newc;
@@ -304,12 +301,12 @@ archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
* XXX TODO: More verification; Could check that only hex
* digits appear in appropriate header locations. XXX
*/
} else if (archive_be16dec(p) == 070707) {
} else if (archive_be16dec(h) == 070707) {
/* big-endian binary cpio archives */
cpio->read_header = header_bin_be;
bid += 16;
/* Is more verification possible here? */
} else if (archive_le16dec(p) == 070707) {
} else if (archive_le16dec(h) == 070707) {
/* little-endian binary cpio archives */
cpio->read_header = header_bin_le;
bid += 16;
@@ -87,9 +87,10 @@ archive_read_format_empty_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
(void)a; /* UNUSED */
(void)buff; /* UNUSED */
(void)size; /* UNUSED */
(void)offset; /* UNUSED */
*buff = NULL;
*size = 0;
*offset = 0;
return (ARCHIVE_EOF);
}
@@ -320,9 +320,6 @@ struct heap_queue {
};
struct iso9660 {
int magic;
#define ISO9660_MAGIC 0x96609660
int opt_support_joliet;
int opt_support_rockridge;
@@ -423,7 +420,7 @@ static struct file_info *
static int parse_rockridge(struct archive_read *a,
struct file_info *file, const unsigned char *start,
const unsigned char *end);
static int register_CE(struct archive_read *a, int32_t location,
static int register_CE(struct archive_read *a, uint32_t location,
struct file_info *file);
static int read_CE(struct archive_read *a, struct iso9660 *iso9660);
static void parse_rockridge_NM1(struct file_info *,
@@ -464,11 +461,9 @@ archive_read_support_format_iso9660(struct archive *_a)
iso9660 = calloc(1, sizeof(*iso9660));
if (iso9660 == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate iso9660 data");
archive_set_error(_a, ENOMEM, "Can't allocate iso9660 data");
return (ARCHIVE_FATAL);
}
iso9660->magic = ISO9660_MAGIC;
iso9660->cache_files.first = NULL;
iso9660->cache_files.last = &(iso9660->cache_files.first);
iso9660->re_files.first = NULL;
@@ -491,11 +486,9 @@ archive_read_support_format_iso9660(struct archive *_a)
NULL,
NULL);
if (r != ARCHIVE_OK) {
if (r != ARCHIVE_OK)
free(iso9660);
return (r);
}
return (ARCHIVE_OK);
return (r);
}
@@ -504,7 +497,7 @@ archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
{
struct iso9660 *iso9660 = a->format->data;
ssize_t bytes_read;
const unsigned char *p;
const unsigned char *h;
int seenTerminator;
/* If there's already a better bid than we can ever
@@ -518,41 +511,41 @@ archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
* if the I/O layer gives us more, we'll take it.
*/
#define RESERVED_AREA (SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE)
p = __archive_read_ahead(a,
h = __archive_read_ahead(a,
RESERVED_AREA + 8 * LOGICAL_BLOCK_SIZE,
&bytes_read);
if (p == NULL)
if (h == NULL)
return (-1);
/* Skip the reserved area. */
bytes_read -= RESERVED_AREA;
p += RESERVED_AREA;
h += RESERVED_AREA;
/* Check each volume descriptor. */
seenTerminator = 0;
for (; bytes_read > LOGICAL_BLOCK_SIZE;
bytes_read -= LOGICAL_BLOCK_SIZE, p += LOGICAL_BLOCK_SIZE) {
bytes_read -= LOGICAL_BLOCK_SIZE, h += LOGICAL_BLOCK_SIZE) {
/* Do not handle undefined Volume Descriptor Type. */
if (p[0] >= 4 && p[0] <= 254)
if (h[0] >= 4 && h[0] <= 254)
return (0);
/* Standard Identifier must be "CD001" */
if (memcmp(p + 1, "CD001", 5) != 0)
if (memcmp(h + 1, "CD001", 5) != 0)
return (0);
if (isPVD(iso9660, p))
if (isPVD(iso9660, h))
continue;
if (!iso9660->joliet.location) {
if (isJolietSVD(iso9660, p))
if (isJolietSVD(iso9660, h))
continue;
}
if (isBootRecord(p))
if (isBootRecord(h))
continue;
if (isEVD(p))
if (isEVD(h))
continue;
if (isSVD(p))
if (isSVD(h))
continue;
if (isVolumePartition(iso9660, p))
if (isVolumePartition(iso9660, h))
continue;
if (isVDSetTerminator(p)) {
if (isVDSetTerminator(h)) {
seenTerminator = 1;
break;
}
@@ -1517,8 +1510,7 @@ zisofs_read_data(struct archive_read *a,
if (zisofs->block_pointers_alloc < xsize) {
size_t alloc;
if (zisofs->block_pointers != NULL)
free(zisofs->block_pointers);
free(zisofs->block_pointers);
alloc = ((xsize >> 10) + 1) << 10;
zisofs->block_pointers = malloc(alloc);
if (zisofs->block_pointers == NULL) {
@@ -1533,8 +1525,7 @@ zisofs_read_data(struct archive_read *a,
/* Allocate uncompressed data buffer. */
xsize = (size_t)1UL << zisofs->pz_log2_bs;
if (zisofs->uncompressed_buffer_size < xsize) {
if (zisofs->uncompressed_buffer != NULL)
free(zisofs->uncompressed_buffer);
free(zisofs->uncompressed_buffer);
zisofs->uncompressed_buffer = malloc(xsize);
if (zisofs->uncompressed_buffer == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -2194,7 +2185,7 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
* 8 byte offset w/in above sector
* 8 byte length of continuation
*/
int32_t location =
uint32_t location =
archive_le32dec(data);
file->ce_offset =
archive_le32dec(data+8);
@@ -2341,22 +2332,24 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
}
static int
register_CE(struct archive_read *a, int32_t location,
register_CE(struct archive_read *a, uint32_t location,
struct file_info *file)
{
struct iso9660 *iso9660 = a->format->data;
struct read_ce_queue *heap;
uint64_t offset, parent_offset;
uint64_t offset, parent_offset, ce_end;
size_t hole, parent;
offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;
if (((file->mode & AE_IFMT) == AE_IFREG &&
if (archive_ckd_mul_u64(&offset, (uint64_t)location,
(uint64_t)iso9660->logical_block_size) ||
archive_ckd_add_u64(&ce_end, offset,
((uint64_t)file->ce_offset) + file->ce_size) ||
((file->mode & AE_IFMT) == AE_IFREG &&
offset >= file->offset) ||
offset < iso9660->current_position ||
(((uint64_t)file->ce_offset) + file->ce_size)
> (uint64_t)iso9660->logical_block_size ||
offset + file->ce_offset + file->ce_size
> iso9660->volume_size) {
ce_end > iso9660->volume_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid parameter in SUSP \"CE\" extension");
return (ARCHIVE_FATAL);
@@ -3061,14 +3054,28 @@ re_get_entry(struct iso9660 *iso9660)
static inline int
rede_add_entry(struct file_info *file)
{
struct file_info *re;
struct file_info *re, *slow;
int slow_turn = 0;
/*
* Find "RE" entry.
*
* A malformed image can chain "CL"/"RE" reparenting so that the
* parent pointers form a cycle in which no node carries the "re"
* flag. Advance a second pointer at half speed (Floyd's cycle
* detection) so such a loop is reported as a malformed archive
* instead of spinning forever.
*/
re = file->parent;
while (re != NULL && !re->re)
re = slow = file->parent;
while (re != NULL && !re->re) {
re = re->parent;
if (slow_turn) {
slow = slow->parent;
if (re == slow)
return (-1); /* Cyclic parent chain. */
}
slow_turn = !slow_turn;
}
if (re == NULL)
return (-1);
@@ -206,10 +206,12 @@ struct lha {
* LHA header common member offset.
*/
#define H_METHOD_OFFSET 2 /* Compress type. */
#define H_ATTR_OFFSET 19 /* DOS attribute. */
#define H_ATTR_OFFSET 19 /* AmigaDOS or DOS attributes. */
#define H_LEVEL_OFFSET 20 /* Header Level. */
#define H_SIZE 22 /* Minimum header size. */
#define SFX_MAX_READAHEAD (1024 * 512)
static int archive_read_format_lha_bid(struct archive_read *, int);
static int archive_read_format_lha_options(struct archive_read *,
const char *, const char *);
@@ -228,7 +230,7 @@ static int lha_read_file_header_2(struct archive_read *, struct lha *);
static int lha_read_file_header_3(struct archive_read *, struct lha *);
static int lha_read_file_extended_header(struct archive_read *,
struct lha *, uint16_t *, int, uint64_t, size_t *);
static size_t lha_check_header_format(const void *);
static size_t lha_check_header_format(const char *);
static int lha_skip_sfx(struct archive_read *);
static unsigned char lha_calcsum(unsigned char, const void *,
int, size_t);
@@ -264,8 +266,7 @@ archive_read_support_format_lha(struct archive *_a)
lha = calloc(1, sizeof(*lha));
if (lha == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate lha data");
archive_set_error(_a, ENOMEM, "Can't allocate lha data");
return (ARCHIVE_FATAL);
}
archive_string_init(&lha->ws);
@@ -285,16 +286,15 @@ archive_read_support_format_lha(struct archive *_a)
if (r != ARCHIVE_OK)
free(lha);
return (ARCHIVE_OK);
return (r);
}
static size_t
lha_check_header_format(const void *h)
lha_check_header_format(const char *h)
{
const unsigned char *p = h;
size_t next_skip_bytes;
switch (p[H_METHOD_OFFSET+3]) {
switch (h[H_METHOD_OFFSET + 3]) {
/*
* "-lh0-" ... "-lh7-" "-lhd-"
* "-lzs-" "-lz5-"
@@ -305,29 +305,27 @@ lha_check_header_format(const void *h)
case 's':
next_skip_bytes = 4;
/* b0 == 0 means the end of an LHa archive file. */
if (p[0] == 0)
/* 0 means the end of an LHa archive file. */
if (h[0] == 0)
break;
if (p[H_METHOD_OFFSET] != '-' || p[H_METHOD_OFFSET+1] != 'l'
|| p[H_METHOD_OFFSET+4] != '-')
if (h[H_METHOD_OFFSET] != '-' || h[H_METHOD_OFFSET + 1] != 'l'
|| h[H_METHOD_OFFSET + 4] != '-')
break;
if (p[H_METHOD_OFFSET+2] == 'h') {
if (h[H_METHOD_OFFSET + 2] == 'h') {
/* "-lh?-" */
if (p[H_METHOD_OFFSET+3] == 's')
if (h[H_METHOD_OFFSET + 3] == 's')
break;
if (p[H_LEVEL_OFFSET] == 0)
return (0);
if (p[H_LEVEL_OFFSET] <= 3 && p[H_ATTR_OFFSET] == 0x20)
if (h[H_LEVEL_OFFSET] <= 3)
return (0);
}
if (p[H_METHOD_OFFSET+2] == 'z') {
if (h[H_METHOD_OFFSET + 2] == 'z') {
/* LArc extensions: -lzs-,-lz4- and -lz5- */
if (p[H_LEVEL_OFFSET] != 0)
if (h[H_LEVEL_OFFSET] != 0)
break;
if (p[H_METHOD_OFFSET+3] == 's'
|| p[H_METHOD_OFFSET+3] == '4'
|| p[H_METHOD_OFFSET+3] == '5')
if (h[H_METHOD_OFFSET + 3] == 's'
|| h[H_METHOD_OFFSET + 3] == '4'
|| h[H_METHOD_OFFSET + 3] == '5')
return (0);
}
break;
@@ -344,43 +342,46 @@ lha_check_header_format(const void *h)
static int
archive_read_format_lha_bid(struct archive_read *a, int best_bid)
{
const char *p;
const void *buff;
ssize_t bytes_avail, offset, window;
size_t next;
const char *h;
/* If there's already a better bid than we can ever
make, don't bother testing. */
if (best_bid > 30)
return (-1);
if ((p = __archive_read_ahead(a, H_SIZE, NULL)) == NULL)
if ((h = __archive_read_ahead(a, H_SIZE, NULL)) == NULL)
return (-1);
if (lha_check_header_format(p) == 0)
if (lha_check_header_format(h) == 0)
return (30);
if (p[0] == 'M' && p[1] == 'Z') {
if (h[0] == 'M' && h[1] == 'Z') {
ssize_t offset, window;
/* PE file */
offset = 0;
window = 4096;
while (offset < (1024 * 20)) {
buff = __archive_read_ahead(a, offset + window,
while (offset + window <= SFX_MAX_READAHEAD) {
ssize_t bytes_avail;
h = __archive_read_ahead(a, offset + window,
&bytes_avail);
if (buff == NULL) {
/* Remaining bytes are less than window. */
window >>= 1;
if (window < (H_SIZE + 3))
return (0);
continue;
if (h == NULL) {
if (bytes_avail >= offset + H_SIZE) {
/* Remaining bytes are less than window. */
window = bytes_avail - offset;
continue;
}
return (0);
}
p = (const char *)buff + offset;
while (p + H_SIZE < (const char *)buff + bytes_avail) {
if ((next = lha_check_header_format(p)) == 0)
if (bytes_avail > SFX_MAX_READAHEAD)
bytes_avail = SFX_MAX_READAHEAD;
while (offset <= bytes_avail - H_SIZE) {
size_t next = lha_check_header_format(h + offset);
if (next == 0)
return (30);
p += next;
offset += next;
}
offset = p - (const char *)buff;
}
}
return (0);
@@ -474,7 +475,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
struct lha *lha = a->format->data;
struct archive_wstring linkname;
struct archive_wstring pathname;
const unsigned char *p;
const char *p;
const char *signature;
int err;
struct archive_mstring conv_buffer;
@@ -500,7 +501,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
return (truncated_error(a));
}
signature = (const char *)p;
signature = p;
if (lha->found_first_header == 0 &&
signature[0] == 'M' && signature[1] == 'Z') {
/* This is an executable? Must be self-extracting... */
@@ -510,7 +511,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
return (truncated_error(a));
signature = (const char *)p;
signature = p;
}
/* signature[0] == 0 means the end of an LHa archive file. */
if (signature[0] == 0)
@@ -588,6 +589,9 @@ archive_read_format_lha_read_header(struct archive_read *a,
if (err < ARCHIVE_WARN)
return (err);
if (!lha->directory && archive_strlen(&lha->filename) == 0)
if (memcmp(lha->method, "lh0", 3) == 0 && archive_strlen(&lha->dirname) > 0)
lha->directory = 1; /* empty directory entry */
if (!lha->directory && archive_strlen(&lha->filename) == 0)
/* The filename has not been set */
@@ -812,7 +816,7 @@ lha_read_file_header_0(struct archive_read *a, struct lha *lha)
headersum = p[H0_HEADER_SUM_OFFSET];
lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET);
lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET);
lha->mtime = dos_to_unix(archive_le32dec(p + H0_DOS_TIME_OFFSET));
lha->mtime = __archive_dos_to_unix(archive_le32dec(p + H0_DOS_TIME_OFFSET));
namelen = p[H0_NAME_LEN_OFFSET];
extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen;
if ((namelen > 221 || extdsize < 0) && extdsize != -2) {
@@ -912,7 +916,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
/* Note: An extended header size is included in a compsize. */
lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET);
lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET);
lha->mtime = dos_to_unix(archive_le32dec(p + H1_DOS_TIME_OFFSET));
lha->mtime = __archive_dos_to_unix(archive_le32dec(p + H1_DOS_TIME_OFFSET));
namelen = p[H1_NAME_LEN_OFFSET];
/* Calculate a padding size. The result will be normally 0 only(?) */
padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen;
@@ -1325,15 +1329,15 @@ lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
break;
case EXT_TIMESTAMP:
if (datasize == (sizeof(uint64_t) * 3)) {
ntfs_to_unix(archive_le64dec(extdheader),
__archive_ntfs_to_unix(archive_le64dec(extdheader),
&lha->birthtime,
&lha->birthtime_tv_nsec);
extdheader += sizeof(uint64_t);
ntfs_to_unix(archive_le64dec(extdheader),
__archive_ntfs_to_unix(archive_le64dec(extdheader),
&lha->mtime,
&lha->mtime_tv_nsec);
extdheader += sizeof(uint64_t);
ntfs_to_unix(archive_le64dec(extdheader),
__archive_ntfs_to_unix(archive_le64dec(extdheader),
&lha->atime,
&lha->atime_tv_nsec);
lha->setflag |= BIRTHTIME_IS_SET |
@@ -1342,11 +1346,19 @@ lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
break;
case EXT_FILESIZE:
if (datasize == sizeof(uint64_t) * 2) {
lha->compsize = archive_le64dec(extdheader);
uint64_t compsize, origsize;
/* Range-check before the conversion to the
* signed type rather than relying on the
* implementation-defined result of it. */
compsize = archive_le64dec(extdheader);
extdheader += sizeof(uint64_t);
lha->origsize = archive_le64dec(extdheader);
if (lha->compsize < 0 || lha->origsize < 0)
origsize = archive_le64dec(extdheader);
if (compsize > INT64_MAX ||
origsize > INT64_MAX)
goto invalid;
lha->compsize = (int64_t)compsize;
lha->origsize = (int64_t)origsize;
}
break;
case EXT_CODEPAGE:
@@ -1551,7 +1563,7 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
struct lha *lha = a->format->data;
ssize_t bytes_avail;
ssize_t bytes_avail, max_in;
int r;
/* If we haven't yet read any data, initialize the decompressor. */
@@ -1598,6 +1610,17 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
if (bytes_avail > lha->entry_bytes_remaining)
bytes_avail = (ssize_t)lha->entry_bytes_remaining;
/* Setup buffer boundaries. strm.avail_in is an int, and the
* compressed size it is bounded by comes straight from the LHa
* header, so clamp the available byte count before the
* assignment. */
if (INT_MAX >= SSIZE_MAX)
max_in = SSIZE_MAX;
else
max_in = INT_MAX;
if (bytes_avail > max_in)
bytes_avail = max_in;
lha->strm.avail_in = (int)bytes_avail;
lha->strm.total_in = 0;
lha->strm.avail_out = 0;
@@ -91,6 +91,7 @@ struct mtree_option {
struct mtree_entry {
struct archive_rb_node rbnode;
struct mtree_entry *next_dup;
struct mtree_entry *last_dup;
struct mtree_entry *next;
struct mtree_option *options;
char *name;
@@ -108,7 +109,6 @@ struct mtree {
const char *archive_format_name;
struct mtree_entry *entries;
struct mtree_entry *this_entry;
struct archive_rb_tree entry_rbtree;
struct archive_string current_dir;
struct archive_string contents_name;
@@ -224,8 +224,7 @@ archive_read_support_format_mtree(struct archive *_a)
mtree = calloc(1, sizeof(*mtree));
if (mtree == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate mtree data");
archive_set_error(_a, ENOMEM, "Can't allocate mtree data");
return (ARCHIVE_FATAL);
}
mtree->checkfs = 0;
@@ -233,12 +232,22 @@ archive_read_support_format_mtree(struct archive *_a)
__archive_rb_tree_init(&mtree->rbtree, &rb_ops);
r = __archive_read_register_format(a, mtree, "mtree",
mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup, NULL, NULL);
r = __archive_read_register_format(a,
mtree,
"mtree",
mtree_bid,
archive_read_format_mtree_options,
read_header,
read_data,
skip,
NULL,
cleanup,
NULL,
NULL);
if (r != ARCHIVE_OK)
free(mtree);
return (ARCHIVE_OK);
return (r);
}
static int
@@ -620,16 +629,16 @@ static int
mtree_bid(struct archive_read *a, int best_bid)
{
const char *signature = "#mtree";
const char *p;
const void *h;
(void)best_bid; /* UNUSED */
/* Now let's look at the actual header and see if it matches. */
p = __archive_read_ahead(a, strlen(signature), NULL);
if (p == NULL)
h = __archive_read_ahead(a, strlen(signature), NULL);
if (h == NULL)
return (-1);
if (memcmp(p, signature, strlen(signature)) == 0)
if (memcmp(h, signature, strlen(signature)) == 0)
return (8 * (int)strlen(signature));
/*
@@ -940,15 +949,15 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
parse_escapes(entry->name, entry);
entry->next_dup = NULL;
entry->last_dup = entry;
if (entry->full) {
if (!__archive_rb_tree_insert_node(&mtree->rbtree, &entry->rbnode)) {
struct mtree_entry *alt;
alt = (struct mtree_entry *)__archive_rb_tree_find_node(
&mtree->rbtree, entry->name);
if (alt != NULL) {
while (alt->next_dup)
alt = alt->next_dup;
alt->next_dup = entry;
alt->last_dup->next_dup = entry;
alt->last_dup = entry;
}
}
}
@@ -1067,7 +1076,6 @@ static int
read_header(struct archive_read *a, struct archive_entry *entry)
{
struct mtree *mtree = a->format->data;
char *p;
int r, use_next;
if (mtree->fd >= 0) {
@@ -1096,14 +1104,9 @@ read_header(struct archive_read *a, struct archive_entry *entry)
mtree->this_entry->used = 1;
if (archive_strlen(&mtree->current_dir) > 0) {
/* Roll back current path. */
p = mtree->current_dir.s
+ mtree->current_dir.length - 1;
while (p >= mtree->current_dir.s && *p != '/')
--p;
if (p >= mtree->current_dir.s)
--p;
mtree->current_dir.length
= p - mtree->current_dir.s + 1;
archive_string_dirname(&mtree->current_dir);
if (strcmp(mtree->current_dir.s, ".") == 0)
archive_string_empty(&mtree->current_dir);
}
}
if (!mtree->this_entry->used) {
@@ -1429,7 +1432,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
* Decode and pack it accordingly.
*/
*dev++ = '\0';
if ((pack = pack_find(val)) == NULL) {
if ((pack = __archive_pack_find(val)) == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
"Unknown format `%s'", val);
return ARCHIVE_WARN;
@@ -1709,6 +1712,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
ARCHIVE_ENTRY_DIGEST_SHA512);
}
if (strcmp(key, "size") == 0) {
*parsed_kws |= MTREE_HAS_SIZE;
archive_entry_set_size(entry, mtree_atol(&val, 10));
return (ARCHIVE_OK);
}
@@ -36,9 +36,7 @@
#endif
#include "archive.h"
#ifndef HAVE_ZLIB_H
#include "archive_crc32.h"
#endif
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
@@ -136,6 +134,8 @@
#define MAX_SYMBOL_LENGTH 0xF
#define MAX_SYMBOLS 20
#define SFX_MAX_READAHEAD (1024 * 512)
/* Virtual Machine Properties */
#define VM_MEMORY_SIZE 0x40000
#define VM_MEMORY_MASK (VM_MEMORY_SIZE - 1)
@@ -328,7 +328,6 @@ struct rar
unsigned int unp_buffer_size;
unsigned char *unp_buffer;
unsigned int dictionary_size;
char start_new_block;
char entry_eof;
unsigned long crc_calculated;
int found_first_header;
@@ -736,7 +735,7 @@ archive_read_support_format_rar(struct archive *_a)
rar = calloc(1, sizeof(*rar));
if (rar == NULL)
{
archive_set_error(&a->archive, ENOMEM, "Can't allocate rar data");
archive_set_error(_a, ENOMEM, "Can't allocate rar data");
return (ARCHIVE_FATAL);
}
@@ -747,17 +746,17 @@ archive_read_support_format_rar(struct archive *_a)
rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
r = __archive_read_register_format(a,
rar,
"rar",
archive_read_format_rar_bid,
archive_read_format_rar_options,
archive_read_format_rar_read_header,
archive_read_format_rar_read_data,
archive_read_format_rar_read_data_skip,
archive_read_format_rar_seek_data,
archive_read_format_rar_cleanup,
archive_read_support_format_rar_capabilities,
archive_read_format_rar_has_encrypted_entries);
rar,
"rar",
archive_read_format_rar_bid,
archive_read_format_rar_options,
archive_read_format_rar_read_header,
archive_read_format_rar_read_data,
archive_read_format_rar_read_data_skip,
archive_read_format_rar_seek_data,
archive_read_format_rar_cleanup,
archive_read_support_format_rar_capabilities,
archive_read_format_rar_has_encrypted_entries);
if (r != ARCHIVE_OK)
free(rar);
@@ -788,39 +787,41 @@ archive_read_format_rar_has_encrypted_entries(struct archive_read *_a)
static int
archive_read_format_rar_bid(struct archive_read *a, int best_bid)
{
const char *p;
const char *h;
/* If there's already a bid > 30, we'll never win. */
if (best_bid > 30)
return (-1);
if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
return (-1);
if (memcmp(p, RAR_SIGNATURE, 7) == 0)
if (memcmp(h, RAR_SIGNATURE, 7) == 0)
return (30);
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
if ((h[0] == 'M' && h[1] == 'Z') || memcmp(h, "\x7F\x45LF", 4) == 0) {
/* This is a PE file */
ssize_t offset = 0x10000;
ssize_t window = 4096;
ssize_t bytes_avail;
while (offset + window <= (1024 * 128)) {
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;
while (offset + window <= SFX_MAX_READAHEAD) {
h = __archive_read_ahead(a, offset + window, &bytes_avail);
if (h == NULL) {
if (bytes_avail >= offset + 0x10) {
/* Remaining bytes are less than window. */
window = bytes_avail - offset;
continue;
}
return (0);
}
p = buff + offset;
while (p + 7 < buff + bytes_avail) {
if (memcmp(p, RAR_SIGNATURE, 7) == 0)
if (bytes_avail > SFX_MAX_READAHEAD)
bytes_avail = SFX_MAX_READAHEAD;
while (offset <= bytes_avail - 7) {
if (memcmp(h + offset, RAR_SIGNATURE, 7) == 0)
return (30);
p += 0x10;
offset += 0x10;
}
offset = p - buff;
}
}
return (0);
@@ -836,7 +837,7 @@ skip_sfx(struct archive_read *a)
total = 0;
window = 4096;
while (total + window <= (1024 * 128)) {
while (total + window <= SFX_MAX_READAHEAD) {
h = __archive_read_ahead(a, window, &bytes);
if (h == NULL) {
/* Remaining bytes are less than window. */
@@ -1005,7 +1006,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
return (ARCHIVE_FATAL);
}
crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
crc32_val = __archive_crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
if ((crc32_val & 0xffff) != archive_le16dec(p)) {
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1064,7 +1065,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
return (ARCHIVE_FATAL);
}
p = h;
crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read);
crc32_val = __archive_crc32(crc32_val, (const unsigned char *)p, to_read);
__archive_read_consume(a, to_read);
skip -= to_read;
}
@@ -1403,7 +1404,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
"Invalid header size");
return (ARCHIVE_FATAL);
}
crc32_computed = crc32(0, (const unsigned char *)p + 2, 7 - 2);
crc32_computed = __archive_crc32(0, (const unsigned char *)p + 2, 7 - 2);
__archive_read_consume(a, 7);
if (!(rar->file_flags & FHD_SOLID))
@@ -1441,7 +1442,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
}
/* File Header CRC check. */
crc32_computed = crc32(crc32_computed, h, (unsigned)(header_size - 7));
crc32_computed = __archive_crc32(crc32_computed, h, (unsigned)(header_size - 7));
crc32_read = archive_le16dec(rar_header.crc);
if ((crc32_computed & 0xffff) != crc32_read) {
#ifndef DONT_FAIL_ON_CRC_ERROR
@@ -1510,12 +1511,14 @@ read_header(struct archive_read *a, struct archive_entry *entry,
* consumed at the end.
*/
if (head_type == NEWSUB_HEAD) {
if (rar->packed_size > INT64_MAX - header_size) {
int64_t skip;
if (archive_ckd_add_i64(&skip, rar->packed_size, header_size) ||
skip < 7) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid RAR file: Overlarge extended header");
return (ARCHIVE_FATAL);
}
if (__archive_read_consume(a, header_size + rar->packed_size - 7) < 0) {
if (__archive_read_consume(a, skip - 7) < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid RAR file: Cannot read extended header data");
return (ARCHIVE_FATAL);
@@ -1866,7 +1869,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
static time_t
get_time(int ttime)
{
struct tm tm;
struct tm tm = { 0 };
tm.tm_sec = 2 * (ttime & 0x1f);
tm.tm_min = (ttime >> 5) & 0x3f;
tm.tm_hour = (ttime >> 11) & 0x1f;
@@ -2037,7 +2040,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
rar->bytes_remaining -= bytes_avail;
rar->bytes_unconsumed = bytes_avail;
/* Calculate File CRC. */
rar->crc_calculated = crc32(rar->crc_calculated, *buff,
rar->crc_calculated = __archive_crc32(rar->crc_calculated, *buff,
(unsigned)bytes_avail);
return (ARCHIVE_OK);
}
@@ -2096,7 +2099,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
*offset = rar->offset_outgoing;
rar->offset_outgoing += *size;
/* Calculate File CRC. */
rar->crc_calculated = crc32(rar->crc_calculated, *buff,
rar->crc_calculated = __archive_crc32(rar->crc_calculated, *buff,
(unsigned)*size);
rar->unp_offset = 0;
return (ARCHIVE_OK);
@@ -2132,7 +2135,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
*offset = rar->offset_outgoing;
rar->offset_outgoing += *size;
/* Calculate File CRC. */
rar->crc_calculated = crc32(rar->crc_calculated, *buff,
rar->crc_calculated = __archive_crc32(rar->crc_calculated, *buff,
(unsigned)*size);
return (ret);
}
@@ -2291,7 +2294,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
rar->offset_outgoing += *size;
ending_block:
/* Calculate File CRC. */
rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size);
rar->crc_calculated = __archive_crc32(rar->crc_calculated, *buff, (unsigned)*size);
return ret;
}
@@ -2993,7 +2996,6 @@ expand(struct archive_read *a, int64_t *end)
if(newfile)
{
rar->start_new_block = 1;
if (!rar_br_read_ahead(a, br, 1))
goto truncated_data;
rar->start_new_table = rar_br_bits(br, 1);
@@ -3477,8 +3479,11 @@ run_filters(struct archive_read *a)
if (tend < 0)
return 0;
end = (size_t)tend;
if (end != start + filter->blocklength)
if (end != start + filter->blocklength) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file data: filter block was not fully decompressed");
return 0;
}
if (!filters->vm)
{
@@ -3554,7 +3559,7 @@ compile_program(const uint8_t *bytes, size_t length)
prog = calloc(1, sizeof(*prog));
if (!prog)
return NULL;
prog->fingerprint = crc32(0, bytes, (unsigned int)length) | ((uint64_t)length << 32);
prog->fingerprint = __archive_crc32(0, bytes, (unsigned int)length) | ((uint64_t)length << 32);
if (membr_bits(&br, 1))
{
@@ -3712,7 +3717,9 @@ execute_filter_delta(struct rar_filter *filter, struct rar_virtual_machine *vm)
uint8_t *src, *dst;
uint32_t i, idx;
if (length > PROGRAM_WORK_SIZE / 2)
if (length > PROGRAM_WORK_SIZE / 2 ||
numchannels == 0 ||
numchannels > 128)
return 0;
src = &vm->memory[0];
@@ -3827,7 +3834,9 @@ execute_filter_audio(struct rar_filter *filter, struct rar_virtual_machine *vm)
uint8_t *src, *dst;
uint32_t i, j;
if (length > PROGRAM_WORK_SIZE / 2)
if (length > PROGRAM_WORK_SIZE / 2 ||
numchannels == 0 ||
numchannels > 128)
return 0;
src = &vm->memory[0];
@@ -38,9 +38,7 @@
#endif
#include "archive.h"
#ifndef HAVE_ZLIB_H
#include "archive_crc32.h"
#endif
#include "archive_entry.h"
#include "archive_entry_locale.h"
@@ -87,11 +85,24 @@ static const unsigned char rar5_signature_xor[] = {
};
static const size_t g_unpack_window_size = 0x20000;
/* Bid returned when the RAR5 signature is found at offset 0. Bidders
* conventionally return the number of bits they verified, so an exact
* match of the 8-byte signature bids 64 (like the ar and warc readers
* do for their 8-byte magics). This must stay above the seekable Zip
* bidder's 32 so that a RAR archive which merely stores an uncompressed
* Zip is still recognized as RAR (see issue #2249). The weaker SFX
* heuristic, which only scans for the signature somewhere inside an
* executable, deliberately keeps its lower bid of 30. */
#define RAR5_SIGNATURE_BID ((int)(8 * sizeof(rar5_signature_xor)))
/* These could have been static const's, but they aren't, because of
* Visual Studio. */
#define MAX_NAME_IN_CHARS 2048
#define MAX_NAME_IN_BYTES (4 * MAX_NAME_IN_CHARS)
/* maximum header size for RAR5 is 2MB */
#define MAX_HEADER_SIZE (2 * 1024 * 1024)
struct file_header {
ssize_t bytes_remaining;
ssize_t unpacked_size;
@@ -152,6 +163,8 @@ enum REDIR_TYPE {
#define OWNER_GROUP_GID 0x08
#define OWNER_MAXNAMELEN 256
#define SFX_MAX_READAHEAD (1024 * 512)
enum FILTER_TYPE {
FILTER_DELTA = 0, /* Generic pattern. */
FILTER_E8 = 1, /* Intel x86 code. */
@@ -404,7 +417,7 @@ static int cdeque_init(struct cdeque* d, int max_capacity_power_of_2) {
return CDE_PARAM;
cdeque_clear(d);
d->arr = malloc(sizeof(void*) * max_capacity_power_of_2);
d->arr = malloc(sizeof(size_t*) * max_capacity_power_of_2);
return d->arr ? CDE_OK : CDE_ALLOC;
}
@@ -889,16 +902,6 @@ static void reset_file_context(struct rar5 *rar5) {
free_filters(rar5);
}
static inline int get_archive_read(struct archive* a,
struct archive_read** ar)
{
*ar = (struct archive_read*) a;
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"archive_read_support_format_rar5");
return ARCHIVE_OK;
}
static int read_ahead(struct archive_read* a, size_t how_many,
const uint8_t** ptr)
{
@@ -914,13 +917,10 @@ static int read_ahead(struct archive_read* a, size_t how_many,
}
static int consume(struct archive_read* a, int64_t how_many) {
int ret;
if(__archive_read_consume(a, how_many) < 0)
return (ARCHIVE_FATAL);
ret = how_many == __archive_read_consume(a, how_many)
? ARCHIVE_OK
: ARCHIVE_FATAL;
return ret;
return (ARCHIVE_OK);
}
/**
@@ -935,9 +935,11 @@ static int consume(struct archive_read* a, int64_t how_many) {
* the number of bytes that `pvalue_len` value contains. If the `pvalue_len`
* is NULL, this consuming operation is done automatically.
*
* Returns 1 if *pvalue was successfully read.
* Returns 0 if there was an error. In this case, *pvalue contains an
* invalid value.
* In case of error (!ARCHIVE_OK), *pvalue contains an invalid value.
*
* Returns ARCHIVE_OK if *pvalue was successfully read.
* Returns ARCHIVE_FATAL if there was an error.
* Returns ARCHIVE_EOF if end of file was reached.
*/
static int read_var(struct archive_read* a, uint64_t* pvalue,
@@ -945,16 +947,36 @@ static int read_var(struct archive_read* a, uint64_t* pvalue,
{
uint64_t multiplier;
uint64_t result = 0;
size_t i;
size_t i, max_bytes;
ssize_t avail;
const uint8_t* p;
/* We will read maximum of 10 bytes. We don't have to handle the
* situation to read the RAR5 variable-sized value stored at the end of
* the file, because such situation will never happen. */
if(!read_ahead(a, 10, &p))
return 0;
/* We will read a maximum of 10 bytes, since that's the longest a
* RAR5 varint can legally be. Ask for a full 10-byte lookahead
* first, since that's the common case. However, a varint is
* self-terminating (a byte with the MSB clear ends the value, so
* most varints take far fewer than 10 bytes), and it's legal for
* one to end fewer than 10 bytes before the end of the archive --
* e.g. a file header's extra field butting up against ENDARC with
* no padding. If a full 10-byte lookahead isn't available, fall
* back to however many bytes actually remain and decode within
* that instead of failing outright; only reaching the real end of
* the archive with zero bytes left, or exhausting the available
* bytes without hitting a terminator, is a genuine error. */
max_bytes = 10;
p = __archive_read_ahead(a, max_bytes, &avail);
if(p == NULL) {
if(avail == 0)
return ARCHIVE_EOF;
if(avail < 1)
return ARCHIVE_FATAL;
max_bytes = (size_t)avail;
p = __archive_read_ahead(a, max_bytes, NULL);
if(p == NULL)
return ARCHIVE_FATAL;
}
for(multiplier = 1, i = 0; i < 10; i++, multiplier *= 128) {
for(multiplier = 1, i = 0; i < max_bytes; i++, multiplier *= 128) {
uint64_t val;
uint8_t b;
@@ -965,7 +987,9 @@ static int read_var(struct archive_read* a, uint64_t* pvalue,
if(archive_ckd_mul_u64(&val, b & 0x7F, multiplier) ||
archive_ckd_add_u64(&result, result, val)) {
/* Integer overflow occurred. */
return 0;
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Number too large");
return ARCHIVE_FATAL;
}
/* MSB set to 1 means we need to continue decoding process.
@@ -991,17 +1015,19 @@ static int read_var(struct archive_read* a, uint64_t* pvalue,
* needs to consume. This is why we handle
* such situation here automatically. */
if(ARCHIVE_OK != consume(a, 1 + i)) {
return 0;
return ARCHIVE_FATAL;
}
}
/* End of decoding process, return success. */
return 1;
return ARCHIVE_OK;
}
}
/* All continuation bits were set. This is an error. */
return 0;
/* Either all 10 bytes had their continuation bit set (a malformed
* varint), or fewer than 10 bytes were available and none of them
* terminated the value (a truncated archive). Both are errors. */
return ARCHIVE_FATAL;
}
static int read_var_sized(struct archive_read* a, size_t* pvalue,
@@ -1010,10 +1036,17 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
uint64_t v;
uint64_t v_size = 0;
const int ret = pvalue_len ? read_var(a, &v, &v_size)
: read_var(a, &v, NULL);
int ret = pvalue_len ? read_var(a, &v, &v_size)
: read_var(a, &v, NULL);
#if UINT64_MAX > SIZE_MAX
if(ret == ARCHIVE_OK && v > SIZE_MAX) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Number too large");
ret = ARCHIVE_FATAL;
}
#endif
if(ret == 1 && pvalue) {
if(ret == ARCHIVE_OK && pvalue) {
*pvalue = (size_t) v;
}
@@ -1111,52 +1144,55 @@ static char read_u64(struct archive_read* a, uint64_t* pvalue) {
}
static int bid_standard(struct archive_read* a) {
const uint8_t* p;
const uint8_t* h;
char signature[sizeof(rar5_signature_xor)];
rar5_signature(signature);
if(!read_ahead(a, sizeof(rar5_signature_xor), &p))
if(!read_ahead(a, sizeof(rar5_signature_xor), &h))
return -1;
if(!memcmp(signature, p, sizeof(rar5_signature_xor)))
return 30;
if(!memcmp(h, signature, sizeof(rar5_signature_xor)))
return RAR5_SIGNATURE_BID;
return -1;
}
static int bid_sfx(struct archive_read *a)
{
const char *p;
const char *h;
if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
return -1;
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
if ((h[0] == 'M' && h[1] == 'Z') || memcmp(h, "\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;
while (offset + window <= SFX_MAX_READAHEAD) {
ssize_t bytes_avail;
h = __archive_read_ahead(a, offset + window, &bytes_avail);
if (h == NULL) {
if (bytes_avail >= offset + 0x10) {
/* Remaining bytes are less than window. */
window = bytes_avail - offset;
continue;
}
return 0;
}
p = buff + offset;
while (p + 8 < buff + bytes_avail) {
if (memcmp(p, signature, sizeof(signature)) == 0)
if (bytes_avail > SFX_MAX_READAHEAD)
bytes_avail = SFX_MAX_READAHEAD;
while (offset <= bytes_avail - 8) {
if (memcmp(h + offset, signature,
sizeof(signature)) == 0)
return 30;
p += 0x10;
offset += 0x10;
}
offset = p - buff;
}
}
@@ -1166,7 +1202,7 @@ static int bid_sfx(struct archive_read *a)
static int rar5_bid(struct archive_read* a, int best_bid) {
int my_bid;
if(best_bid > 30)
if(best_bid >= RAR5_SIGNATURE_BID)
return -1;
my_bid = bid_standard(a);
@@ -1220,26 +1256,30 @@ static int process_main_locator_extra_block(struct archive_read* a,
struct rar5 *rar5)
{
uint64_t locator_flags;
int r;
enum LOCATOR_FLAGS {
QLIST = 0x01, RECOVERY = 0x02,
};
if(!read_var(a, &locator_flags, NULL)) {
return ARCHIVE_EOF;
r = read_var(a, &locator_flags, NULL);
if(r != ARCHIVE_OK) {
return r;
}
if(locator_flags & QLIST) {
if(!read_var(a, &rar5->qlist_offset, NULL)) {
return ARCHIVE_EOF;
r = read_var(a, &rar5->qlist_offset, NULL);
if(r != ARCHIVE_OK) {
return r;
}
/* qlist is not used */
}
if(locator_flags & RECOVERY) {
if(!read_var(a, &rar5->rr_offset, NULL)) {
return ARCHIVE_EOF;
r = read_var(a, &rar5->rr_offset, NULL);
if(r != ARCHIVE_OK) {
return r;
}
/* rr is not used */
@@ -1253,13 +1293,15 @@ static int parse_file_extra_hash(struct archive_read* a, struct rar5 *rar5,
{
size_t hash_type = 0;
size_t value_len;
int r;
enum HASH_TYPE {
BLAKE2sp = 0x00
};
if(!read_var_sized(a, &hash_type, &value_len))
return ARCHIVE_EOF;
r = read_var_sized(a, &hash_type, &value_len);
if(r != ARCHIVE_OK)
return r;
*extra_data_size -= value_len;
if(ARCHIVE_OK != consume(a, value_len)) {
@@ -1307,7 +1349,7 @@ static int parse_htime_item(struct archive_read* a, char unix_time,
if(!read_u64(a, &windows_time))
return ARCHIVE_EOF;
ntfs_to_unix(windows_time, sec, nsec);
__archive_ntfs_to_unix(windows_time, sec, nsec);
*extra_data_size -= 8;
}
@@ -1323,17 +1365,20 @@ static int parse_file_extra_version(struct archive_read* a,
struct archive_string version_string;
struct archive_string name_utf8_string;
const char* cur_filename;
int r;
/* Flags are ignored. */
if(!read_var_sized(a, &flags, &value_len))
return ARCHIVE_EOF;
r = read_var_sized(a, &flags, &value_len);
if(r != ARCHIVE_OK)
return r;
*extra_data_size -= value_len;
if(ARCHIVE_OK != consume(a, value_len))
return ARCHIVE_EOF;
if(!read_var_sized(a, &version, &value_len))
return ARCHIVE_EOF;
r = read_var_sized(a, &version, &value_len);
if(r != ARCHIVE_OK)
return r;
*extra_data_size -= value_len;
if(ARCHIVE_OK != consume(a, value_len))
@@ -1374,6 +1419,7 @@ static int parse_file_extra_htime(struct archive_read* a,
char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;
size_t flags = 0;
size_t value_len;
int ret;
enum HTIME_FLAGS {
IS_UNIX = 0x01,
@@ -1383,8 +1429,9 @@ static int parse_file_extra_htime(struct archive_read* a,
HAS_UNIX_NS = 0x10,
};
if(!read_var_sized(a, &flags, &value_len))
return ARCHIVE_EOF;
ret = read_var_sized(a, &flags, &value_len);
if(ret != ARCHIVE_OK)
return ret;
*extra_data_size -= value_len;
if(ARCHIVE_OK != consume(a, value_len)) {
@@ -1399,18 +1446,24 @@ static int parse_file_extra_htime(struct archive_read* a,
rar5->file.e_atime_ns = rar5->file.e_ctime_ns = rar5->file.e_mtime_ns = 0;
if(has_mtime) {
parse_htime_item(a, unix_time, &rar5->file.e_mtime,
ret = parse_htime_item(a, unix_time, &rar5->file.e_mtime,
&rar5->file.e_mtime_ns, extra_data_size);
if(ret != ARCHIVE_OK)
return ret;
}
if(has_ctime) {
parse_htime_item(a, unix_time, &rar5->file.e_ctime,
ret = parse_htime_item(a, unix_time, &rar5->file.e_ctime,
&rar5->file.e_ctime_ns, extra_data_size);
if(ret != ARCHIVE_OK)
return ret;
}
if(has_atime) {
parse_htime_item(a, unix_time, &rar5->file.e_atime,
ret = parse_htime_item(a, unix_time, &rar5->file.e_atime,
&rar5->file.e_atime_ns, extra_data_size);
if(ret != ARCHIVE_OK)
return ret;
}
if(has_mtime && has_unix_ns) {
@@ -1455,25 +1508,31 @@ static int parse_file_extra_redir(struct archive_read* a,
struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)
{
uint64_t value_size = 0;
size_t varint_len = 0;
size_t target_size = 0;
char target_utf8_buf[MAX_NAME_IN_BYTES];
const uint8_t* p;
int r;
if(!read_var(a, &rar5->file.redir_type, &value_size))
return ARCHIVE_EOF;
r = read_var(a, &rar5->file.redir_type, &value_size);
if(r != ARCHIVE_OK)
return r;
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
return ARCHIVE_EOF;
*extra_data_size -= value_size;
if(!read_var(a, &rar5->file.redir_flags, &value_size))
return ARCHIVE_EOF;
r = read_var(a, &rar5->file.redir_flags, &value_size);
if(r != ARCHIVE_OK)
return r;
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
return ARCHIVE_EOF;
*extra_data_size -= value_size;
if(!read_var_sized(a, &target_size, NULL))
r = read_var_sized(a, &target_size, &varint_len);
if(r != ARCHIVE_OK)
return r;
if(ARCHIVE_OK != consume(a, (int64_t)varint_len))
return ARCHIVE_EOF;
*extra_data_size -= target_size + 1;
if(target_size > (MAX_NAME_IN_CHARS - 1)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1487,6 +1546,14 @@ static int parse_file_extra_redir(struct archive_read* a,
return ARCHIVE_FATAL;
}
if((int64_t)(target_size + varint_len) > *extra_data_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Extra data size is too small for link target");
return ARCHIVE_FATAL;
}
*extra_data_size -= (int64_t)(target_size + varint_len);
if(!read_ahead(a, target_size, &p))
return ARCHIVE_EOF;
@@ -1530,19 +1597,35 @@ static int parse_file_extra_owner(struct archive_read* a,
uint64_t id = 0;
size_t name_len = 0;
size_t name_size = 0;
size_t varint_len = 0;
char namebuf[OWNER_MAXNAMELEN];
const uint8_t* p;
int r;
if(!read_var(a, &flags, &value_size))
return ARCHIVE_EOF;
r = read_var(a, &flags, &value_size);
if(r != ARCHIVE_OK)
return r;
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
return ARCHIVE_EOF;
*extra_data_size -= value_size;
if ((flags & OWNER_USER_NAME) != 0) {
if(!read_var_sized(a, &name_size, NULL))
r = read_var_sized(a, &name_size, &varint_len);
if(r != ARCHIVE_OK)
return r;
/* The name cannot be larger than the remaining extra data of
* this field. Rejecting an oversized length here also avoids
* requesting a huge allocation from read_ahead() below. */
if(*extra_data_size < 0 ||
name_size > (uint64_t)*extra_data_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Owner name is too long");
return ARCHIVE_FATAL;
}
if(ARCHIVE_OK != consume(a, (int64_t)varint_len))
return ARCHIVE_EOF;
*extra_data_size -= name_size + 1;
*extra_data_size -= (int64_t)(name_size + varint_len);
if(!read_ahead(a, name_size, &p))
return ARCHIVE_EOF;
@@ -1561,9 +1644,19 @@ static int parse_file_extra_owner(struct archive_read* a,
archive_entry_set_uname(e, namebuf);
}
if ((flags & OWNER_GROUP_NAME) != 0) {
if(!read_var_sized(a, &name_size, NULL))
r = read_var_sized(a, &name_size, &varint_len);
if(r != ARCHIVE_OK)
return r;
if(*extra_data_size < 0 ||
name_size > (uint64_t)*extra_data_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT, "Group name is too long");
return ARCHIVE_FATAL;
}
if(ARCHIVE_OK != consume(a, (int64_t)varint_len))
return ARCHIVE_EOF;
*extra_data_size -= name_size + 1;
*extra_data_size -= (int64_t)(name_size + varint_len);
if(!read_ahead(a, name_size, &p))
return ARCHIVE_EOF;
@@ -1582,8 +1675,9 @@ static int parse_file_extra_owner(struct archive_read* a,
archive_entry_set_gname(e, namebuf);
}
if ((flags & OWNER_USER_UID) != 0) {
if(!read_var(a, &id, &value_size))
return ARCHIVE_EOF;
r = read_var(a, &id, &value_size);
if(r != ARCHIVE_OK)
return r;
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
return ARCHIVE_EOF;
*extra_data_size -= value_size;
@@ -1591,8 +1685,9 @@ static int parse_file_extra_owner(struct archive_read* a,
archive_entry_set_uid(e, (la_int64_t)id);
}
if ((flags & OWNER_GROUP_GID) != 0) {
if(!read_var(a, &id, &value_size))
return ARCHIVE_EOF;
r = read_var(a, &id, &value_size);
if(r != ARCHIVE_OK)
return r;
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
return ARCHIVE_EOF;
*extra_data_size -= value_size;
@@ -1610,20 +1705,24 @@ static int process_head_file_extra(struct archive_read* a,
uint64_t var_size;
while(extra_data_size > 0) {
int r;
/* Make sure we won't fail if the file declares only unsupported
attributes. */
int ret = ARCHIVE_OK;
if(!read_var(a, &extra_field_size, &var_size))
return ARCHIVE_EOF;
r = read_var(a, &extra_field_size, &var_size);
if(r != ARCHIVE_OK)
return r;
extra_data_size -= var_size;
if(ARCHIVE_OK != consume(a, var_size)) {
return ARCHIVE_EOF;
}
if(!read_var(a, &extra_field_id, &var_size))
return ARCHIVE_EOF;
r = read_var(a, &extra_field_id, &var_size);
if(r != ARCHIVE_OK)
return r;
extra_field_size -= var_size;
extra_data_size -= var_size;
@@ -1662,6 +1761,12 @@ static int process_head_file_extra(struct archive_read* a,
/* fallthrough */
default:
/* Skip unsupported entry. */
if (extra_field_size > (uint64_t)extra_data_size) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"RAR5 extra-field size exceeds remaining extra-field data");
return ARCHIVE_FATAL;
}
extra_data_size -= extra_field_size;
if (ARCHIVE_OK != consume(a, extra_field_size)) {
return ARCHIVE_EOF;
@@ -1734,6 +1839,7 @@ static int process_head_file(struct archive_read* a, struct rar5 *rar5,
char name_utf8_buf[MAX_NAME_IN_BYTES];
const uint8_t* p;
int sanity_ret;
int r;
enum FILE_FLAGS {
DIRECTORY = 0x0001, UTIME = 0x0002, CRC32 = 0x0004,
@@ -1763,16 +1869,32 @@ static int process_head_file(struct archive_read* a, struct rar5 *rar5,
if(block_flags & HFL_EXTRA_DATA) {
uint64_t edata_size = 0;
if(!read_var(a, &edata_size, NULL))
return ARCHIVE_EOF;
r = read_var(a, &edata_size, NULL);
if(r != ARCHIVE_OK)
return r;
/* The extra area is part of the file header, which
* process_base_block() has already bounded to MAX_HEADER_SIZE.
* A declared extra-area size larger than that cannot be valid,
* and if left unchecked it is later used as the ceiling for
* the owner/group name length in parse_file_extra_owner(),
* letting a crafted archive drive read_ahead() into an
* attacker-controlled allocation. Reject it here. */
if(edata_size > MAX_HEADER_SIZE) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"File extra data size is too large");
return ARCHIVE_FATAL;
}
/* Intentional type cast from unsigned to signed. */
extra_data_size = (int64_t) edata_size;
}
if(block_flags & HFL_DATA) {
if(!read_var_sized(a, &data_size, NULL))
return ARCHIVE_EOF;
r = read_var_sized(a, &data_size, NULL);
if(r != ARCHIVE_OK)
return r;
if(data_size > SSIZE_MAX) {
archive_set_error(&a->archive,
@@ -1786,11 +1908,13 @@ static int process_head_file(struct archive_read* a, struct rar5 *rar5,
rar5->file.bytes_remaining = 0;
}
if(!read_var_sized(a, &file_flags, NULL))
return ARCHIVE_EOF;
r = read_var_sized(a, &file_flags, NULL);
if(r != ARCHIVE_OK)
return r;
if(!read_var(a, &unpacked_size, NULL))
return ARCHIVE_EOF;
r = read_var(a, &unpacked_size, NULL);
if(r != ARCHIVE_OK)
return r;
if(file_flags & UNKNOWN_UNPACKED_SIZE) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
@@ -1807,8 +1931,9 @@ static int process_head_file(struct archive_read* a, struct rar5 *rar5,
return sanity_ret;
}
if(!read_var_sized(a, &file_attr, NULL))
return ARCHIVE_EOF;
r = read_var_sized(a, &file_attr, NULL);
if(r != ARCHIVE_OK)
return r;
if(file_flags & UTIME) {
if(!read_u32(a, &mtime))
@@ -1820,8 +1945,9 @@ static int process_head_file(struct archive_read* a, struct rar5 *rar5,
return ARCHIVE_EOF;
}
if(!read_var_sized(a, &compression_info, NULL))
return ARCHIVE_EOF;
r = read_var_sized(a, &compression_info, NULL);
if(r != ARCHIVE_OK)
return r;
c_method = (int) (compression_info >> 7) & 0x7;
c_version = (int) (compression_info & 0x3f);
@@ -1912,8 +2038,9 @@ static int process_head_file(struct archive_read* a, struct rar5 *rar5,
rar5->file.service = 0;
if(!read_var_sized(a, &host_os, NULL))
return ARCHIVE_EOF;
r = read_var_sized(a, &host_os, NULL);
if(r != ARCHIVE_OK)
return r;
if(host_os == HOST_WINDOWS) {
/* Host OS is Windows */
@@ -1964,8 +2091,9 @@ static int process_head_file(struct archive_read* a, struct rar5 *rar5,
return ARCHIVE_FATAL;
}
if(!read_var_sized(a, &name_size, NULL))
return ARCHIVE_EOF;
r = read_var_sized(a, &name_size, NULL);
if(r != ARCHIVE_OK)
return r;
if(name_size > (MAX_NAME_IN_CHARS - 1)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -2093,14 +2221,17 @@ static int process_head_main(struct archive_read* a, struct rar5 *rar5,
(void) entry;
if(block_flags & HFL_EXTRA_DATA) {
if(!read_var(a, &extra_data_size, NULL))
return ARCHIVE_EOF;
int r;
r = read_var(a, &extra_data_size, NULL);
if(r != ARCHIVE_OK)
return r;
} else {
extra_data_size = 0;
}
if(!read_var_sized(a, &archive_flags, NULL)) {
return ARCHIVE_EOF;
ret = read_var_sized(a, &archive_flags, NULL);
if(ret != ARCHIVE_OK) {
return ret;
}
rar5->main.volume = (archive_flags & VOLUME) > 0;
@@ -2108,8 +2239,9 @@ static int process_head_main(struct archive_read* a, struct rar5 *rar5,
if(archive_flags & VOLUME_NUMBER) {
size_t v = 0;
if(!read_var_sized(a, &v, NULL)) {
return ARCHIVE_EOF;
ret = read_var_sized(a, &v, NULL);
if(ret != ARCHIVE_OK) {
return ret;
}
if (v > UINT_MAX) {
@@ -2140,12 +2272,14 @@ static int process_head_main(struct archive_read* a, struct rar5 *rar5,
return ARCHIVE_OK;
}
if(!read_var_sized(a, &extra_field_size, NULL)) {
return ARCHIVE_EOF;
ret = read_var_sized(a, &extra_field_size, NULL);
if(ret != ARCHIVE_OK) {
return ret;
}
if(!read_var_sized(a, &extra_field_id, NULL)) {
return ARCHIVE_EOF;
ret = read_var_sized(a, &extra_field_id, NULL);
if(ret != ARCHIVE_OK) {
return ret;
}
if(extra_field_size == 0) {
@@ -2314,20 +2448,23 @@ static int process_base_block(struct archive_read* a,
}
/* Read header size. */
if(!read_var_sized(a, &raw_hdr_size, &hdr_size_len)) {
return ARCHIVE_EOF;
ret = read_var_sized(a, &raw_hdr_size, &hdr_size_len);
if(ret != ARCHIVE_OK) {
return ret;
}
hdr_size = raw_hdr_size + hdr_size_len;
/* Sanity check, maximum header size for RAR5 is 2MB. */
if(hdr_size > (2 * 1024 * 1024)) {
/* Sanity check. Bounding raw_hdr_size (instead of the sum) also
* ensures that adding hdr_size_len below cannot wrap hdr_size
* around SIZE_MAX. */
if(raw_hdr_size > MAX_HEADER_SIZE - hdr_size_len) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Base block header is too large");
return ARCHIVE_FATAL;
}
hdr_size = raw_hdr_size + hdr_size_len;
/* Additional sanity checks to weed out invalid files. */
if(raw_hdr_size == 0 || hdr_size_len == 0 ||
hdr_size < SMALLEST_RAR5_BLOCK_SIZE)
@@ -2346,7 +2483,7 @@ static int process_base_block(struct archive_read* a,
}
/* Verify the CRC32 of the header data. */
computed_crc = (uint32_t) crc32(0, p, (int) hdr_size);
computed_crc = (uint32_t) __archive_crc32(0, p, (int) hdr_size);
if(computed_crc != hdr_crc) {
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -2365,11 +2502,13 @@ static int process_base_block(struct archive_read* a,
return ARCHIVE_EOF;
}
if(!read_var_sized(a, &header_id, NULL))
return ARCHIVE_EOF;
ret = read_var_sized(a, &header_id, NULL);
if(ret != ARCHIVE_OK)
return ret;
if(!read_var_sized(a, &header_flags, NULL))
return ARCHIVE_EOF;
ret = read_var_sized(a, &header_flags, NULL);
if(ret != ARCHIVE_OK)
return ret;
rar5->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;
rar5->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;
@@ -2507,7 +2646,7 @@ static int try_skip_sfx(struct archive_read *a)
rar5_signature(signature);
while (total + window <= (1024 * 512)) {
while (total + window <= SFX_MAX_READAHEAD) {
h = __archive_read_ahead(a, window, &bytes);
if (h == NULL) {
/* Remaining bytes are less than window. */
@@ -2633,7 +2772,7 @@ static void update_crc(struct rar5 *rar5, const uint8_t* p, size_t to_read) {
* `stored_crc32` info filled in. */
if(rar5->file.stored_crc32 > 0) {
rar5->file.calculated_crc32 =
crc32(rar5->file.calculated_crc32, p,
__archive_crc32(rar5->file.calculated_crc32, p,
(unsigned int)to_read);
}
@@ -3454,6 +3593,18 @@ static int scan_for_signature(struct archive_read* a) {
return ARCHIVE_FATAL;
}
/* Report that the archive ended while the current file was still expected to
* continue in a following volume (its header had the 'split after' flag set),
* which typically happens when a multivolume set is opened without supplying
* its later volumes. Returning a clean EOF here would silently hand back a
* short, corrupted read, so this is a fatal error. */
static int truncated_multivolume_error(struct archive_read* a) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated RAR5 archive: file continues in a subsequent volume "
"that is not available");
return ARCHIVE_FATAL;
}
/* This function will switch the multivolume archive file to another file,
* i.e. from part03 to part 04. */
static int advance_multivolume(struct archive_read* a) {
@@ -3550,8 +3701,7 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
rar5->cstate.switch_multivolume = 1;
/* Reallocate the memory which will hold the whole block. */
if(rar5->vol.push_buf)
free((void*) rar5->vol.push_buf);
free(rar5->vol.push_buf);
/* Increasing the allocation block by 8 is due to bit reading functions,
* which are using additional 2 or 4 bytes. Allocating the block size
@@ -3591,8 +3741,11 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
}
if(!read_ahead(a, cur_block_size, &lp)) {
/* We are in the middle of merging a block that spans
* volumes, so more data must follow; running out of
* input here means the following volume is missing. */
rar5->cstate.switch_multivolume = 0;
return ARCHIVE_EOF;
return truncated_multivolume_error(a);
}
/* Sanity check; there should never be a situation where this
@@ -3636,7 +3789,13 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
rar5->merge_mode++;
ret = advance_multivolume(a);
rar5->merge_mode--;
if(ret != ARCHIVE_OK) {
if(ret == ARCHIVE_EOF) {
/* The block is only partially merged but the
* input ended, so the volume that holds the rest
* of it is missing. */
rar5->cstate.switch_multivolume = 0;
return truncated_multivolume_error(a);
} else if(ret != ARCHIVE_OK) {
rar5->cstate.switch_multivolume = 0;
return ret;
}
@@ -3659,7 +3818,15 @@ static int process_block(struct archive_read* a) {
/* If we don't have any data to be processed, this most probably means
* we need to switch to the next volume. */
if(rar5->main.volume && rar5->file.bytes_remaining == 0) {
/* Capture 'split after' before advancing: advance_multivolume()
* parses following headers and overwrites this flag. */
int split_after = rar5->generic.split_after > 0;
ret = advance_multivolume(a);
if(ret == ARCHIVE_EOF && split_after) {
/* The file is promised to continue in a following
* volume, but the input ended first. */
return truncated_multivolume_error(a);
}
if(ret != ARCHIVE_OK)
return ret;
}
@@ -4063,6 +4230,13 @@ static int do_unstore_file(struct archive_read* a,
size_t to_read;
const uint8_t* p;
/* This function returns without any data on more than one path,
* and the end of the stored data is the position all of them
* should report. */
if(buf) *buf = NULL;
if(size) *size = 0;
if(offset) *offset = rar5->cstate.last_unstore_ptr;
if(rar5->file.bytes_remaining == 0 && rar5->main.volume > 0 &&
rar5->generic.split_after > 0)
{
@@ -4072,7 +4246,16 @@ static int do_unstore_file(struct archive_read* a,
ret = advance_multivolume(a);
rar5->cstate.switch_multivolume = 0;
if(ret != ARCHIVE_OK) {
if(ret == ARCHIVE_EOF) {
/* We only reach this advance because 'split after' was
* set, i.e. the file is promised to continue in a
* following volume, but the input ended before we could
* reach it (for example, only the first volume of the
* set was supplied). The data decoded so far is
* incomplete, so report truncation rather than silently
* returning a short read as a clean end of file. */
return truncated_multivolume_error(a);
} else if(ret != ARCHIVE_OK) {
/* Failed to advance to next multivolume archive
* file. */
return ret;
@@ -4272,6 +4455,8 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
struct rar5 *rar5 = a->format->data;
int ret;
if (buff)
*buff = NULL;
if (size)
*size = 0;
@@ -4307,6 +4492,11 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
}
if(rar5->file.eof == 1) {
/* The entry is over; report the end of the unpacked data,
* so that a sparse-file aware caller does not have to
* guess where it is. */
if (offset)
*offset = rar5->cstate.last_write_ptr;
return ARCHIVE_EOF;
}
@@ -4458,12 +4648,12 @@ static void rar5_deinit(struct rar5 *rar5) {
}
int archive_read_support_format_rar5(struct archive *_a) {
struct archive_read* ar;
int ret;
struct archive_read* ar = (struct archive_read*)_a;
struct rar5 *rar5;
int r;
if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))
return ret;
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"archive_read_support_format_rar5");
rar5 = malloc(sizeof(*rar5));
if(rar5 == NULL) {
@@ -4479,7 +4669,7 @@ int archive_read_support_format_rar5(struct archive *_a) {
return ARCHIVE_FATAL;
}
ret = __archive_read_register_format(ar,
r = __archive_read_register_format(ar,
rar5,
"rar5",
rar5_bid,
@@ -4492,10 +4682,9 @@ int archive_read_support_format_rar5(struct archive *_a) {
rar5_capabilities,
rar5_has_encrypted_entries);
if(ret != ARCHIVE_OK) {
if(r != ARCHIVE_OK) {
rar5_deinit(rar5);
free(rar5);
}
return ARCHIVE_OK;
return r;
}
@@ -64,8 +64,7 @@ archive_read_support_format_raw(struct archive *_a)
raw = calloc(1, sizeof(*raw));
if (raw == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate raw data");
archive_set_error(_a, ENOMEM, "Can't allocate raw data");
return (ARCHIVE_FATAL);
}
@@ -81,6 +80,7 @@ archive_read_support_format_raw(struct archive *_a)
archive_read_format_raw_cleanup,
NULL,
NULL);
if (r != ARCHIVE_OK)
free(raw);
return (r);
@@ -137,8 +137,15 @@ archive_read_format_raw_read_data(struct archive_read *a,
raw->unconsumed = 0;
}
if (raw->end_of_file)
if (raw->end_of_file) {
/* Keep reporting the end of the entry, so that a caller
* that asks once more after end-of-file still gets a
* position it can use. */
*buff = NULL;
*size = 0;
*offset = raw->offset;
return (ARCHIVE_EOF);
}
/* Get whatever bytes are immediately available. */
*buff = __archive_read_ahead(a, 1, &avail);
@@ -187,6 +187,8 @@ static int header_old_tar(struct archive_read *, struct tar *,
struct archive_entry *, const void *);
static int header_pax_extension(struct archive_read *, struct tar *,
struct archive_entry *, const void *, int64_t *);
static int header_pax_records(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, int64_t *, int);
static int header_pax_global(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, int64_t *);
static int header_gnu_longlink(struct archive_read *, struct tar *,
@@ -272,8 +274,7 @@ archive_read_support_format_tar(struct archive *_a)
tar = calloc(1, sizeof(*tar));
if (tar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
archive_set_error(_a, ENOMEM, "Can't allocate tar data");
return (ARCHIVE_FATAL);
}
#ifdef HAVE_COPYFILE_H
@@ -281,7 +282,9 @@ archive_read_support_format_tar(struct archive *_a)
tar->process_mac_extensions = 1;
#endif
r = __archive_read_register_format(a, tar, "tar",
r = __archive_read_register_format(a,
tar,
"tar",
archive_read_format_tar_bid,
archive_read_format_tar_options,
archive_read_format_tar_read_header,
@@ -294,7 +297,7 @@ archive_read_support_format_tar(struct archive *_a)
if (r != ARCHIVE_OK)
free(tar);
return (ARCHIVE_OK);
return (r);
}
static int
@@ -568,11 +571,21 @@ archive_read_format_tar_read_header(struct archive_read *a,
return (ARCHIVE_FATAL);
} else {
struct sparse_block *sb;
size_t added = 0;
int count;
for (sb = tar->sparse_list; sb != NULL; sb = sb->next) {
if (!sb->hole)
if (!sb->hole) {
archive_entry_sparse_add_entry(entry,
sb->offset, sb->remaining);
added++;
}
}
count = archive_entry_sparse_count(entry);
if (count < 0 || (size_t)count != added) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Malformed sparse map data");
return (ARCHIVE_FATAL);
}
}
@@ -1737,34 +1750,102 @@ read_mac_metadata_blob(struct archive_read *a,
}
/*
* Parse a file header for a pax extended archive entry.
* Attributes that we act on when we see them in an `x` header.
*
* A `g` header supplies defaults for every following member, which we
* do not implement. Silently ignoring one of these would therefore
* change how those members are interpreted, so we reject the archive
* instead. Anything not listed here we already ignore wherever it
* appears, so ignoring it in a `g` header is no less correct; that
* keeps well-formed archives readable, in particular the `g` headers
* that star always writes for its `exustar` format.
*/
#define PAX_GLOBAL_EXACT(k) { k, sizeof(k) - 1, 0 }
#define PAX_GLOBAL_PREFIX(k) { k, sizeof(k) - 1, 1 }
static const struct pax_global_unsupported_attr {
const char *key;
size_t length;
int is_prefix;
} pax_global_unsupported_attrs[] = {
/* POSIX-standard attributes that describe the member. */
PAX_GLOBAL_EXACT("atime"),
PAX_GLOBAL_EXACT("ctime"),
PAX_GLOBAL_EXACT("gid"),
PAX_GLOBAL_EXACT("gname"),
PAX_GLOBAL_EXACT("hdrcharset"),
PAX_GLOBAL_EXACT("linkpath"),
PAX_GLOBAL_EXACT("mtime"),
PAX_GLOBAL_EXACT("path"),
PAX_GLOBAL_EXACT("size"),
PAX_GLOBAL_EXACT("uid"),
PAX_GLOBAL_EXACT("uname"),
/* Vendor attributes that we honor. */
PAX_GLOBAL_EXACT("GNU.sparse"),
PAX_GLOBAL_PREFIX("GNU.sparse."),
PAX_GLOBAL_EXACT("LIBARCHIVE.creationtime"),
PAX_GLOBAL_EXACT("LIBARCHIVE.symlinktype"),
PAX_GLOBAL_PREFIX("LIBARCHIVE.xattr."),
PAX_GLOBAL_EXACT("RHT.security.selinux"),
PAX_GLOBAL_EXACT("SCHILY.acl.access"),
PAX_GLOBAL_EXACT("SCHILY.acl.ace"),
PAX_GLOBAL_EXACT("SCHILY.acl.default"),
PAX_GLOBAL_EXACT("SCHILY.dev"),
PAX_GLOBAL_EXACT("SCHILY.devmajor"),
PAX_GLOBAL_EXACT("SCHILY.devminor"),
PAX_GLOBAL_EXACT("SCHILY.fflags"),
PAX_GLOBAL_EXACT("SCHILY.ino"),
PAX_GLOBAL_EXACT("SCHILY.nlink"),
PAX_GLOBAL_EXACT("SCHILY.realsize"),
PAX_GLOBAL_PREFIX("SCHILY.xattr."),
PAX_GLOBAL_EXACT("SUN.holesdata"),
};
/*
* TODO: This is a linear scan over the table above. It runs once per
* attribute in a `g` header, and `g` headers are rare, so the cost is
* not measurable today. If that ever changes -- or if the table grows
* much larger -- a sorted table with a binary search, or a hash of the
* exact keys with a separate short prefix list, would be worth doing.
*/
static int
pax_global_attribute_unsupported(const char *key, size_t key_length)
{
const struct pax_global_unsupported_attr *attr;
size_t i;
for (i = 0; i < sizeof(pax_global_unsupported_attrs)
/ sizeof(pax_global_unsupported_attrs[0]); i++) {
attr = &pax_global_unsupported_attrs[i];
if (attr->is_prefix) {
if (key_length > attr->length
&& memcmp(key, attr->key, attr->length) == 0)
return (1);
} else if (key_length == attr->length
&& memcmp(key, attr->key, attr->length) == 0) {
return (1);
}
}
return (0);
}
/*
* Parse a file header for a pax global archive entry.
*/
static int
header_pax_global(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
const struct archive_entry_header_ustar *header;
int64_t size, to_consume;
return (header_pax_records(a, tar, entry, h, unconsumed, 1));
}
(void)tar; /* UNUSED */
(void)entry; /* UNUSED */
header = (const struct archive_entry_header_ustar *)h;
size = tar_atol(header->size, sizeof(header->size));
if (size < 0 || size > entry_limit) {
archive_set_error(&a->archive, EINVAL,
"Special header has invalid size: %lld",
(long long)size);
return (ARCHIVE_FATAL);
}
if (size == 0) {
archive_set_error(&a->archive, EINVAL,
"Invalid empty pax global extended header");
return (ARCHIVE_FATAL);
}
to_consume = ((size + 511) & ~511);
*unconsumed += to_consume;
return (ARCHIVE_OK);
/*
* Parse a file header for a pax extended archive entry.
*/
static int
header_pax_extension(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
return (header_pax_records(a, tar, entry, h, unconsumed, 0));
}
/*
@@ -1863,9 +1944,18 @@ header_ustar(struct archive_read *a, struct tar *tar,
return (err);
}
/*
* Parse the attribute records in the body of an `x` or `g` header.
*
* With global == 0 each attribute is applied to the entry. With
* global == 1 the attributes are only inspected: we do not implement
* global defaults, so we reject any attribute that we would otherwise
* have honored and ignore the rest.
*/
static int
header_pax_extension(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, int64_t *unconsumed)
header_pax_records(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, int64_t *unconsumed,
int global)
{
/* Sanity checks: The largest `x` body I've ever heard of was
* a little over 4MB. So I doubt there has ever been a
@@ -1910,7 +2000,8 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
}
if (ext_size == 0) {
archive_set_error(&a->archive, EINVAL,
"Invalid empty pax extended header");
global ? "Invalid empty pax global extended header"
: "Invalid empty pax extended header");
return (ARCHIVE_FATAL);
}
@@ -2034,8 +2125,25 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
return (ARCHIVE_WARN);
}
/* pax_attribute will consume value_length - 1 */
r = pax_attribute(a, tar, entry, attr_name.s, archive_strlen(&attr_name), value_length - 1, unconsumed);
if (global) {
if (pax_global_attribute_unsupported(attr_name.s,
archive_strlen(&attr_name))) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported pax global extended header attribute '%s'",
attr_name.s);
archive_string_free(&attr_name);
*unconsumed += ext_size + ext_padding;
return (ARCHIVE_FATAL);
}
/* Not an attribute we would have acted on, so
* ignoring it here changes nothing. */
__archive_read_consume(a, value_length - 1);
r = ARCHIVE_OK;
} else {
/* pax_attribute will consume value_length - 1 */
r = pax_attribute(a, tar, entry, attr_name.s, archive_strlen(&attr_name), value_length - 1, unconsumed);
}
ext_size -= value_length - 1;
// Release the allocated attr_name (either here or before every return in this function)
@@ -3136,6 +3244,8 @@ gnu_add_sparse_entry(struct archive_read *a, struct tar *tar,
{
struct sparse_block *p;
if (remaining == 0)
return (ARCHIVE_OK);
p = calloc(1, sizeof(*p));
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM, "Out of memory");
@@ -72,6 +72,7 @@
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_string.h"
typedef enum {
WT_NONE,
@@ -95,16 +96,6 @@ typedef enum {
LAST_WT
} warc_type_t;
typedef struct {
size_t len;
const char *str;
} warc_string_t;
typedef struct {
size_t len;
char *str;
} warc_strbuf_t;
struct warc {
/* Content length of the current record */
int64_t cntlen;
@@ -113,8 +104,8 @@ struct warc {
/* Bytes to consume before the next read */
int64_t unconsumed;
/* String pool */
warc_strbuf_t pool;
/* Reusable buffer while parsing file names. */
struct archive_string fname;
/* Previous version */
unsigned int pver;
/* Stringified format name */
@@ -132,7 +123,8 @@ static int archive_read_format_warc_read_header(struct archive_read *,
/* Private routines */
static unsigned int warc_read_version(const char *, size_t);
static unsigned int warc_read_type(const char *, size_t);
static warc_string_t warc_read_uri(const char *, size_t);
static void warc_read_uri(const char *, size_t,
struct archive_string *);
static int64_t warc_read_length(const char *, size_t);
static time_t warc_read_date(const char *, size_t);
static time_t warc_read_last_modified(const char *, size_t);
@@ -150,8 +142,7 @@ archive_read_support_format_warc(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_read_support_format_warc");
if ((warc = calloc(1, sizeof(*warc))) == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate warc data");
archive_set_error(_a, ENOMEM, "Can't allocate warc data");
return (ARCHIVE_FATAL);
}
@@ -168,11 +159,9 @@ archive_read_support_format_warc(struct archive *_a)
NULL,
NULL);
if (r != ARCHIVE_OK) {
if (r != ARCHIVE_OK)
free(warc);
return (r);
}
return (ARCHIVE_OK);
return (r);
}
static int
@@ -180,9 +169,7 @@ archive_read_format_warc_cleanup(struct archive_read *a)
{
struct warc *warc = a->format->data;
if (warc->pool.len > 0U) {
free(warc->pool.str);
}
archive_string_free(&warc->fname);
archive_string_free(&warc->sver);
free(warc);
a->format->data = NULL;
@@ -192,20 +179,20 @@ archive_read_format_warc_cleanup(struct archive_read *a)
static int
archive_read_format_warc_bid(struct archive_read *a, int best_bid)
{
const char *hdr;
const void *h;
ssize_t nrd;
unsigned int ver;
(void)best_bid; /* UNUSED */
/* Check the first line, which should already be a record header. */
if ((hdr = __archive_read_ahead(a, 12, &nrd)) == NULL) {
if ((h = __archive_read_ahead(a, 12, &nrd)) == NULL) {
/* Not enough data to identify this format. */
return -1;
}
/* Parse the record version number. */
ver = warc_read_version(hdr, nrd);
ver = warc_read_version(h, nrd);
if (ver < 1200U || ver > 10000U) {
/* Only WARC 0.12 through WARC 1.0 are supported. */
return -1;
@@ -225,9 +212,6 @@ archive_read_format_warc_read_header(struct archive_read *a,
const char *buf;
ssize_t nrd;
const char *eoh;
char *tmp;
/* Reuse the header buffer while parsing the file name. */
warc_string_t fnam;
/* WARC record type */
warc_type_t ftyp;
/* Content length, or a negative error indicator */
@@ -314,31 +298,14 @@ start_over:
case WT_RSP:
/* Read the filename only for record types that are expected to
* have a target URI. */
fnam = warc_read_uri(buf, eoh - buf);
warc_read_uri(buf, eoh - buf, &warc->fname);
/* Avoid creating directory endpoints as files. */
if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {
if (archive_strlen(&warc->fname) == 0 ||
warc->fname.s[warc->fname.length - 1] == '/') {
/* Skip this record. */
fnam.len = 0U;
fnam.str = NULL;
archive_string_empty(&warc->fname);
break;
}
/* Copy the name into the reusable string pool to avoid a malloc/free
* roundtrip for each entry. */
if (fnam.len + 1U > warc->pool.len) {
warc->pool.len = ((fnam.len + 64U) / 64U) * 64U;
tmp = realloc(warc->pool.str, warc->pool.len);
if (tmp == NULL) {
archive_set_error(
&a->archive, ENOMEM,
"Out of memory");
return (ARCHIVE_FATAL);
}
warc->pool.str = tmp;
}
memcpy(warc->pool.str, fnam.str, fnam.len);
warc->pool.str[fnam.len] = '\0';
/* Hide the pool implementation behind the parsed string. */
fnam.str = warc->pool.str;
/* Use a Last-Modified record header when present; otherwise fall back
* to WARC-Date. */
@@ -355,8 +322,7 @@ start_over:
case WT_CONT:
case LAST_WT:
default:
fnam.len = 0U;
fnam.str = NULL;
archive_string_empty(&warc->fname);
break;
}
@@ -366,10 +332,10 @@ start_over:
switch (ftyp) {
case WT_RSRC:
case WT_RSP:
if (fnam.len > 0U) {
if (archive_strlen(&warc->fname) > 0) {
/* Populate the entry object. */
archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_copy_pathname(entry, fnam.str);
archive_entry_copy_pathname(entry, warc->fname.s);
archive_entry_set_size(entry, cntlen);
archive_entry_set_perm(entry, 0644);
/* WARC-Date becomes ctime; mtime comes from Last-Modified or WARC-Date. */
@@ -457,15 +423,8 @@ archive_read_format_warc_skip(struct archive_read *a)
return (ARCHIVE_OK);
}
/* Private routines */
static void*
deconst(const void *c)
{
return (void *)(uintptr_t)c;
}
static char*
static const char*
xmemmem(const char *hay, const size_t haysize,
const char *needle, const size_t needlesize)
{
@@ -482,7 +441,7 @@ xmemmem(const char *hay, const size_t haysize,
* found anywhere in the haystack; otherwise find the first candidate
* that begins with *NEEDLE. */
if (needlesize == 0UL) {
return deconst(hay);
return hay;
} else if ((hay = memchr(hay, *needle, haysize)) == NULL) {
/* No candidate match remains. */
return NULL;
@@ -501,7 +460,7 @@ xmemmem(const char *hay, const size_t haysize,
return NULL;
} else if (eqp) {
/* Found a match. */
return deconst(hay);
return hay;
}
/* Loop through the rest of the haystack and update the rolling XOR
@@ -514,7 +473,7 @@ xmemmem(const char *hay, const size_t haysize,
* NEEDLESIZE - 1 characters for equality. CAND is always before
* HP by design, so no range check is needed. */
if (hsum == nsum && memcmp(cand, needle, needlesize - 1U) == 0) {
return deconst(cand);
return cand;
}
}
return NULL;
@@ -552,24 +511,34 @@ time_from_tm(struct tm *t)
/* Use platform timegm() if available. */
return (timegm(t));
#else
int64_t days, result;
/* Otherwise, calculate directly using POSIX assumptions. */
/* First, fix up tm_yday based on the year, month, and day. */
if (mktime(t) == (time_t)-1)
return ((time_t)-1);
/* Then compute timegm() from first principles. */
return (t->tm_sec
+ t->tm_min * 60
+ t->tm_hour * 3600
+ t->tm_yday * 86400
+ (t->tm_year - 70) * 31536000
+ ((t->tm_year - 69) / 4) * 86400
- ((t->tm_year - 1) / 100) * 86400
+ ((t->tm_year + 299) / 400) * 86400);
days = (int64_t)t->tm_yday
+ ((int64_t)t->tm_year - 70) * 365
+ ((int64_t)t->tm_year - 69) / 4
- ((int64_t)t->tm_year - 1) / 100
+ ((int64_t)t->tm_year + 299) / 400;
if (archive_ckd_mul_i64(&result, days, 86400) ||
archive_ckd_add_i64(&result, result,
(int64_t)t->tm_hour * 3600 + t->tm_min * 60
+ t->tm_sec))
return ((time_t)-1);
if (result < 0) {
if (TIME_MIN == 0 || result < (int64_t)TIME_MIN)
return ((time_t)-1);
} else if ((uint64_t)result > (uint64_t)TIME_MAX)
return ((time_t)-1);
return ((time_t)result);
#endif
}
static time_t
xstrpisotime(const char *s, char **endptr)
xstrpisotime(const char *s, const char **endptr)
{
/* Like strptime(), but only for ISO 8601 Zulu strings. */
struct tm tm;
@@ -617,7 +586,7 @@ xstrpisotime(const char *s, char **endptr)
out:
if (endptr != NULL) {
*endptr = deconst(s);
*endptr = s;
}
return res;
}
@@ -701,22 +670,23 @@ warc_read_type(const char *buf, size_t bsz)
return WT_NONE;
}
static warc_string_t
warc_read_uri(const char *buf, size_t bsz)
static void
warc_read_uri(const char *buf, size_t bsz, struct archive_string *str)
{
static const char _key[] = "\r\nWARC-Target-URI:";
const char *val, *uri, *eol, *p;
warc_string_t res = {0U, NULL};
archive_string_empty(str);
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
/* Header field is absent. */
return res;
return;
}
/* Skip leading whitespace. */
val += sizeof(_key) - 1U;
if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {
/* Header field has no end of line. */
return res;
return;
}
while (val < eol && (*val == ' ' || *val == '\t'))
@@ -725,18 +695,18 @@ warc_read_uri(const char *buf, size_t bsz)
/* Locate the :// separator. */
if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {
/* Ignore values without a :// separator. */
return res;
return;
}
/* Spaces inside a URI are not allowed; CRLF should follow. */
for (p = val; p < eol; p++) {
if (isspace((unsigned char)*p))
return res;
return;
}
/* Require enough room for the shortest supported scheme. */
if (uri < (val + 3U))
return res;
return;
/* Move uri past the :// separator. */
uri += 3U;
@@ -751,11 +721,14 @@ warc_read_uri(const char *buf, size_t bsz)
while (uri < eol && *uri++ != '/');
} else {
/* Unsupported URI scheme. */
return res;
return;
}
res.str = uri;
res.len = eol - uri;
return res;
/* Require valid C string representation. */
if (memchr(uri, '\0', eol - uri) != NULL)
return;
archive_strncpy(str, uri, eol - uri);
}
static int64_t
@@ -803,8 +776,7 @@ static time_t
warc_read_date(const char *buf, size_t bsz)
{
static const char _key[] = "\r\nWARC-Date:";
const char *val, *eol;
char *on = NULL;
const char *val, *eol, *on = NULL;
time_t res;
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
@@ -830,8 +802,7 @@ static time_t
warc_read_last_modified(const char *buf, size_t bsz)
{
static const char _key[] = "\r\nLast-Modified:";
const char *val, *eol;
char *on = NULL;
const char *val, *eol, *on = NULL;
time_t res;
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
@@ -30,16 +30,8 @@
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_LIBXML_XMLREADER_H
#include <libxml/xmlreader.h>
#elif HAVE_BSDXML_H
#include <bsdxml.h>
#elif HAVE_EXPAT_H
#include <expat.h>
#elif HAVE_XMLLITE_H
#include <objidl.h>
#include <initguid.h>
#include <xmllite.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_BZLIB_H
#include <bzlib.h>
@@ -59,12 +51,11 @@
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_xml_private.h"
#if (!defined(HAVE_LIBXML_XMLREADER_H) && \
!defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H) && \
!defined(HAVE_XMLLITE_H)) ||\
!defined(HAVE_ZLIB_H) || \
!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
#if !defined(ARCHIVE_XML_READ) ||\
!defined(HAVE_ZLIB_H) || \
!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
/*
* xar needs several external libraries.
* o libxml2, expat or (Windows only) xmllite --- XML parser
@@ -318,7 +309,6 @@ struct unknown_tag {
struct xar {
uint64_t offset; /* Current position in the file. */
int64_t total;
uint64_t h_base;
int end_of_file;
#define OUTBUFF_SIZE (1024 * 64)
@@ -434,7 +424,7 @@ static void xml_end(void *, const char *);
static int xml_data(void *, const char *, size_t);
static int xml_parse_file_flags(struct xar *, const char *);
static int xml_parse_file_ext2(struct xar *, const char *);
#if defined(HAVE_LIBXML_XMLREADER_H)
#if defined(ARCHIVE_XML_READER_XML2)
static int xml2_xmlattr_setup(struct archive_read *,
struct xmlattr_list *, xmlTextReaderPtr);
static int xml2_read_cb(void *, char *, int);
@@ -442,7 +432,7 @@ static int xml2_close_cb(void *);
static void xml2_error_hdr(void *, const char *, xmlParserSeverities,
xmlTextReaderLocatorPtr);
static int xml2_read_toc(struct archive_read *);
#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
#elif defined(ARCHIVE_XML_READER_BSDXML) || defined(ARCHIVE_XML_READER_EXPAT)
struct expat_userData {
int state;
struct archive_read *archive;
@@ -453,15 +443,15 @@ static void expat_start_cb(void *, const XML_Char *, const XML_Char **);
static void expat_end_cb(void *, const XML_Char *);
static void expat_data_cb(void *, const XML_Char *, int);
static int expat_read_toc(struct archive_read *);
#elif defined(HAVE_XMLLITE_H)
#elif defined(ARCHIVE_XML_READER_XMLLITE)
static int xmllite_read_toc(struct archive_read *);
#endif
int
archive_read_support_format_xar(struct archive *_a)
{
struct xar *xar;
struct archive_read *a = (struct archive_read *)_a;
struct xar *xar;
int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
@@ -469,8 +459,7 @@ archive_read_support_format_xar(struct archive *_a)
xar = calloc(1, sizeof(*xar));
if (xar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate xar data");
archive_set_error(_a, ENOMEM, "Can't allocate xar data");
return (ARCHIVE_FATAL);
}
@@ -491,6 +480,7 @@ archive_read_support_format_xar(struct archive *_a)
xar_cleanup,
NULL,
NULL);
if (r != ARCHIVE_OK)
free(xar);
return (r);
@@ -499,38 +489,38 @@ archive_read_support_format_xar(struct archive *_a)
static int
xar_bid(struct archive_read *a, int best_bid)
{
const unsigned char *b;
const char *h;
int bid;
(void)best_bid; /* UNUSED */
b = __archive_read_ahead(a, HEADER_SIZE, NULL);
if (b == NULL)
h = __archive_read_ahead(a, HEADER_SIZE, NULL);
if (h == NULL)
return (-1);
bid = 0;
/*
* Verify magic code
*/
if (archive_be32dec(b) != HEADER_MAGIC)
if (archive_be32dec(h) != HEADER_MAGIC)
return (0);
bid += 32;
/*
* Verify header size
*/
if (archive_be16dec(b+4) != HEADER_SIZE)
if (archive_be16dec(h+4) != HEADER_SIZE)
return (0);
bid += 16;
/*
* Verify header version
*/
if (archive_be16dec(b+6) != HEADER_VERSION)
if (archive_be16dec(h+6) != HEADER_VERSION)
return (0);
bid += 16;
/*
* Verify type of checksum
*/
switch (archive_be32dec(b+24)) {
switch (archive_be32dec(h+24)) {
case CKSUM_NONE:
case CKSUM_SHA1:
case CKSUM_MD5:
@@ -602,11 +592,11 @@ read_toc(struct archive_read *a)
if (r != ARCHIVE_OK)
return (r);
#ifdef HAVE_LIBXML_XMLREADER_H
#ifdef ARCHIVE_XML_READER_XML2
r = xml2_read_toc(a);
#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
#elif defined(ARCHIVE_XML_READER_BSDXML) || defined(ARCHIVE_XML_READER_EXPAT)
r = expat_read_toc(a);
#elif defined(HAVE_XMLLITE_H)
#elif defined(ARCHIVE_XML_READER_XMLLITE)
r = xmllite_read_toc(a);
#endif
if (r != ARCHIVE_OK)
@@ -918,7 +908,6 @@ xar_read_data(struct archive_read *a,
*offset = xar->entry_total;
xar->entry_total += *size;
xar->total += *size;
xar->offset += used;
xar->entry_remaining -= used;
xar->entry_unconsumed = used;
@@ -1063,6 +1052,11 @@ rd_contents(struct archive_read *a, const void **buff, size_t *size,
*used = bytes;
if (decompress(a, buff, size, b, used) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (remaining > 0 && *used == 0 && *size == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"XAR decompressor made no progress");
return (ARCHIVE_FATAL);
}
/*
* Update checksum of a compressed data and a extracted data.
@@ -1643,6 +1637,11 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
avail_out = *outbytes;
switch (xar->rd_encoding) {
case GZIP:
/* avail_in and avail_out are 32 bits wide in zlib. */
if (avail_in > UINT_MAX)
avail_in = UINT_MAX;
if (avail_out > UINT_MAX)
avail_out = UINT_MAX;
xar->stream.next_in = (Bytef *)(uintptr_t)b;
xar->stream.avail_in = (uInt)avail_in;
xar->stream.next_out = (unsigned char *)outbuff;
@@ -1662,6 +1661,11 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
break;
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
case BZIP2:
/* avail_in and avail_out are 32 bits wide in bzlib. */
if (avail_in > UINT_MAX)
avail_in = UINT_MAX;
if (avail_out > UINT_MAX)
avail_out = UINT_MAX;
xar->bzstream.next_in = (char *)(uintptr_t)b;
xar->bzstream.avail_in = (unsigned int)avail_in;
xar->bzstream.next_out = (char *)outbuff;
@@ -3164,7 +3168,7 @@ xml_parse_file_ext2(struct xar *xar, const char *name)
return (1);
}
#ifdef HAVE_LIBXML_XMLREADER_H
#ifdef ARCHIVE_XML_READER_XML2
static int
xml2_xmlattr_setup(struct archive_read *a,
@@ -3321,7 +3325,7 @@ xml2_read_toc(struct archive_read *a)
return ((r == 0)?ARCHIVE_OK:ARCHIVE_FATAL);
}
#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
#elif defined(ARCHIVE_XML_READER_BSDXML) || defined(ARCHIVE_XML_READER_EXPAT)
static int
expat_xmlattr_setup(struct archive_read *a,
@@ -3445,7 +3449,7 @@ expat_read_toc(struct archive_read *a)
return (ud.state);
}
#elif defined(HAVE_XMLLITE_H)
#elif defined(ARCHIVE_XML_READER_XMLLITE)
struct ArchiveStreamAdapter {
const ISequentialStreamVtbl *lpVtbl; /* see asaStaticVtable */
@@ -3765,6 +3769,6 @@ out:
return r;
}
#endif /* defined(XMLLITE) */
#endif /* defined(ARCHIVE_XML_READER_XMLLITE) */
#endif /* Support xar format */
@@ -45,6 +45,9 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
@@ -74,9 +77,7 @@
#include "archive_time_private.h"
#include "archive_ppmd8_private.h"
#ifndef HAVE_ZLIB_H
#include "archive_crc32.h"
#endif
/* length of local file header, not including filename and extra */
#define ZIP_LOCHDR_LEN 30U
@@ -96,6 +97,12 @@ struct zip_entry {
time_t mtime;
time_t atime;
time_t ctime;
/* File creation time, from an NTFS extra field only */
time_t btime;
/* Nanosecond precision, from an NTFS extra field only */
uint32_t mtime_ns;
uint32_t atime_ns;
uint32_t btime_ns;
uint32_t crc32;
uint16_t mode;
uint16_t zip_flags; /* From GP Flags Field */
@@ -135,6 +142,12 @@ struct trad_enc_ctx {
/* Bits used in flags. */
#define LA_USED_ZIP64 (1 << 0)
#define LA_FROM_CENTRAL_DIRECTORY (1 << 1)
#define LA_MTIME_FROM_EXTRA (1 << 2)
#define LA_ATIME_FROM_EXTRA (1 << 3)
#define LA_CTIME_FROM_EXTRA (1 << 4)
#define LA_NTFS_MTIME (1 << 5)
#define LA_NTFS_ATIME (1 << 6)
#define LA_NTFS_BTIME (1 << 7)
/*
* See "WinZip - AES Encryption Information"
@@ -230,7 +243,6 @@ struct zip {
unsigned char *decrypted_ptr;
size_t decrypted_buffer_size;
size_t decrypted_bytes_remaining;
size_t decrypted_unconsumed_bytes;
/* Traditional PKWARE decryption. */
struct trad_enc_ctx tctx;
@@ -337,7 +349,7 @@ static void
trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c)
{
uint8_t t;
#define CRC32(c, b) (crc32(c ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL)
#define CRC32(c, b) (__archive_crc32(c ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL)
ctx->keys[0] = CRC32(ctx->keys[0], c);
ctx->keys[1] = (ctx->keys[1] + (ctx->keys[0] & 0xff)) * 134775813L + 1;
@@ -479,6 +491,7 @@ zipx_read_header_and_decrypt(struct archive_read *a, const void **buf, size_t in
return (ARCHIVE_OK);
}
#if (HAVE_LZMA_H && HAVE_LIBLZMA) || defined(HAVE_BZLIB_H) || (HAVE_ZSTD_H && HAVE_LIBZSTD) || defined(HAVE_ZLIB_H)
/* Decrypt bulk compressed data for zipx decompression.
* Manages the decryption buffer, handles partial fills, and returns decrypted
* data pointer + length. `sp` is set to the raw pointer for HMAC accounting. */
@@ -575,6 +588,7 @@ zip_read_decrypt_update(struct zip *zip, ssize_t to_consume, const void *sp)
if (zip->hctx_valid)
archive_hmac_sha1_update(&zip->hctx, sp, to_consume);
}
#endif
/*
* Common code for streaming or seeking modes.
@@ -586,7 +600,7 @@ zip_read_decrypt_update(struct zip *zip, ssize_t to_consume, const void *sp)
static unsigned long
real_crc32(unsigned long crc, const void *buff, size_t len)
{
return crc32(crc, buff, (unsigned int)len);
return __archive_crc32(crc, buff, (unsigned int)len);
}
/* Used by "ignorecrc32" option to speed up tests. */
@@ -647,6 +661,23 @@ compression_name(const int compression)
return "??";
}
/*
* Interpret a raw 32-bit Unix timestamp, preferring the signed
* (pre-1970-capable) reading unless it would land before 1960, in
* which case the unsigned (post-2038-capable) reading is used instead.
* On a platform where time_t is no wider than 32 bits, that unsigned
* reading could never be represented anyway, so it's always skipped.
* See https://github.com/libarchive/libarchive/issues/3550.
*/
static time_t
to_time_t(uint32_t raw)
{
const int32_t year_1960_offset = (10 * 365 + 3) * 24 * 60 * 60;
const int32_t t = (int32_t)raw;
return (sizeof(time_t) <= sizeof(raw) || t >= -year_1960_offset)
? (time_t)t : (time_t)raw;
}
/*
* The extra data is stored as a list of
* id1+size1+data1 + id2+size2+data2 ...
@@ -756,12 +787,96 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
* on which file starts, but we don't handle
* multi-volume Zip files. */
break;
case 0x000a:
{
/* NTFS Extra Field: 4 reserved bytes, then one or
* more Tag(2)/Size(2)/Data(Size) attribute blocks.
* Only Tag 1 (size 24: Mtime, Atime, Ctime, each an
* 8-byte Windows FILETIME) is defined; skip any
* other tag, per spec. Unlike every other ZIP
* timestamp source, FILETIME has no negative/pre-
* epoch ambiguity (it's unsigned ticks since
* 1601), and it's 100ns-precision rather than
* 1-second, so it also supplies mtime_ns/atime_ns.
* "Ctime" here is Windows creation time, not POSIX
* ctime, so it maps to btime. */
unsigned sub_offset = offset;
unsigned sub_remaining = datasize;
if (sub_remaining < 4)
break;
sub_offset += 4;
sub_remaining -= 4;
while (sub_remaining >= 4) {
unsigned short tag =
archive_le16dec(p + sub_offset);
unsigned short size =
archive_le16dec(p + sub_offset + 2);
sub_offset += 4;
sub_remaining -= 4;
if (size > sub_remaining)
break;
if (tag == 1 && size == 24) {
/* A raw FILETIME of 0 marks a slot
* the writer didn't have a value
* for (see the matching comment in
* archive_write_set_format_zip.c);
* treat it as absent rather than
* decoding it as 1601-01-01. */
uint64_t raw;
int64_t secs;
uint32_t nsecs;
raw = archive_le64dec(p + sub_offset);
if (raw != 0) {
__archive_ntfs_to_unix(raw,
&secs, &nsecs);
zip_entry->mtime = (time_t)secs;
zip_entry->mtime_ns = nsecs;
zip_entry->flags |= LA_NTFS_MTIME;
zip_entry->flags |= LA_MTIME_FROM_EXTRA;
}
raw = archive_le64dec(p + sub_offset + 8);
if (raw != 0) {
__archive_ntfs_to_unix(raw,
&secs, &nsecs);
zip_entry->atime = (time_t)secs;
zip_entry->atime_ns = nsecs;
zip_entry->flags |= LA_NTFS_ATIME;
zip_entry->flags |= LA_ATIME_FROM_EXTRA;
}
raw = archive_le64dec(p + sub_offset + 16);
if (raw != 0) {
__archive_ntfs_to_unix(raw,
&secs, &nsecs);
zip_entry->btime = (time_t)secs;
zip_entry->btime_ns = nsecs;
zip_entry->flags |= LA_NTFS_BTIME;
}
}
sub_offset += size;
sub_remaining -= size;
}
break;
}
case 0x000d:
/* PKWARE Unix Extra Field fixed metadata. */
if (datasize >= 12) {
zip_entry->atime = archive_le32dec(p + offset);
zip_entry->mtime =
archive_le32dec(p + offset + 4);
if (!(zip_entry->flags & LA_NTFS_ATIME)) {
zip_entry->atime =
to_time_t(archive_le32dec(p + offset));
zip_entry->atime_ns = 0;
zip_entry->flags |= LA_ATIME_FROM_EXTRA;
}
if (!(zip_entry->flags & LA_NTFS_MTIME)) {
zip_entry->mtime =
to_time_t(archive_le32dec(p + offset + 4));
zip_entry->mtime_ns = 0;
zip_entry->flags |= LA_MTIME_FROM_EXTRA;
}
zip_entry->uid =
archive_le16dec(p + offset + 8);
zip_entry->gid =
@@ -812,7 +927,12 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
#endif
if (datasize < 4)
break;
zip_entry->mtime = archive_le32dec(p + offset);
if (!(zip_entry->flags & LA_NTFS_MTIME)) {
zip_entry->mtime =
to_time_t(archive_le32dec(p + offset));
zip_entry->mtime_ns = 0;
zip_entry->flags |= LA_MTIME_FROM_EXTRA;
}
offset += 4;
datasize -= 4;
}
@@ -820,7 +940,12 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
{
if (datasize < 4)
break;
zip_entry->atime = archive_le32dec(p + offset);
if (!(zip_entry->flags & LA_NTFS_ATIME)) {
zip_entry->atime =
to_time_t(archive_le32dec(p + offset));
zip_entry->atime_ns = 0;
zip_entry->flags |= LA_ATIME_FROM_EXTRA;
}
offset += 4;
datasize -= 4;
}
@@ -828,7 +953,9 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
{
if (datasize < 4)
break;
zip_entry->ctime = archive_le32dec(p + offset);
zip_entry->ctime =
to_time_t(archive_le32dec(p + offset));
zip_entry->flags |= LA_CTIME_FROM_EXTRA;
offset += 4;
datasize -= 4;
}
@@ -838,9 +965,18 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
{
/* Info-ZIP Unix Extra Field (old version) "UX". */
if (datasize >= 8) {
zip_entry->atime = archive_le32dec(p + offset);
zip_entry->mtime =
archive_le32dec(p + offset + 4);
if (!(zip_entry->flags & LA_NTFS_ATIME)) {
zip_entry->atime =
to_time_t(archive_le32dec(p + offset));
zip_entry->atime_ns = 0;
zip_entry->flags |= LA_ATIME_FROM_EXTRA;
}
if (!(zip_entry->flags & LA_NTFS_MTIME)) {
zip_entry->mtime =
to_time_t(archive_le32dec(p + offset + 4));
zip_entry->mtime_ns = 0;
zip_entry->flags |= LA_MTIME_FROM_EXTRA;
}
}
if (datasize >= 12) {
zip_entry->uid =
@@ -1155,7 +1291,16 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
}
zip->init_decryption = (zip_entry->zip_flags & ZIP_ENCRYPTED);
zip_entry->compression = (char)archive_le16dec(p + 8);
zip_entry->mtime = dos_to_unix(archive_le32dec(p + 10));
/* This DOS timestamp carries no information a Central Directory
* prescan wouldn't already have, and no sub-second precision:
* only use it (and reset mtime_ns to match, since it has none) as
* a fallback default, not an unconditional override of a more
* precise value the prescan may have already established from an
* extra field the Local Header doesn't itself repeat. */
if (!(zip_entry->flags & LA_MTIME_FROM_EXTRA)) {
zip_entry->mtime = __archive_dos_to_unix(archive_le32dec(p + 10));
zip_entry->mtime_ns = 0;
}
zip_entry->crc32 = archive_le32dec(p + 14);
if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
zip_entry->decdat = p[11];
@@ -1350,9 +1495,17 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
archive_entry_set_mode(entry, zip_entry->mode);
archive_entry_set_uid(entry, zip_entry->uid);
archive_entry_set_gid(entry, zip_entry->gid);
archive_entry_set_mtime(entry, zip_entry->mtime, 0);
archive_entry_set_ctime(entry, zip_entry->ctime, 0);
archive_entry_set_atime(entry, zip_entry->atime, 0);
archive_entry_set_mtime(entry, zip_entry->mtime, zip_entry->mtime_ns);
/* Without an extra field to supply them, leave atime and ctime
* unset, rather than reporting them as set to the Unix epoch. */
if (zip_entry->flags & LA_CTIME_FROM_EXTRA)
archive_entry_set_ctime(entry, zip_entry->ctime, 0);
if (zip_entry->flags & LA_ATIME_FROM_EXTRA)
archive_entry_set_atime(entry, zip_entry->atime,
zip_entry->atime_ns);
if (zip_entry->flags & LA_NTFS_BTIME)
archive_entry_set_birthtime(entry, zip_entry->btime,
zip_entry->btime_ns);
if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
size_t linkname_length;
@@ -2347,17 +2500,18 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
}
}
if(zip->end_of_entry && zip->entry_bytes_remaining > 0) {
ssize_t remaining = (ssize_t)zip->entry_bytes_remaining;
const void *p = __archive_read_ahead(a, remaining, NULL);
if (p != NULL) {
if (zip->hctx_valid)
archive_hmac_sha1_update(&zip->hctx,
p, remaining);
__archive_read_consume(a, remaining);
zip->entry_compressed_bytes_read += remaining;
zip->entry_bytes_remaining = 0;
}
while(zip->end_of_entry && zip->entry_bytes_remaining > 0) {
const void *p = __archive_read_ahead(a, 1, &bytes_avail);
if (p == NULL)
break;
if (bytes_avail > zip->entry_bytes_remaining)
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
if (zip->hctx_valid)
archive_hmac_sha1_update(&zip->hctx,
p, bytes_avail);
__archive_read_consume(a, bytes_avail);
zip->entry_compressed_bytes_read += bytes_avail;
zip->entry_bytes_remaining -= bytes_avail;
}
/* Free lzma decoder handle because we'll no longer need it. */
@@ -2615,7 +2769,7 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
struct zip *zip = a->format->data;
ssize_t bytes_avail = 0, to_consume;
ssize_t bytes_avail = 0, max_in, to_consume;
const void *compressed_buff;
const void *sp;
int r;
@@ -2649,7 +2803,14 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
zip_read_decrypt(zip, compressed_buff, bytes_avail,
&compressed_buff, &bytes_avail, &sp);
/* Setup buffer boundaries. */
/* Setup buffer boundaries. bzstream.avail_in is 32 bits wide,
* so clamp the available byte count before the assignment. */
if (UINT_MAX >= SSIZE_MAX)
max_in = SSIZE_MAX;
else
max_in = UINT_MAX;
if (bytes_avail > max_in)
bytes_avail = max_in;
zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;
zip->bzstream.avail_in = (uint32_t)bytes_avail;
zip->bzstream.total_in_hi32 = 0;
@@ -2888,7 +3049,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, int64_t *offset)
{
struct zip *zip = a->format->data;
ssize_t bytes_avail, to_consume = 0;
ssize_t bytes_avail, max_in, to_consume = 0;
const void *compressed_buff;
const void *sp;
int r;
@@ -2931,6 +3092,16 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
zip_read_decrypt(zip, compressed_buff, bytes_avail,
&compressed_buff, &bytes_avail, &sp);
/* stream.avail_in is a uInt, which is 32 bits wide even where
* ssize_t is 64 bits. Clamp the available byte count so that a
* read-ahead window larger than 4 GiB is not truncated. */
if (UINT_MAX >= SSIZE_MAX)
max_in = SSIZE_MAX;
else
max_in = UINT_MAX;
if (bytes_avail > max_in)
bytes_avail = max_in;
/*
* A bug in zlib.h: stream.next_in should be marked 'const'
* but isn't (the library never alters data through the
@@ -3653,11 +3824,11 @@ archive_read_support_format_zip_capabilities_streamable(struct archive_read * a)
static int
archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
{
const char *p;
const char *h;
(void)best_bid; /* UNUSED */
if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
if ((h = __archive_read_ahead(a, 4, NULL)) == NULL)
return (-1);
/*
@@ -3668,13 +3839,13 @@ archive_read_format_zip_streamable_bid(struct archive_read *a, int best_bid)
*
* So we've effectively verified ~29 total bits of check data.
*/
if (p[0] == 'P' && p[1] == 'K') {
if ((p[2] == '\001' && p[3] == '\002')
|| (p[2] == '\003' && p[3] == '\004')
|| (p[2] == '\005' && p[3] == '\006')
|| (p[2] == '\006' && p[3] == '\006')
|| (p[2] == '\007' && p[3] == '\010')
|| (p[2] == '0' && p[3] == '0'))
if (h[0] == 'P' && h[1] == 'K') {
if ((h[2] == '\001' && h[3] == '\002')
|| (h[2] == '\003' && h[3] == '\004')
|| (h[2] == '\005' && h[3] == '\006')
|| (h[2] == '\006' && h[3] == '\006')
|| (h[2] == '\007' && h[3] == '\010')
|| (h[2] == '0' && h[3] == '0'))
return (29);
}
@@ -3881,8 +4052,7 @@ archive_read_support_format_zip_streamable(struct archive *_a)
zip = calloc(1, sizeof(*zip));
if (zip == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate zip data");
archive_set_error(_a, ENOMEM, "Can't allocate zip data");
return (ARCHIVE_FATAL);
}
@@ -3911,7 +4081,7 @@ archive_read_support_format_zip_streamable(struct archive *_a)
if (r != ARCHIVE_OK)
free(zip);
return (ARCHIVE_OK);
return (r);
}
/* ------------------------------------------------------------------------ */
@@ -4027,7 +4197,7 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
{
struct zip *zip = a->format->data;
int64_t file_size, current_offset;
const char *p;
const char *h;
int i, tail;
/* If someone has already bid more than 32, then avoid
@@ -4045,22 +4215,26 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
current_offset = __archive_read_seek(a, -tail, SEEK_END);
if (current_offset < 0)
return 0;
if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
if ((h = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
return 0;
/* Boyer-Moore search backwards from the end, since we want
* to match the last EOCD in the file (there can be more than
* one if there is an uncompressed Zip archive as a member
* within this Zip archive). */
for (i = tail - 22; i > 0;) {
switch (p[i]) {
* within this Zip archive).
*
* The lower bound is inclusive (>= 0, not > 0): a minimal,
* valid, zero-entry archive is exactly 22 bytes long, putting
* the EOCD signature at index 0 of this search window. */
for (i = tail - 22; i >= 0;) {
switch (h[i]) {
case 'P':
if (memcmp(p + i, "PK\005\006", 4) == 0) {
int ret = read_eocd(zip, p + i,
if (memcmp(h + i, "PK\005\006", 4) == 0) {
int ret = read_eocd(zip, h + i,
current_offset + i);
/* Zip64 EOCD locator precedes
* regular EOCD if present. */
if (i >= 20 && memcmp(p + i - 20, "PK\006\007", 4) == 0) {
int ret_zip64 = read_zip64_eocd(a, zip, p + i - 20);
if (i >= 20 && memcmp(h + i - 20, "PK\006\007", 4) == 0) {
int ret_zip64 = read_zip64_eocd(a, zip, h + i - 20);
if (ret_zip64 > ret)
ret = ret_zip64;
}
@@ -4269,7 +4443,7 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
zip->has_encrypted_entries = 1;
}
zip_entry->compression = (char)archive_le16dec(p + 10);
zip_entry->mtime = dos_to_unix(archive_le32dec(p + 12));
zip_entry->mtime = __archive_dos_to_unix(archive_le32dec(p + 12));
zip_entry->crc32 = archive_le32dec(p + 16);
if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
zip_entry->decdat = p[13];
@@ -4704,7 +4878,7 @@ archive_read_support_format_zip_seekable(struct archive *_a)
if (r != ARCHIVE_OK)
free(zip);
return (ARCHIVE_OK);
return (r);
}
/*# vim:set noet:*/
+44 -19
View File
@@ -62,6 +62,7 @@
#endif
#include "archive_endian.h"
#include "archive_integer.h"
#include "archive_private.h"
#include "archive_string.h"
#include "archive_string_composition.h"
@@ -318,9 +319,8 @@ archive_string_ensure(struct archive_string *as, size_t s)
new_length = as->buffer_length + as->buffer_length;
else {
/* Buffers 8k and over grow by at least 25% each time. */
new_length = as->buffer_length + as->buffer_length / 4;
/* Be safe: If size wraps, fail. */
if (new_length < as->buffer_length) {
if (archive_ckd_add_size(&new_length,
as->buffer_length, as->buffer_length / 4)) {
/* On failure, wipe the string and return NULL. */
archive_string_free(as);
errno = ENOMEM;/* Make sure errno has ENOMEM. */
@@ -445,7 +445,7 @@ static const char *
default_iconv_charset(const char *charset) {
if (charset != NULL && charset[0] != '\0')
return charset;
#if HAVE_LOCALE_CHARSET && !defined(__APPLE__)
#if HAVE_LOCALE_CHARSET && HAVE_LOCALCHARSET_H && !defined(__APPLE__)
/* locale_charset() is broken on Mac OS */
return locale_charset();
#elif HAVE_NL_LANGINFO
@@ -785,6 +785,10 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
r = WideCharToMultiByte(to_cp, 0, ws, (int)wslen,
as->s + as->length,
(int)(as->buffer_length - as->length - 1), NULL, dp);
if (r == 0 && wslen == 0) {
count = 0;
break;
}
if (r == 0 &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
/* Expand the MBS buffer and retry. */
@@ -1316,17 +1320,7 @@ create_sconv_object(const char *fc, const char *tc,
else if (strcmp(fc, "CP932") == 0)
sc->cd = iconv_open(tc, "SJIS");
}
#if defined(__FreeBSD__) && !defined(HAVE_LIBICONV)
/*
* FreeBSD's native iconv() by default returns the number of
* invalid characters in the input string, as specified by
* POSIX, but iconv_strncat_in_locale() assumes GNU iconv
* semantics.
*/
int v = 1;
(void)iconvctl(sc->cd, ICONV_SET_ILSEQ_INVALID, &v);
#elif defined(_WIN32) && !defined(__CYGWIN__)
#if defined(_WIN32) && !defined(__CYGWIN__)
/*
* archive_mstring on Windows directly convert multi-bytes
* into archive_wstring in order not to depend on locale
@@ -1593,9 +1587,15 @@ static struct {
unsigned ocp;
const char *locale;
} acp_ocp_map[] = {
{ 950, 950, "Chinese_Taiwan" },
{ 950, 950, "Chinese_Hong Kong S.A.R." },
{ 950, 950, "Chinese_Macau S.A.R." },
{ 936, 936, "Chinese_People's Republic of China" },
{ 936, 936, "Chinese (Simplified)_China" },
{ 936, 936, "Chinese (Simplified)_People's Republic of China" },
{ 950, 950, "Chinese_Taiwan" },
{ 950, 950, "Chinese (Traditional)_Hong Kong SAR" },
{ 950, 950, "Chinese (Traditional)_Macau SAR" },
{ 950, 950, "Chinese (Traditional)_Taiwan" },
{ 1250, 852, "Czech_Czech Republic" },
{ 1252, 850, "Danish_Denmark" },
{ 1252, 850, "Dutch_Netherlands" },
@@ -1621,14 +1621,20 @@ static struct {
{ 1252, 850, "Italian_Switzerland" },
{ 932, 932, "Japanese_Japan" },
{ 949, 949, "Korean_Korea" },
{ 949, 949, "Korean_South Korea" },
{ 949, 949, "Korean (Unified)_Korea" },
{ 1252, 850, "Norwegian (Bokmål)_Norway" },
{ 1252, 850, "Norwegian (BokmOl)_Norway" },
{ 1252, 850, "Norwegian (BokmOl)_Norway" },
{ 1252, 850, "Norwegian (Nynorsk)_Norway" },
{ 1252, 850, "Norwegian-Nynorsk_Norway" },
{ 1250, 852, "Polish_Poland" },
{ 1252, 850, "Portuguese_Portugal" },
{ 1252, 850, "Portuguese_Brazil" },
{ 1252, 850, "Portuguese_Portugal" },
{ 1252, 850, "Portuguese (Brazil)_Brazil" },
{ 1252, 850, "Portuguese (Portugal)_Portugal" },
{ 1251, 866, "Russian_Russia" },
{ 1250, 852, "Slovak_Slovakia" },
{ 1250, 852, "Slovak_Slovak Republic" },
{ 1252, 850, "Spanish_Spain" },
{ 1252, 850, "Spanish_Mexico" },
{ 1252, 850, "Spanish_Spain" },
@@ -2126,8 +2132,16 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
while (remaining >= from_size) {
size_t result = iconv(cd, &itp, &remaining, &outp, &avail);
if (result != (size_t)-1)
if (result == 0)
break; /* Conversion completed. */
if (result != (size_t)-1) {
/*
* Conversion did not fail, but it performed
* some non-identical character substitutions.
*/
return_value = -1;
break;
}
if (errno == EILSEQ || errno == EINVAL) {
/*
@@ -2163,6 +2177,17 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
avail -= rbytes;
} else {
/* Skip the illegal input bytes. */
if (avail < 1) {
as->length = outp - as->s;
bs = as->buffer_length +
(remaining * to_size) + 1;
if (NULL ==
archive_string_ensure(as, bs))
return (-1);
outp = as->s + as->length;
avail = as->buffer_length
- as->length - to_size;
}
*outp++ = '?';
avail--;
}
@@ -50,11 +50,15 @@
* them to an archive_string.
*/
static void
append_uint(struct archive_string *as, uintmax_t d, unsigned base)
append_uint(struct archive_string *as, uintmax_t d, unsigned base,
int upper)
{
static const char digits[] = "0123456789abcdef";
static const char digits_lower[] = "0123456789abcdef";
static const char digits_upper[] = "0123456789ABCDEF";
const char *digits = upper ? digits_upper : digits_lower;
if (d >= base)
append_uint(as, d/base, base);
append_uint(as, d/base, base, upper);
archive_strappend_char(as, digits[d % base]);
}
@@ -68,7 +72,7 @@ append_int(struct archive_string *as, intmax_t d, unsigned base)
ud = (d == INTMAX_MIN) ? (uintmax_t)(INTMAX_MAX) + 1 : (uintmax_t)(-d);
} else
ud = d;
append_uint(as, ud, base);
append_uint(as, ud, base, 0);
}
@@ -186,9 +190,10 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
}
/* Format it in the correct base. */
switch (*p) {
case 'o': append_uint(as, u, 8); break;
case 'u': append_uint(as, u, 10); break;
default: append_uint(as, u, 16); break;
case 'o': append_uint(as, u, 8, 0); break;
case 'u': append_uint(as, u, 10, 0); break;
case 'x': append_uint(as, u, 16, 0); break;
case 'X': append_uint(as, u, 16, 1); break;
}
break;
default:
+15 -5
View File
@@ -49,7 +49,7 @@
#include <winnt.h>
/* Windows FILETIME to NTFS time. */
uint64_t
FILETIME_to_ntfs(const FILETIME* filetime)
__archive_FILETIME_to_ntfs(const FILETIME* filetime)
{
ULARGE_INTEGER utc;
utc.HighPart = filetime->dwHighDateTime;
@@ -60,7 +60,7 @@ FILETIME_to_ntfs(const FILETIME* filetime)
/* Convert an MSDOS-style date/time into Unix-style time. */
int64_t
dos_to_unix(uint32_t dos_time)
__archive_dos_to_unix(uint32_t dos_time)
{
uint16_t msTime, msDate;
struct tm ts;
@@ -83,7 +83,7 @@ dos_to_unix(uint32_t dos_time)
/* Convert into MSDOS-style date/time. */
uint32_t
unix_to_dos(int64_t unix_time)
__archive_unix_to_dos(int64_t unix_time)
{
struct tm *t;
uint32_t dt;
@@ -132,7 +132,7 @@ unix_to_dos(int64_t unix_time)
/* Convert NTFS time to Unix sec/nsec */
void
ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs)
__archive_ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs)
{
if (ntfs > INT64_MAX) {
ntfs -= NTFS_EPOC_TICKS;
@@ -143,7 +143,17 @@ ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs)
lldiv_t tdiv;
int64_t value = (int64_t)ntfs - (int64_t)NTFS_EPOC_TICKS;
/* lldiv() truncates toward zero, not toward -infinity, so
* for a negative |value| that isn't an exact multiple of
* NTFS_TICKS, tdiv.rem would itself come out negative here.
* Adjust to floor division so *nsecs always ends up
* non-negative, with the sign folded entirely into *secs,
* as callers (e.g. struct timespec) expect. */
tdiv = lldiv(value, NTFS_TICKS);
if (tdiv.rem < 0) {
tdiv.quot -= 1;
tdiv.rem += NTFS_TICKS;
}
*secs = tdiv.quot;
*nsecs = (uint32_t)(tdiv.rem * 100);
}
@@ -151,7 +161,7 @@ ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs)
/* Convert Unix sec/nsec to NTFS time */
uint64_t
unix_to_ntfs(int64_t secs, uint32_t nsecs)
__archive_unix_to_ntfs(int64_t secs, uint32_t nsecs)
{
uint64_t ntfs;
@@ -31,17 +31,17 @@
#include <stdint.h>
/* NTFS time to Unix sec/nsec. */
void ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs);
void __archive_ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs);
/* DOS time to Unix sec. */
int64_t dos_to_unix(uint32_t dos);
int64_t __archive_dos_to_unix(uint32_t dos);
/* Unix sec/nsec to NTFS time. */
uint64_t unix_to_ntfs(int64_t secs, uint32_t nsecs);
uint64_t __archive_unix_to_ntfs(int64_t secs, uint32_t nsecs);
/* Unix sec to DOS time. */
uint32_t unix_to_dos(int64_t secs);
uint32_t __archive_unix_to_dos(int64_t secs);
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windef.h>
#include <winbase.h>
/* Windows FILETIME to NTFS time. */
uint64_t FILETIME_to_ntfs(const FILETIME* filetime);
uint64_t __archive_FILETIME_to_ntfs(const FILETIME* filetime);
#endif
#endif /* ARCHIVE_TIME_PRIVATE_H_INCLUDED */
@@ -0,0 +1,101 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Dave Borman at Cray Research, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "archive_platform.h"
#include "archive_umask_private.h"
#ifdef HAVE_SYS_SINGLE_THREADED_H
#include <sys/single_threaded.h>
#endif
#include <stddef.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/stat.h>
/* Return the current umask. Attempt to read it without changing. */
mode_t
__archive_get_umask(void)
{
mode_t mask;
#ifdef __linux__
#ifdef HAVE_SYS_SINGLE_THREADED_H
if (!__libc_single_threaded)
#endif
{
/*
* Starting with Linux 4.7, the current process umask can be accessed
* via /proc/self/status.
*/
// Lines in status files are almost always less than 100 bytes, so
// 1 KiB should be plenty. Plus, the umask field should show up in
// the first few lines & always be very short. So even if we split
// other lines, that should never happen with umask. We assume any
// lines we split do not contain "Umask:" in the middle of them.
char line[1024];
// The standard doesn't guarantee mode_t size, so scan a specific
// size ourselves. We know the umask will always be 9 bits, so 32
// bits should be plenty.
int int_umask = -1;
FILE *fp = fopen("/proc/self/status", "re");
if (fp != NULL) {
while (fgets(line, sizeof(line), fp)) {
if (sscanf(line, "Umask: %o", &int_umask) == 1)
break;
}
fclose(fp);
if (int_umask != -1)
return (int_umask);
}
}
#elif defined(KERN_PROC_UMASK)
/*
* FreeBSD has a sysctl interface for requesting the umask without
* temporarily modifying it. Note that this does not work if the sysctl
* security.bsd.unprivileged_proc_debug is set to 0.
*/
u_short smask;
size_t len = sizeof(smask);
if (sysctl((int[4]){ CTL_KERN, KERN_PROC, KERN_PROC_UMASK, 0 },
4, &smask, &len, NULL, 0) == 0)
return (smask);
#endif
umask(mask = umask(0));
return (mask);
}
@@ -0,0 +1,49 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Dave Borman at Cray Research, Inc.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef ARCHIVE_UMASK_PRIVATE_H_INCLUDED
#define ARCHIVE_UMASK_PRIVATE_H_INCLUDED
#ifndef __LIBARCHIVE_BUILD
#ifndef __LIBARCHIVE_TEST
#error This header is only to be used internally to libarchive.
#endif
#endif
#include <sys/stat.h>
/* Return the current umask. Attempt to read it without changing. */
extern mode_t __archive_get_umask(void);
#endif
+2 -22
View File
@@ -41,14 +41,6 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <bcrypt.h>
/* Common in other bcrypt implementations, but missing from VS2008. */
#ifndef BCRYPT_SUCCESS
#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
#endif
#endif
#ifdef HAVE_ZLIB_H
#include <zlib.h>
#endif
@@ -243,7 +235,6 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
DWORD attr;
wchar_t *xp, *ep;
int fd;
BCRYPT_ALG_HANDLE hAlg = NULL;
fd = -1;
ws = NULL;
archive_string_init(&temp_name);
@@ -331,12 +322,6 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
abort();
}
if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM,
NULL, 0))) {
la_dosmaperr(GetLastError());
goto exit_tmpfile;
}
for (;;) {
wchar_t *p;
HANDLE h;
@@ -344,13 +329,10 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
CREATEFILE2_EXTENDED_PARAMETERS createExParams;
#endif
/* Generate a random file name through CryptGenRandom(). */
/* Generate a random file name. */
p = xp;
if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p,
(DWORD)(ep - p)*sizeof(wchar_t), 0))) {
la_dosmaperr(GetLastError());
if (archive_random(p, (ep - p)*sizeof(wchar_t)) != ARCHIVE_OK)
goto exit_tmpfile;
}
for (; p < ep; p++)
*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
@@ -404,8 +386,6 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
break;/* success! */
}
exit_tmpfile:
if (hAlg != NULL)
BCryptCloseAlgorithmProvider(hAlg, 0);
free(ws);
if (template == temp_name.s)
archive_wstring_free(&temp_name);
@@ -84,6 +84,7 @@
#include "archive_string.h"
#include "archive_cryptor_private.h"
#include "archive_digest_private.h"
#include "archive_xml_private.h"
static void
archive_regex_version(struct archive_string* str)
@@ -102,13 +103,16 @@ archive_regex_version(struct archive_string* str)
static void
archive_xml_version(struct archive_string* str)
{
#if HAVE_LIBXML_XMLVERSION_H && HAVE_LIBXML2
#if defined(ARCHIVE_XML_USE_XML2)
archive_strcat(str, " libxml2/");
archive_strcat(str, archive_libxml2_version());
#elif HAVE_BSDXML_H && HAVE_LIBBSDXML
#elif defined(ARCHIVE_XML_USE_XMLLITE)
archive_strcat(str, " xmllite/");
archive_strcat(str, archive_xmllite_version());
#elif defined(ARCHIVE_XML_USE_BSDXML)
archive_strcat(str, " bsdxml/");
archive_strcat(str, archive_libbsdxml_version());
#elif HAVE_EXPAT_H && HAVE_LIBEXPAT
#elif defined(ARCHIVE_XML_USE_EXPAT)
archive_strcat(str, " expat/");
archive_strcat(str, archive_libexpat_version());
#else
@@ -320,7 +324,7 @@ archive_liblzo2_version(void)
const char *
archive_libbsdxml_version(void)
{
#if HAVE_BSDXML_H && HAVE_LIBBSDXML
#if defined(ARCHIVE_XML_USE_BSDXML)
return XML_ExpatVersion();
#else
return NULL;
@@ -330,7 +334,7 @@ archive_libbsdxml_version(void)
const char *
archive_libxml2_version(void)
{
#if HAVE_LIBXML_XMLVERSION_H && HAVE_LIBXML2
#if defined(ARCHIVE_XML_USE_XML2)
return LIBXML_DOTTED_VERSION;
#else
return NULL;
@@ -340,13 +344,23 @@ archive_libxml2_version(void)
const char *
archive_libexpat_version(void)
{
#if HAVE_EXPAT_H && HAVE_LIBEXPAT
#if defined(ARCHIVE_XML_USE_EXPAT)
return XML_ExpatVersion();
#else
return NULL;
#endif
}
const char *
archive_xmllite_version(void)
{
#if defined(ARCHIVE_XML_USE_XMLLITE)
return "system";
#else
return NULL;
#endif
}
const char *
archive_mbedtls_version(void)
{
@@ -174,7 +174,7 @@ myclose(struct archive *a, void *client_data)
void
write_archive(const char *outname, const char **filename)
{
struct mydata *mydata = malloc(sizeof(struct mydata));
struct mydata *mydata = malloc(sizeof(*mydata));
struct archive *a;
struct archive_entry *entry;
struct stat st;
@@ -185,7 +185,7 @@ write_archive(const char *outname, const char **filename)
a = archive_write_new();
mydata->name = outname;
/* Set archive format and filter according to output file extension.
* If it fails, set default format. Platform depended function.
* If it fails, set default format. Platform dependent function.
* See supported formats in archive_write_set_format_filter_by_ext.c */
if (archive_write_set_format_filter_by_ext(a, outname) != ARCHIVE_OK) {
archive_write_add_filter_gzip(a);
+21 -2
View File
@@ -58,6 +58,7 @@
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_write_private.h"
#include "archive_write_set_format_private.h"
static int _archive_filter_code(struct archive *, int);
static const char *_archive_filter_name(struct archive *, int);
@@ -89,6 +90,25 @@ archive_write_vtable = {
.archive_write_data = _archive_write_data,
};
int
__archive_write_option_header_charset(struct archive_write *a,
const char *key, const char *val,
struct archive_string_conv **opt_sconv)
{
if (strcmp(key, "hdrcharset") != 0)
return (ARCHIVE_WARN);
if (val == NULL || val[0] == '\0') {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"%s: hdrcharset option needs a character-set name",
a->format_name);
return (ARCHIVE_FAILED);
}
*opt_sconv = archive_string_conversion_to_charset(
&a->archive, val, 0);
return (*opt_sconv != NULL ? ARCHIVE_OK : ARCHIVE_FATAL);
}
/*
* Allocate, initialize and return an archive object.
*/
@@ -621,8 +641,7 @@ _archive_write_close(struct archive *_a)
int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL,
"archive_write_close");
ARCHIVE_STATE_ANY, "archive_write_close");
if (a->archive.state == ARCHIVE_STATE_NEW
|| a->archive.state == ARCHIVE_STATE_CLOSED)
return (ARCHIVE_OK); /* Okay to close() when not open. */
@@ -238,9 +238,17 @@ output_byte(struct archive_write_filter *f, unsigned char c)
if (compress->compressed_buffer_size == compress->compressed_offset) {
int ret = __archive_write_filter(f->next_filter,
compress->compressed, compress->compressed_buffer_size);
/*
* Empty the buffer whether or not the downstream write
* succeeded. Otherwise a failed flush would leave
* compressed_offset at compressed_buffer_size, and the next
* output_byte() (callers such as output_code() keep going
* without checking the return value) would write one byte
* past the end of the buffer.
*/
compress->compressed_offset = 0;
if (ret != ARCHIVE_OK)
return ARCHIVE_FATAL;
compress->compressed_offset = 0;
}
return ARCHIVE_OK;
@@ -260,13 +268,17 @@ output_code(struct archive_write_filter *f, int ocode)
*/
bit_offset = compress->bit_offset % 8;
compress->bit_buf |= (ocode << bit_offset) & 0xff;
output_byte(f, compress->bit_buf);
ret = output_byte(f, compress->bit_buf);
if (ret != ARCHIVE_OK)
return ret;
bits = compress->code_len - (8 - bit_offset);
ocode >>= 8 - bit_offset;
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
if (bits >= 8) {
output_byte(f, ocode & 0xff);
ret = output_byte(f, ocode & 0xff);
if (ret != ARCHIVE_OK)
return ret;
ocode >>= 8;
bits -= 8;
}
@@ -222,7 +222,7 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
}
}
gzip->crc = crc32(0L, NULL, 0);
gzip->crc = __archive_crc32(0L, NULL, 0);
gzip->stream.next_out = gzip->compressed;
gzip->stream.avail_out = (uInt)gzip->compressed_buffer_size;
@@ -263,8 +263,8 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
}
if (ofn_length < ofn_max_length) {
gzip->compressed[3] |= 0x8;
strcpy((char*)gzip->compressed + 10,
gzip->original_filename);
memcpy(gzip->compressed + 10,
gzip->original_filename, ofn_length + 1);
gzip->stream.next_out += ofn_length + 1;
gzip->stream.avail_out -= ofn_length + 1;
} else {
@@ -322,7 +322,7 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
int ret;
/* Update statistics */
gzip->crc = crc32(gzip->crc, (const Bytef *)buff, (uInt)length);
gzip->crc = __archive_crc32(gzip->crc, (const Bytef *)buff, (uInt)length);
gzip->total_in += length;
/* Compress input data to output buffer */
@@ -52,7 +52,6 @@
struct lz4 {
int compression_level;
unsigned header_written:1;
unsigned version_number:1;
unsigned block_independence:1;
unsigned block_checksum:1;
@@ -292,7 +291,10 @@ archive_filter_lz4_open(struct archive_write_filter *f)
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
/* Write the stream descriptor now so that the stream checksum
* state is initialized and the stream is well-formed even if
* no data is ever written through this filter. */
return (lz4_write_stream_descriptor(f));
}
/*
@@ -310,14 +312,6 @@ archive_filter_lz4_write(struct archive_write_filter *f,
size_t remaining;
ssize_t size;
/* If we haven't written a stream descriptor, we have to do it first. */
if (!lz4->header_written) {
ret = lz4_write_stream_descriptor(f);
if (ret != ARCHIVE_OK)
return (ret);
lz4->header_written = 1;
}
p = (const char *)buff;
remaining = length;
while (remaining) {
@@ -57,6 +57,8 @@ archive_write_set_compression_program(struct archive *a, const char *cmd)
}
#endif
#ifdef HAVE_WAITPID
struct archive_write_program_data {
#if defined(_WIN32) && !defined(__CYGWIN__)
HANDLE child;
@@ -396,3 +398,59 @@ free_data(struct program *program)
free(program);
}
}
#else
int
archive_write_add_filter_program(struct archive *a, const char *cmd)
{
(void)cmd; /* UNUSED */
archive_set_error(a, ENOSYS, "Processes not supported");
return (ARCHIVE_FATAL);
}
struct archive_write_program_data *
__archive_write_program_allocate(const char *program)
{
(void)program; /* UNUSED */
return (NULL);
}
int
__archive_write_program_free(struct archive_write_program_data *data)
{
(void)data; /* UNUSED */
return (ARCHIVE_OK);
}
int
__archive_write_program_open(struct archive_write_filter *f,
struct archive_write_program_data *data, const char *cmd)
{
(void)f; /* UNUSED */
(void)data; /* UNUSED */
(void)cmd; /* UNUSED */
return (ARCHIVE_FATAL);
}
int
__archive_write_program_write(struct archive_write_filter *f,
struct archive_write_program_data *data, const void *buff, size_t length)
{
(void)f; /* UNUSED */
(void)data; /* UNUSED */
(void)buff; /* UNUSED */
(void)length; /* UNUSED */
return (ARCHIVE_FATAL);
}
int
__archive_write_program_close(struct archive_write_filter *f,
struct archive_write_program_data *data)
{
(void)f; /* UNUSED */
(void)data; /* UNUSED */
return (ARCHIVE_FATAL);
}
#endif
@@ -70,7 +70,6 @@ struct zstd {
size_t max_frame_in;
size_t min_frame_out;
size_t max_frame_out;
size_t cur_frame;
size_t cur_frame_in;
size_t cur_frame_out;
ZSTD_CStream *cstream;
@@ -494,7 +493,6 @@ drive_compressor(struct archive_write_filter *f,
break;
case resetting:
ZSTD_CCtx_reset(zstd->cstream, ZSTD_reset_session_only);
zstd->cur_frame++;
zstd->cur_frame_in = 0;
zstd->cur_frame_out = 0;
zstd->state = running;
@@ -54,7 +54,7 @@ Returns number of bytes written or -1 on error.
.Tn archive_write
handles, only for
.Tn archive_write_disk
handles.
handles.)
.El
.\" .Sh EXAMPLE
.\"
@@ -327,13 +327,13 @@ is created as well as the final object
In theory, this can be exploited to create an entire directory hierarchy
with a single request.
Of course, this does not work if the
.Cm ARCHIVE_EXTRACT_NODOTDOT
.Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT
option is specified.
.Pp
Implicit directories are always created obeying the current umask.
Explicit objects are created obeying the current umask unless
.Cm ARCHIVE_EXTRACT_PERM
is specified, in which case they current umask is ignored.
is specified, in which case the current umask is ignored.
.Pp
SGID and SUID bits are restored only if the correct user and
group could be set.
@@ -29,6 +29,8 @@
#if !defined(_WIN32) || defined(__CYGWIN__)
#include "archive_umask_private.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -646,7 +648,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
* user edits their umask during the extraction for some
* reason.
*/
umask(a->user_umask = umask(0));
a->user_umask = __archive_get_umask();
/* Figure out what we need to do for this entry. */
a->todo = TODO_MODE_BASE;
@@ -995,8 +997,11 @@ write_data_block(struct archive_write_disk *a, const char *buff, size_t size)
}
/* If this write would run beyond the file size, truncate it. */
if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
start_size = size = (size_t)(a->filesize - a->offset);
if (a->filesize >= 0 && a->filesize - a->offset < (int64_t)size) {
int64_t diff = a->filesize - a->offset;
start_size = size = diff < 0 ? 0 : (size_t)diff;
}
/* Write the data. */
while (size > 0) {
@@ -1612,8 +1617,11 @@ hfs_write_data_block(struct archive_write_disk *a, const char *buff,
}
/* If this write would run beyond the file size, truncate it. */
if (a->filesize >= 0 && (int64_t)(a->offset + size) > a->filesize)
start_size = size = (size_t)(a->filesize - a->offset);
if (a->filesize >= 0 && a->filesize - a->offset < (int64_t)size) {
int64_t diff = a->filesize - a->offset;
start_size = size = diff < 0 ? 0 : (size_t)diff;
}
/* Write the data. */
while (size > 0) {
@@ -2014,8 +2022,8 @@ archive_write_disk_new(void)
a->archive.state = ARCHIVE_STATE_HEADER;
a->archive.vtable = &archive_write_disk_vtable;
a->start_time = time(NULL);
/* Query and restore the umask. */
umask(a->user_umask = umask(0));
/* Query the umask. */
a->user_umask = __archive_get_umask();
#ifdef HAVE_GETEUID
a->user_uid = geteuid();
#endif /* HAVE_GETEUID */
@@ -158,6 +158,8 @@ lookup_gid(void *private_data, const char *gname, int64_t gid)
# endif /* HAVE_GETGRNAM_R */
#elif defined(_WIN32) && !defined(__CYGWIN__)
/* TODO: do a gname->gid lookup for Windows. */
#elif defined(__wasi__)
/* WASI has no way to perform GID lookups, so just pass through */
#else
#error No way to perform gid lookups on this platform
#endif
@@ -228,6 +230,8 @@ lookup_uid(void *private_data, const char *uname, int64_t uid)
#endif /* HAVE_GETPWNAM_R */
#elif defined(_WIN32) && !defined(__CYGWIN__)
/* TODO: do a uname->uid lookup for Windows. */
#elif defined(__wasi__)
/* WASI has no way to perform GID lookups, so just pass through */
#else
#error No way to look up uids on this platform
#endif
@@ -206,7 +206,7 @@ to register an error code and message and return -1.
.Fn archive_close_callback "struct archive *" "void *client_data"
.El
.Pp
The close callback is invoked by archive_close when
The close callback is invoked by archive_write_close when
the archive processing is complete. If the open callback fails, the close
callback is not invoked.
The callback should return
@@ -48,6 +48,7 @@
#endif
#include "archive.h"
#include "archive_private.h"
struct write_fd_data {
int fd;
@@ -62,6 +63,9 @@ archive_write_open_fd(struct archive *a, int fd)
{
struct write_fd_data *mine;
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_open_fd");
mine = malloc(sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
@@ -45,6 +45,7 @@
#endif
#include "archive.h"
#include "archive_private.h"
struct write_FILE_data {
FILE *f;
@@ -59,6 +60,9 @@ archive_write_open_FILE(struct archive *a, FILE *f)
{
struct write_FILE_data *mine;
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_open_FILE");
mine = malloc(sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
@@ -98,6 +98,9 @@ open_filename(struct archive *a, int mbs_fn, const void *filename)
struct write_file_data *mine;
int r;
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "open_filename");
mine = calloc(1, sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
@@ -30,6 +30,7 @@
#include <string.h>
#include "archive.h"
#include "archive_private.h"
struct write_memory_data {
size_t used;
@@ -52,6 +53,9 @@ archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t
{
struct write_memory_data *mine;
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_open_memory");
mine = calloc(1, sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
Loaded 100 of 290 files, more files were not shown because too many files have changed in this diff. Show more