diff options
author | Martin Matuska <mm@FreeBSD.org> | 2023-07-18 07:58:47 +0000 |
---|---|---|
committer | Martin Matuska <mm@FreeBSD.org> | 2023-07-18 07:58:47 +0000 |
commit | 14b646f7c3f709cd0de2d59db3691273bc8d6d16 (patch) | |
tree | ee81e774d1ba68986bf260cd6e094b9f44d944de | |
parent | 309e35276a045cc5ae7f9414c80765863d4a09c4 (diff) | |
download | src-14b646f7c3f709cd0de2d59db3691273bc8d6d16.tar.gz src-14b646f7c3f709cd0de2d59db3691273bc8d6d16.zip |
Update vendor/libarchive to libarchive/libarchive@ee4579617
Important changes (relevant to FreeBSD):
#1840 year 2038 fix for pax archives on platforms with 64-bit time_t
#1873 bsdunzip ported to libarchive from FreeBSD
#1894 read support for zstd compression in 7zip archives
#1918 ARM64 filter support in 7zip archives
Obtained from: libarchive
Libarchive commit: ee45796171324519f0c0bfd012018dd099296336
Libarchive tag: v3.7.0
81 files changed, 4260 insertions, 125 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index e53133da59dd..d942f851c95d 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -10,21 +10,21 @@ FreeBSD_task: BS: cmake matrix: freebsd_instance: - image_family: freebsd-13-1 + image_family: freebsd-13-2 freebsd_instance: - image_family: freebsd-12-3 + image_family: freebsd-12-4 prepare_script: - ./build/ci/cirrus_ci/ci.sh prepare configure_script: - env CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a autogen - env CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a configure build_script: - - ./build/ci/build.sh -a build + - env MAKE_ARGS="-j 2" ./build/ci/build.sh -a build test_script: - - env SKIP_TEST_RESTORE_ATIME=1 ./build/ci/build.sh -a test + - env SKIP_TEST_RESTORE_ATIME=1 MAKE_ARGS="-j 2" ./build/ci/build.sh -a test - ./build/ci/cirrus_ci/ci.sh test install_script: - - ./build/ci/build.sh -a install + - env MAKE_ARGS="-j 2" ./build/ci/build.sh -a install Windows_Cygwin_task: windows_container: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac2fa7e98d04..1d7b32e235a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: MacOS: - runs-on: macos-12 + runs-on: macos-13 strategy: matrix: bs: [autotools, cmake] @@ -24,15 +24,19 @@ jobs: run: ./build/ci/build.sh -a build env: BS: ${{ matrix.bs }} + MAKE_ARGS: -j - name: Test run: ./build/ci/build.sh -a test env: BS: ${{ matrix.bs }} SKIP_OPEN_FD_ERR_TEST: 1 + IGNORE_TRAVERSALS_TEST4: 1 + MAKE_ARGS: -j - name: Install run: ./build/ci/build.sh -a install env: BS: ${{ matrix.bs }} + MAKE_ARGS: -j - name: Artifact run: ./build/ci/build.sh -a artifact env: @@ -50,6 +54,8 @@ jobs: crypto: [mbedtls, nettle, openssl] steps: - uses: actions/checkout@master + - name: Update apt cache + run: sudo apt-get update - name: Install dependencies run: sudo apt-get install -y autoconf automake build-essential cmake git libssl-dev nettle-dev libmbedtls-dev libacl1-dev libbz2-dev liblzma-dev liblz4-dev libzstd-dev lzop pkg-config zlib1g-dev - name: Autogen @@ -65,11 +71,13 @@ jobs: run: ./build/ci/build.sh -a build env: BS: ${{ matrix.bs }} + MAKE_ARGS: -j - name: Test run: ./build/ci/build.sh -a test env: BS: ${{ matrix.bs }} SKIP_OPEN_FD_ERR_TEST: 1 + MAKE_ARGS: -j - name: Install run: ./build/ci/build.sh -a install env: @@ -86,6 +94,8 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@master + - name: Update package definitions + run: sudo apt-get update - name: Install dependencies run: sudo apt-get install -y autoconf automake bsdmainutils build-essential cmake ghostscript git groff libssl-dev libacl1-dev libbz2-dev liblzma-dev liblz4-dev libzstd-dev lzop pkg-config zip zlib1g-dev - name: Autogen diff --git a/.gitignore b/.gitignore index 6b4d2dc76455..359b652368d0 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ autom4te.cache/ bsdcat bsdcpio bsdtar +bsdunzip build/autoconf/compile build/autoconf/config.guess build/autoconf/config.sub @@ -41,6 +42,7 @@ libarchive/test/list.h libtool stamp-h1 tar/test/list.h +unzip/test/list.h CMakeCache.txt CMakeFiles/ DartConfiguration.tcl diff --git a/CMakeLists.txt b/CMakeLists.txt index dbb95e34d3fd..764fe5d4c025 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ endif() # RelWithDebInfo : Release build with Debug Info # MinSizeRel : Release Min Size build IF(NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build Type" FORCE) + SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE) ENDIF(NOT CMAKE_BUILD_TYPE) # Set a value type to properly display CMAKE_BUILD_TYPE on GUI if the # value type is "UNINITIALIZED". @@ -199,6 +199,8 @@ ENDIF (MSVC) # Enable CTest/CDash support include(CTest) +option(BUILD_SHARED_LIBS "Build shared libraries" ON) + OPTION(ENABLE_MBEDTLS "Enable use of mbed TLS" OFF) OPTION(ENABLE_NETTLE "Enable use of Nettle" OFF) OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON) @@ -223,6 +225,13 @@ OPTION(ENABLE_CPIO "Enable cpio building" ON) OPTION(ENABLE_CPIO_SHARED "Enable dynamic build of cpio" FALSE) OPTION(ENABLE_CAT "Enable cat building" ON) OPTION(ENABLE_CAT_SHARED "Enable dynamic build of cat" FALSE) +IF(WIN32 AND NOT CYGWIN) + SET(ENABLE_UNZIP FALSE) + SET(ENABLE_UNZIP_SHARED FALSE) +ELSE() + OPTION(ENABLE_UNZIP "Enable unzip building" ON) + OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE) +ENDIF() OPTION(ENABLE_XATTR "Enable extended attribute support" ON) OPTION(ENABLE_ACL "Enable ACL support" ON) OPTION(ENABLE_ICONV "Enable iconv support" ON) @@ -370,7 +379,11 @@ MACRO (TRY_MACRO_FOR_LIBRARY INCLUDES LIBRARIES IF("${TRY_TYPE}" MATCHES "COMPILES") CHECK_C_SOURCE_COMPILES("${SAMPLE_SOURCE}" ${VAR}) ELSEIF("${TRY_TYPE}" MATCHES "RUNS") - CHECK_C_SOURCE_RUNS("${SAMPLE_SOURCE}" ${VAR}) + IF(CMAKE_CROSSCOMPILING) + MESSAGE(WARNING "Cannot test run \"${VAR}\" when cross-compiling") + ELSE(CMAKE_CROSSCOMPILING) + CHECK_C_SOURCE_RUNS("${SAMPLE_SOURCE}" ${VAR}) + ENDIF(CMAKE_CROSSCOMPILING) ELSE("${TRY_TYPE}" MATCHES "COMPILES") MESSAGE(FATAL_ERROR "UNKNOWN KEYWORD \"${TRY_TYPE}\" FOR TRY_TYPE") ENDIF("${TRY_TYPE}" MATCHES "COMPILES") @@ -508,12 +521,16 @@ IF(LIBLZMA_FOUND) COMPILES "#include <lzma.h>\nint main() {return (int)lzma_version_number(); }" "WITHOUT_LZMA_API_STATIC;LZMA_API_STATIC") + CHECK_C_SOURCE_COMPILES( + "#include <lzma.h>\n#if LZMA_VERSION < 50020000\n#error unsupported\n#endif\nint main(void){lzma_stream_encoder_mt(0, 0); return 0;}" + HAVE_LZMA_STREAM_ENCODER_MT) IF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC) ADD_DEFINITIONS(-DLZMA_API_STATIC) ENDIF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC) CMAKE_POP_CHECK_STATE() ELSE(LIBLZMA_FOUND) # LZMA not found and will not be used. + SET(HAVE_LZMA_STREAM_ENCODER_MT 0) ENDIF(LIBLZMA_FOUND) MARK_AS_ADVANCED(CLEAR LIBLZMA_INCLUDE_DIR) MARK_AS_ADVANCED(CLEAR LIBLZMA_LIBRARY) @@ -567,6 +584,7 @@ IF(LIBB2_FOUND) SET(HAVE_BLAKE2_H 1) SET(ARCHIVE_BLAKE2 FALSE) LIST(APPEND ADDITIONAL_LIBS ${LIBB2_LIBRARY}) + INCLUDE_DIRECTORIES(${LIBB2_INCLUDE_DIR}) CMAKE_PUSH_CHECK_STATE() SET(CMAKE_REQUIRED_LIBRARIES ${LIBB2_LIBRARY}) SET(CMAKE_REQUIRED_INCLUDES ${LIBB2_INCLUDE_DIR}) @@ -676,6 +694,7 @@ CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h> int main(void) { return EXT2_IOC_GETFLAGS; }" HAVE_WORKING_EXT2_IOC_GETFLAGS) LA_CHECK_INCLUDE_FILE("fcntl.h" HAVE_FCNTL_H) +LA_CHECK_INCLUDE_FILE("fnmatch.h" HAVE_FNMATCH_H) LA_CHECK_INCLUDE_FILE("grp.h" HAVE_GRP_H) LA_CHECK_INCLUDE_FILE("inttypes.h" HAVE_INTTYPES_H) LA_CHECK_INCLUDE_FILE("io.h" HAVE_IO_H) @@ -715,6 +734,7 @@ LA_CHECK_INCLUDE_FILE("sys/mkdev.h" HAVE_SYS_MKDEV_H) LA_CHECK_INCLUDE_FILE("sys/mount.h" HAVE_SYS_MOUNT_H) LA_CHECK_INCLUDE_FILE("sys/param.h" HAVE_SYS_PARAM_H) LA_CHECK_INCLUDE_FILE("sys/poll.h" HAVE_SYS_POLL_H) +LA_CHECK_INCLUDE_FILE("sys/queue.h" HAVE_SYS_QUEUE_H) LA_CHECK_INCLUDE_FILE("sys/richacl.h" HAVE_SYS_RICHACL_H) LA_CHECK_INCLUDE_FILE("sys/select.h" HAVE_SYS_SELECT_H) LA_CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H) @@ -734,9 +754,9 @@ LA_CHECK_INCLUDE_FILE("wchar.h" HAVE_WCHAR_H) LA_CHECK_INCLUDE_FILE("wctype.h" HAVE_WCTYPE_H) LA_CHECK_INCLUDE_FILE("windows.h" HAVE_WINDOWS_H) IF(ENABLE_CNG) - LA_CHECK_INCLUDE_FILE("Bcrypt.h" HAVE_BCRYPT_H) + LA_CHECK_INCLUDE_FILE("bcrypt.h" HAVE_BCRYPT_H) IF(HAVE_BCRYPT_H) - LIST(APPEND ADDITIONAL_LIBS "Bcrypt") + LIST(APPEND ADDITIONAL_LIBS "bcrypt") ENDIF(HAVE_BCRYPT_H) ELSE(ENABLE_CNG) UNSET(HAVE_BCRYPT_H CACHE) @@ -813,6 +833,10 @@ IF(ENABLE_OPENSSL AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin") SET(HAVE_LIBCRYPTO 1) INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) LIST(APPEND ADDITIONAL_LIBS ${OPENSSL_CRYPTO_LIBRARY}) + SET(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY}) + SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) + LA_CHECK_INCLUDE_FILE("openssl/evp.h" HAVE_OPENSSL_EVP_H) + CHECK_FUNCTION_EXISTS(PKCS5_PBKDF2_HMAC_SHA1 HAVE_PKCS5_PBKDF2_HMAC_SHA1) ENDIF(OPENSSL_FOUND) ELSE() SET(OPENSSL_FOUND FALSE) # Override cached value @@ -1349,6 +1373,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD) CHECK_FUNCTION_EXISTS_GLIBC(fchown HAVE_FCHOWN) CHECK_FUNCTION_EXISTS_GLIBC(fcntl HAVE_FCNTL) CHECK_FUNCTION_EXISTS_GLIBC(fdopendir HAVE_FDOPENDIR) +CHECK_FUNCTION_EXISTS_GLIBC(fnmatch HAVE_FNMATCH) CHECK_FUNCTION_EXISTS_GLIBC(fork HAVE_FORK) CHECK_FUNCTION_EXISTS_GLIBC(fstat HAVE_FSTAT) CHECK_FUNCTION_EXISTS_GLIBC(fstatat HAVE_FSTATAT) @@ -1461,6 +1486,9 @@ CHECK_C_SOURCE_COMPILES( "#include <fcntl.h>\n#include <unistd.h>\nint main() {char buf[10]; return readlinkat(AT_FDCWD, \"\", buf, 0);}" HAVE_READLINKAT) +# Check for getopt uses optreset to reset +CHECK_SYMBOL_EXISTS(optreset "getopt.h" HAVE_GETOPT_OPTRESET) + # To verify major(), we need to both include the header # of interest and verify that the result can be linked. @@ -1473,14 +1501,6 @@ CHECK_C_SOURCE_COMPILES( "#include <sys/sysmacros.h>\nint main() { return major(256); }" MAJOR_IN_SYSMACROS) -IF(ENABLE_LZMA) -CHECK_C_SOURCE_COMPILES( - "#include <lzma.h>\n#if LZMA_VERSION < 50020000\n#error unsupported\n#endif\nint main(void){lzma_stream_encoder_mt(0, 0); return 0;}" - HAVE_LZMA_STREAM_ENCODER_MT) -ELSE() - SET(HAVE_LZMA_STREAM_ENCODER_MT 0) -ENDIF(ENABLE_LZMA) - IF(HAVE_STRERROR_R) SET(HAVE_DECL_STRERROR_R 1) ENDIF(HAVE_STRERROR_R) @@ -2093,3 +2113,4 @@ add_subdirectory(libarchive) add_subdirectory(cat) add_subdirectory(tar) add_subdirectory(cpio) +add_subdirectory(unzip) diff --git a/Makefile.am b/Makefile.am index 3fd2fdbf6c08..7f0198a40c46 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,17 +8,17 @@ ACLOCAL_AMFLAGS = -I build/autoconf # lib_LTLIBRARIES= libarchive.la noinst_LTLIBRARIES= libarchive_fe.la -bin_PROGRAMS= $(bsdtar_programs) $(bsdcpio_programs) $(bsdcat_programs) -man_MANS= $(libarchive_man_MANS) $(bsdtar_man_MANS) $(bsdcpio_man_MANS) $(bsdcat_man_MANS) -BUILT_SOURCES= libarchive/test/list.h tar/test/list.h cpio/test/list.h cat/test/list.h +bin_PROGRAMS= $(bsdtar_programs) $(bsdcpio_programs) $(bsdcat_programs) $(bsdunzip_programs) +man_MANS= $(libarchive_man_MANS) $(bsdtar_man_MANS) $(bsdcpio_man_MANS) $(bsdcat_man_MANS) $(bsdunzip_man_MANS) +BUILT_SOURCES= libarchive/test/list.h tar/test/list.h cpio/test/list.h cat/test/list.h unzip/test/list.h # # What to test: We always test libarchive, test bsdtar and bsdcpio only # if we built them. # -check_PROGRAMS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) -TESTS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) -TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) $(bsdcat_TESTS_ENVIRONMENT) +check_PROGRAMS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) $(bsdunzip_test_programs) +TESTS= libarchive_test $(bsdtar_test_programs) $(bsdcpio_test_programs) $(bsdcat_test_programs) $(bsdunzip_test_programs) +TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $(bsdcpio_TESTS_ENVIRONMENT) $(bsdcat_TESTS_ENVIRONMENT) $(bsdunzip_TESTS_ENVIRONMENT) # Always build and test both bsdtar and bsdcpio as part of 'distcheck' DISTCHECK_CONFIGURE_FLAGS = --enable-bsdtar --enable-bsdcpio # The next line is commented out by default in shipping libarchive releases. @@ -49,7 +49,9 @@ EXTRA_DIST= \ $(bsdcpio_EXTRA_DIST) \ $(bsdcpio_test_EXTRA_DIST) \ $(bsdcat_EXTRA_DIST) \ - $(bsdcat_test_EXTRA_DIST) + $(bsdcat_test_EXTRA_DIST) \ + $(bsdunzip_EXTRA_DIST) \ + $(bsdunzip_test_EXTRA_DIST) # a) Clean out some unneeded files and directories # b) Collect all documentation and format it for distribution. @@ -69,7 +71,8 @@ DISTCLEANFILES= \ libarchive/test/list.h \ tar/test/list.h \ cpio/test/list.h \ - cat/test/list.h + cat/test/list.h \ + unzip/test/list.h distclean-local: -rm -rf .ref @@ -82,7 +85,9 @@ distclean-local: -[ -f cpio/Makefile ] && cd cpio && make clean -[ -f cpio/test/Makefile ] && cd cpio/test && make clean -[ -f cat/Makefile ] && cd cat && make clean - -[ -f cpio/test/Makefile ] && cd cat/test && make clean + -[ -f cat/test/Makefile ] && cd cat/test && make clean + -[ -f unzip/Makefile ] && cd unzip && make clean + -[ -f unzip/test/Makefile ] && cd unzip/test && make clean # # Libarchive headers, source, etc. @@ -763,6 +768,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_7zip_copy.7z.uu \ libarchive/test/test_read_format_7zip_copy_2.7z.uu \ libarchive/test/test_read_format_7zip_deflate.7z.uu \ + libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu \ libarchive/test/test_read_format_7zip_delta_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_delta4_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_delta_lzma2.7z.uu \ @@ -776,11 +782,18 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_7zip_lzma1_2.7z.uu \ libarchive/test/test_read_format_7zip_lzma1_lzma2.7z.uu \ libarchive/test/test_read_format_7zip_lzma2.7z.uu \ + libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu \ + libarchive/test/test_read_format_7zip_lzma2_arm.7z.uu \ libarchive/test/test_read_format_7zip_malformed.7z.uu \ libarchive/test/test_read_format_7zip_malformed2.7z.uu \ libarchive/test/test_read_format_7zip_packinfo_digests.7z.uu \ libarchive/test/test_read_format_7zip_ppmd.7z.uu \ + libarchive/test/test_read_format_7zip_solid_zstd.7z.uu \ libarchive/test/test_read_format_7zip_symbolic_name.7z.uu \ + libarchive/test/test_read_format_7zip_zstd_arm.7z.uu \ + libarchive/test/test_read_format_7zip_zstd_bcj.7z.uu \ + libarchive/test/test_read_format_7zip_zstd_nobcj.7z.uu \ + libarchive/test/test_read_format_7zip_zstd.7z.uu \ libarchive/test/test_read_format_ar.ar.uu \ libarchive/test/test_read_format_cab_1.cab.uu \ libarchive/test/test_read_format_cab_2.cab.uu \ @@ -1428,3 +1441,99 @@ bsdcat_test_EXTRA_DIST= \ cat/test/test_expand.plain.uu \ cat/test/test_expand.xz.uu \ cat/test/CMakeLists.txt + +# +# +# bsdunzip source, docs, etc. +# +# + +bsdunzip_SOURCES= \ + unzip/bsdunzip.c \ + unzip/bsdunzip_platform.h + +if INC_WINDOWS_FILES +bsdunzip_SOURCES+= +endif + +bsdunzip_DEPENDENCIES = libarchive.la libarchive_fe.la + + +if STATIC_BSDUNZIP +bsdunzip_ldstatic= -static +bsdunzip_ccstatic= -DLIBARCHIVE_STATIC +else +bsdunzip_ldstatic= +bsdunzip_ccstatic= +endif + +bsdunzip_LDADD= libarchive_fe.la libarchive.la $(LTLIBICONV) +bsdunzip_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe $(bsdunzip_ccstatic) $(PLATFORMCPPFLAGS) +bsdunzip_LDFLAGS= $(bsdunzip_ldstatic) $(GC_SECTIONS) + +bsdunzip_EXTRA_DIST= \ + unzip/bsdunzip.1 \ + unzip/CMakeLists.txt + + +if BUILD_BSDUNZIP +# Manpages to install +bsdunzip_man_MANS= unzip/bsdunzip.1 +bsdunzip_programs= bsdunzip +else +bsdunzip_man_MANS= +bsdunzip_programs= +endif + +# +# bsdcat_test +# + +bsdunzip_test_SOURCES= \ + $(test_utils_SOURCES) \ + unzip/test/test.h \ + unzip/test/test_0.c \ + unzip/test/test_basic.c \ + unzip/test/test_glob.c \ + unzip/test/test_not_exist.c \ + unzip/test/test_singlefile.c \ + unzip/test/test_C.c \ + unzip/test/test_p.c \ + unzip/test/test_d.c \ + unzip/test/test_j.c \ + unzip/test/test_L.c \ + unzip/test/test_n.c \ + unzip/test/test_o.c \ + unzip/test/test_q.c \ + unzip/test/test_t.c \ + unzip/test/test_t_bad.c \ + unzip/test/test_x.c \ + unzip/test/test_Z1.c \ + unzip/test/test_P_encryption.c + +bsdunzip_test_CPPFLAGS= \ + -I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \ + -I$(top_srcdir)/test_utils \ + -I$(top_srcdir)/unzip -I$(top_srcdir)/unzip/test \ + -I$(top_builddir)/unzip/test \ + $(PLATFORMCPPFLAGS) +bsdunzip_test_LDADD=libarchive_fe.la + +unzip/test/list.h: Makefile + cat $(top_srcdir)/unzip/test/test_*.c | grep '^DEFINE_TEST' > unzip/test/list.h + +if BUILD_BSDUNZIP +bsdunzip_test_programs= bsdunzip_test +bsdunzip_TESTS_ENVIRONMENT= BSDUNZIP=`cd $(top_builddir);/bin/pwd`/bsdunzip$(EXEEXT) BSDUNZIP_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/unzip/test +else +bsdunzip_test_programs= +bsdunzip_TESTS_ENVIRONMENT= +endif + +bsdunzip_test_EXTRA_DIST= \ + unzip/test/list.h \ + unzip/test/test_basic.zip.uu \ + unzip/test/test_encrypted.zip.uu \ + unzip/test/test_singlefile.zip.uu \ + unzip/test/test_t_bad.zip.uu \ + unzip/test/CMakeLists.txt @@ -1,3 +1,7 @@ +Jul 18, 2023: libarchive 3.7.0 released + +Jul 14, 2023: bsdunzip port from FreeBSD + Dec 07, 2022: libarchive 3.6.2 released Apr 08, 2022: libarchive 3.6.1 released diff --git a/README.md b/README.md index 404076237871..727ed49856b6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ command-line tools that use the libarchive library. ## Questions? Issues? -* http://www.libarchive.org is the home for ongoing +* https://www.libarchive.org is the home for ongoing libarchive development, including documentation, and links to the libarchive mailing lists. * To report an issue, use the issue tracker at @@ -23,6 +23,7 @@ This distribution bundle includes the following major components: * **tar**: the 'bsdtar' program is a full-featured 'tar' implementation built on libarchive * **cpio**: the 'bsdcpio' program is a different interface to essentially the same functionality * **cat**: the 'bsdcat' program is a simple replacement tool for zcat, bzcat, xzcat, and such +* **unzip**: the 'bsdunzip' program is a simple replacement tool for Info-ZIP's unzip * **examples**: Some small example programs that you may find useful. * **examples/minitar**: a compact sample demonstrating use of libarchive. * **contrib**: Various items sent to me by third parties; please contact the authors with any questions. @@ -87,7 +88,7 @@ Currently, the library automatically detects and reads the following formats: * ZIPX archives (with support for bzip2, ppmd8, lzma and xz compressed entries) * GNU and BSD 'ar' archives * 'mtree' format - * 7-Zip archives + * 7-Zip archives (including archives that use zstandard compression) * Microsoft CAB format * LHA and LZH archives * RAR and RAR 5.0 archives (with some limitations due to RAR's proprietary status) @@ -192,6 +193,17 @@ questions we are asked about libarchive: functions. On those platforms, libarchive will use the non-thread-safe functions. Patches to improve this are of great interest to us. +* The function `archive_write_disk_header()` is _not_ thread safe on + POSIX machines and could lead to security issue resulting in world + writeable directories. Thus it must be mutexed by the calling code. + This is due to calling `umask(oldumask = umask(0))`, which sets the + umask for the whole process to 0 for a short time frame. + In case other thread calls the same function in parallel, it might + get interrupted by it and cause the executable to use umask=0 for the + remaining execution. + This will then lead to implicitely created directories to have 777 + permissions without sticky bit. + * In particular, libarchive's modules to read or write a directory tree do use `chdir()` to optimize the directory traversals. This can cause problems for programs that expect to do disk access from diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..6ca188b603fe --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +If you have discovered a security vulnerability in this project, please report it +privately. **Do not disclose it as a public issue.** This gives us time to work with you +to fix the issue before public exposure, reducing the chance that the exploit will be +used before a patch is released. + +You may submit the report in the following ways: + +- send an email to security@libarchive.de; and/or +- send us a [private vulnerability report](https://github.com/libarchive/libarchive/security/advisories/new) + +Please provide the following information in your report: + +- A description of the vulnerability and its impact +- How to reproduce the issue + +This project is maintained by volunteers on a reasonable-effort basis. As such, we ask +that you give me 90 days to work on a fix before public exposure. diff --git a/build/ci/build.sh b/build/ci/build.sh index 79f26d758f35..0cc131cfd8cb 100755 --- a/build/ci/build.sh +++ b/build/ci/build.sh @@ -97,9 +97,6 @@ if [ -n "${DEBUG}" ]; then else export CFLAGS="-g -fsanitize=address" fi - if [ "${BS}" = "cmake" ]; then - CMAKE_ARGS="${CMAKE_ARGS} -DCMAKE_C_CFLAGS=-g -fsanitize=address" - fi fi if [ -z "${ACTIONS}" ]; then ACTIONS="autogen configure build test install" diff --git a/build/cmake/FindMbedTLS.cmake b/build/cmake/FindMbedTLS.cmake index a91639589218..aa40485c3ecd 100644 --- a/build/cmake/FindMbedTLS.cmake +++ b/build/cmake/FindMbedTLS.cmake @@ -7,7 +7,7 @@ find_library(MBEDCRYPTO_LIBRARY mbedcrypto) set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}") include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MBEDTLS DEFAULT_MSG +find_package_handle_standard_args(MbedTLS DEFAULT_MSG MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY) diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in index ff74f33fccd7..3de2ebd8c0ac 100644 --- a/build/cmake/config.h.in +++ b/build/cmake/config.h.in @@ -207,6 +207,9 @@ typedef uint64_t uintmax_t; /* MD5 via ARCHIVE_CRYPTO_MD5_LIBSYSTEM supported. */ #cmakedefine ARCHIVE_CRYPTO_MD5_LIBSYSTEM 1 +/* MD5 via ARCHIVE_CRYPTO_MD5_MBEDTLS supported. */ +#cmakedefine ARCHIVE_CRYPTO_MD5_MBEDTLS 1 + /* MD5 via ARCHIVE_CRYPTO_MD5_NETTLE supported. */ #cmakedefine ARCHIVE_CRYPTO_MD5_NETTLE 1 @@ -222,6 +225,9 @@ typedef uint64_t uintmax_t; /* RMD160 via ARCHIVE_CRYPTO_RMD160_NETTLE supported. */ #cmakedefine ARCHIVE_CRYPTO_RMD160_NETTLE 1 +/* RMD160 via ARCHIVE_CRYPTO_RMD160_MBEDTLS supported. */ +#cmakedefine ARCHIVE_CRYPTO_RMD160_MBEDTLS 1 + /* RMD160 via ARCHIVE_CRYPTO_RMD160_OPENSSL supported. */ #cmakedefine ARCHIVE_CRYPTO_RMD160_OPENSSL 1 @@ -231,6 +237,9 @@ typedef uint64_t uintmax_t; /* SHA1 via ARCHIVE_CRYPTO_SHA1_LIBSYSTEM supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA1_LIBSYSTEM 1 +/* SHA1 via ARCHIVE_CRYPTO_SHA1_MBEDTLS supported. */ +#cmakedefine ARCHIVE_CRYPTO_SHA1_MBEDTLS 1 + /* SHA1 via ARCHIVE_CRYPTO_SHA1_NETTLE supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA1_NETTLE 1 @@ -252,6 +261,9 @@ typedef uint64_t uintmax_t; /* SHA256 via ARCHIVE_CRYPTO_SHA256_LIBSYSTEM supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA256_LIBSYSTEM 1 +/* SHA256 via ARCHIVE_CRYPTO_SHA256_MBEDTLS supported. */ +#cmakedefine ARCHIVE_CRYPTO_SHA256_MBEDTLS 1 + /* SHA256 via ARCHIVE_CRYPTO_SHA256_NETTLE supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA256_NETTLE 1 @@ -273,6 +285,9 @@ typedef uint64_t uintmax_t; /* SHA384 via ARCHIVE_CRYPTO_SHA384_LIBSYSTEM supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA384_LIBSYSTEM 1 +/* SHA384 via ARCHIVE_CRYPTO_SHA384_MBEDTLS supported. */ +#cmakedefine ARCHIVE_CRYPTO_SHA384_MBEDTLS 1 + /* SHA384 via ARCHIVE_CRYPTO_SHA384_NETTLE supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA384_NETTLE 1 @@ -294,6 +309,9 @@ typedef uint64_t uintmax_t; /* SHA512 via ARCHIVE_CRYPTO_SHA512_LIBSYSTEM supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA512_LIBSYSTEM 1 +/* SHA512 via ARCHIVE_CRYPTO_SHA512_MBEDTLS supported. */ +#cmakedefine ARCHIVE_CRYPTO_SHA512_MBEDTLS 1 + /* SHA512 via ARCHIVE_CRYPTO_SHA512_NETTLE supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA512_NETTLE 1 @@ -366,7 +384,7 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the <attr/xattr.h> header file. */ #cmakedefine HAVE_ATTR_XATTR_H 1 -/* Define to 1 if you have the <Bcrypt.h> header file. */ +/* Define to 1 if you have the <bcrypt.h> header file. */ #cmakedefine HAVE_BCRYPT_H 1 /* Define to 1 if you have the <bsdxml.h> header file. */ @@ -570,6 +588,12 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `flistxattr' function. */ #cmakedefine HAVE_FLISTXATTR 1 +/* Define to 1 if you have the `fnmatch' function. */ +#cmakedefine HAVE_FNMATCH 1 + +/* Define to 1 if you have the <fnmatch.h> header file. */ +#cmakedefine HAVE_FNMATCH_H 1 + /* Define to 1 if you have the `fork' function. */ #cmakedefine HAVE_FORK 1 @@ -618,6 +642,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `getgrnam_r' function. */ #cmakedefine HAVE_GETGRNAM_R 1 +/* Define to 1 if platform uses `optreset` to reset `getopt` */ +#cmakedefine HAVE_GETOPT_OPTRESET 1 + /* Define to 1 if you have the `getpid' function. */ #cmakedefine HAVE_GETPID 1 @@ -827,6 +854,15 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the <lzo/lzoconf.h> header file. */ #cmakedefine HAVE_LZO_LZOCONF_H 1 +/* Define to 1 if you have the <mbedtls/aes.h> header file. */ +#cmakedefine HAVE_MBEDTLS_AES_H 1 + +/* Define to 1 if you have the <mbedtls/md.h> header file. */ +#cmakedefine HAVE_MBEDTLS_MD_H 1 + +/* Define to 1 if you have the <mbedtls/pkcs5.h> header file. */ +#cmakedefine HAVE_MBEDTLS_PKCS5_H 1 + /* Define to 1 if you have the `mbrtowc' function. */ #cmakedefine HAVE_MBRTOWC 1 @@ -878,6 +914,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `openat' function. */ #cmakedefine HAVE_OPENAT 1 +/* Define to 1 if you have the <openssl/evp.h> header file. */ +#cmakedefine HAVE_OPENSSL_EVP_H 1 + /* Define to 1 if you have the <paths.h> header file. */ #cmakedefine HAVE_PATHS_H 1 @@ -1073,6 +1112,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the <sys/poll.h> header file. */ #cmakedefine HAVE_SYS_POLL_H 1 +/* Define to 1 if you have the <sys/queue.h> header file. */ +#cmakedefine HAVE_SYS_QUEUE_H 1 + /* Define to 1 if you have the <sys/richacl.h> header file. */ #cmakedefine HAVE_SYS_RICHACL_H 1 diff --git a/build/version b/build/version index f95688df2e4b..130a195a04de 100644 --- a/build/version +++ b/build/version @@ -1 +1 @@ -3006003 +3007000 diff --git a/configure.ac b/configure.ac index 24049852b65d..7f5dbdf3b9ad 100644 --- a/configure.ac +++ b/configure.ac @@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front. dnl In particular, this allows the version macro to be used in AC_INIT dnl These first two version numbers are updated automatically on each release. -m4_define([LIBARCHIVE_VERSION_S],[3.6.3dev]) -m4_define([LIBARCHIVE_VERSION_N],[3006003]) +m4_define([LIBARCHIVE_VERSION_S],[3.7.0]) +m4_define([LIBARCHIVE_VERSION_N],[3007000]) dnl bsdtar and bsdcpio versioning tracks libarchive m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S()) @@ -267,12 +267,64 @@ case $host in ;; esac +# +# Options for building bsdunzip. +# +# Default is to build bsdunzip, but allow people to override that. +# Bsdunzip has not yet been ported for Windows +# +case "$host_os" in + *mingw* | *msys*) + enable_bsdunzip=no + ;; + *) + AC_ARG_ENABLE([bsdunzip], + [AS_HELP_STRING([--enable-bsdunzip], [enable build of bsdunzip (default)]) + AS_HELP_STRING([--enable-bsdunzip=static], [force static build of bsdunzip]) + AS_HELP_STRING([--enable-bsdunzip=shared], [force dynamic build of bsdunzip]) + AS_HELP_STRING([--disable-bsdunzip], [disable build of bsdunzip])], + [], [enable_bsdunzip=yes]) + ;; +esac + +case "$enable_bsdunzip" in +yes) + if test "$enable_static" = "no"; then + static_bsdunzip=no + else + static_bsdunzip=yes + fi + build_bsdunzip=yes + ;; +dynamic|shared) + if test "$enable_shared" = "no"; then + AC_MSG_FAILURE([Shared linking of bsdunzip requires shared libarchive]) + fi + build_bsdunzip=yes + static_bsdunzip=no + ;; +static) + build_bsdunzip=yes + static_bsdunzip=yes + ;; +no) + build_bsdunzip=no + static_bsdunzip=no + ;; +*) + AC_MSG_FAILURE([Unsupported value for --enable-bsdunzip]) + ;; +esac + +AM_CONDITIONAL([BUILD_BSDUNZIP], [ test "$build_bsdunzip" = yes ]) +AM_CONDITIONAL([STATIC_BSDUNZIP], [ test "$static_bsdunzip" = yes ]) + # Checks for header files. AC_HEADER_DIRENT AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([acl/libacl.h attr/xattr.h]) AC_CHECK_HEADERS([copyfile.h ctype.h]) -AC_CHECK_HEADERS([errno.h ext2fs/ext2_fs.h fcntl.h grp.h]) +AC_CHECK_HEADERS([errno.h ext2fs/ext2_fs.h fcntl.h fnmatch.h grp.h]) AC_CACHE_CHECK([whether EXT2_IOC_GETFLAGS is usable], [ac_cv_have_decl_EXT2_IOC_GETFLAGS], @@ -305,7 +357,7 @@ AC_CHECK_HEADERS([locale.h membership.h paths.h poll.h pthread.h pwd.h]) AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h]) AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h]) AC_CHECK_HEADERS([sys/acl.h sys/cdefs.h sys/ea.h sys/extattr.h]) -AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h]) +AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h sys/queue.h]) AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/richacl.h]) AC_CHECK_HEADERS([sys/select.h sys/statfs.h sys/statvfs.h sys/sysmacros.h]) AC_CHECK_HEADERS([sys/time.h sys/utime.h sys/utsname.h sys/vfs.h sys/xattr.h]) @@ -430,6 +482,19 @@ if test "x$with_lzma" != "xno"; then if test "x$ac_cv_lzma_has_mt" != xno; then AC_DEFINE([HAVE_LZMA_STREAM_ENCODER_MT], [1], [Define to 1 if you have the `lzma_stream_encoder_mt' function.]) fi + + AC_CACHE_CHECK( + [whether we have ARM64 filter support in lzma], + ac_cv_lzma_has_arm64, + [AC_LINK_IFELSE([ + AC_LANG_PROGRAM([[#include <lzma.h>] + [#ifndef LZMA_FILTER_ARM64] + [#error unsupported] + [#endif]])], + [ac_cv_lzma_has_arm64=yes], [ac_cv_lzma_has_arm64=no])]) + if test "x$ac_cv_lzma_has_arm64" != xno; then + AC_DEFINE([HAVE_LZMA_FILTER_ARM64], [1], [Define to 1 if you have the `LZMA_FILTER_ARM64' macro.]) + fi fi AC_ARG_WITH([lzo2], @@ -674,7 +739,7 @@ AC_FUNC_VPRINTF # workarounds, we use 'void *' for 'struct SECURITY_ATTRIBUTES *' AC_CHECK_STDCALL_FUNC([CreateHardLinkA],[const char *, const char *, void *]) AC_CHECK_FUNCS([arc4random_buf chflags chown chroot ctime_r]) -AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fdopendir fork]) +AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fdopendir fnmatch fork]) AC_CHECK_FUNCS([fstat fstatat fstatfs fstatvfs ftruncate]) AC_CHECK_FUNCS([futimens futimes futimesat]) AC_CHECK_FUNCS([geteuid getpid getgrgid_r getgrnam_r]) @@ -767,6 +832,11 @@ AC_CHECK_MEMBER(struct dirent.d_namlen,,, #endif ]) +AC_CHECK_DECL([optreset], + [AC_DEFINE(HAVE_GETOPT_OPTRESET, 1, [Platform uses optreset to reset getopt])], + [], + [#include <getopt.h>]) + # Check for Extended Attributes support AC_ARG_ENABLE([xattr], AS_HELP_STRING([--disable-xattr], diff --git a/contrib/android/config/windows_host.h b/contrib/android/config/windows_host.h index 712b7491be62..6550e5e82e2a 100644 --- a/contrib/android/config/windows_host.h +++ b/contrib/android/config/windows_host.h @@ -160,7 +160,7 @@ /* Define to 1 if you have the <attr/xattr.h> header file. */ /* #undef HAVE_ATTR_XATTR_H */ -/* Define to 1 if you have the <Bcrypt.h> header file. */ +/* Define to 1 if you have the <bcrypt.h> header file. */ #define HAVE_BCRYPT_H /* Define to 1 if you have the <bzlib.h> header file. */ diff --git a/cpio/cpio_windows.c b/cpio/cpio_windows.c index 63f6df0397d2..2809ca821e2c 100644 --- a/cpio/cpio_windows.c +++ b/cpio/cpio_windows.c @@ -156,7 +156,11 @@ cpio_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, { wchar_t *wpath; HANDLE handle; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) handle = CreateFileA(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); @@ -164,12 +168,25 @@ cpio_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, return (handle); if (GetLastError() != ERROR_PATH_NOT_FOUND) return (handle); +#endif wpath = permissive_name(path); if (wpath == NULL) - return (handle); + return INVALID_HANDLE_VALUE; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF; + createExParams.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000; + createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F0000; + createExParams.lpSecurityAttributes = lpSecurityAttributes; + createExParams.hTemplateFile = hTemplateFile; + handle = CreateFile2(wpath, dwDesiredAccess, dwShareMode, + dwCreationDisposition, &createExParams); +#else handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); +#endif free(wpath); return (handle); } diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt index ff7ade006fc6..f7fdfb68a103 100644 --- a/libarchive/CMakeLists.txt +++ b/libarchive/CMakeLists.txt @@ -243,10 +243,12 @@ ELSEIF(ARCHIVE_ACL_SUNOS) ENDIF() # Libarchive is a shared library -ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS}) -TARGET_INCLUDE_DIRECTORIES(archive PUBLIC .) -TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS}) -SET_TARGET_PROPERTIES(archive PROPERTIES SOVERSION ${SOVERSION}) +IF(BUILD_SHARED_LIBS) + ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS}) + TARGET_INCLUDE_DIRECTORIES(archive PUBLIC .) + TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS}) + SET_TARGET_PROPERTIES(archive PROPERTIES SOVERSION ${SOVERSION}) +ENDIF(BUILD_SHARED_LIBS) # archive_static is a static library ADD_LIBRARY(archive_static STATIC ${libarchive_SOURCES} ${include_HEADERS}) @@ -254,13 +256,19 @@ TARGET_LINK_LIBRARIES(archive_static ${ADDITIONAL_LIBS}) SET_TARGET_PROPERTIES(archive_static PROPERTIES COMPILE_DEFINITIONS LIBARCHIVE_STATIC) # On Posix systems, libarchive.so and libarchive.a can co-exist. -IF(NOT WIN32 OR CYGWIN) +IF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS) SET_TARGET_PROPERTIES(archive_static PROPERTIES OUTPUT_NAME archive) -ENDIF(NOT WIN32 OR CYGWIN) +ENDIF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS) IF(ENABLE_INSTALL) # How to install the libraries - INSTALL(TARGETS archive archive_static + IF(BUILD_SHARED_LIBS) + INSTALL(TARGETS archive + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + ENDIF(BUILD_SHARED_LIBS) + INSTALL(TARGETS archive_static RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) diff --git a/libarchive/archive.h b/libarchive/archive.h index fa293ddfd34a..1164cedd3244 100644 --- a/libarchive/archive.h +++ b/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 3006003 +#define ARCHIVE_VERSION_NUMBER 3007000 #include <sys/stat.h> #include <stddef.h> /* for wchar_t */ @@ -157,7 +157,7 @@ __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_ONLY_STRING "3.6.3dev" +#define ARCHIVE_VERSION_ONLY_STRING "3.7.0" #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char * archive_version_string(void); diff --git a/libarchive/archive_digest.c b/libarchive/archive_digest.c index 3361b19ada82..08a9aeb02320 100644 --- a/libarchive/archive_digest.c +++ b/libarchive/archive_digest.c @@ -36,6 +36,11 @@ #error Cannot use both OpenSSL and libmd. #endif +/* Common in other bcrypt implementations, but missing from VS2008. */ +#ifndef BCRYPT_SUCCESS +#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS) +#endif + /* * Message digest functions for Windows platform. */ @@ -48,6 +53,26 @@ /* * Initialize a Message digest. */ +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA +static int +win_crypto_init(Digest_CTX *ctx, const WCHAR *algo) +{ + NTSTATUS status; + ctx->valid = 0; + + status = BCryptOpenAlgorithmProvider(&ctx->hAlg, algo, NULL, 0); + if (!BCRYPT_SUCCESS(status)) + return (ARCHIVE_FAILED); + status = BCryptCreateHash(ctx->hAlg, &ctx->hHash, NULL, 0, NULL, 0, 0); + if (!BCRYPT_SUCCESS(status)) { + BCryptCloseAlgorithmProvider(ctx->hAlg, 0); + return (ARCHIVE_FAILED); + } + + ctx->valid = 1; + return (ARCHIVE_OK); +} +#else static int win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId) { @@ -70,6 +95,7 @@ win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId) ctx->valid = 1; return (ARCHIVE_OK); } +#endif /* * Update a Message digest. @@ -81,23 +107,37 @@ win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len) if (!ctx->valid) return (ARCHIVE_FAILED); +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + BCryptHashData(ctx->hHash, + (PUCHAR)(uintptr_t)buf, + len, 0); +#else CryptHashData(ctx->hash, (unsigned char *)(uintptr_t)buf, (DWORD)len, 0); +#endif return (ARCHIVE_OK); } static int win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx) { +#if !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA) DWORD siglen = (DWORD)bufsize; +#endif if (!ctx->valid) return (ARCHIVE_FAILED); +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + BCryptFinishHash(ctx->hHash, buf, (ULONG)bufsize, 0); + BCryptDestroyHash(ctx->hHash); + BCryptCloseAlgorithmProvider(ctx->hAlg, 0); +#else CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0); CryptDestroyHash(ctx->hash); CryptReleaseContext(ctx->cryptProv, 0); +#endif ctx->valid = 0; return (ARCHIVE_OK); } @@ -276,7 +316,11 @@ __archive_md5final(archive_md5_ctx *ctx, void *md) static int __archive_md5init(archive_md5_ctx *ctx) { +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM)); +#else return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5)); +#endif } static int @@ -659,7 +703,11 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md) static int __archive_sha1init(archive_sha1_ctx *ctx) { +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM)); +#else return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1)); +#endif } static int @@ -919,7 +967,11 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md) static int __archive_sha256init(archive_sha256_ctx *ctx) { +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM)); +#else return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256)); +#endif } static int @@ -1155,7 +1207,11 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md) static int __archive_sha384init(archive_sha384_ctx *ctx) { +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM)); +#else return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384)); +#endif } static int @@ -1415,7 +1471,11 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md) static int __archive_sha512init(archive_sha512_ctx *ctx) { +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM)); +#else return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512)); +#endif } static int diff --git a/libarchive/archive_digest_private.h b/libarchive/archive_digest_private.h index 9b3bd6621bf3..339b4edca48d 100644 --- a/libarchive/archive_digest_private.h +++ b/libarchive/archive_digest_private.h @@ -164,6 +164,15 @@ defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\ defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\ defined(ARCHIVE_CRYPTO_SHA512_WIN) +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA +/* don't use bcrypt when XP needs to be supported */ +#include <bcrypt.h> +typedef struct { + int valid; + BCRYPT_ALG_HANDLE hAlg; + BCRYPT_HASH_HANDLE hHash; +} Digest_CTX; +#else #include <windows.h> #include <wincrypt.h> typedef struct { @@ -172,6 +181,7 @@ typedef struct { HCRYPTHASH hash; } Digest_CTX; #endif +#endif /* typedefs */ #if defined(ARCHIVE_CRYPTO_MD5_LIBC) diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h index 13d95fc5bea0..274e380e698f 100644 --- a/libarchive/archive_entry.h +++ b/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 3006003 +#define ARCHIVE_VERSION_NUMBER 3007000 /* * Note: archive_entry.h is for use outside of libarchive; the diff --git a/libarchive/archive_openssl_evp_private.h b/libarchive/archive_openssl_evp_private.h index ebb06702d0c5..8ac4772808e6 100644 --- a/libarchive/archive_openssl_evp_private.h +++ b/libarchive/archive_openssl_evp_private.h @@ -33,7 +33,8 @@ #include <openssl/evp.h> #include <openssl/opensslv.h> -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) #include <stdlib.h> /* malloc, free */ #include <string.h> /* memset */ static inline EVP_MD_CTX *EVP_MD_CTX_new(void) diff --git a/libarchive/archive_random.c b/libarchive/archive_random.c index 9d1aa493f0c8..301765acd830 100644 --- a/libarchive/archive_random.c +++ b/libarchive/archive_random.c @@ -51,16 +51,27 @@ __FBSDID("$FreeBSD$"); #include <pthread.h> #endif -static void arc4random_buf(void *, size_t); +static void la_arc4random_buf(void *, size_t); #endif /* HAVE_ARC4RANDOM_BUF */ #include "archive.h" #include "archive_random_private.h" -#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) +#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA +/* don't use bcrypt when XP needs to be supported */ +#include <bcrypt.h> + +/* Common in other bcrypt implementations, but missing from VS2008. */ +#ifndef BCRYPT_SUCCESS +#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS) +#endif + +#elif defined(HAVE_WINCRYPT_H) #include <wincrypt.h> #endif +#endif #ifndef O_CLOEXEC #define O_CLOEXEC 0 @@ -75,6 +86,20 @@ int archive_random(void *buf, size_t nbytes) { #if defined(_WIN32) && !defined(__CYGWIN__) +# if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + NTSTATUS status; + BCRYPT_ALG_HANDLE hAlg; + + status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0); + if (!BCRYPT_SUCCESS(status)) + return ARCHIVE_FAILED; + status = BCryptGenRandom(hAlg, buf, nbytes, 0); + BCryptCloseAlgorithmProvider(hAlg, 0); + if (!BCRYPT_SUCCESS(status)) + return ARCHIVE_FAILED; + + return ARCHIVE_OK; +# else HCRYPTPROV hProv; BOOL success; @@ -92,6 +117,10 @@ archive_random(void *buf, size_t nbytes) } /* TODO: Does this case really happen? */ return ARCHIVE_FAILED; +# endif +#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__)) + la_arc4random_buf(buf, nbytes); + return ARCHIVE_OK; #else arc4random_buf(buf, nbytes); return ARCHIVE_OK; @@ -256,7 +285,7 @@ arc4_getbyte(void) } static void -arc4random_buf(void *_buf, size_t n) +la_arc4random_buf(void *_buf, size_t n) { uint8_t *buf = (uint8_t *)_buf; _ARC4_LOCK(); diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c index 5a94ec5d4399..e9657f6a72e8 100644 --- a/libarchive/archive_read_disk_posix.c +++ b/libarchive/archive_read_disk_posix.c @@ -1670,6 +1670,11 @@ setup_current_filesystem(struct archive_read_disk *a) else t->current_filesystem->name_max = nm; #endif + if (t->current_filesystem->name_max == 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot determine name_max"); + return (ARCHIVE_FAILED); + } #endif /* USE_READDIR_R */ return (ARCHIVE_OK); } @@ -1860,8 +1865,17 @@ setup_current_filesystem(struct archive_read_disk *a) #if defined(USE_READDIR_R) /* Set maximum filename length. */ +#if defined(HAVE_STATVFS) + t->current_filesystem->name_max = svfs.f_namelen; +#else t->current_filesystem->name_max = sfs.f_namelen; #endif + if (t->current_filesystem->name_max == 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot determine name_max"); + return (ARCHIVE_FAILED); + } +#endif return (ARCHIVE_OK); } @@ -1942,6 +1956,11 @@ setup_current_filesystem(struct archive_read_disk *a) #if defined(USE_READDIR_R) /* Set maximum filename length. */ t->current_filesystem->name_max = svfs.f_namemax; + if (t->current_filesystem->name_max == 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot determine name_max"); + return (ARCHIVE_FAILED); + } #endif return (ARCHIVE_OK); } @@ -1996,6 +2015,11 @@ setup_current_filesystem(struct archive_read_disk *a) else t->current_filesystem->name_max = nm; # endif /* _PC_NAME_MAX */ + if (t->current_filesystem->name_max == 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot determine name_max"); + return (ARCHIVE_FAILED); + } #endif /* USE_READDIR_R */ return (ARCHIVE_OK); } @@ -2543,7 +2567,11 @@ tree_current_lstat(struct tree *t) #else if (tree_enter_working_dir(t) != 0) return NULL; +#ifdef HAVE_LSTAT if (lstat(tree_current_access_path(t), &t->lst) != 0) +#else + if (la_stat(tree_current_access_path(t), &t->lst) != 0) +#endif #endif return NULL; t->flags |= hasLstat; diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c index f9d139557ee0..f92a78a21edd 100644 --- a/libarchive/archive_read_disk_windows.c +++ b/libarchive/archive_read_disk_windows.c @@ -418,9 +418,19 @@ la_linkname_from_pathw(const wchar_t *path, wchar_t **outbuf, int *linktype) FILE_FLAG_OPEN_REPARSE_POINT; int ret; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = flag; + h = CreateFile2(path, 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, &createExParams); +#else h = CreateFileW(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, flag, NULL); +#endif if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); return (-1); @@ -1067,16 +1077,29 @@ next_entry(struct archive_read_disk *a, struct tree *t, if (archive_entry_filetype(entry) == AE_IFREG && archive_entry_size(entry) > 0) { DWORD flags = FILE_FLAG_BACKUP_SEMANTICS; +#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif if (t->async_io) flags |= FILE_FLAG_OVERLAPPED; if (t->direct_io) flags |= FILE_FLAG_NO_BUFFERING; else flags |= FILE_FLAG_SEQUENTIAL_SCAN; +#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = flags; + t->entry_fh = CreateFile2(tree_current_access_path(t), + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, &createExParams); +#else t->entry_fh = CreateFileW(tree_current_access_path(t), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, flags, NULL); +#endif if (t->entry_fh == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); archive_set_error(&a->archive, errno, @@ -1547,6 +1570,9 @@ close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt) { HANDLE handle; int r = 0; +#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype) return (0); @@ -1560,8 +1586,16 @@ close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt) if ((t->flags & needsRestoreTimes) == 0) return (r); +#if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; + handle = CreateFile2(rt->full_path, FILE_WRITE_ATTRIBUTES, + 0, OPEN_EXISTING, &createExParams); +#else handle = CreateFileW(rt->full_path, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); +#endif if (handle == INVALID_HANDLE_VALUE) { errno = EINVAL; return (-1); @@ -2046,12 +2080,24 @@ tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st, HANDLE h; int r; DWORD flag = FILE_FLAG_BACKUP_SEMANTICS; - +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif + if (sim_lstat && tree_current_is_physical_link(t)) flag |= FILE_FLAG_OPEN_REPARSE_POINT; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = flag; + h = CreateFile2(tree_current_access_path(t), 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, &createExParams); +#else h = CreateFileW(tree_current_access_path(t), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, flag, NULL); +#endif if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); t->tree_errno = errno; @@ -2257,7 +2303,10 @@ archive_read_disk_entry_from_file(struct archive *_a, } else { WIN32_FIND_DATAW findData; DWORD flag, desiredAccess; - +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif + h = FindFirstFileW(path, &findData); if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); @@ -2279,9 +2328,18 @@ archive_read_disk_entry_from_file(struct archive *_a, } else desiredAccess = GENERIC_READ; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = flag; + h = CreateFile2(path, desiredAccess, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, &createExParams); +#else h = CreateFileW(path, desiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, flag, NULL); +#endif if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); archive_set_error(&a->archive, errno, @@ -2342,9 +2400,19 @@ archive_read_disk_entry_from_file(struct archive *_a, if (fd >= 0) { h = (HANDLE)_get_osfhandle(fd); } else { +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; + h = CreateFile2(path, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, &createExParams); +#else h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); +#endif if (h == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); archive_set_error(&a->archive, errno, diff --git a/libarchive/archive_read_set_options.3 b/libarchive/archive_read_set_options.3 index b2db4cbcb893..162b79da48f4 100644 --- a/libarchive/archive_read_set_options.3 +++ b/libarchive/archive_read_set_options.3 @@ -255,6 +255,27 @@ have been concatenated together. Without this option, only the contents of the first concatenated archive would be read. .El +.It Format zip +.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 ignorecrc32 +Skip the CRC32 check. +Mostly used for testing. +.It Cm mac-ext +Support Mac OS metadata extension that records data in special +files beginning with a period and underscore. +Defaults to enabled on Mac OS, disabled on other platforms. +Use +.Cm !mac-ext +to disable. +.El .El .\" .Sh ERRORS diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index 0ba4bee358b2..bb595b3e4b07 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_ZLIB_H #include <zlib.h> #endif +#ifdef HAVE_ZSTD_H +#include <zstd.h> +#endif #include "archive.h" #include "archive_entry.h" @@ -80,8 +83,11 @@ __FBSDID("$FreeBSD$"); #define _7Z_IA64 0x03030401 #define _7Z_ARM 0x03030501 #define _7Z_ARMTHUMB 0x03030701 +#define _7Z_ARM64 0xa #define _7Z_SPARC 0x03030805 +#define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */ + /* * 7-Zip header property IDs. */ @@ -278,6 +284,11 @@ struct _7zip { z_stream stream; int stream_valid; #endif + /* Decoding Zstandard data. */ +#if HAVE_ZSTD_H + ZSTD_DStream *zstd_dstream; + int zstdstream_valid; +#endif /* Decoding PPMd data. */ int ppmd7_stat; CPpmd7 ppmd7_context; @@ -397,6 +408,9 @@ static int setup_decode_folder(struct archive_read *, struct _7z_folder *, int); static void x86_Init(struct _7zip *); static size_t x86_Convert(struct _7zip *, uint8_t *, size_t); +static void arm_Init(struct _7zip *); +static size_t arm_Convert(struct _7zip *, uint8_t *, size_t); +static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t); static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t); @@ -1027,10 +1041,13 @@ init_decompression(struct archive_read *a, struct _7zip *zip, case _7Z_COPY: case _7Z_BZ2: case _7Z_DEFLATE: + case _7Z_ZSTD: case _7Z_PPMD: if (coder2 != NULL) { if (coder2->codec != _7Z_X86 && - coder2->codec != _7Z_X86_BCJ2) { + coder2->codec != _7Z_X86_BCJ2 && + coder2->codec != _7Z_ARM && + coder2->codec != _7Z_ARM64) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unsupported filter %lx for %lx", @@ -1041,6 +1058,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip, zip->bcj_state = 0; if (coder2->codec == _7Z_X86) x86_Init(zip); + else if (coder2->codec == _7Z_ARM) + arm_Init(zip); } break; default: @@ -1137,6 +1156,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip, filters[fi].id = LZMA_FILTER_ARMTHUMB; fi++; break; +#ifdef LZMA_FILTER_ARM64 + case _7Z_ARM64: + filters[fi].id = LZMA_FILTER_ARM64; + fi++; + break; +#endif case _7Z_SPARC: filters[fi].id = LZMA_FILTER_SPARC; fi++; @@ -1222,6 +1247,22 @@ init_decompression(struct archive_read *a, struct _7zip *zip, "BZ2 codec is unsupported"); return (ARCHIVE_FAILED); #endif + case _7Z_ZSTD: + { +#if defined(HAVE_ZSTD_H) + if (zip->zstdstream_valid) { + ZSTD_freeDStream(zip->zstd_dstream); + zip->zstdstream_valid = 0; + } + zip->zstd_dstream = ZSTD_createDStream(); + zip->zstdstream_valid = 1; + break; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "ZSTD codec is unsupported"); + return (ARCHIVE_FAILED); +#endif + } case _7Z_DEFLATE: #ifdef HAVE_ZLIB_H if (zip->stream_valid) @@ -1488,6 +1529,22 @@ decompress(struct archive_read *a, struct _7zip *zip, t_avail_out = zip->stream.avail_out; break; #endif +#ifdef HAVE_ZSTD_H + case _7Z_ZSTD: + { + ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 }; // src, size, pos + ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; // dst, size, pos + + size_t const zret = ZSTD_decompressStream(zip->zstd_dstream, &output, &input); + if (ZSTD_isError(zret)) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(zret)); + return ARCHIVE_FAILED; + } + t_avail_in -= input.pos; + t_avail_out -= output.pos; + break; + } +#endif case _7Z_PPMD: { uint64_t flush_bytes; @@ -1572,16 +1629,23 @@ decompress(struct archive_read *a, struct _7zip *zip, /* * Decord BCJ. */ - if (zip->codec != _7Z_LZMA2 && zip->codec2 == _7Z_X86) { - size_t l = x86_Convert(zip, buff, *outbytes); - zip->odd_bcj_size = *outbytes - l; - if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 && - o_avail_in && ret != ARCHIVE_EOF) { - memcpy(zip->odd_bcj, ((unsigned char *)buff) + l, - zip->odd_bcj_size); - *outbytes = l; - } else - zip->odd_bcj_size = 0; + if (zip->codec != _7Z_LZMA2) { + if (zip->codec2 == _7Z_X86) { + size_t l = x86_Convert(zip, buff, *outbytes); + + zip->odd_bcj_size = *outbytes - l; + if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 && + o_avail_in && ret != ARCHIVE_EOF) { + memcpy(zip->odd_bcj, ((unsigned char *)buff) + l, + zip->odd_bcj_size); + *outbytes = l; + } else + zip->odd_bcj_size = 0; + } else if (zip->codec2 == _7Z_ARM) { + *outbytes = arm_Convert(zip, buff, *outbytes); + } else if (zip->codec2 == _7Z_ARM64) { + *outbytes = arm64_Convert(zip, buff, *outbytes); + } } /* @@ -3727,6 +3791,116 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size) return (bufferPos); } +static void +arm_Init(struct _7zip *zip) +{ + zip->bcj_ip = 8; +} + +static size_t +arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size) +{ + // This function was adapted from + // static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size) + // in https://git.tukaani.org/xz-embedded.git + + /* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin <lasse.collin@tukaani.org> + * Igor Pavlov <https://7-zip.org/> + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + if (buf[i + 3] == 0xEB) { + // Calculate the transformed addr. + addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) + | ((uint32_t)buf[i + 2] << 16); + addr <<= 2; + addr -= zip->bcj_ip + (uint32_t)i; + addr >>= 2; + + // Store the transformed addr in buf. + buf[i] = (uint8_t)addr; + buf[i + 1] = (uint8_t)(addr >> 8); + buf[i + 2] = (uint8_t)(addr >> 16); + } + } + + zip->bcj_ip += i; + + return i; +} + +static size_t +arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size) +{ + // This function was adapted from + // static size_t bcj_arm64(struct xz_dec_bcj *s, uint8_t *buf, size_t size) + // in https://git.tukaani.org/xz-embedded.git + + /* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin <lasse.collin@tukaani.org> + * Igor Pavlov <https://7-zip.org/> + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + + size_t i; + uint32_t instr; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = (uint32_t)buf[i] + | ((uint32_t)buf[i+1] << 8) + | ((uint32_t)buf[i+2] << 16) + | ((uint32_t)buf[i+3] << 24); + + if ((instr >> 26) == 0x25) { + /* BL instruction */ + addr = instr - ((zip->bcj_ip + (uint32_t)i) >> 2); + instr = 0x94000000 | (addr & 0x03FFFFFF); + + buf[i] = (uint8_t)instr; + buf[i+1] = (uint8_t)(instr >> 8); + buf[i+2] = (uint8_t)(instr >> 16); + buf[i+3] = (uint8_t)(instr >> 24); + } else if ((instr & 0x9F000000) == 0x90000000) { + /* ADRP instruction */ + addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC); + + /* Only convert values in the range +/-512 MiB. */ + if ((addr + 0x020000) & 0x1C0000) + continue; + + addr -= (zip->bcj_ip + (uint32_t)i) >> 12; + + instr &= 0x9000001F; + instr |= (addr & 3) << 29; + instr |= (addr & 0x03FFFC) << 3; + instr |= (0U - (addr & 0x020000)) & 0xE00000; + + buf[i] = (uint8_t)instr; + buf[i+1] = (uint8_t)(instr >> 8); + buf[i+2] = (uint8_t)(instr >> 16); + buf[i+3] = (uint8_t)(instr >> 24); + } + } + + zip->bcj_ip += i; + + return i; +} + /* * Brought from LZMA SDK. * diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c index 4d5029b1bd2e..3b552a84de12 100644 --- a/libarchive/archive_read_support_format_cab.c +++ b/libarchive/archive_read_support_format_cab.c @@ -2294,10 +2294,10 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br) (br->cache_buffer << 48) | ((uint64_t)strm->next_in[1]) << 40 | ((uint64_t)strm->next_in[0]) << 32 | - ((uint32_t)strm->next_in[3]) << 24 | - ((uint32_t)strm->next_in[2]) << 16 | - ((uint32_t)strm->next_in[5]) << 8 | - (uint32_t)strm->next_in[4]; + ((uint64_t)strm->next_in[3]) << 24 | + ((uint64_t)strm->next_in[2]) << 16 | + ((uint64_t)strm->next_in[5]) << 8 | + (uint64_t)strm->next_in[4]; strm->next_in += 6; strm->avail_in -= 6; br->cache_avail += 6 * 8; diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c index a4899144965c..9adcfd335b12 100644 --- a/libarchive/archive_read_support_format_cpio.c +++ b/libarchive/archive_read_support_format_cpio.c @@ -985,14 +985,14 @@ archive_read_format_cpio_cleanup(struct archive_read *a) static int64_t le4(const unsigned char *p) { - return ((p[0] << 16) + (((int64_t)p[1]) << 24) + (p[2] << 0) + (p[3] << 8)); + return ((p[0] << 16) | (((int64_t)p[1]) << 24) | (p[2] << 0) | (p[3] << 8)); } static int64_t be4(const unsigned char *p) { - return ((((int64_t)p[0]) << 24) + (p[1] << 16) + (p[2] << 8) + (p[3])); + return ((((int64_t)p[0]) << 24) | (p[1] << 16) | (p[2] << 8) | (p[3])); } /* diff --git a/libarchive/archive_read_support_format_lha.c b/libarchive/archive_read_support_format_lha.c index bcfd42e1d920..fa907a346408 100644 --- a/libarchive/archive_read_support_format_lha.c +++ b/libarchive/archive_read_support_format_lha.c @@ -2009,10 +2009,10 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br) ((uint64_t)strm->next_in[0]) << 48 | ((uint64_t)strm->next_in[1]) << 40 | ((uint64_t)strm->next_in[2]) << 32 | - ((uint32_t)strm->next_in[3]) << 24 | - ((uint32_t)strm->next_in[4]) << 16 | - ((uint32_t)strm->next_in[5]) << 8 | - (uint32_t)strm->next_in[6]; + ((uint64_t)strm->next_in[3]) << 24 | + ((uint64_t)strm->next_in[4]) << 16 | + ((uint64_t)strm->next_in[5]) << 8 | + (uint64_t)strm->next_in[6]; strm->next_in += 7; strm->avail_in -= 7; br->cache_avail += 7 * 8; @@ -2022,10 +2022,10 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br) (br->cache_buffer << 48) | ((uint64_t)strm->next_in[0]) << 40 | ((uint64_t)strm->next_in[1]) << 32 | - ((uint32_t)strm->next_in[2]) << 24 | - ((uint32_t)strm->next_in[3]) << 16 | - ((uint32_t)strm->next_in[4]) << 8 | - (uint32_t)strm->next_in[5]; + ((uint64_t)strm->next_in[2]) << 24 | + ((uint64_t)strm->next_in[3]) << 16 | + ((uint64_t)strm->next_in[4]) << 8 | + (uint64_t)strm->next_in[5]; strm->next_in += 6; strm->avail_in -= 6; br->cache_avail += 6 * 8; diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c index 2bc3ba066c3b..a5fa30e3c2b6 100644 --- a/libarchive/archive_read_support_format_mtree.c +++ b/libarchive/archive_read_support_format_mtree.c @@ -1280,7 +1280,13 @@ parse_file(struct archive_read *a, struct archive_entry *entry, mtree->fd = -1; st = NULL; } - } else if (lstat(path, st) == -1) { + } +#ifdef HAVE_LSTAT + else if (lstat(path, st) == -1) +#else + else if (la_stat(path, st) == -1) +#endif + { st = NULL; } diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 9d6c900b2c6e..f800788f6806 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -2227,7 +2227,7 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff, to_consume = zip->bzstream.total_in_lo32; __archive_read_consume(a, to_consume); - total_out = ((uint64_t) zip->bzstream.total_out_hi32 << 32) + + total_out = ((uint64_t) zip->bzstream.total_out_hi32 << 32) | zip->bzstream.total_out_lo32; zip->entry_bytes_remaining -= to_consume; diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 69458e1a12b1..accf52631a89 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -1324,6 +1324,10 @@ free_sconv_object(struct archive_string_conv *sc) } #if defined(_WIN32) && !defined(__CYGWIN__) +# if defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define GetOEMCP() CP_OEMCP +# endif + static unsigned my_atoi(const char *p) { diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c index b1582edbe308..40603c483a60 100644 --- a/libarchive/archive_util.c +++ b/libarchive/archive_util.c @@ -42,9 +42,20 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1 #ifdef HAVE_STRING_H #include <string.h> #endif -#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) +#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA +/* don't use bcrypt when XP needs to be supported */ +#include <bcrypt.h> + +/* Common in other bcrypt implementations, but missing from VS2008. */ +#ifndef BCRYPT_SUCCESS +#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS) +#endif + +#elif defined(HAVE_WINCRYPT_H) #include <wincrypt.h> #endif +#endif #ifdef HAVE_ZLIB_H #include <zlib.h> #endif @@ -233,14 +244,16 @@ __archive_mktempx(const char *tmpdir, wchar_t *template) L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', L'u', L'v', L'w', L'x', L'y', L'z' }; - HCRYPTPROV hProv; struct archive_wstring temp_name; wchar_t *ws; DWORD attr; wchar_t *xp, *ep; int fd; - - hProv = (HCRYPTPROV)NULL; +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + BCRYPT_ALG_HANDLE hAlg = NULL; +#else + HCRYPTPROV hProv = (HCRYPTPROV)NULL; +#endif fd = -1; ws = NULL; @@ -314,23 +327,42 @@ __archive_mktempx(const char *tmpdir, wchar_t *template) abort(); } +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, + NULL, 0))) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } +#else if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { la_dosmaperr(GetLastError()); goto exit_tmpfile; } +#endif for (;;) { wchar_t *p; HANDLE h; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif /* Generate a random file name through CryptGenRandom(). */ p = xp; +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p, + (DWORD)(ep - p)*sizeof(wchar_t), 0))) { + la_dosmaperr(GetLastError()); + goto exit_tmpfile; + } +#else if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), (BYTE*)p)) { la_dosmaperr(GetLastError()); goto exit_tmpfile; } +#endif for (; p < ep; p++) *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; @@ -347,6 +379,17 @@ __archive_mktempx(const char *tmpdir, wchar_t *template) /* mkstemp */ attr = FILE_ATTRIBUTE_NORMAL; } +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileAttributes = attr & 0xFFFF; + createExParams.dwFileFlags = attr & 0xFFF00000; + h = CreateFile2(ws, + GENERIC_READ | GENERIC_WRITE | DELETE, + 0,/* Not share */ + CREATE_NEW, + &createExParams); +#else h = CreateFileW(ws, GENERIC_READ | GENERIC_WRITE | DELETE, 0,/* Not share */ @@ -354,6 +397,7 @@ __archive_mktempx(const char *tmpdir, wchar_t *template) CREATE_NEW,/* Create a new file only */ attr, NULL); +#endif if (h == INVALID_HANDLE_VALUE) { /* The same file already exists. retry with * a new filename. */ @@ -372,8 +416,13 @@ __archive_mktempx(const char *tmpdir, wchar_t *template) break;/* success! */ } exit_tmpfile: +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + if (hAlg != NULL) + BCryptCloseAlgorithmProvider(hAlg, 0); +#else if (hProv != (HCRYPTPROV)NULL) CryptReleaseContext(hProv, 0); +#endif free(ws); if (template == temp_name.s) archive_wstring_free(&temp_name); diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index 624e270095d6..ebc5eefb800a 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -234,7 +234,11 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, { wchar_t *wpath; HANDLE handle; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) handle = CreateFileA(path, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); @@ -242,12 +246,25 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode, return (handle); if (GetLastError() != ERROR_PATH_NOT_FOUND) return (handle); +#endif wpath = __la_win_permissive_name(path); if (wpath == NULL) - return (handle); + return INVALID_HANDLE_VALUE; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF; + createExParams.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000; + createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F00000; + createExParams.lpSecurityAttributes = lpSecurityAttributes; + createExParams.hTemplateFile = hTemplateFile; + handle = CreateFile2(wpath, dwDesiredAccess, dwShareMode, + dwCreationDisposition, &createExParams); +#else /* !WINAPI_PARTITION_DESKTOP */ handle = CreateFileW(wpath, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); +#endif /* !WINAPI_PARTITION_DESKTOP */ free(wpath); return (handle); } @@ -305,7 +322,10 @@ __la_open(const char *path, int flags, ...) * "Permission denied" error. */ attr = GetFileAttributesA(path); - if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) { +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) + if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) +#endif + { ws = __la_win_permissive_name(path); if (ws == NULL) { errno = EINVAL; @@ -320,7 +340,7 @@ __la_open(const char *path, int flags, ...) } if (attr & FILE_ATTRIBUTE_DIRECTORY) { HANDLE handle; - +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) if (ws != NULL) handle = CreateFileW(ws, 0, 0, NULL, OPEN_EXISTING, @@ -333,6 +353,15 @@ __la_open(const char *path, int flags, ...) FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL); +#else /* !WINAPI_PARTITION_DESKTOP */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileAttributes = FILE_ATTRIBUTE_READONLY; + createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; + handle = CreateFile2(ws, 0, 0, + OPEN_EXISTING, &createExParams); +#endif /* !WINAPI_PARTITION_DESKTOP */ free(ws); if (handle == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); diff --git a/libarchive/archive_write_add_filter_compress.c b/libarchive/archive_write_add_filter_compress.c index d404fae7dba4..3ed269fce943 100644 --- a/libarchive/archive_write_add_filter_compress.c +++ b/libarchive/archive_write_add_filter_compress.c @@ -352,7 +352,7 @@ archive_compressor_compress_write(struct archive_write_filter *f, while (length--) { c = *bp++; state->in_count++; - state->cur_fcode = (c << 16) + state->cur_code; + state->cur_fcode = (c << 16) | state->cur_code; i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */ if (state->hashtab[i] == state->cur_fcode) { diff --git a/libarchive/archive_write_add_filter_zstd.c b/libarchive/archive_write_add_filter_zstd.c index 37c5e741ebee..f32258b460eb 100644 --- a/libarchive/archive_write_add_filter_zstd.c +++ b/libarchive/archive_write_add_filter_zstd.c @@ -451,6 +451,7 @@ archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff, static int archive_compressor_zstd_flush(struct archive_write_filter *f) { + (void)f; /* UNUSED */ return (ARCHIVE_OK); } diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c index 09a5eef03dab..f28aaefdce5f 100644 --- a/libarchive/archive_write_disk_posix.c +++ b/libarchive/archive_write_disk_posix.c @@ -397,6 +397,7 @@ static int set_times_from_entry(struct archive_write_disk *); 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 void close_file_descriptor(struct archive_write_disk *); static int _archive_write_disk_close(struct archive *); static int _archive_write_disk_free(struct archive *); @@ -514,7 +515,12 @@ lazy_stat(struct archive_write_disk *a) * XXX At this point, symlinks should not be hit, otherwise * XXX a race occurred. Do we want to check explicitly for that? */ - if (lstat(a->name, &a->st) == 0) { +#ifdef HAVE_LSTAT + if (lstat(a->name, &a->st) == 0) +#else + if (la_stat(a->name, &a->st) == 0) +#endif + { a->pst = &a->st; return (ARCHIVE_OK); } @@ -1726,6 +1732,7 @@ _archive_write_disk_finish_entry(struct archive *_a) r = hfs_write_data_block( a, null_d, a->file_remaining_bytes); if (r < 0) + close_file_descriptor(a); return ((int)r); } #endif @@ -1735,6 +1742,7 @@ _archive_write_disk_finish_entry(struct archive *_a) a->filesize == 0) { archive_set_error(&a->archive, errno, "File size could not be restored"); + close_file_descriptor(a); return (ARCHIVE_FAILED); } #endif @@ -1744,8 +1752,10 @@ _archive_write_disk_finish_entry(struct archive *_a) * to see what happened. */ a->pst = NULL; - if ((ret = lazy_stat(a)) != ARCHIVE_OK) - return (ret); + if ((ret = lazy_stat(a)) != ARCHIVE_OK) { + close_file_descriptor(a); + return (ret); + } /* We can use lseek()/write() to extend the file if * ftruncate didn't work or isn't available. */ if (a->st.st_size < a->filesize) { @@ -1753,11 +1763,13 @@ _archive_write_disk_finish_entry(struct archive *_a) if (lseek(a->fd, a->filesize - 1, SEEK_SET) < 0) { archive_set_error(&a->archive, errno, "Seek failed"); + close_file_descriptor(a); return (ARCHIVE_FATAL); } if (write(a->fd, &nul, 1) < 0) { archive_set_error(&a->archive, errno, "Write to restore size failed"); + close_file_descriptor(a); return (ARCHIVE_FATAL); } a->pst = NULL; @@ -2154,7 +2166,11 @@ restore_entry(struct archive_write_disk *a) * then don't follow it. */ if (r != 0 || !S_ISDIR(a->mode)) +#ifdef HAVE_LSTAT r = lstat(a->name, &a->st); +#else + r = la_stat(a->name, &a->st); +#endif if (r != 0) { archive_set_error(&a->archive, errno, "Can't stat existing object"); @@ -2550,7 +2566,12 @@ _archive_write_disk_close(struct archive *_a) goto skip_fixup_entry; } else #endif - if (lstat(p->name, &st) != 0 || + if ( +#ifdef HAVE_LSTAT + lstat(p->name, &st) != 0 || +#else + la_stat(p->name, &st) != 0 || +#endif la_verify_filetype(st.st_mode, p->filetype) == 0) { goto skip_fixup_entry; @@ -2565,7 +2586,12 @@ _archive_write_disk_close(struct archive *_a) goto skip_fixup_entry; } else #endif - if (lstat(p->name, &st) != 0 || + if ( +#ifdef HAVE_LSTAT + lstat(p->name, &st) != 0 || +#else + la_stat(p->name, &st) != 0 || +#endif la_verify_filetype(st.st_mode, p->filetype) == 0) { goto skip_fixup_entry; @@ -2785,8 +2811,8 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT)) /* Platform doesn't have lstat, so we can't look for symlinks. */ (void)path; /* UNUSED */ - (void)error_number; /* UNUSED */ - (void)error_string; /* UNUSED */ + (void)a_eno; /* UNUSED */ + (void)a_estr; /* UNUSED */ (void)flags; /* UNUSED */ (void)checking_linkname; /* UNUSED */ return (ARCHIVE_OK); @@ -2859,8 +2885,10 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, /* Check that we haven't hit a symlink. */ #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT) r = fstatat(chdir_fd, head, &st, AT_SYMLINK_NOFOLLOW); -#else +#elif defined(HAVE_LSTAT) r = lstat(head, &st); +#else + r = la_stat(head, &st); #endif if (r != 0) { tail[0] = c; @@ -3558,7 +3586,9 @@ set_time(int fd, int mode, const char *name, (void)fd; /* UNUSED */ (void)mode; /* UNUSED */ (void)name; /* UNUSED */ + (void)atime; /* UNUSED */ (void)atime_nsec; /* UNUSED */ + (void)mtime; /* UNUSED */ (void)mtime_nsec; /* UNUSED */ return (ARCHIVE_WARN); #endif @@ -4391,7 +4421,12 @@ fixup_appledouble(struct archive_write_disk *a, const char *pathname) */ archive_strncpy(&datafork, pathname, p - pathname); archive_strcat(&datafork, p + 2); - if (lstat(datafork.s, &st) == -1 || + if ( +#ifdef HAVE_LSTAT + lstat(datafork.s, &st) == -1 || +#else + la_stat(datafork.s, &st) == -1 || +#endif (st.st_mode & AE_IFMT) != AE_IFREG) goto skip_appledouble; @@ -4707,5 +4742,17 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, } #endif +/* + * Close the file descriptor if one is open. + */ +static void close_file_descriptor(struct archive_write_disk* a) +{ + if (a->fd >= 0) { + close(a->fd); + a->fd = -1; + } +} + + #endif /* !_WIN32 || __CYGWIN__ */ diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c index 88df3ce020f4..7b9ea74937cb 100644 --- a/libarchive/archive_write_disk_windows.c +++ b/libarchive/archive_write_disk_windows.c @@ -254,9 +254,9 @@ static ssize_t _archive_write_disk_data_block(struct archive *, const void *, * which is high-16-bits of nFileIndexHigh. */ #define bhfi_ino(bhfi) \ ((((int64_t)((bhfi)->nFileIndexHigh & 0x0000FFFFUL)) << 32) \ - + (bhfi)->nFileIndexLow) + | (bhfi)->nFileIndexLow) #define bhfi_size(bhfi) \ - ((((int64_t)(bhfi)->nFileSizeHigh) << 32) + (bhfi)->nFileSizeLow) + ((((int64_t)(bhfi)->nFileSizeHigh) << 32) | (bhfi)->nFileSizeLow) static int file_information(struct archive_write_disk *a, wchar_t *path, @@ -266,6 +266,9 @@ file_information(struct archive_write_disk *a, wchar_t *path, int r; DWORD flag = FILE_FLAG_BACKUP_SEMANTICS; WIN32_FIND_DATAW findData; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif if (sim_lstat || mode != NULL) { h = FindFirstFileW(path, &findData); @@ -290,14 +293,27 @@ file_information(struct archive_write_disk *a, wchar_t *path, (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK))) flag |= FILE_FLAG_OPEN_REPARSE_POINT; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = flag; + h = CreateFile2(a->name, 0, 0, + OPEN_EXISTING, &createExParams); +#else h = CreateFileW(a->name, 0, 0, NULL, OPEN_EXISTING, flag, NULL); +#endif if (h == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME) { wchar_t *full; full = __la_win_permissive_name_w(path); +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + h = CreateFile2(full, 0, 0, + OPEN_EXISTING, &createExParams); +#else h = CreateFileW(full, 0, 0, NULL, OPEN_EXISTING, flag, NULL); +#endif free(full); } if (h == INVALID_HANDLE_VALUE) { @@ -559,6 +575,7 @@ la_mktemp(struct archive_write_disk *a) return (fd); } +#if _WIN32_WINNT < _WIN32_WINNT_VISTA static void * la_GetFunctionKernel32(const char *name) { @@ -574,18 +591,24 @@ la_GetFunctionKernel32(const char *name) } return (void *)GetProcAddress(lib, name); } +#endif static int la_CreateHardLinkW(wchar_t *linkname, wchar_t *target) { - static BOOLEAN (WINAPI *f)(LPWSTR, LPWSTR, LPSECURITY_ATTRIBUTES); - static int set; + static BOOL (WINAPI *f)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); BOOL ret; +#if _WIN32_WINNT < _WIN32_WINNT_XP + static int set; +/* CreateHardLinkW is available since XP and always loaded */ if (!set) { set = 1; f = la_GetFunctionKernel32("CreateHardLinkW"); } +#else + f = CreateHardLinkW; +#endif if (!f) { errno = ENOTSUP; return (0); @@ -624,7 +647,6 @@ static int la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target, int linktype) { static BOOLEAN (WINAPI *f)(LPCWSTR, LPCWSTR, DWORD); - static int set; wchar_t *ttarget, *p; size_t len; DWORD attrs = 0; @@ -632,10 +654,20 @@ la_CreateSymbolicLinkW(const wchar_t *linkname, const wchar_t *target, DWORD newflags = 0; BOOL ret = 0; +#if _WIN32_WINNT < _WIN32_WINNT_VISTA +/* CreateSymbolicLinkW is available since Vista and always loaded */ + static int set; if (!set) { set = 1; f = la_GetFunctionKernel32("CreateSymbolicLinkW"); } +#else +# if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + f = CreateSymbolicLinkW; +# else + f = NULL; +# endif +#endif if (!f) return (0); @@ -1185,6 +1217,8 @@ _archive_write_disk_finish_entry(struct archive *_a) if (la_ftruncate(a->fh, a->filesize) == -1) { archive_set_error(&a->archive, errno, "File size could not be restored"); + CloseHandle(a->fh); + a->fh = INVALID_HANDLE_VALUE; return (ARCHIVE_FAILED); } } @@ -1656,6 +1690,9 @@ create_filesystem_object(struct archive_write_disk *a) mode_t final_mode, mode; int r; DWORD attrs = 0; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif /* We identify hard/symlinks according to the link names. */ /* Since link(2) and symlink(2) don't handle modes, we're done here. */ @@ -1719,8 +1756,16 @@ create_filesystem_object(struct archive_write_disk *a) a->todo = 0; a->deferred = 0; } else if (r == 0 && a->filesize > 0) { +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + a->fh = CreateFile2(namefull, GENERIC_WRITE, 0, + TRUNCATE_EXISTING, &createExParams); +#else a->fh = CreateFileW(namefull, GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +#endif if (a->fh == INVALID_HANDLE_VALUE) { la_dosmaperr(GetLastError()); r = errno; @@ -1783,14 +1828,27 @@ create_filesystem_object(struct archive_write_disk *a) a->tmpname = NULL; fullname = a->name; /* O_WRONLY | O_CREAT | O_EXCL */ +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + a->fh = CreateFile2(fullname, GENERIC_WRITE, 0, + CREATE_NEW, &createExParams); +#else a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); +#endif if (a->fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME && fullname == a->name) { fullname = __la_win_permissive_name_w(a->name); +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + a->fh = CreateFile2(fullname, GENERIC_WRITE, 0, + CREATE_NEW, &createExParams); +#else a->fh = CreateFileW(fullname, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); +#endif } if (a->fh == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_ACCESS_DENIED) { @@ -2551,14 +2609,25 @@ set_times(struct archive_write_disk *a, hw = NULL; } else { wchar_t *ws; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + CREATEFILE2_EXTENDED_PARAMETERS createExParams; +#endif if (S_ISLNK(mode)) return (ARCHIVE_OK); ws = __la_win_permissive_name_w(name); if (ws == NULL) goto settimes_failed; +# if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ + ZeroMemory(&createExParams, sizeof(createExParams)); + createExParams.dwSize = sizeof(createExParams); + createExParams.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; + hw = CreateFile2(ws, FILE_WRITE_ATTRIBUTES, 0, + OPEN_EXISTING, &createExParams); +#else hw = CreateFileW(ws, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); +#endif free(ws); if (hw == INVALID_HANDLE_VALUE) goto settimes_failed; diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c index f946fc7b5acd..c9c159164680 100644 --- a/libarchive/archive_write_set_format_pax.c +++ b/libarchive/archive_write_set_format_pax.c @@ -45,15 +45,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_pax.c 201162 20 #include "archive_write_private.h" #include "archive_write_set_format_private.h" - /* - * Technically, the mtime field in the ustar header can - * support 33 bits. We are using all of them to keep - * tar/test/test_option_C_mtree.c simple and passing after 2038. - * Platforms that use signed 32-bit time values need to fix - * their handling of timestamps anyway. - */ -#define USTAR_MAX_MTIME 0x1ffffffff - struct sparse_block { struct sparse_block *next; int is_hole; @@ -109,6 +100,7 @@ static int has_non_ASCII(const char *); static void sparse_list_clear(struct pax *); static int sparse_list_add(struct pax *, int64_t, int64_t); static char *url_encode(const char *in); +static time_t get_ustar_max_mtime(void); /* * Set output format to 'restricted pax' format. @@ -604,6 +596,8 @@ archive_write_pax_header(struct archive_write *a, need_extension = 0; pax = (struct pax *)a->format_data; + const time_t ustar_max_mtime = get_ustar_max_mtime(); + /* Sanity check. */ if (archive_entry_pathname(entry_original) == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -1131,7 +1125,7 @@ archive_write_pax_header(struct archive_write *a, */ if (!need_extension && ((archive_entry_mtime(entry_main) < 0) - || (archive_entry_mtime(entry_main) >= USTAR_MAX_MTIME))) + || (archive_entry_mtime(entry_main) >= ustar_max_mtime))) need_extension = 1; /* I use a star-compatible file flag attribute. */ @@ -1196,7 +1190,7 @@ archive_write_pax_header(struct archive_write *a, if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED || need_extension) { if (archive_entry_mtime(entry_main) < 0 || - archive_entry_mtime(entry_main) >= USTAR_MAX_MTIME || + archive_entry_mtime(entry_main) >= ustar_max_mtime || archive_entry_mtime_nsec(entry_main) != 0) add_pax_attr_time(&(pax->pax_header), "mtime", archive_entry_mtime(entry_main), @@ -1434,7 +1428,7 @@ archive_write_pax_header(struct archive_write *a, /* Copy mtime, but clip to ustar limits. */ s = archive_entry_mtime(entry_main); if (s < 0) { s = 0; } - if (s > USTAR_MAX_MTIME) { s = USTAR_MAX_MTIME; } + if (s > ustar_max_mtime) { s = ustar_max_mtime; } archive_entry_set_mtime(pax_attr_entry, s, 0); /* Standard ustar doesn't support atime. */ @@ -2052,3 +2046,18 @@ sparse_list_add(struct pax *pax, int64_t offset, int64_t length) return (_sparse_list_add_block(pax, offset, length, 0)); } +static time_t +get_ustar_max_mtime(void) +{ + /* + * Technically, the mtime field in the ustar header can + * support 33 bits. We are using all of them to keep + * tar/test/test_option_C_mtree.c simple and passing after 2038. + * For platforms that use signed 32-bit time values we + * use the 32-bit maximum. + */ + if (sizeof(time_t) > sizeof(int32_t)) + return (time_t)0x1ffffffff; + else + return (time_t)0x7fffffff; +} diff --git a/libarchive/filter_fork_windows.c b/libarchive/filter_fork_windows.c index 0b963975b90d..9e49c5655f1d 100644 --- a/libarchive/filter_fork_windows.c +++ b/libarchive/filter_fork_windows.c @@ -31,6 +31,7 @@ #include "filter_fork.h" +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) /* 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. */ @@ -224,6 +225,14 @@ fail: __archive_cmdline_free(acmd); return ARCHIVE_FAILED; } +#else /* !WINAPI_PARTITION_DESKTOP */ +int +__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, HANDLE *out_child) +{ + (void)cmd; (void)child_stdin; (void) child_stdout; (void) out_child; + return ARCHIVE_FAILED; +} +#endif /* !WINAPI_PARTITION_DESKTOP */ void __archive_check_child(int in, int out) diff --git a/libarchive/test/test_fuzz.c b/libarchive/test/test_fuzz.c index 3fbe64410bc4..8af4c2f296f8 100644 --- a/libarchive/test/test_fuzz.c +++ b/libarchive/test/test_fuzz.c @@ -124,10 +124,9 @@ test_fuzz(const struct files *filesets) newraw = realloc(rawimage, oldsize + size); if (!assert(newraw != NULL)) { - free(rawimage); - rawimage = NULL; free(tmp); - continue; + size = 0; + break; } rawimage = newraw; memcpy(rawimage + oldsize, tmp, size); diff --git a/libarchive/test/test_read_disk_directory_traversals.c b/libarchive/test/test_read_disk_directory_traversals.c index bca3ce518e21..ad99acfef258 100644 --- a/libarchive/test/test_read_disk_directory_traversals.c +++ b/libarchive/test/test_read_disk_directory_traversals.c @@ -1608,6 +1608,12 @@ test_parent(void) int file_count; int match_count; int r; +#if defined(O_PATH) || defined(O_SEARCH) || \ + (defined(__FreeBSD__) && defined(O_EXEC)) + const char *ignore_traversals_test4; + + ignore_traversals_test4 = getenv("IGNORE_TRAVERSALS_TEST4"); +#endif assertMakeDir("lock", 0311); assertMakeDir("lock/dir1", 0755); @@ -1784,7 +1790,8 @@ test_parent(void) if (r == ARCHIVE_FAILED) { #if defined(O_PATH) || defined(O_SEARCH) || \ (defined(__FreeBSD__) && defined(O_EXEC)) - assertEqualIntA(a, ARCHIVE_OK, r); + if (ignore_traversals_test4 == NULL) + assertEqualIntA(a, ARCHIVE_OK, r); #endif /* Close the disk object. */ archive_read_close(a); diff --git a/libarchive/test/test_read_format_7zip.c b/libarchive/test/test_read_format_7zip.c index 3c72595aeef7..1eca3936e5b4 100644 --- a/libarchive/test/test_read_format_7zip.c +++ b/libarchive/test/test_read_format_7zip.c @@ -30,6 +30,9 @@ __FBSDID("$FreeBSD"); #define open _open #endif +#define __LIBARCHIVE_BUILD +#include <archive_crc32.h> + /* * Extract a non-encoded file. * The header of the 7z archive files is not encoded. @@ -284,6 +287,141 @@ test_extract_all_files(const char *refname) } /* + * Extract multi files. + * Like test_extract_all_files, but with zstandard compression. + */ +static void +test_extract_all_files_zstd(const char *refname) +{ + struct archive_entry *ae; + struct archive *a; + char buff[128]; + + extract_reference_file(refname); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + /* Verify directory dir1. Note that this comes before the dir1/file1 entry in recent versions of 7-Zip. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFDIR | 0755), archive_entry_mode(ae)); + assertEqualString("dir1/", archive_entry_pathname(ae)); + assertEqualInt(2764801, archive_entry_mtime(ae)); + assertEqualInt(archive_entry_is_encrypted(ae), 0); + assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); + + /* Verify regular file1. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae)); + assertEqualString("dir1/file1", archive_entry_pathname(ae)); + assertEqualInt(86401, archive_entry_mtime(ae)); + assertEqualInt(13, archive_entry_size(ae)); + assertEqualInt(archive_entry_is_encrypted(ae), 0); + assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); + assertEqualInt(13, archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, "aaaaaaaaaaaa\n", 13); + + /* Verify regular file2. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae)); + assertEqualString("file2", archive_entry_pathname(ae)); + assertEqualInt(86401, archive_entry_mtime(ae)); + assertEqualInt(26, archive_entry_size(ae)); + assertEqualInt(archive_entry_is_encrypted(ae), 0); + assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); + assertEqualInt(26, archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, "aaaaaaaaaaaa\nbbbbbbbbbbbb\n", 26); + + /* Verify regular file3. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae)); + assertEqualString("file3", archive_entry_pathname(ae)); + assertEqualInt(86401, archive_entry_mtime(ae)); + assertEqualInt(39, archive_entry_size(ae)); + assertEqualInt(archive_entry_is_encrypted(ae), 0); + assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); + assertEqualInt(39, archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, "aaaaaaaaaaaa\nbbbbbbbbbbbb\ncccccccccccc\n", 39); + + /* Verify regular file4. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0644), archive_entry_mode(ae)); + assertEqualString("file4", archive_entry_pathname(ae)); + assertEqualInt(86401, archive_entry_mtime(ae)); + assertEqualInt(52, archive_entry_size(ae)); + assertEqualInt(archive_entry_is_encrypted(ae), 0); + assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); + assertEqualInt(52, archive_read_data(a, buff, sizeof(buff))); + assertEqualMem(buff, + "aaaaaaaaaaaa\nbbbbbbbbbbbb\ncccccccccccc\ndddddddddddd\n", 52); + + assertEqualInt(5, archive_file_count(a)); + + /* End of archive. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + /* Verify archive format. */ + assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0)); + assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a)); + + /* Close the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +/* + * Extract file from an archives using ZSTD compression with and without BCJ. + */ +static void +test_extract_file_zstd_bcj_nobjc(const char *refname) +{ + struct archive_entry *ae; + struct archive *a; + char buff[4096]; + uint32_t computed_crc = 0; + uint32_t expected_crc = 0xbd66eebc; + + extract_reference_file(refname); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + /* Verify regular file: hw. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0775), archive_entry_mode(ae)); + assertEqualString("hw", archive_entry_pathname(ae)); + assertEqualInt(1685913368, archive_entry_mtime(ae)); + assertEqualInt(15952, archive_entry_size(ae)); + assertEqualInt(archive_entry_is_encrypted(ae), 0); + assertEqualIntA(a, archive_read_has_encrypted_entries(a), 0); + + for (;;) { + la_ssize_t bytes_read = archive_read_data(a, buff, sizeof(buff)); + assert(bytes_read >= 0); + if (bytes_read == 0) break; + computed_crc = crc32(computed_crc, buff, bytes_read); + } + assertEqualInt(computed_crc, expected_crc); + + assertEqualInt(1, archive_file_count(a)); + + /* End of archive. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + /* Verify archive format. */ + assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0)); + assertEqualIntA(a, ARCHIVE_FORMAT_7ZIP, archive_format(a)); + + /* Close the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +/* * Extract last file. * The header of the 7z archive files is encoded with LZMA. */ @@ -782,6 +920,74 @@ DEFINE_TEST(test_read_format_7zip_deflate) assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } +DEFINE_TEST(test_read_format_7zip_zstd) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + /* Extracting with libzstd */ + if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) { + skipping( + "7zip:zstd decoding is not supported on this platform"); + } else { + test_extract_all_files_zstd("test_read_format_7zip_zstd.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_zstd_solid) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + /* Extracting with libzstd */ + if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) { + skipping( + "7zip:zstd decoding is not supported on this platform"); + } else { + test_extract_all_files_zstd("test_read_format_7zip_solid_zstd.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_zstd_bcj) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + /* Extracting with libzstd */ + if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) { + skipping( + "7zip:zstd decoding is not supported on this platform"); + } else { + test_extract_file_zstd_bcj_nobjc("test_read_format_7zip_zstd_bcj.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_zstd_nobcj) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + /* Extracting with libzstd */ + if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) { + skipping( + "7zip:zstd decoding is not supported on this platform"); + } else { + test_extract_file_zstd_bcj_nobjc("test_read_format_7zip_zstd_nobcj.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + DEFINE_TEST(test_read_format_7zip_empty) { test_empty_archive(); @@ -832,7 +1038,147 @@ DEFINE_TEST(test_read_format_7zip_lzma2) assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } +static void +test_arm_filter(const char *refname) +{ + struct archive *a; + struct archive_entry *ae; + char buff[7804]; + uint32_t computed_crc = 0; + uint32_t expected_crc = 0x355ec4e1; + + assert((a = archive_read_new()) != NULL); + + extract_reference_file(refname); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0755), archive_entry_mode(ae)); + assertEqualString("hw-gnueabihf", archive_entry_pathname(ae)); + assertEqualInt(sizeof(buff), archive_entry_size(ae)); + assertEqualInt(sizeof(buff), archive_read_data(a, buff, sizeof(buff))); + computed_crc = crc32(computed_crc, buff, sizeof(buff)); + assertEqualInt(computed_crc, expected_crc); + + assertEqualInt(1, archive_file_count(a)); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_zstd_arm) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) { + skipping( + "7zip:zstd decoding is not supported on this platform"); + } else { + test_arm_filter("test_read_format_7zip_zstd_arm.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_lzma2_arm) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { + skipping( + "7zip:lzma decoding is not supported on this platform"); + } else { + test_arm_filter("test_read_format_7zip_lzma2_arm.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + DEFINE_TEST(test_read_format_7zip_ppmd) { test_ppmd(); } + +static void +test_arm64_filter(const char *refname) +{ + struct archive *a; + struct archive_entry *ae; + char buff[70368]; + uint32_t computed_crc = 0; + uint32_t expected_crc = 0xde97d594; + + assert((a = archive_read_new()) != NULL); + + extract_reference_file(refname); + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0775), archive_entry_mode(ae)); + assertEqualString("hw-arm64", archive_entry_pathname(ae)); + assertEqualInt(sizeof(buff), archive_entry_size(ae)); + assertEqualInt(sizeof(buff), archive_read_data(a, buff, sizeof(buff))); + computed_crc = crc32(computed_crc, buff, sizeof(buff)); + assertEqualInt(computed_crc, expected_crc); + + assertEqualInt(1, archive_file_count(a)); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_lzma2_arm64) +{ +#ifdef HAVE_LZMA_FILTER_ARM64 + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { + skipping( + "7zip:lzma decoding is not supported on this platform"); + } else { + test_arm64_filter("test_read_format_7zip_lzma2_arm64.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +#else + skipping("This version of liblzma does not support LZMA_FILTER_ARM64"); +#endif +} + +DEFINE_TEST(test_read_format_7zip_deflate_arm64) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_gzip(a)) { + skipping( + "7zip:deflate decoding is not supported on this platform"); + } else { + test_arm64_filter("test_read_format_7zip_deflate_arm64.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} diff --git a/libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu b/libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu new file mode 100644 index 000000000000..e516ca5b4792 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_deflate_arm64.7z.uu @@ -0,0 +1,64 @@ +begin 664 libarchive/test/test_read_format_7zip_deflate_arm64.7z +M-WJ\KR<<``2V^52G)0H```````!:`````````.HY+B_LU5^(3%$<P/%SYPY+ +M_N1?*/]F5R'Y3_['&'^&0FB]T9BU@ZFQH]F1#65X4C:9"`](HI`'#PHO_N5! +M>2.2T-J0XF&*!R-C_.Z=<^_<NSLKWK^?]MS?GM\]OW//W'ONS*&5:U<%#$,Y +M3'5;6;UP[TH_K/,=_:RLDYNO^LIQM!JEK&%!=USW^,/PQS[.=73=_(`<ND>9 +MV1\-3^RE>M;>QXU.A7.TUWJB)`<[&KZ8T]<]&O#7!73=1:O.CH8O%NQ0C<YE +M@[HUVO-UCRN4/P9UW/`QVVS]?[E.#C7B8J5CE[J-4M=;_;M!.FZRKO>7^[)' +MUEN-U><P/95LFIYJGII*MNQMFQJ/9[;OFCMG6FMZVLS*FH;I9QQ=OUE]G#AY +MPO$S5]KO[MVZ^,;!A0-:?S;L">HU&)4Q[IZH<^Z^V_Z?J?JI.[UJY8?;3]2E +MG^V0&G.LDQ:JD1\IK:%&/MG#^(D]S&_TD&_K/H]^`'NSK2H6D]N^/=::C6>R +ML=WQ9(MDMK?%8SN2+?%4<G]"Q9O2F:RR!EG/8JZ*KET361Z;-6WF//??V7-4 +M;$WCNEAS(I/8F6S-)C*-ZY:GTBV)QGA3*B$3[MR=;M&7B%6&UAQ8$9!/8MK- +MK#POR4SU[*\S^=.]K3L_3^=N2=^JBBC_?C.#>O_K#7#6EZ]NC$+9GV^L<]Z[ +M@,[[^Z_T>$/R\N?J<//^[Y//GKSW??KAR??UY*_J?"!H?<JJFTZ^R_QWG'R7 +M^1]X\G6>_!-/OH\G/RYDOB@=N'^M9*K\>4.=*AUX>/6!&7M9D%Q!;M/@9]'B +MH"-+\J'`N)?66*?9YU[*N4N5<W;_M?0?>?KOI-_IZ7=*/["TVO\D_8:E[MQC +M5.[96&D?377]O1DN=HY7^4^RK@X9JWY$BZ:<"TH[*.L\*LW.?X\6P[(=/I3+ +M(V3=[AIE`YV0'X^\(;%>XE*EOCR0Q_Q>:NJ_1HMQJ2F8QG4EU[;JNHZO5^II +MPZ]#SY?U/WRL_M>RDP]E?*?41GY%BTUV;<"MK=S#>_8]_-9/%8?*'-LBX05A +M0\VSUUB(%G-28U\C&"[F9.V7I854;M.VB%KPK5^X6#KPZ*IW_6_D\SAS=HQ3 +M=]_+O-8V5]O&YMNE5DEMM:;Z#)WG9^A]NRN12J5#^]*95+,R1IF+YNOOJG._ +MR^4-$K]*;)8XNEPN6]\96R2V2[PA\::U_R0^]KR'QOY-*M@VUAC5?YR=&REM +MA<PQQSJYK&ZLE9LB+2>Y&9[?B+"^IO-[$[+>.6M?2FZU73LP=#YXP8R<#*Q_ +M]_;Y0*?.6M-W&>.\<Z.E6>O[(+E)GKK5[]X.5``````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````#PIQUK"7$B"*(ULY_$__\O$M2#"@F; +M]2^"&_^"/S0*(MI,,K.;T62R3"::50\>!/6@B'A8!$'0@X('3^)1;QX4/`I> +M5-23@H(?5#36))79Z4EE=P_B:=[2>>G75=7=-36]F0D1(D2($"%"A`@1(D2( +M$"%"C`I[(U`'L4+=./%XXH<==9Y`_3-D/X?Z5W[7/>=1/TH\EWB0QN<'QK_^ +MJ19KXRK4T$'ZG;8Z=S;FI_&QU+]*/(YX-O$,D-'66%]5J;%*_0KQ=/_V$;.( +M>SID_6R[O.Y'Q&,"\R\`V>Y7M;X_A:0_U-]+\:K>>!V?J+^.QG]0OQW^+YYW +MC(YOXG4=#ND(L(C2E=BV:=.ZV)(#F;+EE&/)Y?'NKN[E7=W)E?%DN:9U+T4U +MT95(QAHCL25&I=^PS8)A.5I^:>QP02LYAAVST7OEVK5KXWW+>U<G,VNZ5ZY= +M91R!4:`-%%BC<KH*:4['OPJKM\,@JW?`0U;OQ#KG]`A>?TZ/PEY6'P-G67TL +MUC&GCX.'K#X>GK/Z!.CIY/2)>`YP^B2XPNJ3X3:K3X%7K#[5.U=D?1H,LOIT +MN,GJ,_#^Y_29^*DR^BR8S.JS(0BE=F]^KH($.A>8.AGO^OCT&.DS`4%Y;HXS +M!;Y$&)W)\QQ^/5Y\QQ^?YE=]^G3)7JX33V>N>YR?UXOSI$6<"X$X*T98_Y7` +M^C=@4QD]1?HC-I\SZ?P90IKL(;">8]@47STH_CA,'9YP;1C]!L7?RUU'IL[O +M8E-(Y^HA&F7B,'7[9-CZG`2#$3[/Z0A?A[GHZ*Y7P_Y"P/X9-H5T&7R<EZX] +MZL'[^BT@F//D.]D_KRK-^V+.MPF*F_UF+$,]!LVXZ.K,N;$5]<E,_M.H+X1F +MG"'[V0%[JZ;/;(I3=M>I-M]WIUO$.>_JS#JOM=C7+=2GJ,WWQ?T6^7GLVOO. +MG_;&[X86]J]:K/.2:^\[]U:0_JZ%_<<6>?Y!<1IUNX3T/[2OH/U8E<_#8M7- +M,_/_<7_6=I*)(BS600@M8PI'ZX/%%4#91#FKY?/BI*$=%[V6JUFH(96<<F]O +M(@NZ81M]IOL[13@%D<T7+:.$<?2BZ,L7,UI>Z$[1+@FMC`&+A?Z\X1AZHHNW +M$+VF90K-MK4!@;^![`'HM;6"(?1RH3"`+KZ>0$M',LV=Q-4(L75?:M<6L67W +M9B%`;#ZT.[5KQR:4M^T^(+9LI]'MF_>!V+9SS\;43K%GZ];]6](BG=JX<PMZ +MB+R9R8J2H]F.*&BFU;-MYXZ-FT1W8OD*$#O2N\30?M.[-KF[36N9O(&.F5*) +M_-PPV8KF[D;+FZ<,+T9R-0A#UQP-:CLE)\/2:R[N0#T"=OH*1<L73B\514ZS +M=)Q)RQ1M1PJY8P]:ZJ8ERB5#A_ZR4Y*&,3X(FL6W3'"WAP)N@])5VQ^[NUJV +M`1*E@8*C99`=N\ZYQC?30I]^2%A%QTCT6>5$IFSF];BIDY3:N"/NUE5M+*>5 +M<I#0!RR,5V.,4A\Y8=@ELVA)'8%CMI'77$/ZUI]WW"E-_'2,"GZZZ<2Q8BVY +M"2-'I9+3[:$>>G@U4_=H?,?`6L',XJQ%C%6/@7F"!%:L^V,<_@7F85-\I]8: +MU6,:EZ&`C$78(C[_M"KSXJ;_.3)6!?PKJLRQ$?PW8_N&SVP-_T%5YOFD=WC/ +M03)VTS.MZCWWROR)]$YL;3[_V<0'25>]YVB9KXZ0OZ/8JK[UKVN7>7I@_6J` +MCV/[X_/?VRYSEV_]"K/_4Y33AO_9=ID?^>=G]G^._#=ZS_$R5WS^,QC_R[2N +M3N^]A\RS1[C^%QO^+9ZC^T'&9)!Q+>#?TRGS>@4D](",ZP'_,Q&9IX^P_IN! +M^^]*Q&/9OT7]W@GXWX[(O'Z$^1\$_%]%9+[7>GZO/B9B:Y/?2R'S]M$`/\4V +M:<B??L<CC]+_A7=O>N]'B.G^5:C^/3^Y#E[3_GWOK8@;]3/\_.]E?U\F%9IG +M^/Q](*W-6Y=*K'#VJ,KX3%H7>)#\-=9?9A6:42&+GNC0>\44<_^.\=8NXV&T +M[K],'7[]4UKXOQE;M_P)P_O_!0$$!@`!"8HE``<+`0`"`P0!"`$*`0`,P>`2 +MP>`2``@*`935E]X```4!&0(``!$3`&@`=P`M`&$`<@!M`#8`-````!D`%`H! +3`#)5M-E?M]D!%08!`""`_8$````` +` +end diff --git a/libarchive/test/test_read_format_7zip_lzma2_arm.7z.uu b/libarchive/test/test_read_format_7zip_lzma2_arm.7z.uu new file mode 100644 index 000000000000..5a6ade031f22 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_lzma2_arm.7z.uu @@ -0,0 +1,50 @@ +begin 664 test_read_format_7zip_lzma2_arm.7z +M-WJ\KR<<``3J_$W1N`<```````!B`````````.JU,0K@'GL'L%T`/Y%%A&@[ +MWMZF$<*4U"093^%DJ=J._J..`X9!2RX<PW^KV'J:BRK]Q@`9?>NX6*J`]\W5 +MV'E1<]9A1&J5D`#J!0K[IET\(=96D87RO?!\YQ>LH!0''871$*/B-@-70EJ0 +M`;\!OE9CF-^[@!DI0LA7Z5P`#.!8`&65OAKG.CZ"F_H1?0DF"U1TA(*8<K$Y +M"`*`&0@9W/J=9Q65I#T7A=LV)A'W8Q6[]T`[8.HQ,<*'Y=%CCL4UL$N;V&GM +MI7RJ;]"A19(O_OR+.K]#3$*$G*^<SN`@%$X^!18W$Y+"$FIZ9)G"S=N3P=MY +M@23KT_,1!2PF)J^TCK3^5BSV3W)6C:UM*;1D!?PAH?98?NIW3O*]ML<LU?8( +ME0(M;`*!0>JEQ>/>U8FBB]^E)QG>MQ_<EC_YO:6#IW1:YGQZ'#(?[%-S&E3` +M>LLWD%-YVI_%$>)09X;WO&$[MP(</^*QI;<0E?AA^"+H/%V:Z`]$HE('A,*@ +M,>[#E"AI4U,3VSH@/S*]#&EGP37GQ_#W*+P:2"&0(O=$S'+O'75NH+-'ZI&2 +M9W^I\?.Y`$T4YPC[ETIN9KTL\>"^-]*+([,!RK2%12BUU!TRF!5:8B?]<3K' +M1/*E5"22231Q(@S6P/`GO*EAHOGEC)B5=%X;>B*\-D*4#KGX(2,,P4)Q\PQ< +M?L=SG>R/AC>SH1S1_FUK7"#5\]0&QR9`];@`YS*UH9Q@P^S977+E@_P<I6:% +MV\9WL&_6E6J$T"1^]-_8C1\,X@29SIR(EJ\O:44&+X/%<$?10J8IR(&%AF]. +M;`+F2G45L/XC-@7U;H=RHM974^T46;FT[:G6,,,P]"10P=GVT5+BV1)_YV=B +M<\B/L"<*&$L@!/P<Q$WJ_V,L(LC941!U;DB(])_;Y7DS-#'M(`!%3000`RRJ +MSE1^5+W]-KSJGZ#GT3O>`0KHZO?1>:7[4.RMGB]SF\_BQFC89B)!U68-_]72 +MY'BDKM\E;<Q49A+\Z/CYP1;`KR7+G]W_08*13H%=,X1;R;/2^#=BVX4X8I'F +M'T?*[;I,B-"91D!&8&\#R_<GHH'7\J@OD=H?SM_W=?N*@SS-$3.!,MFC%0HQ +M7-]>]&4Z%FR?TOR2'H[7X@Y6`M+Q@![*&M9W!0F#^@UO(8TK]U#-8<-I\2$7 +M#?WC\89&95YI\\`DXII"-P@0IQJ:L4]:O*=@V!W58(_#7%9L4BR8-<$P`4S# +MJX#Y/>DIDB#/<S%?1)1#LCP@U968H3'-IR#YC8FQ-3C)Z?):2-`3K03?OEY/ +M3.<T(#E'C4&*,%M6LSQO7A`>.0DY67H@K60XS/*(46/U*%P?G\R_U#/(0%OF +M6B#:U+X9)8*I`.^U(`PKV^7%B=?Z%GP^8CQV8V#'_1?L2KB>;6>!N.8LI>3_ +M%)-N+<;/(+J(QI_U+9C&*VDR9)8X/!5R+N8W6N84NN@'S<J]QRE@GK>9P>KC +MN]XGR&MK!GN<HK%VC/V9OW_0(^T#&6OF+@T>V=Y(MV+YS=QEYQ-,':9VRQ^N +M<?,"^Q>PC!ALZ:]"J8\:9T.Y28?K^B>@@5(:I]M>EFH%-#Z>BRBL(L)]_J#F +MT7U4C[62SWU-_0&#JECK.K2F9Z/5_U\6"K2[$'8K*N!+?`(T`:3BN$=LA)7? +MS`:MK/59JR@1*#FE_'[X+C68S<AFM@Y/G0;^@IM-;&D`?X#.F=B/S'>P*%RH +MGV(2K8@W&^<"%O>`1]-6ODEC`^X__^'#-E9'<`F-W+^-/#*=00[^ER5/Z%<; +M<5>252LEY6L`C9Q:-4^3!XGD]CGO,-XD<B+!HVLXE7<&/+BVK#G.=ZEK#8:G +M=;<?5[UYQ576&(G[V8"PV&-*Y3:*A.<H1X]+J)J@)=KQBT&XAA<1A=JT61F= +M-B&4]P%7U1"[6[=5:\'WY8QN#Z,N.G(&2L:%K]%<)ZY@*^CN!Z[#Y<6+G>LT +M.;'"/12=:`C.Z+3G1-&=R-!O#5,V.W'"C9:N4?==ODY8#*:V;QL.N$ZR'R30 +M>U5QC/A0M`TOK9EX6PZ03U<?.D&.[%6Z($\PB;7M\A6V$P"YRO+\N`?8J;X[ +MJ[8\E=5>*3E;4527?8OP\+9NXTSDP.-ML`U\:36)X[JXOZ],_M[4ZD"D0T.7 +M3C*M=YOXBE!`I5-VO'3:YUR-42G):6"01XCG5%O]H17JJJQM8A<<,3RS8CI- +MT7FK7"\1P9GO?#3O07):>\L_RHRH?]3Z#W42TX43Z=2HC/8M!<N0+!")FIB% +MV?`J$WI4FYZW":A^MEWJ;@B_>H]),JTZ-@/"U#%4-Q#G9EP-$Y^]=$>X70[D +MCP*^+R.X5U[;%+0P8JWW)`P#'VE[%=I>G;TGBX!_**[`)D9.JV9DAAYM[`"# +M0]"E%F5%X?]_%@,>,Y*W"%H.!H6KV`7H>4&=7BX&?6K$"V@"*\#2BVIL.FH9 +M_YP"D5UNL[$1$U$GLQROKS__F*#'PH`%ZC5^,0\)'D&S:;?)8`W<F_<-'U5& +M[#<10!!3-G8TP#$/A-+X9)OJ@3KY$/#%F9C-O]K6DXQG<.AE*)N?>EYT,8"? +M1]-Z'S1^IEL/*WJ-LQ\;?%QQ8/*JUY93:52Y,XHJNY<;Q.GRQ`&ZY5)H9'2< +MVT<0P98-*4HW2:\I<\W>0HW2E[B9D8LYS:````$$!@`!"8>X``<+`0`"(2$! +M`@0#`P4!`0`,GGR>?``("@'AQ%XU```%`1D!`!$;`&@`=P`M`&<`;@!U`&4` +D80!B`&D`:`!F````&0`4"@$```-.&5"<V0$5!@$`((#M@0`` +` +end diff --git a/libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu b/libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu new file mode 100644 index 000000000000..3792a187ff02 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu @@ -0,0 +1,54 @@ +begin 664 libarchive/test/test_read_format_7zip_lzma2_arm64.7z +M-WJ\KR<<``0W'TW><P@```````!:`````````&'_J;[A$M\(:UT`/Y%%A&@] +MB:;:BN&&(J+"URDYX#ZEJ=1:R[LP;*R_8L2:_5F_1<^DV<8-2,=3[&X?U.=W +M*%Q!?DN>B^),$C`%""HM.8#>=`<R:?!<.$B$K6X!RY4*=X/2*.1;F86;KQ[4 +MW?4E#8Q06ZC4C+\8[JXT3(^1NKD"QCKT^=KB=;)Q=SIF6<^4QB+`Z)=$I>#! +MHGG`);CBW],\(2H/P+,[60V#BSUD@SPX?+]7UE`-G%X8-3UI(38JH=H'>(C4 +M.BHYW!+WO_VP/@H5V?EN8ESQEC<5V/WV[($3WNDOW%0OV?,5D(VX$W,9F]X6 +M$@+,!DJ9MCLG?+981]+>4RH&\+O6N:Z[J\UUAP1\;YX=FQG04]%"*WE/:)&N +M7]/;*`CB"$1/1LN;6/@^--#D_P_@^=I7&LU`$C*&]O)XY16O/YBAT\L2Q!M6 +MZ,^,_"DV_%G"4[;]`8E`Y>_4'B-G'SBG0\P#T504(#V)73,/E2#B3I7=S".' +MT?4S]U]05SC_GJUAE*!NK%8\&=\',!%JIL5J>;6'O[D[_5JVE7>4<QH4'CLU +M68W>\(D]JBL8$[^!T?<88]&GF&D!J76?C\!TV:R8*BQ,2%*"NX6^-J!7;)H[ +M,VL2_VSHEIU&_VR#)=O81/7B?&1://2C9_O[-3*X(-,H(QI$N8$/CSMR0_PU +MF+&[-\:YPQ-V_/\D'K<+P1?:NF3DC@(W0X+$X,HG8*-0_+3@`07IT`9`RZO> +M=4MI;EB=PHN\-U*#KN5B^JX'^8EFYG-3'H?CITKDVRN+'.(ABHXGW.51@<$J +MTX]Z-:0Y]$8M))->TGEHM">WLYXA/P.=F-)"H)_M7B5FK,I=7R&:5F=A^H:\ +M<C&)=DJR[6.-:6D+UO*R*E5(I1@<`XBX#_)(:\AWE018L%55"44+!<UF8XH" +M2PE#->"U3HG2Y>^C\3P&?0,F/>+S1<<,$W5!DW#+5:DT!&H>R]*HYAL;3=`9 +MG-6=ZO*O/-T<0GY[;.-GK`F4@EZ(HL.JR%:.V(7[VY:.`?"47U/P;N",R)G" +M%MX4UG$88O@.`;_;(1W&"==@<5,SMBD.R7>ITI@G5OR14O5NB?*E!["2KU6: +MH+P#/KA.)R4]DLK9W^<7&2RL#EF40DU1*VS`"A%7D5^"M`OB.0W5*_<#5K7* +MR'D05`R:?G3Q$`L;B5>KD\B"A%!FAV9F[BA2=I^AWD%J7`WFL7T,T%?%VI^; +M]0`QABMO4"3N3&-",I^)1E`Z61GN*(E7I&+P'2/Z$W,Q4^P3@1\Z01D"VYZ! +MZ]*!@]@/<"ZSHHN2'Z66_/Q1';U/W@:5/JY).$#*$JYEYOXW:DD&\7,"\NUZ +M*R7JO?D$*$NX)#AFK5F&$ZS<ON8N\<8ZI>`,HKM4&XRP,+WL+W:X2X<LR1IP +M\LUM.MA;?@6K(>98<OK=M=W'##O?9?+'[HNT<L089[:PE`(@A&JS#-N(RY8P +MKZP-G:6Y`4UQ,J?7N[H%+%K76C'_YN`??Y;ST/-;EE&8U$"]PQHF8.T5B2$R +M5.5<9Z4N".'9.@D;MD-`[#=B0-M_ZA^6O86*0`E=6GYLN3]\8N#(:R<C=</+ +M3&:'%QFF:O6K+D4SW.LUMRV_HRMS44P:^B0;9H#PEG+GZ*_SN&M,TE1OI9)U +MXU(CEY;4^S-SL,HMTV4C5/0K]0EH5>SA`L."U<Z?33_&H4WW2S)Q2Z=(Y^'A +M[5$+O_=WBN=[!3^07QD02;IL3F"\;31TYAC?19=V0<G<-).;,0L/+4';2.AC +M=S*,I40D-9QB=2R4D0D]YM*`K3_L$,ZD;ZHOFY5Q7(/]/%(\Z_Z*LY^R)"Y; +MFFXA8_UNAWRT-?#T#7J,V`(`CO1[1TS(FF;,M(-/EO'M$JI_'=(M9;V3XH4< +M>XPSOZY<".O^LP->K,4?Z-"*L#Z[P#"4,UW54G>W0KX/!21G-DW010]NZ54" +MT?"[+_BDNGN7B2'-)K$-,Q;L3<*/`/+A_EM-CG,CZT>TOP.1(>#99CO&/97= +MB[##0N[?U\)&U'1(]0C<X.`=LAM&_A*8SB_ADF,WP?*[URFV`;TZZ<Z+:\!Z +M)?@S#7OGKQ%,FO\[C.>FGJ2>AXP_3RLI*,:V)B$I-<88"C66?>!/I0-YKR[, +M,(`W)51UA>T26X/6.,4;@!NGC*;0VLT(3KS2Z>(RX'MC'$C+I1BBR!)!)C1* +M!AZ7_:5Q_RI!L!3"6M0;8&NO0V2HYVA,"18X1IW+/I9?$B,06BS=Z#B<$J,U +M-GI\,NTS)(%MEW#FI%Q,1ZU30VDFO38M=_@*<2-HT`H>8VF^;V6!0,8*T'5/ +MS(?V9HD%DO;K^EOY8MB'_7J6P=+7MGT:AAH>E977IC9\\<$?0X0CKH-,^Y5$ +MPG(L?(8VYY=8"QMC)#MW)JL9?(`E$Q-65D_!\FG\A]NOX"3KECRR&I/I,-_L +MY&!L^F*E(.H&^C3[CL?KK2\S60UD3W[E,,NZ1Y^*&S@5U6J#BIL,-/Q?VP9< +M,5*R?(?<6J69T=K\E=)Y6T0$(RM!_S!38A6'S"CCI=F<`'?6/*5KS2L7ON'B +M:!)QKWUW%-N6`)K7@<="%O@E[$=W9+<WQ,5V8_P\\3RL5R0Z'"4CCM9>1;A, +M+'*KT@O#)$%J/;W$T,J!'NA?2G7F<Q?P3A-U5<G`SRO,BZO\1R[AX06C#4"C +M^HL.TL"TRML`Y"K\@_@6[#[_-&WYX5L`/;WN+%=^=&DL="4<UHF*!/4.A?5W +M]77R*6A0X>7GK88KT1(K\Q52<<(!S6;SKP4H#K%(SYK0`B,Y-/&7\3]CZ/'( +M0@61%II0K.Q,&R`2$K'#I8'B(J0'\20($ONEJ2AXW;-'V3AP;9ME^L7JBW46 +M!+9%;M7.G(>CLF;A8*'@X"+832%9%WXO^K*>?/(]*..3\@`!!`8``0F(<P`' +M"P$``B$A`0D!"@$`#,'@$L'@$@`("@&4U9?>```%`1D"```1$P!H`'<`+0!A +C`'(`;0`V`#0````9`!0*`0`R5;397[?9`14&`0`@@/V!```` +` +end diff --git a/libarchive/test/test_read_format_7zip_solid_zstd.7z.uu b/libarchive/test/test_read_format_7zip_solid_zstd.7z.uu new file mode 100644 index 000000000000..3bffb98f07ea --- /dev/null +++ b/libarchive/test/test_read_format_7zip_solid_zstd.7z.uu @@ -0,0 +1,9 @@ +begin 664 test_read_format_7zip_solid_zstd.7z +M-WJ\KR<<``1&(FS)O@`````````B`````````$V+D*,HM2_]`$@!``!0*DT8 +M!````"$````HM2_]((+%```P80IB8V0*!X"P/JZA4J4;TS.X,9C'`#4``($S +M!ZX/T5NC)*"0H'?;G=XO-Y<-`+"F*K87M`OOZ1+1#31#M/`2YN,FY:(1).I) +M(B(+;9$W4?0*8=3V5N;BSZ)(0UGD/'LOSN"0&#DNX!A2*5\#&8IP$1G=7-]@ +MP\EE$]Z;/%6NU^\_,X:MD?57P#S>.+BINH?CHRX,::[Q5P*!X\DH````%P8V +?`0F`B``'"P$``2,#`0$%70`0```,@-H*`9/CZP`````` +` +end diff --git a/libarchive/test/test_read_format_7zip_zstd.7z.uu b/libarchive/test/test_read_format_7zip_zstd.7z.uu new file mode 100644 index 000000000000..acd49c421a6f --- /dev/null +++ b/libarchive/test/test_read_format_7zip_zstd.7z.uu @@ -0,0 +1,12 @@ +begin 664 test_read_format_7zip_zstd.7z +M-WJ\KR<<``2QPP_C,`$````````C``````````+H!E<HM2_]`$@!``!0*DT8 +M!````!$````HM2_](`U%```080H!``80`BBU+_T`2`$``%`J31@$````%``` +M`"BU+_T@&ET``"!A"F(*`@#`H`'8*+4O_0!(`0``4"I-&`0````6````*+4O +M_2`G;0``,&$*8@IC"@,4``@8V2BU+_T`2`$``%`J31@$````&0```"BU+_T@ +M-(4``$!A"F(*8PID"@04``@8(QL``($S!ZYMP-,)%[KY0NUS!EQ9<T<AN:R" +M7Z^`KZ24FV4LJ?"A)\MX&!"$=31!F6U\W/D!@*G'-=Z@#"&#>8R#*L]U;J=* +M@K`Q6]^1F4MZF33TE2LJK8X@%5MY%P.#1*EM98=_,9"?K'$*_A0YVC)]1ML= +MK-5-,X82B;/_L`I&FQ!5HP#H````%P:`J`$)@(@`!PL!``$C`P$!!5T`$``` ++#(#Z"@%\$`,4```` +` +end diff --git a/libarchive/test/test_read_format_7zip_zstd_arm.7z.uu b/libarchive/test/test_read_format_7zip_zstd_arm.7z.uu new file mode 100644 index 000000000000..770e99b3c10d --- /dev/null +++ b/libarchive/test/test_read_format_7zip_zstd_arm.7z.uu @@ -0,0 +1,61 @@ +begin 644 test_read_format_7zip_zstd_arm.7z +M-WJ\KR<<``0IIN38A`D```````!R``````````1RSP4HM2_]`$@!``!0*DT8 +M!````&\)```HM2_]8'P=+4L`REV0%$E@''(._[5GFW&YEVY]?G/)^,\9+2"B +M(\1H-(@DHJ*L)A?\C,G6FR3?/D.:6QDP<&`QFLOCXM`%J_](<>7+QU&E6E:N +M9=5-A,@4*0%(`38!`-3GD[<=6PPVGV</-O5)9%/+G)7MT/SVF2%"[?YY9?YU +MQOSKV/[5+O_IT#_2EO]=G'^=-?^YMW]5Z!^I;:@BQ:G]/U%1=T.&V5/O?8'$ +M1_>GC_)87GYQ_BZ,9+G<6(:EL+AFM]/OESN[+<?BJN+OQ,!I;>)245575._@ +M^RPCV7?'7IB-7R_..I.<?_RR2]YGMM,\B7QASI_N3>8;"%/NJ_\?\/_!_P<: +M^G3XSS-DOP`414SD%5U,'70<P:9LB=\F,5F\?(8L*B"#5:97+^5R9HG.9OS" +MQ!96@'QA!=NI[<^M__^U_7E!?>-F?MS1VK_/VO^C&^I_1SA*^_=)^^5T\.;Z +M_W0/7Z?^[E_7Q03P`7[I>3]\I]RK_U^TYO^=_E7>+WWZ>^_CU12)<EV_^4?G +MR'7]]O5_"I3K>L[N?\MU#>?H_X-28WKB?Y#2_H5D[#04WF9R/8>-46ZIY]4H +M_[E-HI8CI(5G.6PHP["KW.$%T24@`CT?H"YM4.#W#_7_$LP0H8J@_5G9\>QI +M=PPFO9L77'W,=3WH<A+Y(B62E*$]&2G_PJ-_(0+A_PLGG.V81D:R`=M*5Z/! +MU6XCX&IET$AFM3.2M$&+%6\)F%-88<=J)PG3OY#Y+^R_JOT#S?9Q,8X9"8UD +M%7A&IQ6/@M*_T,._<,>_D`?:4S&I@D;2#5JL<FIIE`GCF)',Z*R@8Z5#0??_ +M2__"LC-U_=P*ZB,Q6_]D:`Q1MAA,Z;/'$/CLP03\_P3_0AQN8^!J-RQP]7]< +M!PJJV2[]-RUCCA\Y'\&X+V;;3#U^<(+Z_)L6S[]I/9W`&=.V!DZ<IY,X:A@7 +M5W:8&%3^/UQN.7_:C64XR9>=/]U?I!=OW1=F+M]/KEY>S4[+:QQ[<3#6#>,P +MS":???N<_*[T7VSG+Y+E_%NEE]<%?4YB^.=!@="D_R`W:7)EGJC+VO<>:,/( +M\K[_V5!^"/W92(#84!'B?5"@#>*'Y&'/_Q;Q1/_;[`_]<+/84PFV[WO2M)[4 +M2L^_FUK-[[<=1DVMEU-2?3DI7H!^/\D=^=X'_6[Q0?]$0Q)M_T)1>VH1],7_ +M:W`1HJNG<KWO=Y334X+4S.>_IVY`DR(,_?O^G7K_0[6:5[\H)=H)`=>"@'Z4 +M/Q^33T_=]2CA&;)S@F?<`77FZ')IJEE:`V4.V`!0HUVT@RG1%MK`':0"J3LH +M;^^*.CNZ+Q*?<OM?).NR_]]4_`--3:<%1*:U:6U:,&SVN(G,L#2$("5%E<NE +M2M0[]Q],\_\'_H>D\+1^+8/_W\ID\V-J^^W(_,#XTKIH4:O2Q$CO2S"#\-CA +M&,ZPD*+'A="2":C_L9T"_Q\,^!YD:/"1%93KNHT#)91V>Q/YSKVS/7:72SFY +M/DTCU^_RU_K)=\G&8JW27=_9ODYWQ=HJKB_/Z_K=Z?9U_0XS87=>?^:Q_-*S +M"V+N2S$Z%FO75]*LDE@556Q?8@N_3>3:C+]6M\OQ^LS9[?&KG#N]/I+M2S%Z +M_9?"XGK^W[ITD\=OVVFN5=7&K)++=,MY&[O/=K9U:1H)Q:>NHHI<G&L*P_&H +MQ:^*45I75/REJK"*61R,_#DW9DWQ*:SBUI'S3ZYARO[&+^?\Q9;+9LO=)3M[ +MO=C<8Y>+L?/,\I=I;=WNPLREG'QGD^7T+/>6PRQ2AK\"@C2H$C.5*65$1$1$ +M)$F2-`9""D@*96%02N8^$J#D.`MT#".12:(@2<HJU-B:`WL`""01MII[1KW] +M.:P7R=+&`+BTZ1F7\S?[C@SB[IQG[ZA[Q/@?MO<?.^4Z.6E&^E"NC6X[H>)# +M4:BMMH#O(,3N\SNY98ID=!W0;%:X'+'JB96]?7)D)*]C(/`75J#"!K*H?_US +MA4W\/A]*S]-7_2]IAM/+/`B("R[9CK@UI^F_L_F\S3TLEF]4;-9K"D.FI-BN +MV;3B7IH,H:X*!VQF'5DKMS(QWD"?M;I7HLYJC5@4O84-JXI4]\ANPCC,Z6V! +MH1<1&1[VBD<[;N__]';,59N\AQ^&]#"-.ERL<TH!+^^O:-90UN(2?41R,7YG +MC=D)1;Z7Q%]M-0-KZ?NVGSM/-)/9WE[9=:\@3"'BI0G5?07Z*O=+2,O@T055 +M`]'KHF?3P7&^LM$=DZ'I%RJ9[,2",X=RL)#A?XC[#7TWG0*WTBO_91+R"@77 +M5JX1_+=H.<UDB7I[WVT+H8+N1^8>W77^#-%@[(V?&%>E1@EGMLCHLB@IEGBO +MR^7F7VZ4^<_*:H]3M2!41<$&Q+=RB)TZU2K(ZASM'+S$FS<U`,,R=?`BY2`5 +M#*1PHK!T/N@X9_BI-U$V`IL%#F'N=A\HG/UR9PGA@4+>C)$0QJJE7#\<..?\ +M5<-K!(&!>!\SDU,3G@>GQG!HY@,:VA83.3UV:[8,/#IFAAR>4[SNQD@#X(ZP +MSB1KCH5,N!*?N?=.*K&"L:.#>WPGFRQ?G!MXSQ%MC#G3I!&A'&2-D>2,A/-E +MECT8^7<1UPS%/*;,`34&^-#OCIS.QE_GW3XH<S`Y<]E[>G\@9&@Y?L((/T]` +M)T;C<[`:OL9XFC,(CGNQ:L7!)HW!FUD*LUE../[1_FDQ56O"(#?<^P\D9Y8S +M\B>"887TP=S,B&&5FXH0#40E'^VT-J)ZZC$8F8IXY#3.]BBD/Y!W$_ZW_PF! +M]O@GGFKZK7B;%/:O*>@EBKE4E'Z,8L,CF729$*JA:H"9A4<-W536[#+GLD*, +MA1`PA]/73?\?687^X]/J)UG5TW%7:20ZKXIC[MVDJ)')G',2BOU+XJ+MC.)< +M.2`Z'M=W?='`QE[.OF=_/FV="Y,I[]N:M1/U6>W;\;-N"M*]+K<S"VM!.5`7 +M8H9W)EDHM[D#]C..3VI`)!.?FH80X:%M%"!>&L1B*%65/ZC8$_36I;+/=_@$ +M3FB?WK+IOVATX0C;5Y*=[>\S4F1(V)J!O?<A_6Y4"P(JCG3]$BG<;7:X.L8- +M.5R.-,-0NA&D)4Y:]3E;M@@=Y>?36$$TKF(S2@FLJ\FLP*@EGBB:2%'/9-Z8 +M8Q,_6=Z>;B0PSV4-O0H-CLX!^O0EGI6A1BSB-+@-^M_[_W@_H7<<>.R8P"(# +M;W9GXI=Q",^;'>9$=#]CA-$DQL\_IE\_^00T'^]Z\9A<H(3D5@4!!`8``0F) +MA``'"P$``B0$]Q$!!0$%`P``!`,#!0$!``R>?)Y\``@*`>'$7C4```4!&0H` +M````````````$1L`:`!W`"T`9P!N`'4`90!A`&(`:0!H`&8````9`!0*`0`` +166S@9)S9`14&`0`@@.V!```` +` +end diff --git a/libarchive/test/test_read_format_7zip_zstd_bcj.7z.uu b/libarchive/test/test_read_format_7zip_zstd_bcj.7z.uu new file mode 100644 index 000000000000..2a75db8972cf --- /dev/null +++ b/libarchive/test/test_read_format_7zip_zstd_bcj.7z.uu @@ -0,0 +1,56 @@ +begin 664 test_read_format_7zip_zstd_bcj.7z +M-WJ\KR<<``0N5BP@P@@```````!B`````````(*-K]$HM2_]`$@!``!0*DT8 +M!````*T(```HM2_]8%`]'44`ZE%D$DIPW'$.RP,C]5>);DM31:I?D,QMZ#'[ +MX]O[KCOFX)J*\$44=%&TV"+)8#QPV28QFR]0!V-3JH9UII:164M``!FT!`!L +MXELXL[8O4Q,!'@$2`5/J6F?&6/][6'!>ZPF&:U6C8%?F9DH.#=>\Y71GN:,M +M^ZA,>'Z0J2/,U:!!Y(?S^B3?P==^[[?]YK&,Q.+\7;C(4KFQ#"L]4<UNIU\L +M=W9;_D1%Y$]$H4B=H$[@2DE$IZ8'OIOBA=GXO>*LEI'SCU\6R?O,=IH;BR_, +M^=,]F?4+_I]'MWL=@)3B4LF]J`%84^*+!@]ERRM(EKDF0@0*\*,A13M[J_;, +M*JBF":I,JT3`(:"1UI!6,G[AH1;N$0&++]Q;5RDTUW:S#K<G2G>B?&TWF[K] +MTO%\G]%M-\G(:E8U$$&Q(;$WDZ;I?H%#_\%^!#:>[<]:V>W_<Z_@?U[X`M[H +MA4"P?^$_:O4:WO9[UYB<ABX"31,=K>LQ-_Y?Q`(@"A`L^!S]UHDBP&X#+X<) +MS4GK>LP.H+]9:E#78]`VV'FC.[!1K?U2*3:2NB93]/].==UT^O\>==W,\/]? +M==V44-=-'0;;@?WP+*-()<@P[!['GHC]HU%G3KK6_QP>N.7:3':M;%ATH6"X +M5K.NM0IE?OG9C8W8_ZH67)-_%.SL'Q6>_:M>@EZKKIMUJ5R"7&M5A.0'M[;4 +M9V?&P.&\UIV>1F5MLE<;FI+U2(R2M=FUI@DE%2V)P>4ZMO6SVU+C=&8,(,YK +MY>EH%F;<4AE<K@_C9Z=>F?GO3?%`"2[7)S_F;T@5U>S"M7+I6DE0Z2*&^9T( +MJG_I9W?UWQ,25(-=_:/IEZ/P9_??RQ%4__=P%-5CYQ*N-=P)*8F#4Q-_J:5U +M'?(JJ";.7XGXA`058FD):LB'3TA23)R_445Q[&_\<LY?B40F6^XBV?GJE7./ +M7:YDYYGEKT]MW>["64C9^%I)EM.SW%L.LT49QN)R:^3(SM^H7ETE.]UGXV.Q +MG;]%EO.7U5^?C5.OJ[*+Z*C1$-(A?J%;#=`G\MY'Q2V%>VHZ_YM'O9).+?@] +M&[B#>O9PXX#A62$P9N#(I\W?">*#9\:C*[Y`E1!]GR=28((]^C4"J>WK;[__ +M:S)_$_HE*_R&?+\TV>-DL>I!>D%)J<F7!I?3K-.T7:\Y%>`P3US430XU<+-S +M),83X)<`RFY;.%N87*>=0>!SX'OZ_PMXW8W.*B=`J28#S1D*U77O4Y3UMK+_ +MO\$[$]BLC/9N@+Y/YWVH[O3MW+GVQ&Q`R,C:,)F[_R=SFIU!UC7+1_G_FTY: +M8Y)D#["R,A(5%88*A3Y0-$W3'+='>?"2_FWPSMRM12UGXO>_YX^R,O;,`86% +MR76-YO\_I%]?Q!O0\0A\!KO'+A(I&]6GZ:+ZQA?)QLIV;H]'5WUY5M7O6FY7 +MW^C2,I:J?H>S6-B=U9]Y++_T[)Z8.U))Q\I6_2/-'H>(24CM.]3";[*H[+.; +M)<]9:C+&4MTNQ^IGS6Z/W^/<:?6+;$<J:?5?Z8F*IHN<?QN[_%N73O+X;3O- +M.1#;F#URF6XYV]EG.]NZ7,B'3DE(5)QJ.,7$Q"&"4*C2@C%")2(21)(DQ1RR +M"R"09#G(&+EY$D!S+-A5AA&"G!$1$1DI*"HJ*%3:#M)%Q65GGN/P$%8VV5B2 +M]NFSWV5TIA<46D6>L+^>0INN&\C!Q)+"<SH9C<?:``)];9<186MJP)B*VK4: +M<%,XO+^L0FV@^)9)8+0SP[K`8[^)+1'?^U#DQOUSWD`NSPKPO[6=TYI:*BDT +M()-&:!P3=L1H1J,'B6H"\'D5T"]'7H=*%&BA]AN]!S@'8HS*8<T"D8=K-Y-B +M>(-?'D)(%2ZL3O]\]"#?E1$+0VXIS="D"#8T@4)AH;OS0QK*@.S(L,50<_CA +MSLQF9'9?XSB;;-U94YD.FO]*997K@$8#<$+3;FE`!=:DQF+2IM`^P_V)X+H8 +M>CA6D83\V2'4'&8019V9GJ;4N^GH!]DY[/[G+;OB1_1;1C*]PB'S([P%1P=2 +MVZWP^0AVC4J*P$8O6>4N-N<4YQ@52=LB99,=Q-92\YTM6_:!O(CLS*.3].4# +M"=G'<EW8WT4PE,R`*.$U^=K#".R@`QA*]1])G-)@U:>`&WN&'Q@PN!^%WP*@ +M>Q#R';%'W>W,J`@NVM/IYT(1Z9WO[L0DR.YFB5_M%B-Q;^"AA"&\S5O?^]2G +M5:<U6.,RP%;%Y"R;NE!;^QBLHNWDHT[PY!X'$RQ]3:HQ#!%;Y"&8XYZ)DEAN +MOEQW1C&Y+8?>0N[G64]G+ZWR@D&V)Q@^LXPO*B9G9F,9'#!BQ>,6;6FU$N?3 +M`.Q/U+S_$G<B>PHT*;\)<@Y@CF:$OL@/;(&MBC.]2FU)]]1H%"W*G?%/.,%R +M%[H<>8MCK*V1.J%.C=7'N/;E*:U^2SX@)@'SYZ\;36III>#+-E0=MARSYX'R +M\WH,G%TT4TXJ7V:1?#Q/HER'4TFC.'Y%Y0D*MH2(6\B5YU*21O#?4OS=K,#> +MM?@F6*^:37;#*>NV\;VYS9R567I^EN(RXY3MF[\:?IS1%VRW7Z[:^VI<W^EW +M+C1I4NN.\7L'K_%;28(A;"6.*=[#.\.NM%)`@9'*7@+F3A[K)9_8.LC%A)"A +M'*)/SZS!C8<S>'LY=_ZBTR<)4IT7]IYY]1OK&'@.&E"VR@9%YH&S'Q,#9CF] +MG8&_K//(.AY#/&&R\L5Y9G9*M">BYP#J+4'9&3=D:QBW=45`IG&!W"1D^=K7 +M3-\)$&`N%0_$JV$!\![TG-`=:",BG5.9A)"?V=NSXPVO21_O-QG<+$FCO"K< +M+7,ER$BPT:CS!0`Z0BV^S#)QZ3PK0-/_L#+OU^QUO<'=-9BN6Y:-5!LY:B;N +MZREX8;-G[,XTOK;@Y$4Z[)9[!"MHPI^1M7KK1KL45B0C''SO8H,4XUG<1RU\ +MG/6=<8^3]'MPL\V\;ITR,#$MU@E[S7%[`00&``$)B,(`!PL!``(D!/<1`04! +M!0,```0#`P$#`0`,OE"^4``("@&\[F:]```%`1D*`````````````!$'`&@` +@=P```!D$`````!0*`0``'';'*9?9`14&`0`@@/V!```` +` +end diff --git a/libarchive/test/test_read_format_7zip_zstd_nobcj.7z.uu b/libarchive/test/test_read_format_7zip_zstd_nobcj.7z.uu new file mode 100644 index 000000000000..c6fed0bebb84 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_zstd_nobcj.7z.uu @@ -0,0 +1,56 @@ +begin 664 test_read_format_7zip_zstd_nobcj.7z +M-WJ\KR<<``0`N.\QQ0@```````!2`````````#TEXKPHM2_]`$@!``!0*DT8 +M!````+`(```HM2_]8%`]-44`*E)P$DIPW'$.R^E<Z*8D%G.UILPF5,4RT_G_ +M</>\_]^S[,>DG"("L:I:;)%D,!ZX;).8S1>H@[$I[8=UII:164M``!FT!`!L +MLB.<6?N3%!4!'@$2`4JZ6"F]QIDPV'_>%=P7BW[I8M4HT)&YD9)#@VO>T')( +M6DXDLR#Z0.9.,$=CQA`?#OR3?`=?^_-\VY];GI%8>_\;%UNJ5YYCX1,5_?(: +MQGKIU]U/5,3]112,U@GKA"U4(CHU_>]?%'#<RO#5;K>,>[\,M\C-Z9;7VUB$ +MX[V_YLFL7_#_N]H]V0'(*.^4G(L:@#4EO&CP8+:T<F298S)$H,!&$F+$<W+5 +MGED%U31AG>NUZ$?T.]HBVDK*<$SDQKRB7Q&.>2PKE>9<?M;A]D4J3U3/Y6=3 +MMU\ZHM\[NIW-LK*:50T$<(QH[,NHJGJZP*7_X'P$MIWMT9K9[?]SK^"!/O@" +M_NB#O[#_X']J]1K>]N=98W(:M@B]-TWPM'<Q-OY?Q((@"A`L_"`]%ZH50+=A +MI\.4ZJB]B]$1]#=+#7H7@^8,0V]R#ISIUOE2*,XCO8\Q^G^GWIM._\^C]V:& +M_P?KO2FA]V8.!MN!\V-ZUE(ES''\'LF<C/6>=H;6Q(O]U]F!6[+-I!?+9H57 +M^J6+/?-BJWKO6EZ`=&0CSO\U"XY)[]U%Z[W[H/VO78!?;`X_\UJW`+O8J@C) +M!W)IZ2AGPL#AOE@>GC:%97*R-C1)6*0P2=BF%YLVI&2T)`*7+!D7D$Y+Q^%, +M&#_<%]O#T5B@<4LE<,G^"R#=>E7FGS?5\P2X9)WXF+XA55232Q>[Q8LE,<6+ +M",9W0JC_$I#NZI\71*B'7?7>MW@Y!H%T_SP<0OV?=\.HDZ$!3DE*')R:]DLM +ML>QP5T$U[?U"XE,25(BE):CA'CXE23'M_<95Z\AA&=Y[OQ*)3+K[1;;TU2MI +M+K];V=)TN^'>ZK[\C;.0L_&WDNVNZ9F[.VZ+<XRU9]>XD7R_<;VZ2O*:T\;' +M:OF&B^W>/Z\^3ANG/H?*221';<;0#A$LY6J0/G'W/REN:NQ3V_D_=]0+=VK` +M]SE_IY#/.3QQONRJ$"`S8.35YO,`Z?$],CY5\5_@SV#Z/T^DP$S#/OT:`=4& +M]K<___N8OPWYDA5\1#V?FN1RLECU0+T@%#;UTN!TFEU-._L:5`$.$\5%W>12 +M`S<\2&,]`7X)P.S&A;.)S3W-#(*?`^_#_U_`Y]SD6.4$"&LQ4IWA4/]CE/4V +ML_^WL4,3V*R.SK-!^KV=[Z4Y:._,H2QOS/:CK*P-DZG[_S'H&0J$9;$\E/^_ +M[:BU)4C.`5961:*BQ-)@L$>:JJJ*X_;ICIW2?XT=FKNQJ.5,_/DPZL/,K$5S +M06)B<^]G_O^#"@9&O`4=C[]G<'+Y12)GX_IU75S?""-;6>G2[O'XKC_3Z_I\ +MZ^7K&]]ZQEK7YW%6&[_T^O269[BFWQ,T1RIK6>FN?ZS;(Q%1*<F%B=P83A:5 +MG'ZS9CIK3<I8Z\MG>?TL^N4R?*1YO7ZQY4AEO?X+GZCJNKCWN_*[WWWKY)9A +ME]>;`]&5V^.>:W>WO/V6M^Z[@WOHI)1$M:F&4TQ,'':"4:CB>C%")2(21)(D +MQ1RR"R@01$'(&+EY$D!C+-E5AA&"G!$1$1DI*"HJ*%3:#M)%"5G$G\<Y$4%Q +M64R2EN_3WVWTII>"8%:>G[^>!M\V$XK!3)(B?F)-CZ=K`("^=H&,T+K]/R8B +M['>&V!;.[RZK*AXHW/(1&>W$L([TS6UB*(17-)#`^=N<-Y!+LP+,;VWOM.:V +MG"H>@K<%',>.&QD-=+)!XH+%'R\&]".3\%"A*"Q49ZE[Z/-`S&!3[<L:E#@& +MA%BW.,7W(7@3D./J)N.CU_NNC!D.LDMIAB9%OI,)=,R+KH$/::@'Y".+K4/- +MPX\'-IN1$_^:[U*/S[A,)7LPX2OTM=(!J2UI0@W=TO;)K?W&TB(--7\FB`$B +M/3++09C?7H+'0_"B9J`3NBFF*?K=)/Y!WTGB_/.61>$CTBVC3R]ZNOP";Z'2 +MH2O_5Y`ZL)EB)470T:OT<M?/"<8&A@JN:9`2T@YA:U_ST9;WZ<.\=.SLUP;[ +ML8&*_`<R7?A?15#RY@&4<!_XM,,(/*`#*!KU7TG<TL`ZI(!;?C0_\(IP/PFC +M!<#J03`[8B^LVZE1$;]HKZ>>2R/20[R[(Y,@NY,>;K5;&0GE`P\E#.%]WG4O +M&5+K/5T3')<)O"I,1MVZ"]]^(&Q5B">>RVD\[W$PP\;7(AE#%.%E-HDY"IIT +MR<O-V]7.57,P-O3L[,9\JA,U[NZ[%.66!(=^O.-+T>+8L[$1_("Y?)9Q7F&M +MK64ED6D`V29*P=.*;'(U%I_))$V/)_?,$=;YBZAX0W2M@PFKU%9S3_T.T:#< +MW/V$HY:ZT^6Q"C":"ARLJ?J@S!>.02=/K6Z%TS_J/3*YY=UH8DNK;;"^H=ZX +M?#9L*(R;]X<0VT7;[:2U;!;IBO(DRB<X/9CD["OJ3U#0)4380JXDEUJQ+?^6 +MQ9]E9?:N1#;!:O6*S!L066>.[\UAYLS,UO/S@RN?PVG?_*AAX1GE0+O-\:J] +M7,:5^[ASH4F3NG>,TSNX9AQPQ>"V$LT4["&]0<RS`D"!CDHM@?6T'K,GK]A2 +MY<)&R'8.49C.U.`&G#,$]H)X]D&G#PQ2G85TGYUQNR,`\*"5<`/_S/,L?XD) +M9XJM2X7?[#Q?'+\4C_E,]6(W,Q\BV@OO(69_>W=&EFLO#1^W/A*04USP-0!9 +MOO8][Q\"!,VAXT'A8CF`N?FP)O*.V0A/YEIF(B0G]^KN-F5KPD;:J[TX$J21 +MW@+<%;CB-NJY,<;P!8#[&A:9S.V+U9\ADL)_&*EW<Y[@TX1U%2S7:L_"MRW9 +MRNK#WA2O/$HMMGEX90/<HA4YI%X[XGOT7\\[]6#K&X[C%K/Q-/QT<4.*><[O +ML2P=S_X<N'7,5CS>O.NY4@\-FS$OP8EX>6=[`00&``$)B,4`!PL!``$D!/<1 +M`04!!0,```R^4``("@&\[F:]```%`1D#````$0<`:`!W````&00`````%`H! +3```<=L<IE]D!%08!`""`_8$````` +` +end diff --git a/libarchive_fe/passphrase.c b/libarchive_fe/passphrase.c index edf72d147182..1cae6a7bc80a 100644 --- a/libarchive_fe/passphrase.c +++ b/libarchive_fe/passphrase.c @@ -171,8 +171,10 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) int input, output, save_errno, i, need_restart; char ch, *p, *end; struct termios term, oterm; +#ifdef HAVE_SIGACTION struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; struct sigaction savetstp, savettin, savettou, savepipe; +#endif /* I suppose we could alloc on demand in this case (XXX). */ if (bufsiz == 0) { @@ -221,6 +223,7 @@ restart: oterm.c_lflag |= ECHO; } +#ifdef HAVE_SIGACTION /* * Catch signals that would otherwise cause the user to end * up with echo turned off in the shell. Don't worry about @@ -239,6 +242,7 @@ restart: (void)sigaction(SIGTSTP, &sa, &savetstp); (void)sigaction(SIGTTIN, &sa, &savettin); (void)sigaction(SIGTTOU, &sa, &savettou); +#endif if (!(flags & RPP_STDIN)) { int r = write(output, prompt, strlen(prompt)); @@ -276,6 +280,7 @@ restart: continue; signo[SIGTTOU] = sigttou; } +#ifdef HAVE_SIGACTION (void)sigaction(SIGALRM, &savealrm, NULL); (void)sigaction(SIGHUP, &savehup, NULL); (void)sigaction(SIGINT, &saveint, NULL); @@ -285,6 +290,7 @@ restart: (void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTTIN, &savettin, NULL); (void)sigaction(SIGTTOU, &savettou, NULL); +#endif if (input != STDIN_FILENO) (void)close(input); diff --git a/test_utils/test_main.c b/test_utils/test_main.c index 3250423a14c2..e4b884ee3c44 100644 --- a/test_utils/test_main.c +++ b/test_utils/test_main.c @@ -327,7 +327,7 @@ my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi) int r; memset(bhfi, 0, sizeof(*bhfi)); - h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL, + h = CreateFileA(path, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) return (0); @@ -1432,7 +1432,7 @@ assertion_file_time(const char *file, int line, /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open * a directory file. If not, CreateFile() will fail when * the pathname is a directory. */ - h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL, + h = CreateFileA(pathname, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (h == INVALID_HANDLE_VALUE) { failure_start(file, line, "Can't access %s\n", pathname); diff --git a/unzip/CMakeLists.txt b/unzip/CMakeLists.txt new file mode 100644 index 000000000000..13b983d89db7 --- /dev/null +++ b/unzip/CMakeLists.txt @@ -0,0 +1,37 @@ +############################################ +# +# How to build bsdunzip +# +############################################ +IF(ENABLE_UNZIP) + + SET(bsdunzip_SOURCES + bsdunzip.c + bsdunzip_platform.h + ../libarchive_fe/err.c + ../libarchive_fe/err.h + ../libarchive_fe/lafe_platform.h + ../libarchive_fe/passphrase.c + ../libarchive_fe/passphrase.h + ) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe) + + # bsdunzip documentation + SET(bsdunzip_MANS bsdunzip.1) + + # How to build bsdunzip + ADD_EXECUTABLE(bsdunzip ${bsdunzip_SOURCES}) + IF(ENABLE_UNZIP_SHARED) + TARGET_LINK_LIBRARIES(bsdunzip archive ${ADDITIONAL_LIBS}) + ELSE(ENABLE_UNZIP_SHARED) + TARGET_LINK_LIBRARIES(bsdunzip archive_static ${ADDITIONAL_LIBS}) + SET_TARGET_PROPERTIES(bsdunzip PROPERTIES COMPILE_DEFINITIONS + LIBARCHIVE_STATIC) + ENDIF(ENABLE_UNZIP_SHARED) + + # Installation rules + INSTALL(TARGETS bsdunzip RUNTIME DESTINATION bin) + INSTALL_MAN(${bsdunzip_MANS}) +ENDIF(ENABLE_UNZIP) + +add_subdirectory(test) diff --git a/unzip/bsdunzip.1 b/unzip/bsdunzip.1 new file mode 100644 index 000000000000..3c656ebc46e2 --- /dev/null +++ b/unzip/bsdunzip.1 @@ -0,0 +1,216 @@ +.\"- +.\" Copyright (c) 2007-2008 Dag-Erling Smørgrav +.\" 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 AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd January 2, 2023 +.Dt BSDUNZIP 1 +.Os +.Sh NAME +.Nm bsdunzip +.Nd extract files from a ZIP archive +.Sh SYNOPSIS +.Nm +.Op Fl aCcfjLlnopqtuvy +.Op Fl d Ar dir +.Op Fl x Ar pattern +.Op Fl P Ar password +.Ar zipfile +.Op Ar member ... +.Sh DESCRIPTION +.\" ... +The following options are available: +.Bl -tag -width Fl +.It Fl a +When extracting a text file, convert DOS-style line endings to +Unix-style line endings. +.It Fl C +Match file names case-insensitively. +.It Fl c +Extract to stdout/screen. +When extracting files from the zipfile, they are written to stdout. +This is similar to +.Fl p , +but does not suppress normal output. +.It Fl d Ar dir +Extract files into the specified directory rather than the current +directory. +.It Fl f +Update existing. +Extract only files from the zipfile if a file with the same name +already exists on disk and is older than the former. +Otherwise, the file is silently skipped. +.It Fl j +Ignore directories stored in the zipfile; instead, extract all files +directly into the extraction directory. +.It Fl L +Convert the names of the extracted files and directories to lowercase. +.It Fl l +List, rather than extract, the contents of the zipfile. +.It Fl n +No overwrite. +When extracting a file from the zipfile, if a file with the same name +already exists on disk, the file is silently skipped. +.It Fl o +Overwrite. +When extracting a file from the zipfile, if a file with the same name +already exists on disk, the existing file is replaced with the file +from the zipfile. +.It Fl p +Extract to stdout. +When extracting files from the zipfile, they are written to stdout. +The normal output is suppressed as if +.Fl q +was specified. +.It Fl P Ar password +Extract encrypted files using a password. +Putting a password on the command line using this option can be +insecure. +.It Fl q +Quiet: print less information while extracting. +.It Fl t +Test: do not extract anything, but verify the checksum of every file +in the archive. +.It Fl u +Update. +When extracting a file from the zipfile, if a file with the same name +already exists on disk, the existing file is replaced with the file +from the zipfile if and only if the latter is newer than the former. +Otherwise, the file is silently skipped. +.It Fl v +List verbosely, rather than extract, the contents of the zipfile. +This differs from +.Fl l +by using the long listing. +Note that most of the data is currently fake and does not reflect the +content of the archive. +.It Fl x Ar pattern +Exclude files matching the pattern +.Ar pattern . +.It Fl y +Print four digit years in listings instead of two. +.It Fl Z Ar mode +Emulate +.Xr zipinfo 1L +mode. +Enabling +.Xr zipinfo 1L +mode changes the way in which additional arguments are parsed. +Currently only +.Xr zipinfo 1L +mode 1 is supported, which lists the file names one per line. +.It Ar [member ...] +Optional list of members to extract from the zipfile. +Can include patterns, e.g. +.Ar 'memberdir/*' +will extract all files and dirs below memberdir. +.El +.Pp +Note that only one of +.Fl n , +.Fl o , +and +.Fl u +may be specified. +If specified filename is +.Qq - , +then data is read from +.Va stdin . +.Sh ENVIRONMENT +If the +.Ev UNZIP_DEBUG +environment variable is defined, the +.Fl q +command-line option has no effect, and additional debugging +information will be printed to +.Va stderr . +.Sh COMPATIBILITY +The +.Nm +utility aims to be sufficiently compatible with other implementations +to serve as a drop-in replacement in the context of the +.Xr ports 7 +system. +No attempt has been made to replicate functionality which is not +required for that purpose. +.Pp +For compatibility reasons, command-line options will be recognized if +they are listed not only before but also after the name of the +zipfile. +.Pp +Normally, the +.Fl a +option should only affect files which are marked as text files in the +zipfile's central directory. +Since the +.Xr archive 3 +library does not provide access to that information, it is not available +to the +.Nm +utility. +Instead, the +.Nm +utility will assume that a file is a text file if no non-ASCII +characters are present within the first block of data decompressed for +that file. +If non-ASCII characters appear in subsequent blocks of data, a warning +will be issued. +.Pp +The +.Nm +utility is only able to process ZIP archives handled by +.Xr libarchive 3 . +Depending on the installed version of +.Xr libarchive 3 , +this may or may not include self-extracting or ZIPX archives. +.Sh SEE ALSO +.Xr libarchive 3 +.Sh HISTORY +The +.Nm +utility appeared in +.Fx 8.0 . +.Sh AUTHORS +The +.Nm +utility and this manual page were written by +.An Dag-Erling Sm\(/orgrav Aq Mt des@FreeBSD.org . +It uses the +.Xr archive 3 +library developed by +.An Tim Kientzle Aq Mt kientzle@FreeBSD.org . +.Sh CAVEATS +The +.Nm +utility performs two scans of the command-line for arguments before +and after the archive name, so as to maintain compatibility with +Info-ZIP unzip. +As a result, the POSIX +.Ql -- +double-dash string used to separate options from arguments will need to +be repeated. +For example, to extract a "-a.jpg" from "-b.zip" with overwrite, one +would need to invoke +.Dl bsdunzip -o -- -a.jpg -- -b.zip diff --git a/unzip/bsdunzip.c b/unzip/bsdunzip.c new file mode 100644 index 000000000000..469c69fd6efb --- /dev/null +++ b/unzip/bsdunzip.c @@ -0,0 +1,1186 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org> + * Copyright (c) 2007-2008 Dag-Erling Smørgrav + * 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 + * in this position and unchanged. + * 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 AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + * This file would be much shorter if we didn't care about command-line + * compatibility with Info-ZIP's UnZip, which requires us to duplicate + * parts of libarchive in order to gain more detailed control of its + * behaviour for the purpose of implementing the -n, -o, -L and -a + * options. + */ + +#include "bsdunzip_platform.h" + +#ifdef HAVE_SYS_QUEUE_H +#include <sys/queue.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_FNMATCH_H +#include <fnmatch.h> +#endif +#ifdef HAVE_STDARG_H +#include <stdarg.h> +#endif +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <archive.h> +#include <archive_entry.h> +#include "passphrase.h" +#include "err.h" + +/* command-line options */ +static int a_opt; /* convert EOL */ +static int C_opt; /* match case-insensitively */ +static int c_opt; /* extract to stdout */ +static const char *d_arg; /* directory */ +static int f_opt; /* update existing files only */ +static int j_opt; /* junk directories */ +static int L_opt; /* lowercase names */ +static int n_opt; /* never overwrite */ +static int o_opt; /* always overwrite */ +static int p_opt; /* extract to stdout, quiet */ +static char *P_arg; /* passphrase */ +static int q_opt; /* quiet */ +static int t_opt; /* test */ +static int u_opt; /* update */ +static int v_opt; /* verbose/list */ +static const char *y_str = ""; /* 4 digit year */ +static int Z1_opt; /* zipinfo mode list files only */ + +/* debug flag */ +static int unzip_debug; + +/* zipinfo mode */ +static int zipinfo_mode; + +/* running on tty? */ +static int tty; + +/* convenience macro */ +/* XXX should differentiate between ARCHIVE_{WARN,FAIL,RETRY} */ +#define ac(call) \ + do { \ + int acret = (call); \ + if (acret != ARCHIVE_OK) \ + errorx("%s", archive_error_string(a)); \ + } while (0) + +/* + * Indicates that last info() did not end with EOL. This helps error() et + * al. avoid printing an error message on the same line as an incomplete + * informational message. + */ +static int noeol; + +/* for an interactive passphrase input */ +static char *passphrase_buf; + +/* fatal error message + errno */ +static void +error(const char *fmt, ...) +{ + va_list ap; + + if (noeol) + fprintf(stdout, "\n"); + fflush(stdout); + fprintf(stderr, "unzip: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(errno)); + exit(EXIT_FAILURE); +} + +/* fatal error message, no errno */ +static void +errorx(const char *fmt, ...) +{ + va_list ap; + + if (noeol) + fprintf(stdout, "\n"); + fflush(stdout); + fprintf(stderr, "unzip: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(EXIT_FAILURE); +} + +/* non-fatal error message + errno */ +static void +warning(const char *fmt, ...) +{ + va_list ap; + + if (noeol) + fprintf(stdout, "\n"); + fflush(stdout); + fprintf(stderr, "unzip: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, ": %s\n", strerror(errno)); +} + +/* non-fatal error message, no errno */ +static void +warningx(const char *fmt, ...) +{ + va_list ap; + + if (noeol) + fprintf(stdout, "\n"); + fflush(stdout); + fprintf(stderr, "unzip: "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} + +/* informational message (if not -q) */ +static void +info(const char *fmt, ...) +{ + va_list ap; + + if (q_opt && !unzip_debug) + return; + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); + fflush(stdout); + + if (*fmt == '\0') + noeol = 1; + else + noeol = fmt[strlen(fmt) - 1] != '\n'; +} + +/* debug message (if unzip_debug) */ +static void +debug(const char *fmt, ...) +{ + va_list ap; + + if (!unzip_debug) + return; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fflush(stderr); + + if (*fmt == '\0') + noeol = 1; + else + noeol = fmt[strlen(fmt) - 1] != '\n'; +} + +/* duplicate a path name, possibly converting to lower case */ +static char * +pathdup(const char *path) +{ + char *str; + size_t i, len; + + if (path == NULL || path[0] == '\0') + return (NULL); + + len = strlen(path); + while (len && path[len - 1] == '/') + len--; + if ((str = malloc(len + 1)) == NULL) { + errno = ENOMEM; + error("malloc()"); + } + if (L_opt) { + for (i = 0; i < len; ++i) + str[i] = tolower((unsigned char)path[i]); + } else { + memcpy(str, path, len); + } + str[len] = '\0'; + + return (str); +} + +/* concatenate two path names */ +static char * +pathcat(const char *prefix, const char *path) +{ + char *str; + size_t prelen, len; + + prelen = prefix ? strlen(prefix) + 1 : 0; + len = strlen(path) + 1; + if ((str = malloc(prelen + len)) == NULL) { + errno = ENOMEM; + error("malloc()"); + } + if (prefix) { + memcpy(str, prefix, prelen); /* includes zero */ + str[prelen - 1] = '/'; /* splat zero */ + } + memcpy(str + prelen, path, len); /* includes zero */ + + return (str); +} + +/* + * Pattern lists for include / exclude processing + */ +struct pattern { + STAILQ_ENTRY(pattern) link; + char pattern[]; +}; + +STAILQ_HEAD(pattern_list, pattern); +static struct pattern_list include = STAILQ_HEAD_INITIALIZER(include); +static struct pattern_list exclude = STAILQ_HEAD_INITIALIZER(exclude); + +/* + * Add an entry to a pattern list + */ +static void +add_pattern(struct pattern_list *list, const char *pattern) +{ + struct pattern *entry; + size_t len; + + debug("adding pattern '%s'\n", pattern); + len = strlen(pattern); + if ((entry = malloc(sizeof *entry + len + 1)) == NULL) { + errno = ENOMEM; + error("malloc()"); + } + memcpy(entry->pattern, pattern, len + 1); + STAILQ_INSERT_TAIL(list, entry, link); +} + +/* + * Match a string against a list of patterns + */ +static int +match_pattern(struct pattern_list *list, const char *str) +{ + struct pattern *entry; + + STAILQ_FOREACH(entry, list, link) { +#ifdef HAVE_FNMATCH + if (fnmatch(entry->pattern, str, C_opt ? FNM_CASEFOLD : 0) == 0) + return (1); +#else +#error "Unsupported platform: fnmatch() is required" +#endif + } + return (0); +} + +/* + * Verify that a given pathname is in the include list and not in the + * exclude list. + */ +static int +accept_pathname(const char *pathname) +{ + + if (!STAILQ_EMPTY(&include) && !match_pattern(&include, pathname)) + return (0); + if (!STAILQ_EMPTY(&exclude) && match_pattern(&exclude, pathname)) + return (0); + return (1); +} + +/* + * Create the specified directory with the specified mode, taking certain + * precautions on they way. + */ +static void +make_dir(const char *path, int mode) +{ + struct stat sb; + + if (lstat(path, &sb) == 0) { + if (S_ISDIR(sb.st_mode)) + return; + /* + * Normally, we should either ask the user about removing + * the non-directory of the same name as a directory we + * wish to create, or respect the -n or -o command-line + * options. However, this may lead to a later failure or + * even compromise (if this non-directory happens to be a + * symlink to somewhere unsafe), so we don't. + */ + + /* + * Don't check unlink() result; failure will cause mkdir() + * to fail later, which we will catch. + */ + (void)unlink(path); + } + if (mkdir(path, mode) != 0 && errno != EEXIST) + error("mkdir('%s')", path); +} + +/* + * Ensure that all directories leading up to (but not including) the + * specified path exist. + * + * XXX inefficient + modifies the file in-place + */ +static void +make_parent(char *path) +{ + struct stat sb; + char *sep; + + sep = strrchr(path, '/'); + if (sep == NULL || sep == path) + return; + *sep = '\0'; + if (lstat(path, &sb) == 0) { + if (S_ISDIR(sb.st_mode)) { + *sep = '/'; + return; + } + unlink(path); + } + make_parent(path); + mkdir(path, 0755); + *sep = '/'; + +#if 0 + for (sep = path; (sep = strchr(sep, '/')) != NULL; sep++) { + /* root in case of absolute d_arg */ + if (sep == path) + continue; + *sep = '\0'; + make_dir(path, 0755); + *sep = '/'; + } +#endif +} + +/* + * Extract a directory. + */ +static void +extract_dir(struct archive *a, struct archive_entry *e, const char *path) +{ + int mode; + + /* + * Dropbox likes to create '/' directory entries, just ignore + * such junk. + */ + if (*path == '\0') + return; + + mode = archive_entry_mode(e) & 0777; + if (mode == 0) + mode = 0755; + + /* + * Some zipfiles contain directories with weird permissions such + * as 0644 or 0444. This can cause strange issues such as being + * unable to extract files into the directory we just created, or + * the user being unable to remove the directory later without + * first manually changing its permissions. Therefore, we whack + * the permissions into shape, assuming that the user wants full + * access and that anyone who gets read access also gets execute + * access. + */ + mode |= 0700; + if (mode & 0040) + mode |= 0010; + if (mode & 0004) + mode |= 0001; + + info(" creating: %s/\n", path); + make_dir(path, mode); + ac(archive_read_data_skip(a)); +} + +static unsigned char buffer[8192]; +static char spinner[] = { '|', '/', '-', '\\' }; + +static int +handle_existing_file(char **path) +{ + size_t alen; + ssize_t len; + char buf[4]; + + for (;;) { + fprintf(stderr, + "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", + *path); + if (fgets(buf, sizeof(buf), stdin) == NULL) { + clearerr(stdin); + printf("NULL\n(EOF or read error, " + "treating as \"[N]one\"...)\n"); + n_opt = 1; + return -1; + } + switch (*buf) { + case 'A': + o_opt = 1; + /* FALLTHROUGH */ + case 'y': + case 'Y': + (void)unlink(*path); + return 1; + case 'N': + n_opt = 1; + /* FALLTHROUGH */ + case 'n': + return -1; + case 'r': + case 'R': + printf("New name: "); + fflush(stdout); + free(*path); + *path = NULL; + alen = 0; + len = getline(path, &alen, stdin); + if ((*path)[len - 1] == '\n') + (*path)[len - 1] = '\0'; + return 0; + default: + break; + } + } +} + +/* + * Detect binary files by a combination of character white list and + * black list. NUL bytes and other control codes without use in text files + * result directly in switching the file to binary mode. Otherwise, at least + * one white-listed byte has to be found. + * + * Black-listed: 0..6, 14..25, 28..31 + * 0xf3ffc07f = 11110011111111111100000001111111b + * White-listed: 9..10, 13, >= 32 + * 0x00002600 = 00000000000000000010011000000000b + * + * See the proginfo/txtvsbin.txt in the zip sources for a detailed discussion. + */ +#define BYTE_IS_BINARY(x) ((x) < 32 && (0xf3ffc07fU & (1U << (x)))) +#define BYTE_IS_TEXT(x) ((x) >= 32 || (0x00002600U & (1U << (x)))) + +static int +check_binary(const unsigned char *buf, size_t len) +{ + int rv; + for (rv = 1; len--; ++buf) { + if (BYTE_IS_BINARY(*buf)) + return 1; + if (BYTE_IS_TEXT(*buf)) + rv = 0; + } + + return rv; +} + +/* + * Extract to a file descriptor + */ +static int +extract2fd(struct archive *a, char *pathname, int fd) +{ + int cr, text, warn; + ssize_t len; + unsigned char *p, *q, *end; + + text = a_opt; + warn = 0; + cr = 0; + + /* loop over file contents and write to fd */ + for (int n = 0; ; n++) { + if (fd != STDOUT_FILENO) + if (tty && (n % 4) == 0) + info(" %c\b\b", spinner[(n / 4) % sizeof spinner]); + + len = archive_read_data(a, buffer, sizeof buffer); + + if (len < 0) + ac(len); + + /* left over CR from previous buffer */ + if (a_opt && cr) { + if (len == 0 || buffer[0] != '\n') + if (write(fd, "\r", 1) != 1) + error("write('%s')", pathname); + cr = 0; + } + + /* EOF */ + if (len == 0) + break; + end = buffer + len; + + /* + * Detect whether this is a text file. The correct way to + * do this is to check the least significant bit of the + * "internal file attributes" field of the corresponding + * file header in the central directory, but libarchive + * does not provide access to this field, so we have to + * guess by looking for non-ASCII characters in the + * buffer. Hopefully we won't guess wrong. If we do + * guess wrong, we print a warning message later. + */ + if (a_opt && n == 0) { + if (check_binary(buffer, len)) + text = 0; + } + + /* simple case */ + if (!a_opt || !text) { + if (write(fd, buffer, len) != len) + error("write('%s')", pathname); + continue; + } + + /* hard case: convert \r\n to \n (sigh...) */ + for (p = buffer; p < end; p = q + 1) { + for (q = p; q < end; q++) { + if (!warn && BYTE_IS_BINARY(*q)) { + warningx("%s may be corrupted due" + " to weak text file detection" + " heuristic", pathname); + warn = 1; + } + if (q[0] != '\r') + continue; + if (&q[1] == end) { + cr = 1; + break; + } + if (q[1] == '\n') + break; + } + if (write(fd, p, q - p) != q - p) + error("write('%s')", pathname); + } + } + + return text; +} + +/* + * Extract a regular file. + */ +static void +extract_file(struct archive *a, struct archive_entry *e, char **path) +{ + int mode; + struct timespec mtime; + struct stat sb; + struct timespec ts[2]; + int fd, check, text; + const char *linkname; + + mode = archive_entry_mode(e) & 0777; + if (mode == 0) + mode = 0644; + mtime.tv_sec = archive_entry_mtime(e); + mtime.tv_nsec = archive_entry_mtime_nsec(e); + + /* look for existing file of same name */ +recheck: + if (lstat(*path, &sb) == 0) { + if (u_opt || f_opt) { + /* check if up-to-date */ + if (S_ISREG(sb.st_mode) && ( +#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC + sb.st_mtimespec.tv_sec > mtime.tv_sec || + (sb.st_mtimespec.tv_sec == mtime.tv_sec && + sb.st_mtimespec.tv_nsec >= mtime.tv_nsec) +#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + sb.st_mtim.tv_sec > mtime.tv_sec || + (sb.st_mtim.tv_sec == mtime.tv_sec && + sb.st_mtim.tv_nsec >= mtime.tv_nsec) +#elif HAVE_STRUCT_STAT_ST_MTIME_N + sb.st_mtime > mtime.tv_sec || + (sb.st_mtime == mtime.tv_sec && + sb.st_mtime_n => mtime.tv_nsec) +#elif HAVE_STRUCT_STAT_ST_MTIME_USEC + sb.st_mtime > mtime.tv_sec || + (sb.st_mtime == mtime.tv_sec && + sb.st_mtime_usec => mtime.tv_nsec / 1000) +#else + sb.st_mtime > mtime.tv_sec +#endif + )) + return; + (void)unlink(*path); + } else if (o_opt) { + /* overwrite */ + (void)unlink(*path); + } else if (n_opt) { + /* do not overwrite */ + return; + } else { + check = handle_existing_file(path); + if (check == 0) + goto recheck; + if (check == -1) + return; /* do not overwrite */ + } + } else { + if (f_opt) + return; + } + + ts[0].tv_sec = 0; + ts[0].tv_nsec = UTIME_NOW; + ts[1] = mtime; + + /* process symlinks */ + linkname = archive_entry_symlink(e); + if (linkname != NULL) { + if (symlink(linkname, *path) != 0) + error("symlink('%s')", *path); + info(" extracting: %s -> %s\n", *path, linkname); + if (lchmod(*path, mode) != 0) + warning("Cannot set mode for '%s'", *path); + /* set access and modification time */ + if (utimensat(AT_FDCWD, *path, ts, AT_SYMLINK_NOFOLLOW) != 0) + warning("utimensat('%s')", *path); + return; + } + + if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0) + error("open('%s')", *path); + + info(" extracting: %s", *path); + + text = extract2fd(a, *path, fd); + + if (tty) + info(" \b\b"); + if (text) + info(" (text)"); + info("\n"); + + /* set access and modification time */ + if (futimens(fd, ts) != 0) + error("futimens('%s')", *path); + if (close(fd) != 0) + error("close('%s')", *path); +} + +/* + * Extract a zipfile entry: first perform some sanity checks to ensure + * that it is either a directory or a regular file and that the path is + * not absolute and does not try to break out of the current directory; + * then call either extract_dir() or extract_file() as appropriate. + * + * This is complicated a bit by the various ways in which we need to + * manipulate the path name. Case conversion (if requested by the -L + * option) happens first, but the include / exclude patterns are applied + * to the full converted path name, before the directory part of the path + * is removed in accordance with the -j option. Sanity checks are + * intentionally done earlier than they need to be, so the user will get a + * warning about insecure paths even for files or directories which + * wouldn't be extracted anyway. + */ +static void +extract(struct archive *a, struct archive_entry *e) +{ + char *pathname, *realpathname; + mode_t filetype; + char *p, *q; + + if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) { + warningx("skipping empty or unreadable filename entry"); + ac(archive_read_data_skip(a)); + return; + } + filetype = archive_entry_filetype(e); + + /* sanity checks */ + if (pathname[0] == '/' || + strncmp(pathname, "../", 3) == 0 || + strstr(pathname, "/../") != NULL) { + warningx("skipping insecure entry '%s'", pathname); + ac(archive_read_data_skip(a)); + free(pathname); + return; + } + + /* I don't think this can happen in a zipfile.. */ + if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { + warningx("skipping non-regular entry '%s'", pathname); + ac(archive_read_data_skip(a)); + free(pathname); + return; + } + + /* skip directories in -j case */ + if (S_ISDIR(filetype) && j_opt) { + ac(archive_read_data_skip(a)); + free(pathname); + return; + } + + /* apply include / exclude patterns */ + if (!accept_pathname(pathname)) { + ac(archive_read_data_skip(a)); + free(pathname); + return; + } + + /* apply -j and -d */ + if (j_opt) { + for (p = q = pathname; *p; ++p) + if (*p == '/') + q = p + 1; + realpathname = pathcat(d_arg, q); + } else { + realpathname = pathcat(d_arg, pathname); + } + + /* ensure that parent directory exists */ + make_parent(realpathname); + + if (S_ISDIR(filetype)) + extract_dir(a, e, realpathname); + else + extract_file(a, e, &realpathname); + + free(realpathname); + free(pathname); +} + +static void +extract_stdout(struct archive *a, struct archive_entry *e) +{ + char *pathname; + mode_t filetype; + + if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) { + warningx("skipping empty or unreadable filename entry"); + ac(archive_read_data_skip(a)); + return; + } + filetype = archive_entry_filetype(e); + + /* I don't think this can happen in a zipfile.. */ + if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { + warningx("skipping non-regular entry '%s'", pathname); + ac(archive_read_data_skip(a)); + free(pathname); + return; + } + + /* skip directories in -j case */ + if (S_ISDIR(filetype)) { + ac(archive_read_data_skip(a)); + free(pathname); + return; + } + + /* apply include / exclude patterns */ + if (!accept_pathname(pathname)) { + ac(archive_read_data_skip(a)); + free(pathname); + return; + } + + if (c_opt) + info("x %s\n", pathname); + + (void)extract2fd(a, pathname, STDOUT_FILENO); + + free(pathname); +} + +/* + * Print the name of an entry to stdout. + */ +static void +list(struct archive *a, struct archive_entry *e) +{ + char buf[20]; + time_t mtime; + struct tm *tm; + + mtime = archive_entry_mtime(e); + tm = localtime(&mtime); + if (*y_str) + strftime(buf, sizeof(buf), "%m-%d-%G %R", tm); + else + strftime(buf, sizeof(buf), "%m-%d-%g %R", tm); + + if (!zipinfo_mode) { + if (v_opt == 1) { + printf(" %8ju %s %s\n", + (uintmax_t)archive_entry_size(e), + buf, archive_entry_pathname(e)); + } else if (v_opt == 2) { + printf("%8ju Stored %7ju 0%% %s %08x %s\n", + (uintmax_t)archive_entry_size(e), + (uintmax_t)archive_entry_size(e), + buf, + 0U, + archive_entry_pathname(e)); + } + } else { + if (Z1_opt) + printf("%s\n",archive_entry_pathname(e)); + } + ac(archive_read_data_skip(a)); +} + +/* + * Extract to memory to check CRC + */ +static int +test(struct archive *a, struct archive_entry *e) +{ + ssize_t len; + int error_count; + + error_count = 0; + if (S_ISDIR(archive_entry_filetype(e))) + return 0; + + info(" testing: %s\t", archive_entry_pathname(e)); + while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0) + /* nothing */; + if (len < 0) { + info(" %s\n", archive_error_string(a)); + ++error_count; + } else { + info(" OK\n"); + } + + /* shouldn't be necessary, but it doesn't hurt */ + ac(archive_read_data_skip(a)); + + return error_count; +} + +/* + * Callback function for reading passphrase. + * Originally from cpio.c and passphrase.c, libarchive. + */ +#define PPBUFF_SIZE 1024 +static const char * +passphrase_callback(struct archive *a, void *_client_data) +{ + char *p; + + (void)a; /* UNUSED */ + (void)_client_data; /* UNUSED */ + + if (passphrase_buf == NULL) { + passphrase_buf = malloc(PPBUFF_SIZE); + if (passphrase_buf == NULL) { + errno = ENOMEM; + error("malloc()"); + } + } + + p = lafe_readpassphrase("\nEnter password: ", passphrase_buf, + PPBUFF_SIZE); + + if (p == NULL && errno != EINTR) + error("Error reading password"); + + return p; +} + +/* + * Main loop: open the zipfile, iterate over its contents and decide what + * to do with each entry. + */ +static void +unzip(const char *fn) +{ + struct archive *a; + struct archive_entry *e; + int ret; + uintmax_t total_size, file_count, error_count; + + if ((a = archive_read_new()) == NULL) + error("archive_read_new failed"); + + ac(archive_read_support_format_zip(a)); + + if (P_arg) + archive_read_add_passphrase(a, P_arg); + else + archive_read_set_passphrase_callback(a, NULL, + &passphrase_callback); + + ac(archive_read_open_filename(a, fn, 8192)); + + if (!zipinfo_mode) { + if (!p_opt && !q_opt) + printf("Archive: %s\n", fn); + if (v_opt == 1) { + printf(" Length %sDate Time Name\n", y_str); + printf(" -------- %s---- ---- ----\n", y_str); + } else if (v_opt == 2) { + printf(" Length Method Size Ratio %sDate Time CRC-32 Name\n", y_str); + printf("-------- ------ ------- ----- %s---- ---- ------ ----\n", y_str); + } + } + + total_size = 0; + file_count = 0; + error_count = 0; + for (;;) { + ret = archive_read_next_header(a, &e); + if (ret == ARCHIVE_EOF) + break; + ac(ret); + if (!zipinfo_mode) { + if (t_opt) + error_count += test(a, e); + else if (v_opt) + list(a, e); + else if (p_opt || c_opt) + extract_stdout(a, e); + else + extract(a, e); + } else { + if (Z1_opt) + list(a, e); + } + + total_size += archive_entry_size(e); + ++file_count; + } + + if (zipinfo_mode) { + if (v_opt == 1) { + printf(" -------- %s-------\n", y_str); + printf(" %8ju %s%ju file%s\n", + total_size, y_str, file_count, file_count != 1 ? "s" : ""); + } else if (v_opt == 2) { + printf("-------- ------- --- %s-------\n", y_str); + printf("%8ju %7ju 0%% %s%ju file%s\n", + total_size, total_size, y_str, file_count, + file_count != 1 ? "s" : ""); + } + } + + ac(archive_read_free(a)); + + if (passphrase_buf != NULL) { + memset(passphrase_buf, 0, PPBUFF_SIZE); + free(passphrase_buf); + } + + if (t_opt) { + if (error_count > 0) { + errorx("%ju checksum error(s) found.", error_count); + } + else { + printf("No errors detected in compressed data of %s.\n", + fn); + } + } +} + +static void +usage(void) +{ + + fprintf(stderr, +"Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] [-x pattern] [-P password] zipfile\n" +" [member ...]\n"); + exit(EXIT_FAILURE); +} + +static int +getopts(int argc, char *argv[]) +{ + int opt; + + optreset = optind = 1; + while ((opt = getopt(argc, argv, "aCcd:fjLlnopP:qtuvx:yZ1")) != -1) + switch (opt) { + case '1': + Z1_opt = 1; + break; + case 'a': + a_opt = 1; + break; + case 'C': + C_opt = 1; + break; + case 'c': + c_opt = 1; + break; + case 'd': + d_arg = optarg; + break; + case 'f': + f_opt = 1; + break; + case 'j': + j_opt = 1; + break; + case 'L': + L_opt = 1; + break; + case 'l': + if (v_opt == 0) + v_opt = 1; + break; + case 'n': + n_opt = 1; + break; + case 'o': + o_opt = 1; + q_opt = 1; + break; + case 'p': + p_opt = 1; + break; + case 'P': + P_arg = optarg; + break; + case 'q': + q_opt = 1; + break; + case 't': + t_opt = 1; + break; + case 'u': + u_opt = 1; + break; + case 'v': + v_opt = 2; + break; + case 'x': + add_pattern(&exclude, optarg); + break; + case 'y': + y_str = " "; + break; + case 'Z': + zipinfo_mode = 1; + break; + default: + usage(); + } + + return (optind); +} + +int +main(int argc, char *argv[]) +{ + const char *zipfile; + int nopts; + + if (isatty(STDOUT_FILENO)) + tty = 1; + + if (getenv("UNZIP_DEBUG") != NULL) + unzip_debug = 1; + for (int i = 0; i < argc; ++i) + debug("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n'); + +#ifdef __GLIBC__ + /* Prevent GNU getopt(3) from rearranging options. */ + setenv("POSIXLY_CORRECT", "", 1); +#endif + /* + * Info-ZIP's unzip(1) expects certain options to come before the + * zipfile name, and others to come after - though it does not + * enforce this. For simplicity, we accept *all* options both + * before and after the zipfile name. + */ + nopts = getopts(argc, argv); + + /* + * When more of the zipinfo mode options are implemented, this + * will need to change. + */ + if (zipinfo_mode && !Z1_opt) { + printf("Zipinfo mode needs additional options\n"); + exit(EXIT_FAILURE); + } + + if (argc <= nopts) + usage(); + zipfile = argv[nopts++]; + + if (strcmp(zipfile, "-") == 0) + zipfile = NULL; /* STDIN */ + + while (nopts < argc && *argv[nopts] != '-') + add_pattern(&include, argv[nopts++]); + + nopts--; /* fake argv[0] */ + nopts += getopts(argc - nopts, argv + nopts); + + /* There may be residual arguments if we encountered -- */ + while (nopts < argc) + add_pattern(&include, argv[nopts++]); + + if (n_opt + o_opt + u_opt > 1) + errorx("-n, -o and -u are contradictory"); + + unzip(zipfile); + + exit(EXIT_SUCCESS); +} diff --git a/unzip/bsdunzip_platform.h b/unzip/bsdunzip_platform.h new file mode 100644 index 000000000000..5aff5f208eab --- /dev/null +++ b/unzip/bsdunzip_platform.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/usr.bin/tar/bsdtar_platform.h,v 1.26 2008/12/06 07:37:14 kientzle Exp $ + */ + +/* + * This header is the first thing included in any of the bsdtar + * source files. As far as possible, platform-specific issues should + * be dealt with here and not within individual source files. + */ + +#ifndef BSDUNZIP_PLATFORM_H_INCLUDED +#define BSDUNZIP_PLATFORM_H_INCLUDED + +#if defined(PLATFORM_CONFIG_H) +/* Use hand-built config.h in environments that need it. */ +#include PLATFORM_CONFIG_H +#else +/* Not having a config.h of some sort is a serious problem. */ +#include "config.h" +#endif + +/* Get a real definition for __FBSDID if we can */ +#if HAVE_SYS_CDEFS_H +#include <sys/cdefs.h> +#endif + +/* If not, define it so as to avoid dangling semicolons. */ +#ifndef __FBSDID +#define __FBSDID(a) struct _undefined_hack +#endif + +#ifdef HAVE_LIBARCHIVE +/* If we're using the platform libarchive, include system headers. */ +#include <archive.h> +#include <archive_entry.h> +#else +/* Otherwise, include user headers. */ +#include "archive.h" +#include "archive_entry.h" +#endif + +#ifndef HAVE_GETOPT_OPTRESET +/* + * If platform doesn't use optreset for resetting getopt, declare it so + * C source doesn't have to know this platform-specific difference + */ +int optreset; +#endif + +/* How to mark functions that don't return. */ +/* This facilitates use of some newer static code analysis tools. */ +#undef __LA_DEAD +#if defined(__GNUC__) && (__GNUC__ > 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)) +#define __LA_DEAD __attribute__((__noreturn__)) +#else +#define __LA_DEAD +#endif + +#endif /* !BSDUNZIP_PLATFORM_H_INCLUDED */ diff --git a/unzip/test/CMakeLists.txt b/unzip/test/CMakeLists.txt new file mode 100644 index 000000000000..bdb3445954f1 --- /dev/null +++ b/unzip/test/CMakeLists.txt @@ -0,0 +1,80 @@ +############################################ +# +# How to build bsdunzip_test +# +############################################ +IF(ENABLE_UNZIP AND ENABLE_TEST) + SET(bsdunzip_test_SOURCES + ../../libarchive_fe/err.c + ../../test_utils/test_utils.c + ../../test_utils/test_main.c + test.h + test_0.c + test_basic.c + test_glob.c + test_singlefile.c + test_C.c + test_p.c + test_d.c + test_j.c + test_L.c + test_n.c + test_o.c + test_q.c + test_t.c + test_t_bad.c + test_x.c + test_Z1.c + test_P_encryption.c + ) + + # + # Register target + # + ADD_EXECUTABLE(bsdunzip_test ${bsdunzip_test_SOURCES}) + IF(ENABLE_ACL) + SET(TEST_ACL_LIBS "") + IF(HAVE_LIBACL) + LIST(APPEND TEST_ACL_LIBS ${ACL_LIBRARY}) + ENDIF(HAVE_LIBACL) + IF(HAVE_LIBRICHACL) + LIST(APPEND TEST_ACL_LIBS ${RICHACL_LIBRARY}) + ENDIF(HAVE_LIBRICHACL) + TARGET_LINK_LIBRARIES(bsdunzip_test ${TEST_ACL_LIBS}) + ENDIF(ENABLE_ACL) + SET_PROPERTY(TARGET bsdunzip_test PROPERTY COMPILE_DEFINITIONS LIST_H) + + # + # Generate list.h by grepping DEFINE_TEST() lines out of the C sources. + # + GENERATE_LIST_H(${CMAKE_CURRENT_BINARY_DIR}/list.h + ${CMAKE_CURRENT_LIST_FILE} ${bsdunzip_test_SOURCES}) + SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES + ${CMAKE_CURRENT_BINARY_DIR}) + + # list.h has a line DEFINE_TEST(testname) for every + # test. We can use that to define the tests for cmake by + # defining a DEFINE_TEST macro and reading list.h in. + MACRO (DEFINE_TEST _testname) + ADD_TEST( + NAME bsdunzip_${_testname} + COMMAND bsdunzip_test -vv + -p $<TARGET_FILE:bsdunzip> + -r ${CMAKE_CURRENT_SOURCE_DIR} + ${_testname}) + ENDMACRO (DEFINE_TEST _testname) + + INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils) + INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/unzip/test) + + # Experimental new test handling + ADD_CUSTOM_TARGET(run_bsdunzip_test + COMMAND bsdunzip_test -p $<TARGET_FILE:bsdunzip> + -r ${CMAKE_CURRENT_SOURCE_DIR} + -vv) + ADD_DEPENDENCIES(run_bsdunzip_test bsdunzip) + ADD_DEPENDENCIES(run_all_tests run_bsdunzip_test) +ENDIF(ENABLE_UNZIP AND ENABLE_TEST) + diff --git a/unzip/test/test.h b/unzip/test/test.h new file mode 100644 index 000000000000..8da017f68e16 --- /dev/null +++ b/unzip/test/test.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003-2017 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* Every test program should #include "test.h" as the first thing. */ + +#define KNOWNREF "test_basic.zip.uu" +#define ENVBASE "BSDUNZIP" /* Prefix for environment variables. */ +#define PROGRAM "bsdunzip" /* Name of program being tested. */ +#define PROGRAM_ALIAS "unzip" /* Generic alias for program */ +#undef LIBRARY /* Not testing a library. */ +#undef EXTRA_DUMP /* How to dump extra data */ +#undef EXTRA_ERRNO /* How to dump errno */ +/* How to generate extra version info. */ +#define EXTRA_VERSION (systemf("%s -v", testprog) ? "" : "") + +#include "test_common.h" diff --git a/unzip/test/test_0.c b/unzip/test/test_0.c new file mode 100644 index 000000000000..41279d388b1f --- /dev/null +++ b/unzip/test/test_0.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* + * This first test does basic sanity checks on the environment. For + * most of these, we just exit on failure. + */ +#if !defined(_WIN32) || defined(__CYGWIN__) +#define DEV_NULL "/dev/null" +#else +#define DEV_NULL "NUL" +#endif + +DEFINE_TEST(test_0) +{ + struct stat st; + + failure("File %s does not exist?!", testprog); + if (!assertEqualInt(0, stat(testprogfile, &st))) { + fprintf(stderr, + "\nFile %s does not exist; aborting test.\n\n", + testprog); + exit(1); + } + + failure("%s is not executable?!", testprog); + if (!assert((st.st_mode & 0111) != 0)) { + fprintf(stderr, + "\nFile %s not executable; aborting test.\n\n", + testprog); + exit(1); + } + + /* TODO: Ensure that our reference files are available. */ +} diff --git a/unzip/test/test_C.c b/unzip/test/test_C.c new file mode 100644 index 000000000000..fc11b970c2f3 --- /dev/null +++ b/unzip/test/test_C.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test C arg - match case-insensitive */ +DEFINE_TEST(test_C) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -C %s test_basic/caps >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +} diff --git a/unzip/test/test_L.c b/unzip/test/test_L.c new file mode 100644 index 000000000000..4815cb2b139d --- /dev/null +++ b/unzip/test/test_L.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test L arg - make names lowercase */ +DEFINE_TEST(test_L) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -L %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "test_basic/a"); + assertTextFileContents("contents b\n", "test_basic/b"); + assertTextFileContents("contents c\n", "test_basic/c"); + assertTextFileContents("contents CAPS\n", "test_basic/caps"); +} diff --git a/unzip/test/test_P_encryption.c b/unzip/test/test_P_encryption.c new file mode 100644 index 000000000000..beabbaa646ee --- /dev/null +++ b/unzip/test/test_P_encryption.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test P arg - password protected */ +DEFINE_TEST(test_P) +{ + const char *reffile = "test_encrypted.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -P password %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("plaintext\n", "encrypted/file.txt"); +} diff --git a/unzip/test/test_Z1.c b/unzip/test/test_Z1.c new file mode 100644 index 000000000000..58dc750030dd --- /dev/null +++ b/unzip/test/test_Z1.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test -Z1 arg - List filenames */ +DEFINE_TEST(test_Z1) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -Z1 %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertTextFileContents("test_basic/\ntest_basic/a\ntest_basic/b\ntest_basic/c\ntest_basic/CAPS\n", "test.out"); + assertEmptyFile("test.err"); +} diff --git a/unzip/test/test_basic.c b/unzip/test/test_basic.c new file mode 100644 index 000000000000..e997755e7e57 --- /dev/null +++ b/unzip/test/test_basic.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* This test just does a basic zip decompression */ +DEFINE_TEST(test_basic) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "test_basic/a"); + assertTextFileContents("contents b\n", "test_basic/b"); + assertTextFileContents("contents c\n", "test_basic/c"); + assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +} diff --git a/unzip/test/test_basic.zip.uu b/unzip/test/test_basic.zip.uu new file mode 100644 index 000000000000..b55aca950327 --- /dev/null +++ b/unzip/test/test_basic.zip.uu @@ -0,0 +1,25 @@ +begin 644 test_basic.zip +M4$L#!!0``````,J0MU8````````````````+`"``=&5S=%]B87-I8R]55`T` +M!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`P04``@`"``)C;=6```` +M```````+````#``@`'1E<W1?8F%S:6,O8554#0`'PS)M9/HY;603.&UD=7@+ +M``$$Z`,```3H`P``2\[/*TG-*RE62.0"`%!+!PAY:C`$#0````L```!02P,$ +M%``(``@`#HVW5@``````````"P````P`(`!T97-T7V)A<VEC+V)55`T`!\TR +M;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``$O.SRM)S2LI5DCB`@!02P<(NCD= +M+PT````+````4$L#!!0`"``(`%*-MU8```````````L````,`"``=&5S=%]B +M87-I8R]C550-``=,,VUDTSAM9,\X;61U>`L``03H`P``!.@#``!+SL\K2<TK +M*59(Y@(`4$L'"/L(!C8-````"P```%!+`P04``@`"`#*D+=6```````````. +M````#P`@`'1E<W1?8F%S:6,O0T%04U54#0`'W#AM9/HY;63<.&UD=7@+``$$ +MZ`,```3H`P``2\[/*TG-*RE6<'8,".8"`%!+!P@I4T'W$`````X```!02P$" +M%`,4``````#*D+=6````````````````"P`@````````````[4$`````=&5S +M=%]B87-I8R]55`T`!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(``F-MU9Y:C`$#0````L````,`"````````````"D@4D```!T97-T +M7V)A<VEC+V%55`T`!\,R;63Z.6UD$SAM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(``Z-MU:Z.1TO#0````L````,`"````````````"D@;````!T97-T +M7V)A<VEC+V)55`T`!\TR;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(`%*-MU;["`8V#0````L````,`"````````````"D@1<!``!T97-T +M7V)A<VEC+V-55`T`!TPS;633.&UDSSAM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(`,J0MU8I4T'W$`````X````/`"````````````"D@7X!``!T97-T +M7V)A<VEC+T-!4%-55`T`!]PX;63Z.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+ +4!08`````!0`%`,0!``#K`0`````` +` +end diff --git a/unzip/test/test_d.c b/unzip/test/test_d.c new file mode 100644 index 000000000000..64950cbbe165 --- /dev/null +++ b/unzip/test/test_d.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test d arg - extract to target dir */ +DEFINE_TEST(test_d) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -d foobar %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "foobar/test_basic/a"); + assertTextFileContents("contents b\n", "foobar/test_basic/b"); + assertTextFileContents("contents c\n", "foobar/test_basic/c"); + assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS"); +} diff --git a/unzip/test/test_encrypted.zip.uu b/unzip/test/test_encrypted.zip.uu new file mode 100644 index 000000000000..6aabeb9f5786 --- /dev/null +++ b/unzip/test/test_encrypted.zip.uu @@ -0,0 +1,13 @@ +begin 644 test_encrypted.zip +M4$L#!!0``````'*1MU8````````````````*`"``96YC<GEP=&5D+U54#0`' +M&#IM9!LZ;608.FUD=7@+``$$Z`,```3H`P``4$L#!!0`"0!C`'*1MU8````` +M``````H````2`"L`96YC<GEP=&5D+V9I;&4N='AT550-``<8.FUD&#IM9!@Z +M;61U>`L``03H`P``!.@#```!F0<``@!!10,(`*_-)-RYPDYFJ$Q9+L<I#->< +M'#C?XVBR9/=H?7U\LC!A^8<6[&CO#PM02P<(`````"@````*````4$L!`A0# +M%```````<I&W5@````````````````H`(````````````.U!`````&5N8W)Y +M<'1E9"]55`T`!Q@Z;60;.FUD&#IM9'5X"P`!!.@#```$Z`,``%!+`0(4`Q0` +M"0!C`'*1MU8`````*`````H````2`"L```````````"D@4@```!E;F-R>7!T +M960O9FEL92YT>'155`T`!Q@Z;608.FUD&#IM9'5X"P`!!.@#```$Z`,```&9 +?!P`"`$%%`P@`4$L%!@`````"``(`PP```-L````````` +` +end diff --git a/unzip/test/test_glob.c b/unzip/test/test_glob.c new file mode 100644 index 000000000000..b334ce4bd37d --- /dev/null +++ b/unzip/test/test_glob.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test that the glob works */ +DEFINE_TEST(test_glob) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s %s test_*/[ab] >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "test_basic/a"); + assertTextFileContents("contents b\n", "test_basic/b"); + assertFileNotExists("test_basic/c"); + assertFileNotExists("test_basic/CAPS"); +} diff --git a/unzip/test/test_j.c b/unzip/test/test_j.c new file mode 100644 index 000000000000..a449e02644b5 --- /dev/null +++ b/unzip/test/test_j.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test j arg - don't make directories */ +DEFINE_TEST(test_j) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -j %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "a"); + assertTextFileContents("contents b\n", "b"); + assertTextFileContents("contents c\n", "c"); + assertTextFileContents("contents CAPS\n", "CAPS"); +} diff --git a/unzip/test/test_n.c b/unzip/test/test_n.c new file mode 100644 index 000000000000..4e893f04b7ae --- /dev/null +++ b/unzip/test/test_n.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test n arg - don't overrite existing files */ +DEFINE_TEST(test_n) +{ + const char *reffile = "test_basic.zip"; + int r; + + assertMakeDir("test_basic", 0755); + assertMakeFile("test_basic/a", 0644, "orig a\n"); + assertMakeFile("test_basic/b", 0644, "orig b\n"); + + extract_reference_file(reffile); + r = systemf("%s -n %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("orig a\n", "test_basic/a"); + assertTextFileContents("orig b\n", "test_basic/b"); + assertTextFileContents("contents c\n", "test_basic/c"); + assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +} diff --git a/unzip/test/test_not_exist.c b/unzip/test/test_not_exist.c new file mode 100644 index 000000000000..aa660dc646e5 --- /dev/null +++ b/unzip/test/test_not_exist.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test non existant file */ +DEFINE_TEST(test_not_exist) +{ + int r; + r = systemf("%s nonexist.zip >test.out 2>test.err", testprog); + assert(r != 0); + assertEmptyFile("test.out"); + assertNonEmptyFile("test.err"); +} diff --git a/unzip/test/test_o.c b/unzip/test/test_o.c new file mode 100644 index 000000000000..af0c4128686f --- /dev/null +++ b/unzip/test/test_o.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test o arg - overrite existing files */ +DEFINE_TEST(test_o) +{ + const char *reffile = "test_basic.zip"; + int r; + + assertMakeDir("test_basic", 0755); + assertMakeFile("test_basic/a", 0644, "orig a\n"); + assertMakeFile("test_basic/b", 0644, "orig b\n"); + + extract_reference_file(reffile); + r = systemf("%s -o %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "test_basic/a"); + assertTextFileContents("contents b\n", "test_basic/b"); + assertTextFileContents("contents c\n", "test_basic/c"); + assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +} diff --git a/unzip/test/test_p.c b/unzip/test/test_p.c new file mode 100644 index 000000000000..f34a5eae8e13 --- /dev/null +++ b/unzip/test/test_p.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test p arg - Print to stdout */ +DEFINE_TEST(test_p) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -p %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertTextFileContents("contents a\ncontents b\ncontents c\ncontents CAPS\n", "test.out"); + assertEmptyFile("test.err"); +} diff --git a/unzip/test/test_q.c b/unzip/test/test_q.c new file mode 100644 index 000000000000..9a532c888366 --- /dev/null +++ b/unzip/test/test_q.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test q arg - Quiet */ +DEFINE_TEST(test_q) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -q %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "test_basic/a"); + assertTextFileContents("contents b\n", "test_basic/b"); + assertTextFileContents("contents c\n", "test_basic/c"); + assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +} diff --git a/unzip/test/test_singlefile.c b/unzip/test/test_singlefile.c new file mode 100644 index 000000000000..70c376eb3932 --- /dev/null +++ b/unzip/test/test_singlefile.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Ensure single-file zips work */ +DEFINE_TEST(test_singlefile) +{ + const char *reffile = "test_singlefile.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("hello\n", "file.txt"); +} diff --git a/unzip/test/test_singlefile.zip.uu b/unzip/test/test_singlefile.zip.uu new file mode 100644 index 000000000000..589e08f12396 --- /dev/null +++ b/unzip/test/test_singlefile.zip.uu @@ -0,0 +1,8 @@ +begin 644 test_singlefile.zip +M4$L#!!0`"``(`&"6MU8```````````8````(`"``9FEL92YT>'155`T`!U1# +M;6140VUD5$-M9'5X"P`!!.@#```$Z`,``,M(S<G)YP(`4$L'""`P.C8(```` +M!@```%!+`0(4`Q0`"``(`&"6MU8@,#HV"`````8````(`"````````````"D +M@0````!F:6QE+G1X=%54#0`'5$-M9%1#;6140VUD=7@+``$$Z`,```3H`P`` +64$L%!@`````!``$`5@```%X````````` +` +end diff --git a/unzip/test/test_t.c b/unzip/test/test_t.c new file mode 100644 index 000000000000..40d8d39e54d5 --- /dev/null +++ b/unzip/test/test_t.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test t arg - Test zip contents */ +DEFINE_TEST(test_t) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -t %s >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); +} diff --git a/unzip/test/test_t_bad.c b/unzip/test/test_t_bad.c new file mode 100644 index 000000000000..f9afbb40dae2 --- /dev/null +++ b/unzip/test/test_t_bad.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test t arg - Test zip contents, but fail! */ +DEFINE_TEST(test_t_bad) +{ + const char *reffile = "test_t_bad.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s -t %s >test.out 2>test.err", testprog, reffile); + assert(r != 0); + assertNonEmptyFile("test.out"); + assertNonEmptyFile("test.err"); +} diff --git a/unzip/test/test_t_bad.zip.uu b/unzip/test/test_t_bad.zip.uu new file mode 100644 index 000000000000..ae6ad07925e6 --- /dev/null +++ b/unzip/test/test_t_bad.zip.uu @@ -0,0 +1,25 @@ +begin 644 test_t_bad.zip +M4$L#!!0``````,J0MU8````````````````+`"``=&5S=%]B87-I8R]55`T` +M!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`P04``@`"``)C;=6```` +M```````+````#``@`'1E<W1?8F%S:6,O85546``'PS)M9/HY;603.&UD=7@+ +M``$$Z`,```3H`P``2\[/*TG-*RE62.0"`%!+!PAY:C`$#0````L```!02P,$ +M%&$(``@`#HVW5@``````````"P````P`(`!T97-T7V)A<VEC+V)55`T`!\TR +M;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``$O.SRM)S2LI5DCB`@!02P<(NCD= +M+PT````+````4$L#!!0`"``(`%*-MU8```````````L````,`"``=&5S=%]B +M87-I8R]C550-``=,,VUDTSAM9,\X;61U>`L``03H`P``!.@#``!+SL\K2<TK +M*59(Y@(`4$L'"/L(!C8-````"P```%!+`P04``@`"`#*D+=6```````````. +M````#P`@`'1E<W1?8F%S:6,O0T%04U54#0`'W#AM9/HY;63<.&UD=7@+``$$ +MZ`,```3H`P``2\[/*TG-*RE6<'8,".8"`%!+!P@I4T'W$`````X```!02P$" +M%`,4``````#*D+=6````````````````"P`@````````````[4(`````=&5S +M=%]B87-I8R]55`T`!]PX;63U.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(``F-MU9Y:C`$#0````L````,`"````````````"D@4D```!T97-T +M7V)A<VEC+V%55`T`!\,R;63Z.6UD$SAM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(``Z-MU:Z.1TO#0````L````,`"````````````"D@;````!T97-T +M7V)A<VEC+V)55`T`!\TR;63Z.6UD.SAM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(`%*-MU;["`8V#0````L````,`"````````````"D@1<!``!T97-T +M7V)A<VEC+V-55`T`!TPS;633.&UDSSAM9'5X"P`!!.@#```$Z`,``%!+`0(4 +M`Q0`"``(`,J0MU8I4T'W$`````X````/`"````````````"D@7X!``!T97-T +M7V)A<VEC+T-!4%-55`T`!]PX;63Z.6UDW#AM9'5X"P`!!.@#```$Z`,``%!+ +5!08`````!0`%`,0!``#K`0`````* +` +end diff --git a/unzip/test/test_x.c b/unzip/test/test_x.c new file mode 100644 index 000000000000..21f01bf65da8 --- /dev/null +++ b/unzip/test/test_x.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Adrian Vovk + * 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 + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +/* Test x arg - Exclude paths */ +DEFINE_TEST(test_x) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s %s -x test_basic/c >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "test_basic/a"); + assertTextFileContents("contents b\n", "test_basic/b"); + assertFileNotExists("test_basic/c"); + assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +} |