mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
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:
commit
61c70dc16a
290 files changed
+14057
-2764
No files matched your search
@@ -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.])
|
||||
])
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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,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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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__))
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:*/
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in new issue
Block a user