diff options
author | Brad King <brad.king@kitware.com> | 2022-02-15 18:03:49 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2022-02-15 18:03:49 (GMT) |
commit | b3644e460fc8556c24c2a520129a16be04d4f2d4 (patch) | |
tree | af7fe4511c0183e2a70a8272c116f62e9c62052e | |
parent | 406503f62087847c7eb34757ca99087bc511cb92 (diff) | |
parent | 5d50940288e9158ea3283abe0e85e81872a20f5c (diff) | |
download | CMake-b3644e460fc8556c24c2a520129a16be04d4f2d4.zip CMake-b3644e460fc8556c24c2a520129a16be04d4f2d4.tar.gz CMake-b3644e460fc8556c24c2a520129a16be04d4f2d4.tar.bz2 |
Merge branch 'upstream-LibArchive' into update-libarchive
* upstream-LibArchive:
LibArchive 2022-02-09 (9147def1)
73 files changed, 3596 insertions, 1500 deletions
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt index c2aa182..932279b 100644 --- a/Utilities/cmlibarchive/CMakeLists.txt +++ b/Utilities/cmlibarchive/CMakeLists.txt @@ -1,6 +1,9 @@ # IF(0) # CMake handles policy settings in its own build. CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR) +if(POLICY CMP0065) + cmake_policy(SET CMP0065 NEW) #3.4 don't use `-rdynamic` with executables +endif() if(POLICY CMP0074) cmake_policy(SET CMP0074 NEW) #3.12.0 `find_package()`` uses ``<PackageName>_ROOT`` variables. endif() @@ -81,7 +84,7 @@ math(EXPR INTERFACE_VERSION "13 + ${_minor}") # ?? Should there be more here ?? SET(SOVERSION "${INTERFACE_VERSION}") -# Enalbe CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros +# Enable CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros # saving and restoring the state of the variables. INCLUDE(${CMake_SOURCE_DIR}/Modules/CMakePushCheckState.cmake) @@ -110,24 +113,9 @@ endif () # Especially for early development, we want to be a little # aggressive about diagnosing build problems; this can get # relaxed somewhat in final shipping versions. -IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$") - SET(CMAKE_REQUIRED_FLAGS "-Wall -Wformat -Wformat-security") - ################################################################# - # Set compile flags for all build types. - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wformat -Wformat-security") - if (ENABLE_WERROR) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") - endif () - ################################################################# - # Set compile flags for debug build. - # This is added into CMAKE_C_FLAGS when CMAKE_BUILD_TYPE is "Debug" - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wextra") - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wunused") - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wshadow") - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wmissing-prototypes") - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wcast-qual") -ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR CMAKE_C_COMPILER_ID MATCHES "^LCC$") -IF (CMAKE_C_COMPILER_ID MATCHES "^Clang$") +IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR + CMAKE_C_COMPILER_ID MATCHES "^LCC$" OR + CMAKE_C_COMPILER_ID MATCHES "^Clang$") SET(CMAKE_REQUIRED_FLAGS "-Wall -Wformat -Wformat-security") ################################################################# # Set compile flags for all build types. @@ -144,7 +132,26 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^Clang$") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wshadow") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wmissing-prototypes") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wcast-qual") -ENDIF (CMAKE_C_COMPILER_ID MATCHES "^Clang$") + # Ideally this will be a compile/link time check, yet there's no obvious way + # how considering how old our minimum required cmake version is. The official + # cmake.org side does not host the manual pages even. Normally we can use + # either of the following two, yet neither is supported as of 3.0.2 + # - check_linker_flag - does not exist + # - try_compile - does not support linker flags + # + # The CI fails with this on MacOS + IF(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin") + # Place the functions and data into separate sections, allowing the linker + # to garbage collect the unused ones. + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") + SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections") + # Printing the discarded section is "too much", so enable on demand. + #SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -Wl,--print-gc-sections") + #SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--print-gc-sections") + ENDIF(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin") +ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR + CMAKE_C_COMPILER_ID MATCHES "^Clang$") IF (CMAKE_C_COMPILER_ID MATCHES "^XL$") SET(CMAKE_C_COMPILER "xlc_r") SET(CMAKE_REQUIRED_FLAGS "-qflag=e:e -qformat=sec") @@ -405,7 +412,7 @@ IF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN) SET(__GNUWIN32PATH "C:/Program Files/GnuWin32") ENDIF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN) IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}") - # You have to add a path availabel DLL file into PATH environment variable. + # You have to add a path available DLL file into PATH environment variable. # Maybe DLL path is "C:/Program Files/GnuWin32/bin". # The zlib and the bzip2 Setup program have installed programs and DLLs into # "C:/Program Files/GnuWin32" by default. @@ -642,7 +649,8 @@ IF(ZSTD_FOUND) CMAKE_PUSH_CHECK_STATE() SET(CMAKE_REQUIRED_LIBRARIES ${ZSTD_LIBRARY}) SET(CMAKE_REQUIRED_INCLUDES ${ZSTD_INCLUDE_DIR}) - CHECK_FUNCTION_EXISTS(ZSTD_compressStream HAVE_LIBZSTD) + CHECK_FUNCTION_EXISTS(ZSTD_decompressStream HAVE_LIBZSTD) + CHECK_FUNCTION_EXISTS(ZSTD_compressStream HAVE_LIBZSTD_COMPRESSOR) # # TODO: test for static library. # @@ -1042,7 +1050,7 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST) CMAKE_C_COMPILER_ID MATCHES "^Clang$") # # During checking iconv proto type, we should use -Werror to avoid the - # success of iconv detection with a warnig which success is a miss + # success of iconv detection with a warning which success is a miss # detection. So this needs for all build mode(even it's a release mode). # SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror") @@ -1378,6 +1386,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS) CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD) CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN) CHECK_FUNCTION_EXISTS_GLIBC(link HAVE_LINK) +CHECK_FUNCTION_EXISTS_GLIBC(linkat HAVE_LINKAT) CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R) CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT) CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES) @@ -1447,6 +1456,10 @@ CHECK_C_SOURCE_COMPILES( "#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct xvfsconf v; return sizeof(v);}" HAVE_STRUCT_XVFSCONF) +CHECK_C_SOURCE_COMPILES( + "#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct statfs s; return sizeof(s);}" + HAVE_STRUCT_STATFS) + # Make sure we have the POSIX version of readdir_r, not the # older 2-argument version. CHECK_C_SOURCE_COMPILES( @@ -1510,9 +1523,14 @@ CHECK_STRUCT_HAS_MEMBER("struct tm" tm_gmtoff CHECK_STRUCT_HAS_MEMBER("struct tm" __tm_gmtoff "time.h" HAVE_STRUCT_TM___TM_GMTOFF) +IF(HAVE_STRUCT_STATFS) # Check for f_namemax in struct statfs CHECK_STRUCT_HAS_MEMBER("struct statfs" f_namemax "sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_NAMEMAX) +# Check for f_iosize in struct statfs +CHECK_STRUCT_HAS_MEMBER("struct statfs" f_iosize + "sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_IOSIZE) +ENDIF(HAVE_STRUCT_STATFS) # Check for birthtime in struct stat CHECK_STRUCT_HAS_MEMBER("struct stat" st_birthtime diff --git a/Utilities/cmlibarchive/build/cmake/config.h.in b/Utilities/cmlibarchive/build/cmake/config.h.in index 9bd2667..72467a5 100644 --- a/Utilities/cmlibarchive/build/cmake/config.h.in +++ b/Utilities/cmlibarchive/build/cmake/config.h.in @@ -522,14 +522,18 @@ /* Define to 1 if you have the `zstd' library (-lzstd). */ #cmakedefine HAVE_LIBZSTD 1 +/* Define to 1 if you have the `zstd' library (-lzstd) with compression + support. */ +#cmakedefine HAVE_LIBZSTD_COMPRESSOR 1 + /* Define to 1 if you have the <limits.h> header file. */ #cmakedefine HAVE_LIMITS_H 1 /* Define to 1 if you have the `link' function. */ #cmakedefine HAVE_LINK 1 -/* Define to 1 if you have the <linux/types.h> header file. */ -#cmakedefine HAVE_LINUX_TYPES_H 1 +/* Define to 1 if you have the `linkat' function. */ +#cmakedefine HAVE_LINKAT 1 /* Define to 1 if you have the <linux/fiemap.h> header file. */ #cmakedefine HAVE_LINUX_FIEMAP_H 1 diff --git a/Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh b/Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh index 925de5c..558e9c0 100755 --- a/Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh +++ b/Utilities/cmlibarchive/build/utils/gen_archive_string_composition_h.sh @@ -246,7 +246,7 @@ function hextoi(hex) # Exclusion code points specified by # http://unicode.org/Public/6.0.0/ucd/CompositionExclusions.txt ## -# 1. Script Specifices +# 1. Script Specifics ## \$1 ~/^095[89ABCDEF]\$/ { next diff --git a/Utilities/cmlibarchive/build/version b/Utilities/cmlibarchive/build/version index 205791c..102ec29 100644 --- a/Utilities/cmlibarchive/build/version +++ b/Utilities/cmlibarchive/build/version @@ -1 +1 @@ -3005001 +3006000 diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt index 891a140..feb8697 100644 --- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt +++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt @@ -144,7 +144,9 @@ SET(libarchive_SOURCES archive_write_set_format_ar.c archive_write_set_format_by_name.c archive_write_set_format_cpio.c + archive_write_set_format_cpio_binary.c archive_write_set_format_cpio_newc.c + archive_write_set_format_cpio_odc.c archive_write_set_format_filter_by_ext.c archive_write_set_format_gnutar.c archive_write_set_format_iso9660.c diff --git a/Utilities/cmlibarchive/libarchive/archive.h b/Utilities/cmlibarchive/libarchive/archive.h index a1f0b87..ac01738 100644 --- a/Utilities/cmlibarchive/libarchive/archive.h +++ b/Utilities/cmlibarchive/libarchive/archive.h @@ -36,7 +36,7 @@ * assert that ARCHIVE_VERSION_NUMBER >= 2012108. */ /* Note: Compiler will complain if this does not match archive_entry.h! */ -#define ARCHIVE_VERSION_NUMBER 3005001 +#define ARCHIVE_VERSION_NUMBER 3006000 #include <sys/stat.h> #include <stddef.h> /* for wchar_t */ @@ -97,7 +97,7 @@ typedef ssize_t la_ssize_t; #endif /* Large file support for Android */ -#ifdef __ANDROID__ +#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__) #include "android_lf.h" #endif @@ -152,7 +152,7 @@ __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_ONLY_STRING "3.5.1" +#define ARCHIVE_VERSION_ONLY_STRING "3.6.0" #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char * archive_version_string(void); @@ -316,6 +316,7 @@ typedef const char *archive_passphrase_callback(struct archive *, #define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4) #define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5) #define ARCHIVE_FORMAT_CPIO_AFIO_LARGE (ARCHIVE_FORMAT_CPIO | 6) +#define ARCHIVE_FORMAT_CPIO_PWB (ARCHIVE_FORMAT_CPIO | 7) #define ARCHIVE_FORMAT_SHAR 0x20000 #define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1) #define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2) @@ -797,7 +798,10 @@ __LA_DECL int archive_write_set_format_7zip(struct archive *); __LA_DECL int archive_write_set_format_ar_bsd(struct archive *); __LA_DECL int archive_write_set_format_ar_svr4(struct archive *); __LA_DECL int archive_write_set_format_cpio(struct archive *); +__LA_DECL int archive_write_set_format_cpio_bin(struct archive *); __LA_DECL int archive_write_set_format_cpio_newc(struct archive *); +__LA_DECL int archive_write_set_format_cpio_odc(struct archive *); +__LA_DECL int archive_write_set_format_cpio_pwb(struct archive *); __LA_DECL int archive_write_set_format_gnutar(struct archive *); __LA_DECL int archive_write_set_format_iso9660(struct archive *); __LA_DECL int archive_write_set_format_mtree(struct archive *); @@ -1017,6 +1021,8 @@ __LA_DECL int archive_read_disk_set_atime_restored(struct archive *); #define ARCHIVE_READDISK_NO_ACL (0x0020) /* Default: File flags are read from disk. */ #define ARCHIVE_READDISK_NO_FFLAGS (0x0040) +/* Default: Sparse file information is read from disk. */ +#define ARCHIVE_READDISK_NO_SPARSE (0x0080) __LA_DECL int archive_read_disk_set_behavior(struct archive *, int flags); diff --git a/Utilities/cmlibarchive/libarchive/archive_blake2.h b/Utilities/cmlibarchive/libarchive/archive_blake2.h index dd6fe6f..8f6b5e9 100644 --- a/Utilities/cmlibarchive/libarchive/archive_blake2.h +++ b/Utilities/cmlibarchive/libarchive/archive_blake2.h @@ -21,8 +21,10 @@ #if defined(_MSC_VER) #define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) -#else +#elif defined(__GNUC__) #define BLAKE2_PACKED(x) x __attribute__((packed)) +#else +#define BLAKE2_PACKED(x) _Pragma("pack 1") x _Pragma("pack 0") #endif #if defined(__cplusplus) diff --git a/Utilities/cmlibarchive/libarchive/archive_blake2_impl.h b/Utilities/cmlibarchive/libarchive/archive_blake2_impl.h index 0f05def..eb8619c 100644 --- a/Utilities/cmlibarchive/libarchive/archive_blake2_impl.h +++ b/Utilities/cmlibarchive/libarchive/archive_blake2_impl.h @@ -154,7 +154,7 @@ static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) /* prevents compiler optimizing out memset() */ static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) { - static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + static void *(__LA_LIBC_CC *const volatile memset_v)(void *, int, size_t) = &memset; memset_v(v, 0, n); } diff --git a/Utilities/cmlibarchive/libarchive/archive_blake2s_ref.c b/Utilities/cmlibarchive/libarchive/archive_blake2s_ref.c index d92ffd0..b21a02b 100644 --- a/Utilities/cmlibarchive/libarchive/archive_blake2s_ref.c +++ b/Utilities/cmlibarchive/libarchive/archive_blake2s_ref.c @@ -17,6 +17,7 @@ #include <string.h> #include <stdio.h> +#include "archive_platform.h" #include "archive_blake2.h" #include "archive_blake2_impl.h" diff --git a/Utilities/cmlibarchive/libarchive/archive_blake2sp_ref.c b/Utilities/cmlibarchive/libarchive/archive_blake2sp_ref.c index aef1010..f412c8e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_blake2sp_ref.c +++ b/Utilities/cmlibarchive/libarchive/archive_blake2sp_ref.c @@ -21,6 +21,7 @@ #include <omp.h> #endif +#include "archive_platform.h" #include "archive_blake2.h" #include "archive_blake2_impl.h" diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor.c b/Utilities/cmlibarchive/libarchive/archive_cryptor.c index d4bca90..112baf1 100644 --- a/Utilities/cmlibarchive/libarchive/archive_cryptor.c +++ b/Utilities/cmlibarchive/libarchive/archive_cryptor.c @@ -401,14 +401,6 @@ aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) memcpy(ctx->key, key, key_len); memset(ctx->nonce, 0, sizeof(ctx->nonce)); ctx->encr_pos = AES_BLOCK_SIZE; -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) - if (!EVP_CIPHER_CTX_reset(ctx->ctx)) { - EVP_CIPHER_CTX_free(ctx->ctx); - ctx->ctx = NULL; - } -#else - EVP_CIPHER_CTX_init(ctx->ctx); -#endif return 0; } diff --git a/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c b/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c index aba41e5..ed4e7a7 100644 --- a/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c +++ b/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c @@ -319,7 +319,7 @@ translate_acl(struct archive_read_disk *a, static int set_acl(struct archive *a, int fd, const char *name, - struct archive_acl *abstract_acl, + struct archive_acl *abstract_acl, __LA_MODE_T mode, int ae_requested_type, const char *tname) { int acl_type = 0; @@ -364,6 +364,13 @@ set_acl(struct archive *a, int fd, const char *name, return (ARCHIVE_FAILED); } + if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) { + errno = EINVAL; + archive_set_error(a, errno, + "Cannot set default ACL on non-directory"); + return (ARCHIVE_WARN); + } + acl = acl_init(entries); if (acl == (acl_t)NULL) { archive_set_error(a, errno, @@ -542,7 +549,10 @@ set_acl(struct archive *a, int fd, const char *name, else if (acl_set_link_np(name, acl_type, acl) != 0) #else /* FreeBSD older than 8.0 */ - else if (acl_set_file(name, acl_type, acl) != 0) + else if (S_ISLNK(mode)) { + /* acl_set_file() follows symbolic links, skip */ + ret = ARCHIVE_OK; + } else if (acl_set_file(name, acl_type, acl) != 0) #endif { if (errno == EOPNOTSUPP) { @@ -677,14 +687,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - ret = set_acl(a, fd, name, abstract_acl, + ret = set_acl(a, fd, name, abstract_acl, mode, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); if (ret != ARCHIVE_OK) return (ret); } if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) - ret = set_acl(a, fd, name, abstract_acl, + ret = set_acl(a, fd, name, abstract_acl, mode, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); /* Simultaneous POSIX.1e and NFSv4 is not supported */ @@ -693,7 +703,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, #if ARCHIVE_ACL_FREEBSD_NFS4 else if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - ret = set_acl(a, fd, name, abstract_acl, + ret = set_acl(a, fd, name, abstract_acl, mode, ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); } #endif diff --git a/Utilities/cmlibarchive/libarchive/archive_disk_acl_linux.c b/Utilities/cmlibarchive/libarchive/archive_disk_acl_linux.c index 3928f3d..31d2705 100644 --- a/Utilities/cmlibarchive/libarchive/archive_disk_acl_linux.c +++ b/Utilities/cmlibarchive/libarchive/archive_disk_acl_linux.c @@ -343,6 +343,11 @@ set_richacl(struct archive *a, int fd, const char *name, return (ARCHIVE_FAILED); } + if (S_ISLNK(mode)) { + /* Linux does not support RichACLs on symbolic links */ + return (ARCHIVE_OK); + } + richacl = richacl_alloc(entries); if (richacl == NULL) { archive_set_error(a, errno, @@ -455,7 +460,7 @@ exit_free: #if ARCHIVE_ACL_LIBACL static int set_acl(struct archive *a, int fd, const char *name, - struct archive_acl *abstract_acl, + struct archive_acl *abstract_acl, __LA_MODE_T mode, int ae_requested_type, const char *tname) { int acl_type = 0; @@ -488,6 +493,18 @@ set_acl(struct archive *a, int fd, const char *name, return (ARCHIVE_FAILED); } + if (S_ISLNK(mode)) { + /* Linux does not support ACLs on symbolic links */ + return (ARCHIVE_OK); + } + + if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) { + errno = EINVAL; + archive_set_error(a, errno, + "Cannot set default ACL on non-directory"); + return (ARCHIVE_WARN); + } + acl = acl_init(entries); if (acl == (acl_t)NULL) { archive_set_error(a, errno, @@ -727,14 +744,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - ret = set_acl(a, fd, name, abstract_acl, + ret = set_acl(a, fd, name, abstract_acl, mode, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); if (ret != ARCHIVE_OK) return (ret); } if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) - ret = set_acl(a, fd, name, abstract_acl, + ret = set_acl(a, fd, name, abstract_acl, mode, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); } #endif /* ARCHIVE_ACL_LIBACL */ diff --git a/Utilities/cmlibarchive/libarchive/archive_disk_acl_sunos.c b/Utilities/cmlibarchive/libarchive/archive_disk_acl_sunos.c index b0f5dfa..0ef3ad5 100644 --- a/Utilities/cmlibarchive/libarchive/archive_disk_acl_sunos.c +++ b/Utilities/cmlibarchive/libarchive/archive_disk_acl_sunos.c @@ -443,7 +443,7 @@ translate_acl(struct archive_read_disk *a, static int set_acl(struct archive *a, int fd, const char *name, - struct archive_acl *abstract_acl, + struct archive_acl *abstract_acl, __LA_MODE_T mode, int ae_requested_type, const char *tname) { aclent_t *aclent; @@ -467,7 +467,6 @@ set_acl(struct archive *a, int fd, const char *name, if (entries == 0) return (ARCHIVE_OK); - switch (ae_requested_type) { case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: cmd = SETACL; @@ -492,6 +491,12 @@ set_acl(struct archive *a, int fd, const char *name, return (ARCHIVE_FAILED); } + if (S_ISLNK(mode)) { + /* Skip ACLs on symbolic links */ + ret = ARCHIVE_OK; + goto exit_free; + } + e = 0; while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, @@ -801,7 +806,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { /* Solaris writes POSIX.1e access and default ACLs together */ - ret = set_acl(a, fd, name, abstract_acl, + ret = set_acl(a, fd, name, abstract_acl, mode, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e"); /* Simultaneous POSIX.1e and NFSv4 is not supported */ @@ -810,7 +815,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, #if ARCHIVE_ACL_SUNOS_NFS4 else if ((archive_acl_types(abstract_acl) & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - ret = set_acl(a, fd, name, abstract_acl, + ret = set_acl(a, fd, name, abstract_acl, mode, ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); } #endif diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.h b/Utilities/cmlibarchive/libarchive/archive_entry.h index 21e89d2..221ef80 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry.h +++ b/Utilities/cmlibarchive/libarchive/archive_entry.h @@ -30,7 +30,7 @@ #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3005001 +#define ARCHIVE_VERSION_NUMBER 3006000 /* * Note: archive_entry.h is for use outside of libarchive; the @@ -99,7 +99,7 @@ typedef ssize_t la_ssize_t; #endif /* Large file support for Android */ -#ifdef __ANDROID__ +#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__) #include "android_lf.h" #endif diff --git a/Utilities/cmlibarchive/libarchive/archive_getdate.c b/Utilities/cmlibarchive/libarchive/archive_getdate.c index 6786d35..5b0b775 100644 --- a/Utilities/cmlibarchive/libarchive/archive_getdate.c +++ b/Utilities/cmlibarchive/libarchive/archive_getdate.c @@ -716,7 +716,7 @@ Convert(time_t Month, time_t Day, time_t Year, ? 29 : 28; /* Checking for 2038 bogusly assumes that time_t is 32 bits. But I'm too lazy to try to check for time_t overflow in another way. */ - if (Year < EPOCH || Year > 2038 + if (Year < EPOCH || Year >= 2038 || Month < 1 || Month > 12 /* Lint fluff: "conversion from long may lose accuracy" */ || Day < 1 || Day > DaysInMonth[(int)--Month] diff --git a/Utilities/cmlibarchive/libarchive/archive_pack_dev.c b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c index f8286d8..d95444d 100644 --- a/Utilities/cmlibarchive/libarchive/archive_pack_dev.c +++ b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c @@ -77,7 +77,7 @@ static pack_t pack_12_20; static pack_t pack_14_18; static pack_t pack_8_24; static pack_t pack_bsdos; -static int compare_format(const void *, const void *); +static int __LA_LIBC_CC compare_format(const void *, const void *); static const char iMajorError[] = "invalid major number"; static const char iMinorError[] = "invalid minor number"; @@ -310,6 +310,7 @@ static const struct format { }; static int +__LA_LIBC_CC compare_format(const void *key, const void *element) { const char *name; diff --git a/Utilities/cmlibarchive/libarchive/archive_pathmatch.c b/Utilities/cmlibarchive/libarchive/archive_pathmatch.c index 619e2b6..0867a26 100644 --- a/Utilities/cmlibarchive/libarchive/archive_pathmatch.c +++ b/Utilities/cmlibarchive/libarchive/archive_pathmatch.c @@ -384,6 +384,8 @@ __archive_pathmatch(const char *p, const char *s, int flags) /* Empty pattern only matches the empty string. */ if (p == NULL || *p == '\0') return (s == NULL || *s == '\0'); + else if (s == NULL) + return (0); /* Leading '^' anchors the start of the pattern. */ if (*p == '^') { @@ -424,6 +426,8 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags) /* Empty pattern only matches the empty string. */ if (p == NULL || *p == L'\0') return (s == NULL || *s == L'\0'); + else if (s == NULL) + return (0); /* Leading '^' anchors the start of the pattern. */ if (*p == L'^') { diff --git a/Utilities/cmlibarchive/libarchive/archive_platform.h b/Utilities/cmlibarchive/libarchive/archive_platform.h index 3273930..f87b423 100644 --- a/Utilities/cmlibarchive/libarchive/archive_platform.h +++ b/Utilities/cmlibarchive/libarchive/archive_platform.h @@ -69,8 +69,16 @@ * either Windows or Posix APIs. */ #if (defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__) #include "archive_windows.h" +/* The C library on Windows specifies a calling convention for callback + * functions and exports; when we interact with them (capture pointers, + * call and pass function pointers) we need to match their calling + * convention. + * This only matters when libarchive is built with /Gr, /Gz or /Gv + * (which change the default calling convention.) */ +#define __LA_LIBC_CC __cdecl #else #define la_stat(path,stref) stat(path,stref) +#define __LA_LIBC_CC #endif /* @@ -148,6 +156,28 @@ #define INTMAX_MIN ((intmax_t)(~INTMAX_MAX)) #endif +/* Some platforms lack the standard PRIxN/PRIdN definitions. */ +#if !HAVE_INTTYPES_H || !defined(PRIx32) || !defined(PRId32) +#ifndef PRIx32 +#if SIZEOF_INT == 4 +#define PRIx32 "x" +#elif SIZEOF_LONG == 4 +#define PRIx32 "lx" +#else +#error No suitable 32-bit unsigned integer type found for this platform +#endif +#endif // PRIx32 +#ifndef PRId32 +#if SIZEOF_INT == 4 +#define PRId32 "d" +#elif SIZEOF_LONG == 4 +#define PRId32 "ld" +#else +#error No suitable 32-bit signed integer type found for this platform +#endif +#endif // PRId32 +#endif // !HAVE_INTTYPES_H || !defined(PRIx32) || !defined(PRId32) + /* * If we can't restore metadata using a file descriptor, then * for compatibility's sake, close files before trying to restore metadata. diff --git a/Utilities/cmlibarchive/libarchive/archive_private.h b/Utilities/cmlibarchive/libarchive/archive_private.h index 937a87b..b2a2cda 100644 --- a/Utilities/cmlibarchive/libarchive/archive_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_private.h @@ -46,6 +46,13 @@ #define __LA_DEAD #endif +#if defined(__GNUC__) && (__GNUC__ > 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) +#define __LA_UNUSED __attribute__((__unused__)) +#else +#define __LA_UNUSED +#endif + #define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU) #define ARCHIVE_READ_MAGIC (0xdeb0c5U) #define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U) @@ -100,14 +107,11 @@ struct archive { * Some public API functions depend on the "real" type of the * archive object. */ - struct archive_vtable *vtable; + const struct archive_vtable *vtable; int archive_format; const char *archive_format_name; - int compression_code; /* Currently active compression. */ - const char *compression_name; - /* Number of file entries processed. */ int file_count; diff --git a/Utilities/cmlibarchive/libarchive/archive_read.c b/Utilities/cmlibarchive/libarchive/archive_read.c index c59f051..45a38ae 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read.c +++ b/Utilities/cmlibarchive/libarchive/archive_read.c @@ -58,7 +58,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2 static int choose_filters(struct archive_read *); static int choose_format(struct archive_read *); static int close_filters(struct archive_read *); -static struct archive_vtable *archive_read_vtable(void); static int64_t _archive_filter_bytes(struct archive *, int); static int _archive_filter_code(struct archive *, int); static const char *_archive_filter_name(struct archive *, int); @@ -73,26 +72,18 @@ static int _archive_read_next_header2(struct archive *, struct archive_entry *); static int64_t advance_file_pointer(struct archive_read_filter *, int64_t); -static struct archive_vtable * -archive_read_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_filter_bytes = _archive_filter_bytes; - av.archive_filter_code = _archive_filter_code; - av.archive_filter_name = _archive_filter_name; - av.archive_filter_count = _archive_filter_count; - av.archive_read_data_block = _archive_read_data_block; - av.archive_read_next_header = _archive_read_next_header; - av.archive_read_next_header2 = _archive_read_next_header2; - av.archive_free = _archive_read_free; - av.archive_close = _archive_read_close; - inited = 1; - } - return (&av); -} +static const struct archive_vtable +archive_read_vtable = { + .archive_filter_bytes = _archive_filter_bytes, + .archive_filter_code = _archive_filter_code, + .archive_filter_name = _archive_filter_name, + .archive_filter_count = _archive_filter_count, + .archive_read_data_block = _archive_read_data_block, + .archive_read_next_header = _archive_read_next_header, + .archive_read_next_header2 = _archive_read_next_header2, + .archive_free = _archive_read_free, + .archive_close = _archive_read_close, +}; /* * Allocate, initialize and return a struct archive object. @@ -109,7 +100,7 @@ archive_read_new(void) a->archive.state = ARCHIVE_STATE_NEW; a->entry = archive_entry_new2(&a->archive); - a->archive.vtable = archive_read_vtable(); + a->archive.vtable = &archive_read_vtable; a->passphrases.last = &a->passphrases.first; @@ -245,18 +236,17 @@ client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence) } static int -client_close_proxy(struct archive_read_filter *self) +read_client_close_proxy(struct archive_read *a) { int r = ARCHIVE_OK, r2; unsigned int i; - if (self->archive->client.closer == NULL) + if (a->client.closer == NULL) return (r); - for (i = 0; i < self->archive->client.nodes; i++) + for (i = 0; i < a->client.nodes; i++) { - r2 = (self->archive->client.closer) - ((struct archive *)self->archive, - self->archive->client.dataset[i].data); + r2 = (a->client.closer) + ((struct archive *)a, a->client.dataset[i].data); if (r > r2) r = r2; } @@ -264,6 +254,12 @@ client_close_proxy(struct archive_read_filter *self) } static int +client_close_proxy(struct archive_read_filter *self) +{ + return read_client_close_proxy(self->archive); +} + +static int client_open_proxy(struct archive_read_filter *self) { int r = ARCHIVE_OK; @@ -298,9 +294,7 @@ client_switch_proxy(struct archive_read_filter *self, unsigned int iindex) r1 = (self->archive->client.closer) ((struct archive *)self->archive, self->data); self->data = data2; - if (self->archive->client.opener != NULL) - r2 = (self->archive->client.opener) - ((struct archive *)self->archive, self->data); + r2 = client_open_proxy(self); } return (r1 < r2) ? r1 : r2; } @@ -457,13 +451,18 @@ archive_read_prepend_callback_data(struct archive *_a, void *client_data) return archive_read_add_callback_data(_a, client_data, 0); } +static const struct archive_read_filter_vtable +none_reader_vtable = { + .read = client_read_proxy, + .close = client_close_proxy, +}; + int archive_read_open1(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; struct archive_read_filter *filter, *tmp; int slot, e = ARCHIVE_OK; - unsigned int i; archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open"); @@ -481,11 +480,7 @@ archive_read_open1(struct archive *_a) e = (a->client.opener)(&a->archive, a->client.dataset[0].data); if (e != 0) { /* If the open failed, call the closer to clean up. */ - if (a->client.closer) { - for (i = 0; i < a->client.nodes; i++) - (a->client.closer)(&a->archive, - a->client.dataset[i].data); - } + read_client_close_proxy(a); return (e); } } @@ -497,14 +492,11 @@ archive_read_open1(struct archive *_a) filter->upstream = NULL; filter->archive = a; filter->data = a->client.dataset[0].data; - filter->open = client_open_proxy; - filter->read = client_read_proxy; - filter->skip = client_skip_proxy; - filter->seek = client_seek_proxy; - filter->close = client_close_proxy; - filter->sswitch = client_switch_proxy; + filter->vtable = &none_reader_vtable; filter->name = "none"; filter->code = ARCHIVE_FILTER_NONE; + filter->can_skip = 1; + filter->can_seek = 1; a->client.dataset[0].begin_position = 0; if (!a->filter || !a->bypass_filter_bidding) @@ -570,12 +562,12 @@ choose_filters(struct archive_read *a) bidder = a->bidders; for (i = 0; i < number_bidders; i++, bidder++) { - if (bidder->bid != NULL) { - bid = (bidder->bid)(bidder, a->filter); - if (bid > best_bid) { - best_bid = bid; - best_bidder = bidder; - } + if (bidder->vtable == NULL) + continue; + bid = (bidder->vtable->bid)(bidder, a->filter); + if (bid > best_bid) { + best_bid = bid; + best_bidder = bidder; } } @@ -587,8 +579,6 @@ choose_filters(struct archive_read *a) __archive_read_free_filters(a); return (ARCHIVE_FATAL); } - a->archive.compression_name = a->filter->name; - a->archive.compression_code = a->filter->code; return (ARCHIVE_OK); } @@ -600,7 +590,7 @@ choose_filters(struct archive_read *a) filter->archive = a; filter->upstream = a->filter; a->filter = filter; - r = (best_bidder->init)(a->filter); + r = (best_bidder->vtable->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_free_filters(a); return (ARCHIVE_FATAL); @@ -614,10 +604,9 @@ choose_filters(struct archive_read *a) int __archive_read_header(struct archive_read *a, struct archive_entry *entry) { - if (a->filter->read_header) - return a->filter->read_header(a->filter, entry); - else + if (!a->filter->vtable->read_header) return (ARCHIVE_OK); + return a->filter->vtable->read_header(a->filter, entry); } /* @@ -1006,8 +995,8 @@ close_filters(struct archive_read *a) /* Close each filter in the pipeline. */ while (f != NULL) { struct archive_read_filter *t = f->upstream; - if (!f->closed && f->close != NULL) { - int r1 = (f->close)(f); + if (!f->closed && f->vtable != NULL) { + int r1 = (f->vtable->close)(f); f->closed = 1; if (r1 < r) r = r1; @@ -1112,11 +1101,10 @@ _archive_read_free(struct archive *_a) /* Release the bidder objects. */ n = sizeof(a->bidders)/sizeof(a->bidders[0]); for (i = 0; i < n; i++) { - if (a->bidders[i].free != NULL) { - int r1 = (a->bidders[i].free)(&a->bidders[i]); - if (r1 < r) - r = r1; - } + if (a->bidders[i].vtable == NULL || + a->bidders[i].vtable->free == NULL) + continue; + (a->bidders[i].vtable->free)(&a->bidders[i]); } /* Release passphrase list. */ @@ -1241,19 +1229,35 @@ __archive_read_register_format(struct archive_read *a, * initialization functions. */ int -__archive_read_get_bidder(struct archive_read *a, - struct archive_read_filter_bidder **bidder) +__archive_read_register_bidder(struct archive_read *a, + void *bidder_data, + const char *name, + const struct archive_read_filter_bidder_vtable *vtable) { + struct archive_read_filter_bidder *bidder; int i, number_slots; + archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "__archive_read_register_bidder"); + number_slots = sizeof(a->bidders) / sizeof(a->bidders[0]); for (i = 0; i < number_slots; i++) { - if (a->bidders[i].bid == NULL) { - memset(a->bidders + i, 0, sizeof(a->bidders[0])); - *bidder = (a->bidders + i); - return (ARCHIVE_OK); + if (a->bidders[i].vtable != NULL) + continue; + memset(a->bidders + i, 0, sizeof(a->bidders[0])); + bidder = (a->bidders + i); + bidder->data = bidder_data; + bidder->name = name; + bidder->vtable = vtable; + if (bidder->vtable->bid == NULL || bidder->vtable->init == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: " + "no bid/init for filter bidder"); + return (ARCHIVE_FATAL); } + + return (ARCHIVE_OK); } archive_set_error(&a->archive, ENOMEM, @@ -1382,7 +1386,7 @@ __archive_read_filter_ahead(struct archive_read_filter *filter, *avail = 0; return (NULL); } - bytes_read = (filter->read)(filter, + bytes_read = (filter->vtable->read)(filter, &filter->client_buff); if (bytes_read < 0) { /* Read error. */ filter->client_total = filter->client_avail = 0; @@ -1561,8 +1565,8 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request) return (total_bytes_skipped); /* If there's an optimized skip function, use it. */ - if (filter->skip != NULL) { - bytes_skipped = (filter->skip)(filter, request); + if (filter->can_skip != 0) { + bytes_skipped = client_skip_proxy(filter, request); if (bytes_skipped < 0) { /* error */ filter->fatal = 1; return (bytes_skipped); @@ -1576,7 +1580,7 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request) /* Use ordinary reads as necessary to complete the request. */ for (;;) { - bytes_read = (filter->read)(filter, &filter->client_buff); + bytes_read = (filter->vtable->read)(filter, &filter->client_buff); if (bytes_read < 0) { filter->client_buff = NULL; filter->fatal = 1; @@ -1631,7 +1635,7 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, if (filter->closed || filter->fatal) return (ARCHIVE_FATAL); - if (filter->seek == NULL) + if (filter->can_seek == 0) return (ARCHIVE_FAILED); client = &(filter->archive->client); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c index da7c55b..25dc4b2 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c @@ -135,7 +135,7 @@ archive_read_append_filter(struct archive *_a, int code) filter->archive = a; filter->upstream = a->filter; a->filter = filter; - r2 = (bidder->init)(a->filter); + r2 = (bidder->vtable->init)(a->filter); if (r2 != ARCHIVE_OK) { __archive_read_free_filters(a); return (ARCHIVE_FATAL); @@ -192,7 +192,7 @@ archive_read_append_filter_program_signature(struct archive *_a, filter->archive = a; filter->upstream = a->filter; a->filter = filter; - r = (bidder->init)(a->filter); + r = (bidder->vtable->init)(a->filter); if (r != ARCHIVE_OK) { __archive_read_free_filters(a); return (ARCHIVE_FATAL); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk.3 b/Utilities/cmlibarchive/libarchive/archive_read_disk.3 index 82d6a5c..8b568d7 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk.3 +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk.3 @@ -29,6 +29,8 @@ .Os .Sh NAME .Nm archive_read_disk_new , +.Nm archive_read_disk_open , +.Nm archive_read_disk_open_w , .Nm archive_read_disk_set_behavior , .Nm archive_read_disk_set_symlink_logical , .Nm archive_read_disk_set_symlink_physical , @@ -38,7 +40,14 @@ .Nm archive_read_disk_uname , .Nm archive_read_disk_set_uname_lookup , .Nm archive_read_disk_set_gname_lookup , -.Nm archive_read_disk_set_standard_lookup +.Nm archive_read_disk_set_standard_lookup , +.Nm archive_read_disk_descend , +.Nm archive_read_disk_can_descend , +.Nm archive_read_disk_current_filesystem , +.Nm archive_read_disk_current_filesystem_is_synthetic , +.Nm archive_read_disk_current_filesystem_is_remote , +.Nm archive_read_disk_set_matching , +.Nm archive_read_disk_set_metadata_filter_callback , .Nd functions for reading objects from disk .Sh LIBRARY Streaming Archive Library (libarchive, -larchive) @@ -47,6 +56,10 @@ Streaming Archive Library (libarchive, -larchive) .Ft struct archive * .Fn archive_read_disk_new "void" .Ft int +.Fn archive_read_disk_open "struct archive *" "const char *" +.Ft int +.Fn archive_read_disk_open_w "struct archive *" "const wchar_t *" +.Ft int .Fn archive_read_disk_set_behavior "struct archive *" "int" .Ft int .Fn archive_read_disk_set_symlink_logical "struct archive *" @@ -81,6 +94,29 @@ Streaming Archive Library (libarchive, -larchive) .Fa "int fd" .Fa "const struct stat *" .Fc +.Ft int +.Fn archive_read_disk_descend "struct archive *" +.Ft int +.Fn archive_read_disk_can_descend "struct archive *" +.Ft int +.Fn archive_read_disk_current_filesystem "struct archive *" +.Ft int +.Fn archive_read_disk_current_filesystem_is_synthetic "struct archive *" +.Ft int +.Fn archive_read_disk_current_filesystem_is_remote "struct archive *" +.Ft int +.Fo archive_read_disk_set_matching +.Fa "struct archive *" +.Fa "struct archive *" +.Fa "void (*excluded_func)(struct archive *, void *, struct archive entry *)" +.Fa "void *" +.Fc +.Ft int +.Fo archive_read_disk_set_metadata_filter_callback +.Fa "struct archive *" +.Fa "int (*metadata_filter_func)(struct archive *, void*, struct archive_entry *)" +.Fa "void *" +.Fc .Sh DESCRIPTION These functions provide an API for reading information about objects on disk. @@ -92,6 +128,14 @@ objects. Allocates and initializes a .Tn struct archive object suitable for reading object information from disk. +.It Fn archive_read_disk_open +Opens the file or directory from the given path and prepares the +.Tn struct archive +to read it from disk. +.It Fn archive_read_disk_open_w +Opens the file or directory from the given path as a wide character string and prepares the +.Tn struct archive +to read it from disk. .It Fn archive_read_disk_set_behavior Configures various behavior options when reading entries from disk. The flags field consists of a bitwise OR of one or more of the @@ -137,6 +181,9 @@ for more information on extended file attributes. .It Cm ARCHIVE_READDISK_RESTORE_ATIME Restore access time of traversed files. By default, access time of traversed files is not restored. +.It Cm ARCHIVE_READDISK_NO_SPARSE +Do not read sparse file information. +By default, sparse file information is read from disk. .El .It Xo .Fn archive_read_disk_set_symlink_logical , @@ -221,6 +268,37 @@ using the currently-registered lookup functions above. This affects the file ownership fields and ACL values in the .Tn struct archive_entry object. +.It Fn archive_read_disk_descend +If the current entry can be descended, this function will mark the directory as the next entry for +.Xr archive_read_header 3 +to visit. +.It Fn archive_read_disk_can_descend +Returns 1 if the current entry is an unvisited directory and 0 otherwise. +.It Fn archive_read_disk_current_filesystem +Returns the index of the most recent filesystem entry that has been visited through archive_read_disk +.It Fn archive_read_disk_current_filesystem_is_synthetic +Returns 1 if the current filesystem is a virtual filesystem. Returns 0 if the current filesystem is not a virtual filesystem. Returns -1 if it is unknown. +.It Fn archive_read_disk_current_filesystem_is_remote +Returns 1 if the current filesystem is a remote filesystem. Returns 0 if the current filesystem is not a remote filesystem. Returns -1 if it is unknown. +.It Fn archive_read_disk_set_matching +Allows the caller to set +.Tn struct archive +*_ma to compare each entry during +.Xr archive_read_header 3 +calls. If matched based on calls to +.Tn archive_match_path_excluded , +.Tn archive_match_time_excluded , +or +.Tn archive_match_owner_excluded , +then the callback function specified by the _excluded_func parameter will execute. This function will recieve data provided to the fourth parameter, void *_client_data. +.It Fn archive_read_disk_set_metadata_filter_callback +Allows the caller to set a callback function during calls to +.Xr archive_read_header 3 +to filter out metadata for each entry. The callback function recieves the +.Tn struct archive +object, void* custom filter data, and the +.Tn struct archive_entry . +If the callback function returns an error, ARCHIVE_RETRY will be returned and the entry will not be further processed. .El More information about the .Va struct archive diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c index 9c9cf38..ab0270b 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c @@ -303,9 +303,11 @@ archive_read_disk_entry_from_file(struct archive *_a, if (r1 < r) r = r1; } - r1 = setup_sparse(a, entry, &fd); - if (r1 < r) - r = r1; + if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) { + r1 = setup_sparse(a, entry, &fd); + if (r1 < r) + r = r1; + } /* If we opened the file earlier in this function, close it. */ if (initial_fd != fd) diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c index 2898206..d0e1f35 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c @@ -369,22 +369,14 @@ static int open_on_current_dir(struct tree *, const char *, int); static int tree_dup(int); -static struct archive_vtable * -archive_read_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_free = _archive_read_free; - av.archive_close = _archive_read_close; - av.archive_read_data_block = _archive_read_data_block; - av.archive_read_next_header = _archive_read_next_header; - av.archive_read_next_header2 = _archive_read_next_header2; - inited = 1; - } - return (&av); -} +static const struct archive_vtable +archive_read_disk_vtable = { + .archive_free = _archive_read_free, + .archive_close = _archive_read_close, + .archive_read_data_block = _archive_read_data_block, + .archive_read_next_header = _archive_read_next_header, + .archive_read_next_header2 = _archive_read_next_header2, +}; const char * archive_read_disk_gname(struct archive *_a, la_int64_t gid) @@ -461,7 +453,7 @@ archive_read_disk_new(void) return (NULL); a->archive.magic = ARCHIVE_READ_DISK_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; - a->archive.vtable = archive_read_disk_vtable(); + a->archive.vtable = &archive_read_disk_vtable; a->entry = archive_entry_new2(&a->archive); a->lookup_uname = trivial_lookup_uname; a->lookup_gname = trivial_lookup_gname; @@ -1290,7 +1282,7 @@ archive_read_disk_descend(struct archive *_a) ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_disk_descend"); - if (t->visit_type != TREE_REGULAR || !t->descend) + if (!archive_read_disk_can_descend(_a)) return (ARCHIVE_OK); /* @@ -1522,8 +1514,40 @@ get_xfer_size(struct tree *t, int fd, const char *path) } #endif -#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \ - && !defined(ST_LOCAL) +#if defined(HAVE_STATVFS) +static inline __LA_UNUSED void +set_statvfs_transfer_size(struct filesystem *fs, const struct statvfs *sfs) +{ + fs->xfer_align = sfs->f_frsize > 0 ? (long)sfs->f_frsize : -1; + fs->max_xfer_size = -1; +#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE) + fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1; + fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1; +#else + fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1; + fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1; +#endif +} +#endif + +#if defined(HAVE_STRUCT_STATFS) +static inline __LA_UNUSED void +set_statfs_transfer_size(struct filesystem *fs, const struct statfs *sfs) +{ + fs->xfer_align = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1; + fs->max_xfer_size = -1; +#if defined(HAVE_STRUCT_STATFS_F_IOSIZE) + fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1; + fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1; +#else + fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1; + fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1; +#endif +} +#endif + +#if defined(HAVE_STRUCT_STATFS) && defined(HAVE_STATFS) && \ + defined(HAVE_FSTATFS) && defined(MNT_LOCAL) && !defined(ST_LOCAL) /* * Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X. @@ -1593,10 +1617,7 @@ setup_current_filesystem(struct archive_read_disk *a) return (ARCHIVE_FAILED); } else if (xr == 1) { /* pathconf(_PC_REX_*) operations are not supported. */ - t->current_filesystem->xfer_align = sfs.f_bsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = sfs.f_iosize; - t->current_filesystem->incr_xfer_size = sfs.f_iosize; + set_statfs_transfer_size(t->current_filesystem, &sfs); } if (sfs.f_flags & MNT_LOCAL) t->current_filesystem->remote = 0; @@ -1688,15 +1709,7 @@ setup_current_filesystem(struct archive_read_disk *a) } else if (xr == 1) { /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN * for pathconf() function. */ - t->current_filesystem->xfer_align = svfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; -#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE) - t->current_filesystem->min_xfer_size = svfs.f_iosize; - t->current_filesystem->incr_xfer_size = svfs.f_iosize; -#else - t->current_filesystem->min_xfer_size = svfs.f_bsize; - t->current_filesystem->incr_xfer_size = svfs.f_bsize; -#endif + set_statvfs_transfer_size(t->current_filesystem, &svfs); } if (svfs.f_flag & ST_LOCAL) t->current_filesystem->remote = 0; @@ -1803,15 +1816,9 @@ setup_current_filesystem(struct archive_read_disk *a) } else if (xr == 1) { /* pathconf(_PC_REX_*) operations are not supported. */ #if defined(HAVE_STATVFS) - t->current_filesystem->xfer_align = svfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = svfs.f_bsize; - t->current_filesystem->incr_xfer_size = svfs.f_bsize; + set_statvfs_transfer_size(t->current_filesystem, &svfs); #else - t->current_filesystem->xfer_align = sfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = sfs.f_bsize; - t->current_filesystem->incr_xfer_size = sfs.f_bsize; + set_statfs_transfer_size(t->current_filesystem, &sfs); #endif } switch (sfs.f_type) { @@ -1918,10 +1925,7 @@ setup_current_filesystem(struct archive_read_disk *a) return (ARCHIVE_FAILED); } else if (xr == 1) { /* pathconf(_PC_REX_*) operations are not supported. */ - t->current_filesystem->xfer_align = svfs.f_frsize; - t->current_filesystem->max_xfer_size = -1; - t->current_filesystem->min_xfer_size = svfs.f_bsize; - t->current_filesystem->incr_xfer_size = svfs.f_bsize; + set_statvfs_transfer_size(t->current_filesystem, &svfs); } #if defined(ST_NOATIME) diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c index fdd376f..ea32e2a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c @@ -449,22 +449,14 @@ entry_symlink_from_pathw(struct archive_entry *entry, const wchar_t *path) return; } -static struct archive_vtable * -archive_read_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_free = _archive_read_free; - av.archive_close = _archive_read_close; - av.archive_read_data_block = _archive_read_data_block; - av.archive_read_next_header = _archive_read_next_header; - av.archive_read_next_header2 = _archive_read_next_header2; - inited = 1; - } - return (&av); -} +static const struct archive_vtable +archive_read_disk_vtable = { + .archive_free = _archive_read_free, + .archive_close = _archive_read_close, + .archive_read_data_block = _archive_read_data_block, + .archive_read_next_header = _archive_read_next_header, + .archive_read_next_header2 = _archive_read_next_header2, +}; const char * archive_read_disk_gname(struct archive *_a, la_int64_t gid) @@ -541,7 +533,7 @@ archive_read_disk_new(void) return (NULL); a->archive.magic = ARCHIVE_READ_DISK_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; - a->archive.vtable = archive_read_disk_vtable(); + a->archive.vtable = &archive_read_disk_vtable; a->entry = archive_entry_new2(&a->archive); a->lookup_uname = trivial_lookup_uname; a->lookup_gname = trivial_lookup_gname; @@ -1090,9 +1082,11 @@ next_entry(struct archive_read_disk *a, struct tree *t, } /* Find sparse data from the disk. */ - if (archive_entry_hardlink(entry) == NULL && - (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0) - r = setup_sparse_from_disk(a, entry, t->entry_fh); + if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) { + if (archive_entry_hardlink(entry) == NULL && + (st->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0) + r = setup_sparse_from_disk(a, entry, t->entry_fh); + } } return (r); } @@ -1300,7 +1294,7 @@ archive_read_disk_descend(struct archive *_a) ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_disk_descend"); - if (t->visit_type != TREE_REGULAR || !t->descend) + if (!archive_read_disk_can_descend(_a)) return (ARCHIVE_OK); if (tree_current_is_physical_dir(t)) { @@ -1844,7 +1838,7 @@ tree_next(struct tree *t) continue; return (r); } else { - HANDLE h = FindFirstFileW(d, &t->_findData); + HANDLE h = FindFirstFileW(t->stack->full_path.s, &t->_findData); if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); t->tree_errno = errno; @@ -2371,9 +2365,11 @@ archive_read_disk_entry_from_file(struct archive *_a, return (ARCHIVE_OK); } - r = setup_sparse_from_disk(a, entry, h); - if (fd < 0) - CloseHandle(h); + if ((a->flags & ARCHIVE_READDISK_NO_SPARSE) == 0) { + r = setup_sparse_from_disk(a, entry, h); + if (fd < 0) + CloseHandle(h); + } return (r); } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_private.h b/Utilities/cmlibarchive/libarchive/archive_read_private.h index c842e6f..383405d 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_read_private.h @@ -42,6 +42,16 @@ struct archive_read; struct archive_read_filter_bidder; struct archive_read_filter; +struct archive_read_filter_bidder_vtable { + /* Taste the upstream filter to see if we handle this. */ + int (*bid)(struct archive_read_filter_bidder *, + struct archive_read_filter *); + /* Initialize a newly-created filter. */ + int (*init)(struct archive_read_filter *); + /* Release the bidder's configuration data. */ + void (*free)(struct archive_read_filter_bidder *); +}; + /* * How bidding works for filters: * * The bid manager initializes the client-provided reader as the @@ -62,16 +72,16 @@ struct archive_read_filter_bidder { void *data; /* Name of the filter */ const char *name; - /* Taste the upstream filter to see if we handle this. */ - int (*bid)(struct archive_read_filter_bidder *, - struct archive_read_filter *); - /* Initialize a newly-created filter. */ - int (*init)(struct archive_read_filter *); - /* Set an option for the filter bidder. */ - int (*options)(struct archive_read_filter_bidder *, - const char *key, const char *value); - /* Release the bidder's configuration data. */ - int (*free)(struct archive_read_filter_bidder *); + const struct archive_read_filter_bidder_vtable *vtable; +}; + +struct archive_read_filter_vtable { + /* Return next block. */ + ssize_t (*read)(struct archive_read_filter *, const void **); + /* Close (just this filter) and free(self). */ + int (*close)(struct archive_read_filter *self); + /* Read any header metadata if available. */ + int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry); }; /* @@ -86,25 +96,14 @@ struct archive_read_filter { struct archive_read_filter_bidder *bidder; /* My bidder. */ struct archive_read_filter *upstream; /* Who I read from. */ struct archive_read *archive; /* Associated archive. */ - /* Open a block for reading */ - int (*open)(struct archive_read_filter *self); - /* Return next block. */ - ssize_t (*read)(struct archive_read_filter *, const void **); - /* Skip forward this many bytes. */ - int64_t (*skip)(struct archive_read_filter *self, int64_t request); - /* Seek to an absolute location. */ - int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence); - /* Close (just this filter) and free(self). */ - int (*close)(struct archive_read_filter *self); - /* Function that handles switching from reading one block to the next/prev */ - int (*sswitch)(struct archive_read_filter *self, unsigned int iindex); - /* Read any header metadata if available. */ - int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry); + const struct archive_read_filter_vtable *vtable; /* My private data. */ void *data; const char *name; int code; + int can_skip; + int can_seek; /* Used by reblocking logic. */ char *buffer; @@ -242,8 +241,10 @@ int __archive_read_register_format(struct archive_read *a, int (*format_capabilities)(struct archive_read *), int (*has_encrypted_entries)(struct archive_read *)); -int __archive_read_get_bidder(struct archive_read *a, - struct archive_read_filter_bidder **bidder); +int __archive_read_register_bidder(struct archive_read *a, + void *bidder_data, + const char *name, + const struct archive_read_filter_bidder_vtable *vtable); const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *); const void *__archive_read_filter_ahead(struct archive_read_filter *, diff --git a/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 b/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 index 78d9999..b2db4cb 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 +++ b/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 @@ -188,9 +188,18 @@ used when translating file names. .El .It Format cpio .Bl -tag -compact -width indent +.It Cm compat-2x +Libarchive 2.x incorrectly encoded Unicode filenames on +some platforms. +This option mimics the libarchive 2.x filename handling +so that such archives can be read correctly. .It Cm hdrcharset The value is used as a character set name that will be used when translating file names. +.It Cm pwb +When reading a binary CPIO archive, assume that it is +in the original PWB cpio format, and handle file mode +bits accordingly. The default is to assume v7 format. .El .It Format iso9660 .Bl -tag -compact -width indent diff --git a/Utilities/cmlibarchive/libarchive/archive_read_set_options.c b/Utilities/cmlibarchive/libarchive/archive_read_set_options.c index 2e2eea6..2bd9b81 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_set_options.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_set_options.c @@ -112,37 +112,15 @@ static int archive_set_filter_option(struct archive *_a, const char *m, const char *o, const char *v) { - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter *filter; - struct archive_read_filter_bidder *bidder; - int r, rv = ARCHIVE_WARN, matched_modules = 0; - - for (filter = a->filter; filter != NULL; filter = filter->upstream) { - bidder = filter->bidder; - if (bidder == NULL) - continue; - if (bidder->options == NULL) - /* This bidder does not support option */ - continue; - if (m != NULL) { - if (strcmp(filter->name, m) != 0) - continue; - ++matched_modules; - } + (void)_a; /* UNUSED */ + (void)o; /* UNUSED */ + (void)v; /* UNUSED */ - r = bidder->options(bidder, o, v); - - if (r == ARCHIVE_FATAL) - return (ARCHIVE_FATAL); - - if (r == ARCHIVE_OK) - rv = ARCHIVE_OK; - } /* If the filter name didn't match, return a special code for * _archive_set_option[s]. */ - if (m != NULL && matched_modules == 0) + if (m != NULL) return ARCHIVE_WARN - 1; - return (rv); + return ARCHIVE_WARN; } static int diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c index 5333d47..a5243af 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_bzip2.c @@ -70,7 +70,6 @@ static int bzip2_filter_close(struct archive_read_filter *); */ static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); static int bzip2_reader_init(struct archive_read_filter *); -static int bzip2_reader_free(struct archive_read_filter_bidder *); #if ARCHIVE_VERSION_NUMBER < 4000000 /* Deprecated; remove in libarchive 4.0 */ @@ -81,24 +80,21 @@ archive_read_support_compression_bzip2(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +bzip2_bidder_vtable = { + .bid = bzip2_reader_bid, + .init = bzip2_reader_init, +}; + int archive_read_support_filter_bzip2(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *reader; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_bzip2"); - if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "bzip2", + &bzip2_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - reader->data = NULL; - reader->name = "bzip2"; - reader->bid = bzip2_reader_bid; - reader->init = bzip2_reader_init; - reader->options = NULL; - reader->free = bzip2_reader_free; #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) return (ARCHIVE_OK); #else @@ -108,12 +104,6 @@ archive_read_support_filter_bzip2(struct archive *_a) #endif } -static int -bzip2_reader_free(struct archive_read_filter_bidder *self){ - (void)self; /* UNUSED */ - return (ARCHIVE_OK); -} - /* * Test whether we can handle this data. * @@ -183,6 +173,12 @@ bzip2_reader_init(struct archive_read_filter *self) #else +static const struct archive_read_filter_vtable +bzip2_reader_vtable = { + .read = bzip2_filter_read, + .close = bzip2_filter_close, +}; + /* * Setup the callbacks. */ @@ -209,9 +205,7 @@ bzip2_reader_init(struct archive_read_filter *self) self->data = state; state->out_block_size = out_block_size; state->out_block = out_block; - self->read = bzip2_filter_read; - self->skip = NULL; /* not supported */ - self->close = bzip2_filter_close; + self->vtable = &bzip2_reader_vtable; return (ARCHIVE_OK); } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c index e05132d..05b80a5 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c @@ -133,7 +133,6 @@ struct private_data { static int compress_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); static int compress_bidder_init(struct archive_read_filter *); -static int compress_bidder_free(struct archive_read_filter_bidder *); static ssize_t compress_filter_read(struct archive_read_filter *, const void **); static int compress_filter_close(struct archive_read_filter *); @@ -150,25 +149,19 @@ archive_read_support_compression_compress(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +compress_bidder_vtable = { + .bid = compress_bidder_bid, + .init = compress_bidder_init, +}; + int archive_read_support_filter_compress(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_compress"); - - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "compress (.Z)"; - bidder->bid = compress_bidder_bid; - bidder->init = compress_bidder_init; - bidder->options = NULL; - bidder->free = compress_bidder_free; - return (ARCHIVE_OK); + return __archive_read_register_bidder(a, NULL, "compress (.Z)", + &compress_bidder_vtable); } /* @@ -205,6 +198,12 @@ compress_bidder_bid(struct archive_read_filter_bidder *self, return (bits_checked); } +static const struct archive_read_filter_vtable +compress_reader_vtable = { + .read = compress_filter_read, + .close = compress_filter_close, +}; + /* * Setup the callbacks. */ @@ -233,9 +232,7 @@ compress_bidder_init(struct archive_read_filter *self) self->data = state; state->out_block_size = out_block_size; state->out_block = out_block; - self->read = compress_filter_read; - self->skip = NULL; /* not supported */ - self->close = compress_filter_close; + self->vtable = &compress_reader_vtable; /* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */ @@ -306,16 +303,6 @@ compress_filter_read(struct archive_read_filter *self, const void **pblock) } /* - * Clean up the reader. - */ -static int -compress_bidder_free(struct archive_read_filter_bidder *self) -{ - self->data = NULL; - return (ARCHIVE_OK); -} - -/* * Close and release the filter. */ static int diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c index 84c86ae..d4d1737 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_grzip.c @@ -54,30 +54,21 @@ static int grzip_bidder_bid(struct archive_read_filter_bidder *, static int grzip_bidder_init(struct archive_read_filter *); -static int -grzip_reader_free(struct archive_read_filter_bidder *self) -{ - (void)self; /* UNUSED */ - return (ARCHIVE_OK); -} +static const struct archive_read_filter_bidder_vtable +grzip_bidder_vtable = { + .bid = grzip_bidder_bid, + .init = grzip_bidder_init, +}; int archive_read_support_filter_grzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *reader; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_grzip"); - if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, NULL, + &grzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - reader->data = NULL; - reader->bid = grzip_bidder_bid; - reader->init = grzip_bidder_init; - reader->options = NULL; - reader->free = grzip_reader_free; /* This filter always uses an external program. */ archive_set_error(_a, ARCHIVE_ERRNO_MISC, "Using external grzip program for grzip decompression"); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c index ac0b694..976a392 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_gzip.c @@ -94,24 +94,21 @@ archive_read_support_compression_gzip(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +gzip_bidder_vtable = { + .bid = gzip_bidder_bid, + .init = gzip_bidder_init, +}; + int archive_read_support_filter_gzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_gzip"); - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "gzip", + &gzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "gzip"; - bidder->bid = gzip_bidder_bid; - bidder->init = gzip_bidder_init; - bidder->options = NULL; - bidder->free = NULL; /* No data, so no cleanup necessary. */ /* Signal the extent of gzip support with the return value here. */ #if HAVE_ZLIB_H return (ARCHIVE_OK); @@ -291,6 +288,15 @@ gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry) return (ARCHIVE_OK); } +static const struct archive_read_filter_vtable +gzip_reader_vtable = { + .read = gzip_filter_read, + .close = gzip_filter_close, +#ifdef HAVE_ZLIB_H + .read_header = gzip_read_header, +#endif +}; + /* * Initialize the filter object. */ @@ -317,12 +323,7 @@ gzip_bidder_init(struct archive_read_filter *self) self->data = state; state->out_block_size = out_block_size; state->out_block = out_block; - self->read = gzip_filter_read; - self->skip = NULL; /* not supported */ - self->close = gzip_filter_close; -#ifdef HAVE_ZLIB_H - self->read_header = gzip_read_header; -#endif + self->vtable = &gzip_reader_vtable; state->in_stream = 0; /* We're not actually within a stream yet. */ diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c index c82a8e2..a238989 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lrzip.c @@ -53,31 +53,21 @@ static int lrzip_bidder_bid(struct archive_read_filter_bidder *, static int lrzip_bidder_init(struct archive_read_filter *); -static int -lrzip_reader_free(struct archive_read_filter_bidder *self) -{ - (void)self; /* UNUSED */ - return (ARCHIVE_OK); -} +static const struct archive_read_filter_bidder_vtable +lrzip_bidder_vtable = { + .bid = lrzip_bidder_bid, + .init = lrzip_bidder_init, +}; int archive_read_support_filter_lrzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *reader; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_lrzip"); - if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "lrzip", + &lrzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - reader->data = NULL; - reader->name = "lrzip"; - reader->bid = lrzip_bidder_bid; - reader->init = lrzip_bidder_init; - reader->options = NULL; - reader->free = lrzip_reader_free; /* This filter always uses an external program. */ archive_set_error(_a, ARCHIVE_ERRNO_MISC, "Using external lrzip program for lrzip decompression"); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c index 43ee6c2..ae0b080 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c @@ -99,7 +99,6 @@ static int lz4_filter_close(struct archive_read_filter *); */ static int lz4_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); static int lz4_reader_init(struct archive_read_filter *); -static int lz4_reader_free(struct archive_read_filter_bidder *); #if defined(HAVE_LIBLZ4) static ssize_t lz4_filter_read_default_stream(struct archive_read_filter *, const void **); @@ -107,24 +106,21 @@ static ssize_t lz4_filter_read_legacy_stream(struct archive_read_filter *, const void **); #endif +static const struct archive_read_filter_bidder_vtable +lz4_bidder_vtable = { + .bid = lz4_reader_bid, + .init = lz4_reader_init, +}; + int archive_read_support_filter_lz4(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *reader; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_lz4"); - if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "lz4", + &lz4_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - reader->data = NULL; - reader->name = "lz4"; - reader->bid = lz4_reader_bid; - reader->init = lz4_reader_init; - reader->options = NULL; - reader->free = lz4_reader_free; #if defined(HAVE_LIBLZ4) return (ARCHIVE_OK); #else @@ -134,12 +130,6 @@ archive_read_support_filter_lz4(struct archive *_a) #endif } -static int -lz4_reader_free(struct archive_read_filter_bidder *self){ - (void)self; /* UNUSED */ - return (ARCHIVE_OK); -} - /* * Test whether we can handle this data. * @@ -218,6 +208,12 @@ lz4_reader_init(struct archive_read_filter *self) #else +static const struct archive_read_filter_vtable +lz4_reader_vtable = { + .read = lz4_filter_read, + .close = lz4_filter_close, +}; + /* * Setup the callbacks. */ @@ -238,9 +234,7 @@ lz4_reader_init(struct archive_read_filter *self) self->data = state; state->stage = SELECT_STREAM; - self->read = lz4_filter_read; - self->skip = NULL; /* not supported */ - self->close = lz4_filter_close; + self->vtable = &lz4_reader_vtable; return (ARCHIVE_OK); } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c index 05f740b..42e2636 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c @@ -101,23 +101,21 @@ static int lzop_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); static int lzop_bidder_init(struct archive_read_filter *); +static const struct archive_read_filter_bidder_vtable +lzop_bidder_vtable = { + .bid = lzop_bidder_bid, + .init = lzop_bidder_init, +}; + int archive_read_support_filter_lzop(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *reader; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_lzop"); - if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, NULL, + &lzop_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - reader->data = NULL; - reader->bid = lzop_bidder_bid; - reader->init = lzop_bidder_init; - reader->options = NULL; - reader->free = NULL; /* Signal the extent of lzop support with the return value here. */ #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H) return (ARCHIVE_OK); @@ -171,6 +169,13 @@ lzop_bidder_init(struct archive_read_filter *self) return (r); } #else + +static const struct archive_read_filter_vtable +lzop_reader_vtable = { + .read = lzop_filter_read, + .close = lzop_filter_close +}; + /* * Initialize the filter object. */ @@ -190,9 +195,7 @@ lzop_bidder_init(struct archive_read_filter *self) } self->data = state; - self->read = lzop_filter_read; - self->skip = NULL; /* not supported */ - self->close = lzop_filter_close; + self->vtable = &lzop_reader_vtable; return (ARCHIVE_OK); } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c index bf5b6f2..885b2c2 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c @@ -98,7 +98,7 @@ struct program_bidder { static int program_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *upstream); static int program_bidder_init(struct archive_read_filter *); -static int program_bidder_free(struct archive_read_filter_bidder *); +static void program_bidder_free(struct archive_read_filter_bidder *); /* * The actual filter needs to track input and output data. @@ -123,43 +123,21 @@ static ssize_t program_filter_read(struct archive_read_filter *, static int program_filter_close(struct archive_read_filter *); static void free_state(struct program_bidder *); -static int -set_bidder_signature(struct archive_read_filter_bidder *bidder, - struct program_bidder *state, const void *signature, size_t signature_len) -{ - - if (signature != NULL && signature_len > 0) { - state->signature_len = signature_len; - state->signature = malloc(signature_len); - memcpy(state->signature, signature, signature_len); - } - - /* - * Fill in the bidder object. - */ - bidder->data = state; - bidder->bid = program_bidder_bid; - bidder->init = program_bidder_init; - bidder->options = NULL; - bidder->free = program_bidder_free; - return (ARCHIVE_OK); -} +static const struct archive_read_filter_bidder_vtable +program_bidder_vtable = { + .bid = program_bidder_bid, + .init = program_bidder_init, + .free = program_bidder_free, +}; int archive_read_support_filter_program_signature(struct archive *_a, const char *cmd, const void *signature, size_t signature_len) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; struct program_bidder *state; /* - * Get a bidder object from the read core. - */ - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - - /* * Allocate our private state. */ state = (struct program_bidder *)calloc(1, sizeof (*state)); @@ -169,20 +147,31 @@ archive_read_support_filter_program_signature(struct archive *_a, if (state->cmd == NULL) goto memerr; - return set_bidder_signature(bidder, state, signature, signature_len); + if (signature != NULL && signature_len > 0) { + state->signature_len = signature_len; + state->signature = malloc(signature_len); + memcpy(state->signature, signature, signature_len); + } + + if (__archive_read_register_bidder(a, state, NULL, + &program_bidder_vtable) != ARCHIVE_OK) { + free_state(state); + return (ARCHIVE_FATAL); + } + return (ARCHIVE_OK); + memerr: free_state(state); archive_set_error(_a, ENOMEM, "Can't allocate memory"); return (ARCHIVE_FATAL); } -static int +static void program_bidder_free(struct archive_read_filter_bidder *self) { struct program_bidder *state = (struct program_bidder *)self->data; free_state(state); - return (ARCHIVE_OK); } static void @@ -393,6 +382,12 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len) } } +static const struct archive_read_filter_vtable +program_reader_vtable = { + .read = program_filter_read, + .close = program_filter_close, +}; + int __archive_read_program(struct archive_read_filter *self, const char *cmd) { @@ -439,9 +434,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd) } self->data = state; - self->read = program_filter_read; - self->skip = NULL; - self->close = program_filter_close; + self->vtable = &program_reader_vtable; /* XXX Check that we can read at least one byte? */ return (ARCHIVE_OK); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_rpm.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_rpm.c index e7e58e5..67a979c 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_rpm.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_rpm.c @@ -72,25 +72,19 @@ archive_read_support_compression_rpm(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +rpm_bidder_vtable = { + .bid = rpm_bidder_bid, + .init = rpm_bidder_init, +}; + int archive_read_support_filter_rpm(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_rpm"); - - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "rpm"; - bidder->bid = rpm_bidder_bid; - bidder->init = rpm_bidder_init; - bidder->options = NULL; - bidder->free = NULL; - return (ARCHIVE_OK); + return __archive_read_register_bidder(a, NULL, "rpm", + &rpm_bidder_vtable); } static int @@ -133,6 +127,12 @@ rpm_bidder_bid(struct archive_read_filter_bidder *self, return (bits_checked); } +static const struct archive_read_filter_vtable +rpm_reader_vtable = { + .read = rpm_filter_read, + .close = rpm_filter_close, +}; + static int rpm_bidder_init(struct archive_read_filter *self) { @@ -140,9 +140,6 @@ rpm_bidder_init(struct archive_read_filter *self) self->code = ARCHIVE_FILTER_RPM; self->name = "rpm"; - self->read = rpm_filter_read; - self->skip = NULL; /* not supported */ - self->close = rpm_filter_close; rpm = (struct rpm *)calloc(sizeof(*rpm), 1); if (rpm == NULL) { @@ -153,6 +150,7 @@ rpm_bidder_init(struct archive_read_filter *self) self->data = rpm; rpm->state = ST_LEAD; + self->vtable = &rpm_reader_vtable; return (ARCHIVE_OK); } @@ -216,7 +214,7 @@ rpm_filter_read(struct archive_read_filter *self, const void **buff) archive_set_error( &self->archive->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Unrecoginized rpm header"); + "Unrecognized rpm header"); return (ARCHIVE_FATAL); } rpm->state = ST_ARCHIVE; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c index 67ddffb..209b2a1 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c @@ -76,25 +76,19 @@ archive_read_support_compression_uu(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +uudecode_bidder_vtable = { + .bid = uudecode_bidder_bid, + .init = uudecode_bidder_init, +}; + int archive_read_support_filter_uu(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_uu"); - - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) - return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "uu"; - bidder->bid = uudecode_bidder_bid; - bidder->init = uudecode_bidder_init; - bidder->options = NULL; - bidder->free = NULL; - return (ARCHIVE_OK); + return __archive_read_register_bidder(a, NULL, "uu", + &uudecode_bidder_vtable); } static const unsigned char ascii[256] = { @@ -248,7 +242,7 @@ bid_get_line(struct archive_read_filter *filter, *ravail = *avail; *b += diff; *avail -= diff; - tested = len;/* Skip some bytes we already determinated. */ + tested = len;/* Skip some bytes we already determined. */ len = get_line(*b + tested, *avail - tested, nl); if (len >= 0) len += tested; @@ -357,6 +351,12 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self, return (0); } +static const struct archive_read_filter_vtable +uudecode_reader_vtable = { + .read = uudecode_filter_read, + .close = uudecode_filter_close, +}; + static int uudecode_bidder_init(struct archive_read_filter *self) { @@ -366,9 +366,6 @@ uudecode_bidder_init(struct archive_read_filter *self) self->code = ARCHIVE_FILTER_UU; self->name = "uu"; - self->read = uudecode_filter_read; - self->skip = NULL; /* not supported */ - self->close = uudecode_filter_close; uudecode = (struct uudecode *)calloc(sizeof(*uudecode), 1); out_buff = malloc(OUT_BUFF_SIZE); @@ -388,6 +385,7 @@ uudecode_bidder_init(struct archive_read_filter *self) uudecode->in_allocated = IN_BUFF_SIZE; uudecode->out_buff = out_buff; uudecode->state = ST_FIND_HEAD; + self->vtable = &uudecode_reader_vtable; return (ARCHIVE_OK); } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c index 3223b38..b978eb0 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c @@ -108,24 +108,21 @@ archive_read_support_compression_xz(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +xz_bidder_vtable = { + .bid = xz_bidder_bid, + .init = xz_bidder_init, +}; + int archive_read_support_filter_xz(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_xz"); - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "xz", + &xz_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "xz"; - bidder->bid = xz_bidder_bid; - bidder->init = xz_bidder_init; - bidder->options = NULL; - bidder->free = NULL; #if HAVE_LZMA_H && HAVE_LIBLZMA return (ARCHIVE_OK); #else @@ -143,24 +140,21 @@ archive_read_support_compression_lzma(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +lzma_bidder_vtable = { + .bid = lzma_bidder_bid, + .init = lzma_bidder_init, +}; + int archive_read_support_filter_lzma(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_lzma"); - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "lzma", + &lzma_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "lzma"; - bidder->bid = lzma_bidder_bid; - bidder->init = lzma_bidder_init; - bidder->options = NULL; - bidder->free = NULL; #if HAVE_LZMA_H && HAVE_LIBLZMA return (ARCHIVE_OK); #else @@ -179,24 +173,21 @@ archive_read_support_compression_lzip(struct archive *a) } #endif +static const struct archive_read_filter_bidder_vtable +lzip_bidder_vtable = { + .bid = lzip_bidder_bid, + .init = lzip_bidder_init, +}; + int archive_read_support_filter_lzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_lzip"); - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "lzip", + &lzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "lzip"; - bidder->bid = lzip_bidder_bid; - bidder->init = lzip_bidder_init; - bidder->options = NULL; - bidder->free = NULL; #if HAVE_LZMA_H && HAVE_LIBLZMA return (ARCHIVE_OK); #else @@ -293,8 +284,8 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self, /* Second through fifth bytes are dictionary size, stored in * little-endian order. The minimum dictionary size is * 1 << 12(4KiB) which the lzma of LZMA SDK uses with option - * -d12 and the maximum dictionary size is 1 << 27(128MiB) - * which the one uses with option -d27. + * -d12 and the maximum dictionary size is 1 << 29(512MiB) + * which the one uses with option -d29. * NOTE: A comment of LZMA SDK source code says this dictionary * range is from 1 << 12 to 1 << 30. */ dicsize = archive_le32dec(buffer+1); @@ -377,7 +368,7 @@ lzip_has_member(struct archive_read_filter *filter) /* Dictionary size. */ log2dic = buffer[5] & 0x1f; - if (log2dic < 12 || log2dic > 27) + if (log2dic < 12 || log2dic > 29) return (0); bits_checked += 8; @@ -470,6 +461,12 @@ set_error(struct archive_read_filter *self, int ret) } } +static const struct archive_read_filter_vtable +xz_lzma_reader_vtable = { + .read = xz_filter_read, + .close = xz_filter_close, +}; + /* * Setup the callbacks. */ @@ -494,9 +491,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self) self->data = state; state->out_block_size = out_block_size; state->out_block = out_block; - self->read = xz_filter_read; - self->skip = NULL; /* not supported */ - self->close = xz_filter_close; + self->vtable = &xz_lzma_reader_vtable; state->stream.avail_in = 0; @@ -562,7 +557,7 @@ lzip_init(struct archive_read_filter *self) /* Get dictionary size. */ log2dic = h[5] & 0x1f; - if (log2dic < 12 || log2dic > 27) + if (log2dic < 12 || log2dic > 29) return (ARCHIVE_FATAL); dicsize = 1U << log2dic; if (log2dic > 12) diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c index c4e8ec7..29d4d62 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c @@ -79,24 +79,21 @@ static int zstd_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); static int zstd_bidder_init(struct archive_read_filter *); +static const struct archive_read_filter_bidder_vtable +zstd_bidder_vtable = { + .bid = zstd_bidder_bid, + .init = zstd_bidder_init, +}; + int archive_read_support_filter_zstd(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder; - - archive_check_magic(_a, ARCHIVE_READ_MAGIC, - ARCHIVE_STATE_NEW, "archive_read_support_filter_zstd"); - if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK) + if (__archive_read_register_bidder(a, NULL, "zstd", + &zstd_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); - bidder->data = NULL; - bidder->name = "zstd"; - bidder->bid = zstd_bidder_bid; - bidder->init = zstd_bidder_init; - bidder->options = NULL; - bidder->free = NULL; #if HAVE_ZSTD_H && HAVE_LIBZSTD return (ARCHIVE_OK); #else @@ -160,6 +157,12 @@ zstd_bidder_init(struct archive_read_filter *self) #else +static const struct archive_read_filter_vtable +zstd_reader_vtable = { + .read = zstd_filter_read, + .close = zstd_filter_close, +}; + /* * Initialize the filter object */ @@ -192,9 +195,7 @@ zstd_bidder_init(struct archive_read_filter *self) state->out_block_size = out_block_size; state->out_block = out_block; state->dstream = dstream; - self->read = zstd_filter_read; - self->skip = NULL; /* not supported */ - self->close = zstd_filter_close; + self->vtable = &zstd_reader_vtable; state->eof = 0; state->in_frame = 0; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c index 456b2f8..7d7e702 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c @@ -808,8 +808,12 @@ archive_read_format_7zip_read_data(struct archive_read *a, if (zip->end_of_entry) return (ARCHIVE_EOF); - bytes = read_stream(a, buff, - (size_t)zip->entry_bytes_remaining, 0); + const uint64_t max_read_size = 16 * 1024 * 1024; // Don't try to read more than 16 MB at a time + size_t bytes_to_read = max_read_size; + if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) { + bytes_to_read = zip->entry_bytes_remaining; + } + bytes = read_stream(a, buff, bytes_to_read, 0); if (bytes < 0) return ((int)bytes); if (bytes == 0) { @@ -1493,7 +1497,7 @@ decompress(struct archive_read *a, struct _7zip *zip, zip->ppmd7_stat = -1; archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Failed to initialize PPMd range decorder"); + "Failed to initialize PPMd range decoder"); return (ARCHIVE_FAILED); } if (zip->ppstream.overconsumed) { @@ -3031,10 +3035,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum) "Truncated 7-Zip file body"); return (ARCHIVE_FATAL); } - if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining) + if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining) bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining; zip->pack_stream_inbytes_remaining -= bytes_avail; - if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining) + if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining) bytes_avail = (ssize_t)zip->folder_outbytes_remaining; zip->folder_outbytes_remaining -= bytes_avail; zip->uncompressed_buffer_bytes_remaining = bytes_avail; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c index 57547d4..8742378 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c @@ -2110,7 +2110,6 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits) ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot); if (ds->pos_tbl == NULL) return (ARCHIVE_FATAL); - lzx_huffman_free(&(ds->mt)); } for (footer = 0; footer < 18; footer++) diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c index 1c96e6a..6b8ae33 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c @@ -185,6 +185,8 @@ struct cpio { struct archive_string_conv *opt_sconv; struct archive_string_conv *sconv_default; int init_default_conversion; + + int option_pwb; }; static int64_t atol16(const char *, unsigned); @@ -343,6 +345,10 @@ archive_read_format_cpio_options(struct archive_read *a, ret = ARCHIVE_FATAL; } return (ret); + } else if (strcmp(key, "pwb") == 0) { + if (val != NULL && val[0] != 0) + cpio->option_pwb = 1; + return (ARCHIVE_OK); } /* Note: The "warn" return is just to inform the options @@ -891,6 +897,12 @@ header_bin_le(struct archive_read *a, struct cpio *cpio, archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256); archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256); archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256); + if (cpio->option_pwb) { + /* turn off random bits left over from V6 inode */ + archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777); + if ((archive_entry_mode(entry) & AE_IFMT) == 0) + archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG); + } archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256); archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256); archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256); @@ -930,6 +942,12 @@ header_bin_be(struct archive_read *a, struct cpio *cpio, archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]); archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]); archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]); + if (cpio->option_pwb) { + /* turn off random bits left over from V6 inode */ + archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777); + if ((archive_entry_mode(entry) & AE_IFMT) == 0) + archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG); + } archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]); archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]); archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c index 93ba295..88bca76 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c @@ -408,7 +408,7 @@ next_line(struct archive_read *a, *ravail = *avail; *b += diff; *avail -= diff; - tested = len;/* Skip some bytes we already determinated. */ + tested = len;/* Skip some bytes we already determined. */ len = get_line_size(*b + len, *avail - len, nl); if (len >= 0) len += tested; @@ -1074,7 +1074,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree) continue; /* Non-printable characters are not allowed */ for (s = p;s < p + len - 1; s++) { - if (!isprint(*s)) { + if (!isprint((unsigned char)*s)) { r = ARCHIVE_FATAL; break; } @@ -1629,11 +1629,11 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, || strcmp(key, "contents") == 0) { parse_escapes(val, NULL); archive_strcpy(&mtree->contents_name, val); - break; + return (ARCHIVE_OK); } if (strcmp(key, "cksum") == 0) - break; - __LA_FALLTHROUGH; + return (ARCHIVE_OK); + break; case 'd': if (strcmp(key, "device") == 0) { /* stat(2) st_rdev field, e.g. the major/minor IDs @@ -1647,65 +1647,64 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, archive_entry_set_rdev(entry, dev); return r; } - __LA_FALLTHROUGH; + break; case 'f': if (strcmp(key, "flags") == 0) { *parsed_kws |= MTREE_HAS_FFLAGS; archive_entry_copy_fflags_text(entry, val); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'g': if (strcmp(key, "gid") == 0) { *parsed_kws |= MTREE_HAS_GID; archive_entry_set_gid(entry, mtree_atol(&val, 10)); - break; + return (ARCHIVE_OK); } if (strcmp(key, "gname") == 0) { *parsed_kws |= MTREE_HAS_GNAME; archive_entry_copy_gname(entry, val); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'i': if (strcmp(key, "inode") == 0) { archive_entry_set_ino(entry, mtree_atol(&val, 10)); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'l': if (strcmp(key, "link") == 0) { + parse_escapes(val, NULL); archive_entry_copy_symlink(entry, val); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'm': if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) { return parse_digest(a, entry, val, ARCHIVE_ENTRY_DIGEST_MD5); } if (strcmp(key, "mode") == 0) { - if (val[0] >= '0' && val[0] <= '7') { - *parsed_kws |= MTREE_HAS_PERM; - archive_entry_set_perm(entry, - (mode_t)mtree_atol(&val, 8)); - } else { + if (val[0] < '0' || val[0] > '7') { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Symbolic or non-octal mode \"%s\" unsupported", val); - return ARCHIVE_WARN; + return (ARCHIVE_WARN); } - break; + *parsed_kws |= MTREE_HAS_PERM; + archive_entry_set_perm(entry, (mode_t)mtree_atol(&val, 8)); + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'n': if (strcmp(key, "nlink") == 0) { *parsed_kws |= MTREE_HAS_NLINK; archive_entry_set_nlink(entry, (unsigned int)mtree_atol(&val, 10)); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'r': if (strcmp(key, "resdevice") == 0) { /* stat(2) st_dev field, e.g. the device ID where the @@ -1723,7 +1722,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, return parse_digest(a, entry, val, ARCHIVE_ENTRY_DIGEST_RMD160); } - __LA_FALLTHROUGH; + break; case 's': if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0) { @@ -1747,9 +1746,9 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, } if (strcmp(key, "size") == 0) { archive_entry_set_size(entry, mtree_atol(&val, 10)); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 't': if (strcmp(key, "tags") == 0) { /* @@ -1757,7 +1756,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, * Ignore the tags for now, but the interface * should be extended to allow inclusion/exclusion. */ - break; + return (ARCHIVE_OK); } if (strcmp(key, "time") == 0) { int64_t m; @@ -1783,79 +1782,85 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, else if (m < my_time_t_min) m = my_time_t_min; archive_entry_set_mtime(entry, (time_t)m, ns); - break; + return (ARCHIVE_OK); } if (strcmp(key, "type") == 0) { switch (val[0]) { case 'b': if (strcmp(val, "block") == 0) { - archive_entry_set_filetype(entry, AE_IFBLK); - break; + *parsed_kws |= MTREE_HAS_TYPE; + archive_entry_set_filetype(entry, + AE_IFBLK); + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'c': if (strcmp(val, "char") == 0) { + *parsed_kws |= MTREE_HAS_TYPE; archive_entry_set_filetype(entry, AE_IFCHR); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'd': if (strcmp(val, "dir") == 0) { + *parsed_kws |= MTREE_HAS_TYPE; archive_entry_set_filetype(entry, AE_IFDIR); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'f': if (strcmp(val, "fifo") == 0) { + *parsed_kws |= MTREE_HAS_TYPE; archive_entry_set_filetype(entry, AE_IFIFO); - break; + return (ARCHIVE_OK); } if (strcmp(val, "file") == 0) { + *parsed_kws |= MTREE_HAS_TYPE; archive_entry_set_filetype(entry, AE_IFREG); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; case 'l': if (strcmp(val, "link") == 0) { + *parsed_kws |= MTREE_HAS_TYPE; archive_entry_set_filetype(entry, AE_IFLNK); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; default: - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Unrecognized file type \"%s\"; " - "assuming \"file\"", val); - archive_entry_set_filetype(entry, AE_IFREG); - return (ARCHIVE_WARN); + break; } - *parsed_kws |= MTREE_HAS_TYPE; - break; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Unrecognized file type \"%s\"; " + "assuming \"file\"", val); + archive_entry_set_filetype(entry, AE_IFREG); + return (ARCHIVE_WARN); } - __LA_FALLTHROUGH; + break; case 'u': if (strcmp(key, "uid") == 0) { *parsed_kws |= MTREE_HAS_UID; archive_entry_set_uid(entry, mtree_atol(&val, 10)); - break; + return (ARCHIVE_OK); } if (strcmp(key, "uname") == 0) { *parsed_kws |= MTREE_HAS_UNAME; archive_entry_copy_uname(entry, val); - break; + return (ARCHIVE_OK); } - __LA_FALLTHROUGH; + break; default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Unrecognized key %s=%s", key, val); - return (ARCHIVE_WARN); + break; } - return (ARCHIVE_OK); + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unrecognized key %s=%s", key, val); + return (ARCHIVE_WARN); } static int @@ -2035,13 +2040,13 @@ mtree_atol(char **p, int base) if (**p == '-') { limit = INT64_MIN / base; - last_digit_limit = INT64_MIN % base; + last_digit_limit = -(INT64_MIN % base); ++(*p); l = 0; digit = parsedigit(**p); while (digit >= 0 && digit < base) { - if (l < limit || (l == limit && digit > last_digit_limit)) + if (l < limit || (l == limit && digit >= last_digit_limit)) return INT64_MIN; l = (l * base) - digit; digit = parsedigit(*++(*p)); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c index 6dca350..5c02a25 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c @@ -135,6 +135,16 @@ #define MAX_SYMBOL_LENGTH 0xF #define MAX_SYMBOLS 20 +/* Virtual Machine Properties */ +#define VM_MEMORY_SIZE 0x40000 +#define VM_MEMORY_MASK (VM_MEMORY_SIZE - 1) +#define PROGRAM_WORK_SIZE 0x3C000 +#define PROGRAM_GLOBAL_SIZE 0x2000 +#define PROGRAM_SYSTEM_GLOBAL_ADDRESS PROGRAM_WORK_SIZE +#define PROGRAM_SYSTEM_GLOBAL_SIZE 0x40 +#define PROGRAM_USER_GLOBAL_ADDRESS (PROGRAM_SYSTEM_GLOBAL_ADDRESS + PROGRAM_SYSTEM_GLOBAL_SIZE) +#define PROGRAM_USER_GLOBAL_SIZE (PROGRAM_GLOBAL_SIZE - PROGRAM_SYSTEM_GLOBAL_SIZE) + /* * Considering L1,L2 cache miss and a calling of write system-call, * the best size of the output buffer(uncompressed buffer) is 128K. @@ -213,6 +223,69 @@ struct data_block_offsets int64_t end_offset; }; +struct rar_program_code +{ + uint8_t *staticdata; + uint32_t staticdatalen; + uint8_t *globalbackup; + uint32_t globalbackuplen; + uint64_t fingerprint; + uint32_t usagecount; + uint32_t oldfilterlength; + struct rar_program_code *next; +}; + +struct rar_filter +{ + struct rar_program_code *prog; + uint32_t initialregisters[8]; + uint8_t *globaldata; + uint32_t globaldatalen; + size_t blockstartpos; + uint32_t blocklength; + uint32_t filteredblockaddress; + uint32_t filteredblocklength; + struct rar_filter *next; +}; + +struct memory_bit_reader +{ + const uint8_t *bytes; + size_t length; + size_t offset; + uint64_t bits; + int available; + int at_eof; +}; + +struct rar_virtual_machine +{ + uint32_t registers[8]; + uint8_t memory[VM_MEMORY_SIZE + sizeof(uint32_t)]; +}; + +struct rar_filters +{ + struct rar_virtual_machine *vm; + struct rar_program_code *progs; + struct rar_filter *stack; + int64_t filterstart; + uint32_t lastfilternum; + int64_t lastend; + uint8_t *bytes; + size_t bytes_ready; +}; + +struct audio_state +{ + int8_t weight[5]; + int16_t delta[4]; + int8_t lastdelta; + int error[11]; + int count; + uint8_t lastbyte; +}; + struct rar { /* Entries from main RAR header */ @@ -273,15 +346,16 @@ struct rar struct huffman_code lengthcode; unsigned char lengthtable[HUFFMAN_TABLE_SIZE]; struct lzss lzss; - char output_last_match; unsigned int lastlength; unsigned int lastoffset; unsigned int oldoffset[4]; unsigned int lastlowoffset; unsigned int numlowoffsetrepeats; - int64_t filterstart; char start_new_table; + /* Filters */ + struct rar_filters filters; + /* PPMd Variant H members */ char ppmd_valid; char ppmd_eod; @@ -343,13 +417,13 @@ static int read_symlink_stored(struct archive_read *, struct archive_entry *, static int read_data_stored(struct archive_read *, const void **, size_t *, int64_t *); static int read_data_compressed(struct archive_read *, const void **, size_t *, - int64_t *, size_t); + int64_t *, size_t); static int rar_br_preparation(struct archive_read *, struct rar_br *); static int parse_codes(struct archive_read *); static void free_codes(struct archive_read *); static int read_next_symbol(struct archive_read *, struct huffman_code *); static int create_code(struct archive_read *, struct huffman_code *, - unsigned char *, int, char); + unsigned char *, int, char); static int add_value(struct archive_read *, struct huffman_code *, int, int, int); static int new_node(struct huffman_code *); @@ -357,9 +431,29 @@ static int make_table(struct archive_read *, struct huffman_code *); static int make_table_recurse(struct archive_read *, struct huffman_code *, int, struct huffman_table_entry *, int, int); static int64_t expand(struct archive_read *, int64_t); -static int copy_from_lzss_window(struct archive_read *, const void **, - int64_t, int); +static int copy_from_lzss_window_to_unp(struct archive_read *, const void **, + int64_t, int); static const void *rar_read_ahead(struct archive_read *, size_t, ssize_t *); +static int parse_filter(struct archive_read *, const uint8_t *, uint16_t, + uint8_t); +static int run_filters(struct archive_read *); +static void clear_filters(struct rar_filters *); +static struct rar_filter *create_filter(struct rar_program_code *, + const uint8_t *, uint32_t, + uint32_t[8], size_t, uint32_t); +static void delete_filter(struct rar_filter *filter); +static struct rar_program_code *compile_program(const uint8_t *, size_t); +static void delete_program_code(struct rar_program_code *prog); +static uint32_t membr_next_rarvm_number(struct memory_bit_reader *br); +static inline uint32_t membr_bits(struct memory_bit_reader *br, int bits); +static int membr_fill(struct memory_bit_reader *br, int bits); +static int read_filter(struct archive_read *, int64_t *); +static int rar_decode_byte(struct archive_read*, uint8_t *); +static int execute_filter(struct archive_read*, struct rar_filter *, + struct rar_virtual_machine *, size_t); +static int copy_from_lzss_window(struct archive_read *, void *, int64_t, int); +static inline void vm_write_32(struct rar_virtual_machine*, size_t, uint32_t); +static inline uint32_t vm_read_32(struct rar_virtual_machine*, size_t); /* * Bit stream reader. @@ -958,17 +1052,17 @@ archive_read_format_rar_read_header(struct archive_read *a, crc32_val = 0; while (skip > 0) { size_t to_read = skip; - ssize_t did_read; - if (to_read > 32 * 1024) { + if (to_read > 32 * 1024) to_read = 32 * 1024; - } - if ((h = __archive_read_ahead(a, to_read, &did_read)) == NULL) { + if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Bad RAR file"); return (ARCHIVE_FATAL); } p = h; - crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned)did_read); - __archive_read_consume(a, did_read); - skip -= did_read; + crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read); + __archive_read_consume(a, to_read); + skip -= to_read; } if ((crc32_val & 0xffff) != crc32_expected) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -1244,6 +1338,7 @@ archive_read_format_rar_cleanup(struct archive_read *a) rar = (struct rar *)(a->format->data); free_codes(a); + clear_filters(&rar->filters); free(rar->filename); free(rar->filename_save); free(rar->dbo); @@ -1662,6 +1757,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, memset(rar->lengthtable, 0, sizeof(rar->lengthtable)); __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context); rar->ppmd_valid = rar->ppmd_eod = 0; + rar->filters.filterstart = INT64_MAX; /* Don't set any archive entries for non-file header types */ if (head_type == NEWSUB_HEAD) @@ -1886,7 +1982,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size, static int read_data_compressed(struct archive_read *a, const void **buff, size_t *size, - int64_t *offset, size_t looper) + int64_t *offset, size_t looper) { if (looper++ > MAX_COMPRESS_DEPTH) return (ARCHIVE_FATAL); @@ -1901,6 +1997,33 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, do { if (!rar->valid) return (ARCHIVE_FATAL); + + if (rar->filters.bytes_ready > 0) + { + /* Flush unp_buffer first */ + if (rar->unp_offset > 0) + { + *buff = rar->unp_buffer; + *size = rar->unp_offset; + rar->unp_offset = 0; + *offset = rar->offset_outgoing; + rar->offset_outgoing += *size; + } + else + { + *buff = rar->filters.bytes; + *size = rar->filters.bytes_ready; + + rar->offset += *size; + *offset = rar->offset_outgoing; + rar->offset_outgoing += *size; + + rar->filters.bytes_ready -= *size; + rar->filters.bytes += *size; + } + goto ending_block; + } + if (rar->ppmd_eod || (rar->dictionary_size && rar->offset >= rar->unp_size)) { @@ -1936,7 +2059,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, bs = rar->unp_buffer_size - rar->unp_offset; else bs = (size_t)rar->bytes_uncopied; - ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs); + ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs); if (ret != ARCHIVE_OK) return (ret); rar->offset += bs; @@ -1954,6 +2077,13 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, continue; } + if (rar->filters.lastend == rar->filters.filterstart) + { + if (!run_filters(a)) + return (ARCHIVE_FATAL); + continue; + } + if (!rar->br.next_in && (ret = rar_br_preparation(a, &(rar->br))) < ARCHIVE_WARN) return (ret); @@ -2045,13 +2175,16 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, { start = rar->offset; end = start + rar->dictionary_size; - rar->filterstart = INT64_MAX; + if (rar->filters.filterstart < end) { + end = rar->filters.filterstart; + } if ((actualend = expand(a, end)) < 0) return ((int)actualend); rar->bytes_uncopied = actualend - start; - if (rar->bytes_uncopied == 0) { + rar->filters.lastend = actualend; + if (rar->filters.lastend != rar->filters.filterstart && rar->bytes_uncopied == 0) { /* Broken RAR files cause this case. * NOTE: If this case were possible on a normal RAR file * we would find out where it was actually bad and @@ -2065,7 +2198,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, bs = rar->unp_buffer_size - rar->unp_offset; else bs = (size_t)rar->bytes_uncopied; - ret = copy_from_lzss_window(a, buff, rar->offset, (int)bs); + ret = copy_from_lzss_window_to_unp(a, buff, rar->offset, (int)bs); if (ret != ARCHIVE_OK) return (ret); rar->offset += bs; @@ -2080,6 +2213,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, *size = rar->unp_buffer_size; *offset = rar->offset_outgoing; rar->offset_outgoing += *size; +ending_block: /* Calculate File CRC. */ rar->crc_calculated = crc32(rar->crc_calculated, *buff, (unsigned)*size); return ret; @@ -2739,25 +2873,19 @@ expand(struct archive_read *a, int64_t end) struct rar *rar = (struct rar *)(a->format->data); struct rar_br *br = &(rar->br); - if (rar->filterstart < end) - end = rar->filterstart; + if (rar->filters.filterstart < end) + end = rar->filters.filterstart; while (1) { - if (rar->output_last_match && - lzss_position(&rar->lzss) + rar->lastlength <= end) - { - lzss_emit_match(rar, rar->lastoffset, rar->lastlength); - rar->output_last_match = 0; - } + if(lzss_position(&rar->lzss) >= end) + return end; - if(rar->is_ppmd_block || rar->output_last_match || - lzss_position(&rar->lzss) >= end) + if(rar->is_ppmd_block) return lzss_position(&rar->lzss); if ((symbol = read_next_symbol(a, &rar->maincode)) < 0) return (ARCHIVE_FATAL); - rar->output_last_match = 0; if (symbol < 256) { @@ -2789,9 +2917,9 @@ expand(struct archive_read *a, int64_t end) } else if(symbol==257) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Parsing filters is unsupported."); - return (ARCHIVE_FAILED); + if (!read_filter(a, &end)) + return (ARCHIVE_FATAL); + continue; } else if(symbol==258) { @@ -2864,7 +2992,7 @@ expand(struct archive_read *a, int64_t end) goto truncated_data; offs += rar_br_bits(br, offsetbits[offssymbol] - 4) << 4; rar_br_consume(br, offsetbits[offssymbol] - 4); - } + } if(rar->numlowoffsetrepeats > 0) { @@ -2908,7 +3036,8 @@ expand(struct archive_read *a, int64_t end) rar->lastoffset = offs; rar->lastlength = len; - rar->output_last_match = 1; + + lzss_emit_match(rar, rar->lastoffset, rar->lastlength); } truncated_data: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -2922,8 +3051,31 @@ bad_data: } static int -copy_from_lzss_window(struct archive_read *a, const void **buffer, - int64_t startpos, int length) +copy_from_lzss_window(struct archive_read *a, void *buffer, + int64_t startpos, int length) +{ + int windowoffs, firstpart; + struct rar *rar = (struct rar *)(a->format->data); + + windowoffs = lzss_offset_for_position(&rar->lzss, startpos); + firstpart = lzss_size(&rar->lzss) - windowoffs; + if (firstpart < 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Bad RAR file data"); + return (ARCHIVE_FATAL); + } + if (firstpart < length) { + memcpy(buffer, &rar->lzss.window[windowoffs], firstpart); + memcpy(buffer, &rar->lzss.window[0], length - firstpart); + } else { + memcpy(buffer, &rar->lzss.window[windowoffs], length); + } + return (ARCHIVE_OK); +} + +static int +copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer, + int64_t startpos, int length) { int windowoffs, firstpart; struct rar *rar = (struct rar *)(a->format->data); @@ -3003,3 +3155,599 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) } return h; } + +static int +parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint8_t flags) +{ + struct rar *rar = (struct rar *)(a->format->data); + struct rar_filters *filters = &rar->filters; + + struct memory_bit_reader br = { 0 }; + struct rar_program_code *prog; + struct rar_filter *filter, **nextfilter; + + uint32_t numprogs, num, blocklength, globaldatalen; + uint8_t *globaldata; + size_t blockstartpos; + uint32_t registers[8] = { 0 }; + uint32_t i; + + br.bytes = bytes; + br.length = length; + + numprogs = 0; + for (prog = filters->progs; prog; prog = prog->next) + numprogs++; + + if ((flags & 0x80)) + { + num = membr_next_rarvm_number(&br); + if (num == 0) + { + delete_filter(filters->stack); + filters->stack = NULL; + delete_program_code(filters->progs); + filters->progs = NULL; + } + else + num--; + if (num > numprogs) { + return 0; + } + filters->lastfilternum = num; + } + else + num = filters->lastfilternum; + + prog = filters->progs; + for (i = 0; i < num; i++) + prog = prog->next; + if (prog) + prog->usagecount++; + + blockstartpos = membr_next_rarvm_number(&br) + (size_t)lzss_position(&rar->lzss); + if ((flags & 0x40)) + blockstartpos += 258; + if ((flags & 0x20)) + blocklength = membr_next_rarvm_number(&br); + else + blocklength = prog ? prog->oldfilterlength : 0; + + registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS; + registers[4] = blocklength; + registers[5] = prog ? prog->usagecount : 0; + registers[7] = VM_MEMORY_SIZE; + + if ((flags & 0x10)) + { + uint8_t mask = (uint8_t)membr_bits(&br, 7); + for (i = 0; i < 7; i++) + if ((mask & (1 << i))) + registers[i] = membr_next_rarvm_number(&br); + } + + if (!prog) + { + uint32_t len = membr_next_rarvm_number(&br); + uint8_t *bytecode; + struct rar_program_code **next; + + if (len == 0 || len > 0x10000) + return 0; + bytecode = malloc(len); + if (!bytecode) + return 0; + for (i = 0; i < len; i++) + bytecode[i] = (uint8_t)membr_bits(&br, 8); + prog = compile_program(bytecode, len); + if (!prog) { + free(bytecode); + return 0; + } + free(bytecode); + next = &filters->progs; + while (*next) + next = &(*next)->next; + *next = prog; + } + prog->oldfilterlength = blocklength; + + globaldata = NULL; + globaldatalen = 0; + if ((flags & 0x08)) + { + globaldatalen = membr_next_rarvm_number(&br); + if (globaldatalen > PROGRAM_USER_GLOBAL_SIZE) + return 0; + globaldata = malloc(globaldatalen + PROGRAM_SYSTEM_GLOBAL_SIZE); + if (!globaldata) + return 0; + for (i = 0; i < globaldatalen; i++) + globaldata[i + PROGRAM_SYSTEM_GLOBAL_SIZE] = (uint8_t)membr_bits(&br, 8); + } + + if (br.at_eof) + { + free(globaldata); + return 0; + } + + filter = create_filter(prog, globaldata, globaldatalen, registers, blockstartpos, blocklength); + free(globaldata); + if (!filter) + return 0; + + for (i = 0; i < 7; i++) + archive_le32enc(&filter->globaldata[i * 4], registers[i]); + archive_le32enc(&filter->globaldata[0x1C], blocklength); + archive_le32enc(&filter->globaldata[0x20], 0); + archive_le32enc(&filter->globaldata[0x2C], prog->usagecount); + + nextfilter = &filters->stack; + while (*nextfilter) + nextfilter = &(*nextfilter)->next; + *nextfilter = filter; + + if (!filters->stack->next) + filters->filterstart = blockstartpos; + + return 1; +} + +static struct rar_filter * +create_filter(struct rar_program_code *prog, const uint8_t *globaldata, uint32_t globaldatalen, uint32_t registers[8], size_t startpos, uint32_t length) +{ + struct rar_filter *filter; + + filter = calloc(1, sizeof(*filter)); + if (!filter) + return NULL; + filter->prog = prog; + filter->globaldatalen = globaldatalen > PROGRAM_SYSTEM_GLOBAL_SIZE ? globaldatalen : PROGRAM_SYSTEM_GLOBAL_SIZE; + filter->globaldata = calloc(1, filter->globaldatalen); + if (!filter->globaldata) + return NULL; + if (globaldata) + memcpy(filter->globaldata, globaldata, globaldatalen); + if (registers) + memcpy(filter->initialregisters, registers, sizeof(filter->initialregisters)); + filter->blockstartpos = startpos; + filter->blocklength = length; + + return filter; +} + +static int +run_filters(struct archive_read *a) +{ + struct rar *rar = (struct rar *)(a->format->data); + struct rar_filters *filters = &rar->filters; + struct rar_filter *filter = filters->stack; + size_t start = filters->filterstart; + size_t end = start + filter->blocklength; + uint32_t lastfilteraddress; + uint32_t lastfilterlength; + int ret; + + filters->filterstart = INT64_MAX; + end = (size_t)expand(a, end); + if (end != start + filter->blocklength) + return 0; + + if (!filters->vm) + { + filters->vm = calloc(1, sizeof(*filters->vm)); + if (!filters->vm) + return 0; + } + + ret = copy_from_lzss_window(a, filters->vm->memory, start, filter->blocklength); + if (ret != ARCHIVE_OK) + return 0; + if (!execute_filter(a, filter, filters->vm, rar->offset)) + return 0; + + lastfilteraddress = filter->filteredblockaddress; + lastfilterlength = filter->filteredblocklength; + filters->stack = filter->next; + filter->next = NULL; + delete_filter(filter); + + while ((filter = filters->stack) != NULL && (int64_t)filter->blockstartpos == filters->filterstart && filter->blocklength == lastfilterlength) + { + memmove(&filters->vm->memory[0], &filters->vm->memory[lastfilteraddress], lastfilterlength); + if (!execute_filter(a, filter, filters->vm, rar->offset)) + return 0; + + lastfilteraddress = filter->filteredblockaddress; + lastfilterlength = filter->filteredblocklength; + filters->stack = filter->next; + filter->next = NULL; + delete_filter(filter); + } + + if (filters->stack) + { + if (filters->stack->blockstartpos < end) + return 0; + filters->filterstart = filters->stack->blockstartpos; + } + + filters->lastend = end; + filters->bytes = &filters->vm->memory[lastfilteraddress]; + filters->bytes_ready = lastfilterlength; + + return 1; +} + +static struct rar_program_code * +compile_program(const uint8_t *bytes, size_t length) +{ + struct memory_bit_reader br = { 0 }; + struct rar_program_code *prog; + // uint32_t instrcount = 0; + uint8_t xor; + size_t i; + + xor = 0; + for (i = 1; i < length; i++) + xor ^= bytes[i]; + if (!length || xor != bytes[0]) + return NULL; + + br.bytes = bytes; + br.length = length; + br.offset = 1; + + prog = calloc(1, sizeof(*prog)); + if (!prog) + return NULL; + prog->fingerprint = crc32(0, bytes, length) | ((uint64_t)length << 32); + + if (membr_bits(&br, 1)) + { + prog->staticdatalen = membr_next_rarvm_number(&br) + 1; + prog->staticdata = malloc(prog->staticdatalen); + if (!prog->staticdata) + { + delete_program_code(prog); + return NULL; + } + for (i = 0; i < prog->staticdatalen; i++) + prog->staticdata[i] = (uint8_t)membr_bits(&br, 8); + } + + return prog; +} + +static void +delete_filter(struct rar_filter *filter) +{ + while (filter) + { + struct rar_filter *next = filter->next; + free(filter->globaldata); + free(filter); + filter = next; + } +} + +static void +clear_filters(struct rar_filters *filters) +{ + delete_filter(filters->stack); + delete_program_code(filters->progs); + free(filters->vm); +} + +static void +delete_program_code(struct rar_program_code *prog) +{ + while (prog) + { + struct rar_program_code *next = prog->next; + free(prog->staticdata); + free(prog->globalbackup); + free(prog); + prog = next; + } +} + +static uint32_t +membr_next_rarvm_number(struct memory_bit_reader *br) +{ + uint32_t val; + switch (membr_bits(br, 2)) + { + case 0: + return membr_bits(br, 4); + case 1: + val = membr_bits(br, 8); + if (val >= 16) + return val; + return 0xFFFFFF00 | (val << 4) | membr_bits(br, 4); + case 2: + return membr_bits(br, 16); + default: + return membr_bits(br, 32); + } +} + +static inline uint32_t +membr_bits(struct memory_bit_reader *br, int bits) +{ + if (bits > br->available && (br->at_eof || !membr_fill(br, bits))) + return 0; + return (uint32_t)((br->bits >> (br->available -= bits)) & (((uint64_t)1 << bits) - 1)); +} + +static int +membr_fill(struct memory_bit_reader *br, int bits) +{ + while (br->available < bits && br->offset < br->length) + { + br->bits = (br->bits << 8) | br->bytes[br->offset++]; + br->available += 8; + } + if (bits > br->available) + { + br->at_eof = 1; + return 0; + } + return 1; +} + +static int +read_filter(struct archive_read *a, int64_t *end) +{ + struct rar *rar = (struct rar *)(a->format->data); + uint8_t flags, val, *code; + uint16_t length, i; + + if (!rar_decode_byte(a, &flags)) + return 0; + length = (flags & 0x07) + 1; + if (length == 7) + { + if (!rar_decode_byte(a, &val)) + return 0; + length = val + 7; + } + else if (length == 8) + { + if (!rar_decode_byte(a, &val)) + return 0; + length = val << 8; + if (!rar_decode_byte(a, &val)) + return 0; + length |= val; + } + + code = malloc(length); + if (!code) + return 0; + for (i = 0; i < length; i++) + { + if (!rar_decode_byte(a, &code[i])) + { + free(code); + return 0; + } + } + if (!parse_filter(a, code, length, flags)) + { + free(code); + return 0; + } + free(code); + + if (rar->filters.filterstart < *end) + *end = rar->filters.filterstart; + + return 1; +} + +static int +execute_filter_delta(struct rar_filter *filter, struct rar_virtual_machine *vm) +{ + uint32_t length = filter->initialregisters[4]; + uint32_t numchannels = filter->initialregisters[0]; + uint8_t *src, *dst; + uint32_t i, idx; + + if (length > PROGRAM_WORK_SIZE / 2) + return 0; + + src = &vm->memory[0]; + dst = &vm->memory[length]; + for (i = 0; i < numchannels; i++) + { + uint8_t lastbyte = 0; + for (idx = i; idx < length; idx += numchannels) + lastbyte = dst[idx] = lastbyte - *src++; + } + + filter->filteredblockaddress = length; + filter->filteredblocklength = length; + + return 1; +} + +static int +execute_filter_e8(struct rar_filter *filter, struct rar_virtual_machine *vm, size_t pos, int e9also) +{ + uint32_t length = filter->initialregisters[4]; + uint32_t filesize = 0x1000000; + uint32_t i; + + if (length > PROGRAM_WORK_SIZE || length < 4) + return 0; + + for (i = 0; i <= length - 5; i++) + { + if (vm->memory[i] == 0xE8 || (e9also && vm->memory[i] == 0xE9)) + { + uint32_t currpos = (uint32_t)pos + i + 1; + int32_t address = (int32_t)vm_read_32(vm, i + 1); + if (address < 0 && currpos >= (uint32_t)-address) + vm_write_32(vm, i + 1, address + filesize); + else if (address >= 0 && (uint32_t)address < filesize) + vm_write_32(vm, i + 1, address - currpos); + i += 4; + } + } + + filter->filteredblockaddress = 0; + filter->filteredblocklength = length; + + return 1; +} + +static int +execute_filter_rgb(struct rar_filter *filter, struct rar_virtual_machine *vm) +{ + uint32_t stride = filter->initialregisters[0]; + uint32_t byteoffset = filter->initialregisters[1]; + uint32_t blocklength = filter->initialregisters[4]; + uint8_t *src, *dst; + uint32_t i, j; + + if (blocklength > PROGRAM_WORK_SIZE / 2 || stride > blocklength) + return 0; + + src = &vm->memory[0]; + dst = &vm->memory[blocklength]; + for (i = 0; i < 3; i++) { + uint8_t byte = 0; + uint8_t *prev = dst + i - stride; + for (j = i; j < blocklength; j += 3) + { + if (prev >= dst) + { + uint32_t delta1 = abs(prev[3] - prev[0]); + uint32_t delta2 = abs(byte - prev[0]); + uint32_t delta3 = abs(prev[3] - prev[0] + byte - prev[0]); + if (delta1 > delta2 || delta1 > delta3) + byte = delta2 <= delta3 ? prev[3] : prev[0]; + } + byte -= *src++; + dst[j] = byte; + prev += 3; + } + } + for (i = byteoffset; i < blocklength - 2; i += 3) + { + dst[i] += dst[i + 1]; + dst[i + 2] += dst[i + 1]; + } + + filter->filteredblockaddress = blocklength; + filter->filteredblocklength = blocklength; + + return 1; +} + +static int +execute_filter_audio(struct rar_filter *filter, struct rar_virtual_machine *vm) +{ + uint32_t length = filter->initialregisters[4]; + uint32_t numchannels = filter->initialregisters[0]; + uint8_t *src, *dst; + uint32_t i, j; + + if (length > PROGRAM_WORK_SIZE / 2) + return 0; + + src = &vm->memory[0]; + dst = &vm->memory[length]; + for (i = 0; i < numchannels; i++) + { + struct audio_state state; + memset(&state, 0, sizeof(state)); + for (j = i; j < length; j += numchannels) + { + int8_t delta = (int8_t)*src++; + uint8_t predbyte, byte; + int prederror; + state.delta[2] = state.delta[1]; + state.delta[1] = state.lastdelta - state.delta[0]; + state.delta[0] = state.lastdelta; + predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF; + byte = (predbyte - delta) & 0xFF; + prederror = delta << 3; + state.error[0] += abs(prederror); + state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]); + state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]); + state.error[5] += abs(prederror - state.delta[2]); state.error[6] += abs(prederror + state.delta[2]); + state.lastdelta = (int8_t)(byte - state.lastbyte); + dst[j] = state.lastbyte = byte; + if (!(state.count++ & 0x1F)) + { + uint8_t k, idx = 0; + for (k = 1; k < 7; k++) + { + if (state.error[k] < state.error[idx]) + idx = k; + } + memset(state.error, 0, sizeof(state.error)); + switch (idx) + { + case 1: if (state.weight[0] >= -16) state.weight[0]--; break; + case 2: if (state.weight[0] < 16) state.weight[0]++; break; + case 3: if (state.weight[1] >= -16) state.weight[1]--; break; + case 4: if (state.weight[1] < 16) state.weight[1]++; break; + case 5: if (state.weight[2] >= -16) state.weight[2]--; break; + case 6: if (state.weight[2] < 16) state.weight[2]++; break; + } + } + } + } + + filter->filteredblockaddress = length; + filter->filteredblocklength = length; + + return 1; +} + + +static int +execute_filter(struct archive_read *a, struct rar_filter *filter, struct rar_virtual_machine *vm, size_t pos) +{ + if (filter->prog->fingerprint == 0x1D0E06077D) + return execute_filter_delta(filter, vm); + if (filter->prog->fingerprint == 0x35AD576887) + return execute_filter_e8(filter, vm, pos, 0); + if (filter->prog->fingerprint == 0x393CD7E57E) + return execute_filter_e8(filter, vm, pos, 1); + if (filter->prog->fingerprint == 0x951C2C5DC8) + return execute_filter_rgb(filter, vm); + if (filter->prog->fingerprint == 0xD8BC85E701) + return execute_filter_audio(filter, vm); + + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "No support for RAR VM program filter"); + return 0; +} + +static int +rar_decode_byte(struct archive_read *a, uint8_t *byte) +{ + struct rar *rar = (struct rar *)(a->format->data); + struct rar_br *br = &(rar->br); + if (!rar_br_read_ahead(a, br, 8)) + return 0; + *byte = (uint8_t)rar_br_bits(br, 8); + rar_br_consume(br, 8); + return 1; +} + +static inline void +vm_write_32(struct rar_virtual_machine* vm, size_t offset, uint32_t u32) +{ + archive_le32enc(vm->memory + offset, u32); +} + +static inline uint32_t +vm_read_32(struct rar_virtual_machine* vm, size_t offset) +{ + return archive_le32dec(vm->memory + offset); +} diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c index 3131955..8850c93 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar5.c @@ -632,7 +632,7 @@ static int run_arm_filter(struct rar5* rar, struct filter_info* flt) { /* 0xEB = ARM's BL (branch + link) instruction. */ offset = read_filter_data(rar, (rar->cstate.solid_offset + flt->block_start + i) & - rar->cstate.window_mask) & 0x00ffffff; + (uint32_t)rar->cstate.window_mask) & 0x00ffffff; offset -= (uint32_t) ((i + flt->block_start) / 4); offset = (offset & 0x00ffffff) | 0xeb000000; @@ -1012,7 +1012,16 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue, return ret; } -static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) { +static int read_bits_32(struct archive_read* a, struct rar5* rar, + const uint8_t* p, uint32_t* value) +{ + if(rar->bits.in_addr >= rar->cstate.cur_block_size) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_PROGRAMMER, + "Premature end of stream during extraction of data (#1)"); + return ARCHIVE_FATAL; + } + uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24; bits |= p[rar->bits.in_addr + 1] << 16; bits |= p[rar->bits.in_addr + 2] << 8; @@ -1023,7 +1032,16 @@ static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) { return ARCHIVE_OK; } -static int read_bits_16(struct rar5* rar, const uint8_t* p, uint16_t* value) { +static int read_bits_16(struct archive_read* a, struct rar5* rar, + const uint8_t* p, uint16_t* value) +{ + if(rar->bits.in_addr >= rar->cstate.cur_block_size) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_PROGRAMMER, + "Premature end of stream during extraction of data (#2)"); + return ARCHIVE_FATAL; + } + int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16; bits |= (int) p[rar->bits.in_addr + 1] << 8; bits |= (int) p[rar->bits.in_addr + 2]; @@ -1039,8 +1057,8 @@ static void skip_bits(struct rar5* rar, int bits) { } /* n = up to 16 */ -static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n, - int* value) +static int read_consume_bits(struct archive_read* a, struct rar5* rar, + const uint8_t* p, int n, int* value) { uint16_t v; int ret, num; @@ -1051,7 +1069,7 @@ static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n, return ARCHIVE_FATAL; } - ret = read_bits_16(rar, p, &v); + ret = read_bits_16(a, rar, p, &v); if(ret != ARCHIVE_OK) return ret; @@ -1099,6 +1117,44 @@ static int bid_standard(struct archive_read* a) { return -1; } +static int bid_sfx(struct archive_read *a) +{ + const char *p; + + if ((p = __archive_read_ahead(a, 7, NULL)) == NULL) + return -1; + + if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) { + /* This is a PE file */ + char signature[sizeof(rar5_signature_xor)]; + ssize_t offset = 0x10000; + ssize_t window = 4096; + ssize_t bytes_avail; + + rar5_signature(signature); + + while (offset + window <= (1024 * 512)) { + const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail); + if (buff == NULL) { + /* Remaining bytes are less than window. */ + window >>= 1; + if (window < 0x40) + return 0; + continue; + } + p = buff + offset; + while (p + 8 < buff + bytes_avail) { + if (memcmp(p, signature, sizeof(signature)) == 0) + return 30; + p += 0x10; + } + offset = p - buff; + } + } + + return 0; +} + static int rar5_bid(struct archive_read* a, int best_bid) { int my_bid; @@ -1109,6 +1165,10 @@ static int rar5_bid(struct archive_read* a, int best_bid) { if(my_bid > -1) { return my_bid; } + my_bid = bid_sfx(a); + if (my_bid > -1) { + return my_bid; + } return -1; } @@ -1712,14 +1772,29 @@ static int process_head_file(struct archive_read* a, struct rar5* rar, } } - /* If we're currently switching volumes, ignore the new definition of - * window_size. */ - if(rar->cstate.switch_multivolume == 0) { - /* Values up to 64M should fit into ssize_t on every - * architecture. */ - rar->cstate.window_size = (ssize_t) window_size; + if(rar->cstate.window_size < (ssize_t) window_size && + rar->cstate.window_buf) + { + /* If window_buf has been allocated before, reallocate it, so + * that its size will match new window_size. */ + + uint8_t* new_window_buf = + realloc(rar->cstate.window_buf, window_size); + + if(!new_window_buf) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Not enough memory when trying to realloc the window " + "buffer."); + return ARCHIVE_FATAL; + } + + rar->cstate.window_buf = new_window_buf; } + /* Values up to 64M should fit into ssize_t on every + * architecture. */ + rar->cstate.window_size = (ssize_t) window_size; + if(rar->file.solid > 0 && rar->file.solid_window_size == 0) { /* Solid files have to have the same window_size across whole archive. Remember the window_size parameter @@ -2273,6 +2348,62 @@ static int skip_base_block(struct archive_read* a) { return ret; } +static int try_skip_sfx(struct archive_read *a) +{ + const char *p; + + if ((p = __archive_read_ahead(a, 7, NULL)) == NULL) + return ARCHIVE_EOF; + + if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) + { + char signature[sizeof(rar5_signature_xor)]; + const void *h; + const char *q; + size_t skip, total = 0; + ssize_t bytes, window = 4096; + + rar5_signature(signature); + + while (total + window <= (1024 * 512)) { + h = __archive_read_ahead(a, window, &bytes); + if (h == NULL) { + /* Remaining bytes are less than window. */ + window >>= 1; + if (window < 0x40) + goto fatal; + continue; + } + if (bytes < 0x40) + goto fatal; + p = h; + q = p + bytes; + + /* + * Scan ahead until we find something that looks + * like the RAR header. + */ + while (p + 8 < q) { + if (memcmp(p, signature, sizeof(signature)) == 0) { + skip = p - (const char *)h; + __archive_read_consume(a, skip); + return (ARCHIVE_OK); + } + p += 0x10; + } + skip = p - (const char *)h; + __archive_read_consume(a, skip); + total += skip; + } + } + + return ARCHIVE_OK; +fatal: + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Couldn't find out RAR header"); + return (ARCHIVE_FATAL); +} + static int rar5_read_header(struct archive_read *a, struct archive_entry *entry) { @@ -2281,6 +2412,8 @@ static int rar5_read_header(struct archive_read *a, if(rar->header_initialized == 0) { init_header(a); + if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN) + return ret; rar->header_initialized = 1; } @@ -2425,13 +2558,13 @@ static int create_decode_tables(uint8_t* bit_length, static int decode_number(struct archive_read* a, struct decode_table* table, const uint8_t* p, uint16_t* num) { - int i, bits, dist; + int i, bits, dist, ret; uint16_t bitfield; uint32_t pos; struct rar5* rar = get_context(a); - if(ARCHIVE_OK != read_bits_16(rar, p, &bitfield)) { - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) { + return ret; } bitfield &= 0xfffe; @@ -2537,14 +2670,6 @@ static int parse_tables(struct archive_read* a, struct rar5* rar, for(i = 0; i < HUFF_TABLE_SIZE;) { uint16_t num; - if((rar->bits.in_addr + 6) >= rar->cstate.cur_block_size) { - /* Truncated data, can't continue. */ - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Truncated data in huffman tables (#2)"); - return ARCHIVE_FATAL; - } - ret = decode_number(a, &rar->cstate.bd, p, &num); if(ret != ARCHIVE_OK) { archive_set_error(&a->archive, @@ -2561,8 +2686,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar, /* 16..17: repeat previous code */ uint16_t n; - if(ARCHIVE_OK != read_bits_16(rar, p, &n)) - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n))) + return ret; if(num == 16) { n >>= 13; @@ -2590,8 +2715,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar, /* other codes: fill with zeroes `n` times */ uint16_t n; - if(ARCHIVE_OK != read_bits_16(rar, p, &n)) - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n))) + return ret; if(num == 18) { n >>= 13; @@ -2707,22 +2832,22 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p, } /* Convenience function used during filter processing. */ -static int parse_filter_data(struct rar5* rar, const uint8_t* p, - uint32_t* filter_data) +static int parse_filter_data(struct archive_read* a, struct rar5* rar, + const uint8_t* p, uint32_t* filter_data) { - int i, bytes; + int i, bytes, ret; uint32_t data = 0; - if(ARCHIVE_OK != read_consume_bits(rar, p, 2, &bytes)) - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes))) + return ret; bytes++; for(i = 0; i < bytes; i++) { uint16_t byte; - if(ARCHIVE_OK != read_bits_16(rar, p, &byte)) { - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) { + return ret; } /* Cast to uint32_t will ensure the shift operation will not @@ -2765,16 +2890,17 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) { uint16_t filter_type; struct filter_info* filt = NULL; struct rar5* rar = get_context(ar); + int ret; /* Read the parameters from the input stream. */ - if(ARCHIVE_OK != parse_filter_data(rar, p, &block_start)) - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start))) + return ret; - if(ARCHIVE_OK != parse_filter_data(rar, p, &block_length)) - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length))) + return ret; - if(ARCHIVE_OK != read_bits_16(rar, p, &filter_type)) - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type))) + return ret; filter_type >>= 13; skip_bits(rar, 3); @@ -2814,8 +2940,8 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) { if(filter_type == FILTER_DELTA) { int channels; - if(ARCHIVE_OK != read_consume_bits(rar, p, 5, &channels)) - return ARCHIVE_EOF; + if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels))) + return ret; filt->channels = channels + 1; } @@ -2823,10 +2949,11 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) { return ARCHIVE_OK; } -static int decode_code_length(struct rar5* rar, const uint8_t* p, - uint16_t code) +static int decode_code_length(struct archive_read* a, struct rar5* rar, + const uint8_t* p, uint16_t code) { int lbits, length = 2; + if(code < 8) { lbits = 0; length += code; @@ -2838,7 +2965,7 @@ static int decode_code_length(struct rar5* rar, const uint8_t* p, if(lbits > 0) { int add; - if(ARCHIVE_OK != read_consume_bits(rar, p, lbits, &add)) + if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add)) return -1; length += add; @@ -2933,7 +3060,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) { continue; } else if(num >= 262) { uint16_t dist_slot; - int len = decode_code_length(rar, p, num - 262), + int len = decode_code_length(a, rar, p, num - 262), dbits, dist = 1; @@ -2975,12 +3102,12 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) { uint16_t low_dist; if(dbits > 4) { - if(ARCHIVE_OK != read_bits_32( - rar, p, &add)) { + if(ARCHIVE_OK != (ret = read_bits_32( + a, rar, p, &add))) { /* Return EOF if we * can't read more * data. */ - return ARCHIVE_EOF; + return ret; } skip_bits(rar, dbits - 4); @@ -3015,11 +3142,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) { /* dbits is one of [0,1,2,3] */ int add; - if(ARCHIVE_OK != read_consume_bits(rar, - p, dbits, &add)) { + if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, + p, dbits, &add))) { /* Return EOF if we can't read * more data. */ - return ARCHIVE_EOF; + return ret; } dist += add; @@ -3076,7 +3203,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) { return ARCHIVE_FATAL; } - len = decode_code_length(rar, p, len_slot); + len = decode_code_length(a, rar, p, len_slot); + if (len == -1) { + return ARCHIVE_FATAL; + } + rar->cstate.last_len = len; if(ARCHIVE_OK != copy_string(a, len, dist)) @@ -3600,6 +3731,16 @@ static int do_uncompress_file(struct archive_read* a) { rar->cstate.initialized = 1; } + /* Don't allow extraction if window_size is invalid. */ + if(rar->cstate.window_size == 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Invalid window size declaration in this file"); + + /* This should never happen in valid files. */ + return ARCHIVE_FATAL; + } + if(rar->cstate.all_filters_applied == 1) { /* We use while(1) here, but standard case allows for just 1 * iteration. The loop will iterate if process_block() didn't @@ -4076,6 +4217,7 @@ int archive_read_support_format_rar5(struct archive *_a) { if(ARCHIVE_OK != rar5_init(rar)) { archive_set_error(&ar->archive, ENOMEM, "Can't allocate rar5 filter buffer"); + free(rar); return ARCHIVE_FATAL; } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c index 96d8101..bfdad7f 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c @@ -573,11 +573,15 @@ archive_read_format_tar_read_header(struct archive_read *a, l = wcslen(wp); if (l > 0 && wp[l - 1] == L'/') { archive_entry_set_filetype(entry, AE_IFDIR); + tar->entry_bytes_remaining = 0; + tar->entry_padding = 0; } } else if ((p = archive_entry_pathname(entry)) != NULL) { l = strlen(p); if (l > 0 && p[l - 1] == '/') { archive_entry_set_filetype(entry, AE_IFDIR); + tar->entry_bytes_remaining = 0; + tar->entry_padding = 0; } } } @@ -1396,6 +1400,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, struct archive_entry *entry, const void *h, size_t *unconsumed) { int64_t size; + size_t msize; const void *data; const char *p, *name; const wchar_t *wp, *wname; @@ -1434,6 +1439,11 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, /* Read the body as a Mac OS metadata blob. */ size = archive_entry_size(entry); + msize = (size_t)size; + if (size < 0 || (uintmax_t)msize != (uintmax_t)size) { + *unconsumed = 0; + return (ARCHIVE_FATAL); + } /* * TODO: Look beyond the body here to peek at the next header. @@ -1447,13 +1457,13 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar, * Q: Is the above idea really possible? Even * when there are GNU or pax extension entries? */ - data = __archive_read_ahead(a, (size_t)size, NULL); + data = __archive_read_ahead(a, msize, NULL); if (data == NULL) { *unconsumed = 0; return (ARCHIVE_FATAL); } - archive_entry_copy_mac_metadata(entry, data, (size_t)size); - *unconsumed = (size_t)((size + 511) & ~ 511); + archive_entry_copy_mac_metadata(entry, data, msize); + *unconsumed = (msize + 511) & ~ 511; tar_flush_unconsumed(a, unconsumed); return (tar_read_header(a, tar, entry, unconsumed)); } @@ -1906,7 +1916,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, } if (strcmp(key, "GNU.sparse.numbytes") == 0) { tar->sparse_numbytes = tar_atol10(value, strlen(value)); - if (tar->sparse_numbytes != -1) { + if (tar->sparse_offset != -1) { if (gnu_add_sparse_entry(a, tar, tar->sparse_offset, tar->sparse_numbytes) != ARCHIVE_OK) @@ -2643,14 +2653,14 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base) maxval = INT64_MIN; limit = -(INT64_MIN / base); - last_digit_limit = INT64_MIN % base; + last_digit_limit = -(INT64_MIN % base); } l = 0; if (char_cnt != 0) { digit = *p - '0'; while (digit >= 0 && digit < base && char_cnt != 0) { - if (l>limit || (l == limit && digit > last_digit_limit)) { + if (l>limit || (l == limit && digit >= last_digit_limit)) { return maxval; /* Truncate on overflow. */ } l = (l * base) + digit; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c index 6314c68..7e99367 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c @@ -58,6 +58,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102 #ifdef HAVE_LZMA_H #include <cm3p/lzma.h> #endif +#ifdef HAVE_ZSTD_H +#include <zstd.h> +#endif #include "archive.h" #include "archive_digest_private.h" @@ -142,6 +145,7 @@ struct zip { /* Structural information about the archive. */ struct archive_string format_name; int64_t central_directory_offset; + int64_t central_directory_offset_adjusted; size_t central_directory_entries_total; size_t central_directory_entries_on_this_disk; int has_encrypted_entries; @@ -190,6 +194,11 @@ struct zip { char bzstream_valid; #endif +#if HAVE_ZSTD_H && HAVE_LIBZSTD + ZSTD_DStream *zstdstream; + char zstdstream_valid; +#endif + IByteIn zipx_ppmd_stream; ssize_t zipx_ppmd_read_compressed; CPpmd8 ppmd8; @@ -246,6 +255,17 @@ struct zip { /* Many systems define min or MIN, but not all. */ #define zipmin(a,b) ((a) < (b) ? (a) : (b)) +#ifdef HAVE_ZLIB_H +static int +zip_read_data_deflate(struct archive_read *a, const void **buff, + size_t *size, int64_t *offset); +#endif +#if HAVE_LZMA_H && HAVE_LIBLZMA +static int +zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff, + size_t *size, int64_t *offset); +#endif + /* This function is used by Ppmd8_DecodeSymbol during decompression of Ppmd8 * streams inside ZIP files. It has 2 purposes: one is to fetch the next * compressed byte from the stream, second one is to increase the counter how @@ -423,6 +443,7 @@ static const struct { {17, "reserved"}, /* Reserved by PKWARE */ {18, "ibm-terse-new"}, /* File is compressed using IBM TERSE (new) */ {19, "ibm-lz777"},/* IBM LZ77 z Architecture (PFS) */ + {93, "zstd"}, /* Zstandard (zstd) Compression */ {95, "xz"}, /* XZ compressed data */ {96, "jpeg"}, /* JPEG compressed data */ {97, "wav-pack"}, /* WavPack compressed data */ @@ -899,81 +920,6 @@ process_extra(struct archive_read *a, struct archive_entry *entry, return ARCHIVE_OK; } -#if HAVE_LZMA_H && HAVE_LIBLZMA -/* - * Auxiliary function to uncompress data chunk from zipx archive - * (zip with lzma compression). - */ -static int -zipx_lzma_uncompress_buffer(const char *compressed_buffer, - size_t compressed_buffer_size, - char *uncompressed_buffer, - size_t uncompressed_buffer_size) -{ - int status = ARCHIVE_FATAL; - // length of 'lzma properties data' in lzma compressed - // data segment (stream) inside zip archive - const size_t lzma_params_length = 5; - // offset of 'lzma properties data' from the beginning of lzma stream - const size_t lzma_params_offset = 4; - // end position of 'lzma properties data' in lzma stream - const size_t lzma_params_end = lzma_params_offset + lzma_params_length; - if (compressed_buffer == NULL || - compressed_buffer_size < lzma_params_end || - uncompressed_buffer == NULL) - return status; - - // prepare header for lzma_alone_decoder to replace zipx header - // (see comments in 'zipx_lzma_alone_init' for justification) -#pragma pack(push) -#pragma pack(1) - struct _alone_header - { - uint8_t bytes[5]; // lzma_params_length - uint64_t uncompressed_size; - } alone_header; -#pragma pack(pop) - // copy 'lzma properties data' blob - memcpy(&alone_header.bytes[0], compressed_buffer + lzma_params_offset, - lzma_params_length); - alone_header.uncompressed_size = UINT64_MAX; - - // prepare new compressed buffer, see 'zipx_lzma_alone_init' for details - const size_t lzma_alone_buffer_size = - compressed_buffer_size - lzma_params_end + sizeof(alone_header); - unsigned char *lzma_alone_compressed_buffer = - (unsigned char*) malloc(lzma_alone_buffer_size); - if (lzma_alone_compressed_buffer == NULL) - return status; - // copy lzma_alone header into new buffer - memcpy(lzma_alone_compressed_buffer, (void*) &alone_header, - sizeof(alone_header)); - // copy compressed data into new buffer - memcpy(lzma_alone_compressed_buffer + sizeof(alone_header), - compressed_buffer + lzma_params_end, - compressed_buffer_size - lzma_params_end); - - // create and fill in lzma_alone_decoder stream - lzma_stream stream = LZMA_STREAM_INIT; - lzma_ret ret = lzma_alone_decoder(&stream, UINT64_MAX); - if (ret == LZMA_OK) - { - stream.next_in = lzma_alone_compressed_buffer; - stream.avail_in = lzma_alone_buffer_size; - stream.total_in = 0; - stream.next_out = (unsigned char*)uncompressed_buffer; - stream.avail_out = uncompressed_buffer_size; - stream.total_out = 0; - ret = lzma_code(&stream, LZMA_RUN); - if (ret == LZMA_OK || ret == LZMA_STREAM_END) - status = ARCHIVE_OK; - } - lzma_end(&stream); - free(lzma_alone_compressed_buffer); - return status; -} -#endif - /* * Assumes file pointer is at beginning of local file header. */ @@ -1207,7 +1153,8 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, (intmax_t)zip_entry->compressed_size); ret = ARCHIVE_WARN; } - if (zip_entry->uncompressed_size == 0) { + if (zip_entry->uncompressed_size == 0 || + zip_entry->uncompressed_size == 0xffffffff) { zip_entry->uncompressed_size = zip_entry_central_dir.uncompressed_size; } else if (zip_entry->uncompressed_size @@ -1242,36 +1189,30 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, linkname_length = (size_t)zip_entry->compressed_size; archive_entry_set_size(entry, 0); - p = __archive_read_ahead(a, linkname_length, NULL); - if (p == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Truncated Zip file"); - return ARCHIVE_FATAL; - } + // take into account link compression if any size_t linkname_full_length = linkname_length; if (zip->entry->compression != 0) { // symlink target string appeared to be compressed int status = ARCHIVE_FATAL; - char *uncompressed_buffer = - (char*) malloc(zip_entry->uncompressed_size); - if (uncompressed_buffer == NULL) - { - archive_set_error(&a->archive, ENOMEM, - "No memory for lzma decompression"); - return status; - } + const void *uncompressed_buffer = NULL; switch (zip->entry->compression) { +#if HAVE_ZLIB_H + case 8: /* Deflate compression. */ + zip->entry_bytes_remaining = zip_entry->compressed_size; + status = zip_read_data_deflate(a, &uncompressed_buffer, + &linkname_full_length, NULL); + break; +#endif #if HAVE_LZMA_H && HAVE_LIBLZMA case 14: /* ZIPx LZMA compression. */ /*(see zip file format specification, section 4.4.5)*/ - status = zipx_lzma_uncompress_buffer(p, - linkname_length, - uncompressed_buffer, - (size_t)zip_entry->uncompressed_size); + zip->entry_bytes_remaining = zip_entry->compressed_size; + status = zip_read_data_zipx_lzma_alone(a, &uncompressed_buffer, + &linkname_full_length, NULL); break; #endif default: /* Unsupported compression. */ @@ -1280,8 +1221,6 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, if (status == ARCHIVE_OK) { p = uncompressed_buffer; - linkname_full_length = - (size_t)zip_entry->uncompressed_size; } else { @@ -1294,6 +1233,16 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, return ARCHIVE_FAILED; } } + else + { + p = __archive_read_ahead(a, linkname_length, NULL); + } + + if (p == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Truncated Zip file"); + return ARCHIVE_FATAL; + } sconv = zip->sconv; if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME)) @@ -1663,7 +1612,8 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip) /* To unpack ZIPX's "LZMA" (id 14) stream we can use standard liblzma * that is a part of XZ Utils. The stream format stored inside ZIPX * file is a modified "lzma alone" file format, that was used by the - * `lzma` utility which was later deprecated in favour of `xz` utility. * Since those formats are nearly the same, we can use a standard + * `lzma` utility which was later deprecated in favour of `xz` utility. + * Since those formats are nearly the same, we can use a standard * "lzma alone" decoder from XZ Utils. */ memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream)); @@ -2298,6 +2248,140 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff, #endif +#if HAVE_ZSTD_H && HAVE_LIBZSTD +static int +zipx_zstd_init(struct archive_read *a, struct zip *zip) +{ + size_t r; + + /* Deallocate already existing Zstd decompression context if it + * exists. */ + if(zip->zstdstream_valid) { + ZSTD_freeDStream(zip->zstdstream); + zip->zstdstream_valid = 0; + } + + /* Allocate a new Zstd decompression context. */ + zip->zstdstream = ZSTD_createDStream(); + + r = ZSTD_initDStream(zip->zstdstream); + if (ZSTD_isError(r)) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Error initializing zstd decompressor: %s", + ZSTD_getErrorName(r)); + + return ARCHIVE_FAILED; + } + + /* Mark the zstdstream field to be released in cleanup phase. */ + zip->zstdstream_valid = 1; + + /* (Re)allocate the buffer that will contain decompressed bytes. */ + free(zip->uncompressed_buffer); + + zip->uncompressed_buffer_size = ZSTD_DStreamOutSize(); + zip->uncompressed_buffer = + (uint8_t*) malloc(zip->uncompressed_buffer_size); + if (zip->uncompressed_buffer == NULL) { + archive_set_error(&a->archive, ENOMEM, + "No memory for Zstd decompression"); + + return ARCHIVE_FATAL; + } + + /* Initialization done. */ + zip->decompress_init = 1; + return ARCHIVE_OK; +} + +static int +zip_read_data_zipx_zstd(struct archive_read *a, const void **buff, + size_t *size, int64_t *offset) +{ + struct zip *zip = (struct zip *)(a->format->data); + ssize_t bytes_avail = 0, in_bytes, to_consume; + const void *compressed_buff; + int r; + size_t ret; + uint64_t total_out; + ZSTD_outBuffer out; + ZSTD_inBuffer in; + + (void) offset; /* UNUSED */ + + /* Initialize decompression context if we're here for the first time. */ + if(!zip->decompress_init) { + r = zipx_zstd_init(a, zip); + if(r != ARCHIVE_OK) + return r; + } + + /* Fetch more compressed bytes */ + compressed_buff = __archive_read_ahead(a, 1, &bytes_avail); + if(bytes_avail < 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated zstd file body"); + return (ARCHIVE_FATAL); + } + + in_bytes = zipmin(zip->entry_bytes_remaining, bytes_avail); + if(in_bytes < 1) { + /* zstd doesn't complain when caller feeds avail_in == 0. + * It will actually return success in this case, which is + * undesirable. This is why we need to make this check + * manually. */ + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Truncated zstd file body"); + return (ARCHIVE_FATAL); + } + + /* Setup buffer boundaries */ + in.src = compressed_buff; + in.size = in_bytes; + in.pos = 0; + out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 }; + + /* Perform the decompression. */ + ret = ZSTD_decompressStream(zip->zstdstream, &out, &in); + if (ZSTD_isError(ret)) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Error during zstd decompression: %s", + ZSTD_getErrorName(ret)); + return (ARCHIVE_FATAL); + } + + /* Check end of the stream. */ + if (ret == 0) { + if ((in.pos == in.size) && (out.pos < out.size)) { + zip->end_of_entry = 1; + ZSTD_freeDStream(zip->zstdstream); + zip->zstdstream_valid = 0; + } + } + + /* Update the pointers so decompressor can continue decoding. */ + to_consume = in.pos; + __archive_read_consume(a, to_consume); + + total_out = out.pos; + + zip->entry_bytes_remaining -= to_consume; + zip->entry_compressed_bytes_read += to_consume; + zip->entry_uncompressed_bytes_read += total_out; + + /* Give libarchive its due. */ + *size = total_out; + *buff = zip->uncompressed_buffer; + + /* Seek for optional marker, like in other entries. */ + r = consume_optional_marker(a, zip); + if(r != ARCHIVE_OK) + return r; + + return ARCHIVE_OK; +} +#endif + #ifdef HAVE_ZLIB_H static int zip_deflate_init(struct archive_read *a, struct zip *zip) @@ -2918,6 +3002,11 @@ archive_read_format_zip_read_data(struct archive_read *a, r = zip_read_data_zipx_xz(a, buff, size, offset); break; #endif +#if HAVE_ZSTD_H && HAVE_LIBZSTD + case 93: /* ZIPx Zstd compression. */ + r = zip_read_data_zipx_zstd(a, buff, size, offset); + break; +#endif /* PPMd support is built-in, so we don't need any #if guards. */ case 98: /* ZIPx PPMd compression. */ r = zip_read_data_zipx_ppmd(a, buff, size, offset); @@ -3008,6 +3097,12 @@ archive_read_format_zip_cleanup(struct archive_read *a) } #endif +#if HAVE_ZSTD_H && HAVE_LIBZSTD + if (zip->zstdstream_valid) { + ZSTD_freeDStream(zip->zstdstream); + } +#endif + free(zip->uncompressed_buffer); if (zip->ppmd8_valid) @@ -3415,24 +3510,31 @@ archive_read_support_format_zip_capabilities_seekable(struct archive_read * a) static int read_eocd(struct zip *zip, const char *p, int64_t current_offset) { + uint16_t disk_num; + uint32_t cd_size, cd_offset; + + disk_num = archive_le16dec(p + 4); + cd_size = archive_le32dec(p + 12); + cd_offset = archive_le32dec(p + 16); + /* Sanity-check the EOCD we've found. */ /* This must be the first volume. */ - if (archive_le16dec(p + 4) != 0) + if (disk_num != 0) return 0; /* Central directory must be on this volume. */ - if (archive_le16dec(p + 4) != archive_le16dec(p + 6)) + if (disk_num != archive_le16dec(p + 6)) return 0; /* All central directory entries must be on this volume. */ if (archive_le16dec(p + 10) != archive_le16dec(p + 8)) return 0; /* Central directory can't extend beyond start of EOCD record. */ - if (archive_le32dec(p + 16) + archive_le32dec(p + 12) - > current_offset) + if (cd_offset + cd_size > current_offset) return 0; /* Save the central directory location for later use. */ - zip->central_directory_offset = archive_le32dec(p + 16); + zip->central_directory_offset = cd_offset; + zip->central_directory_offset_adjusted = current_offset - cd_size; /* This is just a tiny bit higher than the maximum returned by the streaming Zip bidder. This ensures @@ -3484,6 +3586,8 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p) /* Save the central directory offset for later use. */ zip->central_directory_offset = archive_le64dec(p + 48); + /* TODO: Needs scanning backwards to find the eocd64 instead of assuming */ + zip->central_directory_offset_adjusted = zip->central_directory_offset; return 32; } @@ -3655,7 +3759,8 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry, * know the correction we need to apply to account for leading * padding. */ - if (__archive_read_seek(a, zip->central_directory_offset, SEEK_SET) < 0) + if (__archive_read_seek(a, zip->central_directory_offset_adjusted, SEEK_SET) + < 0) return ARCHIVE_FATAL; found = 0; diff --git a/Utilities/cmlibarchive/libarchive/archive_string.c b/Utilities/cmlibarchive/libarchive/archive_string.c index 7460ded..d7f2c46 100644 --- a/Utilities/cmlibarchive/libarchive/archive_string.c +++ b/Utilities/cmlibarchive/libarchive/archive_string.c @@ -745,7 +745,7 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as, dp = &defchar_used; count = WideCharToMultiByte(to_cp, 0, ws, wslen, as->s + as->length, - (int)as->buffer_length - as->length - 1, NULL, dp); + (int)as->buffer_length - (int)as->length - 1, NULL, dp); if (count == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { /* Expand the MBS buffer and retry. */ diff --git a/Utilities/cmlibarchive/libarchive/archive_write.c b/Utilities/cmlibarchive/libarchive/archive_write.c index 8d70f51..66592e8 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write.c +++ b/Utilities/cmlibarchive/libarchive/archive_write.c @@ -60,8 +60,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write.c 201099 2009-12-28 03:03: #include "archive_private.h" #include "archive_write_private.h" -static struct archive_vtable *archive_write_vtable(void); - static int _archive_filter_code(struct archive *, int); static const char *_archive_filter_name(struct archive *, int); static int64_t _archive_filter_bytes(struct archive *, int); @@ -79,26 +77,18 @@ struct archive_none { char *next; }; -static struct archive_vtable * -archive_write_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_close = _archive_write_close; - av.archive_filter_bytes = _archive_filter_bytes; - av.archive_filter_code = _archive_filter_code; - av.archive_filter_name = _archive_filter_name; - av.archive_filter_count = _archive_write_filter_count; - av.archive_free = _archive_write_free; - av.archive_write_header = _archive_write_header; - av.archive_write_finish_entry = _archive_write_finish_entry; - av.archive_write_data = _archive_write_data; - inited = 1; - } - return (&av); -} +static const struct archive_vtable +archive_write_vtable = { + .archive_close = _archive_write_close, + .archive_filter_bytes = _archive_filter_bytes, + .archive_filter_code = _archive_filter_code, + .archive_filter_name = _archive_filter_name, + .archive_filter_count = _archive_write_filter_count, + .archive_free = _archive_write_free, + .archive_write_header = _archive_write_header, + .archive_write_finish_entry = _archive_write_finish_entry, + .archive_write_data = _archive_write_data, +}; /* * Allocate, initialize and return an archive object. @@ -114,7 +104,7 @@ archive_write_new(void) return (NULL); a->archive.magic = ARCHIVE_WRITE_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; - a->archive.vtable = archive_write_vtable(); + a->archive.vtable = &archive_write_vtable; /* * The value 10240 here matches the traditional tar default, * but is otherwise arbitrary. @@ -482,6 +472,8 @@ archive_write_client_close(struct archive_write_filter *f) ssize_t block_length; ssize_t target_block_length; ssize_t bytes_written; + size_t to_write; + char *p; int ret = ARCHIVE_OK; /* If there's pending data, pad and write the last block */ @@ -504,9 +496,24 @@ archive_write_client_close(struct archive_write_filter *f) target_block_length - block_length); block_length = target_block_length; } - bytes_written = (a->client_writer)(&a->archive, - a->client_data, state->buffer, block_length); - ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK; + p = state->buffer; + to_write = block_length; + while (to_write > 0) { + bytes_written = (a->client_writer)(&a->archive, + a->client_data, p, to_write); + if (bytes_written <= 0) { + ret = ARCHIVE_FATAL; + break; + } + if ((size_t)bytes_written > to_write) { + archive_set_error(&(a->archive), + -1, "write overrun"); + ret = ARCHIVE_FATAL; + break; + } + p += bytes_written; + to_write -= bytes_written; + } } if (a->client_closer) (*a->client_closer)(&a->archive, a->client_data); diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c index 00df8da..0cc03b1 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c @@ -251,13 +251,13 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f, int ds, log2dic, wedges; /* Calculate a coded dictionary size */ - if (dict_size < (1 << 12) || dict_size > (1 << 27)) { + if (dict_size < (1 << 12) || dict_size > (1 << 29)) { archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Unacceptable dictionary size for lzip: %d", dict_size); return (ARCHIVE_FATAL); } - for (log2dic = 27; log2dic >= 12; log2dic--) { + for (log2dic = 29; log2dic >= 12; log2dic--) { if (dict_size & (1 << log2dic)) break; } diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c index 6d71628..7d36d58 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c @@ -50,7 +50,8 @@ __FBSDID("$FreeBSD$"); struct private_data { int compression_level; -#if HAVE_ZSTD_H && HAVE_LIBZSTD + int threads; +#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR ZSTD_CStream *cstream; int64_t total_in; ZSTD_outBuffer out; @@ -76,7 +77,7 @@ static int archive_compressor_zstd_write(struct archive_write_filter *, const void *, size_t); static int archive_compressor_zstd_close(struct archive_write_filter *); static int archive_compressor_zstd_free(struct archive_write_filter *); -#if HAVE_ZSTD_H && HAVE_LIBZSTD +#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR static int drive_compressor(struct archive_write_filter *, struct private_data *, int, const void *, size_t); #endif @@ -107,7 +108,8 @@ archive_write_add_filter_zstd(struct archive *_a) f->code = ARCHIVE_FILTER_ZSTD; f->name = "zstd"; data->compression_level = CLEVEL_DEFAULT; -#if HAVE_ZSTD_H && HAVE_LIBZSTD + data->threads = 0; +#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR data->cstream = ZSTD_createCStream(); if (data->cstream == NULL) { free(data); @@ -134,7 +136,7 @@ static int archive_compressor_zstd_free(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; -#if HAVE_ZSTD_H && HAVE_LIBZSTD +#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR ZSTD_freeCStream(data->cstream); free(data->out.dst); #else @@ -187,7 +189,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key, if (string_is_numeric(value) != ARCHIVE_OK) { return (ARCHIVE_WARN); } -#if HAVE_ZSTD_H && HAVE_LIBZSTD +#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR maximum = ZSTD_maxCLevel(); #if ZSTD_VERSION_NUMBER >= MINVER_MINCLEVEL if (ZSTD_versionNumber() >= MINVER_MINCLEVEL) { @@ -204,6 +206,20 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key, } data->compression_level = level; return (ARCHIVE_OK); + } else if (strcmp(key, "threads") == 0) { + int threads = atoi(value); + if (string_is_numeric(value) != ARCHIVE_OK) { + return (ARCHIVE_WARN); + } + + int minimum = 0; + + if (threads < minimum) { + return (ARCHIVE_WARN); + } + + data->threads = threads; + return (ARCHIVE_OK); } /* Note: The "warn" return is just to inform the options @@ -212,7 +228,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key, return (ARCHIVE_WARN); } -#if HAVE_ZSTD_H && HAVE_LIBZSTD +#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR /* * Setup callback. */ @@ -252,6 +268,8 @@ archive_compressor_zstd_open(struct archive_write_filter *f) return (ARCHIVE_FATAL); } + ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads); + return (ARCHIVE_OK); } @@ -335,7 +353,7 @@ drive_compressor(struct archive_write_filter *f, } } -#else /* HAVE_ZSTD_H && HAVE_LIBZSTD */ +#else /* HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR */ static int archive_compressor_zstd_open(struct archive_write_filter *f) @@ -366,6 +384,14 @@ archive_compressor_zstd_open(struct archive_write_filter *f) archive_strcat(&as, " --ultra"); } + if (data->threads != 0) { + struct archive_string as2; + archive_string_init(&as2); + archive_string_sprintf(&as2, " --threads=%d", data->threads); + archive_string_concat(&as, &as2); + archive_string_free(&as2); + } + f->write = archive_compressor_zstd_write; r = __archive_write_program_open(f, data->pdata, as.s); archive_string_free(&as); @@ -389,4 +415,4 @@ archive_compressor_zstd_close(struct archive_write_filter *f) return __archive_write_program_close(f, data->pdata); } -#endif /* HAVE_ZSTD_H && HAVE_LIBZSTD */ +#endif /* HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR */ diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk.3 b/Utilities/cmlibarchive/libarchive/archive_write_disk.3 index 2fa016e..97f3fcd 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk.3 +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk.3 @@ -163,14 +163,14 @@ caused by archives that (deliberately or otherwise) extract files outside of the current directory. The default is not to perform this check. If -.It Cm ARCHIVE_EXTRACT_SPARSE -Scan data for blocks of NUL bytes and try to recreate them with holes. -This results in sparse files, independent of whether the archive format -supports or uses them. .Cm ARCHIVE_EXTRACT_UNLINK is specified together with this option, the library will remove any intermediate symlinks it finds and return an error only if such symlink could not be removed. +.It Cm ARCHIVE_EXTRACT_SPARSE +Scan data for blocks of NUL bytes and try to recreate them with holes. +This results in sparse files, independent of whether the archive format +supports or uses them. .It Cm ARCHIVE_EXTRACT_TIME The timestamps (mtime, ctime, and atime) should be restored. By default, they are ignored. diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c index 2551ebe..b6d3d0a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c @@ -173,6 +173,7 @@ struct fixup_entry { struct fixup_entry *next; struct archive_acl acl; mode_t mode; + __LA_MODE_T filetype; int64_t atime; int64_t birthtime; int64_t mtime; @@ -357,10 +358,11 @@ struct archive_write_disk { static int la_opendirat(int, const char *); static int la_mktemp(struct archive_write_disk *); +static int la_verify_filetype(mode_t, __LA_MODE_T); static void fsobj_error(int *, struct archive_string *, int, const char *, const char *); static int check_symlinks_fsobj(char *, int *, struct archive_string *, - int); + int, int); static int check_symlinks(struct archive_write_disk *); static int create_filesystem_object(struct archive_write_disk *); static struct fixup_entry *current_fixup(struct archive_write_disk *, @@ -396,8 +398,6 @@ static struct fixup_entry *sort_dir_list(struct fixup_entry *p); static ssize_t write_data_block(struct archive_write_disk *, const char *, size_t); -static struct archive_vtable *archive_write_disk_vtable(void); - static int _archive_write_disk_close(struct archive *); static int _archive_write_disk_free(struct archive *); static int _archive_write_disk_header(struct archive *, @@ -465,6 +465,39 @@ la_opendirat(int fd, const char *path) { } static int +la_verify_filetype(mode_t mode, __LA_MODE_T filetype) { + int ret = 0; + + switch (filetype) { + case AE_IFREG: + ret = (S_ISREG(mode)); + break; + case AE_IFDIR: + ret = (S_ISDIR(mode)); + break; + case AE_IFLNK: + ret = (S_ISLNK(mode)); + break; + case AE_IFSOCK: + ret = (S_ISSOCK(mode)); + break; + case AE_IFCHR: + ret = (S_ISCHR(mode)); + break; + case AE_IFBLK: + ret = (S_ISBLK(mode)); + break; + case AE_IFIFO: + ret = (S_ISFIFO(mode)); + break; + default: + break; + } + + return (ret); +} + +static int lazy_stat(struct archive_write_disk *a) { if (a->pst != NULL) { @@ -489,25 +522,16 @@ lazy_stat(struct archive_write_disk *a) return (ARCHIVE_WARN); } -static struct archive_vtable * -archive_write_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_close = _archive_write_disk_close; - av.archive_filter_bytes = _archive_write_disk_filter_bytes; - av.archive_free = _archive_write_disk_free; - av.archive_write_header = _archive_write_disk_header; - av.archive_write_finish_entry - = _archive_write_disk_finish_entry; - av.archive_write_data = _archive_write_disk_data; - av.archive_write_data_block = _archive_write_disk_data_block; - inited = 1; - } - return (&av); -} +static const struct archive_vtable +archive_write_disk_vtable = { + .archive_close = _archive_write_disk_close, + .archive_filter_bytes = _archive_write_disk_filter_bytes, + .archive_free = _archive_write_disk_free, + .archive_write_header = _archive_write_disk_header, + .archive_write_finish_entry = _archive_write_disk_finish_entry, + .archive_write_data = _archive_write_disk_data, + .archive_write_data_block = _archive_write_disk_data_block, +}; static int64_t _archive_write_disk_filter_bytes(struct archive *_a, int n) @@ -822,6 +846,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) fe = current_fixup(a, archive_entry_pathname(entry)); if (fe == NULL) return (ARCHIVE_FATAL); + fe->filetype = archive_entry_filetype(entry); fe->fixup |= TODO_MODE_BASE; fe->mode = a->mode; } @@ -832,6 +857,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) fe = current_fixup(a, archive_entry_pathname(entry)); if (fe == NULL) return (ARCHIVE_FATAL); + fe->filetype = archive_entry_filetype(entry); fe->mode = a->mode; fe->fixup |= TODO_TIMES; if (archive_entry_atime_is_set(entry)) { @@ -865,6 +891,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) fe = current_fixup(a, archive_entry_pathname(entry)); if (fe == NULL) return (ARCHIVE_FATAL); + fe->filetype = archive_entry_filetype(entry); fe->fixup |= TODO_ACLS; archive_acl_copy(&fe->acl, archive_entry_acl(entry)); } @@ -877,6 +904,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) fe = current_fixup(a, archive_entry_pathname(entry)); if (fe == NULL) return (ARCHIVE_FATAL); + fe->filetype = archive_entry_filetype(entry); fe->mac_metadata = malloc(metadata_size); if (fe->mac_metadata != NULL) { memcpy(fe->mac_metadata, metadata, @@ -891,6 +919,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) fe = current_fixup(a, archive_entry_pathname(entry)); if (fe == NULL) return (ARCHIVE_FATAL); + fe->filetype = archive_entry_filetype(entry); fe->fixup |= TODO_FFLAGS; /* TODO: Complete this.. defer fflags from below. */ } @@ -1956,7 +1985,7 @@ archive_write_disk_new(void) a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; /* We're ready to write a header immediately. */ a->archive.state = ARCHIVE_STATE_HEADER; - a->archive.vtable = archive_write_disk_vtable(); + a->archive.vtable = &archive_write_disk_vtable; a->start_time = time(NULL); /* Query and restore the umask. */ umask(a->user_umask = umask(0)); @@ -2263,7 +2292,7 @@ create_filesystem_object(struct archive_write_disk *a) return (EPERM); } r = check_symlinks_fsobj(linkname_copy, &error_number, - &error_string, a->flags); + &error_string, a->flags, 1); if (r != ARCHIVE_OK) { archive_set_error(&a->archive, error_number, "%s", error_string.s); @@ -2284,7 +2313,12 @@ create_filesystem_object(struct archive_write_disk *a) */ if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) unlink(a->name); +#ifdef HAVE_LINKAT + r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name, + 0) ? errno : 0; +#else r = link(linkname, a->name) ? errno : 0; +#endif /* * New cpio and pax formats allow hardlink entries * to carry data, so we may have to open the file @@ -2456,7 +2490,9 @@ _archive_write_disk_close(struct archive *_a) { struct archive_write_disk *a = (struct archive_write_disk *)_a; struct fixup_entry *next, *p; - int fd, ret; + struct stat st; + char *c; + int fd, ret, openflags; archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, @@ -2469,10 +2505,70 @@ _archive_write_disk_close(struct archive *_a) while (p != NULL) { fd = -1; a->pst = NULL; /* Mark stat cache as out-of-date. */ - if (p->fixup & - (TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) { - fd = open(p->name, - O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC); + + /* We must strip trailing slashes from the path to avoid + dereferencing symbolic links to directories */ + c = p->name; + while (*c != '\0') + c++; + while (c != p->name && *(c - 1) == '/') { + c--; + *c = '\0'; + } + + if (p->fixup == 0) + goto skip_fixup_entry; + else { + /* + * We need to verify if the type of the file + * we are going to open matches the file type + * of the fixup entry. + */ + openflags = O_BINARY | O_NOFOLLOW | O_RDONLY + | O_CLOEXEC; +#if defined(O_DIRECTORY) + if (p->filetype == AE_IFDIR) + openflags |= O_DIRECTORY; +#endif + fd = open(p->name, openflags); + +#if defined(O_DIRECTORY) + /* + * If we support O_DIRECTORY and open was + * successful we can skip the file type check + * for directories. For other file types + * we need to verify via fstat() or lstat() + */ + if (fd == -1 || p->filetype != AE_IFDIR) { +#if HAVE_FSTAT + if (fd > 0 && ( + fstat(fd, &st) != 0 || + la_verify_filetype(st.st_mode, + p->filetype) == 0)) { + goto skip_fixup_entry; + } else +#endif + if (lstat(p->name, &st) != 0 || + la_verify_filetype(st.st_mode, + p->filetype) == 0) { + goto skip_fixup_entry; + } + } +#else +#if HAVE_FSTAT + if (fd > 0 && ( + fstat(fd, &st) != 0 || + la_verify_filetype(st.st_mode, + p->filetype) == 0)) { + goto skip_fixup_entry; + } else +#endif + if (lstat(p->name, &st) != 0 || + la_verify_filetype(st.st_mode, + p->filetype) == 0) { + goto skip_fixup_entry; + } +#endif } if (p->fixup & TODO_TIMES) { set_times(a, fd, p->mode, p->name, @@ -2484,10 +2580,14 @@ _archive_write_disk_close(struct archive *_a) if (p->fixup & TODO_MODE_BASE) { #ifdef HAVE_FCHMOD if (fd >= 0) - fchmod(fd, p->mode); + fchmod(fd, p->mode & 07777); else #endif - chmod(p->name, p->mode); +#ifdef HAVE_LCHMOD + lchmod(p->name, p->mode & 07777); +#else + chmod(p->name, p->mode & 07777); +#endif } if (p->fixup & TODO_ACLS) archive_write_disk_set_acls(&a->archive, fd, @@ -2498,6 +2598,7 @@ _archive_write_disk_close(struct archive *_a) if (p->fixup & TODO_MAC_METADATA) set_mac_metadata(a, p->name, p->mac_metadata, p->mac_metadata_size); +skip_fixup_entry: next = p->next; archive_acl_clear(&p->acl); free(p->mac_metadata); @@ -2638,6 +2739,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname) fe->next = a->fixup_list; a->fixup_list = fe; fe->fixup = 0; + fe->filetype = 0; fe->name = strdup(pathname); return (fe); } @@ -2675,7 +2777,7 @@ fsobj_error(int *a_eno, struct archive_string *a_estr, */ static int check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, - int flags) + int flags, int checking_linkname) { #if !defined(HAVE_LSTAT) && \ !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)) @@ -2684,6 +2786,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, (void)error_number; /* UNUSED */ (void)error_string; /* UNUSED */ (void)flags; /* UNUSED */ + (void)checking_linkname; /* UNUSED */ return (ARCHIVE_OK); #else int res = ARCHIVE_OK; @@ -2805,6 +2908,28 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, head = tail + 1; } } else if (S_ISLNK(st.st_mode)) { + if (last && checking_linkname) { +#ifdef HAVE_LINKAT + /* + * Hardlinks to symlinks are safe to write + * if linkat() is supported as it does not + * follow symlinks. + */ + res = ARCHIVE_OK; +#else + /* + * We return ARCHIVE_FAILED here as we are + * not able to safely write hardlinks + * to symlinks. + */ + tail[0] = c; + fsobj_error(a_eno, a_estr, errno, + "Cannot write hardlink to symlink ", + path); + res = ARCHIVE_FAILED; +#endif + break; + } else if (last) { /* * Last element is symlink; remove it @@ -2971,7 +3096,7 @@ check_symlinks(struct archive_write_disk *a) int rc; archive_string_init(&error_string); rc = check_symlinks_fsobj(a->name, &error_number, &error_string, - a->flags); + a->flags, 0); if (rc != ARCHIVE_OK) { archive_set_error(&a->archive, error_number, "%s", error_string.s); @@ -3737,6 +3862,7 @@ set_fflags(struct archive_write_disk *a) le = current_fixup(a, a->name); if (le == NULL) return (ARCHIVE_FATAL); + le->filetype = archive_entry_filetype(a->entry); le->fixup |= TODO_FFLAGS; le->fflags_set = set; /* Store the mode if it's not already there. */ @@ -3899,7 +4025,8 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, /* If we weren't given an fd, open it ourselves. */ if (myfd < 0) { - myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC); + myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | + O_CLOEXEC | O_NOFOLLOW); __archive_ensure_cloexec_flag(myfd); } if (myfd < 0) diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c index 0c60017..1b12a29 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c @@ -213,7 +213,7 @@ static int check_symlinks(struct archive_write_disk *); static int create_filesystem_object(struct archive_write_disk *); static struct fixup_entry *current_fixup(struct archive_write_disk *, const wchar_t *pathname); -static int cleanup_pathname(struct archive_write_disk *); +static int cleanup_pathname(struct archive_write_disk *, wchar_t *); static int create_dir(struct archive_write_disk *, wchar_t *); static int create_parent_dir(struct archive_write_disk *, wchar_t *); static int la_chmod(const wchar_t *, mode_t); @@ -238,8 +238,6 @@ static struct fixup_entry *sort_dir_list(struct fixup_entry *p); static ssize_t write_data_block(struct archive_write_disk *, const char *, size_t); -static struct archive_vtable *archive_write_disk_vtable(void); - static int _archive_write_disk_close(struct archive *); static int _archive_write_disk_free(struct archive *); static int _archive_write_disk_header(struct archive *, @@ -628,7 +626,7 @@ la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target, static BOOLEAN (WINAPI *f)(LPCWSTR, LPCWSTR, DWORD); static int set; wchar_t *ttarget, *p; - int len; + size_t len; DWORD attrs = 0; DWORD flags = 0; DWORD newflags = 0; @@ -759,25 +757,16 @@ lazy_stat(struct archive_write_disk *a) return (ARCHIVE_WARN); } -static struct archive_vtable * -archive_write_disk_vtable(void) -{ - static struct archive_vtable av; - static int inited = 0; - - if (!inited) { - av.archive_close = _archive_write_disk_close; - av.archive_filter_bytes = _archive_write_disk_filter_bytes; - av.archive_free = _archive_write_disk_free; - av.archive_write_header = _archive_write_disk_header; - av.archive_write_finish_entry - = _archive_write_disk_finish_entry; - av.archive_write_data = _archive_write_disk_data; - av.archive_write_data_block = _archive_write_disk_data_block; - inited = 1; - } - return (&av); -} +static const struct archive_vtable +archive_write_disk_vtable = { + .archive_close = _archive_write_disk_close, + .archive_filter_bytes = _archive_write_disk_filter_bytes, + .archive_free = _archive_write_disk_free, + .archive_write_header = _archive_write_disk_header, + .archive_write_finish_entry = _archive_write_disk_finish_entry, + .archive_write_data = _archive_write_disk_data, + .archive_write_data_block = _archive_write_disk_data_block, +}; static int64_t _archive_write_disk_filter_bytes(struct archive *_a, int n) @@ -854,7 +843,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) * dir restores; the dir restore logic otherwise gets messed * up by nonsense like "dir/.". */ - ret = cleanup_pathname(a); + ret = cleanup_pathname(a, a->name); if (ret != ARCHIVE_OK) return (ret); @@ -1373,7 +1362,7 @@ archive_write_disk_new(void) a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; /* We're ready to write a header immediately. */ a->archive.state = ARCHIVE_STATE_HEADER; - a->archive.vtable = archive_write_disk_vtable(); + a->archive.vtable = &archive_write_disk_vtable; a->start_time = time(NULL); /* Query and restore the umask. */ umask(a->user_umask = umask(0)); @@ -1671,9 +1660,22 @@ create_filesystem_object(struct archive_write_disk *a) /* Since link(2) and symlink(2) don't handle modes, we're done here. */ linkname = archive_entry_hardlink_w(a->entry); if (linkname != NULL) { - wchar_t *linkfull, *namefull; - - linkfull = __la_win_permissive_name_w(linkname); + wchar_t *linksanitized, *linkfull, *namefull; + size_t l = (wcslen(linkname) + 1) * sizeof(wchar_t); + linksanitized = malloc(l); + if (linksanitized == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for hardlink target"); + return (-1); + } + memcpy(linksanitized, linkname, l); + r = cleanup_pathname(a, linksanitized); + if (r != ARCHIVE_OK) { + free(linksanitized); + return (r); + } + linkfull = __la_win_permissive_name_w(linksanitized); + free(linksanitized); namefull = __la_win_permissive_name_w(a->name); if (linkfull == NULL || namefull == NULL) { errno = EINVAL; @@ -2184,12 +2186,12 @@ guidword(wchar_t *p, int n) * set) any '..' in the path. */ static int -cleanup_pathname(struct archive_write_disk *a) +cleanup_pathname(struct archive_write_disk *a, wchar_t *name) { wchar_t *dest, *src, *p, *top; wchar_t separator = L'\0'; - p = a->name; + p = name; if (*p == L'\0') { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid empty pathname"); @@ -2201,7 +2203,7 @@ cleanup_pathname(struct archive_write_disk *a) if (*p == L'/') *p = L'\\'; } - p = a->name; + p = name; /* Skip leading "\\.\" or "\\?\" or "\\?\UNC\" or * "\\?\Volume{GUID}\" diff --git a/Utilities/cmlibarchive/libarchive/archive_write_format.3 b/Utilities/cmlibarchive/libarchive/archive_write_format.3 index 47a7403..653089f 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_format.3 +++ b/Utilities/cmlibarchive/libarchive/archive_write_format.3 @@ -35,7 +35,10 @@ .Nm archive_write_set_format_ar_svr4 , .Nm archive_write_set_format_by_name , .Nm archive_write_set_format_cpio , +.Nm archive_write_set_format_cpio_bin , .Nm archive_write_set_format_cpio_newc , +.Nm archive_write_set_format_cpio_odc , +.Nm archive_write_set_format_cpio_pwb , .Nm archive_write_set_format_filter_by_ext , .Nm archive_write_set_format_filter_by_ext_def , .Nm archive_write_set_format_gnutar , @@ -73,8 +76,14 @@ Streaming Archive Library (libarchive, -larchive) .Ft int .Fn archive_write_set_format_cpio "struct archive *" .Ft int +.Fn archive_write_set_format_cpio_bin "struct archive *" +.Ft int .Fn archive_write_set_format_cpio_newc "struct archive *" .Ft int +.Fn archive_write_set_format_cpio_odc "struct archive *" +.Ft int +.Fn archive_write_set_format_cpio_pwb "struct archive *" +.Ft int .Fn archive_write_set_format_filter_by_ext "struct archive *" "const char *filename" .Ft int .Fn archive_write_set_format_filter_by_ext_def "struct archive *" "const char *filename" "const char *def_ext" @@ -119,17 +128,20 @@ to create a new archive with the same format as an existing archive. .It Fn archive_write_set_format_by_name Sets the corresponding format based on the common name. .It Xo -.Fn archive_write_set_format_filter_by_ext , +.Fn archive_write_set_format_filter_by_ext .Fn archive_write_set_format_filter_by_ext_def .Xc Sets both filters and format based on the output filename. Supported extensions: .7z, .zip, .jar, .cpio, .iso, .a, .ar, .tar, .tgz, .tar.gz, .tar.bz2, .tar.xz .It Xo .Fn archive_write_set_format_7zip -.Fn archive_write_set_format_ar_bsd , -.Fn archive_write_set_format_ar_svr4 , +.Fn archive_write_set_format_ar_bsd +.Fn archive_write_set_format_ar_svr4 .Fn archive_write_set_format_cpio +.Fn archive_write_set_format_cpio_bin .Fn archive_write_set_format_cpio_newc +.Fn archive_write_set_format_cpio_odc +.Fn archive_write_set_format_cpio_pwb .Fn archive_write_set_format_gnutar .Fn archive_write_set_format_iso9660 .Fn archive_write_set_format_mtree diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format.c index 7dbe7b9..1f65fa4 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format.c @@ -44,7 +44,9 @@ struct { int code; int (*setter)(struct archive *); } codes[] = { { ARCHIVE_FORMAT_7ZIP, archive_write_set_format_7zip }, { ARCHIVE_FORMAT_CPIO, archive_write_set_format_cpio }, - { ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio }, + { ARCHIVE_FORMAT_CPIO_BIN_LE, archive_write_set_format_cpio_bin }, + { ARCHIVE_FORMAT_CPIO_PWB, archive_write_set_format_cpio_pwb }, + { ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio_odc }, { ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc }, { ARCHIVE_FORMAT_ISO9660, archive_write_set_format_iso9660 }, { ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree }, diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c index 7f2e6ac..87b3586 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c @@ -755,6 +755,10 @@ _7z_close(struct archive_write *a) */ #if HAVE_LZMA_H header_compression = _7Z_LZMA1; + if(zip->opt_compression == _7Z_LZMA2 || + zip->opt_compression == _7Z_COPY) + header_compression = zip->opt_compression; + /* If the stored file is only one, do not encode the header. * This is the same way 7z command does. */ if (zip->total_number_entry == 1) @@ -762,7 +766,8 @@ _7z_close(struct archive_write *a) #else header_compression = _7Z_COPY; #endif - r = _7z_compression_init_encoder(a, header_compression, 6); + r = _7z_compression_init_encoder(a, header_compression, + zip->opt_compression_level); if (r < 0) return (r); zip->crc32flg = PRECODE_CRC32; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c index 86e8621..bfb4b35 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c @@ -49,6 +49,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] = { "arbsd", archive_write_set_format_ar_bsd }, { "argnu", archive_write_set_format_ar_svr4 }, { "arsvr4", archive_write_set_format_ar_svr4 }, + { "bin", archive_write_set_format_cpio_bin }, { "bsdtar", archive_write_set_format_pax_restricted }, { "cd9660", archive_write_set_format_iso9660 }, { "cpio", archive_write_set_format_cpio }, @@ -58,11 +59,12 @@ struct { const char *name; int (*setter)(struct archive *); } names[] = { "mtree", archive_write_set_format_mtree }, { "mtree-classic", archive_write_set_format_mtree_classic }, { "newc", archive_write_set_format_cpio_newc }, - { "odc", archive_write_set_format_cpio }, + { "odc", archive_write_set_format_cpio_odc }, { "oldtar", archive_write_set_format_v7tar }, { "pax", archive_write_set_format_pax }, { "paxr", archive_write_set_format_pax_restricted }, { "posix", archive_write_set_format_pax }, + { "pwb", archive_write_set_format_cpio_pwb }, { "raw", archive_write_set_format_raw }, { "rpax", archive_write_set_format_pax_restricted }, { "shar", archive_write_set_format_shar }, diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c index e066733..47152cc 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c @@ -1,500 +1,11 @@ -/*- - * Copyright (c) 2003-2007 Tim Kientzle - * Copyright (c) 2011-2012 Michihiro NAKAJIMA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - #include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $"); - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#include <stdio.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - #include "archive.h" -#include "archive_entry.h" -#include "archive_entry_locale.h" -#include "archive_private.h" -#include "archive_write_private.h" -#include "archive_write_set_format_private.h" - -static ssize_t archive_write_cpio_data(struct archive_write *, - const void *buff, size_t s); -static int archive_write_cpio_close(struct archive_write *); -static int archive_write_cpio_free(struct archive_write *); -static int archive_write_cpio_finish_entry(struct archive_write *); -static int archive_write_cpio_header(struct archive_write *, - struct archive_entry *); -static int archive_write_cpio_options(struct archive_write *, - const char *, const char *); -static int format_octal(int64_t, void *, int); -static int64_t format_octal_recursive(int64_t, char *, int); -static int write_header(struct archive_write *, struct archive_entry *); - -struct cpio { - uint64_t entry_bytes_remaining; - - int64_t ino_next; - - struct { int64_t old; int new;} *ino_list; - size_t ino_list_size; - size_t ino_list_next; - - struct archive_string_conv *opt_sconv; - struct archive_string_conv *sconv_default; - int init_default_conversion; -}; - -#define c_magic_offset 0 -#define c_magic_size 6 -#define c_dev_offset 6 -#define c_dev_size 6 -#define c_ino_offset 12 -#define c_ino_size 6 -#define c_mode_offset 18 -#define c_mode_size 6 -#define c_uid_offset 24 -#define c_uid_size 6 -#define c_gid_offset 30 -#define c_gid_size 6 -#define c_nlink_offset 36 -#define c_nlink_size 6 -#define c_rdev_offset 42 -#define c_rdev_size 6 -#define c_mtime_offset 48 -#define c_mtime_size 11 -#define c_namesize_offset 59 -#define c_namesize_size 6 -#define c_filesize_offset 65 -#define c_filesize_size 11 /* - * Set output format to 'cpio' format. + * Set output format to the default 'cpio' format. */ int archive_write_set_format_cpio(struct archive *_a) { - struct archive_write *a = (struct archive_write *)_a; - struct cpio *cpio; - - archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, - ARCHIVE_STATE_NEW, "archive_write_set_format_cpio"); - - /* If someone else was already registered, unregister them. */ - if (a->format_free != NULL) - (a->format_free)(a); - - cpio = (struct cpio *)calloc(1, sizeof(*cpio)); - if (cpio == NULL) { - archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); - return (ARCHIVE_FATAL); - } - a->format_data = cpio; - a->format_name = "cpio"; - a->format_options = archive_write_cpio_options; - a->format_write_header = archive_write_cpio_header; - a->format_write_data = archive_write_cpio_data; - a->format_finish_entry = archive_write_cpio_finish_entry; - a->format_close = archive_write_cpio_close; - a->format_free = archive_write_cpio_free; - a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; - a->archive.archive_format_name = "POSIX cpio"; - return (ARCHIVE_OK); -} - -static int -archive_write_cpio_options(struct archive_write *a, const char *key, - const char *val) -{ - struct cpio *cpio = (struct cpio *)a->format_data; - int ret = ARCHIVE_FAILED; - - if (strcmp(key, "hdrcharset") == 0) { - if (val == NULL || val[0] == 0) - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "%s: hdrcharset option needs a character-set name", - a->format_name); - else { - cpio->opt_sconv = archive_string_conversion_to_charset( - &a->archive, val, 0); - if (cpio->opt_sconv != NULL) - ret = ARCHIVE_OK; - else - ret = ARCHIVE_FATAL; - } - return (ret); - } - - /* Note: The "warn" return is just to inform the options - * supervisor that we didn't handle it. It will generate - * a suitable error if no one used this option. */ - return (ARCHIVE_WARN); -} - -/* - * Ino values are as long as 64 bits on some systems; cpio format - * only allows 18 bits and relies on the ino values to identify hardlinked - * files. So, we can't merely "hash" the ino numbers since collisions - * would corrupt the archive. Instead, we generate synthetic ino values - * to store in the archive and maintain a map of original ino values to - * synthetic ones so we can preserve hardlink information. - * - * TODO: Make this more efficient. It's not as bad as it looks (most - * files don't have any hardlinks and we don't do any work here for those), - * but it wouldn't be hard to do better. - * - * TODO: Work with dev/ino pairs here instead of just ino values. - */ -static int -synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) -{ - int64_t ino = archive_entry_ino64(entry); - int ino_new; - size_t i; - - /* - * If no index number was given, don't assign one. In - * particular, this handles the end-of-archive marker - * correctly by giving it a zero index value. (This is also - * why we start our synthetic index numbers with one below.) - */ - if (ino == 0) - return (0); - - /* Don't store a mapping if we don't need to. */ - if (archive_entry_nlink(entry) < 2) { - return (int)(++cpio->ino_next); - } - - /* Look up old ino; if we have it, this is a hardlink - * and we reuse the same value. */ - for (i = 0; i < cpio->ino_list_next; ++i) { - if (cpio->ino_list[i].old == ino) - return (cpio->ino_list[i].new); - } - - /* Assign a new index number. */ - ino_new = (int)(++cpio->ino_next); - - /* Ensure space for the new mapping. */ - if (cpio->ino_list_size <= cpio->ino_list_next) { - size_t newsize = cpio->ino_list_size < 512 - ? 512 : cpio->ino_list_size * 2; - void *newlist = realloc(cpio->ino_list, - sizeof(cpio->ino_list[0]) * newsize); - if (newlist == NULL) - return (-1); - - cpio->ino_list_size = newsize; - cpio->ino_list = newlist; - } - - /* Record and return the new value. */ - cpio->ino_list[cpio->ino_list_next].old = ino; - cpio->ino_list[cpio->ino_list_next].new = ino_new; - ++cpio->ino_list_next; - return (ino_new); -} - - -static struct archive_string_conv * -get_sconv(struct archive_write *a) -{ - struct cpio *cpio; - struct archive_string_conv *sconv; - - cpio = (struct cpio *)a->format_data; - sconv = cpio->opt_sconv; - if (sconv == NULL) { - if (!cpio->init_default_conversion) { - cpio->sconv_default = - archive_string_default_conversion_for_write( - &(a->archive)); - cpio->init_default_conversion = 1; - } - sconv = cpio->sconv_default; - } - return (sconv); -} - -static int -archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry) -{ - const char *path; - size_t len; - - if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) { - archive_set_error(&a->archive, -1, "Filetype required"); - return (ARCHIVE_FAILED); - } - - if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 - && errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Pathname"); - return (ARCHIVE_FATAL); - } - if (len == 0 || path == NULL || path[0] == '\0') { - archive_set_error(&a->archive, -1, "Pathname required"); - return (ARCHIVE_FAILED); - } - - if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) { - archive_set_error(&a->archive, -1, "Size required"); - return (ARCHIVE_FAILED); - } - return write_header(a, entry); -} - -static int -write_header(struct archive_write *a, struct archive_entry *entry) -{ - struct cpio *cpio; - const char *p, *path; - int pathlength, ret, ret_final; - int64_t ino; - char h[76]; - struct archive_string_conv *sconv; - struct archive_entry *entry_main; - size_t len; - - cpio = (struct cpio *)a->format_data; - ret_final = ARCHIVE_OK; - sconv = get_sconv(a); - -#if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pathname, hardlink and symlink - * are all slash '/', not the Windows path separator '\'. */ - entry_main = __la_win_entry_in_posix_pathseparator(entry); - if (entry_main == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate ustar data"); - return(ARCHIVE_FATAL); - } - if (entry != entry_main) - entry = entry_main; - else - entry_main = NULL; -#else - entry_main = NULL; -#endif - - ret = archive_entry_pathname_l(entry, &path, &len, sconv); - if (ret != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Pathname"); - ret_final = ARCHIVE_FATAL; - goto exit_write_header; - } - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate pathname '%s' to %s", - archive_entry_pathname(entry), - archive_string_conversion_charset_name(sconv)); - ret_final = ARCHIVE_WARN; - } - /* Include trailing null. */ - pathlength = (int)len + 1; - - memset(h, 0, sizeof(h)); - format_octal(070707, h + c_magic_offset, c_magic_size); - format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size); - - ino = synthesize_ino_value(cpio, entry); - if (ino < 0) { - archive_set_error(&a->archive, ENOMEM, - "No memory for ino translation table"); - ret_final = ARCHIVE_FATAL; - goto exit_write_header; - } else if (ino > 0777777) { - archive_set_error(&a->archive, ERANGE, - "Too many files for this cpio format"); - ret_final = ARCHIVE_FATAL; - goto exit_write_header; - } - format_octal(ino & 0777777, h + c_ino_offset, c_ino_size); - - /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */ - format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size); - format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size); - format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size); - format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size); - if (archive_entry_filetype(entry) == AE_IFBLK - || archive_entry_filetype(entry) == AE_IFCHR) - format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size); - else - format_octal(0, h + c_rdev_offset, c_rdev_size); - format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size); - format_octal(pathlength, h + c_namesize_offset, c_namesize_size); - - /* Non-regular files don't store bodies. */ - if (archive_entry_filetype(entry) != AE_IFREG) - archive_entry_set_size(entry, 0); - - /* Symlinks get the link written as the body of the entry. */ - ret = archive_entry_symlink_l(entry, &p, &len, sconv); - if (ret != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for Linkname"); - ret_final = ARCHIVE_FATAL; - goto exit_write_header; - } - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate linkname '%s' to %s", - archive_entry_symlink(entry), - archive_string_conversion_charset_name(sconv)); - ret_final = ARCHIVE_WARN; - } - if (len > 0 && p != NULL && *p != '\0') - ret = format_octal(strlen(p), h + c_filesize_offset, - c_filesize_size); - else - ret = format_octal(archive_entry_size(entry), - h + c_filesize_offset, c_filesize_size); - if (ret) { - archive_set_error(&a->archive, ERANGE, - "File is too large for cpio format."); - ret_final = ARCHIVE_FAILED; - goto exit_write_header; - } - - ret = __archive_write_output(a, h, sizeof(h)); - if (ret != ARCHIVE_OK) { - ret_final = ARCHIVE_FATAL; - goto exit_write_header; - } - - ret = __archive_write_output(a, path, pathlength); - if (ret != ARCHIVE_OK) { - ret_final = ARCHIVE_FATAL; - goto exit_write_header; - } - - cpio->entry_bytes_remaining = archive_entry_size(entry); - - /* Write the symlink now. */ - if (p != NULL && *p != '\0') { - ret = __archive_write_output(a, p, strlen(p)); - if (ret != ARCHIVE_OK) { - ret_final = ARCHIVE_FATAL; - goto exit_write_header; - } - } -exit_write_header: - archive_entry_free(entry_main); - return (ret_final); -} - -static ssize_t -archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s) -{ - struct cpio *cpio; - int ret; - - cpio = (struct cpio *)a->format_data; - if (s > cpio->entry_bytes_remaining) - s = (size_t)cpio->entry_bytes_remaining; - - ret = __archive_write_output(a, buff, s); - cpio->entry_bytes_remaining -= s; - if (ret >= 0) - return (s); - else - return (ret); -} - -/* - * Format a number into the specified field. - */ -static int -format_octal(int64_t v, void *p, int digits) -{ - int64_t max; - int ret; - - max = (((int64_t)1) << (digits * 3)) - 1; - if (v >= 0 && v <= max) { - format_octal_recursive(v, (char *)p, digits); - ret = 0; - } else { - format_octal_recursive(max, (char *)p, digits); - ret = -1; - } - return (ret); -} - -static int64_t -format_octal_recursive(int64_t v, char *p, int s) -{ - if (s == 0) - return (v); - v = format_octal_recursive(v, p+1, s-1); - *p = '0' + ((char)v & 7); - return (v >> 3); -} - -static int -archive_write_cpio_close(struct archive_write *a) -{ - int er; - struct archive_entry *trailer; - - trailer = archive_entry_new2(NULL); - /* nlink = 1 here for GNU cpio compat. */ - archive_entry_set_nlink(trailer, 1); - archive_entry_set_size(trailer, 0); - archive_entry_set_pathname(trailer, "TRAILER!!!"); - er = write_header(a, trailer); - archive_entry_free(trailer); - return (er); -} - -static int -archive_write_cpio_free(struct archive_write *a) -{ - struct cpio *cpio; - - cpio = (struct cpio *)a->format_data; - free(cpio->ino_list); - free(cpio); - a->format_data = NULL; - return (ARCHIVE_OK); -} - -static int -archive_write_cpio_finish_entry(struct archive_write *a) -{ - struct cpio *cpio; - - cpio = (struct cpio *)a->format_data; - return (__archive_write_nulls(a, - (size_t)cpio->entry_bytes_remaining)); + return archive_write_set_format_cpio_odc(_a); } diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_binary.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_binary.c new file mode 100644 index 0000000..d6ce35a --- /dev/null +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_binary.c @@ -0,0 +1,610 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $"); + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_entry_locale.h" +#include "archive_private.h" +#include "archive_write_private.h" +#include "archive_write_set_format_private.h" + +static ssize_t archive_write_binary_data(struct archive_write *, + const void *buff, size_t s); +static int archive_write_binary_close(struct archive_write *); +static int archive_write_binary_free(struct archive_write *); +static int archive_write_binary_finish_entry(struct archive_write *); +static int archive_write_binary_header(struct archive_write *, + struct archive_entry *); +static int archive_write_binary_options(struct archive_write *, + const char *, const char *); +static int write_header(struct archive_write *, struct archive_entry *); + +struct cpio { + uint64_t entry_bytes_remaining; + + int64_t ino_next; + + struct { int64_t old; int new;} *ino_list; + size_t ino_list_size; + size_t ino_list_next; + + struct archive_string_conv *opt_sconv; + struct archive_string_conv *sconv_default; + int init_default_conversion; +}; + +/* This struct needs to be packed to get the header right */ + +#if defined(__GNUC__) +#define PACKED(x) x __attribute__((packed)) +#elif defined(_MSC_VER) +#define PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) +#else +#define PACKED(x) x +#endif + +#define HSIZE 26 + +PACKED(struct cpio_binary_header { + uint16_t h_magic; + uint16_t h_dev; + uint16_t h_ino; + uint16_t h_mode; + uint16_t h_uid; + uint16_t h_gid; + uint16_t h_nlink; + uint16_t h_majmin; + uint32_t h_mtime; + uint16_t h_namesize; + uint32_t h_filesize; +}); + +/* Back in the day, the 7th Edition cpio.c had this, to + * adapt to, as the comment said, "VAX, Interdata, ...": + * + * union { long l; short s[2]; char c[4]; } U; + * #define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];} + * long mklong(v) + * short v[]; + * { + * U.l = 1; + * if(U.c[0]) + * U.s[0] = v[1], U.s[1] = v[0]; + * else + * U.s[0] = v[0], U.s[1] = v[1]; + * return U.l; + * } + * + * Of course, that assumes that all machines have little-endian shorts, + * and just adapts the others to the special endianness of the PDP-11. + * + * Now, we could do this: + * + * union { uint32_t l; uint16_t s[2]; uint8_t c[4]; } U; + * #define PUTI16(v,sv) {U.s[0]=1;if(U.c[0]) v=sv; else U.s[0]=sv,U.c[2]=U.c[1],U.c[3]=U.c[0],v=U.s[1];} + * #define PUTI32(v,lv) {char_t Ut;U.l=1;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,Ut=U.c[0],U.c[0]=U.c[1],U.c[1]=Ut,Ut=U.c[2],U.c[2]=U.c[3],U.c[3]=Ut,v[0]=U.s[0],v[1]=U.s[1];} + * + * ...but it feels a little better to do it like this: + */ + +static uint16_t la_swap16(uint16_t in) { + union { + uint16_t s[2]; + uint8_t c[4]; + } U; + U.s[0] = 1; + if (U.c[0]) + return in; + else { + U.s[0] = in; + U.c[2] = U.c[1]; + U.c[3] = U.c[0]; + return U.s[1]; + } + /* NOTREACHED */ +} + +static uint32_t la_swap32(uint32_t in) { + union { + uint32_t l; + uint16_t s[2]; + uint8_t c[4]; + } U; + U.l = 1; + if (U.c[0]) { /* Little-endian */ + uint16_t t; + U.l = in; + t = U.s[0]; + U.s[0] = U.s[1]; + U.s[1] = t; + } else if (U.c[3]) { /* Big-endian */ + U.l = in; + U.s[0] = la_swap16(U.s[0]); + U.s[1] = la_swap16(U.s[1]); + } else { /* PDP-endian */ + U.l = in; + } + return U.l; +} + +/* + * Set output format to the selected binary variant + */ +static int +archive_write_set_format_cpio_binary(struct archive *_a, int format) +{ + struct archive_write *a = (struct archive_write *)_a; + struct cpio *cpio; + + if (sizeof(struct cpio_binary_header) != HSIZE) { + archive_set_error(&a->archive, EINVAL, + "Binary cpio format not supported on this platform"); + return (ARCHIVE_FATAL); + } + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary"); + + /* If someone else was already registered, unregister them. */ + if (a->format_free != NULL) + (a->format_free)(a); + + cpio = (struct cpio *)calloc(1, sizeof(*cpio)); + if (cpio == NULL) { + archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); + return (ARCHIVE_FATAL); + } + a->format_data = cpio; + a->format_name = "cpio"; + a->format_options = archive_write_binary_options; + a->format_write_header = archive_write_binary_header; + a->format_write_data = archive_write_binary_data; + a->format_finish_entry = archive_write_binary_finish_entry; + a->format_close = archive_write_binary_close; + a->format_free = archive_write_binary_free; + a->archive.archive_format = format; + switch (format) { + case ARCHIVE_FORMAT_CPIO_PWB: + a->archive.archive_format_name = "PWB cpio"; + break; + case ARCHIVE_FORMAT_CPIO_BIN_LE: + a->archive.archive_format_name = "7th Edition cpio"; + break; + default: + archive_set_error(&a->archive, EINVAL, "binary format must be 'pwb' or 'bin'"); + return (ARCHIVE_FATAL); + } + return (ARCHIVE_OK); +} + +/* + * Set output format to PWB (6th Edition) binary format + */ +int +archive_write_set_format_cpio_pwb(struct archive *_a) +{ + return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_PWB); +} + +/* + * Set output format to 7th Edition binary format + */ +int +archive_write_set_format_cpio_bin(struct archive *_a) +{ + return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_BIN_LE); +} + +static int +archive_write_binary_options(struct archive_write *a, const char *key, + const char *val) +{ + struct cpio *cpio = (struct cpio *)a->format_data; + int ret = ARCHIVE_FAILED; + + if (strcmp(key, "hdrcharset") == 0) { + if (val == NULL || val[0] == 0) + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "%s: hdrcharset option needs a character-set name", + a->format_name); + else { + cpio->opt_sconv = archive_string_conversion_to_charset( + &a->archive, val, 0); + if (cpio->opt_sconv != NULL) + ret = ARCHIVE_OK; + else + ret = ARCHIVE_FATAL; + } + return (ret); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +/* + * Ino values are as long as 64 bits on some systems; cpio format + * only allows 16 bits and relies on the ino values to identify hardlinked + * files. So, we can't merely "hash" the ino numbers since collisions + * would corrupt the archive. Instead, we generate synthetic ino values + * to store in the archive and maintain a map of original ino values to + * synthetic ones so we can preserve hardlink information. + * + * TODO: Make this more efficient. It's not as bad as it looks (most + * files don't have any hardlinks and we don't do any work here for those), + * but it wouldn't be hard to do better. + * + * TODO: Work with dev/ino pairs here instead of just ino values. + */ +static int +synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) +{ + int64_t ino = archive_entry_ino64(entry); + int ino_new; + size_t i; + + /* + * If no index number was given, don't assign one. In + * particular, this handles the end-of-archive marker + * correctly by giving it a zero index value. (This is also + * why we start our synthetic index numbers with one below.) + */ + if (ino == 0) + return (0); + + /* Don't store a mapping if we don't need to. */ + if (archive_entry_nlink(entry) < 2) { + return (int)(++cpio->ino_next); + } + + /* Look up old ino; if we have it, this is a hardlink + * and we reuse the same value. */ + for (i = 0; i < cpio->ino_list_next; ++i) { + if (cpio->ino_list[i].old == ino) + return (cpio->ino_list[i].new); + } + + /* Assign a new index number. */ + ino_new = (int)(++cpio->ino_next); + + /* Ensure space for the new mapping. */ + if (cpio->ino_list_size <= cpio->ino_list_next) { + size_t newsize = cpio->ino_list_size < 512 + ? 512 : cpio->ino_list_size * 2; + void *newlist = realloc(cpio->ino_list, + sizeof(cpio->ino_list[0]) * newsize); + if (newlist == NULL) + return (-1); + + cpio->ino_list_size = newsize; + cpio->ino_list = newlist; + } + + /* Record and return the new value. */ + cpio->ino_list[cpio->ino_list_next].old = ino; + cpio->ino_list[cpio->ino_list_next].new = ino_new; + ++cpio->ino_list_next; + return (ino_new); +} + + +static struct archive_string_conv * +get_sconv(struct archive_write *a) +{ + struct cpio *cpio; + struct archive_string_conv *sconv; + + cpio = (struct cpio *)a->format_data; + sconv = cpio->opt_sconv; + if (sconv == NULL) { + if (!cpio->init_default_conversion) { + cpio->sconv_default = + archive_string_default_conversion_for_write( + &(a->archive)); + cpio->init_default_conversion = 1; + } + sconv = cpio->sconv_default; + } + return (sconv); +} + +static int +archive_write_binary_header(struct archive_write *a, struct archive_entry *entry) +{ + const char *path; + size_t len; + + if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) { + archive_set_error(&a->archive, -1, "Filetype required"); + return (ARCHIVE_FAILED); + } + + if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 + && errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Pathname"); + return (ARCHIVE_FATAL); + } + if (len == 0 || path == NULL || path[0] == '\0') { + archive_set_error(&a->archive, -1, "Pathname required"); + return (ARCHIVE_FAILED); + } + + if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) { + archive_set_error(&a->archive, -1, "Size required"); + return (ARCHIVE_FAILED); + } + return write_header(a, entry); +} + +static int +write_header(struct archive_write *a, struct archive_entry *entry) +{ + struct cpio *cpio; + const char *p, *path; + int pathlength, ret, ret_final; + int64_t ino; + struct cpio_binary_header h; + struct archive_string_conv *sconv; + struct archive_entry *entry_main; + size_t len; + + cpio = (struct cpio *)a->format_data; + ret_final = ARCHIVE_OK; + sconv = get_sconv(a); + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure the path separators in pathname, hardlink and symlink + * are all slash '/', not the Windows path separator '\'. */ + entry_main = __la_win_entry_in_posix_pathseparator(entry); + if (entry_main == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + return(ARCHIVE_FATAL); + } + if (entry != entry_main) + entry = entry_main; + else + entry_main = NULL; +#else + entry_main = NULL; +#endif + + ret = archive_entry_pathname_l(entry, &path, &len, sconv); + if (ret != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Pathname"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate pathname '%s' to %s", + archive_entry_pathname(entry), + archive_string_conversion_charset_name(sconv)); + ret_final = ARCHIVE_WARN; + } + /* Include trailing null */ + pathlength = (int)len + 1; + + h.h_magic = la_swap16(070707); + h.h_dev = la_swap16(archive_entry_dev(entry)); + + ino = synthesize_ino_value(cpio, entry); + if (ino < 0) { + archive_set_error(&a->archive, ENOMEM, + "No memory for ino translation table"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } else if (ino > 077777) { + archive_set_error(&a->archive, ERANGE, + "Too many files for this cpio format"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + h.h_ino = la_swap16((uint16_t)ino); + + h.h_mode = archive_entry_mode(entry); + if (((h.h_mode & AE_IFMT) == AE_IFSOCK) || ((h.h_mode & AE_IFMT) == AE_IFIFO)) { + archive_set_error(&a->archive, EINVAL, + "sockets and fifos cannot be represented in the binary cpio formats"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) { + if ((h.h_mode & AE_IFMT) == AE_IFLNK) { + archive_set_error(&a->archive, EINVAL, + "symbolic links cannot be represented in the PWB cpio format"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + /* we could turn off AE_IFREG here, but it does no harm, */ + /* and allows v7 cpio to read the entry without confusion */ + } + h.h_mode = la_swap16(h.h_mode); + + h.h_uid = la_swap16((uint16_t)archive_entry_uid(entry)); + h.h_gid = la_swap16((uint16_t)archive_entry_gid(entry)); + h.h_nlink = la_swap16((uint16_t)archive_entry_nlink(entry)); + + if (archive_entry_filetype(entry) == AE_IFBLK + || archive_entry_filetype(entry) == AE_IFCHR) + h.h_majmin = la_swap16(archive_entry_rdev(entry)); + else + h.h_majmin = 0; + + h.h_mtime = la_swap32((uint32_t)archive_entry_mtime(entry)); + h.h_namesize = la_swap16(pathlength); + + /* Non-regular files don't store bodies. */ + if (archive_entry_filetype(entry) != AE_IFREG) + archive_entry_set_size(entry, 0); + + /* Symlinks get the link written as the body of the entry. */ + ret = archive_entry_symlink_l(entry, &p, &len, sconv); + if (ret != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Linkname"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate linkname '%s' to %s", + archive_entry_symlink(entry), + archive_string_conversion_charset_name(sconv)); + ret_final = ARCHIVE_WARN; + } + + if (len > 0 && p != NULL && *p != '\0') { + if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) { + archive_set_error(&a->archive, EINVAL, + "symlinks are not supported by UNIX V6 or by PWB cpio"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + h.h_filesize = la_swap32((uint32_t)strlen(p)); /* symlink */ + } else { + if ((a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) && + (archive_entry_size(entry) > 256*256*256-1)) { + archive_set_error(&a->archive, ERANGE, + "File is too large for PWB binary cpio format."); + ret_final = ARCHIVE_FAILED; + goto exit_write_header; + } else if (archive_entry_size(entry) > INT32_MAX) { + archive_set_error(&a->archive, ERANGE, + "File is too large for binary cpio format."); + ret_final = ARCHIVE_FAILED; + goto exit_write_header; + } + h.h_filesize = la_swap32((uint32_t)archive_entry_size(entry)); /* file */ + } + + ret = __archive_write_output(a, &h, HSIZE); + if (ret != ARCHIVE_OK) { + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + + ret = __archive_write_output(a, path, pathlength); + if ((ret == ARCHIVE_OK) && ((pathlength % 2) != 0)) + ret = __archive_write_nulls(a, 1); + if (ret != ARCHIVE_OK) { + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + + cpio->entry_bytes_remaining = archive_entry_size(entry); + if ((cpio->entry_bytes_remaining % 2) != 0) + cpio->entry_bytes_remaining++; + + /* Write the symlink now. */ + if (p != NULL && *p != '\0') { + ret = __archive_write_output(a, p, strlen(p)); + if ((ret == ARCHIVE_OK) && ((strlen(p) % 2) != 0)) + ret = __archive_write_nulls(a, 1); + if (ret != ARCHIVE_OK) { + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + } + +exit_write_header: + archive_entry_free(entry_main); + return (ret_final); +} + +static ssize_t +archive_write_binary_data(struct archive_write *a, const void *buff, size_t s) +{ + struct cpio *cpio; + int ret; + + cpio = (struct cpio *)a->format_data; + if (s > cpio->entry_bytes_remaining) + s = (size_t)cpio->entry_bytes_remaining; + + ret = __archive_write_output(a, buff, s); + cpio->entry_bytes_remaining -= s; + if (ret >= 0) + return (s); + else + return (ret); +} + +static int +archive_write_binary_close(struct archive_write *a) +{ + int er; + struct archive_entry *trailer; + + trailer = archive_entry_new2(NULL); + /* nlink = 1 here for GNU cpio compat. */ + archive_entry_set_nlink(trailer, 1); + archive_entry_set_size(trailer, 0); + archive_entry_set_pathname(trailer, "TRAILER!!!"); + er = write_header(a, trailer); + archive_entry_free(trailer); + return (er); +} + +static int +archive_write_binary_free(struct archive_write *a) +{ + struct cpio *cpio; + + cpio = (struct cpio *)a->format_data; + free(cpio->ino_list); + free(cpio); + a->format_data = NULL; + return (ARCHIVE_OK); +} + +static int +archive_write_binary_finish_entry(struct archive_write *a) +{ + struct cpio *cpio; + + cpio = (struct cpio *)a->format_data; + return (__archive_write_nulls(a, + (size_t)cpio->entry_bytes_remaining)); +} diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_odc.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_odc.c new file mode 100644 index 0000000..091925a --- /dev/null +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_odc.c @@ -0,0 +1,500 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $"); + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#include "archive.h" +#include "archive_entry.h" +#include "archive_entry_locale.h" +#include "archive_private.h" +#include "archive_write_private.h" +#include "archive_write_set_format_private.h" + +static ssize_t archive_write_odc_data(struct archive_write *, + const void *buff, size_t s); +static int archive_write_odc_close(struct archive_write *); +static int archive_write_odc_free(struct archive_write *); +static int archive_write_odc_finish_entry(struct archive_write *); +static int archive_write_odc_header(struct archive_write *, + struct archive_entry *); +static int archive_write_odc_options(struct archive_write *, + const char *, const char *); +static int format_octal(int64_t, void *, int); +static int64_t format_octal_recursive(int64_t, char *, int); +static int write_header(struct archive_write *, struct archive_entry *); + +struct cpio { + uint64_t entry_bytes_remaining; + + int64_t ino_next; + + struct { int64_t old; int new;} *ino_list; + size_t ino_list_size; + size_t ino_list_next; + + struct archive_string_conv *opt_sconv; + struct archive_string_conv *sconv_default; + int init_default_conversion; +}; + +#define c_magic_offset 0 +#define c_magic_size 6 +#define c_dev_offset 6 +#define c_dev_size 6 +#define c_ino_offset 12 +#define c_ino_size 6 +#define c_mode_offset 18 +#define c_mode_size 6 +#define c_uid_offset 24 +#define c_uid_size 6 +#define c_gid_offset 30 +#define c_gid_size 6 +#define c_nlink_offset 36 +#define c_nlink_size 6 +#define c_rdev_offset 42 +#define c_rdev_size 6 +#define c_mtime_offset 48 +#define c_mtime_size 11 +#define c_namesize_offset 59 +#define c_namesize_size 6 +#define c_filesize_offset 65 +#define c_filesize_size 11 + +/* + * Set output format to 'cpio' format. + */ +int +archive_write_set_format_cpio_odc(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + struct cpio *cpio; + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_odc"); + + /* If someone else was already registered, unregister them. */ + if (a->format_free != NULL) + (a->format_free)(a); + + cpio = (struct cpio *)calloc(1, sizeof(*cpio)); + if (cpio == NULL) { + archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); + return (ARCHIVE_FATAL); + } + a->format_data = cpio; + a->format_name = "cpio"; + a->format_options = archive_write_odc_options; + a->format_write_header = archive_write_odc_header; + a->format_write_data = archive_write_odc_data; + a->format_finish_entry = archive_write_odc_finish_entry; + a->format_close = archive_write_odc_close; + a->format_free = archive_write_odc_free; + a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; + a->archive.archive_format_name = "POSIX cpio"; + return (ARCHIVE_OK); +} + +static int +archive_write_odc_options(struct archive_write *a, const char *key, + const char *val) +{ + struct cpio *cpio = (struct cpio *)a->format_data; + int ret = ARCHIVE_FAILED; + + if (strcmp(key, "hdrcharset") == 0) { + if (val == NULL || val[0] == 0) + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "%s: hdrcharset option needs a character-set name", + a->format_name); + else { + cpio->opt_sconv = archive_string_conversion_to_charset( + &a->archive, val, 0); + if (cpio->opt_sconv != NULL) + ret = ARCHIVE_OK; + else + ret = ARCHIVE_FATAL; + } + return (ret); + } + + /* Note: The "warn" return is just to inform the options + * supervisor that we didn't handle it. It will generate + * a suitable error if no one used this option. */ + return (ARCHIVE_WARN); +} + +/* + * Ino values are as long as 64 bits on some systems; cpio format + * only allows 18 bits and relies on the ino values to identify hardlinked + * files. So, we can't merely "hash" the ino numbers since collisions + * would corrupt the archive. Instead, we generate synthetic ino values + * to store in the archive and maintain a map of original ino values to + * synthetic ones so we can preserve hardlink information. + * + * TODO: Make this more efficient. It's not as bad as it looks (most + * files don't have any hardlinks and we don't do any work here for those), + * but it wouldn't be hard to do better. + * + * TODO: Work with dev/ino pairs here instead of just ino values. + */ +static int +synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry) +{ + int64_t ino = archive_entry_ino64(entry); + int ino_new; + size_t i; + + /* + * If no index number was given, don't assign one. In + * particular, this handles the end-of-archive marker + * correctly by giving it a zero index value. (This is also + * why we start our synthetic index numbers with one below.) + */ + if (ino == 0) + return (0); + + /* Don't store a mapping if we don't need to. */ + if (archive_entry_nlink(entry) < 2) { + return (int)(++cpio->ino_next); + } + + /* Look up old ino; if we have it, this is a hardlink + * and we reuse the same value. */ + for (i = 0; i < cpio->ino_list_next; ++i) { + if (cpio->ino_list[i].old == ino) + return (cpio->ino_list[i].new); + } + + /* Assign a new index number. */ + ino_new = (int)(++cpio->ino_next); + + /* Ensure space for the new mapping. */ + if (cpio->ino_list_size <= cpio->ino_list_next) { + size_t newsize = cpio->ino_list_size < 512 + ? 512 : cpio->ino_list_size * 2; + void *newlist = realloc(cpio->ino_list, + sizeof(cpio->ino_list[0]) * newsize); + if (newlist == NULL) + return (-1); + + cpio->ino_list_size = newsize; + cpio->ino_list = newlist; + } + + /* Record and return the new value. */ + cpio->ino_list[cpio->ino_list_next].old = ino; + cpio->ino_list[cpio->ino_list_next].new = ino_new; + ++cpio->ino_list_next; + return (ino_new); +} + + +static struct archive_string_conv * +get_sconv(struct archive_write *a) +{ + struct cpio *cpio; + struct archive_string_conv *sconv; + + cpio = (struct cpio *)a->format_data; + sconv = cpio->opt_sconv; + if (sconv == NULL) { + if (!cpio->init_default_conversion) { + cpio->sconv_default = + archive_string_default_conversion_for_write( + &(a->archive)); + cpio->init_default_conversion = 1; + } + sconv = cpio->sconv_default; + } + return (sconv); +} + +static int +archive_write_odc_header(struct archive_write *a, struct archive_entry *entry) +{ + const char *path; + size_t len; + + if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) { + archive_set_error(&a->archive, -1, "Filetype required"); + return (ARCHIVE_FAILED); + } + + if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0 + && errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Pathname"); + return (ARCHIVE_FATAL); + } + if (len == 0 || path == NULL || path[0] == '\0') { + archive_set_error(&a->archive, -1, "Pathname required"); + return (ARCHIVE_FAILED); + } + + if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) { + archive_set_error(&a->archive, -1, "Size required"); + return (ARCHIVE_FAILED); + } + return write_header(a, entry); +} + +static int +write_header(struct archive_write *a, struct archive_entry *entry) +{ + struct cpio *cpio; + const char *p, *path; + int pathlength, ret, ret_final; + int64_t ino; + char h[76]; + struct archive_string_conv *sconv; + struct archive_entry *entry_main; + size_t len; + + cpio = (struct cpio *)a->format_data; + ret_final = ARCHIVE_OK; + sconv = get_sconv(a); + +#if defined(_WIN32) && !defined(__CYGWIN__) + /* Make sure the path separators in pathname, hardlink and symlink + * are all slash '/', not the Windows path separator '\'. */ + entry_main = __la_win_entry_in_posix_pathseparator(entry); + if (entry_main == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate ustar data"); + return(ARCHIVE_FATAL); + } + if (entry != entry_main) + entry = entry_main; + else + entry_main = NULL; +#else + entry_main = NULL; +#endif + + ret = archive_entry_pathname_l(entry, &path, &len, sconv); + if (ret != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Pathname"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate pathname '%s' to %s", + archive_entry_pathname(entry), + archive_string_conversion_charset_name(sconv)); + ret_final = ARCHIVE_WARN; + } + /* Include trailing null. */ + pathlength = (int)len + 1; + + memset(h, 0, sizeof(h)); + format_octal(070707, h + c_magic_offset, c_magic_size); + format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size); + + ino = synthesize_ino_value(cpio, entry); + if (ino < 0) { + archive_set_error(&a->archive, ENOMEM, + "No memory for ino translation table"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } else if (ino > 0777777) { + archive_set_error(&a->archive, ERANGE, + "Too many files for this cpio format"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + format_octal(ino & 0777777, h + c_ino_offset, c_ino_size); + + /* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */ + format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size); + format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size); + format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size); + format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size); + if (archive_entry_filetype(entry) == AE_IFBLK + || archive_entry_filetype(entry) == AE_IFCHR) + format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size); + else + format_octal(0, h + c_rdev_offset, c_rdev_size); + format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size); + format_octal(pathlength, h + c_namesize_offset, c_namesize_size); + + /* Non-regular files don't store bodies. */ + if (archive_entry_filetype(entry) != AE_IFREG) + archive_entry_set_size(entry, 0); + + /* Symlinks get the link written as the body of the entry. */ + ret = archive_entry_symlink_l(entry, &p, &len, sconv); + if (ret != 0) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory for Linkname"); + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Can't translate linkname '%s' to %s", + archive_entry_symlink(entry), + archive_string_conversion_charset_name(sconv)); + ret_final = ARCHIVE_WARN; + } + if (len > 0 && p != NULL && *p != '\0') + ret = format_octal(strlen(p), h + c_filesize_offset, + c_filesize_size); + else + ret = format_octal(archive_entry_size(entry), + h + c_filesize_offset, c_filesize_size); + if (ret) { + archive_set_error(&a->archive, ERANGE, + "File is too large for cpio format."); + ret_final = ARCHIVE_FAILED; + goto exit_write_header; + } + + ret = __archive_write_output(a, h, sizeof(h)); + if (ret != ARCHIVE_OK) { + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + + ret = __archive_write_output(a, path, pathlength); + if (ret != ARCHIVE_OK) { + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + + cpio->entry_bytes_remaining = archive_entry_size(entry); + + /* Write the symlink now. */ + if (p != NULL && *p != '\0') { + ret = __archive_write_output(a, p, strlen(p)); + if (ret != ARCHIVE_OK) { + ret_final = ARCHIVE_FATAL; + goto exit_write_header; + } + } +exit_write_header: + archive_entry_free(entry_main); + return (ret_final); +} + +static ssize_t +archive_write_odc_data(struct archive_write *a, const void *buff, size_t s) +{ + struct cpio *cpio; + int ret; + + cpio = (struct cpio *)a->format_data; + if (s > cpio->entry_bytes_remaining) + s = (size_t)cpio->entry_bytes_remaining; + + ret = __archive_write_output(a, buff, s); + cpio->entry_bytes_remaining -= s; + if (ret >= 0) + return (s); + else + return (ret); +} + +/* + * Format a number into the specified field. + */ +static int +format_octal(int64_t v, void *p, int digits) +{ + int64_t max; + int ret; + + max = (((int64_t)1) << (digits * 3)) - 1; + if (v >= 0 && v <= max) { + format_octal_recursive(v, (char *)p, digits); + ret = 0; + } else { + format_octal_recursive(max, (char *)p, digits); + ret = -1; + } + return (ret); +} + +static int64_t +format_octal_recursive(int64_t v, char *p, int s) +{ + if (s == 0) + return (v); + v = format_octal_recursive(v, p+1, s-1); + *p = '0' + ((char)v & 7); + return (v >> 3); +} + +static int +archive_write_odc_close(struct archive_write *a) +{ + int er; + struct archive_entry *trailer; + + trailer = archive_entry_new2(NULL); + /* nlink = 1 here for GNU cpio compat. */ + archive_entry_set_nlink(trailer, 1); + archive_entry_set_size(trailer, 0); + archive_entry_set_pathname(trailer, "TRAILER!!!"); + er = write_header(a, trailer); + archive_entry_free(trailer); + return (er); +} + +static int +archive_write_odc_free(struct archive_write *a) +{ + struct cpio *cpio; + + cpio = (struct cpio *)a->format_data; + free(cpio->ino_list); + free(cpio); + a->format_data = NULL; + return (ARCHIVE_OK); +} + +static int +archive_write_odc_finish_entry(struct archive_write *a) +{ + struct cpio *cpio; + + cpio = (struct cpio *)a->format_data; + return (__archive_write_nulls(a, + (size_t)cpio->entry_bytes_remaining)); +} diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c index 68e3fe3..3190b46 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c @@ -6802,6 +6802,7 @@ isoent_rr_move(struct archive_write *a) * This comparing rule is according to ISO9660 Standard 6.9.1 */ static int +__LA_LIBC_CC _compare_path_table(const void *v1, const void *v2) { const struct isoent *p1, *p2; @@ -6844,6 +6845,7 @@ _compare_path_table(const void *v1, const void *v2) } static int +__LA_LIBC_CC _compare_path_table_joliet(const void *v1, const void *v2) { const struct isoent *p1, *p2; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c index a2b2710..5291149 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c @@ -1028,10 +1028,8 @@ archive_write_pax_header(struct archive_write *a, archive_string_init(&entry_name); archive_strcpy(&entry_name, archive_entry_pathname(entry_main)); - /* If file size is too large, add 'size' to pax extended attrs. */ + /* If file size is too large, we need pax extended attrs. */ if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) { - add_pax_attr_int(&(pax->pax_header), "size", - archive_entry_size(entry_main)); need_extension = 1; } @@ -1347,6 +1345,12 @@ archive_write_pax_header(struct archive_write *a, mapsize + pax->sparse_map_padding + sparse_total); } + /* If file size is too large, add 'size' to pax extended attrs. */ + if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) { + add_pax_attr_int(&(pax->pax_header), "size", + archive_entry_size(entry_main)); + } + /* Format 'ustar' header for main entry. * * The trouble with file size: If the reader can't understand diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c index 66a1f84..530e1e8 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c @@ -740,12 +740,16 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) /* We may know the size, but never the CRC. */ zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END; } else { - /* We don't know the size. In this case, we prefer - * deflate (it has a clear end-of-data marker which - * makes length-at-end more reliable) and will - * enable Zip64 extensions unless we're told not to. + /* We don't know the size. Use the default + * compression unless specified otherwise. + * We enable Zip64 extensions unless we're told not to. */ - zip->entry_compression = COMPRESSION_DEFAULT; + + zip->entry_compression = zip->requested_compression; + if(zip->entry_compression == COMPRESSION_UNSPECIFIED){ + zip->entry_compression = COMPRESSION_DEFAULT; + } + zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END; if ((zip->flags & ZIP_FLAG_AVOID_ZIP64) == 0) { zip->entry_uses_zip64 = 1; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_options.3 b/Utilities/cmlibarchive/libarchive/archive_write_set_options.3 index d4a52e3..dd57358 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_options.3 +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_options.3 @@ -279,7 +279,7 @@ Values between 0 and 9 are supported. The interpretation of the compression level depends on the chosen compression method. .El -.It Format cpio +.It Format bin .Bl -tag -compact -width indent .It Cm hdrcharset The value is used as a character set name that will be @@ -519,6 +519,18 @@ XXX needs explanation XXX The value is used as a character set name that will be used when translating file names. .El +.It Format odc +.Bl -tag -compact -width indent +.It Cm hdrcharset +The value is used as a character set name that will be +used when translating file names. +.El +.It Format pwb +.Bl -tag -compact -width indent +.It Cm hdrcharset +The value is used as a character set name that will be +used when translating file names. +.El .It Format pax .Bl -tag -compact -width indent .It Cm hdrcharset diff --git a/Utilities/cmlibarchive/libarchive/config_freebsd.h b/Utilities/cmlibarchive/libarchive/config_freebsd.h index a484618..758621c 100644 --- a/Utilities/cmlibarchive/libarchive/config_freebsd.h +++ b/Utilities/cmlibarchive/libarchive/config_freebsd.h @@ -138,6 +138,7 @@ #define HAVE_LIBZ 1 #define HAVE_LIMITS_H 1 #define HAVE_LINK 1 +#define HAVE_LINKAT 1 #define HAVE_LOCALE_H 1 #define HAVE_LOCALTIME_R 1 #define HAVE_LONG_LONG_INT 1 @@ -235,6 +236,14 @@ #define HAVE_ZLIB_H 1 #define TIME_WITH_SYS_TIME 1 +#if __FreeBSD_version >= 800505 +#define HAVE_LIBLZMA 1 +#define HAVE_LZMA_H 1 +#if __FreeBSD_version >= 1002504 +#define HAVE_LZMA_STREAM_ENCODER_MT 1 +#endif +#endif + #if __FreeBSD_version >= 1100056 #define HAVE_FUTIMENS 1 #define HAVE_UTIMENSAT 1 diff --git a/Utilities/cmlibarchive/libarchive/cpio.5 b/Utilities/cmlibarchive/libarchive/cpio.5 index a91f0c5..837a456 100644 --- a/Utilities/cmlibarchive/libarchive/cpio.5 +++ b/Utilities/cmlibarchive/libarchive/cpio.5 @@ -56,40 +56,44 @@ The end of the archive is indicated by a special record with the pathname .Dq TRAILER!!! . .Ss PWB format -XXX Any documentation of the original PWB/UNIX 1.0 format? XXX -.Ss Old Binary Format -The old binary +The PWB binary .Nm -format stores numbers as 2-byte and 4-byte binary values. +format is the original format, when cpio was introduced as part of the +Programmer's Work Bench system, a variant of 6th Edition UNIX. It +stores numbers as 2-byte and 4-byte binary values. Each entry begins with a header in the following format: +.Pp .Bd -literal -offset indent -struct header_old_cpio { - unsigned short c_magic; - unsigned short c_dev; - unsigned short c_ino; - unsigned short c_mode; - unsigned short c_uid; - unsigned short c_gid; - unsigned short c_nlink; - unsigned short c_rdev; - unsigned short c_mtime[2]; - unsigned short c_namesize; - unsigned short c_filesize[2]; +struct header_pwb_cpio { + short h_magic; + short h_dev; + short h_ino; + short h_mode; + short h_uid; + short h_gid; + short h_nlink; + short h_majmin; + long h_mtime; + short h_namesize; + long h_filesize; }; .Ed .Pp The -.Va unsigned short -fields here are 16-bit integer values; the -.Va unsigned int -fields are 32-bit integer values. -The fields are as follows +.Va short +fields here are 16-bit integer values, while the +.Va long +fields are 32 bit integers. Since PWB UNIX, like the 6th Edition UNIX +it was based on, only ran on PDP-11 computers, they +are in PDP-endian format, which has little-endian shorts, and +big-endian longs. That is, the long integer whose hexadecimal +representation is 0x12345678 would be stored in four successive bytes +as 0x34, 0x12, 0x78, 0x56. +The fields are as follows: .Bl -tag -width indent -.It Va magic +.It Va h_magic The integer value octal 070707. -This value can be used to determine whether this archive is -written with little-endian or big-endian integers. -.It Va dev , Va ino +.It Va h_dev , Va h_ino The device and inode numbers from the disk. These are used by programs that read .Nm @@ -97,78 +101,138 @@ archives to determine when two entries refer to the same file. Programs that synthesize .Nm archives should be careful to set these to distinct values for each entry. -.It Va mode -The mode specifies both the regular permissions and the file type. -It consists of several bit fields as follows: +.It Va h_mode +The mode specifies both the regular permissions and the file type, and +it also holds a couple of bits that are irrelevant to the cpio format, +because the field is actually a raw copy of the mode field in the inode +representing the file. These are the IALLOC flag, which shows that +the inode entry is in use, and the ILARG flag, which shows that the +file it represents is large enough to have indirect blocks pointers in +the inode. +The mode is decoded as follows: +.Pp .Bl -tag -width "MMMMMMM" -compact -.It 0170000 -This masks the file type bits. -.It 0140000 -File type value for sockets. -.It 0120000 -File type value for symbolic links. -For symbolic links, the link body is stored as file data. .It 0100000 -File type value for regular files. +IALLOC flag - irrelevant to cpio. .It 0060000 -File type value for block special devices. +This masks the file type bits. .It 0040000 File type value for directories. .It 0020000 File type value for character special devices. +.It 0060000 +File type value for block special devices. .It 0010000 -File type value for named pipes or FIFOs. +ILARG flag - irrelevant to cpio. .It 0004000 SUID bit. .It 0002000 SGID bit. .It 0001000 Sticky bit. -On some systems, this modifies the behavior of executables and/or directories. .It 0000777 The lower 9 bits specify read/write/execute permissions for world, group, and user following standard POSIX conventions. .El -.It Va uid , Va gid +.It Va h_uid , Va h_gid The numeric user id and group id of the owner. -.It Va nlink +.It Va h_nlink The number of links to this file. Directories always have a value of at least two here. Note that hardlinked files include file data with every copy in the archive. -.It Va rdev +.It Va h_majmin For block special and character special entries, -this field contains the associated device number. +this field contains the associated device number, with the major +number in the high byte, and the minor number in the low byte. For all other entry types, it should be set to zero by writers and ignored by readers. -.It Va mtime +.It Va h_mtime Modification time of the file, indicated as the number of seconds since the start of the epoch, 00:00:00 UTC January 1, 1970. -The four-byte integer is stored with the most-significant 16 bits first -followed by the least-significant 16 bits. -Each of the two 16 bit values are stored in machine-native byte order. -.It Va namesize +.It Va h_namesize The number of bytes in the pathname that follows the header. This count includes the trailing NUL byte. -.It Va filesize -The size of the file. -Note that this archive format is limited to -four gigabyte file sizes. -See -.Va mtime -above for a description of the storage of four-byte integers. +.It Va h_filesize +The size of the file. Note that this archive format is limited to 16 +megabyte file sizes, because PWB UNIX, like 6th Edition, only used +an unsigned 24 bit integer for the file size internally. .El .Pp The pathname immediately follows the fixed header. -If the -.Cm namesize +If +.Cm h_namesize is odd, an additional NUL byte is added after the pathname. -The file data is then appended, padded with NUL -bytes to an even length. +The file data is then appended, again with an additional NUL +appended if needed to get the next header at an even offset. .Pp Hardlinked files are not given special treatment; the full file contents are included with each copy of the file. +.Ss New Binary Format +The new binary +.Nm +format showed up when cpio was adopted into late 7th Edition UNIX. +It is exactly like the PWB binary format, described above, except for +three changes: +.Pp +First, UNIX now ran on more than one hardware type, so the endianness +of 16 bit integers must be determined by observing the magic number at +the start of the header. The 32 bit integers are still always stored +with the most significant word first, though, so each of those two, in +the struct shown above, was stored as an array of two 16 bit integers, +in the traditional order. Those 16 bit integers, like all the others +in the struct, were accessed using a macro that byte swapped them if +necessary. +.Pp +Next, 7th Edition had more file types to store, and the IALLOC and ILARG +flag bits were re-purposed to accommodate these. The revised use of the +various bits is as follows: +.Pp +.Bl -tag -width "MMMMMMM" -compact +.It 0170000 +This masks the file type bits. +.It 0140000 +File type value for sockets. +.It 0120000 +File type value for symbolic links. +For symbolic links, the link body is stored as file data. +.It 0100000 +File type value for regular files. +.It 0060000 +File type value for block special devices. +.It 0040000 +File type value for directories. +.It 0020000 +File type value for character special devices. +.It 0010000 +File type value for named pipes or FIFOs. +.It 0004000 +SUID bit. +.It 0002000 +SGID bit. +.It 0001000 +Sticky bit. +.It 0000777 +The lower 9 bits specify read/write/execute permissions +for world, group, and user following standard POSIX conventions. +.El +.Pp +Finally, the file size field now represents a signed 32 bit integer in +the underlying file system, so the maximum file size has increased to +2 gigabytes. +.Pp +Note that there is no obvious way to tell which of the two binary +formats an archive uses, other than to see which one makes more +sense. The typical error scenario is that a PWB format archive +unpacked as if it were in the new format will create named sockets +instead of directories, and then fail to unpack files that should +go in those directories. Running +.Va bsdcpio -itv +on an unknown archive will make it obvious which it is: if it's +PWB format, directories will be listed with an 's' instead of +a 'd' as the first character of the mode string, and the larger +files will have a '?' in that position. .Ss Portable ASCII Format .St -susv2 standardized an ASCII variant that is portable across all @@ -180,6 +244,7 @@ format or as the format. It stores the same numeric fields as the old binary format, but represents them as 6-character or 11-character octal values. +.Pp .Bd -literal -offset indent struct cpio_odc_header { char c_magic[6]; @@ -196,9 +261,9 @@ struct cpio_odc_header { }; .Ed .Pp -The fields are identical to those in the old binary format. +The fields are identical to those in the new binary format. The name and file body follow the fixed header. -Unlike the old binary format, there is no additional padding +Unlike the binary formats, there is no additional padding after the pathname or file contents. If the files being archived are themselves entirely ASCII, then the resulting archive will be entirely ASCII, except for the @@ -207,6 +272,7 @@ NUL byte that terminates the name field. The "new" ASCII format uses 8-byte hexadecimal fields for all numbers and separates device numbers into separate fields for major and minor numbers. +.Pp .Bd -literal -offset indent struct cpio_newc_header { char c_magic[6]; @@ -227,7 +293,7 @@ struct cpio_newc_header { .Ed .Pp Except as specified below, the fields here match those specified -for the old binary format above. +for the new binary format above. .Bl -tag -width indent .It Va magic The string @@ -288,9 +354,9 @@ while working in AT&T's Unix Support Group. It appeared in 1977 as part of PWB/UNIX 1.0, the .Dq Programmer's Work Bench derived from -.At v6 +.At 6th Edition UNIX that was used internally at AT&T. -Both the old binary and old character formats were in use +Both the new binary and old character formats were in use by 1980, according to the System III source released by SCO under their .Dq Ancient Unix @@ -304,9 +370,9 @@ The format is mis-named, as it uses a simple checksum and not a cyclic redundancy check. .Pp -The old binary format is limited to 16 bits for user id, -group id, device, and inode numbers. -It is limited to 4 gigabyte file sizes. +The binary formats are limited to 16 bits for user id, group id, +device, and inode numbers. They are limited to 16 megabyte and 2 +gigabyte file sizes for the older and newer variants, respectively. .Pp The old ASCII format is limited to 18 bits for the user id, group id, device, and inode numbers. diff --git a/Utilities/cmlibarchive/libarchive/filter_fork_windows.c b/Utilities/cmlibarchive/libarchive/filter_fork_windows.c index 8d11179..0b96397 100644 --- a/Utilities/cmlibarchive/libarchive/filter_fork_windows.c +++ b/Utilities/cmlibarchive/libarchive/filter_fork_windows.c @@ -31,6 +31,43 @@ #include "filter_fork.h" +/* There are some editions of Windows ("nano server," for example) that + * do not host user32.dll. If we want to keep running on those editions, + * we need to delay-load WaitForInputIdle. */ +static void * +la_GetFunctionUser32(const char *name) +{ + static HINSTANCE lib; + static int set; + if (!set) { + set = 1; + lib = LoadLibrary(TEXT("user32.dll")); + } + if (lib == NULL) { + return NULL; + } + return (void *)GetProcAddress(lib, name); +} + +static int +la_WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds) +{ + static DWORD (WINAPI *f)(HANDLE, DWORD); + static int set; + + if (!set) { + set = 1; + f = la_GetFunctionUser32("WaitForInputIdle"); + } + + if (!f) { + /* An inability to wait for input idle is + * not _good_, but it is not catastrophic. */ + return WAIT_FAILED; + } + return (*f)(hProcess, dwMilliseconds); +} + int __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, HANDLE *out_child) @@ -149,7 +186,7 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0, NULL, NULL, &staInfo, &childInfo) == 0) goto fail; - WaitForInputIdle(childInfo.hProcess, INFINITE); + la_WaitForInputIdle(childInfo.hProcess, INFINITE); CloseHandle(childInfo.hProcess); CloseHandle(childInfo.hThread); diff --git a/Utilities/cmlibarchive/libarchive/libarchive-formats.5 b/Utilities/cmlibarchive/libarchive/libarchive-formats.5 index 62359dd..5a118ff 100644 --- a/Utilities/cmlibarchive/libarchive/libarchive-formats.5 +++ b/Utilities/cmlibarchive/libarchive/libarchive-formats.5 @@ -201,28 +201,27 @@ POSIX.1-2001 extended the ustar format to create the .Dq pax interchange format. .Ss Cpio Formats -The libarchive library can read a number of common cpio variants and can write -.Dq odc -and -.Dq newc -format archives. -A cpio archive stores each entry as a fixed-size header followed -by a variable-length filename and variable-length data. -Unlike the tar format, the cpio format does only minimal padding -of the header or file data. -There are several cpio variants, which differ primarily in -how they store the initial header: some store the values as -octal or hexadecimal numbers in ASCII, others as binary values of -varying byte order and length. +The libarchive library can read and write a number of common cpio +variants. A cpio archive stores each entry as a fixed-size header +followed by a variable-length filename and variable-length data. +Unlike the tar format, the cpio format does only minimal padding of +the header or file data. There are several cpio variants, which +differ primarily in how they store the initial header: some store the +values as octal or hexadecimal numbers in ASCII, others as binary +values of varying byte order and length. .Bl -tag -width indent .It Cm binary -The libarchive library transparently reads both big-endian and little-endian -variants of the original binary cpio format. -This format used 32-bit binary values for file size and mtime, -and 16-bit binary values for the other fields. +The libarchive library transparently reads both big-endian and +little-endian variants of the the two binary cpio formats; the +original one from PWB/UNIX, and the later, more widely used, variant. +This format used 32-bit binary values for file size and mtime, and +16-bit binary values for the other fields. The formats support only +the file types present in UNIX at the time of their creation. File +sizes are limited to 24 bits in the PWB format, because of the limits +of the file system, and to 31 bits in the newer binary format, where +signed 32 bit longs were used. .It Cm odc -The libarchive library can both read and write this -POSIX-standard format, which is officially known as the +This is the POSIX standardized format, which is officially known as the .Dq cpio interchange format or the .Dq octet-oriented cpio archive format diff --git a/Utilities/cmlibarchive/libarchive/libarchive.3 b/Utilities/cmlibarchive/libarchive/libarchive.3 index c6894d2..6490562 100644 --- a/Utilities/cmlibarchive/libarchive/libarchive.3 +++ b/Utilities/cmlibarchive/libarchive/libarchive.3 @@ -62,30 +62,40 @@ GNU-format tar archives, .It most common cpio archive formats, .It -ISO9660 CD images (including RockRidge and Joliet extensions), -.It -Zip archives, +7-Zip archives, .It ar archives (including GNU/SysV and BSD extensions), .It Microsoft CAB archives, .It +ISO9660 CD images (including RockRidge and Joliet extensions), +.It LHA archives, .It mtree file tree descriptions, .It -RAR archives, +RAR and most RAR5 archives, .It -XAR archives. +WARC archives, +.It +XAR archives, +.It +Zip archives. .El The library automatically detects archives compressed with -.Xr gzip 1 , +.Xr compress 1 , .Xr bzip2 1 , -.Xr xz 1 , +.Xr grzip 1 , +.Xr gzip 1 , +.Xr lrzip 1 , +.Xr lz4 1 , .Xr lzip 1 , +.Xr lzop 1 , +.Xr xz 1 , or -.Xr compress 1 -and decompresses them transparently. +.Xr zstd 1 +and decompresses them transparently. Decompression of some formats +requires external decompressor utilities. It can similarly detect and decode archives processed with .Xr uuencode 1 or which have an @@ -105,21 +115,21 @@ POSIX .Dq pax interchange format archives, .It -POSIX octet-oriented cpio archives, +cpio archives, .It -Zip archive, +7-Zip archives, +.It +ar archives, .It two different variants of shar archives, .It ISO9660 CD images, .It -7-Zip archives, -.It -ar archives, -.It mtree file tree descriptions, .It -XAR archives. +XAR archives, +.It +Zip archive. .El Pax interchange format is an extension of the tar archive format that eliminates essentially all of the limitations of historic tar formats diff --git a/Utilities/cmlibarchive/libarchive/xxhash.c b/Utilities/cmlibarchive/libarchive/xxhash.c index 70750ba..f96e9d9 100644 --- a/Utilities/cmlibarchive/libarchive/xxhash.c +++ b/Utilities/cmlibarchive/libarchive/xxhash.c @@ -150,7 +150,11 @@ typedef struct _U32_S { U32 v; } _PACKED U32_S; #if GCC_VERSION >= 409 __attribute__((__no_sanitize_undefined__)) #endif -static inline U32 A32(const void * x) +#if defined(_MSC_VER) +static __inline U32 A32(const void * x) +#else +static inline U32 A32(const void* x) +#endif { return (((const U32_S *)(x))->v); } |