aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--Makefile.am6
-rw-r--r--NEWS2
-rw-r--r--build/cmake/CreatePkgConfigFile.cmake2
-rw-r--r--build/version2
-rw-r--r--configure.ac20
-rw-r--r--cpio/test/test_format_newc.c2
-rw-r--r--cpio/test/test_option_a.c2
-rw-r--r--libarchive/CMakeLists.txt14
-rw-r--r--libarchive/archive.h6
-rw-r--r--libarchive/archive_cryptor_private.h4
-rw-r--r--libarchive/archive_entry.h2
-rw-r--r--libarchive/archive_match.c60
-rw-r--r--libarchive/archive_read_disk_windows.c34
-rw-r--r--libarchive/archive_read_open_file.c11
-rw-r--r--libarchive/archive_read_support_filter_compress.c3
-rw-r--r--libarchive/archive_read_support_format_cab.c7
-rw-r--r--libarchive/archive_read_support_format_tar.c144
-rw-r--r--libarchive/archive_string_sprintf.c11
-rw-r--r--libarchive/archive_util.c76
-rw-r--r--libarchive/archive_version_details.c20
-rw-r--r--libarchive/archive_write_disk_windows.c36
-rw-r--r--libarchive/archive_write_set_format_iso9660.c17
-rw-r--r--libarchive/archive_write_set_format_mtree.c8
-rw-r--r--libarchive/test/CMakeLists.txt3
-rw-r--r--libarchive/test/test_entry.c2
-rw-r--r--libarchive/test/test_read_disk_directory_traversals.c2
-rw-r--r--libarchive/test/test_read_format_gtar_sparse_skip_entry.tar.Z.uu18
-rw-r--r--libarchive/test/test_read_format_rar5.c16
-rw-r--r--libarchive/test/test_read_format_tar_mac_metadata.c85
-rw-r--r--libarchive/test/test_read_format_tar_mac_metadata_1.tar.uu231
-rw-r--r--libarchive/test/test_read_format_tar_pax_negative_time.c68
-rw-r--r--libarchive/test/test_read_format_tar_pax_negative_time.tar.uu60
-rw-r--r--libarchive/test/test_read_pax_empty_val_no_nl.c65
-rw-r--r--libarchive/test/test_read_pax_empty_val_no_nl.tar.uu60
-rw-r--r--tar/test/test_list_item.c60
-rw-r--r--tar/test/test_option_C_mtree.c4
-rw-r--r--test_utils/test_main.c59
38 files changed, 933 insertions, 293 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 042f151edb61..4c1f8770ecde 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1257,7 +1257,7 @@ ELSE(LIBXML2_FOUND)
# Check linkage as well; versions of mingw-w64 before v11.0.0
# do not contain an import library for xmllite.
cmake_push_check_state()
- SET(CMAKE_REQUIRED_LIBRARIES "xmllite")
+ SET(CMAKE_REQUIRED_LIBRARIES "xmllite" "uuid")
check_c_source_compiles("
#include <initguid.h>
#include <xmllite.h>
@@ -1268,7 +1268,7 @@ ELSE(LIBXML2_FOUND)
cmake_pop_check_state()
IF(HAVE_XMLLITE_H)
SET(XMLLITE_FOUND TRUE)
- LIST(APPEND ADDITIONAL_LIBS "xmllite")
+ LIST(APPEND ADDITIONAL_LIBS "xmllite" "uuid")
ENDIF()
ENDIF()
ENDIF(EXPAT_FOUND)
diff --git a/Makefile.am b/Makefile.am
index 74cb6e14b609..05232712a857 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -531,8 +531,10 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_tar_empty_with_gnulabel.c \
libarchive/test/test_read_format_tar_filename.c \
libarchive/test/test_read_format_tar_invalid_pax_size.c \
+ libarchive/test/test_read_format_tar_mac_metadata.c \
libarchive/test/test_read_format_tar_pax_g_large.c \
libarchive/test/test_read_format_tar_pax_large_attr.c \
+ libarchive/test/test_read_format_tar_pax_negative_time.c \
libarchive/test/test_read_format_tbz.c \
libarchive/test/test_read_format_tgz.c \
libarchive/test/test_read_format_tlz.c \
@@ -565,6 +567,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_zip_zip64.c \
libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c \
libarchive/test/test_read_large.c \
+ libarchive/test/test_read_pax_empty_val_no_nl.c \
libarchive/test/test_read_pax_xattr_rht_security_selinux.c \
libarchive/test/test_read_pax_xattr_schily.c \
libarchive/test/test_read_pax_truncated.c \
@@ -975,8 +978,10 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_tar_empty_pax.tar.Z.uu \
libarchive/test/test_read_format_tar_filename_koi8r.tar.Z.uu \
libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu \
+ libarchive/test/test_read_format_tar_mac_metadata_1.tar.uu \
libarchive/test/test_read_format_tar_pax_g_large.tar.uu \
libarchive/test/test_read_format_tar_pax_large_attr.tar.Z.uu \
+ libarchive/test/test_read_format_tar_pax_negative_time.tar.uu \
libarchive/test/test_read_format_ustar_filename_cp866.tar.Z.uu \
libarchive/test/test_read_format_ustar_filename_eucjp.tar.Z.uu \
libarchive/test/test_read_format_ustar_filename_koi8r.tar.Z.uu \
@@ -1041,6 +1046,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_large_splitted_rar_ac.uu \
libarchive/test/test_read_large_splitted_rar_ad.uu \
libarchive/test/test_read_large_splitted_rar_ae.uu \
+ libarchive/test/test_read_pax_empty_val_no_nl.tar.uu \
libarchive/test/test_read_pax_xattr_rht_security_selinux.tar.uu \
libarchive/test/test_read_pax_xattr_schily.tar.uu \
libarchive/test/test_read_splitted_rar_aa.uu \
diff --git a/NEWS b/NEWS
index df5755246ff0..caca7d5cbdb9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+Jun 01, 2026: libarchive 3.8.1 released
+
May 20, 2025: libarchive 3.8.0 released
Mar 30, 2025: libarchive 3.7.9 released
diff --git a/build/cmake/CreatePkgConfigFile.cmake b/build/cmake/CreatePkgConfigFile.cmake
index bc5a43f72af1..50caa5e85097 100644
--- a/build/cmake/CreatePkgConfigFile.cmake
+++ b/build/cmake/CreatePkgConfigFile.cmake
@@ -29,5 +29,5 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in
# And install it, of course ;).
IF(ENABLE_INSTALL)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc
- DESTINATION "lib/pkgconfig")
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
ENDIF()
diff --git a/build/version b/build/version
index 7333f0e7d0cc..f08c8c42bfea 100644
--- a/build/version
+++ b/build/version
@@ -1 +1 @@
-3008000
+3008001
diff --git a/configure.ac b/configure.ac
index 911dcf16b182..d8d85eda929f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front.
dnl In particular, this allows the version macro to be used in AC_INIT
dnl These first two version numbers are updated automatically on each release.
-m4_define([LIBARCHIVE_VERSION_S],[3.8.0])
-m4_define([LIBARCHIVE_VERSION_N],[3008000])
+m4_define([LIBARCHIVE_VERSION_S],[3.8.1])
+m4_define([LIBARCHIVE_VERSION_N],[3008001])
dnl bsdtar and bsdcpio versioning tracks libarchive
m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S())
@@ -258,7 +258,8 @@ AM_CONDITIONAL([STATIC_BSDCPIO], [ test "$static_bsdcpio" = yes ])
case $host in
*mingw* | *cygwin* | *msys* )
AC_PREPROC_IFELSE([AC_LANG_PROGRAM(
- [[#ifdef _WIN32_WINNT
+ [[#include <windows.h>
+ #ifdef _WIN32_WINNT
# error _WIN32_WINNT already defined
#endif
]],[[;]])
@@ -267,7 +268,8 @@ case $host in
AC_DEFINE([NTDDI_VERSION], 0x05020000, [Define to '0x05020000' for Windows Server 2003 APIs.])
])
AC_PREPROC_IFELSE([AC_LANG_PROGRAM(
- [[#ifdef WINVER
+ [[#include <windows.h>
+ #ifdef WINVER
# error WINVER already defined
#endif
]],[[;]])
@@ -436,13 +438,15 @@ if test "x$with_bz2lib" != "xno"; then
esac
fi
+PKG_PROG_PKG_CONFIG
+
AC_ARG_WITH([libb2],
AS_HELP_STRING([--without-libb2], [Don't build support for BLAKE2 through libb2]))
if test "x$with_libb2" != "xno"; then
AC_CHECK_HEADERS([blake2.h])
AC_CHECK_LIB(b2,blake2sp_init)
- BLAKE2_PC_VER=`pkg-config --modversion libb2`
+ BLAKE2_PC_VER=`$PKG_CONFIG --modversion libb2`
if test "x$BLAKE2_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBB2_PKGCONFIG_VERSION], ["$BLAKE2_PC_VER"], [Libb2 version coming from pkg-config.])
fi
@@ -925,7 +929,7 @@ if test "x$enable_xattr" != "xno"; then
])
AC_CHECK_DECLS([XATTR_NOFOLLOW], [], [], [#include <sys/xattr.h>
])
- ATTR_PC_VER=`pkg-config --modversion libattr`
+ ATTR_PC_VER=`$PKG_CONFIG --modversion libattr`
if test "x$ATTR_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBATTR_PKGCONFIG_VERSION], ["$ATTR_PC_VER"], [Libattr version coming from pkg-config.])
fi
@@ -1024,7 +1028,7 @@ AC_ARG_ENABLE([acl],
if test "x$enable_acl" != "xno"; then
# Libacl
AC_CHECK_LIB([acl], [acl_get_file])
- ACL_PC_VER=`pkg-config --modversion libacl`
+ ACL_PC_VER=`$PKG_CONFIG --modversion libacl`
if test "x$ACL_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBACL_PKGCONFIG_VERSION], ["$ACL_PC_VER"], [Libacl version coming from pkg-config.])
fi
@@ -1038,7 +1042,7 @@ if test "x$enable_acl" != "xno"; then
])
AC_CHECK_LIB([richacl], [richacl_get_file])
- RICHACL_PC_VER=`pkg-config --modversion librichacl`
+ RICHACL_PC_VER=`$PKG_CONFIG --modversion librichacl`
if test "x$RICHACL_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBRICHACL_PKGCONFIG_VERSION], ["$RICHACL_PC_VER"], [Librichacl version coming from pkg-config.])
fi
diff --git a/cpio/test/test_format_newc.c b/cpio/test/test_format_newc.c
index 0d59c173fa46..33aa16d07a81 100644
--- a/cpio/test/test_format_newc.c
+++ b/cpio/test/test_format_newc.c
@@ -219,7 +219,7 @@ DEFINE_TEST(test_format_newc)
assert(is_hex(e, 110));
assertEqualMem(e + 0, "070701", 6); /* Magic */
assert(is_hex(e + 6, 8)); /* ino */
-#if defined(_WIN32) && !defined(CYGWIN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
/* Mode: Group members bits and others bits do not work. */
assertEqualInt(0xa180, from_hex(e + 14, 8) & 0xffc0);
#else
diff --git a/cpio/test/test_option_a.c b/cpio/test/test_option_a.c
index e6b87948c65a..28e5b73765d7 100644
--- a/cpio/test/test_option_a.c
+++ b/cpio/test/test_option_a.c
@@ -52,7 +52,7 @@ test_create(void)
* #ifdef this section out. Most of the test below is
* still valid. */
memset(&times, 0, sizeof(times));
-#if defined(_WIN32) && !defined(CYGWIN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
times.actime = 86400;
times.modtime = 86400;
#else
diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt
index 556710ad8285..fd997db4112c 100644
--- a/libarchive/CMakeLists.txt
+++ b/libarchive/CMakeLists.txt
@@ -248,7 +248,7 @@ IF(BUILD_SHARED_LIBS)
ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
TARGET_INCLUDE_DIRECTORIES(archive PUBLIC .)
TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS})
- SET_TARGET_PROPERTIES(archive PROPERTIES
+ SET_TARGET_PROPERTIES(archive PROPERTIES
VERSION ${SOVERSION_FULL}
SOVERSION ${SOVERSION}
MACHO_COMPATIBILITY_VERSION ${MACHO_COMPATIBILITY_VERSION}
@@ -266,18 +266,22 @@ IF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS)
SET_TARGET_PROPERTIES(archive_static PROPERTIES OUTPUT_NAME archive)
ENDIF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS)
+if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
+ set(CMAKE_INSTALL_LIBDIR "lib")
+endif()
+
IF(ENABLE_INSTALL)
# How to install the libraries
IF(BUILD_SHARED_LIBS)
INSTALL(TARGETS archive
RUNTIME DESTINATION bin
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib)
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
ENDIF(BUILD_SHARED_LIBS)
INSTALL(TARGETS archive_static
RUNTIME DESTINATION bin
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib)
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL_MAN(${libarchive_MANS})
INSTALL(FILES ${include_HEADERS} DESTINATION include)
ENDIF()
diff --git a/libarchive/archive.h b/libarchive/archive.h
index be8381413da2..002190a24663 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -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 3008000
+#define ARCHIVE_VERSION_NUMBER 3008001
#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.0"
+#define ARCHIVE_VERSION_ONLY_STRING "3.8.1"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
@@ -1250,8 +1250,10 @@ __LA_DECL int archive_match_include_gname_w(struct archive *,
const wchar_t *);
/* Utility functions */
+#if ARCHIVE_VERSION_NUMBER < 4000000
/* Convenience function to sort a NULL terminated list of strings */
__LA_DECL int archive_utility_string_sort(char **);
+#endif
#ifdef __cplusplus
}
diff --git a/libarchive/archive_cryptor_private.h b/libarchive/archive_cryptor_private.h
index 460d38c122a6..4b3c6c161433 100644
--- a/libarchive/archive_cryptor_private.h
+++ b/libarchive/archive_cryptor_private.h
@@ -144,6 +144,10 @@ typedef struct {
#else
+#if defined(_WIN32) && !defined(__CYGWIN__) && !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
+#define ARCHIVE_CRYPTOR_USE_WINCRYPT 1
+#endif
+
#define AES_BLOCK_SIZE 16
#define AES_MAX_KEY_SIZE 32
typedef int archive_crypto_ctx;
diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h
index 84ed1b0bd93a..2b917b3fde8e 100644
--- a/libarchive/archive_entry.h
+++ b/libarchive/archive_entry.h
@@ -28,7 +28,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
-#define ARCHIVE_VERSION_NUMBER 3008000
+#define ARCHIVE_VERSION_NUMBER 3008001
/*
* Note: archive_entry.h is for use outside of libarchive; the
diff --git a/libarchive/archive_match.c b/libarchive/archive_match.c
index 20880d3d39af..51a0e3fd5778 100644
--- a/libarchive/archive_match.c
+++ b/libarchive/archive_match.c
@@ -35,6 +35,9 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
#include "archive.h"
#include "archive_private.h"
@@ -53,8 +56,7 @@ struct match {
struct match_list {
struct match *first;
struct match **last;
- int count;
- int unmatched_count;
+ size_t unmatched_count;
struct match *unmatched_next;
int unmatched_eof;
};
@@ -73,7 +75,6 @@ struct match_file {
struct entry_list {
struct match_file *first;
struct match_file **last;
- int count;
};
struct id_array {
@@ -144,12 +145,15 @@ static int add_pattern_mbs(struct archive_match *, struct match_list *,
const char *);
static int add_pattern_wcs(struct archive_match *, struct match_list *,
const wchar_t *);
+#if !defined(_WIN32) || defined(__CYGWIN__)
static int cmp_key_mbs(const struct archive_rb_node *, const void *);
-static int cmp_key_wcs(const struct archive_rb_node *, const void *);
static int cmp_node_mbs(const struct archive_rb_node *,
const struct archive_rb_node *);
+#else
+static int cmp_key_wcs(const struct archive_rb_node *, const void *);
static int cmp_node_wcs(const struct archive_rb_node *,
const struct archive_rb_node *);
+#endif
static void entry_list_add(struct entry_list *, struct match_file *);
static void entry_list_free(struct entry_list *);
static void entry_list_init(struct entry_list *);
@@ -189,12 +193,12 @@ static int validate_time_flag(struct archive *, int, const char *);
#define get_date archive_parse_date
-static const struct archive_rb_tree_ops rb_ops_mbs = {
+static const struct archive_rb_tree_ops rb_ops = {
+#if !defined(_WIN32) || defined(__CYGWIN__)
cmp_node_mbs, cmp_key_mbs
-};
-
-static const struct archive_rb_tree_ops rb_ops_wcs = {
+#else
cmp_node_wcs, cmp_key_wcs
+#endif
};
/*
@@ -228,7 +232,7 @@ archive_match_new(void)
a->recursive_include = 1;
match_list_init(&(a->inclusions));
match_list_init(&(a->exclusions));
- __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
+ __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops);
entry_list_init(&(a->exclusion_entry_list));
match_list_init(&(a->inclusion_unames));
match_list_init(&(a->inclusion_gnames));
@@ -507,7 +511,9 @@ archive_match_path_unmatched_inclusions(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
a = (struct archive_match *)_a;
- return (a->inclusions.unmatched_count);
+ if (a->inclusions.unmatched_count > (size_t)INT_MAX)
+ return INT_MAX;
+ return (int)(a->inclusions.unmatched_count);
}
int
@@ -650,7 +656,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
break;
}
} else {
- if (*b == 0x0d || *b == 0x0a) {
+ if (*b == 0x0d || *b == 0x0a) {
found_separator = 1;
break;
}
@@ -735,7 +741,7 @@ path_excluded(struct archive_match *a, int mbs, const void *pathname)
}
}
- /* Exclusions take priority */
+ /* Exclusions take priority. */
for (match = a->exclusions.first; match != NULL;
match = match->next){
r = match_path_exclusion(a, match, mbs, pathname);
@@ -834,7 +840,6 @@ match_list_init(struct match_list *list)
{
list->first = NULL;
list->last = &(list->first);
- list->count = 0;
}
static void
@@ -855,7 +860,6 @@ match_list_add(struct match_list *list, struct match *m)
{
*list->last = m;
list->last = &(m->next);
- list->count++;
list->unmatched_count++;
}
@@ -1275,6 +1279,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
/*
* Call back functions for archive_rb.
*/
+#if !defined(_WIN32) || defined(__CYGWIN__)
static int
cmp_node_mbs(const struct archive_rb_node *n1,
const struct archive_rb_node *n2)
@@ -1291,7 +1296,7 @@ cmp_node_mbs(const struct archive_rb_node *n1,
return (-1);
return (strcmp(p1, p2));
}
-
+
static int
cmp_key_mbs(const struct archive_rb_node *n, const void *key)
{
@@ -1303,7 +1308,7 @@ cmp_key_mbs(const struct archive_rb_node *n, const void *key)
return (-1);
return (strcmp(p, (const char *)key));
}
-
+#else
static int
cmp_node_wcs(const struct archive_rb_node *n1,
const struct archive_rb_node *n2)
@@ -1320,7 +1325,7 @@ cmp_node_wcs(const struct archive_rb_node *n1,
return (-1);
return (wcscmp(p1, p2));
}
-
+
static int
cmp_key_wcs(const struct archive_rb_node *n, const void *key)
{
@@ -1332,13 +1337,13 @@ cmp_key_wcs(const struct archive_rb_node *n, const void *key)
return (-1);
return (wcscmp(p, (const wchar_t *)key));
}
+#endif
static void
entry_list_init(struct entry_list *list)
{
list->first = NULL;
list->last = &(list->first);
- list->count = 0;
}
static void
@@ -1359,7 +1364,6 @@ entry_list_add(struct entry_list *list, struct match_file *file)
{
*list->last = file;
list->last = &(file->next);
- list->count++;
}
static int
@@ -1382,9 +1386,7 @@ add_entry(struct archive_match *a, int flag,
return (ARCHIVE_FAILED);
}
archive_mstring_copy_wcs(&(f->pathname), pathname);
- a->exclusion_tree.rbt_ops = &rb_ops_wcs;
#else
- (void)rb_ops_wcs;
pathname = archive_entry_pathname(entry);
if (pathname == NULL) {
free(f);
@@ -1392,7 +1394,6 @@ add_entry(struct archive_match *a, int flag,
return (ARCHIVE_FAILED);
}
archive_mstring_copy_mbs(&(f->pathname), pathname);
- a->exclusion_tree.rbt_ops = &rb_ops_mbs;
#endif
f->flag = flag;
f->mtime_sec = archive_entry_mtime(entry);
@@ -1517,16 +1518,13 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
}
/* If there is no exclusion list, include the file. */
- if (a->exclusion_entry_list.count == 0)
+ if (a->exclusion_entry_list.first == NULL)
return (0);
#if defined(_WIN32) && !defined(__CYGWIN__)
pathname = archive_entry_pathname_w(entry);
- a->exclusion_tree.rbt_ops = &rb_ops_wcs;
#else
- (void)rb_ops_wcs;
pathname = archive_entry_pathname(entry);
- a->exclusion_tree.rbt_ops = &rb_ops_mbs;
#endif
if (pathname == NULL)
return (0);
@@ -1682,7 +1680,7 @@ archive_match_owner_excluded(struct archive *_a,
static int
add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
{
- unsigned i;
+ size_t i;
if (ids->count + 1 >= ids->size) {
void *p;
@@ -1719,10 +1717,10 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
static int
match_owner_id(struct id_array *ids, int64_t id)
{
- unsigned b, m, t;
+ size_t b, m, t;
t = 0;
- b = (unsigned)ids->count;
+ b = ids->count;
while (t < b) {
m = (t + b)>>1;
if (ids->ids[m] == id)
@@ -1817,7 +1815,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
return (1);
}
- if (a->inclusion_unames.count) {
+ if (a->inclusion_unames.first != NULL) {
#if defined(_WIN32) && !defined(__CYGWIN__)
r = match_owner_name_wcs(a, &(a->inclusion_unames),
archive_entry_uname_w(entry));
@@ -1831,7 +1829,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
return (r);
}
- if (a->inclusion_gnames.count) {
+ if (a->inclusion_gnames.first != NULL) {
#if defined(_WIN32) && !defined(__CYGWIN__)
r = match_owner_name_wcs(a, &(a->inclusion_gnames),
archive_entry_gname_w(entry));
diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c
index a774305d0cf2..689a45958c15 100644
--- a/libarchive/archive_read_disk_windows.c
+++ b/libarchive/archive_read_disk_windows.c
@@ -1652,7 +1652,7 @@ tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path,
/*
* Append a name to the current dir path.
*/
-static void
+static int
tree_append(struct tree *t, const wchar_t *name, size_t name_length)
{
size_t size_needed;
@@ -1665,7 +1665,8 @@ tree_append(struct tree *t, const wchar_t *name, size_t name_length)
/* Resize pathname buffer as needed. */
size_needed = name_length + t->dirname_length + 2;
- archive_wstring_ensure(&t->path, size_needed);
+ if (archive_wstring_ensure(&t->path, size_needed) == NULL)
+ return (TREE_ERROR_FATAL);
/* Add a separating '/' if it's needed. */
if (t->dirname_length > 0 &&
t->path.s[archive_strlen(&t->path)-1] != L'/')
@@ -1677,13 +1678,15 @@ tree_append(struct tree *t, const wchar_t *name, size_t name_length)
t->full_path.s[t->full_path_dir_length] = L'\0';
t->full_path.length = t->full_path_dir_length;
size_needed = name_length + t->full_path_dir_length + 2;
- archive_wstring_ensure(&t->full_path, size_needed);
+ if (archive_wstring_ensure(&t->full_path, size_needed) == NULL)
+ return (TREE_ERROR_FATAL);
/* Add a separating '\' if it's needed. */
if (t->full_path.s[archive_strlen(&t->full_path)-1] != L'\\')
archive_wstrappend_wchar(&t->full_path, L'\\');
archive_wstrncat(&t->full_path, name, name_length);
t->restore_time.full_path = t->full_path.s;
}
+ return (0);
}
/*
@@ -1697,7 +1700,10 @@ tree_open(const wchar_t *path, int symlink_mode, int restore_time)
t = calloc(1, sizeof(*t));
archive_string_init(&(t->full_path));
archive_string_init(&t->path);
- archive_wstring_ensure(&t->path, 15);
+ if (archive_wstring_ensure(&t->path, 15) == NULL) {
+ free(t);
+ return (NULL);
+ }
t->initial_symlink_mode = symlink_mode;
return (tree_reopen(t, path, restore_time));
}
@@ -1756,7 +1762,8 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
p = wcsrchr(base, L'/');
if (p != NULL) {
*p = L'\0';
- tree_append(t, base, p - base);
+ if (tree_append(t, base, p - base))
+ goto failed;
t->dirname_length = archive_strlen(&t->path);
base = p + 1;
}
@@ -1892,8 +1899,10 @@ tree_next(struct tree *t)
}
/* Top stack item needs a regular visit. */
t->current = t->stack;
- tree_append(t, t->stack->name.s,
+ r = tree_append(t, t->stack->name.s,
archive_strlen(&(t->stack->name)));
+ if (r != 0)
+ return (r);
//t->dirname_length = t->path_length;
//tree_pop(t);
t->stack->flags &= ~needsFirstVisit;
@@ -1901,8 +1910,10 @@ tree_next(struct tree *t)
} else if (t->stack->flags & needsDescent) {
/* Top stack item is dir to descend into. */
t->current = t->stack;
- tree_append(t, t->stack->name.s,
+ r = tree_append(t, t->stack->name.s,
archive_strlen(&(t->stack->name)));
+ if (r != 0)
+ return (r);
t->stack->flags &= ~needsDescent;
r = tree_descent(t);
if (r != 0) {
@@ -1945,9 +1956,10 @@ tree_dir_next_windows(struct tree *t, const wchar_t *pattern)
struct archive_wstring pt;
archive_string_init(&pt);
- archive_wstring_ensure(&pt,
+ if (archive_wstring_ensure(&pt,
archive_strlen(&(t->full_path))
- + 2 + wcslen(pattern));
+ + 2 + wcslen(pattern)) == NULL)
+ return (TREE_ERROR_FATAL);
archive_wstring_copy(&pt, &(t->full_path));
archive_wstrappend_wchar(&pt, L'\\');
archive_wstrcat(&pt, pattern);
@@ -1979,7 +1991,9 @@ tree_dir_next_windows(struct tree *t, const wchar_t *pattern)
continue;
if (name[0] == L'.' && name[1] == L'.' && name[2] == L'\0')
continue;
- tree_append(t, name, namelen);
+ r = tree_append(t, name, namelen);
+ if (r != 0)
+ return (r);
return (t->visit_type = TREE_REGULAR);
}
}
diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c
index 6ed18a0c08eb..742923abbee9 100644
--- a/libarchive/archive_read_open_file.c
+++ b/libarchive/archive_read_open_file.c
@@ -132,7 +132,7 @@ FILE_skip(struct archive *a, void *client_data, int64_t request)
#else
long skip = (long)request;
#endif
- int64_t old_offset, new_offset;
+ int64_t old_offset, new_offset = -1;
int skip_bits = sizeof(skip) * 8 - 1;
(void)a; /* UNUSED */
@@ -170,11 +170,14 @@ FILE_skip(struct archive *a, void *client_data, int64_t request)
#ifdef __ANDROID__
new_offset = lseek(fileno(mine->f), skip, SEEK_CUR);
#elif HAVE__FSEEKI64
- new_offset = _fseeki64(mine->f, skip, SEEK_CUR);
+ if (_fseeki64(mine->f, skip, SEEK_CUR) == 0)
+ new_offset = _ftelli64(mine->f);
#elif HAVE_FSEEKO
- new_offset = fseeko(mine->f, skip, SEEK_CUR);
+ if (fseeko(mine->f, skip, SEEK_CUR) == 0)
+ new_offset = ftello(mine->f);
#else
- new_offset = fseek(mine->f, skip, SEEK_CUR);
+ if (fseek(mine->f, skip, SEEK_CUR) == 0)
+ new_offset = ftell(mine->f);
#endif
if (new_offset >= 0)
return (new_offset - old_offset);
diff --git a/libarchive/archive_read_support_filter_compress.c b/libarchive/archive_read_support_filter_compress.c
index b6e9816dfee9..b89eaabe5259 100644
--- a/libarchive/archive_read_support_filter_compress.c
+++ b/libarchive/archive_read_support_filter_compress.c
@@ -328,6 +328,7 @@ next_code(struct archive_read_filter *self)
static int debug_buff[1024];
static unsigned debug_index;
+again:
code = newcode = getbits(self, state->bits);
if (code < 0)
return (code);
@@ -360,7 +361,7 @@ next_code(struct archive_read_filter *self)
state->section_end_code = (1 << state->bits) - 1;
state->free_ent = 257;
state->oldcode = -1;
- return (next_code(self));
+ goto again;
}
if (code > state->free_ent
diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c
index e012248a5bc2..a96f7d313951 100644
--- a/libarchive/archive_read_support_format_cab.c
+++ b/libarchive/archive_read_support_format_cab.c
@@ -363,7 +363,12 @@ archive_read_support_format_cab(struct archive *_a)
return (ARCHIVE_FATAL);
}
archive_string_init(&cab->ws);
- archive_wstring_ensure(&cab->ws, 256);
+ if (archive_wstring_ensure(&cab->ws, 256) == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory");
+ free(cab);
+ return (ARCHIVE_FATAL);
+ }
r = __archive_read_register_format(a,
cab,
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index e9b3312a2cbb..0c87bc6d732f 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -174,7 +174,7 @@ static int gnu_sparse_old_parse(struct archive_read *, struct tar *,
const struct gnu_sparse *sparse, int length);
static int gnu_sparse_01_parse(struct archive_read *, struct tar *,
const char *, size_t);
-static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *,
+static int64_t gnu_sparse_10_read(struct archive_read *, struct tar *,
int64_t *);
static int header_Solaris_ACL(struct archive_read *, struct tar *,
struct archive_entry *, const void *, int64_t *);
@@ -628,7 +628,10 @@ archive_read_format_tar_read_data(struct archive_read *a,
/* If we're at end of file, return EOF. */
if (tar->sparse_list == NULL ||
tar->entry_bytes_remaining == 0) {
- if (__archive_read_consume(a, tar->entry_padding) < 0)
+ int64_t request = tar->entry_bytes_remaining +
+ tar->entry_padding;
+
+ if (__archive_read_consume(a, request) != request)
return (ARCHIVE_FATAL);
tar->entry_padding = 0;
*buff = NULL;
@@ -666,29 +669,15 @@ archive_read_format_tar_read_data(struct archive_read *a,
static int
archive_read_format_tar_skip(struct archive_read *a)
{
- int64_t bytes_skipped;
int64_t request;
- struct sparse_block *p;
struct tar* tar;
tar = (struct tar *)(a->format->data);
- /* Do not consume the hole of a sparse file. */
- request = 0;
- for (p = tar->sparse_list; p != NULL; p = p->next) {
- if (!p->hole) {
- if (p->remaining >= INT64_MAX - request) {
- return ARCHIVE_FATAL;
- }
- request += p->remaining;
- }
- }
- if (request > tar->entry_bytes_remaining)
- request = tar->entry_bytes_remaining;
- request += tar->entry_padding + tar->entry_bytes_unconsumed;
+ request = tar->entry_bytes_remaining + tar->entry_padding +
+ tar->entry_bytes_unconsumed;
- bytes_skipped = __archive_read_consume(a, request);
- if (bytes_skipped < 0)
+ if (__archive_read_consume(a, request) != request)
return (ARCHIVE_FATAL);
tar->entry_bytes_remaining = 0;
@@ -702,6 +691,22 @@ archive_read_format_tar_skip(struct archive_read *a)
}
/*
+ * This function resets the accumulated state while reading
+ * a header.
+ */
+static void
+tar_reset_header_state(struct tar *tar)
+{
+ tar->pax_hdrcharset_utf8 = 1;
+ tar->sparse_gnu_attributes_seen = 0;
+ archive_string_empty(&(tar->entry_gname));
+ archive_string_empty(&(tar->entry_pathname));
+ archive_string_empty(&(tar->entry_pathname_override));
+ archive_string_empty(&(tar->entry_uname));
+ archive_string_empty(&tar->entry_linkpath);
+}
+
+/*
* This function reads and interprets all of the headers associated
* with a single entry.
*/
@@ -726,13 +731,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
static const int32_t seen_x_header = 32; /* Also X */
static const int32_t seen_mac_metadata = 512;
- tar->pax_hdrcharset_utf8 = 1;
- tar->sparse_gnu_attributes_seen = 0;
- archive_string_empty(&(tar->entry_gname));
- archive_string_empty(&(tar->entry_pathname));
- archive_string_empty(&(tar->entry_pathname_override));
- archive_string_empty(&(tar->entry_uname));
- archive_string_empty(&tar->entry_linkpath);
+ tar_reset_header_state(tar);
/* Ensure format is set. */
if (a->archive.archive_format_name == NULL) {
@@ -936,6 +935,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
err = err_combine(err, err2);
/* Note: Other headers can appear again. */
seen_headers = seen_mac_metadata;
+ tar_reset_header_state(tar);
break;
}
@@ -1118,8 +1118,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Malformed Solaris ACL attribute (unsupported type %"
- PRIo64 ")", type);
+ "Malformed Solaris ACL attribute (unsupported type %llu)",
+ (unsigned long long)type);
archive_string_free(&acl_text);
return (ARCHIVE_WARN);
}
@@ -1293,18 +1293,21 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
(void)tar; /* UNUSED */
header = (const struct archive_entry_header_ustar *)h;
size = tar_atol(header->size, sizeof(header->size));
- if (size > entry_limit) {
+ 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 > (int64_t)pathname_limit) || (size < 0)) {
+ if (size > (int64_t)pathname_limit) {
archive_string_empty(as);
int64_t to_consume = ((size + 511) & ~511);
if (to_consume != __archive_read_consume(a, to_consume)) {
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive, EINVAL,
- "Special header too large: %d > 1MiB",
- (int)size);
+ "Special header too large: %lld > 1MiB",
+ (long long)size);
return (ARCHIVE_WARN);
}
r = read_bytes_to_string(a, as, size, unconsumed);
@@ -1743,7 +1746,10 @@ header_pax_global(struct archive_read *a, struct tar *tar,
header = (const struct archive_entry_header_ustar *)h;
size = tar_atol(header->size, sizeof(header->size));
- if (size > entry_limit) {
+ if (size < 0 || size > entry_limit) {
+ archive_set_error(&a->archive, EINVAL,
+ "Special header has invalid size: %lld",
+ (long long)size);
return (ARCHIVE_FATAL);
}
to_consume = ((size + 511) & ~511);
@@ -1890,8 +1896,8 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive, EINVAL,
- "Ignoring oversized pax extensions: %d > %d",
- (int)ext_size, (int)ext_size_limit);
+ "Ignoring oversized pax extensions: %lld > %lld",
+ (long long)ext_size, (long long)ext_size_limit);
return (ARCHIVE_WARN);
}
tar_flush_unconsumed(a, unconsumed);
@@ -1990,6 +1996,13 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
*unconsumed += p - attr_start;
tar_flush_unconsumed(a, unconsumed);
+ if (value_length == 0) {
+ archive_set_error(&a->archive, EINVAL,
+ "Malformed pax attributes");
+ *unconsumed += ext_size + ext_padding;
+ 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);
ext_size -= value_length - 1;
@@ -2199,8 +2212,9 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar,
if (value_length > acl_limit) {
__archive_read_consume(a, value_length);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unreasonably large ACL: %d > %d",
- (int)value_length, (int)acl_limit);
+ "Unreasonably large ACL: %llu > %llu",
+ (unsigned long long)value_length,
+ (unsigned long long)acl_limit);
return (ARCHIVE_WARN);
}
@@ -2247,12 +2261,16 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps
r = read_bytes_to_string(a, &as, value_length, unconsumed);
if (r < ARCHIVE_OK) {
archive_string_free(&as);
+ *ps = 0;
+ *pn = 0;
return (r);
}
pax_time(as.s, archive_strlen(&as), ps, pn);
archive_string_free(&as);
- if (*ps < 0 || *ps == INT64_MAX) {
+ if (*ps == INT64_MIN) {
+ *ps = 0;
+ *pn = 0;
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
@@ -2386,8 +2404,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
tar->sparse_gnu_minor = 1;
if (value_length > sparse_map_limit) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unreasonably large sparse map: %d > %d",
- (int)value_length, (int)sparse_map_limit);
+ "Unreasonably large sparse map: %llu > %llu",
+ (unsigned long long)value_length,
+ (unsigned long long)sparse_map_limit);
err = ARCHIVE_FAILED;
} else {
p = __archive_read_ahead(a, value_length, &bytes_read);
@@ -2494,8 +2513,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"symlink type is very long"
- "(longest recognized value is 4 bytes, this is %d)",
- (int)value_length);
+ "(longest recognized value is 4 bytes, this is %llu)",
+ (unsigned long long)value_length);
err = ARCHIVE_WARN;
}
__archive_read_consume(a, value_length);
@@ -2531,8 +2550,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
if (value_length > xattr_limit) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Ignoring unreasonably large security.selinux attribute:"
- " %d > %d",
- (int)value_length, (int)xattr_limit);
+ " %llu > %llu",
+ (unsigned long long)value_length,
+ (unsigned long long)xattr_limit);
/* TODO: Should this be FAILED instead? */
err = ARCHIVE_WARN;
} else {
@@ -2649,8 +2669,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unreasonably large xattr: %d > %d",
- (int)value_length, (int)xattr_limit);
+ "Unreasonably large xattr: %llu > %llu",
+ (unsigned long long)value_length,
+ (unsigned long long)xattr_limit);
err = ARCHIVE_WARN;
}
__archive_read_consume(a, value_length);
@@ -2680,8 +2701,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Unreasonably large sparse map: %d > %d",
- (int)value_length, (int)sparse_map_limit);
+ "Unreasonably large sparse map: %llu > %llu",
+ (unsigned long long)value_length,
+ (unsigned long long)sparse_map_limit);
err = ARCHIVE_FAILED;
}
__archive_read_consume(a, value_length);
@@ -2750,8 +2772,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "hdrcharset attribute is unreasonably large (%d bytes)",
- (int)value_length);
+ "hdrcharset attribute is unreasonably large (%llu bytes)",
+ (unsigned long long)value_length);
err = ARCHIVE_WARN;
}
__archive_read_consume(a, value_length);
@@ -2838,7 +2860,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
/*
- * parse a decimal time value, which may include a fractional portion
+ * Parse a decimal time value, which may include a fractional portion
+ *
+ * Sets ps to INT64_MIN on error.
*/
static void
pax_time(const char *p, size_t length, int64_t *ps, long *pn)
@@ -2854,6 +2878,7 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
if (length <= 0) {
*ps = 0;
+ *pn = 0;
return;
}
s = 0;
@@ -2867,8 +2892,9 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
digit = *p - '0';
if (s > limit ||
(s == limit && digit > last_digit_limit)) {
- s = INT64_MAX;
- break;
+ *ps = INT64_MIN;
+ *pn = 0;
+ return;
}
s = (s * 10) + digit;
++p;
@@ -3229,12 +3255,10 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
* Returns length (in bytes) of the sparse data description
* that was read.
*/
-static ssize_t
+static int64_t
gnu_sparse_10_read(struct archive_read *a, struct tar *tar, int64_t *unconsumed)
{
- ssize_t bytes_read;
- int entries;
- int64_t offset, size, to_skip, remaining;
+ int64_t bytes_read, entries, offset, size, to_skip, remaining;
/* Clear out the existing sparse list. */
gnu_clear_sparse_list(tar);
@@ -3242,7 +3266,7 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, int64_t *unconsumed)
remaining = tar->entry_bytes_remaining;
/* Parse entries. */
- entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
+ entries = gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
if (entries < 0)
return (ARCHIVE_FATAL);
/* Parse the individual entries. */
@@ -3260,14 +3284,14 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, int64_t *unconsumed)
}
/* Skip rest of block... */
tar_flush_unconsumed(a, unconsumed);
- bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining);
+ bytes_read = tar->entry_bytes_remaining - remaining;
to_skip = 0x1ff & -bytes_read;
/* Fail if tar->entry_bytes_remaing would get negative */
if (to_skip > remaining)
return (ARCHIVE_FATAL);
if (to_skip != __archive_read_consume(a, to_skip))
return (ARCHIVE_FATAL);
- return ((ssize_t)(bytes_read + to_skip));
+ return (bytes_read + to_skip);
}
/*
diff --git a/libarchive/archive_string_sprintf.c b/libarchive/archive_string_sprintf.c
index c785e12bdf6d..1c5910e0b2d3 100644
--- a/libarchive/archive_string_sprintf.c
+++ b/libarchive/archive_string_sprintf.c
@@ -116,8 +116,14 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
long_flag = '\0';
switch(*p) {
- case 'j':
case 'l':
+ if (p[1] == 'l') {
+ long_flag = 'L';
+ p += 2;
+ break;
+ }
+ __LA_FALLTHROUGH;
+ case 'j':
case 'z':
long_flag = *p;
p++;
@@ -136,6 +142,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
switch(long_flag) {
case 'j': s = va_arg(ap, intmax_t); break;
case 'l': s = va_arg(ap, long); break;
+ case 'L': s = va_arg(ap, long long); break;
case 'z': s = va_arg(ap, ssize_t); break;
default: s = va_arg(ap, int); break;
}
@@ -144,6 +151,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
case 's':
switch(long_flag) {
case 'l':
+ case 'L':
pw = va_arg(ap, wchar_t *);
if (pw == NULL)
pw = L"(null)";
@@ -172,6 +180,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
switch(long_flag) {
case 'j': u = va_arg(ap, uintmax_t); break;
case 'l': u = va_arg(ap, unsigned long); break;
+ case 'L': u = va_arg(ap, unsigned long long); break;
case 'z': u = va_arg(ap, size_t); break;
default: u = va_arg(ap, unsigned int); break;
}
diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c
index 3a8caad5262b..900abd0c3c62 100644
--- a/libarchive/archive_util.c
+++ b/libarchive/archive_util.c
@@ -77,7 +77,9 @@
#define O_CLOEXEC 0
#endif
-static int archive_utility_string_sort_helper(char **, unsigned int);
+#if ARCHIVE_VERSION_NUMBER < 4000000
+static int __LA_LIBC_CC archive_utility_string_sort_helper(const void *, const void *);
+#endif
/* Generic initialization of 'struct archive' objects. */
int
@@ -629,74 +631,28 @@ __archive_ensure_cloexec_flag(int fd)
#endif
}
+#if ARCHIVE_VERSION_NUMBER < 4000000
/*
- * Utility function to sort a group of strings using quicksort.
+ * Utility functions to sort a group of strings using quicksort.
*/
static int
-archive_utility_string_sort_helper(char **strings, unsigned int n)
+__LA_LIBC_CC
+archive_utility_string_sort_helper(const void *p1, const void *p2)
{
- unsigned int i, lesser_count, greater_count;
- char **lesser, **greater, **tmp, *pivot;
- int retval1, retval2;
-
- /* A list of 0 or 1 elements is already sorted */
- if (n <= 1)
- return (ARCHIVE_OK);
-
- lesser_count = greater_count = 0;
- lesser = greater = NULL;
- pivot = strings[0];
- for (i = 1; i < n; i++)
- {
- if (strcmp(strings[i], pivot) < 0)
- {
- lesser_count++;
- tmp = realloc(lesser, lesser_count * sizeof(*tmp));
- if (!tmp) {
- free(greater);
- free(lesser);
- return (ARCHIVE_FATAL);
- }
- lesser = tmp;
- lesser[lesser_count - 1] = strings[i];
- }
- else
- {
- greater_count++;
- tmp = realloc(greater, greater_count * sizeof(*tmp));
- if (!tmp) {
- free(greater);
- free(lesser);
- return (ARCHIVE_FATAL);
- }
- greater = tmp;
- greater[greater_count - 1] = strings[i];
- }
- }
+ const char * const * const s1 = p1;
+ const char * const * const s2 = p2;
- /* quicksort(lesser) */
- retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
- for (i = 0; i < lesser_count; i++)
- strings[i] = lesser[i];
- free(lesser);
-
- /* pivot */
- strings[lesser_count] = pivot;
-
- /* quicksort(greater) */
- retval2 = archive_utility_string_sort_helper(greater, greater_count);
- for (i = 0; i < greater_count; i++)
- strings[lesser_count + 1 + i] = greater[i];
- free(greater);
-
- return (retval1 < retval2) ? retval1 : retval2;
+ return strcmp(*s1, *s2);
}
int
archive_utility_string_sort(char **strings)
{
- unsigned int size = 0;
- while (strings[size] != NULL)
+ size_t size = 0;
+ while (strings[size] != NULL)
size++;
- return archive_utility_string_sort_helper(strings, size);
+ qsort(strings, size, sizeof(char *),
+ archive_utility_string_sort_helper);
+ return (ARCHIVE_OK);
}
+#endif
diff --git a/libarchive/archive_version_details.c b/libarchive/archive_version_details.c
index 186e53e50c84..0cf92db73194 100644
--- a/libarchive/archive_version_details.c
+++ b/libarchive/archive_version_details.c
@@ -134,31 +134,31 @@ archive_libb2_version(struct archive_string* str)
static void
archive_crypto_version(struct archive_string* str)
{
-#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto) || defined(ARCHIVE_DIGEST_USE_Apple_CommonCrypto)
+#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto)
archive_strcat(str, " CommonCrypto/");
archive_strcat(str, archive_commoncrypto_version());
#endif
-#if defined(ARCHIVE_CRYPTOR_USE_CNG) || defined(ARCHIVE_DIGEST_USE_CNG)
+#if defined(ARCHIVE_CRYPTOR_USE_CNG)
archive_strcat(str, " cng/");
archive_strcat(str, archive_cng_version());
#endif
-#if defined(ARCHIVE_CRYPTOR_USE_MBED) || defined(ARCHIVE_DIGEST_USE_MBED)
+#if defined(ARCHIVE_CRYPTOR_USE_MBED)
archive_strcat(str, " mbedtls/");
archive_strcat(str, archive_mbedtls_version());
#endif
-#if defined(ARCHIVE_CRYPTOR_USE_NETTLE) || defined(ARCHIVE_DIGEST_USE_NETTLE)
+#if defined(ARCHIVE_CRYPTOR_USE_NETTLE)
archive_strcat(str, " nettle/");
archive_strcat(str, archive_nettle_version());
#endif
-#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL) || defined(ARCHIVE_DIGEST_USE_OPENSSL)
+#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL)
archive_strcat(str, " openssl/");
archive_strcat(str, archive_openssl_version());
#endif
-#if defined(ARCHIVE_CRYPTOR_USE_LIBMD) || defined(ARCHIVE_DIGEST_USE_LIBMD)
+#if defined(ARCHIVE_CRYPTOR_USE_LIBMD)
archive_strcat(str, " libmd/");
archive_strcat(str, archive_libmd_version());
#endif
-#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT) || defined(ARCHIVE_DIGEST_USE_WINCRYPT)
+#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT)
archive_strcat(str, " WinCrypt/");
archive_strcat(str, archive_wincrypt_version());
#endif
@@ -439,11 +439,11 @@ archive_wincrypt_version(void)
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
return NULL;
}
- DWORD length, version;
- if (!CryptGetProvParam(prov, PP_VERSION, &version, &length, 0)) {
+ DWORD version, length = sizeof(version);
+ if (!CryptGetProvParam(prov, PP_VERSION, (BYTE *)&version, &length, 0)) {
return NULL;
} else {
- char major = version >> 8;
+ char major = (version >> 8) & 0xFF;
char minor = version & 0xFF;
static char wincrypt_version[6];
snprintf(wincrypt_version, 6, "%hhd.%hhd", major, minor);
diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c
index c9f10a8ae793..c7339c4ec1b1 100644
--- a/libarchive/archive_write_disk_windows.c
+++ b/libarchive/archive_write_disk_windows.c
@@ -408,7 +408,11 @@ permissive_name_w(struct archive_write_disk *a)
wn = _wcsdup(wnp);
if (wn == NULL)
return (-1);
- archive_wstring_ensure(&(a->_name_data), 4 + wcslen(wn) + 1);
+ if (archive_wstring_ensure(&(a->_name_data),
+ 4 + wcslen(wn) + 1) == NULL) {
+ free(wn);
+ return (-1);
+ }
a->name = a->_name_data.s;
/* Prepend "\\?\" */
archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
@@ -438,8 +442,11 @@ permissive_name_w(struct archive_write_disk *a)
wn = _wcsdup(wnp);
if (wn == NULL)
return (-1);
- archive_wstring_ensure(&(a->_name_data),
- 8 + wcslen(wn) + 1);
+ if (archive_wstring_ensure(&(a->_name_data),
+ 8 + wcslen(wn) + 1) == NULL) {
+ free(wn);
+ return (-1);
+ }
a->name = a->_name_data.s;
/* Prepend "\\?\UNC\" */
archive_wstrncpy(&(a->_name_data),
@@ -471,10 +478,16 @@ permissive_name_w(struct archive_write_disk *a)
*/
if (wnp[0] == L'\\') {
wn = _wcsdup(wnp);
- if (wn == NULL)
+ if (wn == NULL) {
+ free(wsp);
+ return (-1);
+ }
+ if (archive_wstring_ensure(&(a->_name_data),
+ 4 + 2 + wcslen(wn) + 1) == NULL) {
+ free(wsp);
+ free(wn);
return (-1);
- archive_wstring_ensure(&(a->_name_data),
- 4 + 2 + wcslen(wn) + 1);
+ }
a->name = a->_name_data.s;
/* Prepend "\\?\" and drive name. */
archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
@@ -486,9 +499,16 @@ permissive_name_w(struct archive_write_disk *a)
}
wn = _wcsdup(wnp);
- if (wn == NULL)
+ if (wn == NULL) {
+ free(wsp);
return (-1);
- archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1);
+ }
+ if (archive_wstring_ensure(&(a->_name_data),
+ 4 + l + 1 + wcslen(wn) + 1) == NULL) {
+ free(wsp);
+ free(wn);
+ return (-1);
+ }
a->name = a->_name_data.s;
/* Prepend "\\?\" and drive name if not already added. */
if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' &&
diff --git a/libarchive/archive_write_set_format_iso9660.c b/libarchive/archive_write_set_format_iso9660.c
index 3c5b8899434e..c275c1ec92b9 100644
--- a/libarchive/archive_write_set_format_iso9660.c
+++ b/libarchive/archive_write_set_format_iso9660.c
@@ -1167,7 +1167,12 @@ archive_write_set_format_iso9660(struct archive *_a)
iso9660->primary.rootent->parent = iso9660->primary.rootent;
iso9660->cur_dirent = iso9660->primary.rootent;
archive_string_init(&(iso9660->cur_dirstr));
- archive_string_ensure(&(iso9660->cur_dirstr), 1);
+ if (archive_string_ensure(&(iso9660->cur_dirstr), 1) == NULL) {
+ free(iso9660);
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory");
+ return (ARCHIVE_FATAL);
+ }
iso9660->cur_dirstr.s[0] = 0;
iso9660->sconv_to_utf16be = NULL;
iso9660->sconv_from_utf16be = NULL;
@@ -5666,9 +5671,15 @@ isoent_tree(struct archive_write *a, struct isoent **isoentpp)
* inserted. */
iso9660->cur_dirent = dent;
archive_string_empty(&(iso9660->cur_dirstr));
- archive_string_ensure(&(iso9660->cur_dirstr),
+ if (archive_string_ensure(&(iso9660->cur_dirstr),
archive_strlen(&(dent->file->parentdir)) +
- archive_strlen(&(dent->file->basename)) + 2);
+ archive_strlen(&(dent->file->basename)) + 2) == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory");
+ _isoent_free(isoent);
+ *isoentpp = NULL;
+ return (ARCHIVE_FATAL);
+ }
if (archive_strlen(&(dent->file->parentdir)) +
archive_strlen(&(dent->file->basename)) == 0)
iso9660->cur_dirstr.s[0] = 0;
diff --git a/libarchive/archive_write_set_format_mtree.c b/libarchive/archive_write_set_format_mtree.c
index c2ecc424675b..02fbb2d2f555 100644
--- a/libarchive/archive_write_set_format_mtree.c
+++ b/libarchive/archive_write_set_format_mtree.c
@@ -2209,9 +2209,13 @@ mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep)
* inserted. */
mtree->cur_dirent = dent;
archive_string_empty(&(mtree->cur_dirstr));
- archive_string_ensure(&(mtree->cur_dirstr),
+ if (archive_string_ensure(&(mtree->cur_dirstr),
archive_strlen(&(dent->parentdir)) +
- archive_strlen(&(dent->basename)) + 2);
+ archive_strlen(&(dent->basename)) + 2) == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory");
+ return (ARCHIVE_FATAL);
+ }
if (archive_strlen(&(dent->parentdir)) +
archive_strlen(&(dent->basename)) == 0)
mtree->cur_dirstr.s[0] = 0;
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index ffdb5b4ef7c5..b5acb468c4c9 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -174,8 +174,10 @@ IF(ENABLE_TEST)
test_read_format_tar_empty_pax.c
test_read_format_tar_filename.c
test_read_format_tar_invalid_pax_size.c
+ test_read_format_tar_mac_metadata.c
test_read_format_tar_pax_g_large.c
test_read_format_tar_pax_large_attr.c
+ test_read_format_tar_pax_negative_time.c
test_read_format_tbz.c
test_read_format_tgz.c
test_read_format_tlz.c
@@ -208,6 +210,7 @@ IF(ENABLE_TEST)
test_read_format_zip_zip64.c
test_read_format_zip_with_invalid_traditional_eocd.c
test_read_large.c
+ test_read_pax_empty_val_no_nl.c
test_read_pax_xattr_rht_security_selinux.c
test_read_pax_xattr_schily.c
test_read_pax_truncated.c
diff --git a/libarchive/test/test_entry.c b/libarchive/test/test_entry.c
index 38c406e35b5a..9b21b83ecdfb 100644
--- a/libarchive/test/test_entry.c
+++ b/libarchive/test/test_entry.c
@@ -436,7 +436,7 @@ DEFINE_TEST(test_entry)
archive_entry_fflags(e, &set, &clear);
assertEqualInt(UF_HIDDEN, set);
assertEqualInt(UF_NODUMP | UF_IMMUTABLE | UF_APPEND, clear);
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
archive_entry_copy_fflags_text_w(e, L"rdonly,hidden,nosystem");
archive_entry_fflags(e, &set, &clear);
assertEqualInt(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN, set);
diff --git a/libarchive/test/test_read_disk_directory_traversals.c b/libarchive/test/test_read_disk_directory_traversals.c
index 009c9a8db1e1..7597f4b6f6eb 100644
--- a/libarchive/test/test_read_disk_directory_traversals.c
+++ b/libarchive/test/test_read_disk_directory_traversals.c
@@ -39,7 +39,7 @@ atimeIsUpdated(void)
{
const char *fn = "fs_noatime";
struct stat st;
-#if defined(_WIN32) && !defined(CYGWIN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
char *buff = NULL;
char *ptr;
int r;
diff --git a/libarchive/test/test_read_format_gtar_sparse_skip_entry.tar.Z.uu b/libarchive/test/test_read_format_gtar_sparse_skip_entry.tar.Z.uu
index 634ac0673db7..1aff5d386bdb 100644
--- a/libarchive/test/test_read_format_gtar_sparse_skip_entry.tar.Z.uu
+++ b/libarchive/test/test_read_format_gtar_sparse_skip_entry.tar.Z.uu
@@ -1,15 +1,15 @@
begin 644 test_read_format_gtar_sparse_skip_entry.tar.Z
M'YV04,+@05(F#)DR<EZ$`<"PH<.'$"-*G$BQHL6*,#+:L$$#!(",,6[4@.$1
MI$B2'S.JS#A#A@P0,63,L`$C!HP9-VB\K"FCAHT8`$#@N4BTJ-&C2"/6F4,G
-MC)R48^J424HQZE2J$E=F+*G5(]:O8,.*'3M6!LDY:?24Z6'S!DX:,7#(H$%#
-MP0R2;>BD:;,V!@T8-6)NE&'#10T<-#;>R(%CAEV28_3R9?LW\(P8-F[`<#%C
-M)@T<->#6>`PBC.2^E07;J#'#Q>J-F5DJ<`GBB),J+N;`<3JGC(LV8=2\D<-V
-M]DO;N'7S]MTFC9OA/6#,CE'[=N[=<GJ[<!-F<AB[-:HGQZY=3D$V:-6RA>$V
-M9]RY=<G*GT^_OOW[^/.#13Z%?!DC:;!1AD+Z%6B12AMUE%)((W'%($I:U603
-M#!W%-%---^6T4PPM8184#`:&"-9233V5D57SH2A?A%RMY)6(,,8HHPP*2/=7
-M#C8HT-9;[_VE0'PR!BGDD$06:>212"9YD1EOO*&`DE!&*>645%9IY9589JGE
+MC)R48^J424HQZE2J$E=F+*G5(]:O8,.*'3M6!LDY:?24Z:$U(XV?,A3,(-F&
+M3IHV:V/0@%$CYD89-ES4P/'6QHT<.&;()3G&+MX>>OG&F!'#,`P7,V;2P%&#
+M1HP:BT&$<9QW;U_`-FK,<)%ZH^6;"ER"..*DBHLY<)S.*>.B31@U;^1`COV2
+MMFW<NGFW2>,F.-O8,6;7OIU;SFX7;L(\#B.WAO3CU:_+*<@&K5K(,&[@](Q#
+M!@T:"LC*GT^_OOW[^/.#-3XE?!DC:;!1AD+Z%6B12AMUE%)((W'%($IMK=11
+M3#/5=%-..TTF@UY!P6#@AV`MU=13&5DUGXGRM<752EZ!Z.*+,,8%@P)[Y6"#
+M`C:IEU,,[>TE5WPP!BGDD$06:>212"9YD1EOO`&DDE!&*>645%9IY9589JGE
MEEQVZ>678(8IYIADEFGFF6BFJ>::;+;IYIMPQBGGG'36:>>=>.:IYYY\]NGG
-MGX`&*NB@A!9JJ)YB](D@1PZ>U&B#*468484RT11###7<8!8(&-)4PX=^DN@4
-B5%*E6.J*746JTHN'2LFDDZW&*NNLM-9JZZVXYJKKKKR&!0``
+MGX`&*NB@A!9J*)YB](D@1PZ>U&B#*44(PX0RT13#9S>8!8*%--70H9\B.@65
+A5">2FF)7D:K4XJ%2,NDDJ[#&*NNLM-9JZZVXYJKKKF$!
`
end
diff --git a/libarchive/test/test_read_format_rar5.c b/libarchive/test/test_read_format_rar5.c
index 696975354565..fd233277bc1b 100644
--- a/libarchive/test/test_read_format_rar5.c
+++ b/libarchive/test/test_read_format_rar5.c
@@ -1126,7 +1126,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_READONLY;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_READONLY;
#endif
assertEqualInt(flag, set & flag);
@@ -1138,7 +1138,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_HIDDEN;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_HIDDEN;
#endif
assertEqualInt(flag, set & flag);
@@ -1150,7 +1150,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_SYSTEM;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_SYSTEM;
#endif
assertEqualInt(flag, set & flag);
@@ -1162,7 +1162,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_READONLY | UF_HIDDEN;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN;
#endif
assertEqualInt(flag, set & flag);
@@ -1174,7 +1174,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_READONLY;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_READONLY;
#endif
assertEqualInt(flag, set & flag);
@@ -1186,7 +1186,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_HIDDEN;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_HIDDEN;
#endif
assertEqualInt(flag, set & flag);
@@ -1198,7 +1198,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_SYSTEM;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_SYSTEM;
#endif
assertEqualInt(flag, set & flag);
@@ -1210,7 +1210,7 @@ DEFINE_TEST(test_read_format_rar5_fileattr)
archive_entry_fflags(ae, &set, &clear);
#if defined(__FreeBSD__)
flag = UF_READONLY | UF_HIDDEN;
-#elif defined(_WIN32) && !defined(CYGWIN)
+#elif defined(_WIN32) && !defined(__CYGWIN__)
flag = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN;
#endif
assertEqualInt(flag, set & flag);
diff --git a/libarchive/test/test_read_format_tar_mac_metadata.c b/libarchive/test/test_read_format_tar_mac_metadata.c
new file mode 100644
index 000000000000..b4745a22ee3b
--- /dev/null
+++ b/libarchive/test/test_read_format_tar_mac_metadata.c
@@ -0,0 +1,85 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Zhaofeng Li
+ * All rights reserved.
+ */
+#include "test.h"
+
+DEFINE_TEST(test_read_format_tar_mac_metadata)
+{
+ /*
+ This test tar file is crafted with two files in a specific order:
+
+ 1. A ._-prefixed file with pax header containing the path attribute.
+ 2. A file with a pax header but without the path attribute.
+
+ It's designed to trigger the case encountered in:
+ <https://github.com/libarchive/libarchive/pull/2636>
+
+ GNU tar is required to reproduce this tar file:
+
+ ```sh
+ NAME1="._101_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ NAME2="goodname"
+ OUT="test_read_format_tar_mac_metadata_1.tar"
+
+ echo "content of badname" >"${NAME1}"
+ echo "content of goodname" >"${NAME2}"
+
+ rm -f "${OUT}"
+ gnutar \
+ --mtime="@0" \
+ --owner=0 --group=0 --numeric-owner \
+ --pax-option=exthdr.name=%d/PaxHeaders/%f,atime:=0,ctime:=0,foo:=bar \
+ --format=pax \
+ -cf "${OUT}" \
+ "${NAME1}" \
+ "${NAME2}"
+ uuencode "${OUT}" "${OUT}" >"${OUT}.uu"
+
+ sha256sum "${OUT}"
+ sha256sum "${OUT}.uu"
+ ```
+ */
+ const char *refname = "test_read_format_tar_mac_metadata_1.tar";
+ char *p;
+ size_t s;
+ struct archive *a;
+ struct archive_entry *ae;
+
+ /*
+ * This is not a valid AppleDouble metadata file. It is merely to test that
+ * the correct bytes are read.
+ */
+ const unsigned char appledouble[] = {
+ 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x62,
+ 0x61, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x0a
+ };
+
+ extract_reference_file(refname);
+ p = slurpfile(&s, "%s", refname);
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_tar(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_set_option(a, "tar", "mac-ext", "1"));
+ assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 1));
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+
+ /* Correct name and metadata bytes */
+ assertEqualString("goodname", archive_entry_pathname(ae));
+
+ const void *metadata = archive_entry_mac_metadata(ae, &s);
+ if (assert(metadata != NULL)) {
+ assertEqualMem(metadata, appledouble,
+ sizeof(appledouble));
+ }
+
+ /* ... and nothing else */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+
+ free(p);
+}
diff --git a/libarchive/test/test_read_format_tar_mac_metadata_1.tar.uu b/libarchive/test/test_read_format_tar_mac_metadata_1.tar.uu
new file mode 100644
index 000000000000..20b2cf5efe26
--- /dev/null
+++ b/libarchive/test/test_read_format_tar_mac_metadata_1.tar.uu
@@ -0,0 +1,231 @@
+begin 644 test_read_format_tar_mac_metadata_1.tar
+M+B]087A(96%D97)S+RY?,3`Q7V%A86%A86%A86%A86%A86%A86%A86%A86%A
+M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A
+M86%A86%A86%A83`P,#`V-#0`,#`P,#`P,``P,#`P,#`P`#`P,#`P,#`P,C(P
+M`#`P,#`P,#`P,#`P`#`S,#,Q,0`@>```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,```````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````Q,3$@<&%T:#TN7S$P,5]A86%A86%A86%A86%A
+M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A
+M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A80HQ,2!F;V\]
+M8F%R"C$Q(&-T:6UE/3`*,3$@871I;64],`H`````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````"Y?,3`Q7V%A86%A
+M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A
+M86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86%A86$P
+M,#`P-C0T`#`P,#`P,#``,#`P,#`P,``P,#`P,#`P,#`R,P`P,#`P,#`P,#`P
+M,``P,S`S-S8`(#``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````=7-T87(`,#``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````8V]N=&5N="!O9B!B861N86UE"@``````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````N+U!A>$AE861E<G,O9V]O9&YA;64`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````,#`P,#8T-``P,#`P
+M,#`P`#`P,#`P,#``,#`P,#`P,#`P-#$`,#`P,#`P,#`P,#``,#$Q-S0U`"!X
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````'5S=&%R`#`P````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````#$Q(&9O
+M;SUB87(*,3$@8W1I;64],`HQ,2!A=&EM93TP"@``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````9V]O9&YA;64`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````#`P,#`V-#0`,#`P,#`P,``P,#`P,#`P
+M`#`P,#`P,#`P,#(T`#`P,#`P,#`P,#`P`#`P-S0U-0`@,```````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````````!U
+M<W1A<@`P,```````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````!C;VYT96YT(&]F(&=O;V1N
+M86UE"@``````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+9````````````````````````````````````
+`
+end
diff --git a/libarchive/test/test_read_format_tar_pax_negative_time.c b/libarchive/test/test_read_format_tar_pax_negative_time.c
new file mode 100644
index 000000000000..b4edc3c2d951
--- /dev/null
+++ b/libarchive/test/test_read_format_tar_pax_negative_time.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2025 Tobias Stoeckmann
+ * 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"
+
+/*
+ * Read a pax formatted tar archive that has a negative modification time.
+ */
+DEFINE_TEST(test_read_format_tar_pax_negative_time)
+{
+ char name[] = "test_read_format_tar_pax_negative_time.tar";
+ struct archive_entry *ae;
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));
+
+ /* Read first entry. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+ assertEqualString("empty", archive_entry_pathname(ae));
+ assertEqualInt(-2146608000, archive_entry_atime(ae));
+ assertEqualInt(0, archive_entry_atime_nsec(ae));
+ assertEqualInt(1748089464, archive_entry_ctime(ae));
+ assertEqualInt(951928467, archive_entry_ctime_nsec(ae));
+ assertEqualInt(-2146608000, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(0, archive_entry_uid(ae));
+ assertEqualString("root", archive_entry_uname(ae));
+ assertEqualInt(0, archive_entry_gid(ae));
+ assertEqualString("root", archive_entry_gname(ae));
+ assertEqualInt(0100644, archive_entry_mode(ae));
+ assertEqualInt(archive_entry_is_encrypted(ae), 0);
+ assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
+
+ /* Verify the end-of-archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Verify that the format detection worked. */
+ assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
+ assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_read_format_tar_pax_negative_time.tar.uu b/libarchive/test/test_read_format_tar_pax_negative_time.tar.uu
new file mode 100644
index 000000000000..fdf3fc304bc8
--- /dev/null
+++ b/libarchive/test/test_read_format_tar_pax_negative_time.tar.uu
@@ -0,0 +1,60 @@
+begin 644 test_read_format_tar_pax_negative_time.tar
+M4&%X2&5A9&5R+V5M<'1Y````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#8T-"``,#`P,#`P(``P,#`P,#`@`#`P,#`P,#`P,3$P
+M(#`P,#`P,#`P,#`P(#`Q-#`Q-P`@>```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,')O;W0`
+M````````````````````````````````````<F]O=```````````````````
+M```````````````````P,#`P,#`@`#`P,#`P,"``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````S,"!C=&EM93TQ-S0X,#@Y-#8T+CDU,3DR.#0V
+M-PHR,2!A=&EM93TM,C$T-C8P.#`P,`HR,2!M=&EM93TM,C$T-C8P.#`P,`H`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````&5M<'1Y````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````P
+M,#`V-#0@`#`P,#`P,"``,#`P,#`P(``P,#`P,#`P,#`P,"#_________@`U<
+M@"`P,34Q-C8`(#``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````=7-T87(`,#!R;V]T````````````````
+M`````````````````````')O;W0`````````````````````````````````
+M````,#`P,#`P(``P,#`P,#`@````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+H````````````````````````````````````````````````````````
+`
+end
diff --git a/libarchive/test/test_read_pax_empty_val_no_nl.c b/libarchive/test/test_read_pax_empty_val_no_nl.c
new file mode 100644
index 000000000000..f985488754fd
--- /dev/null
+++ b/libarchive/test/test_read_pax_empty_val_no_nl.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2025 Tobias Stoeckmann
+ * 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"
+
+/*
+ * Read a pax formatted tar archive that contains an invalid attribute,
+ * because it does not end in a newline. Additionally, value is empty.
+ * The pax reader should stop and tar reader should continue with warning.
+ */
+DEFINE_TEST(test_read_pax_empty_val_no_nl)
+{
+ char name[] = "test_read_pax_empty_val_no_nl.tar";
+ struct archive_entry *ae;
+ struct archive *a;
+
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));
+
+ /* Read first entry. */
+ assertEqualIntA(a, ARCHIVE_WARN, archive_read_next_header(a, &ae));
+ assertEqualString("empty", archive_entry_pathname(ae));
+ assertEqualInt(1748163748, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_uid(ae));
+ assertEqualString("root", archive_entry_uname(ae));
+ assertEqualInt(0, archive_entry_gid(ae));
+ assertEqualString("root", archive_entry_gname(ae));
+ assertEqualInt(0100600, archive_entry_mode(ae));
+ assertEqualInt(archive_entry_is_encrypted(ae), 0);
+ assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
+
+ /* Verify the end-of-archive. */
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+
+ /* Verify that the format detection worked. */
+ assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE);
+ assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE);
+
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_read_pax_empty_val_no_nl.tar.uu b/libarchive/test/test_read_pax_empty_val_no_nl.tar.uu
new file mode 100644
index 000000000000..5de8b25ecccd
--- /dev/null
+++ b/libarchive/test/test_read_pax_empty_val_no_nl.tar.uu
@@ -0,0 +1,60 @@
+begin 600 test_read_pax_empty_val_no_nl.tar
+M4&%X2&5A9&5R+V5M<'1Y````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#8P,"``,#`P,#`P(``P,#`P,#`@`#`P,#`P,#`P,#`T
+M(#$U,#$T-34V,C0T(#`Q-#`U-@`@>```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,')O;W0`
+M````````````````````````````````````<F]O=```````````````````
+M```````````````````P,#`P,#`@`#`P,#`P,"``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````T('@]````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````H`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````&5M<'1Y````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````P
+M,#`V,#`@`#`P,#`P,"``,#`P,#`P(``P,#`P,#`P,#`P,"`Q-3`Q-#4U-C(T
+M-"`P,3(Q,#$`(#``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````=7-T87(`,#!R;V]T````````````````
+M`````````````````````')O;W0`````````````````````````````````
+M````,#`P,#`P(``P,#`P,#`@````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+H````````````````````````````````````````````````````````
+`
+end
diff --git a/tar/test/test_list_item.c b/tar/test/test_list_item.c
index df64acfada40..fd131c475275 100644
--- a/tar/test/test_list_item.c
+++ b/tar/test/test_list_item.c
@@ -43,54 +43,8 @@ static const char *tvf_out =
"-rw-r--r-- 0 1000 1000 0 Jan 1 1980 f\n";
#endif
-static void
-set_lc_time(const char * str)
-{
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
- if (!SetEnvironmentVariable("LC_TIME", str)) {
- fprintf(stderr, "SetEnvironmentVariable failed with %d\n",
- (int)GetLastError());
- }
-#else
- if (setenv("LC_TIME", str, 1) == -1)
- fprintf(stderr, "setenv: %s\n", strerror(errno));
-#endif
-}
-
-static int
-run_tvf(void)
-{
- char * orig_lc_time;
- char * lc_time;
- int exact_tvf_check;
-
- orig_lc_time = getenv("LC_TIME");
-
- /* Try to set LC_TIME to known (English) dates. */
- set_lc_time("en_US.UTF-8");
-
- /* Check if we've got the right LC_TIME; if not, don't check output. */
- lc_time = getenv("LC_TIME");
- if ((lc_time != NULL) && strcmp(lc_time, "en_US.UTF-8") == 0)
- exact_tvf_check = 1;
- else
- exact_tvf_check = 0;
-
- assertEqualInt(0,
- systemf("%s tvf test_list_item.tar >tvf.out 2>tvf.err", testprog));
-
- /* Restore the original date formatting. */
- if (orig_lc_time != NULL)
- set_lc_time(orig_lc_time);
-
- return (exact_tvf_check);
-}
-
DEFINE_TEST(test_list_item)
{
- int exact_tvf_check;
-
extract_reference_file("test_list_item.tar");
/* Run 'tf' and check output. */
@@ -100,16 +54,10 @@ DEFINE_TEST(test_list_item)
assertTextFileContents(tf_out, "tf.out");
assertEmptyFile("tf.err");
- /* Run 'tvf'. */
- exact_tvf_check = run_tvf();
-
- /* Check 'tvf' output. */
+ /* Run 'tvf' and check output. */
+ assertEqualInt(0,
+ systemf("%s tvf test_list_item.tar >tvf.out 2>tvf.err", testprog));
failure("'t' mode with 'v' should write more results to stdout");
+ assertTextFileContents(tvf_out, "tvf.out");
assertEmptyFile("tvf.err");
- if (exact_tvf_check)
- assertTextFileContents(tvf_out, "tvf.out");
- else {
- /* The 'skipping' macro requires braces. */
- skipping("Can't check exact tvf output");
- }
}
diff --git a/tar/test/test_option_C_mtree.c b/tar/test/test_option_C_mtree.c
index b6ab159941d8..6cbac38fcac5 100644
--- a/tar/test/test_option_C_mtree.c
+++ b/tar/test/test_option_C_mtree.c
@@ -17,7 +17,7 @@ DEFINE_TEST(test_option_C_mtree)
p0 = NULL;
char *content = "./foo type=file uname=root gname=root mode=0755\n";
char *filename = "output.tar";
-#if defined(_WIN32) && !defined(CYGWIN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
char *p;
#endif
@@ -32,7 +32,7 @@ DEFINE_TEST(test_option_C_mtree)
assertMakeDir("bar", 0775);
assertMakeFile("bar/foo", 0777, "abc");
-#if defined(_WIN32) && !defined(CYGWIN)
+#if defined(_WIN32) && !defined(__CYGWIN__)
p = absolute_path;
while(*p != '\0') {
if (*p == '/')
diff --git a/test_utils/test_main.c b/test_utils/test_main.c
index f4456256c1a9..afd077fc6d0b 100644
--- a/test_utils/test_main.c
+++ b/test_utils/test_main.c
@@ -2456,7 +2456,7 @@ void assertVersion(const char *prog, const char *base)
/* Skip arbitrary third-party version numbers. */
while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' ||
- isalnum((unsigned char)*q))) {
+ *q == '_' || isalnum((unsigned char)*q))) {
++q;
--s;
}
@@ -3555,6 +3555,59 @@ test_summarize(int failed, int skips_num)
}
/*
+ * Set or unset environment variable.
+ */
+static void
+set_environment(const char *key, const char *value)
+{
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ if (!SetEnvironmentVariable(key, value)) {
+ fprintf(stderr, "SetEnvironmentVariable failed with %d\n",
+ (int)GetLastError());
+ }
+#else
+ if (value == NULL) {
+ if (unsetenv(key) == -1)
+ fprintf(stderr, "unsetenv: %s\n", strerror(errno));
+ } else {
+ if (setenv(key, value, 1) == -1)
+ fprintf(stderr, "setenv: %s\n", strerror(errno));
+ }
+#endif
+}
+
+/*
+ * Enforce C locale for (sub)processes.
+ */
+static void
+set_c_locale()
+{
+ static const char *lcs[] = {
+ "LC_ADDRESS",
+ "LC_ALL",
+ "LC_COLLATE",
+ "LC_CTYPE",
+ "LC_IDENTIFICATION",
+ "LC_MEASUREMENT",
+ "LC_MESSAGES",
+ "LC_MONETARY",
+ "LC_NAME",
+ "LC_NUMERIC",
+ "LC_PAPER",
+ "LC_TELEPHONE",
+ "LC_TIME",
+ NULL
+ };
+ size_t i;
+
+ setlocale(LC_ALL, "C");
+ set_environment("LANG", "C");
+ for (i = 0; lcs[i] != NULL; i++)
+ set_environment(lcs[i], NULL);
+}
+
+/*
* Actually run a single test, with appropriate setup and cleanup.
*/
static int
@@ -3629,7 +3682,7 @@ test_run(int i, const char *tmpdir)
exit(1);
}
/* Explicitly reset the locale before each test. */
- setlocale(LC_ALL, "C");
+ set_c_locale();
/* Record the umask before we run the test. */
umask(oldumask = umask(0));
/*
@@ -3643,7 +3696,7 @@ test_run(int i, const char *tmpdir)
/* Restore umask */
umask(oldumask);
/* Reset locale. */
- setlocale(LC_ALL, "C");
+ set_c_locale();
/* Reset directory. */
if (!assertChdir(tmpdir)) {
fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",