From 8f38cbcd9c4a4f27bdccf2e75a7e20026cff5181 Mon Sep 17 00:00:00 2001 From: Martin Matuska Date: Thu, 16 Oct 2025 19:36:33 +0200 Subject: [PATCH] Update vendor/libarchive to 3.8.2 Important bugfixes: #2477 tar writer: fix replacing a regular file with a dir for ARCHIVE_EXTRACT_SAFE_WRITES #2659 lib: improve filter process handling #2664 zip writer: fix a memory leak if write callback error early #2665 lib: archive_read_data: handle sparse holes at end of file correctly #2668 7zip: Fix out of boundary access #2670 zip writer: fix writing with ZSTD compression #2672 lib: fix error checking in writing files #2678 zstd write filter: enable Zstandard's checksum feature #2679 lib: handle possible errors from system calls #2707 lib: avoid leaking file descriptors into subprocesses #2713 RAR5 reader: fix multiple issues in extra field parsing function #2716 RAR5 reader: early fail when file declares data for a dir entry #2717 bsdtar: Allow filename to have CRLF endings #2719 tar reader: fix checking the result of the strftime (CVE-2025-25724) #2737 tar reader: fix an infinite loop when parsing V headers #2742 lib: parse_date: handle dates in 2038 and beyond if time_t is big enough Obtained from: libarchive Vendor commit: 7f53fce04e4e672230f4eb80b219af17975e4f83 Security: CVE-2025-25724 --- .github/workflows/ci.yml | 8 +- .github/workflows/codeql.yml | 8 +- .github/workflows/scorecard.yml | 6 +- CMakeLists.txt | 21 ++- Makefile.am | 13 +- NEWS | 2 + SECURITY.md | 2 +- .../install-macos-dependencies.sh | 3 + build/cmake/config.h.in | 9 +- build/version | 2 +- cat/CMakeLists.txt | 4 +- cat/bsdcat.c | 15 +- cat/cmdline.c | 2 +- configure.ac | 21 +-- contrib/android/Android.mk | 2 +- contrib/android/config/android.h | 2 + contrib/android/config/linux_host.h | 4 +- contrib/android/config/windows_host.h | 9 +- contrib/android/include/android_lf.h | 3 +- cpio/CMakeLists.txt | 4 +- cpio/cmdline.c | 2 +- cpio/cpio.c | 14 +- cpio/cpio_windows.c | 2 +- cpio/test/CMakeLists.txt | 2 +- cpio/test/test_owner_parse.c | 2 +- libarchive/CMakeLists.txt | 11 +- libarchive/archive.h | 4 +- libarchive/archive_acl.c | 23 +++ libarchive/archive_check_magic.c | 9 +- libarchive/archive_cryptor.c | 8 +- libarchive/archive_cryptor_private.h | 11 +- libarchive/archive_entry.h | 2 +- libarchive/archive_entry_paths.3 | 2 +- libarchive/archive_entry_stat.c | 6 +- libarchive/archive_parse_date.c | 4 +- libarchive/archive_platform.h | 10 -- libarchive/archive_platform_stat.h | 45 +++++ libarchive/archive_private.h | 1 + libarchive/archive_read.c | 7 +- .../archive_read_disk_entry_from_file.c | 12 +- libarchive/archive_read_disk_posix.c | 157 ++--------------- libarchive/archive_read_open_fd.c | 23 +-- libarchive/archive_read_open_file.c | 16 +- libarchive/archive_read_open_filename.c | 31 ++-- libarchive/archive_read_set_format.c | 32 ++-- .../archive_read_support_filter_program.c | 7 +- libarchive/archive_read_support_format_7zip.c | 7 +- .../archive_read_support_format_mtree.c | 23 ++- libarchive/archive_read_support_format_rar.c | 8 +- libarchive/archive_read_support_format_rar5.c | 66 ++++++- libarchive/archive_read_support_format_tar.c | 70 +++++--- libarchive/archive_read_support_format_warc.c | 2 +- libarchive/archive_read_support_format_xar.c | 2 +- libarchive/archive_read_support_format_zip.c | 4 +- libarchive/archive_string.c | 5 +- libarchive/archive_string_sprintf.c | 2 +- libarchive/archive_util.c | 38 +++- libarchive/archive_windows.c | 148 +++++++++++++++- libarchive/archive_windows.h | 7 + libarchive/archive_write.c | 30 ++-- libarchive/archive_write_add_filter_bzip2.c | 4 + libarchive/archive_write_add_filter_gzip.c | 55 ++++-- libarchive/archive_write_add_filter_program.c | 11 +- libarchive/archive_write_add_filter_zstd.c | 2 + libarchive/archive_write_disk_posix.c | 16 +- libarchive/archive_write_disk_windows.c | 2 +- libarchive/archive_write_open_fd.c | 2 +- libarchive/archive_write_open_file.c | 14 +- libarchive/archive_write_open_filename.c | 3 +- libarchive/archive_write_set_format_7zip.c | 2 +- libarchive/archive_write_set_format_mtree.c | 19 +- libarchive/archive_write_set_format_xar.c | 6 +- libarchive/archive_write_set_format_zip.c | 25 ++- libarchive/filter_fork_posix.c | 37 +++- libarchive/test/CMakeLists.txt | 1 + libarchive/test/test_acl_nfs4.c | 7 + libarchive/test/test_acl_posix1e.c | 5 + libarchive/test/test_archive_parse_date.c | 2 + .../test/test_archive_string_conversion.c | 10 ++ libarchive/test/test_entry.c | 11 ++ .../test/test_read_filter_gzip_recursive.c | 4 +- libarchive/test/test_read_format_7zip.c | 81 +++++---- libarchive/test/test_read_format_rar5.c | 66 +++++++ .../test/test_read_format_rar5_dirdata.rar.uu | 6 + ...rar5_invalid_hash_valid_htime_exfld.rar.uu | 6 + ...t_read_format_rar5_only_crypt_exfld.rar.uu | 7 + ..._read_format_rar5_unsupported_exfld.rar.uu | 6 + .../test_read_format_tar_V_negative_size.c | 48 ++++++ ...est_read_format_tar_V_negative_size.tar.uu | 20 +++ libarchive/test/test_read_set_format.c | 7 +- libarchive/test/test_write_filter_bzip2.c | 29 ++++ libarchive/test/test_write_filter_gzip.c | 12 +- .../test/test_write_filter_gzip_timestamp.c | 7 +- .../test_write_format_mtree_preset_digests.c | 68 ++++---- libarchive_fe/{err.c => lafe_err.c} | 2 +- libarchive_fe/{err.h => lafe_err.h} | 0 libarchive_fe/line_reader.c | 2 +- libarchive_fe/passphrase.c | 2 +- tar/CMakeLists.txt | 4 +- tar/bsdtar.c | 7 +- tar/bsdtar.h | 8 +- tar/bsdtar_windows.c | 2 +- tar/bsdtar_windows.h | 1 + tar/cmdline.c | 2 +- tar/creation_set.c | 2 +- tar/read.c | 2 +- tar/subst.c | 2 +- tar/test/CMakeLists.txt | 1 + tar/test/test_crlf_mtree.c | 74 ++++++++ tar/test/test_option_safe_writes.c | 5 +- tar/util.c | 7 +- tar/write.c | 29 +++- test_utils/test_common.h | 10 +- test_utils/test_main.c | 162 +++++------------- unzip/CMakeLists.txt | 4 +- unzip/bsdunzip.c | 15 +- unzip/cmdline.c | 2 +- unzip/test/CMakeLists.txt | 2 +- unzip/test/test_C.c | 4 + unzip/test/test_L.c | 4 + unzip/test/test_P_encryption.c | 12 +- unzip/test/test_basic.c | 4 + unzip/test/test_d.c | 8 + unzip/test/test_doubledash.c | 4 + unzip/test/test_glob.c | 4 + unzip/test/test_j.c | 4 + unzip/test/test_n.c | 4 + unzip/test/test_o.c | 4 + unzip/test/test_p.c | 4 + unzip/test/test_q.c | 4 + unzip/test/test_singlefile.c | 4 + unzip/test/test_t.c | 4 + unzip/test/test_x.c | 12 ++ 133 files changed, 1382 insertions(+), 641 deletions(-) create mode 100644 libarchive/archive_platform_stat.h create mode 100644 libarchive/test/test_read_format_rar5_dirdata.rar.uu create mode 100644 libarchive/test/test_read_format_rar5_invalid_hash_valid_htime_exfld.rar.uu create mode 100644 libarchive/test/test_read_format_rar5_only_crypt_exfld.rar.uu create mode 100644 libarchive/test/test_read_format_rar5_unsupported_exfld.rar.uu create mode 100644 libarchive/test/test_read_format_tar_V_negative_size.c create mode 100644 libarchive/test/test_read_format_tar_V_negative_size.tar.uu rename libarchive_fe/{err.c => lafe_err.c} (99%) rename libarchive_fe/{err.h => lafe_err.h} (100%) create mode 100644 tar/test/test_crlf_mtree.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbdc70caf00..80adc6ae74b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: matrix: bs: [autotools, cmake] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Install dependencies run: ./build/ci/github_actions/install-macos-dependencies.sh - name: Autogen @@ -59,7 +59,7 @@ jobs: bs: [autotools, cmake] crypto: [mbedtls, nettle, openssl] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Update apt cache run: sudo apt-get update - name: Install dependencies @@ -100,7 +100,7 @@ jobs: Ubuntu-distcheck: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Update package definitions run: sudo apt-get update - name: Install dependencies @@ -127,7 +127,7 @@ jobs: matrix: be: [mingw-gcc, msvc] steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Install mingw if: ${{ matrix.be=='mingw-gcc' }} run: choco install mingw diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4a0ec7b18dd..139d47d5a9a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -26,18 +26,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - name: Initialize CodeQL - uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 + uses: github/codeql-action/init@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 + uses: github/codeql-action/autobuild@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 + uses: github/codeql-action/analyze@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 89cd0648965..4038954a21a 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,12 +29,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif @@ -60,6 +60,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 + uses: github/codeql-action/upload-sarif@64d10c13136e1c5bce3e5fbde8d4906eeaafc885 # v3.30.6 with: sarif_file: results.sarif diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c1f8770ecd..fc9aca4e966 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.17 FATAL_ERROR) PROJECT(libarchive C) # +# Include standard installation directories +include(GNUInstallDirs) +# SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake") if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin) @@ -255,6 +258,10 @@ OPTION(ENABLE_TEST "Enable unit and regression tests" ON) OPTION(ENABLE_COVERAGE "Enable code coverage (GCC only, automatically sets ENABLE_TEST to ON)" FALSE) OPTION(ENABLE_INSTALL "Enable installing of libraries" ON) +IF(WIN32 AND MSVC) + OPTION(MSVC_USE_STATIC_CRT "Use static CRT" OFF) +ENDIF() + SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support") SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)") SET(WINDOWS_VERSION "WIN10" CACHE STRING "Set Windows version to use (Windows only)") @@ -1472,6 +1479,8 @@ CHECK_FUNCTION_EXISTS_GLIBC(arc4random_buf HAVE_ARC4RANDOM_BUF) CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS) CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN) CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT) +CHECK_FUNCTION_EXISTS_GLIBC(closefrom HAVE_CLOSEFROM) +CHECK_FUNCTION_EXISTS_GLIBC(close_range HAVE_CLOSE_RANGE) CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R) CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR) CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS) @@ -1489,15 +1498,19 @@ CHECK_FUNCTION_EXISTS_GLIBC(ftruncate HAVE_FTRUNCATE) CHECK_FUNCTION_EXISTS_GLIBC(futimens HAVE_FUTIMENS) CHECK_FUNCTION_EXISTS_GLIBC(futimes HAVE_FUTIMES) CHECK_FUNCTION_EXISTS_GLIBC(futimesat HAVE_FUTIMESAT) +CHECK_FUNCTION_EXISTS_GLIBC(getegid HAVE_GETEGID) CHECK_FUNCTION_EXISTS_GLIBC(geteuid HAVE_GETEUID) CHECK_FUNCTION_EXISTS_GLIBC(getgrgid_r HAVE_GETGRGID_R) CHECK_FUNCTION_EXISTS_GLIBC(getgrnam_r HAVE_GETGRNAM_R) CHECK_FUNCTION_EXISTS_GLIBC(getline HAVE_GETLINE) +CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID) CHECK_FUNCTION_EXISTS_GLIBC(getpwnam_r HAVE_GETPWNAM_R) CHECK_FUNCTION_EXISTS_GLIBC(getpwuid_r HAVE_GETPWUID_R) -CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID) +CHECK_FUNCTION_EXISTS_GLIBC(getresgid HAVE_GETRESGID) +CHECK_FUNCTION_EXISTS_GLIBC(getresuid HAVE_GETRESUID) CHECK_FUNCTION_EXISTS_GLIBC(getvfsbyname HAVE_GETVFSBYNAME) CHECK_FUNCTION_EXISTS_GLIBC(gmtime_r HAVE_GMTIME_R) +CHECK_FUNCTION_EXISTS_GLIBC(issetugid HAVE_ISSETUGID) CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS) CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD) CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN) @@ -1579,12 +1592,6 @@ CHECK_C_SOURCE_COMPILES( "#include \n#include \nint main(void) { struct statfs s; return sizeof(s);}" HAVE_STRUCT_STATFS) -# Make sure we have the POSIX version of readdir_r, not the -# older 2-argument version. -CHECK_C_SOURCE_COMPILES( - "#include \nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}" - HAVE_READDIR_R) - # dirfd can be either a function or a macro. CHECK_C_SOURCE_COMPILES( "#include \nint main() {DIR *d = opendir(\".\"); return dirfd(d);}" diff --git a/Makefile.am b/Makefile.am index 05232712a85..2827615ad1f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -132,6 +132,7 @@ libarchive_la_SOURCES= \ libarchive/archive_pathmatch.h \ libarchive/archive_platform.h \ libarchive/archive_platform_acl.h \ + libarchive/archive_platform_stat.h \ libarchive/archive_platform_xattr.h \ libarchive/archive_ppmd_private.h \ libarchive/archive_ppmd7.c \ @@ -525,6 +526,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_read_format_rar5.c \ libarchive/test/test_read_format_raw.c \ libarchive/test/test_read_format_tar.c \ + libarchive/test/test_read_format_tar_V_negative_size.c \ libarchive/test/test_read_format_tar_concatenated.c \ libarchive/test/test_read_format_tar_empty_pax.c \ libarchive/test/test_read_format_tar_empty_filename.c \ @@ -921,6 +923,9 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_rar4_encrypted_filenames.rar.uu \ libarchive/test/test_read_format_rar4_solid_encrypted.rar.uu \ libarchive/test/test_read_format_rar4_solid_encrypted_filenames.rar.uu \ + libarchive/test/test_read_format_rar5_only_crypt_exfld.rar.uu \ + libarchive/test/test_read_format_rar5_unsupported_exfld.rar.uu \ + libarchive/test/test_read_format_rar5_invalid_hash_valid_htime_exfld.rar.uu \ libarchive/test/test_read_format_rar5_encrypted.rar.uu \ libarchive/test/test_read_format_rar5_encrypted_filenames.rar.uu \ libarchive/test/test_read_format_rar5_solid_encrypted.rar.uu \ @@ -952,6 +957,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_rar5_multiple_files.rar.uu \ libarchive/test/test_read_format_rar5_multiple_files_solid.rar.uu \ libarchive/test/test_read_format_rar5_nonempty_dir_stream.rar.uu \ + libarchive/test/test_read_format_rar5_dirdata.rar.uu \ libarchive/test/test_read_format_rar5_owner.rar.uu \ libarchive/test/test_read_format_rar5_readtables_overflow.rar.uu \ libarchive/test/test_read_format_rar5_sfx.exe.uu \ @@ -972,6 +978,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_raw.data.gz.uu \ libarchive/test/test_read_format_raw.data.Z.uu \ libarchive/test/test_read_format_raw.data.uu \ + libarchive/test/test_read_format_tar_V_negative_size.tar.uu \ libarchive/test/test_read_format_tar_concatenated.tar.uu \ libarchive/test/test_read_format_tar_empty_filename.tar.uu \ libarchive/test/test_read_format_tar_empty_with_gnulabel.tar.uu \ @@ -1058,6 +1065,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_splitted_rar_seek_support_ab.uu \ libarchive/test/test_splitted_rar_seek_support_ac.uu \ libarchive/test/test_write_disk_appledouble.cpio.gz.uu \ + libarchive/test/test_write_disk_appledouble_zip.zip.uu \ libarchive/test/test_write_disk_hfs_compression.tgz.uu \ libarchive/test/test_write_disk_mac_metadata.tar.gz.uu \ libarchive/test/test_write_disk_no_hfs_compression.tgz.uu \ @@ -1068,8 +1076,8 @@ libarchive_test_EXTRA_DIST=\ # Common code for libarchive frontends (cpio, tar) # libarchive_fe_la_SOURCES= \ - libarchive_fe/err.c \ - libarchive_fe/err.h \ + libarchive_fe/lafe_err.c \ + libarchive_fe/lafe_err.h \ libarchive_fe/lafe_platform.h \ libarchive_fe/line_reader.c \ libarchive_fe/line_reader.h \ @@ -1140,6 +1148,7 @@ bsdtar_test_SOURCES= \ tar/test/test_0.c \ tar/test/test_basic.c \ tar/test/test_copy.c \ + tar/test/test_crlf_mtree.c \ tar/test/test_empty_mtree.c \ tar/test/test_extract_tar_Z.c \ tar/test/test_extract_tar_bz2.c \ diff --git a/NEWS b/NEWS index caca7d5cbdb..f2dd4102fa0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +Oct 15, 2026: libarchive 3.8.2 released + Jun 01, 2026: libarchive 3.8.1 released May 20, 2025: libarchive 3.8.0 released diff --git a/SECURITY.md b/SECURITY.md index 6ca188b603f..f2f60e792a5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,4 +16,4 @@ Please provide the following information in your report: - 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. +that you give us 90 days to work on a fix before public exposure. diff --git a/build/ci/github_actions/install-macos-dependencies.sh b/build/ci/github_actions/install-macos-dependencies.sh index 2aa4823fc3d..b33aed5e556 100755 --- a/build/ci/github_actions/install-macos-dependencies.sh +++ b/build/ci/github_actions/install-macos-dependencies.sh @@ -5,6 +5,9 @@ set -eux #brew update > /dev/null #brew upgrade > /dev/null +# Workaround for cmake in local/pinned tap issue +brew uninstall cmake + # This does an upgrade if the package is already installed brew install \ autoconf \ diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in index 692d4516ab9..06f66b4378c 100644 --- a/build/cmake/config.h.in +++ b/build/cmake/config.h.in @@ -405,6 +405,12 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `chroot' function. */ #cmakedefine HAVE_CHROOT 1 +/* Define to 1 if you have the `closefrom' function. */ +#cmakedefine HAVE_CLOSEFROM 1 + +/* Define to 1 if you have the `close_range' function. */ +#cmakedefine HAVE_CLOSE_RANGE 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_COPYFILE_H 1 @@ -970,9 +976,6 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PWD_H 1 -/* Define to 1 if you have the `readdir_r' function. */ -#cmakedefine HAVE_READDIR_R 1 - /* Define to 1 if you have the `readlink' function. */ #cmakedefine HAVE_READLINK 1 diff --git a/build/version b/build/version index f08c8c42bfe..4c388c39c75 100644 --- a/build/version +++ b/build/version @@ -1 +1 @@ -3008001 +3008002 diff --git a/cat/CMakeLists.txt b/cat/CMakeLists.txt index d534980b9e1..2bf132f78fe 100644 --- a/cat/CMakeLists.txt +++ b/cat/CMakeLists.txt @@ -13,8 +13,8 @@ IF(ENABLE_CAT) bsdcat.h bsdcat_platform.h cmdline.c - ../libarchive_fe/err.c - ../libarchive_fe/err.h + ../libarchive_fe/lafe_err.c + ../libarchive_fe/lafe_err.h ../libarchive_fe/lafe_platform.h ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe) diff --git a/cat/bsdcat.c b/cat/bsdcat.c index 731621fa9b7..2e78870ae50 100644 --- a/cat/bsdcat.c +++ b/cat/bsdcat.c @@ -7,6 +7,9 @@ #include "bsdcat_platform.h" +#ifdef HAVE_SIGNAL_H +#include +#endif #include #ifdef HAVE_STDLIB_H #include @@ -22,7 +25,7 @@ #include #include "bsdcat.h" -#include "err.h" +#include "lafe_err.h" #define BYTES_PER_BLOCK (20*512) @@ -105,6 +108,16 @@ main(int argc, char **argv) bsdcat = &bsdcat_storage; memset(bsdcat, 0, sizeof(*bsdcat)); +#if defined(HAVE_SIGACTION) && defined(SIGCHLD) + { /* Do not ignore SIGCHLD. */ + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGCHLD, &sa, NULL); + } +#endif + lafe_setprogname(*argv, "bsdcat"); bsdcat->argv = argv; diff --git a/cat/cmdline.c b/cat/cmdline.c index 8ecd74aa95e..5a5fcaf0263 100644 --- a/cat/cmdline.c +++ b/cat/cmdline.c @@ -22,7 +22,7 @@ #endif #include "bsdcat.h" -#include "err.h" +#include "lafe_err.h" /* * Short options for bsdcat. Please keep this sorted. diff --git a/configure.ac b/configure.ac index d8d85eda929..a902edb4181 100644 --- a/configure.ac +++ b/configure.ac @@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front. dnl In particular, this allows the version macro to be used in AC_INIT dnl These first two version numbers are updated automatically on each release. -m4_define([LIBARCHIVE_VERSION_S],[3.8.1]) -m4_define([LIBARCHIVE_VERSION_N],[3008001]) +m4_define([LIBARCHIVE_VERSION_S],[3.8.2]) +m4_define([LIBARCHIVE_VERSION_N],[3008002]) dnl bsdtar and bsdcpio versioning tracks libarchive m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S()) @@ -821,12 +821,15 @@ AC_FUNC_VPRINTF # To avoid necessity for including windows.h or special forward declaration # 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([arc4random_buf chflags chown chroot]) +AC_CHECK_FUNCS([closefrom close_range ctime_r]) 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 getline getpid getgrgid_r getgrnam_r]) -AC_CHECK_FUNCS([getpwnam_r getpwuid_r getvfsbyname gmtime_r]) +AC_CHECK_FUNCS([getegid geteuid getline getpid getresgid getresuid]) +AC_CHECK_FUNCS([getgrgid_r getgrnam_r getpwnam_r getpwuid_r]) +AC_CHECK_FUNCS([getvfsbyname gmtime_r]) +AC_CHECK_FUNCS([issetugid]) AC_CHECK_FUNCS([lchflags lchmod lchown link linkat localtime_r lstat lutimes]) AC_CHECK_FUNCS([mbrtowc memmove memset]) AC_CHECK_FUNCS([mkdir mkfifo mknod mkstemp]) @@ -881,14 +884,6 @@ AC_CHECK_TYPES(struct statfs,,, #include ]) -# There are several variants of readdir_r around; we only -# accept the POSIX-compliant version. -AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[#include ]], - [[DIR *dir; struct dirent e, *r; - return(readdir_r(dir, &e, &r));]])], - [AC_DEFINE(HAVE_READDIR_R,1,[Define to 1 if you have a POSIX compatible readdir_r])] -) # dirfd can be either a function or a macro. AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include diff --git a/contrib/android/Android.mk b/contrib/android/Android.mk index 8e7fbdacefe..2e9d9a399ad 100644 --- a/contrib/android/Android.mk +++ b/contrib/android/Android.mk @@ -151,7 +151,7 @@ else libarchive_host_src_files := endif -libarchive_fe_src_files := libarchive_fe/err.c \ +libarchive_fe_src_files := libarchive_fe/lafe_err.c \ libarchive_fe/line_reader.c \ libarchive_fe/passphrase.c diff --git a/contrib/android/config/android.h b/contrib/android/config/android.h index 00fa4e9fdcf..0a273be235b 100644 --- a/contrib/android/config/android.h +++ b/contrib/android/config/android.h @@ -40,6 +40,8 @@ #define HAVE_CHOWN 1 #define HAVE_CHROOT 1 +#define HAVE_CLOSEFROM 1 +#define HAVE_CLOSE_RANGE 1 #define HAVE_CTIME_R 1 #define HAVE_CTYPE_H 1 #define HAVE_DECL_EXTATTR_NAMESPACE_USER 0 diff --git a/contrib/android/config/linux_host.h b/contrib/android/config/linux_host.h index f0f7ab39ca1..cc96e5efe3d 100644 --- a/contrib/android/config/linux_host.h +++ b/contrib/android/config/linux_host.h @@ -28,6 +28,8 @@ #define HAVE_CHOWN 1 #define HAVE_CHROOT 1 +#define HAVE_CLOSEFROM 1 +#define HAVE_CLOSE_RANGE 1 #define HAVE_CTIME_R 1 #define HAVE_CTYPE_H 1 #define HAVE_DECL_EXTATTR_NAMESPACE_USER 0 @@ -180,7 +182,7 @@ #define HAVE_WMEMCMP 1 #define HAVE_WMEMCPY 1 #define HAVE_ZLIB_H 1 -#define ICONV_CONST +#define ICONV_CONST #define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 #define SIZEOF_WCHAR_T 4 #define STDC_HEADERS 1 diff --git a/contrib/android/config/windows_host.h b/contrib/android/config/windows_host.h index 4754744d845..2e24be1d3d7 100644 --- a/contrib/android/config/windows_host.h +++ b/contrib/android/config/windows_host.h @@ -175,6 +175,12 @@ /* Define to 1 if you have the `chroot' function. */ /* #undef HAVE_CHROOT */ +/* Define to 1 if you have the `closefrom' function. */ +/* #undef HAVE_CLOSEFROM */ + +/* Define to 1 if you have the `close_range' function. */ +/* #undef HAVE_CLOSE_RANGE */ + /* Define to 1 if you have the header file. */ /* #undef HAVE_COPYFILE_H */ @@ -620,9 +626,6 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_PWD_H */ -/* Define to 1 if you have a POSIX compatible readdir_r */ -#define HAVE_READDIR_R 1 - /* Define to 1 if you have the `readlink' function. */ /* #undef HAVE_READLINK */ diff --git a/contrib/android/include/android_lf.h b/contrib/android/include/android_lf.h index 3c5475e355a..86d32e26baf 100644 --- a/contrib/android/include/android_lf.h +++ b/contrib/android/include/android_lf.h @@ -1,4 +1,4 @@ -/* +/* * Macros for file64 functions * * Android does not support the macro _FILE_OFFSET_BITS=64 @@ -19,7 +19,6 @@ #include //dirent.h -#define readdir_r readdir64_r #define readdir readdir64 #define dirent dirent64 //fcntl.h diff --git a/cpio/CMakeLists.txt b/cpio/CMakeLists.txt index 2fee053bd48..7678ed658ae 100644 --- a/cpio/CMakeLists.txt +++ b/cpio/CMakeLists.txt @@ -13,8 +13,8 @@ IF(ENABLE_CPIO) cpio.c cpio.h cpio_platform.h - ../libarchive_fe/err.c - ../libarchive_fe/err.h + ../libarchive_fe/lafe_err.c + ../libarchive_fe/lafe_err.h ../libarchive_fe/lafe_platform.h ../libarchive_fe/line_reader.c ../libarchive_fe/line_reader.h diff --git a/cpio/cmdline.c b/cpio/cmdline.c index c67519947db..db06c03c011 100644 --- a/cpio/cmdline.c +++ b/cpio/cmdline.c @@ -26,7 +26,7 @@ #endif #include "cpio.h" -#include "err.h" +#include "lafe_err.h" /* * Short options for cpio. Please keep this sorted. diff --git a/cpio/cpio.c b/cpio/cpio.c index 2bf1bfa2985..262db510568 100644 --- a/cpio/cpio.c +++ b/cpio/cpio.c @@ -60,7 +60,7 @@ #endif #include "cpio.h" -#include "err.h" +#include "lafe_err.h" #include "line_reader.h" #include "passphrase.h" @@ -124,13 +124,21 @@ main(int argc, char *argv[]) cpio->buff_size = sizeof(buff); -#if defined(HAVE_SIGACTION) && defined(SIGPIPE) - { /* Ignore SIGPIPE signals. */ +#if defined(HAVE_SIGACTION) + { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; +#ifdef SIGPIPE + /* Ignore SIGPIPE signals. */ sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); +#endif +#ifdef SIGCHLD + /* Do not ignore SIGCHLD. */ + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); +#endif } #endif diff --git a/cpio/cpio_windows.c b/cpio/cpio_windows.c index 267b379753d..144814186a1 100644 --- a/cpio/cpio_windows.c +++ b/cpio/cpio_windows.c @@ -24,7 +24,7 @@ #include #include "cpio.h" -#include "err.h" +#include "lafe_err.h" #define EPOC_TIME (116444736000000000ULL) diff --git a/cpio/test/CMakeLists.txt b/cpio/test/CMakeLists.txt index 2c530661cfa..fe6ab968d3d 100644 --- a/cpio/test/CMakeLists.txt +++ b/cpio/test/CMakeLists.txt @@ -9,7 +9,7 @@ IF(ENABLE_CPIO AND ENABLE_TEST) SET(bsdcpio_test_SOURCES ../cmdline.c - ../../libarchive_fe/err.c + ../../libarchive_fe/lafe_err.c ../../test_utils/test_utils.c ../../test_utils/test_main.c test.h diff --git a/cpio/test/test_owner_parse.c b/cpio/test/test_owner_parse.c index dfc78ca77ae..bd68f21cec9 100644 --- a/cpio/test/test_owner_parse.c +++ b/cpio/test/test_owner_parse.c @@ -7,7 +7,7 @@ #include "test.h" #include "../cpio.h" -#include "err.h" +#include "lafe_err.h" #if !defined(_WIN32) #define ROOT "root" diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt index fd997db4112..4fb917132ca 100644 --- a/libarchive/CMakeLists.txt +++ b/libarchive/CMakeLists.txt @@ -52,6 +52,7 @@ SET(libarchive_SOURCES archive_pathmatch.h archive_platform.h archive_platform_acl.h + archive_platform_stat.h archive_platform_xattr.h archive_ppmd_private.h archive_ppmd8.c @@ -253,6 +254,9 @@ IF(BUILD_SHARED_LIBS) SOVERSION ${SOVERSION} MACHO_COMPATIBILITY_VERSION ${MACHO_COMPATIBILITY_VERSION} MACHO_CURRENT_VERSION ${MACHO_CURRENT_VERSION}) + IF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT) + SET_PROPERTY(TARGET archive PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + ENDIF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT) ENDIF(BUILD_SHARED_LIBS) # archive_static is a static library @@ -261,15 +265,14 @@ TARGET_INCLUDE_DIRECTORIES(archive_static PUBLIC .) TARGET_LINK_LIBRARIES(archive_static ${ADDITIONAL_LIBS}) SET_TARGET_PROPERTIES(archive_static PROPERTIES COMPILE_DEFINITIONS LIBARCHIVE_STATIC) +IF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT) + SET_PROPERTY(TARGET archive_static PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +ENDIF(WIN32 AND MSVC AND MSVC_USE_STATIC_CRT) # On Posix systems, libarchive.so and libarchive.a can co-exist. IF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS) SET_TARGET_PROPERTIES(archive_static PROPERTIES OUTPUT_NAME archive) ENDIF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS) -if(NOT DEFINED CMAKE_INSTALL_LIBDIR) - set(CMAKE_INSTALL_LIBDIR "lib") -endif() - IF(ENABLE_INSTALL) # How to install the libraries IF(BUILD_SHARED_LIBS) diff --git a/libarchive/archive.h b/libarchive/archive.h index 002190a2466..98d7674e18f 100644 --- a/libarchive/archive.h +++ b/libarchive/archive.h @@ -34,7 +34,7 @@ * assert that ARCHIVE_VERSION_NUMBER >= 2012108. */ /* Note: Compiler will complain if this does not match archive_entry.h! */ -#define ARCHIVE_VERSION_NUMBER 3008001 +#define ARCHIVE_VERSION_NUMBER 3008002 #include #include /* for wchar_t */ @@ -177,7 +177,7 @@ __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_ONLY_STRING "3.8.1" +#define ARCHIVE_VERSION_ONLY_STRING "3.8.2" #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char * archive_version_string(void); diff --git a/libarchive/archive_acl.c b/libarchive/archive_acl.c index 9e71f5ee561..362e3308f43 100644 --- a/libarchive/archive_acl.c +++ b/libarchive/archive_acl.c @@ -270,6 +270,19 @@ acl_new_entry(struct archive_acl *acl, { struct archive_acl_entry *ap, *aq; + /* Reject an invalid type */ + switch (type) { + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + break; + default: + return (NULL); + } + /* Type argument must be a valid NFS4 or POSIX.1e type. * The type must agree with anything already set and * the permset must be compatible. */ @@ -822,6 +835,9 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, wname = NULL; id = -1; break; + default: + **wp = '\0'; + break; } *wp += wcslen(*wp); *(*wp)++ = L':'; @@ -878,6 +894,7 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, wcscpy(*wp, L"alarm"); break; default: + *(*wp) = L'\0'; break; } *wp += wcslen(*wp); @@ -1057,6 +1074,9 @@ append_entry(char **p, const char *prefix, int type, name = NULL; id = -1; break; + default: + **p = '\0'; + break; } *p += strlen(*p); *(*p)++ = ':'; @@ -1112,6 +1132,9 @@ append_entry(char **p, const char *prefix, int type, case ARCHIVE_ENTRY_ACL_TYPE_ALARM: strcpy(*p, "alarm"); break; + default: + *(*p) = '\0'; + break; } *p += strlen(*p); } diff --git a/libarchive/archive_check_magic.c b/libarchive/archive_check_magic.c index d12f0c496e2..6b8e0c5595f 100644 --- a/libarchive/archive_check_magic.c +++ b/libarchive/archive_check_magic.c @@ -30,6 +30,7 @@ #endif #include +#include #ifdef HAVE_STDLIB_H #include #endif @@ -54,8 +55,14 @@ errmsg(const char *m) while (s > 0) { written = write(2, m, s); - if (written <= 0) + if (written == 0) return; + if (written < 0) + { + if (errno == EINTR) + continue; + return; + } m += written; s -= written; } diff --git a/libarchive/archive_cryptor.c b/libarchive/archive_cryptor.c index 1825af4dc51..9f03f9ca6dd 100644 --- a/libarchive/archive_cryptor.c +++ b/libarchive/archive_cryptor.c @@ -151,7 +151,7 @@ pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt, (void)rounds; /* UNUSED */ (void)derived_key; /* UNUSED */ (void)derived_key_len; /* UNUSED */ - return -1; /* UNSUPPORTED */ + return CRYPTOR_STUB_FUNCTION; /* UNSUPPORTED */ } #endif @@ -439,14 +439,14 @@ aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) (void)ctx; /* UNUSED */ (void)key; /* UNUSED */ (void)key_len; /* UNUSED */ - return -1; + return CRYPTOR_STUB_FUNCTION; } static int aes_ctr_encrypt_counter(archive_crypto_ctx *ctx) { (void)ctx; /* UNUSED */ - return -1; + return CRYPTOR_STUB_FUNCTION; } static int @@ -469,7 +469,7 @@ aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in, (void)out; /* UNUSED */ (void)out_len; /* UNUSED */ aes_ctr_encrypt_counter(ctx); /* UNUSED */ /* Fix unused function warning */ - return -1; + return CRYPTOR_STUB_FUNCTION; } #else diff --git a/libarchive/archive_cryptor_private.h b/libarchive/archive_cryptor_private.h index 4b3c6c16143..1dbc5c17a01 100644 --- a/libarchive/archive_cryptor_private.h +++ b/libarchive/archive_cryptor_private.h @@ -43,7 +43,7 @@ int __libarchive_cryptor_build_hack(void); #ifdef __APPLE__ # include # if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 -# define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto +# define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto 1 # endif #endif @@ -144,9 +144,15 @@ typedef struct { #else +#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\ + defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\ + defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\ + defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\ + defined(ARCHIVE_CRYPTO_SHA512_WIN) #if defined(_WIN32) && !defined(__CYGWIN__) && !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA) #define ARCHIVE_CRYPTOR_USE_WINCRYPT 1 #endif +#endif #define AES_BLOCK_SIZE 16 #define AES_MAX_KEY_SIZE 32 @@ -172,6 +178,9 @@ typedef int archive_crypto_ctx; #define archive_encrypto_aes_ctr_release(ctx) \ __archive_cryptor.encrypto_aes_ctr_release(ctx) +/* Stub return value if no encryption support exists. */ +#define CRYPTOR_STUB_FUNCTION -2 + /* Minimal interface to cryptographic functionality for internal use in * libarchive */ struct archive_cryptor diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h index 2b917b3fde8..344f33bffac 100644 --- a/libarchive/archive_entry.h +++ b/libarchive/archive_entry.h @@ -28,7 +28,7 @@ #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3008001 +#define ARCHIVE_VERSION_NUMBER 3008002 /* * Note: archive_entry.h is for use outside of libarchive; the diff --git a/libarchive/archive_entry_paths.3 b/libarchive/archive_entry_paths.3 index 0f849c9ebb3..f739b172308 100644 --- a/libarchive/archive_entry_paths.3 +++ b/libarchive/archive_entry_paths.3 @@ -64,7 +64,7 @@ Streaming Archive Library (libarchive, -larchive) .Ft void .Fn archive_entry_copy_hardlink "struct archive_entry *a" "const char *path" .Ft void -.Fn archive_entry_copy_hardlink_w "struct archive_entry *a "const wchar_t *path" +.Fn archive_entry_copy_hardlink_w "struct archive_entry *a" "const wchar_t *path" .Ft int .Fn archive_entry_update_hardlink_utf8 "struct archive_entry *a" "const char *path" .Ft void diff --git a/libarchive/archive_entry_stat.c b/libarchive/archive_entry_stat.c index c4906838ed0..345d3d29b2f 100644 --- a/libarchive/archive_entry_stat.c +++ b/libarchive/archive_entry_stat.c @@ -38,6 +38,7 @@ const struct stat * archive_entry_stat(struct archive_entry *entry) { + int64_t size; struct stat *st; if (entry->stat == NULL) { entry->stat = calloc(1, sizeof(*st)); @@ -74,7 +75,10 @@ archive_entry_stat(struct archive_entry *entry) st->st_ino = (ino_t)archive_entry_ino64(entry); st->st_nlink = archive_entry_nlink(entry); st->st_rdev = archive_entry_rdev(entry); - st->st_size = (off_t)archive_entry_size(entry); + size = archive_entry_size(entry); + st->st_size = (off_t)size; + if (st->st_size < 0 || (int64_t)st->st_size != size) + st->st_size = 0; st->st_mode = archive_entry_mode(entry); /* diff --git a/libarchive/archive_parse_date.c b/libarchive/archive_parse_date.c index cda0b11a555..d9e968387d3 100644 --- a/libarchive/archive_parse_date.c +++ b/libarchive/archive_parse_date.c @@ -703,9 +703,7 @@ Convert(time_t Month, time_t Day, time_t Year, Year += 1900; DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 29 : 28; - /* Checking for 2038 bogusly assumes that time_t is 32 bits. But - I'm too lazy to try to check for time_t overflow in another way. */ - if (Year < EPOCH || Year >= 2038 + if (Year < EPOCH || (sizeof(time_t) <= 4 && Year >= 2038) || Month < 1 || Month > 12 /* Lint fluff: "conversion from long may lose accuracy" */ || Day < 1 || Day > DaysInMonth[(int)--Month] diff --git a/libarchive/archive_platform.h b/libarchive/archive_platform.h index f30df1104c8..33dc5582b7e 100644 --- a/libarchive/archive_platform.h +++ b/libarchive/archive_platform.h @@ -183,16 +183,6 @@ #define CAN_RESTORE_METADATA_FD #endif -/* - * glibc 2.24 deprecates readdir_r - * bionic c deprecates readdir_r too - */ -#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)) && (!defined(__ANDROID__)) -#define USE_READDIR_R 1 -#else -#undef USE_READDIR_R -#endif - /* Set up defaults for internal error codes. */ #ifndef ARCHIVE_ERRNO_FILE_FORMAT #if HAVE_EFTYPE diff --git a/libarchive/archive_platform_stat.h b/libarchive/archive_platform_stat.h new file mode 100644 index 00000000000..5432b2f6433 --- /dev/null +++ b/libarchive/archive_platform_stat.h @@ -0,0 +1,45 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Tobias Stoeckmann + * All rights reserved. + */ + +/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */ + +#ifndef ARCHIVE_PLATFORM_STAT_H_INCLUDED +#define ARCHIVE_PLATFORM_STAT_H_INCLUDED + +#ifndef __LIBARCHIVE_BUILD +#error This header is only to be used internally to libarchive. +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +/* We use _lseeki64() on Windows. */ +typedef int64_t la_seek_t; + +struct la_seek_stat { + int64_t st_mtime; + ino_t st_ino; + unsigned short st_mode; + uint32_t st_nlink; + gid_t st_gid; + la_seek_t st_size; + uid_t st_uid; + dev_t st_dev; + dev_t st_rdev; +}; +typedef struct la_seek_stat la_seek_stat_t; + +#define la_seek_fstat(fd, st) __la_seek_fstat((fd), (st)) +#define la_seek_stat(fd, st) __la_seek_stat((fd), (st)) + +#else +typedef off_t la_seek_t; +typedef struct stat la_seek_stat_t; + +#define la_seek_fstat(fd, st) fstat((fd), (st)) +#define la_seek_stat(fd, st) stat((fd), (st)) +#endif + +#endif /* !ARCHIVE_PLATFORM_STAT_H_INCLUDED */ diff --git a/libarchive/archive_private.h b/libarchive/archive_private.h index 050fc63c0b2..3a926c6886a 100644 --- a/libarchive/archive_private.h +++ b/libarchive/archive_private.h @@ -158,6 +158,7 @@ int __archive_check_magic(struct archive *, unsigned int magic, __LA_NORETURN void __archive_errx(int retvalue, const char *msg); void __archive_ensure_cloexec_flag(int fd); +int __archive_get_tempdir(struct archive_string *); int __archive_mktemp(const char *tmpdir); #if defined(_WIN32) && !defined(__CYGWIN__) int __archive_mkstemp(wchar_t *templates); diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index 50db8701770..c9b9d598151 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -575,8 +575,7 @@ choose_filters(struct archive_read *a) return (ARCHIVE_OK); } - filter - = calloc(1, sizeof(*filter)); + filter = calloc(1, sizeof(*filter)); if (filter == NULL) return (ARCHIVE_FATAL); filter->bidder = best_bidder; @@ -834,7 +833,9 @@ archive_read_data(struct archive *_a, void *buff, size_t s) r = archive_read_data_block(a, &read_buf, &a->read_data_remaining, &a->read_data_offset); a->read_data_block = read_buf; - if (r == ARCHIVE_EOF) + if (r == ARCHIVE_EOF && + a->read_data_offset == a->read_data_output_offset && + a->read_data_remaining == 0) return (bytes_read); /* * Error codes are all negative, so the status diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c index 19d049770b7..42af4034b07 100644 --- a/libarchive/archive_read_disk_entry_from_file.c +++ b/libarchive/archive_read_disk_entry_from_file.c @@ -338,7 +338,7 @@ setup_mac_metadata(struct archive_read_disk *a, int ret = ARCHIVE_OK; void *buff = NULL; int have_attrs; - const char *name, *tempdir; + const char *name; struct archive_string tempfile; (void)fd; /* UNUSED */ @@ -357,13 +357,11 @@ setup_mac_metadata(struct archive_read_disk *a, if (have_attrs == 0) return (ARCHIVE_OK); - tempdir = NULL; - if (issetugid() == 0) - tempdir = getenv("TMPDIR"); - if (tempdir == NULL) - tempdir = _PATH_TMP; archive_string_init(&tempfile); - archive_strcpy(&tempfile, tempdir); + if (__archive_get_tempdir(&tempfile) != ARCHIVE_OK) { + ret = ARCHIVE_WARN; + goto cleanup; + } archive_strcat(&tempfile, "tar.md.XXXXXX"); tempfd = mkstemp(tempfile.s); if (tempfd < 0) { diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c index a7a98e9cb1c..54a8e66188f 100644 --- a/libarchive/archive_read_disk_posix.c +++ b/libarchive/archive_read_disk_posix.c @@ -168,9 +168,6 @@ struct filesystem { int synthetic; int remote; int noatime; -#if defined(USE_READDIR_R) - size_t name_max; -#endif long incr_xfer_size; long max_xfer_size; long min_xfer_size; @@ -203,10 +200,6 @@ struct tree { DIR *d; #define INVALID_DIR_HANDLE NULL struct dirent *de; -#if defined(USE_READDIR_R) - struct dirent *dirent; - size_t dirent_allocated; -#endif int flags; int visit_type; /* Error code from last failed operation. */ @@ -869,7 +862,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, tree_enter_initial_dir(t); return (ARCHIVE_FATAL); case TREE_ERROR_DIR: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + archive_set_error(&a->archive, t->tree_errno, "%s: Couldn't visit directory", tree_current_path(t)); tree_enter_initial_dir(t); @@ -1578,9 +1571,6 @@ setup_current_filesystem(struct archive_read_disk *a) # endif #endif int r, xr = 0; -#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX) - long nm; -#endif t->current_filesystem->synthetic = -1; t->current_filesystem->remote = -1; @@ -1647,35 +1637,6 @@ setup_current_filesystem(struct archive_read_disk *a) #endif t->current_filesystem->noatime = 0; -#if defined(USE_READDIR_R) - /* Set maximum filename length. */ -#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX) - t->current_filesystem->name_max = sfs.f_namemax; -#else -# if defined(_PC_NAME_MAX) - /* Mac OS X does not have f_namemax in struct statfs. */ - if (tree_current_is_symblic_link_target(t)) { - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); - } else - nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); -# else - nm = -1; -# endif - if (nm == -1) - t->current_filesystem->name_max = NAME_MAX; - 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); } @@ -1863,19 +1824,6 @@ setup_current_filesystem(struct archive_read_disk *a) #endif t->current_filesystem->noatime = 0; -#if defined(USE_READDIR_R) - /* Set maximum filename length. */ -#if defined(HAVE_STATVFS) - t->current_filesystem->name_max = svfs.f_namemax; -#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); } @@ -1953,15 +1901,6 @@ setup_current_filesystem(struct archive_read_disk *a) #endif t->current_filesystem->noatime = 0; -#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); } @@ -1975,9 +1914,6 @@ static int setup_current_filesystem(struct archive_read_disk *a) { struct tree *t = a->tree; -#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R) - long nm; -#endif t->current_filesystem->synthetic = -1;/* Not supported */ t->current_filesystem->remote = -1;/* Not supported */ t->current_filesystem->noatime = 0; @@ -1987,40 +1923,6 @@ setup_current_filesystem(struct archive_read_disk *a) t->current_filesystem->min_xfer_size = -1; t->current_filesystem->incr_xfer_size = -1; -#if defined(USE_READDIR_R) - /* Set maximum filename length. */ -# if defined(_PC_NAME_MAX) - if (tree_current_is_symblic_link_target(t)) { - if (tree_enter_working_dir(t) != 0) { - archive_set_error(&a->archive, errno, "fchdir failed"); - return (ARCHIVE_FAILED); - } - nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX); - } else - nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX); - if (nm == -1) -# endif /* _PC_NAME_MAX */ - /* - * Some systems (HP-UX or others?) incorrectly defined - * NAME_MAX macro to be a smaller value. - */ -# if defined(NAME_MAX) && NAME_MAX >= 255 - t->current_filesystem->name_max = NAME_MAX; -# else - /* No way to get a trusted value of maximum filename - * length. */ - t->current_filesystem->name_max = PATH_MAX; -# endif /* NAME_MAX */ -# if defined(_PC_NAME_MAX) - 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); } @@ -2112,8 +2014,11 @@ tree_dup(int fd) } #endif /* F_DUPFD_CLOEXEC */ new_fd = dup(fd); - __archive_ensure_cloexec_flag(new_fd); - return (new_fd); + if (new_fd != -1) { + __archive_ensure_cloexec_flag(new_fd); + return (new_fd); + } + return (-1); } /* @@ -2235,11 +2140,16 @@ tree_reopen(struct tree *t, const char *path, int restore_time) * so try again for execute. The consequences of not opening this are * unhelpful and unnecessary errors later. */ - if (t->initial_dir_fd < 0) + if (t->initial_dir_fd < 0) { t->initial_dir_fd = open(".", o_flag | O_CLOEXEC); + if (t->initial_dir_fd < 0) + return NULL; + } #endif __archive_ensure_cloexec_flag(t->initial_dir_fd); t->working_dir_fd = tree_dup(t->initial_dir_fd); + if (t->working_dir_fd < 0) + return NULL; return (t); } @@ -2449,12 +2359,11 @@ tree_dir_next_posix(struct tree *t) size_t namelen; if (t->d == NULL) { -#if defined(USE_READDIR_R) - size_t dirent_size; -#endif #if defined(HAVE_FDOPENDIR) - t->d = fdopendir(tree_dup(t->working_dir_fd)); + int fd = tree_dup(t->working_dir_fd); + if (fd != -1) + t->d = fdopendir(fd); #else /* HAVE_FDOPENDIR */ if (tree_enter_working_dir(t) == 0) { t->d = opendir("."); @@ -2470,45 +2379,12 @@ tree_dir_next_posix(struct tree *t) t->visit_type = r != 0 ? r : TREE_ERROR_DIR; return (t->visit_type); } -#if defined(USE_READDIR_R) - dirent_size = offsetof(struct dirent, d_name) + - t->filesystem_table[t->current->filesystem_id].name_max + 1; - if (t->dirent == NULL || t->dirent_allocated < dirent_size) { - free(t->dirent); - t->dirent = malloc(dirent_size); - if (t->dirent == NULL) { - closedir(t->d); - t->d = INVALID_DIR_HANDLE; - (void)tree_ascend(t); - tree_pop(t); - t->tree_errno = ENOMEM; - t->visit_type = TREE_ERROR_DIR; - return (t->visit_type); - } - t->dirent_allocated = dirent_size; - } -#endif /* USE_READDIR_R */ } for (;;) { errno = 0; -#if defined(USE_READDIR_R) - r = readdir_r(t->d, t->dirent, &t->de); -#ifdef _AIX - /* Note: According to the man page, return value 9 indicates - * that the readdir_r was not successful and the error code - * is set to the global errno variable. And then if the end - * of directory entries was reached, the return value is 9 - * and the third parameter is set to NULL and errno is - * unchanged. */ - if (r == 9) - r = errno; -#endif /* _AIX */ - if (r != 0 || t->de == NULL) { -#else t->de = readdir(t->d); if (t->de == NULL) { r = errno; -#endif closedir(t->d); t->d = INVALID_DIR_HANDLE; if (r != 0) { @@ -2747,9 +2623,6 @@ tree_free(struct tree *t) if (t == NULL) return; archive_string_free(&t->path); -#if defined(USE_READDIR_R) - free(t->dirent); -#endif free(t->sparse_list); for (i = 0; i < t->max_filesystem_id; i++) free(t->filesystem_table[i].allocation_ptr); diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c index dc7c9e52c6f..c85a62a3e2d 100644 --- a/libarchive/archive_read_open_fd.c +++ b/libarchive/archive_read_open_fd.c @@ -48,6 +48,7 @@ #endif #include "archive.h" +#include "archive_platform_stat.h" struct read_fd_data { int fd; @@ -65,12 +66,12 @@ static int64_t file_skip(struct archive *, void *, int64_t request); int archive_read_open_fd(struct archive *a, int fd, size_t block_size) { - struct stat st; + la_seek_stat_t st; struct read_fd_data *mine; void *b; archive_clear_error(a); - if (fstat(fd, &st) != 0) { + if (la_seek_fstat(fd, &st) != 0) { archive_set_error(a, errno, "Can't stat fd %d", fd); return (ARCHIVE_FATAL); } @@ -133,7 +134,7 @@ static int64_t file_skip(struct archive *a, void *client_data, int64_t request) { struct read_fd_data *mine = (struct read_fd_data *)client_data; - off_t skip = (off_t)request; + la_seek_t skip = (la_seek_t)request; int64_t old_offset, new_offset; int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */ @@ -149,7 +150,8 @@ file_skip(struct archive *a, void *client_data, int64_t request) } /* Reduce 'skip' to the next smallest multiple of block_size */ - skip = (off_t)(((int64_t)skip / mine->block_size) * mine->block_size); + skip = (la_seek_t)(((int64_t)skip / mine->block_size) * mine->block_size); + if (skip == 0) return (0); @@ -185,27 +187,28 @@ static int64_t file_seek(struct archive *a, void *client_data, int64_t request, int whence) { struct read_fd_data *mine = (struct read_fd_data *)client_data; - off_t seek = (off_t)request; + la_seek_t seek = (la_seek_t)request; int64_t r; int seek_bits = sizeof(seek) * 8 - 1; /* off_t is a signed type. */ /* We use off_t here because lseek() is declared that way. */ - /* Reduce a request that would overflow the 'seek' variable. */ + /* Do not perform a seek which cannot be fulfilled. */ if (sizeof(request) > sizeof(seek)) { const int64_t max_seek = (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; const int64_t min_seek = ~max_seek; - if (request > max_seek) - seek = (off_t)max_seek; - else if (request < min_seek) - seek = (off_t)min_seek; + if (request < min_seek || request > max_seek) { + errno = EOVERFLOW; + goto err; + } } r = lseek(mine->fd, seek, whence); if (r >= 0) return r; +err: if (errno == ESPIPE) { archive_set_error(a, errno, "A file descriptor(%d) is not seekable(PIPE)", mine->fd); diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c index 742923abbee..6ca2ff191aa 100644 --- a/libarchive/archive_read_open_file.c +++ b/libarchive/archive_read_open_file.c @@ -48,6 +48,7 @@ #endif #include "archive.h" +#include "archive_platform_stat.h" struct read_FILE_data { FILE *f; @@ -65,7 +66,7 @@ static int64_t FILE_skip(struct archive *, void *, int64_t); int archive_read_open_FILE(struct archive *a, FILE *f) { - struct stat st; + la_seek_stat_t st; struct read_FILE_data *mine; size_t block_size = 128 * 1024; void *b; @@ -88,7 +89,7 @@ archive_read_open_FILE(struct archive *a, FILE *f) * streams that don't support fileno()). As a result, fileno() * should be used cautiously.) */ - if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) { + if (la_seek_fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) { archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); /* Enable the seek optimization only for regular files. */ mine->can_skip = 1; @@ -205,15 +206,15 @@ FILE_seek(struct archive *a, void *client_data, int64_t request, int whence) int seek_bits = sizeof(seek) * 8 - 1; (void)a; /* UNUSED */ - /* Reduce a request that would overflow the 'seek' variable. */ + /* Do not perform a seek which cannot be fulfilled. */ if (sizeof(request) > sizeof(seek)) { const int64_t max_seek = (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; const int64_t min_seek = ~max_seek; - if (request > max_seek) - seek = max_seek; - else if (request < min_seek) - seek = min_seek; + if (request < min_seek || request > max_seek) { + errno = EOVERFLOW; + goto err; + } } #ifdef __ANDROID__ @@ -236,6 +237,7 @@ FILE_seek(struct archive *a, void *client_data, int64_t request, int whence) } #endif /* If we arrive here, the input is corrupted or truncated so fail. */ +err: archive_set_error(a, errno, "Error seeking in FILE* pointer"); return (ARCHIVE_FATAL); } diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c index 5f5b3f1f725..a910eefcbfd 100644 --- a/libarchive/archive_read_open_filename.c +++ b/libarchive/archive_read_open_filename.c @@ -59,6 +59,7 @@ #endif #include "archive.h" +#include "archive_platform_stat.h" #include "archive_private.h" #include "archive_string.h" @@ -136,8 +137,10 @@ archive_read_open_filenames(struct archive *a, const char **filenames, mine->filename_type = FNT_STDIN; } else mine->filename_type = FNT_MBS; - if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) + if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) { + free(mine); return (ARCHIVE_FATAL); + } if (filenames == NULL) break; filename = *(filenames++); @@ -216,8 +219,10 @@ archive_read_open_filenames_w(struct archive *a, const wchar_t **wfilenames, archive_string_free(&fn); #endif } - if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) + if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK)) { + free(mine); return (ARCHIVE_FATAL); + } if (wfilenames == NULL) break; wfilename = *(wfilenames++); @@ -248,7 +253,7 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename, static int file_open(struct archive *a, void *client_data) { - struct stat st; + la_seek_stat_t st; struct read_file_data *mine = (struct read_file_data *)client_data; void *buffer; const char *filename = NULL; @@ -313,7 +318,7 @@ file_open(struct archive *a, void *client_data) goto fail; #endif } - if (fstat(fd, &st) != 0) { + if (la_seek_fstat(fd, &st) != 0) { #if defined(_WIN32) && !defined(__CYGWIN__) if (mine->filename_type == FNT_WCS) archive_set_error(a, errno, "Can't stat '%ls'", @@ -482,10 +487,11 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request) struct read_file_data *mine = (struct read_file_data *)client_data; #if defined(_WIN32) && !defined(__CYGWIN__) /* We use _lseeki64() on Windows. */ - int64_t old_offset, new_offset, skip = request; + int64_t old_offset, new_offset; #else - off_t old_offset, new_offset, skip = (off_t)request; + off_t old_offset, new_offset; #endif + la_seek_t skip = (la_seek_t)request; int skip_bits = sizeof(skip) * 8 - 1; /* We use off_t here because lseek() is declared that way. */ @@ -552,21 +558,21 @@ static int64_t file_seek(struct archive *a, void *client_data, int64_t request, int whence) { struct read_file_data *mine = (struct read_file_data *)client_data; - off_t seek = (off_t)request; + la_seek_t seek = (la_seek_t)request; int64_t r; int seek_bits = sizeof(seek) * 8 - 1; /* We use off_t here because lseek() is declared that way. */ - /* Reduce a request that would overflow the 'seek' variable. */ + /* Do not perform a seek which cannot be fulfilled. */ if (sizeof(request) > sizeof(seek)) { const int64_t max_seek = (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; const int64_t min_seek = ~max_seek; - if (request > max_seek) - seek = (off_t)max_seek; - else if (request < min_seek) - seek = (off_t)min_seek; + if (request < min_seek || request > max_seek) { + errno = EOVERFLOW; + goto err; + } } r = lseek(mine->fd, seek, whence); @@ -574,6 +580,7 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence) return r; /* If the input is corrupted or truncated, fail. */ +err: if (mine->filename_type == FNT_STDIN) archive_set_error(a, errno, "Error seeking in stdin"); else if (mine->filename_type == FNT_MBS) diff --git a/libarchive/archive_read_set_format.c b/libarchive/archive_read_set_format.c index c74361b20c1..552ab12d2f9 100644 --- a/libarchive/archive_read_set_format.c +++ b/libarchive/archive_read_set_format.c @@ -37,7 +37,7 @@ int archive_read_set_format(struct archive *_a, int code) { int r1, r2, slots, i; - char str[10]; + const char *str; struct archive_read *a = (struct archive_read *)_a; if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK)) @@ -49,49 +49,49 @@ archive_read_set_format(struct archive *_a, int code) switch (code & ARCHIVE_FORMAT_BASE_MASK) { case ARCHIVE_FORMAT_7ZIP: - strcpy(str, "7zip"); + str = "7zip"; break; case ARCHIVE_FORMAT_AR: - strcpy(str, "ar"); + str = "ar"; break; case ARCHIVE_FORMAT_CAB: - strcpy(str, "cab"); + str = "cab"; break; case ARCHIVE_FORMAT_CPIO: - strcpy(str, "cpio"); + str = "cpio"; break; case ARCHIVE_FORMAT_EMPTY: - strcpy(str, "empty"); + str = "empty"; break; case ARCHIVE_FORMAT_ISO9660: - strcpy(str, "iso9660"); + str = "iso9660"; break; case ARCHIVE_FORMAT_LHA: - strcpy(str, "lha"); + str = "lha"; break; case ARCHIVE_FORMAT_MTREE: - strcpy(str, "mtree"); + str = "mtree"; break; case ARCHIVE_FORMAT_RAR: - strcpy(str, "rar"); + str = "rar"; break; case ARCHIVE_FORMAT_RAR_V5: - strcpy(str, "rar5"); + str = "rar5"; break; case ARCHIVE_FORMAT_RAW: - strcpy(str, "raw"); + str = "raw"; break; case ARCHIVE_FORMAT_TAR: - strcpy(str, "tar"); + str = "tar"; break; case ARCHIVE_FORMAT_WARC: - strcpy(str, "warc"); + str = "warc"; break; case ARCHIVE_FORMAT_XAR: - strcpy(str, "xar"); + str = "xar"; break; case ARCHIVE_FORMAT_ZIP: - strcpy(str, "zip"); + str = "zip"; break; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, diff --git a/libarchive/archive_read_support_filter_program.c b/libarchive/archive_read_support_filter_program.c index 9e825223b26..2c8e45302d8 100644 --- a/libarchive/archive_read_support_filter_program.c +++ b/libarchive/archive_read_support_filter_program.c @@ -110,7 +110,7 @@ struct program_filter { pid_t child; #endif int exit_status; - int waitpid_return; + pid_t waitpid_return; int child_stdin, child_stdout; char *out_buf; @@ -242,16 +242,13 @@ child_stop(struct archive_read_filter *self, struct program_filter *state) state->waitpid_return = waitpid(state->child, &state->exit_status, 0); } while (state->waitpid_return == -1 && errno == EINTR); -#if defined(_WIN32) && !defined(__CYGWIN__) - CloseHandle(state->child); -#endif state->child = 0; } if (state->waitpid_return < 0) { /* waitpid() failed? This is ugly. */ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Child process exited badly"); + "Error closing child process"); return (ARCHIVE_WARN); } diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index f273f84be52..59546273310 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -80,7 +80,7 @@ /* * ELF format */ -#define ELF_HDR_MIN_LEN 0x34 +#define ELF_HDR_MIN_LEN 0x3f #define ELF_HDR_EI_CLASS_OFFSET 0x04 #define ELF_HDR_EI_DATA_OFFSET 0x05 @@ -811,6 +811,8 @@ find_elf_data_sec(struct archive_read *a) strtab_size = (*dec32)( h + e_shstrndx * e_shentsize + 0x14); } + if (strtab_size < 6 || strtab_size > SIZE_MAX) + break; /* * Read the STRTAB section to find the .data offset @@ -1391,7 +1393,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip, * size to liblzma when using lzma_raw_decoder() liblzma * could correctly deal with BCJ+LZMA. But unfortunately * there is no way to do that. - * Discussion about this can be found at XZ Utils forum. + * + * Reference: https://web.archive.org/web/20240405171610/https://www.mail-archive.com/xz-devel@tukaani.org/msg00373.html */ if (coder2 != NULL) { zip->codec2 = coder2->codec; diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c index ba0e49de240..ded13bee79a 100644 --- a/libarchive/archive_read_support_format_mtree.c +++ b/libarchive/archive_read_support_format_mtree.c @@ -51,6 +51,7 @@ #include "archive.h" #include "archive_entry.h" #include "archive_entry_private.h" +#include "archive_platform_stat.h" #include "archive_private.h" #include "archive_rb.h" #include "archive_read_private.h" @@ -1073,6 +1074,8 @@ read_mtree(struct archive_read *a, struct mtree *mtree) /* Non-printable characters are not allowed */ for (s = p;s < p + len - 1; s++) { if (!isprint((unsigned char)*s) && *s != '\t') { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Non-printable character 0x%02X", (unsigned char)(*s)); r = ARCHIVE_FATAL; break; } @@ -1175,7 +1178,7 @@ parse_file(struct archive_read *a, struct archive_entry *entry, struct mtree *mtree, struct mtree_entry *mentry, int *use_next) { const char *path; - struct stat st_storage, *st; + la_seek_stat_t st_storage, *st; struct mtree_entry *mp; struct archive_entry *sparse_entry; int r = ARCHIVE_OK, r1, parsed_kws; @@ -1251,7 +1254,7 @@ parse_file(struct archive_read *a, struct archive_entry *entry, archive_entry_filetype(entry) == AE_IFDIR) { mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC); __archive_ensure_cloexec_flag(mtree->fd); - if (mtree->fd == -1 && ( + if (mtree->fd < 0 && ( #if defined(_WIN32) && !defined(__CYGWIN__) /* * On Windows, attempting to open a file with an @@ -1270,7 +1273,7 @@ parse_file(struct archive_read *a, struct archive_entry *entry, st = &st_storage; if (mtree->fd >= 0) { - if (fstat(mtree->fd, st) == -1) { + if (la_seek_fstat(mtree->fd, st) == -1) { archive_set_error(&a->archive, errno, "Could not fstat %s", path); r = ARCHIVE_WARN; @@ -1283,7 +1286,7 @@ parse_file(struct archive_read *a, struct archive_entry *entry, #ifdef HAVE_LSTAT else if (lstat(path, st) == -1) #else - else if (la_stat(path, st) == -1) + else if (la_seek_stat(path, st) == -1) #endif { st = NULL; @@ -2130,6 +2133,13 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, for (u = mtree->line.s + find_off; *u; ++u) { if (u[0] == '\n') { /* Ends with unescaped newline. */ + /* Check if preceded by '\r' for CRLF handling */ + if (u > mtree->line.s && u[-1] == '\r') { + /* CRLF ending - remove the '\r' */ + u[-1] = '\n'; + u[0] = '\0'; + total_size--; + } *start = mtree->line.s; return total_size; } else if (u[0] == '#') { @@ -2144,6 +2154,11 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, total_size -= 2; mtree->line.s[total_size] = '\0'; break; + } else if (u[1] == '\r' && u[2] == '\n') { + /* Trim escaped CRLF. */ + total_size -= 3; + mtree->line.s[total_size] = '\0'; + break; } else if (u[1] != '\0') { /* Skip the two-char escape sequence */ ++u; diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c index 923ae5c65e1..9b401c00ba3 100644 --- a/libarchive/archive_read_support_format_rar.c +++ b/libarchive/archive_read_support_format_rar.c @@ -1117,8 +1117,6 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, if (rar->entry_eof || rar->offset_seek >= rar->unp_size) { *size = 0; *offset = rar->offset; - if (*offset < rar->unp_size) - *offset = rar->unp_size; return (ARCHIVE_EOF); } @@ -1455,7 +1453,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, return (ARCHIVE_FATAL); #endif } - /* If no CRC error, Go on parsing File Header. */ + /* If no CRC error, go on parsing File Header. */ p = h; endp = p + header_size - 7; memcpy(&file_header, p, sizeof(file_header)); @@ -2368,8 +2366,8 @@ parse_codes(struct archive_read *a) return (ARCHIVE_FATAL); } - /* Make sure ppmd7_contest is freed before Ppmd7_Construct - * because reading a broken file cause this abnormal sequence. */ + /* Make sure ppmd7_context is freed before Ppmd7_Construct + * because reading a broken file causes this abnormal sequence. */ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context); rar->bytein.a = a; diff --git a/libarchive/archive_read_support_format_rar5.c b/libarchive/archive_read_support_format_rar5.c index 48dde0c2e81..17e501e02e9 100644 --- a/libarchive/archive_read_support_format_rar5.c +++ b/libarchive/archive_read_support_format_rar5.c @@ -1619,10 +1619,13 @@ static int process_head_file_extra(struct archive_read* a, { uint64_t extra_field_size; uint64_t extra_field_id = 0; - int ret = ARCHIVE_FATAL; uint64_t var_size; while(extra_data_size > 0) { + /* Make sure we won't fail if the file declares only unsupported + attributes. */ + int ret = ARCHIVE_OK; + if(!read_var(a, &extra_field_size, &var_size)) return ARCHIVE_EOF; @@ -1675,12 +1678,53 @@ static int process_head_file_extra(struct archive_read* a, if (ARCHIVE_OK != consume(a, extra_field_size)) { return ARCHIVE_EOF; } + + /* Don't fail on unsupported attribute -- we've handled it + by skipping over it. */ + ret = ARCHIVE_OK; + } + + if (ret != ARCHIVE_OK) { + /* Forward any errors signalled by the attribute parsing + functions. */ + return ret; } } - if(ret != ARCHIVE_OK) { - /* Attribute not implemented. */ - return ret; + if (extra_data_size != 0) { + /* We didn't skip everything, or we skipped too much; either way, + there's an error in this parsing function. */ + + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "unsupported structure of file header extra data"); + return ARCHIVE_FATAL; + } + + return ARCHIVE_OK; +} + +static int file_entry_sanity_checks(struct archive_read* a, + size_t block_flags, uint8_t is_dir, uint64_t unpacked_size, + size_t packed_size) +{ + if (is_dir) { + const int declares_data_size = + (int) (unpacked_size != 0 || packed_size != 0); + + /* FILE entries for directories still declare HFL_DATA in block flags, + even though attaching data to such blocks doesn't make much sense. */ + if (declares_data_size) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "directory entries cannot have any data"); + return ARCHIVE_FATAL; + } + } else { + const int declares_hfl_data = (int) ((block_flags & HFL_DATA) != 0); + if (!declares_hfl_data) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "no data found in file/service block"); + return ARCHIVE_FATAL; + } } return ARCHIVE_OK; @@ -1701,6 +1745,7 @@ static int process_head_file(struct archive_read* a, struct rar5* rar, int c_method = 0, c_version = 0; char name_utf8_buf[MAX_NAME_IN_BYTES]; const uint8_t* p; + int sanity_ret; enum FILE_FLAGS { DIRECTORY = 0x0001, UTIME = 0x0002, CRC32 = 0x0004, @@ -1744,10 +1789,6 @@ static int process_head_file(struct archive_read* a, struct rar5* rar, rar->file.bytes_remaining = data_size; } else { rar->file.bytes_remaining = 0; - - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "no data found in file/service block"); - return ARCHIVE_FATAL; } if(!read_var_sized(a, &file_flags, NULL)) @@ -1764,6 +1805,13 @@ static int process_head_file(struct archive_read* a, struct rar5* rar, rar->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0); + sanity_ret = file_entry_sanity_checks(a, block_flags, rar->file.dir, + unpacked_size, data_size); + + if (sanity_ret != ARCHIVE_OK) { + return sanity_ret; + } + if(!read_var_sized(a, &file_attr, NULL)) return ARCHIVE_EOF; @@ -4163,7 +4211,7 @@ static int rar5_read_data(struct archive_read *a, const void **buff, * it's impossible to perform any decompression. */ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Can't decompress an entry marked as a directory"); - return ARCHIVE_FAILED; + return ARCHIVE_FATAL; } if(!rar->skip_mode && (rar->cstate.last_write_ptr > rar->file.unpacked_size)) { diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index 0c87bc6d732..eeb2c725f6e 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -233,7 +233,7 @@ static int tar_read_header(struct archive_read *, struct tar *, struct archive_entry *, int64_t *); static int tohex(int c); static char *url_decode(const char *, size_t); -static void tar_flush_unconsumed(struct archive_read *, int64_t *); +static int tar_flush_unconsumed(struct archive_read *, int64_t *); /* Sanity limits: These numbers should be low enough to * prevent a maliciously-crafted archive from forcing us to @@ -477,7 +477,7 @@ archive_read_format_tar_options(struct archive_read *a, * how much unconsumed data we have floating around, and to consume * anything outstanding since we're going to do read_aheads */ -static void +static int tar_flush_unconsumed(struct archive_read *a, int64_t *unconsumed) { if (*unconsumed) { @@ -490,9 +490,13 @@ tar_flush_unconsumed(struct archive_read *a, int64_t *unconsumed) memset(data, 0xff, *unconsumed); } */ - __archive_read_consume(a, *unconsumed); + int64_t consumed = __archive_read_consume(a, *unconsumed); + if (consumed != *unconsumed) { + return (ARCHIVE_FATAL); + } *unconsumed = 0; } + return (ARCHIVE_OK); } /* @@ -750,7 +754,9 @@ tar_read_header(struct archive_read *a, struct tar *tar, /* Find the next valid header record. */ while (1) { - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } /* Read 512-byte header record */ h = __archive_read_ahead(a, 512, &bytes); @@ -796,7 +802,9 @@ tar_read_header(struct archive_read *a, struct tar *tar, /* This is NOT a null block, so it must be a valid header. */ if (!checksum(a, h)) { - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } archive_set_error(&a->archive, EINVAL, "Damaged tar archive (bad header checksum)"); /* If we've read some critical information (pax headers, etc) @@ -1236,7 +1244,7 @@ header_volume(struct archive_read *a, struct tar *tar, header = (const struct archive_entry_header_ustar *)h; size = tar_atol(header->size, sizeof(header->size)); - if (size > (int64_t)pathname_limit) { + if (size < 0 || size > (int64_t)pathname_limit) { return (ARCHIVE_FATAL); } to_consume = ((size + 511) & ~511); @@ -1255,13 +1263,15 @@ read_bytes_to_string(struct archive_read *a, const void *src; /* Fail if we can't make our buffer big enough. */ - if (archive_string_ensure(as, (size_t)size+1) == NULL) { + if (archive_string_ensure(as, size + 1) == NULL) { archive_set_error(&a->archive, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } /* Read the body into the string. */ src = __archive_read_ahead(a, size, NULL); @@ -1272,9 +1282,9 @@ read_bytes_to_string(struct archive_read *a, *unconsumed = 0; return (ARCHIVE_FATAL); } - memcpy(as->s, src, (size_t)size); + memcpy(as->s, src, size); as->s[size] = '\0'; - as->length = (size_t)size; + as->length = size; *unconsumed += size; return (ARCHIVE_OK); } @@ -1715,7 +1725,9 @@ read_mac_metadata_blob(struct archive_read *a, * Q: Is the above idea really possible? Even * when there are GNU or pax extension entries? */ - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } data = __archive_read_ahead(a, msize, NULL); if (data == NULL) { archive_set_error(&a->archive, EINVAL, @@ -1900,7 +1912,9 @@ header_pax_extension(struct archive_read *a, struct tar *tar, (long long)ext_size, (long long)ext_size_limit); return (ARCHIVE_WARN); } - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } /* Parse the size/name of each pax attribute in the body */ archive_string_init(&attr_name); @@ -1994,7 +2008,9 @@ header_pax_extension(struct archive_read *a, struct tar *tar, /* Consume size, name, and `=` */ *unconsumed += p - attr_start; - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } if (value_length == 0) { archive_set_error(&a->archive, EINVAL, @@ -2017,7 +2033,9 @@ header_pax_extension(struct archive_read *a, struct tar *tar, err = err_combine(err, r); /* Consume the `\n` that follows the pax attribute value. */ - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } p = __archive_read_ahead(a, 1, &did_read); if (p == NULL) { archive_set_error(&a->archive, EINVAL, @@ -2033,7 +2051,9 @@ header_pax_extension(struct archive_read *a, struct tar *tar, } ext_size -= 1; *unconsumed += 1; - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } } *unconsumed += ext_size + ext_padding; @@ -2290,7 +2310,9 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t * archive_string_init(&as); r = read_bytes_to_string(a, &as, value_length, &unconsumed); - tar_flush_unconsumed(a, &unconsumed); + if (tar_flush_unconsumed(a, &unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } if (r < ARCHIVE_OK) { archive_string_free(&as); *result = 0; @@ -2940,7 +2962,9 @@ header_gnutar(struct archive_read *a, struct tar *tar, /* Copy filename over (to ensure null termination). */ header = (const struct archive_entry_header_gnutar *)h; const char *existing_pathname = archive_entry_pathname(entry); - if (existing_pathname == NULL || existing_pathname[0] == '\0') { + const wchar_t *existing_wcs_pathname = archive_entry_pathname_w(entry); + if ((existing_pathname == NULL || existing_pathname[0] == '\0') + && (existing_wcs_pathname == NULL || existing_wcs_pathname[0] == L'\0')) { if (archive_entry_copy_pathname_l(entry, header->name, sizeof(header->name), tar->sconv) != 0) { err = set_conversion_failed_error(a, tar->sconv, "Pathname"); @@ -3093,7 +3117,9 @@ gnu_sparse_old_read(struct archive_read *a, struct tar *tar, return (ARCHIVE_OK); do { - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } data = __archive_read_ahead(a, 512, &bytes_read); if (data == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -3283,7 +3309,9 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, int64_t *unconsumed) return (ARCHIVE_FATAL); } /* Skip rest of block... */ - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } bytes_read = tar->entry_bytes_remaining - remaining; to_skip = 0x1ff & -bytes_read; /* Fail if tar->entry_bytes_remaing would get negative */ @@ -3509,7 +3537,9 @@ readline(struct archive_read *a, struct tar *tar, const char **start, const char *s; void *p; - tar_flush_unconsumed(a, unconsumed); + if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) { + return (ARCHIVE_FATAL); + } t = __archive_read_ahead(a, 1, &bytes_read); if (bytes_read <= 0 || t == NULL) diff --git a/libarchive/archive_read_support_format_warc.c b/libarchive/archive_read_support_format_warc.c index 696f959c341..d8f188cf0b4 100644 --- a/libarchive/archive_read_support_format_warc.c +++ b/libarchive/archive_read_support_format_warc.c @@ -405,7 +405,7 @@ _warc_read(struct archive_read *a, const void **buf, size_t *bsz, int64_t *off) /* it's our lucky day, no work, we can leave early */ *buf = NULL; *bsz = 0U; - *off = w->cntoff + 4U/*for \r\n\r\n separator*/; + *off = w->cntoff; w->unconsumed = 0U; return (ARCHIVE_EOF); } diff --git a/libarchive/archive_read_support_format_xar.c b/libarchive/archive_read_support_format_xar.c index b4e1192ef77..36b5ab3ae04 100644 --- a/libarchive/archive_read_support_format_xar.c +++ b/libarchive/archive_read_support_format_xar.c @@ -930,7 +930,7 @@ xar_read_data(struct archive_read *a, abort_read_data: *buff = NULL; *size = 0; - *offset = xar->total; + *offset = (int64_t)xar->entry_total; return (r); } diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index daf51933d68..9abd55709e3 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -3015,8 +3015,8 @@ init_WinZip_AES_decryption(struct archive_read *a) p, salt_len, 1000, derived_key, key_len * 2 + 2); if (r != 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Decryption is unsupported due to lack of " - "crypto library"); + r == CRYPTOR_STUB_FUNCTION ? "Decryption is unsupported due " + "to lack of crypto library" : "Failed to process passphrase"); return (ARCHIVE_FAILED); } diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 7437715f912..3bb978335eb 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -2015,7 +2015,7 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n, /* We must allocate memory even if there is no data for conversion * or copy. This simulates archive_string_append behavior. */ if (length == 0) { - int tn = 1; + size_t tn = 1; if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) tn = 2; if (archive_string_ensure(as, as->length + tn) == NULL) @@ -2752,7 +2752,8 @@ archive_string_append_unicode(struct archive_string *as, const void *_p, char *p, *endp; uint32_t uc; size_t w; - int n, ret = 0, ts, tm; + size_t ts, tm; + int n, ret = 0; int (*parse)(uint32_t *, const char *, size_t); size_t (*unparse)(char *, size_t, uint32_t); diff --git a/libarchive/archive_string_sprintf.c b/libarchive/archive_string_sprintf.c index 1c5910e0b2d..69b0cdcd83d 100644 --- a/libarchive/archive_string_sprintf.c +++ b/libarchive/archive_string_sprintf.c @@ -146,7 +146,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, case 'z': s = va_arg(ap, ssize_t); break; default: s = va_arg(ap, int); break; } - append_int(as, s, 10); + append_int(as, s, 10); break; case 's': switch(long_flag) { diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c index 900abd0c3c6..d048bbc9465 100644 --- a/libarchive/archive_util.c +++ b/libarchive/archive_util.c @@ -445,11 +445,39 @@ __archive_mkstemp(wchar_t *template) #else static int -get_tempdir(struct archive_string *temppath) +__archive_issetugid(void) { - const char *tmp; +#ifdef HAVE_ISSETUGID + return (issetugid()); +#elif HAVE_GETRESUID + uid_t ruid, euid, suid; + gid_t rgid, egid, sgid; + if (getresuid(&ruid, &euid, &suid) != 0) + return (-1); + if (ruid != euid || ruid != suid) + return (1); + if (getresgid(&ruid, &egid, &sgid) != 0) + return (-1); + if (rgid != egid || rgid != sgid) + return (1); +#elif HAVE_GETEUID + if (geteuid() != getuid()) + return (1); +#if HAVE_GETEGID + if (getegid() != getgid()) + return (1); +#endif +#endif + return (0); +} - tmp = getenv("TMPDIR"); +int +__archive_get_tempdir(struct archive_string *temppath) +{ + const char *tmp = NULL; + + if (__archive_issetugid() == 0) + tmp = getenv("TMPDIR"); if (tmp == NULL) #ifdef _PATH_TMP tmp = _PATH_TMP; @@ -476,7 +504,7 @@ __archive_mktemp(const char *tmpdir) archive_string_init(&temp_name); if (tmpdir == NULL) { - if (get_tempdir(&temp_name) != ARCHIVE_OK) + if (__archive_get_tempdir(&temp_name) != ARCHIVE_OK) goto exit_tmpfile; } else { archive_strcpy(&temp_name, tmpdir); @@ -538,7 +566,7 @@ __archive_mktempx(const char *tmpdir, char *template) if (template == NULL) { archive_string_init(&temp_name); if (tmpdir == NULL) { - if (get_tempdir(&temp_name) != ARCHIVE_OK) + if (__archive_get_tempdir(&temp_name) != ARCHIVE_OK) goto exit_tmpfile; } else archive_strcpy(&temp_name, tmpdir); diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index 03c9736c06a..e55f995c770 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -45,6 +45,7 @@ #if defined(_WIN32) && !defined(__CYGWIN__) #include "archive_platform.h" +#include "archive_platform_stat.h" #include "archive_private.h" #include "archive_entry.h" #include "archive_time_private.h" @@ -313,6 +314,10 @@ __la_open(const char *path, int flags, ...) pmode = va_arg(ap, int); va_end(ap); ws = NULL; + + /* _(w)sopen_s fails if we provide any other modes */ + pmode = pmode & (_S_IREAD | _S_IWRITE); + if ((flags & ~O_BINARY) == O_RDONLY) { /* * When we open a directory, _open function returns @@ -374,7 +379,7 @@ __la_open(const char *path, int flags, ...) TODO: Fix mode of new file. */ r = _open(path, flags); #else - r = _open(path, flags, pmode); + _sopen_s(&r, path, flags, _SH_DENYNO, pmode); #endif if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { /* Simulate other POSIX system action to pass our test suite. */ @@ -395,7 +400,7 @@ __la_open(const char *path, int flags, ...) return (-1); } } - r = _wopen(ws, flags, pmode); + _wsopen_s(&r, ws, flags, _SH_DENYNO, pmode); if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { /* Simulate other POSIX system action to pass our test suite. */ attr = GetFileAttributesW(ws); @@ -410,6 +415,93 @@ __la_open(const char *path, int flags, ...) return (r); } +int +__la_wopen(const wchar_t *path, int flags, ...) +{ + va_list ap; + wchar_t *fullpath; + int r, pmode; + DWORD attr; + + va_start(ap, flags); + pmode = va_arg(ap, int); + va_end(ap); + fullpath = NULL; + + /* _(w)sopen_s fails if we provide any other modes */ + pmode = pmode & (_S_IREAD | _S_IWRITE); + + if ((flags & ~O_BINARY) == O_RDONLY) { + /* + * When we open a directory, _open function returns + * "Permission denied" error. + */ + attr = GetFileAttributesW(path); +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) + if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND) +#endif + { + fullpath = __la_win_permissive_name_w(path); + if (fullpath == NULL) { + errno = EINVAL; + return (-1); + } + path = fullpath; + attr = GetFileAttributesW(fullpath); + } + if (attr == (DWORD)-1) { + la_dosmaperr(GetLastError()); + free(fullpath); + return (-1); + } + if (attr & FILE_ATTRIBUTE_DIRECTORY) { + HANDLE handle; +#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) + if (fullpath != NULL) + handle = CreateFileW(fullpath, 0, 0, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_ATTRIBUTE_READONLY, + NULL); + else + handle = CreateFileW(path, 0, 0, NULL, + OPEN_EXISTING, + 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(fullpath, 0, 0, + OPEN_EXISTING, &createExParams); +#endif /* !WINAPI_PARTITION_DESKTOP */ + free(fullpath); + if (handle == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + return (-1); + } + r = _open_osfhandle((intptr_t)handle, _O_RDONLY); + return (r); + } + } + _wsopen_s(&r, path, flags, _SH_DENYNO, pmode); + if (r < 0 && errno == EACCES && (flags & O_CREAT) != 0) { + /* Simulate other POSIX system action to pass our test suite. */ + attr = GetFileAttributesW(path); + if (attr == (DWORD)-1) + la_dosmaperr(GetLastError()); + else if (attr & FILE_ATTRIBUTE_DIRECTORY) + errno = EISDIR; + else + errno = EACCES; + } + free(fullpath); + return (r); +} + ssize_t __la_read(int fd, void *buf, size_t nbytes) { @@ -561,6 +653,8 @@ copy_stat(struct stat *st, struct ustat *us) st->st_mode = us->st_mode; st->st_nlink = us->st_nlink; st->st_size = (off_t)us->st_size; + if (st->st_size < 0 || (uint64_t)st->st_size != us->st_size) + st->st_size = 0; st->st_uid = us->st_uid; st->st_dev = us->st_dev; st->st_rdev = us->st_rdev; @@ -630,6 +724,53 @@ __la_stat(const char *path, struct stat *st) return (ret); } +static void +copy_seek_stat(la_seek_stat_t *st, struct ustat *us) +{ + st->st_mtime = us->st_mtime; + st->st_gid = us->st_gid; + st->st_ino = getino(us); + st->st_mode = us->st_mode; + st->st_nlink = us->st_nlink; + st->st_size = (la_seek_t)us->st_size; + if (st->st_size < 0 || (uint64_t)st->st_size != us->st_size) + st->st_size = -1; + st->st_uid = us->st_uid; + st->st_dev = us->st_dev; + st->st_rdev = us->st_rdev; +} + +int +__la_seek_fstat(int fd, la_seek_stat_t *st) +{ + struct ustat u; + int ret; + + ret = __hstat((HANDLE)_get_osfhandle(fd), &u); + copy_seek_stat(st, &u); + return (ret); +} + +int +__la_seek_stat(const char *path, la_seek_stat_t *st) +{ + HANDLE handle; + struct ustat u; + int ret; + + handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + la_dosmaperr(GetLastError()); + return (-1); + } + ret = __hstat(handle, &u); + CloseHandle(handle); + copy_seek_stat(st, &u); + return (ret); +} + /* * This waitpid is limited implementation. */ @@ -641,13 +782,14 @@ __la_waitpid(HANDLE child, int *status, int option) (void)option;/* UNUSED */ do { if (GetExitCodeProcess(child, &cs) == 0) { - CloseHandle(child); la_dosmaperr(GetLastError()); + CloseHandle(child); *status = 0; return (-1); } } while (cs == STILL_ACTIVE); + CloseHandle(child); *status = (int)(cs & 0xff); return (0); } diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h index 4dc8c2b3ad4..ecb14e01087 100644 --- a/libarchive/archive_windows.h +++ b/libarchive/archive_windows.h @@ -72,6 +72,8 @@ #include //#define EFTYPE 7 +#include "archive_platform_stat.h" + #if defined(__BORLANDC__) #pragma warn -8068 /* Constant out of range in comparison. */ #pragma warn -8072 /* Suspicious pointer arithmetic. */ @@ -106,6 +108,7 @@ #endif #define lstat __la_stat #define open __la_open +#define _wopen __la_wopen #define read __la_read #if !defined(__BORLANDC__) && !defined(__WATCOMC__) #define setmode _setmode @@ -261,6 +264,9 @@ #define F_OK 0 /* Test for existence of file */ #endif +/* Functions to circumvent off_t limitations */ +int __la_seek_fstat(int fd, la_seek_stat_t *st); +int __la_seek_stat(const char *path, la_seek_stat_t *st); /* Replacement POSIX function */ extern int __la_fstat(int fd, struct stat *st); @@ -269,6 +275,7 @@ extern int __la_lstat(const char *path, struct stat *st); extern __int64 __la_lseek(int fd, __int64 offset, int whence); #endif extern int __la_open(const char *path, int flags, ...); +extern int __la_wopen(const wchar_t *path, int flags, ...); extern ssize_t __la_read(int fd, void *buf, size_t nbytes); extern int __la_stat(const char *path, struct stat *st); extern pid_t __la_waitpid(HANDLE child, int *status, int option); diff --git a/libarchive/archive_write.c b/libarchive/archive_write.c index a8e7b63b5bf..9b9cb196f0f 100644 --- a/libarchive/archive_write.c +++ b/libarchive/archive_write.c @@ -360,7 +360,6 @@ archive_write_client_open(struct archive_write_filter *f) struct archive_none *state; void *buffer; size_t buffer_size; - int ret; f->bytes_per_block = archive_write_get_bytes_per_block(f->archive); f->bytes_in_last_block = @@ -385,13 +384,7 @@ archive_write_client_open(struct archive_write_filter *f) if (a->client_opener == NULL) return (ARCHIVE_OK); - ret = a->client_opener(f->archive, a->client_data); - if (ret != ARCHIVE_OK) { - free(state->buffer); - free(state); - f->data = NULL; - } - return (ret); + return (a->client_opener(f->archive, a->client_data)); } static int @@ -480,6 +473,7 @@ static int archive_write_client_free(struct archive_write_filter *f) { struct archive_write *a = (struct archive_write *)f->archive; + struct archive_none *state = (struct archive_none *)f->data; if (a->client_freer) (*a->client_freer)(&a->archive, a->client_data); @@ -492,6 +486,13 @@ archive_write_client_free(struct archive_write_filter *f) a->passphrase = NULL; } + /* Free state. */ + if (state != NULL) { + free(state->buffer); + free(state); + f->data = NULL; + } + return (ARCHIVE_OK); } @@ -548,8 +549,6 @@ archive_write_client_close(struct archive_write_filter *f) } if (a->client_closer) (*a->client_closer)(&a->archive, a->client_data); - free(state->buffer); - free(state); /* Clear the close handler myself not to be called again. */ f->state = ARCHIVE_WRITE_FILTER_STATE_CLOSED; @@ -807,7 +806,10 @@ _archive_write_finish_entry(struct archive *_a) if (a->archive.state & ARCHIVE_STATE_DATA && a->format_finish_entry != NULL) ret = (a->format_finish_entry)(a); - a->archive.state = ARCHIVE_STATE_HEADER; + if (ret == ARCHIVE_FATAL) + a->archive.state = ARCHIVE_STATE_FATAL; + else + a->archive.state = ARCHIVE_STATE_HEADER; return (ret); } @@ -819,6 +821,7 @@ _archive_write_data(struct archive *_a, const void *buff, size_t s) { struct archive_write *a = (struct archive_write *)_a; const size_t max_write = INT_MAX; + int ret; archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_DATA, "archive_write_data"); @@ -826,7 +829,10 @@ _archive_write_data(struct archive *_a, const void *buff, size_t s) if (s > max_write) s = max_write; archive_clear_error(&a->archive); - return ((a->format_write_data)(a, buff, s)); + ret = (a->format_write_data)(a, buff, s); + if (ret == ARCHIVE_FATAL) + a->archive.state = ARCHIVE_STATE_FATAL; + return (ret); } static struct archive_write_filter * diff --git a/libarchive/archive_write_add_filter_bzip2.c b/libarchive/archive_write_add_filter_bzip2.c index 0726f08936e..2434528d513 100644 --- a/libarchive/archive_write_add_filter_bzip2.c +++ b/libarchive/archive_write_add_filter_bzip2.c @@ -281,6 +281,10 @@ static int archive_compressor_bzip2_free(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; + + /* May already have been called, but not necessarily. */ + (void)BZ2_bzCompressEnd(&(data->stream)); + free(data->compressed); free(data); f->data = NULL; diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c index 5ef43c1936e..b09e669b753 100644 --- a/libarchive/archive_write_add_filter_gzip.c +++ b/libarchive/archive_write_add_filter_gzip.c @@ -191,7 +191,8 @@ static int archive_compressor_gzip_open(struct archive_write_filter *f) { struct private_data *data = (struct private_data *)f->data; - int ret; + int ret = ARCHIVE_OK; + int init_success; if (data->compressed == NULL) { size_t bs = 65536, bpb; @@ -221,44 +222,66 @@ archive_compressor_gzip_open(struct archive_write_filter *f) data->compressed[0] = 0x1f; /* GZip signature bytes */ data->compressed[1] = 0x8b; data->compressed[2] = 0x08; /* "Deflate" compression */ - data->compressed[3] = data->original_filename == NULL ? 0 : 0x8; + data->compressed[3] = 0x00; /* Flags */ if (data->timestamp >= 0) { time_t t = time(NULL); data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */ data->compressed[5] = (uint8_t)(t>>8)&0xff; data->compressed[6] = (uint8_t)(t>>16)&0xff; data->compressed[7] = (uint8_t)(t>>24)&0xff; - } else + } else { memset(&data->compressed[4], 0, 4); - if (data->compression_level == 9) - data->compressed[8] = 2; - else if(data->compression_level == 1) - data->compressed[8] = 4; - else - data->compressed[8] = 0; + } + if (data->compression_level == 9) { + data->compressed[8] = 2; + } else if(data->compression_level == 1) { + data->compressed[8] = 4; + } else { + data->compressed[8] = 0; + } data->compressed[9] = 3; /* OS=Unix */ data->stream.next_out += 10; data->stream.avail_out -= 10; if (data->original_filename != NULL) { - strcpy((char*)data->compressed + 10, data->original_filename); - data->stream.next_out += strlen(data->original_filename) + 1; - data->stream.avail_out -= strlen(data->original_filename) + 1; + /* Limit "original filename" to 32k or the + * remaining space in the buffer, whichever is smaller. + */ + int ofn_length = strlen(data->original_filename); + int ofn_max_length = 32768; + int ofn_space_available = data->compressed + + data->compressed_buffer_size + - data->stream.next_out + - 1; + if (ofn_max_length > ofn_space_available) { + ofn_max_length = ofn_space_available; + } + if (ofn_length < ofn_max_length) { + data->compressed[3] |= 0x8; + strcpy((char*)data->compressed + 10, + data->original_filename); + data->stream.next_out += ofn_length + 1; + data->stream.avail_out -= ofn_length + 1; + } else { + archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, + "Gzip 'Original Filename' ignored because it is too long"); + ret = ARCHIVE_WARN; + } } f->write = archive_compressor_gzip_write; /* Initialize compression library. */ - ret = deflateInit2(&(data->stream), + init_success = deflateInit2(&(data->stream), data->compression_level, Z_DEFLATED, -15 /* < 0 to suppress zlib header */, 8, Z_DEFAULT_STRATEGY); - if (ret == Z_OK) { + if (init_success == Z_OK) { f->data = data; - return (ARCHIVE_OK); + return (ret); } /* Library setup failed: clean up. */ @@ -266,7 +289,7 @@ archive_compressor_gzip_open(struct archive_write_filter *f) "initializing compression library"); /* Override the error message if we know what really went wrong. */ - switch (ret) { + switch (init_success) { case Z_STREAM_ERROR: archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error initializing " diff --git a/libarchive/archive_write_add_filter_program.c b/libarchive/archive_write_add_filter_program.c index c661cc7f412..f12db337388 100644 --- a/libarchive/archive_write_add_filter_program.c +++ b/libarchive/archive_write_add_filter_program.c @@ -330,6 +330,7 @@ __archive_write_program_close(struct archive_write_filter *f, struct archive_write_program_data *data) { int ret, status; + pid_t pid; ssize_t bytes_read; if (data->child == 0) @@ -373,14 +374,12 @@ __archive_write_program_close(struct archive_write_filter *f, close(data->child_stdin); if (data->child_stdout != -1) close(data->child_stdout); - while (waitpid(data->child, &status, 0) == -1 && errno == EINTR) - continue; -#if defined(_WIN32) && !defined(__CYGWIN__) - CloseHandle(data->child); -#endif + do { + pid = waitpid(data->child, &status, 0); + } while (pid == -1 && errno == EINTR); data->child = 0; - if (status != 0) { + if (pid < 0 || status != 0) { archive_set_error(f->archive, EIO, "Error closing program: %s", data->program_name); ret = ARCHIVE_FATAL; diff --git a/libarchive/archive_write_add_filter_zstd.c b/libarchive/archive_write_add_filter_zstd.c index c0a6e5a37a6..d4752c24715 100644 --- a/libarchive/archive_write_add_filter_zstd.c +++ b/libarchive/archive_write_add_filter_zstd.c @@ -391,6 +391,8 @@ archive_compressor_zstd_open(struct archive_write_filter *f) ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads); + ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_checksumFlag, 1); + #if ZSTD_VERSION_NUMBER >= MINVER_LONG ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_windowLog, data->long_distance); #endif diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c index f1533726469..6fcf3929b5c 100644 --- a/libarchive/archive_write_disk_posix.c +++ b/libarchive/archive_write_disk_posix.c @@ -2204,7 +2204,7 @@ restore_entry(struct archive_write_disk *a) (void)clear_nochange_fflags(a); if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) && - S_ISREG(a->st.st_mode)) { + S_ISREG(a->mode)) { /* Use a temporary file to extract */ if ((a->fd = la_mktemp(a)) == -1) { archive_set_error(&a->archive, errno, @@ -2559,9 +2559,9 @@ _archive_write_disk_close(struct archive *_a) * for directories. For other file types * we need to verify via fstat() or lstat() */ - if (fd == -1 || p->filetype != AE_IFDIR) { + if (fd < 0 || p->filetype != AE_IFDIR) { #if HAVE_FSTAT - if (fd > 0 && ( + if (fd >= 0 && ( fstat(fd, &st) != 0 || la_verify_filetype(st.st_mode, p->filetype) == 0)) { @@ -3930,10 +3930,14 @@ clear_nochange_fflags(struct archive_write_disk *a) #ifdef UF_APPEND | UF_APPEND #endif -#ifdef EXT2_APPEND_FL +#if defined(FS_APPEND_FL) + | FS_APPEND_FL +#elif defined(EXT2_APPEND_FL) | EXT2_APPEND_FL #endif -#ifdef EXT2_IMMUTABLE_FL +#if defined(FS_IMMUTABLE_FL) + | FS_IMMUTABLE_FL +#elif defined(EXT2_IMMUTABLE_FL) | EXT2_IMMUTABLE_FL #endif ; @@ -4437,7 +4441,7 @@ fixup_appledouble(struct archive_write_disk *a, const char *pathname) */ fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC); __archive_ensure_cloexec_flag(fd); - if (fd == -1) { + if (fd < 0) { archive_set_error(&a->archive, errno, "Failed to open a restoring file"); ret = ARCHIVE_WARN; diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c index c7339c4ec1b..d4f6f1820e9 100644 --- a/libarchive/archive_write_disk_windows.c +++ b/libarchive/archive_write_disk_windows.c @@ -1618,7 +1618,7 @@ restore_entry(struct archive_write_disk *a) (void)clear_nochange_fflags(a); } if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) && - S_ISREG(st_mode)) { + S_ISREG(a->mode)) { int fd = la_mktemp(a); if (fd == -1) { diff --git a/libarchive/archive_write_open_fd.c b/libarchive/archive_write_open_fd.c index 8a3f68d0699..ba034ed92f8 100644 --- a/libarchive/archive_write_open_fd.c +++ b/libarchive/archive_write_open_fd.c @@ -122,7 +122,7 @@ file_write(struct archive *a, void *client_data, const void *buff, size_t length mine = (struct write_fd_data *)client_data; for (;;) { bytesWritten = write(mine->fd, buff, length); - if (bytesWritten <= 0) { + if (bytesWritten < 0) { if (errno == EINTR) continue; archive_set_error(a, errno, "Write error"); diff --git a/libarchive/archive_write_open_file.c b/libarchive/archive_write_open_file.c index 4c6ebfb2269..0b310f3da83 100644 --- a/libarchive/archive_write_open_file.c +++ b/libarchive/archive_write_open_file.c @@ -85,16 +85,12 @@ file_write(struct archive *a, void *client_data, const void *buff, size_t length size_t bytesWritten; mine = client_data; - for (;;) { - bytesWritten = fwrite(buff, 1, length, mine->f); - if (bytesWritten <= 0) { - if (errno == EINTR) - continue; - archive_set_error(a, errno, "Write error"); - return (-1); - } - return (bytesWritten); + bytesWritten = fwrite(buff, 1, length, mine->f); + if (bytesWritten != length) { + archive_set_error(a, errno, "Write error"); + return (-1); } + return (bytesWritten); } static int diff --git a/libarchive/archive_write_open_filename.c b/libarchive/archive_write_open_filename.c index 34209426558..7d0f9bde1db 100644 --- a/libarchive/archive_write_open_filename.c +++ b/libarchive/archive_write_open_filename.c @@ -108,6 +108,7 @@ open_filename(struct archive *a, int mbs_fn, const void *filename) else r = archive_mstring_copy_wcs(&mine->filename, filename); if (r < 0) { + free(mine); if (errno == ENOMEM) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); @@ -227,7 +228,7 @@ file_write(struct archive *a, void *client_data, const void *buff, mine = (struct write_file_data *)client_data; for (;;) { bytesWritten = write(mine->fd, buff, length); - if (bytesWritten <= 0) { + if (bytesWritten < 0) { if (errno == EINTR) continue; archive_set_error(a, errno, "Write error"); diff --git a/libarchive/archive_write_set_format_7zip.c b/libarchive/archive_write_set_format_7zip.c index 902d03f6a8f..ebdb16e9022 100644 --- a/libarchive/archive_write_set_format_7zip.c +++ b/libarchive/archive_write_set_format_7zip.c @@ -686,7 +686,7 @@ write_to_temp(struct archive_write *a, const void *buff, size_t s) ws = write(zip->temp_fd, p, s); if (ws < 0) { archive_set_error(&(a->archive), errno, - "fwrite function failed"); + "write function failed"); return (ARCHIVE_FATAL); } s -= ws; diff --git a/libarchive/archive_write_set_format_mtree.c b/libarchive/archive_write_set_format_mtree.c index 02fbb2d2f55..8131574c8da 100644 --- a/libarchive/archive_write_set_format_mtree.c +++ b/libarchive/archive_write_set_format_mtree.c @@ -1927,7 +1927,7 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file, } /* - * Find out the position which points the last position of + * Find out the position which points to the last position of * path separator('/'). */ slash = NULL; @@ -2024,7 +2024,7 @@ mtree_entry_add_child_tail(struct mtree_entry *parent, } /* - * Find a entry from a parent entry with the name. + * Find an entry from a parent entry with given name. */ static struct mtree_entry * mtree_entry_find_child(struct mtree_entry *parent, const char *child_name) @@ -2148,10 +2148,10 @@ mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep) /* Find next sub directory. */ if (!np->dir_info) { - /* NOT Directory! */ + /* NOT a directory! */ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "`%s' is not directory, we cannot insert `%s' ", + "`%s' is not a directory, we cannot insert `%s' ", np->pathname.s, file->pathname.s); return (ARCHIVE_FAILED); } @@ -2243,10 +2243,7 @@ mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep) } same_entry: - /* - * We have already has the entry the filename of which is - * the same. - */ + /* We already have an entry with same filename. */ r = mtree_entry_exchange_same_entry(a, np, file); if (r < ARCHIVE_WARN) return (r); @@ -2264,13 +2261,13 @@ mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np, if ((np->mode & AE_IFMT) != (file->mode & AE_IFMT)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Found duplicate entries `%s' and its file type is " - "different", + "Found duplicate entries for `%s' with " + "differing file types.", np->pathname.s); return (ARCHIVE_FAILED); } - /* Update the existent mtree entry's attributes by the new one's. */ + /* Update the existing mtree entry's attributes by the new one's. */ archive_string_empty(&np->symlink); archive_string_concat(&np->symlink, &file->symlink); archive_string_empty(&np->uname); diff --git a/libarchive/archive_write_set_format_xar.c b/libarchive/archive_write_set_format_xar.c index 3775e9f5819..9921f1032be 100644 --- a/libarchive/archive_write_set_format_xar.c +++ b/libarchive/archive_write_set_format_xar.c @@ -689,7 +689,7 @@ write_to_temp(struct archive_write *a, const void *buff, size_t s) ws = write(xar->temp_fd, p, s); if (ws < 0) { archive_set_error(&(a->archive), errno, - "fwrite function failed"); + "write function failed"); return (ARCHIVE_FATAL); } s -= ws; @@ -3418,8 +3418,8 @@ static int xml_writer_get_final_content_and_length(struct xml_writer *ctx, const char **out, size_t *size) { - *out = (const char*)ctx->bp->content; - *size = (size_t)ctx->bp->use; + *out = (const char*)xmlBufferContent(ctx->bp); + *size = (size_t)xmlBufferLength(ctx->bp); return (0); } diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c index 3630b9f2b3a..19121b51914 100644 --- a/libarchive/archive_write_set_format_zip.c +++ b/libarchive/archive_write_set_format_zip.c @@ -1856,7 +1856,10 @@ archive_write_zip_finish_entry(struct archive_write *a) } ret = __archive_write_output(a, zip->buf, remainder); if (ret != ARCHIVE_OK) + { + deflateEnd(&zip->stream.deflate); return (ret); + } zip->entry_compressed_written += remainder; zip->written_bytes += remainder; zip->stream.deflate.next_out = zip->buf; @@ -1898,7 +1901,10 @@ archive_write_zip_finish_entry(struct archive_write *a) } ret = __archive_write_output(a, zip->buf, remainder); if (ret != ARCHIVE_OK) + { + BZ2_bzCompressEnd(&zip->stream.bzip2); return (ret); + } zip->entry_compressed_written += remainder; zip->written_bytes += remainder; zip->stream.bzip2.next_out = (char*)zip->buf; @@ -1940,13 +1946,17 @@ archive_write_zip_finish_entry(struct archive_write *a) } ret = __archive_write_output(a, zip->buf, remainder); if (ret != ARCHIVE_OK) + { + ZSTD_freeCStream(zip->stream.zstd.context); return (ret); + } zip->entry_compressed_written += remainder; zip->written_bytes += remainder; - zip->stream.zstd.out.dst = zip->buf; if (zip->stream.zstd.out.pos != zip->stream.zstd.out.size) finishing = 0; + zip->stream.zstd.out.dst = zip->buf; zip->stream.zstd.out.size = zip->len_buf; + zip->stream.zstd.out.pos = 0; } while (finishing); ZSTD_freeCStream(zip->stream.zstd.context); break; @@ -1984,7 +1994,10 @@ archive_write_zip_finish_entry(struct archive_write *a) } ret = __archive_write_output(a, zip->buf, remainder); if (ret != ARCHIVE_OK) + { + lzma_end(&zip->stream.lzma.context); return (ret); + } zip->entry_compressed_written += remainder; zip->written_bytes += remainder; zip->stream.lzma.context.next_out = zip->buf; @@ -2434,13 +2447,19 @@ init_winzip_aes_encryption(struct archive_write *a) "Can't generate random number for encryption"); return (ARCHIVE_FATAL); } - archive_pbkdf2_sha1(passphrase, strlen(passphrase), + ret = archive_pbkdf2_sha1(passphrase, strlen(passphrase), salt, salt_len, 1000, derived_key, key_len * 2 + 2); + if (ret != 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + ret == CRYPTOR_STUB_FUNCTION ? "Encryption is unsupported due to " + "lack of crypto library" : "Failed to process passphrase"); + return (ARCHIVE_FAILED); + } ret = archive_encrypto_aes_ctr_init(&zip->cctx, derived_key, key_len); if (ret != 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Decryption is unsupported due to lack of crypto library"); + "Failed to initialize AES CTR mode"); return (ARCHIVE_FAILED); } ret = archive_hmac_sha1_init(&zip->hctx, derived_key + key_len, diff --git a/libarchive/filter_fork_posix.c b/libarchive/filter_fork_posix.c index c895c08e59b..7c48519336f 100644 --- a/libarchive/filter_fork_posix.c +++ b/libarchive/filter_fork_posix.c @@ -1,6 +1,6 @@ /*- * Copyright (c) 2007 Joerg Sonnenberger - * Copyright (c) 2012 Michihiro NAKAJIMA + * Copyright (c) 2012 Michihiro NAKAJIMA * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,7 +76,15 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, { pid_t child = -1; int stdin_pipe[2], stdout_pipe[2], tmp; + +#if !defined(POSIX_SPAWN_CLOEXEC_DEFAULT) && \ + (HAVE_FORK || HAVE_VFORK) && \ + (HAVE_CLOSEFROM || HAVE_CLOSE_RANGE || defined(_SC_OPEN_MAX)) +#undef HAVE_POSIX_SPAWNP +#endif + #if HAVE_POSIX_SPAWNP + posix_spawnattr_t attr; posix_spawn_file_actions_t actions; int r; #endif @@ -107,11 +115,21 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, #if HAVE_POSIX_SPAWNP - r = posix_spawn_file_actions_init(&actions); + r = posix_spawnattr_init(&attr); if (r != 0) { errno = r; goto stdout_opened; } + r = posix_spawn_file_actions_init(&actions); + if (r != 0) { + errno = r; + goto attr_inited; + } +#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT + r = posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT); + if (r != 0) + goto actions_inited; +#endif r = posix_spawn_file_actions_addclose(&actions, stdin_pipe[1]); if (r != 0) goto actions_inited; @@ -136,11 +154,12 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, if (r != 0) goto actions_inited; } - r = posix_spawnp(&child, cmdline->path, &actions, NULL, + r = posix_spawnp(&child, cmdline->path, &actions, &attr, cmdline->argv, NULL); if (r != 0) goto actions_inited; posix_spawn_file_actions_destroy(&actions); + posix_spawnattr_destroy(&attr); #else /* HAVE_POSIX_SPAWNP */ @@ -162,6 +181,16 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, _exit(254); if (stdout_pipe[1] != 1 /* stdout */) close(stdout_pipe[1]); + +#if HAVE_CLOSEFROM + closefrom(3); +#elif HAVE_CLOSE_RANGE + close_range(3, ~0U, 0); +#elif defined(_SC_OPEN_MAX) + for (int i = sysconf(_SC_OPEN_MAX); i > 3;) + close(--i); +#endif + execvp(cmdline->path, cmdline->argv); _exit(254); } @@ -183,6 +212,8 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, actions_inited: errno = r; posix_spawn_file_actions_destroy(&actions); +attr_inited: + posix_spawnattr_destroy(&attr); #endif stdout_opened: close(stdout_pipe[0]); diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index b5acb468c4c..f62737d79f8 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -168,6 +168,7 @@ IF(ENABLE_TEST) test_read_format_rar5.c test_read_format_raw.c test_read_format_tar.c + test_read_format_tar_V_negative_size.c test_read_format_tar_concatenated.c test_read_format_tar_empty_filename.c test_read_format_tar_empty_with_gnulabel.c diff --git a/libarchive/test/test_acl_nfs4.c b/libarchive/test/test_acl_nfs4.c index 98d39689df6..050c0a06365 100644 --- a/libarchive/test/test_acl_nfs4.c +++ b/libarchive/test/test_acl_nfs4.c @@ -145,6 +145,13 @@ static struct archive_test_acl_t acls_bad[] = { ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE, ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, + + /* Multiple types */ + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW | ARCHIVE_ENTRY_ACL_TYPE_AUDIT, + ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_NFS4, ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, }; DEFINE_TEST(test_acl_nfs4) diff --git a/libarchive/test/test_acl_posix1e.c b/libarchive/test/test_acl_posix1e.c index 025ef6afd10..f9b6ffeb6ab 100644 --- a/libarchive/test/test_acl_posix1e.c +++ b/libarchive/test/test_acl_posix1e.c @@ -94,6 +94,11 @@ static struct archive_test_acl_t acls_nfs4[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + + /* Invalid type codes */ + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, }; DEFINE_TEST(test_acl_posix1e) diff --git a/libarchive/test/test_archive_parse_date.c b/libarchive/test/test_archive_parse_date.c index 0a70971b1da..5251b339399 100644 --- a/libarchive/test/test_archive_parse_date.c +++ b/libarchive/test/test_archive_parse_date.c @@ -39,6 +39,8 @@ DEFINE_TEST(test_archive_parse_date) assertEqualInt(get_date(now, "Jan 1, 1970 UTC"), 0); assertEqualInt(get_date(now, "7:12:18-0530 4 May 1983"), 420900138); assertEqualInt(get_date(now, "2004/01/29 513 mest"), 1075345980); + assertEqualInt(get_date(now, "2038-06-01 00:01:02 UTC"), + sizeof(time_t) <= 4 ? -1 : 2158963262); assertEqualInt(get_date(now, "99/02/17 7pm utc"), 919278000); assertEqualInt(get_date(now, "02/17/99 7:11am est"), 919253460); assertEqualInt(get_date(now, "now - 2 hours"), diff --git a/libarchive/test/test_archive_string_conversion.c b/libarchive/test/test_archive_string_conversion.c index 12976f3e70e..055bddc7506 100644 --- a/libarchive/test/test_archive_string_conversion.c +++ b/libarchive/test/test_archive_string_conversion.c @@ -991,6 +991,7 @@ DEFINE_TEST(test_archive_string_update_utf8_koi8) static const char koi8_string[] = "\xD0\xD2\xC9"; static const wchar_t wcs_string[] = L"\U0000043f\U00000440\U00000438"; struct archive_mstring mstr; + struct archive *a; int r; memset(&mstr, 0, sizeof(mstr)); @@ -999,6 +1000,15 @@ DEFINE_TEST(test_archive_string_update_utf8_koi8) skipping("KOI8-R locale not available on this system."); return; } + a = archive_write_new(); + assertEqualInt(ARCHIVE_OK, archive_write_set_format_pax(a)); + if (archive_write_set_options(a, "hdrcharset=UTF-8") != ARCHIVE_OK) { + skipping("This system cannot convert character-set" + " from KOI8-R to UTF-8."); + archive_write_free(a); + return; + } + archive_write_free(a); r = archive_mstring_update_utf8(NULL, &mstr, utf8_string); diff --git a/libarchive/test/test_entry.c b/libarchive/test/test_entry.c index 9b21b83ecdf..cff9c5c86ef 100644 --- a/libarchive/test/test_entry.c +++ b/libarchive/test/test_entry.c @@ -880,6 +880,17 @@ DEFINE_TEST(test_entry) if (pst == NULL) return; assertEqualInt(pst->st_uid, 22); + + /* Check behavior with large sizes. */ + archive_entry_set_size(e, INT64_MAX - 1); + assert((pst = archive_entry_stat(e)) != NULL); + if (pst == NULL) + return; + if (sizeof(pst->st_size) < sizeof(int64_t)) + assertEqualInt(pst->st_size, 0); + else + assertEqualInt(pst->st_size, INT64_MAX - 1); + /* We don't need to check high-res fields here. */ /* diff --git a/libarchive/test/test_read_filter_gzip_recursive.c b/libarchive/test/test_read_filter_gzip_recursive.c index 0042a0511d5..51b614b6c02 100644 --- a/libarchive/test/test_read_filter_gzip_recursive.c +++ b/libarchive/test/test_read_filter_gzip_recursive.c @@ -29,8 +29,8 @@ DEFINE_TEST(test_read_filter_gzip_recursive) const char *name = "test_read_filter_gzip_recursive.gz"; struct archive *a; - if (!canGzip()) { - skipping("gzip not available"); + if (archive_zlib_version() == NULL) { + skipping("zlib not available"); return; } diff --git a/libarchive/test/test_read_format_7zip.c b/libarchive/test/test_read_format_7zip.c index ad10ef06bbc..3236fee2c9d 100644 --- a/libarchive/test/test_read_format_7zip.c +++ b/libarchive/test/test_read_format_7zip.c @@ -1285,19 +1285,26 @@ DEFINE_TEST(test_read_format_7zip_sfx_pe) const char test_txt[] = "123"; int size = sizeof(test_txt) - 1; - extract_reference_file(reffile); assert((a = archive_read_new()) != NULL); - assertA(0 == archive_read_support_filter_all(a)); - assertA(0 == archive_read_support_format_all(a)); - assertA(0 == archive_read_open_filename(a, reffile, bs)); - assertA(0 == archive_read_next_header(a, &ae)); - assertEqualString("test.txt.txt", archive_entry_pathname(ae)); + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { + skipping( + "7zip:lzma decoding is not supported on this platform"); + } else { + extract_reference_file(reffile); + assertA(0 == archive_read_support_filter_all(a)); + assertA(0 == archive_read_support_format_all(a)); + assertA(0 == archive_read_open_filename(a, reffile, bs)); - assertA(size == archive_read_data(a, buff, size)); - assertEqualMem(buff, test_txt, size); + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("test.txt.txt", archive_entry_pathname(ae)); + + assertA(size == archive_read_data(a, buff, size)); + assertEqualMem(buff, test_txt, size); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + } - assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } @@ -1316,19 +1323,26 @@ DEFINE_TEST(test_read_format_7zip_sfx_modified_pe) const char test_txt[] = "123"; int size = sizeof(test_txt) - 1; - extract_reference_file(reffile); assert((a = archive_read_new()) != NULL); - assertA(0 == archive_read_support_filter_all(a)); - assertA(0 == archive_read_support_format_all(a)); - assertA(0 == archive_read_open_filename(a, reffile, bs)); - assertA(0 == archive_read_next_header(a, &ae)); - assertEqualString("test.txt.txt", archive_entry_pathname(ae)); + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { + skipping( + "7zip:lzma decoding is not supported on this platform"); + } else { + extract_reference_file(reffile); + assertA(0 == archive_read_support_filter_all(a)); + assertA(0 == archive_read_support_format_all(a)); + assertA(0 == archive_read_open_filename(a, reffile, bs)); - assertA(size == archive_read_data(a, buff, size)); - assertEqualMem(buff, test_txt, size); + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("test.txt.txt", archive_entry_pathname(ae)); + + assertA(size == archive_read_data(a, buff, size)); + assertEqualMem(buff, test_txt, size); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + } - assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } @@ -1346,20 +1360,27 @@ DEFINE_TEST(test_read_format_7zip_sfx_elf) const char test_txt[] = "123"; int size = sizeof(test_txt) - 1; - extract_reference_file(reffile); assert((a = archive_read_new()) != NULL); - assertA(0 == archive_read_support_filter_all(a)); - assertA(0 == archive_read_support_format_all(a)); - assertA(0 == archive_read_open_filename(a, reffile, bs)); - assertA(0 == archive_read_next_header(a, &ae)); - assertEqualString("test.txt.txt", archive_entry_pathname(ae)); + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { + skipping( + "7zip:lzma decoding is not supported on this platform"); + } else { + extract_reference_file(reffile); + assertA(0 == archive_read_support_filter_all(a)); + assertA(0 == archive_read_support_format_all(a)); + assertA(0 == archive_read_open_filename(a, reffile, bs)); - assertA(size == archive_read_data(a, buff, size)); - assertEqualMem(buff, test_txt, size); + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("test.txt.txt", archive_entry_pathname(ae)); - assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); - assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + assertA(size == archive_read_data(a, buff, size)); + assertEqualMem(buff, test_txt, size); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } DEFINE_TEST(test_read_format_7zip_extract_second) @@ -1597,9 +1618,9 @@ DEFINE_TEST(test_read_format_7zip_lzma2_powerpc) assert((a = archive_read_new()) != NULL); - if (ARCHIVE_OK != archive_read_support_filter_gzip(a)) { + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { skipping( - "7zip:deflate decoding is not supported on this platform"); + "7zip:lzma decoding is not supported on this platform"); } else { test_powerpc_filter("test_read_format_7zip_lzma2_powerpc.7z"); } diff --git a/libarchive/test/test_read_format_rar5.c b/libarchive/test/test_read_format_rar5.c index fd233277bc1..6ab0d236a1e 100644 --- a/libarchive/test/test_read_format_rar5.c +++ b/libarchive/test/test_read_format_rar5.c @@ -1111,6 +1111,18 @@ DEFINE_TEST(test_read_format_rar5_nonempty_dir_stream) EPILOGUE(); } +DEFINE_TEST(test_read_format_rar5_nonempty_dir_data) +{ + PROLOGUE("test_read_format_rar5_dirdata.rar"); + + /* This archive is invalid. It declares a directory entry with nonzero + data size. */ + + assertA(archive_read_next_header(a, &ae) == ARCHIVE_FATAL); + + EPILOGUE(); +} + DEFINE_TEST(test_read_format_rar5_fileattr) { unsigned long set, clear, flag; @@ -1428,3 +1440,57 @@ DEFINE_TEST(test_read_format_rar5_data_ready_pointer_leak) EPILOGUE(); } + +DEFINE_TEST(test_read_format_rar5_only_crypt_exfld) +{ + /* GH #2711 */ + + char buf[4096]; + PROLOGUE("test_read_format_rar5_only_crypt_exfld.rar"); + + /* The reader should allow iteration through files, but should fail + during data extraction. */ + + assertA(archive_read_next_header(a, &ae) == ARCHIVE_OK); + assertA(archive_read_data(a, buf, sizeof(buf)) == ARCHIVE_FATAL); + + /* The reader should also provide a valid error message. */ + assertA(archive_error_string(a) != NULL); + + EPILOGUE(); +} + +DEFINE_TEST(test_read_format_rar5_only_unsupported_exfld) +{ + /* GH #2711 */ + + char buf[4096]; + PROLOGUE("test_read_format_rar5_unsupported_exfld.rar"); + + /* The reader should allow iteration through files, and it should + succeed with data extraction. */ + + assertA(archive_read_next_header(a, &ae) == ARCHIVE_OK); + + /* 48 is the expected number of bytes that should be extracted */ + assertA(archive_read_data(a, buf, sizeof(buf)) == 48); + + EPILOGUE(); +} + +DEFINE_TEST(test_read_format_rar5_invalidhash_and_validhtime_exfld) +{ + /* GH #2711 */ + + char buf[4096]; + PROLOGUE("test_read_format_rar5_invalid_hash_valid_htime_exfld.rar"); + + /* The reader should report an error when trying to process this data. + Returning EOF here means that the reader has failed to identify + malformed structure. */ + + assertA(archive_read_next_header(a, &ae) < 0); + assertA(archive_read_data(a, buf, sizeof(buf)) < 0); + + EPILOGUE(); +} diff --git a/libarchive/test/test_read_format_rar5_dirdata.rar.uu b/libarchive/test/test_read_format_rar5_dirdata.rar.uu new file mode 100644 index 00000000000..c7928f344a8 --- /dev/null +++ b/libarchive/test/test_read_format_rar5_dirdata.rar.uu @@ -0,0 +1,6 @@ +begin 644 - +M4F%R(1H'`0`BD'[;,`$%,#8P`0&`@("``B?GD;$U`@(+@X``"_C5%:2#``(` +M`#"``S`P,#`P,#`P,#!);S#6KA',@]:N$?*IN;YV[8"1S>?4^`,#`R,#`P,# +-`P,#1)'C@XX*4`O.^P`` +` +end diff --git a/libarchive/test/test_read_format_rar5_invalid_hash_valid_htime_exfld.rar.uu b/libarchive/test/test_read_format_rar5_invalid_hash_valid_htime_exfld.rar.uu new file mode 100644 index 00000000000..399acd814ae --- /dev/null +++ b/libarchive/test/test_read_format_rar5_invalid_hash_valid_htime_exfld.rar.uu @@ -0,0 +1,6 @@ +begin 644 - +M4F%R(1H'`0`SDK7E"@$%!@`%`0&`@`#^T/5L)`(###$$,>V#`D840I@``0AF +M:6QE+G1X=`@"OX0]``$"`P(#`&EN=F%L:60@2$%32"!E>'1R82P@86YD(&QA +>=&5R(&$@=F%L:60@2%1)344@97AT)!,``0AF +M:6QE+G1X="0!```&``````````````````````````````````````````!R +M87(U('-T;W)E9"!F:6QE('=I=&@@;VYL>2!A($-265!4(&5X=')A(&9I96QD +'(#W?A@(%!``` +` +end diff --git a/libarchive/test/test_read_format_rar5_unsupported_exfld.rar.uu b/libarchive/test/test_read_format_rar5_unsupported_exfld.rar.uu new file mode 100644 index 00000000000..16b456bf487 --- /dev/null +++ b/libarchive/test/test_read_format_rar5_unsupported_exfld.rar.uu @@ -0,0 +1,6 @@ +begin 644 - +M4F%R(1H'`0`SDK7E"@$%!@`%`0&`@`#>[JDS)@(##C`$,.V#`BX6Z[0``0AF +M:6QE+G1X=`W_____#WA6-!(`````^E#_1.OY96VEI*Z #endif -#include "err.h" +#include "lafe_err.h" static void lafe_vwarnc(int, const char *, va_list) __LA_PRINTFLIKE(2, 0); diff --git a/libarchive_fe/err.h b/libarchive_fe/lafe_err.h similarity index 100% rename from libarchive_fe/err.h rename to libarchive_fe/lafe_err.h diff --git a/libarchive_fe/line_reader.c b/libarchive_fe/line_reader.c index 7f0429ece3c..0af9db53c0a 100644 --- a/libarchive_fe/line_reader.c +++ b/libarchive_fe/line_reader.c @@ -31,7 +31,7 @@ #include #include -#include "err.h" +#include "lafe_err.h" #include "line_reader.h" #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) diff --git a/libarchive_fe/passphrase.c b/libarchive_fe/passphrase.c index 527ad2d6365..1b7a5045366 100644 --- a/libarchive_fe/passphrase.c +++ b/libarchive_fe/passphrase.c @@ -61,7 +61,7 @@ #include #endif -#include "err.h" +#include "lafe_err.h" #include "passphrase.h" #ifndef HAVE_READPASSPHRASE diff --git a/tar/CMakeLists.txt b/tar/CMakeLists.txt index b09426945b9..c082c66e4b0 100644 --- a/tar/CMakeLists.txt +++ b/tar/CMakeLists.txt @@ -18,8 +18,8 @@ IF(ENABLE_TAR) subst.c util.c write.c - ../libarchive_fe/err.c - ../libarchive_fe/err.h + ../libarchive_fe/lafe_err.c + ../libarchive_fe/lafe_err.h ../libarchive_fe/lafe_platform.h ../libarchive_fe/line_reader.c ../libarchive_fe/line_reader.h diff --git a/tar/bsdtar.c b/tar/bsdtar.c index 53ac135f012..92e86fd6bd9 100644 --- a/tar/bsdtar.c +++ b/tar/bsdtar.c @@ -55,7 +55,7 @@ #endif #include "bsdtar.h" -#include "err.h" +#include "lafe_err.h" #if ARCHIVE_VERSION_NUMBER < 4000000 && !defined(_PATH_DEFTAPE) // Libarchive 4.0 and later will NOT define _PATH_DEFTAPE @@ -182,6 +182,11 @@ main(int argc, char **argv) /* Ignore SIGPIPE signals. */ sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); +#endif +#ifdef SIGCHLD + /* Do not ignore SIGCHLD. */ + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); #endif } #endif diff --git a/tar/bsdtar.h b/tar/bsdtar.h index 45dfeed7dce..782d36d6f75 100644 --- a/tar/bsdtar.h +++ b/tar/bsdtar.h @@ -16,6 +16,12 @@ #define ENV_WRITER_OPTIONS "TAR_WRITER_OPTIONS" #define IGNORE_WRONG_MODULE_NAME "__ignore_wrong_module_name__," +#if defined(_MSC_VER ) && (_MSC_VER < 1927 ) /* Check if compiler pre-dated Visual Studio 2019 Release 16.8 */ +#define ARCHIVE_RESTRICT +#else +#define ARCHIVE_RESTRICT restrict +#endif + struct creation_set; /* * The internal state for the "bsdtar" program. @@ -188,7 +194,7 @@ int edit_pathname(struct bsdtar *, struct archive_entry *); void edit_mtime(struct bsdtar *, struct archive_entry *); int need_report(void); int pathcmp(const char *a, const char *b); -void safe_fprintf(FILE * restrict, const char * restrict fmt, ...) __LA_PRINTF(2, 3); +void safe_fprintf(FILE * ARCHIVE_RESTRICT, const char * ARCHIVE_RESTRICT fmt, ...) __LA_PRINTF(2, 3); void set_chdir(struct bsdtar *, const char *newdir); const char *tar_i64toa(int64_t); void tar_mode_c(struct bsdtar *bsdtar); diff --git a/tar/bsdtar_windows.c b/tar/bsdtar_windows.c index a63f27e5053..da49b4363b4 100644 --- a/tar/bsdtar_windows.c +++ b/tar/bsdtar_windows.c @@ -24,7 +24,7 @@ #include #include "bsdtar.h" -#include "err.h" +#include "lafe_err.h" /* This may actually not be needed anymore. * TODO: Review the error handling for chdir() failures and diff --git a/tar/bsdtar_windows.h b/tar/bsdtar_windows.h index d18239782ff..6bedb370269 100644 --- a/tar/bsdtar_windows.h +++ b/tar/bsdtar_windows.h @@ -11,6 +11,7 @@ #include #include #include +#include #ifndef PRId64 #define PRId64 "I64" diff --git a/tar/cmdline.c b/tar/cmdline.c index c766c1a52db..309be312c94 100644 --- a/tar/cmdline.c +++ b/tar/cmdline.c @@ -22,7 +22,7 @@ #endif #include "bsdtar.h" -#include "err.h" +#include "lafe_err.h" /* * Short options for tar. Please keep this sorted. diff --git a/tar/creation_set.c b/tar/creation_set.c index 6883090418b..51f803354a5 100644 --- a/tar/creation_set.c +++ b/tar/creation_set.c @@ -15,7 +15,7 @@ #endif #include "bsdtar.h" -#include "err.h" +#include "lafe_err.h" struct creation_set { char *create_format; diff --git a/tar/read.c b/tar/read.c index 8563fe714f9..7cbcfb19ff0 100644 --- a/tar/read.c +++ b/tar/read.c @@ -57,7 +57,7 @@ #endif #include "bsdtar.h" -#include "err.h" +#include "lafe_err.h" struct progress_data { struct bsdtar *bsdtar; diff --git a/tar/subst.c b/tar/subst.c index 5546b5f93b1..a5d644dc5a7 100644 --- a/tar/subst.c +++ b/tar/subst.c @@ -25,7 +25,7 @@ #define REG_BASIC 0 #endif -#include "err.h" +#include "lafe_err.h" struct subst_rule { struct subst_rule *next; diff --git a/tar/test/CMakeLists.txt b/tar/test/CMakeLists.txt index 7a3803bdcb6..d3c0bd22af9 100644 --- a/tar/test/CMakeLists.txt +++ b/tar/test/CMakeLists.txt @@ -14,6 +14,7 @@ IF(ENABLE_TAR AND ENABLE_TEST) test_0.c test_basic.c test_copy.c + test_crlf_mtree.c test_empty_mtree.c test_extract_tar_Z.c test_extract_tar_bz2.c diff --git a/tar/test/test_crlf_mtree.c b/tar/test/test_crlf_mtree.c new file mode 100644 index 00000000000..5ef8811369c --- /dev/null +++ b/tar/test/test_crlf_mtree.c @@ -0,0 +1,74 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Arshan Khanifar + * under sponsorship from the FreeBSD Foundation. + */ +#include "test.h" + +DEFINE_TEST(test_crlf_mtree) +{ + char *p0; + size_t s; + int r; + p0 = NULL; + char *content = "#mtree\r\n" + "f type=file uname=\\\r\n" + "root gname=root mode=0755 content=bar/foo\r\n" + "g type=file uname=root gname=root mode=0755 content=bar/goo\r\n"; + char *filename = "output.tar"; +#if defined(_WIN32) && !defined(__CYGWIN__) + char *p; +#endif + + /* an absolute path to mtree file */ + char *mtree_file = "/METALOG.mtree"; + char *absolute_path = malloc(strlen(testworkdir) + strlen(mtree_file) + 1); + strcpy(absolute_path, testworkdir); + strcat(absolute_path, mtree_file ); + + /* Create an archive using an mtree file. */ + assertMakeFile(absolute_path, 0777, content); + assertMakeDir("bar", 0775); + assertMakeFile("bar/foo", 0777, "abc"); + assertMakeFile("bar/goo", 0777, "abc"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + p = absolute_path; + while(*p != '\0') { + if (*p == '/') + *p = '\\'; + p++; + } + + r = systemf("%s -cf %s @%s >step1.out 2>step1.err", testprog, filename, absolute_path); + failure("Error invoking %s -cf %s -C bar @%s", testprog, filename, absolute_path); +#else + r = systemf("%s -cf %s \"@%s\" >step1.out 2>step1.err", testprog, filename, absolute_path); + failure("Error invoking %s -cf %s -C bar \"@%s\"", testprog, filename, absolute_path); +#endif + + assertEqualInt(r, 0); + assertEmptyFile("step1.out"); + assertEmptyFile("step1.err"); + + /* Do validation of the constructed archive. */ + + p0 = slurpfile(&s, "output.tar"); + if (!assert(p0 != NULL)) + goto done; + if (!assert(s >= 2048)) + goto done; + assertEqualMem(p0 + 0, "f", 2); + assertEqualMem(p0 + 512, "abc", 4); + assertEqualMem(p0 + 1024, "g", 2); + assertEqualMem(p0 + 1536, "abc", 4); +done: + free(p0); + free(absolute_path); +} + + diff --git a/tar/test/test_option_safe_writes.c b/tar/test/test_option_safe_writes.c index b88479bc5f3..d30b9a74592 100644 --- a/tar/test/test_option_safe_writes.c +++ b/tar/test/test_option_safe_writes.c @@ -16,11 +16,12 @@ DEFINE_TEST(test_option_safe_writes) assertMakeFile("d", 0644, "c"); assertMakeFile("fs", 0644, "d"); assertMakeFile("ds", 0644, "e"); + assertMakeDir("fd", 0755); assertEqualInt(0, chdir("..")); /* Tar files up */ assertEqualInt(0, - systemf("%s -c -C in -f t.tar f fh d fs ds " + systemf("%s -c -C in -f t.tar f fh d fs ds fd " ">pack.out 2>pack.err", testprog)); /* Verify that nothing went to stdout or stderr. */ @@ -32,6 +33,7 @@ DEFINE_TEST(test_option_safe_writes) assertEqualInt(0, chdir("out")); assertMakeFile("f", 0644, "a"); assertMakeHardlink("fh", "f"); + assertMakeFile("fd", 0644, "b"); assertMakeDir("d", 0755); if (canSymlink()) { assertMakeSymlink("fs", "f", 0); @@ -55,4 +57,5 @@ DEFINE_TEST(test_option_safe_writes) assertTextFileContents("c","d"); assertTextFileContents("d","fs"); assertTextFileContents("e","ds"); + assertIsDir("fd", 0755); } diff --git a/tar/util.c b/tar/util.c index c99f6779756..fc5e15cb039 100644 --- a/tar/util.c +++ b/tar/util.c @@ -41,7 +41,7 @@ #endif #include "bsdtar.h" -#include "err.h" +#include "lafe_err.h" #include "passphrase.h" static size_t bsdtar_expand_char(char *, size_t, size_t, char); @@ -682,6 +682,7 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) { char tmp[100]; size_t w; + size_t sw; const char *p; const char *fmt; time_t tim; @@ -769,8 +770,8 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) ltime = localtime(&tim); #endif if (ltime) - strftime(tmp, sizeof(tmp), fmt, ltime); - else + sw = strftime(tmp, sizeof(tmp), fmt, ltime); + if (!ltime || !sw) sprintf(tmp, "-- -- ----"); fprintf(out, " %s ", tmp); safe_fprintf(out, "%s", archive_entry_pathname(entry)); diff --git a/tar/write.c b/tar/write.c index 21984e980eb..9e6c97b580b 100644 --- a/tar/write.c +++ b/tar/write.c @@ -58,7 +58,7 @@ #endif #include "bsdtar.h" -#include "err.h" +#include "lafe_err.h" #include "line_reader.h" #ifndef O_BINARY @@ -111,7 +111,32 @@ seek_file(int fd, int64_t offset, int whence) return (SetFilePointerEx((HANDLE)_get_osfhandle(fd), distance, NULL, FILE_BEGIN) ? 1 : -1); } -#define open _open + +static int +_open_wrap_sopen(char const *const path, int const oflag, ...) +{ + va_list ap; + int r, pmode; + + pmode = 0; + if (oflag & _O_CREAT) + { + va_start(ap, oflag); + pmode = va_arg(ap, int); + va_end(ap); + } + + _sopen_s(&r, path, oflag, _SH_DENYNO, pmode & 0600); + if (r < 0) + { + /* _sopen_s populates errno */ + return -1; + } + + return r; +} + +#define open _open_wrap_sopen #define close _close #define read _read #ifdef lseek diff --git a/test_utils/test_common.h b/test_utils/test_common.h index 064f0a6ec24..a9df300e3be 100644 --- a/test_utils/test_common.h +++ b/test_utils/test_common.h @@ -340,8 +340,14 @@ int canGrzip(void); /* Return true if this platform can run the "gzip" program. */ int canGzip(void); -/* Return true if this platform can run the specified command. */ -int canRunCommand(const char *); +/* Return true if this platform can run the specified command. + * + * Result can be optionally cached with `*tested`: + * - 0 if not tested yet + * - <0 if already tested negative + * - >0 if already tested positive + */ +int canRunCommand(const char *cmd, int *tested); /* Return true if this platform can run the "lrzip" program. */ int canLrzip(void); diff --git a/test_utils/test_main.c b/test_utils/test_main.c index afd077fc6d0..f4d443060d8 100644 --- a/test_utils/test_main.c +++ b/test_utils/test_main.c @@ -2523,167 +2523,77 @@ static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */ #else static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */ #endif + +/* + * Can this platform run the specified command? + */ +int +canRunCommand(const char *cmd, int *tested) +{ + int value = tested ? *tested : 0; + if (!value) { + value = systemf("%s %s", cmd, redirectArgs) ? -1 : +1; + if (tested) + *tested = value; + } + return (value > 0); +} + +#define CAN_RUN_FUNC(Program, Command) \ + int can##Program(void) { \ + static int tested = 0; \ + return canRunCommand((Command), &tested); \ + } + /* * Can this platform run the bzip2 program? */ -int -canBzip2(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("bzip2 --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Bzip2, "bzip2 --help") /* * Can this platform run the grzip program? */ -int -canGrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("grzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Grzip, "grzip -V") /* * Can this platform run the gzip program? */ -int -canGzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("gzip --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Gzip, "gzip --help") /* * Can this platform run the lrzip program? */ -int -canRunCommand(const char *cmd) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("%s %s", cmd, redirectArgs) == 0) - value = 1; - } - return (value); -} - -int -canLrzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lrzip -V %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Lrzip, "lrzip -V") /* * Can this platform run the lz4 program? */ -int -canLz4(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lz4 --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Lz4, "lz4 --help") /* * Can this platform run the zstd program? */ -int -canZstd(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("zstd --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Zstd, "zstd --help") /* * Can this platform run the lzip program? */ -int -canLzip(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzip --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Lzip, "lzip --help") /* * Can this platform run the lzma program? */ -int -canLzma(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzma --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Lzma, "lzma --help") /* * Can this platform run the lzop program? */ -int -canLzop(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("lzop --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Lzop, "lzop --help") /* * Can this platform run the xz program? */ -int -canXz(void) -{ - static int tested = 0, value = 0; - if (!tested) { - tested = 1; - if (systemf("xz --help %s", redirectArgs) == 0) - value = 1; - } - return (value); -} +CAN_RUN_FUNC(Xz, "xz --help") /* * Can this filesystem handle nodump flags. @@ -3581,7 +3491,7 @@ set_environment(const char *key, const char *value) * Enforce C locale for (sub)processes. */ static void -set_c_locale() +set_c_locale(void) { static const char *lcs[] = { "LC_ADDRESS", @@ -4184,6 +4094,9 @@ main(int argc, char **argv) if (testprogfile == NULL) { tmp2_len = strlen(testprogdir) + 1 + strlen(PROGRAM) + 1; +#if defined(_WIN32) && !defined(__CYGWIN__) + tmp2_len += 4; +#endif if ((tmp2 = malloc(tmp2_len)) == NULL) { fprintf(stderr, "ERROR: Out of memory."); @@ -4192,6 +4105,9 @@ main(int argc, char **argv) strncpy(tmp2, testprogdir, tmp2_len); strncat(tmp2, "/", tmp2_len); strncat(tmp2, PROGRAM, tmp2_len); +#if defined(_WIN32) && !defined(__CYGWIN__) + strncat(tmp2, ".exe", tmp2_len); +#endif testprogfile = tmp2; } diff --git a/unzip/CMakeLists.txt b/unzip/CMakeLists.txt index 586245b67fd..f3c62cb339c 100644 --- a/unzip/CMakeLists.txt +++ b/unzip/CMakeLists.txt @@ -16,8 +16,8 @@ IF(ENABLE_UNZIP) la_getline.c la_getline.h la_queue.h - ../libarchive_fe/err.c - ../libarchive_fe/err.h + ../libarchive_fe/lafe_err.c + ../libarchive_fe/lafe_err.h ../libarchive_fe/lafe_platform.h ../libarchive_fe/passphrase.c ../libarchive_fe/passphrase.h diff --git a/unzip/bsdunzip.c b/unzip/bsdunzip.c index 621afbeb9d6..1b520e84169 100644 --- a/unzip/bsdunzip.c +++ b/unzip/bsdunzip.c @@ -29,6 +29,9 @@ #ifdef HAVE_LOCALE_H #include #endif +#ifdef HAVE_SIGNAL_H +#include +#endif #ifdef HAVE_STDARG_H #include #endif @@ -54,7 +57,7 @@ #include "bsdunzip.h" #include "passphrase.h" -#include "err.h" +#include "lafe_err.h" /* command-line options */ static int a_opt; /* convert EOL */ @@ -1187,6 +1190,16 @@ main(int argc, char *argv[]) const char *zipfile; int nopts; +#if defined(HAVE_SIGACTION) && defined(SIGCHLD) + { /* Do not ignore SIGCHLD. */ + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGCHLD, &sa, NULL); + } +#endif + lafe_setprogname(*argv, "bsdunzip"); #if HAVE_SETLOCALE diff --git a/unzip/cmdline.c b/unzip/cmdline.c index 8afddedd5ea..8e6eedd2321 100644 --- a/unzip/cmdline.c +++ b/unzip/cmdline.c @@ -21,7 +21,7 @@ #endif #include "bsdunzip.h" -#include "err.h" +#include "lafe_err.h" /* * Short options for bsdunzip. Please keep this sorted. diff --git a/unzip/test/CMakeLists.txt b/unzip/test/CMakeLists.txt index 789cfb7e492..57ed651a58b 100644 --- a/unzip/test/CMakeLists.txt +++ b/unzip/test/CMakeLists.txt @@ -5,7 +5,7 @@ ############################################ IF(ENABLE_UNZIP AND ENABLE_TEST) SET(bsdunzip_test_SOURCES - ../../libarchive_fe/err.c + ../../libarchive_fe/lafe_err.c ../../test_utils/test_utils.c ../../test_utils/test_main.c test.h diff --git a/unzip/test/test_C.c b/unzip/test/test_C.c index 66835c8406f..d386bd61e85 100644 --- a/unzip/test/test_C.c +++ b/unzip/test/test_C.c @@ -9,6 +9,7 @@ /* Test C arg - match case-insensitive */ DEFINE_TEST(test_C) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -19,4 +20,7 @@ DEFINE_TEST(test_C) assertEmptyFile("test.err"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_L.c b/unzip/test/test_L.c index 5b004d5d570..85b43f59254 100644 --- a/unzip/test/test_L.c +++ b/unzip/test/test_L.c @@ -9,6 +9,7 @@ /* Test L arg - make names lowercase */ DEFINE_TEST(test_L) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,4 +23,7 @@ DEFINE_TEST(test_L) assertTextFileContents("contents b\n", "test_basic/b"); assertTextFileContents("contents c\n", "test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/caps"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_P_encryption.c b/unzip/test/test_P_encryption.c index e2cf3cda0eb..ed08a068811 100644 --- a/unzip/test/test_P_encryption.c +++ b/unzip/test/test_P_encryption.c @@ -14,9 +14,13 @@ DEFINE_TEST(test_P_encryption) 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"); + if (r == 256) { + assertTextFileContents("unzip: Decryption is unsupported due to lack of crypto library\n", "test.err"); + } else { + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); - assertTextFileContents("plaintext\n", "encrypted/file.txt"); + assertTextFileContents("plaintext\n", "encrypted/file.txt"); + } } diff --git a/unzip/test/test_basic.c b/unzip/test/test_basic.c index 1f37dcd416a..3a884aa30e5 100644 --- a/unzip/test/test_basic.c +++ b/unzip/test/test_basic.c @@ -9,6 +9,7 @@ /* This test just does a basic zip decompression */ DEFINE_TEST(test_basic) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,4 +23,7 @@ DEFINE_TEST(test_basic) assertTextFileContents("contents b\n", "test_basic/b"); assertTextFileContents("contents c\n", "test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_d.c b/unzip/test/test_d.c index ea67246207f..cd7c3dfd97a 100644 --- a/unzip/test/test_d.c +++ b/unzip/test/test_d.c @@ -9,6 +9,7 @@ /* Test d arg - extract to target dir - before zipfile argument */ DEFINE_TEST(test_d_before_zipfile) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,11 +23,15 @@ DEFINE_TEST(test_d_before_zipfile) assertTextFileContents("contents b\n", "foobar/test_basic/b"); assertTextFileContents("contents c\n", "foobar/test_basic/c"); assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } /* Test d arg - extract to target dir - after zipfile argument */ DEFINE_TEST(test_d_after_zipfile) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -40,4 +45,7 @@ DEFINE_TEST(test_d_after_zipfile) assertTextFileContents("contents b\n", "foobar/test_basic/b"); assertTextFileContents("contents c\n", "foobar/test_basic/c"); assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_doubledash.c b/unzip/test/test_doubledash.c index 4467213dbb8..db0445ec3c2 100644 --- a/unzip/test/test_doubledash.c +++ b/unzip/test/test_doubledash.c @@ -9,6 +9,7 @@ /* Test double dash arg - swallow "--" and use next argument as file name */ DEFINE_TEST(test_doubledash) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,4 +23,7 @@ DEFINE_TEST(test_doubledash) assertTextFileContents("contents b\n", "test_basic/b"); assertTextFileContents("contents c\n", "test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_glob.c b/unzip/test/test_glob.c index b53aa16fd85..589ff1c55ef 100644 --- a/unzip/test/test_glob.c +++ b/unzip/test/test_glob.c @@ -9,6 +9,7 @@ /* Test that the glob works */ DEFINE_TEST(test_glob) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,4 +23,7 @@ DEFINE_TEST(test_glob) assertTextFileContents("contents b\n", "test_basic/b"); assertFileNotExists("test_basic/c"); assertFileNotExists("test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_j.c b/unzip/test/test_j.c index b87229f42e2..1fba8ca207e 100644 --- a/unzip/test/test_j.c +++ b/unzip/test/test_j.c @@ -9,6 +9,7 @@ /* Test j arg - don't make directories */ DEFINE_TEST(test_j) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,4 +23,7 @@ DEFINE_TEST(test_j) assertTextFileContents("contents b\n", "b"); assertTextFileContents("contents c\n", "c"); assertTextFileContents("contents CAPS\n", "CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_n.c b/unzip/test/test_n.c index bb75c5d7696..a13623ce23d 100644 --- a/unzip/test/test_n.c +++ b/unzip/test/test_n.c @@ -9,6 +9,7 @@ /* Test n arg - don't overwrite existing files */ DEFINE_TEST(test_n) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -26,4 +27,7 @@ DEFINE_TEST(test_n) assertTextFileContents("orig b\n", "test_basic/b"); assertTextFileContents("contents c\n", "test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_o.c b/unzip/test/test_o.c index 64f94677444..8c48348c41a 100644 --- a/unzip/test/test_o.c +++ b/unzip/test/test_o.c @@ -9,6 +9,7 @@ /* Test o arg - overwrite existing files */ DEFINE_TEST(test_o) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -25,4 +26,7 @@ DEFINE_TEST(test_o) assertTextFileContents("contents b\n", "test_basic/b"); assertTextFileContents("contents c\n", "test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_p.c b/unzip/test/test_p.c index 8bfffbe5dc3..13a7765463e 100644 --- a/unzip/test/test_p.c +++ b/unzip/test/test_p.c @@ -9,6 +9,7 @@ /* Test p arg - Print to stdout */ DEFINE_TEST(test_p) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -17,4 +18,7 @@ DEFINE_TEST(test_p) assertEqualInt(0, r); assertTextFileContents("contents a\ncontents b\ncontents c\ncontents CAPS\n", "test.out"); assertEmptyFile("test.err"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_q.c b/unzip/test/test_q.c index 13222a48399..0579e8028d7 100644 --- a/unzip/test/test_q.c +++ b/unzip/test/test_q.c @@ -9,6 +9,7 @@ /* Test q arg - Quiet */ DEFINE_TEST(test_q) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,4 +23,7 @@ DEFINE_TEST(test_q) assertTextFileContents("contents b\n", "test_basic/b"); assertTextFileContents("contents c\n", "test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_singlefile.c b/unzip/test/test_singlefile.c index a72811f046d..a5a35ecacc4 100644 --- a/unzip/test/test_singlefile.c +++ b/unzip/test/test_singlefile.c @@ -9,6 +9,7 @@ /* Ensure single-file zips work */ DEFINE_TEST(test_singlefile) { +#ifdef HAVE_LIBZ const char *reffile = "test_singlefile.zip"; int r; @@ -19,4 +20,7 @@ DEFINE_TEST(test_singlefile) assertEmptyFile("test.err"); assertTextFileContents("hello\n", "file.txt"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_t.c b/unzip/test/test_t.c index 55a516fc636..7565830915c 100644 --- a/unzip/test/test_t.c +++ b/unzip/test/test_t.c @@ -9,6 +9,7 @@ /* Test t arg - Test zip contents */ DEFINE_TEST(test_t) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -17,4 +18,7 @@ DEFINE_TEST(test_t) assertEqualInt(0, r); assertNonEmptyFile("test.out"); assertEmptyFile("test.err"); +#else + skipping("zlib not available"); +#endif } diff --git a/unzip/test/test_x.c b/unzip/test/test_x.c index 959beb1950d..43a2085dc5b 100644 --- a/unzip/test/test_x.c +++ b/unzip/test/test_x.c @@ -9,6 +9,7 @@ /* Test x arg with single exclude path */ DEFINE_TEST(test_x_single) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -22,11 +23,15 @@ DEFINE_TEST(test_x_single) assertTextFileContents("contents b\n", "test_basic/b"); assertFileNotExists("test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } /* Test x arg with multiple exclude paths */ DEFINE_TEST(test_x_multiple) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -40,11 +45,15 @@ DEFINE_TEST(test_x_multiple) assertFileNotExists("test_basic/b"); assertFileNotExists("test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif } /* Test x arg with multiple exclude paths and a d arg afterwards */ DEFINE_TEST(test_x_multiple_with_d) { +#ifdef HAVE_LIBZ const char *reffile = "test_basic.zip"; int r; @@ -58,4 +67,7 @@ DEFINE_TEST(test_x_multiple_with_d) assertFileNotExists("foobar/test_basic/b"); assertFileNotExists("foobar/test_basic/c"); assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS"); +#else + skipping("zlib not available"); +#endif }