libarchive: merge from vendor branch

libarchive 3.8.3

Important bugfixes:
 #2753 lib: Create temporary files in the target directory
 #2768 lha: Fix for an out-of-bounds buffer overrun when using
       p[H_LEVEL_OFFSET]
 #2769 7-zip: Fix a buffer overrun when reading truncated 7zip headers
 #2771 lz4 and zstd: Support both lz4 and zstd data with leading
       skippable frames

Obtained from:	libarchive
Vendor commit:	1368b08875351df8aa268237b882c8f4ceb0882d
MFC after:	1 week
This commit is contained in:
Martin Matuska 2025-11-19 14:33:40 +01:00
commit 007679a138
26 changed files with 7110 additions and 61 deletions

View file

@ -1,3 +1,5 @@
Nov 17, 2026: libarchive 3.8.3 released
Oct 15, 2026: libarchive 3.8.2 released
Jun 01, 2026: libarchive 3.8.1 released

View file

@ -34,7 +34,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3008002
#define ARCHIVE_VERSION_NUMBER 3008003
#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.2"
#define ARCHIVE_VERSION_ONLY_STRING "3.8.3"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);

View file

@ -28,7 +28,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
#define ARCHIVE_VERSION_NUMBER 3008002
#define ARCHIVE_VERSION_NUMBER 3008003
/*
* Note: archive_entry.h is for use outside of libarchive; the

View file

@ -207,7 +207,7 @@ for setting is recommended.
The function
.Fn archive_entry_size
returns the file size, if it has been set, and 0 otherwise.
.Fn archive_entry_size
.Fn archive_entry_size_is_set
can be used to query that status.
.Fn archive_entry_set_size
and

View file

@ -358,12 +358,10 @@ setup_mac_metadata(struct archive_read_disk *a,
return (ARCHIVE_OK);
archive_string_init(&tempfile);
if (__archive_get_tempdir(&tempfile) != ARCHIVE_OK) {
ret = ARCHIVE_WARN;
goto cleanup;
}
archive_strcat(&tempfile, "tar.md.XXXXXX");
tempfd = mkstemp(tempfile.s);
archive_strcpy(&tempfile, name);
archive_string_dirname(&tempfile);
archive_strcat(&tempfile, "/tar.XXXXXXXX");
tempfd = __archive_mkstemp(tempfile.s);
if (tempfd < 0) {
archive_set_error(&a->archive, errno,
"Could not open extended attribute file");

View file

@ -107,6 +107,8 @@
#define O_CLOEXEC 0
#endif
#define MAX_FILESYSTEM_ID 1000000
#if defined(__hpux) && !defined(HAVE_DIRFD)
#define dirfd(x) ((x)->__dd_fd)
#define HAVE_DIRFD
@ -1412,8 +1414,12 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
* This is the new filesystem which we have to generate a new ID for.
*/
fid = t->max_filesystem_id++;
if (fid > MAX_FILESYSTEM_ID) {
archive_set_error(&a->archive, ENOMEM, "Too many filesystems");
return (ARCHIVE_FATAL);
}
if (t->max_filesystem_id > t->allocated_filesystem) {
size_t s;
int s;
void *p;
s = t->max_filesystem_id * 2;
@ -1693,8 +1699,6 @@ setup_current_filesystem(struct archive_read_disk *a)
#endif
t->current_filesystem->noatime = 0;
/* Set maximum filename length. */
t->current_filesystem->name_max = svfs.f_namemax;
return (ARCHIVE_OK);
}

View file

@ -49,9 +49,12 @@
#include "archive_xxhash.h"
#define LZ4_MAGICNUMBER 0x184d2204
#define LZ4_SKIPPABLED 0x184d2a50
#define LZ4_LEGACY 0x184c2102
// Note: LZ4 and zstd share the same skippable frame format with the same magic numbers.
#define LZ4_SKIPPABLE_START 0x184D2A50
#define LZ4_SKIPPABLE_MASK 0xFFFFFFF0
#if defined(HAVE_LIBLZ4)
struct private_data {
enum { SELECT_STREAM,
@ -141,19 +144,67 @@ lz4_reader_bid(struct archive_read_filter_bidder *self,
{
const unsigned char *buffer;
ssize_t avail;
int bits_checked;
uint32_t number;
int bits_checked = 0;
ssize_t min_lz4_archive_size = 11;
(void)self; /* UNUSED */
// LZ4 skippable frames contain a 4 byte magic number followed by
// a 4 byte frame data size, then that number of bytes of data. Regular
// frames contain a 4 byte magic number followed by a 2-14 byte frame
// header, some data, and a 3 byte end marker.
ssize_t min_lz4_frame_size = 8;
/* Minimal lz4 archive is 11 bytes. */
buffer = __archive_read_filter_ahead(filter, 11, &avail);
ssize_t offset_in_buffer = 0;
ssize_t max_lookahead = 64 * 1024;
(void)self; // UNUSED
// Zstd and LZ4 skippable frame magic numbers are identical. To
// differentiate these two, we need to look for a non-skippable
// frame.
// Minimal lz4 archive is 11 bytes.
buffer = __archive_read_filter_ahead(filter, min_lz4_archive_size, &avail);
if (buffer == NULL)
return (0);
/* First four bytes must be LZ4 magic numbers. */
bits_checked = 0;
if ((number = archive_le32dec(buffer)) == LZ4_MAGICNUMBER) {
uint32_t magic_number = archive_le32dec(buffer);
while ((magic_number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
offset_in_buffer += 4; // Skip over the magic number
// Ensure that we can read another 4 bytes.
if (offset_in_buffer + 4 > avail) {
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
if (buffer == NULL)
return (0);
}
uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
// Skip over the 4 frame data size bytes, plus the value stored there.
offset_in_buffer += 4 + frame_data_size;
// There should be at least one more frame if this is LZ4 data.
if (offset_in_buffer + min_lz4_frame_size > avail) { // TODO: should this be >= ?
if (offset_in_buffer + min_lz4_frame_size > max_lookahead)
return (0);
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_lz4_frame_size, &avail);
if (buffer == NULL)
return (0);
}
magic_number = archive_le32dec(buffer + offset_in_buffer);
}
// We have skipped over any skippable frames. Either a regular LZ4 frame
// follows, or this isn't LZ4 data.
bits_checked = offset_in_buffer;
buffer = buffer + offset_in_buffer;
if (magic_number == LZ4_MAGICNUMBER) {
unsigned char flag, BD;
bits_checked += 32;
@ -175,11 +226,16 @@ lz4_reader_bid(struct archive_read_filter_bidder *self,
if (BD & ~0x70)
return (0);
bits_checked += 8;
} else if (number == LZ4_LEGACY) {
bits_checked += 32;
return (bits_checked);
}
return (bits_checked);
if (magic_number == LZ4_LEGACY) {
bits_checked += 32;
return (bits_checked);
}
return (0);
}
#if !defined(HAVE_LIBLZ4)
@ -342,7 +398,7 @@ lz4_filter_read(struct archive_read_filter *self, const void **p)
return lz4_filter_read_default_stream(self, p);
else if (number == LZ4_LEGACY)
return lz4_filter_read_legacy_stream(self, p);
else if ((number & ~0xF) == LZ4_SKIPPABLED) {
else if ((number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
read_buf = __archive_read_filter_ahead(
self->upstream, 4, NULL);
if (read_buf == NULL) {

View file

@ -110,24 +110,67 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
{
const unsigned char *buffer;
ssize_t avail;
unsigned prefix;
/* Zstd frame magic values */
unsigned zstd_magic = 0xFD2FB528U;
unsigned zstd_magic_skippable_start = 0x184D2A50U;
unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
// Zstandard skippable frames contain a 4 byte magic number followed by
// a 4 byte frame data size, then that number of bytes of data. Regular
// frames contain a 4 byte magic number followed by a 2-14 byte frame
// header, some data, and a 3 byte end marker.
ssize_t min_zstd_frame_size = 8;
(void) self; /* UNUSED */
ssize_t offset_in_buffer = 0;
ssize_t max_lookahead = 64 * 1024;
buffer = __archive_read_filter_ahead(filter, 4, &avail);
// Zstd regular frame magic number.
uint32_t zstd_magic = 0xFD2FB528U;
// Note: Zstd and LZ4 skippable frame magic numbers are identical.
// To differentiate these two, we need to look for a non-skippable
// frame.
uint32_t zstd_magic_skippable_start = 0x184D2A50;
uint32_t zstd_magic_skippable_mask = 0xFFFFFFF0;
(void) self; // UNUSED
buffer = __archive_read_filter_ahead(filter, min_zstd_frame_size, &avail);
if (buffer == NULL)
return (0);
prefix = archive_le32dec(buffer);
if (prefix == zstd_magic)
return (32);
if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start)
return (32);
uint32_t magic_number = archive_le32dec(buffer);
while ((magic_number & zstd_magic_skippable_mask) == zstd_magic_skippable_start) {
offset_in_buffer += 4; // Skip over the magic number
// Ensure that we can read another 4 bytes.
if (offset_in_buffer + 4 > avail) {
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
if (buffer == NULL)
return (0);
}
uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
// Skip over the 4 frame data size bytes, plus the value stored there.
offset_in_buffer += 4 + frame_data_size;
// There should be at least one more frame if this is zstd data.
if (offset_in_buffer + min_zstd_frame_size > avail) {
if (offset_in_buffer + min_zstd_frame_size > max_lookahead)
return (0);
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_zstd_frame_size, &avail);
if (buffer == NULL)
return (0);
}
magic_number = archive_le32dec(buffer + offset_in_buffer);
}
// We have skipped over any skippable frames. Either a regular zstd frame
// follows, or this isn't zstd data.
if (magic_number == zstd_magic)
return (offset_in_buffer + 4);
return (0);
}

View file

@ -744,6 +744,7 @@ find_elf_data_sec(struct archive_read *a)
const char *h;
char big_endian, format_64;
ssize_t bytes, min_addr = SFX_MIN_ADDR;
ssize_t request;
uint64_t e_shoff, strtab_offset, strtab_size;
uint16_t e_shentsize, e_shnum, e_shstrndx;
uint16_t (*dec16)(const void *);
@ -796,7 +797,12 @@ find_elf_data_sec(struct archive_read *a)
if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
break;
}
h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
if (format_64) {
request = (size_t)e_shnum * (size_t)e_shentsize + 0x28;
} else {
request = (size_t)e_shnum * (size_t)e_shentsize + 0x18;
}
h = __archive_read_ahead(a, request, &bytes);
if (h == NULL) {
break;
}

View file

@ -689,7 +689,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
* a pathname and a symlink has '\' character, a directory
* separator in DOS/Windows. So we should convert it to '/'.
*/
if (p[H_LEVEL_OFFSET] == 0)
if (lha->level == 0)
lha_replace_path_separator(lha, entry);
archive_entry_set_mode(entry, lha->mode);

View file

@ -2311,6 +2311,7 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *
archive_string_init(&as);
r = read_bytes_to_string(a, &as, value_length, &unconsumed);
if (tar_flush_unconsumed(a, &unconsumed) != ARCHIVE_OK) {
*result = 0;
return (ARCHIVE_FATAL);
}
if (r < ARCHIVE_OK) {

View file

@ -78,6 +78,12 @@
#include "archive_crc32.h"
#endif
/* length of local file header, not including filename and extra */
#define ZIP_LOCHDR_LEN 30U
/* maximum length of Mac metadata in MiB */
#define ZIP_MAX_METADATA 10U
struct zip_entry {
struct archive_rb_node node;
struct zip_entry *next;
@ -933,7 +939,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
zip->init_default_conversion = 1;
}
if ((p = __archive_read_ahead(a, 30, NULL)) == NULL) {
if ((p = __archive_read_ahead(a, ZIP_LOCHDR_LEN, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
@ -969,7 +975,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
filename_length = archive_le16dec(p + 26);
extra_length = archive_le16dec(p + 28);
__archive_read_consume(a, 30);
__archive_read_consume(a, ZIP_LOCHDR_LEN);
/* Read the filename. */
if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {
@ -3637,7 +3643,7 @@ read_eocd(struct zip *zip, const char *p, int64_t current_offset)
{
uint16_t disk_num;
uint32_t cd_size, cd_offset;
disk_num = archive_le16dec(p + 4);
cd_size = archive_le32dec(p + 12);
cd_offset = archive_le32dec(p + 16);
@ -4097,7 +4103,7 @@ zip_get_local_file_header_size(struct archive_read *a, size_t extra)
const char *p;
ssize_t filename_length, extra_length;
if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
if ((p = __archive_read_ahead(a, extra + ZIP_LOCHDR_LEN, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_WARN);
@ -4111,7 +4117,7 @@ zip_get_local_file_header_size(struct archive_read *a, size_t extra)
filename_length = archive_le16dec(p + 26);
extra_length = archive_le16dec(p + 28);
return (30 + filename_length + extra_length);
return (ZIP_LOCHDR_LEN + filename_length + extra_length);
}
static int
@ -4148,16 +4154,16 @@ zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
return (ARCHIVE_WARN);
}
if (rsrc->uncompressed_size > (4 * 1024 * 1024)) {
if (rsrc->uncompressed_size > ZIP_MAX_METADATA * 1048576U) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Mac metadata is too large: %jd > 4M bytes",
(intmax_t)rsrc->uncompressed_size);
"Mac metadata is too large: %jd > %u MiB",
(intmax_t)rsrc->uncompressed_size, ZIP_MAX_METADATA);
return (ARCHIVE_WARN);
}
if (rsrc->compressed_size > (4 * 1024 * 1024)) {
if (rsrc->compressed_size > ZIP_MAX_METADATA * 1048576U) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Mac metadata is too large: %jd > 4M bytes",
(intmax_t)rsrc->compressed_size);
"Mac metadata is too large: %jd > %u MiB",
(intmax_t)rsrc->compressed_size, ZIP_MAX_METADATA);
return (ARCHIVE_WARN);
}

View file

@ -2054,6 +2054,26 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
return (r);
}
struct archive_string *
archive_string_dirname(struct archive_string *as)
{
/* strip trailing separators */
while (as->length > 1 && as->s[as->length - 1] == '/')
as->length--;
/* strip final component */
while (as->length > 0 && as->s[as->length - 1] != '/')
as->length--;
/* empty path -> cwd */
if (as->length == 0)
return (archive_strcat(as, "."));
/* strip separator(s) */
while (as->length > 1 && as->s[as->length - 1] == '/')
as->length--;
/* terminate */
as->s[as->length] = '\0';
return (as);
}
#if HAVE_ICONV
/*

View file

@ -192,6 +192,10 @@ void archive_string_vsprintf(struct archive_string *, const char *,
void archive_string_sprintf(struct archive_string *, const char *, ...)
__LA_PRINTF(2, 3);
/* Equivalent to dirname(3) */
struct archive_string *
archive_string_dirname(struct archive_string *);
/* Translates from MBS to Unicode. */
/* Returns non-zero if conversion failed in any way. */
int archive_wstring_append_from_mbs(struct archive_wstring *dest,

View file

@ -412,12 +412,14 @@ static ssize_t _archive_write_disk_data_block(struct archive *, const void *,
static int
la_mktemp(struct archive_write_disk *a)
{
struct archive_string *tmp = &a->_tmpname_data;
int oerrno, fd;
mode_t mode;
archive_string_empty(&a->_tmpname_data);
archive_string_sprintf(&a->_tmpname_data, "%s.XXXXXX", a->name);
a->tmpname = a->_tmpname_data.s;
archive_strcpy(tmp, a->name);
archive_string_dirname(tmp);
archive_strcat(tmp, "/tar.XXXXXXXX");
a->tmpname = tmp->s;
fd = __archive_mkstemp(a->tmpname);
if (fd == -1)
@ -4287,8 +4289,10 @@ create_tempdatafork(struct archive_write_disk *a, const char *pathname)
int tmpfd;
archive_string_init(&tmpdatafork);
archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");
tmpfd = mkstemp(tmpdatafork.s);
archive_strcpy(&tmpdatafork, pathname);
archive_string_dirname(&tmpdatafork);
archive_strcat(&tmpdatafork, "/tar.XXXXXXXX");
tmpfd = __archive_mkstemp(tmpdatafork.s);
if (tmpfd < 0) {
archive_set_error(&a->archive, errno,
"Failed to mkstemp");
@ -4367,8 +4371,10 @@ set_mac_metadata(struct archive_write_disk *a, const char *pathname,
* silly dance of writing the data to disk just so that
* copyfile() can read it back in again. */
archive_string_init(&tmp);
archive_strcpy(&tmp, "tar.mmd.XXXXXX");
fd = mkstemp(tmp.s);
archive_strcpy(&tmp, pathname);
archive_string_dirname(&tmp);
archive_strcat(&tmp, "/tar.XXXXXXXX");
fd = __archive_mkstemp(tmp.s);
if (fd < 0) {
archive_set_error(&a->archive, errno,

View file

@ -191,6 +191,8 @@ file_open(struct archive *a, void *client_data)
archive_set_error(a, errno, "Couldn't stat '%s'", mbs);
else
archive_set_error(a, errno, "Couldn't stat '%ls'", wcs);
close(mine->fd);
mine->fd = -1;
return (ARCHIVE_FATAL);
}

View file

@ -0,0 +1,34 @@
/*
* Clang Module Map for libarchive
*
* What this is:
* This file tells the Clang compiler how to treat libarchive as a "module" -
* a self-contained unit of code that can be imported all at once instead of
* including individual header files. Think of it like a package definition.
*
* How it works:
* - When you write `@import CArchive` (Objective-C) or `import CArchive` (Swift),
* the compiler uses this file to know which headers belong to libarchive
* - Instead of processing each #include separately, the compiler can load a
* pre-compiled version of the entire library, making builds faster
* - This also provides better dependency tracking and can catch issues like
* conflicting macro definitions between libraries
*
* When to update:
* Update this file whenever:
* - New public header files are added to libarchive's libarchive/ directory
* - Public headers are removed or renamed
* - The library's API structure changes significantly
*
* You typically don't need to update this for:
* - Internal implementation changes
* - Private/internal header modifications
* - Documentation updates
*
* NOTE: This only affects projects using Clang with modules enabled. Traditional
* #include-based builds will continue to work normally with or without this file.
*/
module CArchive {
header "archive.h"
header "archive_entry.h"
}

View file

@ -353,6 +353,43 @@ test_archive_string_sprintf(void)
archive_string_free(&s);
}
static void
test_archive_string_dirname(void)
{
static struct pair { const char *str, *exp; } pairs[] = {
{ "", "." },
{ "/", "/" },
{ "//", "/" },
{ "///", "/" },
{ "./", "." },
{ ".", "." },
{ "..", "." },
{ "foo", "." },
{ "foo/", "." },
{ "foo//", "." },
{ "foo/bar", "foo" },
{ "foo/bar/", "foo" },
{ "foo/bar//", "foo" },
{ "foo//bar", "foo" },
{ "foo//bar/", "foo" },
{ "foo//bar//", "foo" },
{ "/foo", "/" },
{ "//foo", "/" },
{ "//foo/", "/" },
{ "//foo//", "/" },
{ 0 },
};
struct pair *pair;
struct archive_string s;
archive_string_init(&s);
for (pair = pairs; pair->str; pair++) {
archive_strcpy(&s, pair->str);
archive_string_dirname(&s);
assertEqualString(pair->exp, s.s);
}
}
DEFINE_TEST(test_archive_string)
{
test_archive_string_ensure();
@ -364,6 +401,7 @@ DEFINE_TEST(test_archive_string)
test_archive_string_concat();
test_archive_string_copy();
test_archive_string_sprintf();
test_archive_string_dirname();
}
static const char *strings[] =

View file

@ -98,6 +98,8 @@ DEFINE_TEST(test_compat_lz4)
verify("test_compat_lz4_3.tar.lz4.uu", n);
/* This sample has been compressed with -B4 option. */
verify("test_compat_lz4_B4.tar.lz4.uu", n2);
/* This sample has been compresed with -B4, and has two skippable frames at the start. */
verify("test_compat_lz4_skippable_frames_B4.tar.lz4.uu", n2);
/* This sample has been compressed with -B5 option. */
verify("test_compat_lz4_B5.tar.lz4.uu", n2);
/* This sample has been compressed with -B6 option. */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
begin 644 test_read_format_7zip_issue2765.7z
M?T5,1@$!`0!@```(0``````````R````-``@``$`````````````````````
D1TD``0`!````4$L`</]_```````````(````N`$```#-@```
`
end

View file

@ -0,0 +1,51 @@
/*-
* Copyright (c) 2025 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
/*
* Sample file from Github Issue #2765
*/
DEFINE_TEST(test_read_format_7zip_issue2765)
{
const char *refname = "test_read_format_7zip_issue2765.7z";
struct archive_entry *ae;
struct archive *a;
extract_reference_file(refname);
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
assertEqualIntA(a, ARCHIVE_FATAL,
archive_read_open_filename(a, refname, 10240));
/* End of archive. */
assertEqualIntA(a, ARCHIVE_FATAL, archive_read_next_header(a, &ae));
assertEqualInt(0, archive_file_count(a));
/* Close the archive. */
assertEqualInt(ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}

View file

@ -8,6 +8,7 @@
DEFINE_TEST(test_option_safe_writes)
{
assertUmask(0);
/* Create files */
assertMakeDir("in", 0755);
assertEqualInt(0, chdir("in"));

View file

@ -314,7 +314,10 @@ set_chdir(struct bsdtar *bsdtar, const char *newdir)
/* The -C /foo -C bar case; concatenate */
char *old_pending = bsdtar->pending_chdir;
size_t old_len = strlen(old_pending);
size_t new_len = old_len + strlen(newdir) + 2;
size_t newdir_len = strlen(newdir);
size_t new_len = old_len + newdir_len + 2;
if (old_len > SIZE_MAX - newdir_len - 2)
lafe_errc(1, errno, "Path too long");
bsdtar->pending_chdir = malloc(new_len);
if (old_pending[old_len - 1] == '/')
old_pending[old_len - 1] = '\0';

View file

@ -84,6 +84,18 @@
#if HAVE_MEMBERSHIP_H
#include <membership.h>
#endif
#if !defined(_WIN32) || defined(__CYGWIN__)
# if HAVE_POSIX_SPAWN
# if HAVE_SYS_WAIT_H
# include <sys/wait.h>
# endif
# if HAVE_SPAWN_H
# include <spawn.h>
# endif
extern char **environ;
# define USE_POSIX_SPAWN 1
# endif
#endif
#ifndef nitems
#define nitems(arr) (sizeof(arr) / sizeof((arr)[0]))
@ -3009,15 +3021,28 @@ int
systemf(const char *fmt, ...)
{
char buff[8192];
#if USE_POSIX_SPAWN
char *argv[] = { "/bin/sh", "-c", buff, NULL };
pid_t pid;
#endif
va_list ap;
int r;
va_start(ap, fmt);
vsnprintf(buff, sizeof(buff), fmt, ap);
va_end(ap);
if (verbosity > VERBOSITY_FULL)
logprintf("Cmd: %s\n", buff);
#if USE_POSIX_SPAWN
if ((r = posix_spawn(&pid, *argv, NULL, NULL, argv, environ)) == 0) {
while (waitpid(pid, &r, 0) == -1) {
if (errno != EINTR)
return (-1);
}
}
#else
r = system(buff);
va_end(ap);
#endif
return (r);
}

View file

@ -125,6 +125,7 @@ TESTS_SRCS= \
test_read_format_7zip_encryption_data.c \
test_read_format_7zip_encryption_header.c \
test_read_format_7zip_encryption_partially.c \
test_read_format_7zip_issue2765.c \
test_read_format_7zip_malformed.c \
test_read_format_7zip_packinfo_digests.c \
test_read_format_ar.c \
@ -392,6 +393,7 @@ ${PACKAGE}FILES+= test_compat_lz4_B6.tar.lz4.uu
${PACKAGE}FILES+= test_compat_lz4_B6BD.tar.lz4.uu
${PACKAGE}FILES+= test_compat_lz4_B7.tar.lz4.uu
${PACKAGE}FILES+= test_compat_lz4_B7BD.tar.lz4.uu
${PACKAGE}FILES+= test_compat_lz4_skippable_frames_B4.tar.lz4.uu
${PACKAGE}FILES+= test_compat_lzip_1.tlz.uu
${PACKAGE}FILES+= test_compat_lzip_2.tlz.uu
${PACKAGE}FILES+= test_compat_lzip_3.lz.uu
@ -485,6 +487,7 @@ ${PACKAGE}FILES+= test_read_format_7zip_encryption.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_encryption_header.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_encryption_partially.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_extract_second.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_issue2765.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_lzma1.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_lzma1_2.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_lzma1_lzma2.7z.uu