mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Merge topic 'update-libarchive'
e420259ecclibarchive: Restore compilation of archive_parse_date within CMakeLib5b530ba347libarchive: Set build options the way we need for CMakedbcd6402c3Utilities: Update hard-coded try_compile results for libarchive 3.8.9357710687fMerge branch 'upstream-LibArchive' into update-libarchive94ae161ab5LibArchive 2026-07-28 (27cbc782)46ccf27ae3libarchive: Update script to get 3.8.916984b0124ctest: Fix STOP_TIME for vendored archive_parse_date from libarchive 3.8.8+ Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: buildbot <buildbot@kitware.com> Merge-request: !12398
This commit is contained in:
@@ -288,7 +288,8 @@ else()
|
||||
set(ENABLE_PCREPOSIX OFF)
|
||||
set(ENABLE_PCRE2POSIX OFF)
|
||||
set(ENABLE_LIBGCC OFF)
|
||||
set(ENABLE_CNG OFF)
|
||||
set(ENABLE_CLANG_TIDY OFF)
|
||||
set(ENABLE_CNG ON)
|
||||
set(ENABLE_TAR OFF)
|
||||
set(ENABLE_TAR_SHARED OFF)
|
||||
set(ENABLE_CPIO OFF)
|
||||
|
||||
+1
-1
@@ -2864,7 +2864,7 @@ void cmCTest::SetStopTime(std::string const& time_str)
|
||||
|
||||
tzone_offset *= 100;
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
|
||||
snprintf(buf, sizeof(buf), "%d-%02d-%02d %s %+05i", lctime->tm_year + 1900,
|
||||
lctime->tm_mon + 1, lctime->tm_mday, time_str.c_str(),
|
||||
tzone_offset);
|
||||
|
||||
|
||||
@@ -12,11 +12,11 @@ bool parse_date()
|
||||
std::time_t now;
|
||||
std::time(&now);
|
||||
{
|
||||
std::time_t t = cm_parse_date(now, "20000101 00:01:02 -0000");
|
||||
std::time_t t = cm_parse_date(now, "2000-01-01 00:01:02 -0000");
|
||||
ASSERT_EQUAL(t, 946684862);
|
||||
}
|
||||
{
|
||||
std::time_t t = cm_parse_date(now, "20380601 00:01:02 -0000");
|
||||
std::time_t t = cm_parse_date(now, "2038-06-01 00:01:02 -0000");
|
||||
ASSERT_EQUAL(t, sizeof(time_t) <= 4 ? -1 : 2158963262);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -8,7 +8,7 @@ readonly name="LibArchive"
|
||||
readonly ownership="LibArchive Upstream <libarchive-discuss@googlegroups.com>"
|
||||
readonly subtree="Utilities/cmlibarchive"
|
||||
readonly repo="https://github.com/libarchive/libarchive.git"
|
||||
readonly tag="v3.8.6"
|
||||
readonly tag="v3.8.9"
|
||||
readonly shortlog=false
|
||||
readonly exact_tree_match=false
|
||||
readonly paths="
|
||||
|
||||
@@ -33,6 +33,7 @@ if(WIN32)
|
||||
set(HAVE_ARC4RANDOM 0)
|
||||
set(HAVE_ARC4RANDOM_BUF 0)
|
||||
set(HAVE_ARPA_TFTP_H 0)
|
||||
set(HAVE_BCRYPT_H 1)
|
||||
set(HAVE_BSWAP_16 0)
|
||||
set(HAVE_BSWAP_32 0)
|
||||
set(HAVE_BSWAP_64 0)
|
||||
@@ -259,7 +260,10 @@ if(WIN32)
|
||||
set(HAVE_SIZEOF_CURL_SOCKET_T 1)
|
||||
set(SIZEOF_CURL_SOCKET_T 8)
|
||||
|
||||
if(NOT MINGW)
|
||||
if(MINGW)
|
||||
set(HAVE_GETTIMEOFDAY 1)
|
||||
else()
|
||||
set(HAVE_GETTIMEOFDAY 0)
|
||||
set(HAVE_STRTOK_R 0)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -277,19 +277,15 @@ OPTION(ENABLE_CPIO "Enable cpio building" ON)
|
||||
OPTION(ENABLE_CPIO_SHARED "Enable dynamic build of cpio" FALSE)
|
||||
OPTION(ENABLE_CAT "Enable cat building" ON)
|
||||
OPTION(ENABLE_CAT_SHARED "Enable dynamic build of cat" FALSE)
|
||||
IF(WIN32 AND NOT CYGWIN)
|
||||
SET(ENABLE_UNZIP FALSE)
|
||||
SET(ENABLE_UNZIP_SHARED FALSE)
|
||||
ELSE()
|
||||
OPTION(ENABLE_UNZIP "Enable unzip building" ON)
|
||||
OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE)
|
||||
ENDIF()
|
||||
OPTION(ENABLE_UNZIP "Enable unzip building" ON)
|
||||
OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE)
|
||||
OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
|
||||
OPTION(ENABLE_ACL "Enable ACL support" ON)
|
||||
OPTION(ENABLE_ICONV "Enable iconv support" ON)
|
||||
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)
|
||||
OPTION(ENABLE_CLANG_TIDY "Enable custom build-time code health checks" OFF)
|
||||
|
||||
IF(WIN32 AND MSVC)
|
||||
OPTION(MSVC_USE_STATIC_CRT "Use static CRT" OFF)
|
||||
@@ -372,27 +368,69 @@ INCLUDE(CheckTypeSize)
|
||||
#
|
||||
# Generate list.h
|
||||
#
|
||||
MACRO (GENERATE_LIST_H _listfile _cmlist __list_sources)
|
||||
MACRO (GENERATE_LIST_H _listfile _cmlist _target __list_sources)
|
||||
SET(_argv ${ARGV})
|
||||
# Remove _listfile and _cmlist from _argv
|
||||
LIST(REMOVE_AT _argv 0 1)
|
||||
IF (NOT EXISTS "${_listfile}" OR
|
||||
${_cmlist} IS_NEWER_THAN "${_listfile}")
|
||||
|
||||
MESSAGE(STATUS "Generating ${_listfile}")
|
||||
FILE(WRITE ${_listfile} "")
|
||||
FOREACH (testfile ${_argv})
|
||||
IF (testfile MATCHES "^test_[^/]+[.]c$")
|
||||
FILE(STRINGS ${testfile} testvar REGEX "^DEFINE_TEST")
|
||||
FOREACH (deftest ${testvar})
|
||||
FILE(APPEND ${_listfile} "${deftest}\n")
|
||||
ENDFOREACH (deftest)
|
||||
ENDIF (testfile MATCHES "^test_[^/]+[.]c$")
|
||||
ENDFOREACH (testfile)
|
||||
|
||||
ENDIF (NOT EXISTS "${_listfile}" OR
|
||||
${_cmlist} IS_NEWER_THAN "${_listfile}")
|
||||
# Remove _listfile, _cmlist, and _target from _argv
|
||||
LIST(REMOVE_AT _argv 0 1 2)
|
||||
# Convert source paths to absolute so discover_tests.cmake can find them
|
||||
# regardless of the working directory when cmake -P runs.
|
||||
SET(_gl_abs_sources "")
|
||||
FOREACH(_gl_src ${_argv})
|
||||
IF(IS_ABSOLUTE "${_gl_src}")
|
||||
LIST(APPEND _gl_abs_sources "${_gl_src}")
|
||||
ELSE()
|
||||
LIST(APPEND _gl_abs_sources "${CMAKE_CURRENT_SOURCE_DIR}/${_gl_src}")
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
# Stamp out discover_tests.cmake with source list and output path baked in.
|
||||
SET(SOURCES "${_gl_abs_sources}")
|
||||
SET(OUTPUT "${_listfile}")
|
||||
CONFIGURE_FILE(
|
||||
${CMAKE_SOURCE_DIR}/build/cmake/discover_tests.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/discover_tests.cmake
|
||||
@ONLY)
|
||||
UNSET(SOURCES)
|
||||
UNSET(OUTPUT)
|
||||
# list.h is regenerated at build time whenever any test .c file changes.
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT "${_listfile}"
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/discover_tests.cmake
|
||||
DEPENDS ${_gl_abs_sources}
|
||||
COMMENT "Generating ${_listfile}"
|
||||
VERBATIM)
|
||||
# Attaching list.h to the target tells CMake to build it before compiling.
|
||||
TARGET_SOURCES(${_target} PRIVATE "${_listfile}")
|
||||
ENDMACRO (GENERATE_LIST_H)
|
||||
|
||||
#
|
||||
# Register individual tests with CTest by scanning DEFINE_TEST() declarations.
|
||||
#
|
||||
MACRO (DISCOVER_TESTS _component __list_sources)
|
||||
IF(ENABLE_TEST)
|
||||
SET(_sources ${ARGV})
|
||||
LIST(REMOVE_AT _sources 0)
|
||||
FOREACH (_src ${_sources})
|
||||
IF (_src MATCHES "test_[^/]+\\.c$")
|
||||
FILE(STRINGS "${_src}" _lines REGEX "^DEFINE_TEST\(.*\)")
|
||||
FOREACH (_line ${_lines})
|
||||
STRING(REGEX MATCH "DEFINE_TEST\((.*)\)" _full_match ${_line})
|
||||
# CMake REGEX seems to handle ( and \( rather inconsistently...
|
||||
# So we go through an extra dance to definitively strip the parens
|
||||
STRING(REPLACE "(" "" _test_name_with_paren "${CMAKE_MATCH_1}")
|
||||
STRING(REPLACE ")" "" _test_name "${_test_name_with_paren}")
|
||||
SET(_full_test_name "${_component}_${_test_name}")
|
||||
ADD_TEST(NAME ${_full_test_name}
|
||||
COMMAND ${_component}_test -vv
|
||||
-r ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-s
|
||||
${_test_name})
|
||||
SET_TESTS_PROPERTIES(${_full_test_name} PROPERTIES SKIP_RETURN_CODE 2)
|
||||
ENDFOREACH (_line)
|
||||
ENDIF (_src MATCHES "test_[^/]+\\.c$")
|
||||
ENDFOREACH (_src)
|
||||
ENDIF(ENABLE_TEST)
|
||||
ENDMACRO (DISCOVER_TESTS __list_sources)
|
||||
|
||||
#
|
||||
# Generate installation rules for man pages.
|
||||
#
|
||||
@@ -690,7 +728,7 @@ IF(ENABLE_ZSTD)
|
||||
ENDIF()
|
||||
|
||||
FIND_PATH(ZSTD_INCLUDE_DIR zstd.h HINTS ${PC_ZSTD_INCLUDEDIR} ${PC_ZSTD_INCLUDE_DIRS})
|
||||
FIND_LIBRARY(ZSTD_LIBRARY NAMES zstd libzstd HINTS ${PC_ZSTD_LIBDIR} ${PC_ZSTD_LIBRARY_DIRS})
|
||||
FIND_LIBRARY(ZSTD_LIBRARY NAMES zstd libzstd zstd_static HINTS ${PC_ZSTD_LIBDIR} ${PC_ZSTD_LIBRARY_DIRS})
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZSTD DEFAULT_MSG ZSTD_LIBRARY ZSTD_INCLUDE_DIR)
|
||||
ELSE(ENABLE_ZSTD)
|
||||
@@ -767,6 +805,7 @@ CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS)
|
||||
|
||||
LA_CHECK_INCLUDE_FILE("intsafe.h" HAVE_INTSAFE_H)
|
||||
LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
|
||||
LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
|
||||
LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H)
|
||||
@@ -781,6 +820,8 @@ LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
|
||||
LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H)
|
||||
LA_CHECK_INCLUDE_FILE("spawn.h" HAVE_SPAWN_H)
|
||||
LA_CHECK_INCLUDE_FILE("stdarg.h" HAVE_STDARG_H)
|
||||
LA_CHECK_INCLUDE_FILE("stdckdint.h" HAVE_STDCKDINT_H)
|
||||
LA_CHECK_INCLUDE_FILE("stdio.h" HAVE_STDIO_H)
|
||||
LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
|
||||
LA_CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H)
|
||||
LA_CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
|
||||
@@ -814,12 +855,22 @@ IF(ENABLE_CNG)
|
||||
LA_CHECK_INCLUDE_FILE("bcrypt.h" HAVE_BCRYPT_H)
|
||||
IF(HAVE_BCRYPT_H)
|
||||
LIST(APPEND ADDITIONAL_LIBS "bcrypt")
|
||||
# bcrypt supports these algorithms on all available versions
|
||||
SET(ARCHIVE_CRYPTO_MD5 1)
|
||||
SET(ARCHIVE_CRYPTO_MD5_WIN 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA1 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA1_WIN 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA256 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA256_WIN 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA384 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA384_WIN 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA512 1)
|
||||
SET(ARCHIVE_CRYPTO_SHA512_WIN 1)
|
||||
ENDIF(HAVE_BCRYPT_H)
|
||||
ELSE(ENABLE_CNG)
|
||||
UNSET(HAVE_BCRYPT_H CACHE)
|
||||
ENDIF(ENABLE_CNG)
|
||||
# Following files need windows.h, so we should test it after windows.h test.
|
||||
LA_CHECK_INCLUDE_FILE("wincrypt.h" HAVE_WINCRYPT_H)
|
||||
LA_CHECK_INCLUDE_FILE("winioctl.h" HAVE_WINIOCTL_H)
|
||||
|
||||
#
|
||||
@@ -847,11 +898,14 @@ IF(ENABLE_MBEDTLS)
|
||||
LIST(APPEND ADDITIONAL_LIBS ${MBEDCRYPTO_LIBRARY})
|
||||
INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIRS})
|
||||
|
||||
CMAKE_PUSH_CHECK_STATE()
|
||||
LIST(APPEND CMAKE_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIRS})
|
||||
LA_CHECK_INCLUDE_FILE("mbedtls/aes.h" HAVE_MBEDTLS_AES_H)
|
||||
LA_CHECK_INCLUDE_FILE("mbedtls/md.h" HAVE_MBEDTLS_MD_H)
|
||||
LA_CHECK_INCLUDE_FILE("mbedtls/pkcs5.h" HAVE_MBEDTLS_PKCS5_H)
|
||||
LA_CHECK_INCLUDE_FILE("mbedtls/version.h" HAVE_MBEDTLS_VERSION_H)
|
||||
CMAKE_POP_CHECK_STATE()
|
||||
|
||||
ENDIF(MBEDTLS_FOUND)
|
||||
MARK_AS_ADVANCED(CLEAR MBEDTLS_INCLUDE_DIRS)
|
||||
MARK_AS_ADVANCED(CLEAR MBEDCRYPTO_LIBRARY)
|
||||
@@ -867,6 +921,7 @@ IF(ENABLE_NETTLE)
|
||||
LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARIES})
|
||||
INCLUDE_DIRECTORIES(${NETTLE_INCLUDE_DIR})
|
||||
|
||||
CMAKE_PUSH_CHECK_STATE()
|
||||
LIST(APPEND CMAKE_REQUIRED_INCLUDES ${NETTLE_INCLUDE_DIR})
|
||||
LA_CHECK_INCLUDE_FILE("nettle/aes.h" HAVE_NETTLE_AES_H)
|
||||
LA_CHECK_INCLUDE_FILE("nettle/hmac.h" HAVE_NETTLE_HMAC_H)
|
||||
@@ -875,6 +930,8 @@ IF(ENABLE_NETTLE)
|
||||
LA_CHECK_INCLUDE_FILE("nettle/ripemd160.h" HAVE_NETTLE_RIPEMD160_H)
|
||||
LA_CHECK_INCLUDE_FILE("nettle/sha.h" HAVE_NETTLE_SHA_H)
|
||||
LA_CHECK_INCLUDE_FILE("nettle/version.h" HAVE_NETTLE_VERSION_H)
|
||||
CMAKE_POP_CHECK_STATE()
|
||||
|
||||
ENDIF(NETTLE_FOUND)
|
||||
MARK_AS_ADVANCED(CLEAR NETTLE_INCLUDE_DIR)
|
||||
MARK_AS_ADVANCED(CLEAR NETTLE_LIBRARIES)
|
||||
@@ -890,11 +947,15 @@ IF(ENABLE_OPENSSL AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
SET(HAVE_LIBCRYPTO 1)
|
||||
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
|
||||
list(APPEND ADDITIONAL_LIBS OpenSSL::Crypto)
|
||||
|
||||
CMAKE_PUSH_CHECK_STATE()
|
||||
set(CMAKE_REQUIRED_LIBRARIES OpenSSL::Crypto)
|
||||
SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
|
||||
LA_CHECK_INCLUDE_FILE("openssl/evp.h" HAVE_OPENSSL_EVP_H)
|
||||
LA_CHECK_INCLUDE_FILE("openssl/opensslv.h" HAVE_OPENSSL_OPENSSLV_H)
|
||||
CHECK_FUNCTION_EXISTS(PKCS5_PBKDF2_HMAC_SHA1 HAVE_PKCS5_PBKDF2_HMAC_SHA1)
|
||||
CMAKE_POP_CHECK_STATE()
|
||||
|
||||
ENDIF(OPENSSL_FOUND)
|
||||
ELSE()
|
||||
SET(OPENSSL_FOUND FALSE) # Override cached value
|
||||
@@ -915,9 +976,13 @@ ENDIF(NOT OPENSSL_FOUND)
|
||||
# libbsd for readpassphrase on Haiku
|
||||
IF("${CMAKE_SYSTEM_NAME}" MATCHES "Haiku")
|
||||
MESSAGE(STATUS "Adding libbsd for Haiku")
|
||||
|
||||
CMAKE_PUSH_CHECK_STATE()
|
||||
SET(CMAKE_REQUIRED_LIBRARIES "bsd")
|
||||
FIND_LIBRARY(LIBBSD_LIBRARY NAMES bsd)
|
||||
LIST(APPEND ADDITIONAL_LIBS ${LIBBSD_LIBRARY})
|
||||
CMAKE_POP_CHECK_STATE()
|
||||
|
||||
ENDIF("${CMAKE_SYSTEM_NAME}" MATCHES "Haiku")
|
||||
|
||||
#
|
||||
@@ -1029,85 +1094,6 @@ main(int argc, char **argv)
|
||||
ENDFOREACH(ALGORITHM ${ALGORITHMS})
|
||||
ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
|
||||
|
||||
#
|
||||
# CRYPTO functions on Windows is defined at archive_windows.c, thus we do not
|
||||
# need the test what the functions can be mapped to archive_{crypto name}_init,
|
||||
# archive_{crypto name}_update and archive_{crypto name}_final.
|
||||
# The functions on Windows use CALG_{crypto name} macro to create a crypt object
|
||||
# and then we need to know what CALG_{crypto name} macros is available to show
|
||||
# ARCHIVE_CRYPTO_{crypto name}_WIN macros because Windows 2000 and earlier version
|
||||
# of Windows XP do not support SHA256, SHA384 and SHA512.
|
||||
#
|
||||
MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
|
||||
IF(WIN32 AND NOT CYGWIN)
|
||||
FOREACH(CRYPTO ${CRYPTO_LIST})
|
||||
IF(NOT ARCHIVE_CRYPTO_${CRYPTO})
|
||||
IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
|
||||
STRING(TOUPPER "${CRYPTO}" crypto)
|
||||
SET(ALGID "")
|
||||
IF ("${CRYPTO}" MATCHES "^MD5$")
|
||||
SET(ALGID "CALG_MD5")
|
||||
ENDIF ("${CRYPTO}" MATCHES "^MD5$")
|
||||
IF ("${CRYPTO}" MATCHES "^SHA1$")
|
||||
SET(ALGID "CALG_SHA1")
|
||||
ENDIF ("${CRYPTO}" MATCHES "^SHA1$")
|
||||
IF ("${CRYPTO}" MATCHES "^SHA256$")
|
||||
SET(ALGID "CALG_SHA_256")
|
||||
ENDIF ("${CRYPTO}" MATCHES "^SHA256$")
|
||||
IF ("${CRYPTO}" MATCHES "^SHA384$")
|
||||
SET(ALGID "CALG_SHA_384")
|
||||
ENDIF ("${CRYPTO}" MATCHES "^SHA384$")
|
||||
IF ("${CRYPTO}" MATCHES "^SHA512$")
|
||||
SET(ALGID "CALG_SHA_512")
|
||||
ENDIF ("${CRYPTO}" MATCHES "^SHA512$")
|
||||
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
|
||||
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
|
||||
FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
|
||||
CONFDEFS_H)
|
||||
|
||||
SET(SOURCE "${CONFDEFS_H}
|
||||
|
||||
#define ${crypto}_COMPILE_TEST
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
return ${ALGID};
|
||||
}
|
||||
")
|
||||
SET(SOURCE_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_win.c")
|
||||
|
||||
FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
|
||||
MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
|
||||
|
||||
TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
|
||||
${CMAKE_BINARY_DIR}
|
||||
${SOURCE_FILE}
|
||||
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive"
|
||||
OUTPUT_VARIABLE OUTPUT)
|
||||
|
||||
IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
|
||||
MESSAGE(STATUS
|
||||
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
|
||||
SET(ARCHIVE_CRYPTO_${CRYPTO} 1)
|
||||
ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
|
||||
MESSAGE(STATUS
|
||||
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
|
||||
FILE(APPEND
|
||||
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
|
||||
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN failed with the following output:\n"
|
||||
"${OUTPUT}\n"
|
||||
"Source file was:\n${SOURCE}\n")
|
||||
ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
|
||||
ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
|
||||
ENDIF(NOT ARCHIVE_CRYPTO_${CRYPTO})
|
||||
ENDFOREACH(CRYPTO)
|
||||
ENDIF(WIN32 AND NOT CYGWIN)
|
||||
ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
|
||||
|
||||
#
|
||||
# Find iconv
|
||||
# POSIX defines the second arg as const char **
|
||||
@@ -1551,6 +1537,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(getpwnam_r HAVE_GETPWNAM_R)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getpwuid_r HAVE_GETPWUID_R)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getresgid HAVE_GETRESGID)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getresuid HAVE_GETRESUID)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(getvfsbyname HAVE_GETVFSBYNAME)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(gmtime_r HAVE_GMTIME_R)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(issetugid HAVE_ISSETUGID)
|
||||
@@ -2155,18 +2142,19 @@ ENDIF(ENABLE_ACL)
|
||||
# Check MD5/RMD160/SHA support
|
||||
# NOTE: Crypto checks must be run last before generating config.h
|
||||
#
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" LIBC)
|
||||
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC2)
|
||||
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC3)
|
||||
CHECK_CRYPTO("MD5;SHA1;SHA256;SHA384;SHA512" LIBSYSTEM)
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" MBEDTLS)
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" NETTLE)
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" OPENSSL)
|
||||
IF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
CHECK_CRYPTO("MD5;SHA1;SHA256;SHA384;SHA512" LIBSYSTEM)
|
||||
ELSE()
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" LIBC)
|
||||
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC2)
|
||||
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC3)
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" MBEDTLS)
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" NETTLE)
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" OPENSSL)
|
||||
|
||||
# Libmd has to be probed after OpenSSL.
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA512" LIBMD)
|
||||
|
||||
CHECK_CRYPTO_WIN("MD5;SHA1;SHA256;SHA384;SHA512")
|
||||
# Libmd has to be probed after OpenSSL.
|
||||
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA512" LIBMD)
|
||||
ENDIF()
|
||||
|
||||
IF(0) # CMake does not build libarchive's shared library.
|
||||
# Check visibility annotations
|
||||
@@ -2231,6 +2219,13 @@ IF(APPLE)
|
||||
LIST(APPEND ADDITIONAL_LIBS "-framework CoreServices")
|
||||
ENDIF(APPLE)
|
||||
|
||||
IF(ENABLE_CLANG_TIDY)
|
||||
IF(NOT CLANG_TIDY_PATH)
|
||||
SET(CLANG_TIDY_PATH clang-tidy)
|
||||
ENDIF(NOT CLANG_TIDY_PATH)
|
||||
SET(CMAKE_C_CLANG_TIDY ${CLANG_TIDY_PATH})
|
||||
ENDIF(ENABLE_CLANG_TIDY)
|
||||
|
||||
add_subdirectory(libarchive)
|
||||
IF(0) # CMake does not build libarchive's command-line tools.
|
||||
add_subdirectory(cat)
|
||||
|
||||
@@ -453,6 +453,9 @@
|
||||
/* Define to 1 if you have the `getpwuid_r' function. */
|
||||
#cmakedefine HAVE_GETPWUID_R 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#cmakedefine HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the `getvfsbyname' function. */
|
||||
#cmakedefine HAVE_GETVFSBYNAME 1
|
||||
|
||||
@@ -471,6 +474,9 @@
|
||||
/* Define to 1 if you have the <iconv.h> header file. */
|
||||
#cmakedefine HAVE_ICONV_H 1
|
||||
|
||||
/* Define to 1 if you have the <intsafe.h> header file. */
|
||||
#cmakedefine HAVE_INTSAFE_H 1
|
||||
|
||||
/* Define to 1 if you have the <io.h> header file. */
|
||||
#cmakedefine HAVE_IO_H 1
|
||||
|
||||
@@ -809,6 +815,12 @@
|
||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||
#cmakedefine HAVE_STDARG_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdckdint.h> header file. */
|
||||
#cmakedefine HAVE_STDCKDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#cmakedefine HAVE_STDIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#cmakedefine HAVE_STDLIB_H 1
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Generated by CMake at configure time -- do not edit.
|
||||
# Scans test source files for DEFINE_TEST() declarations and writes list.h.
|
||||
set(_sources @SOURCES@)
|
||||
set(_output "@OUTPUT@")
|
||||
file(WRITE "${_output}" "")
|
||||
foreach(_src ${_sources})
|
||||
if(_src MATCHES "test_[^/]+\\.c$")
|
||||
file(STRINGS "${_src}" _lines REGEX "^DEFINE_TEST")
|
||||
foreach(_line ${_lines})
|
||||
file(APPEND "${_output}" "${_line}\n")
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -1 +1 @@
|
||||
3008006
|
||||
3008009
|
||||
|
||||
@@ -40,6 +40,7 @@ SET(libarchive_SOURCES
|
||||
archive_entry_xattr.c
|
||||
archive_hmac.c
|
||||
archive_hmac_private.h
|
||||
archive_integer.h
|
||||
archive_match.c
|
||||
archive_openssl_evp_private.h
|
||||
archive_openssl_hmac_private.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 3008006
|
||||
#define ARCHIVE_VERSION_NUMBER 3008009
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stddef.h> /* for wchar_t */
|
||||
@@ -174,7 +174,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.6"
|
||||
#define ARCHIVE_VERSION_ONLY_STRING "3.8.9"
|
||||
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
|
||||
__LA_DECL const char * archive_version_string(void);
|
||||
|
||||
@@ -207,7 +207,9 @@ __LA_DECL const char * archive_openssl_version(void);
|
||||
__LA_DECL const char * archive_libmd_version(void);
|
||||
__LA_DECL const char * archive_commoncrypto_version(void);
|
||||
__LA_DECL const char * archive_cng_version(void);
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
__LA_DECL const char * archive_wincrypt_version(void);
|
||||
#endif
|
||||
__LA_DECL const char * archive_librichacl_version(void);
|
||||
__LA_DECL const char * archive_libacl_version(void);
|
||||
__LA_DECL const char * archive_libattr_version(void);
|
||||
@@ -650,7 +652,6 @@ __LA_DECL int archive_read_data_block(struct archive *a,
|
||||
/*-
|
||||
* Some convenience functions that are built on archive_read_data:
|
||||
* 'skip': skips entire entry
|
||||
* 'into_buffer': writes data into memory buffer that you provide
|
||||
* 'into_fd': writes data to specified filedes
|
||||
*/
|
||||
__LA_DECL int archive_read_data_skip(struct archive *);
|
||||
@@ -1231,7 +1232,7 @@ __LA_DECL int archive_match_exclude_entry(struct archive *,
|
||||
int _flag, struct archive_entry *);
|
||||
|
||||
/*
|
||||
* Test if a file is excluded by its uid ,gid, uname or gname.
|
||||
* Test if a file is excluded by its uid, gid, uname or gname.
|
||||
* The conditions are set by following functions.
|
||||
*/
|
||||
__LA_DECL int archive_match_owner_excluded(struct archive *,
|
||||
|
||||
@@ -60,9 +60,7 @@ static int archive_acl_add_entry_len_l(struct archive_acl *acl,
|
||||
int type, int permset, int tag, int id, const char *name,
|
||||
size_t len, struct archive_string_conv *sc);
|
||||
static int archive_acl_text_want_type(struct archive_acl *acl, int flags);
|
||||
static size_t archive_acl_text_len(struct archive_acl *acl, int want_type,
|
||||
int flags, int wide, struct archive *a,
|
||||
struct archive_string_conv *sc);
|
||||
static size_t archive_acl_text_empty(struct archive_acl *acl, int want_type);
|
||||
static int isint_w(const wchar_t *start, const wchar_t *end, int *result);
|
||||
static int ismode_w(const wchar_t *start, const wchar_t *end, int *result);
|
||||
static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end,
|
||||
@@ -71,9 +69,9 @@ static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end,
|
||||
int *result);
|
||||
static void next_field_w(const wchar_t **wp, const wchar_t **start,
|
||||
const wchar_t **end, wchar_t *sep);
|
||||
static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
|
||||
static void append_entry_w(struct archive_wstring *ws, const wchar_t *prefix, int type,
|
||||
int tag, int flags, const wchar_t *wname, int perm, int id);
|
||||
static void append_id_w(wchar_t **wp, int id);
|
||||
static void append_id_w(struct archive_wstring *ws, int id);
|
||||
static int isint(const char *start, const char *end, int *result);
|
||||
static int ismode(const char *start, const char *end, int *result);
|
||||
static int is_nfs4_flags(const char *start, const char *end,
|
||||
@@ -82,9 +80,9 @@ static int is_nfs4_perms(const char *start, const char *end,
|
||||
int *result);
|
||||
static void next_field(const char **p, size_t *l, const char **start,
|
||||
const char **end, char *sep);
|
||||
static void append_entry(char **p, const char *prefix, int type,
|
||||
static void append_entry(struct archive_string *s, const char *prefix, int type,
|
||||
int tag, int flags, const char *name, int perm, int id);
|
||||
static void append_id(char **p, int id);
|
||||
static void append_id(struct archive_string *s, int id);
|
||||
|
||||
static const struct {
|
||||
const int perm;
|
||||
@@ -543,20 +541,12 @@ archive_acl_text_want_type(struct archive_acl *acl, int flags)
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate ACL text string length
|
||||
* Check if ACL text would be empty
|
||||
*/
|
||||
static size_t
|
||||
archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
|
||||
int wide, struct archive *a, struct archive_string_conv *sc) {
|
||||
archive_acl_text_empty(struct archive_acl *acl, int want_type) {
|
||||
struct archive_acl_entry *ap;
|
||||
const char *name;
|
||||
const wchar_t *wname;
|
||||
int count, idlen, tmp, r;
|
||||
size_t length;
|
||||
size_t len;
|
||||
|
||||
count = 0;
|
||||
length = 0;
|
||||
for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
|
||||
if ((ap->type & want_type) == 0)
|
||||
continue;
|
||||
@@ -569,107 +559,11 @@ archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
|
||||
|| ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
|
||||
|| ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
|
||||
continue;
|
||||
count++;
|
||||
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0
|
||||
&& (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
|
||||
length += 8; /* "default:" */
|
||||
switch (ap->tag) {
|
||||
case ARCHIVE_ENTRY_ACL_USER_OBJ:
|
||||
if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
|
||||
length += 6; /* "owner@" */
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case ARCHIVE_ENTRY_ACL_USER:
|
||||
case ARCHIVE_ENTRY_ACL_MASK:
|
||||
length += 4; /* "user", "mask" */
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
|
||||
if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
|
||||
length += 6; /* "group@" */
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case ARCHIVE_ENTRY_ACL_GROUP:
|
||||
case ARCHIVE_ENTRY_ACL_OTHER:
|
||||
length += 5; /* "group", "other" */
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_EVERYONE:
|
||||
length += 9; /* "everyone@" */
|
||||
break;
|
||||
}
|
||||
length += 1; /* colon after tag */
|
||||
if (ap->tag == ARCHIVE_ENTRY_ACL_USER ||
|
||||
ap->tag == ARCHIVE_ENTRY_ACL_GROUP) {
|
||||
if (wide) {
|
||||
r = archive_mstring_get_wcs(a, &ap->name,
|
||||
&wname);
|
||||
if (r == 0 && wname != NULL)
|
||||
length += wcslen(wname);
|
||||
else if (r < 0 && errno == ENOMEM)
|
||||
return (0);
|
||||
else
|
||||
length += sizeof(uid_t) * 3 + 1;
|
||||
} else {
|
||||
r = archive_mstring_get_mbs_l(a, &ap->name, &name,
|
||||
&len, sc);
|
||||
if (r != 0)
|
||||
return (0);
|
||||
if (len > 0 && name != NULL)
|
||||
length += len;
|
||||
else
|
||||
length += sizeof(uid_t) * 3 + 1;
|
||||
}
|
||||
length += 1; /* colon after user or group name */
|
||||
} else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4)
|
||||
length += 1; /* 2nd colon empty user,group or other */
|
||||
|
||||
if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0)
|
||||
&& ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
|
||||
&& (ap->tag == ARCHIVE_ENTRY_ACL_OTHER
|
||||
|| ap->tag == ARCHIVE_ENTRY_ACL_MASK)) {
|
||||
/* Solaris has no colon after other: and mask: */
|
||||
length = length - 1;
|
||||
}
|
||||
|
||||
if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
|
||||
/* rwxpdDaARWcCos:fdinSFI:deny */
|
||||
length += 27;
|
||||
if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0)
|
||||
length += 1; /* allow, alarm, audit */
|
||||
} else
|
||||
length += 3; /* rwx */
|
||||
|
||||
if ((ap->tag == ARCHIVE_ENTRY_ACL_USER ||
|
||||
ap->tag == ARCHIVE_ENTRY_ACL_GROUP) &&
|
||||
(flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) {
|
||||
length += 1; /* colon */
|
||||
/* ID digit count */
|
||||
idlen = 1;
|
||||
tmp = ap->id;
|
||||
while (tmp > 9) {
|
||||
tmp = tmp / 10;
|
||||
idlen++;
|
||||
}
|
||||
length += idlen;
|
||||
}
|
||||
length ++; /* entry separator */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Add filemode-mapping access entries to the length */
|
||||
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) {
|
||||
/* "user::rwx\ngroup::rwx\nother:rwx\n" */
|
||||
length += 31;
|
||||
} else {
|
||||
/* "user::rwx\ngroup::rwx\nother::rwx\n" */
|
||||
length += 32;
|
||||
}
|
||||
} else if (count == 0)
|
||||
return (0);
|
||||
|
||||
/* The terminating character is included in count */
|
||||
return (length);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -680,15 +574,12 @@ wchar_t *
|
||||
archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
struct archive *a)
|
||||
{
|
||||
int count;
|
||||
size_t length;
|
||||
size_t len;
|
||||
const wchar_t *wname;
|
||||
const wchar_t *prefix;
|
||||
wchar_t separator;
|
||||
struct archive_acl_entry *ap;
|
||||
struct archive_wstring ws;
|
||||
int id, r, want_type;
|
||||
wchar_t *wp, *ws;
|
||||
|
||||
want_type = archive_acl_text_want_type(acl, flags);
|
||||
|
||||
@@ -699,9 +590,7 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
|
||||
flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
|
||||
|
||||
length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL);
|
||||
|
||||
if (length == 0)
|
||||
if (archive_acl_text_empty(acl, want_type))
|
||||
return (NULL);
|
||||
|
||||
if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
|
||||
@@ -709,28 +598,20 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
else
|
||||
separator = L'\n';
|
||||
|
||||
/* Now, allocate the string and actually populate it. */
|
||||
wp = ws = malloc(length * sizeof(*wp));
|
||||
if (wp == NULL) {
|
||||
if (errno == ENOMEM)
|
||||
__archive_errx(1, "No memory");
|
||||
return (NULL);
|
||||
}
|
||||
count = 0;
|
||||
archive_string_init(&ws);
|
||||
|
||||
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
append_entry_w(&ws, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
|
||||
acl->mode & 0700, -1);
|
||||
*wp++ = separator;
|
||||
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
archive_wstrappend_wchar(&ws, separator);
|
||||
append_entry_w(&ws, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
|
||||
acl->mode & 0070, -1);
|
||||
*wp++ = separator;
|
||||
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
archive_wstrappend_wchar(&ws, separator);
|
||||
append_entry_w(&ws, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
|
||||
acl->mode & 0007, -1);
|
||||
count += 3;
|
||||
}
|
||||
|
||||
for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
|
||||
@@ -752,108 +633,95 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
prefix = NULL;
|
||||
r = archive_mstring_get_wcs(a, &ap->name, &wname);
|
||||
if (r == 0) {
|
||||
if (count > 0)
|
||||
*wp++ = separator;
|
||||
if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
|
||||
if (ws.length > 0)
|
||||
archive_wstrappend_wchar(&ws, separator);
|
||||
if ((flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) ||
|
||||
wname == NULL)
|
||||
id = ap->id;
|
||||
else
|
||||
id = -1;
|
||||
append_entry_w(&wp, prefix, ap->type, ap->tag, flags,
|
||||
append_entry_w(&ws, prefix, ap->type, ap->tag, flags,
|
||||
wname, ap->permset, id);
|
||||
count++;
|
||||
} else if (r < 0 && errno == ENOMEM) {
|
||||
free(ws);
|
||||
archive_wstring_free(&ws);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add terminating character */
|
||||
*wp++ = L'\0';
|
||||
|
||||
len = wcslen(ws);
|
||||
|
||||
if (len > length - 1)
|
||||
__archive_errx(1, "Buffer overrun");
|
||||
|
||||
if (text_len != NULL)
|
||||
*text_len = len;
|
||||
*text_len = ws.length;
|
||||
|
||||
return (ws);
|
||||
return (ws.s);
|
||||
}
|
||||
|
||||
static void
|
||||
append_id_w(wchar_t **wp, int id)
|
||||
append_id_w(struct archive_wstring *ws, int id)
|
||||
{
|
||||
if (id < 0)
|
||||
id = 0;
|
||||
if (id > 9)
|
||||
append_id_w(wp, id / 10);
|
||||
*(*wp)++ = L"0123456789"[id % 10];
|
||||
append_id_w(ws, id / 10);
|
||||
archive_wstrappend_wchar(ws, L"0123456789"[id % 10]);
|
||||
}
|
||||
|
||||
static void
|
||||
append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
|
||||
append_entry_w(struct archive_wstring *ws, const wchar_t *prefix, int type,
|
||||
int tag, int flags, const wchar_t *wname, int perm, int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (prefix != NULL) {
|
||||
wcscpy(*wp, prefix);
|
||||
*wp += wcslen(*wp);
|
||||
}
|
||||
if (prefix != NULL)
|
||||
archive_wstrcat(ws, prefix);
|
||||
switch (tag) {
|
||||
case ARCHIVE_ENTRY_ACL_USER_OBJ:
|
||||
wname = NULL;
|
||||
id = -1;
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
|
||||
wcscpy(*wp, L"owner@");
|
||||
archive_wstrcat(ws, L"owner@");
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case ARCHIVE_ENTRY_ACL_USER:
|
||||
wcscpy(*wp, L"user");
|
||||
archive_wstrcat(ws, L"user");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
|
||||
wname = NULL;
|
||||
id = -1;
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
|
||||
wcscpy(*wp, L"group@");
|
||||
archive_wstrcat(ws, L"group@");
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case ARCHIVE_ENTRY_ACL_GROUP:
|
||||
wcscpy(*wp, L"group");
|
||||
archive_wstrcat(ws, L"group");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_MASK:
|
||||
wcscpy(*wp, L"mask");
|
||||
archive_wstrcat(ws, L"mask");
|
||||
wname = NULL;
|
||||
id = -1;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_OTHER:
|
||||
wcscpy(*wp, L"other");
|
||||
archive_wstrcat(ws, L"other");
|
||||
wname = NULL;
|
||||
id = -1;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_EVERYONE:
|
||||
wcscpy(*wp, L"everyone@");
|
||||
archive_wstrcat(ws, L"everyone@");
|
||||
wname = NULL;
|
||||
id = -1;
|
||||
break;
|
||||
default:
|
||||
**wp = '\0';
|
||||
break;
|
||||
}
|
||||
*wp += wcslen(*wp);
|
||||
*(*wp)++ = L':';
|
||||
archive_wstrappend_wchar(ws, L':');
|
||||
if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
|
||||
tag == ARCHIVE_ENTRY_ACL_USER ||
|
||||
tag == ARCHIVE_ENTRY_ACL_GROUP) {
|
||||
if (wname != NULL) {
|
||||
wcscpy(*wp, wname);
|
||||
*wp += wcslen(*wp);
|
||||
archive_wstrcat(ws, wname);
|
||||
} else if (tag == ARCHIVE_ENTRY_ACL_USER
|
||||
|| tag == ARCHIVE_ENTRY_ACL_GROUP) {
|
||||
append_id_w(wp, id);
|
||||
append_id_w(ws, id);
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
|
||||
id = -1;
|
||||
}
|
||||
@@ -861,51 +729,49 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
|
||||
if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
|
||||
|| (tag != ARCHIVE_ENTRY_ACL_OTHER
|
||||
&& tag != ARCHIVE_ENTRY_ACL_MASK))
|
||||
*(*wp)++ = L':';
|
||||
archive_wstrappend_wchar(ws, L':');
|
||||
}
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
|
||||
/* POSIX.1e ACL perms */
|
||||
*(*wp)++ = (perm & 0444) ? L'r' : L'-';
|
||||
*(*wp)++ = (perm & 0222) ? L'w' : L'-';
|
||||
*(*wp)++ = (perm & 0111) ? L'x' : L'-';
|
||||
archive_wstrappend_wchar(ws, (perm & 0444) ? L'r' : L'-');
|
||||
archive_wstrappend_wchar(ws, (perm & 0222) ? L'w' : L'-');
|
||||
archive_wstrappend_wchar(ws, (perm & 0111) ? L'x' : L'-');
|
||||
} else {
|
||||
/* NFSv4 ACL perms */
|
||||
for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
|
||||
if (perm & nfsv4_acl_perm_map[i].perm)
|
||||
*(*wp)++ = nfsv4_acl_perm_map[i].wc;
|
||||
archive_wstrappend_wchar(ws, nfsv4_acl_perm_map[i].wc);
|
||||
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
|
||||
*(*wp)++ = L'-';
|
||||
archive_wstrappend_wchar(ws, L'-');
|
||||
}
|
||||
*(*wp)++ = L':';
|
||||
archive_wstrappend_wchar(ws, L':');
|
||||
for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
|
||||
if (perm & nfsv4_acl_flag_map[i].perm)
|
||||
*(*wp)++ = nfsv4_acl_flag_map[i].wc;
|
||||
archive_wstrappend_wchar(ws, nfsv4_acl_flag_map[i].wc);
|
||||
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
|
||||
*(*wp)++ = L'-';
|
||||
archive_wstrappend_wchar(ws, L'-');
|
||||
}
|
||||
*(*wp)++ = L':';
|
||||
archive_wstrappend_wchar(ws, L':');
|
||||
switch (type) {
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
|
||||
wcscpy(*wp, L"allow");
|
||||
archive_wstrcat(ws, L"allow");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
|
||||
wcscpy(*wp, L"deny");
|
||||
archive_wstrcat(ws, L"deny");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
|
||||
wcscpy(*wp, L"audit");
|
||||
archive_wstrcat(ws, L"audit");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
|
||||
wcscpy(*wp, L"alarm");
|
||||
archive_wstrcat(ws, L"alarm");
|
||||
break;
|
||||
default:
|
||||
*(*wp) = L'\0';
|
||||
break;
|
||||
}
|
||||
*wp += wcslen(*wp);
|
||||
}
|
||||
if (id != -1) {
|
||||
*(*wp)++ = L':';
|
||||
append_id_w(wp, id);
|
||||
archive_wstrappend_wchar(ws, L':');
|
||||
append_id_w(ws, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,15 +783,13 @@ char *
|
||||
archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
struct archive_string_conv *sc)
|
||||
{
|
||||
int count;
|
||||
size_t length;
|
||||
size_t len;
|
||||
const char *name;
|
||||
const char *prefix;
|
||||
char separator;
|
||||
struct archive_acl_entry *ap;
|
||||
struct archive_string s;
|
||||
int id, r, want_type;
|
||||
char *p, *s;
|
||||
|
||||
want_type = archive_acl_text_want_type(acl, flags);
|
||||
|
||||
@@ -936,9 +800,7 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
|
||||
flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
|
||||
|
||||
length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc);
|
||||
|
||||
if (length == 0)
|
||||
if (archive_acl_text_empty(acl, want_type))
|
||||
return (NULL);
|
||||
|
||||
if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
|
||||
@@ -946,28 +808,20 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
else
|
||||
separator = '\n';
|
||||
|
||||
/* Now, allocate the string and actually populate it. */
|
||||
p = s = malloc(length * sizeof(*p));
|
||||
if (p == NULL) {
|
||||
if (errno == ENOMEM)
|
||||
__archive_errx(1, "No memory");
|
||||
return (NULL);
|
||||
}
|
||||
count = 0;
|
||||
archive_string_init(&s);
|
||||
|
||||
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
append_entry(&s, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
|
||||
acl->mode & 0700, -1);
|
||||
*p++ = separator;
|
||||
append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
archive_strappend_char(&s, separator);
|
||||
append_entry(&s, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
|
||||
acl->mode & 0070, -1);
|
||||
*p++ = separator;
|
||||
append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
archive_strappend_char(&s, separator);
|
||||
append_entry(&s, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
|
||||
ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
|
||||
acl->mode & 0007, -1);
|
||||
count += 3;
|
||||
}
|
||||
|
||||
for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
|
||||
@@ -990,109 +844,95 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
r = archive_mstring_get_mbs_l(
|
||||
NULL, &ap->name, &name, &len, sc);
|
||||
if (r != 0) {
|
||||
free(s);
|
||||
archive_string_free(&s);
|
||||
return (NULL);
|
||||
}
|
||||
if (count > 0)
|
||||
*p++ = separator;
|
||||
if (s.length > 0)
|
||||
archive_strappend_char(&s, separator);
|
||||
if (name == NULL ||
|
||||
(flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) {
|
||||
id = ap->id;
|
||||
} else {
|
||||
id = -1;
|
||||
}
|
||||
append_entry(&p, prefix, ap->type, ap->tag, flags, name,
|
||||
append_entry(&s, prefix, ap->type, ap->tag, flags, name,
|
||||
ap->permset, id);
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Add terminating character */
|
||||
*p++ = '\0';
|
||||
|
||||
len = strlen(s);
|
||||
|
||||
if (len > length - 1)
|
||||
__archive_errx(1, "Buffer overrun");
|
||||
|
||||
if (text_len != NULL)
|
||||
*text_len = len;
|
||||
*text_len = s.length;
|
||||
|
||||
return (s);
|
||||
return (s.s);
|
||||
}
|
||||
|
||||
static void
|
||||
append_id(char **p, int id)
|
||||
append_id(struct archive_string *s, int id)
|
||||
{
|
||||
if (id < 0)
|
||||
id = 0;
|
||||
if (id > 9)
|
||||
append_id(p, id / 10);
|
||||
*(*p)++ = "0123456789"[id % 10];
|
||||
append_id(s, id / 10);
|
||||
archive_strappend_char(s, "0123456789"[id % 10]);
|
||||
}
|
||||
|
||||
static void
|
||||
append_entry(char **p, const char *prefix, int type,
|
||||
append_entry(struct archive_string *s, const char *prefix, int type,
|
||||
int tag, int flags, const char *name, int perm, int id)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (prefix != NULL) {
|
||||
strcpy(*p, prefix);
|
||||
*p += strlen(*p);
|
||||
}
|
||||
if (prefix != NULL)
|
||||
archive_strcat(s, prefix);
|
||||
switch (tag) {
|
||||
case ARCHIVE_ENTRY_ACL_USER_OBJ:
|
||||
name = NULL;
|
||||
id = -1;
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
|
||||
strcpy(*p, "owner@");
|
||||
archive_strcat(s, "owner@");
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case ARCHIVE_ENTRY_ACL_USER:
|
||||
strcpy(*p, "user");
|
||||
archive_strcat(s, "user");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
|
||||
name = NULL;
|
||||
id = -1;
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
|
||||
strcpy(*p, "group@");
|
||||
archive_strcat(s, "group@");
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case ARCHIVE_ENTRY_ACL_GROUP:
|
||||
strcpy(*p, "group");
|
||||
archive_strcat(s, "group");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_MASK:
|
||||
strcpy(*p, "mask");
|
||||
archive_strcat(s, "mask");
|
||||
name = NULL;
|
||||
id = -1;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_OTHER:
|
||||
strcpy(*p, "other");
|
||||
archive_strcat(s, "other");
|
||||
name = NULL;
|
||||
id = -1;
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_EVERYONE:
|
||||
strcpy(*p, "everyone@");
|
||||
archive_strcat(s, "everyone@");
|
||||
name = NULL;
|
||||
id = -1;
|
||||
break;
|
||||
default:
|
||||
**p = '\0';
|
||||
break;
|
||||
}
|
||||
*p += strlen(*p);
|
||||
*(*p)++ = ':';
|
||||
archive_strappend_char(s, ':');
|
||||
if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
|
||||
tag == ARCHIVE_ENTRY_ACL_USER ||
|
||||
tag == ARCHIVE_ENTRY_ACL_GROUP) {
|
||||
if (name != NULL) {
|
||||
strcpy(*p, name);
|
||||
*p += strlen(*p);
|
||||
archive_strcat(s, name);
|
||||
} else if (tag == ARCHIVE_ENTRY_ACL_USER
|
||||
|| tag == ARCHIVE_ENTRY_ACL_GROUP) {
|
||||
append_id(p, id);
|
||||
append_id(s, id);
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
|
||||
id = -1;
|
||||
}
|
||||
@@ -1100,51 +940,49 @@ append_entry(char **p, const char *prefix, int type,
|
||||
if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
|
||||
|| (tag != ARCHIVE_ENTRY_ACL_OTHER
|
||||
&& tag != ARCHIVE_ENTRY_ACL_MASK))
|
||||
*(*p)++ = ':';
|
||||
archive_strappend_char(s, ':');
|
||||
}
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
|
||||
/* POSIX.1e ACL perms */
|
||||
*(*p)++ = (perm & 0444) ? 'r' : '-';
|
||||
*(*p)++ = (perm & 0222) ? 'w' : '-';
|
||||
*(*p)++ = (perm & 0111) ? 'x' : '-';
|
||||
archive_strappend_char(s, (perm & 0444) ? 'r' : '-');
|
||||
archive_strappend_char(s, (perm & 0222) ? 'w' : '-');
|
||||
archive_strappend_char(s, (perm & 0111) ? 'x' : '-');
|
||||
} else {
|
||||
/* NFSv4 ACL perms */
|
||||
for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
|
||||
if (perm & nfsv4_acl_perm_map[i].perm)
|
||||
*(*p)++ = nfsv4_acl_perm_map[i].c;
|
||||
archive_strappend_char(s, nfsv4_acl_perm_map[i].c);
|
||||
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
|
||||
*(*p)++ = '-';
|
||||
archive_strappend_char(s, '-');
|
||||
}
|
||||
*(*p)++ = ':';
|
||||
archive_strappend_char(s, ':');
|
||||
for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
|
||||
if (perm & nfsv4_acl_flag_map[i].perm)
|
||||
*(*p)++ = nfsv4_acl_flag_map[i].c;
|
||||
archive_strappend_char(s, nfsv4_acl_flag_map[i].c);
|
||||
else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
|
||||
*(*p)++ = '-';
|
||||
archive_strappend_char(s, '-');
|
||||
}
|
||||
*(*p)++ = ':';
|
||||
archive_strappend_char(s, ':');
|
||||
switch (type) {
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
|
||||
strcpy(*p, "allow");
|
||||
archive_strcat(s, "allow");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
|
||||
strcpy(*p, "deny");
|
||||
archive_strcat(s, "deny");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
|
||||
strcpy(*p, "audit");
|
||||
archive_strcat(s, "audit");
|
||||
break;
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
|
||||
strcpy(*p, "alarm");
|
||||
archive_strcat(s, "alarm");
|
||||
break;
|
||||
default:
|
||||
*(*p) = '\0';
|
||||
break;
|
||||
}
|
||||
*p += strlen(*p);
|
||||
}
|
||||
if (id != -1) {
|
||||
*(*p)++ = ':';
|
||||
append_id(p, id);
|
||||
archive_strappend_char(s, ':');
|
||||
append_id(s, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,11 +1093,18 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
|
||||
type = want_type;
|
||||
|
||||
/* Check for a numeric ID in field n+1 or n+3. */
|
||||
isint_w(field[n + 1].start, field[n + 1].end, &id);
|
||||
if (isint_w(field[n + 1].start, field[n + 1].end,
|
||||
&id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
/* Field n+3 is optional. */
|
||||
if (id == -1 && fields > n+3)
|
||||
isint_w(field[n + 3].start, field[n + 3].end,
|
||||
&id);
|
||||
if (id == -1 && fields > n+3 &&
|
||||
isint_w(field[n + 3].start, field[n + 3].end,
|
||||
&id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
|
||||
tag = 0;
|
||||
s = field[n].start;
|
||||
@@ -1374,7 +1219,10 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
|
||||
tag == ARCHIVE_ENTRY_ACL_GROUP) {
|
||||
n = 1;
|
||||
name = field[1];
|
||||
isint_w(name.start, name.end, &id);
|
||||
if (isint_w(name.start, name.end, &id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
n = 0;
|
||||
|
||||
@@ -1409,7 +1257,11 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
isint_w(field[4 + n].start, field[4 + n].end, &id);
|
||||
if (isint_w(field[4 + n].start, field[4 + n].end,
|
||||
&id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add entry to the internal list. */
|
||||
@@ -1443,8 +1295,8 @@ isint_w(const wchar_t *start, const wchar_t *end, int *result)
|
||||
if (*start < L'0' || *start > L'9')
|
||||
return (0);
|
||||
if (n > (INT_MAX / 10) ||
|
||||
(n == INT_MAX / 10 && (*start - L'0') > INT_MAX % 10)) {
|
||||
n = INT_MAX;
|
||||
(n == INT_MAX / 10 && (*start - L'0') >= INT_MAX % 10)) {
|
||||
return (-1);
|
||||
} else {
|
||||
n *= 10;
|
||||
n += *start - L'0';
|
||||
@@ -1671,7 +1523,7 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
const char *end;
|
||||
} field[6], name;
|
||||
|
||||
const char *s, *st;
|
||||
const char *s, *st, *text_end;
|
||||
int numfields, fields, n, r, sol, ret;
|
||||
int type, types, tag, permset, id;
|
||||
size_t len;
|
||||
@@ -1694,6 +1546,7 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
|
||||
ret = ARCHIVE_OK;
|
||||
types = 0;
|
||||
text_end = (text == NULL) ? text : text + length;
|
||||
|
||||
while (text != NULL && length > 0 && *text != '\0') {
|
||||
/*
|
||||
@@ -1720,6 +1573,18 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (field[0].start == text_end) {
|
||||
/*
|
||||
* Empty entry: next_field() consumed the rest of the
|
||||
* buffer as separators or whitespace, leaving
|
||||
* field[0].start one past the end. 'text' is not
|
||||
* guaranteed to be NUL terminated, so the byte after it
|
||||
* must not be dereferenced.
|
||||
*/
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*(field[0].start) == '#') {
|
||||
/* Comment, skip entry */
|
||||
continue;
|
||||
@@ -1757,15 +1622,21 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
type = want_type;
|
||||
|
||||
/* Check for a numeric ID in field n+1 or n+3. */
|
||||
isint(field[n + 1].start, field[n + 1].end, &id);
|
||||
if (isint(field[n + 1].start, field[n + 1].end,
|
||||
&id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
/* Field n+3 is optional. */
|
||||
if (id == -1 && fields > (n + 3))
|
||||
isint(field[n + 3].start, field[n + 3].end,
|
||||
&id);
|
||||
if (id == -1 && fields > (n + 3) &&
|
||||
isint(field[n + 3].start, field[n + 3].end,
|
||||
&id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
|
||||
tag = 0;
|
||||
s = field[n].start;
|
||||
st = field[n].start + 1;
|
||||
len = field[n].end - field[n].start;
|
||||
|
||||
if (len == 0) {
|
||||
@@ -1773,6 +1644,8 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
continue;
|
||||
}
|
||||
|
||||
st = s + 1;
|
||||
|
||||
switch (*s) {
|
||||
case 'u':
|
||||
if (len == 1 || (len == 4
|
||||
@@ -1878,7 +1751,10 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
tag == ARCHIVE_ENTRY_ACL_GROUP) {
|
||||
n = 1;
|
||||
name = field[1];
|
||||
isint(name.start, name.end, &id);
|
||||
if (isint(name.start, name.end, &id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
n = 0;
|
||||
|
||||
@@ -1913,8 +1789,11 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
isint(field[4 + n].start, field[4 + n].end,
|
||||
&id);
|
||||
if (isint(field[4 + n].start, field[4 + n].end,
|
||||
&id) < 0) {
|
||||
ret = ARCHIVE_WARN;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add entry to the internal list. */
|
||||
@@ -1948,8 +1827,8 @@ isint(const char *start, const char *end, int *result)
|
||||
if (*start < '0' || *start > '9')
|
||||
return (0);
|
||||
if (n > (INT_MAX / 10) ||
|
||||
(n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
|
||||
n = INT_MAX;
|
||||
(n == INT_MAX / 10 && (*start - '0') >= INT_MAX % 10)) {
|
||||
return (-1);
|
||||
} else {
|
||||
n *= 10;
|
||||
n += *start - '0';
|
||||
@@ -2131,7 +2010,10 @@ next_field(const char **p, size_t *l, const char **start,
|
||||
(*p)++;
|
||||
(*l)--;
|
||||
}
|
||||
*sep = **p;
|
||||
if (*l > 0)
|
||||
*sep = **p;
|
||||
else
|
||||
*sep = '\0';
|
||||
|
||||
/* Handle in-field comments */
|
||||
if (*sep == '#') {
|
||||
@@ -2139,7 +2021,10 @@ next_field(const char **p, size_t *l, const char **start,
|
||||
(*p)++;
|
||||
(*l)--;
|
||||
}
|
||||
*sep = **p;
|
||||
if (*l > 0)
|
||||
*sep = **p;
|
||||
else
|
||||
*sep = '\0';
|
||||
}
|
||||
|
||||
/* Skip separator. */
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
#define ARCHIVE_ACL_PRIVATE_H_INCLUDED
|
||||
|
||||
#ifndef __LIBARCHIVE_BUILD
|
||||
#ifndef __LIBARCHIVE_TEST
|
||||
#error This header is only to be used internally to libarchive.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "archive_string.h"
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ state_name(unsigned s)
|
||||
case ARCHIVE_STATE_NEW: return ("new");
|
||||
case ARCHIVE_STATE_HEADER: return ("header");
|
||||
case ARCHIVE_STATE_DATA: return ("data");
|
||||
case ARCHIVE_STATE_DATA_RECOVERY: return ("data_recovery");
|
||||
case ARCHIVE_STATE_EOF: return ("eof");
|
||||
case ARCHIVE_STATE_CLOSED: return ("closed");
|
||||
case ARCHIVE_STATE_FATAL: return ("fatal");
|
||||
@@ -148,14 +149,14 @@ __archive_check_magic(struct archive *a, unsigned int magic,
|
||||
if (!handle_type) {
|
||||
errmsg("PROGRAMMER ERROR: Function ");
|
||||
errmsg(function);
|
||||
errmsg(" invoked with invalid archive handle.\n");
|
||||
errmsg(" invoked with invalid archive handle\n");
|
||||
diediedie();
|
||||
}
|
||||
|
||||
if (a->magic != magic) {
|
||||
archive_set_error(a, -1,
|
||||
"PROGRAMMER ERROR: Function '%s' invoked"
|
||||
" on '%s' archive object, which is not supported.",
|
||||
" on '%s' archive object, which is not supported",
|
||||
function,
|
||||
handle_type);
|
||||
a->state = ARCHIVE_STATE_FATAL;
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "archive_cmdline_private.h"
|
||||
#include "archive_string.h"
|
||||
|
||||
static int cmdline_set_path(struct archive_cmdline *, const char *);
|
||||
static int cmdline_add_arg(struct archive_cmdline *, const char *);
|
||||
|
||||
static ssize_t
|
||||
@@ -98,7 +97,7 @@ get_argument(struct archive_string *as, const char *p)
|
||||
|
||||
/*
|
||||
* Set up command line arguments.
|
||||
* Returns ARCHIVE_OK if everything okey.
|
||||
* Returns ARCHIVE_OK if everything okay.
|
||||
* Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an
|
||||
* empty command line.
|
||||
* Returns ARCHIVE_FATAL if no memory.
|
||||
@@ -123,9 +122,12 @@ __archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)
|
||||
r = ARCHIVE_FAILED;/* An empty command path. */
|
||||
goto exit_function;
|
||||
}
|
||||
r = cmdline_set_path(data, as.s);
|
||||
if (r != ARCHIVE_OK)
|
||||
free(data->path);
|
||||
data->path = strdup(as.s);
|
||||
if (data->path == NULL) {
|
||||
r = ARCHIVE_FATAL;
|
||||
goto exit_function;
|
||||
}
|
||||
p = strrchr(as.s, '/');
|
||||
if (p == NULL)
|
||||
p = as.s;
|
||||
@@ -158,23 +160,7 @@ exit_function:
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the program path.
|
||||
*/
|
||||
static int
|
||||
cmdline_set_path(struct archive_cmdline *data, const char *path)
|
||||
{
|
||||
char *newptr;
|
||||
|
||||
newptr = realloc(data->path, strlen(path) + 1);
|
||||
if (newptr == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
data->path = newptr;
|
||||
strcpy(data->path, path);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a argument for the program.
|
||||
* Add an argument for the program.
|
||||
*/
|
||||
static int
|
||||
cmdline_add_arg(struct archive_cmdline *data, const char *arg)
|
||||
|
||||
@@ -43,28 +43,65 @@
|
||||
static unsigned long
|
||||
crc32(unsigned long crc, const void *_p, size_t len)
|
||||
{
|
||||
unsigned long crc2, b, i;
|
||||
const unsigned char *p = _p;
|
||||
static volatile int crc_tbl_inited = 0;
|
||||
static unsigned long crc_tbl[256];
|
||||
static const unsigned long crc_tbl[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
|
||||
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
|
||||
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
|
||||
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
|
||||
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
|
||||
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
|
||||
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
|
||||
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
|
||||
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
|
||||
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
|
||||
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
|
||||
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
|
||||
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
|
||||
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
|
||||
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
|
||||
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
|
||||
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
|
||||
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
|
||||
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
|
||||
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
|
||||
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
|
||||
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
|
||||
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
|
||||
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
|
||||
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
|
||||
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
|
||||
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
|
||||
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
|
||||
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
|
||||
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
|
||||
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
|
||||
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
|
||||
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
|
||||
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
|
||||
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
|
||||
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
|
||||
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
|
||||
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
|
||||
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
|
||||
0x2d02ef8d
|
||||
};
|
||||
|
||||
if (_p == NULL)
|
||||
return (0);
|
||||
|
||||
if (!crc_tbl_inited) {
|
||||
for (b = 0; b < 256; ++b) {
|
||||
crc2 = b;
|
||||
for (i = 8; i > 0; --i) {
|
||||
if (crc2 & 1)
|
||||
crc2 = (crc2 >> 1) ^ 0xedb88320UL;
|
||||
else
|
||||
crc2 = (crc2 >> 1);
|
||||
}
|
||||
crc_tbl[b] = crc2;
|
||||
}
|
||||
crc_tbl_inited = 1;
|
||||
}
|
||||
|
||||
crc = crc ^ 0xffffffffUL;
|
||||
/* A use of this loop is about 20% - 30% faster than
|
||||
* no use version in any optimization option of gcc. */
|
||||
|
||||
@@ -57,7 +57,7 @@ pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "Bcrypt.lib")
|
||||
#endif
|
||||
@@ -197,7 +197,7 @@ aes_ctr_release(archive_crypto_ctx *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
|
||||
|
||||
static int
|
||||
aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
|
||||
|
||||
@@ -62,7 +62,7 @@ typedef struct {
|
||||
size_t encr_pos;
|
||||
} archive_crypto_ctx;
|
||||
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
|
||||
#include <bcrypt.h>
|
||||
#define ARCHIVE_CRYPTOR_USE_CNG 1
|
||||
|
||||
@@ -148,16 +148,6 @@ 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
|
||||
typedef int archive_crypto_ctx;
|
||||
|
||||
@@ -44,16 +44,11 @@
|
||||
/*
|
||||
* Message digest functions for Windows platform.
|
||||
*/
|
||||
#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(HAVE_BCRYPT_H)
|
||||
|
||||
/*
|
||||
* Initialize a Message digest.
|
||||
*/
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
static int
|
||||
win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)
|
||||
{
|
||||
@@ -72,30 +67,6 @@ win_crypto_init(Digest_CTX *ctx, const WCHAR *algo)
|
||||
ctx->valid = 1;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
#else
|
||||
static int
|
||||
win_crypto_init(Digest_CTX *ctx, DWORD prov, ALG_ID algId)
|
||||
{
|
||||
|
||||
ctx->valid = 0;
|
||||
if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
|
||||
prov, CRYPT_VERIFYCONTEXT)) {
|
||||
if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
|
||||
return (ARCHIVE_FAILED);
|
||||
if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
|
||||
prov, CRYPT_NEWKEYSET))
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
|
||||
CryptReleaseContext(ctx->cryptProv, 0);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
ctx->valid = 1;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update a Message digest.
|
||||
@@ -107,42 +78,26 @@ win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
|
||||
if (!ctx->valid)
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
BCryptHashData(ctx->hHash,
|
||||
(PUCHAR)(uintptr_t)buf,
|
||||
(ULONG)len, 0);
|
||||
#else
|
||||
CryptHashData(ctx->hash,
|
||||
(unsigned char *)(uintptr_t)buf,
|
||||
(DWORD)len, 0);
|
||||
#endif
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
|
||||
{
|
||||
#if !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
|
||||
DWORD siglen = (DWORD)bufsize;
|
||||
#endif
|
||||
|
||||
if (!ctx->valid)
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
BCryptFinishHash(ctx->hHash, buf, (ULONG)bufsize, 0);
|
||||
BCryptDestroyHash(ctx->hHash);
|
||||
BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
|
||||
#else
|
||||
CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
|
||||
CryptDestroyHash(ctx->hash);
|
||||
CryptReleaseContext(ctx->cryptProv, 0);
|
||||
#endif
|
||||
ctx->valid = 0;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */
|
||||
#endif /* defined(HAVE_BCRYPT_H) */
|
||||
|
||||
|
||||
/* MD5 implementations */
|
||||
@@ -234,11 +189,7 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
|
||||
static int
|
||||
__archive_md5init(archive_md5_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -645,11 +596,7 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
|
||||
static int
|
||||
__archive_sha1init(archive_sha1_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -925,11 +872,7 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
|
||||
static int
|
||||
__archive_sha256init(archive_sha256_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1177,11 +1120,7 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
|
||||
static int
|
||||
__archive_sha384init(archive_sha384_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1453,11 +1392,7 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
|
||||
static int
|
||||
__archive_sha512init(archive_sha512_ctx *ctx)
|
||||
{
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
|
||||
#else
|
||||
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -165,8 +165,7 @@
|
||||
defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
|
||||
defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
|
||||
defined(ARCHIVE_CRYPTO_SHA512_WIN)
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
/* don't use bcrypt when XP needs to be supported */
|
||||
#if defined(HAVE_BCRYPT_H)
|
||||
#include <bcrypt.h>
|
||||
#define ARCHIVE_CRYPTO_CNG 1
|
||||
typedef struct {
|
||||
@@ -174,22 +173,6 @@ typedef struct {
|
||||
BCRYPT_ALG_HANDLE hAlg;
|
||||
BCRYPT_HASH_HANDLE hHash;
|
||||
} Digest_CTX;
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
/* Undefine indirect <wincrypt.h> symbols conflicting with BoringSSL/AWS-LC. */
|
||||
#undef X509_NAME
|
||||
#undef X509_EXTENSIONS
|
||||
#undef PKCS7_ISSUER_AND_SERIAL
|
||||
#undef PKCS7_SIGNER_INFO
|
||||
#undef OCSP_REQUEST
|
||||
#undef OCSP_RESPONSE
|
||||
#define ARCHIVE_CRYPTO_WINCRYPT 1
|
||||
typedef struct {
|
||||
int valid;
|
||||
HCRYPTPROV cryptProv;
|
||||
HCRYPTHASH hash;
|
||||
} Digest_CTX;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -70,6 +70,22 @@ archive_be16dec(const void *pp)
|
||||
return ((p0 << 8) | p1);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
archive_be24dec(const void *pp)
|
||||
{
|
||||
unsigned char const *p = (unsigned char const *)pp;
|
||||
|
||||
/* Store into unsigned temporaries before left shifting, to avoid
|
||||
promotion to signed int and then left shifting into the sign bit,
|
||||
which is undefined behaviour. */
|
||||
unsigned int p2 = p[2];
|
||||
unsigned int p1 = p[1];
|
||||
unsigned int p0 = p[0];
|
||||
|
||||
return ((p0 << 16) | (p1 << 8) | p2);
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t
|
||||
archive_be32dec(const void *pp)
|
||||
{
|
||||
@@ -108,6 +124,21 @@ archive_le16dec(const void *pp)
|
||||
return ((p1 << 8) | p0);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
archive_le24dec(const void *pp)
|
||||
{
|
||||
unsigned char const *p = (unsigned char const *)pp;
|
||||
|
||||
/* Store into unsigned temporaries before left shifting, to avoid
|
||||
promotion to signed int and then left shifting into the sign bit,
|
||||
which is undefined behaviour. */
|
||||
unsigned int p2 = p[2];
|
||||
unsigned int p1 = p[1];
|
||||
unsigned int p0 = p[0];
|
||||
|
||||
return ((p2 << 16) | (p1 << 8) | p0);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
archive_le32dec(const void *pp)
|
||||
{
|
||||
@@ -170,6 +201,16 @@ archive_le16enc(void *pp, uint16_t u)
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static inline void
|
||||
archive_le24enc(void *pp, uint32_t u)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
p[2] = (u >> 16) & 0xff;
|
||||
}
|
||||
|
||||
static inline void
|
||||
archive_le32enc(void *pp, uint32_t u)
|
||||
{
|
||||
|
||||
@@ -1239,7 +1239,7 @@ _archive_entry_copy_link_l(struct archive_entry *entry,
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_mode(struct archive_entry *entry, mode_t m)
|
||||
archive_entry_set_mode(struct archive_entry *entry, __LA_MODE_T m)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->acl.mode = m;
|
||||
@@ -1314,7 +1314,7 @@ _archive_entry_copy_pathname_l(struct archive_entry *entry,
|
||||
}
|
||||
|
||||
void
|
||||
archive_entry_set_perm(struct archive_entry *entry, mode_t p)
|
||||
archive_entry_set_perm(struct archive_entry *entry, __LA_MODE_T p)
|
||||
{
|
||||
entry->stat_valid = 0;
|
||||
entry->acl.mode &= AE_IFMT;
|
||||
@@ -1562,17 +1562,21 @@ void
|
||||
archive_entry_copy_mac_metadata(struct archive_entry *entry,
|
||||
const void *p, size_t s)
|
||||
{
|
||||
free(entry->mac_metadata);
|
||||
if (p == NULL || s == 0) {
|
||||
entry->mac_metadata = NULL;
|
||||
entry->mac_metadata_size = 0;
|
||||
} else {
|
||||
entry->mac_metadata_size = s;
|
||||
entry->mac_metadata = malloc(s);
|
||||
if (entry->mac_metadata == NULL)
|
||||
abort();
|
||||
memcpy(entry->mac_metadata, p, s);
|
||||
}
|
||||
void *metadata;
|
||||
|
||||
if (p == NULL || s == 0) {
|
||||
free(entry->mac_metadata);
|
||||
entry->mac_metadata = NULL;
|
||||
entry->mac_metadata_size = 0;
|
||||
} else {
|
||||
metadata = malloc(s);
|
||||
if (metadata == NULL)
|
||||
abort();
|
||||
memcpy(metadata, p, s);
|
||||
free(entry->mac_metadata);
|
||||
entry->mac_metadata = metadata;
|
||||
entry->mac_metadata_size = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* Digest handling */
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define ARCHIVE_ENTRY_H_INCLUDED
|
||||
|
||||
/* Note: Compiler will complain if this does not match archive.h! */
|
||||
#define ARCHIVE_VERSION_NUMBER 3008006
|
||||
#define ARCHIVE_VERSION_NUMBER 3008009
|
||||
|
||||
/*
|
||||
* Note: archive_entry.h is for use outside of libarchive; the
|
||||
@@ -662,7 +662,7 @@ __LA_DECL void archive_entry_sparse_add_entry(struct archive_entry *,
|
||||
la_int64_t /* offset */, la_int64_t /* length */);
|
||||
|
||||
/*
|
||||
* To retrieve the xattr list, first "reset", then repeatedly ask for the
|
||||
* To retrieve the sparse list, first "reset", then repeatedly ask for the
|
||||
* "next" entry.
|
||||
*/
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_integer.h"
|
||||
|
||||
/*
|
||||
* This is mostly a pretty straightforward hash table implementation.
|
||||
@@ -78,7 +79,7 @@ struct links_entry {
|
||||
struct archive_entry_linkresolver {
|
||||
struct links_entry **buckets;
|
||||
struct links_entry *spare;
|
||||
unsigned long number_entries;
|
||||
size_t number_entries;
|
||||
size_t number_buckets;
|
||||
int strategy;
|
||||
};
|
||||
@@ -158,13 +159,12 @@ archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res,
|
||||
void
|
||||
archive_entry_linkresolver_free(struct archive_entry_linkresolver *res)
|
||||
{
|
||||
struct links_entry *le;
|
||||
|
||||
if (res == NULL)
|
||||
return;
|
||||
|
||||
while ((le = next_entry(res, NEXT_ENTRY_ALL)) != NULL)
|
||||
archive_entry_free(le->entry);
|
||||
while (next_entry(res, NEXT_ENTRY_ALL) != NULL) {
|
||||
/* Actual freeing done by next_entry() */
|
||||
}
|
||||
free(res->buckets);
|
||||
free(res);
|
||||
}
|
||||
@@ -382,9 +382,13 @@ insert_entry(struct archive_entry_linkresolver *res,
|
||||
if (le == NULL)
|
||||
return (NULL);
|
||||
le->canonical = archive_entry_clone(entry);
|
||||
if (le->canonical == NULL) {
|
||||
free(le);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* If the links cache is getting too full, enlarge the hash table. */
|
||||
if (res->number_entries > res->number_buckets * 2)
|
||||
if (res->number_entries / 2 > res->number_buckets)
|
||||
grow_hash(res);
|
||||
|
||||
hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));
|
||||
@@ -410,8 +414,7 @@ grow_hash(struct archive_entry_linkresolver *res)
|
||||
size_t i, bucket;
|
||||
|
||||
/* Try to enlarge the bucket list. */
|
||||
new_size = res->number_buckets * 2;
|
||||
if (new_size < res->number_buckets)
|
||||
if (archive_ckd_mul_size(&new_size, res->number_buckets, 2))
|
||||
return;
|
||||
new_buckets = calloc(new_size, sizeof(struct links_entry *));
|
||||
|
||||
|
||||
@@ -127,9 +127,10 @@ archive_entry_sparse_count(struct archive_entry *entry)
|
||||
int
|
||||
archive_entry_sparse_reset(struct archive_entry * entry)
|
||||
{
|
||||
/* Counting can change sparse_head, so do it first */
|
||||
int count = archive_entry_sparse_count(entry);
|
||||
entry->sparse_p = entry->sparse_head;
|
||||
|
||||
return archive_entry_sparse_count(entry);
|
||||
return (count);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_private.h"
|
||||
@@ -38,16 +35,10 @@
|
||||
const char *
|
||||
archive_entry_strmode(struct archive_entry *entry)
|
||||
{
|
||||
static const mode_t permbits[] =
|
||||
{ 0400, 0200, 0100, 0040, 0020, 0010, 0004, 0002, 0001 };
|
||||
char *bp = entry->strmode;
|
||||
mode_t mode;
|
||||
mode_t mask, mode;
|
||||
int i;
|
||||
|
||||
/* Fill in a default string, then selectively override. */
|
||||
strcpy(bp, "?rwxrwxrwx ");
|
||||
|
||||
mode = archive_entry_mode(entry);
|
||||
switch (archive_entry_filetype(entry)) {
|
||||
case AE_IFREG: bp[0] = '-'; break;
|
||||
case AE_IFBLK: bp[0] = 'b'; break;
|
||||
@@ -57,30 +48,22 @@ archive_entry_strmode(struct archive_entry *entry)
|
||||
case AE_IFSOCK: bp[0] = 's'; break;
|
||||
case AE_IFIFO: bp[0] = 'p'; break;
|
||||
default:
|
||||
if (archive_entry_hardlink(entry) != NULL) {
|
||||
bp[0] = 'h';
|
||||
break;
|
||||
}
|
||||
bp[0] = (archive_entry_hardlink(entry) != NULL) ? 'h' : '?';
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
if (!(mode & permbits[i]))
|
||||
bp[i+1] = '-';
|
||||
mode = archive_entry_mode(entry);
|
||||
for (i = 0, mask = 0400; i < 9; i++, mask >>= 1)
|
||||
bp[i + 1] = (mode & mask) ? "rwx"[i % 3] : '-';
|
||||
|
||||
if (mode & S_ISUID) {
|
||||
if (mode & 0100) bp[3] = 's';
|
||||
else bp[3] = 'S';
|
||||
}
|
||||
if (mode & S_ISGID) {
|
||||
if (mode & 0010) bp[6] = 's';
|
||||
else bp[6] = 'S';
|
||||
}
|
||||
if (mode & S_ISVTX) {
|
||||
if (mode & 0001) bp[9] = 't';
|
||||
else bp[9] = 'T';
|
||||
}
|
||||
if (archive_entry_acl_types(entry) != 0)
|
||||
bp[10] = '+';
|
||||
if (mode & S_ISUID)
|
||||
bp[3] = (mode & 0100) ? 's' : 'S';
|
||||
if (mode & S_ISGID)
|
||||
bp[6] = (mode & 0010) ? 's' : 'S';
|
||||
if (mode & S_ISVTX)
|
||||
bp[9] = (mode & 0001) ? 't' : 'T';
|
||||
bp[10] = (archive_entry_acl_types(entry) != 0) ? '+' : ' ';
|
||||
bp[11] = '\0';
|
||||
|
||||
return (bp);
|
||||
}
|
||||
|
||||
@@ -96,11 +96,11 @@ archive_entry_xattr_add_entry(struct archive_entry *entry,
|
||||
if ((xp->name = strdup(name)) == NULL)
|
||||
__archive_errx(1, "Out of memory");
|
||||
|
||||
if ((xp->value = malloc(size)) != NULL) {
|
||||
memcpy(xp->value, value, size);
|
||||
xp->size = size;
|
||||
} else
|
||||
xp->size = 0;
|
||||
if ((xp->value = malloc(size)) == NULL)
|
||||
__archive_errx(1, "Out of memory");
|
||||
|
||||
memcpy(xp->value, value, size);
|
||||
xp->size = size;
|
||||
|
||||
xp->next = entry->xattr_head;
|
||||
entry->xattr_head = xp;
|
||||
|
||||
@@ -74,7 +74,7 @@ __hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
|
||||
|
||||
#ifndef BCRYPT_HASH_REUSABLE_FLAG
|
||||
# define BCRYPT_HASH_REUSABLE_FLAG 0x00000020
|
||||
|
||||
@@ -52,7 +52,7 @@ int __libarchive_hmac_build_hack(void);
|
||||
|
||||
typedef CCHmacContext archive_hmac_sha1_ctx;
|
||||
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
|
||||
#include <bcrypt.h>
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/*-
|
||||
* Copyright (c) 2026 Tobias Stoeckmann
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ARCHIVE_INTEGER_H_INCLUDED
|
||||
#define ARCHIVE_INTEGER_H_INCLUDED
|
||||
|
||||
#ifdef CM_PARSE_DATE
|
||||
#define HAVE_STDINT_H 1
|
||||
#define USE_STDCKDINT 0
|
||||
#else
|
||||
#include "archive_platform.h"
|
||||
|
||||
/* Note: This is a purely internal header! */
|
||||
/* Do not use this outside of libarchive internal code! */
|
||||
|
||||
#ifndef __LIBARCHIVE_BUILD
|
||||
#error This header is only to be used internally to libarchive.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTSAFE_H
|
||||
#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
|
||||
#include <intsafe.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDCKDINT_H
|
||||
#include <stdckdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDCKDINT_H
|
||||
#define USE_STDCKDINT 1
|
||||
#elif (__GNUC__ >= 5 && !defined(__INTEL_COMPILER))
|
||||
#define USE_BUILTIN 1
|
||||
#elif __has_builtin(__builtin_add_overflow)
|
||||
#define USE_BUILTIN 1
|
||||
#elif defined HAVE_INTSAFE_H
|
||||
#define USE_INTSAFE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Disabling inline keyword for compilers known to choke on it:
|
||||
* - Watcom C++ in C code. (For any version?)
|
||||
* - SGI MIPSpro
|
||||
* - Microsoft Visual C++ 6.0 (supposedly newer versions too)
|
||||
* - IBM VisualAge 6 (XL v6)
|
||||
* - Sun WorkShop C (SunPro) before 5.9
|
||||
*/
|
||||
#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__)
|
||||
#define inline
|
||||
#elif defined(__IBMC__) && __IBMC__ < 700
|
||||
#define inline
|
||||
#elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590
|
||||
#define inline
|
||||
#elif defined(_MSC_VER) || defined(__osf__)
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
/* Returns 0 on success, a non-zero value otherwise. */
|
||||
static inline int
|
||||
archive_ckd_add_i64(int64_t *result, int64_t a, int64_t b)
|
||||
{
|
||||
#if USE_STDCKDINT
|
||||
return ckd_add(result, a, b);
|
||||
#elif USE_BUILTIN
|
||||
return __builtin_add_overflow(a, b, result);
|
||||
#elif USE_INTSAFE
|
||||
LONGLONG res;
|
||||
int ret;
|
||||
|
||||
ret = LongLongAdd(a, b, &res);
|
||||
*result = (int64_t)res;
|
||||
return ret;
|
||||
#else
|
||||
if ((b > 0 && a > INT64_MAX - b) ||
|
||||
(b < 0 && a < INT64_MIN - b))
|
||||
return 1;
|
||||
|
||||
*result = a + b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 0 on success, a non-zero value otherwise. */
|
||||
static inline int
|
||||
archive_ckd_add_size(size_t *result, size_t a, size_t b)
|
||||
{
|
||||
#if USE_STDCKDINT
|
||||
return ckd_add(result, a, b);
|
||||
#elif USE_BUILTIN
|
||||
return __builtin_add_overflow(a, b, result);
|
||||
#elif USE_INTSAFE
|
||||
return SizeTAdd(a, b, result);
|
||||
#else
|
||||
if (a > SIZE_MAX - b)
|
||||
return 1;
|
||||
*result = a + b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 0 on success, a non-zero value otherwise. */
|
||||
static inline int
|
||||
archive_ckd_add_u64(uint64_t *result, uint64_t a, uint64_t b)
|
||||
{
|
||||
#if USE_STDCKDINT
|
||||
return ckd_add(result, a, b);
|
||||
#elif USE_BUILTIN
|
||||
return __builtin_add_overflow(a, b, result);
|
||||
#elif USE_INTSAFE
|
||||
ULONGLONG res;
|
||||
int ret;
|
||||
|
||||
ret = ULongLongAdd(a, b, &res);
|
||||
*result = (uint64_t)res;
|
||||
return ret;
|
||||
#else
|
||||
if (a > UINT64_MAX - b)
|
||||
return 1;
|
||||
*result = a + b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 0 on success, a non-zero value otherwise. */
|
||||
static inline int
|
||||
archive_ckd_mul_i64(int64_t *result, int64_t a, int64_t b)
|
||||
{
|
||||
#if USE_STDCKDINT
|
||||
return ckd_mul(result, a, b);
|
||||
#elif USE_BUILTIN
|
||||
return __builtin_mul_overflow(a, b, result);
|
||||
#elif USE_INTSAFE
|
||||
LONGLONG res;
|
||||
int ret;
|
||||
|
||||
ret = LongLongMult(a, b, &res);
|
||||
*result = (int64_t)res;
|
||||
return ret;
|
||||
#else
|
||||
if ((a > 0 && b > 0 && a > INT64_MAX / b) ||
|
||||
(a < 0 && b > 0 && a < INT64_MIN / b) ||
|
||||
(a > 0 && b < 0 && b < INT64_MIN / a) ||
|
||||
(a < 0 && b < 0 && a < INT64_MAX / b))
|
||||
return 1;
|
||||
|
||||
*result = a * b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 0 on success, a non-zero value otherwise. */
|
||||
static inline int
|
||||
archive_ckd_mul_size(size_t *result, size_t a, size_t b)
|
||||
{
|
||||
#if USE_STDCKDINT
|
||||
return ckd_mul(result, a, b);
|
||||
#elif USE_BUILTIN
|
||||
return __builtin_mul_overflow(a, b, result);
|
||||
#elif USE_INTSAFE
|
||||
return SizeTMult(a, b, result);
|
||||
#else
|
||||
if (b != 0 && a > SIZE_MAX / b)
|
||||
return 1;
|
||||
*result = a * b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 0 on success, a non-zero value otherwise. */
|
||||
static inline int
|
||||
archive_ckd_mul_u64(uint64_t *result, uint64_t a, uint64_t b)
|
||||
{
|
||||
#if USE_STDCKDINT
|
||||
return ckd_mul(result, a, b);
|
||||
#elif USE_BUILTIN
|
||||
return __builtin_mul_overflow(a, b, result);
|
||||
#elif USE_INTSAFE
|
||||
ULONGLONG res;
|
||||
int ret;
|
||||
|
||||
ret = ULongLongMult(a, b, &res);
|
||||
*result = (uint64_t)res;
|
||||
return ret;
|
||||
#else
|
||||
if (b != 0 && a > UINT64_MAX / b)
|
||||
return 1;
|
||||
*result = a * b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns 0 on success, a non-zero value otherwise. */
|
||||
static inline int
|
||||
archive_ckd_sub_i64(int64_t *result, int64_t a, int64_t b)
|
||||
{
|
||||
#if USE_STDCKDINT
|
||||
return ckd_sub(result, a, b);
|
||||
#elif USE_BUILTIN
|
||||
return __builtin_sub_overflow(a, b, result);
|
||||
#elif USE_INTSAFE
|
||||
LONGLONG res;
|
||||
int ret;
|
||||
|
||||
ret = LongLongSub(a, b, &res);
|
||||
*result = (int64_t)res;
|
||||
return ret;
|
||||
#else
|
||||
if ((b > 0 && a < INT64_MIN + b) ||
|
||||
(b < 0 && a > INT64_MAX + b))
|
||||
return 1;
|
||||
|
||||
*result = a - b;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(TIME_MAX)
|
||||
#define TIME_MAX (((time_t)0 < (time_t)-1) ? (time_t)~0 : \
|
||||
sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MAX : \
|
||||
sizeof(time_t) == sizeof(long) ? (time_t)LONG_MAX : \
|
||||
sizeof(time_t) == sizeof(int) ? (time_t)INT_MAX : \
|
||||
sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MAX : \
|
||||
1 /* I give up */)
|
||||
#endif
|
||||
#if !defined(TIME_MIN)
|
||||
#define TIME_MIN (((time_t)0 < (time_t)-1) ? (time_t)0 : \
|
||||
sizeof(time_t) == sizeof(long long) ? (time_t)LLONG_MIN : \
|
||||
sizeof(time_t) == sizeof(long) ? (time_t)LONG_MIN : \
|
||||
sizeof(time_t) == sizeof(int) ? (time_t)INT_MIN : \
|
||||
sizeof(time_t) == sizeof(short) ? (time_t)SHRT_MIN : \
|
||||
-1 /* I give up */)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -40,6 +40,7 @@
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_pathmatch.h"
|
||||
@@ -216,6 +217,14 @@ error_nomem(struct archive_match *a)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
error_pattern(struct archive_match *a)
|
||||
{
|
||||
archive_set_error(&(a->archive), EINVAL, "Failed to apply pattern");
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an ARCHIVE_MATCH object.
|
||||
*/
|
||||
@@ -269,7 +278,7 @@ archive_match_free(struct archive *_a)
|
||||
*
|
||||
* Returns 1 if archive entry is excluded.
|
||||
* Returns 0 if archive entry is not excluded.
|
||||
* Returns <0 if something error happened.
|
||||
* Returns <0 if some error happened.
|
||||
*/
|
||||
int
|
||||
archive_match_excluded(struct archive *_a, struct archive_entry *entry)
|
||||
@@ -293,6 +302,8 @@ archive_match_excluded(struct archive *_a, struct archive_entry *entry)
|
||||
#else
|
||||
r = path_excluded(a, 1, archive_entry_pathname(entry));
|
||||
#endif
|
||||
if (r < 0)
|
||||
return (error_pattern(a));
|
||||
if (r != 0)
|
||||
return (r);
|
||||
}
|
||||
@@ -449,13 +460,14 @@ archive_match_include_pattern_from_file_w(struct archive *_a,
|
||||
*
|
||||
* Returns 1 if archive entry is excluded.
|
||||
* Returns 0 if archive entry is not excluded.
|
||||
* Returns <0 if something error happened.
|
||||
* Returns <0 if some error happened.
|
||||
*/
|
||||
int
|
||||
archive_match_path_excluded(struct archive *_a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct archive_match *a;
|
||||
int r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_match_path_excluded");
|
||||
@@ -471,10 +483,13 @@ archive_match_path_excluded(struct archive *_a,
|
||||
if ((a->setflag & PATTERN_IS_SET) == 0)
|
||||
return (0);
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
|
||||
r = path_excluded(a, 0, archive_entry_pathname_w(entry));
|
||||
#else
|
||||
return (path_excluded(a, 1, archive_entry_pathname(entry)));
|
||||
r = path_excluded(a, 1, archive_entry_pathname(entry));
|
||||
#endif
|
||||
if (r < 0)
|
||||
return (error_pattern(a));
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -605,7 +620,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
|
||||
int64_t offset;
|
||||
int r;
|
||||
|
||||
ar = archive_read_new();
|
||||
ar = archive_read_new();
|
||||
if (ar == NULL) {
|
||||
archive_set_error(&(a->archive), ENOMEM, "No memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -629,11 +644,12 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
|
||||
}
|
||||
r = archive_read_next_header(ar, &ae);
|
||||
if (r != ARCHIVE_OK) {
|
||||
archive_read_free(ar);
|
||||
if (r == ARCHIVE_EOF) {
|
||||
archive_read_free(ar);
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
archive_copy_error(&(a->archive), ar);
|
||||
archive_read_free(ar);
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
@@ -1007,7 +1023,7 @@ archive_match_exclude_entry(struct archive *_a, int flag,
|
||||
*
|
||||
* Returns 1 if archive entry is excluded.
|
||||
* Returns 0 if archive entry is not excluded.
|
||||
* Returns <0 if something error happened.
|
||||
* Returns <0 if some error happened.
|
||||
*/
|
||||
int
|
||||
archive_match_time_excluded(struct archive *_a,
|
||||
@@ -1653,7 +1669,7 @@ archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
|
||||
*
|
||||
* Returns 1 if archive entry is excluded.
|
||||
* Returns 0 if archive entry is not excluded.
|
||||
* Returns <0 if something error happened.
|
||||
* Returns <0 if some error happened.
|
||||
*/
|
||||
int
|
||||
archive_match_owner_excluded(struct archive *_a,
|
||||
@@ -1684,15 +1700,22 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
|
||||
|
||||
if (ids->count + 1 >= ids->size) {
|
||||
void *p;
|
||||
size_t alloc_size, new_size;
|
||||
|
||||
if (ids->size == 0)
|
||||
ids->size = 8;
|
||||
else
|
||||
ids->size *= 2;
|
||||
p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
|
||||
new_size = 8;
|
||||
else {
|
||||
if (archive_ckd_mul_size(&new_size, ids->size, 2))
|
||||
return (error_nomem(a));
|
||||
}
|
||||
if (archive_ckd_mul_size(&alloc_size,
|
||||
new_size, sizeof(*ids->ids)))
|
||||
return (error_nomem(a));
|
||||
p = realloc(ids->ids, alloc_size);
|
||||
if (p == NULL)
|
||||
return (error_nomem(a));
|
||||
ids->ids = (int64_t *)p;
|
||||
ids->size = new_size;
|
||||
}
|
||||
|
||||
/* Find an insert point. */
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
|
||||
#include "archive_options_private.h"
|
||||
|
||||
static const char *
|
||||
parse_option(const char **str,
|
||||
static char *
|
||||
parse_option(char **str,
|
||||
const char **mod, const char **opt, const char **val);
|
||||
|
||||
int
|
||||
@@ -90,7 +90,9 @@ _archive_set_either_option(struct archive *a, const char *m, const char *o, cons
|
||||
if (r2 == ARCHIVE_FATAL)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
if (r2 == ARCHIVE_WARN - 1)
|
||||
if (r1 == ARCHIVE_WARN - 1)
|
||||
return r2;
|
||||
if (r2 == ARCHIVE_WARN -1)
|
||||
return r1;
|
||||
return r1 > r2 ? r1 : r2;
|
||||
}
|
||||
@@ -100,8 +102,8 @@ _archive_set_options(struct archive *a, const char *options,
|
||||
unsigned int magic, const char *fn, option_handler use_option)
|
||||
{
|
||||
int allok = 1, anyok = 0, ignore_mod_err = 0, r;
|
||||
char *data;
|
||||
const char *s, *mod, *opt, *val;
|
||||
char *data, *s;
|
||||
const char *mod, *opt, *val;
|
||||
|
||||
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
|
||||
|
||||
@@ -113,7 +115,7 @@ _archive_set_options(struct archive *a, const char *options,
|
||||
ENOMEM, "Out of memory adding file to list");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
s = (const char *)data;
|
||||
s = data;
|
||||
|
||||
do {
|
||||
mod = opt = val = NULL;
|
||||
@@ -165,11 +167,11 @@ _archive_set_options(struct archive *a, const char *options,
|
||||
return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
static const char *
|
||||
parse_option(const char **s, const char **m, const char **o, const char **v)
|
||||
static char *
|
||||
parse_option(char **s, const char **m, const char **o, const char **v)
|
||||
{
|
||||
const char *end, *mod, *opt, *val;
|
||||
char *p;
|
||||
const char *mod, *val;
|
||||
char *end, *opt, *p;
|
||||
|
||||
end = NULL;
|
||||
mod = NULL;
|
||||
@@ -180,7 +182,7 @@ parse_option(const char **s, const char **m, const char **o, const char **v)
|
||||
|
||||
if (p != NULL) {
|
||||
*p = '\0';
|
||||
end = ((const char *)p) + 1;
|
||||
end = p + 1;
|
||||
}
|
||||
|
||||
if (0 == strlen(opt)) {
|
||||
|
||||
@@ -319,7 +319,7 @@ compare_format(const void *key, const void *element)
|
||||
pack_t *
|
||||
pack_find(const char *name)
|
||||
{
|
||||
struct format *format;
|
||||
const struct format *format;
|
||||
|
||||
format = bsearch(name, formats,
|
||||
sizeof(formats)/sizeof(formats[0]),
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_integer.h"
|
||||
|
||||
/* Basic time units. */
|
||||
#define EPOCH 1970
|
||||
@@ -51,7 +52,7 @@ enum DSTMODE { DSTon, DSToff, DSTmaybe };
|
||||
enum { tAM, tPM };
|
||||
/* Token types returned by nexttoken() */
|
||||
enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT,
|
||||
tUNUMBER, tZONE, tDST };
|
||||
tUNUMBER, tZONE, tDST, tERROR };
|
||||
struct token { int token; time_t value; };
|
||||
|
||||
/*
|
||||
@@ -820,20 +821,33 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses and consumes an unsigned number.
|
||||
* Returns 1 if any number is parsed. Otherwise, *value is unchanged.
|
||||
* Parses and consumes an unsigned 64-bit number.
|
||||
* Returns UINT64_MAX if the number overflows.
|
||||
*/
|
||||
static char
|
||||
consume_unsigned_number(const char **in, time_t *value)
|
||||
{
|
||||
char c;
|
||||
if (isdigit((unsigned char)(c = **in))) {
|
||||
for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
|
||||
*value = 10 * *value + c - '0';
|
||||
(*in)--;
|
||||
return 1;
|
||||
static uint64_t
|
||||
consume_unsigned_number(const char **in) {
|
||||
uint64_t value = 0;
|
||||
unsigned char c;
|
||||
|
||||
/* Get the first character, abort if it's not a digit */
|
||||
c = (unsigned char)(**in);
|
||||
if (c < '0' || c > '9') {
|
||||
return UINT64_MAX;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* Fold digits into the value, abort on overflow */
|
||||
while (c >= '0' && c <= '9') {
|
||||
unsigned char digit = c - '0';
|
||||
|
||||
/* Return error if the result would overflow UINT64_MAX */
|
||||
if (archive_ckd_mul_u64(&value, value, 10) ||
|
||||
archive_ckd_add_u64(&value, value, digit)) {
|
||||
return UINT64_MAX;
|
||||
}
|
||||
(*in)++;
|
||||
c = (unsigned char)(**in);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -908,12 +922,19 @@ nexttoken(const char **in, time_t *value)
|
||||
}
|
||||
|
||||
/*
|
||||
* Not in the word table, maybe it's a number. Note:
|
||||
* Because '-' and '+' have other special meanings, I
|
||||
* don't deal with signed numbers here.
|
||||
* Not in the word table. If it starts with a digit,
|
||||
* it must be a number. Note: Because '-' and '+' have
|
||||
* other special meanings, I don't deal with signed
|
||||
* numbers here.
|
||||
*/
|
||||
if (consume_unsigned_number(in, value)) {
|
||||
return (tUNUMBER);
|
||||
if (isdigit((unsigned char)(**in))) {
|
||||
uint64_t val = consume_unsigned_number(in);
|
||||
if (val > 9999) {
|
||||
return (tERROR);
|
||||
} else {
|
||||
*value = val;
|
||||
return (tUNUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
return *(*in)++;
|
||||
@@ -951,6 +972,7 @@ difftm (struct tm *a, struct tm *b)
|
||||
static time_t
|
||||
parse_unix_epoch(const char *p)
|
||||
{
|
||||
uint64_t val;
|
||||
time_t epoch;
|
||||
|
||||
/* may begin with + */
|
||||
@@ -959,12 +981,18 @@ parse_unix_epoch(const char *p)
|
||||
}
|
||||
|
||||
/* followed by some number */
|
||||
if (!consume_unsigned_number(&p, &epoch))
|
||||
val = consume_unsigned_number(&p);
|
||||
/* Truncate to time_t */
|
||||
epoch = (time_t)val;
|
||||
/* If truncated value is different, then
|
||||
* the value is too large for `time_t`. */
|
||||
if (epoch < 0 || (uint64_t)epoch != val) {
|
||||
return (time_t)-1;
|
||||
|
||||
/* ...and nothing else */
|
||||
if (*p != '\0')
|
||||
}
|
||||
/* If there's any more characters, fail. */
|
||||
if (*p != '\0') {
|
||||
return (time_t)-1;
|
||||
}
|
||||
|
||||
return epoch;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
#include "archive_pathmatch.h"
|
||||
|
||||
#define MAX_RECURSION 100
|
||||
|
||||
/*
|
||||
* Check whether a character 'c' is matched by a list specification [...]:
|
||||
* * Leading '!' or '^' negates the class.
|
||||
@@ -167,9 +169,13 @@ pm_slashskip_w(const wchar_t *s) {
|
||||
}
|
||||
|
||||
static int
|
||||
pm(const char *p, const char *s, int flags)
|
||||
pm(const char *p, const char *s, int flags, int depth)
|
||||
{
|
||||
const char *end;
|
||||
int r;
|
||||
|
||||
if (depth > MAX_RECURSION)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Ignore leading './', './/', '././', etc.
|
||||
@@ -202,8 +208,9 @@ pm(const char *p, const char *s, int flags)
|
||||
if (*p == '\0')
|
||||
return (1);
|
||||
while (*s) {
|
||||
if (archive_pathmatch(p, s, flags))
|
||||
return (1);
|
||||
r = pm(p, s, flags, depth + 1);
|
||||
if (r)
|
||||
return (r);
|
||||
++s;
|
||||
}
|
||||
return (0);
|
||||
@@ -220,7 +227,7 @@ pm(const char *p, const char *s, int flags)
|
||||
}
|
||||
if (*end == ']') {
|
||||
/* We found [...], try to match it. */
|
||||
if (!pm_list(p + 1, end, *s, flags))
|
||||
if (*s == '\0' || !pm_list(p + 1, end, *s, flags))
|
||||
return (0);
|
||||
p = end; /* Jump to trailing ']' char. */
|
||||
break;
|
||||
@@ -272,9 +279,13 @@ pm(const char *p, const char *s, int flags)
|
||||
}
|
||||
|
||||
static int
|
||||
pm_w(const wchar_t *p, const wchar_t *s, int flags)
|
||||
pm_w(const wchar_t *p, const wchar_t *s, int flags, int depth)
|
||||
{
|
||||
const wchar_t *end;
|
||||
int r;
|
||||
|
||||
if (depth > MAX_RECURSION)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Ignore leading './', './/', '././', etc.
|
||||
@@ -307,8 +318,9 @@ pm_w(const wchar_t *p, const wchar_t *s, int flags)
|
||||
if (*p == L'\0')
|
||||
return (1);
|
||||
while (*s) {
|
||||
if (archive_pathmatch_w(p, s, flags))
|
||||
return (1);
|
||||
r = pm_w(p, s, flags, depth + 1);
|
||||
if (r)
|
||||
return (r);
|
||||
++s;
|
||||
}
|
||||
return (0);
|
||||
@@ -325,7 +337,7 @@ pm_w(const wchar_t *p, const wchar_t *s, int flags)
|
||||
}
|
||||
if (*end == L']') {
|
||||
/* We found [...], try to match it. */
|
||||
if (!pm_list_w(p + 1, end, *s, flags))
|
||||
if (*s == L'\0' || !pm_list_w(p + 1, end, *s, flags))
|
||||
return (0);
|
||||
p = end; /* Jump to trailing ']' char. */
|
||||
break;
|
||||
@@ -387,7 +399,7 @@ __archive_pathmatch(const char *p, const char *s, int flags)
|
||||
return (0);
|
||||
|
||||
/* Leading '^' anchors the start of the pattern. */
|
||||
if (*p == '^') {
|
||||
if ((flags & PATHMATCH_NO_ANCHOR_START) && *p == '^') {
|
||||
++p;
|
||||
flags &= ~PATHMATCH_NO_ANCHOR_START;
|
||||
}
|
||||
@@ -401,22 +413,25 @@ __archive_pathmatch(const char *p, const char *s, int flags)
|
||||
++p;
|
||||
while (*s == '/')
|
||||
++s;
|
||||
return (pm(p, s, flags));
|
||||
return (pm(p, s, flags, 0));
|
||||
}
|
||||
|
||||
/* If start is unanchored, try to match start of each path element. */
|
||||
if (flags & PATHMATCH_NO_ANCHOR_START) {
|
||||
for ( ; s != NULL; s = strchr(s, '/')) {
|
||||
int r;
|
||||
|
||||
if (*s == '/')
|
||||
s++;
|
||||
if (pm(p, s, flags))
|
||||
return (1);
|
||||
r = pm(p, s, flags, 0);
|
||||
if (r)
|
||||
return (r);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Default: Match from beginning. */
|
||||
return (pm(p, s, flags));
|
||||
return (pm(p, s, flags, 0));
|
||||
}
|
||||
|
||||
int
|
||||
@@ -429,7 +444,7 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
|
||||
return (0);
|
||||
|
||||
/* Leading '^' anchors the start of the pattern. */
|
||||
if (*p == L'^') {
|
||||
if ((flags & PATHMATCH_NO_ANCHOR_START) && *p == L'^') {
|
||||
++p;
|
||||
flags &= ~PATHMATCH_NO_ANCHOR_START;
|
||||
}
|
||||
@@ -443,20 +458,23 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
|
||||
++p;
|
||||
while (*s == L'/')
|
||||
++s;
|
||||
return (pm_w(p, s, flags));
|
||||
return (pm_w(p, s, flags, 0));
|
||||
}
|
||||
|
||||
/* If start is unanchored, try to match start of each path element. */
|
||||
if (flags & PATHMATCH_NO_ANCHOR_START) {
|
||||
for ( ; s != NULL; s = wcschr(s, L'/')) {
|
||||
int r;
|
||||
|
||||
if (*s == L'/')
|
||||
s++;
|
||||
if (pm_w(p, s, flags))
|
||||
return (1);
|
||||
r = pm_w(p, s, flags, 0);
|
||||
if (r)
|
||||
return (r);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Default: Match from beginning. */
|
||||
return (pm_w(p, s, flags));
|
||||
return (pm_w(p, s, flags, 0));
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ typedef struct CPpmd8_Node_
|
||||
|
||||
#define EMPTY_NODE 0xFFFFFFFF
|
||||
|
||||
void Ppmd8_Construct(CPpmd8 *p)
|
||||
static void Ppmd8_Construct(CPpmd8 *p)
|
||||
{
|
||||
unsigned i, k, m;
|
||||
|
||||
@@ -93,14 +93,14 @@ void Ppmd8_Construct(CPpmd8 *p)
|
||||
}
|
||||
}
|
||||
|
||||
void Ppmd8_Free(CPpmd8 *p)
|
||||
static void Ppmd8_Free(CPpmd8 *p)
|
||||
{
|
||||
free(p->Base);
|
||||
p->Size = 0;
|
||||
p->Base = 0;
|
||||
}
|
||||
|
||||
Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size)
|
||||
static Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size)
|
||||
{
|
||||
if (p->Base == 0 || p->Size != size)
|
||||
{
|
||||
@@ -414,7 +414,7 @@ static void RestartModel(CPpmd8 *p)
|
||||
}
|
||||
}
|
||||
|
||||
void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
|
||||
static void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
|
||||
{
|
||||
p->MaxOrder = maxOrder;
|
||||
p->RestoreMethod = restoreMethod;
|
||||
@@ -1054,7 +1054,7 @@ static void Rescale(CPpmd8 *p)
|
||||
p->FoundState = STATS(p->MinContext);
|
||||
}
|
||||
|
||||
CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
|
||||
static CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
|
||||
{
|
||||
CPpmd_See *see;
|
||||
if (p->MinContext->NumStats != 0xFF)
|
||||
@@ -1090,7 +1090,7 @@ static void NextContext(CPpmd8 *p)
|
||||
}
|
||||
}
|
||||
|
||||
void Ppmd8_Update1(CPpmd8 *p)
|
||||
static void Ppmd8_Update1(CPpmd8 *p)
|
||||
{
|
||||
CPpmd_State *s = p->FoundState;
|
||||
s->Freq += 4;
|
||||
@@ -1105,7 +1105,7 @@ void Ppmd8_Update1(CPpmd8 *p)
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd8_Update1_0(CPpmd8 *p)
|
||||
static void Ppmd8_Update1_0(CPpmd8 *p)
|
||||
{
|
||||
p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq);
|
||||
p->RunLength += p->PrevSuccess;
|
||||
@@ -1115,7 +1115,7 @@ void Ppmd8_Update1_0(CPpmd8 *p)
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd8_UpdateBin(CPpmd8 *p)
|
||||
static void Ppmd8_UpdateBin(CPpmd8 *p)
|
||||
{
|
||||
p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196));
|
||||
p->PrevSuccess = 1;
|
||||
@@ -1123,7 +1123,7 @@ void Ppmd8_UpdateBin(CPpmd8 *p)
|
||||
NextContext(p);
|
||||
}
|
||||
|
||||
void Ppmd8_Update2(CPpmd8 *p)
|
||||
static void Ppmd8_Update2(CPpmd8 *p)
|
||||
{
|
||||
p->MinContext->SummFreq += 4;
|
||||
if ((p->FoundState->Freq += 4) > MAX_FREQ)
|
||||
@@ -1139,7 +1139,7 @@ This code is based on:
|
||||
PPMd var.I (2002): Dmitry Shkarin : Public domain
|
||||
Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
Bool Ppmd8_RangeDec_Init(CPpmd8 *p)
|
||||
static Bool Ppmd8_RangeDec_Init(CPpmd8 *p)
|
||||
{
|
||||
unsigned i;
|
||||
p->Low = 0;
|
||||
@@ -1173,7 +1173,7 @@ static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size)
|
||||
|
||||
#define MASK(sym) ((signed char *)charMask)[sym]
|
||||
|
||||
int Ppmd8_DecodeSymbol(CPpmd8 *p)
|
||||
static int Ppmd8_DecodeSymbol(CPpmd8 *p)
|
||||
{
|
||||
size_t charMask[256 / sizeof(size_t)];
|
||||
if (p->MinContext->NumStats != 0)
|
||||
|
||||
@@ -83,12 +83,6 @@ typedef struct
|
||||
UInt16 BinSumm[25][64];
|
||||
} CPpmd8;
|
||||
|
||||
void Ppmd8_Construct(CPpmd8 *p);
|
||||
Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size);
|
||||
void Ppmd8_Free(CPpmd8 *p);
|
||||
void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod);
|
||||
#define Ppmd8_WasAllocated(p) ((p)->Base != NULL)
|
||||
|
||||
|
||||
/* ---------- Internal Functions ---------- */
|
||||
|
||||
@@ -104,30 +98,11 @@ extern const Byte PPMD8_kExpEscape[16];
|
||||
#define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats)))
|
||||
#endif
|
||||
|
||||
void Ppmd8_Update1(CPpmd8 *p);
|
||||
void Ppmd8_Update1_0(CPpmd8 *p);
|
||||
void Ppmd8_Update2(CPpmd8 *p);
|
||||
void Ppmd8_UpdateBin(CPpmd8 *p);
|
||||
|
||||
#define Ppmd8_GetBinSumm(p) \
|
||||
&p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \
|
||||
p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \
|
||||
p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)]
|
||||
|
||||
CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale);
|
||||
|
||||
|
||||
/* ---------- Decode ---------- */
|
||||
|
||||
Bool Ppmd8_RangeDec_Init(CPpmd8 *p);
|
||||
#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
|
||||
int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */
|
||||
|
||||
/* ---------- Encode ---------- */
|
||||
|
||||
#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; }
|
||||
void Ppmd8_RangeEnc_FlushData(CPpmd8 *p);
|
||||
void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
@@ -61,12 +61,38 @@
|
||||
#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
|
||||
#define ARCHIVE_MATCH_MAGIC (0xcad11c9U)
|
||||
|
||||
/*
|
||||
* Having the state be a bitmask makes it easy to check
|
||||
* for combinations of allowed states. These should
|
||||
* generally only be used in public API entry points,
|
||||
* primarily in archive_read.c, archive_write.c, etc.
|
||||
* Internal callbacks can rely on the core machinery
|
||||
* to only call them when appropriate.
|
||||
*
|
||||
* Generally checked via `__archive_check_magic()`.
|
||||
*/
|
||||
|
||||
/* Newly created archive object, not yet opened */
|
||||
#define ARCHIVE_STATE_NEW 1U
|
||||
/* Archive is ready to read a header. */
|
||||
#define ARCHIVE_STATE_HEADER 2U
|
||||
/* A header has been read: client can ask for data
|
||||
* or they can ask for the next header and
|
||||
* we'll automatically skip the remaining data. */
|
||||
#define ARCHIVE_STATE_DATA 4U
|
||||
/* Similar to STATE_DATA but after a FAILED header:
|
||||
* the client may not read data, but they may ask
|
||||
* for the next header and we'll recover. */
|
||||
#define ARCHIVE_STATE_DATA_RECOVERY 8U
|
||||
/* End-of-archive has been reached. Client can only
|
||||
* close or free the archive. */
|
||||
#define ARCHIVE_STATE_EOF 0x10U
|
||||
/* Archive is closed; client is only allowed to free the archive. */
|
||||
#define ARCHIVE_STATE_CLOSED 0x20U
|
||||
/* Archive is in a FATAL error state: a close request
|
||||
* is permitted but ignored. */
|
||||
#define ARCHIVE_STATE_FATAL 0x8000U
|
||||
/* Any valid (non-fatal) state. */
|
||||
#define ARCHIVE_STATE_ANY (0xFFFFU & ~ARCHIVE_STATE_FATAL)
|
||||
|
||||
struct archive_vtable {
|
||||
|
||||
@@ -58,18 +58,12 @@ static void la_arc4random_buf(void *, size_t);
|
||||
#include "archive_random_private.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
/* don't use bcrypt when XP needs to be supported */
|
||||
#include <bcrypt.h>
|
||||
|
||||
/* Common in other bcrypt implementations, but missing from VS2008. */
|
||||
#ifndef BCRYPT_SUCCESS
|
||||
#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_WINCRYPT_H)
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
@@ -85,7 +79,6 @@ int
|
||||
archive_random(void *buf, size_t nbytes)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
# if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
NTSTATUS status;
|
||||
BCRYPT_ALG_HANDLE hAlg;
|
||||
|
||||
@@ -98,25 +91,6 @@ archive_random(void *buf, size_t nbytes)
|
||||
return ARCHIVE_FAILED;
|
||||
|
||||
return ARCHIVE_OK;
|
||||
# else
|
||||
HCRYPTPROV hProv;
|
||||
BOOL success;
|
||||
|
||||
success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT);
|
||||
if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) {
|
||||
success = CryptAcquireContext(&hProv, NULL, NULL,
|
||||
PROV_RSA_FULL, CRYPT_NEWKEYSET);
|
||||
}
|
||||
if (success) {
|
||||
success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf);
|
||||
CryptReleaseContext(hProv, 0);
|
||||
if (success)
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
/* TODO: Does this case really happen? */
|
||||
return ARCHIVE_FAILED;
|
||||
# endif
|
||||
#elif !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
|
||||
la_arc4random_buf(buf, nbytes);
|
||||
return ARCHIVE_OK;
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
@@ -49,6 +52,7 @@
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
@@ -99,7 +103,12 @@ archive_read_new(void)
|
||||
|
||||
a->archive.state = ARCHIVE_STATE_NEW;
|
||||
a->entry = archive_entry_new2(&a->archive);
|
||||
if (a->entry == NULL) {
|
||||
free(a);
|
||||
return (NULL);
|
||||
}
|
||||
a->archive.vtable = &archive_read_vtable;
|
||||
a->entry_bytes_declared = -1;
|
||||
|
||||
a->passphrases.last = &a->passphrases.first;
|
||||
|
||||
@@ -131,12 +140,16 @@ archive_read_open(struct archive *a, void *client_data,
|
||||
archive_open_callback *client_opener, archive_read_callback *client_reader,
|
||||
archive_close_callback *client_closer)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Old archive_read_open() is just a thin shell around
|
||||
* archive_read_open1. */
|
||||
archive_read_set_open_callback(a, client_opener);
|
||||
archive_read_set_read_callback(a, client_reader);
|
||||
archive_read_set_close_callback(a, client_closer);
|
||||
archive_read_set_callback_data(a, client_data);
|
||||
r = archive_read_set_callback_data(a, client_data);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
return archive_read_open1(a);
|
||||
}
|
||||
|
||||
@@ -148,9 +161,13 @@ archive_read_open2(struct archive *a, void *client_data,
|
||||
archive_skip_callback *client_skipper,
|
||||
archive_close_callback *client_closer)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* Old archive_read_open2() is just a thin shell around
|
||||
* archive_read_open1. */
|
||||
archive_read_set_callback_data(a, client_data);
|
||||
r = archive_read_set_callback_data(a, client_data);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
archive_read_set_open_callback(a, client_opener);
|
||||
archive_read_set_read_callback(a, client_reader);
|
||||
archive_read_set_skip_callback(a, client_skipper);
|
||||
@@ -159,28 +176,28 @@ archive_read_open2(struct archive *a, void *client_data,
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
client_read_proxy(struct archive_read_filter *self, const void **buff)
|
||||
client_read_proxy(struct archive_read_filter *f, const void **buff)
|
||||
{
|
||||
ssize_t r;
|
||||
r = (self->archive->client.reader)(&self->archive->archive,
|
||||
self->data, buff);
|
||||
r = (f->archive->client.reader)(&f->archive->archive,
|
||||
f->data, buff);
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
client_skip_proxy(struct archive_read_filter *self, int64_t request)
|
||||
client_skip_proxy(struct archive_read_filter *f, int64_t request)
|
||||
{
|
||||
if (request < 0)
|
||||
__archive_errx(1, "Negative skip requested.");
|
||||
__archive_errx(1, "Negative skip requested");
|
||||
if (request == 0)
|
||||
return 0;
|
||||
|
||||
if (self->archive->client.skipper != NULL) {
|
||||
if (f->archive->client.skipper != NULL) {
|
||||
int64_t total = 0;
|
||||
for (;;) {
|
||||
int64_t get, ask = request;
|
||||
get = (self->archive->client.skipper)
|
||||
(&self->archive->archive, self->data, ask);
|
||||
get = (f->archive->client.skipper)
|
||||
(&f->archive->archive, f->data, ask);
|
||||
total += get;
|
||||
if (get == 0 || get == request)
|
||||
return (total);
|
||||
@@ -188,7 +205,7 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
|
||||
return ARCHIVE_FATAL;
|
||||
request -= get;
|
||||
}
|
||||
} else if (self->archive->client.seeker != NULL
|
||||
} else if (f->archive->client.seeker != NULL
|
||||
&& request > 64 * 1024) {
|
||||
/* If the client provided a seeker but not a skipper,
|
||||
* we can use the seeker to skip forward.
|
||||
@@ -201,9 +218,9 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
|
||||
* to just reading and discarding. That's why we
|
||||
* only do this for skips of over 64k.
|
||||
*/
|
||||
int64_t before = self->position;
|
||||
int64_t after = (self->archive->client.seeker)
|
||||
(&self->archive->archive, self->data, request, SEEK_CUR);
|
||||
int64_t before = f->position;
|
||||
int64_t after = (f->archive->client.seeker)
|
||||
(&f->archive->archive, f->data, request, SEEK_CUR);
|
||||
if (after != before + request)
|
||||
return ARCHIVE_FATAL;
|
||||
return after - before;
|
||||
@@ -212,20 +229,20 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
|
||||
}
|
||||
|
||||
static int64_t
|
||||
client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
|
||||
client_seek_proxy(struct archive_read_filter *f, int64_t offset, int whence)
|
||||
{
|
||||
/* DO NOT use the skipper here! If we transparently handled
|
||||
* forward seek here by using the skipper, that will break
|
||||
* other libarchive code that assumes a successful forward
|
||||
* seek means it can also seek backwards.
|
||||
*/
|
||||
if (self->archive->client.seeker == NULL) {
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
if (f->archive->client.seeker == NULL) {
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Current client reader does not support seeking a device");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
return (self->archive->client.seeker)(&self->archive->archive,
|
||||
self->data, offset, whence);
|
||||
return (f->archive->client.seeker)(&f->archive->archive,
|
||||
f->data, offset, whence);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -247,47 +264,44 @@ read_client_close_proxy(struct archive_read *a)
|
||||
}
|
||||
|
||||
static int
|
||||
client_close_proxy(struct archive_read_filter *self)
|
||||
client_close_proxy(struct archive_read_filter *f)
|
||||
{
|
||||
return read_client_close_proxy(self->archive);
|
||||
return read_client_close_proxy(f->archive);
|
||||
}
|
||||
|
||||
static int
|
||||
client_open_proxy(struct archive_read_filter *self)
|
||||
client_switch_proxy(struct archive_read_filter *f, unsigned int iindex)
|
||||
{
|
||||
int r = ARCHIVE_OK;
|
||||
if (self->archive->client.opener != NULL)
|
||||
r = (self->archive->client.opener)(
|
||||
(struct archive *)self->archive, self->data);
|
||||
return (r);
|
||||
}
|
||||
struct archive_read *a;
|
||||
int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
|
||||
void *data2;
|
||||
|
||||
static int
|
||||
client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)
|
||||
{
|
||||
int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
|
||||
void *data2 = NULL;
|
||||
while (f->upstream != NULL)
|
||||
f = f->upstream;
|
||||
a = f->archive;
|
||||
|
||||
/* Don't do anything if already in the specified data node */
|
||||
if (self->archive->client.cursor == iindex)
|
||||
if (a->client.cursor == iindex)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
self->archive->client.cursor = iindex;
|
||||
data2 = self->archive->client.dataset[self->archive->client.cursor].data;
|
||||
if (self->archive->client.switcher != NULL)
|
||||
a->client.cursor = iindex;
|
||||
data2 = a->client.dataset[a->client.cursor].data;
|
||||
if (a->client.switcher != NULL)
|
||||
{
|
||||
r1 = r2 = (self->archive->client.switcher)
|
||||
((struct archive *)self->archive, self->data, data2);
|
||||
self->data = data2;
|
||||
r1 = r2 = (a->client.switcher)
|
||||
((struct archive *)a, f->data, data2);
|
||||
f->data = data2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Attempt to call close and open instead */
|
||||
if (self->archive->client.closer != NULL)
|
||||
r1 = (self->archive->client.closer)
|
||||
((struct archive *)self->archive, self->data);
|
||||
self->data = data2;
|
||||
r2 = client_open_proxy(self);
|
||||
if (a->client.closer != NULL)
|
||||
r1 = (a->client.closer)
|
||||
((struct archive *)a, f->data);
|
||||
f->data = data2;
|
||||
if (a->client.opener != NULL)
|
||||
r2 = (a->client.opener)
|
||||
((struct archive *)a, f->data);
|
||||
}
|
||||
return (r1 < r2) ? r1 : r2;
|
||||
}
|
||||
@@ -379,7 +393,7 @@ archive_read_set_callback_data2(struct archive *_a, void *client_data,
|
||||
if (a->client.dataset == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory.");
|
||||
"No memory");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
a->client.nodes = 1;
|
||||
@@ -388,7 +402,7 @@ archive_read_set_callback_data2(struct archive *_a, void *client_data,
|
||||
if (iindex > a->client.nodes - 1)
|
||||
{
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Invalid index specified.");
|
||||
"Invalid index specified");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
a->client.dataset[iindex].data = client_data;
|
||||
@@ -403,23 +417,37 @@ archive_read_add_callback_data(struct archive *_a, void *client_data,
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
void *p;
|
||||
size_t alloc_size;
|
||||
unsigned int i;
|
||||
unsigned int nodes;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
|
||||
"archive_read_add_callback_data");
|
||||
if (iindex > a->client.nodes) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Invalid index specified.");
|
||||
"Invalid index specified");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
p = realloc(a->client.dataset, sizeof(*a->client.dataset)
|
||||
* (++(a->client.nodes)));
|
||||
|
||||
if (a->client.nodes == UINT_MAX ||
|
||||
archive_ckd_mul_size(&alloc_size,
|
||||
(size_t)a->client.nodes + 1, sizeof(*a->client.dataset))) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
nodes = a->client.nodes + 1;
|
||||
p = realloc(a->client.dataset, alloc_size);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory.");
|
||||
"No memory");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
a->client.dataset = (struct archive_read_data_node *)p;
|
||||
a->client.nodes = nodes;
|
||||
|
||||
for (i = a->client.nodes - 1; i > iindex; i--) {
|
||||
a->client.dataset[i].data = a->client.dataset[i-1].data;
|
||||
a->client.dataset[i].begin_position = -1;
|
||||
@@ -454,7 +482,7 @@ int
|
||||
archive_read_open1(struct archive *_a)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
struct archive_read_filter *filter, *tmp;
|
||||
struct archive_read_filter *f, *tmp;
|
||||
int slot, e = ARCHIVE_OK;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
|
||||
@@ -478,23 +506,23 @@ archive_read_open1(struct archive *_a)
|
||||
}
|
||||
}
|
||||
|
||||
filter = calloc(1, sizeof(*filter));
|
||||
if (filter == NULL)
|
||||
f = calloc(1, sizeof(*f));
|
||||
if (f == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
filter->bidder = NULL;
|
||||
filter->upstream = NULL;
|
||||
filter->archive = a;
|
||||
filter->data = a->client.dataset[0].data;
|
||||
filter->vtable = &none_reader_vtable;
|
||||
filter->name = "none";
|
||||
filter->code = ARCHIVE_FILTER_NONE;
|
||||
filter->can_skip = 1;
|
||||
filter->can_seek = 1;
|
||||
f->bidder = NULL;
|
||||
f->upstream = NULL;
|
||||
f->archive = a;
|
||||
f->data = a->client.dataset[0].data;
|
||||
f->vtable = &none_reader_vtable;
|
||||
f->name = "none";
|
||||
f->code = ARCHIVE_FILTER_NONE;
|
||||
f->can_skip = 1;
|
||||
f->can_seek = 1;
|
||||
|
||||
a->client.dataset[0].begin_position = 0;
|
||||
if (!a->filter || !a->bypass_filter_bidding)
|
||||
{
|
||||
a->filter = filter;
|
||||
a->filter = f;
|
||||
/* Build out the input pipeline. */
|
||||
e = choose_filters(a);
|
||||
if (e < ARCHIVE_WARN) {
|
||||
@@ -508,7 +536,7 @@ archive_read_open1(struct archive *_a)
|
||||
tmp = a->filter;
|
||||
while (tmp->upstream)
|
||||
tmp = tmp->upstream;
|
||||
tmp->upstream = filter;
|
||||
tmp->upstream = f;
|
||||
}
|
||||
|
||||
if (!a->format)
|
||||
@@ -543,7 +571,7 @@ choose_filters(struct archive_read *a)
|
||||
{
|
||||
int number_bidders, i, bid, best_bid, number_filters;
|
||||
struct archive_read_filter_bidder *bidder, *best_bidder;
|
||||
struct archive_read_filter *filter;
|
||||
struct archive_read_filter *f;
|
||||
ssize_t avail;
|
||||
int r;
|
||||
|
||||
@@ -575,13 +603,13 @@ choose_filters(struct archive_read *a)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
filter = calloc(1, sizeof(*filter));
|
||||
if (filter == NULL)
|
||||
f = calloc(1, sizeof(*f));
|
||||
if (f == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
filter->bidder = best_bidder;
|
||||
filter->archive = a;
|
||||
filter->upstream = a->filter;
|
||||
a->filter = filter;
|
||||
f->bidder = best_bidder;
|
||||
f->archive = a;
|
||||
f->upstream = a->filter;
|
||||
a->filter = f;
|
||||
r = (best_bidder->vtable->init)(a->filter);
|
||||
if (r != ARCHIVE_OK) {
|
||||
__archive_read_free_filters(a);
|
||||
@@ -611,7 +639,8 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
|
||||
int r1 = ARCHIVE_OK, r2;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
|
||||
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
||||
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA |
|
||||
ARCHIVE_STATE_DATA_RECOVERY,
|
||||
"archive_read_next_header");
|
||||
|
||||
archive_entry_clear(entry);
|
||||
@@ -620,12 +649,16 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
|
||||
/*
|
||||
* If client didn't consume entire data, skip any remainder
|
||||
* (This is especially important for GNU incremental directories.)
|
||||
* A header that failed to parse (DATA_RECOVERY) still needs the
|
||||
* same treatment: whatever of its body the format reader left
|
||||
* unconsumed must be skipped before we can read the next header.
|
||||
*/
|
||||
if (a->archive.state == ARCHIVE_STATE_DATA) {
|
||||
if (a->archive.state == ARCHIVE_STATE_DATA ||
|
||||
a->archive.state == ARCHIVE_STATE_DATA_RECOVERY) {
|
||||
r1 = archive_read_data_skip(&a->archive);
|
||||
if (r1 == ARCHIVE_EOF)
|
||||
archive_set_error(&a->archive, EIO,
|
||||
"Premature end-of-file.");
|
||||
"Premature end-of-file");
|
||||
if (r1 == ARCHIVE_EOF || r1 == ARCHIVE_FATAL) {
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -659,8 +692,26 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
|
||||
case ARCHIVE_FATAL:
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
break;
|
||||
case ARCHIVE_FAILED:
|
||||
/*
|
||||
* This entry's header could not be parsed, so its metadata
|
||||
* cannot be trusted. ARCHIVE_STATE_DATA_RECOVERY still
|
||||
* permits skipping past it (the format reader is
|
||||
* responsible for ensuring that's actually possible), but
|
||||
* blocks archive_read_data() and friends, which all check
|
||||
* for ARCHIVE_STATE_DATA specifically and would otherwise
|
||||
* return content for an entry we don't actually understand.
|
||||
*/
|
||||
a->archive.state = ARCHIVE_STATE_DATA_RECOVERY;
|
||||
break;
|
||||
}
|
||||
|
||||
if (r2 == ARCHIVE_OK || r2 == ARCHIVE_WARN)
|
||||
a->entry_bytes_declared = archive_entry_size_is_set(entry)
|
||||
? archive_entry_size(entry) : -1;
|
||||
else
|
||||
a->entry_bytes_declared = -1;
|
||||
|
||||
__archive_reset_read_data(&a->archive);
|
||||
|
||||
a->data_start_node = a->client.cursor;
|
||||
@@ -749,7 +800,7 @@ archive_read_header_position(struct archive *_a)
|
||||
|
||||
/*
|
||||
* Returns 1 if the archive contains at least one encrypted entry.
|
||||
* If the archive format not support encryption at all
|
||||
* If the archive format does not support encryption at all,
|
||||
* ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.
|
||||
* If for any other reason (e.g. not enough data read so far)
|
||||
* we cannot say whether there are encrypted entries, then
|
||||
@@ -919,7 +970,8 @@ archive_read_data_skip(struct archive *_a)
|
||||
size_t size;
|
||||
int64_t offset;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
|
||||
ARCHIVE_STATE_DATA | ARCHIVE_STATE_DATA_RECOVERY,
|
||||
"archive_read_data_skip");
|
||||
|
||||
if (a->format->read_data_skip != NULL)
|
||||
@@ -934,7 +986,10 @@ archive_read_data_skip(struct archive *_a)
|
||||
if (r == ARCHIVE_EOF)
|
||||
r = ARCHIVE_OK;
|
||||
|
||||
a->archive.state = ARCHIVE_STATE_HEADER;
|
||||
if (r == ARCHIVE_FATAL)
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
else
|
||||
a->archive.state = ARCHIVE_STATE_HEADER;
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -942,17 +997,21 @@ la_int64_t
|
||||
archive_seek_data(struct archive *_a, int64_t offset, int whence)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
la_int64_t r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
|
||||
"archive_seek_data_block");
|
||||
|
||||
if (a->format->seek_data == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Internal error: "
|
||||
"No format_seek_data_block function registered");
|
||||
return (ARCHIVE_FATAL);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Cannot seek data with this format");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
return (a->format->seek_data)(a, offset, whence);
|
||||
r = (a->format->seek_data)(a, offset, whence);
|
||||
if (r == ARCHIVE_FATAL)
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -968,6 +1027,8 @@ _archive_read_data_block(struct archive *_a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
int r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
|
||||
"archive_read_data_block");
|
||||
|
||||
@@ -975,10 +1036,14 @@ _archive_read_data_block(struct archive *_a,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Internal error: "
|
||||
"No format->read_data function registered");
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
return (a->format->read_data)(a, buff, size, offset);
|
||||
r = (a->format->read_data)(a, buff, size, offset);
|
||||
if (r == ARCHIVE_FATAL)
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1317,13 +1382,13 @@ __archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
|
||||
}
|
||||
|
||||
const void *
|
||||
__archive_read_filter_ahead(struct archive_read_filter *filter,
|
||||
__archive_read_filter_ahead(struct archive_read_filter *f,
|
||||
size_t min, ssize_t *avail)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
size_t tocopy;
|
||||
|
||||
if (filter->fatal) {
|
||||
if (f->fatal) {
|
||||
if (avail)
|
||||
*avail = ARCHIVE_FATAL;
|
||||
return (NULL);
|
||||
@@ -1340,79 +1405,79 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
|
||||
* note that min == 0 is a perfectly well-defined
|
||||
* request.
|
||||
*/
|
||||
if (filter->avail >= min && filter->avail > 0) {
|
||||
if (f->avail >= min && f->avail > 0) {
|
||||
if (avail != NULL)
|
||||
*avail = filter->avail;
|
||||
return (filter->next);
|
||||
*avail = f->avail;
|
||||
return (f->next);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can satisfy directly from client buffer if everything
|
||||
* currently in the copy buffer is still in the client buffer.
|
||||
*/
|
||||
if (filter->client_total >= filter->client_avail + filter->avail
|
||||
&& filter->client_avail + filter->avail >= min) {
|
||||
if (f->client_total >= f->client_avail + f->avail
|
||||
&& f->client_avail + f->avail >= min) {
|
||||
/* "Roll back" to client buffer. */
|
||||
filter->client_avail += filter->avail;
|
||||
filter->client_next -= filter->avail;
|
||||
f->client_avail += f->avail;
|
||||
f->client_next -= f->avail;
|
||||
/* Copy buffer is now empty. */
|
||||
filter->avail = 0;
|
||||
filter->next = filter->buffer;
|
||||
f->avail = 0;
|
||||
f->next = f->buffer;
|
||||
/* Return data from client buffer. */
|
||||
if (avail != NULL)
|
||||
*avail = filter->client_avail;
|
||||
return (filter->client_next);
|
||||
*avail = f->client_avail;
|
||||
return (f->client_next);
|
||||
}
|
||||
|
||||
/* Move data forward in copy buffer if necessary. */
|
||||
if (filter->next > filter->buffer &&
|
||||
filter->next + min > filter->buffer + filter->buffer_size) {
|
||||
if (filter->avail > 0)
|
||||
memmove(filter->buffer, filter->next,
|
||||
filter->avail);
|
||||
filter->next = filter->buffer;
|
||||
if (f->next > f->buffer &&
|
||||
min > f->buffer_size - (f->next - f->buffer)) {
|
||||
if (f->avail > 0)
|
||||
memmove(f->buffer, f->next,
|
||||
f->avail);
|
||||
f->next = f->buffer;
|
||||
}
|
||||
|
||||
/* If we've used up the client data, get more. */
|
||||
if (filter->client_avail <= 0) {
|
||||
if (filter->end_of_file) {
|
||||
if (f->client_avail <= 0) {
|
||||
if (f->end_of_file) {
|
||||
if (avail != NULL)
|
||||
*avail = filter->avail;
|
||||
*avail = f->avail;
|
||||
return (NULL);
|
||||
}
|
||||
bytes_read = (filter->vtable->read)(filter,
|
||||
&filter->client_buff);
|
||||
bytes_read = (f->vtable->read)(f,
|
||||
&f->client_buff);
|
||||
if (bytes_read < 0) { /* Read error. */
|
||||
filter->client_total = filter->client_avail = 0;
|
||||
filter->client_next =
|
||||
filter->client_buff = NULL;
|
||||
filter->fatal = 1;
|
||||
f->client_total = f->client_avail = 0;
|
||||
f->client_next =
|
||||
f->client_buff = NULL;
|
||||
f->fatal = 1;
|
||||
if (avail != NULL)
|
||||
*avail = ARCHIVE_FATAL;
|
||||
return (NULL);
|
||||
}
|
||||
if (bytes_read == 0) {
|
||||
/* Check for another client object first */
|
||||
if (filter->archive->client.cursor !=
|
||||
filter->archive->client.nodes - 1) {
|
||||
if (client_switch_proxy(filter,
|
||||
filter->archive->client.cursor + 1)
|
||||
if (f->archive->client.cursor !=
|
||||
f->archive->client.nodes - 1) {
|
||||
if (client_switch_proxy(f,
|
||||
f->archive->client.cursor + 1)
|
||||
== ARCHIVE_OK)
|
||||
continue;
|
||||
}
|
||||
/* Premature end-of-file. */
|
||||
filter->client_total = filter->client_avail = 0;
|
||||
filter->client_next =
|
||||
filter->client_buff = NULL;
|
||||
filter->end_of_file = 1;
|
||||
f->client_total = f->client_avail = 0;
|
||||
f->client_next =
|
||||
f->client_buff = NULL;
|
||||
f->end_of_file = 1;
|
||||
/* Return whatever we do have. */
|
||||
if (avail != NULL)
|
||||
*avail = filter->avail;
|
||||
*avail = f->avail;
|
||||
return (NULL);
|
||||
}
|
||||
filter->client_total = bytes_read;
|
||||
filter->client_avail = filter->client_total;
|
||||
filter->client_next = filter->client_buff;
|
||||
f->client_total = bytes_read;
|
||||
f->client_avail = f->client_total;
|
||||
f->client_next = f->client_buff;
|
||||
} else {
|
||||
/*
|
||||
* We can't satisfy the request from the copy
|
||||
@@ -1422,67 +1487,66 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
|
||||
*/
|
||||
|
||||
/* Ensure the buffer is big enough. */
|
||||
if (min > filter->buffer_size) {
|
||||
size_t s, t;
|
||||
if (min > f->buffer_size) {
|
||||
size_t s;
|
||||
char *p;
|
||||
|
||||
/* Double the buffer; watch for overflow. */
|
||||
s = t = filter->buffer_size;
|
||||
s = f->buffer_size;
|
||||
if (s == 0)
|
||||
s = min;
|
||||
while (s < min) {
|
||||
t *= 2;
|
||||
if (t <= s) { /* Integer overflow! */
|
||||
if (archive_ckd_mul_size(&s, s, 2)) {
|
||||
/* Integer overflow! */
|
||||
archive_set_error(
|
||||
&filter->archive->archive,
|
||||
&f->archive->archive,
|
||||
ENOMEM,
|
||||
"Unable to allocate copy"
|
||||
" buffer");
|
||||
filter->fatal = 1;
|
||||
f->fatal = 1;
|
||||
if (avail != NULL)
|
||||
*avail = ARCHIVE_FATAL;
|
||||
return (NULL);
|
||||
}
|
||||
s = t;
|
||||
}
|
||||
/* Now s >= min, so allocate a new buffer. */
|
||||
p = malloc(s);
|
||||
if (p == NULL) {
|
||||
archive_set_error(
|
||||
&filter->archive->archive,
|
||||
&f->archive->archive,
|
||||
ENOMEM,
|
||||
"Unable to allocate copy buffer");
|
||||
filter->fatal = 1;
|
||||
f->fatal = 1;
|
||||
if (avail != NULL)
|
||||
*avail = ARCHIVE_FATAL;
|
||||
return (NULL);
|
||||
}
|
||||
/* Move data into newly-enlarged buffer. */
|
||||
if (filter->avail > 0)
|
||||
memmove(p, filter->next, filter->avail);
|
||||
free(filter->buffer);
|
||||
filter->next = filter->buffer = p;
|
||||
filter->buffer_size = s;
|
||||
if (f->avail > 0)
|
||||
memmove(p, f->next, f->avail);
|
||||
free(f->buffer);
|
||||
f->next = f->buffer = p;
|
||||
f->buffer_size = s;
|
||||
}
|
||||
|
||||
/* We can add client data to copy buffer. */
|
||||
/* First estimate: copy to fill rest of buffer. */
|
||||
tocopy = (filter->buffer + filter->buffer_size)
|
||||
- (filter->next + filter->avail);
|
||||
tocopy = (f->buffer + f->buffer_size)
|
||||
- (f->next + f->avail);
|
||||
/* Don't waste time buffering more than we need to. */
|
||||
if (tocopy + filter->avail > min)
|
||||
tocopy = min - filter->avail;
|
||||
if (tocopy + f->avail > min)
|
||||
tocopy = min - f->avail;
|
||||
/* Don't copy more than is available. */
|
||||
if (tocopy > filter->client_avail)
|
||||
tocopy = filter->client_avail;
|
||||
if (tocopy > f->client_avail)
|
||||
tocopy = f->client_avail;
|
||||
|
||||
memcpy(filter->next + filter->avail,
|
||||
filter->client_next, tocopy);
|
||||
memcpy(f->next + f->avail,
|
||||
f->client_next, tocopy);
|
||||
/* Remove this data from client buffer. */
|
||||
filter->client_next += tocopy;
|
||||
filter->client_avail -= tocopy;
|
||||
f->client_next += tocopy;
|
||||
f->client_avail -= tocopy;
|
||||
/* add it to copy buffer. */
|
||||
filter->avail += tocopy;
|
||||
f->avail += tocopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1497,7 +1561,7 @@ __archive_read_consume(struct archive_read *a, int64_t request)
|
||||
}
|
||||
|
||||
int64_t
|
||||
__archive_read_filter_consume(struct archive_read_filter * filter,
|
||||
__archive_read_filter_consume(struct archive_read_filter *f,
|
||||
int64_t request)
|
||||
{
|
||||
int64_t skipped;
|
||||
@@ -1507,13 +1571,13 @@ __archive_read_filter_consume(struct archive_read_filter * filter,
|
||||
if (request == 0)
|
||||
return 0;
|
||||
|
||||
skipped = advance_file_pointer(filter, request);
|
||||
skipped = advance_file_pointer(f, request);
|
||||
if (skipped == request)
|
||||
return (skipped);
|
||||
/* We hit EOF before we satisfied the skip request. */
|
||||
if (skipped < 0) /* Map error code to 0 for error message below. */
|
||||
skipped = 0;
|
||||
archive_set_error(&filter->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Truncated input file (needed %jd bytes, only %jd available)",
|
||||
(intmax_t)request, (intmax_t)skipped);
|
||||
@@ -1527,45 +1591,45 @@ __archive_read_filter_consume(struct archive_read_filter * filter,
|
||||
* Returns a negative value if there's an I/O error.
|
||||
*/
|
||||
static int64_t
|
||||
advance_file_pointer(struct archive_read_filter *filter, int64_t request)
|
||||
advance_file_pointer(struct archive_read_filter *f, int64_t request)
|
||||
{
|
||||
int64_t bytes_skipped, total_bytes_skipped = 0;
|
||||
ssize_t bytes_read;
|
||||
size_t min;
|
||||
|
||||
if (filter->fatal)
|
||||
if (f->fatal)
|
||||
return (-1);
|
||||
|
||||
/* Use up the copy buffer first. */
|
||||
if (filter->avail > 0) {
|
||||
min = (size_t)minimum(request, (int64_t)filter->avail);
|
||||
filter->next += min;
|
||||
filter->avail -= min;
|
||||
if (f->avail > 0) {
|
||||
min = (size_t)minimum(request, (int64_t)f->avail);
|
||||
f->next += min;
|
||||
f->avail -= min;
|
||||
request -= min;
|
||||
filter->position += min;
|
||||
f->position += min;
|
||||
total_bytes_skipped += min;
|
||||
}
|
||||
|
||||
/* Then use up the client buffer. */
|
||||
if (filter->client_avail > 0) {
|
||||
min = (size_t)minimum(request, (int64_t)filter->client_avail);
|
||||
filter->client_next += min;
|
||||
filter->client_avail -= min;
|
||||
if (f->client_avail > 0) {
|
||||
min = (size_t)minimum(request, (int64_t)f->client_avail);
|
||||
f->client_next += min;
|
||||
f->client_avail -= min;
|
||||
request -= min;
|
||||
filter->position += min;
|
||||
f->position += min;
|
||||
total_bytes_skipped += min;
|
||||
}
|
||||
if (request == 0)
|
||||
return (total_bytes_skipped);
|
||||
|
||||
/* If there's an optimized skip function, use it. */
|
||||
if (filter->can_skip != 0) {
|
||||
bytes_skipped = client_skip_proxy(filter, request);
|
||||
if (f->can_skip != 0) {
|
||||
bytes_skipped = client_skip_proxy(f, request);
|
||||
if (bytes_skipped < 0) { /* error */
|
||||
filter->fatal = 1;
|
||||
f->fatal = 1;
|
||||
return (bytes_skipped);
|
||||
}
|
||||
filter->position += bytes_skipped;
|
||||
f->position += bytes_skipped;
|
||||
total_bytes_skipped += bytes_skipped;
|
||||
request -= bytes_skipped;
|
||||
if (request == 0)
|
||||
@@ -1574,37 +1638,37 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
|
||||
|
||||
/* Use ordinary reads as necessary to complete the request. */
|
||||
for (;;) {
|
||||
bytes_read = (filter->vtable->read)(filter, &filter->client_buff);
|
||||
bytes_read = (f->vtable->read)(f, &f->client_buff);
|
||||
if (bytes_read < 0) {
|
||||
filter->client_buff = NULL;
|
||||
filter->fatal = 1;
|
||||
f->client_buff = NULL;
|
||||
f->fatal = 1;
|
||||
return (bytes_read);
|
||||
}
|
||||
|
||||
if (bytes_read == 0) {
|
||||
if (filter->archive->client.cursor !=
|
||||
filter->archive->client.nodes - 1) {
|
||||
if (client_switch_proxy(filter,
|
||||
filter->archive->client.cursor + 1)
|
||||
if (f->archive->client.cursor !=
|
||||
f->archive->client.nodes - 1) {
|
||||
if (client_switch_proxy(f,
|
||||
f->archive->client.cursor + 1)
|
||||
== ARCHIVE_OK)
|
||||
continue;
|
||||
}
|
||||
filter->client_buff = NULL;
|
||||
filter->end_of_file = 1;
|
||||
f->client_buff = NULL;
|
||||
f->end_of_file = 1;
|
||||
return (total_bytes_skipped);
|
||||
}
|
||||
|
||||
if (bytes_read >= request) {
|
||||
filter->client_next =
|
||||
((const char *)filter->client_buff) + request;
|
||||
filter->client_avail = (size_t)(bytes_read - request);
|
||||
filter->client_total = bytes_read;
|
||||
f->client_next =
|
||||
((const char *)f->client_buff) + request;
|
||||
f->client_avail = (size_t)(bytes_read - request);
|
||||
f->client_total = bytes_read;
|
||||
total_bytes_skipped += request;
|
||||
filter->position += request;
|
||||
f->position += request;
|
||||
return (total_bytes_skipped);
|
||||
}
|
||||
|
||||
filter->position += bytes_read;
|
||||
f->position += bytes_read;
|
||||
total_bytes_skipped += bytes_read;
|
||||
request -= bytes_read;
|
||||
}
|
||||
@@ -1620,23 +1684,23 @@ __archive_read_seek(struct archive_read *a, int64_t offset, int whence)
|
||||
}
|
||||
|
||||
int64_t
|
||||
__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
|
||||
__archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
|
||||
int whence)
|
||||
{
|
||||
struct archive_read_client *client;
|
||||
int64_t r;
|
||||
unsigned int cursor;
|
||||
|
||||
if (filter->closed || filter->fatal)
|
||||
if (f->closed || f->fatal)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (filter->can_seek == 0)
|
||||
if (f->can_seek == 0)
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
client = &(filter->archive->client);
|
||||
client = &(f->archive->client);
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
/* Adjust the offset and use SEEK_SET instead */
|
||||
offset += filter->position;
|
||||
offset += f->position;
|
||||
__LA_FALLTHROUGH;
|
||||
case SEEK_SET:
|
||||
cursor = 0;
|
||||
@@ -1653,10 +1717,10 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
|
||||
client->dataset[++cursor].begin_position = r;
|
||||
}
|
||||
while (1) {
|
||||
r = client_switch_proxy(filter, cursor);
|
||||
r = client_switch_proxy(f, cursor);
|
||||
if (r != ARCHIVE_OK)
|
||||
return r;
|
||||
if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
|
||||
if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
|
||||
return r;
|
||||
client->dataset[cursor].total_size = r;
|
||||
if (client->dataset[cursor].begin_position +
|
||||
@@ -1671,7 +1735,7 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
|
||||
if (offset < 0
|
||||
|| offset > client->dataset[cursor].total_size)
|
||||
return ARCHIVE_FATAL;
|
||||
if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)
|
||||
if ((r = client_seek_proxy(f, offset, SEEK_SET)) < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
@@ -1687,10 +1751,10 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
|
||||
client->dataset[++cursor].begin_position = r;
|
||||
}
|
||||
while (1) {
|
||||
r = client_switch_proxy(filter, cursor);
|
||||
r = client_switch_proxy(f, cursor);
|
||||
if (r != ARCHIVE_OK)
|
||||
return r;
|
||||
if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
|
||||
if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
|
||||
return r;
|
||||
client->dataset[cursor].total_size = r;
|
||||
r = client->dataset[cursor].begin_position +
|
||||
@@ -1711,9 +1775,9 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
|
||||
client->dataset[cursor].total_size;
|
||||
}
|
||||
offset = (r + offset) - client->dataset[cursor].begin_position;
|
||||
if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)
|
||||
if ((r = client_switch_proxy(f, cursor)) != ARCHIVE_OK)
|
||||
return r;
|
||||
r = client_seek_proxy(filter, offset, SEEK_SET);
|
||||
r = client_seek_proxy(f, offset, SEEK_SET);
|
||||
if (r < ARCHIVE_OK)
|
||||
return r;
|
||||
break;
|
||||
@@ -1741,10 +1805,10 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
|
||||
* size is (r - offset). Can we use that to simplify
|
||||
* the TODO items above?
|
||||
*/
|
||||
filter->avail = filter->client_avail = 0;
|
||||
filter->next = filter->buffer;
|
||||
filter->position = r;
|
||||
filter->end_of_file = 0;
|
||||
f->avail = f->client_avail = 0;
|
||||
f->next = f->buffer;
|
||||
f->position = r;
|
||||
f->end_of_file = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -37,9 +37,9 @@ int
|
||||
archive_read_append_filter(struct archive *_a, int code)
|
||||
{
|
||||
int r1, r2, number_bidders, i;
|
||||
char str[20];
|
||||
struct archive_read_filter_bidder *bidder;
|
||||
struct archive_read_filter *filter;
|
||||
const char *str;
|
||||
struct archive_read_filter_bidder *b;
|
||||
struct archive_read_filter *f;
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
|
||||
r2 = (ARCHIVE_OK);
|
||||
@@ -53,15 +53,15 @@ archive_read_append_filter(struct archive *_a, int code)
|
||||
r1 = (ARCHIVE_OK);
|
||||
break;
|
||||
case ARCHIVE_FILTER_GZIP:
|
||||
strcpy(str, "gzip");
|
||||
str = "gzip";
|
||||
r1 = archive_read_support_filter_gzip(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_BZIP2:
|
||||
strcpy(str, "bzip2");
|
||||
str = "bzip2";
|
||||
r1 = archive_read_support_filter_bzip2(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_COMPRESS:
|
||||
strcpy(str, "compress (.Z)");
|
||||
str = "compress (.Z)";
|
||||
r1 = archive_read_support_filter_compress(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_PROGRAM:
|
||||
@@ -69,41 +69,45 @@ archive_read_append_filter(struct archive *_a, int code)
|
||||
"Cannot append program filter using archive_read_append_filter");
|
||||
return (ARCHIVE_FATAL);
|
||||
case ARCHIVE_FILTER_LZMA:
|
||||
strcpy(str, "lzma");
|
||||
str = "lzma";
|
||||
r1 = archive_read_support_filter_lzma(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_XZ:
|
||||
strcpy(str, "xz");
|
||||
str = "xz";
|
||||
r1 = archive_read_support_filter_xz(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_UU:
|
||||
strcpy(str, "uu");
|
||||
str = "uu";
|
||||
r1 = archive_read_support_filter_uu(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_RPM:
|
||||
strcpy(str, "rpm");
|
||||
str = "rpm";
|
||||
r1 = archive_read_support_filter_rpm(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZ4:
|
||||
strcpy(str, "lz4");
|
||||
str = "lz4";
|
||||
r1 = archive_read_support_filter_lz4(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_ZSTD:
|
||||
strcpy(str, "zstd");
|
||||
str = "zstd";
|
||||
r1 = archive_read_support_filter_zstd(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZIP:
|
||||
strcpy(str, "lzip");
|
||||
str = "lzip";
|
||||
r1 = archive_read_support_filter_lzip(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LZOP:
|
||||
strcpy(str, "lzop");
|
||||
str = "lzop";
|
||||
r1 = archive_read_support_filter_lzop(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_LRZIP:
|
||||
strcpy(str, "lrzip");
|
||||
str = "lrzip";
|
||||
r1 = archive_read_support_filter_lrzip(_a);
|
||||
break;
|
||||
case ARCHIVE_FILTER_GRZIP:
|
||||
str = "grzip";
|
||||
r1 = archive_read_support_filter_grzip(_a);
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Invalid filter code specified");
|
||||
@@ -114,30 +118,30 @@ archive_read_append_filter(struct archive *_a, int code)
|
||||
{
|
||||
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
|
||||
|
||||
bidder = a->bidders;
|
||||
for (i = 1; i < number_bidders; i++, bidder++)
|
||||
b = a->bidders;
|
||||
for (i = 1; i < number_bidders; i++, b++)
|
||||
{
|
||||
if (!bidder->name || !strcmp(bidder->name, str))
|
||||
if (!b->name || !strcmp(b->name, str))
|
||||
break;
|
||||
}
|
||||
if (!bidder->name || strcmp(bidder->name, str))
|
||||
if (!b->name || strcmp(b->name, str))
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Internal error: Unable to append filter");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
filter = calloc(1, sizeof(*filter));
|
||||
if (filter == NULL)
|
||||
f = calloc(1, sizeof(*f));
|
||||
if (f == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
filter->bidder = bidder;
|
||||
filter->archive = a;
|
||||
filter->upstream = a->filter;
|
||||
a->filter = filter;
|
||||
r2 = (bidder->vtable->init)(a->filter);
|
||||
f->bidder = b;
|
||||
f->archive = a;
|
||||
f->upstream = a->filter;
|
||||
a->filter = f;
|
||||
r2 = (b->vtable->init)(a->filter);
|
||||
if (r2 != ARCHIVE_OK) {
|
||||
__archive_read_free_filters(a);
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -159,8 +163,8 @@ archive_read_append_filter_program_signature(struct archive *_a,
|
||||
const char *cmd, const void *signature, size_t signature_len)
|
||||
{
|
||||
int r, number_bidders, i;
|
||||
struct archive_read_filter_bidder *bidder;
|
||||
struct archive_read_filter *filter;
|
||||
struct archive_read_filter_bidder *b;
|
||||
struct archive_read_filter *f;
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
|
||||
if (archive_read_support_filter_program_signature(_a, cmd, signature,
|
||||
@@ -169,36 +173,36 @@ archive_read_append_filter_program_signature(struct archive *_a,
|
||||
|
||||
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
|
||||
|
||||
bidder = a->bidders;
|
||||
for (i = 0; i < number_bidders; i++, bidder++)
|
||||
b = a->bidders;
|
||||
for (i = 0; i < number_bidders; i++, b++)
|
||||
{
|
||||
/* Program bidder name set to filter name after initialization */
|
||||
if (bidder->data && !bidder->name)
|
||||
if (b->data && !b->name)
|
||||
break;
|
||||
}
|
||||
if (!bidder->data)
|
||||
if (!b->data)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Internal error: Unable to append program filter");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
filter = calloc(1, sizeof(*filter));
|
||||
if (filter == NULL)
|
||||
f = calloc(1, sizeof(*f));
|
||||
if (f == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
filter->bidder = bidder;
|
||||
filter->archive = a;
|
||||
filter->upstream = a->filter;
|
||||
a->filter = filter;
|
||||
r = (bidder->vtable->init)(a->filter);
|
||||
f->bidder = b;
|
||||
f->archive = a;
|
||||
f->upstream = a->filter;
|
||||
a->filter = f;
|
||||
r = (b->vtable->init)(a->filter);
|
||||
if (r != ARCHIVE_OK) {
|
||||
__archive_read_free_filters(a);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
bidder->name = a->filter->name;
|
||||
b->name = a->filter->name;
|
||||
|
||||
a->bypass_filter_bidding = 1;
|
||||
return r;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
/* Maximum amount of data to write at one time. */
|
||||
#define MAX_WRITE (1024 * 1024)
|
||||
@@ -46,9 +47,9 @@
|
||||
*/
|
||||
static int
|
||||
pad_to(struct archive *a, int fd, int can_lseek,
|
||||
size_t nulls_size, const char *nulls,
|
||||
int64_t target_offset, int64_t actual_offset)
|
||||
char **nulls, int64_t target_offset, int64_t actual_offset)
|
||||
{
|
||||
const size_t nulls_size = 16384;
|
||||
size_t to_write;
|
||||
ssize_t bytes_written;
|
||||
|
||||
@@ -56,16 +57,26 @@ pad_to(struct archive *a, int fd, int can_lseek,
|
||||
actual_offset = lseek(fd,
|
||||
target_offset - actual_offset, SEEK_CUR);
|
||||
if (actual_offset != target_offset) {
|
||||
archive_set_error(a, errno, "Seek error");
|
||||
archive_set_error(a,
|
||||
actual_offset == -1 ? errno : ARCHIVE_ERRNO_MISC,
|
||||
"Seek error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (*nulls == NULL) {
|
||||
*nulls = calloc(1, nulls_size);
|
||||
if (*nulls == NULL) {
|
||||
archive_set_error(a, errno, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
while (target_offset > actual_offset) {
|
||||
to_write = nulls_size;
|
||||
if (target_offset < actual_offset + (int64_t)nulls_size)
|
||||
to_write = (size_t)(target_offset - actual_offset);
|
||||
bytes_written = write(fd, nulls, to_write);
|
||||
bytes_written = write(fd, *nulls, to_write);
|
||||
if (bytes_written < 0) {
|
||||
archive_set_error(a, errno, "Write error");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -84,29 +95,48 @@ archive_read_data_into_fd(struct archive *a, int fd)
|
||||
const void *buff;
|
||||
size_t size, bytes_to_write;
|
||||
ssize_t bytes_written;
|
||||
int64_t fd_offset;
|
||||
int64_t target_offset;
|
||||
int64_t actual_offset = 0;
|
||||
int64_t declared_size;
|
||||
int can_lseek;
|
||||
char *nulls = NULL;
|
||||
size_t nulls_size = 16384;
|
||||
|
||||
archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
|
||||
"archive_read_data_into_fd");
|
||||
|
||||
declared_size = ((struct archive_read *)a)->entry_bytes_declared;
|
||||
|
||||
can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);
|
||||
if (!can_lseek) {
|
||||
nulls = calloc(1, nulls_size);
|
||||
if (!nulls) {
|
||||
r = ARCHIVE_FATAL;
|
||||
goto cleanup;
|
||||
}
|
||||
if (can_lseek) {
|
||||
fd_offset = lseek(fd, 0, SEEK_CUR);
|
||||
if (fd_offset == -1)
|
||||
can_lseek = 0;
|
||||
}
|
||||
|
||||
while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) ==
|
||||
ARCHIVE_OK) {
|
||||
const char *p = buff;
|
||||
int overran = 0;
|
||||
|
||||
if (declared_size >= 0) {
|
||||
/* We know the expected size, let's enforce that we don't overrun. */
|
||||
if (target_offset > declared_size) {
|
||||
/* We're already beyond the end? Don't write any more. */
|
||||
target_offset = declared_size;
|
||||
size = 0;
|
||||
overran = 1;
|
||||
} else if (size > (uint64_t)(declared_size - target_offset)) {
|
||||
/* Above is safe because target_offset <= declared_size */
|
||||
/* This block is bigger than the expected remainder */
|
||||
size = (size_t)(declared_size - target_offset);
|
||||
overran = 1;
|
||||
}
|
||||
/* Else size <= expected remainder of data and we're OK. */
|
||||
}
|
||||
|
||||
if (target_offset > actual_offset) {
|
||||
r = pad_to(a, fd, can_lseek, nulls_size, nulls,
|
||||
r = pad_to(a, fd, can_lseek, &nulls,
|
||||
target_offset, actual_offset);
|
||||
if (r != ARCHIVE_OK)
|
||||
break;
|
||||
@@ -126,18 +156,52 @@ archive_read_data_into_fd(struct archive *a, int fd)
|
||||
p += bytes_written;
|
||||
size -= bytes_written;
|
||||
}
|
||||
if (overran) {
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Actual entry size exceeds the declared size "
|
||||
"(%jd); truncated output at the declared size",
|
||||
(intmax_t)declared_size);
|
||||
r = ARCHIVE_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (r == ARCHIVE_EOF && target_offset > actual_offset) {
|
||||
r2 = pad_to(a, fd, can_lseek, nulls_size, nulls,
|
||||
target_offset, actual_offset);
|
||||
if (r2 != ARCHIVE_OK)
|
||||
r = r2;
|
||||
int trailing_hole_overran =
|
||||
declared_size >= 0 && target_offset > declared_size;
|
||||
if (trailing_hole_overran)
|
||||
target_offset = declared_size;
|
||||
if (target_offset > actual_offset) {
|
||||
r2 = pad_to(a, fd, can_lseek, &nulls,
|
||||
target_offset, actual_offset);
|
||||
if (r2 != ARCHIVE_OK)
|
||||
r = r2;
|
||||
else
|
||||
actual_offset = target_offset;
|
||||
}
|
||||
if (trailing_hole_overran) {
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Actual entry size exceeds the declared size "
|
||||
"(%jd); truncated output at the declared size",
|
||||
(intmax_t)declared_size);
|
||||
r = ARCHIVE_FAILED;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(nulls);
|
||||
if (r != ARCHIVE_EOF)
|
||||
return (r);
|
||||
return (ARCHIVE_OK);
|
||||
r = ARCHIVE_OK;
|
||||
if (can_lseek) {
|
||||
int64_t offset = lseek(fd, 0, SEEK_CUR);
|
||||
if (offset - fd_offset != actual_offset) {
|
||||
archive_set_error(a,
|
||||
offset == -1 ? errno : ARCHIVE_ERRNO_MISC,
|
||||
"Seek error");
|
||||
r = ARCHIVE_FATAL;
|
||||
}
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -256,6 +256,11 @@ archive_read_disk_entry_from_file(struct archive *_a,
|
||||
char *linkbuffer;
|
||||
ssize_t lnklen;
|
||||
|
||||
if (st->st_size >= SSIZE_MAX) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Couldn't read link data");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
linkbuffer = malloc(linkbuffer_len + 1);
|
||||
if (linkbuffer == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
@@ -894,7 +899,7 @@ setup_sparse_fiemap(struct archive_read_disk *a,
|
||||
|
||||
r = ioctl(*fd, FS_IOC_FIEMAP, fm);
|
||||
if (r < 0) {
|
||||
/* When something error happens, it is better we
|
||||
/* When some error happens, it is better we
|
||||
* should return ARCHIVE_OK because an earlier
|
||||
* version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
|
||||
goto exit_setup_sparse_fiemap;
|
||||
|
||||
@@ -457,6 +457,10 @@ archive_read_disk_new(void)
|
||||
a->archive.state = ARCHIVE_STATE_NEW;
|
||||
a->archive.vtable = &archive_read_disk_vtable;
|
||||
a->entry = archive_entry_new2(&a->archive);
|
||||
if (a->entry == NULL) {
|
||||
free(a);
|
||||
return (NULL);
|
||||
}
|
||||
a->lookup_uname = trivial_lookup_uname;
|
||||
a->lookup_gname = trivial_lookup_gname;
|
||||
a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
|
||||
@@ -928,8 +932,8 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
if (a->matching) {
|
||||
r = archive_match_path_excluded(a->matching, entry);
|
||||
if (r < 0) {
|
||||
archive_set_error(&(a->archive), errno,
|
||||
"Failed : %s", archive_error_string(a->matching));
|
||||
archive_set_error(&(a->archive), archive_errno(a->matching),
|
||||
"%s", archive_error_string(a->matching));
|
||||
return (r);
|
||||
}
|
||||
if (r) {
|
||||
@@ -1042,8 +1046,8 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
if (a->matching) {
|
||||
r = archive_match_time_excluded(a->matching, entry);
|
||||
if (r < 0) {
|
||||
archive_set_error(&(a->archive), errno,
|
||||
"Failed : %s", archive_error_string(a->matching));
|
||||
archive_set_error(&(a->archive), archive_errno(a->matching),
|
||||
"%s", archive_error_string(a->matching));
|
||||
return (r);
|
||||
}
|
||||
if (r) {
|
||||
@@ -1068,8 +1072,8 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
if (a->matching) {
|
||||
r = archive_match_owner_excluded(a->matching, entry);
|
||||
if (r < 0) {
|
||||
archive_set_error(&(a->archive), errno,
|
||||
"Failed : %s", archive_error_string(a->matching));
|
||||
archive_set_error(&(a->archive), archive_errno(a->matching),
|
||||
"%s", archive_error_string(a->matching));
|
||||
return (r);
|
||||
}
|
||||
if (r) {
|
||||
@@ -1421,18 +1425,18 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
|
||||
/*
|
||||
* This is the new filesystem which we have to generate a new ID for.
|
||||
*/
|
||||
fid = t->max_filesystem_id++;
|
||||
if (fid > MAX_FILESYSTEM_ID) {
|
||||
fid = t->max_filesystem_id;
|
||||
if (fid >= MAX_FILESYSTEM_ID) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Too many filesystems");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (t->max_filesystem_id > t->allocated_filesystem) {
|
||||
if (fid + 1 > t->allocated_filesystem) {
|
||||
int s;
|
||||
void *p;
|
||||
|
||||
s = t->max_filesystem_id * 2;
|
||||
s = (fid + 1) * 2;
|
||||
p = realloc(t->filesystem_table,
|
||||
s * sizeof(*t->filesystem_table));
|
||||
s * sizeof(*t->filesystem_table));
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate tar data");
|
||||
@@ -1441,6 +1445,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
|
||||
t->filesystem_table = (struct filesystem *)p;
|
||||
t->allocated_filesystem = s;
|
||||
}
|
||||
t->max_filesystem_id = fid + 1;
|
||||
t->current_filesystem_id = fid;
|
||||
t->current_filesystem = &(t->filesystem_table[fid]);
|
||||
t->current_filesystem->dev = dev;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_integer.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
int
|
||||
@@ -209,7 +210,8 @@ lookup_uname_helper(struct name_cache *cache, id_t id)
|
||||
* we just double it and try again. Because the buffer
|
||||
* is kept around in the cache object, we shouldn't
|
||||
* have to do this very often. */
|
||||
nbuff_size = cache->buff_size * 2;
|
||||
if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))
|
||||
break;
|
||||
nbuff = realloc(cache->buff, nbuff_size);
|
||||
if (nbuff == NULL)
|
||||
break;
|
||||
@@ -276,7 +278,8 @@ lookup_gname_helper(struct name_cache *cache, id_t id)
|
||||
/* ERANGE means our buffer was too small, but POSIX
|
||||
* doesn't tell us how big the buffer should be, so
|
||||
* we just double it and try again. */
|
||||
nbuff_size = cache->buff_size * 2;
|
||||
if (archive_ckd_mul_size(&nbuff_size, cache->buff_size, 2))
|
||||
break;
|
||||
nbuff = realloc(cache->buff, nbuff_size);
|
||||
if (nbuff == NULL)
|
||||
break;
|
||||
|
||||
@@ -37,10 +37,11 @@
|
||||
#include <winioctl.h>
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_string.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_disk_private.h"
|
||||
#include "archive_string.h"
|
||||
#include "archive_time_private.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
@@ -151,6 +152,8 @@ struct tree {
|
||||
size_t dirname_length;
|
||||
|
||||
int depth;
|
||||
/* Whether this tree began as a wildcard search */
|
||||
int rootwild;
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION lst;
|
||||
BY_HANDLE_FILE_INFORMATION st;
|
||||
@@ -358,6 +361,8 @@ la_linkname_from_handle(HANDLE h, wchar_t **linkname, int *linktype)
|
||||
}
|
||||
|
||||
indata = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
||||
if (indata == NULL)
|
||||
return (-1);
|
||||
ret = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, indata,
|
||||
1024, &inbytes, NULL);
|
||||
if (ret == 0) {
|
||||
@@ -553,6 +558,10 @@ archive_read_disk_new(void)
|
||||
a->archive.state = ARCHIVE_STATE_NEW;
|
||||
a->archive.vtable = &archive_read_disk_vtable;
|
||||
a->entry = archive_entry_new2(&a->archive);
|
||||
if (a->entry == NULL) {
|
||||
free(a);
|
||||
return (NULL);
|
||||
}
|
||||
a->lookup_uname = trivial_lookup_uname;
|
||||
a->lookup_gname = trivial_lookup_gname;
|
||||
a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
|
||||
@@ -924,7 +933,27 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
case 0:
|
||||
return (ARCHIVE_EOF);
|
||||
case TREE_POSTDESCENT:
|
||||
if (t->depth == 1 && t->rootwild && t->symlink_mode == 'H') {
|
||||
/*
|
||||
* We have descended from a directory at depth 0 specified by a
|
||||
* wildcard search in 'H'ybrid link mode. All items under this
|
||||
* directory should be 'P'hysical.
|
||||
*/
|
||||
t->symlink_mode = 'P';
|
||||
a->follow_symlinks = 0;
|
||||
}
|
||||
break;
|
||||
case TREE_POSTASCENT:
|
||||
if (t->depth == 0 && t->rootwild && t->initial_symlink_mode == 'H') {
|
||||
/*
|
||||
* We have returned to the root of a wildcard search, in 'H'ybrid
|
||||
* mode, so restore the symlink mode we overwrote in
|
||||
* TREE_POSTDESCENT.
|
||||
*/
|
||||
t->symlink_mode = t->initial_symlink_mode;
|
||||
/* Mimics setup done in setup_symlink_mode */
|
||||
a->follow_symlinks = 1;
|
||||
}
|
||||
break;
|
||||
case TREE_REGULAR:
|
||||
lst = tree_current_lstat(t);
|
||||
@@ -946,8 +975,8 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
if (a->matching) {
|
||||
r = archive_match_path_excluded(a->matching, entry);
|
||||
if (r < 0) {
|
||||
archive_set_error(&(a->archive), errno,
|
||||
"Failed : %s", archive_error_string(a->matching));
|
||||
archive_set_error(&(a->archive), archive_errno(a->matching),
|
||||
"%s", archive_error_string(a->matching));
|
||||
return (r);
|
||||
}
|
||||
if (r) {
|
||||
@@ -964,7 +993,14 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
switch(t->symlink_mode) {
|
||||
case 'H':
|
||||
/* 'H': After the first item, rest like 'P'. */
|
||||
t->symlink_mode = 'P';
|
||||
if (!t->rootwild) {
|
||||
/*
|
||||
* 'H': When we started with a wildcard, entries at the starting
|
||||
* depth should be kept in `H` mode; switching into 'P' mode
|
||||
* is handled in TREE_POSTDESCENT when we enter depth = 1.
|
||||
*/
|
||||
t->symlink_mode = 'P';
|
||||
}
|
||||
/* 'H': First item (from command line) like 'L'. */
|
||||
/* FALLTHROUGH */
|
||||
case 'L':
|
||||
@@ -1018,8 +1054,8 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
if (a->matching) {
|
||||
r = archive_match_time_excluded(a->matching, entry);
|
||||
if (r < 0) {
|
||||
archive_set_error(&(a->archive), errno,
|
||||
"Failed : %s", archive_error_string(a->matching));
|
||||
archive_set_error(&(a->archive), archive_errno(a->matching),
|
||||
"%s", archive_error_string(a->matching));
|
||||
return (r);
|
||||
}
|
||||
if (r) {
|
||||
@@ -1044,8 +1080,8 @@ next_entry(struct archive_read_disk *a, struct tree *t,
|
||||
if (a->matching) {
|
||||
r = archive_match_owner_excluded(a->matching, entry);
|
||||
if (r < 0) {
|
||||
archive_set_error(&(a->archive), errno,
|
||||
"Failed : %s", archive_error_string(a->matching));
|
||||
archive_set_error(&(a->archive), archive_errno(a->matching),
|
||||
"%s", archive_error_string(a->matching));
|
||||
return (r);
|
||||
}
|
||||
if (r) {
|
||||
@@ -1450,18 +1486,18 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
|
||||
/*
|
||||
* There is a new filesystem, we generate a new ID for.
|
||||
*/
|
||||
fid = t->max_filesystem_id++;
|
||||
if (fid > MAX_FILESYSTEM_ID) {
|
||||
fid = t->max_filesystem_id;
|
||||
if (fid >= MAX_FILESYSTEM_ID) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Too many filesystems");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (t->max_filesystem_id > t->allocated_filesystem) {
|
||||
if (fid + 1 > t->allocated_filesystem) {
|
||||
int s;
|
||||
void *p;
|
||||
|
||||
s = t->max_filesystem_id * 2;
|
||||
s = (fid + 1) * 2;
|
||||
p = realloc(t->filesystem_table,
|
||||
s * sizeof(*t->filesystem_table));
|
||||
s * sizeof(*t->filesystem_table));
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate tar data");
|
||||
@@ -1470,6 +1506,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
|
||||
t->filesystem_table = (struct filesystem *)p;
|
||||
t->allocated_filesystem = s;
|
||||
}
|
||||
t->max_filesystem_id = fid + 1;
|
||||
t->current_filesystem_id = fid;
|
||||
t->current_filesystem = &(t->filesystem_table[fid]);
|
||||
t->current_filesystem->dev = dev;
|
||||
@@ -1632,6 +1669,8 @@ tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path,
|
||||
struct tree_entry *te;
|
||||
|
||||
te = calloc(1, sizeof(*te));
|
||||
if (te == NULL)
|
||||
return;
|
||||
te->next = t->stack;
|
||||
te->parent = t->current;
|
||||
if (te->parent)
|
||||
@@ -1704,6 +1743,8 @@ tree_open(const wchar_t *path, int symlink_mode, int restore_time)
|
||||
struct tree *t;
|
||||
|
||||
t = calloc(1, sizeof(*t));
|
||||
if (t == NULL)
|
||||
return (NULL);
|
||||
archive_string_init(&(t->full_path));
|
||||
archive_string_init(&t->path);
|
||||
if (archive_wstring_ensure(&t->path, 15) == NULL) {
|
||||
@@ -1726,6 +1767,7 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
|
||||
t->full_path_dir_length = 0;
|
||||
t->dirname_length = 0;
|
||||
t->depth = 0;
|
||||
t->rootwild = 0;
|
||||
t->descend = 0;
|
||||
t->current = NULL;
|
||||
t->d = INVALID_HANDLE_VALUE;
|
||||
@@ -1779,6 +1821,7 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
|
||||
t->full_path.length = wcslen(t->full_path.s);
|
||||
t->full_path_dir_length = archive_strlen(&t->full_path);
|
||||
}
|
||||
t->rootwild = 1;
|
||||
}
|
||||
tree_push(t, base, t->full_path.s, 0, 0, 0, NULL);
|
||||
archive_wstring_free(&ws);
|
||||
@@ -2498,7 +2541,12 @@ setup_sparse_from_disk(struct archive_read_disk *a,
|
||||
(DWORD)outranges_size, &retbytes, NULL);
|
||||
if (ret == 0 && GetLastError() == ERROR_MORE_DATA) {
|
||||
free(outranges);
|
||||
outranges_size *= 2;
|
||||
if (archive_ckd_mul_size(&outranges_size, outranges_size, 2)) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Couldn't allocate memory");
|
||||
exit_sts = ARCHIVE_FATAL;
|
||||
goto exit_setup_sparse;
|
||||
}
|
||||
outranges = (FILE_ALLOCATED_RANGE_BUFFER *)
|
||||
malloc(outranges_size);
|
||||
if (outranges == NULL) {
|
||||
|
||||
@@ -142,7 +142,9 @@ These functions return
|
||||
.Cm ARCHIVE_OK
|
||||
if the compression is fully supported,
|
||||
.Cm ARCHIVE_WARN
|
||||
if the compression is supported only through an external program.
|
||||
if the compression is supported only through an external program, or
|
||||
.Cm ARCHIVE_FATAL
|
||||
on error.
|
||||
.Pp
|
||||
.Fn archive_read_support_filter_none
|
||||
always succeeds.
|
||||
@@ -158,5 +160,4 @@ functions.
|
||||
.Xr archive_read 3 ,
|
||||
.Xr archive_read_data 3 ,
|
||||
.Xr archive_read_format 3 ,
|
||||
.Xr archive_read_format 3 ,
|
||||
.Xr libarchive 3
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
.Nm archive_read_open_fd ,
|
||||
.Nm archive_read_open_FILE ,
|
||||
.Nm archive_read_open_filename ,
|
||||
.Nm archive_read_open_filenames ,
|
||||
.Nm archive_read_open_memory
|
||||
.Nd functions for reading streaming archives
|
||||
.Sh LIBRARY
|
||||
@@ -65,6 +66,12 @@ Streaming Archive Library (libarchive, -larchive)
|
||||
.Fa "size_t block_size"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo archive_read_open_filenames
|
||||
.Fa "struct archive *"
|
||||
.Fa "const char **filenames"
|
||||
.Fa "size_t block_size"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn archive_read_open_memory "struct archive *" "const void *buff" "size_t size"
|
||||
.Sh DESCRIPTION
|
||||
.Bl -tag -compact -width indent
|
||||
@@ -111,6 +118,15 @@ Like
|
||||
except that it accepts a simple filename and a block size.
|
||||
A NULL filename represents standard input.
|
||||
This function is safe for use with tape drives or other blocked devices.
|
||||
.It Fn archive_read_open_filenames
|
||||
Like
|
||||
.Fn archive_read_open ,
|
||||
except that it accepts a NULL-terminated array of filenames to open in
|
||||
sequence (as would be created by the
|
||||
.Xr split 1
|
||||
command) and a block size.
|
||||
A NULL filename at the beginning of the array represents standard input.
|
||||
This function is safe for use with tape drives or other blocked devices.
|
||||
.It Fn archive_read_open_memory
|
||||
Like
|
||||
.Fn archive_read_open ,
|
||||
|
||||
@@ -69,6 +69,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
|
||||
la_seek_stat_t st;
|
||||
struct read_fd_data *mine;
|
||||
void *b;
|
||||
int r;
|
||||
|
||||
archive_clear_error(a);
|
||||
if (la_seek_fstat(fd, &st) != 0) {
|
||||
@@ -107,7 +108,9 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
|
||||
archive_read_set_skip_callback(a, file_skip);
|
||||
archive_read_set_seek_callback(a, file_seek);
|
||||
archive_read_set_close_callback(a, file_close);
|
||||
archive_read_set_callback_data(a, mine);
|
||||
r = archive_read_set_callback_data(a, mine);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
return (archive_read_open1(a));
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ archive_read_open_FILE(struct archive *a, FILE *f)
|
||||
struct read_FILE_data *mine;
|
||||
size_t block_size = 128 * 1024;
|
||||
void *b;
|
||||
int r;
|
||||
|
||||
archive_clear_error(a);
|
||||
mine = calloc(1, sizeof(*mine));
|
||||
@@ -104,7 +105,9 @@ archive_read_open_FILE(struct archive *a, FILE *f)
|
||||
archive_read_set_skip_callback(a, FILE_skip);
|
||||
archive_read_set_seek_callback(a, FILE_seek);
|
||||
archive_read_set_close_callback(a, FILE_close);
|
||||
archive_read_set_callback_data(a, mine);
|
||||
r = archive_read_set_callback_data(a, mine);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
return (archive_read_open1(a));
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
#ifdef HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
@@ -181,7 +184,7 @@ archive_read_open_filenames_w(struct archive *a, const wchar_t **wfilenames,
|
||||
if (wfilename == NULL)
|
||||
wfilename = L"";
|
||||
mine = calloc(1,
|
||||
sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
|
||||
sizeof(*mine) + wcslen(wfilename) * MB_LEN_MAX);
|
||||
if (mine == NULL)
|
||||
goto no_memory;
|
||||
mine->block_size = block_size;
|
||||
@@ -315,7 +318,7 @@ file_open(struct archive *a, void *client_data)
|
||||
}
|
||||
#else
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Unexpedted operation in archive_read_open_filename");
|
||||
"Unexpected operation in archive_read_open_filename");
|
||||
goto fail;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ archive_read_open_memory2(struct archive *a, const void *buff,
|
||||
size_t size, size_t read_size)
|
||||
{
|
||||
struct read_memory_data *mine;
|
||||
int r;
|
||||
|
||||
mine = calloc(1, sizeof(*mine));
|
||||
if (mine == NULL) {
|
||||
@@ -82,7 +83,9 @@ archive_read_open_memory2(struct archive *a, const void *buff,
|
||||
archive_read_set_seek_callback(a, memory_read_seek);
|
||||
archive_read_set_skip_callback(a, memory_read_skip);
|
||||
archive_read_set_close_callback(a, memory_read_close);
|
||||
archive_read_set_callback_data(a, mine);
|
||||
r = archive_read_set_callback_data(a, mine);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
return (archive_read_open1(a));
|
||||
}
|
||||
|
||||
|
||||
@@ -76,10 +76,10 @@ struct archive_read_filter_bidder {
|
||||
struct archive_read_filter_vtable {
|
||||
/* Return next block. */
|
||||
ssize_t (*read)(struct archive_read_filter *, const void **);
|
||||
/* Close (just this filter) and free(self). */
|
||||
int (*close)(struct archive_read_filter *self);
|
||||
/* Close (just this filter) and free(filter). */
|
||||
int (*close)(struct archive_read_filter *);
|
||||
/* Read any header metadata if available. */
|
||||
int (*read_header)(struct archive_read_filter *self, struct archive_entry *entry);
|
||||
int (*read_header)(struct archive_read_filter *, struct archive_entry *);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -180,6 +180,15 @@ struct archive_read {
|
||||
/* File offset of beginning of most recently-read header. */
|
||||
int64_t header_position;
|
||||
|
||||
/*
|
||||
* Declared uncompressed size of the entry whose header was most
|
||||
* recently read, or -1 if no size was declared. Lets format-
|
||||
* agnostic consumers like archive_read_data_into_fd() cap their
|
||||
* output at the size an entry actually promised, regardless of
|
||||
* whether the format reader enforces that itself.
|
||||
*/
|
||||
int64_t entry_bytes_declared;
|
||||
|
||||
/* Nodes and offsets of compressed data block */
|
||||
unsigned int data_start_node;
|
||||
unsigned int data_end_node;
|
||||
|
||||
@@ -43,34 +43,34 @@ archive_read_support_filter_all(struct archive *a)
|
||||
archive_check_magic(a, ARCHIVE_READ_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_read_support_filter_all");
|
||||
|
||||
/* Bzip falls back to "bunzip2" command-line */
|
||||
/* Bzip falls back to "bzip2 -d" command-line */
|
||||
archive_read_support_filter_bzip2(a);
|
||||
/* The decompress code doesn't use an outside library. */
|
||||
archive_read_support_filter_compress(a);
|
||||
/* Gzip decompress falls back to "gzip -d" command-line. */
|
||||
archive_read_support_filter_gzip(a);
|
||||
/* Lzip falls back to "unlzip" command-line program. */
|
||||
/* Lzip falls back to "lzip -d -q" command-line. */
|
||||
archive_read_support_filter_lzip(a);
|
||||
/* The LZMA file format has a very weak signature, so it
|
||||
* may not be feasible to keep this here, but we'll try.
|
||||
* This will come back out if there are problems. */
|
||||
/* Lzma falls back to "unlzma" command-line program. */
|
||||
/* Lzma falls back to "lzma -d -qq" command-line. */
|
||||
archive_read_support_filter_lzma(a);
|
||||
/* Xz falls back to "unxz" command-line program. */
|
||||
/* Xz falls back to "xz -d -qq" command-line. */
|
||||
archive_read_support_filter_xz(a);
|
||||
/* The decode code doesn't use an outside library. */
|
||||
archive_read_support_filter_uu(a);
|
||||
/* The decode code doesn't use an outside library. */
|
||||
archive_read_support_filter_rpm(a);
|
||||
/* The decode code always uses "lrzip -q -d" command-line. */
|
||||
/* The decode code always uses "lrzip -d -q" command-line. */
|
||||
archive_read_support_filter_lrzip(a);
|
||||
/* Lzop decompress falls back to "lzop -d" command-line. */
|
||||
archive_read_support_filter_lzop(a);
|
||||
/* The decode code always uses "grzip -d" command-line. */
|
||||
archive_read_support_filter_grzip(a);
|
||||
/* Lz4 falls back to "lz4 -d" command-line program. */
|
||||
/* Lz4 falls back to "lz4 -d -q" command-line. */
|
||||
archive_read_support_filter_lz4(a);
|
||||
/* Zstd falls back to "zstd -d" command-line program. */
|
||||
/* Zstd falls back to "zstd -d -qq" command-line. */
|
||||
archive_read_support_filter_zstd(a);
|
||||
|
||||
/* Note: We always return ARCHIVE_OK here, even if some of the
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
@@ -47,7 +50,7 @@
|
||||
#include "archive_read_private.h"
|
||||
|
||||
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
|
||||
struct private_data {
|
||||
struct bzip2 {
|
||||
bz_stream stream;
|
||||
char *out_block;
|
||||
size_t out_block_size;
|
||||
@@ -63,8 +66,7 @@ static int bzip2_filter_close(struct archive_read_filter *);
|
||||
/*
|
||||
* Note that we can detect bzip2 archives even if we can't decompress
|
||||
* them. (In fact, we like detecting them because we can give better
|
||||
* error messages.) So the bid framework here gets compiled even
|
||||
* if bzlib is unavailable.
|
||||
* error messages.)
|
||||
*/
|
||||
static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
|
||||
static int bzip2_reader_init(struct archive_read_filter *);
|
||||
@@ -110,16 +112,15 @@ archive_read_support_filter_bzip2(struct archive *_a)
|
||||
* from verifying as much as we would like.
|
||||
*/
|
||||
static int
|
||||
bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_filter *filter)
|
||||
bzip2_reader_bid(struct archive_read_filter_bidder *b, struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
ssize_t avail;
|
||||
int bits_checked;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
/* Minimal bzip2 archive is 14 bytes. */
|
||||
buffer = __archive_read_filter_ahead(filter, 14, &avail);
|
||||
buffer = __archive_read_filter_ahead(f, 14, NULL);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
|
||||
@@ -150,21 +151,21 @@ bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_fi
|
||||
#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
|
||||
|
||||
/*
|
||||
* If we don't have the library on this system, we can't actually do the
|
||||
* decompression. We can, however, still detect compressed archives
|
||||
* and emit a useful message.
|
||||
* If we don't have the library on this system, we can't do the
|
||||
* decompression directly. We can, however, try to run "bzip2 -d"
|
||||
* in case that's available.
|
||||
*/
|
||||
static int
|
||||
bzip2_reader_init(struct archive_read_filter *self)
|
||||
bzip2_reader_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "bzip2 -d");
|
||||
r = __archive_read_program(f, "bzip2 -d");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_BZIP2;
|
||||
self->name = "bzip2";
|
||||
f->code = ARCHIVE_FILTER_BZIP2;
|
||||
f->name = "bzip2";
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -181,29 +182,29 @@ bzip2_reader_vtable = {
|
||||
* Setup the callbacks.
|
||||
*/
|
||||
static int
|
||||
bzip2_reader_init(struct archive_read_filter *self)
|
||||
bzip2_reader_init(struct archive_read_filter *f)
|
||||
{
|
||||
static const size_t out_block_size = 64 * 1024;
|
||||
void *out_block;
|
||||
struct private_data *state;
|
||||
struct bzip2 *bzip2;
|
||||
|
||||
self->code = ARCHIVE_FILTER_BZIP2;
|
||||
self->name = "bzip2";
|
||||
f->code = ARCHIVE_FILTER_BZIP2;
|
||||
f->name = "bzip2";
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
bzip2 = calloc(1, sizeof(*bzip2));
|
||||
out_block = malloc(out_block_size);
|
||||
if (state == NULL || out_block == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
if (bzip2 == NULL || out_block == NULL) {
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for bzip2 decompression");
|
||||
free(out_block);
|
||||
free(state);
|
||||
free(bzip2);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
state->out_block_size = out_block_size;
|
||||
state->out_block = out_block;
|
||||
self->vtable = &bzip2_reader_vtable;
|
||||
f->data = bzip2;
|
||||
bzip2->out_block_size = out_block_size;
|
||||
bzip2->out_block = out_block;
|
||||
f->vtable = &bzip2_reader_vtable;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -212,42 +213,42 @@ bzip2_reader_init(struct archive_read_filter *self)
|
||||
* Return the next block of decompressed data.
|
||||
*/
|
||||
static ssize_t
|
||||
bzip2_filter_read(struct archive_read_filter *self, const void **p)
|
||||
bzip2_filter_read(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
size_t decompressed;
|
||||
const char *read_buf;
|
||||
ssize_t ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
if (state->eof) {
|
||||
if (bzip2->eof) {
|
||||
*p = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Empty our output buffer. */
|
||||
state->stream.next_out = state->out_block;
|
||||
state->stream.avail_out = (uint32_t)state->out_block_size;
|
||||
bzip2->stream.next_out = bzip2->out_block;
|
||||
bzip2->stream.avail_out = (uint32_t)bzip2->out_block_size;
|
||||
|
||||
/* Try to fill the output buffer. */
|
||||
for (;;) {
|
||||
if (!state->valid) {
|
||||
if (bzip2_reader_bid(self->bidder, self->upstream) == 0) {
|
||||
state->eof = 1;
|
||||
*p = state->out_block;
|
||||
decompressed = state->stream.next_out
|
||||
- state->out_block;
|
||||
ssize_t max_in;
|
||||
|
||||
if (!bzip2->valid) {
|
||||
if (bzip2_reader_bid(f->bidder, f->upstream) == 0) {
|
||||
bzip2->eof = 1;
|
||||
*p = bzip2->out_block;
|
||||
decompressed = bzip2->stream.next_out
|
||||
- bzip2->out_block;
|
||||
return (decompressed);
|
||||
}
|
||||
/* Initialize compression library. */
|
||||
ret = BZ2_bzDecompressInit(&(state->stream),
|
||||
ret = BZ2_bzDecompressInit(&(bzip2->stream),
|
||||
0 /* library verbosity */,
|
||||
0 /* don't use low-mem algorithm */);
|
||||
|
||||
/* If init fails, try low-memory algorithm instead. */
|
||||
if (ret == BZ_MEM_ERROR)
|
||||
ret = BZ2_bzDecompressInit(&(state->stream),
|
||||
ret = BZ2_bzDecompressInit(&(bzip2->stream),
|
||||
0 /* library verbosity */,
|
||||
1 /* do use low-mem algo */);
|
||||
|
||||
@@ -266,65 +267,63 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
|
||||
detail = "mis-compiled library";
|
||||
break;
|
||||
}
|
||||
archive_set_error(&self->archive->archive, err,
|
||||
archive_set_error(&f->archive->archive, err,
|
||||
"Internal error initializing decompressor%s%s",
|
||||
detail == NULL ? "" : ": ",
|
||||
detail);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->valid = 1;
|
||||
bzip2->valid = 1;
|
||||
}
|
||||
|
||||
/* stream.next_in is really const, but bzlib
|
||||
* doesn't declare it so. <sigh> */
|
||||
read_buf =
|
||||
__archive_read_filter_ahead(self->upstream, 1, &ret);
|
||||
__archive_read_filter_ahead(f->upstream, 1, &ret);
|
||||
if (read_buf == NULL) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"truncated bzip2 input");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->stream.next_in = (char *)(uintptr_t)read_buf;
|
||||
state->stream.avail_in = (uint32_t)ret;
|
||||
/* There is no more data, return whatever we have. */
|
||||
if (ret == 0) {
|
||||
state->eof = 1;
|
||||
*p = state->out_block;
|
||||
decompressed = state->stream.next_out
|
||||
- state->out_block;
|
||||
return (decompressed);
|
||||
}
|
||||
bzip2->stream.next_in = (char *)(uintptr_t)read_buf;
|
||||
if (UINT_MAX >= SSIZE_MAX)
|
||||
max_in = SSIZE_MAX;
|
||||
else
|
||||
max_in = UINT_MAX;
|
||||
if (ret > max_in)
|
||||
ret = max_in;
|
||||
bzip2->stream.avail_in = (uint32_t)ret;
|
||||
|
||||
/* Decompress as much as we can in one pass. */
|
||||
ret = BZ2_bzDecompress(&(state->stream));
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
state->stream.next_in - read_buf);
|
||||
ret = BZ2_bzDecompress(&(bzip2->stream));
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
bzip2->stream.next_in - read_buf);
|
||||
|
||||
switch (ret) {
|
||||
case BZ_STREAM_END: /* Found end of stream. */
|
||||
switch (BZ2_bzDecompressEnd(&(state->stream))) {
|
||||
switch (BZ2_bzDecompressEnd(&(bzip2->stream))) {
|
||||
case BZ_OK:
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&(self->archive->archive),
|
||||
archive_set_error(&(f->archive->archive),
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Failed to clean up decompressor");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->valid = 0;
|
||||
bzip2->valid = 0;
|
||||
/* FALLTHROUGH */
|
||||
case BZ_OK: /* Decompressor made some progress. */
|
||||
/* If we filled our buffer, update stats and return. */
|
||||
if (state->stream.avail_out == 0) {
|
||||
*p = state->out_block;
|
||||
decompressed = state->stream.next_out
|
||||
- state->out_block;
|
||||
if (bzip2->stream.avail_out == 0) {
|
||||
*p = bzip2->out_block;
|
||||
decompressed = bzip2->stream.next_out
|
||||
- bzip2->out_block;
|
||||
return (decompressed);
|
||||
}
|
||||
break;
|
||||
default: /* Return an error. */
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "bzip decompression failed");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -335,28 +334,26 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
|
||||
* Clean up the decompressor.
|
||||
*/
|
||||
static int
|
||||
bzip2_filter_close(struct archive_read_filter *self)
|
||||
bzip2_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
if (state->valid) {
|
||||
switch (BZ2_bzDecompressEnd(&state->stream)) {
|
||||
if (bzip2->valid) {
|
||||
switch (BZ2_bzDecompressEnd(&bzip2->stream)) {
|
||||
case BZ_OK:
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Failed to clean up decompressor");
|
||||
ret = ARCHIVE_FATAL;
|
||||
}
|
||||
state->valid = 0;
|
||||
bzip2->valid = 0;
|
||||
}
|
||||
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
free(bzip2->out_block);
|
||||
free(bzip2);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
* names and structure here don't exactly match those used by compress.
|
||||
*/
|
||||
|
||||
struct private_data {
|
||||
struct compress {
|
||||
/* Input variables. */
|
||||
const unsigned char *next_in;
|
||||
size_t avail_in;
|
||||
@@ -104,6 +104,7 @@ struct private_data {
|
||||
void *out_block;
|
||||
|
||||
/* Decompression status variables. */
|
||||
int initialized;
|
||||
int use_reset_code;
|
||||
int end_of_stream; /* EOF status. */
|
||||
int maxcode; /* Largest code. */
|
||||
@@ -168,17 +169,16 @@ archive_read_support_filter_compress(struct archive *_a)
|
||||
* This logic returns zero if any part of the signature fails.
|
||||
*/
|
||||
static int
|
||||
compress_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
compress_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
ssize_t avail;
|
||||
int bits_checked;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
/* Shortest valid compress file is 3 bytes. */
|
||||
buffer = __archive_read_filter_ahead(filter, 3, &avail);
|
||||
buffer = __archive_read_filter_ahead(f, 3, NULL);
|
||||
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
@@ -207,61 +207,69 @@ compress_reader_vtable = {
|
||||
* Setup the callbacks.
|
||||
*/
|
||||
static int
|
||||
compress_bidder_init(struct archive_read_filter *self)
|
||||
compress_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct compress *compress;
|
||||
static const size_t out_block_size = 64 * 1024;
|
||||
void *out_block;
|
||||
int code;
|
||||
|
||||
self->code = ARCHIVE_FILTER_COMPRESS;
|
||||
self->name = "compress (.Z)";
|
||||
f->code = ARCHIVE_FILTER_COMPRESS;
|
||||
f->name = "compress (.Z)";
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
compress = calloc(1, sizeof(*compress));
|
||||
out_block = malloc(out_block_size);
|
||||
if (state == NULL || out_block == NULL) {
|
||||
if (compress == NULL || out_block == NULL) {
|
||||
free(out_block);
|
||||
free(state);
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
free(compress);
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for %s decompression",
|
||||
self->name);
|
||||
f->name);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
state->out_block_size = out_block_size;
|
||||
state->out_block = out_block;
|
||||
self->vtable = &compress_reader_vtable;
|
||||
f->data = compress;
|
||||
compress->out_block_size = out_block_size;
|
||||
compress->out_block = out_block;
|
||||
f->vtable = &compress_reader_vtable;
|
||||
|
||||
/* XXX MOVE THE FOLLOWING OUT OF INIT() XXX */
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
(void)getbits(self, 8); /* Skip first signature byte. */
|
||||
(void)getbits(self, 8); /* Skip second signature byte. */
|
||||
static int
|
||||
compress_filter_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct compress *compress = f->data;
|
||||
int code;
|
||||
|
||||
compress->initialized = 1;
|
||||
|
||||
(void)getbits(f, 8); /* Skip first signature byte. */
|
||||
(void)getbits(f, 8); /* Skip second signature byte. */
|
||||
|
||||
/* Get compression parameters. */
|
||||
code = getbits(self, 8);
|
||||
if ((code & 0x1f) > 16) {
|
||||
archive_set_error(&self->archive->archive, -1,
|
||||
code = getbits(f, 8);
|
||||
if (code < 0 || (code & 0x1f) > 16) {
|
||||
archive_set_error(&f->archive->archive, -1,
|
||||
"Invalid compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->maxcode_bits = code & 0x1f;
|
||||
state->maxcode = (1 << state->maxcode_bits);
|
||||
state->use_reset_code = code & 0x80;
|
||||
compress->maxcode_bits = code & 0x1f;
|
||||
compress->maxcode = (1 << compress->maxcode_bits);
|
||||
compress->use_reset_code = code & 0x80;
|
||||
|
||||
/* Initialize decompressor. */
|
||||
state->free_ent = 256;
|
||||
state->stackp = state->stack;
|
||||
if (state->use_reset_code)
|
||||
state->free_ent++;
|
||||
state->bits = 9;
|
||||
state->section_end_code = (1<<state->bits) - 1;
|
||||
state->oldcode = -1;
|
||||
compress->free_ent = 256;
|
||||
compress->stackp = compress->stack;
|
||||
if (compress->use_reset_code)
|
||||
compress->free_ent++;
|
||||
compress->bits = 9;
|
||||
compress->section_end_code = (1<<compress->bits) - 1;
|
||||
compress->oldcode = -1;
|
||||
for (code = 255; code >= 0; code--) {
|
||||
state->prefix[code] = 0;
|
||||
state->suffix[code] = code;
|
||||
compress->prefix[code] = 0;
|
||||
compress->suffix[code] = code;
|
||||
}
|
||||
next_code(self);
|
||||
next_code(f);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -271,27 +279,31 @@ compress_bidder_init(struct archive_read_filter *self)
|
||||
* as necessary.
|
||||
*/
|
||||
static ssize_t
|
||||
compress_filter_read(struct archive_read_filter *self, const void **pblock)
|
||||
compress_filter_read(struct archive_read_filter *f, const void **pblock)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct compress *compress = f->data;
|
||||
unsigned char *p, *start, *end;
|
||||
int ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
if (state->end_of_stream) {
|
||||
if (!compress->initialized) {
|
||||
ret = compress_filter_init(f);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
if (compress->end_of_stream) {
|
||||
*pblock = NULL;
|
||||
return (0);
|
||||
}
|
||||
p = start = (unsigned char *)state->out_block;
|
||||
end = start + state->out_block_size;
|
||||
p = start = (unsigned char *)compress->out_block;
|
||||
end = start + compress->out_block_size;
|
||||
|
||||
while (p < end && !state->end_of_stream) {
|
||||
if (state->stackp > state->stack) {
|
||||
*p++ = *--state->stackp;
|
||||
while (p < end && !compress->end_of_stream) {
|
||||
if (compress->stackp > compress->stack) {
|
||||
*p++ = *--compress->stackp;
|
||||
} else {
|
||||
ret = next_code(self);
|
||||
ret = next_code(f);
|
||||
if (ret == -1)
|
||||
state->end_of_stream = ret;
|
||||
compress->end_of_stream = ret;
|
||||
else if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
@@ -305,12 +317,12 @@ compress_filter_read(struct archive_read_filter *self, const void **pblock)
|
||||
* Close and release the filter.
|
||||
*/
|
||||
static int
|
||||
compress_filter_close(struct archive_read_filter *self)
|
||||
compress_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct compress *compress = f->data;
|
||||
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
free(compress->out_block);
|
||||
free(compress);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -320,25 +332,18 @@ compress_filter_close(struct archive_read_filter *self)
|
||||
* format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
|
||||
*/
|
||||
static int
|
||||
next_code(struct archive_read_filter *self)
|
||||
next_code(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct compress *compress = f->data;
|
||||
int code, newcode;
|
||||
|
||||
static int debug_buff[1024];
|
||||
static unsigned debug_index;
|
||||
|
||||
again:
|
||||
code = newcode = getbits(self, state->bits);
|
||||
code = newcode = getbits(f, compress->bits);
|
||||
if (code < 0)
|
||||
return (code);
|
||||
|
||||
debug_buff[debug_index++] = code;
|
||||
if (debug_index >= sizeof(debug_buff)/sizeof(debug_buff[0]))
|
||||
debug_index = 0;
|
||||
|
||||
/* If it's a reset code, reset the dictionary. */
|
||||
if ((code == 256) && state->use_reset_code) {
|
||||
if ((code == 256) && compress->use_reset_code) {
|
||||
/*
|
||||
* The original 'compress' implementation blocked its
|
||||
* I/O in a manner that resulted in junk bytes being
|
||||
@@ -346,63 +351,63 @@ again:
|
||||
* this junk. (Yes, the number of *bytes* to skip is
|
||||
* a function of the current *bit* length.)
|
||||
*/
|
||||
int skip_bytes = state->bits -
|
||||
(state->bytes_in_section % state->bits);
|
||||
skip_bytes %= state->bits;
|
||||
state->bits_avail = 0; /* Discard rest of this byte. */
|
||||
int skip_bytes = compress->bits -
|
||||
(compress->bytes_in_section % compress->bits);
|
||||
skip_bytes %= compress->bits;
|
||||
compress->bits_avail = 0; /* Discard rest of this byte. */
|
||||
while (skip_bytes-- > 0) {
|
||||
code = getbits(self, 8);
|
||||
code = getbits(f, 8);
|
||||
if (code < 0)
|
||||
return (code);
|
||||
}
|
||||
/* Now, actually do the reset. */
|
||||
state->bytes_in_section = 0;
|
||||
state->bits = 9;
|
||||
state->section_end_code = (1 << state->bits) - 1;
|
||||
state->free_ent = 257;
|
||||
state->oldcode = -1;
|
||||
compress->bytes_in_section = 0;
|
||||
compress->bits = 9;
|
||||
compress->section_end_code = (1 << compress->bits) - 1;
|
||||
compress->free_ent = 257;
|
||||
compress->oldcode = -1;
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (code > state->free_ent
|
||||
|| (code == state->free_ent && state->oldcode < 0)) {
|
||||
if (code > compress->free_ent
|
||||
|| (code == compress->free_ent && compress->oldcode < 0)) {
|
||||
/* An invalid code is a fatal error. */
|
||||
archive_set_error(&(self->archive->archive), -1,
|
||||
archive_set_error(&(f->archive->archive), -1,
|
||||
"Invalid compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/* Special case for KwKwK string. */
|
||||
if (code >= state->free_ent) {
|
||||
*state->stackp++ = state->finbyte;
|
||||
code = state->oldcode;
|
||||
if (code >= compress->free_ent) {
|
||||
*compress->stackp++ = compress->finbyte;
|
||||
code = compress->oldcode;
|
||||
}
|
||||
|
||||
/* Generate output characters in reverse order. */
|
||||
while (code >= 256) {
|
||||
*state->stackp++ = state->suffix[code];
|
||||
code = state->prefix[code];
|
||||
*compress->stackp++ = compress->suffix[code];
|
||||
code = compress->prefix[code];
|
||||
}
|
||||
*state->stackp++ = state->finbyte = code;
|
||||
*compress->stackp++ = compress->finbyte = code;
|
||||
|
||||
/* Generate the new entry. */
|
||||
code = state->free_ent;
|
||||
if (code < state->maxcode && state->oldcode >= 0) {
|
||||
state->prefix[code] = state->oldcode;
|
||||
state->suffix[code] = state->finbyte;
|
||||
++state->free_ent;
|
||||
code = compress->free_ent;
|
||||
if (code < compress->maxcode && compress->oldcode >= 0) {
|
||||
compress->prefix[code] = compress->oldcode;
|
||||
compress->suffix[code] = compress->finbyte;
|
||||
++compress->free_ent;
|
||||
}
|
||||
if (state->free_ent > state->section_end_code) {
|
||||
state->bits++;
|
||||
state->bytes_in_section = 0;
|
||||
if (state->bits == state->maxcode_bits)
|
||||
state->section_end_code = state->maxcode;
|
||||
if (compress->free_ent > compress->section_end_code) {
|
||||
compress->bits++;
|
||||
compress->bytes_in_section = 0;
|
||||
if (compress->bits == compress->maxcode_bits)
|
||||
compress->section_end_code = compress->maxcode;
|
||||
else
|
||||
state->section_end_code = (1 << state->bits) - 1;
|
||||
compress->section_end_code = (1 << compress->bits) - 1;
|
||||
}
|
||||
|
||||
/* Remember previous code. */
|
||||
state->oldcode = newcode;
|
||||
compress->oldcode = newcode;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -412,9 +417,9 @@ again:
|
||||
* -1 indicates end of available data.
|
||||
*/
|
||||
static int
|
||||
getbits(struct archive_read_filter *self, int n)
|
||||
getbits(struct archive_read_filter *f, int n)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct compress *compress = f->data;
|
||||
int code;
|
||||
ssize_t ret;
|
||||
static const int mask[] = {
|
||||
@@ -422,31 +427,31 @@ getbits(struct archive_read_filter *self, int n)
|
||||
0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
||||
};
|
||||
|
||||
while (state->bits_avail < n) {
|
||||
if (state->avail_in <= 0) {
|
||||
if (state->consume_unnotified) {
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
state->consume_unnotified);
|
||||
state->consume_unnotified = 0;
|
||||
while (compress->bits_avail < n) {
|
||||
if (compress->avail_in <= 0) {
|
||||
if (compress->consume_unnotified) {
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
compress->consume_unnotified);
|
||||
compress->consume_unnotified = 0;
|
||||
}
|
||||
state->next_in
|
||||
= __archive_read_filter_ahead(self->upstream,
|
||||
compress->next_in
|
||||
= __archive_read_filter_ahead(f->upstream,
|
||||
1, &ret);
|
||||
if (ret == 0)
|
||||
return (-1);
|
||||
if (ret < 0 || state->next_in == NULL)
|
||||
if (compress->next_in == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
state->consume_unnotified = state->avail_in = ret;
|
||||
compress->consume_unnotified = compress->avail_in = ret;
|
||||
}
|
||||
state->bit_buffer |= *state->next_in++ << state->bits_avail;
|
||||
state->avail_in--;
|
||||
state->bits_avail += 8;
|
||||
state->bytes_in_section++;
|
||||
compress->bit_buffer |= *compress->next_in++ << compress->bits_avail;
|
||||
compress->avail_in--;
|
||||
compress->bits_avail += 8;
|
||||
compress->bytes_in_section++;
|
||||
}
|
||||
|
||||
code = state->bit_buffer;
|
||||
state->bit_buffer >>= n;
|
||||
state->bits_avail -= n;
|
||||
code = compress->bit_buffer;
|
||||
compress->bit_buffer >>= n;
|
||||
compress->bits_avail -= n;
|
||||
|
||||
return (code & mask[n]);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ archive_read_support_filter_grzip(struct archive *_a)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
|
||||
if (__archive_read_register_bidder(a, NULL, NULL,
|
||||
if (__archive_read_register_bidder(a, NULL, "grzip",
|
||||
&grzip_bidder_vtable) != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
@@ -76,16 +76,15 @@ archive_read_support_filter_grzip(struct archive *_a)
|
||||
* Bidder just verifies the header and returns the number of verified bits.
|
||||
*/
|
||||
static int
|
||||
grzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
grzip_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *p;
|
||||
ssize_t avail;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), &avail);
|
||||
if (p == NULL || avail == 0)
|
||||
p = __archive_read_filter_ahead(f, sizeof(grzip_magic), NULL);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
|
||||
if (memcmp(p, grzip_magic, sizeof(grzip_magic)))
|
||||
@@ -95,15 +94,15 @@ grzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
}
|
||||
|
||||
static int
|
||||
grzip_bidder_init(struct archive_read_filter *self)
|
||||
grzip_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "grzip -d");
|
||||
r = __archive_read_program(f, "grzip -d");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_GRZIP;
|
||||
self->name = "grzip";
|
||||
f->code = ARCHIVE_FILTER_GRZIP;
|
||||
f->name = "grzip";
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -51,12 +51,11 @@
|
||||
#include "archive_read_private.h"
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
struct private_data {
|
||||
struct gzip {
|
||||
z_stream stream;
|
||||
char in_stream;
|
||||
unsigned char *out_block;
|
||||
size_t out_block_size;
|
||||
int64_t total_out;
|
||||
unsigned long crc;
|
||||
uint32_t mtime;
|
||||
char *name;
|
||||
@@ -71,12 +70,7 @@ static int gzip_filter_close(struct archive_read_filter *);
|
||||
/*
|
||||
* Note that we can detect gzip archives even if we can't decompress
|
||||
* them. (In fact, we like detecting them because we can give better
|
||||
* error messages.) So the bid framework here gets compiled even
|
||||
* if zlib is unavailable.
|
||||
*
|
||||
* TODO: If zlib is unavailable, gzip_bidder_init() should
|
||||
* use the compress_program framework to try to fire up an external
|
||||
* gzip program.
|
||||
* error messages.)
|
||||
*/
|
||||
static int gzip_bidder_bid(struct archive_read_filter_bidder *,
|
||||
struct archive_read_filter *);
|
||||
@@ -126,9 +120,9 @@ archive_read_support_filter_gzip(struct archive *_a)
|
||||
#define MAX_FILENAME_LENGTH (1024 * 1024L)
|
||||
#define MAX_COMMENT_LENGTH (1024 * 1024L)
|
||||
static ssize_t
|
||||
peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
peek_at_header(struct archive_read_filter *f, int *pbits,
|
||||
#ifdef HAVE_ZLIB_H
|
||||
struct private_data *state
|
||||
struct gzip *gzip
|
||||
#else
|
||||
void *state
|
||||
#endif
|
||||
@@ -145,8 +139,8 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
/* Start by looking at the first ten bytes of the header, which
|
||||
* is all fixed layout. */
|
||||
len = 10;
|
||||
p = __archive_read_filter_ahead(filter, len, &avail);
|
||||
if (p == NULL || avail == 0)
|
||||
p = __archive_read_filter_ahead(f, len, &avail);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
/* We only support deflation- third byte must be 0x08. */
|
||||
if (memcmp(p, "\x1F\x8B\x08", 3) != 0)
|
||||
@@ -158,8 +152,8 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
header_flags = p[3];
|
||||
/* Bytes 4-7 are mod time in little endian. */
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (state)
|
||||
state->mtime = archive_le32dec(p + 4);
|
||||
if (gzip)
|
||||
gzip->mtime = archive_le32dec(p + 4);
|
||||
#endif
|
||||
/* Byte 8 is deflate flags. */
|
||||
/* XXXX TODO: return deflate flags back to consume_header for use
|
||||
@@ -168,10 +162,10 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
|
||||
/* Optional extra data: 2 byte length plus variable body. */
|
||||
if (header_flags & 4) {
|
||||
p = __archive_read_filter_ahead(filter, len + 2, &avail);
|
||||
p = __archive_read_filter_ahead(f, len + 2, &avail);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
len += ((int)p[len + 1] << 8) | (int)p[len];
|
||||
len += archive_le16dec(p + len);
|
||||
len += 2;
|
||||
}
|
||||
|
||||
@@ -186,7 +180,7 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
if (avail > MAX_FILENAME_LENGTH) {
|
||||
return (0);
|
||||
}
|
||||
p = __archive_read_filter_ahead(filter,
|
||||
p = __archive_read_filter_ahead(f,
|
||||
len, &avail);
|
||||
}
|
||||
if (p == NULL)
|
||||
@@ -194,10 +188,10 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
} while (p[len - 1] != 0);
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (state) {
|
||||
if (gzip) {
|
||||
/* Reset the name in case of repeat header reads. */
|
||||
free(state->name);
|
||||
state->name = strdup((const char *)&p[file_start]);
|
||||
free(gzip->name);
|
||||
gzip->name = strdup((const char *)&p[file_start]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -210,7 +204,7 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
if (avail > MAX_COMMENT_LENGTH) {
|
||||
return (0);
|
||||
}
|
||||
p = __archive_read_filter_ahead(filter,
|
||||
p = __archive_read_filter_ahead(f,
|
||||
len, &avail);
|
||||
}
|
||||
if (p == NULL)
|
||||
@@ -220,7 +214,7 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
|
||||
/* Optional header CRC */
|
||||
if ((header_flags & 2)) {
|
||||
p = __archive_read_filter_ahead(filter, len + 2, &avail);
|
||||
p = __archive_read_filter_ahead(f, len + 2, &avail);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
#if 0
|
||||
@@ -242,14 +236,14 @@ peek_at_header(struct archive_read_filter *filter, int *pbits,
|
||||
* Bidder just verifies the header and returns the number of verified bits.
|
||||
*/
|
||||
static int
|
||||
gzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
gzip_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
int bits_checked;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
if (peek_at_header(filter, &bits_checked, NULL))
|
||||
if (peek_at_header(f, &bits_checked, NULL))
|
||||
return (bits_checked);
|
||||
return (0);
|
||||
}
|
||||
@@ -262,35 +256,33 @@ gzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
* in case that's available.
|
||||
*/
|
||||
static int
|
||||
gzip_bidder_init(struct archive_read_filter *self)
|
||||
gzip_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "gzip -d");
|
||||
r = __archive_read_program(f, "gzip -d");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_GZIP;
|
||||
self->name = "gzip";
|
||||
f->code = ARCHIVE_FILTER_GZIP;
|
||||
f->name = "gzip";
|
||||
return (r);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int
|
||||
gzip_read_header(struct archive_read_filter *self, struct archive_entry *entry)
|
||||
gzip_read_header(struct archive_read_filter *f, struct archive_entry *entry)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct gzip *gzip = f->data;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
/* A mtime of 0 is considered invalid/missing. */
|
||||
if (state->mtime != 0)
|
||||
archive_entry_set_mtime(entry, state->mtime, 0);
|
||||
/* An mtime of 0 is considered invalid/missing. */
|
||||
if (gzip->mtime != 0)
|
||||
archive_entry_set_mtime(entry, gzip->mtime, 0);
|
||||
|
||||
/* If the name is available, extract it. */
|
||||
if (state->name)
|
||||
archive_entry_set_pathname(entry, state->name);
|
||||
if (gzip->name)
|
||||
archive_entry_set_pathname(entry, gzip->name);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -308,85 +300,95 @@ gzip_reader_vtable = {
|
||||
* Initialize the filter object.
|
||||
*/
|
||||
static int
|
||||
gzip_bidder_init(struct archive_read_filter *self)
|
||||
gzip_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct gzip *gzip;
|
||||
static const size_t out_block_size = 64 * 1024;
|
||||
void *out_block;
|
||||
|
||||
self->code = ARCHIVE_FILTER_GZIP;
|
||||
self->name = "gzip";
|
||||
f->code = ARCHIVE_FILTER_GZIP;
|
||||
f->name = "gzip";
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
gzip = calloc(1, sizeof(*gzip));
|
||||
out_block = malloc(out_block_size);
|
||||
if (state == NULL || out_block == NULL) {
|
||||
if (gzip == NULL || out_block == NULL) {
|
||||
free(out_block);
|
||||
free(state);
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
free(gzip);
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for gzip decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
state->out_block_size = out_block_size;
|
||||
state->out_block = out_block;
|
||||
self->vtable = &gzip_reader_vtable;
|
||||
f->data = gzip;
|
||||
gzip->out_block_size = out_block_size;
|
||||
gzip->out_block = out_block;
|
||||
f->vtable = &gzip_reader_vtable;
|
||||
|
||||
state->in_stream = 0; /* We're not actually within a stream yet. */
|
||||
gzip->in_stream = 0; /* We're not actually within a stream yet. */
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
consume_header(struct archive_read_filter *self)
|
||||
consume_header(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
ssize_t avail;
|
||||
struct gzip *gzip = f->data;
|
||||
ssize_t avail, max_in;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
/* If this is a real header, consume it. */
|
||||
len = peek_at_header(self->upstream, NULL, state);
|
||||
len = peek_at_header(f->upstream, NULL, gzip);
|
||||
if (len == 0)
|
||||
return (ARCHIVE_EOF);
|
||||
__archive_read_filter_consume(self->upstream, len);
|
||||
__archive_read_filter_consume(f->upstream, len);
|
||||
|
||||
/* Initialize CRC accumulator. */
|
||||
state->crc = crc32(0L, NULL, 0);
|
||||
gzip->crc = crc32(0L, NULL, 0);
|
||||
|
||||
/* Initialize compression library. */
|
||||
state->stream.next_in = (unsigned char *)(uintptr_t)
|
||||
__archive_read_filter_ahead(self->upstream, 1, &avail);
|
||||
state->stream.avail_in = (uInt)avail;
|
||||
ret = inflateInit2(&(state->stream),
|
||||
gzip->stream.next_in = (unsigned char *)(uintptr_t)
|
||||
__archive_read_filter_ahead(f->upstream, 1, &avail);
|
||||
if (avail < 0) {
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Failed to read gzip input");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (UINT_MAX >= SSIZE_MAX)
|
||||
max_in = SSIZE_MAX;
|
||||
else
|
||||
max_in = UINT_MAX;
|
||||
if (avail > max_in)
|
||||
avail = max_in;
|
||||
gzip->stream.avail_in = (uInt)avail;
|
||||
ret = inflateInit2(&(gzip->stream),
|
||||
-15 /* Don't check for zlib header */);
|
||||
|
||||
/* Decipher the error code. */
|
||||
switch (ret) {
|
||||
case Z_OK:
|
||||
state->in_stream = 1;
|
||||
gzip->in_stream = 1;
|
||||
return (ARCHIVE_OK);
|
||||
case Z_STREAM_ERROR:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Internal error initializing compression library: "
|
||||
"invalid setup parameter");
|
||||
break;
|
||||
case Z_MEM_ERROR:
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Internal error initializing compression library: "
|
||||
"out of memory");
|
||||
break;
|
||||
case Z_VERSION_ERROR:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Internal error initializing compression library: "
|
||||
"invalid library version");
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Internal error initializing compression library: "
|
||||
" Zlib error %d", ret);
|
||||
@@ -396,60 +398,55 @@ consume_header(struct archive_read_filter *self)
|
||||
}
|
||||
|
||||
static int
|
||||
consume_trailer(struct archive_read_filter *self)
|
||||
consume_trailer(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct gzip *gzip = f->data;
|
||||
const unsigned char *p;
|
||||
ssize_t avail;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
state->in_stream = 0;
|
||||
switch (inflateEnd(&(state->stream))) {
|
||||
gzip->in_stream = 0;
|
||||
switch (inflateEnd(&(gzip->stream))) {
|
||||
case Z_OK:
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Failed to clean up gzip decompressor");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/* GZip trailer is a fixed 8 byte structure. */
|
||||
p = __archive_read_filter_ahead(self->upstream, 8, &avail);
|
||||
if (p == NULL || avail == 0)
|
||||
p = __archive_read_filter_ahead(f->upstream, 8, NULL);
|
||||
if (p == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
/* XXX TODO: Verify the length and CRC. */
|
||||
|
||||
/* We've verified the trailer, so consume it now. */
|
||||
__archive_read_filter_consume(self->upstream, 8);
|
||||
__archive_read_filter_consume(f->upstream, 8);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
gzip_filter_read(struct archive_read_filter *self, const void **p)
|
||||
gzip_filter_read(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct gzip *gzip = f->data;
|
||||
size_t decompressed;
|
||||
ssize_t avail_in, max_in;
|
||||
int ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
/* Empty our output buffer. */
|
||||
state->stream.next_out = state->out_block;
|
||||
state->stream.avail_out = (uInt)state->out_block_size;
|
||||
gzip->stream.next_out = gzip->out_block;
|
||||
gzip->stream.avail_out = (uInt)gzip->out_block_size;
|
||||
|
||||
/* Try to fill the output buffer. */
|
||||
while (state->stream.avail_out > 0 && !state->eof) {
|
||||
while (gzip->stream.avail_out > 0 && !gzip->eof) {
|
||||
/* If we're not in a stream, read a header
|
||||
* and initialize the decompression library. */
|
||||
if (!state->in_stream) {
|
||||
ret = consume_header(self);
|
||||
if (!gzip->in_stream) {
|
||||
ret = consume_header(f);
|
||||
if (ret == ARCHIVE_EOF) {
|
||||
state->eof = 1;
|
||||
gzip->eof = 1;
|
||||
break;
|
||||
}
|
||||
if (ret < ARCHIVE_OK)
|
||||
@@ -459,10 +456,10 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
|
||||
/* Peek at the next available data. */
|
||||
/* ZLib treats stream.next_in as const but doesn't declare
|
||||
* it so, hence this ugly cast. */
|
||||
state->stream.next_in = (unsigned char *)(uintptr_t)
|
||||
__archive_read_filter_ahead(self->upstream, 1, &avail_in);
|
||||
if (state->stream.next_in == NULL) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
gzip->stream.next_in = (unsigned char *)(uintptr_t)
|
||||
__archive_read_filter_ahead(f->upstream, 1, &avail_in);
|
||||
if (gzip->stream.next_in == NULL) {
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"truncated gzip input");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -473,27 +470,27 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
|
||||
max_in = UINT_MAX;
|
||||
if (avail_in > max_in)
|
||||
avail_in = max_in;
|
||||
state->stream.avail_in = (uInt)avail_in;
|
||||
gzip->stream.avail_in = (uInt)avail_in;
|
||||
|
||||
/* Decompress and consume some of that data. */
|
||||
ret = inflate(&(state->stream), 0);
|
||||
ret = inflate(&(gzip->stream), 0);
|
||||
switch (ret) {
|
||||
case Z_OK: /* Decompressor made some progress. */
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
avail_in - state->stream.avail_in);
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
avail_in - gzip->stream.avail_in);
|
||||
break;
|
||||
case Z_STREAM_END: /* Found end of stream. */
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
avail_in - state->stream.avail_in);
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
avail_in - gzip->stream.avail_in);
|
||||
/* Consume the stream trailer; release the
|
||||
* decompression library. */
|
||||
ret = consume_trailer(self);
|
||||
ret = consume_trailer(f);
|
||||
if (ret < ARCHIVE_OK)
|
||||
return (ret);
|
||||
break;
|
||||
default:
|
||||
/* Return an error. */
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"gzip decompression failed");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -501,12 +498,11 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
|
||||
}
|
||||
|
||||
/* We've read as much as we can. */
|
||||
decompressed = state->stream.next_out - state->out_block;
|
||||
state->total_out += decompressed;
|
||||
decompressed = gzip->stream.next_out - gzip->out_block;
|
||||
if (decompressed == 0)
|
||||
*p = NULL;
|
||||
else
|
||||
*p = state->out_block;
|
||||
*p = gzip->out_block;
|
||||
return (decompressed);
|
||||
}
|
||||
|
||||
@@ -514,29 +510,28 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
|
||||
* Clean up the decompressor.
|
||||
*/
|
||||
static int
|
||||
gzip_filter_close(struct archive_read_filter *self)
|
||||
gzip_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct gzip *gzip = f->data;
|
||||
int ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
ret = ARCHIVE_OK;
|
||||
|
||||
if (state->in_stream) {
|
||||
switch (inflateEnd(&(state->stream))) {
|
||||
if (gzip->in_stream) {
|
||||
switch (inflateEnd(&(gzip->stream))) {
|
||||
case Z_OK:
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&(self->archive->archive),
|
||||
archive_set_error(&(f->archive->archive),
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Failed to clean up gzip compressor");
|
||||
ret = ARCHIVE_FATAL;
|
||||
}
|
||||
}
|
||||
|
||||
free(state->name);
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
free(gzip->name);
|
||||
free(gzip->out_block);
|
||||
free(gzip);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,19 +75,19 @@ archive_read_support_filter_lrzip(struct archive *_a)
|
||||
* Bidder just verifies the header and returns the number of verified bits.
|
||||
*/
|
||||
static int
|
||||
lrzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
lrzip_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *p;
|
||||
ssize_t avail, len;
|
||||
ssize_t len;
|
||||
int i;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
/* Start by looking at the first six bytes of the header, which
|
||||
* is all fixed layout. */
|
||||
len = 6;
|
||||
p = __archive_read_filter_ahead(filter, len, &avail);
|
||||
if (p == NULL || avail == 0)
|
||||
p = __archive_read_filter_ahead(f, len, NULL);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
|
||||
if (memcmp(p, LRZIP_HEADER_MAGIC, LRZIP_HEADER_MAGIC_LEN))
|
||||
@@ -105,15 +105,15 @@ lrzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
}
|
||||
|
||||
static int
|
||||
lrzip_bidder_init(struct archive_read_filter *self)
|
||||
lrzip_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "lrzip -d -q");
|
||||
r = __archive_read_program(f, "lrzip -d -q");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_LRZIP;
|
||||
self->name = "lrzip";
|
||||
f->code = ARCHIVE_FILTER_LRZIP;
|
||||
f->name = "lrzip";
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_endian.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
#include "archive_xxhash.h"
|
||||
@@ -56,7 +57,7 @@
|
||||
#define LZ4_SKIPPABLE_MASK 0xFFFFFFF0
|
||||
|
||||
#if defined(HAVE_LIBLZ4)
|
||||
struct private_data {
|
||||
struct lz4 {
|
||||
enum { SELECT_STREAM,
|
||||
READ_DEFAULT_STREAM,
|
||||
READ_DEFAULT_BLOCK,
|
||||
@@ -95,8 +96,7 @@ static int lz4_filter_close(struct archive_read_filter *);
|
||||
/*
|
||||
* Note that we can detect lz4 archives even if we can't decompress
|
||||
* them. (In fact, we like detecting them because we can give better
|
||||
* error messages.) So the bid framework here gets compiled even
|
||||
* if liblz4 is unavailable.
|
||||
* error messages.)
|
||||
*/
|
||||
static int lz4_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
|
||||
static int lz4_reader_init(struct archive_read_filter *);
|
||||
@@ -139,58 +139,81 @@ archive_read_support_filter_lz4(struct archive *_a)
|
||||
* from verifying as much as we would like.
|
||||
*/
|
||||
static int
|
||||
lz4_reader_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
lz4_reader_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
ssize_t avail;
|
||||
int bits_checked = 0;
|
||||
ssize_t min_lz4_archive_size = 11;
|
||||
const size_t min_lz4_archive_size = 11;
|
||||
|
||||
// LZ4 skippable frames contain a 4 byte magic number followed by
|
||||
// a 4 byte frame data size, then that number of bytes of data. Regular
|
||||
// frames contain a 4 byte magic number followed by a 2-14 byte frame
|
||||
// header, some data, and a 3 byte end marker.
|
||||
ssize_t min_lz4_frame_size = 8;
|
||||
/*
|
||||
* LZ4 skippable frames contain a 4 byte magic number followed by
|
||||
* a 4 byte frame data size, then that number of bytes of data.
|
||||
* Regular frames contain a 4 byte magic number followed by a 2-14
|
||||
* byte frame header, some data, and a 3 byte end marker.
|
||||
*/
|
||||
const size_t min_lz4_frame_size = 8;
|
||||
|
||||
ssize_t offset_in_buffer = 0;
|
||||
ssize_t max_lookahead = 64 * 1024;
|
||||
size_t offset_in_buffer = 0;
|
||||
const size_t max_lookahead = 64 * 1024;
|
||||
uint32_t magic_number;
|
||||
|
||||
(void)self; // UNUSED
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
// Zstd and LZ4 skippable frame magic numbers are identical. To
|
||||
// differentiate these two, we need to look for a non-skippable
|
||||
// frame.
|
||||
/*
|
||||
* Zstd and LZ4 skippable frame magic numbers are identical. To
|
||||
* differentiate these two, we need to look for a non-skippable
|
||||
* frame.
|
||||
*/
|
||||
|
||||
// Minimal lz4 archive is 11 bytes.
|
||||
buffer = __archive_read_filter_ahead(filter, min_lz4_archive_size, &avail);
|
||||
/* Minimal lz4 archive is 11 bytes. */
|
||||
buffer = __archive_read_filter_ahead(f, min_lz4_archive_size,
|
||||
&avail);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
|
||||
uint32_t magic_number = archive_le32dec(buffer);
|
||||
magic_number = archive_le32dec(buffer);
|
||||
|
||||
while ((magic_number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
|
||||
size_t min;
|
||||
uint32_t frame_data_size;
|
||||
|
||||
offset_in_buffer += 4; // Skip over the magic number
|
||||
/* Skip over the magic number */
|
||||
offset_in_buffer += 4;
|
||||
|
||||
// Ensure that we can read another 4 bytes.
|
||||
if (offset_in_buffer + 4 > avail) {
|
||||
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
|
||||
/* Ensure that we can read another 4 bytes. */
|
||||
if (offset_in_buffer + 4 > (size_t)avail) {
|
||||
buffer = __archive_read_filter_ahead(f,
|
||||
offset_in_buffer + 4, &avail);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
|
||||
frame_data_size = archive_le32dec(buffer + offset_in_buffer);
|
||||
|
||||
// Skip over the 4 frame data size bytes, plus the value stored there.
|
||||
offset_in_buffer += 4 + frame_data_size;
|
||||
/* Skip over the 4 frame data size bytes */
|
||||
offset_in_buffer += 4;
|
||||
|
||||
// There should be at least one more frame if this is LZ4 data.
|
||||
if (offset_in_buffer + min_lz4_frame_size > avail) { // TODO: should this be >= ?
|
||||
if (offset_in_buffer + min_lz4_frame_size > max_lookahead)
|
||||
/* Skip over the value stored there. */
|
||||
if (archive_ckd_add_size(&offset_in_buffer,
|
||||
offset_in_buffer, frame_data_size))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* There should be at least one more frame
|
||||
* if this is LZ4 data.
|
||||
*/
|
||||
if (archive_ckd_add_size(&min,
|
||||
offset_in_buffer, min_lz4_frame_size))
|
||||
return (0);
|
||||
/* TODO: should this be >= ? */
|
||||
if (min > (size_t)avail) {
|
||||
if (min > max_lookahead)
|
||||
return (0);
|
||||
|
||||
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_lz4_frame_size, &avail);
|
||||
buffer = __archive_read_filter_ahead(f,
|
||||
min, &avail);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
}
|
||||
@@ -198,8 +221,10 @@ lz4_reader_bid(struct archive_read_filter_bidder *self,
|
||||
magic_number = archive_le32dec(buffer + offset_in_buffer);
|
||||
}
|
||||
|
||||
// We have skipped over any skippable frames. Either a regular LZ4 frame
|
||||
// follows, or this isn't LZ4 data.
|
||||
/*
|
||||
* We have skipped over any skippable frames. Either a regular LZ4 frame
|
||||
* follows, or this isn't LZ4 data.
|
||||
*/
|
||||
|
||||
bits_checked = offset_in_buffer;
|
||||
buffer = buffer + offset_in_buffer;
|
||||
@@ -241,21 +266,21 @@ lz4_reader_bid(struct archive_read_filter_bidder *self,
|
||||
#if !defined(HAVE_LIBLZ4)
|
||||
|
||||
/*
|
||||
* If we don't have the library on this system, we can't actually do the
|
||||
* decompression. We can, however, still detect compressed archives
|
||||
* and emit a useful message.
|
||||
* If we don't have the library on this system, we can't do the
|
||||
* decompression directly. We can, however, try to run "lz4 -d -q"
|
||||
* in case that's available.
|
||||
*/
|
||||
static int
|
||||
lz4_reader_init(struct archive_read_filter *self)
|
||||
lz4_reader_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "lz4 -d -q");
|
||||
r = __archive_read_program(f, "lz4 -d -q");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_LZ4;
|
||||
self->name = "lz4";
|
||||
f->code = ARCHIVE_FILTER_LZ4;
|
||||
f->name = "lz4";
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -272,69 +297,73 @@ lz4_reader_vtable = {
|
||||
* Setup the callbacks.
|
||||
*/
|
||||
static int
|
||||
lz4_reader_init(struct archive_read_filter *self)
|
||||
lz4_reader_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct lz4 *lz4;
|
||||
|
||||
self->code = ARCHIVE_FILTER_LZ4;
|
||||
self->name = "lz4";
|
||||
f->code = ARCHIVE_FILTER_LZ4;
|
||||
f->name = "lz4";
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
if (state == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
lz4 = calloc(1, sizeof(*lz4));
|
||||
if (lz4 == NULL) {
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for lz4 decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
state->stage = SELECT_STREAM;
|
||||
self->vtable = &lz4_reader_vtable;
|
||||
f->data = lz4;
|
||||
lz4->stage = SELECT_STREAM;
|
||||
f->vtable = &lz4_reader_vtable;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
lz4_allocate_out_block(struct archive_read_filter *self)
|
||||
lz4_allocate_out_block(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
size_t out_block_size = state->flags.block_maximum_size;
|
||||
struct lz4 *lz4 = f->data;
|
||||
size_t out_block_size = lz4->flags.block_maximum_size;
|
||||
void *out_block;
|
||||
|
||||
if (!state->flags.block_independence)
|
||||
if (!lz4->flags.block_independence)
|
||||
out_block_size += 64 * 1024;
|
||||
if (state->out_block_size < out_block_size) {
|
||||
free(state->out_block);
|
||||
if (lz4->out_block_size < out_block_size) {
|
||||
free(lz4->out_block);
|
||||
lz4->out_block = NULL;
|
||||
out_block = malloc(out_block_size);
|
||||
state->out_block_size = out_block_size;
|
||||
if (out_block == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
lz4->out_block_size = 0;
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for lz4 decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->out_block = out_block;
|
||||
lz4->out_block_size = out_block_size;
|
||||
lz4->out_block = out_block;
|
||||
}
|
||||
if (!state->flags.block_independence)
|
||||
memset(state->out_block, 0, 64 * 1024);
|
||||
if (!lz4->flags.block_independence)
|
||||
memset(lz4->out_block, 0, 64 * 1024);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)
|
||||
lz4_allocate_out_block_for_legacy(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
size_t out_block_size = LEGACY_BLOCK_SIZE;
|
||||
void *out_block;
|
||||
|
||||
if (state->out_block_size < out_block_size) {
|
||||
free(state->out_block);
|
||||
if (lz4->out_block_size < out_block_size) {
|
||||
free(lz4->out_block);
|
||||
lz4->out_block = NULL;
|
||||
out_block = malloc(out_block_size);
|
||||
state->out_block_size = out_block_size;
|
||||
if (out_block == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
lz4->out_block_size = 0;
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for lz4 decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->out_block = out_block;
|
||||
lz4->out_block_size = out_block_size;
|
||||
lz4->out_block = out_block;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -343,90 +372,96 @@ lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)
|
||||
* Return the next block of decompressed data.
|
||||
*/
|
||||
static ssize_t
|
||||
lz4_filter_read(struct archive_read_filter *self, const void **p)
|
||||
lz4_filter_read(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
ssize_t ret;
|
||||
|
||||
if (state->eof) {
|
||||
if (lz4->eof) {
|
||||
*p = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
__archive_read_filter_consume(self->upstream, state->unconsumed);
|
||||
state->unconsumed = 0;
|
||||
__archive_read_filter_consume(f->upstream, lz4->unconsumed);
|
||||
lz4->unconsumed = 0;
|
||||
|
||||
switch (state->stage) {
|
||||
switch (lz4->stage) {
|
||||
case SELECT_STREAM:
|
||||
break;
|
||||
case READ_DEFAULT_STREAM:
|
||||
case READ_LEGACY_STREAM:
|
||||
/* Reading a lz4 stream already failed. */
|
||||
archive_set_error(&self->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Invalid sequence.");
|
||||
/* Reading an lz4 stream already failed. */
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Invalid sequence");
|
||||
return (ARCHIVE_FATAL);
|
||||
case READ_DEFAULT_BLOCK:
|
||||
ret = lz4_filter_read_default_stream(self, p);
|
||||
if (ret != 0 || state->stage != SELECT_STREAM)
|
||||
ret = lz4_filter_read_default_stream(f, p);
|
||||
if (ret != 0 || lz4->stage != SELECT_STREAM)
|
||||
return ret;
|
||||
break;
|
||||
case READ_LEGACY_BLOCK:
|
||||
ret = lz4_filter_read_legacy_stream(self, p);
|
||||
if (ret != 0 || state->stage != SELECT_STREAM)
|
||||
ret = lz4_filter_read_legacy_stream(f, p);
|
||||
if (ret != 0 || lz4->stage != SELECT_STREAM)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&self->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Program error.");
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Program error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
while (state->stage == SELECT_STREAM) {
|
||||
while (lz4->stage == SELECT_STREAM) {
|
||||
const char *read_buf;
|
||||
|
||||
/* Read a magic number. */
|
||||
read_buf = __archive_read_filter_ahead(self->upstream, 4,
|
||||
read_buf = __archive_read_filter_ahead(f->upstream, 4,
|
||||
NULL);
|
||||
if (read_buf == NULL) {
|
||||
state->eof = 1;
|
||||
lz4->eof = 1;
|
||||
*p = NULL;
|
||||
return (0);
|
||||
}
|
||||
uint32_t number = archive_le32dec(read_buf);
|
||||
__archive_read_filter_consume(self->upstream, 4);
|
||||
__archive_read_filter_consume(f->upstream, 4);
|
||||
if (number == LZ4_MAGICNUMBER)
|
||||
return lz4_filter_read_default_stream(self, p);
|
||||
return lz4_filter_read_default_stream(f, p);
|
||||
else if (number == LZ4_LEGACY)
|
||||
return lz4_filter_read_legacy_stream(self, p);
|
||||
return lz4_filter_read_legacy_stream(f, p);
|
||||
else if ((number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
|
||||
read_buf = __archive_read_filter_ahead(
|
||||
self->upstream, 4, NULL);
|
||||
f->upstream, 4, NULL);
|
||||
if (read_buf == NULL) {
|
||||
archive_set_error(
|
||||
&self->archive->archive,
|
||||
&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Malformed lz4 data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
uint32_t skip_bytes = archive_le32dec(read_buf);
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
4 + skip_bytes);
|
||||
int64_t skip_bytes = archive_le32dec(read_buf);
|
||||
if (__archive_read_filter_consume(f->upstream,
|
||||
4 + skip_bytes) < 0) {
|
||||
archive_set_error(
|
||||
&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Malformed lz4 data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
} else {
|
||||
/* Ignore following unrecognized data. */
|
||||
state->eof = 1;
|
||||
lz4->eof = 1;
|
||||
*p = NULL;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
state->eof = 1;
|
||||
lz4->eof = 1;
|
||||
*p = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
lz4_filter_read_descriptor(struct archive_read_filter *self)
|
||||
lz4_filter_read_descriptor(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
const char *read_buf;
|
||||
ssize_t bytes_remaining;
|
||||
ssize_t descriptor_bytes;
|
||||
@@ -434,10 +469,10 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
|
||||
unsigned int chsum, chsum_verifier;
|
||||
|
||||
/* Make sure we have 2 bytes for flags. */
|
||||
read_buf = __archive_read_filter_ahead(self->upstream, 2,
|
||||
read_buf = __archive_read_filter_ahead(f->upstream, 2,
|
||||
&bytes_remaining);
|
||||
if (read_buf == NULL) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"truncated lz4 input");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -453,11 +488,11 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
|
||||
/* A reserved bit must be zero. */
|
||||
if (flag & 0x02)
|
||||
goto malformed_error;
|
||||
state->flags.block_independence = (flag & 0x20) != 0;
|
||||
state->flags.block_checksum = (flag & 0x10)?4:0;
|
||||
state->flags.stream_size = (flag & 0x08) != 0;
|
||||
state->flags.stream_checksum = (flag & 0x04) != 0;
|
||||
state->flags.preset_dictionary = (flag & 0x01) != 0;
|
||||
lz4->flags.block_independence = (flag & 0x20) != 0;
|
||||
lz4->flags.block_checksum = (flag & 0x10)?4:0;
|
||||
lz4->flags.stream_size = (flag & 0x08) != 0;
|
||||
lz4->flags.stream_checksum = (flag & 0x04) != 0;
|
||||
lz4->flags.preset_dictionary = (flag & 0x01) != 0;
|
||||
|
||||
/* BD */
|
||||
bd = (unsigned char)read_buf[1];
|
||||
@@ -467,16 +502,16 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
|
||||
/* Get a maximum block size. */
|
||||
switch (read_buf[1] >> 4) {
|
||||
case 4: /* 64 KB */
|
||||
state->flags.block_maximum_size = 64 * 1024;
|
||||
lz4->flags.block_maximum_size = 64 * 1024;
|
||||
break;
|
||||
case 5: /* 256 KB */
|
||||
state->flags.block_maximum_size = 256 * 1024;
|
||||
lz4->flags.block_maximum_size = 256 * 1024;
|
||||
break;
|
||||
case 6: /* 1 MB */
|
||||
state->flags.block_maximum_size = 1024 * 1024;
|
||||
lz4->flags.block_maximum_size = 1024 * 1024;
|
||||
break;
|
||||
case 7: /* 4 MB */
|
||||
state->flags.block_maximum_size = 4 * 1024 * 1024;
|
||||
lz4->flags.block_maximum_size = 4 * 1024 * 1024;
|
||||
break;
|
||||
default:
|
||||
goto malformed_error;
|
||||
@@ -484,15 +519,15 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
|
||||
|
||||
/* Read the whole descriptor in a stream block. */
|
||||
descriptor_bytes = 3;
|
||||
if (state->flags.stream_size)
|
||||
if (lz4->flags.stream_size)
|
||||
descriptor_bytes += 8;
|
||||
if (state->flags.preset_dictionary)
|
||||
if (lz4->flags.preset_dictionary)
|
||||
descriptor_bytes += 4;
|
||||
if (bytes_remaining < descriptor_bytes) {
|
||||
read_buf = __archive_read_filter_ahead(self->upstream,
|
||||
read_buf = __archive_read_filter_ahead(f->upstream,
|
||||
descriptor_bytes, &bytes_remaining);
|
||||
if (read_buf == NULL) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"truncated lz4 input");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -507,30 +542,32 @@ lz4_filter_read_descriptor(struct archive_read_filter *self)
|
||||
goto malformed_error;
|
||||
#endif
|
||||
|
||||
__archive_read_filter_consume(self->upstream, descriptor_bytes);
|
||||
__archive_read_filter_consume(f->upstream, descriptor_bytes);
|
||||
|
||||
/* Make sure we have a large enough buffer for uncompressed data. */
|
||||
if (lz4_allocate_out_block(self) != ARCHIVE_OK)
|
||||
if (lz4_allocate_out_block(f) != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (state->flags.stream_checksum)
|
||||
state->xxh32_state = __archive_xxhash.XXH32_init(0);
|
||||
if (lz4->flags.stream_checksum) {
|
||||
lz4->xxh32_state = __archive_xxhash.XXH32_init(0);
|
||||
if (lz4->xxh32_state == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
state->decoded_size = 0;
|
||||
lz4->decoded_size = 0;
|
||||
/* Success */
|
||||
return (ARCHIVE_OK);
|
||||
malformed_error:
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"malformed lz4 data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
|
||||
lz4_filter_read_data_block(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
ssize_t compressed_size;
|
||||
const char *read_buf;
|
||||
ssize_t bytes_remaining;
|
||||
int checksum_size;
|
||||
ssize_t uncompressed_size;
|
||||
size_t prefix64k;
|
||||
@@ -538,20 +575,19 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
|
||||
*p = NULL;
|
||||
|
||||
/* Make sure we have 4 bytes for a block size. */
|
||||
read_buf = __archive_read_filter_ahead(self->upstream, 4,
|
||||
&bytes_remaining);
|
||||
read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL);
|
||||
if (read_buf == NULL)
|
||||
goto truncated_error;
|
||||
compressed_size = archive_le32dec(read_buf);
|
||||
if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size)
|
||||
if ((compressed_size & 0x7fffffff) > lz4->flags.block_maximum_size)
|
||||
goto malformed_error;
|
||||
/* A compressed size == 0 means the end of stream blocks. */
|
||||
if (compressed_size == 0) {
|
||||
__archive_read_filter_consume(self->upstream, 4);
|
||||
__archive_read_filter_consume(f->upstream, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
checksum_size = state->flags.block_checksum;
|
||||
checksum_size = lz4->flags.block_checksum;
|
||||
/* Check if the block is uncompressed. */
|
||||
if (compressed_size & 0x80000000U) {
|
||||
compressed_size &= 0x7fffffff;
|
||||
@@ -564,8 +600,8 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
|
||||
for its decompression speed, so we read a whole block and allocate
|
||||
a huge buffer used for decoded data.
|
||||
*/
|
||||
read_buf = __archive_read_filter_ahead(self->upstream,
|
||||
4 + compressed_size + checksum_size, &bytes_remaining);
|
||||
read_buf = __archive_read_filter_ahead(f->upstream,
|
||||
4 + compressed_size + checksum_size, NULL);
|
||||
if (read_buf == NULL)
|
||||
goto truncated_error;
|
||||
|
||||
@@ -585,24 +621,24 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
|
||||
/* If the block is uncompressed, there is nothing to do. */
|
||||
if (uncompressed_size) {
|
||||
/* Prepare a prefix 64k block for next block. */
|
||||
if (!state->flags.block_independence) {
|
||||
if (!lz4->flags.block_independence) {
|
||||
prefix64k = 64 * 1024;
|
||||
if (uncompressed_size < (ssize_t)prefix64k) {
|
||||
memcpy(state->out_block
|
||||
memcpy(lz4->out_block
|
||||
+ prefix64k - uncompressed_size,
|
||||
read_buf + 4,
|
||||
uncompressed_size);
|
||||
memset(state->out_block, 0,
|
||||
memset(lz4->out_block, 0,
|
||||
prefix64k - uncompressed_size);
|
||||
} else {
|
||||
memcpy(state->out_block,
|
||||
memcpy(lz4->out_block,
|
||||
read_buf + 4
|
||||
+ uncompressed_size - prefix64k,
|
||||
prefix64k);
|
||||
}
|
||||
state->decoded_size = 0;
|
||||
lz4->decoded_size = 0;
|
||||
}
|
||||
state->unconsumed = 4 + uncompressed_size + checksum_size;
|
||||
lz4->unconsumed = 4 + uncompressed_size + checksum_size;
|
||||
*p = read_buf + 4;
|
||||
return uncompressed_size;
|
||||
}
|
||||
@@ -610,169 +646,168 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
|
||||
/*
|
||||
Decompress a block data.
|
||||
*/
|
||||
if (state->flags.block_independence) {
|
||||
if (lz4->flags.block_independence) {
|
||||
prefix64k = 0;
|
||||
uncompressed_size = LZ4_decompress_safe(read_buf + 4,
|
||||
state->out_block, (int)compressed_size,
|
||||
state->flags.block_maximum_size);
|
||||
lz4->out_block, (int)compressed_size,
|
||||
lz4->flags.block_maximum_size);
|
||||
} else {
|
||||
prefix64k = 64 * 1024;
|
||||
if (state->decoded_size) {
|
||||
if (state->decoded_size < prefix64k) {
|
||||
memmove(state->out_block
|
||||
+ prefix64k - state->decoded_size,
|
||||
state->out_block + prefix64k,
|
||||
state->decoded_size);
|
||||
memset(state->out_block, 0,
|
||||
prefix64k - state->decoded_size);
|
||||
if (lz4->decoded_size) {
|
||||
if (lz4->decoded_size < prefix64k) {
|
||||
memmove(lz4->out_block
|
||||
+ prefix64k - lz4->decoded_size,
|
||||
lz4->out_block + prefix64k,
|
||||
lz4->decoded_size);
|
||||
memset(lz4->out_block, 0,
|
||||
prefix64k - lz4->decoded_size);
|
||||
} else {
|
||||
memmove(state->out_block,
|
||||
state->out_block + state->decoded_size,
|
||||
memmove(lz4->out_block,
|
||||
lz4->out_block + lz4->decoded_size,
|
||||
prefix64k);
|
||||
}
|
||||
}
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
uncompressed_size = LZ4_decompress_safe_usingDict(
|
||||
read_buf + 4,
|
||||
state->out_block + prefix64k, (int)compressed_size,
|
||||
state->flags.block_maximum_size,
|
||||
state->out_block,
|
||||
lz4->out_block + prefix64k, (int)compressed_size,
|
||||
lz4->flags.block_maximum_size,
|
||||
lz4->out_block,
|
||||
(int)prefix64k);
|
||||
#else
|
||||
uncompressed_size = LZ4_decompress_safe_withPrefix64k(
|
||||
read_buf + 4,
|
||||
state->out_block + prefix64k, (int)compressed_size,
|
||||
state->flags.block_maximum_size);
|
||||
lz4->out_block + prefix64k, (int)compressed_size,
|
||||
lz4->flags.block_maximum_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if an error occurred in the decompression process. */
|
||||
if (uncompressed_size < 0) {
|
||||
archive_set_error(&(self->archive->archive),
|
||||
archive_set_error(&(f->archive->archive),
|
||||
ARCHIVE_ERRNO_MISC, "lz4 decompression failed");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
state->unconsumed = 4 + compressed_size + checksum_size;
|
||||
*p = state->out_block + prefix64k;
|
||||
state->decoded_size = uncompressed_size;
|
||||
lz4->unconsumed = 4 + compressed_size + checksum_size;
|
||||
*p = lz4->out_block + prefix64k;
|
||||
lz4->decoded_size = uncompressed_size;
|
||||
return uncompressed_size;
|
||||
|
||||
malformed_error:
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"malformed lz4 data");
|
||||
return (ARCHIVE_FATAL);
|
||||
truncated_error:
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"truncated lz4 input");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
lz4_filter_read_default_stream(struct archive_read_filter *self, const void **p)
|
||||
lz4_filter_read_default_stream(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
const char *read_buf;
|
||||
ssize_t bytes_remaining;
|
||||
ssize_t ret;
|
||||
|
||||
if (state->stage == SELECT_STREAM) {
|
||||
state->stage = READ_DEFAULT_STREAM;
|
||||
if (lz4->stage == SELECT_STREAM) {
|
||||
lz4->stage = READ_DEFAULT_STREAM;
|
||||
/* First, read a descriptor. */
|
||||
if((ret = lz4_filter_read_descriptor(self)) != ARCHIVE_OK)
|
||||
if((ret = lz4_filter_read_descriptor(f)) != ARCHIVE_OK)
|
||||
return (ret);
|
||||
state->stage = READ_DEFAULT_BLOCK;
|
||||
lz4->stage = READ_DEFAULT_BLOCK;
|
||||
}
|
||||
/* Decompress a block. */
|
||||
ret = lz4_filter_read_data_block(self, p);
|
||||
ret = lz4_filter_read_data_block(f, p);
|
||||
|
||||
/* If the end of block is detected, change the filter status
|
||||
to read next stream. */
|
||||
if (ret == 0 && *p == NULL)
|
||||
state->stage = SELECT_STREAM;
|
||||
lz4->stage = SELECT_STREAM;
|
||||
|
||||
/* Optional processing, checking a stream sum. */
|
||||
if (state->flags.stream_checksum) {
|
||||
if (state->stage == SELECT_STREAM) {
|
||||
if (lz4->flags.stream_checksum) {
|
||||
if (lz4->stage == SELECT_STREAM) {
|
||||
unsigned int checksum;
|
||||
unsigned int checksum_stream;
|
||||
read_buf = __archive_read_filter_ahead(self->upstream,
|
||||
4, &bytes_remaining);
|
||||
read_buf = __archive_read_filter_ahead(f->upstream,
|
||||
4, NULL);
|
||||
if (read_buf == NULL) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "truncated lz4 input");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
checksum = archive_le32dec(read_buf);
|
||||
__archive_read_filter_consume(self->upstream, 4);
|
||||
__archive_read_filter_consume(f->upstream, 4);
|
||||
checksum_stream = __archive_xxhash.XXH32_digest(
|
||||
state->xxh32_state);
|
||||
state->xxh32_state = NULL;
|
||||
lz4->xxh32_state);
|
||||
lz4->xxh32_state = NULL;
|
||||
if (checksum != checksum_stream) {
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"lz4 stream checksum error");
|
||||
return (ARCHIVE_FATAL);
|
||||
#endif
|
||||
}
|
||||
} else if (ret > 0)
|
||||
__archive_xxhash.XXH32_update(state->xxh32_state,
|
||||
__archive_xxhash.XXH32_update(lz4->xxh32_state,
|
||||
*p, (int)ret);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)
|
||||
lz4_filter_read_legacy_stream(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)self->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
uint32_t compressed;
|
||||
const char *read_buf;
|
||||
ssize_t ret;
|
||||
|
||||
*p = NULL;
|
||||
ret = lz4_allocate_out_block_for_legacy(self);
|
||||
ret = lz4_allocate_out_block_for_legacy(f);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
/* Make sure we have 4 bytes for a block size. */
|
||||
read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
||||
read_buf = __archive_read_filter_ahead(f->upstream, 4, NULL);
|
||||
if (read_buf == NULL) {
|
||||
if (state->stage == SELECT_STREAM) {
|
||||
state->stage = READ_LEGACY_STREAM;
|
||||
archive_set_error(&self->archive->archive,
|
||||
if (lz4->stage == SELECT_STREAM) {
|
||||
lz4->stage = READ_LEGACY_STREAM;
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"truncated lz4 input");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->stage = SELECT_STREAM;
|
||||
lz4->stage = SELECT_STREAM;
|
||||
return 0;
|
||||
}
|
||||
state->stage = READ_LEGACY_BLOCK;
|
||||
lz4->stage = READ_LEGACY_BLOCK;
|
||||
compressed = archive_le32dec(read_buf);
|
||||
if (compressed > LZ4_COMPRESSBOUND(LEGACY_BLOCK_SIZE)) {
|
||||
state->stage = SELECT_STREAM;
|
||||
lz4->stage = SELECT_STREAM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure we have a whole block. */
|
||||
read_buf = __archive_read_filter_ahead(self->upstream,
|
||||
read_buf = __archive_read_filter_ahead(f->upstream,
|
||||
4 + compressed, NULL);
|
||||
if (read_buf == NULL) {
|
||||
archive_set_error(&(self->archive->archive),
|
||||
archive_set_error(&(f->archive->archive),
|
||||
ARCHIVE_ERRNO_MISC, "truncated lz4 input");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
ret = LZ4_decompress_safe(read_buf + 4, state->out_block,
|
||||
compressed, (int)state->out_block_size);
|
||||
ret = LZ4_decompress_safe(read_buf + 4, lz4->out_block,
|
||||
compressed, (int)lz4->out_block_size);
|
||||
if (ret < 0) {
|
||||
archive_set_error(&(self->archive->archive),
|
||||
archive_set_error(&(f->archive->archive),
|
||||
ARCHIVE_ERRNO_MISC, "lz4 decompression failed");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
*p = state->out_block;
|
||||
state->unconsumed = 4 + compressed;
|
||||
*p = lz4->out_block;
|
||||
lz4->unconsumed = 4 + compressed;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -780,15 +815,14 @@ lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)
|
||||
* Clean up the decompressor.
|
||||
*/
|
||||
static int
|
||||
lz4_filter_close(struct archive_read_filter *self)
|
||||
lz4_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct lz4 *lz4 = f->data;
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
free(state->xxh32_state);
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
free(lz4->xxh32_state);
|
||||
free(lz4->out_block);
|
||||
free(lz4);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,10 +68,9 @@
|
||||
#define LZOP_HEADER_MAGIC_LEN 9
|
||||
|
||||
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
||||
struct read_lzop {
|
||||
struct lzop {
|
||||
unsigned char *out_block;
|
||||
size_t out_block_size;
|
||||
int64_t total_out;
|
||||
int flags;
|
||||
uint32_t compressed_cksum;
|
||||
uint32_t uncompressed_cksum;
|
||||
@@ -110,7 +109,7 @@ archive_read_support_filter_lzop(struct archive *_a)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
|
||||
if (__archive_read_register_bidder(a, NULL, NULL,
|
||||
if (__archive_read_register_bidder(a, NULL, "lzop",
|
||||
&lzop_bidder_vtable) != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
@@ -118,7 +117,6 @@ archive_read_support_filter_lzop(struct archive *_a)
|
||||
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
||||
return (ARCHIVE_OK);
|
||||
#else
|
||||
/* Return ARCHIVE_WARN since this always uses an external program. */
|
||||
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
|
||||
"Using external lzop program for lzop decompression");
|
||||
return (ARCHIVE_WARN);
|
||||
@@ -129,16 +127,15 @@ archive_read_support_filter_lzop(struct archive *_a)
|
||||
* Bidder just verifies the header and returns the number of verified bits.
|
||||
*/
|
||||
static int
|
||||
lzop_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
lzop_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *p;
|
||||
ssize_t avail;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
|
||||
if (p == NULL || avail == 0)
|
||||
p = __archive_read_filter_ahead(f, LZOP_HEADER_MAGIC_LEN, NULL);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
|
||||
if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
|
||||
@@ -154,16 +151,16 @@ lzop_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
* in case that's available.
|
||||
*/
|
||||
static int
|
||||
lzop_bidder_init(struct archive_read_filter *self)
|
||||
lzop_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "lzop -d");
|
||||
r = __archive_read_program(f, "lzop -d");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_LZOP;
|
||||
self->name = "lzop";
|
||||
f->code = ARCHIVE_FILTER_LZOP;
|
||||
f->name = "lzop";
|
||||
return (r);
|
||||
}
|
||||
#else
|
||||
@@ -178,47 +175,47 @@ lzop_reader_vtable = {
|
||||
* Initialize the filter object.
|
||||
*/
|
||||
static int
|
||||
lzop_bidder_init(struct archive_read_filter *self)
|
||||
lzop_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct read_lzop *state;
|
||||
struct lzop *lzop;
|
||||
|
||||
self->code = ARCHIVE_FILTER_LZOP;
|
||||
self->name = "lzop";
|
||||
f->code = ARCHIVE_FILTER_LZOP;
|
||||
f->name = "lzop";
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
if (state == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
lzop = calloc(1, sizeof(*lzop));
|
||||
if (lzop == NULL) {
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for lzop decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
self->vtable = &lzop_reader_vtable;
|
||||
f->data = lzop;
|
||||
f->vtable = &lzop_reader_vtable;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
consume_header(struct archive_read_filter *self)
|
||||
consume_header(struct archive_read_filter *f)
|
||||
{
|
||||
struct read_lzop *state = (struct read_lzop *)self->data;
|
||||
struct lzop *lzop = f->data;
|
||||
const unsigned char *p, *_p;
|
||||
unsigned checksum, flags, len, method, version;
|
||||
|
||||
/*
|
||||
* Check LZOP magic code.
|
||||
*/
|
||||
p = __archive_read_filter_ahead(self->upstream,
|
||||
p = __archive_read_filter_ahead(f->upstream,
|
||||
LZOP_HEADER_MAGIC_LEN, NULL);
|
||||
if (p == NULL)
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
|
||||
return (ARCHIVE_EOF);
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
LZOP_HEADER_MAGIC_LEN);
|
||||
|
||||
p = __archive_read_filter_ahead(self->upstream, 29, NULL);
|
||||
p = __archive_read_filter_ahead(f->upstream, 29, NULL);
|
||||
if (p == NULL)
|
||||
goto truncated;
|
||||
_p = p;
|
||||
@@ -228,7 +225,7 @@ consume_header(struct archive_read_filter *self)
|
||||
if (version >= 0x940) {
|
||||
unsigned reqversion = archive_be16dec(p); p += 2;
|
||||
if (reqversion < 0x900) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Invalid required version");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
@@ -236,7 +233,7 @@ consume_header(struct archive_read_filter *self)
|
||||
|
||||
method = *p++;
|
||||
if (method < 1 || method > 3) {
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unsupported method");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
@@ -255,7 +252,7 @@ consume_header(struct archive_read_filter *self)
|
||||
;/* NOP */
|
||||
#endif
|
||||
else if (level > 9) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Invalid level");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
@@ -273,7 +270,7 @@ consume_header(struct archive_read_filter *self)
|
||||
len = *p++; /* Read filename length */
|
||||
len += p - _p;
|
||||
/* Make sure we have all bytes we need to calculate checksum. */
|
||||
p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
|
||||
p = __archive_read_filter_ahead(f->upstream, len + 4, NULL);
|
||||
if (p == NULL)
|
||||
goto truncated;
|
||||
if (flags & CRC32_HEADER)
|
||||
@@ -284,201 +281,199 @@ consume_header(struct archive_read_filter *self)
|
||||
if (archive_be32dec(p + len) != checksum)
|
||||
goto corrupted;
|
||||
#endif
|
||||
__archive_read_filter_consume(self->upstream, len + 4);
|
||||
__archive_read_filter_consume(f->upstream, len + 4);
|
||||
if (flags & EXTRA_FIELD) {
|
||||
/* Skip extra field */
|
||||
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
||||
p = __archive_read_filter_ahead(f->upstream, 4, NULL);
|
||||
if (p == NULL)
|
||||
goto truncated;
|
||||
len = archive_be32dec(p);
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
(int64_t)len + 4 + 4);
|
||||
}
|
||||
state->flags = flags;
|
||||
state->in_stream = 1;
|
||||
lzop->flags = flags;
|
||||
lzop->in_stream = 1;
|
||||
return (ARCHIVE_OK);
|
||||
truncated:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
|
||||
return (ARCHIVE_FAILED);
|
||||
corrupted:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static int
|
||||
consume_block_info(struct archive_read_filter *self)
|
||||
consume_block_info(struct archive_read_filter *f)
|
||||
{
|
||||
struct read_lzop *state = (struct read_lzop *)self->data;
|
||||
struct lzop *lzop = f->data;
|
||||
const unsigned char *p;
|
||||
unsigned flags = state->flags;
|
||||
unsigned flags = lzop->flags;
|
||||
|
||||
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
||||
p = __archive_read_filter_ahead(f->upstream, 4, NULL);
|
||||
if (p == NULL)
|
||||
goto truncated;
|
||||
state->uncompressed_size = archive_be32dec(p);
|
||||
__archive_read_filter_consume(self->upstream, 4);
|
||||
if (state->uncompressed_size == 0)
|
||||
lzop->uncompressed_size = archive_be32dec(p);
|
||||
__archive_read_filter_consume(f->upstream, 4);
|
||||
if (lzop->uncompressed_size == 0)
|
||||
return (ARCHIVE_EOF);
|
||||
if (state->uncompressed_size > MAX_BLOCK_SIZE)
|
||||
if (lzop->uncompressed_size > MAX_BLOCK_SIZE)
|
||||
goto corrupted;
|
||||
|
||||
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
||||
p = __archive_read_filter_ahead(f->upstream, 4, NULL);
|
||||
if (p == NULL)
|
||||
goto truncated;
|
||||
state->compressed_size = archive_be32dec(p);
|
||||
__archive_read_filter_consume(self->upstream, 4);
|
||||
if (state->compressed_size > state->uncompressed_size)
|
||||
lzop->compressed_size = archive_be32dec(p);
|
||||
__archive_read_filter_consume(f->upstream, 4);
|
||||
if (lzop->compressed_size > lzop->uncompressed_size)
|
||||
goto corrupted;
|
||||
|
||||
if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
|
||||
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
||||
p = __archive_read_filter_ahead(f->upstream, 4, NULL);
|
||||
if (p == NULL)
|
||||
goto truncated;
|
||||
state->compressed_cksum = state->uncompressed_cksum =
|
||||
lzop->compressed_cksum = lzop->uncompressed_cksum =
|
||||
archive_be32dec(p);
|
||||
__archive_read_filter_consume(self->upstream, 4);
|
||||
__archive_read_filter_consume(f->upstream, 4);
|
||||
}
|
||||
if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
|
||||
state->compressed_size < state->uncompressed_size) {
|
||||
p = __archive_read_filter_ahead(self->upstream, 4, NULL);
|
||||
lzop->compressed_size < lzop->uncompressed_size) {
|
||||
p = __archive_read_filter_ahead(f->upstream, 4, NULL);
|
||||
if (p == NULL)
|
||||
goto truncated;
|
||||
state->compressed_cksum = archive_be32dec(p);
|
||||
__archive_read_filter_consume(self->upstream, 4);
|
||||
lzop->compressed_cksum = archive_be32dec(p);
|
||||
__archive_read_filter_consume(f->upstream, 4);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
truncated:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
|
||||
return (ARCHIVE_FAILED);
|
||||
corrupted:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
lzop_filter_read(struct archive_read_filter *self, const void **p)
|
||||
lzop_filter_read(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct read_lzop *state = (struct read_lzop *)self->data;
|
||||
struct lzop *lzop = f->data;
|
||||
const void *b;
|
||||
lzo_uint out_size;
|
||||
uint32_t cksum;
|
||||
int ret, r;
|
||||
|
||||
if (state->unconsumed_bytes) {
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
state->unconsumed_bytes);
|
||||
state->unconsumed_bytes = 0;
|
||||
if (lzop->unconsumed_bytes) {
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
lzop->unconsumed_bytes);
|
||||
lzop->unconsumed_bytes = 0;
|
||||
}
|
||||
if (state->eof)
|
||||
if (lzop->eof)
|
||||
return (0);
|
||||
|
||||
for (;;) {
|
||||
if (!state->in_stream) {
|
||||
ret = consume_header(self);
|
||||
if (!lzop->in_stream) {
|
||||
ret = consume_header(f);
|
||||
if (ret < ARCHIVE_OK)
|
||||
return (ret);
|
||||
if (ret == ARCHIVE_EOF) {
|
||||
state->eof = 1;
|
||||
lzop->eof = 1;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
ret = consume_block_info(self);
|
||||
ret = consume_block_info(f);
|
||||
if (ret < ARCHIVE_OK)
|
||||
return (ret);
|
||||
if (ret == ARCHIVE_EOF)
|
||||
state->in_stream = 0;
|
||||
lzop->in_stream = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (state->out_block == NULL ||
|
||||
state->out_block_size < state->uncompressed_size) {
|
||||
if (lzop->out_block == NULL ||
|
||||
lzop->out_block_size < lzop->uncompressed_size) {
|
||||
void *new_block;
|
||||
|
||||
new_block = realloc(state->out_block, state->uncompressed_size);
|
||||
new_block = realloc(lzop->out_block, lzop->uncompressed_size);
|
||||
if (new_block == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for lzop decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->out_block = new_block;
|
||||
state->out_block_size = state->uncompressed_size;
|
||||
lzop->out_block = new_block;
|
||||
lzop->out_block_size = lzop->uncompressed_size;
|
||||
}
|
||||
|
||||
b = __archive_read_filter_ahead(self->upstream,
|
||||
state->compressed_size, NULL);
|
||||
b = __archive_read_filter_ahead(f->upstream,
|
||||
lzop->compressed_size, NULL);
|
||||
if (b == NULL) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (state->flags & CRC32_COMPRESSED)
|
||||
cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
|
||||
else if (state->flags & ADLER32_COMPRESSED)
|
||||
cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
|
||||
if (lzop->flags & CRC32_COMPRESSED)
|
||||
cksum = crc32(crc32(0, NULL, 0), b, lzop->compressed_size);
|
||||
else if (lzop->flags & ADLER32_COMPRESSED)
|
||||
cksum = adler32(adler32(0, NULL, 0), b, lzop->compressed_size);
|
||||
else
|
||||
cksum = state->compressed_cksum;
|
||||
if (cksum != state->compressed_cksum) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
cksum = lzop->compressed_cksum;
|
||||
if (cksum != lzop->compressed_cksum) {
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Corrupted data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the both uncompressed size and compressed size are the same,
|
||||
* If both uncompressed size and compressed size are the same,
|
||||
* we do not decompress this block.
|
||||
*/
|
||||
if (state->uncompressed_size == state->compressed_size) {
|
||||
if (lzop->uncompressed_size == lzop->compressed_size) {
|
||||
*p = b;
|
||||
state->total_out += state->compressed_size;
|
||||
state->unconsumed_bytes = state->compressed_size;
|
||||
return ((ssize_t)state->uncompressed_size);
|
||||
lzop->unconsumed_bytes = lzop->compressed_size;
|
||||
return ((ssize_t)lzop->uncompressed_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drive lzo uncompression.
|
||||
*/
|
||||
out_size = (lzo_uint)state->uncompressed_size;
|
||||
r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
|
||||
state->out_block, &out_size, NULL);
|
||||
out_size = (lzo_uint)lzop->uncompressed_size;
|
||||
r = lzo1x_decompress_safe(b, (lzo_uint)lzop->compressed_size,
|
||||
lzop->out_block, &out_size, NULL);
|
||||
switch (r) {
|
||||
case LZO_E_OK:
|
||||
if (out_size == state->uncompressed_size)
|
||||
if (out_size == lzop->uncompressed_size)
|
||||
break;
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Corrupted data");
|
||||
return (ARCHIVE_FATAL);
|
||||
case LZO_E_OUT_OF_MEMORY:
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"lzop decompression failed: out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
default:
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"lzop decompression failed: %d", r);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (state->flags & CRC32_UNCOMPRESSED)
|
||||
cksum = crc32(crc32(0, NULL, 0), state->out_block,
|
||||
state->uncompressed_size);
|
||||
else if (state->flags & ADLER32_UNCOMPRESSED)
|
||||
cksum = adler32(adler32(0, NULL, 0), state->out_block,
|
||||
state->uncompressed_size);
|
||||
if (lzop->flags & CRC32_UNCOMPRESSED)
|
||||
cksum = crc32(crc32(0, NULL, 0), lzop->out_block,
|
||||
lzop->uncompressed_size);
|
||||
else if (lzop->flags & ADLER32_UNCOMPRESSED)
|
||||
cksum = adler32(adler32(0, NULL, 0), lzop->out_block,
|
||||
lzop->uncompressed_size);
|
||||
else
|
||||
cksum = state->uncompressed_cksum;
|
||||
if (cksum != state->uncompressed_cksum) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
cksum = lzop->uncompressed_cksum;
|
||||
if (cksum != lzop->uncompressed_cksum) {
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Corrupted data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
__archive_read_filter_consume(self->upstream, state->compressed_size);
|
||||
*p = state->out_block;
|
||||
state->total_out += out_size;
|
||||
__archive_read_filter_consume(f->upstream, lzop->compressed_size);
|
||||
*p = lzop->out_block;
|
||||
return ((ssize_t)out_size);
|
||||
}
|
||||
|
||||
@@ -486,12 +481,12 @@ lzop_filter_read(struct archive_read_filter *self, const void **p)
|
||||
* Clean up the decompressor.
|
||||
*/
|
||||
static int
|
||||
lzop_filter_close(struct archive_read_filter *self)
|
||||
lzop_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct read_lzop *state = (struct read_lzop *)self->data;
|
||||
struct lzop *lzop = f->data;
|
||||
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
free(lzop->out_block);
|
||||
free(lzop);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ archive_read_support_filter_program(struct archive *a, const char *cmd)
|
||||
* bid twice in the same pipeline.
|
||||
*/
|
||||
struct program_bidder {
|
||||
char *description;
|
||||
struct archive_string description;
|
||||
char *cmd;
|
||||
void *signature;
|
||||
size_t signature_len;
|
||||
@@ -102,7 +102,7 @@ static void program_bidder_free(struct archive_read_filter_bidder *);
|
||||
/*
|
||||
* The actual filter needs to track input and output data.
|
||||
*/
|
||||
struct program_filter {
|
||||
struct program {
|
||||
struct archive_string description;
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
HANDLE child;
|
||||
@@ -145,6 +145,8 @@ archive_read_support_filter_program_signature(struct archive *_a,
|
||||
state->cmd = strdup(cmd);
|
||||
if (state->cmd == NULL)
|
||||
goto memerr;
|
||||
archive_strcpy(&state->description, "Program: ");
|
||||
archive_strcat(&state->description, cmd);
|
||||
|
||||
if (signature != NULL && signature_len > 0) {
|
||||
state->signature_len = signature_len;
|
||||
@@ -168,9 +170,9 @@ memerr:
|
||||
}
|
||||
|
||||
static void
|
||||
program_bidder_free(struct archive_read_filter_bidder *self)
|
||||
program_bidder_free(struct archive_read_filter_bidder *b)
|
||||
{
|
||||
struct program_bidder *state = (struct program_bidder *)self->data;
|
||||
struct program_bidder *state = (struct program_bidder *)b->data;
|
||||
|
||||
free_state(state);
|
||||
}
|
||||
@@ -180,6 +182,7 @@ free_state(struct program_bidder *state)
|
||||
{
|
||||
|
||||
if (state) {
|
||||
archive_string_free(&state->description);
|
||||
free(state->cmd);
|
||||
free(state->signature);
|
||||
free(state);
|
||||
@@ -193,15 +196,15 @@ free_state(struct program_bidder *state)
|
||||
* we're called, then never bid again.
|
||||
*/
|
||||
static int
|
||||
program_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *upstream)
|
||||
program_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
struct program_bidder *state = self->data;
|
||||
struct program_bidder *state = b->data;
|
||||
const char *p;
|
||||
|
||||
/* If we have a signature, use that to match. */
|
||||
if (state->signature_len > 0) {
|
||||
p = __archive_read_filter_ahead(upstream,
|
||||
p = __archive_read_filter_ahead(f,
|
||||
state->signature_len, NULL);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
@@ -226,36 +229,36 @@ program_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
* (including error message if the child came to a bad end).
|
||||
*/
|
||||
static int
|
||||
child_stop(struct archive_read_filter *self, struct program_filter *state)
|
||||
child_stop(struct archive_read_filter *f, struct program *program)
|
||||
{
|
||||
/* Close our side of the I/O with the child. */
|
||||
if (state->child_stdin != -1) {
|
||||
close(state->child_stdin);
|
||||
state->child_stdin = -1;
|
||||
if (program->child_stdin != -1) {
|
||||
close(program->child_stdin);
|
||||
program->child_stdin = -1;
|
||||
}
|
||||
if (state->child_stdout != -1) {
|
||||
close(state->child_stdout);
|
||||
state->child_stdout = -1;
|
||||
if (program->child_stdout != -1) {
|
||||
close(program->child_stdout);
|
||||
program->child_stdout = -1;
|
||||
}
|
||||
|
||||
if (state->child != 0) {
|
||||
if (program->child != 0) {
|
||||
/* Reap the child. */
|
||||
do {
|
||||
state->waitpid_return
|
||||
= waitpid(state->child, &state->exit_status, 0);
|
||||
} while (state->waitpid_return == -1 && errno == EINTR);
|
||||
state->child = 0;
|
||||
program->waitpid_return
|
||||
= waitpid(program->child, &program->exit_status, 0);
|
||||
} while (program->waitpid_return == -1 && errno == EINTR);
|
||||
program->child = 0;
|
||||
}
|
||||
|
||||
if (state->waitpid_return < 0) {
|
||||
if (program->waitpid_return < 0) {
|
||||
/* waitpid() failed? This is ugly. */
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Error closing child process");
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
if (WIFSIGNALED(state->exit_status)) {
|
||||
if (WIFSIGNALED(program->exit_status)) {
|
||||
#ifdef SIGPIPE
|
||||
/* If the child died because we stopped reading before
|
||||
* it was done, that's okay. Some archive formats
|
||||
@@ -263,24 +266,24 @@ child_stop(struct archive_read_filter *self, struct program_filter *state)
|
||||
/* The alternative to this would be to add a step
|
||||
* before close(child_stdout) above to read from the
|
||||
* child until the child has no more to write. */
|
||||
if (WTERMSIG(state->exit_status) == SIGPIPE)
|
||||
if (WTERMSIG(program->exit_status) == SIGPIPE)
|
||||
return (ARCHIVE_OK);
|
||||
#endif
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Child process exited with signal %d",
|
||||
WTERMSIG(state->exit_status));
|
||||
WTERMSIG(program->exit_status));
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
#endif /* !_WIN32 || __CYGWIN__ */
|
||||
|
||||
if (WIFEXITED(state->exit_status)) {
|
||||
if (WEXITSTATUS(state->exit_status) == 0)
|
||||
if (WIFEXITED(program->exit_status)) {
|
||||
if (WEXITSTATUS(program->exit_status) == 0)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Child process exited with status %d",
|
||||
WEXITSTATUS(state->exit_status));
|
||||
WEXITSTATUS(program->exit_status));
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
@@ -291,13 +294,13 @@ child_stop(struct archive_read_filter *self, struct program_filter *state)
|
||||
* Use select() to decide whether the child is ready for read or write.
|
||||
*/
|
||||
static ssize_t
|
||||
child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
|
||||
child_read(struct archive_read_filter *f, char *buf, size_t buf_len)
|
||||
{
|
||||
struct program_filter *state = self->data;
|
||||
struct program *program = f->data;
|
||||
ssize_t ret, requested, avail;
|
||||
const char *p;
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);
|
||||
HANDLE handle = (HANDLE)_get_osfhandle(program->child_stdout);
|
||||
#endif
|
||||
|
||||
requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
|
||||
@@ -325,7 +328,7 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
ret = read(state->child_stdout, buf, requested);
|
||||
ret = read(program->child_stdout, buf, requested);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret > 0)
|
||||
@@ -333,44 +336,44 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
|
||||
if (ret == 0 || (ret == -1 && errno == EPIPE))
|
||||
/* Child has closed its output; reap the child
|
||||
* and return the status. */
|
||||
return (child_stop(self, state));
|
||||
return (child_stop(f, program));
|
||||
if (ret == -1 && errno != EAGAIN)
|
||||
return (-1);
|
||||
|
||||
if (state->child_stdin == -1) {
|
||||
if (program->child_stdin == -1) {
|
||||
/* Block until child has some I/O ready. */
|
||||
__archive_check_child(state->child_stdin,
|
||||
state->child_stdout);
|
||||
__archive_check_child(program->child_stdin,
|
||||
program->child_stdout);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get some more data from upstream. */
|
||||
p = __archive_read_filter_ahead(self->upstream, 1, &avail);
|
||||
p = __archive_read_filter_ahead(f->upstream, 1, &avail);
|
||||
if (p == NULL) {
|
||||
close(state->child_stdin);
|
||||
state->child_stdin = -1;
|
||||
fcntl(state->child_stdout, F_SETFL, 0);
|
||||
close(program->child_stdin);
|
||||
program->child_stdin = -1;
|
||||
fcntl(program->child_stdout, F_SETFL, 0);
|
||||
if (avail < 0)
|
||||
return (avail);
|
||||
continue;
|
||||
}
|
||||
|
||||
do {
|
||||
ret = write(state->child_stdin, p, avail);
|
||||
ret = write(program->child_stdin, p, avail);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret > 0) {
|
||||
/* Consume whatever we managed to write. */
|
||||
__archive_read_filter_consume(self->upstream, ret);
|
||||
__archive_read_filter_consume(f->upstream, ret);
|
||||
} else if (ret == -1 && errno == EAGAIN) {
|
||||
/* Block until child has some I/O ready. */
|
||||
__archive_check_child(state->child_stdin,
|
||||
state->child_stdout);
|
||||
__archive_check_child(program->child_stdin,
|
||||
program->child_stdout);
|
||||
} else {
|
||||
/* Write failed. */
|
||||
close(state->child_stdin);
|
||||
state->child_stdin = -1;
|
||||
fcntl(state->child_stdout, F_SETFL, 0);
|
||||
close(program->child_stdin);
|
||||
program->child_stdin = -1;
|
||||
fcntl(program->child_stdout, F_SETFL, 0);
|
||||
/* If it was a bad error, we're done; otherwise
|
||||
* it was EPIPE or EOF, and we can still read
|
||||
* from the child. */
|
||||
@@ -387,9 +390,9 @@ program_reader_vtable = {
|
||||
};
|
||||
|
||||
int
|
||||
__archive_read_program(struct archive_read_filter *self, const char *cmd)
|
||||
__archive_read_program(struct archive_read_filter *f, const char *cmd)
|
||||
{
|
||||
struct program_filter *state;
|
||||
struct program *program;
|
||||
static const size_t out_buf_len = 65536;
|
||||
char *out_buf;
|
||||
const char *prefix = "Program: ";
|
||||
@@ -397,70 +400,71 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
|
||||
size_t l;
|
||||
|
||||
l = strlen(prefix) + strlen(cmd) + 1;
|
||||
state = calloc(1, sizeof(*state));
|
||||
program = calloc(1, sizeof(*program));
|
||||
out_buf = malloc(out_buf_len);
|
||||
if (state == NULL || out_buf == NULL ||
|
||||
archive_string_ensure(&state->description, l) == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
if (program == NULL || out_buf == NULL ||
|
||||
archive_string_ensure(&program->description, l) == NULL) {
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate input data");
|
||||
if (state != NULL) {
|
||||
archive_string_free(&state->description);
|
||||
free(state);
|
||||
if (program != NULL) {
|
||||
archive_string_free(&program->description);
|
||||
free(program);
|
||||
}
|
||||
free(out_buf);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_strcpy(&state->description, prefix);
|
||||
archive_strcat(&state->description, cmd);
|
||||
archive_strcpy(&program->description, prefix);
|
||||
archive_strcat(&program->description, cmd);
|
||||
|
||||
self->code = ARCHIVE_FILTER_PROGRAM;
|
||||
self->name = state->description.s;
|
||||
f->code = ARCHIVE_FILTER_PROGRAM;
|
||||
f->name = program->description.s;
|
||||
|
||||
state->out_buf = out_buf;
|
||||
state->out_buf_len = out_buf_len;
|
||||
program->out_buf = out_buf;
|
||||
program->out_buf_len = out_buf_len;
|
||||
|
||||
ret = __archive_create_child(cmd, &state->child_stdin,
|
||||
&state->child_stdout, &state->child);
|
||||
ret = __archive_create_child(cmd, &program->child_stdin,
|
||||
&program->child_stdout, &program->child);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
free(state->out_buf);
|
||||
archive_string_free(&state->description);
|
||||
free(state);
|
||||
archive_set_error(&self->archive->archive, EINVAL,
|
||||
free(program->out_buf);
|
||||
archive_string_free(&program->description);
|
||||
free(program);
|
||||
archive_set_error(&f->archive->archive, EINVAL,
|
||||
"Can't initialize filter; unable to run program \"%s\"",
|
||||
cmd);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
self->vtable = &program_reader_vtable;
|
||||
f->data = program;
|
||||
f->vtable = &program_reader_vtable;
|
||||
|
||||
/* XXX Check that we can read at least one byte? */
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
program_bidder_init(struct archive_read_filter *self)
|
||||
program_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct program_bidder *bidder_state;
|
||||
int r;
|
||||
|
||||
bidder_state = (struct program_bidder *)self->bidder->data;
|
||||
return (__archive_read_program(self, bidder_state->cmd));
|
||||
bidder_state = (struct program_bidder *)f->bidder->data;
|
||||
r = __archive_read_program(f, bidder_state->cmd);
|
||||
f->name = bidder_state->description.s;
|
||||
return (r);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
program_filter_read(struct archive_read_filter *self, const void **buff)
|
||||
program_filter_read(struct archive_read_filter *f, const void **buff)
|
||||
{
|
||||
struct program_filter *state;
|
||||
struct program *program = f->data;
|
||||
ssize_t bytes;
|
||||
size_t total;
|
||||
char *p;
|
||||
|
||||
state = (struct program_filter *)self->data;
|
||||
|
||||
total = 0;
|
||||
p = state->out_buf;
|
||||
while (state->child_stdout != -1 && total < state->out_buf_len) {
|
||||
bytes = child_read(self, p, state->out_buf_len - total);
|
||||
p = program->out_buf;
|
||||
while (program->child_stdout != -1 && total < program->out_buf_len) {
|
||||
bytes = child_read(f, p, program->out_buf_len - total);
|
||||
if (bytes < 0)
|
||||
/* No recovery is possible if we can no longer
|
||||
* read from the child. */
|
||||
@@ -472,23 +476,22 @@ program_filter_read(struct archive_read_filter *self, const void **buff)
|
||||
p += bytes;
|
||||
}
|
||||
|
||||
*buff = state->out_buf;
|
||||
*buff = program->out_buf;
|
||||
return (total);
|
||||
}
|
||||
|
||||
static int
|
||||
program_filter_close(struct archive_read_filter *self)
|
||||
program_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct program_filter *state;
|
||||
struct program *program = f->data;
|
||||
int e;
|
||||
|
||||
state = (struct program_filter *)self->data;
|
||||
e = child_stop(self, state);
|
||||
e = child_stop(f, program);
|
||||
|
||||
/* Release our private data. */
|
||||
free(state->out_buf);
|
||||
archive_string_free(&state->description);
|
||||
free(state);
|
||||
free(program->out_buf);
|
||||
archive_string_free(&program->description);
|
||||
free(program);
|
||||
|
||||
return (e);
|
||||
}
|
||||
|
||||
@@ -38,20 +38,7 @@
|
||||
#include "archive_read_private.h"
|
||||
|
||||
struct rpm {
|
||||
int64_t total_in;
|
||||
uint64_t hpos;
|
||||
uint64_t hlen;
|
||||
unsigned char header[16];
|
||||
enum {
|
||||
ST_LEAD, /* Skipping 'Lead' section. */
|
||||
ST_HEADER, /* Reading 'Header' section;
|
||||
* first 16 bytes. */
|
||||
ST_HEADER_DATA, /* Skipping 'Header' section. */
|
||||
ST_PADDING, /* Skipping padding data after the
|
||||
* 'Header' section. */
|
||||
ST_ARCHIVE /* Reading 'Archive' section. */
|
||||
} state;
|
||||
int first_header;
|
||||
int data_reached;
|
||||
};
|
||||
#define RPM_LEAD_SIZE 96 /* Size of 'Lead' section. */
|
||||
#define RPM_MIN_HEAD_SIZE 16 /* Minimum size of 'Head'. */
|
||||
@@ -64,8 +51,6 @@ static ssize_t rpm_filter_read(struct archive_read_filter *,
|
||||
const void **);
|
||||
static int rpm_filter_close(struct archive_read_filter *);
|
||||
|
||||
static inline size_t rpm_limit_bytes(uint64_t, size_t);
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Deprecated; remove in libarchive 4.0 */
|
||||
int
|
||||
@@ -91,39 +76,38 @@ archive_read_support_filter_rpm(struct archive *_a)
|
||||
}
|
||||
|
||||
static int
|
||||
rpm_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
rpm_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *b;
|
||||
ssize_t avail;
|
||||
const unsigned char *p;
|
||||
int bits_checked;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
b = __archive_read_filter_ahead(filter, 8, &avail);
|
||||
if (b == NULL)
|
||||
p = __archive_read_filter_ahead(f, 8, NULL);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
|
||||
bits_checked = 0;
|
||||
/*
|
||||
* Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
|
||||
*/
|
||||
if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
|
||||
if (memcmp(p, "\xED\xAB\xEE\xDB", 4) != 0)
|
||||
return (0);
|
||||
bits_checked += 32;
|
||||
/*
|
||||
* Check major version.
|
||||
*/
|
||||
if (b[4] != 3 && b[4] != 4)
|
||||
if (p[4] != 3 && p[4] != 4)
|
||||
return (0);
|
||||
bits_checked += 8;
|
||||
/*
|
||||
* Check package type; binary or source.
|
||||
*/
|
||||
if (b[6] != 0)
|
||||
if (p[6] != 0)
|
||||
return (0);
|
||||
bits_checked += 8;
|
||||
if (b[7] != 0 && b[7] != 1)
|
||||
if (p[7] != 0 && p[7] != 1)
|
||||
return (0);
|
||||
bits_checked += 8;
|
||||
|
||||
@@ -137,156 +121,127 @@ rpm_reader_vtable = {
|
||||
};
|
||||
|
||||
static int
|
||||
rpm_bidder_init(struct archive_read_filter *self)
|
||||
rpm_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct rpm *rpm;
|
||||
|
||||
self->code = ARCHIVE_FILTER_RPM;
|
||||
self->name = "rpm";
|
||||
f->code = ARCHIVE_FILTER_RPM;
|
||||
f->name = "rpm";
|
||||
|
||||
rpm = calloc(1, sizeof(*rpm));
|
||||
if (rpm == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for rpm");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = rpm;
|
||||
rpm->state = ST_LEAD;
|
||||
self->vtable = &rpm_reader_vtable;
|
||||
f->data = rpm;
|
||||
rpm->data_reached = 0;
|
||||
f->vtable = &rpm_reader_vtable;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
rpm_limit_bytes(uint64_t bytes, size_t max)
|
||||
static ssize_t
|
||||
skip_padding(struct archive_read_filter *f)
|
||||
{
|
||||
return (bytes > max ? max : (size_t)bytes);
|
||||
const unsigned char *h;
|
||||
ssize_t avail, count, r;
|
||||
|
||||
do {
|
||||
h = __archive_read_filter_ahead(f->upstream, 1, &avail);
|
||||
if (h == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
for (count = 0; count < avail && *h++ == '\0'; count++)
|
||||
;
|
||||
r = __archive_read_filter_consume(f->upstream, count);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
} while (count == avail);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
rpm_filter_read(struct archive_read_filter *self, const void **buff)
|
||||
skip_prologue(struct archive_read_filter *f)
|
||||
{
|
||||
struct rpm *rpm;
|
||||
const unsigned char *b;
|
||||
ssize_t avail_in, total, used;
|
||||
size_t n;
|
||||
uint64_t section;
|
||||
uint64_t bytes;
|
||||
const unsigned char *h;
|
||||
ssize_t r;
|
||||
int header, seen_header = 0;
|
||||
|
||||
/* Skip lead size. */
|
||||
r = __archive_read_filter_consume(f->upstream, RPM_LEAD_SIZE);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
|
||||
rpm = (struct rpm *)self->data;
|
||||
*buff = NULL;
|
||||
total = avail_in = 0;
|
||||
b = NULL;
|
||||
used = 0;
|
||||
do {
|
||||
if (b == NULL) {
|
||||
b = __archive_read_filter_ahead(self->upstream, 1,
|
||||
&avail_in);
|
||||
if (b == NULL) {
|
||||
if (avail_in < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Read header intro. */
|
||||
h = __archive_read_filter_ahead(f->upstream,
|
||||
RPM_MIN_HEAD_SIZE, NULL);
|
||||
if (h == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
switch (rpm->state) {
|
||||
case ST_LEAD:
|
||||
if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
|
||||
used += avail_in;
|
||||
else {
|
||||
n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
|
||||
used += n;
|
||||
b += n;
|
||||
rpm->state = ST_HEADER;
|
||||
rpm->hpos = 0;
|
||||
rpm->hlen = 0;
|
||||
rpm->first_header = 1;
|
||||
}
|
||||
break;
|
||||
case ST_HEADER:
|
||||
n = rpm_limit_bytes(RPM_MIN_HEAD_SIZE - rpm->hpos,
|
||||
avail_in - used);
|
||||
memcpy(rpm->header+rpm->hpos, b, n);
|
||||
b += n;
|
||||
used += n;
|
||||
rpm->hpos += n;
|
||||
header = (memcmp(h, "\x8E\xAD\xE8\x01", 4) == 0);
|
||||
if (header) {
|
||||
int64_t bytes, length, section;
|
||||
|
||||
if (rpm->hpos == RPM_MIN_HEAD_SIZE) {
|
||||
if (rpm->header[0] != 0x8e ||
|
||||
rpm->header[1] != 0xad ||
|
||||
rpm->header[2] != 0xe8 ||
|
||||
rpm->header[3] != 0x01) {
|
||||
if (rpm->first_header) {
|
||||
archive_set_error(
|
||||
&self->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unrecognized rpm header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rpm->state = ST_ARCHIVE;
|
||||
*buff = rpm->header;
|
||||
total = RPM_MIN_HEAD_SIZE;
|
||||
break;
|
||||
}
|
||||
/* Calculate 'Header' length. */
|
||||
section = archive_be32dec(rpm->header+8);
|
||||
bytes = archive_be32dec(rpm->header+12);
|
||||
rpm->hlen = rpm->hpos + section * 16 + bytes;
|
||||
rpm->state = ST_HEADER_DATA;
|
||||
rpm->first_header = 0;
|
||||
}
|
||||
break;
|
||||
case ST_HEADER_DATA:
|
||||
n = rpm_limit_bytes(rpm->hlen - rpm->hpos,
|
||||
avail_in - used);
|
||||
b += n;
|
||||
used += n;
|
||||
rpm->hpos += n;
|
||||
if (rpm->hpos == rpm->hlen)
|
||||
rpm->state = ST_PADDING;
|
||||
break;
|
||||
case ST_PADDING:
|
||||
while (used < avail_in) {
|
||||
if (*b != 0) {
|
||||
/* Read next header. */
|
||||
rpm->state = ST_HEADER;
|
||||
rpm->hpos = 0;
|
||||
rpm->hlen = 0;
|
||||
break;
|
||||
}
|
||||
b++;
|
||||
used++;
|
||||
}
|
||||
break;
|
||||
case ST_ARCHIVE:
|
||||
*buff = b;
|
||||
total = avail_in;
|
||||
used = avail_in;
|
||||
break;
|
||||
}
|
||||
if (used == avail_in) {
|
||||
rpm->total_in += used;
|
||||
__archive_read_filter_consume(self->upstream, used);
|
||||
b = NULL;
|
||||
used = 0;
|
||||
}
|
||||
} while (total == 0 && avail_in > 0);
|
||||
seen_header = 1;
|
||||
|
||||
if (used > 0 && b != NULL) {
|
||||
rpm->total_in += used;
|
||||
__archive_read_filter_consume(self->upstream, used);
|
||||
/* Calculate header length. */
|
||||
section = archive_be32dec(h + 8);
|
||||
bytes = archive_be32dec(h + 12);
|
||||
length = RPM_MIN_HEAD_SIZE + section * 16 + bytes;
|
||||
|
||||
/* Skip header. */
|
||||
r = __archive_read_filter_consume(f->upstream,
|
||||
length);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
|
||||
/* Skip padding. */
|
||||
r = skip_padding(f);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
}
|
||||
} while (header);
|
||||
|
||||
/* At least one header must have been encountered. */
|
||||
if (!seen_header) {
|
||||
archive_set_error(
|
||||
&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unrecognized rpm header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (total);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
rpm_filter_read(struct archive_read_filter *f, const void **buff)
|
||||
{
|
||||
struct rpm *rpm = f->data;
|
||||
ssize_t r;
|
||||
|
||||
if (!rpm->data_reached) {
|
||||
r = skip_prologue(f);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
rpm->data_reached = 1;
|
||||
}
|
||||
|
||||
*buff = __archive_read_filter_ahead(f->upstream, 1, &r);
|
||||
if (r > 0)
|
||||
__archive_read_filter_consume(f->upstream, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
rpm_filter_close(struct archive_read_filter *self)
|
||||
rpm_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct rpm *rpm;
|
||||
struct rpm *rpm = f->data;
|
||||
|
||||
rpm = (struct rpm *)self->data;
|
||||
free(rpm);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
@@ -47,9 +47,7 @@
|
||||
/* Maximum lookahead during bid phase */
|
||||
#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
|
||||
|
||||
#define UUENCODE_MAX_LINE_LENGTH 34*1024 /* in bytes */
|
||||
|
||||
struct uudecode {
|
||||
struct uu {
|
||||
int64_t total;
|
||||
unsigned char *in_buff;
|
||||
#define IN_BUFF_SIZE (1024)
|
||||
@@ -69,7 +67,7 @@ struct uudecode {
|
||||
};
|
||||
|
||||
static int uudecode_bidder_bid(struct archive_read_filter_bidder *,
|
||||
struct archive_read_filter *filter);
|
||||
struct archive_read_filter *f);
|
||||
static int uudecode_bidder_init(struct archive_read_filter *);
|
||||
|
||||
static int uudecode_read_header(struct archive_read_filter *,
|
||||
@@ -213,7 +211,7 @@ get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
bid_get_line(struct archive_read_filter *filter,
|
||||
bid_get_line(struct archive_read_filter *f,
|
||||
const unsigned char **b, ssize_t *avail, ssize_t *ravail,
|
||||
ssize_t *nl, size_t* nbytes_read)
|
||||
{
|
||||
@@ -228,7 +226,7 @@ bid_get_line(struct archive_read_filter *filter,
|
||||
len = get_line(*b, *avail, nl);
|
||||
|
||||
/*
|
||||
* Read bytes more while it does not reach the end of line.
|
||||
* Read more bytes while it does not reach the end of line.
|
||||
*/
|
||||
while (*nl == 0 && len == *avail && !quit &&
|
||||
*nbytes_read < UUENCODE_BID_MAX_READ) {
|
||||
@@ -241,12 +239,12 @@ bid_get_line(struct archive_read_filter *filter,
|
||||
if (nbytes_req < (size_t)*ravail + 160)
|
||||
nbytes_req <<= 1;
|
||||
|
||||
*b = __archive_read_filter_ahead(filter, nbytes_req, avail);
|
||||
*b = __archive_read_filter_ahead(f, nbytes_req, avail);
|
||||
if (*b == NULL) {
|
||||
if (*ravail >= *avail)
|
||||
return (0);
|
||||
/* Reading bytes reaches the end of a stream. */
|
||||
*b = __archive_read_filter_ahead(filter, *avail, avail);
|
||||
*b = __archive_read_filter_ahead(f, *avail, avail);
|
||||
quit = 1;
|
||||
}
|
||||
*nbytes_read = *avail;
|
||||
@@ -264,42 +262,42 @@ bid_get_line(struct archive_read_filter *filter,
|
||||
#define UUDECODE(c) (((c) - 0x20) & 0x3f)
|
||||
|
||||
static int
|
||||
uudecode_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
uudecode_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *b;
|
||||
const unsigned char *p;
|
||||
ssize_t avail, ravail;
|
||||
ssize_t len, nl;
|
||||
int l;
|
||||
int firstline;
|
||||
size_t nbytes_read;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
b = __archive_read_filter_ahead(filter, 1, &avail);
|
||||
if (b == NULL)
|
||||
p = __archive_read_filter_ahead(f, 1, &avail);
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
|
||||
firstline = 20;
|
||||
ravail = avail;
|
||||
nbytes_read = avail;
|
||||
for (;;) {
|
||||
len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
|
||||
len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read);
|
||||
if (len < 0 || nl == 0)
|
||||
return (0); /* No match found. */
|
||||
if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
|
||||
if (len - nl >= 11 && memcmp(p, "begin ", 6) == 0)
|
||||
l = 6;
|
||||
else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)
|
||||
else if (len -nl >= 18 && memcmp(p, "begin-base64 ", 13) == 0)
|
||||
l = 13;
|
||||
else
|
||||
l = 0;
|
||||
|
||||
if (l > 0 && (b[l] < '0' || b[l] > '7' ||
|
||||
b[l+1] < '0' || b[l+1] > '7' ||
|
||||
b[l+2] < '0' || b[l+2] > '7' || b[l+3] != ' '))
|
||||
if (l > 0 && (p[l] < '0' || p[l] > '7' ||
|
||||
p[l+1] < '0' || p[l+1] > '7' ||
|
||||
p[l+2] < '0' || p[l+2] > '7' || p[l+3] != ' '))
|
||||
l = 0;
|
||||
|
||||
b += len;
|
||||
p += len;
|
||||
avail -= len;
|
||||
if (l)
|
||||
break;
|
||||
@@ -311,51 +309,51 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
}
|
||||
if (!avail)
|
||||
return (0);
|
||||
len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
|
||||
len = bid_get_line(f, &p, &avail, &ravail, &nl, &nbytes_read);
|
||||
if (len < 0 || nl == 0)
|
||||
return (0);/* There are non-ascii characters. */
|
||||
avail -= len;
|
||||
|
||||
if (l == 6) {
|
||||
/* "begin " */
|
||||
if (!uuchar[*b])
|
||||
if (!uuchar[*p])
|
||||
return (0);
|
||||
/* Get a length of decoded bytes. */
|
||||
l = UUDECODE(*b++); len--;
|
||||
l = UUDECODE(*p++); len--;
|
||||
if (l > 45)
|
||||
/* Normally, maximum length is 45(character 'M'). */
|
||||
return (0);
|
||||
if (l > len - nl)
|
||||
return (0); /* Line too short. */
|
||||
while (l) {
|
||||
if (!uuchar[*b++])
|
||||
if (!uuchar[*p++])
|
||||
return (0);
|
||||
--len;
|
||||
--l;
|
||||
}
|
||||
if (len-nl == 1 &&
|
||||
(uuchar[*b] || /* Check sum. */
|
||||
(*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
|
||||
++b;
|
||||
(uuchar[*p] || /* Check sum. */
|
||||
(*p >= 'a' && *p <= 'z'))) {/* Padding data(MINIX). */
|
||||
++p;
|
||||
--len;
|
||||
}
|
||||
b += nl;
|
||||
if (avail && uuchar[*b])
|
||||
p += nl;
|
||||
if (avail && uuchar[*p])
|
||||
return (firstline+30);
|
||||
} else if (l == 13) {
|
||||
/* "begin-base64 " */
|
||||
while (len-nl > 0) {
|
||||
if (!base64[*b++])
|
||||
if (!base64[*p++])
|
||||
return (0);
|
||||
--len;
|
||||
}
|
||||
b += nl;
|
||||
p += nl;
|
||||
|
||||
if (avail >= 5 && memcmp(b, "====\n", 5) == 0)
|
||||
if (avail >= 5 && memcmp(p, "====\n", 5) == 0)
|
||||
return (firstline+40);
|
||||
if (avail >= 6 && memcmp(b, "====\r\n", 6) == 0)
|
||||
if (avail >= 6 && memcmp(p, "====\r\n", 6) == 0)
|
||||
return (firstline+40);
|
||||
if (avail > 0 && base64[*b])
|
||||
if (avail > 0 && base64[*p])
|
||||
return (firstline+30);
|
||||
}
|
||||
|
||||
@@ -370,46 +368,46 @@ uudecode_reader_vtable = {
|
||||
};
|
||||
|
||||
static int
|
||||
uudecode_bidder_init(struct archive_read_filter *self)
|
||||
uudecode_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct uudecode *uudecode;
|
||||
struct uu *uu;
|
||||
void *out_buff;
|
||||
void *in_buff;
|
||||
|
||||
self->code = ARCHIVE_FILTER_UU;
|
||||
self->name = "uu";
|
||||
f->code = ARCHIVE_FILTER_UU;
|
||||
f->name = "uu";
|
||||
|
||||
uudecode = calloc(1, sizeof(*uudecode));
|
||||
uu = calloc(1, sizeof(*uu));
|
||||
out_buff = malloc(OUT_BUFF_SIZE);
|
||||
in_buff = malloc(IN_BUFF_SIZE);
|
||||
if (uudecode == NULL || out_buff == NULL || in_buff == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
if (uu == NULL || out_buff == NULL || in_buff == NULL) {
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for uudecode");
|
||||
free(uudecode);
|
||||
free(uu);
|
||||
free(out_buff);
|
||||
free(in_buff);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = uudecode;
|
||||
uudecode->in_buff = in_buff;
|
||||
uudecode->in_cnt = 0;
|
||||
uudecode->in_allocated = IN_BUFF_SIZE;
|
||||
uudecode->out_buff = out_buff;
|
||||
uudecode->state = ST_FIND_HEAD;
|
||||
uudecode->mode_set = 0;
|
||||
uudecode->name = NULL;
|
||||
self->vtable = &uudecode_reader_vtable;
|
||||
f->data = uu;
|
||||
uu->in_buff = in_buff;
|
||||
uu->in_cnt = 0;
|
||||
uu->in_allocated = IN_BUFF_SIZE;
|
||||
uu->out_buff = out_buff;
|
||||
uu->state = ST_FIND_HEAD;
|
||||
uu->mode_set = 0;
|
||||
uu->name = NULL;
|
||||
f->vtable = &uudecode_reader_vtable;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
ensure_in_buff_size(struct archive_read_filter *self,
|
||||
struct uudecode *uudecode, size_t size)
|
||||
ensure_in_buff_size(struct archive_read_filter *f,
|
||||
struct uu *uu, size_t size)
|
||||
{
|
||||
|
||||
if (size > uudecode->in_allocated) {
|
||||
if (size > uu->in_allocated) {
|
||||
unsigned char *ptr;
|
||||
size_t newsize;
|
||||
|
||||
@@ -417,7 +415,7 @@ ensure_in_buff_size(struct archive_read_filter *self,
|
||||
* Calculate a new buffer size for in_buff.
|
||||
* Increase its value until it is enough for our needs.
|
||||
*/
|
||||
newsize = uudecode->in_allocated;
|
||||
newsize = uu->in_allocated;
|
||||
do {
|
||||
if (newsize < IN_BUFF_SIZE*32)
|
||||
newsize <<= 1;
|
||||
@@ -427,43 +425,40 @@ ensure_in_buff_size(struct archive_read_filter *self,
|
||||
/* Allocate the new buffer. */
|
||||
ptr = malloc(newsize);
|
||||
if (ptr == NULL) {
|
||||
free(ptr);
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ENOMEM,
|
||||
"Can't allocate data for uudecode");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/* Move the remaining data in in_buff into the new buffer. */
|
||||
if (uudecode->in_cnt)
|
||||
memmove(ptr, uudecode->in_buff, uudecode->in_cnt);
|
||||
if (uu->in_cnt)
|
||||
memmove(ptr, uu->in_buff, uu->in_cnt);
|
||||
/* Replace in_buff with the new buffer. */
|
||||
free(uudecode->in_buff);
|
||||
uudecode->in_buff = ptr;
|
||||
uudecode->in_allocated = newsize;
|
||||
free(uu->in_buff);
|
||||
uu->in_buff = ptr;
|
||||
uu->in_allocated = newsize;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
uudecode_read_header(struct archive_read_filter *self, struct archive_entry *entry)
|
||||
uudecode_read_header(struct archive_read_filter *f, struct archive_entry *entry)
|
||||
{
|
||||
struct uu *uu = f->data;
|
||||
|
||||
struct uudecode *uudecode;
|
||||
uudecode = (struct uudecode *)self->data;
|
||||
if (uu->mode_set != 0)
|
||||
archive_entry_set_mode(entry, S_IFREG | uu->mode);
|
||||
|
||||
if (uudecode->mode_set != 0)
|
||||
archive_entry_set_mode(entry, S_IFREG | uudecode->mode);
|
||||
|
||||
if (uudecode->name != NULL)
|
||||
archive_entry_set_pathname(entry, uudecode->name);
|
||||
if (uu->name != NULL)
|
||||
archive_entry_set_pathname(entry, uu->name);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
uudecode_filter_read(struct archive_read_filter *self, const void **buff)
|
||||
uudecode_filter_read(struct archive_read_filter *f, const void **buff)
|
||||
{
|
||||
struct uudecode *uudecode;
|
||||
struct uu *uu = f->data;
|
||||
const unsigned char *b, *d;
|
||||
unsigned char *out;
|
||||
ssize_t avail_in, ravail;
|
||||
@@ -471,10 +466,8 @@ uudecode_filter_read(struct archive_read_filter *self, const void **buff)
|
||||
ssize_t total;
|
||||
ssize_t len, llen, nl, namelen;
|
||||
|
||||
uudecode = (struct uudecode *)self->data;
|
||||
|
||||
read_more:
|
||||
d = __archive_read_filter_ahead(self->upstream, 1, &avail_in);
|
||||
d = __archive_read_filter_ahead(f->upstream, 1, &avail_in);
|
||||
if (d == NULL && avail_in < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
/* Quiet a code analyzer; make sure avail_in must be zero
|
||||
@@ -483,15 +476,17 @@ read_more:
|
||||
avail_in = 0;
|
||||
used = 0;
|
||||
total = 0;
|
||||
out = uudecode->out_buff;
|
||||
out = uu->out_buff;
|
||||
if (avail_in > 2 * UUENCODE_BID_MAX_READ)
|
||||
avail_in = 2 * UUENCODE_BID_MAX_READ;
|
||||
ravail = avail_in;
|
||||
if (uudecode->state == ST_IGNORE) {
|
||||
if (uu->state == ST_IGNORE) {
|
||||
used = avail_in;
|
||||
goto finish;
|
||||
}
|
||||
if (uudecode->in_cnt) {
|
||||
if (uudecode->in_cnt > UUENCODE_MAX_LINE_LENGTH) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
if (uu->in_cnt) {
|
||||
if (uu->in_cnt > UUENCODE_BID_MAX_READ) {
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid format data");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -500,17 +495,18 @@ read_more:
|
||||
* If there is remaining data which is saved by
|
||||
* a previous call, use it first.
|
||||
*/
|
||||
if (ensure_in_buff_size(self, uudecode,
|
||||
avail_in + uudecode->in_cnt) != ARCHIVE_OK)
|
||||
if (ensure_in_buff_size(f, uu,
|
||||
avail_in + uu->in_cnt) != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
#ifdef __clang_analyzer__
|
||||
assert(d);
|
||||
#endif
|
||||
memcpy(uudecode->in_buff + uudecode->in_cnt,
|
||||
d, avail_in);
|
||||
d = uudecode->in_buff;
|
||||
avail_in += uudecode->in_cnt;
|
||||
uudecode->in_cnt = 0;
|
||||
if (avail_in > 0)
|
||||
memcpy(uu->in_buff + uu->in_cnt,
|
||||
d, avail_in);
|
||||
d = uu->in_buff;
|
||||
avail_in += uu->in_cnt;
|
||||
uu->in_cnt = 0;
|
||||
}
|
||||
for (;used < avail_in; d += llen, used += llen) {
|
||||
ssize_t l, body;
|
||||
@@ -519,22 +515,28 @@ read_more:
|
||||
len = get_line(b, avail_in - used, &nl);
|
||||
if (len < 0) {
|
||||
/* Non-ascii character is found. */
|
||||
if (uudecode->state == ST_FIND_HEAD &&
|
||||
(uudecode->total > 0 || total > 0)) {
|
||||
uudecode->state = ST_IGNORE;
|
||||
if (uu->state == ST_FIND_HEAD &&
|
||||
(uu->total > 0 || total > 0)) {
|
||||
uu->state = ST_IGNORE;
|
||||
used = avail_in;
|
||||
goto finish;
|
||||
}
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Insufficient compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (len > UUENCODE_BID_MAX_READ) {
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid format data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
llen = len;
|
||||
if ((nl == 0) && (uudecode->state != ST_UUEND)) {
|
||||
if ((nl == 0) && (uu->state != ST_UUEND)) {
|
||||
if (total == 0 && ravail <= 0) {
|
||||
/* There is nothing more to read, fail */
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Missing format data");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -543,28 +545,28 @@ read_more:
|
||||
* Save remaining data which does not contain
|
||||
* NL('\n','\r').
|
||||
*/
|
||||
if (ensure_in_buff_size(self, uudecode, len)
|
||||
if (ensure_in_buff_size(f, uu, len)
|
||||
!= ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (uudecode->in_buff != b)
|
||||
memmove(uudecode->in_buff, b, len);
|
||||
uudecode->in_cnt = len;
|
||||
if (uu->in_buff != b)
|
||||
memmove(uu->in_buff, b, len);
|
||||
uu->in_cnt = len;
|
||||
if (total == 0) {
|
||||
/* Do not return 0; it means end-of-file.
|
||||
* We should try to read bytes more. */
|
||||
* We should try to read more bytes. */
|
||||
__archive_read_filter_consume(
|
||||
self->upstream, ravail);
|
||||
f->upstream, ravail);
|
||||
goto read_more;
|
||||
}
|
||||
used += len;
|
||||
break;
|
||||
}
|
||||
switch (uudecode->state) {
|
||||
switch (uu->state) {
|
||||
default:
|
||||
case ST_FIND_HEAD:
|
||||
/* Do not read more than UUENCODE_BID_MAX_READ bytes */
|
||||
if (total + len >= UUENCODE_BID_MAX_READ) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid format data");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -580,30 +582,30 @@ read_more:
|
||||
b[l+1] >= '0' && b[l+1] <= '7' &&
|
||||
b[l+2] >= '0' && b[l+2] <= '7' && b[l+3] == ' ') {
|
||||
if (l == 6)
|
||||
uudecode->state = ST_READ_UU;
|
||||
uu->state = ST_READ_UU;
|
||||
else
|
||||
uudecode->state = ST_READ_BASE64;
|
||||
uudecode->mode = (mode_t)(
|
||||
uu->state = ST_READ_BASE64;
|
||||
uu->mode = (mode_t)(
|
||||
((int)(b[l] - '0') * 64) +
|
||||
((int)(b[l+1] - '0') * 8) +
|
||||
(int)(b[l+2] - '0'));
|
||||
uudecode->mode_set = 1;
|
||||
uu->mode_set = 1;
|
||||
namelen = len - nl - 4 - l;
|
||||
if (namelen > 1) {
|
||||
if (uudecode->name != NULL)
|
||||
free(uudecode->name);
|
||||
uudecode->name = malloc(namelen + 1);
|
||||
if (uudecode->name == NULL) {
|
||||
archive_set_error(
|
||||
&self->archive->archive,
|
||||
ENOMEM,
|
||||
"Can't allocate data for uudecode");
|
||||
if (uu->name != NULL)
|
||||
free(uu->name);
|
||||
uu->name = malloc(namelen + 1);
|
||||
if (uu->name == NULL) {
|
||||
archive_set_error(
|
||||
&f->archive->archive,
|
||||
ENOMEM,
|
||||
"Can't allocate data for uudecode");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
strncpy(uudecode->name,
|
||||
strncpy(uu->name,
|
||||
(const char *)(b + l + 4),
|
||||
namelen);
|
||||
uudecode->name[namelen] = '\0';
|
||||
uu->name[namelen] = '\0';
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -612,7 +614,7 @@ read_more:
|
||||
goto finish;
|
||||
body = len - nl;
|
||||
if (!uuchar[*b] || body <= 0) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Insufficient compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -621,13 +623,13 @@ read_more:
|
||||
l = UUDECODE(*b++);
|
||||
body--;
|
||||
if (l > body) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Insufficient compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (l == 0) {
|
||||
uudecode->state = ST_UUEND;
|
||||
uu->state = ST_UUEND;
|
||||
break;
|
||||
}
|
||||
while (l > 0) {
|
||||
@@ -656,7 +658,7 @@ read_more:
|
||||
}
|
||||
}
|
||||
if (l) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Insufficient compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -664,9 +666,9 @@ read_more:
|
||||
break;
|
||||
case ST_UUEND:
|
||||
if (len - nl == 3 && memcmp(b, "end ", 3) == 0)
|
||||
uudecode->state = ST_FIND_HEAD;
|
||||
uu->state = ST_FIND_HEAD;
|
||||
else {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Insufficient compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -678,7 +680,7 @@ read_more:
|
||||
l = len - nl;
|
||||
if (l >= 3 && b[0] == '=' && b[1] == '=' &&
|
||||
b[2] == '=') {
|
||||
uudecode->state = ST_FIND_HEAD;
|
||||
uu->state = ST_FIND_HEAD;
|
||||
break;
|
||||
}
|
||||
while (l > 0) {
|
||||
@@ -711,7 +713,7 @@ read_more:
|
||||
}
|
||||
}
|
||||
if (l && *b != '=') {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Insufficient compressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -722,23 +724,22 @@ read_more:
|
||||
finish:
|
||||
if (ravail < avail_in)
|
||||
used -= avail_in - ravail;
|
||||
__archive_read_filter_consume(self->upstream, used);
|
||||
__archive_read_filter_consume(f->upstream, used);
|
||||
|
||||
*buff = uudecode->out_buff;
|
||||
uudecode->total += total;
|
||||
*buff = uu->out_buff;
|
||||
uu->total += total;
|
||||
return (total);
|
||||
}
|
||||
|
||||
static int
|
||||
uudecode_filter_close(struct archive_read_filter *self)
|
||||
uudecode_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct uudecode *uudecode;
|
||||
struct uu *uu = f->data;
|
||||
|
||||
uudecode = (struct uudecode *)self->data;
|
||||
free(uudecode->in_buff);
|
||||
free(uudecode->out_buff);
|
||||
free(uudecode->name);
|
||||
free(uudecode);
|
||||
free(uu->in_buff);
|
||||
free(uu->out_buff);
|
||||
free(uu->name);
|
||||
free(uu);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -50,11 +50,10 @@
|
||||
|
||||
#if HAVE_LZMA_H && HAVE_LIBLZMA
|
||||
|
||||
struct private_data {
|
||||
struct xz {
|
||||
lzma_stream stream;
|
||||
unsigned char *out_block;
|
||||
size_t out_block_size;
|
||||
int64_t total_out;
|
||||
char eof; /* True = found end of compressed data. */
|
||||
char in_stream;
|
||||
|
||||
@@ -83,8 +82,7 @@ static int xz_lzma_bidder_init(struct archive_read_filter *);
|
||||
/*
|
||||
* Note that we can detect xz and lzma compressed files even if we
|
||||
* can't decompress them. (In fact, we like detecting them because we
|
||||
* can give better error messages.) So the bid framework here gets
|
||||
* compiled even if no lzma library is available.
|
||||
* can give better error messages.)
|
||||
*/
|
||||
static int xz_bidder_bid(struct archive_read_filter_bidder *,
|
||||
struct archive_read_filter *);
|
||||
@@ -199,15 +197,14 @@ archive_read_support_filter_lzip(struct archive *_a)
|
||||
* Test whether we can handle this data.
|
||||
*/
|
||||
static int
|
||||
xz_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
xz_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
ssize_t avail;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
buffer = __archive_read_filter_ahead(filter, 6, &avail);
|
||||
buffer = __archive_read_filter_ahead(f, 6, NULL);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
|
||||
@@ -233,18 +230,17 @@ xz_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
* they have other evidence (file name, command-line option) to go on.
|
||||
*/
|
||||
static int
|
||||
lzma_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
lzma_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
ssize_t avail;
|
||||
uint32_t dicsize;
|
||||
uint64_t uncompressed_size;
|
||||
int bits_checked;
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
(void)b; /* UNUSED */
|
||||
|
||||
buffer = __archive_read_filter_ahead(filter, 14, &avail);
|
||||
buffer = __archive_read_filter_ahead(f, 14, NULL);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
|
||||
@@ -340,14 +336,13 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
}
|
||||
|
||||
static int
|
||||
lzip_has_member(struct archive_read_filter *filter)
|
||||
lzip_has_member(struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
ssize_t avail;
|
||||
int bits_checked;
|
||||
int log2dic;
|
||||
|
||||
buffer = __archive_read_filter_ahead(filter, 6, &avail);
|
||||
buffer = __archive_read_filter_ahead(f, 6, NULL);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
|
||||
@@ -374,12 +369,12 @@ lzip_has_member(struct archive_read_filter *filter)
|
||||
}
|
||||
|
||||
static int
|
||||
lzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
lzip_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
|
||||
(void)self; /* UNUSED */
|
||||
return (lzip_has_member(filter));
|
||||
(void)b; /* UNUSED */
|
||||
return (lzip_has_member(f));
|
||||
}
|
||||
|
||||
#if HAVE_LZMA_H && HAVE_LIBLZMA
|
||||
@@ -388,34 +383,34 @@ lzip_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
* liblzma 4.999.7 and later support both lzma and xz streams.
|
||||
*/
|
||||
static int
|
||||
xz_bidder_init(struct archive_read_filter *self)
|
||||
xz_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
self->code = ARCHIVE_FILTER_XZ;
|
||||
self->name = "xz";
|
||||
return (xz_lzma_bidder_init(self));
|
||||
f->code = ARCHIVE_FILTER_XZ;
|
||||
f->name = "xz";
|
||||
return (xz_lzma_bidder_init(f));
|
||||
}
|
||||
|
||||
static int
|
||||
lzma_bidder_init(struct archive_read_filter *self)
|
||||
lzma_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
self->code = ARCHIVE_FILTER_LZMA;
|
||||
self->name = "lzma";
|
||||
return (xz_lzma_bidder_init(self));
|
||||
f->code = ARCHIVE_FILTER_LZMA;
|
||||
f->name = "lzma";
|
||||
return (xz_lzma_bidder_init(f));
|
||||
}
|
||||
|
||||
static int
|
||||
lzip_bidder_init(struct archive_read_filter *self)
|
||||
lzip_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
self->code = ARCHIVE_FILTER_LZIP;
|
||||
self->name = "lzip";
|
||||
return (xz_lzma_bidder_init(self));
|
||||
f->code = ARCHIVE_FILTER_LZIP;
|
||||
f->name = "lzip";
|
||||
return (xz_lzma_bidder_init(f));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set an error code and choose an error message
|
||||
*/
|
||||
static void
|
||||
set_error(struct archive_read_filter *self, int ret)
|
||||
set_error(struct archive_read_filter *f, int ret)
|
||||
{
|
||||
|
||||
switch (ret) {
|
||||
@@ -423,36 +418,36 @@ set_error(struct archive_read_filter *self, int ret)
|
||||
case LZMA_OK: /* Decompressor made some progress. */
|
||||
break;
|
||||
case LZMA_MEM_ERROR:
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Lzma library error: Cannot allocate memory");
|
||||
break;
|
||||
case LZMA_MEMLIMIT_ERROR:
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Lzma library error: Out of memory");
|
||||
break;
|
||||
case LZMA_FORMAT_ERROR:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Lzma library error: format not recognized");
|
||||
break;
|
||||
case LZMA_OPTIONS_ERROR:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Lzma library error: Invalid options");
|
||||
break;
|
||||
case LZMA_DATA_ERROR:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Lzma library error: Corrupted input data");
|
||||
break;
|
||||
case LZMA_BUF_ERROR:
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Lzma library error: No progress is possible");
|
||||
break;
|
||||
default:
|
||||
/* Return an error. */
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Lzma decompression failed: Unknown error");
|
||||
break;
|
||||
@@ -469,84 +464,83 @@ xz_lzma_reader_vtable = {
|
||||
* Setup the callbacks.
|
||||
*/
|
||||
static int
|
||||
xz_lzma_bidder_init(struct archive_read_filter *self)
|
||||
xz_lzma_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
static const size_t out_block_size = 64 * 1024;
|
||||
void *out_block;
|
||||
struct private_data *state;
|
||||
struct xz *xz;
|
||||
int ret;
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
xz = calloc(1, sizeof(*xz));
|
||||
out_block = malloc(out_block_size);
|
||||
if (state == NULL || out_block == NULL) {
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
if (xz == NULL || out_block == NULL) {
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for xz decompression");
|
||||
free(out_block);
|
||||
free(state);
|
||||
free(xz);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
state->out_block_size = out_block_size;
|
||||
state->out_block = out_block;
|
||||
self->vtable = &xz_lzma_reader_vtable;
|
||||
f->data = xz;
|
||||
xz->out_block_size = out_block_size;
|
||||
xz->out_block = out_block;
|
||||
f->vtable = &xz_lzma_reader_vtable;
|
||||
|
||||
state->stream.avail_in = 0;
|
||||
xz->stream.avail_in = 0;
|
||||
|
||||
state->stream.next_out = state->out_block;
|
||||
state->stream.avail_out = state->out_block_size;
|
||||
xz->stream.next_out = xz->out_block;
|
||||
xz->stream.avail_out = xz->out_block_size;
|
||||
|
||||
state->crc32 = 0;
|
||||
if (self->code == ARCHIVE_FILTER_LZIP) {
|
||||
xz->crc32 = 0;
|
||||
if (f->code == ARCHIVE_FILTER_LZIP) {
|
||||
/*
|
||||
* We have to read a lzip header and use it to initialize
|
||||
* compression library, thus we cannot initialize the
|
||||
* library for lzip here.
|
||||
*/
|
||||
state->in_stream = 0;
|
||||
xz->in_stream = 0;
|
||||
return (ARCHIVE_OK);
|
||||
} else
|
||||
state->in_stream = 1;
|
||||
xz->in_stream = 1;
|
||||
|
||||
/* Initialize compression library. */
|
||||
if (self->code == ARCHIVE_FILTER_XZ)
|
||||
ret = lzma_stream_decoder(&(state->stream),
|
||||
if (f->code == ARCHIVE_FILTER_XZ)
|
||||
ret = lzma_stream_decoder(&(xz->stream),
|
||||
LZMA_MEMLIMIT,/* memlimit */
|
||||
LZMA_CONCATENATED);
|
||||
else
|
||||
ret = lzma_alone_decoder(&(state->stream),
|
||||
ret = lzma_alone_decoder(&(xz->stream),
|
||||
LZMA_MEMLIMIT);/* memlimit */
|
||||
|
||||
if (ret == LZMA_OK)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
/* Library setup failed: Choose an error message and clean up. */
|
||||
set_error(self, ret);
|
||||
set_error(f, ret);
|
||||
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
self->data = NULL;
|
||||
free(xz->out_block);
|
||||
free(xz);
|
||||
f->data = NULL;
|
||||
f->vtable = NULL;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
lzip_init(struct archive_read_filter *self)
|
||||
lzip_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct xz *xz = f->data;
|
||||
const unsigned char *h;
|
||||
lzma_filter filters[2];
|
||||
unsigned char props[5];
|
||||
ssize_t avail_in;
|
||||
uint32_t dicsize;
|
||||
int log2dic, ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
h = __archive_read_filter_ahead(self->upstream, 6, &avail_in);
|
||||
h = __archive_read_filter_ahead(f->upstream, 6, NULL);
|
||||
if (h == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
/* Get a version number. */
|
||||
state->lzip_ver = h[4];
|
||||
xz->lzip_ver = h[4];
|
||||
|
||||
/*
|
||||
* Setup lzma property.
|
||||
@@ -563,8 +557,8 @@ lzip_init(struct archive_read_filter *self)
|
||||
archive_le32enc(props+1, dicsize);
|
||||
|
||||
/* Consume lzip header. */
|
||||
__archive_read_filter_consume(self->upstream, 6);
|
||||
state->member_in = 6;
|
||||
__archive_read_filter_consume(f->upstream, 6);
|
||||
xz->member_in = 6;
|
||||
|
||||
filters[0].id = LZMA_FILTER_LZMA1;
|
||||
filters[0].options = NULL;
|
||||
@@ -573,74 +567,73 @@ lzip_init(struct archive_read_filter *self)
|
||||
|
||||
ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props));
|
||||
if (ret != LZMA_OK) {
|
||||
set_error(self, ret);
|
||||
set_error(f, ret);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
ret = lzma_raw_decoder(&(state->stream), filters);
|
||||
ret = lzma_raw_decoder(&(xz->stream), filters);
|
||||
free(filters[0].options);
|
||||
if (ret != LZMA_OK) {
|
||||
set_error(self, ret);
|
||||
set_error(f, ret);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
lzip_tail(struct archive_read_filter *self)
|
||||
lzip_tail(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
const unsigned char *f;
|
||||
struct xz *xz = f->data;
|
||||
const unsigned char *p;
|
||||
ssize_t avail_in;
|
||||
int tail;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
if (state->lzip_ver == 0)
|
||||
if (xz->lzip_ver == 0)
|
||||
tail = 12;
|
||||
else
|
||||
tail = 20;
|
||||
f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);
|
||||
if (f == NULL && avail_in < 0)
|
||||
p = __archive_read_filter_ahead(f->upstream, tail, &avail_in);
|
||||
if (p == NULL && avail_in < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (f == NULL || avail_in < tail) {
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
if (p == NULL || avail_in < tail) {
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Lzip: Remaining data is less bytes");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/* Check the crc32 value of the uncompressed data of the current
|
||||
* member */
|
||||
if (state->crc32 != archive_le32dec(f)) {
|
||||
if (xz->crc32 != archive_le32dec(p)) {
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Lzip: CRC32 error");
|
||||
return (ARCHIVE_FAILED);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check the uncompressed size of the current member */
|
||||
if ((uint64_t)state->member_out != archive_le64dec(f + 4)) {
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
if ((uint64_t)xz->member_out != archive_le64dec(p + 4)) {
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Lzip: Uncompressed size error");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/* Check the total size of the current member */
|
||||
if (state->lzip_ver == 1 &&
|
||||
(uint64_t)state->member_in + tail != archive_le64dec(f + 12)) {
|
||||
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
if (xz->lzip_ver == 1 &&
|
||||
(uint64_t)xz->member_in + tail != archive_le64dec(p + 12)) {
|
||||
archive_set_error(&f->archive->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Lzip: Member size error");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
__archive_read_filter_consume(self->upstream, tail);
|
||||
__archive_read_filter_consume(f->upstream, tail);
|
||||
|
||||
/* If current lzip data consists of multi member, try decompressing
|
||||
* a next member. */
|
||||
if (lzip_has_member(self->upstream) != 0) {
|
||||
state->in_stream = 0;
|
||||
state->crc32 = 0;
|
||||
state->member_out = 0;
|
||||
state->member_in = 0;
|
||||
state->eof = 0;
|
||||
if (lzip_has_member(f->upstream) != 0) {
|
||||
xz->in_stream = 0;
|
||||
xz->crc32 = 0;
|
||||
xz->member_out = 0;
|
||||
xz->member_in = 0;
|
||||
xz->eof = 0;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -649,83 +642,80 @@ lzip_tail(struct archive_read_filter *self)
|
||||
* Return the next block of decompressed data.
|
||||
*/
|
||||
static ssize_t
|
||||
xz_filter_read(struct archive_read_filter *self, const void **p)
|
||||
xz_filter_read(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct xz *xz = f->data;
|
||||
size_t decompressed;
|
||||
ssize_t avail_in;
|
||||
int64_t member_in;
|
||||
int ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
redo:
|
||||
/* Empty our output buffer. */
|
||||
state->stream.next_out = state->out_block;
|
||||
state->stream.avail_out = state->out_block_size;
|
||||
member_in = state->member_in;
|
||||
xz->stream.next_out = xz->out_block;
|
||||
xz->stream.avail_out = xz->out_block_size;
|
||||
member_in = xz->member_in;
|
||||
|
||||
/* Try to fill the output buffer. */
|
||||
while (state->stream.avail_out > 0 && !state->eof) {
|
||||
if (!state->in_stream) {
|
||||
while (xz->stream.avail_out > 0 && !xz->eof) {
|
||||
if (!xz->in_stream) {
|
||||
/*
|
||||
* Initialize liblzma for lzip
|
||||
*/
|
||||
ret = lzip_init(self);
|
||||
ret = lzip_init(f);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
state->in_stream = 1;
|
||||
xz->in_stream = 1;
|
||||
}
|
||||
state->stream.next_in =
|
||||
__archive_read_filter_ahead(self->upstream, 1, &avail_in);
|
||||
if (state->stream.next_in == NULL && avail_in < 0) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
xz->stream.next_in =
|
||||
__archive_read_filter_ahead(f->upstream, 1, &avail_in);
|
||||
if (xz->stream.next_in == NULL && avail_in < 0) {
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"truncated input");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
state->stream.avail_in = avail_in;
|
||||
xz->stream.avail_in = avail_in;
|
||||
|
||||
/* Decompress as much as we can in one pass. */
|
||||
ret = lzma_code(&(state->stream),
|
||||
(state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);
|
||||
ret = lzma_code(&(xz->stream),
|
||||
(xz->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN);
|
||||
switch (ret) {
|
||||
case LZMA_STREAM_END: /* Found end of stream. */
|
||||
state->eof = 1;
|
||||
xz->eof = 1;
|
||||
/* FALL THROUGH */
|
||||
case LZMA_OK: /* Decompressor made some progress. */
|
||||
__archive_read_filter_consume(self->upstream,
|
||||
avail_in - state->stream.avail_in);
|
||||
state->member_in +=
|
||||
avail_in - state->stream.avail_in;
|
||||
__archive_read_filter_consume(f->upstream,
|
||||
avail_in - xz->stream.avail_in);
|
||||
xz->member_in +=
|
||||
avail_in - xz->stream.avail_in;
|
||||
break;
|
||||
default:
|
||||
set_error(self, ret);
|
||||
set_error(f, ret);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
decompressed = state->stream.next_out - state->out_block;
|
||||
state->total_out += decompressed;
|
||||
state->member_out += decompressed;
|
||||
decompressed = xz->stream.next_out - xz->out_block;
|
||||
xz->member_out += decompressed;
|
||||
if (decompressed == 0) {
|
||||
if (member_in != state->member_in &&
|
||||
self->code == ARCHIVE_FILTER_LZIP &&
|
||||
state->eof) {
|
||||
ret = lzip_tail(self);
|
||||
if (member_in != xz->member_in &&
|
||||
f->code == ARCHIVE_FILTER_LZIP &&
|
||||
xz->eof) {
|
||||
ret = lzip_tail(f);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
if (!state->eof)
|
||||
if (!xz->eof)
|
||||
goto redo;
|
||||
}
|
||||
*p = NULL;
|
||||
} else {
|
||||
*p = state->out_block;
|
||||
if (self->code == ARCHIVE_FILTER_LZIP) {
|
||||
state->crc32 = lzma_crc32(state->out_block,
|
||||
decompressed, state->crc32);
|
||||
if (state->eof) {
|
||||
ret = lzip_tail(self);
|
||||
*p = xz->out_block;
|
||||
if (f->code == ARCHIVE_FILTER_LZIP) {
|
||||
xz->crc32 = lzma_crc32(xz->out_block,
|
||||
decompressed, xz->crc32);
|
||||
if (xz->eof) {
|
||||
ret = lzip_tail(f);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
@@ -738,14 +728,13 @@ xz_filter_read(struct archive_read_filter *self, const void **p)
|
||||
* Clean up the decompressor.
|
||||
*/
|
||||
static int
|
||||
xz_filter_close(struct archive_read_filter *self)
|
||||
xz_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct xz *xz = f->data;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
lzma_end(&(state->stream));
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
lzma_end(&(xz->stream));
|
||||
free(xz->out_block);
|
||||
free(xz);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -759,44 +748,44 @@ xz_filter_close(struct archive_read_filter *self)
|
||||
*
|
||||
*/
|
||||
static int
|
||||
lzma_bidder_init(struct archive_read_filter *self)
|
||||
lzma_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "lzma -d -qq");
|
||||
r = __archive_read_program(f, "lzma -d -qq");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_LZMA;
|
||||
self->name = "lzma";
|
||||
f->code = ARCHIVE_FILTER_LZMA;
|
||||
f->name = "lzma";
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
xz_bidder_init(struct archive_read_filter *self)
|
||||
xz_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "xz -d -qq");
|
||||
r = __archive_read_program(f, "xz -d -qq");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_XZ;
|
||||
self->name = "xz";
|
||||
f->code = ARCHIVE_FILTER_XZ;
|
||||
f->name = "xz";
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
lzip_bidder_init(struct archive_read_filter *self)
|
||||
lzip_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "lzip -d -q");
|
||||
r = __archive_read_program(f, "lzip -d -q");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_LZIP;
|
||||
self->name = "lzip";
|
||||
f->code = ARCHIVE_FILTER_LZIP;
|
||||
f->name = "lzip";
|
||||
return (r);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,16 +48,16 @@
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_endian.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
#if HAVE_ZSTD_H && HAVE_LIBZSTD
|
||||
|
||||
struct private_data {
|
||||
struct zstd {
|
||||
ZSTD_DStream *dstream;
|
||||
unsigned char *out_block;
|
||||
size_t out_block_size;
|
||||
int64_t total_out;
|
||||
char in_frame; /* True = in the middle of a zstd frame. */
|
||||
char eof; /* True = found end of compressed data. */
|
||||
};
|
||||
@@ -70,8 +70,7 @@ static int zstd_filter_close(struct archive_read_filter *);
|
||||
/*
|
||||
* Note that we can detect zstd compressed files even if we can't decompress
|
||||
* them. (In fact, we like detecting them because we can give better error
|
||||
* messages.) So the bid framework here gets compiled even if no zstd library
|
||||
* is available.
|
||||
* messages.)
|
||||
*/
|
||||
static int zstd_bidder_bid(struct archive_read_filter_bidder *,
|
||||
struct archive_read_filter *);
|
||||
@@ -105,60 +104,82 @@ archive_read_support_filter_zstd(struct archive *_a)
|
||||
* Test whether we can handle this data.
|
||||
*/
|
||||
static int
|
||||
zstd_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
struct archive_read_filter *filter)
|
||||
zstd_bidder_bid(struct archive_read_filter_bidder *b,
|
||||
struct archive_read_filter *f)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
ssize_t avail;
|
||||
/*
|
||||
* Zstandard skippable frames contain a 4 byte magic number followed
|
||||
* by a 4 byte frame data size, then that number of bytes of data.
|
||||
* Regular frames contain a 4 byte magic number followed by a 2-14
|
||||
* byte frame header, some data, and a 3 byte end marker.
|
||||
*/
|
||||
const size_t min_zstd_frame_size = 8;
|
||||
|
||||
// Zstandard skippable frames contain a 4 byte magic number followed by
|
||||
// a 4 byte frame data size, then that number of bytes of data. Regular
|
||||
// frames contain a 4 byte magic number followed by a 2-14 byte frame
|
||||
// header, some data, and a 3 byte end marker.
|
||||
ssize_t min_zstd_frame_size = 8;
|
||||
size_t offset_in_buffer = 0;
|
||||
const size_t max_lookahead = 64 * 1024;
|
||||
uint32_t magic_number;
|
||||
|
||||
ssize_t offset_in_buffer = 0;
|
||||
ssize_t max_lookahead = 64 * 1024;
|
||||
/* Zstd regular frame magic number. */
|
||||
const uint32_t zstd_magic = 0xFD2FB528U;
|
||||
|
||||
// Zstd regular frame magic number.
|
||||
uint32_t zstd_magic = 0xFD2FB528U;
|
||||
/*
|
||||
* Note: Zstd and LZ4 skippable frame magic numbers are identical.
|
||||
* To differentiate these two, we need to look for a non-skippable
|
||||
* frame.
|
||||
*/
|
||||
const uint32_t zstd_magic_skippable_start = 0x184D2A50;
|
||||
const uint32_t zstd_magic_skippable_mask = 0xFFFFFFF0;
|
||||
|
||||
// Note: Zstd and LZ4 skippable frame magic numbers are identical.
|
||||
// To differentiate these two, we need to look for a non-skippable
|
||||
// frame.
|
||||
uint32_t zstd_magic_skippable_start = 0x184D2A50;
|
||||
uint32_t zstd_magic_skippable_mask = 0xFFFFFFF0;
|
||||
(void) b; /* UNUSED */
|
||||
|
||||
(void) self; // UNUSED
|
||||
|
||||
buffer = __archive_read_filter_ahead(filter, min_zstd_frame_size, &avail);
|
||||
buffer = __archive_read_filter_ahead(f, min_zstd_frame_size,
|
||||
&avail);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
|
||||
uint32_t magic_number = archive_le32dec(buffer);
|
||||
magic_number = archive_le32dec(buffer);
|
||||
|
||||
while ((magic_number & zstd_magic_skippable_mask) == zstd_magic_skippable_start) {
|
||||
while ((magic_number & zstd_magic_skippable_mask) ==
|
||||
zstd_magic_skippable_start) {
|
||||
size_t min;
|
||||
uint32_t frame_data_size;
|
||||
|
||||
offset_in_buffer += 4; // Skip over the magic number
|
||||
/* Skip over the magic number */
|
||||
offset_in_buffer += 4;
|
||||
|
||||
// Ensure that we can read another 4 bytes.
|
||||
if (offset_in_buffer + 4 > avail) {
|
||||
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
|
||||
/* Ensure that we can read another 4 bytes. */
|
||||
if (offset_in_buffer + 4 > (size_t)avail) {
|
||||
buffer = __archive_read_filter_ahead(f,
|
||||
offset_in_buffer + 4, &avail);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
|
||||
frame_data_size = archive_le32dec(buffer + offset_in_buffer);
|
||||
|
||||
// Skip over the 4 frame data size bytes, plus the value stored there.
|
||||
offset_in_buffer += 4 + frame_data_size;
|
||||
/* Skip over the 4 frame data size bytes */
|
||||
offset_in_buffer += 4;
|
||||
|
||||
// There should be at least one more frame if this is zstd data.
|
||||
if (offset_in_buffer + min_zstd_frame_size > avail) {
|
||||
if (offset_in_buffer + min_zstd_frame_size > max_lookahead)
|
||||
/* Skip over the value stored there. */
|
||||
if (archive_ckd_add_size(&offset_in_buffer,
|
||||
offset_in_buffer, frame_data_size))
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* There should be at least one more frame
|
||||
* if this is zstd data.
|
||||
*/
|
||||
if (archive_ckd_add_size(&min,
|
||||
offset_in_buffer, min_zstd_frame_size))
|
||||
return (0);
|
||||
if (min > (size_t)avail) {
|
||||
if (min > max_lookahead)
|
||||
return (0);
|
||||
|
||||
buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_zstd_frame_size, &avail);
|
||||
buffer = __archive_read_filter_ahead(f,
|
||||
min, &avail);
|
||||
if (buffer == NULL)
|
||||
return (0);
|
||||
}
|
||||
@@ -166,8 +187,10 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
magic_number = archive_le32dec(buffer + offset_in_buffer);
|
||||
}
|
||||
|
||||
// We have skipped over any skippable frames. Either a regular zstd frame
|
||||
// follows, or this isn't zstd data.
|
||||
/*
|
||||
* We have skipped over any skippable frames. Either a regular zstd
|
||||
* frame follows, or this isn't zstd data.
|
||||
*/
|
||||
|
||||
if (magic_number == zstd_magic)
|
||||
return (offset_in_buffer + 4);
|
||||
@@ -179,20 +202,20 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
|
||||
|
||||
/*
|
||||
* If we don't have the library on this system, we can't do the
|
||||
* decompression directly. We can, however, try to run "zstd -d"
|
||||
* decompression directly. We can, however, try to run "zstd -d -qq"
|
||||
* in case that's available.
|
||||
*/
|
||||
static int
|
||||
zstd_bidder_init(struct archive_read_filter *self)
|
||||
zstd_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = __archive_read_program(self, "zstd -d -qq");
|
||||
r = __archive_read_program(f, "zstd -d -qq");
|
||||
/* Note: We set the format here even if __archive_read_program()
|
||||
* above fails. We do, after all, know what the format is
|
||||
* even if we weren't able to read it. */
|
||||
self->code = ARCHIVE_FILTER_ZSTD;
|
||||
self->name = "zstd";
|
||||
f->code = ARCHIVE_FILTER_ZSTD;
|
||||
f->name = "zstd";
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -208,80 +231,78 @@ zstd_reader_vtable = {
|
||||
* Initialize the filter object
|
||||
*/
|
||||
static int
|
||||
zstd_bidder_init(struct archive_read_filter *self)
|
||||
zstd_bidder_init(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct zstd *zstd;
|
||||
size_t out_block_size = ZSTD_DStreamOutSize();
|
||||
void *out_block;
|
||||
ZSTD_DStream *dstream;
|
||||
|
||||
self->code = ARCHIVE_FILTER_ZSTD;
|
||||
self->name = "zstd";
|
||||
f->code = ARCHIVE_FILTER_ZSTD;
|
||||
f->name = "zstd";
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
zstd = calloc(1, sizeof(*zstd));
|
||||
out_block = malloc(out_block_size);
|
||||
dstream = ZSTD_createDStream();
|
||||
|
||||
if (state == NULL || out_block == NULL || dstream == NULL) {
|
||||
if (zstd == NULL || out_block == NULL || dstream == NULL) {
|
||||
free(out_block);
|
||||
free(state);
|
||||
free(zstd);
|
||||
ZSTD_freeDStream(dstream); /* supports free on NULL */
|
||||
archive_set_error(&self->archive->archive, ENOMEM,
|
||||
archive_set_error(&f->archive->archive, ENOMEM,
|
||||
"Can't allocate data for zstd decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
self->data = state;
|
||||
f->data = zstd;
|
||||
|
||||
state->out_block_size = out_block_size;
|
||||
state->out_block = out_block;
|
||||
state->dstream = dstream;
|
||||
self->vtable = &zstd_reader_vtable;
|
||||
zstd->out_block_size = out_block_size;
|
||||
zstd->out_block = out_block;
|
||||
zstd->dstream = dstream;
|
||||
f->vtable = &zstd_reader_vtable;
|
||||
|
||||
state->eof = 0;
|
||||
state->in_frame = 0;
|
||||
zstd->eof = 0;
|
||||
zstd->in_frame = 0;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
zstd_filter_read(struct archive_read_filter *self, const void **p)
|
||||
zstd_filter_read(struct archive_read_filter *f, const void **p)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct zstd *zstd = f->data;
|
||||
size_t decompressed;
|
||||
ssize_t avail_in;
|
||||
ZSTD_outBuffer out;
|
||||
ZSTD_inBuffer in;
|
||||
size_t ret;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };
|
||||
out = (ZSTD_outBuffer) { zstd->out_block, zstd->out_block_size, 0 };
|
||||
|
||||
/* Try to fill the output buffer. */
|
||||
while (out.pos < out.size && !state->eof) {
|
||||
if (!state->in_frame) {
|
||||
ret = ZSTD_initDStream(state->dstream);
|
||||
while (out.pos < out.size && !zstd->eof) {
|
||||
if (!zstd->in_frame) {
|
||||
ret = ZSTD_initDStream(zstd->dstream);
|
||||
if (ZSTD_isError(ret)) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Error initializing zstd decompressor: %s",
|
||||
ZSTD_getErrorName(ret));
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
in.src = __archive_read_filter_ahead(self->upstream, 1,
|
||||
in.src = __archive_read_filter_ahead(f->upstream, 1,
|
||||
&avail_in);
|
||||
if (avail_in < 0) {
|
||||
return avail_in;
|
||||
}
|
||||
if (in.src == NULL && avail_in == 0) {
|
||||
if (!state->in_frame) {
|
||||
if (!zstd->in_frame) {
|
||||
/* end of stream */
|
||||
state->eof = 1;
|
||||
zstd->eof = 1;
|
||||
break;
|
||||
} else {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Truncated zstd input");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -291,10 +312,10 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
|
||||
in.pos = 0;
|
||||
|
||||
{
|
||||
ret = ZSTD_decompressStream(state->dstream, &out, &in);
|
||||
ret = ZSTD_decompressStream(zstd->dstream, &out, &in);
|
||||
|
||||
if (ZSTD_isError(ret)) {
|
||||
archive_set_error(&self->archive->archive,
|
||||
archive_set_error(&f->archive->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Zstd decompression failed: %s",
|
||||
ZSTD_getErrorName(ret));
|
||||
@@ -302,19 +323,18 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
|
||||
}
|
||||
|
||||
/* Decompressor made some progress */
|
||||
__archive_read_filter_consume(self->upstream, in.pos);
|
||||
__archive_read_filter_consume(f->upstream, in.pos);
|
||||
|
||||
/* ret guaranteed to be > 0 if frame isn't done yet */
|
||||
state->in_frame = (ret != 0);
|
||||
zstd->in_frame = (ret != 0);
|
||||
}
|
||||
}
|
||||
|
||||
decompressed = out.pos;
|
||||
state->total_out += decompressed;
|
||||
if (decompressed == 0)
|
||||
*p = NULL;
|
||||
else
|
||||
*p = state->out_block;
|
||||
*p = zstd->out_block;
|
||||
return (decompressed);
|
||||
}
|
||||
|
||||
@@ -322,15 +342,13 @@ zstd_filter_read(struct archive_read_filter *self, const void **p)
|
||||
* Clean up the decompressor.
|
||||
*/
|
||||
static int
|
||||
zstd_filter_close(struct archive_read_filter *self)
|
||||
zstd_filter_close(struct archive_read_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct zstd *zstd = f->data;
|
||||
|
||||
state = (struct private_data *)self->data;
|
||||
|
||||
ZSTD_freeDStream(state->dstream);
|
||||
free(state->out_block);
|
||||
free(state);
|
||||
ZSTD_freeDStream(zstd->dstream);
|
||||
free(zstd->out_block);
|
||||
free(zstd);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_ppmd7_private.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
@@ -71,16 +72,17 @@
|
||||
#define SFX_MIN_ADDR 0x27000
|
||||
#define SFX_MAX_ADDR 0x60000
|
||||
#define SFX_MAX_OFFSET (SFX_MAX_ADDR - SFX_MIN_ADDR)
|
||||
#define SFX_MAX_SEEK 0x800000
|
||||
|
||||
/*
|
||||
* PE format
|
||||
*/
|
||||
#define PE_DOS_HDR_LEN 0x40
|
||||
#define PE_DOS_HDR_LEN 0x40
|
||||
#define PE_DOS_HDR_ELFANEW_OFFSET 0x3c
|
||||
#define PE_COFF_HDR_LEN 0x18
|
||||
#define PE_COFF_HDR_LEN 0x18
|
||||
#define PE_COFF_HDR_SEC_CNT_OFFSET 0x6
|
||||
#define PE_COFF_HDR_OPT_SZ_OFFSET 0x14
|
||||
#define PE_SEC_HDR_LEN 0x28
|
||||
#define PE_SEC_HDR_LEN 0x28
|
||||
#define PE_SEC_HDR_RAW_ADDR_OFFSET 0x14
|
||||
#define PE_SEC_HDR_RAW_SZ_OFFSET 0x10
|
||||
|
||||
@@ -101,8 +103,8 @@
|
||||
#define _7Z_BZ2 0x040202
|
||||
#define _7Z_PPMD 0x030401
|
||||
#define _7Z_DELTA 0x03
|
||||
#define _7Z_CRYPTO_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */
|
||||
#define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */
|
||||
#define _7Z_CRYPTO_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */
|
||||
#define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */
|
||||
#define _7Z_CRYPTO_AES_256_SHA_256 0x06F10701 /* AES-256 + SHA-256 */
|
||||
|
||||
|
||||
@@ -176,50 +178,48 @@ struct _7z_digests {
|
||||
};
|
||||
|
||||
struct _7z_folder {
|
||||
uint64_t numCoders;
|
||||
size_t numCoders;
|
||||
struct _7z_coder {
|
||||
unsigned long codec;
|
||||
uint64_t numInStreams;
|
||||
uint64_t numOutStreams;
|
||||
uint64_t propertiesSize;
|
||||
int64_t codec;
|
||||
size_t numInStreams;
|
||||
size_t numOutStreams;
|
||||
size_t propertiesSize;
|
||||
unsigned char *properties;
|
||||
} *coders;
|
||||
uint64_t numBindPairs;
|
||||
size_t numBindPairs;
|
||||
struct {
|
||||
uint64_t inIndex;
|
||||
uint64_t outIndex;
|
||||
size_t inIndex;
|
||||
size_t outIndex;
|
||||
} *bindPairs;
|
||||
uint64_t numPackedStreams;
|
||||
uint64_t *packedStreams;
|
||||
uint64_t numInStreams;
|
||||
uint64_t numOutStreams;
|
||||
uint64_t *unPackSize;
|
||||
size_t numPackedStreams;
|
||||
size_t numInStreams;
|
||||
size_t numOutStreams;
|
||||
int64_t *unPackSize;
|
||||
unsigned char digest_defined;
|
||||
uint32_t digest;
|
||||
uint64_t numUnpackStreams;
|
||||
uint32_t packIndex;
|
||||
size_t numUnpackStreams;
|
||||
size_t packIndex;
|
||||
/* Unoperated bytes. */
|
||||
uint64_t skipped_bytes;
|
||||
int64_t skipped_bytes;
|
||||
};
|
||||
|
||||
struct _7z_coders_info {
|
||||
uint64_t numFolders;
|
||||
size_t numFolders;
|
||||
struct _7z_folder *folders;
|
||||
uint64_t dataStreamIndex;
|
||||
};
|
||||
|
||||
struct _7z_pack_info {
|
||||
uint64_t pos;
|
||||
uint64_t numPackStreams;
|
||||
uint64_t *sizes;
|
||||
int64_t pos;
|
||||
size_t numPackStreams;
|
||||
int64_t *sizes;
|
||||
struct _7z_digests digest;
|
||||
/* Calculated from pos and numPackStreams. */
|
||||
uint64_t *positions;
|
||||
int64_t *positions;
|
||||
};
|
||||
|
||||
struct _7z_substream_info {
|
||||
size_t unpack_streams;
|
||||
uint64_t *unpackSizes;
|
||||
int64_t *unpackSizes;
|
||||
unsigned char *digestsDefined;
|
||||
uint32_t *digests;
|
||||
};
|
||||
@@ -231,8 +231,6 @@ struct _7z_stream_info {
|
||||
};
|
||||
|
||||
struct _7z_header_info {
|
||||
uint64_t dataIndex;
|
||||
|
||||
unsigned char *emptyStreamBools;
|
||||
unsigned char *emptyFileBools;
|
||||
unsigned char *antiBools;
|
||||
@@ -245,8 +243,8 @@ struct _7zip_entry {
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
|
||||
const wchar_t *wname;
|
||||
#endif
|
||||
uint32_t folderIndex;
|
||||
uint32_t ssIndex;
|
||||
size_t folderIndex;
|
||||
size_t ssIndex;
|
||||
unsigned flg;
|
||||
#define MTIME_IS_SET (1<<0)
|
||||
#define ATIME_IS_SET (1<<1)
|
||||
@@ -270,24 +268,24 @@ struct _7zip {
|
||||
|
||||
int header_is_being_read;
|
||||
int header_is_encoded;
|
||||
uint64_t header_bytes_remaining;
|
||||
int64_t header_bytes_remaining;
|
||||
unsigned long header_crc32;
|
||||
/* Header offset to check that reading points of the file contents
|
||||
* will not exceed the header. */
|
||||
uint64_t header_offset;
|
||||
int64_t header_offset;
|
||||
/* Base offset of the archive file for a seek in case reading SFX. */
|
||||
uint64_t seek_base;
|
||||
int64_t seek_base;
|
||||
|
||||
/* List of entries */
|
||||
size_t entries_remaining;
|
||||
uint64_t numFiles;
|
||||
size_t numFiles;
|
||||
struct _7zip_entry *entries;
|
||||
struct _7zip_entry *entry;
|
||||
unsigned char *entry_names;
|
||||
|
||||
/* entry_bytes_remaining is the number of bytes we expect. */
|
||||
int64_t entry_offset;
|
||||
uint64_t entry_bytes_remaining;
|
||||
int64_t entry_bytes_remaining;
|
||||
|
||||
/* Running CRC32 of the decompressed data */
|
||||
unsigned long entry_crc32;
|
||||
@@ -308,16 +306,16 @@ struct _7zip {
|
||||
/*
|
||||
* Decompressing control data.
|
||||
*/
|
||||
unsigned folder_index;
|
||||
uint64_t folder_outbytes_remaining;
|
||||
unsigned pack_stream_index;
|
||||
unsigned pack_stream_remaining;
|
||||
uint64_t pack_stream_inbytes_remaining;
|
||||
size_t pack_stream_bytes_unconsumed;
|
||||
size_t folder_index;
|
||||
int64_t folder_outbytes_remaining;
|
||||
size_t pack_stream_index;
|
||||
size_t pack_stream_remaining;
|
||||
int64_t pack_stream_inbytes_remaining;
|
||||
int64_t pack_stream_bytes_unconsumed;
|
||||
|
||||
/* The codec information of a folder. */
|
||||
unsigned long codec;
|
||||
unsigned long codec2;
|
||||
int64_t codec;
|
||||
int64_t codec2;
|
||||
|
||||
/*
|
||||
* Decompressor controllers.
|
||||
@@ -338,7 +336,7 @@ struct _7zip {
|
||||
int stream_valid;
|
||||
#endif
|
||||
/* Decoding Zstandard data. */
|
||||
#if HAVE_ZSTD_H
|
||||
#if HAVE_ZSTD_H && HAVE_LIBZSTD
|
||||
ZSTD_DStream *zstd_dstream;
|
||||
int zstdstream_valid;
|
||||
#endif
|
||||
@@ -349,12 +347,10 @@ struct _7zip {
|
||||
IByteIn bytein;
|
||||
struct {
|
||||
const unsigned char *next_in;
|
||||
int64_t avail_in;
|
||||
int64_t total_in;
|
||||
int64_t stream_in;
|
||||
size_t avail_in;
|
||||
size_t stream_in;
|
||||
unsigned char *next_out;
|
||||
int64_t avail_out;
|
||||
int64_t total_out;
|
||||
size_t avail_out;
|
||||
int overconsumed;
|
||||
} ppstream;
|
||||
int ppmd7_valid;
|
||||
@@ -369,7 +365,7 @@ struct _7zip {
|
||||
uint32_t bcj_ip;
|
||||
|
||||
/* Decoding BCJ2 data. */
|
||||
size_t main_stream_bytes_remaining;
|
||||
int64_t main_stream_bytes_remaining;
|
||||
unsigned char *sub_stream_buff[3];
|
||||
size_t sub_stream_size[3];
|
||||
size_t sub_stream_bytes_remaining[3];
|
||||
@@ -386,13 +382,11 @@ struct _7zip {
|
||||
uint8_t bcj2_prevByte;
|
||||
uint32_t bcj2_range;
|
||||
uint32_t bcj2_code;
|
||||
uint64_t bcj2_outPos;
|
||||
size_t bcj2_outPos;
|
||||
|
||||
/* Filename character-set conversion data. */
|
||||
struct archive_string_conv *sconv;
|
||||
|
||||
char format_name[64];
|
||||
|
||||
/* Custom value that is non-zero if this archive contains encrypted entries. */
|
||||
int has_encrypted_entries;
|
||||
};
|
||||
@@ -400,10 +394,14 @@ struct _7zip {
|
||||
/* Maximum entry size. This limitation prevents reading intentional
|
||||
* corrupted 7-zip files on assuming there are not so many entries in
|
||||
* the files. */
|
||||
#define UMAX_ENTRY ARCHIVE_LITERAL_ULL(100000000)
|
||||
#define UMAX_ENTRY ARCHIVE_LITERAL_LL(100000000)
|
||||
|
||||
/* Don't try to read more than 16 MB at a time */
|
||||
#define MAX_READ 16 * 1024 * 1024
|
||||
|
||||
static size_t align_size(size_t);
|
||||
static int archive_read_format_7zip_has_encrypted_entries(struct archive_read *);
|
||||
static int archive_read_support_format_7zip_capabilities(struct archive_read *a);
|
||||
static int archive_read_support_format_7zip_capabilities(struct archive_read *);
|
||||
static int archive_read_format_7zip_bid(struct archive_read *, int);
|
||||
static int archive_read_format_7zip_cleanup(struct archive_read *);
|
||||
static int archive_read_format_7zip_read_data(struct archive_read *,
|
||||
@@ -411,14 +409,15 @@ static int archive_read_format_7zip_read_data(struct archive_read *,
|
||||
static int archive_read_format_7zip_read_data_skip(struct archive_read *);
|
||||
static int archive_read_format_7zip_read_header(struct archive_read *,
|
||||
struct archive_entry *);
|
||||
static int check_7zip_header_in_sfx(const char *);
|
||||
static unsigned long decode_codec_id(const unsigned char *, size_t);
|
||||
static size_t check_7zip_header_in_sfx(const unsigned char *);
|
||||
static int decode_codec_id(const unsigned char *, size_t, int64_t *);
|
||||
static int decode_encoded_header_info(struct archive_read *,
|
||||
struct _7z_stream_info *);
|
||||
static int decompress(struct archive_read *, struct _7zip *,
|
||||
void *, size_t *, const void *, size_t *);
|
||||
static ssize_t extract_pack_stream(struct archive_read *, size_t);
|
||||
static uint64_t folder_uncompressed_size(struct _7z_folder *);
|
||||
static int files_info_numfiles_is_sane(const struct _7zip *);
|
||||
static int64_t folder_uncompressed_size(struct _7z_folder *);
|
||||
static void free_CodersInfo(struct _7z_coders_info *);
|
||||
static void free_Digest(struct _7z_digests *);
|
||||
static void free_Folder(struct _7z_folder *);
|
||||
@@ -429,10 +428,11 @@ static void free_SubStreamsInfo(struct _7z_substream_info *);
|
||||
static int free_decompression(struct archive_read *, struct _7zip *);
|
||||
static ssize_t get_uncompressed_data(struct archive_read *, const void **,
|
||||
size_t, size_t);
|
||||
static const unsigned char * header_bytes(struct archive_read *, size_t);
|
||||
static const unsigned char *header_bytes(struct archive_read *, size_t);
|
||||
static int init_decompression(struct archive_read *, struct _7zip *,
|
||||
const struct _7z_coder *, const struct _7z_coder *);
|
||||
static int parse_7zip_uint64(struct archive_read *, uint64_t *);
|
||||
static int parse_7zip_size(struct archive_read *, size_t *);
|
||||
static int parse_7zip_int64(struct archive_read *, int64_t *);
|
||||
static int read_Bools(struct archive_read *, unsigned char *, size_t);
|
||||
static int read_CodersInfo(struct archive_read *,
|
||||
struct _7z_coders_info *);
|
||||
@@ -446,16 +446,15 @@ static int read_StreamsInfo(struct archive_read *,
|
||||
struct _7z_stream_info *);
|
||||
static int read_SubStreamsInfo(struct archive_read *,
|
||||
struct _7z_substream_info *, struct _7z_folder *, size_t);
|
||||
static int read_Times(struct archive_read *, struct _7z_header_info *,
|
||||
int);
|
||||
static void read_consume(struct archive_read *);
|
||||
static int read_Times(struct archive_read *, int);
|
||||
static int read_consume(struct archive_read *);
|
||||
static ssize_t read_stream(struct archive_read *, const void **, size_t,
|
||||
size_t);
|
||||
static int seek_pack(struct archive_read *);
|
||||
static int64_t skip_stream(struct archive_read *, size_t);
|
||||
static int skip_sfx(struct archive_read *, const ssize_t);
|
||||
static ssize_t find_pe_overlay(struct archive_read *);
|
||||
static ssize_t find_elf_data_sec(struct archive_read *);
|
||||
static int skip_stream(struct archive_read *, int64_t);
|
||||
static int get_data_offset(struct archive_read *, int64_t *, int);
|
||||
static int get_pe_sfx_offset(struct archive_read *, int64_t *);
|
||||
static int get_elf_sfx_offset(struct archive_read *, int64_t *, int);
|
||||
static int slurp_central_directory(struct archive_read *, struct _7zip *,
|
||||
struct _7z_header_info *);
|
||||
static int setup_decode_folder(struct archive_read *, struct _7z_folder *,
|
||||
@@ -465,9 +464,10 @@ static size_t x86_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static void arm_Init(struct _7zip *);
|
||||
static size_t arm_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
|
||||
static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
|
||||
static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t);
|
||||
static int64_t seek_compat(struct archive_read *, int64_t, int, int);
|
||||
|
||||
|
||||
int
|
||||
@@ -513,19 +513,18 @@ archive_read_support_format_7zip(struct archive *_a)
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_support_format_7zip_capabilities(struct archive_read * a)
|
||||
archive_read_support_format_7zip_capabilities(struct archive_read *a)
|
||||
{
|
||||
(void)a; /* UNUSED */
|
||||
return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |
|
||||
ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a)
|
||||
archive_read_format_7zip_has_encrypted_entries(struct archive_read *a)
|
||||
{
|
||||
if (_a && _a->format) {
|
||||
struct _7zip * zip = (struct _7zip *)_a->format->data;
|
||||
if (a && a->format) {
|
||||
struct _7zip *zip = a->format->data;
|
||||
if (zip) {
|
||||
return zip->has_encrypted_entries;
|
||||
}
|
||||
@@ -533,65 +532,93 @@ archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a)
|
||||
return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
|
||||
}
|
||||
|
||||
static int
|
||||
get_data_offset(struct archive_read *a, int64_t *data_offset, int compat)
|
||||
{
|
||||
const unsigned char *p;
|
||||
int64_t offset, sfx_offset;
|
||||
int r, window;
|
||||
|
||||
if ((p = __archive_read_ahead(a, 6, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated 7-Zip file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/* If first six bytes are the 7-Zip signature,
|
||||
* return the offset right now. */
|
||||
if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0) {
|
||||
*data_offset = 0;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* It may be a 7-Zip SFX archive file. If first two bytes are
|
||||
* 'M' and 'Z' (PE, Windows) or first four bytes are
|
||||
* "\x7F\x45LF" (ELF, Posix-like systems), seek the 7-Zip
|
||||
* signature. While get_pe_sfx_offset can be performed without
|
||||
* performing a seek, get_elf_sfx_offset requires one,
|
||||
* thus a performance difference between the two is expected.
|
||||
*/
|
||||
if ((p[0] == 'M' && p[1] == 'Z'))
|
||||
r = get_pe_sfx_offset(a, &sfx_offset);
|
||||
else if (memcmp(p, "\x7F\x45LF", 4) == 0)
|
||||
r = get_elf_sfx_offset(a, &sfx_offset, compat);
|
||||
else
|
||||
r = ARCHIVE_FATAL;
|
||||
if (r < ARCHIVE_WARN || sfx_offset > SFX_MAX_SEEK)
|
||||
goto fail;
|
||||
|
||||
offset = sfx_offset;
|
||||
window = 4096;
|
||||
while (offset + window <= (sfx_offset + SFX_MAX_OFFSET)) {
|
||||
ssize_t bytes_avail;
|
||||
const unsigned char *buff = __archive_read_ahead(a,
|
||||
offset + window, &bytes_avail);
|
||||
if (buff == NULL) {
|
||||
/* Remaining bytes are less than window. */
|
||||
window >>= 1;
|
||||
if (window < 0x40)
|
||||
goto fail;
|
||||
continue;
|
||||
}
|
||||
p = buff + offset;
|
||||
while (buff + bytes_avail - p >= 32) {
|
||||
size_t step = check_7zip_header_in_sfx(p);
|
||||
if (step == 0) {
|
||||
*data_offset = p - buff;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
p += step;
|
||||
}
|
||||
offset = p - buff;
|
||||
}
|
||||
fail:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Couldn't find out 7-Zip header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
|
||||
{
|
||||
const char *p;
|
||||
int64_t data_offset;
|
||||
|
||||
/* If someone has already bid more than 32, then avoid
|
||||
trashing the look-ahead buffers with a seek. */
|
||||
if (best_bid > 32)
|
||||
return (-1);
|
||||
|
||||
if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
|
||||
if (get_data_offset(a, &data_offset, 0) < 0)
|
||||
return (0);
|
||||
|
||||
/* If first six bytes are the 7-Zip signature,
|
||||
* return the bid right now. */
|
||||
if (memcmp(p, _7ZIP_SIGNATURE, 6) == 0)
|
||||
return (48);
|
||||
|
||||
/*
|
||||
* It may a 7-Zip SFX archive file. If first two bytes are
|
||||
* 'M' and 'Z' available on Windows or first four bytes are
|
||||
* "\x7F\x45LF" available on posix like system, seek the 7-Zip
|
||||
* signature. While find_pe_overlay can be performed without
|
||||
* performing a seek, find_elf_data_sec requires one,
|
||||
* thus a performance difference between the two is expected.
|
||||
*/
|
||||
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
|
||||
const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
|
||||
find_elf_data_sec(a);
|
||||
ssize_t offset = min_addr;
|
||||
ssize_t window = 4096;
|
||||
ssize_t bytes_avail;
|
||||
while (offset + window <= (min_addr + SFX_MAX_OFFSET)) {
|
||||
const char *buff = __archive_read_ahead(a,
|
||||
offset + window, &bytes_avail);
|
||||
if (buff == NULL) {
|
||||
/* Remaining bytes are less than window. */
|
||||
window >>= 1;
|
||||
if (window < 0x40)
|
||||
return (0);
|
||||
continue;
|
||||
}
|
||||
p = buff + offset;
|
||||
while (p + 32 < buff + bytes_avail) {
|
||||
int step = check_7zip_header_in_sfx(p);
|
||||
if (step == 0)
|
||||
return (48);
|
||||
p += step;
|
||||
}
|
||||
offset = p - buff;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
return (48);
|
||||
}
|
||||
|
||||
static int
|
||||
check_7zip_header_in_sfx(const char *p)
|
||||
static size_t
|
||||
check_7zip_header_in_sfx(const unsigned char *p)
|
||||
{
|
||||
switch ((unsigned char)p[5]) {
|
||||
switch (p[5]) {
|
||||
case 0x1C:
|
||||
if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0)
|
||||
return (6);
|
||||
@@ -600,8 +627,7 @@ check_7zip_header_in_sfx(const char *p)
|
||||
* Magic Code, so we should do this in order not to
|
||||
* make a mis-detection.
|
||||
*/
|
||||
if (crc32(0, (const unsigned char *)p + 12, 20)
|
||||
!= archive_le32dec(p + 8))
|
||||
if (crc32(0, p + 12, 20) != archive_le32dec(p + 8))
|
||||
return (6);
|
||||
/* Hit the header! */
|
||||
return (0);
|
||||
@@ -615,79 +641,33 @@ check_7zip_header_in_sfx(const char *p)
|
||||
}
|
||||
|
||||
static int
|
||||
skip_sfx(struct archive_read *a, const ssize_t min_addr)
|
||||
{
|
||||
const void *h;
|
||||
const char *p, *q;
|
||||
size_t skip, offset;
|
||||
ssize_t bytes, window;
|
||||
|
||||
if (__archive_read_seek(a, min_addr, SEEK_SET) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
offset = 0;
|
||||
window = 1;
|
||||
while (offset + window <= SFX_MAX_ADDR - SFX_MIN_ADDR) {
|
||||
h = __archive_read_ahead(a, window, &bytes);
|
||||
if (h == NULL) {
|
||||
/* Remaining bytes are less than window. */
|
||||
window >>= 1;
|
||||
if (window < 0x40)
|
||||
goto fatal;
|
||||
continue;
|
||||
}
|
||||
if (bytes < 6) {
|
||||
/* This case might happen when window == 1. */
|
||||
window = 4096;
|
||||
continue;
|
||||
}
|
||||
p = (const char *)h;
|
||||
q = p + bytes;
|
||||
|
||||
/*
|
||||
* Scan ahead until we find something that looks
|
||||
* like the 7-Zip header.
|
||||
*/
|
||||
while (p + 32 < q) {
|
||||
int step = check_7zip_header_in_sfx(p);
|
||||
if (step == 0) {
|
||||
struct _7zip *zip =
|
||||
(struct _7zip *)a->format->data;
|
||||
skip = p - (const char *)h;
|
||||
__archive_read_consume(a, skip);
|
||||
zip->seek_base = min_addr + offset + skip;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
p += step;
|
||||
}
|
||||
skip = p - (const char *)h;
|
||||
__archive_read_consume(a, skip);
|
||||
offset += skip;
|
||||
if (window == 1)
|
||||
window = 4096;
|
||||
}
|
||||
fatal:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Couldn't find out 7-Zip header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
find_pe_overlay(struct archive_read *a)
|
||||
get_pe_sfx_offset(struct archive_read *a, int64_t *sfx_offset)
|
||||
{
|
||||
const char *h;
|
||||
ssize_t bytes, max_offset, offset, sec_end;
|
||||
ssize_t opt_hdr_sz, sec_cnt;
|
||||
int64_t max_offset, offset;
|
||||
ssize_t bytes;
|
||||
uint16_t opt_hdr_sz, sec_cnt;
|
||||
|
||||
/*
|
||||
* If encounter any weirdness, revert to old brute-force style search
|
||||
*/
|
||||
*sfx_offset = SFX_MIN_ADDR;
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Read Dos header to find e_lfanew
|
||||
*/
|
||||
h = __archive_read_ahead(a, PE_DOS_HDR_LEN, &bytes);
|
||||
if (h == NULL || h[0] != 'M' || h[1] != 'Z') {
|
||||
if (h == NULL) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (h[0] != 'M' || h[1] != 'Z') {
|
||||
break;
|
||||
}
|
||||
offset = archive_le32dec(h + PE_DOS_HDR_ELFANEW_OFFSET);
|
||||
if (offset > SFX_MAX_SEEK) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read COFF header to find opt header size and sec cnt
|
||||
@@ -695,8 +675,10 @@ find_pe_overlay(struct archive_read *a)
|
||||
if (bytes < offset + PE_COFF_HDR_LEN) {
|
||||
h = __archive_read_ahead(a, offset + PE_COFF_HDR_LEN,
|
||||
&bytes);
|
||||
if (h == NULL || h[offset] != 'P' ||
|
||||
h[offset + 1] != 'E') {
|
||||
if (h == NULL) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (h[offset] != 'P' || h[offset + 1] != 'E') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -714,6 +696,10 @@ find_pe_overlay(struct archive_read *a)
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset + sec_cnt * PE_SEC_HDR_LEN > SFX_MAX_SEEK) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Traverse sec table to find max raw offset (i.e., overlay)
|
||||
*/
|
||||
@@ -721,12 +707,14 @@ find_pe_overlay(struct archive_read *a)
|
||||
h = __archive_read_ahead(a,
|
||||
offset + sec_cnt * PE_SEC_HDR_LEN, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
max_offset = offset;
|
||||
while (sec_cnt > 0) {
|
||||
sec_end = archive_le32dec(
|
||||
int64_t sec_end;
|
||||
|
||||
sec_end = (int64_t)archive_le32dec(
|
||||
h + offset + PE_SEC_HDR_RAW_SZ_OFFSET) +
|
||||
archive_le32dec(
|
||||
h + offset + PE_SEC_HDR_RAW_ADDR_OFFSET);
|
||||
@@ -736,34 +724,40 @@ find_pe_overlay(struct archive_read *a)
|
||||
offset += PE_SEC_HDR_LEN;
|
||||
sec_cnt--;
|
||||
}
|
||||
return (max_offset);
|
||||
*sfx_offset = max_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If encounter any weirdness, revert to old brute-force style search
|
||||
*/
|
||||
return (SFX_MIN_ADDR);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
find_elf_data_sec(struct archive_read *a)
|
||||
static int
|
||||
get_elf_sfx_offset(struct archive_read *a, int64_t *sfx_offset, int compat)
|
||||
{
|
||||
int64_t r;
|
||||
const char *h;
|
||||
char big_endian, format_64;
|
||||
ssize_t bytes, min_addr = SFX_MIN_ADDR;
|
||||
ssize_t request;
|
||||
size_t request;
|
||||
uint64_t e_shoff, strtab_offset, strtab_size;
|
||||
uint16_t e_shentsize, e_shnum, e_shstrndx;
|
||||
uint16_t (*dec16)(const void *);
|
||||
uint32_t (*dec32)(const void *);
|
||||
uint64_t (*dec64)(const void *);
|
||||
|
||||
/*
|
||||
* If encounter any weirdness, revert to old brute-force style search
|
||||
*/
|
||||
*sfx_offset = SFX_MIN_ADDR;
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
* Read Elf header to find bitness & endianness
|
||||
*/
|
||||
h = __archive_read_ahead(a, ELF_HDR_MIN_LEN, &bytes);
|
||||
if (h == NULL || memcmp(h, "\x7F\x45LF", 4) != 0) {
|
||||
h = __archive_read_ahead(a, ELF_HDR_MIN_LEN, NULL);
|
||||
if (h == NULL) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (memcmp(h, "\x7F\x45LF", 4) != 0) {
|
||||
break;
|
||||
}
|
||||
format_64 = h[ELF_HDR_EI_CLASS_OFFSET] == 0x2;
|
||||
@@ -786,7 +780,7 @@ find_elf_data_sec(struct archive_read *a)
|
||||
e_shentsize = (*dec16)(h + 0x3A);
|
||||
e_shnum = (*dec16)(h + 0x3C);
|
||||
e_shstrndx = (*dec16)(h + 0x3E);
|
||||
if (e_shnum < e_shstrndx || e_shentsize < 0x28)
|
||||
if (e_shnum <= e_shstrndx || e_shentsize < 0x28)
|
||||
break;
|
||||
|
||||
} else {
|
||||
@@ -794,24 +788,32 @@ find_elf_data_sec(struct archive_read *a)
|
||||
e_shentsize = (*dec16)(h + 0x2E);
|
||||
e_shnum = (*dec16)(h + 0x30);
|
||||
e_shstrndx = (*dec16)(h + 0x32);
|
||||
if (e_shnum < e_shstrndx || e_shentsize < 0x18)
|
||||
if (e_shnum <= e_shstrndx || e_shentsize < 0x18)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((int64_t)e_shoff < 0) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reading the section table to find strtab section
|
||||
*/
|
||||
if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
|
||||
break;
|
||||
if (seek_compat(a, e_shoff, SEEK_SET, compat) < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (format_64) {
|
||||
request = (size_t)e_shnum * (size_t)e_shentsize + 0x28;
|
||||
request = (size_t)e_shnum * e_shentsize + 0x28;
|
||||
} else {
|
||||
request = (size_t)e_shnum * (size_t)e_shentsize + 0x18;
|
||||
request = (size_t)e_shnum * e_shentsize + 0x18;
|
||||
}
|
||||
h = __archive_read_ahead(a, request, &bytes);
|
||||
if (request > SFX_MAX_SEEK) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
h = __archive_read_ahead(a, request, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (format_64) {
|
||||
strtab_offset = (*dec64)(
|
||||
@@ -824,45 +826,50 @@ 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;
|
||||
if ((int64_t)strtab_offset < 0 || strtab_size < 6 ||
|
||||
strtab_size > SFX_MAX_SEEK)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
/*
|
||||
* Read the STRTAB section to find the .data offset
|
||||
*/
|
||||
if (__archive_read_seek(a, strtab_offset, SEEK_SET) < 0) {
|
||||
break;
|
||||
if (seek_compat(a, strtab_offset, SEEK_SET, compat) < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
h = __archive_read_ahead(a, strtab_size, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
ssize_t data_sym_offset = -1;
|
||||
for (size_t offset = 0; offset < strtab_size - 6; offset++) {
|
||||
size_t data_sym_offset = strtab_size;
|
||||
for (size_t offset = 0; offset + 6 <= strtab_size; offset++) {
|
||||
if (memcmp(h + offset, ".data\00", 6) == 0) {
|
||||
data_sym_offset = offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (data_sym_offset == -1) {
|
||||
if (data_sym_offset == strtab_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the section with the .data name
|
||||
*/
|
||||
if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
|
||||
break;
|
||||
if (seek_compat(a, e_shoff, SEEK_SET, compat) < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
|
||||
h = __archive_read_ahead(a, (size_t)e_shnum * e_shentsize, NULL);
|
||||
if (h == NULL) {
|
||||
break;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
ssize_t sec_tbl_offset = 0, name_offset;
|
||||
size_t sec_tbl_offset = 0;
|
||||
while (e_shnum > 0) {
|
||||
uint32_t name_offset;
|
||||
|
||||
name_offset = (*dec32)(h + sec_tbl_offset);
|
||||
if (name_offset == data_sym_offset) {
|
||||
uint64_t sel_offset;
|
||||
int64_t sel_offset;
|
||||
|
||||
if (format_64) {
|
||||
sel_offset = (*dec64)(
|
||||
@@ -871,9 +878,8 @@ find_elf_data_sec(struct archive_read *a)
|
||||
sel_offset = (*dec32)(
|
||||
h + sec_tbl_offset + 0x10);
|
||||
}
|
||||
if (sel_offset > SSIZE_MAX)
|
||||
break;
|
||||
min_addr = (ssize_t)sel_offset;
|
||||
if (sel_offset >= 0)
|
||||
*sfx_offset = sel_offset;
|
||||
break;
|
||||
}
|
||||
sec_tbl_offset += e_shentsize;
|
||||
@@ -882,19 +888,20 @@ find_elf_data_sec(struct archive_read *a)
|
||||
break;
|
||||
}
|
||||
|
||||
__archive_read_seek(a, 0, SEEK_SET);
|
||||
return (min_addr);
|
||||
r = seek_compat(a, 0, SEEK_SET, compat);
|
||||
if (r < 0)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
|
||||
return (int)r;
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
struct _7zip_entry *zip_entry;
|
||||
int r, ret = ARCHIVE_OK;
|
||||
struct _7z_folder *folder = 0;
|
||||
uint64_t fidx = 0;
|
||||
|
||||
/*
|
||||
* It should be sufficient to call archive_read_next_header() for
|
||||
@@ -908,8 +915,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
}
|
||||
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
|
||||
if (a->archive.archive_format_name == NULL)
|
||||
a->archive.archive_format_name = "7-Zip";
|
||||
a->archive.archive_format_name = "7-Zip";
|
||||
|
||||
if (zip->entries == NULL) {
|
||||
struct _7z_header_info header;
|
||||
@@ -919,20 +925,20 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
free_Header(&header);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
zip->entries_remaining = (size_t)zip->numFiles;
|
||||
zip->entries_remaining = zip->numFiles;
|
||||
zip->entry = zip->entries;
|
||||
} else {
|
||||
++zip->entry;
|
||||
}
|
||||
zip_entry = zip->entry;
|
||||
|
||||
if (zip->entries_remaining <= 0 || zip_entry == NULL)
|
||||
if (zip->entries_remaining == 0 || zip_entry == NULL)
|
||||
return ARCHIVE_EOF;
|
||||
--zip->entries_remaining;
|
||||
|
||||
zip->entry_offset = 0;
|
||||
zip->end_of_entry = 0;
|
||||
zip->entry_crc32 = crc32(0, NULL, 0);
|
||||
zip->entry_crc32 = 0;
|
||||
|
||||
/* Setup a string conversion for a filename. */
|
||||
if (zip->sconv == NULL) {
|
||||
@@ -946,9 +952,11 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
that is associated to the current 7zip entry. If the folder
|
||||
has a coder with a _7Z_CRYPTO codec then the folder is encrypted.
|
||||
Hence the entry must also be encrypted. */
|
||||
if (zip_entry && zip_entry->folderIndex < zip->si.ci.numFolders) {
|
||||
if (zip_entry->folderIndex < zip->si.ci.numFolders) {
|
||||
size_t fidx = 0;
|
||||
|
||||
folder = &(zip->si.ci.folders[zip_entry->folderIndex]);
|
||||
for (fidx=0; folder && fidx<folder->numCoders; fidx++) {
|
||||
for (fidx = 0; fidx < folder->numCoders; fidx++) {
|
||||
switch(folder->coders[fidx].codec) {
|
||||
case _7Z_CRYPTO_MAIN_ZIP:
|
||||
case _7Z_CRYPTO_RAR_29:
|
||||
@@ -961,13 +969,6 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
}
|
||||
}
|
||||
|
||||
/* Now that we've checked for encryption, if there were still no
|
||||
* encrypted entries found we can say for sure that there are none.
|
||||
*/
|
||||
if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
zip->has_encrypted_entries = 0;
|
||||
}
|
||||
|
||||
if (archive_entry_copy_pathname_l(entry,
|
||||
(const char *)zip_entry->utf16name,
|
||||
zip_entry->name_len, zip->sconv) != 0) {
|
||||
@@ -979,7 +980,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted "
|
||||
"from %s to current locale.",
|
||||
"from %s to current locale",
|
||||
archive_string_conversion_charset_name(zip->sconv));
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -995,7 +996,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
if (zip_entry->flg & ATIME_IS_SET)
|
||||
archive_entry_set_atime(entry, zip_entry->atime,
|
||||
zip_entry->atime_ns);
|
||||
if (zip_entry->ssIndex != (uint32_t)-1) {
|
||||
if (zip_entry->ssIndex != (size_t)-1) {
|
||||
zip->entry_bytes_remaining =
|
||||
zip->si.ss.unpackSizes[zip_entry->ssIndex];
|
||||
archive_entry_set_size(entry, zip->entry_bytes_remaining);
|
||||
@@ -1008,29 +1009,19 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
const int supported_attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
|
||||
|
||||
if (zip_entry->attr & supported_attrs) {
|
||||
char *fflags_text, *ptr;
|
||||
/* allocate for ",rdonly,hidden,system" */
|
||||
fflags_text = malloc(22 * sizeof(*fflags_text));
|
||||
if (fflags_text != NULL) {
|
||||
ptr = fflags_text;
|
||||
if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) {
|
||||
strcpy(ptr, ",rdonly");
|
||||
ptr = ptr + 7;
|
||||
}
|
||||
if (zip_entry->attr & FILE_ATTRIBUTE_HIDDEN) {
|
||||
strcpy(ptr, ",hidden");
|
||||
ptr = ptr + 7;
|
||||
}
|
||||
if (zip_entry->attr & FILE_ATTRIBUTE_SYSTEM) {
|
||||
strcpy(ptr, ",system");
|
||||
ptr = ptr + 7;
|
||||
}
|
||||
if (ptr > fflags_text) {
|
||||
archive_entry_copy_fflags_text(entry,
|
||||
fflags_text + 1);
|
||||
}
|
||||
free(fflags_text);
|
||||
}
|
||||
char buf[sizeof(",rdonly,hidden,system")];
|
||||
const char *fflags[3] = { "", "", "" };
|
||||
const char **flag = fflags;
|
||||
|
||||
if (zip_entry->attr & FILE_ATTRIBUTE_READONLY)
|
||||
*flag++ = ",rdonly";
|
||||
if (zip_entry->attr & FILE_ATTRIBUTE_HIDDEN)
|
||||
*flag++ = ",hidden";
|
||||
if (zip_entry->attr & FILE_ATTRIBUTE_SYSTEM)
|
||||
*flag++ = ",system";
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s%s", fflags[0], fflags[1], fflags[2]);
|
||||
archive_entry_copy_fflags_text(entry, buf + 1);
|
||||
}
|
||||
|
||||
/* If there's no body, force read_data() to return EOF immediately. */
|
||||
@@ -1041,6 +1032,13 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
unsigned char *symname = NULL;
|
||||
size_t symsize = 0;
|
||||
|
||||
if (zip->entry_bytes_remaining > 1024 * 1024) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Rejecting malformed 7zip archive: "
|
||||
"symlink contents exceed 1 megabyte");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Symbolic-name is recorded as its contents. We have to
|
||||
* read the contents at this time.
|
||||
@@ -1097,10 +1095,6 @@ archive_read_format_7zip_read_header(struct archive_read *a,
|
||||
archive_entry_set_size(entry, 0);
|
||||
}
|
||||
|
||||
/* Set up a more descriptive format name. */
|
||||
snprintf(zip->format_name, sizeof(zip->format_name), "7-Zip");
|
||||
a->archive.archive_format_name = zip->format_name;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -1108,12 +1102,10 @@ static int
|
||||
archive_read_format_7zip_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct _7zip *zip;
|
||||
struct _7zip *zip = a->format->data;
|
||||
ssize_t bytes;
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
zip = (struct _7zip *)(a->format->data);
|
||||
|
||||
if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
zip->has_encrypted_entries = 0;
|
||||
}
|
||||
@@ -1131,8 +1123,8 @@ archive_read_format_7zip_read_data(struct archive_read *a,
|
||||
if (zip->end_of_entry)
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
size_t bytes_to_read = 16 * 1024 * 1024; // Don't try to read more than 16 MB at a time
|
||||
if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) {
|
||||
size_t bytes_to_read = MAX_READ;
|
||||
if ((int64_t)bytes_to_read > zip->entry_bytes_remaining) {
|
||||
bytes_to_read = (size_t)zip->entry_bytes_remaining;
|
||||
}
|
||||
bytes = read_stream(a, buff, bytes_to_read, 0);
|
||||
@@ -1161,7 +1153,7 @@ archive_read_format_7zip_read_data(struct archive_read *a,
|
||||
zip->entry_crc32) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"7-Zip bad CRC: 0x%lx should be 0x%lx",
|
||||
(unsigned long)zip->entry_crc32,
|
||||
zip->entry_crc32,
|
||||
(unsigned long)zip->si.ss.digests[
|
||||
zip->entry->ssIndex]);
|
||||
ret = ARCHIVE_WARN;
|
||||
@@ -1178,10 +1170,8 @@ archive_read_format_7zip_read_data(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_7zip_read_data_skip(struct archive_read *a)
|
||||
{
|
||||
struct _7zip *zip;
|
||||
int64_t bytes_skipped;
|
||||
|
||||
zip = (struct _7zip *)(a->format->data);
|
||||
struct _7zip *zip = a->format->data;
|
||||
int r;
|
||||
|
||||
if (zip->pack_stream_bytes_unconsumed)
|
||||
read_consume(a);
|
||||
@@ -1194,9 +1184,9 @@ archive_read_format_7zip_read_data_skip(struct archive_read *a)
|
||||
* If the length is at the beginning, we can skip the
|
||||
* compressed data much more quickly.
|
||||
*/
|
||||
bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);
|
||||
if (bytes_skipped < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
r = skip_stream(a, zip->entry_bytes_remaining);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
zip->entry_bytes_remaining = 0;
|
||||
|
||||
/* This entry is finished and done. */
|
||||
@@ -1207,9 +1197,8 @@ archive_read_format_7zip_read_data_skip(struct archive_read *a)
|
||||
static int
|
||||
archive_read_format_7zip_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct _7zip *zip;
|
||||
struct _7zip *zip = a->format->data;
|
||||
|
||||
zip = (struct _7zip *)(a->format->data);
|
||||
free_StreamsInfo(&(zip->si));
|
||||
free(zip->entries);
|
||||
free(zip->entry_names);
|
||||
@@ -1220,24 +1209,30 @@ archive_read_format_7zip_cleanup(struct archive_read *a)
|
||||
free(zip->sub_stream_buff[2]);
|
||||
free(zip->tmp_stream_buff);
|
||||
free(zip);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
read_consume(struct archive_read *a)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
|
||||
if (zip->pack_stream_bytes_unconsumed) {
|
||||
__archive_read_consume(a, zip->pack_stream_bytes_unconsumed);
|
||||
int64_t r;
|
||||
|
||||
if ((r = __archive_read_consume(a,
|
||||
zip->pack_stream_bytes_unconsumed)) < 0)
|
||||
return ((int)r);
|
||||
|
||||
zip->stream_offset += zip->pack_stream_bytes_unconsumed;
|
||||
zip->pack_stream_bytes_unconsumed = 0;
|
||||
}
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LZMA_H
|
||||
|
||||
/*
|
||||
* Set an error code and choose an error message for liblzma.
|
||||
*/
|
||||
@@ -1285,52 +1280,49 @@ set_error(struct archive_read *a, int ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static unsigned long
|
||||
decode_codec_id(const unsigned char *codecId, size_t id_size)
|
||||
static int
|
||||
decode_codec_id(const unsigned char *codecId, size_t id_size, int64_t *id)
|
||||
{
|
||||
unsigned i;
|
||||
unsigned long id = 0;
|
||||
size_t i;
|
||||
|
||||
*id = 0;
|
||||
for (i = 0; i < id_size; i++) {
|
||||
id <<= 8;
|
||||
id += codecId[i];
|
||||
if (archive_ckd_mul_i64(id, *id, 256) ||
|
||||
archive_ckd_add_i64(id, *id, codecId[i]))
|
||||
return (-1);
|
||||
}
|
||||
return (id);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static Byte
|
||||
ppmd_read(void *p)
|
||||
{
|
||||
struct archive_read *a = ((IByteIn*)p)->a;
|
||||
struct _7zip *zip = (struct _7zip *)(a->format->data);
|
||||
struct _7zip *zip = a->format->data;
|
||||
Byte b;
|
||||
|
||||
if (zip->ppstream.avail_in <= 0) {
|
||||
if (zip->ppstream.avail_in == 0) {
|
||||
/*
|
||||
* Ppmd7_DecodeSymbol might require reading multiple bytes
|
||||
* and we are on boundary;
|
||||
* last resort to read using __archive_read_ahead.
|
||||
*/
|
||||
ssize_t bytes_avail = 0;
|
||||
const uint8_t* data = __archive_read_ahead(a,
|
||||
(size_t)zip->ppstream.stream_in+1, &bytes_avail);
|
||||
if(data == NULL || bytes_avail < zip->ppstream.stream_in+1) {
|
||||
const uint8_t *data = __archive_read_ahead(a,
|
||||
zip->ppstream.stream_in + 1, NULL);
|
||||
if (data == NULL) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated 7z file data");
|
||||
zip->ppstream.overconsumed = 1;
|
||||
return (0);
|
||||
}
|
||||
zip->ppstream.next_in++;
|
||||
b = data[zip->ppstream.stream_in];
|
||||
} else {
|
||||
b = *zip->ppstream.next_in++;
|
||||
zip->ppstream.avail_in--;
|
||||
}
|
||||
zip->ppstream.avail_in--;
|
||||
zip->ppstream.total_in++;
|
||||
zip->ppstream.stream_in++;
|
||||
return (b);
|
||||
}
|
||||
@@ -1359,8 +1351,9 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
coder2->codec != _7Z_SPARC) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Unsupported filter %lx for %lx",
|
||||
coder2->codec, coder1->codec);
|
||||
"Unsupported filter %jx for %jx",
|
||||
(uintmax_t)coder2->codec,
|
||||
(uintmax_t)coder1->codec);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
zip->codec2 = coder2->codec;
|
||||
@@ -1445,7 +1438,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
memset(&delta_opt, 0, sizeof(delta_opt));
|
||||
delta_opt.type = LZMA_DELTA_TYPE_BYTE;
|
||||
delta_opt.dist =
|
||||
(uint32_t)coder2->properties[0] + 1;
|
||||
coder2->properties[0] + 1;
|
||||
filters[fi].options = &delta_opt;
|
||||
fi++;
|
||||
break;
|
||||
@@ -1485,7 +1478,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
default:
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Unexpected codec ID: %lX", zip->codec2);
|
||||
"Unexpected codec ID: %jX",
|
||||
(uintmax_t)zip->codec2);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
}
|
||||
@@ -1497,7 +1491,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
filters[fi].options = NULL;
|
||||
ff = &filters[fi];
|
||||
r = lzma_properties_decode(&filters[fi], NULL,
|
||||
coder1->properties, (size_t)coder1->propertiesSize);
|
||||
coder1->properties, coder1->propertiesSize);
|
||||
if (r != LZMA_OK) {
|
||||
set_error(a, r);
|
||||
return (ARCHIVE_FAILED);
|
||||
@@ -1565,7 +1559,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
#endif
|
||||
case _7Z_ZSTD:
|
||||
{
|
||||
#if defined(HAVE_ZSTD_H)
|
||||
#if HAVE_ZSTD_H && HAVE_LIBZSTD
|
||||
if (zip->zstdstream_valid) {
|
||||
ZSTD_freeDStream(zip->zstd_dstream);
|
||||
zip->zstdstream_valid = 0;
|
||||
@@ -1588,7 +1582,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
-15 /* Don't check for zlib header */);
|
||||
if (r != Z_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Couldn't initialize zlib stream.");
|
||||
"Couldn't initialize zlib stream");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
zip->stream_valid = 1;
|
||||
@@ -1639,8 +1633,6 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
zip->ppmd7_valid = 1;
|
||||
zip->ppmd7_stat = 0;
|
||||
zip->ppstream.overconsumed = 0;
|
||||
zip->ppstream.total_in = 0;
|
||||
zip->ppstream.total_out = 0;
|
||||
break;
|
||||
}
|
||||
case _7Z_X86:
|
||||
@@ -1654,7 +1646,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
case _7Z_SPARC:
|
||||
case _7Z_DELTA:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unexpected codec ID: %lX", zip->codec);
|
||||
"Unexpected codec ID: %jX", (uintmax_t)zip->codec);
|
||||
return (ARCHIVE_FAILED);
|
||||
case _7Z_CRYPTO_MAIN_ZIP:
|
||||
case _7Z_CRYPTO_RAR_29:
|
||||
@@ -1665,11 +1657,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
|
||||
zip->has_encrypted_entries = 1;
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Crypto codec not supported yet (ID: 0x%lX)", zip->codec);
|
||||
"Crypto codec not supported yet (ID: 0x%jX)",
|
||||
(uintmax_t)zip->codec);
|
||||
return (ARCHIVE_FAILED);
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unknown codec ID: %lX", zip->codec);
|
||||
"Unknown codec ID: %jX", (uintmax_t)zip->codec);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
@@ -1721,7 +1714,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
bcj2_avail_out = t_avail_out;
|
||||
if (zip->codec2 == _7Z_X86_BCJ2) {
|
||||
/*
|
||||
* Decord a remaining decompressed main stream for BCJ2.
|
||||
* Decode a remaining decompressed main stream for BCJ2.
|
||||
*/
|
||||
if (zip->tmp_stream_bytes_remaining) {
|
||||
ssize_t bytes;
|
||||
@@ -1730,7 +1723,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
if (bytes < 0) {
|
||||
archive_set_error(&(a->archive),
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"BCJ2 conversion Failed");
|
||||
"BCJ2 conversion failed");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
zip->main_stream_bytes_remaining -=
|
||||
@@ -1755,8 +1748,8 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
switch (zip->codec) {
|
||||
case _7Z_COPY:
|
||||
{
|
||||
size_t bytes =
|
||||
(t_avail_in > t_avail_out)?t_avail_out:t_avail_in;
|
||||
size_t bytes = (t_avail_in > t_avail_out) ?
|
||||
t_avail_out : t_avail_in;
|
||||
|
||||
memcpy(t_next_out, t_next_in, bytes);
|
||||
t_avail_in -= bytes;
|
||||
@@ -1784,7 +1777,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
default:
|
||||
archive_set_error(&(a->archive),
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Decompression failed(%d)",
|
||||
"Decompression failed (%d)",
|
||||
r);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
@@ -1794,10 +1787,14 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
#endif
|
||||
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
|
||||
case _7Z_BZ2:
|
||||
if (t_avail_in > UINT_MAX)
|
||||
t_avail_in = UINT_MAX;
|
||||
if (t_avail_out > UINT_MAX)
|
||||
t_avail_out = UINT_MAX;
|
||||
zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;
|
||||
zip->bzstream.avail_in = (uint32_t)t_avail_in;
|
||||
zip->bzstream.avail_in = (unsigned int)t_avail_in;
|
||||
zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;
|
||||
zip->bzstream.avail_out = (uint32_t)t_avail_out;
|
||||
zip->bzstream.avail_out = (unsigned int)t_avail_out;
|
||||
r = BZ2_bzDecompress(&(zip->bzstream));
|
||||
switch (r) {
|
||||
case BZ_STREAM_END: /* Found end of stream. */
|
||||
@@ -1827,6 +1824,10 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
#endif
|
||||
#ifdef HAVE_ZLIB_H
|
||||
case _7Z_DEFLATE:
|
||||
if (t_avail_in > UINT_MAX)
|
||||
t_avail_in = UINT_MAX;
|
||||
if (t_avail_out > UINT_MAX)
|
||||
t_avail_out = UINT_MAX;
|
||||
zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;
|
||||
zip->stream.avail_in = (uInt)t_avail_in;
|
||||
zip->stream.next_out = t_next_out;
|
||||
@@ -1847,15 +1848,20 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
t_avail_out = zip->stream.avail_out;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_ZSTD_H
|
||||
#if HAVE_ZSTD_H && HAVE_LIBZSTD
|
||||
case _7Z_ZSTD:
|
||||
{
|
||||
ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 }; // src, size, pos
|
||||
ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 }; // dst, size, pos
|
||||
/* src, size, pos */
|
||||
ZSTD_inBuffer input = { t_next_in, t_avail_in, 0 };
|
||||
/* dst, size, pos */
|
||||
ZSTD_outBuffer output = { t_next_out, t_avail_out, 0 };
|
||||
|
||||
size_t const zret = ZSTD_decompressStream(zip->zstd_dstream, &output, &input);
|
||||
size_t const zret = ZSTD_decompressStream(zip->zstd_dstream,
|
||||
&output, &input);
|
||||
if (ZSTD_isError(zret)) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Zstd decompression failed: %s", ZSTD_getErrorName(zret));
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Zstd decompression failed: %s",
|
||||
ZSTD_getErrorName(zret));
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
t_avail_in -= input.pos;
|
||||
@@ -1865,7 +1871,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
#endif
|
||||
case _7Z_PPMD:
|
||||
{
|
||||
uint64_t flush_bytes;
|
||||
int64_t flush_bytes;
|
||||
|
||||
if (!zip->ppmd7_valid || zip->ppmd7_stat < 0 ||
|
||||
t_avail_out <= 0) {
|
||||
@@ -1923,14 +1929,13 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
}
|
||||
*zip->ppstream.next_out++ = (unsigned char)sym;
|
||||
zip->ppstream.avail_out--;
|
||||
zip->ppstream.total_out++;
|
||||
if (flush_bytes)
|
||||
if (flush_bytes > 0)
|
||||
flush_bytes--;
|
||||
} while (zip->ppstream.avail_out &&
|
||||
(zip->ppstream.avail_in || flush_bytes));
|
||||
|
||||
t_avail_in = (size_t)zip->ppstream.avail_in;
|
||||
t_avail_out = (size_t)zip->ppstream.avail_out;
|
||||
t_avail_in = zip->ppstream.avail_in;
|
||||
t_avail_out = zip->ppstream.avail_out;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1945,7 +1950,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
*outbytes = o_avail_out - t_avail_out;
|
||||
|
||||
/*
|
||||
* Decord BCJ.
|
||||
* Decode BCJ.
|
||||
*/
|
||||
if (zip->codec != _7Z_LZMA2) {
|
||||
if (zip->codec2 == _7Z_X86) {
|
||||
@@ -1953,9 +1958,10 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
|
||||
zip->odd_bcj_size = *outbytes - l;
|
||||
if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 &&
|
||||
o_avail_in && ret != ARCHIVE_EOF) {
|
||||
memcpy(zip->odd_bcj, ((unsigned char *)buff) + l,
|
||||
zip->odd_bcj_size);
|
||||
o_avail_in && ret != ARCHIVE_EOF) {
|
||||
memcpy(zip->odd_bcj,
|
||||
((unsigned char *)buff) + l,
|
||||
zip->odd_bcj_size);
|
||||
*outbytes = l;
|
||||
} else
|
||||
zip->odd_bcj_size = 0;
|
||||
@@ -1971,7 +1977,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
}
|
||||
|
||||
/*
|
||||
* Decord BCJ2 with a decompressed main stream.
|
||||
* Decode BCJ2 with a decompressed main stream.
|
||||
*/
|
||||
if (zip->codec2 == _7Z_X86_BCJ2) {
|
||||
ssize_t bytes;
|
||||
@@ -1979,14 +1985,14 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
zip->tmp_stream_bytes_avail =
|
||||
zip->tmp_stream_buff_size - t_avail_out;
|
||||
if (zip->tmp_stream_bytes_avail >
|
||||
zip->main_stream_bytes_remaining)
|
||||
(uint64_t)zip->main_stream_bytes_remaining)
|
||||
zip->tmp_stream_bytes_avail =
|
||||
zip->main_stream_bytes_remaining;
|
||||
zip->tmp_stream_bytes_remaining = zip->tmp_stream_bytes_avail;
|
||||
bytes = Bcj2_Decode(zip, bcj2_next_out, bcj2_avail_out);
|
||||
if (bytes < 0) {
|
||||
archive_set_error(&(a->archive),
|
||||
ARCHIVE_ERRNO_MISC, "BCJ2 conversion Failed");
|
||||
ARCHIVE_ERRNO_MISC, "BCJ2 conversion failed");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
zip->main_stream_bytes_remaining -=
|
||||
@@ -2034,7 +2040,7 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
|
||||
zip->stream_valid = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_ZSTD_H
|
||||
#if HAVE_ZSTD_H && HAVE_LIBZSTD
|
||||
if (zip->zstdstream_valid)
|
||||
ZSTD_freeDStream(zip->zstd_dstream);
|
||||
#endif
|
||||
@@ -2047,8 +2053,21 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
|
||||
}
|
||||
|
||||
static int
|
||||
parse_7zip_uint64(struct archive_read *a, uint64_t *val)
|
||||
parse_7zip_size(struct archive_read *a, size_t *val)
|
||||
{
|
||||
int64_t v;
|
||||
|
||||
if (parse_7zip_int64(a, &v) < 0 || v > UMAX_ENTRY)
|
||||
return (-1);
|
||||
|
||||
*val = (size_t)v;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
parse_7zip_int64(struct archive_read *a, int64_t *val)
|
||||
{
|
||||
uint64_t v;
|
||||
const unsigned char *p;
|
||||
unsigned char avail, mask;
|
||||
int i;
|
||||
@@ -2057,18 +2076,21 @@ parse_7zip_uint64(struct archive_read *a, uint64_t *val)
|
||||
return (-1);
|
||||
avail = *p;
|
||||
mask = 0x80;
|
||||
*val = 0;
|
||||
v = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (avail & mask) {
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
return (-1);
|
||||
*val |= ((uint64_t)*p) << (8 * i);
|
||||
v |= ((uint64_t)*p) << (8 * i);
|
||||
mask >>= 1;
|
||||
continue;
|
||||
}
|
||||
*val += ((uint64_t)(avail & (mask -1))) << (8 * i);
|
||||
v += ((uint64_t)(avail & (mask - 1))) << (8 * i);
|
||||
break;
|
||||
}
|
||||
if (v > (uint64_t)INT64_MAX)
|
||||
return (-1);
|
||||
*val = (int64_t)v;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -2076,7 +2098,8 @@ static int
|
||||
read_Bools(struct archive_read *a, unsigned char *data, size_t num)
|
||||
{
|
||||
const unsigned char *p;
|
||||
unsigned i, mask = 0, avail = 0;
|
||||
size_t i;
|
||||
unsigned mask = 0, avail = 0;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (mask == 0) {
|
||||
@@ -2085,7 +2108,7 @@ read_Bools(struct archive_read *a, unsigned char *data, size_t num)
|
||||
avail = *p;
|
||||
mask = 0x80;
|
||||
}
|
||||
data[i] = (avail & mask)?1:0;
|
||||
data[i] = (avail & mask) ? 1 : 0;
|
||||
mask >>= 1;
|
||||
}
|
||||
return (0);
|
||||
@@ -2102,7 +2125,7 @@ static int
|
||||
read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
|
||||
{
|
||||
const unsigned char *p;
|
||||
unsigned i;
|
||||
size_t i;
|
||||
|
||||
if (num == 0)
|
||||
return (-1);
|
||||
@@ -2149,25 +2172,23 @@ static int
|
||||
read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
|
||||
{
|
||||
const unsigned char *p;
|
||||
unsigned i;
|
||||
size_t i;
|
||||
|
||||
memset(pi, 0, sizeof(*pi));
|
||||
|
||||
/*
|
||||
* Read PackPos.
|
||||
*/
|
||||
if (parse_7zip_uint64(a, &(pi->pos)) < 0)
|
||||
if (parse_7zip_int64(a, &(pi->pos)) < 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Read NumPackStreams.
|
||||
*/
|
||||
if (parse_7zip_uint64(a, &(pi->numPackStreams)) < 0)
|
||||
if (parse_7zip_size(a, &(pi->numPackStreams)) < 0)
|
||||
return (-1);
|
||||
if (pi->numPackStreams == 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < pi->numPackStreams)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Read PackSizes[num]
|
||||
@@ -2179,13 +2200,13 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
|
||||
return (0);
|
||||
if (*p != kSize)
|
||||
return (-1);
|
||||
pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
|
||||
pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
|
||||
pi->sizes = calloc(pi->numPackStreams, sizeof(int64_t));
|
||||
pi->positions = calloc(pi->numPackStreams, sizeof(int64_t));
|
||||
if (pi->sizes == NULL || pi->positions == NULL)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < pi->numPackStreams; i++) {
|
||||
if (parse_7zip_uint64(a, &(pi->sizes[i])) < 0)
|
||||
if (parse_7zip_int64(a, &(pi->sizes[i])) < 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@@ -2197,9 +2218,9 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
|
||||
if (*p == kEnd) {
|
||||
/* PackStreamDigests[num] are not present. */
|
||||
pi->digest.defineds =
|
||||
calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
|
||||
calloc(pi->numPackStreams, sizeof(*pi->digest.defineds));
|
||||
pi->digest.digests =
|
||||
calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));
|
||||
calloc(pi->numPackStreams, sizeof(*pi->digest.digests));
|
||||
if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
|
||||
return (-1);
|
||||
return (0);
|
||||
@@ -2208,7 +2229,7 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
|
||||
if (*p != kCRC)
|
||||
return (-1);
|
||||
|
||||
if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
|
||||
if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
@@ -2224,40 +2245,39 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
|
||||
static void
|
||||
free_Folder(struct _7z_folder *f)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (f->coders) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i< f->numCoders; i++) {
|
||||
free(f->coders[i].properties);
|
||||
}
|
||||
free(f->coders);
|
||||
}
|
||||
free(f->bindPairs);
|
||||
free(f->packedStreams);
|
||||
free(f->unPackSize);
|
||||
}
|
||||
|
||||
static int
|
||||
read_Folder(struct archive_read *a, struct _7z_folder *f)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
const unsigned char *p;
|
||||
uint64_t numInStreamsTotal = 0;
|
||||
uint64_t numOutStreamsTotal = 0;
|
||||
unsigned i;
|
||||
size_t numInStreamsTotal = 0;
|
||||
size_t numOutStreamsTotal = 0;
|
||||
size_t i;
|
||||
|
||||
memset(f, 0, sizeof(*f));
|
||||
|
||||
/*
|
||||
* Read NumCoders.
|
||||
*/
|
||||
if (parse_7zip_uint64(a, &(f->numCoders)) < 0)
|
||||
if (parse_7zip_size(a, &(f->numCoders)) < 0)
|
||||
return (-1);
|
||||
if (f->numCoders > 4)
|
||||
/* Too many coders. */
|
||||
return (-1);
|
||||
|
||||
f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));
|
||||
f->coders = calloc(f->numCoders, sizeof(*f->coders));
|
||||
if (f->coders == NULL)
|
||||
return (-1);
|
||||
for (i = 0; i< f->numCoders; i++) {
|
||||
@@ -2275,7 +2295,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
|
||||
* 7: Must be zero.
|
||||
*/
|
||||
codec_size = *p & 0xf;
|
||||
simple = (*p & 0x10)?0:1;
|
||||
simple = (*p & 0x10) ? 0 : 1;
|
||||
attr = *p & 0x20;
|
||||
if (*p & 0x80)
|
||||
return (-1);/* Not supported. */
|
||||
@@ -2286,43 +2306,41 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
|
||||
if ((p = header_bytes(a, codec_size)) == NULL)
|
||||
return (-1);
|
||||
|
||||
f->coders[i].codec = decode_codec_id(p, codec_size);
|
||||
if (decode_codec_id(p, codec_size, &f->coders[i].codec) < 0)
|
||||
return (-1);
|
||||
|
||||
if (simple) {
|
||||
f->coders[i].numInStreams = 1;
|
||||
f->coders[i].numOutStreams = 1;
|
||||
} else {
|
||||
if (parse_7zip_uint64(
|
||||
if (parse_7zip_size(
|
||||
a, &(f->coders[i].numInStreams)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < f->coders[i].numInStreams)
|
||||
return (-1);
|
||||
if (parse_7zip_uint64(
|
||||
if (parse_7zip_size(
|
||||
a, &(f->coders[i].numOutStreams)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < f->coders[i].numOutStreams)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (attr) {
|
||||
if (parse_7zip_uint64(
|
||||
if (parse_7zip_size(
|
||||
a, &(f->coders[i].propertiesSize)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < f->coders[i].propertiesSize)
|
||||
return (-1);
|
||||
if ((p = header_bytes(
|
||||
a, (size_t)f->coders[i].propertiesSize)) == NULL)
|
||||
a, f->coders[i].propertiesSize)) == NULL)
|
||||
return (-1);
|
||||
f->coders[i].properties =
|
||||
malloc((size_t)f->coders[i].propertiesSize);
|
||||
malloc(f->coders[i].propertiesSize);
|
||||
if (f->coders[i].properties == NULL)
|
||||
return (-1);
|
||||
memcpy(f->coders[i].properties, p,
|
||||
(size_t)f->coders[i].propertiesSize);
|
||||
f->coders[i].propertiesSize);
|
||||
}
|
||||
|
||||
numInStreamsTotal += f->coders[i].numInStreams;
|
||||
numOutStreamsTotal += f->coders[i].numOutStreams;
|
||||
if (archive_ckd_add_size(&numInStreamsTotal,
|
||||
numInStreamsTotal, f->coders[i].numInStreams) ||
|
||||
archive_ckd_add_size(&numOutStreamsTotal,
|
||||
numOutStreamsTotal, f->coders[i].numOutStreams))
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (numOutStreamsTotal == 0 ||
|
||||
@@ -2330,34 +2348,27 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
|
||||
return (-1);
|
||||
|
||||
f->numBindPairs = numOutStreamsTotal - 1;
|
||||
if (zip->header_bytes_remaining < f->numBindPairs)
|
||||
if ((uint64_t)zip->header_bytes_remaining < f->numBindPairs)
|
||||
return (-1);
|
||||
if (f->numBindPairs > 0) {
|
||||
f->bindPairs =
|
||||
calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));
|
||||
calloc(f->numBindPairs, sizeof(*f->bindPairs));
|
||||
if (f->bindPairs == NULL)
|
||||
return (-1);
|
||||
} else
|
||||
f->bindPairs = NULL;
|
||||
for (i = 0; i < f->numBindPairs; i++) {
|
||||
if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
|
||||
if (parse_7zip_size(a, &(f->bindPairs[i].inIndex)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < f->bindPairs[i].inIndex)
|
||||
return (-1);
|
||||
if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < f->bindPairs[i].outIndex)
|
||||
if (parse_7zip_size(a, &(f->bindPairs[i].outIndex)) < 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
|
||||
f->packedStreams =
|
||||
calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));
|
||||
if (f->packedStreams == NULL)
|
||||
return (-1);
|
||||
/* packedStreams are not needed; parse/verify nonetheless */
|
||||
if (f->numPackedStreams == 1) {
|
||||
for (i = 0; i < numInStreamsTotal; i++) {
|
||||
unsigned j;
|
||||
size_t j;
|
||||
for (j = 0; j < f->numBindPairs; j++) {
|
||||
if (f->bindPairs[j].inIndex == i)
|
||||
break;
|
||||
@@ -2367,12 +2378,10 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
|
||||
}
|
||||
if (i == numInStreamsTotal)
|
||||
return (-1);
|
||||
f->packedStreams[0] = i;
|
||||
} else {
|
||||
for (i = 0; i < f->numPackedStreams; i++) {
|
||||
if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < f->packedStreams[i])
|
||||
size_t packedStream;
|
||||
if (parse_7zip_size(a, &packedStream) < 0)
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
@@ -2385,7 +2394,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
|
||||
static void
|
||||
free_CodersInfo(struct _7z_coders_info *ci)
|
||||
{
|
||||
unsigned i;
|
||||
size_t i;
|
||||
|
||||
if (ci->folders) {
|
||||
for (i = 0; i < ci->numFolders; i++)
|
||||
@@ -2397,9 +2406,10 @@ free_CodersInfo(struct _7z_coders_info *ci)
|
||||
static int
|
||||
read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
|
||||
{
|
||||
struct _7zip *zip = a->format->data;
|
||||
const unsigned char *p;
|
||||
struct _7z_digests digest;
|
||||
unsigned i;
|
||||
size_t dataStreamIndex, i;
|
||||
|
||||
memset(ci, 0, sizeof(*ci));
|
||||
memset(&digest, 0, sizeof(digest));
|
||||
@@ -2412,10 +2422,16 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
|
||||
/*
|
||||
* Read NumFolders.
|
||||
*/
|
||||
if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
|
||||
if (parse_7zip_size(a, &(ci->numFolders)) < 0)
|
||||
goto failed;
|
||||
/*
|
||||
* Each folder is encoded by at least one byte in the coders
|
||||
* list that follows, so a folder count larger than the bytes
|
||||
* left in the header cannot be honored and is rejected here
|
||||
* before it is used to size the folders allocation.
|
||||
*/
|
||||
if (ci->numFolders > (uint64_t)zip->header_bytes_remaining)
|
||||
goto failed;
|
||||
if (UMAX_ENTRY < ci->numFolders)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Read External.
|
||||
@@ -2425,7 +2441,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
|
||||
switch (*p) {
|
||||
case 0:
|
||||
ci->folders =
|
||||
calloc((size_t)ci->numFolders, sizeof(*ci->folders));
|
||||
calloc(ci->numFolders, sizeof(*ci->folders));
|
||||
if (ci->folders == NULL)
|
||||
return (-1);
|
||||
for (i = 0; i < ci->numFolders; i++) {
|
||||
@@ -2434,9 +2450,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < ci->dataStreamIndex)
|
||||
if (parse_7zip_size(a, &dataStreamIndex) < 0)
|
||||
return (-1);
|
||||
if (ci->numFolders > 0) {
|
||||
archive_set_error(&a->archive, -1,
|
||||
@@ -2457,14 +2471,14 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
|
||||
|
||||
for (i = 0; i < ci->numFolders; i++) {
|
||||
struct _7z_folder *folder = &(ci->folders[i]);
|
||||
unsigned j;
|
||||
size_t j;
|
||||
|
||||
folder->unPackSize =
|
||||
calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
|
||||
calloc(folder->numOutStreams, sizeof(*folder->unPackSize));
|
||||
if (folder->unPackSize == NULL)
|
||||
goto failed;
|
||||
for (j = 0; j < folder->numOutStreams; j++) {
|
||||
if (parse_7zip_uint64(a, &(folder->unPackSize[j])) < 0)
|
||||
if (parse_7zip_int64(a, &(folder->unPackSize[j])) < 0)
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
@@ -2478,7 +2492,7 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
|
||||
return (0);
|
||||
if (*p != kCRC)
|
||||
goto failed;
|
||||
if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
|
||||
if (read_Digests(a, &digest, ci->numFolders) < 0)
|
||||
goto failed;
|
||||
for (i = 0; i < ci->numFolders; i++) {
|
||||
ci->folders[i].digest_defined = digest.defineds[i];
|
||||
@@ -2499,16 +2513,16 @@ failed:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
static int64_t
|
||||
folder_uncompressed_size(struct _7z_folder *f)
|
||||
{
|
||||
int n = (int)f->numOutStreams;
|
||||
unsigned pairs = (unsigned)f->numBindPairs;
|
||||
size_t n = f->numOutStreams;
|
||||
size_t pairs = f->numBindPairs;
|
||||
|
||||
while (--n >= 0) {
|
||||
unsigned i;
|
||||
while (n-- > 0) {
|
||||
size_t i;
|
||||
for (i = 0; i < pairs; i++) {
|
||||
if (f->bindPairs[i].outIndex == (uint64_t)n)
|
||||
if (f->bindPairs[i].outIndex == n)
|
||||
break;
|
||||
}
|
||||
if (i >= pairs)
|
||||
@@ -2530,11 +2544,11 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
|
||||
struct _7z_folder *f, size_t numFolders)
|
||||
{
|
||||
const unsigned char *p;
|
||||
uint64_t *usizes;
|
||||
int64_t *usizes;
|
||||
size_t numDigests;
|
||||
size_t unpack_streams;
|
||||
size_t i;
|
||||
int type;
|
||||
unsigned i;
|
||||
uint32_t numDigests;
|
||||
|
||||
memset(ss, 0, sizeof(*ss));
|
||||
|
||||
@@ -2548,14 +2562,11 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
|
||||
if (type == kNumUnPackStream) {
|
||||
unpack_streams = 0;
|
||||
for (i = 0; i < numFolders; i++) {
|
||||
if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
|
||||
if (parse_7zip_size(a, &(f[i].numUnpackStreams)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < f[i].numUnpackStreams)
|
||||
if (archive_ckd_add_size(&unpack_streams,
|
||||
unpack_streams, f[i].numUnpackStreams))
|
||||
return (-1);
|
||||
if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {
|
||||
return (-1);
|
||||
}
|
||||
unpack_streams += (size_t)f[i].numUnpackStreams;
|
||||
}
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
return (-1);
|
||||
@@ -2563,6 +2574,16 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
|
||||
} else
|
||||
unpack_streams = numFolders;
|
||||
|
||||
if (unpack_streams > UMAX_ENTRY)
|
||||
return (-1);
|
||||
|
||||
if (type != kSize) {
|
||||
for (i = 0; i < numFolders; i++) {
|
||||
if (f[i].numUnpackStreams > 1)
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
ss->unpack_streams = unpack_streams;
|
||||
if (unpack_streams) {
|
||||
ss->unpackSizes = calloc(unpack_streams,
|
||||
@@ -2578,8 +2599,8 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
|
||||
|
||||
usizes = ss->unpackSizes;
|
||||
for (i = 0; i < numFolders; i++) {
|
||||
unsigned pack;
|
||||
uint64_t size, sum;
|
||||
int64_t size, sum;
|
||||
size_t pack;
|
||||
|
||||
if (f[i].numUnpackStreams == 0)
|
||||
continue;
|
||||
@@ -2587,11 +2608,10 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
|
||||
sum = 0;
|
||||
if (type == kSize) {
|
||||
for (pack = 1; pack < f[i].numUnpackStreams; pack++) {
|
||||
if (parse_7zip_uint64(a, usizes) < 0)
|
||||
if (parse_7zip_int64(a, usizes) < 0)
|
||||
return (-1);
|
||||
if (*usizes > UINT64_MAX - sum)
|
||||
if (archive_ckd_add_i64(&sum, sum, *usizes++))
|
||||
return (-1);
|
||||
sum += *usizes++;
|
||||
}
|
||||
}
|
||||
size = folder_uncompressed_size(&f[i]);
|
||||
@@ -2606,22 +2626,21 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
|
||||
type = *p;
|
||||
}
|
||||
|
||||
for (i = 0; i < unpack_streams; i++) {
|
||||
ss->digestsDefined[i] = 0;
|
||||
ss->digests[i] = 0;
|
||||
}
|
||||
|
||||
numDigests = 0;
|
||||
for (i = 0; i < numFolders; i++) {
|
||||
if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
|
||||
numDigests += (uint32_t)f[i].numUnpackStreams;
|
||||
if (archive_ckd_add_size(&numDigests,
|
||||
numDigests, f[i].numUnpackStreams)) {
|
||||
errno = ENOMEM;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (type == kCRC) {
|
||||
struct _7z_digests tmpDigests;
|
||||
unsigned char *digestsDefined = ss->digestsDefined;
|
||||
uint32_t * digests = ss->digests;
|
||||
int di = 0;
|
||||
uint32_t *digests = ss->digests;
|
||||
size_t di = 0;
|
||||
|
||||
memset(&tmpDigests, 0, sizeof(tmpDigests));
|
||||
if (read_Digests(a, &(tmpDigests), numDigests) < 0) {
|
||||
@@ -2633,7 +2652,7 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
|
||||
*digestsDefined++ = 1;
|
||||
*digests++ = f[i].digest;
|
||||
} else {
|
||||
unsigned j;
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < f[i].numUnpackStreams;
|
||||
j++, di++) {
|
||||
@@ -2669,16 +2688,16 @@ free_StreamsInfo(struct _7z_stream_info *si)
|
||||
static int
|
||||
read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
const unsigned char *p;
|
||||
unsigned i;
|
||||
size_t i;
|
||||
|
||||
memset(si, 0, sizeof(*si));
|
||||
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
return (-1);
|
||||
if (*p == kPackInfo) {
|
||||
uint64_t packPos;
|
||||
int64_t packPos;
|
||||
|
||||
if (read_PackInfo(a, &(si->pi)) < 0)
|
||||
return (-1);
|
||||
@@ -2691,9 +2710,9 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
|
||||
packPos = si->pi.pos;
|
||||
for (i = 0; i < si->pi.numPackStreams; i++) {
|
||||
si->pi.positions[i] = packPos;
|
||||
if (packPos > UINT64_MAX - si->pi.sizes[i])
|
||||
if (archive_ckd_add_i64(&packPos,
|
||||
packPos, si->pi.sizes[i]))
|
||||
return (-1);
|
||||
packPos += si->pi.sizes[i];
|
||||
if (packPos > zip->header_offset)
|
||||
return (-1);
|
||||
}
|
||||
@@ -2701,7 +2720,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
|
||||
return (-1);
|
||||
}
|
||||
if (*p == kUnPackInfo) {
|
||||
uint32_t packIndex;
|
||||
size_t packIndex;
|
||||
struct _7z_folder *f;
|
||||
|
||||
if (read_CodersInfo(a, &(si->ci)) < 0)
|
||||
@@ -2714,12 +2733,9 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
|
||||
f = si->ci.folders;
|
||||
for (i = 0; i < si->ci.numFolders; i++) {
|
||||
f[i].packIndex = packIndex;
|
||||
if (f[i].numPackedStreams > UINT32_MAX)
|
||||
return (-1);
|
||||
if (packIndex > UINT32_MAX - (uint32_t)f[i].numPackedStreams)
|
||||
return (-1);
|
||||
packIndex += (uint32_t)f[i].numPackedStreams;
|
||||
if (packIndex > si->pi.numPackStreams)
|
||||
if (archive_ckd_add_size(&packIndex,
|
||||
packIndex, f[i].numPackedStreams) ||
|
||||
packIndex > si->pi.numPackStreams)
|
||||
return (-1);
|
||||
}
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
@@ -2728,7 +2744,7 @@ read_StreamsInfo(struct archive_read *a, struct _7z_stream_info *si)
|
||||
|
||||
if (*p == kSubStreamsInfo) {
|
||||
if (read_SubStreamsInfo(a, &(si->ss),
|
||||
si->ci.folders, (size_t)si->ci.numFolders) < 0)
|
||||
si->ci.folders, si->ci.numFolders) < 0)
|
||||
return (-1);
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
return (-1);
|
||||
@@ -2751,18 +2767,38 @@ free_Header(struct _7z_header_info *h)
|
||||
free(h->attrBools);
|
||||
}
|
||||
|
||||
/*
|
||||
* Files without unpack streams must be described by the EmptyStream bitmap,
|
||||
* which consumes one bit for every file entry in FilesInfo.
|
||||
*/
|
||||
static int
|
||||
files_info_numfiles_is_sane(const struct _7zip *zip)
|
||||
{
|
||||
int64_t empty_stream_map_bytes;
|
||||
|
||||
if (zip->numFiles > SIZE_MAX / sizeof(*zip->entries))
|
||||
return (0);
|
||||
|
||||
if (zip->numFiles <= zip->si.ss.unpack_streams)
|
||||
return (1);
|
||||
|
||||
empty_stream_map_bytes = (zip->numFiles + 7) / 8;
|
||||
return (empty_stream_map_bytes <= zip->header_bytes_remaining);
|
||||
}
|
||||
|
||||
static int
|
||||
read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
int check_header_id)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
const unsigned char *p;
|
||||
struct _7z_folder *folders;
|
||||
struct _7z_stream_info *si = &(zip->si);
|
||||
struct _7zip_entry *entries;
|
||||
uint32_t folderIndex, indexInFolder;
|
||||
unsigned i;
|
||||
int eindex, empty_streams, sindex;
|
||||
size_t folderIndex, indexInFolder;
|
||||
size_t i;
|
||||
size_t eindex, empty_streams, sindex;
|
||||
int attr_seen = 0;
|
||||
|
||||
if (check_header_id) {
|
||||
/*
|
||||
@@ -2781,13 +2817,26 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
return (-1);
|
||||
if (*p == kArchiveProperties) {
|
||||
for (;;) {
|
||||
uint64_t size;
|
||||
int64_t size;
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
return (-1);
|
||||
if (*p == 0)
|
||||
if (*p == kEnd)
|
||||
break;
|
||||
if (parse_7zip_uint64(a, &size) < 0)
|
||||
if (parse_7zip_int64(a, &size) < 0)
|
||||
return (-1);
|
||||
if (size < 0 || zip->header_bytes_remaining < size)
|
||||
return (-1);
|
||||
|
||||
/* Skip the property data to keep header parsing aligned. */
|
||||
while (size > 0) {
|
||||
int64_t skip = size;
|
||||
|
||||
if (skip > UBUFF_SIZE)
|
||||
skip = UBUFF_SIZE;
|
||||
if (header_bytes(a, (size_t)skip) == NULL)
|
||||
return (-1);
|
||||
size -= skip;
|
||||
}
|
||||
}
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
return (-1);
|
||||
@@ -2811,12 +2860,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
if (*p != kFilesInfo)
|
||||
return (-1);
|
||||
|
||||
if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
|
||||
if (parse_7zip_size(a, &(zip->numFiles)) < 0)
|
||||
return (-1);
|
||||
if (UMAX_ENTRY < zip->numFiles)
|
||||
if (!files_info_numfiles_is_sane(zip))
|
||||
return (-1);
|
||||
|
||||
zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
|
||||
zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
|
||||
if (zip->entries == NULL)
|
||||
return (-1);
|
||||
entries = zip->entries;
|
||||
@@ -2824,7 +2873,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
empty_streams = 0;
|
||||
for (;;) {
|
||||
int type;
|
||||
uint64_t size;
|
||||
int64_t size;
|
||||
size_t ll;
|
||||
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
@@ -2833,9 +2882,10 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
if (type == kEnd)
|
||||
break;
|
||||
|
||||
if (parse_7zip_uint64(a, &size) < 0)
|
||||
if (parse_7zip_int64(a, &size) < 0)
|
||||
return (-1);
|
||||
if (zip->header_bytes_remaining < size)
|
||||
if (zip->header_bytes_remaining < size ||
|
||||
size > (int64_t)(SIZE_MAX / 4))
|
||||
return (-1);
|
||||
ll = (size_t)size;
|
||||
|
||||
@@ -2843,12 +2893,12 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
case kEmptyStream:
|
||||
if (h->emptyStreamBools != NULL)
|
||||
return (-1);
|
||||
h->emptyStreamBools = calloc((size_t)zip->numFiles,
|
||||
h->emptyStreamBools = calloc(zip->numFiles,
|
||||
sizeof(*h->emptyStreamBools));
|
||||
if (h->emptyStreamBools == NULL)
|
||||
return (-1);
|
||||
if (read_Bools(
|
||||
a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)
|
||||
a, h->emptyStreamBools, zip->numFiles) < 0)
|
||||
return (-1);
|
||||
empty_streams = 0;
|
||||
for (i = 0; i < zip->numFiles; i++) {
|
||||
@@ -2891,7 +2941,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
case kCTime:
|
||||
case kATime:
|
||||
case kMTime:
|
||||
if (read_Times(a, h, type) < 0)
|
||||
if (read_Times(a, type) < 0)
|
||||
return (-1);
|
||||
break;
|
||||
case kName:
|
||||
@@ -2964,21 +3014,20 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
if ((p = header_bytes(a, 2)) == NULL)
|
||||
return (-1);
|
||||
allAreDefined = *p;
|
||||
if (h->attrBools != NULL)
|
||||
if (attr_seen)
|
||||
return (-1);
|
||||
h->attrBools = calloc((size_t)zip->numFiles,
|
||||
sizeof(*h->attrBools));
|
||||
if (h->attrBools == NULL)
|
||||
return (-1);
|
||||
if (allAreDefined)
|
||||
memset(h->attrBools, 1, (size_t)zip->numFiles);
|
||||
else {
|
||||
attr_seen = 1;
|
||||
if (!allAreDefined) {
|
||||
h->attrBools = calloc(zip->numFiles,
|
||||
sizeof(*h->attrBools));
|
||||
if (h->attrBools == NULL)
|
||||
return (-1);
|
||||
if (read_Bools(a, h->attrBools,
|
||||
(size_t)zip->numFiles) < 0)
|
||||
zip->numFiles) < 0)
|
||||
return (-1);
|
||||
}
|
||||
for (i = 0; i < zip->numFiles; i++) {
|
||||
if (h->attrBools[i]) {
|
||||
if (allAreDefined || h->attrBools[i]) {
|
||||
if ((p = header_bytes(a, 4)) == NULL)
|
||||
return (-1);
|
||||
entries[i].attr = archive_le32dec(p);
|
||||
@@ -3031,7 +3080,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
}
|
||||
|
||||
if (entries[i].flg & HAS_STREAM) {
|
||||
if ((size_t)sindex >= si->ss.unpack_streams)
|
||||
if (sindex >= si->ss.unpack_streams)
|
||||
return (-1);
|
||||
if (entries[i].mode == 0)
|
||||
entries[i].mode = AE_IFREG | 0666;
|
||||
@@ -3040,14 +3089,10 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
entries[i].ssIndex = sindex;
|
||||
sindex++;
|
||||
} else {
|
||||
int dir;
|
||||
if (h->emptyFileBools == NULL)
|
||||
dir = 1;
|
||||
else {
|
||||
if (h->emptyFileBools[eindex])
|
||||
dir = 0;
|
||||
else
|
||||
dir = 1;
|
||||
int dir = 1;
|
||||
|
||||
if (h->emptyFileBools != NULL) {
|
||||
dir = !h->emptyFileBools[eindex];
|
||||
eindex++;
|
||||
}
|
||||
if (entries[i].mode == 0) {
|
||||
@@ -3104,27 +3149,25 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
|
||||
}
|
||||
|
||||
static int
|
||||
read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
|
||||
read_Times(struct archive_read *a, int type)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
const unsigned char *p;
|
||||
struct _7zip_entry *entries = zip->entries;
|
||||
unsigned char *timeBools;
|
||||
unsigned char *timeBools = NULL;
|
||||
int allAreDefined;
|
||||
unsigned i;
|
||||
|
||||
timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));
|
||||
if (timeBools == NULL)
|
||||
return (-1);
|
||||
size_t dataIndex, i;
|
||||
|
||||
/* Read allAreDefined. */
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
goto failed;
|
||||
allAreDefined = *p;
|
||||
if (allAreDefined)
|
||||
memset(timeBools, 1, (size_t)zip->numFiles);
|
||||
else {
|
||||
if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)
|
||||
|
||||
if (!allAreDefined) {
|
||||
timeBools = calloc(zip->numFiles, sizeof(*timeBools));
|
||||
if (timeBools == NULL)
|
||||
goto failed;
|
||||
if (read_Bools(a, timeBools, zip->numFiles) < 0)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
@@ -3132,14 +3175,12 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
|
||||
if ((p = header_bytes(a, 1)) == NULL)
|
||||
goto failed;
|
||||
if (*p) {
|
||||
if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
|
||||
goto failed;
|
||||
if (UMAX_ENTRY < h->dataIndex)
|
||||
if (parse_7zip_size(a, &dataIndex) < 0)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i = 0; i < zip->numFiles; i++) {
|
||||
if (!timeBools[i])
|
||||
if (!allAreDefined && !timeBools[i])
|
||||
continue;
|
||||
if ((p = header_bytes(a, 8)) == NULL)
|
||||
goto failed;
|
||||
@@ -3175,7 +3216,8 @@ failed:
|
||||
static int
|
||||
decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
int64_t pi_end;
|
||||
|
||||
errno = 0;
|
||||
if (read_StreamsInfo(a, si) < 0) {
|
||||
@@ -3193,9 +3235,12 @@ decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (zip->header_offset < si->pi.pos + si->pi.sizes[0] ||
|
||||
(int64_t)(si->pi.pos + si->pi.sizes[0]) < 0 ||
|
||||
si->pi.sizes[0] == 0 || (int64_t)si->pi.pos < 0) {
|
||||
if (archive_ckd_add_i64(&pi_end, si->pi.pos, si->pi.sizes[0])) {
|
||||
archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (zip->header_offset < pi_end) {
|
||||
archive_set_error(&a->archive, -1, "Malformed Header offset");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -3206,10 +3251,10 @@ decode_encoded_header_info(struct archive_read *a, struct _7z_stream_info *si)
|
||||
static const unsigned char *
|
||||
header_bytes(struct archive_read *a, size_t rbytes)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
const unsigned char *p;
|
||||
|
||||
if (zip->header_bytes_remaining < rbytes)
|
||||
if ((uint64_t)zip->header_bytes_remaining < rbytes)
|
||||
return (NULL);
|
||||
if (zip->pack_stream_bytes_unconsumed)
|
||||
read_consume(a);
|
||||
@@ -3241,26 +3286,29 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
|
||||
struct _7z_header_info *header)
|
||||
{
|
||||
const unsigned char *p;
|
||||
uint64_t next_header_offset;
|
||||
uint64_t next_header_size;
|
||||
int64_t next_header_offset;
|
||||
int64_t next_header_size;
|
||||
uint32_t next_header_crc;
|
||||
ssize_t bytes_avail;
|
||||
int64_t data_offset;
|
||||
int check_header_crc, r;
|
||||
|
||||
if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
|
||||
if (get_data_offset(a, &data_offset, 1) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (__archive_read_consume(a, data_offset) < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated 7-Zip file header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (archive_ckd_add_i64(&zip->seek_base, data_offset, 32)) {
|
||||
archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
|
||||
/* This is an executable ? Must be self-extracting... */
|
||||
const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
|
||||
find_elf_data_sec(a);
|
||||
r = skip_sfx(a, min_addr);
|
||||
if (r < ARCHIVE_WARN)
|
||||
return (r);
|
||||
if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
zip->seek_base += 32;
|
||||
|
||||
if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0) {
|
||||
archive_set_error(&a->archive, -1, "Not 7-Zip archive file");
|
||||
@@ -3268,7 +3316,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
|
||||
}
|
||||
|
||||
/* CRC check. */
|
||||
if (crc32(0, (const unsigned char *)p + 12, 20)
|
||||
if (crc32(0, p + 12, 20)
|
||||
!= archive_le32dec(p + 8)) {
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive, -1, "Header CRC error");
|
||||
@@ -3277,24 +3325,36 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
|
||||
}
|
||||
|
||||
next_header_offset = archive_le64dec(p + 12);
|
||||
next_header_size = archive_le64dec(p + 20);
|
||||
next_header_crc = archive_le32dec(p + 28);
|
||||
|
||||
if (next_header_size == 0)
|
||||
/* There is no entry in an archive file. */
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
if (((int64_t)next_header_offset) < 0) {
|
||||
if (next_header_offset < 0) {
|
||||
archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
next_header_size = archive_le64dec(p + 20);
|
||||
if (next_header_size < 0) {
|
||||
archive_set_error(&a->archive, -1, "Malformed 7-Zip archive");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
next_header_crc = archive_le32dec(p + 28);
|
||||
|
||||
if (next_header_size == 0)
|
||||
/* There is no entry in the archive file. */
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
__archive_read_consume(a, 32);
|
||||
if (next_header_offset != 0) {
|
||||
if (bytes_avail >= (ssize_t)next_header_offset)
|
||||
if (bytes_avail >= next_header_offset)
|
||||
__archive_read_consume(a, next_header_offset);
|
||||
else if (__archive_read_seek(a,
|
||||
next_header_offset + zip->seek_base, SEEK_SET) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
else {
|
||||
int64_t target;
|
||||
|
||||
if (archive_ckd_add_i64(&target,
|
||||
zip->seek_base, next_header_offset) ||
|
||||
seek_compat(a, target, SEEK_SET, 1) < 0) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC, "Seek error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
zip->stream_offset = next_header_offset;
|
||||
zip->header_offset = next_header_offset;
|
||||
@@ -3405,10 +3465,10 @@ static ssize_t
|
||||
get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
|
||||
size_t minimum)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
ssize_t bytes_avail;
|
||||
|
||||
if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
|
||||
if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
|
||||
/* Copy mode. */
|
||||
|
||||
*buff = __archive_read_ahead(a, minimum, &bytes_avail);
|
||||
@@ -3454,14 +3514,25 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
|
||||
return (bytes_avail);
|
||||
}
|
||||
|
||||
static size_t
|
||||
align_size(size_t s)
|
||||
{
|
||||
size_t r;
|
||||
|
||||
if (archive_ckd_add_size(&r, s, 1023))
|
||||
return (s);
|
||||
r &= ~0x3ff;
|
||||
return (r);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
ssize_t bytes_avail;
|
||||
int r;
|
||||
|
||||
if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
|
||||
if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
|
||||
if (minimum == 0)
|
||||
minimum = 1;
|
||||
if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
|
||||
@@ -3471,10 +3542,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
"Truncated 7-Zip file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining)
|
||||
if (bytes_avail > zip->pack_stream_inbytes_remaining)
|
||||
bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
|
||||
zip->pack_stream_inbytes_remaining -= bytes_avail;
|
||||
if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining)
|
||||
if (bytes_avail > zip->folder_outbytes_remaining)
|
||||
bytes_avail = (ssize_t)zip->folder_outbytes_remaining;
|
||||
zip->folder_outbytes_remaining -= bytes_avail;
|
||||
zip->uncompressed_buffer_bytes_remaining = bytes_avail;
|
||||
@@ -3483,18 +3554,17 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
|
||||
/* If the buffer hasn't been allocated, allocate it now. */
|
||||
if (zip->uncompressed_buffer == NULL) {
|
||||
zip->uncompressed_buffer_size = UBUFF_SIZE;
|
||||
if (zip->uncompressed_buffer_size < minimum) {
|
||||
zip->uncompressed_buffer_size = minimum + 1023;
|
||||
zip->uncompressed_buffer_size &= ~0x3ff;
|
||||
}
|
||||
zip->uncompressed_buffer =
|
||||
malloc(zip->uncompressed_buffer_size);
|
||||
size_t new_size = UBUFF_SIZE;
|
||||
|
||||
if (new_size < minimum)
|
||||
new_size = align_size(minimum);
|
||||
zip->uncompressed_buffer = malloc(new_size);
|
||||
if (zip->uncompressed_buffer == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory for 7-Zip decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
zip->uncompressed_buffer_size = new_size;
|
||||
zip->uncompressed_buffer_bytes_remaining = 0;
|
||||
} else if (zip->uncompressed_buffer_size < minimum ||
|
||||
zip->uncompressed_buffer_bytes_remaining < minimum) {
|
||||
@@ -3515,10 +3585,8 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
* the minimum size.
|
||||
*/
|
||||
void *p;
|
||||
size_t new_size;
|
||||
size_t new_size = align_size(minimum);
|
||||
|
||||
new_size = minimum + 1023;
|
||||
new_size &= ~0x3ff;
|
||||
p = realloc(zip->uncompressed_buffer, new_size);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
@@ -3564,7 +3632,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
bytes_out = zip->uncompressed_buffer_size
|
||||
- zip->uncompressed_buffer_bytes_remaining;
|
||||
bytes_in = bytes_avail;
|
||||
if (bytes_in > zip->pack_stream_inbytes_remaining)
|
||||
if (bytes_in > (uint64_t)zip->pack_stream_inbytes_remaining)
|
||||
bytes_in = (size_t)zip->pack_stream_inbytes_remaining;
|
||||
/* Drive decompression. */
|
||||
r = decompress(a, zip, buff_out, &bytes_out,
|
||||
@@ -3580,7 +3648,7 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
zip->pack_stream_inbytes_remaining -= bytes_in;
|
||||
if (bytes_out > zip->folder_outbytes_remaining)
|
||||
if (bytes_out > (uint64_t)zip->folder_outbytes_remaining)
|
||||
bytes_out = (size_t)zip->folder_outbytes_remaining;
|
||||
zip->folder_outbytes_remaining -= bytes_out;
|
||||
zip->uncompressed_buffer_bytes_remaining += bytes_out;
|
||||
@@ -3618,10 +3686,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
static int
|
||||
seek_pack(struct archive_read *a)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
int64_t pack_offset;
|
||||
|
||||
if (zip->pack_stream_remaining <= 0) {
|
||||
if (zip->pack_stream_remaining == 0) {
|
||||
archive_set_error(&(a->archive),
|
||||
ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -3630,9 +3698,14 @@ seek_pack(struct archive_read *a)
|
||||
zip->si.pi.sizes[zip->pack_stream_index];
|
||||
pack_offset = zip->si.pi.positions[zip->pack_stream_index];
|
||||
if (zip->stream_offset != pack_offset) {
|
||||
if (0 > __archive_read_seek(a, pack_offset + zip->seek_base,
|
||||
SEEK_SET))
|
||||
int64_t target;
|
||||
|
||||
if (archive_ckd_add_i64(&target,
|
||||
zip->seek_base, pack_offset) ||
|
||||
0 > seek_compat(a, target, SEEK_SET, 1)) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
zip->stream_offset = pack_offset;
|
||||
}
|
||||
zip->pack_stream_index++;
|
||||
@@ -3644,8 +3717,8 @@ static ssize_t
|
||||
read_stream(struct archive_read *a, const void **buff, size_t size,
|
||||
size_t minimum)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
uint64_t skip_bytes = 0;
|
||||
struct _7zip *zip = a->format->data;
|
||||
int64_t skip_bytes = 0;
|
||||
ssize_t r;
|
||||
|
||||
if (zip->uncompressed_buffer_bytes_remaining == 0) {
|
||||
@@ -3698,7 +3771,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
|
||||
r = setup_decode_folder(a,
|
||||
&(zip->si.ci.folders[zip->folder_index]), 0);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (r);
|
||||
|
||||
zip->folder_index++;
|
||||
}
|
||||
@@ -3716,9 +3789,10 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
|
||||
return (r);
|
||||
|
||||
/*
|
||||
* Skip the bytes we already has skipped in skip_stream().
|
||||
* Skip the bytes we already have skipped in skip_stream().
|
||||
*/
|
||||
while (1) {
|
||||
size_t request;
|
||||
ssize_t skipped;
|
||||
|
||||
if (zip->uncompressed_buffer_bytes_remaining == 0) {
|
||||
@@ -3742,8 +3816,12 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
|
||||
if (!skip_bytes)
|
||||
break;
|
||||
|
||||
skipped = get_uncompressed_data(
|
||||
a, buff, (size_t)skip_bytes, 0);
|
||||
if (skip_bytes > MAX_READ)
|
||||
request = MAX_READ;
|
||||
else
|
||||
request = (size_t)skip_bytes;
|
||||
|
||||
skipped = get_uncompressed_data(a, buff, request, 0);
|
||||
if (skipped < 0)
|
||||
return (skipped);
|
||||
skip_bytes -= skipped;
|
||||
@@ -3758,10 +3836,10 @@ static int
|
||||
setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
int header)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
const struct _7z_coder *coder1, *coder2;
|
||||
const char *cname = (header)?"archive header":"file content";
|
||||
unsigned i;
|
||||
size_t i;
|
||||
int r, found_bcj2 = 0;
|
||||
|
||||
/*
|
||||
@@ -3773,15 +3851,9 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a stream reader.
|
||||
*/
|
||||
zip->pack_stream_remaining = (unsigned)folder->numPackedStreams;
|
||||
zip->pack_stream_index = (unsigned)folder->packIndex;
|
||||
zip->folder_outbytes_remaining = folder_uncompressed_size(folder);
|
||||
zip->uncompressed_buffer_bytes_remaining = 0;
|
||||
|
||||
/*
|
||||
* Check coder types.
|
||||
* Check coder types before modifying any stream-reader state, so that
|
||||
* an early return leaves zip unchanged (avoids partially-initialized
|
||||
* state that callers would have to reason about).
|
||||
*/
|
||||
for (i = 0; i < folder->numCoders; i++) {
|
||||
switch(folder->coders[i].codec) {
|
||||
@@ -3799,7 +3871,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"The %s is encrypted, "
|
||||
"but currently not supported", cname);
|
||||
return (ARCHIVE_FATAL);
|
||||
return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
|
||||
}
|
||||
case _7Z_X86_BCJ2: {
|
||||
found_bcj2++;
|
||||
@@ -3819,8 +3891,16 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"The %s is encoded with many filters, "
|
||||
"but currently not supported", cname);
|
||||
return (ARCHIVE_FATAL);
|
||||
return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a stream reader.
|
||||
*/
|
||||
zip->pack_stream_remaining = folder->numPackedStreams;
|
||||
zip->pack_stream_index = folder->packIndex;
|
||||
zip->folder_outbytes_remaining = folder_uncompressed_size(folder);
|
||||
zip->uncompressed_buffer_bytes_remaining = 0;
|
||||
coder1 = &(folder->coders[0]);
|
||||
if (folder->numCoders == 2)
|
||||
coder2 = &(folder->coders[1]);
|
||||
@@ -3840,7 +3920,8 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
const void *buff;
|
||||
ssize_t bytes;
|
||||
unsigned char *b[3] = {NULL, NULL, NULL};
|
||||
uint64_t sunpack[3] ={-1, -1, -1};
|
||||
int64_t sunpack[3] ={-1, -1, -1};
|
||||
int64_t remaining;
|
||||
size_t s[3] = {0, 0, 0};
|
||||
int idx[3] = {0, 1, 2};
|
||||
|
||||
@@ -3893,14 +3974,12 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
}
|
||||
}
|
||||
coder2 = &(fc[3]);
|
||||
zip->main_stream_bytes_remaining =
|
||||
(size_t)folder->unPackSize[2];
|
||||
remaining = folder->unPackSize[2];
|
||||
} else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
|
||||
zip->pack_stream_remaining == 4 &&
|
||||
folder->numInStreams == 5 && folder->numOutStreams == 2) {
|
||||
/* Source type 0 made by 7z */
|
||||
zip->main_stream_bytes_remaining =
|
||||
(size_t)folder->unPackSize[0];
|
||||
remaining = folder->unPackSize[0];
|
||||
} else {
|
||||
/* We got an unexpected form. */
|
||||
archive_set_error(&(a->archive),
|
||||
@@ -3908,13 +3987,16 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
"Unsupported form of BCJ2 streams");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
zip->main_stream_bytes_remaining = remaining;
|
||||
|
||||
|
||||
/* Skip the main stream at this time. */
|
||||
if ((r = seek_pack(a)) < 0)
|
||||
return (r);
|
||||
zip->pack_stream_bytes_unconsumed =
|
||||
(size_t)zip->pack_stream_inbytes_remaining;
|
||||
read_consume(a);
|
||||
zip->pack_stream_inbytes_remaining;
|
||||
if ((r = read_consume(a)) < 0)
|
||||
return (r);
|
||||
|
||||
/* Read following three sub streams. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
@@ -3925,7 +4007,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
return (r);
|
||||
}
|
||||
|
||||
if (sunpack[i] == (uint64_t)-1)
|
||||
if (sunpack[i] == -1)
|
||||
zip->folder_outbytes_remaining =
|
||||
zip->pack_stream_inbytes_remaining;
|
||||
else
|
||||
@@ -3939,6 +4021,14 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
|
||||
/* Allocate memory for the decoded data of a sub
|
||||
* stream. */
|
||||
if ((uint64_t)zip->folder_outbytes_remaining > SIZE_MAX) {
|
||||
free(b[0]); free(b[1]); free(b[2]);
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"7-Zip sub-stream size exceeds "
|
||||
"platform maximum");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
b[i] = malloc((size_t)zip->folder_outbytes_remaining);
|
||||
if (b[i] == NULL) {
|
||||
free(b[0]); free(b[1]); free(b[2]);
|
||||
@@ -3996,7 +4086,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
* of BCJ2.
|
||||
*/
|
||||
zip->pack_stream_remaining = 1;
|
||||
zip->pack_stream_index = (unsigned)folder->packIndex;
|
||||
zip->pack_stream_index = folder->packIndex;
|
||||
zip->folder_outbytes_remaining =
|
||||
folder_uncompressed_size(folder);
|
||||
zip->uncompressed_buffer_bytes_remaining = 0;
|
||||
@@ -4011,26 +4101,40 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
skip_stream(struct archive_read *a, size_t skip_bytes)
|
||||
static int
|
||||
skip_stream(struct archive_read *a, int64_t skip_bytes)
|
||||
{
|
||||
struct _7zip *zip = (struct _7zip *)a->format->data;
|
||||
struct _7zip *zip = a->format->data;
|
||||
const void *p;
|
||||
int64_t skipped_bytes;
|
||||
size_t bytes = skip_bytes;
|
||||
int64_t bytes = skip_bytes;
|
||||
|
||||
if (zip->folder_index == 0) {
|
||||
int64_t *v;
|
||||
|
||||
/*
|
||||
* Optimization for a list mode.
|
||||
* Avoid unnecessary decoding operations.
|
||||
*/
|
||||
zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
|
||||
+= skip_bytes;
|
||||
return (skip_bytes);
|
||||
v = &zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes;
|
||||
if (archive_ckd_add_i64(v, *v, skip_bytes)) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Too many bytes to skip");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
while (bytes) {
|
||||
skipped_bytes = read_stream(a, &p, bytes, 0);
|
||||
size_t request;
|
||||
|
||||
if (bytes > MAX_READ)
|
||||
request = MAX_READ;
|
||||
else
|
||||
request = (size_t)bytes;
|
||||
|
||||
skipped_bytes = read_stream(a, &p, request, 0);
|
||||
if (skipped_bytes < 0)
|
||||
return (skipped_bytes);
|
||||
if (skipped_bytes == 0) {
|
||||
@@ -4039,11 +4143,11 @@ skip_stream(struct archive_read *a, size_t skip_bytes)
|
||||
"Truncated 7-Zip file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
bytes -= (size_t)skipped_bytes;
|
||||
bytes -= skipped_bytes;
|
||||
if (zip->pack_stream_bytes_unconsumed)
|
||||
read_consume(a);
|
||||
}
|
||||
return (skip_bytes);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4092,7 +4196,7 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
|
||||
if (p >= limit)
|
||||
break;
|
||||
prevPosT = bufferPos - prevPosT;
|
||||
if (prevPosT > 3)
|
||||
if (prevPosT == 0 || prevPosT > 3)
|
||||
prevMask = 0;
|
||||
else {
|
||||
prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
|
||||
@@ -4111,9 +4215,7 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
|
||||
prevPosT = bufferPos;
|
||||
|
||||
if (Test86MSByte(p[4])) {
|
||||
uint32_t src = ((uint32_t)p[4] << 24) |
|
||||
((uint32_t)p[3] << 16) | ((uint32_t)p[2] << 8) |
|
||||
((uint32_t)p[1]);
|
||||
uint32_t src = archive_le32dec(p + 1);
|
||||
uint32_t dest;
|
||||
for (;;) {
|
||||
uint8_t b;
|
||||
@@ -4173,16 +4275,13 @@ arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
if (buf[i + 3] == 0xEB) {
|
||||
// Calculate the transformed addr.
|
||||
addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
|
||||
| ((uint32_t)buf[i + 2] << 16);
|
||||
addr = archive_le24dec(buf + i);
|
||||
addr <<= 2;
|
||||
addr -= zip->bcj_ip + (uint32_t)i;
|
||||
addr >>= 2;
|
||||
|
||||
// Store the transformed addr in buf.
|
||||
buf[i] = (uint8_t)addr;
|
||||
buf[i + 1] = (uint8_t)(addr >> 8);
|
||||
buf[i + 2] = (uint8_t)(addr >> 16);
|
||||
archive_le24enc(buf + i, addr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4213,20 +4312,14 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
uint32_t addr;
|
||||
|
||||
for (i = 0; i + 4 <= size; i += 4) {
|
||||
instr = (uint32_t)buf[i]
|
||||
| ((uint32_t)buf[i+1] << 8)
|
||||
| ((uint32_t)buf[i+2] << 16)
|
||||
| ((uint32_t)buf[i+3] << 24);
|
||||
instr = archive_le32dec(buf + i);
|
||||
|
||||
if ((instr >> 26) == 0x25) {
|
||||
/* BL instruction */
|
||||
addr = instr - ((zip->bcj_ip + (uint32_t)i) >> 2);
|
||||
instr = 0x94000000 | (addr & 0x03FFFFFF);
|
||||
|
||||
buf[i] = (uint8_t)instr;
|
||||
buf[i+1] = (uint8_t)(instr >> 8);
|
||||
buf[i+2] = (uint8_t)(instr >> 16);
|
||||
buf[i+3] = (uint8_t)(instr >> 24);
|
||||
archive_le32enc(buf + i, instr);
|
||||
} else if ((instr & 0x9F000000) == 0x90000000) {
|
||||
/* ADRP instruction */
|
||||
addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC);
|
||||
@@ -4242,10 +4335,7 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
instr |= (addr & 0x03FFFC) << 3;
|
||||
instr |= (0U - (addr & 0x020000)) & 0xE00000;
|
||||
|
||||
buf[i] = (uint8_t)instr;
|
||||
buf[i+1] = (uint8_t)(instr >> 8);
|
||||
buf[i+2] = (uint8_t)(instr >> 16);
|
||||
buf[i+3] = (uint8_t)(instr >> 24);
|
||||
archive_le32enc(buf + i, instr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4288,10 +4378,7 @@ sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
size &= ~(size_t)3;
|
||||
|
||||
for (i = 0; i < size; i += 4) {
|
||||
instr = (uint32_t)(buf[i] << 24)
|
||||
| ((uint32_t)buf[i+1] << 16)
|
||||
| ((uint32_t)buf[i+2] << 8)
|
||||
| (uint32_t)buf[i+3];
|
||||
instr = archive_be32dec(buf + i);
|
||||
|
||||
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
|
||||
instr <<= 2;
|
||||
@@ -4300,10 +4387,7 @@ sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
|
||||
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
|
||||
| 0x40000000 | (instr & 0x3FFFFF);
|
||||
|
||||
buf[i] = (uint8_t)(instr >> 24);
|
||||
buf[i+1] = (uint8_t)(instr >> 16);
|
||||
buf[i+2] = (uint8_t)(instr >> 8);
|
||||
buf[i+3] = (uint8_t)instr;
|
||||
archive_be32enc(buf + i, instr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4416,7 +4500,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
|
||||
const uint8_t *buf0, *buf1, *buf2, *buf3;
|
||||
size_t size0, size1, size2, size3;
|
||||
const uint8_t *buffer, *bufferLim;
|
||||
unsigned int i, j;
|
||||
size_t i, j;
|
||||
|
||||
size0 = zip->tmp_stream_bytes_remaining;
|
||||
buf0 = zip->tmp_stream_buff + zip->tmp_stream_bytes_avail - size0;
|
||||
@@ -4514,15 +4598,10 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
|
||||
buf2 += 4;
|
||||
size2 -= 4;
|
||||
}
|
||||
dest = (((uint32_t)v[0] << 24) |
|
||||
((uint32_t)v[1] << 16) |
|
||||
((uint32_t)v[2] << 8) |
|
||||
((uint32_t)v[3])) -
|
||||
((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);
|
||||
out[0] = (uint8_t)dest;
|
||||
out[1] = (uint8_t)(dest >> 8);
|
||||
out[2] = (uint8_t)(dest >> 16);
|
||||
out[3] = zip->bcj2_prevByte = (uint8_t)(dest >> 24);
|
||||
dest = archive_be32dec(v) -
|
||||
(zip->bcj2_outPos + outPos + 4);
|
||||
archive_le32enc(out, dest);
|
||||
zip->bcj2_prevByte = out[3];
|
||||
|
||||
for (i = 0; i < 4 && outPos < outSize; i++)
|
||||
outBuf[outPos++] = out[i];
|
||||
@@ -4531,7 +4610,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
|
||||
* Save odd bytes which we could not add into
|
||||
* the output buffer because of out of space.
|
||||
*/
|
||||
zip->odd_bcj_size = 4 -i;
|
||||
zip->odd_bcj_size = 4 - i;
|
||||
for (; i < 4; i++) {
|
||||
j = i - 4 + (unsigned)zip->odd_bcj_size;
|
||||
zip->odd_bcj[j] = out[i];
|
||||
@@ -4548,3 +4627,34 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
|
||||
|
||||
return ((ssize_t)outPos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a seek to given position. If seeking is not supported,
|
||||
* target position is in front of current position, and compat is requested,
|
||||
* try to consume bytes until position is reached.
|
||||
*/
|
||||
int64_t
|
||||
seek_compat(struct archive_read *a, int64_t offset, int whence, int compat)
|
||||
{
|
||||
int64_t ret = ARCHIVE_FAILED;
|
||||
|
||||
if (a->filter->can_seek)
|
||||
ret = __archive_read_seek(a, offset, whence);
|
||||
else if (compat) {
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
ret = __archive_read_consume(a, offset);
|
||||
break;
|
||||
case SEEK_SET:
|
||||
if (a->filter->position > offset)
|
||||
break;
|
||||
ret = __archive_read_consume(a,
|
||||
offset - a->filter->position);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ archive_read_support_format_all(struct archive *a)
|
||||
/* Note: We always return ARCHIVE_OK here, even if some of the
|
||||
* above return ARCHIVE_WARN. The intent here is to enable
|
||||
* "as much as possible." Clients who need specific
|
||||
* compression should enable those individually so they can
|
||||
* formats should enable those individually so they can
|
||||
* verify the level of support. */
|
||||
/* Clear any warning messages set by the above functions. */
|
||||
archive_clear_error(a);
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
@@ -54,7 +55,7 @@ struct ar {
|
||||
* but haven't yet marked as consumed. Must be paired with
|
||||
* entry_bytes_remaining usage/modification.
|
||||
*/
|
||||
size_t entry_bytes_unconsumed;
|
||||
int64_t entry_bytes_unconsumed;
|
||||
int64_t entry_offset;
|
||||
int64_t entry_padding;
|
||||
char *strtab;
|
||||
@@ -80,18 +81,18 @@ struct ar {
|
||||
#define AR_fmag_offset 58
|
||||
#define AR_fmag_size 2
|
||||
|
||||
static int archive_read_format_ar_bid(struct archive_read *a, int);
|
||||
static int archive_read_format_ar_cleanup(struct archive_read *a);
|
||||
static int archive_read_format_ar_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset);
|
||||
static int archive_read_format_ar_skip(struct archive_read *a);
|
||||
static int archive_read_format_ar_read_header(struct archive_read *a,
|
||||
struct archive_entry *e);
|
||||
static uint64_t ar_atol8(const char *p, unsigned char_cnt);
|
||||
static uint64_t ar_atol10(const char *p, unsigned char_cnt);
|
||||
static int ar_parse_gnu_filename_table(struct archive_read *a);
|
||||
static int ar_parse_common_header(struct ar *ar, struct archive_entry *,
|
||||
const char *h);
|
||||
static int archive_read_format_ar_bid(struct archive_read *, int);
|
||||
static int archive_read_format_ar_cleanup(struct archive_read *);
|
||||
static int archive_read_format_ar_read_data(struct archive_read *,
|
||||
const void **, size_t *, int64_t *);
|
||||
static int archive_read_format_ar_skip(struct archive_read *);
|
||||
static int archive_read_format_ar_read_header(struct archive_read *,
|
||||
struct archive_entry *);
|
||||
static uint64_t ar_atol8(const char *, size_t);
|
||||
static uint64_t ar_atol10(const char *, size_t);
|
||||
static int ar_parse_gnu_filename_table(struct archive_read *);
|
||||
static void ar_parse_common_header(struct ar *, struct archive_entry *,
|
||||
const char *);
|
||||
|
||||
int
|
||||
archive_read_support_format_ar(struct archive *_a)
|
||||
@@ -134,12 +135,12 @@ archive_read_support_format_ar(struct archive *_a)
|
||||
static int
|
||||
archive_read_format_ar_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct ar *ar;
|
||||
struct ar *ar = a->format->data;
|
||||
|
||||
ar = (struct ar *)(a->format->data);
|
||||
free(ar->strtab);
|
||||
free(ar);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -164,14 +165,12 @@ archive_read_format_ar_bid(struct archive_read *a, int best_bid)
|
||||
|
||||
static int
|
||||
_ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
struct ar *ar, const char *h, size_t *unconsumed)
|
||||
struct ar *ar, const char *h, int64_t *unconsumed)
|
||||
{
|
||||
char filename[AR_name_size + 1];
|
||||
uint64_t number; /* Used to hold parsed numbers before validation. */
|
||||
size_t bsd_name_length, entry_size;
|
||||
char *p, *st;
|
||||
char *p;
|
||||
const void *b;
|
||||
int r;
|
||||
|
||||
/* Verify the magic signature on the file header. */
|
||||
if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {
|
||||
@@ -246,15 +245,21 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the time, owner, mode, size fields.
|
||||
* This must come before any call to _read_ahead.
|
||||
*/
|
||||
ar_parse_common_header(ar, entry, h);
|
||||
|
||||
/*
|
||||
* '//' is the GNU filename table.
|
||||
* Later entries can refer to names in this table.
|
||||
*/
|
||||
if (strcmp(filename, "//") == 0) {
|
||||
/* This must come before any call to _read_ahead. */
|
||||
ar_parse_common_header(ar, entry, h);
|
||||
char *st;
|
||||
size_t entry_size;
|
||||
|
||||
archive_entry_copy_pathname(entry, filename);
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
/* Get the size of the filename table. */
|
||||
number = ar_atol10(h + AR_size_offset, AR_size_size);
|
||||
if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {
|
||||
@@ -309,22 +314,15 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
*/
|
||||
if (filename[0] == '/' && filename[1] >= '0' && filename[1] <= '9') {
|
||||
number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);
|
||||
/*
|
||||
* If we can't look up the real name, warn and return
|
||||
* the entry with the wrong name.
|
||||
*/
|
||||
/* Fail if we can't look up the real name. */
|
||||
if (ar->strtab == NULL || number >= ar->strtab_size) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Can't find long filename for GNU/SVR4 archive entry");
|
||||
archive_entry_copy_pathname(entry, filename);
|
||||
/* Parse the time, owner, mode, size fields. */
|
||||
ar_parse_common_header(ar, entry, h);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);
|
||||
/* Parse the time, owner, mode, size fields. */
|
||||
return (ar_parse_common_header(ar, entry, h));
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -333,9 +331,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
* the filename to the file contents.
|
||||
*/
|
||||
if (strncmp(filename, "#1/", 3) == 0) {
|
||||
/* Parse the time, owner, mode, size fields. */
|
||||
/* This must occur before _read_ahead is called again. */
|
||||
ar_parse_common_header(ar, entry, h);
|
||||
size_t bsd_name_length;
|
||||
|
||||
/* Parse the size of the name, adjust the file size. */
|
||||
number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);
|
||||
@@ -346,7 +342,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
*/
|
||||
if (number > SIZE_MAX - 1
|
||||
|| number > 1024 * 1024
|
||||
|| (int64_t)number > ar->entry_bytes_remaining) {
|
||||
|| number > (uint64_t)ar->entry_bytes_remaining) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Bad input file size");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -384,50 +380,34 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* "/" is the SVR4/GNU archive symbol table.
|
||||
* "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.
|
||||
*/
|
||||
if (strcmp(filename, "/") == 0 || strcmp(filename, "/SYM64/") == 0) {
|
||||
archive_entry_copy_pathname(entry, filename);
|
||||
/* Parse the time, owner, mode, size fields. */
|
||||
r = ar_parse_common_header(ar, entry, h);
|
||||
/* Force the file type to a regular file. */
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
* "__.SYMDEF" is a BSD archive symbol table.
|
||||
*/
|
||||
if (strcmp(filename, "__.SYMDEF") == 0) {
|
||||
archive_entry_copy_pathname(entry, filename);
|
||||
/* Parse the time, owner, mode, size fields. */
|
||||
return (ar_parse_common_header(ar, entry, h));
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, this is a standard entry. The filename
|
||||
* has already been trimmed as much as possible, based
|
||||
* on our current knowledge of the format.
|
||||
*
|
||||
* Note for future implementations:
|
||||
*
|
||||
* - "/" is the SVR4/GNU archive symbol table.
|
||||
* - "/SYM64/" is the SVR4/GNU 64-bit variant archive symbol table.
|
||||
* - "__.SYMDEF" is a BSD archive symbol table.
|
||||
*/
|
||||
archive_entry_copy_pathname(entry, filename);
|
||||
return (ar_parse_common_header(ar, entry, h));
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_ar_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct ar *ar = (struct ar*)(a->format->data);
|
||||
size_t unconsumed;
|
||||
struct ar *ar = a->format->data;
|
||||
int64_t unconsumed;
|
||||
const void *header_data;
|
||||
int ret;
|
||||
|
||||
if (!ar->read_global_header) {
|
||||
/*
|
||||
* We are now at the beginning of the archive,
|
||||
* so we need first consume the ar global header.
|
||||
* We are at the beginning of the archive now,
|
||||
* so we have to consume the ar global header first.
|
||||
*/
|
||||
__archive_read_consume(a, 8);
|
||||
ar->read_global_header = 1;
|
||||
@@ -451,11 +431,11 @@ archive_read_format_ar_read_header(struct archive_read *a,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
static void
|
||||
ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
|
||||
const char *h)
|
||||
{
|
||||
uint64_t n;
|
||||
int64_t n;
|
||||
|
||||
/* Copy remaining header */
|
||||
archive_entry_set_mtime(entry,
|
||||
@@ -467,23 +447,20 @@ ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
|
||||
archive_entry_set_mode(entry,
|
||||
(mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size));
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
n = ar_atol10(h + AR_size_offset, AR_size_size);
|
||||
n = (int64_t)ar_atol10(h + AR_size_offset, AR_size_size);
|
||||
|
||||
ar->entry_offset = 0;
|
||||
ar->entry_padding = n % 2;
|
||||
archive_entry_set_size(entry, n);
|
||||
ar->entry_bytes_remaining = n;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_ar_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct ar *ar = a->format->data;
|
||||
ssize_t bytes_read;
|
||||
struct ar *ar;
|
||||
|
||||
ar = (struct ar *)(a->format->data);
|
||||
|
||||
if (ar->entry_bytes_unconsumed) {
|
||||
__archive_read_consume(a, ar->entry_bytes_unconsumed);
|
||||
@@ -508,17 +485,9 @@ archive_read_format_ar_read_data(struct archive_read *a,
|
||||
ar->entry_bytes_remaining -= bytes_read;
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
int64_t skipped = __archive_read_consume(a, ar->entry_padding);
|
||||
if (skipped >= 0) {
|
||||
ar->entry_padding -= skipped;
|
||||
}
|
||||
if (ar->entry_padding) {
|
||||
if (skipped >= 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Truncated ar archive - failed consuming padding");
|
||||
}
|
||||
if (__archive_read_consume(a, ar->entry_padding) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
ar->entry_padding = 0;
|
||||
*buff = NULL;
|
||||
*size = 0;
|
||||
*offset = ar->entry_offset;
|
||||
@@ -529,15 +498,11 @@ archive_read_format_ar_read_data(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_ar_skip(struct archive_read *a)
|
||||
{
|
||||
int64_t bytes_skipped;
|
||||
struct ar* ar;
|
||||
struct ar *ar = a->format->data;
|
||||
|
||||
ar = (struct ar *)(a->format->data);
|
||||
|
||||
bytes_skipped = __archive_read_consume(a,
|
||||
ar->entry_bytes_remaining + ar->entry_padding
|
||||
+ ar->entry_bytes_unconsumed);
|
||||
if (bytes_skipped < 0)
|
||||
if (__archive_read_consume(a,
|
||||
ar->entry_bytes_remaining + ar->entry_padding +
|
||||
ar->entry_bytes_unconsumed) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
ar->entry_bytes_remaining = 0;
|
||||
@@ -550,11 +515,10 @@ archive_read_format_ar_skip(struct archive_read *a)
|
||||
static int
|
||||
ar_parse_gnu_filename_table(struct archive_read *a)
|
||||
{
|
||||
struct ar *ar;
|
||||
struct ar *ar = a->format->data;
|
||||
char *p;
|
||||
size_t size;
|
||||
|
||||
ar = (struct ar*)(a->format->data);
|
||||
size = ar->strtab_size;
|
||||
|
||||
for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {
|
||||
@@ -586,51 +550,47 @@ bad_string_table:
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
ar_atol8(const char *p, unsigned char_cnt)
|
||||
ar_atol8(const char *p, size_t char_cnt)
|
||||
{
|
||||
uint64_t l, limit, last_digit_limit;
|
||||
uint64_t l;
|
||||
unsigned int digit, base;
|
||||
|
||||
base = 8;
|
||||
limit = UINT64_MAX / base;
|
||||
last_digit_limit = UINT64_MAX % base;
|
||||
|
||||
while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
|
||||
p++;
|
||||
|
||||
l = 0;
|
||||
digit = *p - '0';
|
||||
while (*p >= '0' && digit < base && char_cnt-- > 0) {
|
||||
if (l>limit || (l == limit && digit > last_digit_limit)) {
|
||||
while (*p >= '0' && digit < base && char_cnt-- > 0) {
|
||||
if (archive_ckd_mul_u64(&l, l, base) ||
|
||||
archive_ckd_add_u64(&l, l, digit)) {
|
||||
l = UINT64_MAX; /* Truncate on overflow. */
|
||||
break;
|
||||
}
|
||||
l = (l * base) + digit;
|
||||
digit = *++p - '0';
|
||||
}
|
||||
return (l);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
ar_atol10(const char *p, unsigned char_cnt)
|
||||
ar_atol10(const char *p, size_t char_cnt)
|
||||
{
|
||||
uint64_t l, limit, last_digit_limit;
|
||||
uint64_t l;
|
||||
unsigned int base, digit;
|
||||
|
||||
base = 10;
|
||||
limit = UINT64_MAX / base;
|
||||
last_digit_limit = UINT64_MAX % base;
|
||||
|
||||
while ((*p == ' ' || *p == '\t') && char_cnt-- > 0)
|
||||
p++;
|
||||
l = 0;
|
||||
digit = *p - '0';
|
||||
while (*p >= '0' && digit < base && char_cnt-- > 0) {
|
||||
if (l > limit || (l == limit && digit > last_digit_limit)) {
|
||||
if (archive_ckd_mul_u64(&l, l, base) ||
|
||||
archive_ckd_add_u64(&l, l, digit)) {
|
||||
l = UINT64_MAX; /* Truncate on overflow. */
|
||||
break;
|
||||
}
|
||||
l = (l * base) + digit;
|
||||
digit = *++p - '0';
|
||||
}
|
||||
return (l);
|
||||
|
||||
@@ -49,85 +49,186 @@
|
||||
#include "archive_endian.h"
|
||||
|
||||
|
||||
/*
|
||||
* Huffman coding.
|
||||
*
|
||||
* Array representation of a Huffman tree for codes of up to 16 bit lengths.
|
||||
* Lookups are performed through a direct, expanded lookup table.
|
||||
*
|
||||
* An expanded table has as many elements as needed to cover all possible
|
||||
* indices formable with bit patterns of given lookup_bits length.
|
||||
*
|
||||
* If less codes exist, these span multiple entries for all possible
|
||||
* combinations of following bits.
|
||||
*
|
||||
* Example of a Huffman tree with len_size = 3, lookup_bits = 2:
|
||||
*
|
||||
* Symbol | Code
|
||||
* -------+-----
|
||||
* A | 0b0
|
||||
* B | 0b10
|
||||
* C | 0b11
|
||||
*
|
||||
* The bit sequences 0b00 and 0b01 are rightfully not covered by a code,
|
||||
* since code 0b0 already maps to symbol A. The table will contain two
|
||||
* entries for symbol A instead:
|
||||
*
|
||||
* idx | tbl[idx]
|
||||
* -----+---------
|
||||
* 0b00 | A
|
||||
* 0b01 | A
|
||||
* 0b10 | B
|
||||
* 0b11 | C
|
||||
*
|
||||
* By using lookup_bits bits as a lookup, it becomes apparent that 0b00 and
|
||||
* 0b01 point to a symbol which actually has the code 0b0. A user of this
|
||||
* data structure must check the code bit length of a retrieved symbol after
|
||||
* the lookup to properly advance the bit stream:
|
||||
*
|
||||
* idx | bitlen[idx]
|
||||
* ----+------------
|
||||
* A | 1
|
||||
* B | 2
|
||||
* C | 2
|
||||
*
|
||||
* Thus, a proper code sequence would be:
|
||||
*
|
||||
* symbol = tbl[read_bits(lookup_bits)]
|
||||
* consume_bits(bitlen[symbol])
|
||||
*/
|
||||
struct huffman {
|
||||
/*
|
||||
* Amount of symbols.
|
||||
*
|
||||
* This implementation keeps track of unused symbols as well,
|
||||
* thus symbols start with 0x0000 up to given symbol amount:
|
||||
* [0..symbol_count)
|
||||
*
|
||||
* Used to construct tbl.
|
||||
*/
|
||||
uint16_t symbol_count;
|
||||
/*
|
||||
* Frequency of code bit lengths.
|
||||
*
|
||||
* Represents the amount of occurrences of given bit lengths.
|
||||
* Index 0 is used for "empty" codes (aka unused symbols),
|
||||
* otherwise index represents the bit length
|
||||
* (index 1 is bit length 1 and so on).
|
||||
*
|
||||
* Used to construct tbl.
|
||||
*/
|
||||
uint16_t freq[17];
|
||||
/* Map of symbols to their code bit lengths. */
|
||||
uint8_t *bitlen;
|
||||
/* Amount of bits to use for lookup (<= tbl_bits). */
|
||||
uint8_t lookup_bits;
|
||||
/*
|
||||
* Code bit length used for allocation (<= 16).
|
||||
*
|
||||
* Used to construct tbl.
|
||||
*/
|
||||
uint8_t tbl_bits;
|
||||
/* Direct, expanded lookup table. */
|
||||
uint16_t *tbl;
|
||||
};
|
||||
|
||||
/*
|
||||
* Bit stream reader.
|
||||
*/
|
||||
struct lzx_br {
|
||||
#define CACHE_TYPE uint64_t
|
||||
#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
|
||||
/* Cache buffer. */
|
||||
CACHE_TYPE cache_buffer;
|
||||
/* Indicates how many bits avail in cache_buffer. */
|
||||
size_t cache_avail;
|
||||
uint8_t odd;
|
||||
int have_odd;
|
||||
};
|
||||
|
||||
struct lzx_pos_tbl {
|
||||
uint32_t base;
|
||||
uint8_t footer_bits;
|
||||
};
|
||||
|
||||
struct lzx_dec {
|
||||
/* Decoding status. */
|
||||
int state;
|
||||
#define ST_RD_TRANSLATION 0
|
||||
#define ST_RD_TRANSLATION_SIZE 1
|
||||
#define ST_RD_BLOCK_TYPE 2
|
||||
#define ST_RD_BLOCK_SIZE 3
|
||||
#define ST_RD_ALIGNMENT 4
|
||||
#define ST_RD_R0 5
|
||||
#define ST_RD_R1 6
|
||||
#define ST_RD_R2 7
|
||||
#define ST_COPY_UNCOMP1 8
|
||||
#define ST_COPY_UNCOMP2 9
|
||||
#define ST_RD_ALIGNED_OFFSET 10
|
||||
#define ST_RD_VERBATIM 11
|
||||
#define ST_RD_PRE_MAIN_TREE_256 12
|
||||
#define ST_MAIN_TREE_256 13
|
||||
#define ST_RD_PRE_MAIN_TREE_REM 14
|
||||
#define ST_MAIN_TREE_REM 15
|
||||
#define ST_RD_PRE_LENGTH_TREE 16
|
||||
#define ST_LENGTH_TREE 17
|
||||
#define ST_MAIN 18
|
||||
#define ST_LENGTH 19
|
||||
#define ST_OFFSET 20
|
||||
#define ST_REAL_POS 21
|
||||
#define ST_COPY 22
|
||||
|
||||
/*
|
||||
* Window to see last decoded data, from 32KBi to 2MBi.
|
||||
* Window to see last decoded data, from 32 KiB to 2 MiB.
|
||||
*/
|
||||
int w_size;
|
||||
int w_mask;
|
||||
size_t w_size;
|
||||
size_t w_mask;
|
||||
/* Window buffer, which is a loop buffer. */
|
||||
unsigned char *w_buff;
|
||||
uint8_t *w_buff;
|
||||
/* The insert position to the window. */
|
||||
int w_pos;
|
||||
size_t w_pos;
|
||||
/* The position where we can copy decoded code from the window. */
|
||||
int copy_pos;
|
||||
size_t copy_pos;
|
||||
/* The length how many bytes we can copy decoded code from
|
||||
* the window. */
|
||||
int copy_len;
|
||||
size_t copy_len;
|
||||
/* Translation reversal for x86 processor CALL byte sequence(E8).
|
||||
* This is used for LZX only. */
|
||||
uint32_t translation_size;
|
||||
char translation;
|
||||
char block_type;
|
||||
int32_t translation_size;
|
||||
int translation;
|
||||
uint8_t block_type;
|
||||
#define VERBATIM_BLOCK 1
|
||||
#define ALIGNED_OFFSET_BLOCK 2
|
||||
#define UNCOMPRESSED_BLOCK 3
|
||||
size_t block_size;
|
||||
size_t block_bytes_avail;
|
||||
/* Repeated offset. */
|
||||
int r0, r1, r2;
|
||||
unsigned char rbytes[4];
|
||||
int rbytes_avail;
|
||||
int length_header;
|
||||
int position_slot;
|
||||
int offset_bits;
|
||||
size_t r0, r1, r2;
|
||||
uint8_t rbytes[4];
|
||||
size_t rbytes_avail;
|
||||
uint8_t length_header;
|
||||
uint16_t position_slot;
|
||||
uint8_t offset_bits;
|
||||
|
||||
struct lzx_pos_tbl {
|
||||
int base;
|
||||
int footer_bits;
|
||||
} *pos_tbl;
|
||||
struct lzx_pos_tbl *pos_tbl;
|
||||
/*
|
||||
* Bit stream reader.
|
||||
*/
|
||||
struct lzx_br {
|
||||
#define CACHE_TYPE uint64_t
|
||||
#define CACHE_BITS (8 * sizeof(CACHE_TYPE))
|
||||
/* Cache buffer. */
|
||||
CACHE_TYPE cache_buffer;
|
||||
/* Indicates how many bits avail in cache_buffer. */
|
||||
int cache_avail;
|
||||
unsigned char odd;
|
||||
char have_odd;
|
||||
} br;
|
||||
struct lzx_br br;
|
||||
|
||||
/*
|
||||
* Huffman coding.
|
||||
*/
|
||||
struct huffman {
|
||||
int len_size;
|
||||
int freq[17];
|
||||
unsigned char *bitlen;
|
||||
struct huffman at;
|
||||
struct huffman lt;
|
||||
struct huffman mt;
|
||||
struct huffman pt;
|
||||
|
||||
/*
|
||||
* Use a index table. It's faster than searching a huffman
|
||||
* coding tree, which is a binary tree. But a use of a large
|
||||
* index table causes L1 cache read miss many times.
|
||||
*/
|
||||
int max_bits;
|
||||
int tbl_bits;
|
||||
int tree_used;
|
||||
/* Direct access table. */
|
||||
uint16_t *tbl;
|
||||
} at, lt, mt, pt;
|
||||
|
||||
int loop;
|
||||
uint16_t loop;
|
||||
int error;
|
||||
};
|
||||
|
||||
static const int slots[] = {
|
||||
static const size_t slots[] = {
|
||||
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
|
||||
};
|
||||
#define SLOT_BASE 15
|
||||
@@ -135,11 +236,11 @@ static const int slots[] = {
|
||||
|
||||
struct lzx_stream {
|
||||
const unsigned char *next_in;
|
||||
int64_t avail_in;
|
||||
int64_t total_in;
|
||||
size_t avail_in;
|
||||
size_t total_in;
|
||||
unsigned char *next_out;
|
||||
int64_t avail_out;
|
||||
int64_t total_out;
|
||||
size_t avail_out;
|
||||
size_t total_out;
|
||||
struct lzx_dec *ds;
|
||||
};
|
||||
|
||||
@@ -179,6 +280,11 @@ struct lzx_stream {
|
||||
#define CFDATA_cbData 4
|
||||
#define CFDATA_cbUncomp 6
|
||||
|
||||
/* Limits */
|
||||
#define MAX_UNCOMPRESS_SIZE 0x8000
|
||||
#define MAX_FILE_SIZE (UINT16_MAX * MAX_UNCOMPRESS_SIZE)
|
||||
#define MAX_E8_TRANSLATION (0x8000 * MAX_UNCOMPRESS_SIZE)
|
||||
|
||||
static const char * const compression_name[] = {
|
||||
"NONE",
|
||||
"MSZIP",
|
||||
@@ -240,8 +346,6 @@ struct cffile {
|
||||
};
|
||||
|
||||
struct cfheader {
|
||||
/* Total bytes of all file size in a Cabinet. */
|
||||
uint32_t total_bytes;
|
||||
uint32_t files_offset;
|
||||
uint16_t folder_count;
|
||||
uint16_t file_count;
|
||||
@@ -249,7 +353,6 @@ struct cfheader {
|
||||
#define PREV_CABINET 0x0001
|
||||
#define NEXT_CABINET 0x0002
|
||||
#define RESERVE_PRESENT 0x0004
|
||||
uint16_t setid;
|
||||
uint16_t cabinet;
|
||||
/* Version number. */
|
||||
unsigned char major;
|
||||
@@ -264,12 +367,10 @@ struct cfheader {
|
||||
};
|
||||
|
||||
struct cab {
|
||||
/* entry_bytes_remaining is the number of bytes we expect. */
|
||||
/* entry_bytes_remaining is the number of bytes we expect. */
|
||||
int64_t entry_offset;
|
||||
int64_t entry_bytes_remaining;
|
||||
int64_t entry_unconsumed;
|
||||
int64_t entry_compressed_bytes_read;
|
||||
int64_t entry_uncompressed_bytes_read;
|
||||
struct cffolder *entry_cffolder;
|
||||
struct cffile *entry_cffile;
|
||||
struct cfdata *entry_cfdata;
|
||||
@@ -279,7 +380,7 @@ struct cab {
|
||||
struct cfheader cfheader;
|
||||
struct archive_wstring ws;
|
||||
|
||||
/* Flag to mark progress that an archive was read their first header.*/
|
||||
/* Flag to mark progress that first header of an archive was read.*/
|
||||
char found_header;
|
||||
char end_of_archive;
|
||||
char end_of_entry;
|
||||
@@ -314,7 +415,7 @@ static int archive_read_format_cab_read_data_skip(struct archive_read *);
|
||||
static int archive_read_format_cab_cleanup(struct archive_read *);
|
||||
|
||||
static int cab_skip_sfx(struct archive_read *);
|
||||
static time_t cab_dos_time(const unsigned char *);
|
||||
static time_t cab_dos_time(const char *);
|
||||
static int cab_read_data(struct archive_read *, const void **,
|
||||
size_t *, int64_t *);
|
||||
static int cab_read_header(struct archive_read *);
|
||||
@@ -335,15 +436,15 @@ static int lzx_decode_init(struct lzx_stream *, int);
|
||||
static int lzx_read_blocks(struct lzx_stream *, int);
|
||||
static int lzx_decode_blocks(struct lzx_stream *, int);
|
||||
static void lzx_decode_free(struct lzx_stream *);
|
||||
static void lzx_translation(struct lzx_stream *, void *, size_t, uint32_t);
|
||||
static void lzx_translation(struct lzx_stream *, unsigned char *, size_t, int32_t);
|
||||
static void lzx_cleanup_bitstream(struct lzx_stream *);
|
||||
static int lzx_decode(struct lzx_stream *, int);
|
||||
static int lzx_read_pre_tree(struct lzx_stream *);
|
||||
static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
|
||||
static int lzx_huffman_init(struct huffman *, size_t, int);
|
||||
static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, uint16_t);
|
||||
static int lzx_huffman_init(struct huffman *, uint16_t, uint8_t);
|
||||
static void lzx_huffman_free(struct huffman *);
|
||||
static int lzx_make_huffman_table(struct huffman *);
|
||||
static inline int lzx_decode_huffman(struct huffman *, unsigned);
|
||||
static uint16_t lzx_decode_huffman(struct huffman *, uint16_t);
|
||||
|
||||
|
||||
int
|
||||
@@ -433,7 +534,7 @@ archive_read_format_cab_bid(struct archive_read *a, int best_bid)
|
||||
/*
|
||||
* Attempt to handle self-extracting archives
|
||||
* by noting a PE header and searching forward
|
||||
* up to 128k for a 'MSCF' marker.
|
||||
* up to 128k for an 'MSCF' marker.
|
||||
*/
|
||||
if (p[0] == 'M' && p[1] == 'Z') {
|
||||
offset = 0;
|
||||
@@ -465,10 +566,9 @@ static int
|
||||
archive_read_format_cab_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct cab *cab;
|
||||
struct cab *cab = a->format->data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
cab = (struct cab *)(a->format->data);
|
||||
if (strcmp(key, "hdrcharset") == 0) {
|
||||
if (val == NULL || val[0] == 0)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
@@ -501,7 +601,7 @@ cab_skip_sfx(struct archive_read *a)
|
||||
for (;;) {
|
||||
const char *h = __archive_read_ahead(a, window, &bytes);
|
||||
if (h == NULL) {
|
||||
/* Remaining size are less than window. */
|
||||
/* Remaining size is less than window. */
|
||||
window >>= 1;
|
||||
if (window < 128) {
|
||||
archive_set_error(&a->archive,
|
||||
@@ -540,33 +640,34 @@ truncated_error(struct archive_read *a)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
cab_strnlen(const unsigned char *p, size_t maxlen)
|
||||
#ifdef HAVE_STRNLEN
|
||||
#define cab_strnlen(a,b) strnlen(a,b)
|
||||
#else
|
||||
static size_t
|
||||
cab_strnlen(const char *p, size_t maxlen)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i <= maxlen; i++) {
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
if (p[i] == 0)
|
||||
break;
|
||||
}
|
||||
if (i > maxlen)
|
||||
return (-1);/* invalid */
|
||||
return ((ssize_t)i);
|
||||
return (i);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read bytes as much as remaining. */
|
||||
/* Read up to max remaining bytes. */
|
||||
static const void *
|
||||
cab_read_ahead_remaining(struct archive_read *a, size_t min, ssize_t *avail)
|
||||
cab_read_ahead_remaining(struct archive_read *a, size_t max, ssize_t *avail)
|
||||
{
|
||||
const void *p;
|
||||
const void *p = __archive_read_ahead(a, max, avail);
|
||||
|
||||
while (min > 0) {
|
||||
p = __archive_read_ahead(a, min, avail);
|
||||
if (p != NULL)
|
||||
return (p);
|
||||
min--;
|
||||
}
|
||||
return (NULL);
|
||||
if (p == NULL && *avail > 0)
|
||||
p = __archive_read_ahead(a, *avail, avail);
|
||||
if (p != NULL && (size_t)*avail > max)
|
||||
*avail = max;
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* Convert a path separator '\' -> '/' */
|
||||
@@ -623,11 +724,11 @@ cab_convert_path_separator_2(struct cab *cab, struct archive_entry *entry)
|
||||
static int
|
||||
cab_read_header(struct archive_read *a)
|
||||
{
|
||||
const unsigned char *p;
|
||||
struct cab *cab;
|
||||
struct cab *cab = a->format->data;
|
||||
const char *p;
|
||||
struct cfheader *hd;
|
||||
size_t bytes, used;
|
||||
ssize_t len;
|
||||
size_t bytes, len, maxlen, used;
|
||||
ssize_t avail;
|
||||
int64_t skip;
|
||||
int err, i;
|
||||
int cur_folder, prev_folder;
|
||||
@@ -640,7 +741,6 @@ cab_read_header(struct archive_read *a)
|
||||
if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
|
||||
return (truncated_error(a));
|
||||
|
||||
cab = (struct cab *)(a->format->data);
|
||||
if (cab->found_header == 0 &&
|
||||
p[0] == 'M' && p[1] == 'Z') {
|
||||
/* This is an executable? Must be self-extracting... */
|
||||
@@ -664,7 +764,6 @@ cab_read_header(struct archive_read *a)
|
||||
"Couldn't find out CAB header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
hd->total_bytes = archive_le32dec(p + CFHEADER_cbCabinet);
|
||||
hd->files_offset = archive_le32dec(p + CFHEADER_coffFiles);
|
||||
hd->minor = p[CFHEADER_versionMinor];
|
||||
hd->major = p[CFHEADER_versionMajor];
|
||||
@@ -675,7 +774,6 @@ cab_read_header(struct archive_read *a)
|
||||
if (hd->file_count == 0)
|
||||
goto invalid;
|
||||
hd->flags = archive_le16dec(p + CFHEADER_flags);
|
||||
hd->setid = archive_le16dec(p + CFHEADER_setID);
|
||||
hd->cabinet = archive_le16dec(p + CFHEADER_iCabinet);
|
||||
used = CFHEADER_iCabinet + 2;
|
||||
if (hd->flags & RESERVE_PRESENT) {
|
||||
@@ -691,29 +789,42 @@ cab_read_header(struct archive_read *a)
|
||||
hd->cffolder = 0;/* Avoid compiling warning. */
|
||||
if (hd->flags & PREV_CABINET) {
|
||||
/* How many bytes are used for szCabinetPrev. */
|
||||
if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
|
||||
if ((p = cab_read_ahead_remaining(a, used + 256,
|
||||
&avail)) == NULL || (size_t)avail <= used)
|
||||
return (truncated_error(a));
|
||||
if ((len = cab_strnlen(p + used, 255)) <= 0)
|
||||
maxlen = avail - used;
|
||||
len = cab_strnlen(p + used, maxlen);
|
||||
if (len == 0 || len == maxlen) {
|
||||
goto invalid;
|
||||
}
|
||||
used += len + 1;
|
||||
/* How many bytes are used for szDiskPrev. */
|
||||
if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
|
||||
if ((p = cab_read_ahead_remaining(a, used + 256,
|
||||
&avail)) == NULL || (size_t)avail <= used)
|
||||
return (truncated_error(a));
|
||||
if ((len = cab_strnlen(p + used, 255)) <= 0)
|
||||
maxlen = avail - used;
|
||||
len = cab_strnlen(p + used, maxlen);
|
||||
if (len == maxlen)
|
||||
goto invalid;
|
||||
used += len + 1;
|
||||
}
|
||||
if (hd->flags & NEXT_CABINET) {
|
||||
/* How many bytes are used for szCabinetNext. */
|
||||
if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
|
||||
if ((p = cab_read_ahead_remaining(a, used + 256,
|
||||
&avail)) == NULL || (size_t)avail <= used)
|
||||
return (truncated_error(a));
|
||||
if ((len = cab_strnlen(p + used, 255)) <= 0)
|
||||
maxlen = avail - used;
|
||||
len = cab_strnlen(p + used, maxlen);
|
||||
if (len == 0 || len == maxlen)
|
||||
goto invalid;
|
||||
used += len + 1;
|
||||
/* How many bytes are used for szDiskNext. */
|
||||
if ((p = __archive_read_ahead(a, used+256, NULL)) == NULL)
|
||||
if ((p = cab_read_ahead_remaining(a, used + 256,
|
||||
&avail)) == NULL || (size_t)avail <= used)
|
||||
return (truncated_error(a));
|
||||
if ((len = cab_strnlen(p + used, 255)) <= 0)
|
||||
maxlen = avail - used;
|
||||
len = cab_strnlen(p + used, maxlen);
|
||||
if (len == maxlen)
|
||||
goto invalid;
|
||||
used += len + 1;
|
||||
}
|
||||
@@ -776,14 +887,15 @@ cab_read_header(struct archive_read *a)
|
||||
*/
|
||||
/* Seek read pointer to the offset of CFFILE if needed. */
|
||||
skip = (int64_t)hd->files_offset - cab->cab_offset;
|
||||
if (skip < 0) {
|
||||
if (skip < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Invalid offset of CFFILE %jd < %jd",
|
||||
(intmax_t)hd->files_offset, (intmax_t)cab->cab_offset);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (skip) {
|
||||
__archive_read_consume(a, skip);
|
||||
if (__archive_read_consume(a, skip) < 0)
|
||||
return (truncated_error(a));
|
||||
cab->cab_offset += skip;
|
||||
}
|
||||
/* Allocate memory for CFDATA */
|
||||
@@ -795,7 +907,6 @@ cab_read_header(struct archive_read *a)
|
||||
prev_folder = -1;
|
||||
for (i = 0; i < hd->file_count; i++) {
|
||||
struct cffile *file = &(hd->file_array[i]);
|
||||
ssize_t avail;
|
||||
|
||||
if ((p = __archive_read_ahead(a, 16, NULL)) == NULL)
|
||||
return (truncated_error(a));
|
||||
@@ -809,7 +920,9 @@ cab_read_header(struct archive_read *a)
|
||||
cab->cab_offset += 16;
|
||||
if ((p = cab_read_ahead_remaining(a, 256, &avail)) == NULL)
|
||||
return (truncated_error(a));
|
||||
if ((len = cab_strnlen(p, avail-1)) <= 0)
|
||||
maxlen = avail;
|
||||
len = cab_strnlen(p, maxlen);
|
||||
if (len == 0 || len == maxlen)
|
||||
goto invalid;
|
||||
|
||||
/* Copy a pathname. */
|
||||
@@ -821,10 +934,10 @@ cab_read_header(struct archive_read *a)
|
||||
/*
|
||||
* Sanity check if each data is acceptable.
|
||||
*/
|
||||
if (file->uncompressed_size > 0x7FFF8000)
|
||||
if (file->uncompressed_size > MAX_FILE_SIZE)
|
||||
goto invalid;/* Too large */
|
||||
if ((int64_t)file->offset + (int64_t)file->uncompressed_size
|
||||
> ARCHIVE_LITERAL_LL(0x7FFF8000))
|
||||
> (int64_t)MAX_FILE_SIZE)
|
||||
goto invalid;/* Too large */
|
||||
switch (file->folder) {
|
||||
case iFoldCONTINUED_TO_NEXT:
|
||||
@@ -890,14 +1003,13 @@ static int
|
||||
archive_read_format_cab_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct cab *cab;
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfheader *hd;
|
||||
struct cffolder *prev_folder;
|
||||
struct cffile *file;
|
||||
struct archive_string_conv *sconv;
|
||||
int err = ARCHIVE_OK, r;
|
||||
|
||||
cab = (struct cab *)(a->format->data);
|
||||
|
||||
if (cab->found_header == 0) {
|
||||
err = cab_read_header(a);
|
||||
if (err < ARCHIVE_WARN)
|
||||
@@ -915,8 +1027,6 @@ archive_read_format_cab_read_header(struct archive_read *a,
|
||||
|
||||
cab->end_of_entry = 0;
|
||||
cab->end_of_entry_cleanup = 0;
|
||||
cab->entry_compressed_bytes_read = 0;
|
||||
cab->entry_uncompressed_bytes_read = 0;
|
||||
cab->entry_unconsumed = 0;
|
||||
cab->entry_cffile = file;
|
||||
|
||||
@@ -980,7 +1090,7 @@ archive_read_format_cab_read_header(struct archive_read *a,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted "
|
||||
"from %s to current locale.",
|
||||
"from %s to current locale",
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
err = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -1014,7 +1124,7 @@ static int
|
||||
archive_read_format_cab_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
int r;
|
||||
|
||||
switch (cab->entry_cffile->folder) {
|
||||
@@ -1026,7 +1136,7 @@ archive_read_format_cab_read_data(struct archive_read *a,
|
||||
*offset = 0;
|
||||
archive_clear_error(&a->archive);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Cannot restore this file split in multivolume.");
|
||||
"Cannot restore this file split in multivolume");
|
||||
return (ARCHIVE_FAILED);
|
||||
default:
|
||||
break;
|
||||
@@ -1114,7 +1224,7 @@ cab_checksum_cfdata(const void *p, size_t bytes, uint32_t seed)
|
||||
static void
|
||||
cab_checksum_update(struct archive_read *a, size_t bytes)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata = cab->entry_cfdata;
|
||||
const unsigned char *p;
|
||||
size_t sumbytes;
|
||||
@@ -1154,7 +1264,7 @@ cab_checksum_update(struct archive_read *a, size_t bytes)
|
||||
static int
|
||||
cab_checksum_finish(struct archive_read *a)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata = cab->entry_cfdata;
|
||||
int l;
|
||||
|
||||
@@ -1175,6 +1285,9 @@ cab_checksum_finish(struct archive_read *a)
|
||||
l = 4;
|
||||
if (cab->cfheader.flags & RESERVE_PRESENT)
|
||||
l += cab->cfheader.cfdata;
|
||||
if (cfdata->memimage == NULL) {
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
cfdata->sum_calculated = cab_checksum_cfdata(
|
||||
cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
|
||||
if (cfdata->sum_calculated != cfdata->sum) {
|
||||
@@ -1196,7 +1309,7 @@ cab_checksum_finish(struct archive_read *a)
|
||||
static int
|
||||
cab_next_cfdata(struct archive_read *a)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata = cab->entry_cfdata;
|
||||
|
||||
/* There are remaining bytes in current CFDATA, use it first. */
|
||||
@@ -1274,9 +1387,9 @@ cab_next_cfdata(struct archive_read *a)
|
||||
* Sanity check if data size is acceptable.
|
||||
*/
|
||||
if (cfdata->compressed_size == 0 ||
|
||||
cfdata->compressed_size > (0x8000+6144))
|
||||
cfdata->compressed_size > (MAX_UNCOMPRESS_SIZE + 6144))
|
||||
goto invalid;
|
||||
if (cfdata->uncompressed_size > 0x8000)
|
||||
if (cfdata->uncompressed_size > MAX_UNCOMPRESS_SIZE)
|
||||
goto invalid;
|
||||
if (cfdata->uncompressed_size == 0) {
|
||||
switch (cab->entry_cffile->folder) {
|
||||
@@ -1289,10 +1402,10 @@ cab_next_cfdata(struct archive_read *a)
|
||||
}
|
||||
}
|
||||
/* If CFDATA is not last in a folder, an uncompressed
|
||||
* size must be 0x8000(32KBi) */
|
||||
* size must be 0x8000 (32 KiB) */
|
||||
if ((cab->entry_cffolder->cfdata_index <
|
||||
cab->entry_cffolder->cfdata_count) &&
|
||||
cfdata->uncompressed_size != 0x8000)
|
||||
cfdata->uncompressed_size != MAX_UNCOMPRESS_SIZE)
|
||||
goto invalid;
|
||||
|
||||
/* A compressed data size and an uncompressed data size must
|
||||
@@ -1344,7 +1457,7 @@ invalid:
|
||||
static const void *
|
||||
cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
int err;
|
||||
|
||||
err = cab_next_cfdata(a);
|
||||
@@ -1362,7 +1475,7 @@ cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
|
||||
return (cab_read_ahead_cfdata_lzx(a, avail));
|
||||
default: /* Unsupported compression. */
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported CAB compression : %s",
|
||||
"Unsupported CAB compression: %s",
|
||||
cab->entry_cffolder->compname);
|
||||
*avail = ARCHIVE_FAILED;
|
||||
return (NULL);
|
||||
@@ -1375,7 +1488,7 @@ cab_read_ahead_cfdata(struct archive_read *a, ssize_t *avail)
|
||||
static const void *
|
||||
cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata;
|
||||
const void *d;
|
||||
|
||||
@@ -1407,7 +1520,7 @@ cab_read_ahead_cfdata_none(struct archive_read *a, ssize_t *avail)
|
||||
static const void *
|
||||
cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata;
|
||||
const void *d;
|
||||
int r, mszip;
|
||||
@@ -1417,7 +1530,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
|
||||
cfdata = cab->entry_cfdata;
|
||||
/* If the buffer hasn't been allocated, allocate it now. */
|
||||
if (cab->uncompressed_buffer == NULL) {
|
||||
cab->uncompressed_buffer_size = 0x8000;
|
||||
cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE;
|
||||
cab->uncompressed_buffer
|
||||
= malloc(cab->uncompressed_buffer_size);
|
||||
if (cab->uncompressed_buffer == NULL) {
|
||||
@@ -1449,7 +1562,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
|
||||
-15 /* Don't check for zlib header */);
|
||||
if (r != Z_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Can't initialize deflate decompression.");
|
||||
"Can't initialize deflate decompression");
|
||||
*avail = ARCHIVE_FATAL;
|
||||
return (NULL);
|
||||
}
|
||||
@@ -1562,11 +1675,9 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
|
||||
* correctly compute the sum of CFDATA accordingly.
|
||||
*/
|
||||
if (cfdata->compressed_bytes_remaining > 0) {
|
||||
ssize_t bytes_avail;
|
||||
|
||||
d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
|
||||
&bytes_avail);
|
||||
if (bytes_avail <= 0) {
|
||||
NULL);
|
||||
if (d == NULL) {
|
||||
*avail = truncated_error(a);
|
||||
return (NULL);
|
||||
}
|
||||
@@ -1637,7 +1748,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
|
||||
static const void *
|
||||
cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata;
|
||||
const void *d;
|
||||
int r;
|
||||
@@ -1646,7 +1757,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
|
||||
cfdata = cab->entry_cfdata;
|
||||
/* If the buffer hasn't been allocated, allocate it now. */
|
||||
if (cab->uncompressed_buffer == NULL) {
|
||||
cab->uncompressed_buffer_size = 0x8000;
|
||||
cab->uncompressed_buffer_size = MAX_UNCOMPRESS_SIZE;
|
||||
cab->uncompressed_buffer
|
||||
= malloc(cab->uncompressed_buffer_size);
|
||||
if (cab->uncompressed_buffer == NULL) {
|
||||
@@ -1669,7 +1780,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
|
||||
cab->entry_cffolder->compdata);
|
||||
if (r != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Can't initialize LZX decompression.");
|
||||
"Can't initialize LZX decompression");
|
||||
*avail = ARCHIVE_FATAL;
|
||||
return (NULL);
|
||||
}
|
||||
@@ -1727,11 +1838,9 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
|
||||
* Make sure a read pointer advances to next CFDATA.
|
||||
*/
|
||||
if (cfdata->compressed_bytes_remaining > 0) {
|
||||
ssize_t bytes_avail;
|
||||
|
||||
d = __archive_read_ahead(a, cfdata->compressed_bytes_remaining,
|
||||
&bytes_avail);
|
||||
if (bytes_avail <= 0) {
|
||||
NULL);
|
||||
if (d == NULL) {
|
||||
*avail = truncated_error(a);
|
||||
return (NULL);
|
||||
}
|
||||
@@ -1748,7 +1857,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
|
||||
*/
|
||||
lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
|
||||
cfdata->uncompressed_size,
|
||||
(cab->entry_cffolder->cfdata_index-1) * 0x8000);
|
||||
(cab->entry_cffolder->cfdata_index - 1) * MAX_UNCOMPRESS_SIZE);
|
||||
|
||||
d = cab->uncompressed_buffer + cfdata->read_offset;
|
||||
*avail = uavail - cfdata->read_offset;
|
||||
@@ -1769,7 +1878,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
|
||||
static int64_t
|
||||
cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata;
|
||||
int64_t cbytes, rbytes;
|
||||
int err;
|
||||
@@ -1862,7 +1971,7 @@ cab_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
|
||||
static int64_t
|
||||
cab_minimum_consume_cfdata(struct archive_read *a, int64_t consumed_bytes)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfdata *cfdata;
|
||||
int64_t cbytes, rbytes;
|
||||
int err;
|
||||
@@ -1919,7 +2028,7 @@ static int
|
||||
cab_read_data(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
ssize_t bytes_avail;
|
||||
|
||||
if (cab->entry_bytes_remaining == 0) {
|
||||
@@ -1965,12 +2074,10 @@ cab_read_data(struct archive_read *a, const void **buff,
|
||||
static int
|
||||
archive_read_format_cab_read_data_skip(struct archive_read *a)
|
||||
{
|
||||
struct cab *cab;
|
||||
struct cab *cab = a->format->data;
|
||||
int64_t bytes_skipped;
|
||||
int r;
|
||||
|
||||
cab = (struct cab *)(a->format->data);
|
||||
|
||||
if (cab->end_of_archive)
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
@@ -2020,9 +2127,9 @@ archive_read_format_cab_read_data_skip(struct archive_read *a)
|
||||
static int
|
||||
archive_read_format_cab_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct cab *cab = (struct cab *)(a->format->data);
|
||||
struct cab *cab = a->format->data;
|
||||
struct cfheader *hd = &cab->cfheader;
|
||||
int i;
|
||||
uint16_t i;
|
||||
|
||||
if (hd->folder_array != NULL) {
|
||||
for (i = 0; i < hd->folder_count; i++)
|
||||
@@ -2042,13 +2149,13 @@ archive_read_format_cab_cleanup(struct archive_read *a)
|
||||
archive_wstring_free(&cab->ws);
|
||||
free(cab->uncompressed_buffer);
|
||||
free(cab);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/* Convert an MSDOS-style date/time into Unix-style time. */
|
||||
static time_t
|
||||
cab_dos_time(const unsigned char *p)
|
||||
cab_dos_time(const char *p)
|
||||
{
|
||||
int msTime, msDate;
|
||||
struct tm ts;
|
||||
@@ -2084,10 +2191,11 @@ cab_dos_time(const unsigned char *p)
|
||||
static int
|
||||
lzx_decode_init(struct lzx_stream *strm, int w_bits)
|
||||
{
|
||||
struct lzx_dec *ds;
|
||||
int slot, w_size, w_slot;
|
||||
int base, footer;
|
||||
int base_inc[18];
|
||||
struct lzx_dec *ds;
|
||||
uint32_t base;
|
||||
uint16_t slot, w_size, w_slot;
|
||||
uint8_t footer;
|
||||
|
||||
if (strm->ds == NULL) {
|
||||
strm->ds = calloc(1, sizeof(*strm->ds));
|
||||
@@ -2097,7 +2205,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
|
||||
ds = strm->ds;
|
||||
ds->error = ARCHIVE_FAILED;
|
||||
|
||||
/* Allow bits from 15(32KBi) up to 21(2MBi) */
|
||||
/* Allow bits from 15 (32 KiB) up to 21 (2 MiB) */
|
||||
if (w_bits < SLOT_BASE || w_bits > SLOT_MAX)
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
@@ -2109,7 +2217,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
|
||||
w_size = ds->w_size;
|
||||
w_slot = slots[w_bits - SLOT_BASE];
|
||||
ds->w_size = 1U << w_bits;
|
||||
ds->w_mask = ds->w_size -1;
|
||||
ds->w_mask = ds->w_size - 1;
|
||||
if (ds->w_buff == NULL || w_size != ds->w_size) {
|
||||
free(ds->w_buff);
|
||||
ds->w_buff = malloc(ds->w_size);
|
||||
@@ -2131,18 +2239,20 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
|
||||
else
|
||||
base += base_inc[footer];
|
||||
if (footer < 17) {
|
||||
footer = -2;
|
||||
footer = 0;
|
||||
for (n = base; n; n >>= 1)
|
||||
footer++;
|
||||
if (footer <= 0)
|
||||
if (footer <= 2)
|
||||
footer = 0;
|
||||
else
|
||||
footer -= 2;
|
||||
}
|
||||
ds->pos_tbl[slot].base = base;
|
||||
ds->pos_tbl[slot].footer_bits = footer;
|
||||
}
|
||||
|
||||
ds->w_pos = 0;
|
||||
ds->state = 0;
|
||||
ds->state = ST_RD_TRANSLATION;
|
||||
ds->br.cache_buffer = 0;
|
||||
ds->br.cache_avail = 0;
|
||||
ds->r0 = ds->r1 = ds->r2 = 1;
|
||||
@@ -2156,7 +2266,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
/* Initialize Main tree. */
|
||||
if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
|
||||
if (lzx_huffman_init(&(ds->mt), 256 + (w_slot << 3), 16)
|
||||
!= ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
@@ -2192,29 +2302,36 @@ lzx_decode_free(struct lzx_stream *strm)
|
||||
* E8 Call Translation reversal.
|
||||
*/
|
||||
static void
|
||||
lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
|
||||
lzx_translation(struct lzx_stream *strm, unsigned char *buffer, size_t size,
|
||||
int32_t offset)
|
||||
{
|
||||
struct lzx_dec *ds = strm->ds;
|
||||
unsigned char *b, *end;
|
||||
unsigned char *p, *end;
|
||||
|
||||
if (!ds->translation || size <= 10)
|
||||
if (!ds->translation || offset >= MAX_E8_TRANSLATION || size <= 10)
|
||||
return;
|
||||
b = p;
|
||||
end = b + size - 10;
|
||||
while (b < end && (b = memchr(b, 0xE8, end - b)) != NULL) {
|
||||
size_t i = b - (unsigned char *)p;
|
||||
int32_t cp, displacement, value;
|
||||
|
||||
cp = (int32_t)(offset + (uint32_t)i);
|
||||
value = archive_le32dec(&b[1]);
|
||||
if (value >= -cp && value < (int32_t)ds->translation_size) {
|
||||
if (value >= 0)
|
||||
displacement = value - cp;
|
||||
p = buffer;
|
||||
end = buffer + size - 10;
|
||||
|
||||
while (p < end && (p = memchr(p, 0xE8, end - p)) != NULL) {
|
||||
int32_t address, position;
|
||||
|
||||
address = archive_le32dec(p + 1);
|
||||
position = offset + (p - buffer);
|
||||
|
||||
if (address >= -position && address < ds->translation_size) {
|
||||
uint32_t relative;
|
||||
|
||||
if (address >= 0)
|
||||
relative = address - position;
|
||||
else
|
||||
displacement = value + ds->translation_size;
|
||||
archive_le32enc(&b[1], (uint32_t)displacement);
|
||||
relative = address + ds->translation_size;
|
||||
|
||||
archive_le32enc(p + 1, relative);
|
||||
}
|
||||
b += 5;
|
||||
|
||||
p += 5;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2236,7 +2353,7 @@ lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
|
||||
* False : we met that strm->next_in is empty, we have to get following
|
||||
* bytes. */
|
||||
#define lzx_br_read_ahead_0(strm, br, n) \
|
||||
(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
|
||||
(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br) == ARCHIVE_OK)
|
||||
/* True : the cache buffer has some bits as much as we need.
|
||||
* False : there are no enough bits in the cache buffer to be used,
|
||||
* we have to get following bytes if we could. */
|
||||
@@ -2265,8 +2382,8 @@ static const uint32_t cache_masks[] = {
|
||||
* Shift away used bits in the cache data and fill it up with following bits.
|
||||
* Call this when cache buffer does not have enough bits you need.
|
||||
*
|
||||
* Returns 1 if the cache buffer is full.
|
||||
* Returns 0 if the cache buffer is not full; input buffer is empty.
|
||||
* Returns ARCHIVE_OK if the cache buffer is full.
|
||||
* Returns ARCHIVE_EOF if the cache buffer is not full; input buffer is empty.
|
||||
*/
|
||||
static int
|
||||
lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
@@ -2274,7 +2391,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
/*
|
||||
* x86 processor family can read misaligned data without an access error.
|
||||
*/
|
||||
int n = CACHE_BITS - br->cache_avail;
|
||||
ssize_t n = CACHE_BITS - br->cache_avail;
|
||||
|
||||
for (;;) {
|
||||
switch (n >> 4) {
|
||||
@@ -2292,7 +2409,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
strm->next_in += 8;
|
||||
strm->avail_in -= 8;
|
||||
br->cache_avail += 8 * 8;
|
||||
return (1);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@@ -2308,13 +2425,13 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
strm->next_in += 6;
|
||||
strm->avail_in -= 6;
|
||||
br->cache_avail += 6 * 8;
|
||||
return (1);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
/* We have enough compressed data in
|
||||
* the cache buffer.*/
|
||||
return (1);
|
||||
return (ARCHIVE_EOF);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2326,7 +2443,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
strm->avail_in--;
|
||||
br->have_odd = 1;
|
||||
}
|
||||
return (0);
|
||||
return (ARCHIVE_EOF);
|
||||
}
|
||||
br->cache_buffer =
|
||||
(br->cache_buffer << 16) |
|
||||
@@ -2341,7 +2458,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
static void
|
||||
lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
|
||||
{
|
||||
int n = CACHE_BITS - br->cache_avail;
|
||||
ssize_t n = CACHE_BITS - br->cache_avail;
|
||||
|
||||
if (br->have_odd && n >= 16 && strm->avail_in > 0) {
|
||||
br->cache_buffer =
|
||||
@@ -2370,35 +2487,11 @@ lzx_cleanup_bitstream(struct lzx_stream *strm)
|
||||
* 3. Returns ARCHIVE_FAILED if an error occurred; compressed data
|
||||
* is broken or you do not set 'last' flag properly.
|
||||
*/
|
||||
#define ST_RD_TRANSLATION 0
|
||||
#define ST_RD_TRANSLATION_SIZE 1
|
||||
#define ST_RD_BLOCK_TYPE 2
|
||||
#define ST_RD_BLOCK_SIZE 3
|
||||
#define ST_RD_ALIGNMENT 4
|
||||
#define ST_RD_R0 5
|
||||
#define ST_RD_R1 6
|
||||
#define ST_RD_R2 7
|
||||
#define ST_COPY_UNCOMP1 8
|
||||
#define ST_COPY_UNCOMP2 9
|
||||
#define ST_RD_ALIGNED_OFFSET 10
|
||||
#define ST_RD_VERBATIM 11
|
||||
#define ST_RD_PRE_MAIN_TREE_256 12
|
||||
#define ST_MAIN_TREE_256 13
|
||||
#define ST_RD_PRE_MAIN_TREE_REM 14
|
||||
#define ST_MAIN_TREE_REM 15
|
||||
#define ST_RD_PRE_LENGTH_TREE 16
|
||||
#define ST_LENGTH_TREE 17
|
||||
#define ST_MAIN 18
|
||||
#define ST_LENGTH 19
|
||||
#define ST_OFFSET 20
|
||||
#define ST_REAL_POS 21
|
||||
#define ST_COPY 22
|
||||
|
||||
static int
|
||||
lzx_decode(struct lzx_stream *strm, int last)
|
||||
{
|
||||
struct lzx_dec *ds = strm->ds;
|
||||
int64_t avail_in;
|
||||
size_t avail_in;
|
||||
int r;
|
||||
|
||||
if (ds->error)
|
||||
@@ -2410,7 +2503,8 @@ lzx_decode(struct lzx_stream *strm, int last)
|
||||
if (ds->state < ST_MAIN)
|
||||
r = lzx_read_blocks(strm, last);
|
||||
else {
|
||||
int64_t bytes_written = strm->avail_out;
|
||||
size_t bytes_written = strm->avail_out;
|
||||
|
||||
r = lzx_decode_blocks(strm, last);
|
||||
bytes_written -= strm->avail_out;
|
||||
strm->next_out += bytes_written;
|
||||
@@ -2426,7 +2520,8 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
{
|
||||
struct lzx_dec *ds = strm->ds;
|
||||
struct lzx_br *br = &(ds->br);
|
||||
int i, r;
|
||||
int r;
|
||||
uint16_t i;
|
||||
|
||||
for (;;) {
|
||||
switch (ds->state) {
|
||||
@@ -2442,16 +2537,21 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
/* FALL THROUGH */
|
||||
case ST_RD_TRANSLATION_SIZE:
|
||||
if (ds->translation) {
|
||||
uint32_t v;
|
||||
|
||||
if (!lzx_br_read_ahead(strm, br, 32)) {
|
||||
ds->state = ST_RD_TRANSLATION_SIZE;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
ds->translation_size = lzx_br_bits(br, 16);
|
||||
v = lzx_br_bits(br, 16);
|
||||
lzx_br_consume(br, 16);
|
||||
ds->translation_size <<= 16;
|
||||
ds->translation_size |= lzx_br_bits(br, 16);
|
||||
v <<= 16;
|
||||
v |= lzx_br_bits(br, 16);
|
||||
if (v > MAX_FILE_SIZE)
|
||||
goto failed;
|
||||
ds->translation_size = (int32_t)v;
|
||||
lzx_br_consume(br, 16);
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
@@ -2558,17 +2658,17 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
ds->rbytes_avail = 0;
|
||||
if (ds->state == ST_RD_R0) {
|
||||
ds->r0 = archive_le32dec(ds->rbytes);
|
||||
if (ds->r0 < 0)
|
||||
if (ds->r0 > (size_t)INT32_MAX)
|
||||
goto failed;
|
||||
ds->state = ST_RD_R1;
|
||||
} else if (ds->state == ST_RD_R1) {
|
||||
ds->r1 = archive_le32dec(ds->rbytes);
|
||||
if (ds->r1 < 0)
|
||||
if (ds->r1 > (size_t)INT32_MAX)
|
||||
goto failed;
|
||||
ds->state = ST_RD_R2;
|
||||
} else if (ds->state == ST_RD_R2) {
|
||||
ds->r2 = archive_le32dec(ds->rbytes);
|
||||
if (ds->r2 < 0)
|
||||
if (ds->r2 > (size_t)INT32_MAX)
|
||||
goto failed;
|
||||
/* We've gotten all repeated offsets. */
|
||||
ds->state = ST_COPY_UNCOMP1;
|
||||
@@ -2577,10 +2677,10 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
/* FALL THROUGH */
|
||||
case ST_COPY_UNCOMP1:
|
||||
/*
|
||||
* Copy bytes form next_in to next_out directly.
|
||||
* Copy bytes from next_in to next_out directly.
|
||||
*/
|
||||
while (ds->block_bytes_avail) {
|
||||
int l;
|
||||
size_t l;
|
||||
|
||||
if (strm->avail_out <= 0)
|
||||
/* Output buffer is empty. */
|
||||
@@ -2591,13 +2691,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
l = (int)ds->block_bytes_avail;
|
||||
l = ds->block_bytes_avail;
|
||||
if (l > ds->w_size - ds->w_pos)
|
||||
l = ds->w_size - ds->w_pos;
|
||||
if (l > strm->avail_out)
|
||||
l = (int)strm->avail_out;
|
||||
l = strm->avail_out;
|
||||
if (l > strm->avail_in)
|
||||
l = (int)strm->avail_in;
|
||||
l = strm->avail_in;
|
||||
memcpy(strm->next_out, strm->next_in, l);
|
||||
memcpy(&(ds->w_buff[ds->w_pos]),
|
||||
strm->next_in, l);
|
||||
@@ -2631,19 +2731,19 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
/*
|
||||
* Read Aligned offset tree.
|
||||
*/
|
||||
if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
|
||||
if (!lzx_br_read_ahead(strm, br, 3 * ds->at.symbol_count)) {
|
||||
ds->state = ST_RD_ALIGNED_OFFSET;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
memset(ds->at.freq, 0, sizeof(ds->at.freq));
|
||||
for (i = 0; i < ds->at.len_size; i++) {
|
||||
for (i = 0; i < ds->at.symbol_count; i++) {
|
||||
ds->at.bitlen[i] = lzx_br_bits(br, 3);
|
||||
ds->at.freq[ds->at.bitlen[i]]++;
|
||||
lzx_br_consume(br, 3);
|
||||
}
|
||||
if (!lzx_make_huffman_table(&ds->at))
|
||||
if (lzx_make_huffman_table(&ds->at) < 0)
|
||||
goto failed;
|
||||
/* FALL THROUGH */
|
||||
case ST_RD_VERBATIM:
|
||||
@@ -2653,13 +2753,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
/*
|
||||
* Read Pre-tree for first 256 elements of main tree.
|
||||
*/
|
||||
if (!lzx_read_pre_tree(strm)) {
|
||||
if (lzx_read_pre_tree(strm) < 0) {
|
||||
ds->state = ST_RD_PRE_MAIN_TREE_256;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (!lzx_make_huffman_table(&ds->pt))
|
||||
if (lzx_make_huffman_table(&ds->pt) < 0)
|
||||
goto failed;
|
||||
ds->loop = 0;
|
||||
/* FALL THROUGH */
|
||||
@@ -2668,27 +2768,26 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
* Get path lengths of first 256 elements of main tree.
|
||||
*/
|
||||
r = lzx_read_bitlen(strm, &ds->mt, 256);
|
||||
if (r < 0)
|
||||
goto failed;
|
||||
else if (!r) {
|
||||
if (r == ARCHIVE_EOF) {
|
||||
ds->state = ST_MAIN_TREE_256;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
} else if (r < 0)
|
||||
goto failed;
|
||||
ds->loop = 0;
|
||||
/* FALL THROUGH */
|
||||
case ST_RD_PRE_MAIN_TREE_REM:
|
||||
/*
|
||||
* Read Pre-tree for remaining elements of main tree.
|
||||
*/
|
||||
if (!lzx_read_pre_tree(strm)) {
|
||||
if (lzx_read_pre_tree(strm) < 0) {
|
||||
ds->state = ST_RD_PRE_MAIN_TREE_REM;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (!lzx_make_huffman_table(&ds->pt))
|
||||
if (lzx_make_huffman_table(&ds->pt) < 0)
|
||||
goto failed;
|
||||
ds->loop = 256;
|
||||
/* FALL THROUGH */
|
||||
@@ -2696,16 +2795,15 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
/*
|
||||
* Get path lengths of remaining elements of main tree.
|
||||
*/
|
||||
r = lzx_read_bitlen(strm, &ds->mt, -1);
|
||||
if (r < 0)
|
||||
goto failed;
|
||||
else if (!r) {
|
||||
r = lzx_read_bitlen(strm, &ds->mt, 0);
|
||||
if (r == ARCHIVE_EOF) {
|
||||
ds->state = ST_MAIN_TREE_REM;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (!lzx_make_huffman_table(&ds->mt))
|
||||
} else if (r < 0)
|
||||
goto failed;
|
||||
if (lzx_make_huffman_table(&ds->mt) < 0)
|
||||
goto failed;
|
||||
ds->loop = 0;
|
||||
/* FALL THROUGH */
|
||||
@@ -2713,13 +2811,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
/*
|
||||
* Read Pre-tree for remaining elements of main tree.
|
||||
*/
|
||||
if (!lzx_read_pre_tree(strm)) {
|
||||
if (lzx_read_pre_tree(strm) < 0) {
|
||||
ds->state = ST_RD_PRE_LENGTH_TREE;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (!lzx_make_huffman_table(&ds->pt))
|
||||
if (lzx_make_huffman_table(&ds->pt) < 0)
|
||||
goto failed;
|
||||
ds->loop = 0;
|
||||
/* FALL THROUGH */
|
||||
@@ -2727,16 +2825,15 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
|
||||
/*
|
||||
* Get path lengths of remaining elements of main tree.
|
||||
*/
|
||||
r = lzx_read_bitlen(strm, &ds->lt, -1);
|
||||
if (r < 0)
|
||||
goto failed;
|
||||
else if (!r) {
|
||||
r = lzx_read_bitlen(strm, &ds->lt, 0);
|
||||
if (r == ARCHIVE_EOF) {
|
||||
ds->state = ST_LENGTH_TREE;
|
||||
if (last)
|
||||
goto failed;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (!lzx_make_huffman_table(&ds->lt))
|
||||
} else if (r < 0)
|
||||
goto failed;
|
||||
if (lzx_make_huffman_table(&ds->lt) < 0)
|
||||
goto failed;
|
||||
ds->state = ST_MAIN;
|
||||
return (100);
|
||||
@@ -2755,22 +2852,23 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
|
||||
unsigned char *noutp = strm->next_out;
|
||||
unsigned char *endp = noutp + strm->avail_out;
|
||||
unsigned char *w_buff = ds->w_buff;
|
||||
unsigned char *at_bitlen = at->bitlen;
|
||||
unsigned char *lt_bitlen = lt->bitlen;
|
||||
unsigned char *mt_bitlen = mt->bitlen;
|
||||
uint8_t *w_buff = ds->w_buff;
|
||||
uint8_t *at_bitlen = at->bitlen;
|
||||
uint8_t *lt_bitlen = lt->bitlen;
|
||||
uint8_t *mt_bitlen = mt->bitlen;
|
||||
size_t block_bytes_avail = ds->block_bytes_avail;
|
||||
int at_max_bits = at->max_bits;
|
||||
int lt_max_bits = lt->max_bits;
|
||||
int mt_max_bits = mt->max_bits;
|
||||
int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
|
||||
int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
|
||||
int length_header = ds->length_header;
|
||||
int offset_bits = ds->offset_bits;
|
||||
int position_slot = ds->position_slot;
|
||||
int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
|
||||
uint8_t at_lookup_bits = at->lookup_bits;
|
||||
uint8_t lt_lookup_bits = lt->lookup_bits;
|
||||
uint8_t mt_lookup_bits = mt->lookup_bits;
|
||||
size_t copy_len = ds->copy_len, copy_pos = ds->copy_pos;
|
||||
size_t w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
|
||||
uint8_t length_header = ds->length_header;
|
||||
uint8_t offset_bits = ds->offset_bits;
|
||||
uint16_t position_slot = ds->position_slot;
|
||||
size_t r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
|
||||
int state = ds->state;
|
||||
char block_type = ds->block_type;
|
||||
uint16_t c;
|
||||
uint8_t block_type = ds->block_type;
|
||||
|
||||
for (;;) {
|
||||
switch (state) {
|
||||
@@ -2796,26 +2894,26 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
goto next_data;
|
||||
|
||||
if (!lzx_br_read_ahead(strm, &bre,
|
||||
mt_max_bits)) {
|
||||
mt_lookup_bits)) {
|
||||
if (!last)
|
||||
goto next_data;
|
||||
/* Remaining bits are less than
|
||||
* maximum bits(mt.max_bits) but maybe
|
||||
* it still remains as much as we need,
|
||||
* so we should try to use it with
|
||||
* dummy bits. */
|
||||
* maximum bits (mt.lookup_bits) but
|
||||
* maybe it still remains as much as we
|
||||
* need, so we should try to use it
|
||||
* with dummy bits. */
|
||||
c = lzx_decode_huffman(mt,
|
||||
lzx_br_bits_forced(
|
||||
&bre, mt_max_bits));
|
||||
lzx_br_consume(&bre, mt_bitlen[c]);
|
||||
if (!lzx_br_has(&bre, 0))
|
||||
&bre, mt_lookup_bits));
|
||||
if (!lzx_br_has(&bre, mt_bitlen[c]))
|
||||
goto failed;/* Over read. */
|
||||
lzx_br_consume(&bre, mt_bitlen[c]);
|
||||
} else {
|
||||
c = lzx_decode_huffman(mt,
|
||||
lzx_br_bits(&bre, mt_max_bits));
|
||||
lzx_br_bits(&bre, mt_lookup_bits));
|
||||
lzx_br_consume(&bre, mt_bitlen[c]);
|
||||
}
|
||||
if ((unsigned int)c > UCHAR_MAX)
|
||||
if (c > UCHAR_MAX)
|
||||
break;
|
||||
/*
|
||||
* 'c' is exactly literal code.
|
||||
@@ -2841,26 +2939,26 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
*/
|
||||
if (length_header == 7) {
|
||||
if (!lzx_br_read_ahead(strm, &bre,
|
||||
lt_max_bits)) {
|
||||
lt_lookup_bits)) {
|
||||
if (!last) {
|
||||
state = ST_LENGTH;
|
||||
goto next_data;
|
||||
}
|
||||
c = lzx_decode_huffman(lt,
|
||||
lzx_br_bits_forced(
|
||||
&bre, lt_max_bits));
|
||||
lzx_br_consume(&bre, lt_bitlen[c]);
|
||||
if (!lzx_br_has(&bre, 0))
|
||||
&bre, lt_lookup_bits));
|
||||
if (!lzx_br_has(&bre, lt_bitlen[c]))
|
||||
goto failed;/* Over read. */
|
||||
lzx_br_consume(&bre, lt_bitlen[c]);
|
||||
} else {
|
||||
c = lzx_decode_huffman(lt,
|
||||
lzx_br_bits(&bre, lt_max_bits));
|
||||
lzx_br_bits(&bre, lt_lookup_bits));
|
||||
lzx_br_consume(&bre, lt_bitlen[c]);
|
||||
}
|
||||
copy_len = c + 7 + 2;
|
||||
} else
|
||||
copy_len = length_header + 2;
|
||||
if ((size_t)copy_len > block_bytes_avail)
|
||||
if (copy_len > block_bytes_avail)
|
||||
goto failed;
|
||||
/*
|
||||
* Get an offset.
|
||||
@@ -2897,7 +2995,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
*/
|
||||
if (block_type == ALIGNED_OFFSET_BLOCK &&
|
||||
offset_bits >= 3) {
|
||||
int offbits = offset_bits - 3;
|
||||
unsigned offbits = offset_bits - 3;
|
||||
|
||||
if (!lzx_br_read_ahead(strm, &bre, offbits)) {
|
||||
state = ST_OFFSET;
|
||||
@@ -2909,7 +3007,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
|
||||
/* Get an aligned number. */
|
||||
if (!lzx_br_read_ahead(strm, &bre,
|
||||
offbits + at_max_bits)) {
|
||||
offbits + at_lookup_bits)) {
|
||||
if (!last) {
|
||||
state = ST_OFFSET;
|
||||
goto next_data;
|
||||
@@ -2917,14 +3015,14 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
lzx_br_consume(&bre, offbits);
|
||||
c = lzx_decode_huffman(at,
|
||||
lzx_br_bits_forced(&bre,
|
||||
at_max_bits));
|
||||
lzx_br_consume(&bre, at_bitlen[c]);
|
||||
if (!lzx_br_has(&bre, 0))
|
||||
at_lookup_bits));
|
||||
if (!lzx_br_has(&bre, at_bitlen[c]))
|
||||
goto failed;/* Over read. */
|
||||
lzx_br_consume(&bre, at_bitlen[c]);
|
||||
} else {
|
||||
lzx_br_consume(&bre, offbits);
|
||||
c = lzx_decode_huffman(at,
|
||||
lzx_br_bits(&bre, at_max_bits));
|
||||
lzx_br_bits(&bre, at_lookup_bits));
|
||||
lzx_br_consume(&bre, at_bitlen[c]);
|
||||
}
|
||||
/* Add an aligned number. */
|
||||
@@ -2940,7 +3038,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
copy_pos = lzx_br_bits(&bre, offset_bits);
|
||||
lzx_br_consume(&bre, offset_bits);
|
||||
}
|
||||
copy_pos += pos_tbl[position_slot].base -2;
|
||||
copy_pos += pos_tbl[position_slot].base - 2;
|
||||
|
||||
/* Update repeated offset LRU queue. */
|
||||
r2 = r1;
|
||||
@@ -2959,8 +3057,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
* into the output buffer.
|
||||
*/
|
||||
for (;;) {
|
||||
const unsigned char *s;
|
||||
int l;
|
||||
const uint8_t *s;
|
||||
size_t l;
|
||||
|
||||
l = copy_len;
|
||||
if (copy_pos > w_pos) {
|
||||
@@ -2971,15 +3069,15 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
|
||||
l = w_size - w_pos;
|
||||
}
|
||||
if (noutp + l >= endp)
|
||||
l = (int)(endp - noutp);
|
||||
l = endp - noutp;
|
||||
s = w_buff + copy_pos;
|
||||
if (l >= 8 && ((copy_pos + l < w_pos)
|
||||
|| (w_pos + l < copy_pos))) {
|
||||
memcpy(w_buff + w_pos, s, l);
|
||||
memcpy(noutp, s, l);
|
||||
} else {
|
||||
unsigned char *d;
|
||||
int li;
|
||||
uint8_t *d;
|
||||
size_t li;
|
||||
|
||||
d = w_buff + w_pos;
|
||||
for (li = 0; li < l; li++)
|
||||
@@ -3025,122 +3123,124 @@ lzx_read_pre_tree(struct lzx_stream *strm)
|
||||
{
|
||||
struct lzx_dec *ds = strm->ds;
|
||||
struct lzx_br *br = &(ds->br);
|
||||
int i;
|
||||
uint16_t i;
|
||||
|
||||
if (ds->loop == 0)
|
||||
memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
|
||||
for (i = ds->loop; i < ds->pt.len_size; i++) {
|
||||
for (i = ds->loop; i < ds->pt.symbol_count; i++) {
|
||||
if (!lzx_br_read_ahead(strm, br, 4)) {
|
||||
ds->loop = i;
|
||||
return (0);
|
||||
return (ARCHIVE_EOF);
|
||||
}
|
||||
ds->pt.bitlen[i] = lzx_br_bits(br, 4);
|
||||
ds->pt.freq[ds->pt.bitlen[i]]++;
|
||||
lzx_br_consume(br, 4);
|
||||
}
|
||||
ds->loop = i;
|
||||
return (1);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a bunch of bit-lengths from pre-tree.
|
||||
*/
|
||||
static int
|
||||
lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
|
||||
lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, uint16_t end)
|
||||
{
|
||||
struct lzx_dec *ds = strm->ds;
|
||||
struct lzx_br *br = &(ds->br);
|
||||
int c, i, j, ret, same;
|
||||
unsigned rbits;
|
||||
int ret;
|
||||
uint16_t c, i, j, rbits, same;
|
||||
|
||||
i = ds->loop;
|
||||
if (i == 0)
|
||||
memset(d->freq, 0, sizeof(d->freq));
|
||||
ret = 0;
|
||||
if (end < 0)
|
||||
end = d->len_size;
|
||||
ret = ARCHIVE_EOF;
|
||||
if (end == 0)
|
||||
end = d->symbol_count;
|
||||
while (i < end) {
|
||||
ds->loop = i;
|
||||
if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
|
||||
if (!lzx_br_read_ahead(strm, br, (unsigned)ds->pt.lookup_bits))
|
||||
goto getdata;
|
||||
rbits = lzx_br_bits(br, ds->pt.max_bits);
|
||||
rbits = lzx_br_bits(br, ds->pt.lookup_bits);
|
||||
c = lzx_decode_huffman(&(ds->pt), rbits);
|
||||
switch (c) {
|
||||
case 17:/* several zero lengths, from 4 to 19. */
|
||||
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
|
||||
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 4U))
|
||||
goto getdata;
|
||||
lzx_br_consume(br, ds->pt.bitlen[c]);
|
||||
same = lzx_br_bits(br, 4) + 4;
|
||||
if (i + same > end)
|
||||
return (-1);/* Invalid */
|
||||
if (same > end - i)
|
||||
return (ARCHIVE_FATAL);
|
||||
lzx_br_consume(br, 4);
|
||||
for (j = 0; j < same; j++)
|
||||
d->bitlen[i++] = 0;
|
||||
break;
|
||||
case 18:/* many zero lengths, from 20 to 51. */
|
||||
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
|
||||
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 5U))
|
||||
goto getdata;
|
||||
lzx_br_consume(br, ds->pt.bitlen[c]);
|
||||
same = lzx_br_bits(br, 5) + 20;
|
||||
if (i + same > end)
|
||||
return (-1);/* Invalid */
|
||||
if (same > end - i)
|
||||
return (ARCHIVE_FATAL);
|
||||
lzx_br_consume(br, 5);
|
||||
memset(d->bitlen + i, 0, same);
|
||||
i += same;
|
||||
break;
|
||||
case 19:/* a few same lengths. */
|
||||
if (!lzx_br_read_ahead(strm, br,
|
||||
ds->pt.bitlen[c]+1+ds->pt.max_bits))
|
||||
ds->pt.bitlen[c] + 1U + ds->pt.lookup_bits))
|
||||
goto getdata;
|
||||
lzx_br_consume(br, ds->pt.bitlen[c]);
|
||||
same = lzx_br_bits(br, 1) + 4;
|
||||
if (i + same > end)
|
||||
return (-1);
|
||||
if (same > end - i)
|
||||
return (ARCHIVE_FATAL);
|
||||
lzx_br_consume(br, 1);
|
||||
rbits = lzx_br_bits(br, ds->pt.max_bits);
|
||||
rbits = lzx_br_bits(br, ds->pt.lookup_bits);
|
||||
c = lzx_decode_huffman(&(ds->pt), rbits);
|
||||
lzx_br_consume(br, ds->pt.bitlen[c]);
|
||||
c = (d->bitlen[i] - c + 17) % 17;
|
||||
if (c < 0)
|
||||
return (-1);/* Invalid */
|
||||
if (c > d->bitlen[i] + 17)
|
||||
return (ARCHIVE_FATAL);
|
||||
c = (d->bitlen[i] + 17 - c) % 17;
|
||||
for (j = 0; j < same; j++)
|
||||
d->bitlen[i++] = c;
|
||||
d->freq[c] += same;
|
||||
break;
|
||||
default:
|
||||
lzx_br_consume(br, ds->pt.bitlen[c]);
|
||||
c = (d->bitlen[i] - c + 17) % 17;
|
||||
if (c < 0)
|
||||
return (-1);/* Invalid */
|
||||
if (c > d->bitlen[i] + 17)
|
||||
return (ARCHIVE_FATAL);
|
||||
c = (d->bitlen[i] + 17 - c) % 17;
|
||||
d->freq[c]++;
|
||||
d->bitlen[i++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret = 1;
|
||||
ret = ARCHIVE_OK;
|
||||
getdata:
|
||||
ds->loop = i;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
|
||||
lzx_huffman_init(struct huffman *hf, uint16_t symbol_count, uint8_t tbl_bits)
|
||||
{
|
||||
size_t tbl_size = (size_t)1 << tbl_bits;
|
||||
|
||||
if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
|
||||
if (hf->bitlen == NULL || hf->symbol_count != symbol_count) {
|
||||
free(hf->bitlen);
|
||||
hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));
|
||||
hf->bitlen = calloc(symbol_count, sizeof(hf->bitlen[0]));
|
||||
if (hf->bitlen == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
hf->len_size = (int)len_size;
|
||||
hf->symbol_count = symbol_count;
|
||||
} else
|
||||
memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));
|
||||
memset(hf->bitlen, 0, symbol_count * sizeof(hf->bitlen[0]));
|
||||
if (hf->tbl == NULL) {
|
||||
hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));
|
||||
hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));
|
||||
if (hf->tbl == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
hf->tbl_bits = tbl_bits;
|
||||
}
|
||||
} else
|
||||
memset(hf->tbl, 0, tbl_size * sizeof(hf->bitlen[0]));
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -3152,19 +3252,47 @@ lzx_huffman_free(struct huffman *hf)
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a huffman coding table.
|
||||
* Create a direct, expanded Huffman lookup table based on
|
||||
* canonical representation.
|
||||
*/
|
||||
static int
|
||||
lzx_make_huffman_table(struct huffman *hf)
|
||||
{
|
||||
uint16_t bitptn[17], weight[17];
|
||||
uint16_t *tbl;
|
||||
const unsigned char *bitlen;
|
||||
int bitptn[17], weight[17];
|
||||
int i, maxbits = 0, ptn, tbl_size, w;
|
||||
int len_avail;
|
||||
const uint8_t *bitlen;
|
||||
uint8_t maxbits = 0;
|
||||
uint32_t ptn;
|
||||
uint16_t i, symbol_count, w;
|
||||
|
||||
/*
|
||||
* Initialize bit patterns.
|
||||
*
|
||||
* Each bitptn element represents the smallest possible
|
||||
* code sequence allowed. The weight represents the amount
|
||||
* of lookup bit patterns covered by a code of this length.
|
||||
*
|
||||
* Example of a Huffman tree:
|
||||
*
|
||||
* idx | freq[idx]
|
||||
* ----+----------
|
||||
* 1 | 1
|
||||
* 2 | 2
|
||||
*
|
||||
* The result will be:
|
||||
*
|
||||
* idx | bitptn[idx] | weight[idx]
|
||||
* ----+-------------+------------
|
||||
* 1 | 0x0000 | 32768
|
||||
* 2 | 0x8000 | 16384
|
||||
*
|
||||
* This means that a code with bit length 1 will take 32768
|
||||
* possible combinations starting with 0b0. Since one such code exists
|
||||
* (freq[1] = 1), codes with bit length 2 must start with 0b1. Since
|
||||
* two codes with bit length 2 exist (freq[2] = 2), no more codes can
|
||||
* be added.
|
||||
*
|
||||
* In this example, maxbits will be 2 (longest code length is 2).
|
||||
*/
|
||||
ptn = 0;
|
||||
for (i = 1, w = 1 << 15; i <= 16; i++, w >>= 1) {
|
||||
@@ -3175,65 +3303,108 @@ lzx_make_huffman_table(struct huffman *hf)
|
||||
maxbits = i;
|
||||
}
|
||||
}
|
||||
if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
|
||||
return (0);/* Invalid */
|
||||
|
||||
hf->max_bits = maxbits;
|
||||
/* Verify Kraft's inequality. */
|
||||
if (ptn != 0 && ptn != 0x10000)
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
/*
|
||||
* Cut out extra bits which we won't house in the table.
|
||||
* This preparation reduces the same calculation in the for-loop
|
||||
* making the table.
|
||||
* Shrink codes to smallest size by removing extra bits after
|
||||
* the actual code sequences as good as possible.
|
||||
*
|
||||
* Continuing the example above:
|
||||
*
|
||||
* idx | bitptn[idx] | weight[idx]
|
||||
* ----+-------------+-------------
|
||||
* 1 | 0x0000 | 32768
|
||||
* 2 | 0x8000 | 16384
|
||||
*
|
||||
* As can be seen, a total of 65536 entries must be created even
|
||||
* though 4 would be sufficient (indices 0b00 to 0b11). Right shift
|
||||
* the pattern and divide weight as much as possible:
|
||||
*
|
||||
* idx | bitptn[idx] | weight[idx]
|
||||
* ----+-------------+-------------
|
||||
* 1 | 0x0000 | 2
|
||||
* 2 | 0x0002 | 1
|
||||
*
|
||||
* Thus, the direct, expanded lookup table only needs 4 entries.
|
||||
*/
|
||||
if (maxbits < 16) {
|
||||
int ebits = 16 - maxbits;
|
||||
uint8_t ebits = 16 - maxbits;
|
||||
for (i = 1; i <= maxbits; i++) {
|
||||
bitptn[i] >>= ebits;
|
||||
weight[i] >>= ebits;
|
||||
}
|
||||
}
|
||||
|
||||
/* Grow table if necessary. */
|
||||
if (maxbits > hf->tbl_bits) {
|
||||
size_t tbl_size;
|
||||
|
||||
hf->tbl_bits = 16;
|
||||
tbl_size = (size_t)1 << hf->tbl_bits;
|
||||
|
||||
free(hf->tbl);
|
||||
hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));
|
||||
if (hf->tbl == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
hf->lookup_bits = maxbits;
|
||||
|
||||
/*
|
||||
* Make the table.
|
||||
* Construct the direct, expanded lookup table.
|
||||
*
|
||||
* Store each symbol in table for every possible bit patterns starting
|
||||
* with their code.
|
||||
*
|
||||
* Following the example with len_avail being 4:
|
||||
*
|
||||
* idx | bitlen[idx]
|
||||
* ----+------------
|
||||
* 0 | 0
|
||||
* 1 | 1
|
||||
* 2 | 0
|
||||
* 3 | 2
|
||||
* 4 | 2
|
||||
*
|
||||
* The resulting table contains all used symbols (1, 3, 4) for up to
|
||||
* max_len bit patterns:
|
||||
*
|
||||
* idx | tbl[idx]
|
||||
* ----------+---------
|
||||
* 0 (0b00) | 1
|
||||
* 1 (0b01) | 1
|
||||
* 2 (0b10) | 3
|
||||
* 3 (0b11) | 4
|
||||
*/
|
||||
tbl_size = 1 << hf->tbl_bits;
|
||||
tbl = hf->tbl;
|
||||
bitlen = hf->bitlen;
|
||||
len_avail = hf->len_size;
|
||||
hf->tree_used = 0;
|
||||
/* Initialize table to invalid values */
|
||||
for (i = 0; i < tbl_size; i++) {
|
||||
tbl[i] = (uint16_t)hf->len_size;
|
||||
}
|
||||
for (i = 0; i < len_avail; i++) {
|
||||
symbol_count = hf->symbol_count;
|
||||
for (i = 0; i < symbol_count; i++) {
|
||||
uint16_t *p;
|
||||
int len, cnt;
|
||||
uint16_t cnt;
|
||||
uint8_t len;
|
||||
|
||||
if (bitlen[i] == 0)
|
||||
continue;
|
||||
/* Get a bit pattern */
|
||||
len = bitlen[i];
|
||||
if (len > tbl_size)
|
||||
return (0);
|
||||
if (len > maxbits)
|
||||
return (ARCHIVE_FATAL);
|
||||
ptn = bitptn[len];
|
||||
cnt = weight[len];
|
||||
/* Calculate next bit pattern */
|
||||
if ((bitptn[len] = ptn + cnt) > tbl_size)
|
||||
return (0);/* Invalid */
|
||||
bitptn[len] = ptn + cnt;
|
||||
/* Update the table */
|
||||
p = &(tbl[ptn]);
|
||||
while (--cnt >= 0)
|
||||
p[cnt] = (uint16_t)i;
|
||||
p = tbl + ptn;
|
||||
while (cnt-- > 0)
|
||||
*p++ = i;
|
||||
}
|
||||
return (1);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static inline int
|
||||
lzx_decode_huffman(struct huffman *hf, unsigned rbits)
|
||||
static uint16_t
|
||||
lzx_decode_huffman(struct huffman *hf, uint16_t rbits)
|
||||
{
|
||||
int c;
|
||||
c = hf->tbl[rbits];
|
||||
if (c < hf->len_size)
|
||||
return (c);
|
||||
return (0);
|
||||
return hf->tbl[rbits];
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_endian.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_private.h"
|
||||
@@ -160,6 +161,8 @@
|
||||
#define afiol_filesize_c_offset 115 /* ':' */
|
||||
#define afiol_header_size 116
|
||||
|
||||
/* CPIO name fields store a full pathname, including the terminating NUL. */
|
||||
#define CPIO_PATHNAME_MAX (1024 * 1024)
|
||||
|
||||
struct links_entry {
|
||||
struct links_entry *next;
|
||||
@@ -200,7 +203,7 @@ static int archive_read_format_cpio_read_data(struct archive_read *,
|
||||
static int archive_read_format_cpio_read_header(struct archive_read *,
|
||||
struct archive_entry *);
|
||||
static int archive_read_format_cpio_skip(struct archive_read *);
|
||||
static int64_t be4(const unsigned char *);
|
||||
static int64_t be32dec(const unsigned char *);
|
||||
static int find_odc_header(struct archive_read *);
|
||||
static int find_newc_header(struct archive_read *);
|
||||
static int header_bin_be(struct archive_read *, struct cpio *,
|
||||
@@ -215,7 +218,7 @@ static int header_afiol(struct archive_read *, struct cpio *,
|
||||
struct archive_entry *, size_t *, size_t *);
|
||||
static int is_octal(const char *, size_t);
|
||||
static int is_hex(const char *, size_t);
|
||||
static int64_t le4(const unsigned char *);
|
||||
static int64_t le32dec(const unsigned char *);
|
||||
static int record_hardlink(struct archive_read *a,
|
||||
struct cpio *cpio, struct archive_entry *entry);
|
||||
|
||||
@@ -258,14 +261,12 @@ archive_read_support_format_cpio(struct archive *_a)
|
||||
static int
|
||||
archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
|
||||
{
|
||||
struct cpio *cpio = a->format->data;
|
||||
const unsigned char *p;
|
||||
struct cpio *cpio;
|
||||
int bid;
|
||||
|
||||
(void)best_bid; /* UNUSED */
|
||||
|
||||
cpio = (struct cpio *)(a->format->data);
|
||||
|
||||
if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
|
||||
return (-1);
|
||||
|
||||
@@ -303,12 +304,12 @@ archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
|
||||
* XXX TODO: More verification; Could check that only hex
|
||||
* digits appear in appropriate header locations. XXX
|
||||
*/
|
||||
} else if (p[0] * 256 + p[1] == 070707) {
|
||||
} else if (archive_be16dec(p) == 070707) {
|
||||
/* big-endian binary cpio archives */
|
||||
cpio->read_header = header_bin_be;
|
||||
bid += 16;
|
||||
/* Is more verification possible here? */
|
||||
} else if (p[0] + p[1] * 256 == 070707) {
|
||||
} else if (archive_le16dec(p) == 070707) {
|
||||
/* little-endian binary cpio archives */
|
||||
cpio->read_header = header_bin_le;
|
||||
bid += 16;
|
||||
@@ -323,10 +324,9 @@ static int
|
||||
archive_read_format_cpio_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
struct cpio *cpio = a->format->data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
cpio = (struct cpio *)(a->format->data);
|
||||
if (strcmp(key, "compat-2x") == 0) {
|
||||
/* Handle filenames as libarchive 2.x */
|
||||
cpio->init_default_conversion = (val != NULL)?1:0;
|
||||
@@ -361,14 +361,14 @@ static int
|
||||
archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
struct cpio *cpio = a->format->data;
|
||||
const void *h, *hl;
|
||||
struct archive_string_conv *sconv;
|
||||
size_t namelength;
|
||||
size_t name_pad;
|
||||
int is_trailer;
|
||||
int r;
|
||||
|
||||
cpio = (struct cpio *)(a->format->data);
|
||||
sconv = cpio->opt_sconv;
|
||||
if (sconv == NULL) {
|
||||
if (!cpio->init_default_conversion) {
|
||||
@@ -385,8 +385,15 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
if (r < ARCHIVE_WARN)
|
||||
return (r);
|
||||
|
||||
if (namelength > CPIO_PATHNAME_MAX) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Rejecting malformed cpio archive: "
|
||||
"pathname exceeds 1 megabyte");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/* Read name from buffer. */
|
||||
h = __archive_read_ahead(a, namelength + name_pad, NULL);
|
||||
h = __archive_read_ahead(a, namelength, NULL);
|
||||
if (h == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (archive_entry_copy_pathname_l(entry,
|
||||
@@ -397,13 +404,17 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname can't be converted from %s to current locale.",
|
||||
"Pathname can't be converted from %s to current locale",
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
r = ARCHIVE_WARN;
|
||||
}
|
||||
/* Save this before consuming the name buffer below. */
|
||||
is_trailer = (namelength == 11 &&
|
||||
memcmp((const char *)h, "TRAILER!!!", 10) == 0);
|
||||
cpio->entry_offset = 0;
|
||||
|
||||
__archive_read_consume(a, namelength + name_pad);
|
||||
__archive_read_consume(a, namelength);
|
||||
__archive_read_consume(a, name_pad);
|
||||
|
||||
/* If this is a symlink, read the link contents. */
|
||||
if (archive_entry_filetype(entry) == AE_IFLNK) {
|
||||
@@ -426,7 +437,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Linkname can't be converted from %s to "
|
||||
"current locale.",
|
||||
"current locale",
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
r = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -440,8 +451,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
* header. XXX */
|
||||
|
||||
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
|
||||
if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",
|
||||
10) == 0) {
|
||||
if (is_trailer) {
|
||||
/* TODO: Store file location of start of block. */
|
||||
archive_clear_error(&a->archive);
|
||||
return (ARCHIVE_EOF);
|
||||
@@ -459,10 +469,8 @@ static int
|
||||
archive_read_format_cpio_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct cpio *cpio = a->format->data;
|
||||
ssize_t bytes_read;
|
||||
struct cpio *cpio;
|
||||
|
||||
cpio = (struct cpio *)(a->format->data);
|
||||
|
||||
if (cpio->entry_bytes_unconsumed) {
|
||||
__archive_read_consume(a, cpio->entry_bytes_unconsumed);
|
||||
@@ -497,7 +505,7 @@ archive_read_format_cpio_read_data(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_cpio_skip(struct archive_read *a)
|
||||
{
|
||||
struct cpio *cpio = (struct cpio *)(a->format->data);
|
||||
struct cpio *cpio = a->format->data;
|
||||
int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding +
|
||||
cpio->entry_bytes_unconsumed;
|
||||
|
||||
@@ -534,7 +542,8 @@ find_newc_header(struct archive_read *a)
|
||||
{
|
||||
const void *h;
|
||||
const char *p, *q;
|
||||
size_t skip, skipped = 0;
|
||||
int64_t skip;
|
||||
uintmax_t skipped = 0;
|
||||
ssize_t bytes;
|
||||
|
||||
for (;;) {
|
||||
@@ -566,9 +575,9 @@ find_newc_header(struct archive_read *a)
|
||||
if (skipped > 0) {
|
||||
archive_set_error(&a->archive,
|
||||
0,
|
||||
"Skipped %d bytes before "
|
||||
"Skipped %ju bytes before "
|
||||
"finding valid header",
|
||||
(int)skipped);
|
||||
skipped);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
@@ -703,13 +712,24 @@ find_odc_header(struct archive_read *a)
|
||||
{
|
||||
const void *h;
|
||||
const char *p, *q;
|
||||
size_t skip, skipped = 0;
|
||||
int64_t skip;
|
||||
uintmax_t skipped = 0;
|
||||
ssize_t bytes;
|
||||
|
||||
for (;;) {
|
||||
h = __archive_read_ahead(a, odc_header_size, &bytes);
|
||||
if (h == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
size_t header_size;
|
||||
|
||||
header_size = afiol_header_size;
|
||||
h = __archive_read_ahead(a, afiol_header_size, &bytes);
|
||||
if (h == NULL) {
|
||||
if (bytes >= odc_header_size) {
|
||||
header_size = odc_header_size;
|
||||
h = __archive_read_ahead(a, odc_header_size,
|
||||
&bytes);
|
||||
}
|
||||
if (h == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
q = p + bytes;
|
||||
|
||||
@@ -725,7 +745,7 @@ find_odc_header(struct archive_read *a)
|
||||
* Scan ahead until we find something that looks
|
||||
* like an odc header.
|
||||
*/
|
||||
while (p + odc_header_size <= q) {
|
||||
while (p + header_size <= q) {
|
||||
switch (p[5]) {
|
||||
case '7':
|
||||
if ((memcmp("070707", p, 6) == 0
|
||||
@@ -741,9 +761,9 @@ find_odc_header(struct archive_read *a)
|
||||
if (skipped > 0) {
|
||||
archive_set_error(&a->archive,
|
||||
0,
|
||||
"Skipped %d bytes before "
|
||||
"Skipped %ju bytes before "
|
||||
"finding valid header",
|
||||
(int)skipped);
|
||||
skipped);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
@@ -828,7 +848,7 @@ header_odc(struct archive_read *a, struct cpio *cpio,
|
||||
* NOTE: if a filename suffix is ".z", it is a file gzipped by afio.
|
||||
* it would be nice if we could show uncompressed file size and
|
||||
* uncompress file contents automatically, unfortunately we have nothing
|
||||
* to get a uncompressed file size while reading each header. It means
|
||||
* to get an uncompressed file size while reading each header. It means
|
||||
* we also cannot uncompress file contents under our framework.
|
||||
*/
|
||||
static int
|
||||
@@ -873,7 +893,8 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
|
||||
|
||||
t = atol16(header + afiol_filesize_offset, afiol_filesize_size);
|
||||
if (t < 0) {
|
||||
archive_set_error(&a->archive, 0, "Nonsensical file size");
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Nonsensical file size");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
cpio->entry_bytes_remaining = t;
|
||||
@@ -897,7 +918,7 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
|
||||
/* Read fixed-size portion of header. */
|
||||
h = __archive_read_ahead(a, bin_header_size, NULL);
|
||||
if (h == NULL) {
|
||||
archive_set_error(&a->archive, 0,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"End of file trying to read next cpio header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -905,24 +926,24 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
|
||||
/* Parse out binary fields. */
|
||||
header = (const unsigned char *)h;
|
||||
|
||||
archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);
|
||||
archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);
|
||||
archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);
|
||||
archive_entry_set_dev(entry, archive_le16dec(header + bin_dev_offset));
|
||||
archive_entry_set_ino(entry, archive_le16dec(header + bin_ino_offset));
|
||||
archive_entry_set_mode(entry, archive_le16dec(header + bin_mode_offset));
|
||||
if (cpio->option_pwb) {
|
||||
/* turn off random bits left over from V6 inode */
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
|
||||
if ((archive_entry_mode(entry) & AE_IFMT) == 0)
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
|
||||
}
|
||||
archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);
|
||||
archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);
|
||||
archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);
|
||||
archive_entry_set_rdev(entry, header[bin_rdev_offset] + header[bin_rdev_offset + 1] * 256);
|
||||
archive_entry_set_mtime(entry, le4(header + bin_mtime_offset), 0);
|
||||
*namelength = header[bin_namesize_offset] + header[bin_namesize_offset + 1] * 256;
|
||||
archive_entry_set_uid(entry, archive_le16dec(header + bin_uid_offset));
|
||||
archive_entry_set_gid(entry, archive_le16dec(header + bin_gid_offset));
|
||||
archive_entry_set_nlink(entry, archive_le16dec(header + bin_nlink_offset));
|
||||
archive_entry_set_rdev(entry, archive_le16dec(header + bin_rdev_offset));
|
||||
archive_entry_set_mtime(entry, le32dec(header + bin_mtime_offset), 0);
|
||||
*namelength = archive_le16dec(header + bin_namesize_offset);
|
||||
*name_pad = *namelength & 1; /* Pad to even. */
|
||||
|
||||
cpio->entry_bytes_remaining = le4(header + bin_filesize_offset);
|
||||
cpio->entry_bytes_remaining = le32dec(header + bin_filesize_offset);
|
||||
archive_entry_set_size(entry, cpio->entry_bytes_remaining);
|
||||
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
|
||||
__archive_read_consume(a, bin_header_size);
|
||||
@@ -942,7 +963,7 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
|
||||
/* Read fixed-size portion of header. */
|
||||
h = __archive_read_ahead(a, bin_header_size, NULL);
|
||||
if (h == NULL) {
|
||||
archive_set_error(&a->archive, 0,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"End of file trying to read next cpio header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -950,24 +971,24 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
|
||||
/* Parse out binary fields. */
|
||||
header = (const unsigned char *)h;
|
||||
|
||||
archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
|
||||
archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
|
||||
archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
|
||||
archive_entry_set_dev(entry, archive_be16dec(header + bin_dev_offset));
|
||||
archive_entry_set_ino(entry, archive_be16dec(header + bin_ino_offset));
|
||||
archive_entry_set_mode(entry, archive_be16dec(header + bin_mode_offset));
|
||||
if (cpio->option_pwb) {
|
||||
/* turn off random bits left over from V6 inode */
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
|
||||
if ((archive_entry_mode(entry) & AE_IFMT) == 0)
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
|
||||
}
|
||||
archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
|
||||
archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
|
||||
archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
|
||||
archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]);
|
||||
archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0);
|
||||
*namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1];
|
||||
archive_entry_set_uid(entry, archive_be16dec(header + bin_uid_offset));
|
||||
archive_entry_set_gid(entry, archive_be16dec(header + bin_gid_offset));
|
||||
archive_entry_set_nlink(entry, archive_be16dec(header + bin_nlink_offset));
|
||||
archive_entry_set_rdev(entry, archive_be16dec(header + bin_rdev_offset));
|
||||
archive_entry_set_mtime(entry, be32dec(header + bin_mtime_offset), 0);
|
||||
*namelength = archive_be16dec(header + bin_namesize_offset);
|
||||
*name_pad = *namelength & 1; /* Pad to even. */
|
||||
|
||||
cpio->entry_bytes_remaining = be4(header + bin_filesize_offset);
|
||||
cpio->entry_bytes_remaining = be32dec(header + bin_filesize_offset);
|
||||
archive_entry_set_size(entry, cpio->entry_bytes_remaining);
|
||||
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
|
||||
__archive_read_consume(a, bin_header_size);
|
||||
@@ -977,9 +998,8 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
|
||||
static int
|
||||
archive_read_format_cpio_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
struct cpio *cpio = a->format->data;
|
||||
|
||||
cpio = (struct cpio *)(a->format->data);
|
||||
/* Free inode->name map */
|
||||
while (cpio->links_head != NULL) {
|
||||
struct links_entry *lp = cpio->links_head->next;
|
||||
@@ -989,21 +1009,20 @@ archive_read_format_cpio_cleanup(struct archive_read *a)
|
||||
cpio->links_head = lp;
|
||||
}
|
||||
free(cpio);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
le4(const unsigned char *p)
|
||||
le32dec(const unsigned char *p)
|
||||
{
|
||||
return ((p[0] << 16) | (((int64_t)p[1]) << 24) | (p[2] << 0) | (p[3] << 8));
|
||||
return ((int64_t)archive_le16dec(p) << 16) | archive_le16dec(p + 2);
|
||||
}
|
||||
|
||||
|
||||
static int64_t
|
||||
be4(const unsigned char *p)
|
||||
be32dec(const unsigned char *p)
|
||||
{
|
||||
return ((((int64_t)p[0]) << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
|
||||
return ((int64_t)archive_be16dec(p) << 16) | archive_be16dec(p + 2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1051,7 +1070,7 @@ atol16u(const char *p, unsigned char_cnt)
|
||||
else if (*p >= '0' && *p <= '9')
|
||||
digit = *p - '0';
|
||||
else
|
||||
return ((int64_t)l);
|
||||
return (l);
|
||||
p++;
|
||||
l <<= 4;
|
||||
l |= digit;
|
||||
@@ -1106,17 +1125,12 @@ record_hardlink(struct archive_read *a,
|
||||
const char *pathname = archive_entry_pathname(entry);
|
||||
if (pathname == NULL) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid hardlink entry with no pathname");
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid hardlink entry with no pathname");
|
||||
free(le);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (cpio->links_head != NULL)
|
||||
cpio->links_head->previous = le;
|
||||
le->next = cpio->links_head;
|
||||
le->previous = NULL;
|
||||
cpio->links_head = le;
|
||||
le->dev = dev;
|
||||
le->ino = ino;
|
||||
le->links = archive_entry_nlink(entry) - 1;
|
||||
@@ -1128,5 +1142,11 @@ record_hardlink(struct archive_read *a,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (cpio->links_head != NULL)
|
||||
cpio->links_head->previous = le;
|
||||
le->next = cpio->links_head;
|
||||
le->previous = NULL;
|
||||
cpio->links_head = le;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "archive_endian.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
#include "archive_string.h"
|
||||
@@ -268,6 +269,7 @@ struct file_info {
|
||||
uint64_t size; /* File size in bytes. */
|
||||
uint32_t ce_offset; /* Offset of CE. */
|
||||
uint32_t ce_size; /* Size of CE. */
|
||||
uint64_t ce_processed_end;/* End offset of processed CE. */
|
||||
char rr_moved; /* Flag to rr_moved. */
|
||||
char rr_moved_has_re_only;
|
||||
char re; /* Having RRIP "RE" extension. */
|
||||
@@ -313,8 +315,8 @@ struct file_info {
|
||||
|
||||
struct heap_queue {
|
||||
struct file_info **files;
|
||||
int allocated;
|
||||
int used;
|
||||
size_t allocated;
|
||||
size_t used;
|
||||
};
|
||||
|
||||
struct iso9660 {
|
||||
@@ -336,8 +338,8 @@ struct iso9660 {
|
||||
uint64_t offset;/* Offset of CE on disk. */
|
||||
struct file_info *file;
|
||||
} *reqs;
|
||||
int cnt;
|
||||
int allocated;
|
||||
size_t cnt;
|
||||
size_t allocated;
|
||||
} read_ce_req;
|
||||
|
||||
int64_t previous_number;
|
||||
@@ -378,8 +380,6 @@ struct iso9660 {
|
||||
size_t utf16be_path_len;
|
||||
unsigned char *utf16be_previous_path;
|
||||
size_t utf16be_previous_path_len;
|
||||
/* Null buffer used in bidder to improve its performance. */
|
||||
unsigned char null[2048];
|
||||
};
|
||||
|
||||
static int archive_read_format_iso9660_bid(struct archive_read *, int);
|
||||
@@ -402,12 +402,12 @@ static time_t isodate17(const unsigned char *);
|
||||
static int isodate17_valid(const unsigned char *);
|
||||
static time_t isodate7(const unsigned char *);
|
||||
static int isodate7_valid(const unsigned char *);
|
||||
static int isBootRecord(struct iso9660 *, const unsigned char *);
|
||||
static int isBootRecord(const unsigned char *);
|
||||
static int isVolumePartition(struct iso9660 *, const unsigned char *);
|
||||
static int isVDSetTerminator(struct iso9660 *, const unsigned char *);
|
||||
static int isVDSetTerminator(const unsigned char *);
|
||||
static int isJolietSVD(struct iso9660 *, const unsigned char *);
|
||||
static int isSVD(struct iso9660 *, const unsigned char *);
|
||||
static int isEVD(struct iso9660 *, const unsigned char *);
|
||||
static int isSVD(const unsigned char *);
|
||||
static int isEVD(const unsigned char *);
|
||||
static int isPVD(struct iso9660 *, const unsigned char *);
|
||||
static int isRootDirectoryRecord(const unsigned char *);
|
||||
static int isValid723Integer(const unsigned char *);
|
||||
@@ -436,7 +436,6 @@ static void parse_rockridge_ZF1(struct file_info *,
|
||||
const unsigned char *, int);
|
||||
static void register_file(struct iso9660 *, struct file_info *);
|
||||
static void release_files(struct iso9660 *);
|
||||
static unsigned toi(const void *p, int n);
|
||||
static inline void re_add_entry(struct iso9660 *, struct file_info *);
|
||||
static inline struct file_info * re_get_entry(struct iso9660 *);
|
||||
static inline int rede_add_entry(struct file_info *);
|
||||
@@ -503,7 +502,7 @@ archive_read_support_format_iso9660(struct archive *_a)
|
||||
static int
|
||||
archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
ssize_t bytes_read;
|
||||
const unsigned char *p;
|
||||
int seenTerminator;
|
||||
@@ -513,8 +512,6 @@ archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
|
||||
if (best_bid > 48)
|
||||
return (-1);
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
|
||||
/*
|
||||
* Skip the first 32k (reserved area) and get the first
|
||||
* 8 sectors of the volume descriptor table. Of course,
|
||||
@@ -547,15 +544,15 @@ archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
|
||||
if (isJolietSVD(iso9660, p))
|
||||
continue;
|
||||
}
|
||||
if (isBootRecord(iso9660, p))
|
||||
if (isBootRecord(p))
|
||||
continue;
|
||||
if (isEVD(iso9660, p))
|
||||
if (isEVD(p))
|
||||
continue;
|
||||
if (isSVD(iso9660, p))
|
||||
if (isSVD(p))
|
||||
continue;
|
||||
if (isVolumePartition(iso9660, p))
|
||||
continue;
|
||||
if (isVDSetTerminator(iso9660, p)) {
|
||||
if (isVDSetTerminator(p)) {
|
||||
seenTerminator = 1;
|
||||
break;
|
||||
}
|
||||
@@ -576,9 +573,7 @@ static int
|
||||
archive_read_format_iso9660_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
|
||||
if (strcmp(key, "joliet") == 0) {
|
||||
if (val == NULL || strcmp(val, "off") == 0 ||
|
||||
@@ -603,26 +598,23 @@ archive_read_format_iso9660_options(struct archive_read *a,
|
||||
}
|
||||
|
||||
static int
|
||||
isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,
|
||||
unsigned bytes)
|
||||
isNull(const unsigned char *h, unsigned offset, unsigned bytes)
|
||||
{
|
||||
|
||||
while (bytes >= sizeof(iso9660->null)) {
|
||||
if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))
|
||||
return (0);
|
||||
offset += sizeof(iso9660->null);
|
||||
bytes -= sizeof(iso9660->null);
|
||||
}
|
||||
if (bytes)
|
||||
return memcmp(iso9660->null, h + offset, bytes) == 0;
|
||||
else
|
||||
if (bytes == 0)
|
||||
return (1);
|
||||
|
||||
/*
|
||||
* If the first byte is zero and every byte equals the following
|
||||
* byte, the entire range is zero.
|
||||
*/
|
||||
return (h[offset] == 0 &&
|
||||
(bytes == 1 ||
|
||||
memcmp(h + offset, h + offset + 1, bytes - 1) == 0));
|
||||
}
|
||||
|
||||
static int
|
||||
isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
|
||||
isBootRecord(const unsigned char *h)
|
||||
{
|
||||
(void)iso9660; /* UNUSED */
|
||||
|
||||
/* Type of the Volume Descriptor Boot Record must be 0. */
|
||||
if (h[0] != 0)
|
||||
@@ -662,9 +654,8 @@ isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
|
||||
}
|
||||
|
||||
static int
|
||||
isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
|
||||
isVDSetTerminator(const unsigned char *h)
|
||||
{
|
||||
(void)iso9660; /* UNUSED */
|
||||
|
||||
/* Type of the Volume Descriptor Set Terminator must be 255. */
|
||||
if (h[0] != 255)
|
||||
@@ -675,7 +666,7 @@ isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, 7, 2048-7))
|
||||
if (!isNull(h, 7, 2048-7))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
@@ -690,7 +681,7 @@ isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
|
||||
/* Check if current sector is a kind of Supplementary Volume
|
||||
* Descriptor. */
|
||||
if (!isSVD(iso9660, h))
|
||||
if (!isSVD(h))
|
||||
return (0);
|
||||
|
||||
/* FIXME: do more validations according to joliet spec. */
|
||||
@@ -731,25 +722,24 @@ isJolietSVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
}
|
||||
|
||||
static int
|
||||
isSVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
isSVD(const unsigned char *h)
|
||||
{
|
||||
const unsigned char *p;
|
||||
ssize_t logical_block_size;
|
||||
int32_t volume_block;
|
||||
int32_t location;
|
||||
|
||||
(void)iso9660; /* UNUSED */
|
||||
|
||||
/* Type 2 means it's a SVD. */
|
||||
if (h[SVD_type_offset] != 2)
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))
|
||||
if (!isNull(h, SVD_reserved1_offset, SVD_reserved1_size))
|
||||
return (0);
|
||||
if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))
|
||||
if (!isNull(h, SVD_reserved2_offset, SVD_reserved2_size))
|
||||
return (0);
|
||||
if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))
|
||||
if (!isNull(h, SVD_reserved3_offset, SVD_reserved3_size))
|
||||
return (0);
|
||||
|
||||
/* File structure version must be 1 for ISO9660/ECMA119. */
|
||||
@@ -791,14 +781,13 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
}
|
||||
|
||||
static int
|
||||
isEVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
isEVD(const unsigned char *h)
|
||||
{
|
||||
const unsigned char *p;
|
||||
ssize_t logical_block_size;
|
||||
int32_t volume_block;
|
||||
int32_t location;
|
||||
|
||||
(void)iso9660; /* UNUSED */
|
||||
|
||||
/* Type of the Enhanced Volume Descriptor must be 2. */
|
||||
if (h[PVD_type_offset] != 2)
|
||||
@@ -813,11 +802,11 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
|
||||
if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size))
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
|
||||
if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size))
|
||||
return (0);
|
||||
|
||||
/* Logical block size must be > 0. */
|
||||
@@ -853,11 +842,11 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))
|
||||
if (!isNull(h, PVD_reserved4_offset, PVD_reserved4_size))
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
|
||||
if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size))
|
||||
return (0);
|
||||
|
||||
/* Read Root Directory Record in Volume Descriptor. */
|
||||
@@ -891,7 +880,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
|
||||
if (!isNull(h, PVD_reserved2_offset, PVD_reserved2_size))
|
||||
return (0);
|
||||
|
||||
/* Volume space size must be encoded according to 7.3.3 */
|
||||
@@ -903,7 +892,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
|
||||
if (!isNull(h, PVD_reserved3_offset, PVD_reserved3_size))
|
||||
return (0);
|
||||
|
||||
/* Volume set size must be encoded according to 7.2.3 */
|
||||
@@ -961,7 +950,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
return (0);
|
||||
|
||||
/* Reserved field must be 0. */
|
||||
if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
|
||||
if (!isNull(h, PVD_reserved5_offset, PVD_reserved5_size))
|
||||
return (0);
|
||||
|
||||
/* XXX TODO: Check other values for sanity; reject more
|
||||
@@ -1034,12 +1023,11 @@ isRootDirectoryRecord(const unsigned char *p) {
|
||||
static int
|
||||
read_children(struct archive_read *a, struct file_info *parent)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
const unsigned char *b, *p;
|
||||
struct file_info *multi;
|
||||
size_t step, skip_size;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
/* flush any remaining bytes from the last round to ensure
|
||||
* we're positioned */
|
||||
if (iso9660->entry_bytes_unconsumed) {
|
||||
@@ -1086,7 +1074,7 @@ read_children(struct archive_read *a, struct file_info *parent)
|
||||
p = b;
|
||||
b += iso9660->logical_block_size;
|
||||
step -= iso9660->logical_block_size;
|
||||
for (; *p != 0 && p + DR_name_offset < b && p + *p <= b;
|
||||
for (; p < b && b - p > DR_name_offset && *p != 0 && *p <= b - p;
|
||||
p += *p) {
|
||||
struct file_info *child;
|
||||
|
||||
@@ -1247,12 +1235,10 @@ static int
|
||||
archive_read_format_iso9660_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
struct file_info *file;
|
||||
int r, rd_r = ARCHIVE_OK;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
|
||||
if (!a->archive.archive_format) {
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
|
||||
a->archive.archive_format_name = "ISO9660";
|
||||
@@ -1322,7 +1308,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted "
|
||||
"from %s to current locale.",
|
||||
"from %s to current locale",
|
||||
archive_string_conversion_charset_name(
|
||||
iso9660->sconv_utf16be));
|
||||
|
||||
@@ -1400,7 +1386,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Linkname cannot be converted "
|
||||
"from %s to current locale.",
|
||||
"from %s to current locale",
|
||||
archive_string_conversion_charset_name(
|
||||
iso9660->sconv_utf16be));
|
||||
rd_r = ARCHIVE_WARN;
|
||||
@@ -1499,7 +1485,7 @@ static int
|
||||
zisofs_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
struct zisofs *zisofs;
|
||||
const unsigned char *p;
|
||||
size_t avail;
|
||||
@@ -1507,7 +1493,6 @@ zisofs_read_data(struct archive_read *a,
|
||||
size_t uncompressed_size;
|
||||
int r;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
zisofs = &iso9660->entry_zisofs;
|
||||
|
||||
p = __archive_read_ahead(a, 1, &bytes_read);
|
||||
@@ -1663,7 +1648,7 @@ zisofs_read_data(struct archive_read *a,
|
||||
r = inflateInit(&zisofs->stream);
|
||||
if (r != Z_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Can't initialize zisofs decompression.");
|
||||
"Can't initialize zisofs decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
zisofs->stream_valid = 1;
|
||||
@@ -1728,7 +1713,7 @@ zisofs_read_data(struct archive_read *a,
|
||||
(void)size;/* UNUSED */
|
||||
(void)offset;/* UNUSED */
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"zisofs is not supported on this platform.");
|
||||
"zisofs is not supported on this platform");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
@@ -1738,10 +1723,8 @@ static int
|
||||
archive_read_format_iso9660_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
ssize_t bytes_read;
|
||||
struct iso9660 *iso9660;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
|
||||
if (iso9660->entry_bytes_unconsumed) {
|
||||
__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
|
||||
@@ -1805,10 +1788,9 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_iso9660_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
int r = ARCHIVE_OK;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
release_files(iso9660);
|
||||
free(iso9660->read_ce_req.reqs);
|
||||
archive_string_free(&iso9660->pathname);
|
||||
@@ -1828,7 +1810,7 @@ archive_read_format_iso9660_cleanup(struct archive_read *a)
|
||||
free(iso9660->utf16be_path);
|
||||
free(iso9660->utf16be_previous_path);
|
||||
free(iso9660);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -1840,7 +1822,7 @@ static struct file_info *
|
||||
parse_file_info(struct archive_read *a, struct file_info *parent,
|
||||
const unsigned char *isodirrec, size_t reclen)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
struct file_info *file, *filep;
|
||||
size_t name_len;
|
||||
const unsigned char *rr_start, *rr_end;
|
||||
@@ -1850,8 +1832,6 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
||||
int32_t location;
|
||||
int flags;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
|
||||
if (reclen != 0)
|
||||
dr_len = (size_t)isodirrec[DR_length_offset];
|
||||
/*
|
||||
@@ -1865,7 +1845,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
||||
}
|
||||
name_len = (size_t)isodirrec[DR_name_len_offset];
|
||||
location = archive_le32dec(isodirrec + DR_extent_offset);
|
||||
fsize = toi(isodirrec + DR_size_offset, DR_size_size);
|
||||
fsize = archive_le32dec(isodirrec + DR_size_offset);
|
||||
/* Sanity check that name_len doesn't exceed dr_len. */
|
||||
if (dr_len - 33 < name_len || name_len == 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
@@ -2162,7 +2142,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
||||
fprintf(stderr, "\n ** Unrecognized flag: ");
|
||||
dump_isodirrec(stderr, isodirrec);
|
||||
fprintf(stderr, "\n");
|
||||
} else if (toi(isodirrec + DR_volume_sequence_number_offset, 2) != 1) {
|
||||
} else if (archive_le16dec(isodirrec + DR_volume_sequence_number_offset) != 1) {
|
||||
fprintf(stderr, "\n ** Unrecognized sequence number: ");
|
||||
dump_isodirrec(stderr, isodirrec);
|
||||
fprintf(stderr, "\n");
|
||||
@@ -2192,11 +2172,9 @@ static int
|
||||
parse_rockridge(struct archive_read *a, struct file_info *file,
|
||||
const unsigned char *p, const unsigned char *end)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
int entry_seen = 0;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
|
||||
while (p + 4 <= end /* Enough space for another entry. */
|
||||
&& p[0] >= 'A' && p[0] <= 'Z' /* Sanity-check 1st char of name. */
|
||||
&& p[1] >= 'A' && p[1] <= 'Z' /* Sanity-check 2nd char of name. */
|
||||
@@ -2255,9 +2233,10 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
|
||||
*/
|
||||
if (p[1] == 'N') {
|
||||
if (version == 1 && data_length == 16) {
|
||||
file->rdev = toi(data,4);
|
||||
file->rdev = archive_le32dec(data);
|
||||
file->rdev <<= 32;
|
||||
file->rdev |= toi(data + 8, 4);
|
||||
file->rdev |=
|
||||
archive_le32dec(data + 8);
|
||||
iso9660->seenRockridge = 1;
|
||||
}
|
||||
}
|
||||
@@ -2272,20 +2251,20 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
|
||||
*/
|
||||
if (version == 1) {
|
||||
if (data_length >= 8)
|
||||
file->mode
|
||||
= (__LA_MODE_T)toi(data, 4);
|
||||
file->mode = (__LA_MODE_T)
|
||||
archive_le32dec(data);
|
||||
if (data_length >= 16)
|
||||
file->nlinks
|
||||
= toi(data + 8, 4);
|
||||
file->nlinks =
|
||||
archive_le32dec(data + 8);
|
||||
if (data_length >= 24)
|
||||
file->uid
|
||||
= toi(data + 16, 4);
|
||||
file->uid =
|
||||
archive_le32dec(data + 16);
|
||||
if (data_length >= 32)
|
||||
file->gid
|
||||
= toi(data + 24, 4);
|
||||
file->gid =
|
||||
archive_le32dec(data + 24);
|
||||
if (data_length >= 40)
|
||||
file->number
|
||||
= toi(data + 32, 4);
|
||||
file->number =
|
||||
archive_le32dec(data + 32);
|
||||
iso9660->seenRockridge = 1;
|
||||
}
|
||||
}
|
||||
@@ -2365,13 +2344,11 @@ static int
|
||||
register_CE(struct archive_read *a, int32_t location,
|
||||
struct file_info *file)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct iso9660 *iso9660 = a->format->data;
|
||||
struct read_ce_queue *heap;
|
||||
struct read_ce_req *p;
|
||||
uint64_t offset, parent_offset;
|
||||
int hole, parent;
|
||||
size_t hole, parent;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;
|
||||
if (((file->mode & AE_IFMT) == AE_IFREG &&
|
||||
offset >= file->offset) ||
|
||||
@@ -2388,14 +2365,13 @@ register_CE(struct archive_read *a, int32_t location,
|
||||
/* Expand our CE list as necessary. */
|
||||
heap = &(iso9660->read_ce_req);
|
||||
if (heap->cnt >= heap->allocated) {
|
||||
int new_size;
|
||||
struct read_ce_req *p;
|
||||
size_t new_size;
|
||||
|
||||
if (heap->allocated < 16)
|
||||
new_size = 16;
|
||||
else
|
||||
new_size = heap->allocated * 2;
|
||||
/* Overflow might keep us from growing the list. */
|
||||
if (new_size <= heap->allocated) {
|
||||
else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
|
||||
/* Overflow keeps us from growing the list. */
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -2437,7 +2413,7 @@ static void
|
||||
next_CE(struct read_ce_queue *heap)
|
||||
{
|
||||
uint64_t a_offset, b_offset, c_offset;
|
||||
int a, b, c;
|
||||
size_t a, b, c;
|
||||
struct read_ce_req tmp;
|
||||
|
||||
if (heap->cnt < 1)
|
||||
@@ -2483,6 +2459,7 @@ read_CE(struct archive_read *a, struct iso9660 *iso9660)
|
||||
const unsigned char *b, *p, *end;
|
||||
struct file_info *file;
|
||||
size_t step;
|
||||
uint64_t ce_start, ce_end;
|
||||
int r;
|
||||
|
||||
/* Read data which RRIP "CE" extension points. */
|
||||
@@ -2506,8 +2483,16 @@ read_CE(struct archive_read *a, struct iso9660 *iso9660)
|
||||
"Malformed CE information");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
ce_start = heap->reqs[0].offset + file->ce_offset;
|
||||
ce_end = ce_start + file->ce_size;
|
||||
if (ce_start < file->ce_processed_end) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Invalid parameter in SUSP \"CE\" extension");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = b + file->ce_offset;
|
||||
end = p + file->ce_size;
|
||||
file->ce_processed_end = ce_end;
|
||||
next_CE(heap);
|
||||
r = parse_rockridge(a, file, p, end);
|
||||
if (r != ARCHIVE_OK)
|
||||
@@ -2755,12 +2740,20 @@ parse_rockridge_ZF1(struct file_info *file, const unsigned char *data,
|
||||
int data_length)
|
||||
{
|
||||
|
||||
if (data[0] == 0x70 && data[1] == 0x7a && data_length == 12) {
|
||||
/* paged zlib */
|
||||
file->pz = 1;
|
||||
file->pz_log2_bs = data[3];
|
||||
file->pz_uncompressed_size = archive_le32dec(&data[4]);
|
||||
}
|
||||
if (data_length == 12 && data[0] == 0x70 && data[1] == 0x7a) {
|
||||
/* paged zlib */
|
||||
file->pz = 1;
|
||||
file->pz_log2_bs = data[3];
|
||||
if (file->pz_log2_bs < 15 || file->pz_log2_bs > 17) {
|
||||
/* TODO: Return an error here instead of silently
|
||||
* disabling zisofs. That requires propagating an
|
||||
* error return through parse_rockridge() and its
|
||||
* callers. */
|
||||
file->pz = 0;
|
||||
return;
|
||||
}
|
||||
file->pz_uncompressed_size = archive_le32dec(&data[4]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3126,7 +3119,7 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
|
||||
struct file_info *file, uint64_t key)
|
||||
{
|
||||
uint64_t file_key, parent_key;
|
||||
int hole, parent;
|
||||
size_t hole, parent;
|
||||
|
||||
/* Reserve 16 bits for possible key collisions (needed for linked items) */
|
||||
/* For ISO files with more than 65535 entries, reordering will still occur */
|
||||
@@ -3137,12 +3130,12 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
|
||||
/* Expand our pending files list as necessary. */
|
||||
if (heap->used >= heap->allocated) {
|
||||
struct file_info **new_pending_files;
|
||||
int new_size = heap->allocated * 2;
|
||||
size_t new_size;
|
||||
|
||||
if (heap->allocated < 1024)
|
||||
new_size = 1024;
|
||||
/* Overflow might keep us from growing the list. */
|
||||
if (new_size <= heap->allocated) {
|
||||
else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
|
||||
/* Overflow keeps us from growing the list. */
|
||||
archive_set_error(&a->archive,
|
||||
ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -3170,7 +3163,7 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
|
||||
*/
|
||||
hole = heap->used++;
|
||||
while (hole > 0) {
|
||||
parent = (hole - 1)/2;
|
||||
parent = (hole - 1) / 2;
|
||||
parent_key = heap->files[parent]->key;
|
||||
if (file_key >= parent_key) {
|
||||
heap->files[hole] = file;
|
||||
@@ -3189,7 +3182,7 @@ static struct file_info *
|
||||
heap_get_entry(struct heap_queue *heap)
|
||||
{
|
||||
uint64_t a_key, b_key, c_key;
|
||||
int a, b, c;
|
||||
size_t a, b, c;
|
||||
struct file_info *r, *tmp;
|
||||
|
||||
if (heap->used < 1)
|
||||
@@ -3232,17 +3225,6 @@ heap_get_entry(struct heap_queue *heap)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
toi(const void *p, int n)
|
||||
{
|
||||
const unsigned char *v = (const unsigned char *)p;
|
||||
if (n > 1)
|
||||
return v[0] + 256 * toi(v + 1, n - 1);
|
||||
if (n == 1)
|
||||
return v[0];
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ECMA119/ISO9660 stores multi-byte integers in one of
|
||||
* three different formats:
|
||||
@@ -3487,6 +3469,8 @@ build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,
|
||||
if (file->parent != NULL && file->parent->utf16be_bytes > 0) {
|
||||
if (build_pathname_utf16be(p, max, len, file->parent) != 0)
|
||||
return (-1);
|
||||
if (*len + 2 > max)
|
||||
return (-1);/* Path is too long! */
|
||||
p[*len] = 0;
|
||||
p[*len + 1] = '/';
|
||||
*len += 2;
|
||||
@@ -3511,26 +3495,24 @@ static void
|
||||
dump_isodirrec(FILE *out, const unsigned char *isodirrec)
|
||||
{
|
||||
fprintf(out, " l %d,",
|
||||
toi(isodirrec + DR_length_offset, DR_length_size));
|
||||
isodirrec[DR_length_offset]);
|
||||
fprintf(out, " a %d,",
|
||||
toi(isodirrec + DR_ext_attr_length_offset, DR_ext_attr_length_size));
|
||||
isodirrec[DR_ext_attr_length_offset]);
|
||||
fprintf(out, " ext 0x%x,",
|
||||
toi(isodirrec + DR_extent_offset, DR_extent_size));
|
||||
archive_le32dec(isodirrec + DR_extent_offset));
|
||||
fprintf(out, " s %d,",
|
||||
toi(isodirrec + DR_size_offset, DR_extent_size));
|
||||
archive_le32dec(isodirrec + DR_size_offset));
|
||||
fprintf(out, " f 0x%x,",
|
||||
toi(isodirrec + DR_flags_offset, DR_flags_size));
|
||||
isodirrec[DR_flags_offset]);
|
||||
fprintf(out, " u %d,",
|
||||
toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));
|
||||
isodirrec[DR_file_unit_size_offset]);
|
||||
fprintf(out, " ilv %d,",
|
||||
toi(isodirrec + DR_interleave_offset, DR_interleave_size));
|
||||
isodirrec[DR_interleave_offset]);
|
||||
fprintf(out, " seq %d,",
|
||||
toi(isodirrec + DR_volume_sequence_number_offset,
|
||||
DR_volume_sequence_number_size));
|
||||
archive_le16dec(isodirrec + DR_volume_sequence_number_offset));
|
||||
fprintf(out, " nl %d:",
|
||||
toi(isodirrec + DR_name_len_offset, DR_name_len_size));
|
||||
isodirrec[DR_name_len_offset]);
|
||||
fprintf(out, " `%.*s'",
|
||||
toi(isodirrec + DR_name_len_offset, DR_name_len_size),
|
||||
isodirrec + DR_name_offset);
|
||||
isodirrec[DR_name_len_offset], isodirrec + DR_name_offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -107,8 +107,8 @@ struct lzh_dec {
|
||||
unsigned char *bitlen;
|
||||
|
||||
/*
|
||||
* Use a index table. It's faster than searching a huffman
|
||||
* coding tree, which is a binary tree. But a use of a large
|
||||
* Use an index table. It's faster than searching a huffman
|
||||
* coding tree, which is a binary tree. But usage of a large
|
||||
* index table causes L1 cache read miss many times.
|
||||
*/
|
||||
#define HTBL_BITS 10
|
||||
@@ -142,7 +142,6 @@ struct lzh_stream {
|
||||
int64_t total_in;
|
||||
const unsigned char *ref_ptr;
|
||||
int avail_out;
|
||||
int64_t total_out;
|
||||
struct lzh_dec *ds;
|
||||
};
|
||||
|
||||
@@ -239,7 +238,6 @@ static int lha_read_data_none(struct archive_read *, const void **,
|
||||
size_t *, int64_t *);
|
||||
static int lha_read_data_lzh(struct archive_read *, const void **,
|
||||
size_t *, int64_t *);
|
||||
static void lha_crc16_init(void);
|
||||
static uint16_t lha_crc16(uint16_t, const void *, size_t);
|
||||
static int lzh_decode_init(struct lzh_stream *, const char *);
|
||||
static void lzh_decode_free(struct lzh_stream *);
|
||||
@@ -392,10 +390,9 @@ static int
|
||||
archive_read_format_lha_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct lha *lha;
|
||||
struct lha *lha = a->format->data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
lha = (struct lha *)(a->format->data);
|
||||
if (strcmp(key, "hdrcharset") == 0) {
|
||||
if (val == NULL || val[0] == 0)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
@@ -474,22 +471,19 @@ static int
|
||||
archive_read_format_lha_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct lha *lha = a->format->data;
|
||||
struct archive_wstring linkname;
|
||||
struct archive_wstring pathname;
|
||||
struct lha *lha;
|
||||
const unsigned char *p;
|
||||
const char *signature;
|
||||
int err;
|
||||
struct archive_mstring conv_buffer;
|
||||
const wchar_t *conv_buffer_p;
|
||||
|
||||
lha_crc16_init();
|
||||
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_LHA;
|
||||
if (a->archive.archive_format_name == NULL)
|
||||
a->archive.archive_format_name = "lha";
|
||||
|
||||
lha = (struct lha *)(a->format->data);
|
||||
lha->decompress_init = 0;
|
||||
lha->end_of_entry = 0;
|
||||
lha->end_of_entry_cleanup = 0;
|
||||
@@ -613,7 +607,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted "
|
||||
"from %s to Unicode.",
|
||||
"from %s to Unicode",
|
||||
archive_string_conversion_charset_name(lha->sconv_dir));
|
||||
err = ARCHIVE_FATAL;
|
||||
} else if (0 != archive_mstring_get_wcs(&a->archive, &conv_buffer, &conv_buffer_p))
|
||||
@@ -634,7 +628,7 @@ archive_read_format_lha_read_header(struct archive_read *a,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted "
|
||||
"from %s to Unicode.",
|
||||
"from %s to Unicode",
|
||||
archive_string_conversion_charset_name(lha->sconv_fname));
|
||||
err = ARCHIVE_FATAL;
|
||||
}
|
||||
@@ -904,7 +898,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
|
||||
{
|
||||
const unsigned char *p;
|
||||
size_t extdsize;
|
||||
int i, err, err2;
|
||||
int err, err2;
|
||||
int namelen, padding;
|
||||
unsigned char headersum, sum_calculated;
|
||||
|
||||
@@ -929,10 +923,9 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
|
||||
if ((p = __archive_read_ahead(a, lha->header_size, NULL)) == NULL)
|
||||
return (truncated_error(a));
|
||||
|
||||
for (i = 0; i < namelen; i++) {
|
||||
if (p[i + H1_FILE_NAME_OFFSET] == 0xff)
|
||||
goto invalid;/* Invalid filename. */
|
||||
}
|
||||
if (memchr(p + H1_FILE_NAME_OFFSET, 0xff,
|
||||
(size_t)namelen) != NULL)
|
||||
goto invalid; /* Invalid filename. */
|
||||
archive_strncpy(&lha->filename, p + H1_FILE_NAME_OFFSET, namelen);
|
||||
lha->crc = archive_le16dec(p + H1_FILE_NAME_OFFSET + namelen);
|
||||
lha->setflag |= CRC_IS_SET;
|
||||
@@ -1101,7 +1094,7 @@ lha_read_file_header_3(struct archive_read *a, struct lha *lha)
|
||||
header_crc = lha_crc16(0, p, H3_FIXED_SIZE);
|
||||
__archive_read_consume(a, H3_FIXED_SIZE);
|
||||
|
||||
/* Reject rediculously large header */
|
||||
/* Reject ridiculously large header */
|
||||
if (lha->header_size > 65536) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"LHa header size too large");
|
||||
@@ -1456,7 +1449,7 @@ invalid:
|
||||
static int
|
||||
lha_end_of_entry(struct archive_read *a)
|
||||
{
|
||||
struct lha *lha = (struct lha *)(a->format->data);
|
||||
struct lha *lha = a->format->data;
|
||||
int r = ARCHIVE_EOF;
|
||||
|
||||
if (!lha->end_of_entry_cleanup) {
|
||||
@@ -1477,7 +1470,7 @@ static int
|
||||
archive_read_format_lha_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct lha *lha = (struct lha *)(a->format->data);
|
||||
struct lha *lha = a->format->data;
|
||||
int r;
|
||||
|
||||
if (lha->entry_unconsumed) {
|
||||
@@ -1510,7 +1503,7 @@ static int
|
||||
lha_read_data_none(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct lha *lha = (struct lha *)(a->format->data);
|
||||
struct lha *lha = a->format->data;
|
||||
ssize_t bytes_avail;
|
||||
|
||||
if (lha->entry_bytes_remaining == 0) {
|
||||
@@ -1557,7 +1550,7 @@ static int
|
||||
lha_read_data_lzh(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct lha *lha = (struct lha *)(a->format->data);
|
||||
struct lha *lha = a->format->data;
|
||||
ssize_t bytes_avail;
|
||||
int r;
|
||||
|
||||
@@ -1588,7 +1581,6 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
|
||||
/* We've initialized decompression for this stream. */
|
||||
lha->decompress_init = 1;
|
||||
lha->strm.avail_out = 0;
|
||||
lha->strm.total_out = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1648,11 +1640,9 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
|
||||
static int
|
||||
archive_read_format_lha_read_data_skip(struct archive_read *a)
|
||||
{
|
||||
struct lha *lha;
|
||||
struct lha *lha = a->format->data;
|
||||
int64_t bytes_skipped;
|
||||
|
||||
lha = (struct lha *)(a->format->data);
|
||||
|
||||
if (lha->entry_unconsumed) {
|
||||
/* Consume as much as the decompressor actually used. */
|
||||
__archive_read_consume(a, lha->entry_unconsumed);
|
||||
@@ -1679,7 +1669,7 @@ archive_read_format_lha_read_data_skip(struct archive_read *a)
|
||||
static int
|
||||
archive_read_format_lha_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct lha *lha = (struct lha *)(a->format->data);
|
||||
struct lha *lha = a->format->data;
|
||||
|
||||
lzh_decode_free(&(lha->strm));
|
||||
archive_string_free(&(lha->dirname));
|
||||
@@ -1688,7 +1678,7 @@ archive_read_format_lha_cleanup(struct archive_read *a)
|
||||
archive_string_free(&(lha->gname));
|
||||
archive_wstring_free(&(lha->ws));
|
||||
free(lha);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -1733,30 +1723,86 @@ lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
|
||||
return (sum);
|
||||
}
|
||||
|
||||
static uint16_t crc16tbl[2][256];
|
||||
static void
|
||||
lha_crc16_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
static int crc16init = 0;
|
||||
|
||||
if (crc16init)
|
||||
return;
|
||||
crc16init = 1;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
unsigned int j;
|
||||
uint16_t crc = (uint16_t)i;
|
||||
for (j = 8; j; j--)
|
||||
crc = (crc >> 1) ^ ((crc & 1) * 0xA001);
|
||||
crc16tbl[0][i] = crc;
|
||||
static const uint16_t crc16tbl[2][256] = {
|
||||
{
|
||||
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280,
|
||||
0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1,
|
||||
0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00,
|
||||
0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40,
|
||||
0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980,
|
||||
0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1,
|
||||
0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400,
|
||||
0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
|
||||
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081,
|
||||
0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1,
|
||||
0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501,
|
||||
0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40,
|
||||
0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80,
|
||||
0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1,
|
||||
0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01,
|
||||
0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
|
||||
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681,
|
||||
0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
|
||||
0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300,
|
||||
0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740,
|
||||
0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81,
|
||||
0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0,
|
||||
0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800,
|
||||
0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
|
||||
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81,
|
||||
0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1,
|
||||
0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101,
|
||||
0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140,
|
||||
0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780,
|
||||
0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0,
|
||||
0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00,
|
||||
0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
|
||||
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81,
|
||||
0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0,
|
||||
0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701,
|
||||
0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
|
||||
0x4100, 0x81c1, 0x8081, 0x4040
|
||||
},
|
||||
{
|
||||
0x0000, 0x9001, 0x6001, 0xf000, 0xc002, 0x5003, 0xa003,
|
||||
0x3002, 0xc007, 0x5006, 0xa006, 0x3007, 0x0005, 0x9004,
|
||||
0x6004, 0xf005, 0xc00d, 0x500c, 0xa00c, 0x300d, 0x000f,
|
||||
0x900e, 0x600e, 0xf00f, 0x000a, 0x900b, 0x600b, 0xf00a,
|
||||
0xc008, 0x5009, 0xa009, 0x3008, 0xc019, 0x5018, 0xa018,
|
||||
0x3019, 0x001b, 0x901a, 0x601a, 0xf01b, 0x001e, 0x901f,
|
||||
0x601f, 0xf01e, 0xc01c, 0x501d, 0xa01d, 0x301c, 0x0014,
|
||||
0x9015, 0x6015, 0xf014, 0xc016, 0x5017, 0xa017, 0x3016,
|
||||
0xc013, 0x5012, 0xa012, 0x3013, 0x0011, 0x9010, 0x6010,
|
||||
0xf011, 0xc031, 0x5030, 0xa030, 0x3031, 0x0033, 0x9032,
|
||||
0x6032, 0xf033, 0x0036, 0x9037, 0x6037, 0xf036, 0xc034,
|
||||
0x5035, 0xa035, 0x3034, 0x003c, 0x903d, 0x603d, 0xf03c,
|
||||
0xc03e, 0x503f, 0xa03f, 0x303e, 0xc03b, 0x503a, 0xa03a,
|
||||
0x303b, 0x0039, 0x9038, 0x6038, 0xf039, 0x0028, 0x9029,
|
||||
0x6029, 0xf028, 0xc02a, 0x502b, 0xa02b, 0x302a, 0xc02f,
|
||||
0x502e, 0xa02e, 0x302f, 0x002d, 0x902c, 0x602c, 0xf02d,
|
||||
0xc025, 0x5024, 0xa024, 0x3025, 0x0027, 0x9026, 0x6026,
|
||||
0xf027, 0x0022, 0x9023, 0x6023, 0xf022, 0xc020, 0x5021,
|
||||
0xa021, 0x3020, 0xc061, 0x5060, 0xa060, 0x3061, 0x0063,
|
||||
0x9062, 0x6062, 0xf063, 0x0066, 0x9067, 0x6067, 0xf066,
|
||||
0xc064, 0x5065, 0xa065, 0x3064, 0x006c, 0x906d, 0x606d,
|
||||
0xf06c, 0xc06e, 0x506f, 0xa06f, 0x306e, 0xc06b, 0x506a,
|
||||
0xa06a, 0x306b, 0x0069, 0x9068, 0x6068, 0xf069, 0x0078,
|
||||
0x9079, 0x6079, 0xf078, 0xc07a, 0x507b, 0xa07b, 0x307a,
|
||||
0xc07f, 0x507e, 0xa07e, 0x307f, 0x007d, 0x907c, 0x607c,
|
||||
0xf07d, 0xc075, 0x5074, 0xa074, 0x3075, 0x0077, 0x9076,
|
||||
0x6076, 0xf077, 0x0072, 0x9073, 0x6073, 0xf072, 0xc070,
|
||||
0x5071, 0xa071, 0x3070, 0x0050, 0x9051, 0x6051, 0xf050,
|
||||
0xc052, 0x5053, 0xa053, 0x3052, 0xc057, 0x5056, 0xa056,
|
||||
0x3057, 0x0055, 0x9054, 0x6054, 0xf055, 0xc05d, 0x505c,
|
||||
0xa05c, 0x305d, 0x005f, 0x905e, 0x605e, 0xf05f, 0x005a,
|
||||
0x905b, 0x605b, 0xf05a, 0xc058, 0x5059, 0xa059, 0x3058,
|
||||
0xc049, 0x5048, 0xa048, 0x3049, 0x004b, 0x904a, 0x604a,
|
||||
0xf04b, 0x004e, 0x904f, 0x604f, 0xf04e, 0xc04c, 0x504d,
|
||||
0xa04d, 0x304c, 0x0044, 0x9045, 0x6045, 0xf044, 0xc046,
|
||||
0x5047, 0xa047, 0x3046, 0xc043, 0x5042, 0xa042, 0x3043,
|
||||
0x0041, 0x9040, 0x6040, 0xf041
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
crc16tbl[1][i] = (crc16tbl[0][i] >> 8)
|
||||
^ crc16tbl[0][crc16tbl[0][i] & 0xff];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static uint16_t
|
||||
lha_crc16(uint16_t crc, const void *pp, size_t len)
|
||||
@@ -2084,7 +2130,6 @@ lzh_emit_window(struct lzh_stream *strm, size_t s)
|
||||
{
|
||||
strm->ref_ptr = strm->ds->w_buff;
|
||||
strm->avail_out = (int)s;
|
||||
strm->total_out += s;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_private.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_platform_stat.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_rb.h"
|
||||
@@ -140,56 +141,6 @@ static int64_t mtree_atol(char **, int base);
|
||||
static size_t mtree_strnlen(const char *, size_t);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them
|
||||
* here. TODO: Move this to configure time, but be careful
|
||||
* about cross-compile environments.
|
||||
*/
|
||||
static int64_t
|
||||
get_time_t_max(void)
|
||||
{
|
||||
#if defined(TIME_T_MAX)
|
||||
return TIME_T_MAX;
|
||||
#else
|
||||
/* ISO C allows time_t to be a floating-point type,
|
||||
but POSIX requires an integer type. The following
|
||||
should work on any system that follows the POSIX
|
||||
conventions. */
|
||||
if (((time_t)0) < ((time_t)-1)) {
|
||||
/* Time_t is unsigned */
|
||||
return (~(time_t)0);
|
||||
} else {
|
||||
/* Time_t is signed. */
|
||||
/* Assume it's the same as int64_t or int32_t */
|
||||
if (sizeof(time_t) == sizeof(int64_t)) {
|
||||
return (time_t)INT64_MAX;
|
||||
} else {
|
||||
return (time_t)INT32_MAX;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int64_t
|
||||
get_time_t_min(void)
|
||||
{
|
||||
#if defined(TIME_T_MIN)
|
||||
return TIME_T_MIN;
|
||||
#else
|
||||
if (((time_t)0) < ((time_t)-1)) {
|
||||
/* Time_t is unsigned */
|
||||
return (time_t)0;
|
||||
} else {
|
||||
/* Time_t is signed. */
|
||||
if (sizeof(time_t) == sizeof(int64_t)) {
|
||||
return (time_t)INT64_MIN;
|
||||
} else {
|
||||
return (time_t)INT32_MIN;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_STRNLEN
|
||||
#define mtree_strnlen(a,b) strnlen(a,b)
|
||||
#else
|
||||
@@ -198,12 +149,10 @@ mtree_strnlen(const char *p, size_t maxlen)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i <= maxlen; i++) {
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
if (p[i] == 0)
|
||||
break;
|
||||
}
|
||||
if (i > maxlen)
|
||||
return (-1);/* invalid */
|
||||
return (i);
|
||||
}
|
||||
#endif
|
||||
@@ -212,9 +161,8 @@ static int
|
||||
archive_read_format_mtree_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct mtree *mtree;
|
||||
struct mtree *mtree = a->format->data;
|
||||
|
||||
mtree = (struct mtree *)(a->format->data);
|
||||
if (strcmp(key, "checkfs") == 0) {
|
||||
/* Allows to read information missing from the mtree from the file system */
|
||||
if (val == NULL || val[0] == 0) {
|
||||
@@ -296,11 +244,9 @@ archive_read_support_format_mtree(struct archive *_a)
|
||||
static int
|
||||
cleanup(struct archive_read *a)
|
||||
{
|
||||
struct mtree *mtree;
|
||||
struct mtree *mtree = a->format->data;
|
||||
struct mtree_entry *p, *q;
|
||||
|
||||
mtree = (struct mtree *)(a->format->data);
|
||||
|
||||
/* Close any dangling file descriptor before freeing */
|
||||
if (mtree->fd >= 0) {
|
||||
close(mtree->fd);
|
||||
@@ -321,7 +267,7 @@ cleanup(struct archive_read *a)
|
||||
|
||||
free(mtree->buff);
|
||||
free(mtree);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -386,7 +332,7 @@ next_line(struct archive_read *a,
|
||||
*/
|
||||
while (*nl == 0 && len == *avail && !quit) {
|
||||
ssize_t diff = *ravail - *avail;
|
||||
size_t nbytes_req = (*ravail+1023) & ~1023U;
|
||||
size_t nbytes_req = ((size_t)*ravail + 1023) & ~1023U;
|
||||
ssize_t tested;
|
||||
|
||||
/*
|
||||
@@ -875,7 +821,7 @@ process_global_set(struct archive_read *a,
|
||||
line = next;
|
||||
next = line + strcspn(line, " \t\r\n");
|
||||
eq = strchr(line, '=');
|
||||
if (eq > next)
|
||||
if (eq == NULL || eq > next)
|
||||
len = next - line;
|
||||
else
|
||||
len = eq - line;
|
||||
@@ -1120,12 +1066,10 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
|
||||
static int
|
||||
read_header(struct archive_read *a, struct archive_entry *entry)
|
||||
{
|
||||
struct mtree *mtree;
|
||||
struct mtree *mtree = a->format->data;
|
||||
char *p;
|
||||
int r, use_next;
|
||||
|
||||
mtree = (struct mtree *)(a->format->data);
|
||||
|
||||
if (mtree->fd >= 0) {
|
||||
close(mtree->fd);
|
||||
mtree->fd = -1;
|
||||
@@ -1780,8 +1724,6 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
|
||||
}
|
||||
if (strcmp(key, "time") == 0) {
|
||||
int64_t m;
|
||||
int64_t my_time_t_max = get_time_t_max();
|
||||
int64_t my_time_t_min = get_time_t_min();
|
||||
long ns = 0;
|
||||
|
||||
*parsed_kws |= MTREE_HAS_MTIME;
|
||||
@@ -1790,17 +1732,21 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
|
||||
* 123456789.1 represents 123456789
|
||||
* seconds and 1 nanosecond. */
|
||||
if (*val == '.') {
|
||||
int64_t v;
|
||||
|
||||
++val;
|
||||
ns = (long)mtree_atol(&val, 10);
|
||||
if (ns < 0)
|
||||
v = mtree_atol(&val, 10);
|
||||
if (v < 0)
|
||||
ns = 0;
|
||||
else if (ns > 999999999)
|
||||
else if (v > 999999999)
|
||||
ns = 999999999;
|
||||
else
|
||||
ns = (long)v;
|
||||
}
|
||||
if (m > my_time_t_max)
|
||||
m = my_time_t_max;
|
||||
else if (m < my_time_t_min)
|
||||
m = my_time_t_min;
|
||||
if (m > TIME_MAX)
|
||||
m = TIME_MAX;
|
||||
else if (m < TIME_MIN)
|
||||
m = TIME_MIN;
|
||||
archive_entry_set_mtime(entry, (time_t)m, ns);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -1887,11 +1833,10 @@ static int
|
||||
read_data(struct archive_read *a, const void **buff, size_t *size,
|
||||
int64_t *offset)
|
||||
{
|
||||
struct mtree *mtree = a->format->data;
|
||||
size_t bytes_to_read;
|
||||
ssize_t bytes_read;
|
||||
struct mtree *mtree;
|
||||
|
||||
mtree = (struct mtree *)(a->format->data);
|
||||
if (mtree->fd < 0) {
|
||||
*buff = NULL;
|
||||
*offset = 0;
|
||||
@@ -1932,9 +1877,8 @@ read_data(struct archive_read *a, const void **buff, size_t *size,
|
||||
static int
|
||||
skip(struct archive_read *a)
|
||||
{
|
||||
struct mtree *mtree;
|
||||
struct mtree *mtree = a->format->data;
|
||||
|
||||
mtree = (struct mtree *)(a->format->data);
|
||||
if (mtree->fd >= 0) {
|
||||
close(mtree->fd);
|
||||
mtree->fd = -1;
|
||||
@@ -2029,9 +1973,9 @@ parsedigit(char c)
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a';
|
||||
return 10 + c - 'a';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A';
|
||||
return 10 + c - 'A';
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
@@ -2044,8 +1988,8 @@ parsedigit(char c)
|
||||
static int64_t
|
||||
mtree_atol(char **p, int base)
|
||||
{
|
||||
int64_t l, limit;
|
||||
int digit, last_digit_limit;
|
||||
int64_t l;
|
||||
int digit;
|
||||
|
||||
if (base == 0) {
|
||||
if (**p != '0')
|
||||
@@ -2059,29 +2003,24 @@ mtree_atol(char **p, int base)
|
||||
}
|
||||
|
||||
if (**p == '-') {
|
||||
limit = INT64_MIN / base;
|
||||
last_digit_limit = -(INT64_MIN % base);
|
||||
++(*p);
|
||||
|
||||
l = 0;
|
||||
digit = parsedigit(**p);
|
||||
while (digit >= 0 && digit < base) {
|
||||
if (l < limit || (l == limit && digit >= last_digit_limit))
|
||||
if (archive_ckd_mul_i64(&l, l, base) ||
|
||||
archive_ckd_sub_i64(&l, l, digit))
|
||||
return INT64_MIN;
|
||||
l = (l * base) - digit;
|
||||
digit = parsedigit(*++(*p));
|
||||
}
|
||||
return l;
|
||||
} else {
|
||||
limit = INT64_MAX / base;
|
||||
last_digit_limit = INT64_MAX % base;
|
||||
|
||||
l = 0;
|
||||
digit = parsedigit(**p);
|
||||
while (digit >= 0 && digit < base) {
|
||||
if (l > limit || (l == limit && digit > last_digit_limit))
|
||||
if (archive_ckd_mul_i64(&l, l, base) ||
|
||||
archive_ckd_add_i64(&l, l, digit))
|
||||
return INT64_MAX;
|
||||
l = (l * base) + digit;
|
||||
digit = parsedigit(*++(*p));
|
||||
}
|
||||
return l;
|
||||
@@ -2100,8 +2039,7 @@ readline(struct archive_read *a, struct mtree *mtree, char **start,
|
||||
ssize_t bytes_read;
|
||||
ssize_t total_size = 0;
|
||||
ssize_t find_off = 0;
|
||||
const void *t;
|
||||
void *nl;
|
||||
const void *nl, *t;
|
||||
char *u;
|
||||
|
||||
/* Accumulate line in a line buffer. */
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "archive_endian.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_ppmd7_private.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
@@ -156,7 +157,7 @@
|
||||
#define UNP_BUFFER_SIZE (128 * 1024)
|
||||
|
||||
/* Define this here for non-Windows platforms */
|
||||
#if !((defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__))
|
||||
#ifndef FILE_ATTRIBUTE_DIRECTORY
|
||||
#define FILE_ATTRIBUTE_DIRECTORY 0x10
|
||||
#endif
|
||||
|
||||
@@ -203,8 +204,8 @@ struct huffman_table_entry
|
||||
struct huffman_code
|
||||
{
|
||||
struct huffman_tree_node *tree;
|
||||
int numentries;
|
||||
int numallocatedentries;
|
||||
size_t numentries;
|
||||
size_t numallocatedentries;
|
||||
int minlength;
|
||||
int maxlength;
|
||||
int tablesize;
|
||||
@@ -229,8 +230,6 @@ struct rar_program_code
|
||||
{
|
||||
uint8_t *staticdata;
|
||||
uint32_t staticdatalen;
|
||||
uint8_t *globalbackup;
|
||||
uint32_t globalbackuplen;
|
||||
uint64_t fingerprint;
|
||||
uint32_t usagecount;
|
||||
uint32_t oldfilterlength;
|
||||
@@ -501,7 +500,7 @@ static const uint32_t cache_masks[] = {
|
||||
static int
|
||||
rar_br_fillup(struct archive_read *a, struct rar_br *br)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
int n = CACHE_BITS - br->cache_avail;
|
||||
|
||||
for (;;) {
|
||||
@@ -596,7 +595,7 @@ rar_br_fillup(struct archive_read *a, struct rar_br *br)
|
||||
static int
|
||||
rar_br_preparation(struct archive_read *a, struct rar_br *br)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
|
||||
if (rar->bytes_remaining > 0) {
|
||||
br->next_in = rar_read_ahead(a, 1, &(br->avail_in));
|
||||
@@ -711,7 +710,7 @@ static Byte
|
||||
ppmd_read(void *p)
|
||||
{
|
||||
struct archive_read *a = ((IByteIn*)p)->a;
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
struct rar_br *br = &(rar->br);
|
||||
Byte b;
|
||||
if (!rar_br_read_ahead(a, br, 8))
|
||||
@@ -779,7 +778,7 @@ static int
|
||||
archive_read_format_rar_has_encrypted_entries(struct archive_read *_a)
|
||||
{
|
||||
if (_a && _a->format) {
|
||||
struct rar * rar = (struct rar *)_a->format->data;
|
||||
struct rar *rar = _a->format->data;
|
||||
if (rar) {
|
||||
return rar->has_encrypted_entries;
|
||||
}
|
||||
@@ -879,10 +878,9 @@ static int
|
||||
archive_read_format_rar_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct rar *rar;
|
||||
struct rar *rar = a->format->data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
if (strcmp(key, "hdrcharset") == 0) {
|
||||
if (val == NULL || val[0] == 0)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
@@ -909,9 +907,9 @@ static int
|
||||
archive_read_format_rar_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
const void *h;
|
||||
const char *p;
|
||||
struct rar *rar;
|
||||
int64_t skip;
|
||||
char head_type;
|
||||
int ret;
|
||||
@@ -922,8 +920,6 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
if (a->archive.archive_format_name == NULL)
|
||||
a->archive.archive_format_name = "RAR";
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
|
||||
/*
|
||||
* It should be sufficient to call archive_read_next_header() for
|
||||
* a reader to determine if an entry is encrypted or not. If the
|
||||
@@ -957,7 +953,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
|
||||
if ((h = __archive_read_ahead(a, 7, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read next header.");
|
||||
"Failed to read next header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
@@ -1007,7 +1003,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
archive_entry_set_is_data_encrypted(entry, 1);
|
||||
rar->has_encrypted_entries = 1;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"RAR encryption support unavailable.");
|
||||
"RAR encryption support unavailable");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
@@ -1102,7 +1098,7 @@ static int
|
||||
archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
int ret;
|
||||
|
||||
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
@@ -1143,8 +1139,8 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
|
||||
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported compression method for RAR file.");
|
||||
ret = ARCHIVE_FATAL;
|
||||
"Unsupported compression method for RAR file");
|
||||
ret = ARCHIVE_FAILED;
|
||||
break;
|
||||
}
|
||||
return (ret);
|
||||
@@ -1153,12 +1149,10 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
|
||||
static int
|
||||
archive_read_format_rar_read_data_skip(struct archive_read *a)
|
||||
{
|
||||
struct rar *rar;
|
||||
struct rar *rar = a->format->data;
|
||||
int64_t bytes_skipped;
|
||||
int ret;
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
|
||||
if (rar->bytes_unconsumed > 0) {
|
||||
/* Consume as much as the decompressor actually used. */
|
||||
__archive_read_consume(a, rar->bytes_unconsumed);
|
||||
@@ -1191,9 +1185,9 @@ static int64_t
|
||||
archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
|
||||
int whence)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
int64_t client_offset, ret;
|
||||
size_t i;
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
|
||||
if (rar->compression_method == COMPRESS_METHOD_STORE)
|
||||
{
|
||||
@@ -1296,6 +1290,12 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
|
||||
"Error during seek of RAR file");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (rar->cursor == 0)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Invalid RAR seek cursor state");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
client_offset += rar->dbo[rar->cursor].start_offset -
|
||||
rar->dbo[rar->cursor-1].end_offset;
|
||||
continue;
|
||||
@@ -1344,9 +1344,8 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
|
||||
static int
|
||||
archive_read_format_rar_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct rar *rar;
|
||||
struct rar *rar = a->format->data;
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
free_codes(a);
|
||||
clear_filters(&rar->filters);
|
||||
free(rar->filename);
|
||||
@@ -1356,7 +1355,7 @@ archive_read_format_rar_cleanup(struct archive_read *a)
|
||||
free(rar->lzss.window);
|
||||
__archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
|
||||
free(rar);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -1364,9 +1363,9 @@ static int
|
||||
read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
char head_type)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
const void *h;
|
||||
const char *p, *endp;
|
||||
struct rar *rar;
|
||||
struct rar_header rar_header;
|
||||
struct rar_file_header file_header;
|
||||
int64_t header_size;
|
||||
@@ -1382,8 +1381,6 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
char *newptr;
|
||||
size_t newsize;
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
|
||||
/* Setup a string conversion object for non-rar-unicode filenames. */
|
||||
sconv = rar->opt_sconv;
|
||||
if (sconv == NULL) {
|
||||
@@ -1434,14 +1431,14 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
else
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"RAR solid archive support unavailable.");
|
||||
"RAR solid archive support unavailable");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read full header content.");
|
||||
"Failed to read full header content");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
@@ -1473,7 +1470,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
archive_entry_set_is_data_encrypted(entry, 1);
|
||||
rar->has_encrypted_entries = 1;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"RAR encryption support unavailable.");
|
||||
"RAR encryption support unavailable");
|
||||
/* Since it is only the data part itself that is encrypted we can at least
|
||||
extract information about the currently processed entry and don't need
|
||||
to return ARCHIVE_FATAL here. */
|
||||
@@ -1505,7 +1502,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
if (rar->packed_size < 0 || rar->unp_size < 0)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid sizes specified.");
|
||||
"Invalid sizes specified");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
@@ -1515,27 +1512,23 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
* consumed at the end.
|
||||
*/
|
||||
if (head_type == NEWSUB_HEAD) {
|
||||
size_t distance = p - (const char *)h;
|
||||
if (rar->packed_size > INT64_MAX - header_size) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Extended header size too large.");
|
||||
"Invalid RAR file: Overlarge extended header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
header_size += rar->packed_size;
|
||||
if ((uintmax_t)header_size > SIZE_MAX) {
|
||||
if (__archive_read_consume(a, header_size + rar->packed_size - 7) < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to read extended header data.");
|
||||
"Invalid RAR file: Cannot read extended header data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/* Make sure we have the extended data. */
|
||||
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read extended header data.");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
endp = p + header_size - 7;
|
||||
p += distance;
|
||||
|
||||
/*
|
||||
* NEWSUB records are metadata-only in this reader. The block header
|
||||
* has already been validated, so it is safe to skip exactly the
|
||||
* remaining header bytes and the associated data payload.
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
filename_size = archive_le16dec(file_header.name_size);
|
||||
@@ -1549,7 +1542,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
newptr = realloc(rar->filename, newsize);
|
||||
if (newptr == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Couldn't allocate memory.");
|
||||
"Couldn't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->filename = newptr;
|
||||
@@ -1674,16 +1667,18 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
fn_sconv = rar->sconv_utf8;
|
||||
while ((strp = strchr(filename, '\\')) != NULL)
|
||||
*strp = '/';
|
||||
strp = filename;
|
||||
while ((strp = strchr(strp, '\\')) != NULL)
|
||||
*strp++ = '/';
|
||||
p += filename_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fn_sconv = sconv;
|
||||
while ((strp = strchr(filename, '\\')) != NULL)
|
||||
*strp = '/';
|
||||
strp = filename;
|
||||
while ((strp = strchr(strp, '\\')) != NULL)
|
||||
*strp++ = '/';
|
||||
p += filename_size;
|
||||
}
|
||||
|
||||
@@ -1703,7 +1698,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
newsize = sizeof(*rar->dbo) * (rar->nodes + 1);
|
||||
if ((newdbo = realloc(rar->dbo, newsize)) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
|
||||
archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->dbo = newdbo;
|
||||
@@ -1717,7 +1712,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
if (rar->packed_size > INT64_MAX - a->filter->position)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to store offsets.");
|
||||
"Unable to store offsets");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->dbo[rar->cursor].start_offset = a->filter->position;
|
||||
@@ -1736,7 +1731,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
newsize = filename_size + 1;
|
||||
if ((newptr = realloc(rar->filename_save, newsize)) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
|
||||
archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->filename_save = newptr;
|
||||
@@ -1747,7 +1742,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
free(rar->dbo);
|
||||
if ((rar->dbo = calloc(1, sizeof(*rar->dbo))) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory.");
|
||||
archive_set_error(&a->archive, ENOMEM, "Couldn't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->dbo[0].header_size = header_size;
|
||||
@@ -1778,7 +1773,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
__archive_read_consume(a, header_size - 7);
|
||||
if (rar->packed_size > INT64_MAX - a->filter->position) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to store offsets.");
|
||||
"Unable to store offsets");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->dbo[0].start_offset = a->filter->position;
|
||||
@@ -1831,10 +1826,6 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
rar->ppmd_valid = rar->ppmd_eod = 0;
|
||||
rar->filters.filterstart = INT64_MAX;
|
||||
|
||||
/* Don't set any archive entries for non-file header types */
|
||||
if (head_type == NEWSUB_HEAD)
|
||||
return ret;
|
||||
|
||||
archive_entry_set_mtime(entry, rar->mtime, rar->mnsec);
|
||||
archive_entry_set_ctime(entry, rar->ctime, rar->cnsec);
|
||||
archive_entry_set_atime(entry, rar->atime, rar->ansec);
|
||||
@@ -1850,7 +1841,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted from %s to current locale.",
|
||||
"Pathname cannot be converted from %s to current locale",
|
||||
archive_string_conversion_charset_name(fn_sconv));
|
||||
ret = (ARCHIVE_WARN);
|
||||
}
|
||||
@@ -1972,22 +1963,21 @@ static int
|
||||
read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
|
||||
struct archive_string_conv *sconv)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
const void *h;
|
||||
const char *p;
|
||||
struct rar *rar;
|
||||
int ret = (ARCHIVE_OK);
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
if ((uintmax_t)rar->packed_size > SIZE_MAX)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to read link.");
|
||||
"Unable to read link");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to read link.");
|
||||
"Failed to read link");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
@@ -2002,7 +1992,7 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"link cannot be converted from %s to current locale.",
|
||||
"link cannot be converted from %s to current locale",
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret = (ARCHIVE_WARN);
|
||||
}
|
||||
@@ -2014,10 +2004,9 @@ static int
|
||||
read_data_stored(struct archive_read *a, const void **buff, size_t *size,
|
||||
int64_t *offset)
|
||||
{
|
||||
struct rar *rar;
|
||||
struct rar *rar = a->format->data;
|
||||
ssize_t bytes_avail;
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
if (rar->bytes_remaining == 0 &&
|
||||
!(rar->main_flags & MHD_VOLUME && rar->file_flags & FHD_SPLIT_AFTER))
|
||||
{
|
||||
@@ -2028,7 +2017,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"File CRC error");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
#endif
|
||||
}
|
||||
rar->entry_eof = 1;
|
||||
@@ -2040,7 +2029,7 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
*size = bytes_avail;
|
||||
@@ -2060,18 +2049,16 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
int64_t *offset, size_t looper)
|
||||
{
|
||||
if (looper++ > MAX_COMPRESS_DEPTH)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
struct rar *rar;
|
||||
struct rar *rar = a->format->data;
|
||||
int64_t start, end;
|
||||
size_t bs;
|
||||
int ret = (ARCHIVE_OK), sym, code, lzss_offset, length, i;
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
|
||||
do {
|
||||
if (!rar->valid)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
if (rar->filters.bytes_ready > 0)
|
||||
{
|
||||
@@ -2123,7 +2110,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"File CRC error");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
#endif
|
||||
}
|
||||
rar->entry_eof = 1;
|
||||
@@ -2157,7 +2144,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
if (rar->filters.lastend == rar->filters.filterstart)
|
||||
{
|
||||
if (!run_filters(a))
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2174,7 +2161,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if(sym != rar->ppmd_escape)
|
||||
{
|
||||
@@ -2188,7 +2175,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
switch(code)
|
||||
@@ -2203,7 +2190,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
|
||||
case 3:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Parsing filters is unsupported.");
|
||||
"Parsing filters is unsupported");
|
||||
return (ARCHIVE_FAILED);
|
||||
|
||||
case 4:
|
||||
@@ -2215,7 +2202,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lzss_offset |= code << (i * 8);
|
||||
}
|
||||
@@ -2224,7 +2211,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lzss_emit_match(rar, lzss_offset + 2, length + 32);
|
||||
rar->bytes_uncopied += length + 32;
|
||||
@@ -2236,7 +2223,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid symbol");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lzss_emit_match(rar, 1, length + 4);
|
||||
rar->bytes_uncopied += length + 4;
|
||||
@@ -2282,7 +2269,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
|
||||
* what we would do to solve it. */
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Internal error extracting RAR file");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
}
|
||||
if (rar->bytes_uncopied > (rar->unp_buffer_size - rar->unp_offset))
|
||||
@@ -2313,11 +2300,11 @@ ending_block:
|
||||
static int
|
||||
parse_codes(struct archive_read *a)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
int i, j, val, n, r;
|
||||
unsigned char bitlengths[MAX_SYMBOLS], zerocount, ppmd_flags;
|
||||
unsigned int maxorder;
|
||||
struct huffman_code precode;
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar_br *br = &(rar->br);
|
||||
|
||||
free_codes(a);
|
||||
@@ -2365,7 +2352,7 @@ parse_codes(struct archive_read *a)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/* Make sure ppmd7_context is freed before Ppmd7_Construct
|
||||
@@ -2381,7 +2368,7 @@ parse_codes(struct archive_read *a)
|
||||
if (rar->dictionary_size == 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid zero dictionary size");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
|
||||
@@ -2395,7 +2382,7 @@ parse_codes(struct archive_read *a)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to initialize PPMd range decoder");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
__archive_ppmd7_functions.Ppmd7_Init(&rar->ppmd7_context, maxorder);
|
||||
rar->ppmd_valid = 1;
|
||||
@@ -2405,13 +2392,13 @@ parse_codes(struct archive_read *a)
|
||||
if (!rar->ppmd_valid) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid PPMd sequence");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (!__archive_ppmd7_functions.PpmdRAR_RangeDec_Init(&rar->range_dec))
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unable to initialize PPMd range decoder");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2419,6 +2406,13 @@ parse_codes(struct archive_read *a)
|
||||
{
|
||||
rar_br_consume(br, 1);
|
||||
|
||||
/*
|
||||
* Low-distance repeat state belongs to the current LZ table and
|
||||
* must not be reused after starting a new table.
|
||||
*/
|
||||
rar->lastlowoffset = 0;
|
||||
rar->numlowoffsetrepeats = 0;
|
||||
|
||||
/* Keep existing table flag */
|
||||
if (!rar_br_read_ahead(a, br, 1))
|
||||
goto truncated_data;
|
||||
@@ -2461,7 +2455,7 @@ parse_codes(struct archive_read *a)
|
||||
if ((val = read_next_symbol(a, &precode)) < 0) {
|
||||
free(precode.tree);
|
||||
free(precode.table);
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (val < 16)
|
||||
{
|
||||
@@ -2475,8 +2469,8 @@ parse_codes(struct archive_read *a)
|
||||
free(precode.tree);
|
||||
free(precode.table);
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Internal error extracting RAR file.");
|
||||
return (ARCHIVE_FATAL);
|
||||
"Internal error extracting RAR file");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if(val == 16) {
|
||||
@@ -2550,7 +2544,8 @@ parse_codes(struct archive_read *a)
|
||||
return (r);
|
||||
}
|
||||
|
||||
if (!rar->dictionary_size || !rar->lzss.window)
|
||||
if (!rar->dictionary_size || !rar->lzss.window ||
|
||||
(unsigned int)(rar->lzss.mask + 1) < rar->dictionary_size)
|
||||
{
|
||||
/* Seems as though dictionary sizes are not used. Even so, minimize
|
||||
* memory usage as much as possible.
|
||||
@@ -2564,13 +2559,13 @@ parse_codes(struct archive_read *a)
|
||||
new_size = rar_fls((unsigned int)rar->unp_size) << 1;
|
||||
if (new_size == 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Zero window size is invalid.");
|
||||
return (ARCHIVE_FATAL);
|
||||
"Zero window size is invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
new_window = realloc(rar->lzss.window, new_size);
|
||||
if (new_window == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Unable to allocate memory for uncompressed data.");
|
||||
"Unable to allocate memory for uncompressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rar->lzss.window = (unsigned char *)new_window;
|
||||
@@ -2585,13 +2580,13 @@ truncated_data:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
rar->valid = 0;
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static void
|
||||
free_codes(struct archive_read *a)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
free(rar->maincode.tree);
|
||||
free(rar->offsetcode.tree);
|
||||
free(rar->lowoffsetcode.tree);
|
||||
@@ -2610,10 +2605,10 @@ free_codes(struct archive_read *a)
|
||||
static int
|
||||
read_next_symbol(struct archive_read *a, struct huffman_code *code)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
unsigned char bit;
|
||||
unsigned int bits;
|
||||
int length, value, node;
|
||||
struct rar *rar;
|
||||
struct rar_br *br;
|
||||
|
||||
if (!code->table)
|
||||
@@ -2622,7 +2617,6 @@ read_next_symbol(struct archive_read *a, struct huffman_code *code)
|
||||
return -1;
|
||||
}
|
||||
|
||||
rar = (struct rar *)(a->format->data);
|
||||
br = &(rar->br);
|
||||
|
||||
/* Look ahead (peek) at bits */
|
||||
@@ -2688,7 +2682,7 @@ create_code(struct archive_read *a, struct huffman_code *code,
|
||||
code->numallocatedentries = 0;
|
||||
if (new_node(code) < 0) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Unable to allocate memory for node data.");
|
||||
"Unable to allocate memory for node data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
code->numentries = 1;
|
||||
@@ -2701,7 +2695,7 @@ create_code(struct archive_read *a, struct huffman_code *code,
|
||||
{
|
||||
if (lengths[j] != i) continue;
|
||||
if (add_value(a, code, j, codebits, i) != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
codebits++;
|
||||
if (--symbolsleft <= 0)
|
||||
break;
|
||||
@@ -2753,7 +2747,7 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Prefix found");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2771,12 +2765,12 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
|
||||
|
||||
if ((repeatnode = new_node(code)) < 0) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Unable to allocate memory for node data.");
|
||||
"Unable to allocate memory for node data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if ((nextnode = new_node(code)) < 0) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Unable to allocate memory for node data.");
|
||||
"Unable to allocate memory for node data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
@@ -2796,7 +2790,7 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
|
||||
{
|
||||
if (new_node(code) < 0) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Unable to allocate memory for node data.");
|
||||
"Unable to allocate memory for node data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
code->tree[lastnode].branches[bit] = code->numentries++;
|
||||
@@ -2812,7 +2806,7 @@ add_value(struct archive_read *a, struct huffman_code *code, int value,
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Prefix found");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
/* Set leaf value */
|
||||
@@ -2827,11 +2821,16 @@ new_node(struct huffman_code *code)
|
||||
{
|
||||
void *new_tree;
|
||||
if (code->numallocatedentries == code->numentries) {
|
||||
int new_num_entries = 256;
|
||||
if (code->numentries > 0) {
|
||||
new_num_entries = code->numentries * 2;
|
||||
}
|
||||
new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree));
|
||||
size_t size, new_num_entries;
|
||||
|
||||
if (code->numentries == 0)
|
||||
new_num_entries = 256;
|
||||
else if (archive_ckd_mul_size(&new_num_entries, code->numentries, 2)
|
||||
|| new_num_entries > INT_MAX)
|
||||
return -1;
|
||||
if (archive_ckd_mul_size(&size, new_num_entries, sizeof(*code->tree)))
|
||||
return -1;
|
||||
new_tree = realloc(code->tree, size);
|
||||
if (new_tree == NULL)
|
||||
return (-1);
|
||||
code->tree = (struct huffman_tree_node *)new_tree;
|
||||
@@ -2851,6 +2850,10 @@ make_table(struct archive_read *a, struct huffman_code *code)
|
||||
code->tablesize = code->maxlength;
|
||||
|
||||
code->table = calloc(((size_t)1U) << code->tablesize, sizeof(*code->table));
|
||||
if (code->table == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
|
||||
}
|
||||
@@ -2865,14 +2868,14 @@ make_table_recurse(struct archive_read *a, struct huffman_code *code, int node,
|
||||
if (!code->tree)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Huffman tree was not created.");
|
||||
return (ARCHIVE_FATAL);
|
||||
"Huffman tree was not created");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (node < 0 || node >= code->numentries)
|
||||
if (node < 0 || (size_t)node >= code->numentries)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid location to Huffman tree specified.");
|
||||
return (ARCHIVE_FATAL);
|
||||
"Invalid location to Huffman tree specified");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
currtablesize = 1 << (maxdepth - depth);
|
||||
@@ -2956,9 +2959,9 @@ expand(struct archive_read *a, int64_t *end)
|
||||
static const unsigned char shortbits[] =
|
||||
{ 2, 2, 3, 4, 5, 6, 6, 6 };
|
||||
|
||||
struct rar *rar = a->format->data;
|
||||
int symbol, offs, len, offsindex, lensymbol, i, offssymbol, lowoffsetsymbol;
|
||||
unsigned char newfile;
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar_br *br = &(rar->br);
|
||||
|
||||
if (rar->filters.filterstart < *end)
|
||||
@@ -3135,26 +3138,31 @@ truncated_data:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated RAR file data");
|
||||
rar->valid = 0;
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
bad_data:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static int
|
||||
copy_from_lzss_window(struct archive_read *a, uint8_t *buffer,
|
||||
int64_t startpos, int length)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
int windowoffs, firstpart;
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
|
||||
windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
|
||||
firstpart = lzss_size(&rar->lzss) - windowoffs;
|
||||
if (length > lzss_size(&rar->lzss)) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (firstpart < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (firstpart < length) {
|
||||
memcpy(buffer, &rar->lzss.window[windowoffs], firstpart);
|
||||
@@ -3169,8 +3177,8 @@ static int
|
||||
copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
|
||||
int64_t startpos, size_t length)
|
||||
{
|
||||
struct rar *rar = a->format->data;
|
||||
int windowoffs, firstpart;
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
|
||||
if (length > rar->unp_buffer_size)
|
||||
{
|
||||
@@ -3182,7 +3190,7 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
|
||||
if ((rar->unp_buffer = malloc(rar->unp_buffer_size)) == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Unable to allocate memory for uncompressed data.");
|
||||
"Unable to allocate memory for uncompressed data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
@@ -3196,7 +3204,7 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
|
||||
if (firstpart < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if ((size_t)firstpart < length) {
|
||||
memcpy(&rar->unp_buffer[rar->unp_offset],
|
||||
@@ -3220,13 +3228,13 @@ copy_from_lzss_window_to_unp(struct archive_read *a, const void **buffer,
|
||||
fatal:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static const void *
|
||||
rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
const void *h;
|
||||
int ret;
|
||||
|
||||
@@ -3263,7 +3271,7 @@ again:
|
||||
static int
|
||||
parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint8_t flags)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
struct rar_filters *filters = &rar->filters;
|
||||
|
||||
struct memory_bit_reader br = { 0 };
|
||||
@@ -3318,7 +3326,8 @@ parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint
|
||||
else
|
||||
blocklength = prog ? prog->oldfilterlength : 0;
|
||||
|
||||
if (blocklength > rar->dictionary_size)
|
||||
if (blocklength > rar->dictionary_size ||
|
||||
blocklength > (uint32_t)(rar->lzss.mask + 1))
|
||||
return 0;
|
||||
|
||||
registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS;
|
||||
@@ -3431,7 +3440,7 @@ create_filter(struct rar_program_code *prog, const uint8_t *globaldata, uint32_t
|
||||
static int
|
||||
run_filters(struct archive_read *a)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
struct rar_filters *filters = &rar->filters;
|
||||
struct rar_filter *filter = filters->stack;
|
||||
struct rar_filter *f;
|
||||
@@ -3552,7 +3561,13 @@ compile_program(const uint8_t *bytes, size_t length)
|
||||
|
||||
if (membr_bits(&br, 1))
|
||||
{
|
||||
prog->staticdatalen = membr_next_rarvm_number(&br) + 1;
|
||||
uint32_t staticdatalen = membr_next_rarvm_number(&br);
|
||||
if (staticdatalen >= VM_MEMORY_SIZE)
|
||||
{
|
||||
delete_program_code(prog);
|
||||
return NULL;
|
||||
}
|
||||
prog->staticdatalen = staticdatalen + 1;
|
||||
prog->staticdata = malloc(prog->staticdatalen);
|
||||
if (!prog->staticdata)
|
||||
{
|
||||
@@ -3593,7 +3608,6 @@ delete_program_code(struct rar_program_code *prog)
|
||||
{
|
||||
struct rar_program_code *next = prog->next;
|
||||
free(prog->staticdata);
|
||||
free(prog->globalbackup);
|
||||
free(prog);
|
||||
prog = next;
|
||||
}
|
||||
@@ -3646,7 +3660,7 @@ membr_fill(struct memory_bit_reader *br, int bits)
|
||||
static int
|
||||
read_filter(struct archive_read *a, int64_t *end)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
uint8_t flags, val, *code;
|
||||
uint16_t length, i;
|
||||
|
||||
@@ -3842,7 +3856,7 @@ execute_filter_audio(struct rar_filter *filter, struct rar_virtual_machine *vm)
|
||||
state.delta[0] = state.lastdelta;
|
||||
predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF;
|
||||
byte = (predbyte - delta) & 0xFF;
|
||||
prederror = delta << 3;
|
||||
prederror = delta * 8;
|
||||
state.error[0] += abs(prederror);
|
||||
state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]);
|
||||
state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]);
|
||||
@@ -3899,7 +3913,7 @@ execute_filter(struct archive_read *a, struct rar_filter *filter, struct rar_vir
|
||||
static int
|
||||
rar_decode_byte(struct archive_read *a, uint8_t *byte)
|
||||
{
|
||||
struct rar *rar = (struct rar *)(a->format->data);
|
||||
struct rar *rar = a->format->data;
|
||||
struct rar_br *br = &(rar->br);
|
||||
if (!rar_br_read_ahead(a, br, 8))
|
||||
return 0;
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_ppmd7_private.h"
|
||||
#include "archive_entry_private.h"
|
||||
#include "archive_time_private.h"
|
||||
@@ -81,7 +82,9 @@
|
||||
*
|
||||
* The array itself is decrypted in `rar5_init` function. */
|
||||
|
||||
static unsigned char rar5_signature_xor[] = { 243, 192, 211, 128, 187, 166, 160, 161 };
|
||||
static const unsigned char rar5_signature_xor[] = {
|
||||
243, 192, 211, 128, 187, 166, 160, 161
|
||||
};
|
||||
static const size_t g_unpack_window_size = 0x20000;
|
||||
|
||||
/* These could have been static const's, but they aren't, because of
|
||||
@@ -165,11 +168,9 @@ enum FILTER_TYPE {
|
||||
struct filter_info {
|
||||
int type;
|
||||
int channels;
|
||||
int pos_r;
|
||||
|
||||
int64_t block_start;
|
||||
ssize_t block_length;
|
||||
uint16_t width;
|
||||
};
|
||||
|
||||
struct data_ready {
|
||||
@@ -372,10 +373,10 @@ struct rar5 {
|
||||
static void rar5_signature(char *buf);
|
||||
static int verify_global_checksums(struct archive_read* a);
|
||||
static int rar5_read_data_skip(struct archive_read *a);
|
||||
static int push_data_ready(struct archive_read* a, struct rar5* rar,
|
||||
static int push_data_ready(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* buf, size_t size, int64_t offset);
|
||||
static void clear_data_ready_stack(struct rar5* rar);
|
||||
static void rar5_deinit(struct rar5* rar);
|
||||
static void clear_data_ready_stack(struct rar5 *rar5);
|
||||
static void rar5_deinit(struct rar5 *rar5);
|
||||
|
||||
/* CDE_xxx = Circular Double Ended (Queue) return values. */
|
||||
enum CDE_RETURN_VALUES {
|
||||
@@ -514,10 +515,6 @@ uint8_t bf_is_last_block(const struct compressed_block_header* hdr) {
|
||||
return (hdr->block_flags_u8 >> 6) & 1;
|
||||
}
|
||||
|
||||
static inline struct rar5* get_context(struct archive_read* a) {
|
||||
return (struct rar5*) a->format->data;
|
||||
}
|
||||
|
||||
/* Convenience functions used by filter implementations. */
|
||||
static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,
|
||||
int64_t start, int64_t end)
|
||||
@@ -533,28 +530,28 @@ static void circular_memcpy(uint8_t* dst, uint8_t* window, const ssize_t mask,
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t read_filter_data(struct rar5* rar, uint32_t offset) {
|
||||
static uint32_t read_filter_data(struct rar5 *rar5, uint32_t offset) {
|
||||
uint8_t linear_buf[4];
|
||||
circular_memcpy(linear_buf, rar->cstate.window_buf,
|
||||
rar->cstate.window_mask, offset, offset + 4);
|
||||
circular_memcpy(linear_buf, rar5->cstate.window_buf,
|
||||
rar5->cstate.window_mask, offset, offset + 4);
|
||||
return archive_le32dec(linear_buf);
|
||||
}
|
||||
|
||||
static void write_filter_data(struct rar5* rar, uint32_t offset,
|
||||
static void write_filter_data(struct rar5 *rar5, uint32_t offset,
|
||||
uint32_t value)
|
||||
{
|
||||
archive_le32enc(&rar->cstate.filtered_buf[offset], value);
|
||||
archive_le32enc(&rar5->cstate.filtered_buf[offset], value);
|
||||
}
|
||||
|
||||
/* Allocates a new filter descriptor and adds it to the filter array. */
|
||||
static struct filter_info* add_new_filter(struct rar5* rar) {
|
||||
static struct filter_info* add_new_filter(struct rar5 *rar5) {
|
||||
struct filter_info* f = calloc(1, sizeof(*f));
|
||||
|
||||
if(!f) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CDE_OK != cdeque_push_back(&rar->cstate.filters, cdeque_filter(f))) {
|
||||
if (CDE_OK != cdeque_push_back(&rar5->cstate.filters, cdeque_filter(f))) {
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
@@ -562,7 +559,7 @@ static struct filter_info* add_new_filter(struct rar5* rar) {
|
||||
return f;
|
||||
}
|
||||
|
||||
static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {
|
||||
static int run_delta_filter(struct rar5 *rar5, struct filter_info* flt) {
|
||||
int i;
|
||||
ssize_t dest_pos, src_pos = 0;
|
||||
|
||||
@@ -574,12 +571,12 @@ static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
byte = rar->cstate.window_buf[
|
||||
(rar->cstate.solid_offset + flt->block_start +
|
||||
src_pos) & rar->cstate.window_mask];
|
||||
byte = rar5->cstate.window_buf[
|
||||
(rar5->cstate.solid_offset + flt->block_start +
|
||||
src_pos) & rar5->cstate.window_mask];
|
||||
|
||||
prev_byte -= byte;
|
||||
rar->cstate.filtered_buf[dest_pos] = prev_byte;
|
||||
rar5->cstate.filtered_buf[dest_pos] = prev_byte;
|
||||
src_pos++;
|
||||
}
|
||||
}
|
||||
@@ -587,21 +584,21 @@ static int run_delta_filter(struct rar5* rar, struct filter_info* flt) {
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,
|
||||
static int run_e8e9_filter(struct rar5 *rar5, struct filter_info* flt,
|
||||
int extended)
|
||||
{
|
||||
const uint32_t file_size = 0x1000000;
|
||||
ssize_t i;
|
||||
|
||||
circular_memcpy(rar->cstate.filtered_buf,
|
||||
rar->cstate.window_buf, rar->cstate.window_mask,
|
||||
rar->cstate.solid_offset + flt->block_start,
|
||||
rar->cstate.solid_offset + flt->block_start + flt->block_length);
|
||||
circular_memcpy(rar5->cstate.filtered_buf,
|
||||
rar5->cstate.window_buf, rar5->cstate.window_mask,
|
||||
rar5->cstate.solid_offset + flt->block_start,
|
||||
rar5->cstate.solid_offset + flt->block_start + flt->block_length);
|
||||
|
||||
for(i = 0; i < flt->block_length - 4;) {
|
||||
uint8_t b = rar->cstate.window_buf[
|
||||
(rar->cstate.solid_offset + flt->block_start +
|
||||
i++) & rar->cstate.window_mask];
|
||||
uint8_t b = rar5->cstate.window_buf[
|
||||
(rar5->cstate.solid_offset + flt->block_start +
|
||||
i++) & rar5->cstate.window_mask];
|
||||
|
||||
/*
|
||||
* 0xE8 = x86's call <relative_addr_uint32> (function call)
|
||||
@@ -612,19 +609,19 @@ static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,
|
||||
uint32_t addr;
|
||||
uint32_t offset = (i + flt->block_start) % file_size;
|
||||
|
||||
addr = read_filter_data(rar,
|
||||
(uint32_t)(rar->cstate.solid_offset +
|
||||
flt->block_start + i) & rar->cstate.window_mask);
|
||||
addr = read_filter_data(rar5,
|
||||
(uint32_t)(rar5->cstate.solid_offset +
|
||||
flt->block_start + i) & rar5->cstate.window_mask);
|
||||
|
||||
if(addr & 0x80000000) {
|
||||
if(((addr + offset) & 0x80000000) == 0) {
|
||||
write_filter_data(rar, (uint32_t)i,
|
||||
write_filter_data(rar5, (uint32_t)i,
|
||||
addr + file_size);
|
||||
}
|
||||
} else {
|
||||
if((addr - file_size) & 0x80000000) {
|
||||
uint32_t naddr = addr - offset;
|
||||
write_filter_data(rar, (uint32_t)i,
|
||||
write_filter_data(rar5, (uint32_t)i,
|
||||
naddr);
|
||||
}
|
||||
}
|
||||
@@ -636,29 +633,29 @@ static int run_e8e9_filter(struct rar5* rar, struct filter_info* flt,
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {
|
||||
static int run_arm_filter(struct rar5 *rar5, struct filter_info* flt) {
|
||||
ssize_t i = 0;
|
||||
uint32_t offset;
|
||||
|
||||
circular_memcpy(rar->cstate.filtered_buf,
|
||||
rar->cstate.window_buf, rar->cstate.window_mask,
|
||||
rar->cstate.solid_offset + flt->block_start,
|
||||
rar->cstate.solid_offset + flt->block_start + flt->block_length);
|
||||
circular_memcpy(rar5->cstate.filtered_buf,
|
||||
rar5->cstate.window_buf, rar5->cstate.window_mask,
|
||||
rar5->cstate.solid_offset + flt->block_start,
|
||||
rar5->cstate.solid_offset + flt->block_start + flt->block_length);
|
||||
|
||||
for(i = 0; i < flt->block_length - 3; i += 4) {
|
||||
uint8_t* b = &rar->cstate.window_buf[
|
||||
(rar->cstate.solid_offset +
|
||||
flt->block_start + i + 3) & rar->cstate.window_mask];
|
||||
uint8_t* b = &rar5->cstate.window_buf[
|
||||
(rar5->cstate.solid_offset +
|
||||
flt->block_start + i + 3) & rar5->cstate.window_mask];
|
||||
|
||||
if(*b == 0xEB) {
|
||||
/* 0xEB = ARM's BL (branch + link) instruction. */
|
||||
offset = read_filter_data(rar,
|
||||
(rar->cstate.solid_offset + flt->block_start + i) &
|
||||
(uint32_t)rar->cstate.window_mask) & 0x00ffffff;
|
||||
offset = read_filter_data(rar5,
|
||||
(rar5->cstate.solid_offset + flt->block_start + i) &
|
||||
(uint32_t)rar5->cstate.window_mask) & 0x00ffffff;
|
||||
|
||||
offset -= (uint32_t) ((i + flt->block_start) / 4);
|
||||
offset = (offset & 0x00ffffff) | 0xeb000000;
|
||||
write_filter_data(rar, (uint32_t)i, offset);
|
||||
write_filter_data(rar5, (uint32_t)i, offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -666,33 +663,33 @@ static int run_arm_filter(struct rar5* rar, struct filter_info* flt) {
|
||||
}
|
||||
|
||||
static int run_filter(struct archive_read* a, struct filter_info* flt) {
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int ret;
|
||||
struct rar5* rar = get_context(a);
|
||||
|
||||
clear_data_ready_stack(rar);
|
||||
free(rar->cstate.filtered_buf);
|
||||
clear_data_ready_stack(rar5);
|
||||
free(rar5->cstate.filtered_buf);
|
||||
|
||||
rar->cstate.filtered_buf = malloc(flt->block_length);
|
||||
if(!rar->cstate.filtered_buf) {
|
||||
rar5->cstate.filtered_buf = malloc(flt->block_length);
|
||||
if(!rar5->cstate.filtered_buf) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for filter data.");
|
||||
"Can't allocate memory for filter data");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
switch(flt->type) {
|
||||
case FILTER_DELTA:
|
||||
ret = run_delta_filter(rar, flt);
|
||||
ret = run_delta_filter(rar5, flt);
|
||||
break;
|
||||
|
||||
case FILTER_E8:
|
||||
/* fallthrough */
|
||||
case FILTER_E8E9:
|
||||
ret = run_e8e9_filter(rar, flt,
|
||||
ret = run_e8e9_filter(rar5, flt,
|
||||
flt->type == FILTER_E8E9);
|
||||
break;
|
||||
|
||||
case FILTER_ARM:
|
||||
ret = run_arm_filter(rar, flt);
|
||||
ret = run_arm_filter(rar5, flt);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -700,7 +697,7 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported filter type: 0x%x",
|
||||
(unsigned int)flt->type);
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(ret != ARCHIVE_OK) {
|
||||
@@ -708,8 +705,8 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(ARCHIVE_OK != push_data_ready(a, rar, rar->cstate.filtered_buf,
|
||||
flt->block_length, rar->cstate.last_write_ptr))
|
||||
if(ARCHIVE_OK != push_data_ready(a, rar5, rar5->cstate.filtered_buf,
|
||||
flt->block_length, rar5->cstate.last_write_ptr))
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Stack overflow when submitting unpacked data");
|
||||
@@ -717,7 +714,7 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->cstate.last_write_ptr += flt->block_length;
|
||||
rar5->cstate.last_write_ptr += flt->block_length;
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
@@ -725,15 +722,15 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
|
||||
* Next call of `use_data` will use the pointer, size and offset arguments
|
||||
* that are specified here. These arguments are pushed to the FIFO stack here,
|
||||
* and popped from the stack by the `use_data` function. */
|
||||
static void push_data(struct archive_read* a, struct rar5* rar,
|
||||
static void push_data(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* buf, int64_t idx_begin, int64_t idx_end)
|
||||
{
|
||||
const ssize_t wmask = rar->cstate.window_mask;
|
||||
const ssize_t solid_write_ptr = (rar->cstate.solid_offset +
|
||||
rar->cstate.last_write_ptr) & wmask;
|
||||
const ssize_t wmask = rar5->cstate.window_mask;
|
||||
const ssize_t solid_write_ptr = (rar5->cstate.solid_offset +
|
||||
rar5->cstate.last_write_ptr) & wmask;
|
||||
|
||||
idx_begin += rar->cstate.solid_offset;
|
||||
idx_end += rar->cstate.solid_offset;
|
||||
idx_begin += rar5->cstate.solid_offset;
|
||||
idx_end += rar5->cstate.solid_offset;
|
||||
|
||||
/* Check if our unpacked data is wrapped inside the window circular
|
||||
* buffer. If it's not wrapped, it can be copied out by using
|
||||
@@ -743,57 +740,57 @@ static void push_data(struct archive_read* a, struct rar5* rar,
|
||||
if((idx_begin & wmask) > (idx_end & wmask)) {
|
||||
/* The data is wrapped (begin offset sis bigger than end
|
||||
* offset). */
|
||||
const ssize_t frag1_size = rar->cstate.window_size -
|
||||
const ssize_t frag1_size = rar5->cstate.window_size -
|
||||
(idx_begin & wmask);
|
||||
const ssize_t frag2_size = idx_end & wmask;
|
||||
|
||||
/* Copy the first part of the buffer first. */
|
||||
push_data_ready(a, rar, buf + solid_write_ptr, frag1_size,
|
||||
rar->cstate.last_write_ptr);
|
||||
push_data_ready(a, rar5, buf + solid_write_ptr, frag1_size,
|
||||
rar5->cstate.last_write_ptr);
|
||||
|
||||
/* Copy the second part of the buffer. */
|
||||
push_data_ready(a, rar, buf, frag2_size,
|
||||
rar->cstate.last_write_ptr + frag1_size);
|
||||
push_data_ready(a, rar5, buf, frag2_size,
|
||||
rar5->cstate.last_write_ptr + frag1_size);
|
||||
|
||||
rar->cstate.last_write_ptr += frag1_size + frag2_size;
|
||||
rar5->cstate.last_write_ptr += frag1_size + frag2_size;
|
||||
} else {
|
||||
/* Data is not wrapped, so we can just use one call to copy the
|
||||
* data. */
|
||||
push_data_ready(a, rar,
|
||||
push_data_ready(a, rar5,
|
||||
buf + solid_write_ptr, (idx_end - idx_begin) & wmask,
|
||||
rar->cstate.last_write_ptr);
|
||||
rar5->cstate.last_write_ptr);
|
||||
|
||||
rar->cstate.last_write_ptr += idx_end - idx_begin;
|
||||
rar5->cstate.last_write_ptr += idx_end - idx_begin;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convenience function that submits the data to the user. It uses the
|
||||
* unpack window buffer as a source location. */
|
||||
static void push_window_data(struct archive_read* a, struct rar5* rar,
|
||||
static void push_window_data(struct archive_read* a, struct rar5 *rar5,
|
||||
int64_t idx_begin, int64_t idx_end)
|
||||
{
|
||||
push_data(a, rar, rar->cstate.window_buf, idx_begin, idx_end);
|
||||
push_data(a, rar5, rar5->cstate.window_buf, idx_begin, idx_end);
|
||||
}
|
||||
|
||||
static int apply_filters(struct archive_read* a) {
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
struct filter_info* flt;
|
||||
struct rar5* rar = get_context(a);
|
||||
int ret;
|
||||
|
||||
rar->cstate.all_filters_applied = 0;
|
||||
rar5->cstate.all_filters_applied = 0;
|
||||
|
||||
/* Get the first filter that can be applied to our data. The data
|
||||
* needs to be fully unpacked before the filter can be run. */
|
||||
if(CDE_OK == cdeque_front(&rar->cstate.filters,
|
||||
if(CDE_OK == cdeque_front(&rar5->cstate.filters,
|
||||
cdeque_filter_p(&flt))) {
|
||||
/* Check if our unpacked data fully covers this filter's
|
||||
* range. */
|
||||
if(rar->cstate.write_ptr > flt->block_start &&
|
||||
rar->cstate.write_ptr >= flt->block_start +
|
||||
if(rar5->cstate.write_ptr > flt->block_start &&
|
||||
rar5->cstate.write_ptr >= flt->block_start +
|
||||
flt->block_length) {
|
||||
/* Check if we have some data pending to be written
|
||||
* right before the filter's start offset. */
|
||||
if(rar->cstate.last_write_ptr == flt->block_start) {
|
||||
if(rar5->cstate.last_write_ptr == flt->block_start) {
|
||||
/* Run the filter specified by descriptor
|
||||
* `flt`. */
|
||||
ret = run_filter(a, flt);
|
||||
@@ -805,15 +802,15 @@ static int apply_filters(struct archive_read* a) {
|
||||
/* Filter descriptor won't be needed anymore
|
||||
* after it's used, * so remove it from the
|
||||
* filter list and free its memory. */
|
||||
(void) cdeque_pop_front(&rar->cstate.filters,
|
||||
(void) cdeque_pop_front(&rar5->cstate.filters,
|
||||
cdeque_filter_p(&flt));
|
||||
|
||||
free(flt);
|
||||
} else {
|
||||
/* We can't run filters yet, dump the memory
|
||||
* right before the filter. */
|
||||
push_window_data(a, rar,
|
||||
rar->cstate.last_write_ptr,
|
||||
push_window_data(a, rar5,
|
||||
rar5->cstate.last_write_ptr,
|
||||
flt->block_start);
|
||||
}
|
||||
|
||||
@@ -823,12 +820,12 @@ static int apply_filters(struct archive_read* a) {
|
||||
}
|
||||
}
|
||||
|
||||
rar->cstate.all_filters_applied = 1;
|
||||
rar5->cstate.all_filters_applied = 1;
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static void dist_cache_push(struct rar5* rar, int value) {
|
||||
int* q = rar->cstate.dist_cache;
|
||||
static void dist_cache_push(struct rar5 *rar5, int value) {
|
||||
int* q = rar5->cstate.dist_cache;
|
||||
|
||||
q[3] = q[2];
|
||||
q[2] = q[1];
|
||||
@@ -836,8 +833,8 @@ static void dist_cache_push(struct rar5* rar, int value) {
|
||||
q[0] = value;
|
||||
}
|
||||
|
||||
static int dist_cache_touch(struct rar5* rar, int idx) {
|
||||
int* q = rar->cstate.dist_cache;
|
||||
static int dist_cache_touch(struct rar5 *rar5, int idx) {
|
||||
int* q = rar5->cstate.dist_cache;
|
||||
int i, dist = q[idx];
|
||||
|
||||
for(i = idx; i > 0; i--)
|
||||
@@ -847,8 +844,8 @@ static int dist_cache_touch(struct rar5* rar, int idx) {
|
||||
return dist;
|
||||
}
|
||||
|
||||
static void free_filters(struct rar5* rar) {
|
||||
struct cdeque* d = &rar->cstate.filters;
|
||||
static void free_filters(struct rar5 *rar5) {
|
||||
struct cdeque* d = &rar5->cstate.filters;
|
||||
|
||||
/* Free any remaining filters. All filters should be naturally
|
||||
* consumed by the unpacking function, so remaining filters after
|
||||
@@ -868,28 +865,28 @@ static void free_filters(struct rar5* rar) {
|
||||
cdeque_clear(d);
|
||||
|
||||
/* Also clear out the variables needed for sanity checking. */
|
||||
rar->cstate.last_block_start = 0;
|
||||
rar->cstate.last_block_length = 0;
|
||||
rar5->cstate.last_block_start = 0;
|
||||
rar5->cstate.last_block_length = 0;
|
||||
}
|
||||
|
||||
static void reset_file_context(struct rar5* rar) {
|
||||
memset(&rar->file, 0, sizeof(rar->file));
|
||||
blake2sp_init(&rar->file.b2state, 32);
|
||||
static void reset_file_context(struct rar5 *rar5) {
|
||||
memset(&rar5->file, 0, sizeof(rar5->file));
|
||||
blake2sp_init(&rar5->file.b2state, 32);
|
||||
|
||||
if(rar->main.solid) {
|
||||
rar->cstate.solid_offset += rar->cstate.write_ptr;
|
||||
if(rar5->main.solid) {
|
||||
rar5->cstate.solid_offset += rar5->cstate.write_ptr;
|
||||
} else {
|
||||
rar->cstate.solid_offset = 0;
|
||||
rar5->cstate.solid_offset = 0;
|
||||
}
|
||||
|
||||
rar->cstate.write_ptr = 0;
|
||||
rar->cstate.last_write_ptr = 0;
|
||||
rar->cstate.last_unstore_ptr = 0;
|
||||
rar5->cstate.write_ptr = 0;
|
||||
rar5->cstate.last_write_ptr = 0;
|
||||
rar5->cstate.last_unstore_ptr = 0;
|
||||
|
||||
rar->file.redir_type = REDIR_TYPE_NONE;
|
||||
rar->file.redir_flags = 0;
|
||||
rar5->file.redir_type = REDIR_TYPE_NONE;
|
||||
rar5->file.redir_flags = 0;
|
||||
|
||||
free_filters(rar);
|
||||
free_filters(rar5);
|
||||
}
|
||||
|
||||
static inline int get_archive_read(struct archive* a,
|
||||
@@ -905,11 +902,10 @@ static inline int get_archive_read(struct archive* a,
|
||||
static int read_ahead(struct archive_read* a, size_t how_many,
|
||||
const uint8_t** ptr)
|
||||
{
|
||||
ssize_t avail = -1;
|
||||
if(!ptr)
|
||||
return 0;
|
||||
|
||||
*ptr = __archive_read_ahead(a, how_many, &avail);
|
||||
*ptr = __archive_read_ahead(a, how_many, NULL);
|
||||
if(*ptr == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@@ -947,23 +943,30 @@ static int consume(struct archive_read* a, int64_t how_many) {
|
||||
static int read_var(struct archive_read* a, uint64_t* pvalue,
|
||||
uint64_t* pvalue_len)
|
||||
{
|
||||
uint64_t multiplier;
|
||||
uint64_t result = 0;
|
||||
size_t shift, i;
|
||||
size_t i;
|
||||
const uint8_t* p;
|
||||
uint8_t b;
|
||||
|
||||
/* We will read maximum of 8 bytes. We don't have to handle the
|
||||
/* We will read maximum of 10 bytes. We don't have to handle the
|
||||
* situation to read the RAR5 variable-sized value stored at the end of
|
||||
* the file, because such situation will never happen. */
|
||||
if(!read_ahead(a, 8, &p))
|
||||
if(!read_ahead(a, 10, &p))
|
||||
return 0;
|
||||
|
||||
for(shift = 0, i = 0; i < 8; i++, shift += 7) {
|
||||
for(multiplier = 1, i = 0; i < 10; i++, multiplier *= 128) {
|
||||
uint64_t val;
|
||||
uint8_t b;
|
||||
|
||||
b = p[i];
|
||||
|
||||
/* Strip the MSB from the input byte and add the resulting
|
||||
* number to the `result`. */
|
||||
result += (b & (uint64_t)0x7F) << shift;
|
||||
if(archive_ckd_mul_u64(&val, b & 0x7F, multiplier) ||
|
||||
archive_ckd_add_u64(&result, result, val)) {
|
||||
/* Integer overflow occurred. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MSB set to 1 means we need to continue decoding process.
|
||||
* MSB set to 0 means we're done.
|
||||
@@ -997,22 +1000,8 @@ static int read_var(struct archive_read* a, uint64_t* pvalue,
|
||||
}
|
||||
}
|
||||
|
||||
/* The decoded value takes the maximum number of 8 bytes.
|
||||
* It's a maximum number of bytes, so end decoding process here
|
||||
* even if the first bit of last byte is 1. */
|
||||
if(pvalue) {
|
||||
*pvalue = result;
|
||||
}
|
||||
|
||||
if(pvalue_len) {
|
||||
*pvalue_len = 9;
|
||||
} else {
|
||||
if(ARCHIVE_OK != consume(a, 9)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* All continuation bits were set. This is an error. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_var_sized(struct archive_read* a, size_t* pvalue,
|
||||
@@ -1036,52 +1025,47 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_bits_32(struct archive_read* a, struct rar5* rar,
|
||||
static int read_bits_32(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* p, uint32_t* value)
|
||||
{
|
||||
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
|
||||
if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Premature end of stream during extraction of data (#1)");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24;
|
||||
bits |= p[rar->bits.in_addr + 1] << 16;
|
||||
bits |= p[rar->bits.in_addr + 2] << 8;
|
||||
bits |= p[rar->bits.in_addr + 3];
|
||||
bits <<= rar->bits.bit_addr;
|
||||
bits |= p[rar->bits.in_addr + 4] >> (8 - rar->bits.bit_addr);
|
||||
uint32_t bits = archive_be32dec(p + rar5->bits.in_addr);
|
||||
bits <<= rar5->bits.bit_addr;
|
||||
bits |= p[rar5->bits.in_addr + 4] >> (8 - rar5->bits.bit_addr);
|
||||
*value = bits;
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int read_bits_16(struct archive_read* a, struct rar5* rar,
|
||||
static int read_bits_16(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* p, uint16_t* value)
|
||||
{
|
||||
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
|
||||
if(rar5->bits.in_addr >= rar5->cstate.cur_block_size) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Premature end of stream during extraction of data (#2)");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16;
|
||||
bits |= (int) p[rar->bits.in_addr + 1] << 8;
|
||||
bits |= (int) p[rar->bits.in_addr + 2];
|
||||
bits >>= (8 - rar->bits.bit_addr);
|
||||
uint32_t bits = archive_be24dec(p + (unsigned)rar5->bits.in_addr);
|
||||
bits >>= (8 - rar5->bits.bit_addr);
|
||||
*value = bits & 0xffff;
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static void skip_bits(struct rar5* rar, int bits) {
|
||||
const int new_bits = rar->bits.bit_addr + bits;
|
||||
rar->bits.in_addr += new_bits >> 3;
|
||||
rar->bits.bit_addr = new_bits & 7;
|
||||
static void skip_bits(struct rar5 *rar5, int bits) {
|
||||
const int new_bits = rar5->bits.bit_addr + bits;
|
||||
rar5->bits.in_addr += new_bits >> 3;
|
||||
rar5->bits.bit_addr = new_bits & 7;
|
||||
}
|
||||
|
||||
/* n = up to 16 */
|
||||
static int read_consume_bits(struct archive_read* a, struct rar5* rar,
|
||||
static int read_consume_bits(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* p, int n, int* value)
|
||||
{
|
||||
uint16_t v;
|
||||
@@ -1093,14 +1077,14 @@ static int read_consume_bits(struct archive_read* a, struct rar5* rar,
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
ret = read_bits_16(a, rar, p, &v);
|
||||
ret = read_bits_16(a, rar5, p, &v);
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
num = (int) v;
|
||||
num >>= 16 - n;
|
||||
|
||||
skip_bits(rar, n);
|
||||
skip_bits(rar5, n);
|
||||
|
||||
if(value)
|
||||
*value = num;
|
||||
@@ -1215,11 +1199,11 @@ static void init_header(struct archive_read* a) {
|
||||
a->archive.archive_format_name = "RAR5";
|
||||
}
|
||||
|
||||
static void init_window_mask(struct rar5* rar) {
|
||||
if (rar->cstate.window_size)
|
||||
rar->cstate.window_mask = rar->cstate.window_size - 1;
|
||||
static void init_window_mask(struct rar5 *rar5) {
|
||||
if (rar5->cstate.window_size)
|
||||
rar5->cstate.window_mask = rar5->cstate.window_size - 1;
|
||||
else
|
||||
rar->cstate.window_mask = 0;
|
||||
rar5->cstate.window_mask = 0;
|
||||
}
|
||||
|
||||
enum HEADER_FLAGS {
|
||||
@@ -1233,7 +1217,7 @@ enum HEADER_FLAGS {
|
||||
};
|
||||
|
||||
static int process_main_locator_extra_block(struct archive_read* a,
|
||||
struct rar5* rar)
|
||||
struct rar5 *rar5)
|
||||
{
|
||||
uint64_t locator_flags;
|
||||
|
||||
@@ -1246,7 +1230,7 @@ static int process_main_locator_extra_block(struct archive_read* a,
|
||||
}
|
||||
|
||||
if(locator_flags & QLIST) {
|
||||
if(!read_var(a, &rar->qlist_offset, NULL)) {
|
||||
if(!read_var(a, &rar5->qlist_offset, NULL)) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
@@ -1254,7 +1238,7 @@ static int process_main_locator_extra_block(struct archive_read* a,
|
||||
}
|
||||
|
||||
if(locator_flags & RECOVERY) {
|
||||
if(!read_var(a, &rar->rr_offset, NULL)) {
|
||||
if(!read_var(a, &rar5->rr_offset, NULL)) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
@@ -1264,7 +1248,7 @@ static int process_main_locator_extra_block(struct archive_read* a,
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,
|
||||
static int parse_file_extra_hash(struct archive_read* a, struct rar5 *rar5,
|
||||
int64_t* extra_data_size)
|
||||
{
|
||||
size_t hash_type = 0;
|
||||
@@ -1286,13 +1270,13 @@ static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,
|
||||
* CRC32. */
|
||||
if(hash_type == BLAKE2sp) {
|
||||
const uint8_t* p;
|
||||
const int hash_size = sizeof(rar->file.blake2sp);
|
||||
const int hash_size = sizeof(rar5->file.blake2sp);
|
||||
|
||||
if(!read_ahead(a, hash_size, &p))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
rar->file.has_blake2 = 1;
|
||||
memcpy(&rar->file.blake2sp, p, hash_size);
|
||||
rar5->file.has_blake2 = 1;
|
||||
memcpy(&rar5->file.blake2sp, p, hash_size);
|
||||
|
||||
if(ARCHIVE_OK != consume(a, hash_size)) {
|
||||
return ARCHIVE_EOF;
|
||||
@@ -1385,7 +1369,7 @@ static int parse_file_extra_version(struct archive_read* a,
|
||||
}
|
||||
|
||||
static int parse_file_extra_htime(struct archive_read* a,
|
||||
struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)
|
||||
struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)
|
||||
{
|
||||
char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;
|
||||
size_t flags = 0;
|
||||
@@ -1412,39 +1396,39 @@ static int parse_file_extra_htime(struct archive_read* a,
|
||||
has_mtime = flags & HAS_MTIME;
|
||||
has_atime = flags & HAS_ATIME;
|
||||
has_ctime = flags & HAS_CTIME;
|
||||
rar->file.e_atime_ns = rar->file.e_ctime_ns = rar->file.e_mtime_ns = 0;
|
||||
rar5->file.e_atime_ns = rar5->file.e_ctime_ns = rar5->file.e_mtime_ns = 0;
|
||||
|
||||
if(has_mtime) {
|
||||
parse_htime_item(a, unix_time, &rar->file.e_mtime,
|
||||
&rar->file.e_mtime_ns, extra_data_size);
|
||||
parse_htime_item(a, unix_time, &rar5->file.e_mtime,
|
||||
&rar5->file.e_mtime_ns, extra_data_size);
|
||||
}
|
||||
|
||||
if(has_ctime) {
|
||||
parse_htime_item(a, unix_time, &rar->file.e_ctime,
|
||||
&rar->file.e_ctime_ns, extra_data_size);
|
||||
parse_htime_item(a, unix_time, &rar5->file.e_ctime,
|
||||
&rar5->file.e_ctime_ns, extra_data_size);
|
||||
}
|
||||
|
||||
if(has_atime) {
|
||||
parse_htime_item(a, unix_time, &rar->file.e_atime,
|
||||
&rar->file.e_atime_ns, extra_data_size);
|
||||
parse_htime_item(a, unix_time, &rar5->file.e_atime,
|
||||
&rar5->file.e_atime_ns, extra_data_size);
|
||||
}
|
||||
|
||||
if(has_mtime && has_unix_ns) {
|
||||
if(!read_u32(a, &rar->file.e_mtime_ns))
|
||||
if(!read_u32(a, &rar5->file.e_mtime_ns))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*extra_data_size -= 4;
|
||||
}
|
||||
|
||||
if(has_ctime && has_unix_ns) {
|
||||
if(!read_u32(a, &rar->file.e_ctime_ns))
|
||||
if(!read_u32(a, &rar5->file.e_ctime_ns))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*extra_data_size -= 4;
|
||||
}
|
||||
|
||||
if(has_atime && has_unix_ns) {
|
||||
if(!read_u32(a, &rar->file.e_atime_ns))
|
||||
if(!read_u32(a, &rar5->file.e_atime_ns))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
*extra_data_size -= 4;
|
||||
@@ -1453,35 +1437,35 @@ static int parse_file_extra_htime(struct archive_read* a,
|
||||
/* The seconds and nanoseconds are either together, or separated in two
|
||||
* fields so we parse them, then set the archive_entry's times. */
|
||||
if(has_mtime) {
|
||||
archive_entry_set_mtime(e, rar->file.e_mtime, rar->file.e_mtime_ns);
|
||||
archive_entry_set_mtime(e, rar5->file.e_mtime, rar5->file.e_mtime_ns);
|
||||
}
|
||||
|
||||
if(has_ctime) {
|
||||
archive_entry_set_ctime(e, rar->file.e_ctime, rar->file.e_ctime_ns);
|
||||
archive_entry_set_ctime(e, rar5->file.e_ctime, rar5->file.e_ctime_ns);
|
||||
}
|
||||
|
||||
if(has_atime) {
|
||||
archive_entry_set_atime(e, rar->file.e_atime, rar->file.e_atime_ns);
|
||||
archive_entry_set_atime(e, rar5->file.e_atime, rar5->file.e_atime_ns);
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int parse_file_extra_redir(struct archive_read* a,
|
||||
struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)
|
||||
struct archive_entry* e, struct rar5 *rar5, int64_t* extra_data_size)
|
||||
{
|
||||
uint64_t value_size = 0;
|
||||
size_t target_size = 0;
|
||||
char target_utf8_buf[MAX_NAME_IN_BYTES];
|
||||
const uint8_t* p;
|
||||
|
||||
if(!read_var(a, &rar->file.redir_type, &value_size))
|
||||
if(!read_var(a, &rar5->file.redir_type, &value_size))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
|
||||
return ARCHIVE_EOF;
|
||||
*extra_data_size -= value_size;
|
||||
|
||||
if(!read_var(a, &rar->file.redir_flags, &value_size))
|
||||
if(!read_var(a, &rar5->file.redir_flags, &value_size))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != consume(a, (int64_t)value_size))
|
||||
return ARCHIVE_EOF;
|
||||
@@ -1512,12 +1496,12 @@ static int parse_file_extra_redir(struct archive_read* a,
|
||||
if(ARCHIVE_OK != consume(a, (int64_t)target_size))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
switch(rar->file.redir_type) {
|
||||
switch(rar5->file.redir_type) {
|
||||
case REDIR_TYPE_UNIXSYMLINK:
|
||||
case REDIR_TYPE_WINSYMLINK:
|
||||
archive_entry_set_filetype(e, AE_IFLNK);
|
||||
archive_entry_update_symlink_utf8(e, target_utf8_buf);
|
||||
if (rar->file.redir_flags & REDIR_SYMLINK_IS_DIR) {
|
||||
if (rar5->file.redir_flags & REDIR_SYMLINK_IS_DIR) {
|
||||
archive_entry_set_symlink_type(e,
|
||||
AE_SYMLINK_TYPE_DIRECTORY);
|
||||
} else {
|
||||
@@ -1619,7 +1603,7 @@ static int parse_file_extra_owner(struct archive_read* a,
|
||||
}
|
||||
|
||||
static int process_head_file_extra(struct archive_read* a,
|
||||
struct archive_entry* e, struct rar5* rar, int64_t extra_data_size)
|
||||
struct archive_entry* e, struct rar5 *rar5, int64_t extra_data_size)
|
||||
{
|
||||
uint64_t extra_field_size;
|
||||
uint64_t extra_field_id = 0;
|
||||
@@ -1649,15 +1633,15 @@ static int process_head_file_extra(struct archive_read* a,
|
||||
|
||||
switch(extra_field_id) {
|
||||
case EX_HASH:
|
||||
ret = parse_file_extra_hash(a, rar,
|
||||
ret = parse_file_extra_hash(a, rar5,
|
||||
&extra_data_size);
|
||||
break;
|
||||
case EX_HTIME:
|
||||
ret = parse_file_extra_htime(a, e, rar,
|
||||
ret = parse_file_extra_htime(a, e, rar5,
|
||||
&extra_data_size);
|
||||
break;
|
||||
case EX_REDIR:
|
||||
ret = parse_file_extra_redir(a, e, rar,
|
||||
ret = parse_file_extra_redir(a, e, rar5,
|
||||
&extra_data_size);
|
||||
break;
|
||||
case EX_UOWNER:
|
||||
@@ -1671,8 +1655,8 @@ static int process_head_file_extra(struct archive_read* a,
|
||||
case EX_CRYPT:
|
||||
/* Mark the entry as encrypted */
|
||||
archive_entry_set_is_data_encrypted(e, 1);
|
||||
rar->has_encrypted_entries = 1;
|
||||
rar->cstate.data_encrypted = 1;
|
||||
rar5->has_encrypted_entries = 1;
|
||||
rar5->cstate.data_encrypted = 1;
|
||||
/* fallthrough */
|
||||
case EX_SUBDATA:
|
||||
/* fallthrough */
|
||||
@@ -1734,7 +1718,7 @@ static int file_entry_sanity_checks(struct archive_read* a,
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
static int process_head_file(struct archive_read* a, struct rar5 *rar5,
|
||||
struct archive_entry* entry, size_t block_flags)
|
||||
{
|
||||
int64_t extra_data_size = 0;
|
||||
@@ -1773,8 +1757,8 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
archive_entry_clear(entry);
|
||||
|
||||
/* Do not reset file context if we're switching archives. */
|
||||
if(!rar->cstate.switch_multivolume) {
|
||||
reset_file_context(rar);
|
||||
if(!rar5->cstate.switch_multivolume) {
|
||||
reset_file_context(rar5);
|
||||
}
|
||||
|
||||
if(block_flags & HFL_EXTRA_DATA) {
|
||||
@@ -1790,9 +1774,16 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
if(!read_var_sized(a, &data_size, NULL))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
rar->file.bytes_remaining = data_size;
|
||||
if(data_size > SSIZE_MAX) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"File data size is too large");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar5->file.bytes_remaining = data_size;
|
||||
} else {
|
||||
rar->file.bytes_remaining = 0;
|
||||
rar5->file.bytes_remaining = 0;
|
||||
}
|
||||
|
||||
if(!read_var_sized(a, &file_flags, NULL))
|
||||
@@ -1807,9 +1798,9 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);
|
||||
rar5->file.dir = (uint8_t) ((file_flags & DIRECTORY) > 0);
|
||||
|
||||
sanity_ret = file_entry_sanity_checks(a, block_flags, rar->file.dir,
|
||||
sanity_ret = file_entry_sanity_checks(a, block_flags, rar5->file.dir,
|
||||
unpacked_size, data_size);
|
||||
|
||||
if (sanity_ret != ARCHIVE_OK) {
|
||||
@@ -1836,90 +1827,90 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
c_version = (int) (compression_info & 0x3f);
|
||||
|
||||
/* RAR5 seems to limit the dictionary size to 64MB. */
|
||||
window_size = (rar->file.dir > 0) ?
|
||||
window_size = (rar5->file.dir > 0) ?
|
||||
0 :
|
||||
g_unpack_window_size << ((compression_info >> 10) & 15);
|
||||
rar->cstate.method = c_method;
|
||||
rar->cstate.version = c_version + 50;
|
||||
rar->file.solid = (compression_info & SOLID) > 0;
|
||||
rar5->cstate.method = c_method;
|
||||
rar5->cstate.version = c_version + 50;
|
||||
rar5->file.solid = (compression_info & SOLID) > 0;
|
||||
|
||||
/* Archives which declare solid files without initializing the window
|
||||
* buffer first are invalid, unless previous data was encrypted, in
|
||||
* which case we may never have had the chance */
|
||||
|
||||
if(rar->file.solid > 0 && rar->cstate.data_encrypted == 0 &&
|
||||
rar->cstate.window_buf == NULL) {
|
||||
if(rar5->file.solid > 0 && rar5->cstate.data_encrypted == 0 &&
|
||||
rar5->cstate.window_buf == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Declared solid file, but no window buffer "
|
||||
"initialized yet.");
|
||||
"initialized yet");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
/* Check if window_size is a sane value. Also, if the file is not
|
||||
* declared as a directory, disallow window_size == 0. */
|
||||
if(window_size > (64 * 1024 * 1024) ||
|
||||
(rar->file.dir == 0 && window_size == 0))
|
||||
(rar5->file.dir == 0 && window_size == 0))
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Declared dictionary size is not supported.");
|
||||
"Declared dictionary size is not supported");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(rar->file.solid > 0) {
|
||||
if(rar5->file.solid > 0) {
|
||||
/* Re-check if current window size is the same as previous
|
||||
* window size (for solid files only). */
|
||||
if(rar->file.solid_window_size > 0 &&
|
||||
rar->file.solid_window_size != (ssize_t) window_size)
|
||||
if(rar5->file.solid_window_size > 0 &&
|
||||
rar5->file.solid_window_size != (ssize_t) window_size)
|
||||
{
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Window size for this solid file doesn't match "
|
||||
"the window size used in previous solid file. ");
|
||||
"the window size used in previous solid file");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
rar->cstate.data_encrypted = 0; /* Reset for new buffer */
|
||||
rar5->cstate.data_encrypted = 0; /* Reset for new buffer */
|
||||
|
||||
if(rar->cstate.window_size < (ssize_t) window_size &&
|
||||
rar->cstate.window_buf)
|
||||
if(rar5->cstate.window_size < (ssize_t) window_size &&
|
||||
rar5->cstate.window_buf)
|
||||
{
|
||||
/* The `data_ready` stack contains pointers to the `window_buf` or
|
||||
* `filtered_buf` buffers. Since we're about to reallocate the first
|
||||
* buffer, some of those pointers could become invalid. Therefore, we
|
||||
* need to dispose of all entries from the stack before attempting the
|
||||
* realloc. */
|
||||
clear_data_ready_stack(rar);
|
||||
clear_data_ready_stack(rar5);
|
||||
|
||||
/* If window_buf has been allocated before, reallocate it, so
|
||||
* that its size will match new window_size. */
|
||||
|
||||
uint8_t* new_window_buf =
|
||||
realloc(rar->cstate.window_buf, (size_t) window_size);
|
||||
realloc(rar5->cstate.window_buf, (size_t) window_size);
|
||||
|
||||
if(!new_window_buf) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Not enough memory when trying to realloc the window "
|
||||
"buffer.");
|
||||
"buffer");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->cstate.window_buf = new_window_buf;
|
||||
rar5->cstate.window_buf = new_window_buf;
|
||||
}
|
||||
|
||||
/* Values up to 64M should fit into ssize_t on every
|
||||
* architecture. */
|
||||
rar->cstate.window_size = (ssize_t) window_size;
|
||||
rar5->cstate.window_size = (ssize_t) window_size;
|
||||
|
||||
if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {
|
||||
if(rar5->file.solid > 0 && rar5->file.solid_window_size == 0) {
|
||||
/* Solid files have to have the same window_size across
|
||||
whole archive. Remember the window_size parameter
|
||||
for first solid file found. */
|
||||
rar->file.solid_window_size = rar->cstate.window_size;
|
||||
rar5->file.solid_window_size = rar5->cstate.window_size;
|
||||
}
|
||||
|
||||
init_window_mask(rar);
|
||||
init_window_mask(rar5);
|
||||
|
||||
rar->file.service = 0;
|
||||
rar5->file.service = 0;
|
||||
|
||||
if(!read_var_sized(a, &host_os, NULL))
|
||||
return ARCHIVE_EOF;
|
||||
@@ -1946,29 +1937,20 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
archive_entry_set_mode(entry, mode);
|
||||
|
||||
if (file_attr & (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM)) {
|
||||
char *fflags_text, *ptr;
|
||||
/* allocate for ",rdonly,hidden,system" */
|
||||
fflags_text = malloc(22 * sizeof(*fflags_text));
|
||||
if (fflags_text != NULL) {
|
||||
ptr = fflags_text;
|
||||
if (file_attr & ATTR_READONLY) {
|
||||
strcpy(ptr, ",rdonly");
|
||||
ptr = ptr + 7;
|
||||
}
|
||||
if (file_attr & ATTR_HIDDEN) {
|
||||
strcpy(ptr, ",hidden");
|
||||
ptr = ptr + 7;
|
||||
}
|
||||
if (file_attr & ATTR_SYSTEM) {
|
||||
strcpy(ptr, ",system");
|
||||
ptr = ptr + 7;
|
||||
}
|
||||
if (ptr > fflags_text) {
|
||||
archive_entry_copy_fflags_text(entry,
|
||||
fflags_text + 1);
|
||||
}
|
||||
free(fflags_text);
|
||||
}
|
||||
char buf[sizeof(",rdonly,hidden,system")];
|
||||
const char *fflags[3] = { "", "", "" };
|
||||
const char **flag = fflags;
|
||||
|
||||
if (file_attr & ATTR_READONLY)
|
||||
*flag++ = ",rdonly";
|
||||
if (file_attr & ATTR_HIDDEN)
|
||||
*flag++ = ",hidden";
|
||||
if (file_attr & ATTR_SYSTEM)
|
||||
*flag++ = ",system";
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s%s",
|
||||
fflags[0], fflags[1], fflags[2]);
|
||||
archive_entry_copy_fflags_text(entry, buf + 1);
|
||||
}
|
||||
} else if(host_os == HOST_UNIX) {
|
||||
/* Host OS is Unix */
|
||||
@@ -2011,7 +1993,7 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
archive_entry_update_pathname_utf8(entry, name_utf8_buf);
|
||||
|
||||
if(extra_data_size > 0) {
|
||||
int ret = process_head_file_extra(a, entry, rar,
|
||||
int ret = process_head_file_extra(a, entry, rar5,
|
||||
extra_data_size);
|
||||
|
||||
/*
|
||||
@@ -2030,8 +2012,8 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
|
||||
if((file_flags & UNKNOWN_UNPACKED_SIZE) == 0) {
|
||||
rar->file.unpacked_size = (ssize_t) unpacked_size;
|
||||
if(rar->file.redir_type == REDIR_TYPE_NONE)
|
||||
rar5->file.unpacked_size = (ssize_t) unpacked_size;
|
||||
if(rar5->file.redir_type == REDIR_TYPE_NONE)
|
||||
archive_entry_set_size(entry, unpacked_size);
|
||||
}
|
||||
|
||||
@@ -2040,18 +2022,18 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
|
||||
if(file_flags & CRC32) {
|
||||
rar->file.stored_crc32 = crc;
|
||||
rar5->file.stored_crc32 = crc;
|
||||
}
|
||||
|
||||
if(!rar->cstate.switch_multivolume) {
|
||||
if(!rar5->cstate.switch_multivolume) {
|
||||
/* Do not reinitialize unpacking state if we're switching
|
||||
* archives. */
|
||||
rar->cstate.block_parsing_finished = 1;
|
||||
rar->cstate.all_filters_applied = 1;
|
||||
rar->cstate.initialized = 0;
|
||||
rar5->cstate.block_parsing_finished = 1;
|
||||
rar5->cstate.all_filters_applied = 1;
|
||||
rar5->cstate.initialized = 0;
|
||||
}
|
||||
|
||||
if(rar->generic.split_before > 0) {
|
||||
if(rar5->generic.split_before > 0) {
|
||||
/* If now we're standing on a header that has a 'split before'
|
||||
* mark, it means we're standing on a 'continuation' file
|
||||
* header. Signal the caller that if it wants to move to
|
||||
@@ -2064,15 +2046,15 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
}
|
||||
|
||||
static int process_head_service(struct archive_read* a, struct rar5* rar,
|
||||
static int process_head_service(struct archive_read* a, struct rar5 *rar5,
|
||||
struct archive_entry* entry, size_t block_flags)
|
||||
{
|
||||
/* Process this SERVICE block the same way as FILE blocks. */
|
||||
int ret = process_head_file(a, rar, entry, block_flags);
|
||||
int ret = process_head_file(a, rar5, entry, block_flags);
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
rar->file.service = 1;
|
||||
rar5->file.service = 1;
|
||||
|
||||
/* But skip the data part automatically. It's no use for the user
|
||||
* anyway. It contains only service data, not even needed to
|
||||
@@ -2085,7 +2067,7 @@ static int process_head_service(struct archive_read* a, struct rar5* rar,
|
||||
return ARCHIVE_RETRY;
|
||||
}
|
||||
|
||||
static int process_head_main(struct archive_read* a, struct rar5* rar,
|
||||
static int process_head_main(struct archive_read* a, struct rar5 *rar5,
|
||||
struct archive_entry* entry, size_t block_flags)
|
||||
{
|
||||
int ret;
|
||||
@@ -2121,8 +2103,8 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
rar->main.volume = (archive_flags & VOLUME) > 0;
|
||||
rar->main.solid = (archive_flags & SOLID) > 0;
|
||||
rar5->main.volume = (archive_flags & VOLUME) > 0;
|
||||
rar5->main.solid = (archive_flags & SOLID) > 0;
|
||||
|
||||
if(archive_flags & VOLUME_NUMBER) {
|
||||
size_t v = 0;
|
||||
@@ -2137,13 +2119,13 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->main.vol_no = (unsigned int) v;
|
||||
rar5->main.vol_no = (unsigned int) v;
|
||||
} else {
|
||||
rar->main.vol_no = 0;
|
||||
rar5->main.vol_no = 0;
|
||||
}
|
||||
|
||||
if(rar->vol.expected_vol_no > 0 &&
|
||||
rar->main.vol_no != rar->vol.expected_vol_no)
|
||||
if(rar5->vol.expected_vol_no > 0 &&
|
||||
rar5->main.vol_no != rar5->vol.expected_vol_no)
|
||||
{
|
||||
/* Returning EOF instead of FATAL because of strange
|
||||
* libarchive behavior. When opening multiple files via
|
||||
@@ -2174,7 +2156,7 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
|
||||
|
||||
switch(extra_field_id) {
|
||||
case LOCATOR:
|
||||
ret = process_main_locator_extra_block(a, rar);
|
||||
ret = process_main_locator_extra_block(a, rar5);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
/* Error while parsing main locator extra
|
||||
* block. */
|
||||
@@ -2194,25 +2176,25 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
|
||||
static int skip_unprocessed_bytes(struct archive_read* a) {
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int ret;
|
||||
|
||||
if(rar->file.bytes_remaining) {
|
||||
if(rar5->file.bytes_remaining) {
|
||||
/* Use different skipping method in block merging mode than in
|
||||
* normal mode. If merge mode is active, rar5_read_data_skip
|
||||
* can't be used, because it could allow recursive use of
|
||||
* merge_block() * function, and this function doesn't support
|
||||
* recursive use. */
|
||||
if(rar->merge_mode) {
|
||||
if(rar5->merge_mode) {
|
||||
/* Discard whole merged block. This is valid in solid
|
||||
* mode as well, because the code will discard blocks
|
||||
* only if those blocks are safe to discard (i.e.
|
||||
* they're not FILE blocks). */
|
||||
ret = consume(a, rar->file.bytes_remaining);
|
||||
ret = consume(a, rar5->file.bytes_remaining);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
return ret;
|
||||
}
|
||||
rar->file.bytes_remaining = 0;
|
||||
rar5->file.bytes_remaining = 0;
|
||||
} else {
|
||||
/* If we're not in merge mode, use safe skipping code.
|
||||
* This will ensure we'll handle solid archives
|
||||
@@ -2274,17 +2256,45 @@ static int scan_for_signature(struct archive_read* a);
|
||||
* <FILE> block.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A header that carries no file data (HEAD_MAIN, or an unknown block
|
||||
* flagged HFL_SKIP_IF_UNKNOWN) may leave bytes in its body that the
|
||||
* sub-parser did not read. Skip them before returning ARCHIVE_RETRY,
|
||||
* otherwise rar5_read_header() re-parses the same block region O(N)
|
||||
* times instead of O(1), letting a crafted RAR5 file stall the reader
|
||||
* (GHSA-9h2c-464f-j3hj).
|
||||
*
|
||||
* Safe because read_ahead(a, hdr_size, &p) pre-loaded the whole block
|
||||
* into one contiguous buffer with no compaction until we return, so
|
||||
* body_start stays valid and (cur - body_start) is the exact number of
|
||||
* body bytes consumed so far.
|
||||
*/
|
||||
static void
|
||||
rar5_skip_remaining_block(struct archive_read* a,
|
||||
const uint8_t* body_start, size_t raw_hdr_size)
|
||||
{
|
||||
const uint8_t* cur;
|
||||
|
||||
if(read_ahead(a, 1, &cur)) {
|
||||
size_t body_used = (size_t)(cur - body_start);
|
||||
|
||||
if(body_used < raw_hdr_size)
|
||||
(void)consume(a, raw_hdr_size - body_used);
|
||||
}
|
||||
}
|
||||
|
||||
static int process_base_block(struct archive_read* a,
|
||||
struct archive_entry* entry)
|
||||
{
|
||||
const size_t SMALLEST_RAR5_BLOCK_SIZE = 3;
|
||||
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
uint32_t hdr_crc, computed_crc;
|
||||
size_t raw_hdr_size = 0, hdr_size_len, hdr_size;
|
||||
size_t header_id = 0;
|
||||
size_t header_flags = 0;
|
||||
const uint8_t* p;
|
||||
const uint8_t* body_start;
|
||||
int ret;
|
||||
|
||||
enum HEADER_TYPE {
|
||||
@@ -2346,6 +2356,10 @@ static int process_base_block(struct archive_read* a,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Remember the first byte of the block body so we can later skip
|
||||
* any bytes the sub-parser leaves unconsumed. */
|
||||
body_start = p + hdr_size_len;
|
||||
|
||||
/* If the checksum is OK, we proceed with parsing. */
|
||||
if(ARCHIVE_OK != consume(a, hdr_size_len)) {
|
||||
return ARCHIVE_EOF;
|
||||
@@ -2357,47 +2371,50 @@ static int process_base_block(struct archive_read* a,
|
||||
if(!read_var_sized(a, &header_flags, NULL))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
rar->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;
|
||||
rar->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;
|
||||
rar->generic.size = (int)hdr_size;
|
||||
rar->generic.last_header_id = (int)header_id;
|
||||
rar->main.endarc = 0;
|
||||
rar5->generic.split_after = (header_flags & HFL_SPLIT_AFTER) > 0;
|
||||
rar5->generic.split_before = (header_flags & HFL_SPLIT_BEFORE) > 0;
|
||||
rar5->generic.size = (int)hdr_size;
|
||||
rar5->generic.last_header_id = (int)header_id;
|
||||
rar5->main.endarc = 0;
|
||||
|
||||
/* Those are possible header ids in RARv5. */
|
||||
switch(header_id) {
|
||||
case HEAD_MAIN:
|
||||
ret = process_head_main(a, rar, entry, header_flags);
|
||||
ret = process_head_main(a, rar5, entry, header_flags);
|
||||
|
||||
/* Main header doesn't have any files in it, so it's
|
||||
* pointless to return to the caller. Retry to next
|
||||
* header, which should be HEAD_FILE/HEAD_SERVICE. */
|
||||
if(ret == ARCHIVE_OK)
|
||||
if(ret == ARCHIVE_OK) {
|
||||
rar5_skip_remaining_block(a, body_start,
|
||||
raw_hdr_size);
|
||||
return ARCHIVE_RETRY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
case HEAD_SERVICE:
|
||||
ret = process_head_service(a, rar, entry, header_flags);
|
||||
ret = process_head_service(a, rar5, entry, header_flags);
|
||||
return ret;
|
||||
case HEAD_FILE:
|
||||
ret = process_head_file(a, rar, entry, header_flags);
|
||||
ret = process_head_file(a, rar5, entry, header_flags);
|
||||
return ret;
|
||||
case HEAD_CRYPT:
|
||||
archive_entry_set_is_metadata_encrypted(entry, 1);
|
||||
archive_entry_set_is_data_encrypted(entry, 1);
|
||||
rar->has_encrypted_entries = 1;
|
||||
rar->headers_are_encrypted = 1;
|
||||
rar5->has_encrypted_entries = 1;
|
||||
rar5->headers_are_encrypted = 1;
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Encryption is not supported");
|
||||
return ARCHIVE_FATAL;
|
||||
case HEAD_ENDARC:
|
||||
rar->main.endarc = 1;
|
||||
rar5->main.endarc = 1;
|
||||
|
||||
/* After encountering an end of file marker, we need
|
||||
* to take into consideration if this archive is
|
||||
* continued in another file (i.e. is it part01.rar:
|
||||
* is there a part02.rar?) */
|
||||
if(rar->main.volume) {
|
||||
if(rar5->main.volume) {
|
||||
/* In case there is part02.rar, position the
|
||||
* read pointer in a proper place, so we can
|
||||
* resume parsing. */
|
||||
@@ -2405,7 +2422,7 @@ static int process_base_block(struct archive_read* a,
|
||||
if(ret == ARCHIVE_FATAL) {
|
||||
return ARCHIVE_EOF;
|
||||
} else {
|
||||
if(rar->vol.expected_vol_no ==
|
||||
if(rar5->vol.expected_vol_no ==
|
||||
UINT_MAX) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
@@ -2413,8 +2430,8 @@ static int process_base_block(struct archive_read* a,
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->vol.expected_vol_no =
|
||||
rar->main.vol_no + 1;
|
||||
rar5->vol.expected_vol_no =
|
||||
rar5->main.vol_no + 1;
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
} else {
|
||||
@@ -2432,6 +2449,8 @@ static int process_base_block(struct archive_read* a,
|
||||
/* If the block is marked as 'skip if unknown',
|
||||
* do as the flag says: skip the block
|
||||
* instead on failing on it. */
|
||||
rar5_skip_remaining_block(a, body_start,
|
||||
raw_hdr_size);
|
||||
return ARCHIVE_RETRY;
|
||||
}
|
||||
}
|
||||
@@ -2445,13 +2464,16 @@ static int process_base_block(struct archive_read* a,
|
||||
}
|
||||
|
||||
static int skip_base_block(struct archive_read* a) {
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int ret;
|
||||
struct rar5* rar = get_context(a);
|
||||
|
||||
/* Create a new local archive_entry structure that will be operated on
|
||||
* by header reader; operations on this archive_entry will be discarded.
|
||||
*/
|
||||
struct archive_entry* entry = archive_entry_new();
|
||||
if (entry == NULL)
|
||||
return ARCHIVE_FATAL;
|
||||
|
||||
ret = process_base_block(a, entry);
|
||||
|
||||
/* Discard operations on this archive_entry structure. */
|
||||
@@ -2459,7 +2481,7 @@ static int skip_base_block(struct archive_read* a) {
|
||||
if(ret == ARCHIVE_FATAL)
|
||||
return ret;
|
||||
|
||||
if(rar->generic.last_header_id == 2 && rar->generic.split_before > 0)
|
||||
if(rar5->generic.last_header_id == 2 && rar5->generic.split_before > 0)
|
||||
return ARCHIVE_OK;
|
||||
|
||||
if(ret == ARCHIVE_OK)
|
||||
@@ -2527,71 +2549,77 @@ fatal:
|
||||
static int rar5_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* It should be sufficient to call archive_read_next_header() for
|
||||
* a reader to determine if an entry is encrypted or not.
|
||||
*/
|
||||
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
rar->has_encrypted_entries = 0;
|
||||
if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
rar5->has_encrypted_entries = 0;
|
||||
}
|
||||
|
||||
if(rar->header_initialized == 0) {
|
||||
if(rar5->header_initialized == 0) {
|
||||
init_header(a);
|
||||
if ((ret = try_skip_sfx(a)) < ARCHIVE_WARN)
|
||||
return ret;
|
||||
rar->header_initialized = 1;
|
||||
rar5->header_initialized = 1;
|
||||
}
|
||||
|
||||
if(rar->skipped_magic == 0) {
|
||||
if(rar5->skipped_magic == 0) {
|
||||
if(ARCHIVE_OK != consume(a, sizeof(rar5_signature_xor))) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
rar->skipped_magic = 1;
|
||||
rar5->skipped_magic = 1;
|
||||
}
|
||||
|
||||
do {
|
||||
ret = process_base_block(a, entry);
|
||||
} while(ret == ARCHIVE_RETRY ||
|
||||
(rar->main.endarc > 0 && ret == ARCHIVE_OK));
|
||||
(rar5->main.endarc > 0 && ret == ARCHIVE_OK));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void init_unpack(struct rar5* rar) {
|
||||
rar->file.calculated_crc32 = 0;
|
||||
init_window_mask(rar);
|
||||
static int init_unpack(struct rar5 *rar5) {
|
||||
rar5->file.calculated_crc32 = 0;
|
||||
init_window_mask(rar5);
|
||||
|
||||
free(rar->cstate.window_buf);
|
||||
free(rar->cstate.filtered_buf);
|
||||
free(rar5->cstate.window_buf);
|
||||
free(rar5->cstate.filtered_buf);
|
||||
|
||||
if(rar->cstate.window_size > 0) {
|
||||
rar->cstate.window_buf = calloc(1, rar->cstate.window_size);
|
||||
rar->cstate.filtered_buf = calloc(1, rar->cstate.window_size);
|
||||
} else {
|
||||
rar->cstate.window_buf = NULL;
|
||||
rar->cstate.filtered_buf = NULL;
|
||||
rar5->cstate.window_buf = NULL;
|
||||
rar5->cstate.filtered_buf = NULL;
|
||||
|
||||
if(rar5->cstate.window_size > 0) {
|
||||
rar5->cstate.window_buf = calloc(1, rar5->cstate.window_size);
|
||||
if(rar5->cstate.window_buf == NULL)
|
||||
return ARCHIVE_FATAL;
|
||||
rar5->cstate.filtered_buf = calloc(1,
|
||||
rar5->cstate.window_size);
|
||||
if(rar5->cstate.filtered_buf == NULL)
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
clear_data_ready_stack(rar);
|
||||
clear_data_ready_stack(rar5);
|
||||
|
||||
rar->cstate.write_ptr = 0;
|
||||
rar->cstate.last_write_ptr = 0;
|
||||
rar5->cstate.write_ptr = 0;
|
||||
rar5->cstate.last_write_ptr = 0;
|
||||
|
||||
memset(&rar->cstate.bd, 0, sizeof(rar->cstate.bd));
|
||||
memset(&rar->cstate.ld, 0, sizeof(rar->cstate.ld));
|
||||
memset(&rar->cstate.dd, 0, sizeof(rar->cstate.dd));
|
||||
memset(&rar->cstate.ldd, 0, sizeof(rar->cstate.ldd));
|
||||
memset(&rar->cstate.rd, 0, sizeof(rar->cstate.rd));
|
||||
memset(&rar5->cstate.bd, 0, sizeof(rar5->cstate.bd));
|
||||
memset(&rar5->cstate.ld, 0, sizeof(rar5->cstate.ld));
|
||||
memset(&rar5->cstate.dd, 0, sizeof(rar5->cstate.dd));
|
||||
memset(&rar5->cstate.ldd, 0, sizeof(rar5->cstate.ldd));
|
||||
memset(&rar5->cstate.rd, 0, sizeof(rar5->cstate.rd));
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {
|
||||
static void update_crc(struct rar5 *rar5, const uint8_t* p, size_t to_read) {
|
||||
int verify_crc;
|
||||
|
||||
if(rar->skip_mode) {
|
||||
if(rar5->skip_mode) {
|
||||
#if defined CHECK_CRC_ON_SOLID_SKIP
|
||||
verify_crc = 1;
|
||||
#else
|
||||
@@ -2603,17 +2631,19 @@ static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {
|
||||
if(verify_crc) {
|
||||
/* Don't update CRC32 if the file doesn't have the
|
||||
* `stored_crc32` info filled in. */
|
||||
if(rar->file.stored_crc32 > 0) {
|
||||
rar->file.calculated_crc32 =
|
||||
crc32(rar->file.calculated_crc32, p, (unsigned int)to_read);
|
||||
if(rar5->file.stored_crc32 > 0) {
|
||||
rar5->file.calculated_crc32 =
|
||||
crc32(rar5->file.calculated_crc32, p,
|
||||
(unsigned int)to_read);
|
||||
}
|
||||
|
||||
/* Check if the file uses an optional BLAKE2sp checksum
|
||||
* algorithm. */
|
||||
if(rar->file.has_blake2 > 0) {
|
||||
if(rar5->file.has_blake2 > 0) {
|
||||
/* Return value of the `update` function is always 0,
|
||||
* so we can explicitly ignore it here. */
|
||||
(void) blake2sp_update(&rar->file.b2state, p, to_read);
|
||||
(void) blake2sp_update(&rar5->file.b2state, p,
|
||||
to_read);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2647,6 +2677,15 @@ static int create_decode_tables(uint8_t* bit_length,
|
||||
upper_limit <<= 1;
|
||||
}
|
||||
|
||||
/* Verify the code-length distribution is not over-subscribed.
|
||||
* After the loop above, upper_limit == sum(lc[i] * 2^(16-i)).
|
||||
* For a valid prefix-free code this must be <= 2^16 = 65536.
|
||||
* An over-subscribed table (> 65536) cannot produce a valid
|
||||
* decode table and must be rejected. */
|
||||
if(upper_limit > 65536) {
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
memcpy(decode_pos_clone, table->decode_pos, sizeof(decode_pos_clone));
|
||||
|
||||
for(i = 0; i < size; i++) {
|
||||
@@ -2688,12 +2727,12 @@ static int create_decode_tables(uint8_t* bit_length,
|
||||
static int decode_number(struct archive_read* a, struct decode_table* table,
|
||||
const uint8_t* p, uint16_t* num)
|
||||
{
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int i, bits, dist, ret;
|
||||
uint16_t bitfield;
|
||||
uint32_t pos;
|
||||
struct rar5* rar = get_context(a);
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &bitfield))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2701,7 +2740,7 @@ static int decode_number(struct archive_read* a, struct decode_table* table,
|
||||
|
||||
if(bitfield < table->decode_len[table->quick_bits]) {
|
||||
int code = bitfield >> (16 - table->quick_bits);
|
||||
skip_bits(rar, table->quick_len[code]);
|
||||
skip_bits(rar5, table->quick_len[code]);
|
||||
*num = table->quick_num[code];
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
@@ -2715,7 +2754,7 @@ static int decode_number(struct archive_read* a, struct decode_table* table,
|
||||
}
|
||||
}
|
||||
|
||||
skip_bits(rar, bits);
|
||||
skip_bits(rar5, bits);
|
||||
|
||||
dist = bitfield - table->decode_len[bits - 1];
|
||||
dist >>= (16 - bits);
|
||||
@@ -2729,7 +2768,7 @@ static int decode_number(struct archive_read* a, struct decode_table* table,
|
||||
}
|
||||
|
||||
/* Reads and parses Huffman tables from the beginning of the block. */
|
||||
static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
static int parse_tables(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* p)
|
||||
{
|
||||
int ret, value, i, w, idx = 0;
|
||||
@@ -2743,12 +2782,12 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
/* The data for table generation is compressed using a simple RLE-like
|
||||
* algorithm when storing zeroes, so we need to unpack it first. */
|
||||
for(w = 0, i = 0; w < HUFF_BC;) {
|
||||
if(i >= rar->cstate.cur_block_size) {
|
||||
if(i >= rar5->cstate.cur_block_size) {
|
||||
/* Truncated data, can't continue. */
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated data in huffman tables");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
value = (p[i] & nibble_mask) >> nibble_shift;
|
||||
@@ -2787,25 +2826,25 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
}
|
||||
|
||||
rar->bits.in_addr = i;
|
||||
rar->bits.bit_addr = nibble_shift ^ 4;
|
||||
rar5->bits.in_addr = i;
|
||||
rar5->bits.bit_addr = nibble_shift ^ 4;
|
||||
|
||||
ret = create_decode_tables(bit_length, &rar->cstate.bd, HUFF_BC);
|
||||
ret = create_decode_tables(bit_length, &rar5->cstate.bd, HUFF_BC);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Decoding huffman tables failed");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
for(i = 0; i < HUFF_TABLE_SIZE;) {
|
||||
uint16_t num;
|
||||
|
||||
ret = decode_number(a, &rar->cstate.bd, p, &num);
|
||||
ret = decode_number(a, &rar5->cstate.bd, p, &num);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Decoding huffman tables failed");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(num < 16) {
|
||||
@@ -2816,17 +2855,17 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
/* 16..17: repeat previous code */
|
||||
uint16_t n;
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))
|
||||
return ret;
|
||||
|
||||
if(num == 16) {
|
||||
n >>= 13;
|
||||
n += 3;
|
||||
skip_bits(rar, 3);
|
||||
skip_bits(rar5, 3);
|
||||
} else {
|
||||
n >>= 9;
|
||||
n += 11;
|
||||
skip_bits(rar, 7);
|
||||
skip_bits(rar5, 7);
|
||||
}
|
||||
|
||||
if(i > 0) {
|
||||
@@ -2839,23 +2878,23 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unexpected error when decoding "
|
||||
"huffman tables");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
} else {
|
||||
/* other codes: fill with zeroes `n` times */
|
||||
uint16_t n;
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &n)))
|
||||
return ret;
|
||||
|
||||
if(num == 18) {
|
||||
n >>= 13;
|
||||
n += 3;
|
||||
skip_bits(rar, 3);
|
||||
skip_bits(rar5, 3);
|
||||
} else {
|
||||
n >>= 9;
|
||||
n += 11;
|
||||
skip_bits(rar, 7);
|
||||
skip_bits(rar5, 7);
|
||||
}
|
||||
|
||||
while(n-- > 0 && i < HUFF_TABLE_SIZE)
|
||||
@@ -2863,38 +2902,38 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
}
|
||||
|
||||
ret = create_decode_tables(&table[idx], &rar->cstate.ld, HUFF_NC);
|
||||
ret = create_decode_tables(&table[idx], &rar5->cstate.ld, HUFF_NC);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create literal table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
idx += HUFF_NC;
|
||||
|
||||
ret = create_decode_tables(&table[idx], &rar->cstate.dd, HUFF_DC);
|
||||
ret = create_decode_tables(&table[idx], &rar5->cstate.dd, HUFF_DC);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create distance table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
idx += HUFF_DC;
|
||||
|
||||
ret = create_decode_tables(&table[idx], &rar->cstate.ldd, HUFF_LDC);
|
||||
ret = create_decode_tables(&table[idx], &rar5->cstate.ldd, HUFF_LDC);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create lower bits of distances table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
idx += HUFF_LDC;
|
||||
|
||||
ret = create_decode_tables(&table[idx], &rar->cstate.rd, HUFF_RC);
|
||||
ret = create_decode_tables(&table[idx], &rar5->cstate.rd, HUFF_RC);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Failed to create repeating distances table");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
@@ -2912,7 +2951,7 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unsupported block header size (was %d, max is 2)",
|
||||
bf_byte_count(hdr));
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
/* This should probably use bit reader interface in order to be more
|
||||
@@ -2956,7 +2995,7 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
|
||||
"Block checksum error: got 0x%x, expected 0x%x",
|
||||
hdr->block_cksum, calculated_cksum);
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2964,13 +3003,13 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
|
||||
}
|
||||
|
||||
/* Convenience function used during filter processing. */
|
||||
static int parse_filter_data(struct archive_read* a, struct rar5* rar,
|
||||
static int parse_filter_data(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* p, uint32_t* filter_data)
|
||||
{
|
||||
int i, bytes, ret;
|
||||
uint32_t data = 0;
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5, p, 2, &bytes)))
|
||||
return ret;
|
||||
|
||||
bytes++;
|
||||
@@ -2978,14 +3017,14 @@ static int parse_filter_data(struct archive_read* a, struct rar5* rar,
|
||||
for(i = 0; i < bytes; i++) {
|
||||
uint16_t byte;
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar5, p, &byte))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Cast to uint32_t will ensure the shift operation will not
|
||||
* produce undefined result. */
|
||||
data += ((uint32_t) byte >> 8) << (i * 8);
|
||||
skip_bits(rar, 8);
|
||||
skip_bits(rar5, 8);
|
||||
}
|
||||
|
||||
*filter_data = data;
|
||||
@@ -2993,12 +3032,12 @@ static int parse_filter_data(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
|
||||
/* Function is used during sanity checking. */
|
||||
static int is_valid_filter_block_start(struct rar5* rar,
|
||||
static int is_valid_filter_block_start(struct rar5 *rar5,
|
||||
uint32_t start)
|
||||
{
|
||||
const int64_t block_start = (ssize_t) start + rar->cstate.write_ptr;
|
||||
const int64_t last_bs = rar->cstate.last_block_start;
|
||||
const ssize_t last_bl = rar->cstate.last_block_length;
|
||||
const int64_t block_start = (ssize_t) start + rar5->cstate.write_ptr;
|
||||
const int64_t last_bs = rar5->cstate.last_block_start;
|
||||
const ssize_t last_bl = rar5->cstate.last_block_length;
|
||||
|
||||
if(last_bs == 0 || last_bl == 0) {
|
||||
/* We didn't have any filters yet, so accept this offset. */
|
||||
@@ -3018,55 +3057,52 @@ static int is_valid_filter_block_start(struct rar5* rar,
|
||||
/* The function will create a new filter, read its parameters from the input
|
||||
* stream and add it to the filter collection. */
|
||||
static int parse_filter(struct archive_read* ar, const uint8_t* p) {
|
||||
struct rar5 *rar5 = ar->format->data;
|
||||
uint32_t block_start, block_length;
|
||||
uint16_t filter_type;
|
||||
struct filter_info* filt = NULL;
|
||||
struct rar5* rar = get_context(ar);
|
||||
int ret;
|
||||
|
||||
/* Read the parameters from the input stream. */
|
||||
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))
|
||||
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_start)))
|
||||
return ret;
|
||||
|
||||
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))
|
||||
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar5, p, &block_length)))
|
||||
return ret;
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(ar, rar5, p, &filter_type)))
|
||||
return ret;
|
||||
|
||||
filter_type >>= 13;
|
||||
skip_bits(rar, 3);
|
||||
skip_bits(rar5, 3);
|
||||
|
||||
/* Perform some sanity checks on this filter parameters. Note that we
|
||||
* allow only DELTA, E8/E9 and ARM filters here, because rest of
|
||||
* filters are not used in RARv5. */
|
||||
/* Perform some sanity checks on this filter parameters. */
|
||||
|
||||
if(block_length < 4 ||
|
||||
block_length > 0x400000 ||
|
||||
filter_type > FILTER_ARM ||
|
||||
!is_valid_filter_block_start(rar, block_start) ||
|
||||
(rar->cstate.window_size > 0 &&
|
||||
(ssize_t)block_length > rar->cstate.window_size >> 1))
|
||||
!is_valid_filter_block_start(rar5, block_start) ||
|
||||
(rar5->cstate.window_size > 0 &&
|
||||
(ssize_t)block_length > rar5->cstate.window_size >> 1))
|
||||
{
|
||||
archive_set_error(&ar->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid filter encountered");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
/* Allocate a new filter. */
|
||||
filt = add_new_filter(rar);
|
||||
filt = add_new_filter(rar5);
|
||||
if(filt == NULL) {
|
||||
archive_set_error(&ar->archive, ENOMEM,
|
||||
"Can't allocate memory for a filter descriptor.");
|
||||
"Can't allocate memory for a filter descriptor");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
filt->type = filter_type;
|
||||
filt->block_start = rar->cstate.write_ptr + block_start;
|
||||
filt->block_start = rar5->cstate.write_ptr + block_start;
|
||||
filt->block_length = block_length;
|
||||
|
||||
rar->cstate.last_block_start = filt->block_start;
|
||||
rar->cstate.last_block_length = filt->block_length;
|
||||
rar5->cstate.last_block_start = filt->block_start;
|
||||
rar5->cstate.last_block_length = filt->block_length;
|
||||
|
||||
/* Read some more data in case this is a DELTA filter. Other filter
|
||||
* types don't require any additional data over what was already
|
||||
@@ -3074,7 +3110,7 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
|
||||
if(filter_type == FILTER_DELTA) {
|
||||
int channels;
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels))) {
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar5, p, 5, &channels))) {
|
||||
#ifdef __clang_analyzer__
|
||||
/* Tell clang-analyzer that 'filt' does not leak.
|
||||
add_new_filter passes off ownership. */
|
||||
@@ -3094,7 +3130,7 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int decode_code_length(struct archive_read* a, struct rar5* rar,
|
||||
static int decode_code_length(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* p, uint16_t code)
|
||||
{
|
||||
int lbits, length = 2;
|
||||
@@ -3110,7 +3146,7 @@ static int decode_code_length(struct archive_read* a, struct rar5* rar,
|
||||
if(lbits > 0) {
|
||||
int add;
|
||||
|
||||
if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))
|
||||
if(ARCHIVE_OK != read_consume_bits(a, rar5, p, lbits, &add))
|
||||
return -1;
|
||||
|
||||
length += add;
|
||||
@@ -3120,15 +3156,22 @@ static int decode_code_length(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
|
||||
static int copy_string(struct archive_read* a, int len, int dist) {
|
||||
struct rar5* rar = get_context(a);
|
||||
const ssize_t cmask = rar->cstate.window_mask;
|
||||
const uint64_t write_ptr = rar->cstate.write_ptr +
|
||||
rar->cstate.solid_offset;
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
const ssize_t cmask = rar5->cstate.window_mask;
|
||||
const uint64_t write_ptr = rar5->cstate.write_ptr +
|
||||
rar5->cstate.solid_offset;
|
||||
int i;
|
||||
|
||||
if (rar->cstate.window_buf == NULL)
|
||||
if (rar5->cstate.window_buf == NULL)
|
||||
return ARCHIVE_FATAL;
|
||||
|
||||
if (rar5->cstate.write_ptr > rar5->file.unpacked_size ||
|
||||
len > rar5->file.unpacked_size - rar5->cstate.write_ptr) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Uncompressed data exceeds declared size");
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
/* The unpacker spends most of the time in this function. It would be
|
||||
* a good idea to introduce some optimizations here.
|
||||
*
|
||||
@@ -3139,26 +3182,26 @@ static int copy_string(struct archive_read* a, int len, int dist) {
|
||||
for(i = 0; i < len; i++) {
|
||||
const ssize_t write_idx = (write_ptr + i) & cmask;
|
||||
const ssize_t read_idx = (write_ptr + i - dist) & cmask;
|
||||
rar->cstate.window_buf[write_idx] =
|
||||
rar->cstate.window_buf[read_idx];
|
||||
rar5->cstate.window_buf[write_idx] =
|
||||
rar5->cstate.window_buf[read_idx];
|
||||
}
|
||||
|
||||
rar->cstate.write_ptr += len;
|
||||
rar5->cstate.write_ptr += len;
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
uint16_t num;
|
||||
int ret;
|
||||
|
||||
const uint64_t cmask = rar->cstate.window_mask;
|
||||
const struct compressed_block_header* hdr = &rar->last_block_hdr;
|
||||
const uint64_t cmask = rar5->cstate.window_mask;
|
||||
const struct compressed_block_header* hdr = &rar5->last_block_hdr;
|
||||
const uint8_t bit_size = 1 + bf_bit_size(hdr);
|
||||
|
||||
while(1) {
|
||||
if(rar->cstate.write_ptr - rar->cstate.last_write_ptr >
|
||||
(rar->cstate.window_size >> 1)) {
|
||||
if(rar5->cstate.write_ptr - rar5->cstate.last_write_ptr >
|
||||
(rar5->cstate.window_size >> 1)) {
|
||||
/* Don't allow growing data by more than half of the
|
||||
* window size at a time. In such case, break the loop;
|
||||
* next call to this function will continue processing
|
||||
@@ -3166,18 +3209,18 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(rar->bits.in_addr > rar->cstate.cur_block_size - 1 ||
|
||||
(rar->bits.in_addr == rar->cstate.cur_block_size - 1 &&
|
||||
rar->bits.bit_addr >= bit_size))
|
||||
if(rar5->bits.in_addr > rar5->cstate.cur_block_size - 1 ||
|
||||
(rar5->bits.in_addr == rar5->cstate.cur_block_size - 1 &&
|
||||
rar5->bits.bit_addr >= bit_size))
|
||||
{
|
||||
/* If the program counter is here, it means the
|
||||
* function has finished processing the block. */
|
||||
rar->cstate.block_parsing_finished = 1;
|
||||
rar5->cstate.block_parsing_finished = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Decode the next literal. */
|
||||
if(ARCHIVE_OK != decode_number(a, &rar->cstate.ld, p, &num)) {
|
||||
if(ARCHIVE_OK != decode_number(a, &rar5->cstate.ld, p, &num)) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
@@ -3197,15 +3240,25 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
|
||||
if(num < 256) {
|
||||
/* Directly store the byte. */
|
||||
int64_t write_idx = rar->cstate.solid_offset +
|
||||
rar->cstate.write_ptr++;
|
||||
int64_t write_idx;
|
||||
|
||||
rar->cstate.window_buf[write_idx & cmask] =
|
||||
/* A literal write emits one byte; copy_string() checks len. */
|
||||
if(rar5->cstate.write_ptr >= rar5->file.unpacked_size) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Uncompressed data exceeds declared size");
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
write_idx = rar5->cstate.solid_offset +
|
||||
rar5->cstate.write_ptr++;
|
||||
|
||||
rar5->cstate.window_buf[write_idx & cmask] =
|
||||
(uint8_t) num;
|
||||
continue;
|
||||
} else if(num >= 262) {
|
||||
uint16_t dist_slot;
|
||||
int len = decode_code_length(a, rar, p, num - 262),
|
||||
int len = decode_code_length(a, rar5, p, num - 262),
|
||||
dbits,
|
||||
dist = 1;
|
||||
|
||||
@@ -3214,17 +3267,17 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Failed to decode the code length");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(ARCHIVE_OK != decode_number(a, &rar->cstate.dd, p,
|
||||
if(ARCHIVE_OK != decode_number(a, &rar5->cstate.dd, p,
|
||||
&dist_slot))
|
||||
{
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Failed to decode the distance slot");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(dist_slot < 4) {
|
||||
@@ -3248,28 +3301,28 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
|
||||
if(dbits > 4) {
|
||||
if(ARCHIVE_OK != (ret = read_bits_32(
|
||||
a, rar, p, &add))) {
|
||||
a, rar5, p, &add))) {
|
||||
/* Return EOF if we
|
||||
* can't read more
|
||||
* data. */
|
||||
return ret;
|
||||
}
|
||||
|
||||
skip_bits(rar, dbits - 4);
|
||||
skip_bits(rar5, dbits - 4);
|
||||
add = (add >> (
|
||||
36 - dbits)) << 4;
|
||||
dist += add;
|
||||
}
|
||||
|
||||
if(ARCHIVE_OK != decode_number(a,
|
||||
&rar->cstate.ldd, p, &low_dist))
|
||||
&rar5->cstate.ldd, p, &low_dist))
|
||||
{
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Failed to decode the "
|
||||
"distance slot");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(dist >= INT_MAX - low_dist - 1) {
|
||||
@@ -3279,7 +3332,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Distance pointer "
|
||||
"overflow");
|
||||
return ARCHIVE_FATAL;
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
dist += low_dist;
|
||||
@@ -3287,7 +3340,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
/* dbits is one of [0,1,2,3] */
|
||||
int add;
|
||||
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar5,
|
||||
p, dbits, &add))) {
|
||||
/* Return EOF if we can't read
|
||||
* more data. */
|
||||
@@ -3310,11 +3363,12 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
}
|
||||
}
|
||||
|
||||
dist_cache_push(rar, dist);
|
||||
rar->cstate.last_len = len;
|
||||
dist_cache_push(rar5, dist);
|
||||
rar5->cstate.last_len = len;
|
||||
|
||||
if(ARCHIVE_OK != copy_string(a, len, dist))
|
||||
return ARCHIVE_FATAL;
|
||||
ret = copy_string(a, len, dist);
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
continue;
|
||||
} else if(num == 256) {
|
||||
@@ -3325,38 +3379,38 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
|
||||
continue;
|
||||
} else if(num == 257) {
|
||||
if(rar->cstate.last_len != 0) {
|
||||
if(ARCHIVE_OK != copy_string(a,
|
||||
rar->cstate.last_len,
|
||||
rar->cstate.dist_cache[0]))
|
||||
{
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
if(rar5->cstate.last_len != 0) {
|
||||
ret = copy_string(a,
|
||||
rar5->cstate.last_len,
|
||||
rar5->cstate.dist_cache[0]);
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
/* num < 262 */
|
||||
const int idx = num - 258;
|
||||
const int dist = dist_cache_touch(rar, idx);
|
||||
const int dist = dist_cache_touch(rar5, idx);
|
||||
|
||||
uint16_t len_slot;
|
||||
int len;
|
||||
|
||||
if(ARCHIVE_OK != decode_number(a, &rar->cstate.rd, p,
|
||||
if(ARCHIVE_OK != decode_number(a, &rar5->cstate.rd, p,
|
||||
&len_slot)) {
|
||||
return ARCHIVE_FATAL;
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
len = decode_code_length(a, rar, p, len_slot);
|
||||
len = decode_code_length(a, rar5, p, len_slot);
|
||||
if (len == -1) {
|
||||
return ARCHIVE_FATAL;
|
||||
return rar5->main.solid ? ARCHIVE_FATAL : ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
rar->cstate.last_len = len;
|
||||
rar5->cstate.last_len = len;
|
||||
|
||||
if(ARCHIVE_OK != copy_string(a, len, dist))
|
||||
return ARCHIVE_FATAL;
|
||||
ret = copy_string(a, len, dist);
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -3414,15 +3468,15 @@ static int scan_for_signature(struct archive_read* a) {
|
||||
/* This function will switch the multivolume archive file to another file,
|
||||
* i.e. from part03 to part 04. */
|
||||
static int advance_multivolume(struct archive_read* a) {
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int lret;
|
||||
struct rar5* rar = get_context(a);
|
||||
|
||||
/* A small state machine that will skip unnecessary data, needed to
|
||||
* switch from one multivolume to another. Such skipping is needed if
|
||||
* we want to be an stream-oriented (instead of file-oriented)
|
||||
* unpacker.
|
||||
*
|
||||
* The state machine starts with `rar->main.endarc` == 0. It also
|
||||
* The state machine starts with `rar5->main.endarc` == 0. It also
|
||||
* assumes that current stream pointer points to some base block
|
||||
* header.
|
||||
*
|
||||
@@ -3431,10 +3485,10 @@ static int advance_multivolume(struct archive_read* a) {
|
||||
*/
|
||||
|
||||
while(1) {
|
||||
if(rar->main.endarc == 1) {
|
||||
if(rar5->main.endarc == 1) {
|
||||
int looping = 1;
|
||||
|
||||
rar->main.endarc = 0;
|
||||
rar5->main.endarc = 0;
|
||||
|
||||
while(looping) {
|
||||
lret = skip_base_block(a);
|
||||
@@ -3472,7 +3526,7 @@ static int advance_multivolume(struct archive_read* a) {
|
||||
/* If there was an error during skipping, or we
|
||||
* have just skipped a FILE base block... */
|
||||
|
||||
if(rar->main.endarc == 0) {
|
||||
if(rar5->main.endarc == 0) {
|
||||
return lret;
|
||||
} else {
|
||||
continue;
|
||||
@@ -3491,12 +3545,12 @@ static int advance_multivolume(struct archive_read* a) {
|
||||
static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
const uint8_t** p)
|
||||
{
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
ssize_t cur_block_size, partial_offset = 0;
|
||||
const uint8_t* lp;
|
||||
int ret;
|
||||
|
||||
if(rar->merge_mode) {
|
||||
if(rar5->merge_mode) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Recursive merge is not allowed");
|
||||
|
||||
@@ -3504,26 +3558,27 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
}
|
||||
|
||||
/* Set a flag that we're in the switching mode. */
|
||||
rar->cstate.switch_multivolume = 1;
|
||||
rar5->cstate.switch_multivolume = 1;
|
||||
|
||||
/* Reallocate the memory which will hold the whole block. */
|
||||
if(rar->vol.push_buf)
|
||||
free((void*) rar->vol.push_buf);
|
||||
if(rar5->vol.push_buf)
|
||||
free((void*) rar5->vol.push_buf);
|
||||
|
||||
/* Increasing the allocation block by 8 is due to bit reading functions,
|
||||
* which are using additional 2 or 4 bytes. Allocating the block size
|
||||
* by exact value would make bit reader perform reads from invalid
|
||||
* memory block when reading the last byte from the buffer. */
|
||||
rar->vol.push_buf = malloc(block_size + 8);
|
||||
if(!rar->vol.push_buf) {
|
||||
rar5->vol.push_buf = malloc(block_size + 8);
|
||||
if(!rar5->vol.push_buf) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for a merge block buffer.");
|
||||
"Can't allocate memory for a merge block buffer");
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
/* Valgrind complains if the extension block for bit reader is not
|
||||
* initialized, so initialize it. */
|
||||
memset(&rar->vol.push_buf[block_size], 0, 8);
|
||||
memset(&rar5->vol.push_buf[block_size], 0, 8);
|
||||
|
||||
/* A single block can span across multiple multivolume archive files,
|
||||
* so we use a loop here. This loop will consume enough multivolume
|
||||
@@ -3532,41 +3587,52 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
while(1) {
|
||||
/* Get the size of current block chunk in this multivolume
|
||||
* archive file and read it. */
|
||||
cur_block_size = rar5_min(rar->file.bytes_remaining,
|
||||
cur_block_size = rar5_min(rar5->file.bytes_remaining,
|
||||
block_size - partial_offset);
|
||||
|
||||
if(cur_block_size == 0) {
|
||||
if(cur_block_size < 1) {
|
||||
/* bytes_remaining is less than 1 at the wrong point in
|
||||
* the merge loop, indicating corrupt volume
|
||||
* accounting. */
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Encountered block size == 0 during block merge");
|
||||
"Encountered invalid block size during block merge");
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(!read_ahead(a, cur_block_size, &lp))
|
||||
if(!read_ahead(a, cur_block_size, &lp)) {
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
/* Sanity check; there should never be a situation where this
|
||||
* function reads more data than the block's size. */
|
||||
if(partial_offset + cur_block_size > block_size) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Consumed too much data when merging blocks.");
|
||||
"Consumed too much data when merging blocks");
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
/* Merge previous block chunk with current block chunk,
|
||||
* or create first block chunk if this is our first
|
||||
* iteration. */
|
||||
memcpy(&rar->vol.push_buf[partial_offset], lp, cur_block_size);
|
||||
memcpy(&rar5->vol.push_buf[partial_offset], lp, cur_block_size);
|
||||
|
||||
/* Advance the stream read pointer by this block chunk size. */
|
||||
if(ARCHIVE_OK != consume(a, cur_block_size))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != consume(a, cur_block_size)) {
|
||||
/* Data was copied but stream pointer didn't advance;
|
||||
* stream position is unrecoverable. */
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
/* Update the pointers. `partial_offset` contains information
|
||||
* about the sum of merged block chunks. */
|
||||
partial_offset += cur_block_size;
|
||||
rar->file.bytes_remaining -= cur_block_size;
|
||||
rar5->file.bytes_remaining -= cur_block_size;
|
||||
|
||||
/* If `partial_offset` is the same as `block_size`, this means
|
||||
* we've merged all block chunks and we have a valid full
|
||||
@@ -3577,17 +3643,18 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
|
||||
/* If we don't have any bytes to read, this means we should
|
||||
* switch to another multivolume archive file. */
|
||||
if(rar->file.bytes_remaining == 0) {
|
||||
rar->merge_mode++;
|
||||
if(rar5->file.bytes_remaining == 0) {
|
||||
rar5->merge_mode++;
|
||||
ret = advance_multivolume(a);
|
||||
rar->merge_mode--;
|
||||
rar5->merge_mode--;
|
||||
if(ret != ARCHIVE_OK) {
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*p = rar->vol.push_buf;
|
||||
*p = rar5->vol.push_buf;
|
||||
|
||||
/* If we're here, we can resume unpacking by processing the block
|
||||
* pointed to by the `*p` memory pointer. */
|
||||
@@ -3596,19 +3663,19 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
}
|
||||
|
||||
static int process_block(struct archive_read* a) {
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
const uint8_t* p;
|
||||
struct rar5* rar = get_context(a);
|
||||
int ret;
|
||||
|
||||
/* If we don't have any data to be processed, this most probably means
|
||||
* we need to switch to the next volume. */
|
||||
if(rar->main.volume && rar->file.bytes_remaining == 0) {
|
||||
if(rar5->main.volume && rar5->file.bytes_remaining == 0) {
|
||||
ret = advance_multivolume(a);
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(rar->cstate.block_parsing_finished) {
|
||||
if(rar5->cstate.block_parsing_finished) {
|
||||
ssize_t block_size;
|
||||
ssize_t to_skip;
|
||||
ssize_t cur_block_size;
|
||||
@@ -3628,7 +3695,7 @@ static int process_block(struct archive_read* a) {
|
||||
* `parse_block_header` as the second argument. */
|
||||
|
||||
ret = parse_block_header(a, p, &block_size,
|
||||
&rar->last_block_hdr);
|
||||
&rar5->last_block_hdr);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
return ret;
|
||||
}
|
||||
@@ -3636,12 +3703,21 @@ static int process_block(struct archive_read* a) {
|
||||
/* Skip block header. Next data is huffman tables,
|
||||
* if present. */
|
||||
to_skip = sizeof(struct compressed_block_header) +
|
||||
bf_byte_count(&rar->last_block_hdr) + 1;
|
||||
bf_byte_count(&rar5->last_block_hdr) + 1;
|
||||
|
||||
/* If the block header's to_skip value exceeds the declared
|
||||
* remaining data, the archive is malformed. */
|
||||
if(to_skip > rar5->file.bytes_remaining) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Block header size exceeds remaining file data");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(ARCHIVE_OK != consume(a, to_skip))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
rar->file.bytes_remaining -= to_skip;
|
||||
rar5->file.bytes_remaining -= to_skip;
|
||||
|
||||
/* The block size gives information about the whole block size,
|
||||
* but the block could be stored in split form when using
|
||||
@@ -3650,9 +3726,9 @@ static int process_block(struct archive_read* a) {
|
||||
* part of the data will be in another file. */
|
||||
|
||||
cur_block_size =
|
||||
rar5_min(rar->file.bytes_remaining, block_size);
|
||||
rar5_min(rar5->file.bytes_remaining, block_size);
|
||||
|
||||
if(block_size > rar->file.bytes_remaining) {
|
||||
if(block_size > rar5->file.bytes_remaining) {
|
||||
/* If current blocks' size is bigger than our data
|
||||
* size, this means we have a multivolume archive.
|
||||
* In this case, skip all base headers until the end
|
||||
@@ -3676,7 +3752,7 @@ static int process_block(struct archive_read* a) {
|
||||
* the *whole* block (merged from partial blocks
|
||||
* stored in multiple archives files). */
|
||||
} else {
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
|
||||
/* Read the whole block size into memory. This can take
|
||||
* up to 8 megabytes of memory in theoretical cases.
|
||||
@@ -3688,16 +3764,16 @@ static int process_block(struct archive_read* a) {
|
||||
}
|
||||
}
|
||||
|
||||
rar->cstate.block_buf = p;
|
||||
rar->cstate.cur_block_size = cur_block_size;
|
||||
rar->cstate.block_parsing_finished = 0;
|
||||
rar5->cstate.block_buf = p;
|
||||
rar5->cstate.cur_block_size = cur_block_size;
|
||||
rar5->cstate.block_parsing_finished = 0;
|
||||
|
||||
rar->bits.in_addr = 0;
|
||||
rar->bits.bit_addr = 0;
|
||||
rar5->bits.in_addr = 0;
|
||||
rar5->bits.bit_addr = 0;
|
||||
|
||||
if(bf_is_table_present(&rar->last_block_hdr)) {
|
||||
if(bf_is_table_present(&rar5->last_block_hdr)) {
|
||||
/* Load Huffman tables. */
|
||||
ret = parse_tables(a, rar, p);
|
||||
ret = parse_tables(a, rar5, p);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
/* Error during decompression of Huffman
|
||||
* tables. */
|
||||
@@ -3706,7 +3782,7 @@ static int process_block(struct archive_read* a) {
|
||||
}
|
||||
} else {
|
||||
/* Block parsing not finished, reuse previous memory buffer. */
|
||||
p = rar->cstate.block_buf;
|
||||
p = rar5->cstate.block_buf;
|
||||
}
|
||||
|
||||
/* Uncompress the block, or a part of it, depending on how many bytes
|
||||
@@ -3719,22 +3795,22 @@ static int process_block(struct archive_read* a) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(rar->cstate.block_parsing_finished &&
|
||||
rar->cstate.switch_multivolume == 0 &&
|
||||
rar->cstate.cur_block_size > 0)
|
||||
if(rar5->cstate.block_parsing_finished &&
|
||||
rar5->cstate.switch_multivolume == 0 &&
|
||||
rar5->cstate.cur_block_size > 0)
|
||||
{
|
||||
/* If we're processing a normal block, consume the whole
|
||||
* block. We can do this because we've already read the whole
|
||||
* block to memory. */
|
||||
if(ARCHIVE_OK != consume(a, rar->cstate.cur_block_size))
|
||||
if(ARCHIVE_OK != consume(a, rar5->cstate.cur_block_size))
|
||||
return ARCHIVE_FATAL;
|
||||
|
||||
rar->file.bytes_remaining -= rar->cstate.cur_block_size;
|
||||
} else if(rar->cstate.switch_multivolume) {
|
||||
rar5->file.bytes_remaining -= rar5->cstate.cur_block_size;
|
||||
} else if(rar5->cstate.switch_multivolume) {
|
||||
/* Don't consume the block if we're doing multivolume
|
||||
* processing. The volume switching function will consume
|
||||
* the proper count of bytes instead. */
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
@@ -3744,13 +3820,13 @@ static int process_block(struct archive_read* a) {
|
||||
*
|
||||
* Returns ARCHIVE_OK when those arguments can be used, ARCHIVE_RETRY
|
||||
* when there is no data on the stack. */
|
||||
static int use_data(struct rar5* rar, const void** buf, size_t* size,
|
||||
static int use_data(struct rar5 *rar5, const void** buf, size_t* size,
|
||||
int64_t* offset)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {
|
||||
struct data_ready *d = &rar->cstate.dready[i];
|
||||
for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {
|
||||
struct data_ready *d = &rar5->cstate.dready[i];
|
||||
|
||||
if(d->used) {
|
||||
if(buf) *buf = d->buf;
|
||||
@@ -3765,14 +3841,14 @@ static int use_data(struct rar5* rar, const void** buf, size_t* size,
|
||||
return ARCHIVE_RETRY;
|
||||
}
|
||||
|
||||
static void clear_data_ready_stack(struct rar5* rar) {
|
||||
memset(&rar->cstate.dready, 0, sizeof(rar->cstate.dready));
|
||||
static void clear_data_ready_stack(struct rar5 *rar5) {
|
||||
memset(&rar5->cstate.dready, 0, sizeof(rar5->cstate.dready));
|
||||
}
|
||||
|
||||
/* Pushes the `buf`, `size` and `offset` arguments to the rar->cstate.dready
|
||||
/* Pushes the `buf`, `size` and `offset` arguments to the rar5->cstate.dready
|
||||
* FIFO stack. Those values will be popped from this stack by the `use_data`
|
||||
* function. */
|
||||
static int push_data_ready(struct archive_read* a, struct rar5* rar,
|
||||
static int push_data_ready(struct archive_read* a, struct rar5 *rar5,
|
||||
const uint8_t* buf, size_t size, int64_t offset)
|
||||
{
|
||||
int i;
|
||||
@@ -3783,18 +3859,18 @@ static int push_data_ready(struct archive_read* a, struct rar5* rar,
|
||||
* because we're interested only in the side effect: building up the
|
||||
* internal window circular buffer. This window buffer will be used
|
||||
* later during unpacking of requested data. */
|
||||
if(rar->skip_mode)
|
||||
if(rar5->skip_mode)
|
||||
return ARCHIVE_OK;
|
||||
|
||||
/* Sanity check. */
|
||||
if(offset != rar->file.last_offset + rar->file.last_size) {
|
||||
if(offset != rar5->file.last_offset + rar5->file.last_size) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Sanity check error: output stream is not continuous");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
for(i = 0; i < rar5_countof(rar->cstate.dready); i++) {
|
||||
struct data_ready* d = &rar->cstate.dready[i];
|
||||
for(i = 0; i < rar5_countof(rar5->cstate.dready); i++) {
|
||||
struct data_ready* d = &rar5->cstate.dready[i];
|
||||
if(!d->used) {
|
||||
d->used = 1;
|
||||
d->buf = buf;
|
||||
@@ -3802,24 +3878,24 @@ static int push_data_ready(struct archive_read* a, struct rar5* rar,
|
||||
d->offset = offset;
|
||||
|
||||
/* These fields are used only in sanity checking. */
|
||||
rar->file.last_offset = offset;
|
||||
rar->file.last_size = size;
|
||||
rar5->file.last_offset = offset;
|
||||
rar5->file.last_size = size;
|
||||
|
||||
/* Calculate the checksum of this new block before
|
||||
* submitting data to libarchive's engine. */
|
||||
update_crc(rar, d->buf, d->size);
|
||||
update_crc(rar5, d->buf, d->size);
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Program counter will reach this code if the `rar->cstate.data_ready`
|
||||
* stack will be filled up so that no new entries will be allowed. The
|
||||
* code shouldn't allow such situation to occur. So we treat this case
|
||||
* as an internal error. */
|
||||
/* Program counter will reach this code if the
|
||||
* `rar5->cstate.data_ready` stack will be filled up so that no new
|
||||
* entries will be allowed. The code shouldn't allow such situation to
|
||||
* occur. So we treat this case as an internal error. */
|
||||
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Error: premature end of data_ready stack");
|
||||
"Premature end of data_ready stack");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
@@ -3866,31 +3942,32 @@ static int push_data_ready(struct archive_read* a, struct rar5* rar,
|
||||
* */
|
||||
|
||||
static int do_uncompress_file(struct archive_read* a) {
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int ret;
|
||||
int64_t max_end_pos;
|
||||
|
||||
if(!rar->cstate.initialized) {
|
||||
if(!rar5->cstate.initialized) {
|
||||
/* Don't perform full context reinitialization if we're
|
||||
* processing a solid archive. */
|
||||
if(!rar->main.solid || !rar->cstate.window_buf) {
|
||||
init_unpack(rar);
|
||||
if(!rar5->main.solid || !rar5->cstate.window_buf) {
|
||||
if((ret = init_unpack(rar5)) != ARCHIVE_OK)
|
||||
return ret;
|
||||
}
|
||||
|
||||
rar->cstate.initialized = 1;
|
||||
rar5->cstate.initialized = 1;
|
||||
}
|
||||
|
||||
/* Don't allow extraction if window_size is invalid. */
|
||||
if(rar->cstate.window_size == 0) {
|
||||
if(rar5->cstate.window_size == 0) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid window size declaration in this file");
|
||||
|
||||
/* This should never happen in valid files. */
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(rar->cstate.all_filters_applied == 1) {
|
||||
if(rar5->cstate.all_filters_applied == 1) {
|
||||
/* We use while(1) here, but standard case allows for just 1
|
||||
* iteration. The loop will iterate if process_block() didn't
|
||||
* generate any data at all. This can happen if the block
|
||||
@@ -3898,15 +3975,15 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
* files). */
|
||||
while(1) {
|
||||
ret = process_block(a);
|
||||
if(ret == ARCHIVE_EOF || ret == ARCHIVE_FATAL)
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
if(rar->cstate.last_write_ptr ==
|
||||
rar->cstate.write_ptr) {
|
||||
if(rar5->cstate.last_write_ptr ==
|
||||
rar5->cstate.write_ptr) {
|
||||
/* The block didn't generate any new data,
|
||||
* so just process a new block if this one
|
||||
* wasn't the last block in the file. */
|
||||
if (bf_is_last_block(&rar->last_block_hdr)) {
|
||||
if (bf_is_last_block(&rar5->last_block_hdr)) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
@@ -3924,19 +4001,17 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
ret = apply_filters(a);
|
||||
if(ret == ARCHIVE_RETRY) {
|
||||
return ARCHIVE_OK;
|
||||
} else if(ret == ARCHIVE_FATAL) {
|
||||
return ARCHIVE_FATAL;
|
||||
} else if(ret != ARCHIVE_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If apply_filters() will return ARCHIVE_OK, we can continue here. */
|
||||
|
||||
if(cdeque_size(&rar->cstate.filters) > 0) {
|
||||
if(cdeque_size(&rar5->cstate.filters) > 0) {
|
||||
/* Check if we can write something before hitting first
|
||||
* filter. */
|
||||
struct filter_info* flt;
|
||||
|
||||
/* Get the block_start offset from the first filter. */
|
||||
if(CDE_OK != cdeque_front(&rar->cstate.filters,
|
||||
if(CDE_OK != cdeque_front(&rar5->cstate.filters,
|
||||
cdeque_filter_p(&flt)))
|
||||
{
|
||||
archive_set_error(&a->archive,
|
||||
@@ -3946,15 +4021,15 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
}
|
||||
|
||||
max_end_pos = rar5_min(flt->block_start,
|
||||
rar->cstate.write_ptr);
|
||||
rar5->cstate.write_ptr);
|
||||
} else {
|
||||
/* There are no filters defined, or all filters were applied.
|
||||
* This means we can just store the data without any
|
||||
* postprocessing. */
|
||||
max_end_pos = rar->cstate.write_ptr;
|
||||
max_end_pos = rar5->cstate.write_ptr;
|
||||
}
|
||||
|
||||
if(max_end_pos == rar->cstate.last_write_ptr) {
|
||||
if(max_end_pos == rar5->cstate.last_write_ptr) {
|
||||
/* We can't write anything yet. The block uncompression
|
||||
* function did not generate enough data, and no filter can be
|
||||
* applied. At the same time we don't have any data that can be
|
||||
@@ -3971,9 +4046,9 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
* So let's do it. The push_window_data() function will
|
||||
* effectively return the selected data block to the user
|
||||
* application. */
|
||||
push_window_data(a, rar, rar->cstate.last_write_ptr,
|
||||
push_window_data(a, rar5, rar5->cstate.last_write_ptr,
|
||||
max_end_pos);
|
||||
rar->cstate.last_write_ptr = max_end_pos;
|
||||
rar5->cstate.last_write_ptr = max_end_pos;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
@@ -3994,19 +4069,19 @@ static int uncompress_file(struct archive_read* a) {
|
||||
|
||||
|
||||
static int do_unstore_file(struct archive_read* a,
|
||||
struct rar5* rar, const void** buf, size_t* size, int64_t* offset)
|
||||
struct rar5 *rar5, const void** buf, size_t* size, int64_t* offset)
|
||||
{
|
||||
size_t to_read;
|
||||
const uint8_t* p;
|
||||
|
||||
if(rar->file.bytes_remaining == 0 && rar->main.volume > 0 &&
|
||||
rar->generic.split_after > 0)
|
||||
if(rar5->file.bytes_remaining == 0 && rar5->main.volume > 0 &&
|
||||
rar5->generic.split_after > 0)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rar->cstate.switch_multivolume = 1;
|
||||
rar5->cstate.switch_multivolume = 1;
|
||||
ret = advance_multivolume(a);
|
||||
rar->cstate.switch_multivolume = 0;
|
||||
rar5->cstate.switch_multivolume = 0;
|
||||
|
||||
if(ret != ARCHIVE_OK) {
|
||||
/* Failed to advance to next multivolume archive
|
||||
@@ -4015,7 +4090,7 @@ static int do_unstore_file(struct archive_read* a,
|
||||
}
|
||||
}
|
||||
|
||||
to_read = rar5_min(rar->file.bytes_remaining, 64 * 1024);
|
||||
to_read = rar5_min(rar5->file.bytes_remaining, 64 * 1024);
|
||||
if(to_read == 0) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
@@ -4032,16 +4107,16 @@ static int do_unstore_file(struct archive_read* a,
|
||||
|
||||
if(buf) *buf = p;
|
||||
if(size) *size = to_read;
|
||||
if(offset) *offset = rar->cstate.last_unstore_ptr;
|
||||
if(offset) *offset = rar5->cstate.last_unstore_ptr;
|
||||
|
||||
rar->file.bytes_remaining -= to_read;
|
||||
rar->cstate.last_unstore_ptr += to_read;
|
||||
rar5->file.bytes_remaining -= to_read;
|
||||
rar5->cstate.last_unstore_ptr += to_read;
|
||||
|
||||
update_crc(rar, p, to_read);
|
||||
update_crc(rar5, p, to_read);
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int do_unpack(struct archive_read* a, struct rar5* rar,
|
||||
static int do_unpack(struct archive_read* a, struct rar5 *rar5,
|
||||
const void** buf, size_t* size, int64_t* offset)
|
||||
{
|
||||
enum COMPRESSION_METHOD {
|
||||
@@ -4049,12 +4124,12 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
|
||||
BEST = 5
|
||||
};
|
||||
|
||||
if(rar->file.service > 0) {
|
||||
return do_unstore_file(a, rar, buf, size, offset);
|
||||
if(rar5->file.service > 0) {
|
||||
return do_unstore_file(a, rar5, buf, size, offset);
|
||||
} else {
|
||||
switch(rar->cstate.method) {
|
||||
switch(rar5->cstate.method) {
|
||||
case STORE:
|
||||
return do_unstore_file(a, rar, buf, size,
|
||||
return do_unstore_file(a, rar5, buf, size,
|
||||
offset);
|
||||
case FASTEST:
|
||||
/* fallthrough */
|
||||
@@ -4071,13 +4146,13 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
|
||||
* accordingly. At this point the decoder doesn't have any
|
||||
* pending uncompressed data blocks, so the current position in
|
||||
* the output file should be last_write_ptr. */
|
||||
if (offset) *offset = rar->cstate.last_write_ptr;
|
||||
if (offset) *offset = rar5->cstate.last_write_ptr;
|
||||
return uncompress_file(a);
|
||||
default:
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Compression method not supported: 0x%x",
|
||||
(unsigned int)rar->cstate.method);
|
||||
(unsigned int)rar5->cstate.method);
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
@@ -4090,15 +4165,15 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
|
||||
static int verify_checksums(struct archive_read* a) {
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int verify_crc;
|
||||
struct rar5* rar = get_context(a);
|
||||
|
||||
/* Check checksums only when actually unpacking the data. There's no
|
||||
* need to calculate checksum when we're skipping data in solid archives
|
||||
* (skipping in solid archives is the same thing as unpacking compressed
|
||||
* data and discarding the result). */
|
||||
|
||||
if(!rar->skip_mode) {
|
||||
if(!rar5->skip_mode) {
|
||||
/* Always check checksums if we're not in skip mode */
|
||||
verify_crc = 1;
|
||||
} else {
|
||||
@@ -4122,39 +4197,39 @@ static int verify_checksums(struct archive_read* a) {
|
||||
* process is already over and we can check if calculated
|
||||
* checksum (CRC32 or BLAKE2sp) is the same as what is stored
|
||||
* in the archive. */
|
||||
if(rar->file.stored_crc32 > 0) {
|
||||
if(rar5->file.stored_crc32 > 0) {
|
||||
/* Check CRC32 only when the file contains a CRC32
|
||||
* value for this file. */
|
||||
|
||||
if(rar->file.calculated_crc32 !=
|
||||
rar->file.stored_crc32) {
|
||||
if(rar5->file.calculated_crc32 !=
|
||||
rar5->file.stored_crc32) {
|
||||
/* Checksums do not match; the unpacked file
|
||||
* is corrupted. */
|
||||
|
||||
DEBUG_CODE {
|
||||
printf("Checksum error: CRC32 "
|
||||
"(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",
|
||||
rar->file.calculated_crc32,
|
||||
rar->file.stored_crc32);
|
||||
rar5->file.calculated_crc32,
|
||||
rar5->file.stored_crc32);
|
||||
}
|
||||
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Checksum error: CRC32");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
#endif
|
||||
} else {
|
||||
DEBUG_CODE {
|
||||
printf("Checksum OK: CRC32 "
|
||||
"(%08" PRIx32 "/%08" PRIx32 ")\n",
|
||||
rar->file.stored_crc32,
|
||||
rar->file.calculated_crc32);
|
||||
rar5->file.stored_crc32,
|
||||
rar5->file.calculated_crc32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(rar->file.has_blake2 > 0) {
|
||||
if(rar5->file.has_blake2 > 0) {
|
||||
/* BLAKE2sp is an optional checksum algorithm that is
|
||||
* added to RARv5 archives when using the `-htb` switch
|
||||
* during creation of archive.
|
||||
@@ -4169,15 +4244,15 @@ static int verify_checksums(struct archive_read* a) {
|
||||
* This is why we're explicitly ignoring it. */
|
||||
|
||||
uint8_t b2_buf[32];
|
||||
(void) blake2sp_final(&rar->file.b2state, b2_buf, 32);
|
||||
(void) blake2sp_final(&rar5->file.b2state, b2_buf, 32);
|
||||
|
||||
if(memcmp(&rar->file.blake2sp, b2_buf, 32) != 0) {
|
||||
if(memcmp(&rar5->file.blake2sp, b2_buf, 32) != 0) {
|
||||
#ifndef DONT_FAIL_ON_CRC_ERROR
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Checksum error: BLAKE2");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -4205,23 +4280,23 @@ static void rar5_signature(char *buf) {
|
||||
|
||||
static int rar5_read_data(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset) {
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
int ret;
|
||||
struct rar5* rar = get_context(a);
|
||||
|
||||
if (size)
|
||||
*size = 0;
|
||||
|
||||
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
rar->has_encrypted_entries = 0;
|
||||
if (rar5->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
rar5->has_encrypted_entries = 0;
|
||||
}
|
||||
|
||||
if (rar->headers_are_encrypted || rar->cstate.data_encrypted) {
|
||||
if (rar5->headers_are_encrypted || rar5->cstate.data_encrypted) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Reading encrypted data is not currently supported");
|
||||
return ARCHIVE_FATAL;
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
|
||||
if(rar->file.dir > 0) {
|
||||
if(rar5->file.dir > 0) {
|
||||
/* Don't process any data if this file entry was declared
|
||||
* as a directory. This is needed, because entries marked as
|
||||
* directory doesn't have any dictionary buffer allocated, so
|
||||
@@ -4231,28 +4306,28 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(!rar->skip_mode && (rar->cstate.last_write_ptr > rar->file.unpacked_size)) {
|
||||
if(!rar5->skip_mode && (rar5->cstate.last_write_ptr > rar5->file.unpacked_size)) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Unpacker has written too many bytes");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
ret = use_data(rar, buff, size, offset);
|
||||
ret = use_data(rar5, buff, size, offset);
|
||||
if(ret == ARCHIVE_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(rar->file.eof == 1) {
|
||||
if(rar5->file.eof == 1) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
ret = do_unpack(a, rar, buff, size, offset);
|
||||
ret = do_unpack(a, rar5, buff, size, offset);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(rar->file.bytes_remaining == 0 &&
|
||||
rar->cstate.last_write_ptr == rar->file.unpacked_size)
|
||||
if(rar5->file.bytes_remaining == 0 &&
|
||||
rar5->cstate.last_write_ptr == rar5->file.unpacked_size)
|
||||
{
|
||||
/* If all bytes of current file were processed, run
|
||||
* finalization.
|
||||
@@ -4262,7 +4337,7 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
|
||||
* value in the last `archive_read_data` call to signal an error
|
||||
* to the user. */
|
||||
|
||||
rar->file.eof = 1;
|
||||
rar5->file.eof = 1;
|
||||
return verify_global_checksums(a);
|
||||
}
|
||||
|
||||
@@ -4270,21 +4345,21 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
|
||||
}
|
||||
|
||||
static int rar5_read_data_skip(struct archive_read *a) {
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
|
||||
if(rar->main.solid && (rar->cstate.data_encrypted == 0)) {
|
||||
if(rar5->main.solid && (rar5->cstate.data_encrypted == 0)) {
|
||||
/* In solid archives, instead of skipping the data, we need to
|
||||
* extract it, and dispose the result. The side effect of this
|
||||
* operation will be setting up the initial window buffer state
|
||||
* needed to be able to extract the selected file. Note that
|
||||
* this is only possible when data withing this solid block is
|
||||
* this is only possible when data within this solid block is
|
||||
* not encrypted, in which case we'll skip and fail if the user
|
||||
* tries to read data. */
|
||||
|
||||
int ret;
|
||||
|
||||
/* Make sure to process all blocks in the compressed stream. */
|
||||
while(rar->file.bytes_remaining > 0) {
|
||||
while(rar5->file.bytes_remaining > 0) {
|
||||
/* Setting the "skip mode" will allow us to skip
|
||||
* checksum checks during data skipping. Checking the
|
||||
* checksum of skipped data isn't really necessary and
|
||||
@@ -4293,14 +4368,14 @@ static int rar5_read_data_skip(struct archive_read *a) {
|
||||
* This is incremented instead of setting to 1 because
|
||||
* this data skipping function can be called
|
||||
* recursively. */
|
||||
rar->skip_mode++;
|
||||
rar5->skip_mode++;
|
||||
|
||||
/* We're disposing 1 block of data, so we use triple
|
||||
* NULLs in arguments. */
|
||||
ret = rar5_read_data(a, NULL, NULL, NULL);
|
||||
|
||||
/* Turn off "skip mode". */
|
||||
rar->skip_mode--;
|
||||
rar5->skip_mode--;
|
||||
|
||||
if(ret < 0 || ret == ARCHIVE_EOF) {
|
||||
/* Propagate any potential error conditions
|
||||
@@ -4313,11 +4388,11 @@ static int rar5_read_data_skip(struct archive_read *a) {
|
||||
* stream. Each file in non-solid archives starts from an empty
|
||||
* window buffer. */
|
||||
|
||||
if(ARCHIVE_OK != consume(a, rar->file.bytes_remaining)) {
|
||||
if(ARCHIVE_OK != consume(a, rar5->file.bytes_remaining)) {
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->file.bytes_remaining = 0;
|
||||
rar5->file.bytes_remaining = 0;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
@@ -4326,28 +4401,30 @@ static int rar5_read_data_skip(struct archive_read *a) {
|
||||
static int64_t rar5_seek_data(struct archive_read *a, int64_t offset,
|
||||
int whence)
|
||||
{
|
||||
(void) a;
|
||||
(void) offset;
|
||||
(void) whence;
|
||||
|
||||
/* We're a streaming unpacker, and we don't support seeking. */
|
||||
/* We're a streaming unpacker, and we don't support seeking.
|
||||
* That's a capability gap, not a fatal error. */
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Seeking of RAR5 files is unsupported");
|
||||
|
||||
return ARCHIVE_FATAL;
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
static int rar5_cleanup(struct archive_read *a) {
|
||||
struct rar5* rar = get_context(a);
|
||||
struct rar5 *rar5 = a->format->data;
|
||||
|
||||
free(rar->cstate.window_buf);
|
||||
free(rar->cstate.filtered_buf);
|
||||
clear_data_ready_stack(rar);
|
||||
free(rar5->cstate.window_buf);
|
||||
free(rar5->cstate.filtered_buf);
|
||||
clear_data_ready_stack(rar5);
|
||||
|
||||
free(rar->vol.push_buf);
|
||||
free(rar5->vol.push_buf);
|
||||
|
||||
free_filters(rar);
|
||||
rar5_deinit(rar);
|
||||
free_filters(rar5);
|
||||
rar5_deinit(rar5);
|
||||
|
||||
free(rar);
|
||||
free(rar5);
|
||||
a->format->data = NULL;
|
||||
|
||||
return ARCHIVE_OK;
|
||||
@@ -4361,9 +4438,9 @@ static int rar5_capabilities(struct archive_read * a) {
|
||||
|
||||
static int rar5_has_encrypted_entries(struct archive_read *_a) {
|
||||
if (_a && _a->format) {
|
||||
struct rar5 *rar = (struct rar5 *)_a->format->data;
|
||||
if (rar) {
|
||||
return rar->has_encrypted_entries;
|
||||
struct rar5 *rar5 = _a->format->data;
|
||||
if (rar5) {
|
||||
return rar5->has_encrypted_entries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4371,50 +4448,50 @@ static int rar5_has_encrypted_entries(struct archive_read *_a) {
|
||||
}
|
||||
|
||||
/* Must match deallocations in rar5_deinit */
|
||||
static int rar5_init(struct rar5* rar) {
|
||||
memset(rar, 0, sizeof(struct rar5));
|
||||
static int rar5_init(struct rar5 *rar5) {
|
||||
memset(rar5, 0, sizeof(struct rar5));
|
||||
|
||||
if(CDE_OK != cdeque_init(&rar->cstate.filters, 8192))
|
||||
if(CDE_OK != cdeque_init(&rar5->cstate.filters, 8192))
|
||||
return ARCHIVE_FATAL;
|
||||
|
||||
/*
|
||||
* Until enough data has been read, we cannot tell about
|
||||
* any encrypted entries yet.
|
||||
*/
|
||||
rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
|
||||
rar5->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
/* Must match allocations in rar5_init */
|
||||
static void rar5_deinit(struct rar5* rar) {
|
||||
cdeque_free(&rar->cstate.filters);
|
||||
static void rar5_deinit(struct rar5 *rar5) {
|
||||
cdeque_free(&rar5->cstate.filters);
|
||||
}
|
||||
|
||||
int archive_read_support_format_rar5(struct archive *_a) {
|
||||
struct archive_read* ar;
|
||||
int ret;
|
||||
struct rar5* rar;
|
||||
struct rar5 *rar5;
|
||||
|
||||
if(ARCHIVE_OK != (ret = get_archive_read(_a, &ar)))
|
||||
return ret;
|
||||
|
||||
rar = malloc(sizeof(*rar));
|
||||
if(rar == NULL) {
|
||||
rar5 = malloc(sizeof(*rar5));
|
||||
if(rar5 == NULL) {
|
||||
archive_set_error(&ar->archive, ENOMEM,
|
||||
"Can't allocate rar5 data");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(ARCHIVE_OK != rar5_init(rar)) {
|
||||
if(ARCHIVE_OK != rar5_init(rar5)) {
|
||||
archive_set_error(&ar->archive, ENOMEM,
|
||||
"Can't allocate rar5 filter buffer");
|
||||
free(rar);
|
||||
free(rar5);
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
ret = __archive_read_register_format(ar,
|
||||
rar,
|
||||
rar5,
|
||||
"rar5",
|
||||
rar5_bid,
|
||||
rar5_options,
|
||||
@@ -4427,8 +4504,8 @@ int archive_read_support_format_rar5(struct archive *_a) {
|
||||
rar5_has_encrypted_entries);
|
||||
|
||||
if(ret != ARCHIVE_OK) {
|
||||
rar5_deinit(rar);
|
||||
free(rar);
|
||||
rar5_deinit(rar5);
|
||||
free(rar5);
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
|
||||
@@ -34,10 +34,11 @@
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
struct raw_info {
|
||||
struct raw {
|
||||
int64_t offset; /* Current position in the file. */
|
||||
int64_t unconsumed;
|
||||
int end_of_file;
|
||||
@@ -54,22 +55,22 @@ static int archive_read_format_raw_read_header(struct archive_read *,
|
||||
int
|
||||
archive_read_support_format_raw(struct archive *_a)
|
||||
{
|
||||
struct raw_info *info;
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
struct raw *raw;
|
||||
int r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_read_support_format_raw");
|
||||
|
||||
info = calloc(1, sizeof(*info));
|
||||
if (info == NULL) {
|
||||
raw = calloc(1, sizeof(*raw));
|
||||
if (raw == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate raw_info data");
|
||||
"Can't allocate raw data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
r = __archive_read_register_format(a,
|
||||
info,
|
||||
raw,
|
||||
"raw",
|
||||
archive_read_format_raw_bid,
|
||||
NULL,
|
||||
@@ -81,7 +82,7 @@ archive_read_support_format_raw(struct archive *_a)
|
||||
NULL,
|
||||
NULL);
|
||||
if (r != ARCHIVE_OK)
|
||||
free(info);
|
||||
free(raw);
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -107,10 +108,9 @@ static int
|
||||
archive_read_format_raw_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct raw_info *info;
|
||||
struct raw *raw = a->format->data;
|
||||
|
||||
info = (struct raw_info *)(a->format->data);
|
||||
if (info->end_of_file)
|
||||
if (raw->end_of_file)
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_RAW;
|
||||
@@ -128,39 +128,43 @@ static int
|
||||
archive_read_format_raw_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct raw_info *info;
|
||||
struct raw *raw = a->format->data;
|
||||
ssize_t avail;
|
||||
|
||||
info = (struct raw_info *)(a->format->data);
|
||||
|
||||
/* Consume the bytes we read last time. */
|
||||
if (info->unconsumed) {
|
||||
__archive_read_consume(a, info->unconsumed);
|
||||
info->unconsumed = 0;
|
||||
if (raw->unconsumed) {
|
||||
__archive_read_consume(a, raw->unconsumed);
|
||||
raw->unconsumed = 0;
|
||||
}
|
||||
|
||||
if (info->end_of_file)
|
||||
if (raw->end_of_file)
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
/* Get whatever bytes are immediately available. */
|
||||
*buff = __archive_read_ahead(a, 1, &avail);
|
||||
if (avail > 0) {
|
||||
/* Return the bytes we just read */
|
||||
*offset = raw->offset;
|
||||
if (archive_ckd_add_i64(&raw->offset, raw->offset, avail)) {
|
||||
avail = INT64_MAX - *offset;
|
||||
if (avail == 0) {
|
||||
*size = 0;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
*size = avail;
|
||||
*offset = info->offset;
|
||||
info->offset += *size;
|
||||
info->unconsumed = avail;
|
||||
raw->unconsumed = avail;
|
||||
return (ARCHIVE_OK);
|
||||
} else if (0 == avail) {
|
||||
/* Record and return end-of-file. */
|
||||
info->end_of_file = 1;
|
||||
raw->end_of_file = 1;
|
||||
*size = 0;
|
||||
*offset = info->offset;
|
||||
*offset = raw->offset;
|
||||
return (ARCHIVE_EOF);
|
||||
} else {
|
||||
/* Record and return an error. */
|
||||
*size = 0;
|
||||
*offset = info->offset;
|
||||
*offset = raw->offset;
|
||||
return ((int)avail);
|
||||
}
|
||||
}
|
||||
@@ -168,24 +172,23 @@ archive_read_format_raw_read_data(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_raw_read_data_skip(struct archive_read *a)
|
||||
{
|
||||
struct raw_info *info = (struct raw_info *)(a->format->data);
|
||||
struct raw *raw = a->format->data;
|
||||
|
||||
/* Consume the bytes we read last time. */
|
||||
if (info->unconsumed) {
|
||||
__archive_read_consume(a, info->unconsumed);
|
||||
info->unconsumed = 0;
|
||||
if (raw->unconsumed) {
|
||||
__archive_read_consume(a, raw->unconsumed);
|
||||
raw->unconsumed = 0;
|
||||
}
|
||||
info->end_of_file = 1;
|
||||
raw->end_of_file = 1;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_raw_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct raw_info *info;
|
||||
struct raw *raw = a->format->data;
|
||||
|
||||
info = (struct raw_info *)(a->format->data);
|
||||
free(info);
|
||||
free(raw);
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "archive_acl_private.h" /* For ACL parsing routines. */
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
@@ -153,6 +154,8 @@ struct tar {
|
||||
int compat_2x;
|
||||
int process_mac_extensions;
|
||||
int read_concatenated_archives;
|
||||
int default_inode;
|
||||
int default_dev;
|
||||
};
|
||||
|
||||
/* Track which size fields were present in the headers */
|
||||
@@ -297,9 +300,8 @@ archive_read_support_format_tar(struct archive *_a)
|
||||
static int
|
||||
archive_read_format_tar_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct tar *tar;
|
||||
struct tar *tar = a->format->data;
|
||||
|
||||
tar = (struct tar *)(a->format->data);
|
||||
gnu_clear_sparse_list(tar);
|
||||
archive_string_free(&tar->entry_pathname);
|
||||
archive_string_free(&tar->entry_pathname_override);
|
||||
@@ -309,7 +311,7 @@ archive_read_format_tar_cleanup(struct archive_read *a)
|
||||
archive_string_free(&tar->line);
|
||||
archive_string_free(&tar->localname);
|
||||
free(tar);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -436,10 +438,9 @@ static int
|
||||
archive_read_format_tar_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct tar *tar;
|
||||
struct tar *tar = a->format->data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
tar = (struct tar *)(a->format->data);
|
||||
if (strcmp(key, "compat-2x") == 0) {
|
||||
/* Handle UTF-8 filenames as libarchive 2.x */
|
||||
tar->compat_2x = (val != NULL && val[0] != 0);
|
||||
@@ -522,11 +523,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
|
||||
* probably not worthwhile just to support the relatively
|
||||
* obscure tar->cpio conversion case.
|
||||
*/
|
||||
/* TODO: Move this into `struct tar` to avoid conflicts
|
||||
* when reading multiple archives */
|
||||
static int default_inode;
|
||||
static int default_dev;
|
||||
struct tar *tar;
|
||||
struct tar *tar = a->format->data;
|
||||
const char *p;
|
||||
const wchar_t *wp;
|
||||
int r;
|
||||
@@ -534,15 +531,14 @@ archive_read_format_tar_read_header(struct archive_read *a,
|
||||
int64_t unconsumed = 0;
|
||||
|
||||
/* Assign default device/inode values. */
|
||||
archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */
|
||||
archive_entry_set_ino(entry, ++default_inode); /* Don't use zero. */
|
||||
archive_entry_set_dev(entry, 1 + tar->default_dev); /* Don't use zero. */
|
||||
archive_entry_set_ino(entry, ++tar->default_inode); /* Don't use zero. */
|
||||
/* Limit generated st_ino number to 16 bits. */
|
||||
if (default_inode >= 0xffff) {
|
||||
++default_dev;
|
||||
default_inode = 0;
|
||||
if (tar->default_inode >= 0xffff) {
|
||||
++tar->default_dev;
|
||||
tar->default_inode = 0;
|
||||
}
|
||||
|
||||
tar = (struct tar *)(a->format->data);
|
||||
tar->entry_offset = 0;
|
||||
gnu_clear_sparse_list(tar);
|
||||
tar->size_fields = 0; /* We don't have any size info yet */
|
||||
@@ -586,16 +582,16 @@ archive_read_format_tar_read_header(struct archive_read *a,
|
||||
* directory: This is needed for certain old tar
|
||||
* variants and even for some broken newer ones.
|
||||
*/
|
||||
if ((wp = archive_entry_pathname_w(entry)) != NULL) {
|
||||
l = wcslen(wp);
|
||||
if (l > 0 && wp[l - 1] == L'/') {
|
||||
if ((p = archive_entry_pathname(entry)) != NULL) {
|
||||
l = strlen(p);
|
||||
if (l > 0 && p[l - 1] == '/') {
|
||||
archive_entry_set_filetype(entry, AE_IFDIR);
|
||||
tar->entry_bytes_remaining = 0;
|
||||
tar->entry_padding = 0;
|
||||
}
|
||||
} else if ((p = archive_entry_pathname(entry)) != NULL) {
|
||||
l = strlen(p);
|
||||
if (l > 0 && p[l - 1] == '/') {
|
||||
} else if ((wp = archive_entry_pathname_w(entry)) != NULL) {
|
||||
l = wcslen(wp);
|
||||
if (l > 0 && wp[l - 1] == L'/') {
|
||||
archive_entry_set_filetype(entry, AE_IFDIR);
|
||||
tar->entry_bytes_remaining = 0;
|
||||
tar->entry_padding = 0;
|
||||
@@ -609,12 +605,10 @@ static int
|
||||
archive_read_format_tar_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct tar *tar = a->format->data;
|
||||
ssize_t bytes_read;
|
||||
struct tar *tar;
|
||||
struct sparse_block *p;
|
||||
|
||||
tar = (struct tar *)(a->format->data);
|
||||
|
||||
for (;;) {
|
||||
/* Remove exhausted entries from sparse list. */
|
||||
while (tar->sparse_list != NULL &&
|
||||
@@ -673,10 +667,8 @@ archive_read_format_tar_read_data(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_tar_skip(struct archive_read *a)
|
||||
{
|
||||
struct tar *tar = a->format->data;
|
||||
int64_t request;
|
||||
struct tar* tar;
|
||||
|
||||
tar = (struct tar *)(a->format->data);
|
||||
|
||||
request = tar->entry_bytes_remaining + tar->entry_padding +
|
||||
tar->entry_bytes_unconsumed;
|
||||
@@ -1074,21 +1066,19 @@ static int
|
||||
header_Solaris_ACL(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
const struct archive_entry_header_ustar *header;
|
||||
struct archive_string acl_text;
|
||||
size_t size;
|
||||
int err, acl_type;
|
||||
uint64_t type;
|
||||
char *acl, *p;
|
||||
|
||||
header = (const struct archive_entry_header_ustar *)h;
|
||||
size = (size_t)tar_atol(header->size, sizeof(header->size));
|
||||
archive_string_init(&acl_text);
|
||||
err = read_body_to_string(a, tar, &acl_text, h, unconsumed);
|
||||
if (err != ARCHIVE_OK) {
|
||||
archive_string_free(&acl_text);
|
||||
return (err);
|
||||
}
|
||||
size = archive_strlen(&acl_text);
|
||||
|
||||
/* TODO: Examine the first characters to see if this
|
||||
* is an AIX ACL descriptor. We'll likely never support
|
||||
@@ -1202,7 +1192,7 @@ set_conversion_failed_error(struct archive_read *a,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"%s can't be converted from %s to current locale.",
|
||||
"%s can't be converted from %s to current locale",
|
||||
name, archive_string_conversion_charset_name(sconv));
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
@@ -1347,6 +1337,7 @@ header_common(struct archive_read *a, struct tar *tar,
|
||||
const struct archive_entry_header_ustar *header;
|
||||
const char *existing_linkpath;
|
||||
const wchar_t *existing_wcs_linkpath;
|
||||
mode_t header_mode;
|
||||
int err = ARCHIVE_OK;
|
||||
|
||||
header = (const struct archive_entry_header_ustar *)h;
|
||||
@@ -1354,12 +1345,10 @@ header_common(struct archive_read *a, struct tar *tar,
|
||||
/* Parse out the numeric fields (all are octal) */
|
||||
|
||||
/* Split mode handling: Set filetype always, perm only if not already set */
|
||||
archive_entry_set_filetype(entry,
|
||||
(mode_t)tar_atol(header->mode, sizeof(header->mode)));
|
||||
if (!archive_entry_perm_is_set(entry)) {
|
||||
archive_entry_set_perm(entry,
|
||||
(mode_t)tar_atol(header->mode, sizeof(header->mode)));
|
||||
}
|
||||
header_mode = (mode_t)tar_atol(header->mode, sizeof(header->mode));
|
||||
archive_entry_set_filetype(entry, header_mode);
|
||||
if (!archive_entry_perm_is_set(entry))
|
||||
archive_entry_set_perm(entry, header_mode);
|
||||
|
||||
/* Set uid, gid, mtime if not already set */
|
||||
if (!archive_entry_uid_is_set(entry)) {
|
||||
@@ -1369,7 +1358,12 @@ header_common(struct archive_read *a, struct tar *tar,
|
||||
archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
|
||||
}
|
||||
if (!archive_entry_mtime_is_set(entry)) {
|
||||
archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
|
||||
int64_t t64 = tar_atol(header->mtime, sizeof(header->mtime));
|
||||
time_t t = (time_t)t64;
|
||||
if ((int64_t)t != t64) { /* time_t overflowed */
|
||||
t = TIME_MAX;
|
||||
}
|
||||
archive_entry_set_mtime(entry, t, 0);
|
||||
}
|
||||
|
||||
/* Reconcile the size info. */
|
||||
@@ -1644,24 +1638,9 @@ is_mac_metadata_entry(struct archive_entry *entry) {
|
||||
const char *p, *name;
|
||||
const wchar_t *wp, *wname;
|
||||
|
||||
wname = wp = archive_entry_pathname_w(entry);
|
||||
if (wp != NULL) {
|
||||
name = p = archive_entry_pathname(entry);
|
||||
if (p != NULL) {
|
||||
/* Find the last path element. */
|
||||
for (; *wp != L'\0'; ++wp) {
|
||||
if (wp[0] == '/' && wp[1] != L'\0')
|
||||
wname = wp + 1;
|
||||
}
|
||||
/*
|
||||
* If last path element starts with "._", then
|
||||
* this is a Mac extension.
|
||||
*/
|
||||
if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0')
|
||||
return 1;
|
||||
} else {
|
||||
/* Find the last path element. */
|
||||
name = p = archive_entry_pathname(entry);
|
||||
if (p == NULL)
|
||||
return (ARCHIVE_FAILED);
|
||||
for (; *p != '\0'; ++p) {
|
||||
if (p[0] == '/' && p[1] != '\0')
|
||||
name = p + 1;
|
||||
@@ -1672,6 +1651,21 @@ is_mac_metadata_entry(struct archive_entry *entry) {
|
||||
*/
|
||||
if (name[0] == '.' && name[1] == '_' && name[2] != '\0')
|
||||
return 1;
|
||||
} else {
|
||||
/* Find the last path element. */
|
||||
wname = wp = archive_entry_pathname_w(entry);
|
||||
if (wp == NULL)
|
||||
return 0;
|
||||
for (; *wp != L'\0'; ++wp) {
|
||||
if (wp[0] == L'/' && wp[1] != L'\0')
|
||||
wname = wp + 1;
|
||||
}
|
||||
/*
|
||||
* If last path element starts with "._", then
|
||||
* this is a Mac extension.
|
||||
*/
|
||||
if (wname[0] == L'.' && wname[1] == L'_' && wname[2] != L'\0')
|
||||
return 1;
|
||||
}
|
||||
/* Not a mac extension */
|
||||
return 0;
|
||||
@@ -1752,7 +1746,6 @@ header_pax_global(struct archive_read *a, struct tar *tar,
|
||||
const struct archive_entry_header_ustar *header;
|
||||
int64_t size, to_consume;
|
||||
|
||||
(void)a; /* UNUSED */
|
||||
(void)tar; /* UNUSED */
|
||||
(void)entry; /* UNUSED */
|
||||
|
||||
@@ -1764,6 +1757,11 @@ header_pax_global(struct archive_read *a, struct tar *tar,
|
||||
(long long)size);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (size == 0) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Invalid empty pax global extended header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
to_consume = ((size + 511) & ~511);
|
||||
*unconsumed += to_consume;
|
||||
return (ARCHIVE_OK);
|
||||
@@ -1782,32 +1780,42 @@ header_ustar(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h)
|
||||
{
|
||||
const struct archive_entry_header_ustar *header;
|
||||
struct archive_string as;
|
||||
int err = ARCHIVE_OK, r;
|
||||
|
||||
header = (const struct archive_entry_header_ustar *)h;
|
||||
|
||||
/* Copy name into an internal buffer to ensure null-termination. */
|
||||
/*
|
||||
* The name field is fixed-width and may not be NUL-terminated.
|
||||
* Use a temporary string only when prefix/name joining is required.
|
||||
*/
|
||||
const char *existing_pathname = archive_entry_pathname(entry);
|
||||
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] == '\0')) {
|
||||
struct archive_string as;
|
||||
const char *pathname;
|
||||
size_t pathname_length;
|
||||
|
||||
archive_string_init(&as);
|
||||
if (header->prefix[0]) {
|
||||
archive_strncpy(&as, header->prefix, sizeof(header->prefix));
|
||||
if (as.s[archive_strlen(&as) - 1] != '/')
|
||||
archive_strappend_char(&as, '/');
|
||||
archive_strncat(&as, header->name, sizeof(header->name));
|
||||
pathname = as.s;
|
||||
pathname_length = archive_strlen(&as);
|
||||
} else {
|
||||
archive_strncpy(&as, header->name, sizeof(header->name));
|
||||
pathname = header->name;
|
||||
pathname_length = sizeof(header->name);
|
||||
}
|
||||
if (archive_entry_copy_pathname_l(entry, as.s, archive_strlen(&as),
|
||||
tar->sconv) != 0) {
|
||||
r = archive_entry_copy_pathname_l(entry, pathname,
|
||||
pathname_length, tar->sconv);
|
||||
archive_string_free(&as);
|
||||
if (r != 0) {
|
||||
err = set_conversion_failed_error(a, tar->sconv, "Pathname");
|
||||
if (err == ARCHIVE_FATAL)
|
||||
return (err);
|
||||
}
|
||||
archive_string_free(&as);
|
||||
}
|
||||
|
||||
/* Handle rest of common fields. */
|
||||
@@ -1900,6 +1908,11 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
|
||||
(long long)ext_size);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (ext_size == 0) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Invalid empty pax extended header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
ext_padding = 0x1ff & (-ext_size);
|
||||
if (ext_size > ext_size_limit) {
|
||||
@@ -2009,6 +2022,7 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
|
||||
/* Consume size, name, and `=` */
|
||||
*unconsumed += p - attr_start;
|
||||
if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) {
|
||||
archive_string_free(&attr_name);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
@@ -2016,6 +2030,7 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Malformed pax attributes");
|
||||
*unconsumed += ext_size + ext_padding;
|
||||
archive_string_free(&attr_name);
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
@@ -2256,18 +2271,18 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar,
|
||||
if (r != ARCHIVE_OK) {
|
||||
if (r == ARCHIVE_FATAL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"%s %s", "Can't allocate memory for ",
|
||||
"%s %s", "Can't allocate memory for",
|
||||
errstr);
|
||||
return (r);
|
||||
}
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr);
|
||||
ARCHIVE_ERRNO_MISC, "%s %s", "Parse error:", errstr);
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, int64_t *unconsumed) {
|
||||
pax_attribute_read_time(struct archive_read *a, size_t value_length, __LA_TIME_T *ps, long *pn, int64_t *unconsumed) {
|
||||
struct archive_string as;
|
||||
int r;
|
||||
|
||||
@@ -2287,12 +2302,16 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps
|
||||
return (r);
|
||||
}
|
||||
|
||||
pax_time(as.s, archive_strlen(&as), ps, pn);
|
||||
int64_t sec = 0;
|
||||
pax_time(as.s, archive_strlen(&as), &sec, pn);
|
||||
archive_string_free(&as);
|
||||
if (*ps == INT64_MIN) {
|
||||
|
||||
if (sec == INT64_MIN) {
|
||||
*ps = 0;
|
||||
*pn = 0;
|
||||
return (ARCHIVE_WARN);
|
||||
} else {
|
||||
*ps = (__LA_TIME_T)sec;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -2349,7 +2368,6 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
int64_t t;
|
||||
long n;
|
||||
const char *p;
|
||||
ssize_t bytes_read;
|
||||
int err = ARCHIVE_OK;
|
||||
|
||||
switch (key[0]) {
|
||||
@@ -2433,7 +2451,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
(unsigned long long)sparse_map_limit);
|
||||
err = ARCHIVE_FAILED;
|
||||
} else {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Truncated archive"
|
||||
@@ -2508,15 +2526,20 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
*/
|
||||
if (key_length == 12 && memcmp(key, "creationtime", 12) == 0) {
|
||||
/* LIBARCHIVE.creationtime */
|
||||
if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_birthtime(entry, t, n);
|
||||
__LA_TIME_T sec = 0;
|
||||
if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_birthtime(entry, sec, n);
|
||||
} else {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Ignoring malformed pax creationtime");
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
else if (key_length == 11 && memcmp(key, "symlinktype", 11) == 0) {
|
||||
/* LIBARCHIVE.symlinktype */
|
||||
if (value_length < 16) {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated tar archive "
|
||||
@@ -2550,7 +2573,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
if (value_length > xattr_limit) {
|
||||
err = ARCHIVE_WARN;
|
||||
} else {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Truncated archive"
|
||||
@@ -2580,7 +2603,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
/* TODO: Should this be FAILED instead? */
|
||||
err = ARCHIVE_WARN;
|
||||
} else {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Truncated archive"
|
||||
@@ -2633,7 +2656,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
}
|
||||
else if (key_length == 6 && memcmp(key, "fflags", 6) == 0) {
|
||||
if (value_length < fflags_limit) {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
/* Truncated archive */
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
@@ -2680,7 +2703,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
key_length -= 6;
|
||||
key += 6;
|
||||
if (value_length < xattr_limit) {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Truncated archive"
|
||||
@@ -2710,7 +2733,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
if (key_length == 9 && memcmp(key, "holesdata", 9) == 0) {
|
||||
/* SUN.holesdata */
|
||||
if (value_length < sparse_map_limit) {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Truncated archive"
|
||||
@@ -2737,16 +2760,26 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
break;
|
||||
case 'a':
|
||||
if (key_length == 5 && memcmp(key, "atime", 5) == 0) {
|
||||
if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_atime(entry, t, n);
|
||||
__LA_TIME_T sec = 0;
|
||||
if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_atime(entry, sec, n);
|
||||
} else {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Ignoring malformed pax atime");
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (key_length == 5 && memcmp(key, "ctime", 5) == 0) {
|
||||
if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_ctime(entry, t, n);
|
||||
__LA_TIME_T sec = 0;
|
||||
if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_ctime(entry, sec, n);
|
||||
} else {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Ignoring malformed pax ctime");
|
||||
}
|
||||
return (err);
|
||||
} else if (key_length == 7 && memcmp(key, "charset", 7) == 0) {
|
||||
@@ -2774,7 +2807,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
case 'h':
|
||||
if (key_length == 10 && memcmp(key, "hdrcharset", 10) == 0) {
|
||||
if (value_length < 64) {
|
||||
p = __archive_read_ahead(a, value_length, &bytes_read);
|
||||
p = __archive_read_ahead(a, value_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated tar archive "
|
||||
@@ -2818,8 +2851,13 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
break;
|
||||
case 'm':
|
||||
if (key_length == 5 && memcmp(key, "mtime", 5) == 0) {
|
||||
if ((err = pax_attribute_read_time(a, value_length, &t, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_mtime(entry, t, n);
|
||||
__LA_TIME_T sec;
|
||||
if ((err = pax_attribute_read_time(a, value_length, &sec, &n, unconsumed)) == ARCHIVE_OK) {
|
||||
archive_entry_set_mtime(entry, sec, n);
|
||||
} else {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Ignoring malformed pax mtime");
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
@@ -2886,7 +2924,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
|
||||
/*
|
||||
* Parse a decimal time value, which may include a fractional portion
|
||||
*
|
||||
* Sets ps to INT64_MIN on error.
|
||||
* Sets ps to INT64_MIN on error, including syntax issues such as non-digits,
|
||||
* or a time value that's outside the range of time_t.
|
||||
*/
|
||||
static void
|
||||
pax_time(const char *p, size_t length, int64_t *ps, long *pn)
|
||||
@@ -2895,10 +2934,6 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
|
||||
int64_t s;
|
||||
unsigned long l;
|
||||
int sign;
|
||||
int64_t limit, last_digit_limit;
|
||||
|
||||
limit = INT64_MAX / 10;
|
||||
last_digit_limit = INT64_MAX % 10;
|
||||
|
||||
if (length <= 0) {
|
||||
*ps = 0;
|
||||
@@ -2914,34 +2949,73 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
|
||||
}
|
||||
while (length > 0 && *p >= '0' && *p <= '9') {
|
||||
digit = *p - '0';
|
||||
if (s > limit ||
|
||||
(s == limit && digit > last_digit_limit)) {
|
||||
if (archive_ckd_mul_i64(&s, s, 10) ||
|
||||
archive_ckd_add_i64(&s, s, digit)) {
|
||||
*ps = INT64_MIN;
|
||||
*pn = 0;
|
||||
return;
|
||||
}
|
||||
s = (s * 10) + digit;
|
||||
++p;
|
||||
--length;
|
||||
}
|
||||
|
||||
*ps = s * sign;
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
/* Libarchive 4.0 will have __LA_TIME_T == int64_t, so
|
||||
this will be unnecessary. */
|
||||
/* Test whether it overflows __LA_TIME_T */
|
||||
__LA_TIME_T sec = (__LA_TIME_T)*ps;
|
||||
if ((int64_t)sec != *ps) {
|
||||
*ps = INT64_MIN;
|
||||
*pn = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate nanoseconds. */
|
||||
*pn = 0;
|
||||
|
||||
if (length <= 0 || *p != '.')
|
||||
if (length <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip `.` */
|
||||
if (*p != '.') {
|
||||
*ps = INT64_MIN;
|
||||
*pn = 0;
|
||||
return;
|
||||
}
|
||||
++p;
|
||||
--length;
|
||||
|
||||
l = 100000000UL;
|
||||
do {
|
||||
if (length <= 0) {
|
||||
return;
|
||||
}
|
||||
if (*p >= '0' && *p <= '9') {
|
||||
*pn += (*p - '0') * l;
|
||||
} else {
|
||||
*ps = INT64_MIN;
|
||||
*pn = 0;
|
||||
return;
|
||||
}
|
||||
++p;
|
||||
--length;
|
||||
if (length > 0 && *p >= '0' && *p <= '9')
|
||||
*pn += (*p - '0') * l;
|
||||
else
|
||||
break;
|
||||
} while (l /= 10);
|
||||
|
||||
/* Ignore resolution beyond nanoseconds,
|
||||
but verify it's all decimal digits. */
|
||||
while (length > 0) {
|
||||
if (*p < '0' || *p > '9') {
|
||||
*ps = INT64_MIN;
|
||||
*pn = 0;
|
||||
return;
|
||||
}
|
||||
++p;
|
||||
--length;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2951,6 +3025,7 @@ static int
|
||||
header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
struct archive_entry *entry, const void *h, int64_t *unconsumed)
|
||||
{
|
||||
struct archive_entry_header_gnutar header_copy;
|
||||
const struct archive_entry_header_gnutar *header;
|
||||
int64_t t;
|
||||
int err = ARCHIVE_OK;
|
||||
@@ -2961,8 +3036,14 @@ header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
* filename is stored as in old-style archives.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sparse extension reads can reuse the callback buffer containing h,
|
||||
* so preserve the main header until common fields are parsed.
|
||||
*/
|
||||
memcpy(&header_copy, h, sizeof(header_copy));
|
||||
header = &header_copy;
|
||||
|
||||
/* Copy filename over (to ensure null termination). */
|
||||
header = (const struct archive_entry_header_gnutar *)h;
|
||||
const char *existing_pathname = archive_entry_pathname(entry);
|
||||
const wchar_t *existing_wcs_pathname = archive_entry_pathname_w(entry);
|
||||
if ((existing_pathname == NULL || existing_pathname[0] == '\0')
|
||||
@@ -3041,7 +3122,7 @@ header_gnutar(struct archive_read *a, struct tar *tar,
|
||||
}
|
||||
|
||||
/* Grab fields common to all tar variants. */
|
||||
err = header_common(a, tar, entry, h);
|
||||
err = header_common(a, tar, entry, header);
|
||||
if (err == ARCHIVE_FATAL)
|
||||
return (err);
|
||||
|
||||
@@ -3104,7 +3185,6 @@ static int
|
||||
gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
|
||||
const struct archive_entry_header_gnutar *header, int64_t *unconsumed)
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
const void *data;
|
||||
struct extended {
|
||||
struct gnu_sparse sparse[21];
|
||||
@@ -3122,7 +3202,7 @@ gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
|
||||
if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data = __archive_read_ahead(a, 512, &bytes_read);
|
||||
data = __archive_read_ahead(a, 512, NULL);
|
||||
if (data == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated tar archive "
|
||||
@@ -3240,14 +3320,12 @@ static int64_t
|
||||
gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
|
||||
int64_t *remaining, int64_t *unconsumed)
|
||||
{
|
||||
int64_t l, limit, last_digit_limit;
|
||||
int64_t l;
|
||||
const char *p;
|
||||
ssize_t bytes_read;
|
||||
int base, digit;
|
||||
|
||||
base = 10;
|
||||
limit = INT64_MAX / base;
|
||||
last_digit_limit = INT64_MAX % base;
|
||||
|
||||
/*
|
||||
* Skip any lines starting with '#'; GNU tar specs
|
||||
@@ -3268,10 +3346,10 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
|
||||
if (*p < '0' || *p >= '0' + base)
|
||||
return (ARCHIVE_WARN);
|
||||
digit = *p - '0';
|
||||
if (l > limit || (l == limit && digit > last_digit_limit))
|
||||
if (archive_ckd_mul_i64(&l, l, base) ||
|
||||
archive_ckd_add_i64(&l, l, digit)) {
|
||||
l = INT64_MAX; /* Truncate on overflow. */
|
||||
else
|
||||
l = (l * base) + digit;
|
||||
}
|
||||
p++;
|
||||
bytes_read--;
|
||||
}
|
||||
@@ -3367,13 +3445,10 @@ pax_attribute_SUN_holesdata(struct archive_read *a, struct tar *tar,
|
||||
return (ARCHIVE_FATAL);
|
||||
tar->sparse_last->hole = hole;
|
||||
}
|
||||
if (length == 0 || *e == '\n') {
|
||||
if (length == 0 && *e == '\n') {
|
||||
return (ARCHIVE_OK);
|
||||
} else {
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
}
|
||||
if (length == 0)
|
||||
return (ARCHIVE_OK);
|
||||
if (*e == '\n')
|
||||
return (ARCHIVE_WARN);
|
||||
p = e + 1;
|
||||
length--;
|
||||
hole = hole == 0;
|
||||
@@ -3417,13 +3492,9 @@ tar_atol(const char *p, size_t char_cnt)
|
||||
static int64_t
|
||||
tar_atol_base_n(const char *p, size_t char_cnt, int base)
|
||||
{
|
||||
int64_t l, maxval, limit, last_digit_limit;
|
||||
int64_t l;
|
||||
int digit, sign;
|
||||
|
||||
maxval = INT64_MAX;
|
||||
limit = INT64_MAX / base;
|
||||
last_digit_limit = INT64_MAX % base;
|
||||
|
||||
/* the pointer will not be dereferenced if char_cnt is zero
|
||||
* due to the way the && operator is evaluated.
|
||||
*/
|
||||
@@ -3437,25 +3508,22 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
|
||||
sign = -1;
|
||||
p++;
|
||||
char_cnt--;
|
||||
|
||||
maxval = INT64_MIN;
|
||||
limit = -(INT64_MIN / base);
|
||||
last_digit_limit = -(INT64_MIN % base);
|
||||
}
|
||||
|
||||
l = 0;
|
||||
if (char_cnt != 0) {
|
||||
while (char_cnt != 0) {
|
||||
digit = *p - '0';
|
||||
while (digit >= 0 && digit < base && char_cnt != 0) {
|
||||
if (l>limit || (l == limit && digit >= last_digit_limit)) {
|
||||
return maxval; /* Truncate on overflow. */
|
||||
}
|
||||
l = (l * base) + digit;
|
||||
digit = *++p - '0';
|
||||
char_cnt--;
|
||||
if (digit < 0 || digit >= base)
|
||||
break;
|
||||
if (archive_ckd_mul_i64(&l, l, base) ||
|
||||
archive_ckd_add_i64(&l, l, sign * digit)) {
|
||||
/* Truncate on overflow. */
|
||||
return sign < 0 ? INT64_MIN : INT64_MAX;
|
||||
}
|
||||
p++;
|
||||
char_cnt--;
|
||||
}
|
||||
return (sign < 0) ? -l : l;
|
||||
return l;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
@@ -3535,9 +3603,8 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
|
||||
{
|
||||
ssize_t bytes_read;
|
||||
ssize_t total_size = 0;
|
||||
const void *t;
|
||||
const void *p, *t;
|
||||
const char *s;
|
||||
void *p;
|
||||
|
||||
if (tar_flush_unconsumed(a, unconsumed) != ARCHIVE_OK) {
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -3609,24 +3676,20 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
|
||||
static char *
|
||||
base64_decode(const char *s, size_t len, size_t *out_len)
|
||||
{
|
||||
static const unsigned char digits[64] = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
|
||||
'O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b',
|
||||
'c','d','e','f','g','h','i','j','k','l','m','n','o','p',
|
||||
'q','r','s','t','u','v','w','x','y','z','0','1','2','3',
|
||||
'4','5','6','7','8','9','+','/' };
|
||||
static unsigned char decode_table[128];
|
||||
static const unsigned char decode_table[128] = {
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255,
|
||||
255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255,
|
||||
255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 255, 255, 255, 255, 255 };
|
||||
char *out, *d;
|
||||
const unsigned char *src = (const unsigned char *)s;
|
||||
|
||||
/* If the decode table is not yet initialized, prepare it. */
|
||||
if (decode_table[digits[1]] != 1) {
|
||||
unsigned i;
|
||||
memset(decode_table, 0xff, sizeof(decode_table));
|
||||
for (i = 0; i < sizeof(digits); i++)
|
||||
decode_table[digits[i]] = i;
|
||||
}
|
||||
|
||||
/* Allocate enough space to hold the entire output. */
|
||||
/* Note that we may not use all of this... */
|
||||
out = malloc(len - len / 4 + 1);
|
||||
|
||||
@@ -25,28 +25,35 @@
|
||||
|
||||
#include "archive_platform.h"
|
||||
|
||||
/**
|
||||
* WARC is standardised by ISO TC46/SC4/WG12 and currently available as
|
||||
* ISO 28500:2009.
|
||||
* For the purposes of this file we used the final draft from:
|
||||
/*
|
||||
* An overview of WARC format:
|
||||
*
|
||||
* WARC files are laid out as a sequence of records. Each record has
|
||||
* a text header followed by a content block whose size is given by
|
||||
* Content-Length. This reader supports WARC/0.12 through WARC/1.0
|
||||
* and was written using the final draft that became ISO 28500:2009:
|
||||
* http://bibnum.bnf.fr/warc/WARC_ISO_28500_version1_latestdraft.pdf
|
||||
*
|
||||
* Todo:
|
||||
* [ ] real-world warcs can contain resources at endpoints ending in /
|
||||
* e.g. http://bibnum.bnf.fr/warc/
|
||||
* if you're lucky their response contains a Content-Location: header
|
||||
* pointing to a unix-compliant filename, in the example above it's
|
||||
* Content-Location: http://bibnum.bnf.fr/warc/index.html
|
||||
* however, that's not mandated and github for example doesn't follow
|
||||
* this convention.
|
||||
* We need a set of archive options to control what to do with
|
||||
* entries like these, at the moment care is taken to skip them.
|
||||
* This reader exposes resource and response records as regular files
|
||||
* when they have a usable WARC-Target-URI. WARC-Date is exposed as
|
||||
* ctime, and a Last-Modified record header is exposed as mtime when
|
||||
* present.
|
||||
*
|
||||
**/
|
||||
* TODO: Real-world WARCs can contain resources at endpoints ending in
|
||||
* a slash, for example http://bibnum.bnf.fr/warc/. Some responses
|
||||
* include a Content-Location header that points to a Unix-compatible
|
||||
* filename such as http://bibnum.bnf.fr/warc/index.html, but WARC does
|
||||
* not require that convention and some sites do not follow it. Until
|
||||
* archive options exist to control these entries, this reader skips
|
||||
* them instead of creating directory endpoints as files.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_CTYPE_H
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
@@ -56,40 +63,35 @@
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_CTYPE_H
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
typedef enum {
|
||||
WT_NONE,
|
||||
/* warcinfo */
|
||||
/* WARC info */
|
||||
WT_INFO,
|
||||
/* metadata */
|
||||
/* Metadata */
|
||||
WT_META,
|
||||
/* resource */
|
||||
/* Resource */
|
||||
WT_RSRC,
|
||||
/* request, unsupported */
|
||||
/* Request, unsupported */
|
||||
WT_REQ,
|
||||
/* response, unsupported */
|
||||
/* Response */
|
||||
WT_RSP,
|
||||
/* revisit, unsupported */
|
||||
/* Revisit, unsupported */
|
||||
WT_RVIS,
|
||||
/* conversion, unsupported */
|
||||
/* Conversion, unsupported */
|
||||
WT_CONV,
|
||||
/* continuation, unsupported at the moment */
|
||||
/* Continuation, currently unsupported */
|
||||
WT_CONT,
|
||||
/* invalid type */
|
||||
/* Invalid type */
|
||||
LAST_WT
|
||||
} warc_type_t;
|
||||
|
||||
@@ -103,82 +105,92 @@ typedef struct {
|
||||
char *str;
|
||||
} warc_strbuf_t;
|
||||
|
||||
struct warc_s {
|
||||
/* content length ahead */
|
||||
size_t cntlen;
|
||||
/* and how much we've processed so far */
|
||||
size_t cntoff;
|
||||
/* and how much we need to consume between calls */
|
||||
size_t unconsumed;
|
||||
struct warc {
|
||||
/* Content length of the current record */
|
||||
int64_t cntlen;
|
||||
/* Bytes processed from the current record */
|
||||
int64_t cntoff;
|
||||
/* Bytes to consume before the next read */
|
||||
int64_t unconsumed;
|
||||
|
||||
/* string pool */
|
||||
/* String pool */
|
||||
warc_strbuf_t pool;
|
||||
/* previous version */
|
||||
/* Previous version */
|
||||
unsigned int pver;
|
||||
/* stringified format name */
|
||||
/* Stringified format name */
|
||||
struct archive_string sver;
|
||||
};
|
||||
|
||||
static int _warc_bid(struct archive_read *a, int);
|
||||
static int _warc_cleanup(struct archive_read *a);
|
||||
static int _warc_read(struct archive_read*, const void**, size_t*, int64_t*);
|
||||
static int _warc_skip(struct archive_read *a);
|
||||
static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);
|
||||
static int archive_read_format_warc_bid(struct archive_read *, int);
|
||||
static int archive_read_format_warc_cleanup(struct archive_read *);
|
||||
static int archive_read_format_warc_read_data(struct archive_read *,
|
||||
const void **, size_t *, int64_t *);
|
||||
static int archive_read_format_warc_skip(struct archive_read *);
|
||||
static int archive_read_format_warc_read_header(struct archive_read *,
|
||||
struct archive_entry *);
|
||||
|
||||
/* private routines */
|
||||
static unsigned int _warc_rdver(const char *buf, size_t bsz);
|
||||
static unsigned int _warc_rdtyp(const char *buf, size_t bsz);
|
||||
static warc_string_t _warc_rduri(const char *buf, size_t bsz);
|
||||
static ssize_t _warc_rdlen(const char *buf, size_t bsz);
|
||||
static time_t _warc_rdrtm(const char *buf, size_t bsz);
|
||||
static time_t _warc_rdmtm(const char *buf, size_t bsz);
|
||||
static const char *_warc_find_eoh(const char *buf, size_t bsz);
|
||||
static const char *_warc_find_eol(const char *buf, size_t bsz);
|
||||
/* Private routines */
|
||||
static unsigned int warc_read_version(const char *, size_t);
|
||||
static unsigned int warc_read_type(const char *, size_t);
|
||||
static warc_string_t warc_read_uri(const char *, size_t);
|
||||
static int64_t warc_read_length(const char *, size_t);
|
||||
static time_t warc_read_date(const char *, size_t);
|
||||
static time_t warc_read_last_modified(const char *, size_t);
|
||||
static const char *warc_find_eoh(const char *, size_t);
|
||||
static const char *warc_find_eol(const char *, size_t);
|
||||
|
||||
int
|
||||
archive_read_support_format_warc(struct archive *_a)
|
||||
{
|
||||
struct archive_read *a = (struct archive_read *)_a;
|
||||
struct warc_s *w;
|
||||
struct warc *warc;
|
||||
int r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_read_support_format_warc");
|
||||
|
||||
if ((w = calloc(1, sizeof(*w))) == NULL) {
|
||||
if ((warc = calloc(1, sizeof(*warc))) == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate warc data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
r = __archive_read_register_format(
|
||||
a, w, "warc",
|
||||
_warc_bid, NULL, _warc_rdhdr, _warc_read,
|
||||
_warc_skip, NULL, _warc_cleanup, NULL, NULL);
|
||||
r = __archive_read_register_format(a,
|
||||
warc,
|
||||
"warc",
|
||||
archive_read_format_warc_bid,
|
||||
NULL,
|
||||
archive_read_format_warc_read_header,
|
||||
archive_read_format_warc_read_data,
|
||||
archive_read_format_warc_skip,
|
||||
NULL,
|
||||
archive_read_format_warc_cleanup,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (r != ARCHIVE_OK) {
|
||||
free(w);
|
||||
free(warc);
|
||||
return (r);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
_warc_cleanup(struct archive_read *a)
|
||||
archive_read_format_warc_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct warc_s *w = a->format->data;
|
||||
struct warc *warc = a->format->data;
|
||||
|
||||
if (w->pool.len > 0U) {
|
||||
free(w->pool.str);
|
||||
if (warc->pool.len > 0U) {
|
||||
free(warc->pool.str);
|
||||
}
|
||||
archive_string_free(&w->sver);
|
||||
free(w);
|
||||
archive_string_free(&warc->sver);
|
||||
free(warc);
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
_warc_bid(struct archive_read *a, int best_bid)
|
||||
archive_read_format_warc_bid(struct archive_read *a, int best_bid)
|
||||
{
|
||||
const char *hdr;
|
||||
ssize_t nrd;
|
||||
@@ -186,55 +198,52 @@ _warc_bid(struct archive_read *a, int best_bid)
|
||||
|
||||
(void)best_bid; /* UNUSED */
|
||||
|
||||
/* check first line of file, it should be a record already */
|
||||
if ((hdr = __archive_read_ahead(a, 12U, &nrd)) == NULL) {
|
||||
/* no idea what to do */
|
||||
return -1;
|
||||
} else if (nrd < 12) {
|
||||
/* nah, not for us, our magic cookie is at least 12 bytes */
|
||||
/* Check the first line, which should already be a record header. */
|
||||
if ((hdr = __archive_read_ahead(a, 12, &nrd)) == NULL) {
|
||||
/* Not enough data to identify this format. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* otherwise snarf the record's version number */
|
||||
ver = _warc_rdver(hdr, nrd);
|
||||
/* Parse the record version number. */
|
||||
ver = warc_read_version(hdr, nrd);
|
||||
if (ver < 1200U || ver > 10000U) {
|
||||
/* we only support WARC 0.12 to 1.0 */
|
||||
/* Only WARC 0.12 through WARC 1.0 are supported. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* otherwise be confident */
|
||||
/* WARC magic and version checks passed. */
|
||||
return (64);
|
||||
}
|
||||
|
||||
static int
|
||||
_warc_rdhdr(struct archive_read *a, struct archive_entry *entry)
|
||||
archive_read_format_warc_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
#define HDR_PROBE_LEN (12U)
|
||||
struct warc_s *w = a->format->data;
|
||||
struct warc *warc = a->format->data;
|
||||
unsigned int ver;
|
||||
const char *buf;
|
||||
ssize_t nrd;
|
||||
const char *eoh;
|
||||
char *tmp;
|
||||
/* for the file name, saves some strndup()'ing */
|
||||
/* Reuse the header buffer while parsing the file name. */
|
||||
warc_string_t fnam;
|
||||
/* warc record type, not that we really use it a lot */
|
||||
/* WARC record type */
|
||||
warc_type_t ftyp;
|
||||
/* content-length+error monad */
|
||||
ssize_t cntlen;
|
||||
/* record time is the WARC-Date time we reinterpret it as ctime */
|
||||
/* Content length, or a negative error indicator */
|
||||
int64_t cntlen;
|
||||
/* WARC-Date is exposed as the entry ctime. */
|
||||
time_t rtime;
|
||||
/* mtime is the Last-Modified time which will be the entry's mtime */
|
||||
/* A Last-Modified record header is exposed as the entry mtime. */
|
||||
time_t mtime;
|
||||
|
||||
start_over:
|
||||
/* just use read_ahead() they keep track of unconsumed
|
||||
* bits and bobs for us; no need to put an extra shift in
|
||||
* and reproduce that functionality here */
|
||||
/* Use read_ahead(); it already tracks unconsumed bytes, so this
|
||||
* reader does not need a separate shift buffer. */
|
||||
buf = __archive_read_ahead(a, HDR_PROBE_LEN, &nrd);
|
||||
|
||||
if (nrd < 0) {
|
||||
/* no good */
|
||||
/* I/O or stream error. */
|
||||
archive_set_error(
|
||||
&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Bad record header");
|
||||
@@ -244,19 +253,17 @@ start_over:
|
||||
* must be EOF therefore */
|
||||
return (ARCHIVE_EOF);
|
||||
}
|
||||
/* looks good so far, try and find the end of the header now */
|
||||
eoh = _warc_find_eoh(buf, nrd);
|
||||
/* Locate the end of the record header. */
|
||||
eoh = warc_find_eoh(buf, nrd);
|
||||
if (eoh == NULL) {
|
||||
/* still no good, the header end might be beyond the
|
||||
* probe we've requested, but then again who'd cram
|
||||
* so much stuff into the header *and* be 28500-compliant */
|
||||
/* The header terminator was not found in the probed data. */
|
||||
archive_set_error(
|
||||
&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Bad record header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
ver = _warc_rdver(buf, eoh - buf);
|
||||
/* we currently support WARC 0.12 to 1.0 */
|
||||
ver = warc_read_version(buf, eoh - buf);
|
||||
/* Only WARC 0.12 through WARC 1.0 are supported. */
|
||||
if (ver == 0U) {
|
||||
archive_set_error(
|
||||
&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
@@ -269,78 +276,73 @@ start_over:
|
||||
ver / 10000, (ver % 10000) / 100);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
cntlen = _warc_rdlen(buf, eoh - buf);
|
||||
cntlen = warc_read_length(buf, eoh - buf);
|
||||
if (cntlen < 0) {
|
||||
/* nightmare! the specs say content-length is mandatory
|
||||
* so I don't feel overly bad stopping the reader here */
|
||||
/* This reader requires Content-Length before processing a record. */
|
||||
archive_set_error(
|
||||
&a->archive, EINVAL,
|
||||
"Bad content length");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rtime = _warc_rdrtm(buf, eoh - buf);
|
||||
rtime = warc_read_date(buf, eoh - buf);
|
||||
if (rtime == (time_t)-1) {
|
||||
/* record time is mandatory as per WARC/1.0,
|
||||
* so just barf here, fast and loud */
|
||||
/* This reader requires WARC-Date before processing a record. */
|
||||
archive_set_error(
|
||||
&a->archive, EINVAL,
|
||||
"Bad record time");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/* let the world know we're a WARC archive */
|
||||
/* Report this archive as WARC. */
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_WARC;
|
||||
if (ver != w->pver) {
|
||||
/* stringify this entry's version */
|
||||
archive_string_sprintf(&w->sver,
|
||||
if (ver != warc->pver) {
|
||||
/* Format this entry's WARC version. */
|
||||
archive_string_sprintf(&warc->sver,
|
||||
"WARC/%u.%u", ver / 10000, (ver % 10000) / 100);
|
||||
/* remember the version */
|
||||
w->pver = ver;
|
||||
/* Remember the version for later entries. */
|
||||
warc->pver = ver;
|
||||
}
|
||||
/* start off with the type */
|
||||
ftyp = _warc_rdtyp(buf, eoh - buf);
|
||||
/* and let future calls know about the content */
|
||||
w->cntlen = cntlen;
|
||||
w->cntoff = 0U;
|
||||
mtime = 0;/* Avoid compiling error on some platform. */
|
||||
/* Parse the record type. */
|
||||
ftyp = warc_read_type(buf, eoh - buf);
|
||||
/* Save content state for subsequent read calls. */
|
||||
warc->cntlen = cntlen;
|
||||
warc->cntoff = 0;
|
||||
mtime = 0;/* Avoid compiler warnings on some platforms. */
|
||||
|
||||
switch (ftyp) {
|
||||
case WT_RSRC:
|
||||
case WT_RSP:
|
||||
/* only try and read the filename in the cases that are
|
||||
* guaranteed to have one */
|
||||
fnam = _warc_rduri(buf, eoh - buf);
|
||||
/* check the last character in the URI to avoid creating
|
||||
* directory endpoints as files, see Todo above */
|
||||
/* Read the filename only for record types that are expected to
|
||||
* have a target URI. */
|
||||
fnam = warc_read_uri(buf, eoh - buf);
|
||||
/* Avoid creating directory endpoints as files. */
|
||||
if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {
|
||||
/* break here for now */
|
||||
/* Skip this record. */
|
||||
fnam.len = 0U;
|
||||
fnam.str = NULL;
|
||||
break;
|
||||
}
|
||||
/* bang to our string pool, so we save a
|
||||
* malloc()+free() roundtrip */
|
||||
if (fnam.len + 1U > w->pool.len) {
|
||||
w->pool.len = ((fnam.len + 64U) / 64U) * 64U;
|
||||
tmp = realloc(w->pool.str, w->pool.len);
|
||||
/* Copy the name into the reusable string pool to avoid a malloc/free
|
||||
* roundtrip for each entry. */
|
||||
if (fnam.len + 1U > warc->pool.len) {
|
||||
warc->pool.len = ((fnam.len + 64U) / 64U) * 64U;
|
||||
tmp = realloc(warc->pool.str, warc->pool.len);
|
||||
if (tmp == NULL) {
|
||||
archive_set_error(
|
||||
&a->archive, ENOMEM,
|
||||
"Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
w->pool.str = tmp;
|
||||
warc->pool.str = tmp;
|
||||
}
|
||||
memcpy(w->pool.str, fnam.str, fnam.len);
|
||||
w->pool.str[fnam.len] = '\0';
|
||||
/* let no one else know about the pool, it's a secret, shhh */
|
||||
fnam.str = w->pool.str;
|
||||
memcpy(warc->pool.str, fnam.str, fnam.len);
|
||||
warc->pool.str[fnam.len] = '\0';
|
||||
/* Hide the pool implementation behind the parsed string. */
|
||||
fnam.str = warc->pool.str;
|
||||
|
||||
/* snarf mtime or deduce from rtime
|
||||
* this is a custom header added by our writer, it's quite
|
||||
* hard to believe anyone else would go through with it
|
||||
* (apart from being part of some http responses of course) */
|
||||
if ((mtime = _warc_rdmtm(buf, eoh - buf)) == (time_t)-1) {
|
||||
/* Use a Last-Modified record header when present; otherwise fall back
|
||||
* to WARC-Date. */
|
||||
if ((mtime = warc_read_last_modified(buf, eoh - buf)) == (time_t)-1) {
|
||||
mtime = rtime;
|
||||
}
|
||||
break;
|
||||
@@ -358,19 +360,19 @@ start_over:
|
||||
break;
|
||||
}
|
||||
|
||||
/* now eat some of those delicious buffer bits */
|
||||
/* Consume the record header. */
|
||||
__archive_read_consume(a, eoh - buf);
|
||||
|
||||
switch (ftyp) {
|
||||
case WT_RSRC:
|
||||
case WT_RSP:
|
||||
if (fnam.len > 0U) {
|
||||
/* populate entry object */
|
||||
/* Populate the entry object. */
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
archive_entry_copy_pathname(entry, fnam.str);
|
||||
archive_entry_set_size(entry, cntlen);
|
||||
archive_entry_set_perm(entry, 0644);
|
||||
/* rtime is the new ctime, mtime stays mtime */
|
||||
/* WARC-Date becomes ctime; mtime comes from Last-Modified or WARC-Date. */
|
||||
archive_entry_set_ctime(entry, rtime, 0L);
|
||||
archive_entry_set_mtime(entry, mtime, 0L);
|
||||
break;
|
||||
@@ -385,8 +387,8 @@ start_over:
|
||||
case WT_CONT:
|
||||
case LAST_WT:
|
||||
default:
|
||||
/* consume the content and start over */
|
||||
if (_warc_skip(a) < 0)
|
||||
/* Skip this record body and look for the next one. */
|
||||
if (archive_read_format_warc_skip(a) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
goto start_over;
|
||||
}
|
||||
@@ -394,62 +396,69 @@ start_over:
|
||||
}
|
||||
|
||||
static int
|
||||
_warc_read(struct archive_read *a, const void **buf, size_t *bsz, int64_t *off)
|
||||
archive_read_format_warc_read_data(struct archive_read *a, const void **buf,
|
||||
size_t *bsz, int64_t *off)
|
||||
{
|
||||
struct warc_s *w = a->format->data;
|
||||
struct warc *warc = a->format->data;
|
||||
const char *rab;
|
||||
ssize_t nrd;
|
||||
|
||||
if (w->cntoff >= w->cntlen) {
|
||||
eof:
|
||||
/* it's our lucky day, no work, we can leave early */
|
||||
*buf = NULL;
|
||||
*bsz = 0U;
|
||||
*off = w->cntoff;
|
||||
w->unconsumed = 0U;
|
||||
return (ARCHIVE_EOF);
|
||||
if (warc->unconsumed) {
|
||||
__archive_read_consume(a, warc->unconsumed);
|
||||
warc->unconsumed = 0;
|
||||
}
|
||||
|
||||
if (w->unconsumed) {
|
||||
__archive_read_consume(a, w->unconsumed);
|
||||
w->unconsumed = 0U;
|
||||
if (warc->cntoff >= warc->cntlen) {
|
||||
/* No data is available to return for this entry. */
|
||||
*buf = NULL;
|
||||
*bsz = 0U;
|
||||
*off = warc->cntoff;
|
||||
return (ARCHIVE_EOF);
|
||||
}
|
||||
|
||||
rab = __archive_read_ahead(a, 1U, &nrd);
|
||||
if (nrd < 0) {
|
||||
*bsz = 0U;
|
||||
/* big catastrophe */
|
||||
/* Propagate the read error. */
|
||||
return (int)nrd;
|
||||
} else if (nrd == 0) {
|
||||
goto eof;
|
||||
} else if ((size_t)nrd > w->cntlen - w->cntoff) {
|
||||
/* clamp to content-length */
|
||||
nrd = w->cntlen - w->cntoff;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated WARC file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
} else if ((int64_t)nrd > warc->cntlen - warc->cntoff) {
|
||||
/* Clamp reads to Content-Length. */
|
||||
nrd = warc->cntlen - warc->cntoff;
|
||||
}
|
||||
*off = w->cntoff;
|
||||
*off = warc->cntoff;
|
||||
*bsz = nrd;
|
||||
*buf = rab;
|
||||
|
||||
w->cntoff += nrd;
|
||||
w->unconsumed = (size_t)nrd;
|
||||
warc->cntoff += nrd;
|
||||
warc->unconsumed = nrd;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
_warc_skip(struct archive_read *a)
|
||||
archive_read_format_warc_skip(struct archive_read *a)
|
||||
{
|
||||
struct warc_s *w = a->format->data;
|
||||
struct warc *warc = a->format->data;
|
||||
|
||||
if (__archive_read_consume(a, w->cntlen) < 0 ||
|
||||
if (warc->cntoff > warc->cntlen)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (warc->unconsumed) {
|
||||
__archive_read_consume(a, warc->unconsumed);
|
||||
warc->unconsumed = 0;
|
||||
}
|
||||
if (__archive_read_consume(a, warc->cntlen - warc->cntoff) < 0 ||
|
||||
__archive_read_consume(a, 4U/*\r\n\r\n separator*/) < 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
w->cntlen = 0U;
|
||||
w->cntoff = 0U;
|
||||
warc->cntlen = 0;
|
||||
warc->cntoff = 0;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
|
||||
/* private routines */
|
||||
/* Private routines */
|
||||
static void*
|
||||
deconst(const void *c)
|
||||
{
|
||||
@@ -469,44 +478,41 @@ xmemmem(const char *hay, const size_t haysize,
|
||||
unsigned int nsum;
|
||||
unsigned int eqp;
|
||||
|
||||
/* trivial checks first
|
||||
* a 0-sized needle is defined to be found anywhere in haystack
|
||||
* then run strchr() to find a candidate in HAYSTACK (i.e. a portion
|
||||
* that happens to begin with *NEEDLE) */
|
||||
/* Handle trivial cases first. A zero-sized needle is defined to be
|
||||
* found anywhere in the haystack; otherwise find the first candidate
|
||||
* that begins with *NEEDLE. */
|
||||
if (needlesize == 0UL) {
|
||||
return deconst(hay);
|
||||
} else if ((hay = memchr(hay, *needle, haysize)) == NULL) {
|
||||
/* trivial */
|
||||
/* No candidate match remains. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* First characters of haystack and needle are the same now. Both are
|
||||
* guaranteed to be at least one character long. Now computes the sum
|
||||
* of characters values of needle together with the sum of the first
|
||||
* needle_len characters of haystack. */
|
||||
/* The first characters of haystack and needle already match, and both
|
||||
* strings are at least one character long. Compute the rolling XOR
|
||||
* values for the needle and the first NEEDLESIZE characters of haystack. */
|
||||
for (hp = hay + 1U, np = needle + 1U, hsum = *hay, nsum = *hay, eqp = 1U;
|
||||
hp < eoh && np < eon;
|
||||
hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++);
|
||||
|
||||
/* HP now references the (NEEDLESIZE + 1)-th character. */
|
||||
if (np < eon) {
|
||||
/* haystack is smaller than needle, :O */
|
||||
/* The haystack is smaller than the needle. */
|
||||
return NULL;
|
||||
} else if (eqp) {
|
||||
/* found a match */
|
||||
/* Found a match. */
|
||||
return deconst(hay);
|
||||
}
|
||||
|
||||
/* now loop through the rest of haystack,
|
||||
* updating the sum iteratively */
|
||||
/* Loop through the rest of the haystack and update the rolling XOR
|
||||
* iteratively. */
|
||||
for (cand = hay; hp < eoh; hp++) {
|
||||
hsum ^= *cand++;
|
||||
hsum ^= *hp;
|
||||
|
||||
/* Since the sum of the characters is already known to be
|
||||
* equal at that point, it is enough to check just NEEDLESIZE - 1
|
||||
* characters for equality,
|
||||
* also CAND is by design < HP, so no need for range checks */
|
||||
/* When the rolling XOR values match, it is enough to check
|
||||
* NEEDLESIZE - 1 characters for equality. CAND is always before
|
||||
* HP by design, so no range check is needed. */
|
||||
if (hsum == nsum && memcmp(cand, needle, needlesize - 1U) == 0) {
|
||||
return deconst(cand);
|
||||
}
|
||||
@@ -519,7 +525,7 @@ strtoi_lim(const char *str, const char **ep, int llim, int ulim)
|
||||
{
|
||||
int res = 0;
|
||||
const char *sp;
|
||||
/* we keep track of the number of digits via rulim */
|
||||
/* Track the number of digits with rulim. */
|
||||
int rulim;
|
||||
|
||||
for (sp = str, rulim = ulim > 10 ? ulim : 10;
|
||||
@@ -546,11 +552,11 @@ time_from_tm(struct tm *t)
|
||||
/* Use platform timegm() if available. */
|
||||
return (timegm(t));
|
||||
#else
|
||||
/* Else use direct calculation using POSIX assumptions. */
|
||||
/* First, fix up tm_yday based on the year/month/day. */
|
||||
/* Otherwise, calculate directly using POSIX assumptions. */
|
||||
/* First, fix up tm_yday based on the year, month, and day. */
|
||||
if (mktime(t) == (time_t)-1)
|
||||
return ((time_t)-1);
|
||||
/* Then we can compute timegm() from first principles. */
|
||||
/* Then compute timegm() from first principles. */
|
||||
return (t->tm_sec
|
||||
+ t->tm_min * 60
|
||||
+ t->tm_hour * 3600
|
||||
@@ -565,48 +571,48 @@ time_from_tm(struct tm *t)
|
||||
static time_t
|
||||
xstrpisotime(const char *s, char **endptr)
|
||||
{
|
||||
/** like strptime() but strictly for ISO 8601 Zulu strings */
|
||||
/* Like strptime(), but only for ISO 8601 Zulu strings. */
|
||||
struct tm tm;
|
||||
time_t res = (time_t)-1;
|
||||
|
||||
/* make sure tm is clean */
|
||||
/* Clear the tm structure. */
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
|
||||
/* as a courtesy to our callers, and since this is a non-standard
|
||||
* routine, we skip leading whitespace */
|
||||
/* This is a non-standard routine, so skip leading whitespace for
|
||||
* caller convenience. */
|
||||
while (*s == ' ' || *s == '\t')
|
||||
++s;
|
||||
|
||||
/* read year */
|
||||
/* Read the year. */
|
||||
if ((tm.tm_year = strtoi_lim(s, &s, 1583, 4095)) < 0 || *s++ != '-') {
|
||||
goto out;
|
||||
}
|
||||
/* read month */
|
||||
/* Read the month. */
|
||||
if ((tm.tm_mon = strtoi_lim(s, &s, 1, 12)) < 0 || *s++ != '-') {
|
||||
goto out;
|
||||
}
|
||||
/* read day-of-month */
|
||||
/* Read the day of the month. */
|
||||
if ((tm.tm_mday = strtoi_lim(s, &s, 1, 31)) < 0 || *s++ != 'T') {
|
||||
goto out;
|
||||
}
|
||||
/* read hour */
|
||||
/* Read the hour. */
|
||||
if ((tm.tm_hour = strtoi_lim(s, &s, 0, 23)) < 0 || *s++ != ':') {
|
||||
goto out;
|
||||
}
|
||||
/* read minute */
|
||||
/* Read the minute. */
|
||||
if ((tm.tm_min = strtoi_lim(s, &s, 0, 59)) < 0 || *s++ != ':') {
|
||||
goto out;
|
||||
}
|
||||
/* read second */
|
||||
/* Read the second. */
|
||||
if ((tm.tm_sec = strtoi_lim(s, &s, 0, 60)) < 0 || *s++ != 'Z') {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* massage TM to fulfill some of POSIX' constraints */
|
||||
/* Adjust tm fields to satisfy POSIX constraints. */
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon--;
|
||||
|
||||
/* now convert our custom tm struct to a unix stamp using UTC */
|
||||
/* Convert the tm structure to a Unix timestamp in UTC. */
|
||||
res = time_from_tm(&tm);
|
||||
|
||||
out:
|
||||
@@ -616,8 +622,14 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
warc_isdigit(const char c)
|
||||
{
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
_warc_rdver(const char *buf, size_t bsz)
|
||||
warc_read_version(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char magic[] = "WARC/";
|
||||
const char *c;
|
||||
@@ -625,35 +637,34 @@ _warc_rdver(const char *buf, size_t bsz)
|
||||
unsigned int end = 0U;
|
||||
|
||||
if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) {
|
||||
/* buffer too small or invalid magic */
|
||||
/* Buffer too small or invalid magic. */
|
||||
return ver;
|
||||
}
|
||||
/* looks good so far, read the version number for a laugh */
|
||||
/* Parse the version number. */
|
||||
buf += sizeof(magic) - 1U;
|
||||
|
||||
if (isdigit((unsigned char)buf[0U]) && (buf[1U] == '.') &&
|
||||
isdigit((unsigned char)buf[2U])) {
|
||||
/* we support a maximum of 2 digits in the minor version */
|
||||
if (isdigit((unsigned char)buf[3U]))
|
||||
if (warc_isdigit(buf[0]) && buf[1] == '.' && warc_isdigit(buf[2])) {
|
||||
/* Support at most two digits in the minor version. */
|
||||
if (warc_isdigit(buf[3]))
|
||||
end = 1U;
|
||||
/* set up major version */
|
||||
/* Set up the major version. */
|
||||
ver = (buf[0U] - '0') * 10000U;
|
||||
/* set up minor version */
|
||||
/* Set up the minor version. */
|
||||
if (end == 1U) {
|
||||
ver += (buf[2U] - '0') * 1000U;
|
||||
ver += (buf[3U] - '0') * 100U;
|
||||
} else
|
||||
ver += (buf[2U] - '0') * 100U;
|
||||
/*
|
||||
* WARC below version 0.12 has a space-separated header
|
||||
* WARC 0.12 and above terminates the version with a CRLF
|
||||
* WARC versions before 0.12 use a space-separated header.
|
||||
* WARC 0.12 and later terminate the version with CRLF.
|
||||
*/
|
||||
c = buf + 3U + end;
|
||||
if (ver >= 1200U) {
|
||||
if (memcmp(c, "\r\n", 2U) != 0)
|
||||
ver = 0U;
|
||||
} else {
|
||||
/* ver < 1200U */
|
||||
/* Version is below WARC 0.12. */
|
||||
if (*c != ' ' && *c != '\t')
|
||||
ver = 0U;
|
||||
}
|
||||
@@ -662,22 +673,22 @@ _warc_rdver(const char *buf, size_t bsz)
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
_warc_rdtyp(const char *buf, size_t bsz)
|
||||
warc_read_type(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nWARC-Type:";
|
||||
const char *val, *eol;
|
||||
|
||||
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
|
||||
/* no bother */
|
||||
/* Header field is absent. */
|
||||
return WT_NONE;
|
||||
}
|
||||
val += sizeof(_key) - 1U;
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* no end of line */
|
||||
if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* Header field has no end of line. */
|
||||
return WT_NONE;
|
||||
}
|
||||
|
||||
/* overread whitespace */
|
||||
/* Skip leading whitespace. */
|
||||
while (val < eol && (*val == ' ' || *val == '\t'))
|
||||
++val;
|
||||
|
||||
@@ -691,55 +702,55 @@ _warc_rdtyp(const char *buf, size_t bsz)
|
||||
}
|
||||
|
||||
static warc_string_t
|
||||
_warc_rduri(const char *buf, size_t bsz)
|
||||
warc_read_uri(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nWARC-Target-URI:";
|
||||
const char *val, *uri, *eol, *p;
|
||||
warc_string_t res = {0U, NULL};
|
||||
|
||||
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
|
||||
/* no bother */
|
||||
/* Header field is absent. */
|
||||
return res;
|
||||
}
|
||||
/* overread whitespace */
|
||||
/* Skip leading whitespace. */
|
||||
val += sizeof(_key) - 1U;
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* no end of line */
|
||||
if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* Header field has no end of line. */
|
||||
return res;
|
||||
}
|
||||
|
||||
while (val < eol && (*val == ' ' || *val == '\t'))
|
||||
++val;
|
||||
|
||||
/* overread URL designators */
|
||||
/* Locate the :// separator. */
|
||||
if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {
|
||||
/* not touching that! */
|
||||
/* Ignore values without a :// separator. */
|
||||
return res;
|
||||
}
|
||||
|
||||
/* spaces inside uri are not allowed, CRLF should follow */
|
||||
/* Spaces inside a URI are not allowed; CRLF should follow. */
|
||||
for (p = val; p < eol; p++) {
|
||||
if (isspace((unsigned char)*p))
|
||||
return res;
|
||||
}
|
||||
|
||||
/* there must be at least space for ftp */
|
||||
/* Require enough room for the shortest supported scheme. */
|
||||
if (uri < (val + 3U))
|
||||
return res;
|
||||
|
||||
/* move uri to point to after :// */
|
||||
/* Move uri past the :// separator. */
|
||||
uri += 3U;
|
||||
|
||||
/* now then, inspect the URI */
|
||||
/* Inspect the scheme prefix. */
|
||||
if (memcmp(val, "file", 4U) == 0) {
|
||||
/* perfect, nothing left to do here */
|
||||
/* Keep file:// paths as-is. */
|
||||
|
||||
} else if (memcmp(val, "http", 4U) == 0 ||
|
||||
memcmp(val, "ftp", 3U) == 0) {
|
||||
/* overread domain, and the first / */
|
||||
/* Skip the domain and the first slash. */
|
||||
while (uri < eol && *uri++ != '/');
|
||||
} else {
|
||||
/* not sure what to do? best to bugger off */
|
||||
/* Unsupported URI scheme. */
|
||||
return res;
|
||||
}
|
||||
res.str = uri;
|
||||
@@ -747,42 +758,49 @@ _warc_rduri(const char *buf, size_t bsz)
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
_warc_rdlen(const char *buf, size_t bsz)
|
||||
static int64_t
|
||||
warc_read_length(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nContent-Length:";
|
||||
const char *val, *eol;
|
||||
char *on = NULL;
|
||||
long int len;
|
||||
const char *val, *eol, *p;
|
||||
int64_t len;
|
||||
|
||||
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
|
||||
/* no bother */
|
||||
/* Header field is absent. */
|
||||
return -1;
|
||||
}
|
||||
val += sizeof(_key) - 1U;
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* no end of line */
|
||||
|
||||
if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* Malformed field with no end of line. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* skip leading whitespace */
|
||||
/* Skip leading whitespace. */
|
||||
while (val < eol && (*val == ' ' || *val == '\t'))
|
||||
val++;
|
||||
/* there must be at least one digit */
|
||||
if (!isdigit((unsigned char)*val))
|
||||
return -1;
|
||||
errno = 0;
|
||||
len = strtol(val, &on, 10);
|
||||
if (errno != 0 || on != eol) {
|
||||
/* line must end here */
|
||||
|
||||
/* Require at least one digit. */
|
||||
if (val >= eol || *val < '0' || *val > '9')
|
||||
return -1;
|
||||
|
||||
len = 0;
|
||||
for (p = val; p < eol; p++) {
|
||||
int64_t digit;
|
||||
|
||||
if (*p < '0' || *p > '9')
|
||||
return -1;
|
||||
digit = *p - '0';
|
||||
if (archive_ckd_mul_i64(&len, len, 10) ||
|
||||
archive_ckd_add_i64(&len, len, digit))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (size_t)len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static time_t
|
||||
_warc_rdrtm(const char *buf, size_t bsz)
|
||||
warc_read_date(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nWARC-Date:";
|
||||
const char *val, *eol;
|
||||
@@ -790,26 +808,26 @@ _warc_rdrtm(const char *buf, size_t bsz)
|
||||
time_t res;
|
||||
|
||||
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
|
||||
/* no bother */
|
||||
/* Header field is absent. */
|
||||
return (time_t)-1;
|
||||
}
|
||||
val += sizeof(_key) - 1U;
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
|
||||
/* no end of line */
|
||||
if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {
|
||||
/* Header field has no end of line. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* xstrpisotime() kindly overreads whitespace for us, so use that */
|
||||
/* xstrpisotime() skips leading whitespace. */
|
||||
res = xstrpisotime(val, &on);
|
||||
if (on != eol) {
|
||||
/* line must end here */
|
||||
/* The field must end here. */
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static time_t
|
||||
_warc_rdmtm(const char *buf, size_t bsz)
|
||||
warc_read_last_modified(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nLast-Modified:";
|
||||
const char *val, *eol;
|
||||
@@ -817,26 +835,26 @@ _warc_rdmtm(const char *buf, size_t bsz)
|
||||
time_t res;
|
||||
|
||||
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
|
||||
/* no bother */
|
||||
/* Header field is absent. */
|
||||
return (time_t)-1;
|
||||
}
|
||||
val += sizeof(_key) - 1U;
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
|
||||
/* no end of line */
|
||||
if ((eol = warc_find_eol(val, buf + bsz - val)) == NULL ) {
|
||||
/* Header field has no end of line. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* xstrpisotime() kindly overreads whitespace for us, so use that */
|
||||
/* xstrpisotime() skips leading whitespace. */
|
||||
res = xstrpisotime(val, &on);
|
||||
if (on != eol) {
|
||||
/* line must end here */
|
||||
/* The field must end here. */
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char*
|
||||
_warc_find_eoh(const char *buf, size_t bsz)
|
||||
static const char *
|
||||
warc_find_eoh(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _marker[] = "\r\n\r\n";
|
||||
const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);
|
||||
@@ -847,12 +865,11 @@ _warc_find_eoh(const char *buf, size_t bsz)
|
||||
return hit;
|
||||
}
|
||||
|
||||
static const char*
|
||||
_warc_find_eol(const char *buf, size_t bsz)
|
||||
static const char *
|
||||
warc_find_eol(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _marker[] = "\r\n";
|
||||
const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);
|
||||
|
||||
return hit;
|
||||
}
|
||||
/* archive_read_support_format_warc.c ends here */
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "archive_endian.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_read_private.h"
|
||||
|
||||
@@ -107,10 +108,14 @@ archive_read_support_format_xar(struct archive *_a)
|
||||
#define CKSUM_NONE 0
|
||||
#define CKSUM_SHA1 1
|
||||
#define CKSUM_MD5 2
|
||||
#define CKSUM_SHA256 3
|
||||
#define CKSUM_SHA512 4
|
||||
|
||||
#define MD5_SIZE 16
|
||||
#define SHA1_SIZE 20
|
||||
#define MAX_SUM_SIZE 20
|
||||
#define SHA256_SIZE 32
|
||||
#define SHA512_SIZE 64
|
||||
#define MAX_SUM_SIZE 64
|
||||
|
||||
enum enctype {
|
||||
NONE,
|
||||
@@ -134,6 +139,12 @@ struct chksumwork {
|
||||
#ifdef ARCHIVE_HAS_SHA1
|
||||
archive_sha1_ctx sha1ctx;
|
||||
#endif
|
||||
#ifdef ARCHIVE_HAS_SHA256
|
||||
archive_sha256_ctx sha256ctx;
|
||||
#endif
|
||||
#ifdef ARCHIVE_HAS_SHA512
|
||||
archive_sha512_ctx sha512ctx;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct xattr {
|
||||
@@ -213,8 +224,8 @@ struct hdlink {
|
||||
|
||||
struct heap_queue {
|
||||
struct xar_file **files;
|
||||
int allocated;
|
||||
int used;
|
||||
size_t allocated;
|
||||
size_t used;
|
||||
};
|
||||
|
||||
enum xmlstatus {
|
||||
@@ -387,8 +398,7 @@ static int rd_contents_init(struct archive_read *,
|
||||
enum enctype, int, int);
|
||||
static int rd_contents(struct archive_read *, const void **,
|
||||
size_t *, size_t *, uint64_t);
|
||||
static uint64_t atol10(const char *, size_t);
|
||||
static int64_t atol8(const char *, size_t);
|
||||
static int atou64(const char *, size_t, int, uint64_t *);
|
||||
static size_t atohex(unsigned char *, size_t, const char *, size_t);
|
||||
static time_t parse_time(const char *p, size_t n);
|
||||
static int heap_add_entry(struct archive_read *a,
|
||||
@@ -396,7 +406,7 @@ static int heap_add_entry(struct archive_read *a,
|
||||
static struct xar_file *heap_get_entry(struct heap_queue *);
|
||||
static int add_link(struct archive_read *,
|
||||
struct xar *, struct xar_file *);
|
||||
static void checksum_init(struct archive_read *, int, int);
|
||||
static int checksum_init(struct archive_read *, int, int);
|
||||
static void checksum_update(struct archive_read *, const void *,
|
||||
size_t, const void *, size_t);
|
||||
static int checksum_final(struct archive_read *, const void *,
|
||||
@@ -421,7 +431,7 @@ static void unknowntag_end(struct xar *, const char *);
|
||||
static int xml_start(struct archive_read *,
|
||||
const char *, struct xmlattr_list *);
|
||||
static void xml_end(void *, const char *);
|
||||
static void xml_data(void *, const char *, size_t);
|
||||
static int xml_data(void *, const char *, size_t);
|
||||
static int xml_parse_file_flags(struct xar *, const char *);
|
||||
static int xml_parse_file_ext2(struct xar *, const char *);
|
||||
#if defined(HAVE_LIBXML_XMLREADER_H)
|
||||
@@ -524,6 +534,8 @@ xar_bid(struct archive_read *a, int best_bid)
|
||||
case CKSUM_NONE:
|
||||
case CKSUM_SHA1:
|
||||
case CKSUM_MD5:
|
||||
case CKSUM_SHA256:
|
||||
case CKSUM_SHA512:
|
||||
bid += 32;
|
||||
break;
|
||||
default:
|
||||
@@ -536,7 +548,7 @@ xar_bid(struct archive_read *a, int best_bid)
|
||||
static int
|
||||
read_toc(struct archive_read *a)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
struct xar_file *file;
|
||||
const unsigned char *b;
|
||||
uint64_t toc_compressed_size;
|
||||
@@ -545,8 +557,6 @@ read_toc(struct archive_read *a)
|
||||
ssize_t bytes;
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
/*
|
||||
* Read xar header.
|
||||
*/
|
||||
@@ -674,12 +684,11 @@ read_toc(struct archive_read *a)
|
||||
static int
|
||||
xar_read_header(struct archive_read *a, struct archive_entry *entry)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
struct xar_file *file;
|
||||
struct xattr *xattr;
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
r = ARCHIVE_OK;
|
||||
|
||||
if (xar->offset == 0) {
|
||||
@@ -729,11 +738,12 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Gname");
|
||||
file_free(file);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Gname cannot be converted from %s to current locale.",
|
||||
"Gname cannot be converted from %s to current locale",
|
||||
archive_string_conversion_charset_name(xar->sconv));
|
||||
r = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -744,11 +754,12 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Uname");
|
||||
file_free(file);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Uname cannot be converted from %s to current locale.",
|
||||
"Uname cannot be converted from %s to current locale",
|
||||
archive_string_conversion_charset_name(xar->sconv));
|
||||
r = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -758,11 +769,12 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Pathname");
|
||||
file_free(file);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted from %s to current locale.",
|
||||
"Pathname cannot be converted from %s to current locale",
|
||||
archive_string_conversion_charset_name(xar->sconv));
|
||||
r = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -774,11 +786,12 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Linkname");
|
||||
file_free(file);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Linkname cannot be converted from %s to current locale.",
|
||||
"Linkname cannot be converted from %s to current locale",
|
||||
archive_string_conversion_charset_name(xar->sconv));
|
||||
r = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -874,12 +887,10 @@ static int
|
||||
xar_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
size_t used = 0;
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
if (xar->entry_unconsumed) {
|
||||
__archive_read_consume(a, xar->entry_unconsumed);
|
||||
xar->entry_unconsumed = 0;
|
||||
@@ -937,10 +948,9 @@ abort_read_data:
|
||||
static int
|
||||
xar_read_data_skip(struct archive_read *a)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
int64_t bytes_skipped;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
if (xar->end_of_file)
|
||||
return (ARCHIVE_EOF);
|
||||
bytes_skipped = __archive_read_consume(a, xar->entry_remaining +
|
||||
@@ -955,12 +965,11 @@ xar_read_data_skip(struct archive_read *a)
|
||||
static int
|
||||
xar_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
struct hdlink *hdlink;
|
||||
int i;
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
checksum_cleanup(a);
|
||||
r = decompression_cleanup(a);
|
||||
hdlink = xar->hdlink_list;
|
||||
@@ -990,9 +999,8 @@ xar_cleanup(struct archive_read *a)
|
||||
static int
|
||||
move_reading_point(struct archive_read *a, uint64_t offset)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
if (xar->offset - xar->h_base != offset) {
|
||||
/* Seek forward to the start of file contents. */
|
||||
int64_t step;
|
||||
@@ -1008,7 +1016,7 @@ move_reading_point(struct archive_read *a, uint64_t offset)
|
||||
if (pos == ARCHIVE_FAILED) {
|
||||
archive_set_error(&(a->archive),
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Cannot seek.");
|
||||
"Cannot seek");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
xar->offset = pos;
|
||||
@@ -1027,8 +1035,7 @@ rd_contents_init(struct archive_read *a, enum enctype encoding,
|
||||
if ((r = decompression_init(a, encoding)) != ARCHIVE_OK)
|
||||
return (r);
|
||||
/* Init checksum library. */
|
||||
checksum_init(a, a_sum_alg, e_sum_alg);
|
||||
return (ARCHIVE_OK);
|
||||
return (checksum_init(a, a_sum_alg, e_sum_alg));
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1071,44 +1078,24 @@ rd_contents(struct archive_read *a, const void **buff, size_t *size,
|
||||
* it does obey locale.
|
||||
*/
|
||||
|
||||
static uint64_t
|
||||
atol10(const char *p, size_t char_cnt)
|
||||
static int
|
||||
atou64(const char *p, size_t char_cnt, int base, uint64_t *val)
|
||||
{
|
||||
uint64_t l;
|
||||
int digit;
|
||||
|
||||
if (char_cnt == 0)
|
||||
return (0);
|
||||
|
||||
l = 0;
|
||||
digit = *p - '0';
|
||||
while (digit >= 0 && digit < 10 && char_cnt-- > 0) {
|
||||
l = (l * 10) + digit;
|
||||
digit = *++p - '0';
|
||||
}
|
||||
return (l);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
atol8(const char *p, size_t char_cnt)
|
||||
{
|
||||
int64_t l;
|
||||
int digit;
|
||||
|
||||
if (char_cnt == 0)
|
||||
return (0);
|
||||
|
||||
l = 0;
|
||||
while (char_cnt-- > 0) {
|
||||
if (*p >= '0' && *p <= '7')
|
||||
digit = *p - '0';
|
||||
else
|
||||
int digit = *p++ - '0';
|
||||
|
||||
if (digit < 0 || digit >= base)
|
||||
break;
|
||||
p++;
|
||||
l <<= 3;
|
||||
l |= digit;
|
||||
if (archive_ckd_mul_u64(&l, l, base) ||
|
||||
archive_ckd_add_u64(&l, l, digit))
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (l);
|
||||
|
||||
*val = l;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static size_t
|
||||
@@ -1173,48 +1160,42 @@ parse_time(const char *p, size_t n)
|
||||
{
|
||||
struct tm tm;
|
||||
time_t t = 0;
|
||||
int64_t data;
|
||||
uint64_t data;
|
||||
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
if (n != 20)
|
||||
return (t);
|
||||
data = atol10(p, 4);
|
||||
if (data < 1900)
|
||||
if (atou64(p, 4, 10, &data) != ARCHIVE_OK || data < 1900)
|
||||
return (t);
|
||||
tm.tm_year = (int)data - 1900;
|
||||
p += 4;
|
||||
if (*p++ != '-')
|
||||
return (t);
|
||||
data = atol10(p, 2);
|
||||
if (data < 1 || data > 12)
|
||||
if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 12)
|
||||
return (t);
|
||||
tm.tm_mon = (int)data -1;
|
||||
p += 2;
|
||||
if (*p++ != '-')
|
||||
return (t);
|
||||
data = atol10(p, 2);
|
||||
if (data < 1 || data > 31)
|
||||
if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data < 1 || data > 31)
|
||||
return (t);
|
||||
tm.tm_mday = (int)data;
|
||||
p += 2;
|
||||
if (*p++ != 'T')
|
||||
return (t);
|
||||
data = atol10(p, 2);
|
||||
if (data < 0 || data > 23)
|
||||
if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 23)
|
||||
return (t);
|
||||
tm.tm_hour = (int)data;
|
||||
p += 2;
|
||||
if (*p++ != ':')
|
||||
return (t);
|
||||
data = atol10(p, 2);
|
||||
if (data < 0 || data > 59)
|
||||
if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 59)
|
||||
return (t);
|
||||
tm.tm_min = (int)data;
|
||||
p += 2;
|
||||
if (*p++ != ':')
|
||||
return (t);
|
||||
data = atol10(p, 2);
|
||||
if (data < 0 || data > 60)
|
||||
if (atou64(p, 2, 10, &data) != ARCHIVE_OK || data > 60)
|
||||
return (t);
|
||||
tm.tm_sec = (int)data;
|
||||
#if 0
|
||||
@@ -1233,19 +1214,17 @@ heap_add_entry(struct archive_read *a,
|
||||
struct heap_queue *heap, struct xar_file *file)
|
||||
{
|
||||
uint64_t file_id, parent_id;
|
||||
int hole, parent;
|
||||
size_t hole, parent;
|
||||
|
||||
/* Expand our pending files list as necessary. */
|
||||
if (heap->used >= heap->allocated) {
|
||||
struct xar_file **new_pending_files;
|
||||
int new_size;
|
||||
size_t new_size;
|
||||
|
||||
if (heap->allocated < 1024)
|
||||
new_size = 1024;
|
||||
else
|
||||
new_size = heap->allocated * 2;
|
||||
/* Overflow might keep us from growing the list. */
|
||||
if (new_size <= heap->allocated) {
|
||||
else if (archive_ckd_mul_size(&new_size, heap->allocated, 2)) {
|
||||
/* Overflow keeps us from growing the list. */
|
||||
archive_set_error(&a->archive,
|
||||
ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -1273,7 +1252,7 @@ heap_add_entry(struct archive_read *a,
|
||||
*/
|
||||
hole = heap->used++;
|
||||
while (hole > 0) {
|
||||
parent = (hole - 1)/2;
|
||||
parent = (hole - 1) / 2;
|
||||
parent_id = heap->files[parent]->id;
|
||||
if (file_id >= parent_id) {
|
||||
heap->files[hole] = file;
|
||||
@@ -1292,7 +1271,7 @@ static struct xar_file *
|
||||
heap_get_entry(struct heap_queue *heap)
|
||||
{
|
||||
uint64_t a_id, b_id, c_id;
|
||||
int a, b, c;
|
||||
size_t a, b, c;
|
||||
struct xar_file *r, *tmp;
|
||||
|
||||
if (heap->used < 1)
|
||||
@@ -1362,7 +1341,7 @@ add_link(struct archive_read *a, struct xar *xar, struct xar_file *file)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
_checksum_init(struct chksumwork *sumwrk, int sum_alg)
|
||||
{
|
||||
sumwrk->alg = sum_alg;
|
||||
@@ -1375,7 +1354,20 @@ _checksum_init(struct chksumwork *sumwrk, int sum_alg)
|
||||
case CKSUM_MD5:
|
||||
archive_md5_init(&(sumwrk->md5ctx));
|
||||
break;
|
||||
#ifdef ARCHIVE_HAS_SHA256
|
||||
case CKSUM_SHA256:
|
||||
archive_sha256_init(&(sumwrk->sha256ctx));
|
||||
break;
|
||||
#endif
|
||||
#ifdef ARCHIVE_HAS_SHA512
|
||||
case CKSUM_SHA512:
|
||||
archive_sha512_init(&(sumwrk->sha512ctx));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1391,6 +1383,16 @@ _checksum_update(struct chksumwork *sumwrk, const void *buff, size_t size)
|
||||
case CKSUM_MD5:
|
||||
archive_md5_update(&(sumwrk->md5ctx), buff, size);
|
||||
break;
|
||||
#ifdef ARCHIVE_HAS_SHA256
|
||||
case CKSUM_SHA256:
|
||||
archive_sha256_update(&(sumwrk->sha256ctx), buff, size);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ARCHIVE_HAS_SHA512
|
||||
case CKSUM_SHA512:
|
||||
archive_sha512_update(&(sumwrk->sha512ctx), buff, size);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1415,27 +1417,48 @@ _checksum_final(struct chksumwork *sumwrk, const void *val, size_t len)
|
||||
memcmp(val, sum, MD5_SIZE) != 0)
|
||||
r = ARCHIVE_FAILED;
|
||||
break;
|
||||
#ifdef ARCHIVE_HAS_SHA256
|
||||
case CKSUM_SHA256:
|
||||
archive_sha256_final(&(sumwrk->sha256ctx), sum);
|
||||
if (len != SHA256_SIZE ||
|
||||
memcmp(val, sum, SHA256_SIZE) != 0)
|
||||
r = ARCHIVE_FAILED;
|
||||
break;
|
||||
#endif
|
||||
#ifdef ARCHIVE_HAS_SHA512
|
||||
case CKSUM_SHA512:
|
||||
archive_sha512_final(&(sumwrk->sha512ctx), sum);
|
||||
if (len != SHA512_SIZE ||
|
||||
memcmp(val, sum, SHA512_SIZE) != 0)
|
||||
r = ARCHIVE_FAILED;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
r = ARCHIVE_FAILED;
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
checksum_init(struct archive_read *a, int a_sum_alg, int e_sum_alg)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
_checksum_init(&(xar->a_sumwrk), a_sum_alg);
|
||||
_checksum_init(&(xar->e_sumwrk), e_sum_alg);
|
||||
if (_checksum_init(&(xar->a_sumwrk), a_sum_alg) != ARCHIVE_OK ||
|
||||
_checksum_init(&(xar->e_sumwrk), e_sum_alg) != ARCHIVE_OK) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"Unsupported checksum");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
checksum_update(struct archive_read *a, const void *abuff, size_t asize,
|
||||
const void *ebuff, size_t esize)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
_checksum_update(&(xar->a_sumwrk), abuff, asize);
|
||||
_checksum_update(&(xar->e_sumwrk), ebuff, esize);
|
||||
}
|
||||
@@ -1444,27 +1467,24 @@ static int
|
||||
checksum_final(struct archive_read *a, const void *a_sum_val,
|
||||
size_t a_sum_len, const void *e_sum_val, size_t e_sum_len)
|
||||
{
|
||||
struct xar *xar;
|
||||
int r;
|
||||
struct xar *xar = a->format->data;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
r = _checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len);
|
||||
if (r == ARCHIVE_OK)
|
||||
r = _checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len);
|
||||
if (r != ARCHIVE_OK)
|
||||
if (_checksum_final(&(xar->a_sumwrk), a_sum_val, a_sum_len) != ARCHIVE_OK ||
|
||||
_checksum_final(&(xar->e_sumwrk), e_sum_val, e_sum_len) != ARCHIVE_OK) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"Sumcheck error");
|
||||
return (r);
|
||||
"Checksum error");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
decompression_init(struct archive_read *a, enum enctype encoding)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
const char *detail;
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
xar->rd_encoding = encoding;
|
||||
switch (encoding) {
|
||||
case NONE:
|
||||
@@ -1476,7 +1496,7 @@ decompression_init(struct archive_read *a, enum enctype encoding)
|
||||
r = inflateInit(&(xar->stream));
|
||||
if (r != Z_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Couldn't initialize zlib stream.");
|
||||
"Couldn't initialize zlib stream");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
xar->stream_valid = 1;
|
||||
@@ -1600,12 +1620,11 @@ static int
|
||||
decompress(struct archive_read *a, const void **buff, size_t *outbytes,
|
||||
const void *b, size_t *used)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
void *outbuff;
|
||||
size_t avail_in, avail_out;
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
avail_in = *used;
|
||||
outbuff = (void *)(uintptr_t)*buff;
|
||||
if (outbuff == NULL) {
|
||||
@@ -1691,7 +1710,7 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
|
||||
default:
|
||||
archive_set_error(&(a->archive),
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"%s decompression failed(%d)",
|
||||
"%s decompression failed (%d)",
|
||||
(xar->entry_encoding == XZ)?"xz":"lzma",
|
||||
r);
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -1728,10 +1747,9 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
|
||||
static int
|
||||
decompression_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
r = ARCHIVE_OK;
|
||||
if (xar->stream_valid) {
|
||||
if (inflateEnd(&(xar->stream)) != Z_OK) {
|
||||
@@ -1760,9 +1778,7 @@ decompression_cleanup(struct archive_read *a)
|
||||
|
||||
static void
|
||||
checksum_cleanup(struct archive_read *a) {
|
||||
struct xar *xar;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
struct xar *xar = a->format->data;
|
||||
|
||||
_checksum_final(&(xar->a_sumwrk), NULL, 0);
|
||||
_checksum_final(&(xar->e_sumwrk), NULL, 0);
|
||||
@@ -1800,15 +1816,26 @@ file_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
|
||||
file->mode = 0777 | AE_IFREG;
|
||||
file->atime = 0;
|
||||
file->mtime = 0;
|
||||
xar->file = file;
|
||||
xar->xattr = NULL;
|
||||
for (attr = list->first; attr != NULL; attr = attr->next) {
|
||||
if (strcmp(attr->name, "id") == 0)
|
||||
file->id = atol10(attr->value, strlen(attr->value));
|
||||
if (strcmp(attr->name, "id") == 0) {
|
||||
int r;
|
||||
|
||||
r = atou64(attr->value, strlen(attr->value),
|
||||
10, &file->id);
|
||||
if (r != ARCHIVE_OK) {
|
||||
free(file);
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
xar->file = file;
|
||||
file->nlink = 1;
|
||||
if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)
|
||||
if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK) {
|
||||
xar->file = file->parent;
|
||||
file_free(file);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -1822,6 +1849,7 @@ file_free(struct xar_file *file)
|
||||
archive_string_free(&(file->uname));
|
||||
archive_string_free(&(file->gname));
|
||||
archive_string_free(&(file->hardlink));
|
||||
archive_string_free(&(file->fflags_text));
|
||||
xattr = file->xattr_list;
|
||||
while (xattr != NULL) {
|
||||
struct xattr *next;
|
||||
@@ -1845,11 +1873,19 @@ xattr_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
xar->xattr = xattr;
|
||||
for (attr = list->first; attr != NULL; attr = attr->next) {
|
||||
if (strcmp(attr->name, "id") == 0)
|
||||
xattr->id = atol10(attr->value, strlen(attr->value));
|
||||
if (strcmp(attr->name, "id") == 0) {
|
||||
int r;
|
||||
|
||||
r = atou64(attr->value, strlen(attr->value),
|
||||
10, &xattr->id);
|
||||
if (r != ARCHIVE_OK) {
|
||||
free(xattr);
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
xar->xattr = xattr;
|
||||
/* Chain to xattr list. */
|
||||
for (nx = &(xar->file->xattr_list);
|
||||
*nx != NULL; nx = &((*nx)->next)) {
|
||||
@@ -1866,6 +1902,7 @@ static void
|
||||
xattr_free(struct xattr *xattr)
|
||||
{
|
||||
archive_string_free(&(xattr->name));
|
||||
archive_string_free(&(xattr->fstype));
|
||||
free(xattr);
|
||||
}
|
||||
|
||||
@@ -1903,9 +1940,16 @@ getsumalgorithm(struct xmlattr_list *list)
|
||||
const char *v = attr->value;
|
||||
if ((v[0] == 'S' || v[0] == 's') &&
|
||||
(v[1] == 'H' || v[1] == 'h') &&
|
||||
(v[2] == 'A' || v[2] == 'a') &&
|
||||
v[3] == '1' && v[4] == '\0')
|
||||
alg = CKSUM_SHA1;
|
||||
(v[2] == 'A' || v[2] == 'a')) {
|
||||
if (v[3] == '1' && v[4] == '\0')
|
||||
alg = CKSUM_SHA1;
|
||||
else if (v[3] == '2' && v[4] == '5' &&
|
||||
v[5] == '6' && v[6] == '\0')
|
||||
alg = CKSUM_SHA256;
|
||||
else if (v[3] == '5' && v[4] == '1' &&
|
||||
v[5] == '2' && v[6] == '\0')
|
||||
alg = CKSUM_SHA512;
|
||||
}
|
||||
if ((v[0] == 'M' || v[0] == 'm') &&
|
||||
(v[1] == 'D' || v[1] == 'd') &&
|
||||
v[2] == '5' && v[3] == '\0')
|
||||
@@ -1963,11 +2007,9 @@ unknowntag_end(struct xar *xar, const char *name)
|
||||
static int
|
||||
xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
struct xmlattr *attr;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "xml_sta:[%s]\n", name);
|
||||
for (attr = list->first; attr != NULL; attr = attr->next)
|
||||
@@ -2065,8 +2107,17 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
|
||||
xar->file->hdnext = xar->hdlink_orgs;
|
||||
xar->hdlink_orgs = xar->file;
|
||||
} else {
|
||||
xar->file->link = (unsigned)atol10(attr->value,
|
||||
strlen(attr->value));
|
||||
uint64_t val;
|
||||
int r;
|
||||
r = atou64(attr->value,
|
||||
strlen(attr->value), 10, &val);
|
||||
if (r != ARCHIVE_OK) {
|
||||
return (r);
|
||||
}
|
||||
if (val > UINT_MAX) {
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
xar->file->link = (unsigned)val;
|
||||
if (xar->file->link > 0)
|
||||
if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -2250,11 +2301,8 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
|
||||
static void
|
||||
xml_end(void *userData, const char *name)
|
||||
{
|
||||
struct archive_read *a;
|
||||
struct xar *xar;
|
||||
|
||||
a = (struct archive_read *)userData;
|
||||
xar = (struct xar *)(a->format->data);
|
||||
struct archive_read *a = (struct archive_read *)userData;
|
||||
struct xar *xar = a->format->data;
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "xml_end:[%s]\n", name);
|
||||
@@ -2628,7 +2676,7 @@ strappend_base64(struct xar *xar,
|
||||
len = 0;
|
||||
out = buff;
|
||||
b = (const unsigned char *)s;
|
||||
while (l > 0) {
|
||||
while (l > 1) {
|
||||
int n = 0;
|
||||
|
||||
if (base64[b[0]] < 0 || base64[b[1]] < 0)
|
||||
@@ -2673,37 +2721,41 @@ is_string(const char *known, const char *data, size_t len)
|
||||
return memcmp(data, known, len);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
xml_data(void *userData, const char *s, size_t len)
|
||||
{
|
||||
struct archive_read *a;
|
||||
struct xar *xar;
|
||||
|
||||
a = (struct archive_read *)userData;
|
||||
xar = (struct xar *)(a->format->data);
|
||||
struct archive_read *a = (struct archive_read *)userData;
|
||||
struct xar *xar = a->format->data;
|
||||
uint64_t val;
|
||||
int r;
|
||||
|
||||
#if DEBUG
|
||||
{
|
||||
char buff[1024];
|
||||
if (len > (int)(sizeof(buff)-1))
|
||||
len = (int)(sizeof(buff)-1);
|
||||
strncpy(buff, s, len);
|
||||
buff[len] = 0;
|
||||
fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff);
|
||||
size_t dlen = len;
|
||||
if (dlen > sizeof(buff) - 1)
|
||||
dlen = sizeof(buff) - 1;
|
||||
strncpy(buff, s, dlen);
|
||||
buff[dlen] = 0;
|
||||
fprintf(stderr, "\tlen=%zu:\"%s\"\n", dlen, buff);
|
||||
}
|
||||
#endif
|
||||
switch (xar->xmlsts) {
|
||||
case TOC_CHECKSUM_OFFSET:
|
||||
xar->toc_chksum_offset = atol10(s, len);
|
||||
r = atou64(s, len, 10, &xar->toc_chksum_offset);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
break;
|
||||
case TOC_CHECKSUM_SIZE:
|
||||
xar->toc_chksum_size = atol10(s, len);
|
||||
r = atou64(s, len, 10, &xar->toc_chksum_size);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (xar->file == NULL)
|
||||
return;
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
switch (xar->xmlsts) {
|
||||
case FILE_NAME:
|
||||
@@ -2752,42 +2804,76 @@ xml_data(void *userData, const char *s, size_t len)
|
||||
xar->file->has |= HAS_TYPE;
|
||||
break;
|
||||
case FILE_INODE:
|
||||
r = atou64(s, len, 10, &val);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
if (val > (uint64_t)INT64_MAX)
|
||||
return (ARCHIVE_FATAL);
|
||||
xar->file->has |= HAS_INO;
|
||||
xar->file->ino64 = atol10(s, len);
|
||||
xar->file->ino64 = (int64_t)val;
|
||||
break;
|
||||
case FILE_DEVICE_MAJOR:
|
||||
r = atou64(s, len, 10, &val);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
if (val != (dev_t)val)
|
||||
return (ARCHIVE_FATAL);
|
||||
xar->file->has |= HAS_DEVMAJOR;
|
||||
xar->file->devmajor = (dev_t)atol10(s, len);
|
||||
xar->file->devmajor = (dev_t)val;
|
||||
break;
|
||||
case FILE_DEVICE_MINOR:
|
||||
r = atou64(s, len, 10, &val);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
if (val != (dev_t)val)
|
||||
return (ARCHIVE_FATAL);
|
||||
xar->file->has |= HAS_DEVMINOR;
|
||||
xar->file->devminor = (dev_t)atol10(s, len);
|
||||
xar->file->devminor = (dev_t)val;
|
||||
break;
|
||||
case FILE_DEVICENO:
|
||||
r = atou64(s, len, 10, &val);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
if (val != (dev_t)val)
|
||||
return (ARCHIVE_FATAL);
|
||||
xar->file->has |= HAS_DEV;
|
||||
xar->file->dev = (dev_t)atol10(s, len);
|
||||
xar->file->dev = (dev_t)val;
|
||||
break;
|
||||
case FILE_MODE:
|
||||
r = atou64(s, len, 8, &val);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
if (val != (mode_t)val)
|
||||
return (ARCHIVE_FATAL);
|
||||
xar->file->has |= HAS_MODE;
|
||||
xar->file->mode =
|
||||
(xar->file->mode & AE_IFMT) |
|
||||
((mode_t)(atol8(s, len)) & ~AE_IFMT);
|
||||
(xar->file->mode & AE_IFMT) | ((mode_t)val & ~AE_IFMT);
|
||||
break;
|
||||
case FILE_GROUP:
|
||||
xar->file->has |= HAS_GID;
|
||||
archive_strncpy(&(xar->file->gname), s, len);
|
||||
break;
|
||||
case FILE_GID:
|
||||
r = atou64(s, len, 10, &val);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
if (val > (uint64_t)INT64_MAX)
|
||||
return (ARCHIVE_FATAL);
|
||||
xar->file->has |= HAS_GID;
|
||||
xar->file->gid = atol10(s, len);
|
||||
xar->file->gid = (int64_t)val;
|
||||
break;
|
||||
case FILE_USER:
|
||||
xar->file->has |= HAS_UID;
|
||||
archive_strncpy(&(xar->file->uname), s, len);
|
||||
break;
|
||||
case FILE_UID:
|
||||
r = atou64(s, len, 10, &val);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
if (val > (uint64_t)INT64_MAX)
|
||||
return (ARCHIVE_FATAL);
|
||||
xar->file->has |= HAS_UID;
|
||||
xar->file->uid = atol10(s, len);
|
||||
xar->file->uid = (int64_t)val;
|
||||
break;
|
||||
case FILE_CTIME:
|
||||
xar->file->has |= HAS_TIME | HAS_CTIME;
|
||||
@@ -2802,16 +2888,22 @@ xml_data(void *userData, const char *s, size_t len)
|
||||
xar->file->atime = parse_time(s, len);
|
||||
break;
|
||||
case FILE_DATA_LENGTH:
|
||||
r = atou64(s, len, 10, &xar->file->length);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
xar->file->has |= HAS_DATA;
|
||||
xar->file->length = atol10(s, len);
|
||||
break;
|
||||
case FILE_DATA_OFFSET:
|
||||
r = atou64(s, len, 10, &xar->file->offset);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
xar->file->has |= HAS_DATA;
|
||||
xar->file->offset = atol10(s, len);
|
||||
break;
|
||||
case FILE_DATA_SIZE:
|
||||
r = atou64(s, len, 10, &xar->file->size);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
xar->file->has |= HAS_DATA;
|
||||
xar->file->size = atol10(s, len);
|
||||
break;
|
||||
case FILE_DATA_A_CHECKSUM:
|
||||
xar->file->a_sum.len = atohex(xar->file->a_sum.val,
|
||||
@@ -2822,16 +2914,22 @@ xml_data(void *userData, const char *s, size_t len)
|
||||
sizeof(xar->file->e_sum.val), s, len);
|
||||
break;
|
||||
case FILE_EA_LENGTH:
|
||||
r = atou64(s, len, 10, &xar->xattr->length);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
xar->file->has |= HAS_XATTR;
|
||||
xar->xattr->length = atol10(s, len);
|
||||
break;
|
||||
case FILE_EA_OFFSET:
|
||||
r = atou64(s, len, 10, &xar->xattr->offset);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
xar->file->has |= HAS_XATTR;
|
||||
xar->xattr->offset = atol10(s, len);
|
||||
break;
|
||||
case FILE_EA_SIZE:
|
||||
r = atou64(s, len, 10, &xar->xattr->size);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
xar->file->has |= HAS_XATTR;
|
||||
xar->xattr->size = atol10(s, len);
|
||||
break;
|
||||
case FILE_EA_A_CHECKSUM:
|
||||
xar->file->has |= HAS_XATTR;
|
||||
@@ -2907,6 +3005,8 @@ xml_data(void *userData, const char *s, size_t len)
|
||||
case UNKNOWN:
|
||||
break;
|
||||
}
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3108,16 +3208,13 @@ xml2_xmlattr_setup(struct archive_read *a,
|
||||
static int
|
||||
xml2_read_cb(void *context, char *buffer, int len)
|
||||
{
|
||||
struct archive_read *a;
|
||||
struct xar *xar;
|
||||
struct archive_read *a = (struct archive_read *)context;
|
||||
struct xar *xar = a->format->data;
|
||||
const void *d;
|
||||
size_t outbytes;
|
||||
size_t used = 0;
|
||||
int r;
|
||||
|
||||
a = (struct archive_read *)context;
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
if (xar->toc_remaining <= 0)
|
||||
return (0);
|
||||
d = buffer;
|
||||
@@ -3146,10 +3243,9 @@ static void
|
||||
xml2_error_hdr(void *arg, const char *msg, xmlParserSeverities severity,
|
||||
xmlTextReaderLocatorPtr locator)
|
||||
{
|
||||
struct archive_read *a;
|
||||
struct archive_read *a = (struct archive_read *)arg;
|
||||
|
||||
(void)locator; /* UNUSED */
|
||||
a = (struct archive_read *)arg;
|
||||
switch (severity) {
|
||||
case XML_PARSER_SEVERITY_VALIDITY_WARNING:
|
||||
case XML_PARSER_SEVERITY_WARNING:
|
||||
@@ -3205,7 +3301,12 @@ xml2_read_toc(struct archive_read *a)
|
||||
break;
|
||||
case XML_READER_TYPE_TEXT:
|
||||
value = (const char *)xmlTextReaderConstValue(reader);
|
||||
xml_data(a, value, strlen(value));
|
||||
r = xml_data(a, value, strlen(value));
|
||||
if (r != ARCHIVE_OK) {
|
||||
xmlFreeTextReader(reader);
|
||||
xmlCleanupParser();
|
||||
return (r);
|
||||
}
|
||||
break;
|
||||
case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
|
||||
default:
|
||||
@@ -3285,21 +3386,22 @@ expat_data_cb(void *userData, const XML_Char *s, int len)
|
||||
{
|
||||
struct expat_userData *ud = (struct expat_userData *)userData;
|
||||
|
||||
xml_data(ud->archive, s, (size_t)len);
|
||||
if (ud->state != ARCHIVE_OK)
|
||||
return;
|
||||
|
||||
ud->state = xml_data(ud->archive, s, (size_t)len);
|
||||
}
|
||||
|
||||
static int
|
||||
expat_read_toc(struct archive_read *a)
|
||||
{
|
||||
struct xar *xar;
|
||||
struct xar *xar = a->format->data;
|
||||
XML_Parser parser;
|
||||
struct expat_userData ud;
|
||||
|
||||
ud.state = ARCHIVE_OK;
|
||||
ud.archive = a;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
/* Initialize XML Parser library. */
|
||||
parser = XML_ParserCreate(NULL);
|
||||
if (parser == NULL) {
|
||||
@@ -3321,7 +3423,7 @@ expat_read_toc(struct archive_read *a)
|
||||
|
||||
d = NULL;
|
||||
r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
|
||||
if (r != ARCHIVE_OK) {
|
||||
if (r != ARCHIVE_OK || outbytes > INT_MAX) {
|
||||
XML_ParserFree(parser);
|
||||
return (r);
|
||||
}
|
||||
@@ -3383,16 +3485,13 @@ static HRESULT STDMETHODCALLTYPE
|
||||
asaRead(ISequentialStream *this, void *pv, ULONG cb, ULONG *pcbRead)
|
||||
{
|
||||
struct ArchiveStreamAdapter *asa = (struct ArchiveStreamAdapter *)this;
|
||||
struct archive_read *a;
|
||||
struct xar *xar;
|
||||
struct archive_read *a = asa->a;
|
||||
struct xar *xar = a->format->data;
|
||||
const void *d = pv;
|
||||
size_t outbytes = cb;
|
||||
size_t used = 0;
|
||||
int r;
|
||||
|
||||
a = asa->a;
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
*pcbRead = 0;
|
||||
|
||||
if (xar->toc_remaining <= 0)
|
||||
@@ -3638,7 +3737,11 @@ xmllite_read_toc(struct archive_read *a)
|
||||
goto out;
|
||||
}
|
||||
|
||||
xml_data(a, as.s, (int)archive_strlen(&as));
|
||||
r = xml_data(a, as.s, archive_strlen(&as));
|
||||
if (r != ARCHIVE_OK) {
|
||||
/* xml_data sets an appropriate error */
|
||||
goto out;
|
||||
}
|
||||
archive_string_free(&as);
|
||||
|
||||
case XmlNodeType_None:
|
||||
|
||||
@@ -152,8 +152,6 @@ struct zip {
|
||||
struct archive_string format_name;
|
||||
int64_t central_directory_offset;
|
||||
int64_t central_directory_offset_adjusted;
|
||||
size_t central_directory_entries_total;
|
||||
size_t central_directory_entries_on_this_disk;
|
||||
int has_encrypted_entries;
|
||||
|
||||
/* List of entries (seekable Zip only) */
|
||||
@@ -261,6 +259,15 @@ struct zip {
|
||||
/* Many systems define min or MIN, but not all. */
|
||||
#define zipmin(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
/* True if this entry has declared a specific uncompressed size. */
|
||||
static int
|
||||
zip_entry_size_is_set(const struct zip_entry *zip_entry)
|
||||
{
|
||||
return (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
|| (zip_entry->uncompressed_size > 0
|
||||
&& zip_entry->uncompressed_size != 0xffffffff));
|
||||
}
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
static int
|
||||
zip_read_data_deflate(struct archive_read *a, const void **buff,
|
||||
@@ -272,6 +279,10 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset);
|
||||
#endif
|
||||
|
||||
static void
|
||||
trad_enc_decrypt_update(struct trad_enc_ctx *, const uint8_t *, size_t,
|
||||
uint8_t *, size_t);
|
||||
|
||||
/* This function is used by Ppmd8_DecodeSymbol during decompression of Ppmd8
|
||||
* streams inside ZIP files. It has 2 purposes: one is to fetch the next
|
||||
* compressed byte from the stream, second one is to increase the counter how
|
||||
@@ -280,16 +291,33 @@ static Byte
|
||||
ppmd_read(void* p) {
|
||||
/* Get the handle to current decompression context. */
|
||||
struct archive_read *a = ((IByteIn*)p)->a;
|
||||
struct zip *zip = (struct zip*) a->format->data;
|
||||
ssize_t bytes_avail = 0;
|
||||
struct zip *zip = a->format->data;
|
||||
|
||||
/* Fetch next byte. */
|
||||
const uint8_t* data = __archive_read_ahead(a, 1, &bytes_avail);
|
||||
if(bytes_avail < 1) {
|
||||
const uint8_t* data = __archive_read_ahead(a, 1, NULL);
|
||||
if(data == NULL) {
|
||||
zip->ppmd8_stream_failed = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
uint8_t val;
|
||||
if (zip->tctx_valid) {
|
||||
trad_enc_decrypt_update(&zip->tctx,
|
||||
data, 1, &val, 1);
|
||||
} else {
|
||||
size_t dsize = 1;
|
||||
archive_decrypto_aes_ctr_update(&zip->cctx,
|
||||
data, 1, &val, &dsize);
|
||||
}
|
||||
if (zip->hctx_valid)
|
||||
archive_hmac_sha1_update(&zip->hctx, data, 1);
|
||||
|
||||
__archive_read_consume(a, 1);
|
||||
++zip->zipx_ppmd_read_compressed;
|
||||
return val;
|
||||
}
|
||||
|
||||
__archive_read_consume(a, 1);
|
||||
|
||||
/* Increment the counter. */
|
||||
@@ -401,6 +429,153 @@ crypt_derive_key_sha1(const void *p, int size, unsigned char *key,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Read and decrypt bytes for zipx init headers.
|
||||
* Used by format-specific init functions (lzma, ppmd) that need to
|
||||
* read a small header from the compressed stream. When encryption is
|
||||
* active the bytes are decrypted in-place into the decryption buffer. */
|
||||
static int
|
||||
zipx_read_header_and_decrypt(struct archive_read *a, const void **buf, size_t in_len,
|
||||
size_t *out_len, size_t *consumed)
|
||||
{
|
||||
struct zip *zip = a->format->data;
|
||||
const void *raw;
|
||||
ssize_t bytes_avail;
|
||||
size_t to_decrypt;
|
||||
|
||||
raw = __archive_read_ahead(a, in_len, &bytes_avail);
|
||||
if (raw == NULL || bytes_avail < (ssize_t)in_len) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated ZIP file data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
to_decrypt = in_len;
|
||||
if (to_decrypt > zip->decrypted_buffer_size)
|
||||
to_decrypt = zip->decrypted_buffer_size;
|
||||
|
||||
if (zip->tctx_valid) {
|
||||
trad_enc_decrypt_update(&zip->tctx,
|
||||
raw, to_decrypt,
|
||||
zip->decrypted_buffer, to_decrypt);
|
||||
} else {
|
||||
size_t dsize = to_decrypt;
|
||||
archive_decrypto_aes_ctr_update(&zip->cctx,
|
||||
raw, to_decrypt,
|
||||
zip->decrypted_buffer, &dsize);
|
||||
}
|
||||
if (zip->hctx_valid)
|
||||
archive_hmac_sha1_update(&zip->hctx,
|
||||
raw, to_decrypt);
|
||||
|
||||
*buf = zip->decrypted_buffer;
|
||||
*out_len = to_decrypt;
|
||||
*consumed = to_decrypt;
|
||||
} else {
|
||||
*buf = raw;
|
||||
*out_len = in_len;
|
||||
*consumed = in_len;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/* Decrypt bulk compressed data for zipx decompression.
|
||||
* Manages the decryption buffer, handles partial fills, and returns decrypted
|
||||
* data pointer + length. `sp` is set to the raw pointer for HMAC accounting. */
|
||||
static void
|
||||
zip_read_decrypt(struct zip *zip, const void *compressed_buff,
|
||||
ssize_t bytes_avail, const void **result_buff, ssize_t *result_avail,
|
||||
const void **sp)
|
||||
{
|
||||
*sp = compressed_buff;
|
||||
|
||||
/* Safety check to prevent potential OOB reads if something went wrong
|
||||
* previously. We should not have a negative bytes_avail count here.
|
||||
* If we do, set them to zero so that reading the ZIP will fail later,
|
||||
* safely as corrupted instead of crashing. */
|
||||
if (bytes_avail < 0)
|
||||
bytes_avail = 0;
|
||||
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
|
||||
size_t buff_remaining =
|
||||
(zip->decrypted_buffer +
|
||||
zip->decrypted_buffer_size)
|
||||
- (zip->decrypted_ptr +
|
||||
zip->decrypted_bytes_remaining);
|
||||
/* The new bytes to decrypt start after decrypted_bytes_remaining
|
||||
* in the raw stream: those leading bytes were already
|
||||
* decrypted on a previous call but have not yet been consumed. */
|
||||
size_t new_bytes =
|
||||
(size_t)bytes_avail
|
||||
- zip->decrypted_bytes_remaining;
|
||||
|
||||
if (buff_remaining > new_bytes)
|
||||
buff_remaining = new_bytes;
|
||||
|
||||
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) &&
|
||||
zip->entry_bytes_remaining > 0) {
|
||||
if ((int64_t)(zip->decrypted_bytes_remaining
|
||||
+ buff_remaining)
|
||||
> zip->entry_bytes_remaining) {
|
||||
if (zip->entry_bytes_remaining <
|
||||
(int64_t)zip->decrypted_bytes_remaining)
|
||||
buff_remaining = 0;
|
||||
else
|
||||
buff_remaining =
|
||||
(size_t)zip->entry_bytes_remaining
|
||||
- zip->decrypted_bytes_remaining;
|
||||
}
|
||||
}
|
||||
if (buff_remaining > 0) {
|
||||
if (zip->tctx_valid) {
|
||||
trad_enc_decrypt_update(&zip->tctx,
|
||||
(const uint8_t *)compressed_buff
|
||||
+ zip->decrypted_bytes_remaining,
|
||||
buff_remaining,
|
||||
zip->decrypted_ptr
|
||||
+ zip->decrypted_bytes_remaining,
|
||||
buff_remaining);
|
||||
} else {
|
||||
size_t dsize = buff_remaining;
|
||||
archive_decrypto_aes_ctr_update(
|
||||
&zip->cctx,
|
||||
(const uint8_t *)compressed_buff
|
||||
+ zip->decrypted_bytes_remaining,
|
||||
buff_remaining,
|
||||
zip->decrypted_ptr
|
||||
+ zip->decrypted_bytes_remaining,
|
||||
&dsize);
|
||||
}
|
||||
zip->decrypted_bytes_remaining +=
|
||||
buff_remaining;
|
||||
}
|
||||
}
|
||||
*result_avail = zip->decrypted_bytes_remaining;
|
||||
*result_buff = (const char *)zip->decrypted_ptr;
|
||||
} else {
|
||||
*result_buff = compressed_buff;
|
||||
*result_avail = bytes_avail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Post-decompression decrypt state update.
|
||||
* Updates decrypt buffer pointers and HMAC after the decompressor
|
||||
* has consumed `to_consume` bytes. */
|
||||
static void
|
||||
zip_read_decrypt_update(struct zip *zip, ssize_t to_consume, const void *sp)
|
||||
{
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
zip->decrypted_bytes_remaining -= to_consume;
|
||||
if (zip->decrypted_bytes_remaining == 0)
|
||||
zip->decrypted_ptr = zip->decrypted_buffer;
|
||||
else
|
||||
zip->decrypted_ptr += to_consume;
|
||||
}
|
||||
if (zip->hctx_valid)
|
||||
archive_hmac_sha1_update(&zip->hctx, sp, to_consume);
|
||||
}
|
||||
|
||||
/*
|
||||
* Common code for streaming or seeking modes.
|
||||
*
|
||||
@@ -481,8 +656,8 @@ static int
|
||||
process_extra(struct archive_read *a, struct archive_entry *entry,
|
||||
const char *p, size_t extra_length, struct zip_entry* zip_entry)
|
||||
{
|
||||
struct zip *zip = a->format->data;
|
||||
unsigned offset = 0;
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
|
||||
if (extra_length == 0) {
|
||||
return ARCHIVE_OK;
|
||||
@@ -581,6 +756,22 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
|
||||
* on which file starts, but we don't handle
|
||||
* multi-volume Zip files. */
|
||||
break;
|
||||
case 0x000d:
|
||||
/* PKWARE Unix Extra Field fixed metadata. */
|
||||
if (datasize >= 12) {
|
||||
zip_entry->atime = archive_le32dec(p + offset);
|
||||
zip_entry->mtime =
|
||||
archive_le32dec(p + offset + 4);
|
||||
zip_entry->uid =
|
||||
archive_le16dec(p + offset + 8);
|
||||
zip_entry->gid =
|
||||
archive_le16dec(p + offset + 10);
|
||||
/*
|
||||
* APPNOTE.TXT also defines additional data after
|
||||
* this fixed metadata, depending on file type.
|
||||
*/
|
||||
}
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case 0x0017:
|
||||
{
|
||||
@@ -1008,7 +1199,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Pathname cannot be converted "
|
||||
"from %s to current locale.",
|
||||
"from %s to current locale",
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
@@ -1256,7 +1447,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Symlink cannot be converted "
|
||||
"from %s to current locale.",
|
||||
"from %s to current locale",
|
||||
archive_string_conversion_charset_name(
|
||||
sconv));
|
||||
ret = ARCHIVE_WARN;
|
||||
@@ -1269,10 +1460,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
"Read error skipping symlink target name");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
} else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
|| (zip_entry->uncompressed_size > 0
|
||||
&& zip_entry->uncompressed_size != 0xffffffff)) {
|
||||
/* Set the size only if it's meaningful. */
|
||||
} else if (zip_entry_size_is_set(zip_entry)) {
|
||||
archive_entry_set_size(entry, zip_entry->uncompressed_size);
|
||||
}
|
||||
zip->entry_bytes_remaining = zip_entry->compressed_size;
|
||||
@@ -1295,7 +1483,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
static int
|
||||
check_authentication_code(struct archive_read *a, const void *_p)
|
||||
{
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
|
||||
/* Check authentication code. */
|
||||
if (zip->hctx_valid) {
|
||||
@@ -1522,6 +1710,26 @@ consume_end_of_file_marker(struct archive_read *a, struct zip *zip)
|
||||
return;
|
||||
}
|
||||
|
||||
/* None of the exact patterns matched. If entry size was unknown
|
||||
* (ZIP_LENGTH_AT_END flag), before treating this as
|
||||
* corruption, check whether the next ZIP record follows the data
|
||||
* immediately: a length-at-end entry whose compression format has
|
||||
* its own end-of-stream marker (e.g. PPMd) may be written with no
|
||||
* data descriptor at all. In that case the byte counts we measured
|
||||
* during decompression are authoritative, so trust them and leave
|
||||
* the stream untouched. */
|
||||
if (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
{
|
||||
const uint32_t sig = archive_le32dec(p);
|
||||
if (sig == 0x04034b50U /* Local file header */
|
||||
|| sig == 0x02014b50U /* Central directory record */
|
||||
|| sig == 0x06054b50U) /* End of central directory */ {
|
||||
zip->entry->compressed_size = compressed_actual;
|
||||
zip->entry->uncompressed_size = uncompressed_actual;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If none of the above patterns gives us a full exact match,
|
||||
* then there's something definitely amiss. The fallback code
|
||||
* below will parse out some plausible values for error
|
||||
@@ -1599,7 +1807,7 @@ static int
|
||||
zip_read_data_none(struct archive_read *a, const void **_buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip *zip;
|
||||
struct zip *zip = a->format->data;
|
||||
const char *buff;
|
||||
ssize_t bytes_avail;
|
||||
ssize_t trailing_extra;
|
||||
@@ -1607,7 +1815,6 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
|
||||
|
||||
(void)offset; /* UNUSED */
|
||||
|
||||
zip = (struct zip *)(a->format->data);
|
||||
trailing_extra = zip->hctx_valid ? AUTH_CODE_SIZE : 0;
|
||||
|
||||
if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) {
|
||||
@@ -1726,7 +1933,7 @@ zipx_xz_init(struct archive_read *a, struct zip *zip)
|
||||
r = lzma_stream_decoder(&zip->zipx_lzma_stream, UINT64_MAX, 0);
|
||||
if (r != LZMA_OK) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"xz initialization failed(%d)",
|
||||
"xz initialization failed (%d)",
|
||||
r);
|
||||
|
||||
return (ARCHIVE_FAILED);
|
||||
@@ -1775,10 +1982,10 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
|
||||
* "lzma alone" decoder from XZ Utils. */
|
||||
|
||||
memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream));
|
||||
r = lzma_alone_decoder(&zip->zipx_lzma_stream, UINT64_MAX);
|
||||
r = lzma_alone_decoder(&zip->zipx_lzma_stream, 576 * ((uint64_t)1 << 20));
|
||||
if (r != LZMA_OK) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"lzma initialization failed(%d)", r);
|
||||
"lzma initialization failed (%d)", r);
|
||||
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
@@ -1825,12 +2032,38 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
|
||||
*/
|
||||
|
||||
/* Read magic1,magic2,lzma_params from the ZIPX stream. */
|
||||
if(zip->entry_bytes_remaining < 9 || (p = __archive_read_ahead(a, 9, NULL)) == NULL) {
|
||||
/* When the compressed size is unknown (e.g. ZIP_LENGTH_AT_END read
|
||||
* from a non-seekable source), entry_bytes_remaining is 0 or negative
|
||||
* here. We can still attempt to read the 9-byte header; if the data
|
||||
* is truly truncated, the __archive_read_ahead calls below will catch
|
||||
* it. */
|
||||
if(zip->entry_bytes_remaining > 0
|
||||
&& zip->entry_bytes_remaining < 9) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated lzma data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
const void *decrypted;
|
||||
size_t out_len;
|
||||
size_t consumed;
|
||||
int ret;
|
||||
|
||||
ret = zipx_read_header_and_decrypt(a, &decrypted, 9, &out_len, &consumed);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
p = decrypted;
|
||||
} else {
|
||||
p = __archive_read_ahead(a, 9, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated lzma data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
if(p[2] != 0x05 || p[3] != 0x00) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid lzma data");
|
||||
@@ -1868,15 +2101,21 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
|
||||
* output bytes yet. */
|
||||
r = lzma_code(&zip->zipx_lzma_stream, LZMA_RUN);
|
||||
if (r != LZMA_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"lzma stream initialization error");
|
||||
if (r == LZMA_MEMLIMIT_ERROR)
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"lzma stream requires too much memory");
|
||||
else
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"lzma stream initialization error");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
/* We've already consumed some bytes, so take this into account. */
|
||||
__archive_read_consume(a, 9);
|
||||
zip->entry_bytes_remaining -= 9;
|
||||
zip->entry_compressed_bytes_read += 9;
|
||||
if (zip->entry_bytes_remaining > 0) {
|
||||
zip->entry_bytes_remaining -= 9;
|
||||
}
|
||||
|
||||
zip->decompress_init = 1;
|
||||
return (ARCHIVE_OK);
|
||||
@@ -1886,11 +2125,12 @@ static int
|
||||
zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip* zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
int ret;
|
||||
lzma_ret lz_ret;
|
||||
const void* compressed_buf;
|
||||
ssize_t bytes_avail, in_bytes, to_consume = 0;
|
||||
const void* sp;
|
||||
ssize_t bytes_avail, to_consume = 0;
|
||||
|
||||
(void) offset; /* UNUSED */
|
||||
|
||||
@@ -1901,16 +2141,22 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
|
||||
return (ret);
|
||||
}
|
||||
|
||||
compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);
|
||||
compressed_buf = sp = __archive_read_ahead(a, 1, &bytes_avail);
|
||||
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
&& bytes_avail > zip->entry_bytes_remaining) {
|
||||
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
|
||||
}
|
||||
if (bytes_avail < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated xz file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
|
||||
zip_read_decrypt(zip, compressed_buf, bytes_avail,
|
||||
&compressed_buf, &bytes_avail, &sp);
|
||||
|
||||
zip->zipx_lzma_stream.next_in = compressed_buf;
|
||||
zip->zipx_lzma_stream.avail_in = in_bytes;
|
||||
zip->zipx_lzma_stream.avail_in = bytes_avail;
|
||||
zip->zipx_lzma_stream.total_in = 0;
|
||||
zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;
|
||||
zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;
|
||||
@@ -1921,7 +2167,7 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
|
||||
switch(lz_ret) {
|
||||
case LZMA_DATA_ERROR:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"xz data error (error %d)", (int) lz_ret);
|
||||
"xz data error (%d)", (int) lz_ret);
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
case LZMA_NO_CHECK:
|
||||
@@ -1930,15 +2176,17 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
|
||||
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"xz unknown error %d", (int) lz_ret);
|
||||
"xz unknown error (%d)", (int) lz_ret);
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
case LZMA_STREAM_END:
|
||||
lzma_end(&zip->zipx_lzma_stream);
|
||||
zip->zipx_lzma_valid = 0;
|
||||
|
||||
if((int64_t) zip->zipx_lzma_stream.total_in !=
|
||||
zip->entry_bytes_remaining)
|
||||
/* This assertion is only possible if the size of the compressed data
|
||||
* stream is known -> !ZIP_LENGTH_AT_END */
|
||||
if((int64_t) zip->zipx_lzma_stream.total_in != zip->entry_bytes_remaining
|
||||
&& !(zip->entry->zip_flags & ZIP_LENGTH_AT_END))
|
||||
{
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
@@ -1957,6 +2205,16 @@ zip_read_data_zipx_xz(struct archive_read *a, const void **buff,
|
||||
zip->entry_compressed_bytes_read += to_consume;
|
||||
zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;
|
||||
|
||||
zip_read_decrypt_update(zip, to_consume, sp);
|
||||
|
||||
if (zip->end_of_entry) {
|
||||
if (zip->hctx_valid) {
|
||||
ret = check_authentication_code(a, NULL);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*size = (size_t)zip->zipx_lzma_stream.total_out;
|
||||
*buff = zip->uncompressed_buffer;
|
||||
|
||||
@@ -1967,11 +2225,12 @@ static int
|
||||
zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip* zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
int ret;
|
||||
lzma_ret lz_ret;
|
||||
const void* compressed_buf;
|
||||
ssize_t bytes_avail, in_bytes, to_consume;
|
||||
const void* sp;
|
||||
ssize_t bytes_avail, to_consume;
|
||||
|
||||
(void) offset; /* UNUSED */
|
||||
|
||||
@@ -1991,26 +2250,38 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
* data.
|
||||
*/
|
||||
compressed_buf = __archive_read_ahead(a, 1, &bytes_avail);
|
||||
if (zip->entry_bytes_remaining > 0
|
||||
&& bytes_avail > zip->entry_bytes_remaining) {
|
||||
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
|
||||
}
|
||||
if (bytes_avail < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated lzma file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/* Set decompressor parameters. */
|
||||
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
|
||||
zip_read_decrypt(zip, compressed_buf, bytes_avail,
|
||||
&compressed_buf, &bytes_avail, &sp);
|
||||
|
||||
zip->zipx_lzma_stream.next_in = compressed_buf;
|
||||
zip->zipx_lzma_stream.avail_in = in_bytes;
|
||||
zip->zipx_lzma_stream.avail_in = bytes_avail;
|
||||
zip->zipx_lzma_stream.total_in = 0;
|
||||
zip->zipx_lzma_stream.next_out = zip->uncompressed_buffer;
|
||||
zip->zipx_lzma_stream.avail_out =
|
||||
/* These lzma_alone streams lack end of stream marker, so let's
|
||||
* make sure the unpacker won't try to unpack more than it's
|
||||
* supposed to. */
|
||||
(size_t)zipmin((int64_t) zip->uncompressed_buffer_size,
|
||||
zip->entry->uncompressed_size -
|
||||
zip->entry_uncompressed_bytes_read);
|
||||
/* These lzma_alone streams lack an end of stream marker in some
|
||||
* cases, so when the uncompressed size is known we cap avail_out to
|
||||
* make sure the unpacker won't try to unpack more than it's supposed
|
||||
* to. When the compressed size is unknown (entry_bytes_remaining <= 0,
|
||||
* e.g. ZIP_LENGTH_AT_END from a non-seekable source) we must use the
|
||||
* full buffer and rely on the LZMA stream end marker to detect the end
|
||||
* of the entry. */
|
||||
if (zip->entry_bytes_remaining <= 0) {
|
||||
zip->zipx_lzma_stream.avail_out = zip->uncompressed_buffer_size;
|
||||
} else {
|
||||
zip->zipx_lzma_stream.avail_out =
|
||||
(size_t)zipmin((int64_t) zip->uncompressed_buffer_size,
|
||||
zip->entry->uncompressed_size -
|
||||
zip->entry_uncompressed_bytes_read);
|
||||
}
|
||||
zip->zipx_lzma_stream.total_out = 0;
|
||||
|
||||
/* Perform the decompression. */
|
||||
@@ -2018,14 +2289,17 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
switch(lz_ret) {
|
||||
case LZMA_DATA_ERROR:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"lzma data error (error %d)", (int) lz_ret);
|
||||
"lzma data error (%d)", (int) lz_ret);
|
||||
return (ARCHIVE_FATAL);
|
||||
|
||||
/* This case is optional in lzma alone format. It can happen,
|
||||
* but most of the files don't have it. (GitHub #1257) */
|
||||
case LZMA_STREAM_END:
|
||||
/* This assertion is only possible if the size of the
|
||||
* compressed data stream is known. */
|
||||
if((int64_t) zip->zipx_lzma_stream.total_in !=
|
||||
zip->entry_bytes_remaining)
|
||||
zip->entry_bytes_remaining
|
||||
&& zip->entry_bytes_remaining > 0)
|
||||
{
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
@@ -2039,9 +2313,21 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
case LZMA_OK:
|
||||
break;
|
||||
|
||||
case LZMA_BUF_ERROR:
|
||||
if (zip->zipx_lzma_stream.avail_out == 0) {
|
||||
/* The output buffer was filled exactly. When
|
||||
* the uncompressed size is known this means we
|
||||
* have decompressed all expected bytes. When
|
||||
* the size is unknown a full buffer just means
|
||||
* we need another iteration. */
|
||||
if (zip->entry_bytes_remaining > 0)
|
||||
zip->end_of_entry = 1;
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
default:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"lzma unknown error %d", (int) lz_ret);
|
||||
"lzma unknown error (%d)", (int) lz_ret);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
@@ -2049,12 +2335,29 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
|
||||
/* Update pointers. */
|
||||
__archive_read_consume(a, to_consume);
|
||||
zip->entry_bytes_remaining -= to_consume;
|
||||
zip->entry_compressed_bytes_read += to_consume;
|
||||
zip->entry_uncompressed_bytes_read += zip->zipx_lzma_stream.total_out;
|
||||
|
||||
if(zip->entry_bytes_remaining == 0) {
|
||||
zip->end_of_entry = 1;
|
||||
zip_read_decrypt_update(zip, to_consume, sp);
|
||||
|
||||
if(zip->entry_bytes_remaining > 0) {
|
||||
zip->entry_bytes_remaining -= to_consume;
|
||||
if(zip->entry_bytes_remaining == 0) {
|
||||
zip->end_of_entry = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(zip->end_of_entry && zip->entry_bytes_remaining > 0) {
|
||||
ssize_t remaining = (ssize_t)zip->entry_bytes_remaining;
|
||||
const void *p = __archive_read_ahead(a, remaining, NULL);
|
||||
if (p != NULL) {
|
||||
if (zip->hctx_valid)
|
||||
archive_hmac_sha1_update(&zip->hctx,
|
||||
p, remaining);
|
||||
__archive_read_consume(a, remaining);
|
||||
zip->entry_compressed_bytes_read += remaining;
|
||||
zip->entry_bytes_remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free lzma decoder handle because we'll no longer need it. */
|
||||
@@ -2063,6 +2366,12 @@ zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
if(zip->end_of_entry) {
|
||||
lzma_end(&zip->zipx_lzma_stream);
|
||||
zip->zipx_lzma_valid = 0;
|
||||
|
||||
if (zip->hctx_valid) {
|
||||
ret = check_authentication_code(a, NULL);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return values. */
|
||||
@@ -2104,11 +2413,22 @@ zipx_ppmd8_init(struct archive_read *a, struct zip *zip)
|
||||
zip->zipx_ppmd_read_compressed = 0;
|
||||
|
||||
/* Read Ppmd8 header (2 bytes). */
|
||||
p = __archive_read_ahead(a, 2, NULL);
|
||||
if(!p) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated file data in PPMd8 stream");
|
||||
return (ARCHIVE_FATAL);
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
size_t out_len;
|
||||
size_t consumed;
|
||||
int ret;
|
||||
|
||||
ret = zipx_read_header_and_decrypt(a, &p, 2, &out_len, &consumed);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
} else {
|
||||
p = __archive_read_ahead(a, 2, NULL);
|
||||
if(!p) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated file data in PPMd8 stream");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
__archive_read_consume(a, 2);
|
||||
|
||||
@@ -2175,10 +2495,9 @@ static int
|
||||
zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip* zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
int ret;
|
||||
size_t consumed_bytes = 0;
|
||||
ssize_t bytes_avail = 0;
|
||||
|
||||
(void) offset; /* UNUSED */
|
||||
|
||||
@@ -2192,8 +2511,7 @@ zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,
|
||||
|
||||
/* Fetch for more data. We're reading 1 byte here, but libarchive
|
||||
* should prefetch more bytes. */
|
||||
(void) __archive_read_ahead(a, 1, &bytes_avail);
|
||||
if(bytes_avail < 0) {
|
||||
if(__archive_read_ahead(a, 1, NULL) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated PPMd8 file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
@@ -2234,6 +2552,12 @@ zip_read_data_zipx_ppmd(struct archive_read *a, const void **buff,
|
||||
if(zip->end_of_entry) {
|
||||
__archive_ppmd8_functions.Ppmd8_Free(&zip->ppmd8);
|
||||
zip->ppmd8_valid = 0;
|
||||
|
||||
if (zip->hctx_valid) {
|
||||
int r = check_authentication_code(a, NULL);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update pointers for libarchive. */
|
||||
@@ -2261,7 +2585,7 @@ zipx_bzip2_init(struct archive_read *a, struct zip *zip)
|
||||
r = BZ2_bzDecompressInit(&zip->bzstream, 0, 1);
|
||||
if(r != BZ_OK) {
|
||||
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
|
||||
"bzip2 initialization failed(%d)",
|
||||
"bzip2 initialization failed (%d)",
|
||||
r);
|
||||
|
||||
return ARCHIVE_FAILED;
|
||||
@@ -2290,9 +2614,10 @@ static int
|
||||
zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
ssize_t bytes_avail = 0, in_bytes, to_consume;
|
||||
struct zip *zip = a->format->data;
|
||||
ssize_t bytes_avail = 0, to_consume;
|
||||
const void *compressed_buff;
|
||||
const void *sp;
|
||||
int r;
|
||||
uint64_t total_out;
|
||||
|
||||
@@ -2307,27 +2632,26 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
|
||||
|
||||
/* Fetch more compressed bytes. */
|
||||
compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
|
||||
if(bytes_avail < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated bzip2 file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
&& bytes_avail > zip->entry_bytes_remaining) {
|
||||
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
|
||||
}
|
||||
|
||||
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
|
||||
if(in_bytes < 1) {
|
||||
if(bytes_avail < 1) {
|
||||
/* libbz2 doesn't complain when caller feeds avail_in == 0.
|
||||
* It will actually return success in this case, which is
|
||||
* undesirable. This is why we need to make this check
|
||||
* manually. */
|
||||
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated bzip2 file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
zip_read_decrypt(zip, compressed_buff, bytes_avail,
|
||||
&compressed_buff, &bytes_avail, &sp);
|
||||
|
||||
/* Setup buffer boundaries. */
|
||||
zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;
|
||||
zip->bzstream.avail_in = (uint32_t)in_bytes;
|
||||
zip->bzstream.avail_in = (uint32_t)bytes_avail;
|
||||
zip->bzstream.total_in_hi32 = 0;
|
||||
zip->bzstream.total_in_lo32 = 0;
|
||||
zip->bzstream.next_out = (char*) zip->uncompressed_buffer;
|
||||
@@ -2375,6 +2699,14 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
|
||||
zip->entry_compressed_bytes_read += to_consume;
|
||||
zip->entry_uncompressed_bytes_read += total_out;
|
||||
|
||||
zip_read_decrypt_update(zip, to_consume, sp);
|
||||
|
||||
if (zip->end_of_entry && zip->hctx_valid) {
|
||||
r = check_authentication_code(a, NULL);
|
||||
if (r != ARCHIVE_OK)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Give libarchive its due. */
|
||||
*size = (size_t)total_out;
|
||||
*buff = zip->uncompressed_buffer;
|
||||
@@ -2433,9 +2765,10 @@ static int
|
||||
zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
ssize_t bytes_avail = 0, in_bytes, to_consume;
|
||||
struct zip *zip = a->format->data;
|
||||
ssize_t bytes_avail = 0, to_consume;
|
||||
const void *compressed_buff;
|
||||
const void *sp;
|
||||
int r;
|
||||
size_t ret;
|
||||
uint64_t total_out;
|
||||
@@ -2452,15 +2785,12 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
|
||||
}
|
||||
|
||||
/* Fetch more compressed bytes */
|
||||
compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
|
||||
if(bytes_avail < 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated zstd file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);
|
||||
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
|
||||
&& bytes_avail > zip->entry_bytes_remaining) {
|
||||
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
|
||||
}
|
||||
|
||||
in_bytes = (ssize_t)zipmin(zip->entry_bytes_remaining, bytes_avail);
|
||||
if(in_bytes < 1) {
|
||||
if(bytes_avail < 1) {
|
||||
/* zstd doesn't complain when caller feeds avail_in == 0.
|
||||
* It will actually return success in this case, which is
|
||||
* undesirable. This is why we need to make this check
|
||||
@@ -2470,9 +2800,12 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
zip_read_decrypt(zip, compressed_buff, bytes_avail,
|
||||
&compressed_buff, &bytes_avail, &sp);
|
||||
|
||||
/* Setup buffer boundaries */
|
||||
in.src = compressed_buff;
|
||||
in.size = in_bytes;
|
||||
in.size = bytes_avail;
|
||||
in.pos = 0;
|
||||
out = (ZSTD_outBuffer) { zip->uncompressed_buffer, zip->uncompressed_buffer_size, 0 };
|
||||
|
||||
@@ -2484,6 +2817,10 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
|
||||
ZSTD_getErrorName(ret));
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/* End of stream handling for zips with ZIP_LENGTH_AT_END flag */
|
||||
if (ret == 0 && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {
|
||||
zip->end_of_entry = 1;
|
||||
}
|
||||
|
||||
/* Check end of the stream. */
|
||||
if (ret == 0) {
|
||||
@@ -2504,6 +2841,14 @@ zip_read_data_zipx_zstd(struct archive_read *a, const void **buff,
|
||||
zip->entry_compressed_bytes_read += to_consume;
|
||||
zip->entry_uncompressed_bytes_read += total_out;
|
||||
|
||||
zip_read_decrypt_update(zip, to_consume, sp);
|
||||
|
||||
if (zip->end_of_entry && zip->hctx_valid) {
|
||||
r = check_authentication_code(a, NULL);
|
||||
if (r != ARCHIVE_OK)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Give libarchive its due. */
|
||||
*size = (size_t)total_out;
|
||||
*buff = zip->uncompressed_buffer;
|
||||
@@ -2527,7 +2872,7 @@ zip_deflate_init(struct archive_read *a, struct zip *zip)
|
||||
-15 /* Don't check for zlib header */);
|
||||
if (r != Z_OK) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Can't initialize ZIP decompression.");
|
||||
"Can't initialize ZIP decompression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/* Stream structure has been set up. */
|
||||
@@ -2542,15 +2887,14 @@ static int
|
||||
zip_read_data_deflate(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip *zip;
|
||||
struct zip *zip = a->format->data;
|
||||
ssize_t bytes_avail, to_consume = 0;
|
||||
const void *compressed_buff, *sp;
|
||||
const void *compressed_buff;
|
||||
const void *sp;
|
||||
int r;
|
||||
|
||||
(void)offset; /* UNUSED */
|
||||
|
||||
zip = (struct zip *)(a->format->data);
|
||||
|
||||
/* If the buffer hasn't been allocated, allocate it now. */
|
||||
if (zip->uncompressed_buffer == NULL) {
|
||||
zip->uncompressed_buffer_size = 256 * 1024;
|
||||
@@ -2584,54 +2928,8 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
|
||||
size_t buff_remaining =
|
||||
(zip->decrypted_buffer +
|
||||
zip->decrypted_buffer_size)
|
||||
- (zip->decrypted_ptr +
|
||||
zip->decrypted_bytes_remaining);
|
||||
|
||||
if (buff_remaining > (size_t)bytes_avail)
|
||||
buff_remaining = (size_t)bytes_avail;
|
||||
|
||||
if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) &&
|
||||
zip->entry_bytes_remaining > 0) {
|
||||
if ((int64_t)(zip->decrypted_bytes_remaining
|
||||
+ buff_remaining)
|
||||
> zip->entry_bytes_remaining) {
|
||||
if (zip->entry_bytes_remaining <
|
||||
(int64_t)zip->decrypted_bytes_remaining)
|
||||
buff_remaining = 0;
|
||||
else
|
||||
buff_remaining =
|
||||
(size_t)zip->entry_bytes_remaining
|
||||
- zip->decrypted_bytes_remaining;
|
||||
}
|
||||
}
|
||||
if (buff_remaining > 0) {
|
||||
if (zip->tctx_valid) {
|
||||
trad_enc_decrypt_update(&zip->tctx,
|
||||
compressed_buff, buff_remaining,
|
||||
zip->decrypted_ptr
|
||||
+ zip->decrypted_bytes_remaining,
|
||||
buff_remaining);
|
||||
} else {
|
||||
size_t dsize = buff_remaining;
|
||||
archive_decrypto_aes_ctr_update(
|
||||
&zip->cctx,
|
||||
compressed_buff, buff_remaining,
|
||||
zip->decrypted_ptr
|
||||
+ zip->decrypted_bytes_remaining,
|
||||
&dsize);
|
||||
}
|
||||
zip->decrypted_bytes_remaining +=
|
||||
buff_remaining;
|
||||
}
|
||||
}
|
||||
bytes_avail = zip->decrypted_bytes_remaining;
|
||||
compressed_buff = (const char *)zip->decrypted_ptr;
|
||||
}
|
||||
zip_read_decrypt(zip, compressed_buff, bytes_avail,
|
||||
&compressed_buff, &bytes_avail, &sp);
|
||||
|
||||
/*
|
||||
* A bug in zlib.h: stream.next_in should be marked 'const'
|
||||
@@ -2670,22 +2968,12 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
|
||||
zip->entry_compressed_bytes_read += to_consume;
|
||||
zip->entry_uncompressed_bytes_read += zip->stream.total_out;
|
||||
|
||||
if (zip->tctx_valid || zip->cctx_valid) {
|
||||
zip->decrypted_bytes_remaining -= to_consume;
|
||||
if (zip->decrypted_bytes_remaining == 0)
|
||||
zip->decrypted_ptr = zip->decrypted_buffer;
|
||||
else
|
||||
zip->decrypted_ptr += to_consume;
|
||||
}
|
||||
if (zip->hctx_valid)
|
||||
archive_hmac_sha1_update(&zip->hctx, sp, to_consume);
|
||||
zip_read_decrypt_update(zip, to_consume, sp);
|
||||
|
||||
if (zip->end_of_entry) {
|
||||
if (zip->hctx_valid) {
|
||||
r = check_authentication_code(a, NULL);
|
||||
if (r != ARCHIVE_OK) {
|
||||
return (r);
|
||||
}
|
||||
if (zip->end_of_entry && zip->hctx_valid) {
|
||||
r = check_authentication_code(a, NULL);
|
||||
if (r != ARCHIVE_OK) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2699,7 +2987,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
|
||||
static int
|
||||
read_decryption_header(struct archive_read *a)
|
||||
{
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
const char *p;
|
||||
unsigned int remaining_size;
|
||||
unsigned int ts;
|
||||
@@ -2893,7 +3181,7 @@ nomem:
|
||||
static int
|
||||
zip_alloc_decryption_buffer(struct archive_read *a)
|
||||
{
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
size_t bs = 256 * 1024;
|
||||
|
||||
if (zip->decrypted_buffer == NULL) {
|
||||
@@ -2912,7 +3200,7 @@ zip_alloc_decryption_buffer(struct archive_read *a)
|
||||
static int
|
||||
init_traditional_PKWARE_decryption(struct archive_read *a)
|
||||
{
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
const void *p;
|
||||
int retry;
|
||||
int r;
|
||||
@@ -2984,7 +3272,7 @@ init_traditional_PKWARE_decryption(struct archive_read *a)
|
||||
static int
|
||||
init_WinZip_AES_decryption(struct archive_read *a)
|
||||
{
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
const void *p;
|
||||
const uint8_t *pv;
|
||||
size_t key_len, salt_len;
|
||||
@@ -3078,8 +3366,8 @@ static int
|
||||
archive_read_format_zip_read_data(struct archive_read *a,
|
||||
const void **buff, size_t *size, int64_t *offset)
|
||||
{
|
||||
struct zip *zip = a->format->data;
|
||||
int r;
|
||||
struct zip *zip = (struct zip *)(a->format->data);
|
||||
|
||||
if (zip->has_encrypted_entries ==
|
||||
ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
|
||||
@@ -3157,6 +3445,25 @@ archive_read_format_zip_read_data(struct archive_read *a,
|
||||
}
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
|
||||
/*
|
||||
* FAIL if there are more uncompressed bytes than were
|
||||
* initially advertised. The end-of-entry check below also
|
||||
* compares these values, but only once decoding reaches its
|
||||
* own natural end. Fail the entry so a caller relying on
|
||||
* archive_entry_size() as a hard boundary is never misled;
|
||||
* later entries in the archive can still be read normally.
|
||||
*/
|
||||
if (*size > 0 && zip_entry_size_is_set(zip->entry) &&
|
||||
zip->entry_uncompressed_bytes_read > zip->entry->uncompressed_size) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"ZIP uncompressed data is larger than the declared "
|
||||
"entry size (read at least %jd, expected %jd)",
|
||||
(intmax_t)zip->entry_uncompressed_bytes_read,
|
||||
(intmax_t)zip->entry->uncompressed_size);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (*size > 0) {
|
||||
zip->computed_crc32 = zip->crc32func(zip->computed_crc32, *buff,
|
||||
(unsigned)*size);
|
||||
@@ -3187,13 +3494,11 @@ archive_read_format_zip_read_data(struct archive_read *a,
|
||||
(intmax_t)zip->entry->compressed_size);
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
/* Size field only stores the lower 32 bits of the actual
|
||||
* size. */
|
||||
if ((zip->entry->uncompressed_size & UINT32_MAX)
|
||||
!= (zip->entry_uncompressed_bytes_read & UINT32_MAX)) {
|
||||
if (zip->entry->uncompressed_size !=
|
||||
zip->entry_uncompressed_bytes_read) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"ZIP uncompressed data is wrong size "
|
||||
"(read %jd, expected %jd)\n",
|
||||
"(read %jd, expected %jd)",
|
||||
(intmax_t)zip->entry_uncompressed_bytes_read,
|
||||
(intmax_t)zip->entry->uncompressed_size);
|
||||
return (ARCHIVE_FAILED);
|
||||
@@ -3206,11 +3511,9 @@ archive_read_format_zip_read_data(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_zip_cleanup(struct archive_read *a)
|
||||
{
|
||||
struct zip *zip;
|
||||
struct zip *zip = a->format->data;
|
||||
struct zip_entry *zip_entry, *next_zip_entry;
|
||||
|
||||
zip = (struct zip *)(a->format->data);
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
if (zip->stream_valid)
|
||||
inflateEnd(&zip->stream);
|
||||
@@ -3258,7 +3561,7 @@ archive_read_format_zip_cleanup(struct archive_read *a)
|
||||
free(zip->v_data);
|
||||
archive_string_free(&zip->format_name);
|
||||
free(zip);
|
||||
(a->format->data) = NULL;
|
||||
a->format->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -3266,7 +3569,7 @@ static int
|
||||
archive_read_format_zip_has_encrypted_entries(struct archive_read *_a)
|
||||
{
|
||||
if (_a && _a->format) {
|
||||
struct zip * zip = (struct zip *)_a->format->data;
|
||||
struct zip *zip = _a->format->data;
|
||||
if (zip) {
|
||||
return zip->has_encrypted_entries;
|
||||
}
|
||||
@@ -3278,10 +3581,9 @@ static int
|
||||
archive_read_format_zip_options(struct archive_read *a,
|
||||
const char *key, const char *val)
|
||||
{
|
||||
struct zip *zip;
|
||||
struct zip *zip = a->format->data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
zip = (struct zip *)(a->format->data);
|
||||
if (strcmp(key, "compat-2x") == 0) {
|
||||
/* Handle filenames as libarchive 2.x */
|
||||
zip->init_default_conversion = (val != NULL) ? 1 : 0;
|
||||
@@ -3388,14 +3690,12 @@ static int
|
||||
archive_read_format_zip_streamable_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct zip *zip;
|
||||
struct zip *zip = a->format->data;
|
||||
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
|
||||
if (a->archive.archive_format_name == NULL)
|
||||
a->archive.archive_format_name = "ZIP";
|
||||
|
||||
zip = (struct zip *)(a->format->data);
|
||||
|
||||
/*
|
||||
* It should be sufficient to call archive_read_next_header() for
|
||||
* a reader to determine if an entry is encrypted or not. If the
|
||||
@@ -3481,10 +3781,9 @@ archive_read_format_zip_streamable_read_header(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_zip_read_data_skip_streamable(struct archive_read *a)
|
||||
{
|
||||
struct zip *zip;
|
||||
struct zip *zip = a->format->data;
|
||||
int64_t bytes_skipped;
|
||||
|
||||
zip = (struct zip *)(a->format->data);
|
||||
bytes_skipped = __archive_read_consume(a, zip->unconsumed);
|
||||
zip->unconsumed = 0;
|
||||
if (bytes_skipped < 0)
|
||||
@@ -3726,7 +4025,7 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
|
||||
static int
|
||||
archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
|
||||
{
|
||||
struct zip *zip = (struct zip *)a->format->data;
|
||||
struct zip *zip = a->format->data;
|
||||
int64_t file_size, current_offset;
|
||||
const char *p;
|
||||
int i, tail;
|
||||
@@ -3932,7 +4231,6 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
|
||||
__archive_rb_tree_init(&zip->tree, &rb_ops);
|
||||
__archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
|
||||
|
||||
zip->central_directory_entries_total = 0;
|
||||
while (1) {
|
||||
struct zip_entry *zip_entry;
|
||||
size_t filename_length, extra_length, comment_length;
|
||||
@@ -3961,7 +4259,6 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
|
||||
zip_entry->next = zip->zip_entries;
|
||||
zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY;
|
||||
zip->zip_entries = zip_entry;
|
||||
zip->central_directory_entries_total++;
|
||||
|
||||
/* version = p[4]; */
|
||||
zip_entry->system = p[5];
|
||||
@@ -4041,12 +4338,14 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
|
||||
r = rsrc_basename(name, filename_length);
|
||||
if (filename_length >= 9 &&
|
||||
strncmp("__MACOSX/", name, 9) == 0) {
|
||||
const char *name_end;
|
||||
|
||||
name_end = name + filename_length;
|
||||
/* If this file is not a resource fork nor
|
||||
* a directory. We should treat it as a non
|
||||
* resource fork file to expose it. */
|
||||
if (name[filename_length-1] != '/' &&
|
||||
(r - name < 3 || r[0] != '.' ||
|
||||
r[1] != '_')) {
|
||||
(name_end - r < 2 || r[0] != '.' || r[1] != '_')) {
|
||||
__archive_rb_tree_insert_node(
|
||||
&zip->tree, &zip_entry->node);
|
||||
/* Expose its parent directories. */
|
||||
@@ -4124,7 +4423,7 @@ static int
|
||||
zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
|
||||
struct zip_entry *rsrc)
|
||||
{
|
||||
struct zip *zip = (struct zip *)a->format->data;
|
||||
struct zip *zip = a->format->data;
|
||||
unsigned char *metadata, *mp;
|
||||
int64_t offset = archive_filter_bytes(&a->archive, 0);
|
||||
size_t remaining_bytes, metadata_bytes;
|
||||
@@ -4275,7 +4574,7 @@ static int
|
||||
archive_read_format_zip_seekable_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct zip *zip = (struct zip *)a->format->data;
|
||||
struct zip *zip = a->format->data;
|
||||
struct zip_entry *rsrc;
|
||||
int64_t offset;
|
||||
int r, ret = ARCHIVE_OK;
|
||||
@@ -4355,8 +4654,7 @@ archive_read_format_zip_seekable_read_header(struct archive_read *a,
|
||||
static int
|
||||
archive_read_format_zip_read_data_skip_seekable(struct archive_read *a)
|
||||
{
|
||||
struct zip *zip;
|
||||
zip = (struct zip *)(a->format->data);
|
||||
struct zip *zip = a->format->data;
|
||||
|
||||
zip->unconsumed = 0;
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
@@ -450,6 +450,8 @@ default_iconv_charset(const char *charset) {
|
||||
return locale_charset();
|
||||
#elif HAVE_NL_LANGINFO
|
||||
return nl_langinfo(CODESET);
|
||||
#elif defined(__BIONIC__)
|
||||
return "UTF-8";
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
@@ -1314,7 +1316,17 @@ create_sconv_object(const char *fc, const char *tc,
|
||||
else if (strcmp(fc, "CP932") == 0)
|
||||
sc->cd = iconv_open(tc, "SJIS");
|
||||
}
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#if defined(__FreeBSD__) && !defined(HAVE_LIBICONV)
|
||||
/*
|
||||
* FreeBSD's native iconv() by default returns the number of
|
||||
* invalid characters in the input string, as specified by
|
||||
* POSIX, but iconv_strncat_in_locale() assumes GNU iconv
|
||||
* semantics.
|
||||
*/
|
||||
int v = 1;
|
||||
|
||||
(void)iconvctl(sc->cd, ICONV_SET_ILSEQ_INVALID, &v);
|
||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/*
|
||||
* archive_mstring on Windows directly convert multi-bytes
|
||||
* into archive_wstring in order not to depend on locale
|
||||
@@ -1362,7 +1374,7 @@ free_sconv_object(struct archive_string_conv *sc)
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
# if defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
# define GetOEMCP() CP_OEMCP
|
||||
# endif
|
||||
|
||||
@@ -1713,7 +1725,7 @@ get_sconv_object(struct archive *a, const char *fc, const char *tc, int flag)
|
||||
if (a != NULL) {
|
||||
#if HAVE_ICONV
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"iconv_open failed : Cannot handle ``%s''",
|
||||
"iconv_open failed: Cannot handle ``%s''",
|
||||
(flag & SCONV_TO_CHARSET)?tc:fc);
|
||||
#else
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
@@ -2315,7 +2327,7 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
|
||||
|
||||
remaining = length;
|
||||
itp = (const uint8_t *)_p;
|
||||
while (*itp && remaining > 0) {
|
||||
while (remaining > 0 && *itp) {
|
||||
if (*itp > 127) {
|
||||
// Non-ASCII: Substitute with suitable replacement
|
||||
if (sc->flag & SCONV_TO_UTF8) {
|
||||
@@ -2330,6 +2342,7 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
|
||||
archive_strappend_char(as, *itp);
|
||||
}
|
||||
++itp;
|
||||
--remaining;
|
||||
}
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
@@ -24,11 +24,20 @@
|
||||
*/
|
||||
|
||||
#include "archive_platform.h"
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_time_private.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NTFS_EPOC_TIME ARCHIVE_LITERAL_ULL(11644473600)
|
||||
#define NTFS_TICKS ARCHIVE_LITERAL_ULL(10000000)
|
||||
@@ -149,15 +158,11 @@ unix_to_ntfs(int64_t secs, uint32_t nsecs)
|
||||
if (secs < -(int64_t)NTFS_EPOC_TIME)
|
||||
return 0;
|
||||
|
||||
ntfs = secs + NTFS_EPOC_TIME;
|
||||
|
||||
if (ntfs > UINT64_MAX / NTFS_TICKS)
|
||||
/* (secs + NTFS_EPOC_TIME) * NTFS_TICKS + nsecs / 100 */
|
||||
if (archive_ckd_add_u64(&ntfs, secs, NTFS_EPOC_TIME) ||
|
||||
archive_ckd_mul_u64(&ntfs, ntfs, NTFS_TICKS) ||
|
||||
archive_ckd_add_u64(&ntfs, ntfs, nsecs / 100))
|
||||
return UINT64_MAX;
|
||||
|
||||
ntfs *= NTFS_TICKS;
|
||||
|
||||
if (ntfs > UINT64_MAX - nsecs/100)
|
||||
return UINT64_MAX;
|
||||
|
||||
return ntfs + nsecs/100;
|
||||
return ntfs;
|
||||
}
|
||||
|
||||
@@ -33,12 +33,15 @@
|
||||
.Nm archive_errno ,
|
||||
.Nm archive_error_string ,
|
||||
.Nm archive_file_count ,
|
||||
.Nm archive_filter_bytes ,
|
||||
.Nm archive_filter_code ,
|
||||
.Nm archive_filter_count ,
|
||||
.Nm archive_filter_name ,
|
||||
.Nm archive_format ,
|
||||
.Nm archive_format_name ,
|
||||
.Nm archive_position ,
|
||||
.Nm archive_free ,
|
||||
.Nm archive_position_compressed ,
|
||||
.Nm archive_position_uncompressed ,
|
||||
.Nm archive_set_error
|
||||
.Nd libarchive utility functions
|
||||
.Sh LIBRARY
|
||||
@@ -59,6 +62,8 @@ Streaming Archive Library (libarchive, -larchive)
|
||||
.Fn archive_error_string "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_file_count "struct archive *"
|
||||
.Ft int64_t
|
||||
.Fn archive_filter_bytes "struct archive *" "int"
|
||||
.Ft int
|
||||
.Fn archive_filter_code "struct archive *" "int"
|
||||
.Ft int
|
||||
@@ -69,8 +74,12 @@ Streaming Archive Library (libarchive, -larchive)
|
||||
.Fn archive_format "struct archive *"
|
||||
.Ft const char *
|
||||
.Fn archive_format_name "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_free "struct archive *"
|
||||
.Ft int64_t
|
||||
.Fn archive_position "struct archive *" "int"
|
||||
.Fn archive_position_compressed "struct archive *"
|
||||
.Ft int64_t
|
||||
.Fn archive_position_uncompressed "struct archive *"
|
||||
.Ft void
|
||||
.Fo archive_set_error
|
||||
.Fa "struct archive *"
|
||||
@@ -140,13 +149,13 @@ filter 0 is the gunzip filter,
|
||||
filter 1 is the uudecode filter,
|
||||
and filter 2 is the pseudo-filter that wraps the archive read functions.
|
||||
In this case, requesting
|
||||
.Fn archive_position a -1
|
||||
.Fn archive_filter_bytes a -1
|
||||
would be a synonym for
|
||||
.Fn archive_position a 2
|
||||
.Fn archive_filter_bytes a 2
|
||||
which would return the number of bytes currently read from the archive, while
|
||||
.Fn archive_position a 1
|
||||
.Fn archive_filter_bytes a 1
|
||||
would return the number of bytes after uudecoding, and
|
||||
.Fn archive_position a 0
|
||||
.Fn archive_filter_bytes a 0
|
||||
would return the number of bytes after decompression.
|
||||
.It Fn archive_filter_name
|
||||
Returns a textual name identifying the indicated filter.
|
||||
@@ -165,16 +174,24 @@ utilize GNU tar extensions and several entries that do not.
|
||||
These entries will have different format codes.
|
||||
.It Fn archive_format_name
|
||||
A textual description of the format of the current entry.
|
||||
.It Fn archive_position
|
||||
.It Fn archive_free
|
||||
Closes the archive if necessary, then releases all resources.
|
||||
.It Fn archive_filter_bytes
|
||||
Returns the number of bytes read from or written to the indicated filter.
|
||||
In particular,
|
||||
.Fn archive_position a 0
|
||||
.Fn archive_filter_bytes a 0
|
||||
returns the number of bytes read or written by the format handler, while
|
||||
.Fn archive_position a -1
|
||||
.Fn archive_filter_bytes a -1
|
||||
returns the number of bytes read or written to the archive.
|
||||
See
|
||||
.Fn archive_filter_count
|
||||
for details of the numbering here.
|
||||
.It Fn archive_position_compressed
|
||||
Synonym for
|
||||
.Fn archive_filter_bytes a -1 .
|
||||
.It Fn archive_position_uncompressed
|
||||
Synonym for
|
||||
.Fn archive_filter_bytes a 0 .
|
||||
.It Fn archive_set_error
|
||||
Sets the numeric error code and error description that will be returned
|
||||
by
|
||||
|
||||
@@ -42,18 +42,12 @@
|
||||
#include <string.h>
|
||||
#endif
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
/* don't use bcrypt when XP needs to be supported */
|
||||
#include <bcrypt.h>
|
||||
|
||||
/* Common in other bcrypt implementations, but missing from VS2008. */
|
||||
#ifndef BCRYPT_SUCCESS
|
||||
#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_WINCRYPT_H)
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_ZLIB_H
|
||||
#include <cm3p/zlib.h>
|
||||
@@ -110,8 +104,7 @@ archive_errno(struct archive *a)
|
||||
const char *
|
||||
archive_error_string(struct archive *a)
|
||||
{
|
||||
|
||||
if (a->error != NULL && *a->error != '\0')
|
||||
if (a->error != NULL && *a->error != '\0')
|
||||
return (a->error);
|
||||
else
|
||||
return (NULL);
|
||||
@@ -250,11 +243,7 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
|
||||
DWORD attr;
|
||||
wchar_t *xp, *ep;
|
||||
int fd;
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
BCRYPT_ALG_HANDLE hAlg = NULL;
|
||||
#else
|
||||
HCRYPTPROV hProv = (HCRYPTPROV)NULL;
|
||||
#endif
|
||||
fd = -1;
|
||||
ws = NULL;
|
||||
archive_string_init(&temp_name);
|
||||
@@ -262,22 +251,36 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
|
||||
if (template == NULL) {
|
||||
/* Get a temporary directory. */
|
||||
if (tmpdir == NULL) {
|
||||
size_t l;
|
||||
wchar_t *tmp;
|
||||
wchar_t buf[MAX_PATH + 1];
|
||||
wchar_t *p = buf, *buf2 = NULL;
|
||||
size_t l, s;
|
||||
|
||||
l = GetTempPathW(0, NULL);
|
||||
s = MAX_PATH + 1;
|
||||
l = GetTempPathW((DWORD)s, buf);
|
||||
if (l == 0) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
tmp = malloc(l*sizeof(wchar_t));
|
||||
if (tmp == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto exit_tmpfile;
|
||||
while (l > s) {
|
||||
wchar_t *tmp;
|
||||
|
||||
s = l;
|
||||
tmp = realloc(buf2, s * sizeof(wchar_t));
|
||||
if (tmp == NULL) {
|
||||
free(buf2);
|
||||
errno = ENOMEM;
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
p = buf2 = tmp;
|
||||
l = GetTempPathW((DWORD)s, buf2);
|
||||
if (l == 0) {
|
||||
free(buf2);
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
}
|
||||
GetTempPathW((DWORD)l, tmp);
|
||||
archive_wstrcpy(&temp_name, tmp);
|
||||
free(tmp);
|
||||
archive_wstrcpy(&temp_name, p);
|
||||
free(buf2);
|
||||
} else {
|
||||
if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
|
||||
strlen(tmpdir)) < 0)
|
||||
@@ -328,19 +331,11 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
|
||||
abort();
|
||||
}
|
||||
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM,
|
||||
NULL, 0))) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
#else
|
||||
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
wchar_t *p;
|
||||
@@ -351,19 +346,11 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
|
||||
|
||||
/* Generate a random file name through CryptGenRandom(). */
|
||||
p = xp;
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p,
|
||||
(DWORD)(ep - p)*sizeof(wchar_t), 0))) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
#else
|
||||
if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
|
||||
(BYTE*)p)) {
|
||||
la_dosmaperr(GetLastError());
|
||||
goto exit_tmpfile;
|
||||
}
|
||||
#endif
|
||||
for (; p < ep; p++)
|
||||
*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
|
||||
|
||||
@@ -417,13 +404,8 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
|
||||
break;/* success! */
|
||||
}
|
||||
exit_tmpfile:
|
||||
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
|
||||
if (hAlg != NULL)
|
||||
BCryptCloseAlgorithmProvider(hAlg, 0);
|
||||
#else
|
||||
if (hProv != (HCRYPTPROV)NULL)
|
||||
CryptReleaseContext(hProv, 0);
|
||||
#endif
|
||||
free(ws);
|
||||
if (template == temp_name.s)
|
||||
archive_wstring_free(&temp_name);
|
||||
|
||||
@@ -157,10 +157,6 @@ archive_crypto_version(struct archive_string* str)
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_LIBMD)
|
||||
archive_strcat(str, " libmd/");
|
||||
archive_strcat(str, archive_libmd_version());
|
||||
#endif
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT)
|
||||
archive_strcat(str, " WinCrypt/");
|
||||
archive_strcat(str, archive_wincrypt_version());
|
||||
#endif
|
||||
// Just in case
|
||||
(void)str; /* UNUSED */
|
||||
@@ -180,7 +176,7 @@ archive_version_details(void)
|
||||
const char *libiconv = archive_libiconv_version();
|
||||
const char *libacl = archive_libacl_version();
|
||||
const char *librichacl = archive_librichacl_version();
|
||||
const char *libattr = archive_libacl_version();
|
||||
const char *libattr = archive_libattr_version();
|
||||
|
||||
if (!init) {
|
||||
archive_string_init(&str);
|
||||
@@ -234,6 +230,7 @@ archive_version_details(void)
|
||||
archive_strcat(&str, " libiconv/");
|
||||
archive_strcat(&str, libiconv);
|
||||
}
|
||||
init = 1;
|
||||
}
|
||||
return str.s;
|
||||
}
|
||||
@@ -431,27 +428,7 @@ archive_cng_version(void)
|
||||
const char *
|
||||
archive_wincrypt_version(void)
|
||||
{
|
||||
#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT) || defined(ARCHIVE_CRYPTO_WINCRYPT)
|
||||
HCRYPTPROV prov;
|
||||
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
||||
if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
|
||||
return NULL;
|
||||
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
|
||||
return NULL;
|
||||
}
|
||||
DWORD version, length = sizeof(version);
|
||||
if (!CryptGetProvParam(prov, PP_VERSION, (BYTE *)&version, &length, 0)) {
|
||||
return NULL;
|
||||
} else {
|
||||
char major = (version >> 8) & 0xFF;
|
||||
char minor = version & 0xFF;
|
||||
static char wincrypt_version[6];
|
||||
snprintf(wincrypt_version, 6, "%hhd.%hhd", major, minor);
|
||||
return wincrypt_version;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
|
||||
@@ -63,23 +63,6 @@
|
||||
#include <windows.h>
|
||||
#include <share.h>
|
||||
|
||||
#if defined(__LA_LSEEK_NEEDED)
|
||||
static BOOL SetFilePointerEx_perso(HANDLE hFile,
|
||||
LARGE_INTEGER liDistanceToMove,
|
||||
PLARGE_INTEGER lpNewFilePointer,
|
||||
DWORD dwMoveMethod)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = liDistanceToMove.QuadPart;
|
||||
li.LowPart = SetFilePointer(
|
||||
hFile, li.LowPart, &li.HighPart, dwMoveMethod);
|
||||
if(lpNewFilePointer) {
|
||||
lpNewFilePointer->QuadPart = li.QuadPart;
|
||||
}
|
||||
return li.LowPart != -1 || GetLastError() == NO_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ustat {
|
||||
int64_t st_atime;
|
||||
uint32_t st_atime_nsec;
|
||||
@@ -236,7 +219,7 @@ la_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
CREATEFILE2_EXTENDED_PARAMETERS createExParams;
|
||||
#endif
|
||||
|
||||
#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
|
||||
lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
|
||||
hTemplateFile);
|
||||
@@ -285,7 +268,7 @@ __la_lseek(int fd, __int64 offset, int whence)
|
||||
return (-1);
|
||||
}
|
||||
distance.QuadPart = offset;
|
||||
if (!SetFilePointerEx_perso(handle, distance, &newpointer, whence)) {
|
||||
if (!SetFilePointerEx(handle, distance, &newpointer, whence)) {
|
||||
DWORD lasterr;
|
||||
|
||||
lasterr = GetLastError();
|
||||
@@ -324,7 +307,7 @@ __la_open(const char *path, int flags, ...)
|
||||
* "Permission denied" error.
|
||||
*/
|
||||
attr = GetFileAttributesA(path);
|
||||
#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND)
|
||||
#endif
|
||||
{
|
||||
@@ -342,7 +325,7 @@ __la_open(const char *path, int flags, ...)
|
||||
}
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
HANDLE handle;
|
||||
#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
if (ws != NULL)
|
||||
handle = CreateFileW(ws, 0, 0, NULL,
|
||||
OPEN_EXISTING,
|
||||
@@ -437,7 +420,7 @@ __la_wopen(const wchar_t *path, int flags, ...)
|
||||
* "Permission denied" error.
|
||||
*/
|
||||
attr = GetFileAttributesW(path);
|
||||
#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
if (attr == (DWORD)-1 && GetLastError() == ERROR_PATH_NOT_FOUND)
|
||||
#endif
|
||||
{
|
||||
@@ -456,7 +439,7 @@ __la_wopen(const wchar_t *path, int flags, ...)
|
||||
}
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
HANDLE handle;
|
||||
#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
|
||||
if (fullpath != NULL)
|
||||
handle = CreateFileW(fullpath, 0, 0, NULL,
|
||||
OPEN_EXISTING,
|
||||
|
||||
@@ -192,7 +192,6 @@
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) /* directory */
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) /* regular file */
|
||||
#endif
|
||||
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) /* Symbolic link */
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) /* Socket */
|
||||
|
||||
@@ -306,6 +305,26 @@ typedef int mbstate_t;
|
||||
size_t wcrtomb(char *, wchar_t, mbstate_t *);
|
||||
#endif
|
||||
|
||||
#ifndef WINAPI_FAMILY_PARTITION
|
||||
#define WINAPI_FAMILY_PARTITION(x) (x)
|
||||
#endif
|
||||
|
||||
#ifndef WINAPI_PARTITION_DESKTOP
|
||||
#define WINAPI_PARTITION_DESKTOP 1
|
||||
#endif
|
||||
|
||||
#ifndef WINAPI_PARTITION_SYSTEM
|
||||
#define WINAPI_PARTITION_SYSTEM 1
|
||||
#endif
|
||||
|
||||
#ifndef NTDDI_VERSION
|
||||
#define NTDDI_VERSION 0x05020000
|
||||
#endif
|
||||
|
||||
#ifndef NTDDI_WIN10_VB
|
||||
#define NTDDI_WIN10_VB 0x0A000008
|
||||
#endif
|
||||
|
||||
#if !WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP) && NTDDI_VERSION < NTDDI_WIN10_VB
|
||||
// not supported in UWP SDK before 20H1
|
||||
#define GetVolumePathNameW(f, v, c) (0)
|
||||
@@ -316,17 +335,4 @@ WINBASEAPI BOOL WINAPI GetVolumePathNameW(
|
||||
DWORD cchBufferLength
|
||||
);
|
||||
#endif
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1300
|
||||
# if _WIN32_WINNT < 0x0500 /* windows.h not providing 0x500 API */
|
||||
typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
|
||||
LARGE_INTEGER FileOffset;
|
||||
LARGE_INTEGER Length;
|
||||
} FILE_ALLOCATED_RANGE_BUFFER, *PFILE_ALLOCATED_RANGE_BUFFER;
|
||||
# define FSCTL_SET_SPARSE \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_WRITE_DATA)
|
||||
# define FSCTL_QUERY_ALLOCATED_RANGES \
|
||||
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 51, METHOD_NEITHER, FILE_READ_DATA)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif /* !LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */
|
||||
|
||||
@@ -69,7 +69,7 @@ static int _archive_write_header(struct archive *, struct archive_entry *);
|
||||
static int _archive_write_finish_entry(struct archive *);
|
||||
static ssize_t _archive_write_data(struct archive *, const void *, size_t);
|
||||
|
||||
struct archive_none {
|
||||
struct client {
|
||||
size_t buffer_size;
|
||||
size_t avail;
|
||||
char *buffer;
|
||||
@@ -135,7 +135,7 @@ archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block)
|
||||
|
||||
if (bytes_per_block < 0) {
|
||||
// Do nothing if the bytes_per_block is negative
|
||||
return 0;
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
a->bytes_per_block = bytes_per_block;
|
||||
return (ARCHIVE_OK);
|
||||
@@ -240,8 +240,10 @@ __archive_write_filter(struct archive_write_filter *f,
|
||||
/* If unset, a fatal error has already occurred, so this filter
|
||||
* didn't open. We cannot write anything. */
|
||||
return(ARCHIVE_FATAL);
|
||||
if (length > (uint64_t)(INT64_MAX - f->bytes_written))
|
||||
return(ARCHIVE_FATAL);
|
||||
r = (f->write)(f, buff, length);
|
||||
f->bytes_written += length;
|
||||
f->bytes_written += (int64_t)length;
|
||||
return (r);
|
||||
}
|
||||
|
||||
@@ -338,7 +340,7 @@ __archive_write_filters_flush(struct archive_write *a)
|
||||
}
|
||||
|
||||
int
|
||||
__archive_write_nulls(struct archive_write *a, size_t length)
|
||||
__archive_write_nulls(struct archive_write *a, uint64_t length)
|
||||
{
|
||||
if (length == 0)
|
||||
return (ARCHIVE_OK);
|
||||
@@ -357,7 +359,7 @@ static int
|
||||
archive_write_client_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)f->archive;
|
||||
struct archive_none *state;
|
||||
struct client *client;
|
||||
void *buffer;
|
||||
size_t buffer_size;
|
||||
|
||||
@@ -366,21 +368,21 @@ archive_write_client_open(struct archive_write_filter *f)
|
||||
archive_write_get_bytes_in_last_block(f->archive);
|
||||
buffer_size = f->bytes_per_block;
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
client = calloc(1, sizeof(*client));
|
||||
buffer = malloc(buffer_size);
|
||||
if (state == NULL || buffer == NULL) {
|
||||
free(state);
|
||||
if (client == NULL || buffer == NULL) {
|
||||
free(client);
|
||||
free(buffer);
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for output buffering");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
state->buffer_size = buffer_size;
|
||||
state->buffer = buffer;
|
||||
state->next = state->buffer;
|
||||
state->avail = state->buffer_size;
|
||||
f->data = state;
|
||||
client->buffer_size = buffer_size;
|
||||
client->buffer = buffer;
|
||||
client->next = client->buffer;
|
||||
client->avail = client->buffer_size;
|
||||
f->data = client;
|
||||
|
||||
if (a->client_opener == NULL)
|
||||
return (ARCHIVE_OK);
|
||||
@@ -392,7 +394,7 @@ archive_write_client_write(struct archive_write_filter *f,
|
||||
const void *_buff, size_t length)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)f->archive;
|
||||
struct archive_none *state = (struct archive_none *)f->data;
|
||||
struct client *client = f->data;
|
||||
const char *buff = (const char *)_buff;
|
||||
ssize_t remaining, to_copy;
|
||||
ssize_t bytes_written;
|
||||
@@ -405,7 +407,7 @@ archive_write_client_write(struct archive_write_filter *f,
|
||||
* particular, this supports "no write delay" operation for
|
||||
* special applications. Just set the block size to zero.
|
||||
*/
|
||||
if (state->buffer_size == 0) {
|
||||
if (client->buffer_size == 0) {
|
||||
while (remaining > 0) {
|
||||
bytes_written = (a->client_writer)(&a->archive,
|
||||
a->client_data, buff, remaining);
|
||||
@@ -418,20 +420,20 @@ archive_write_client_write(struct archive_write_filter *f,
|
||||
}
|
||||
|
||||
/* If the copy buffer isn't empty, try to fill it. */
|
||||
if (state->avail < state->buffer_size) {
|
||||
if (client->avail < client->buffer_size) {
|
||||
/* If buffer is not empty... */
|
||||
/* ... copy data into buffer ... */
|
||||
to_copy = ((size_t)remaining > state->avail) ?
|
||||
state->avail : (size_t)remaining;
|
||||
memcpy(state->next, buff, to_copy);
|
||||
state->next += to_copy;
|
||||
state->avail -= to_copy;
|
||||
to_copy = ((size_t)remaining > client->avail) ?
|
||||
client->avail : (size_t)remaining;
|
||||
memcpy(client->next, buff, to_copy);
|
||||
client->next += to_copy;
|
||||
client->avail -= to_copy;
|
||||
buff += to_copy;
|
||||
remaining -= to_copy;
|
||||
/* ... if it's full, write it out. */
|
||||
if (state->avail == 0) {
|
||||
char *p = state->buffer;
|
||||
size_t to_write = state->buffer_size;
|
||||
if (client->avail == 0) {
|
||||
char *p = client->buffer;
|
||||
size_t to_write = client->buffer_size;
|
||||
while (to_write > 0) {
|
||||
bytes_written = (a->client_writer)(&a->archive,
|
||||
a->client_data, p, to_write);
|
||||
@@ -445,15 +447,15 @@ archive_write_client_write(struct archive_write_filter *f,
|
||||
p += bytes_written;
|
||||
to_write -= bytes_written;
|
||||
}
|
||||
state->next = state->buffer;
|
||||
state->avail = state->buffer_size;
|
||||
client->next = client->buffer;
|
||||
client->avail = client->buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
while ((size_t)remaining >= state->buffer_size) {
|
||||
while ((size_t)remaining >= client->buffer_size) {
|
||||
/* Write out full blocks directly to client. */
|
||||
bytes_written = (a->client_writer)(&a->archive,
|
||||
a->client_data, buff, state->buffer_size);
|
||||
a->client_data, buff, client->buffer_size);
|
||||
if (bytes_written <= 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
buff += bytes_written;
|
||||
@@ -462,9 +464,9 @@ archive_write_client_write(struct archive_write_filter *f,
|
||||
|
||||
if (remaining > 0) {
|
||||
/* Copy last bit into copy buffer. */
|
||||
memcpy(state->next, buff, remaining);
|
||||
state->next += remaining;
|
||||
state->avail -= remaining;
|
||||
memcpy(client->next, buff, remaining);
|
||||
client->next += remaining;
|
||||
client->avail -= remaining;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -473,7 +475,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;
|
||||
struct client *client = f->data;
|
||||
|
||||
if (a->client_freer)
|
||||
(*a->client_freer)(&a->archive, a->client_data);
|
||||
@@ -487,9 +489,9 @@ archive_write_client_free(struct archive_write_filter *f)
|
||||
}
|
||||
|
||||
/* Free state. */
|
||||
if (state != NULL) {
|
||||
free(state->buffer);
|
||||
free(state);
|
||||
if (client != NULL) {
|
||||
free(client->buffer);
|
||||
free(client);
|
||||
f->data = NULL;
|
||||
}
|
||||
|
||||
@@ -500,7 +502,7 @@ static int
|
||||
archive_write_client_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)f->archive;
|
||||
struct archive_none *state = (struct archive_none *)f->data;
|
||||
struct client *client = f->data;
|
||||
ssize_t block_length;
|
||||
ssize_t target_block_length;
|
||||
ssize_t bytes_written;
|
||||
@@ -509,8 +511,8 @@ archive_write_client_close(struct archive_write_filter *f)
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
/* If there's pending data, pad and write the last block */
|
||||
if (state->next != state->buffer) {
|
||||
block_length = state->buffer_size - state->avail;
|
||||
if (client->next != client->buffer) {
|
||||
block_length = client->buffer_size - client->avail;
|
||||
|
||||
/* Tricky calculation to determine size of last block */
|
||||
if (a->bytes_in_last_block <= 0)
|
||||
@@ -524,11 +526,11 @@ archive_write_client_close(struct archive_write_filter *f)
|
||||
if (target_block_length > a->bytes_per_block)
|
||||
target_block_length = a->bytes_per_block;
|
||||
if (block_length < target_block_length) {
|
||||
memset(state->next, 0,
|
||||
memset(client->next, 0,
|
||||
target_block_length - block_length);
|
||||
block_length = target_block_length;
|
||||
}
|
||||
p = state->buffer;
|
||||
p = client->buffer;
|
||||
to_write = block_length;
|
||||
while (to_write > 0) {
|
||||
bytes_written = (a->client_writer)(&a->archive,
|
||||
@@ -683,6 +685,29 @@ __archive_write_filters_free(struct archive *_a)
|
||||
a->filter_last = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
__archive_write_unregister_format(struct archive_write *a)
|
||||
{
|
||||
int r = ARCHIVE_OK;
|
||||
|
||||
if (a->format_free != NULL)
|
||||
r = (a->format_free)(a);
|
||||
|
||||
a->format_data = NULL;
|
||||
a->format_name = NULL;
|
||||
a->format_init = NULL;
|
||||
a->format_options = NULL;
|
||||
a->format_finish_entry = NULL;
|
||||
a->format_write_header = NULL;
|
||||
a->format_write_data = NULL;
|
||||
a->format_close = NULL;
|
||||
a->format_free = NULL;
|
||||
a->archive.archive_format = 0;
|
||||
a->archive.archive_format_name = NULL;
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the archive structure.
|
||||
*
|
||||
@@ -705,11 +730,9 @@ _archive_write_free(struct archive *_a)
|
||||
r = archive_write_close(&a->archive);
|
||||
|
||||
/* Release format resources. */
|
||||
if (a->format_free != NULL) {
|
||||
r1 = (a->format_free)(a);
|
||||
if (r1 < r)
|
||||
r = r1;
|
||||
}
|
||||
r1 = __archive_write_unregister_format(a);
|
||||
if (r1 < r)
|
||||
r = r1;
|
||||
|
||||
__archive_write_filters_free(_a);
|
||||
|
||||
@@ -742,7 +765,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
|
||||
|
||||
if (a->format_write_header == NULL) {
|
||||
archive_set_error(&(a->archive), -1,
|
||||
"Format must be set before you can write to an archive.");
|
||||
"Format must be set before you can write to an archive");
|
||||
a->archive.state = ARCHIVE_STATE_FATAL;
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -761,7 +784,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
|
||||
archive_entry_ino_is_set(entry) &&
|
||||
archive_entry_dev(entry) == (dev_t)a->skip_file_dev &&
|
||||
archive_entry_ino64(entry) == a->skip_file_ino) {
|
||||
archive_set_error(&a->archive, 0,
|
||||
archive_set_error(&a->archive, EIO,
|
||||
"Can't add archive to itself");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
|
||||
{ ARCHIVE_FILTER_LZ4, archive_write_add_filter_lz4 },
|
||||
{ ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip },
|
||||
{ ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma },
|
||||
{ ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip },
|
||||
{ ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzop },
|
||||
{ ARCHIVE_FILTER_UU, archive_write_add_filter_uuencode },
|
||||
{ ARCHIVE_FILTER_XZ, archive_write_add_filter_xz },
|
||||
{ ARCHIVE_FILTER_ZSTD, archive_write_add_filter_zstd },
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
@@ -36,13 +39,14 @@
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_string.h"
|
||||
#include "archive_write_private.h"
|
||||
|
||||
#define LBYTES 57
|
||||
|
||||
struct private_b64encode {
|
||||
struct b64encode {
|
||||
int mode;
|
||||
struct archive_string name;
|
||||
struct archive_string encoded_buff;
|
||||
@@ -60,6 +64,7 @@ static int archive_filter_b64encode_close(struct archive_write_filter *);
|
||||
static int archive_filter_b64encode_free(struct archive_write_filter *);
|
||||
static void la_b64_encode(struct archive_string *, const unsigned char *, size_t);
|
||||
static int64_t atol8(const char *, size_t);
|
||||
static void free_data(struct b64encode *);
|
||||
|
||||
static const char base64[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
@@ -76,34 +81,38 @@ static const char base64[] = {
|
||||
* Add a compress filter to this write handle.
|
||||
*/
|
||||
int
|
||||
archive_write_add_filter_b64encode(struct archive *_a)
|
||||
archive_write_add_filter_b64encode(struct archive *a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct private_b64encode *state;
|
||||
struct archive_write_filter *f;
|
||||
struct b64encode *b64encode;
|
||||
|
||||
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_b64encode");
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
if (state == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for b64encode filter");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_strcpy(&state->name, "-");
|
||||
state->mode = 0644;
|
||||
b64encode = calloc(1, sizeof(*b64encode));
|
||||
if (b64encode == NULL)
|
||||
goto memerr;
|
||||
archive_strcpy(&b64encode->name, "-");
|
||||
b64encode->mode = 0644;
|
||||
|
||||
f->data = state;
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "b64encode";
|
||||
f->code = ARCHIVE_FILTER_UU;
|
||||
f->open = archive_filter_b64encode_open;
|
||||
f->data = b64encode;
|
||||
f->options = archive_filter_b64encode_options;
|
||||
f->open = archive_filter_b64encode_open;
|
||||
f->write = archive_filter_b64encode_write;
|
||||
f->close = archive_filter_b64encode_close;
|
||||
f->free = archive_filter_b64encode_free;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
memerr:
|
||||
free_data(b64encode);
|
||||
archive_set_error(a, ENOMEM,
|
||||
"Can't allocate data for b64encode filter");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -113,15 +122,23 @@ static int
|
||||
archive_filter_b64encode_options(struct archive_write_filter *f, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
struct private_b64encode *state = (struct private_b64encode *)f->data;
|
||||
struct b64encode *b64encode = f->data;
|
||||
|
||||
if (strcmp(key, "mode") == 0) {
|
||||
int64_t val;
|
||||
|
||||
if (value == NULL) {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"mode option requires octal digits");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
state->mode = (int)atol8(value, strlen(value)) & 0777;
|
||||
val = atol8(value, strlen(value));
|
||||
if (val < 0 || val > INT_MAX) {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"invalid mode option");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
b64encode->mode = (int)val & 0777;
|
||||
return (ARCHIVE_OK);
|
||||
} else if (strcmp(key, "name") == 0) {
|
||||
if (value == NULL) {
|
||||
@@ -129,7 +146,7 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key
|
||||
"name option requires a string");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
archive_strcpy(&state->name, value);
|
||||
archive_strcpy(&b64encode->name, value);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -145,7 +162,7 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key
|
||||
static int
|
||||
archive_filter_b64encode_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_b64encode *state = (struct private_b64encode *)f->data;
|
||||
struct b64encode *b64encode = f->data;
|
||||
size_t bs = 65536, bpb;
|
||||
|
||||
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
|
||||
@@ -158,18 +175,17 @@ archive_filter_b64encode_open(struct archive_write_filter *f)
|
||||
bs -= bs % bpb;
|
||||
}
|
||||
|
||||
state->bs = bs;
|
||||
if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
|
||||
b64encode->bs = bs;
|
||||
if (archive_string_ensure(&b64encode->encoded_buff, bs + 512) == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for b64encode buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",
|
||||
(unsigned int)state->mode, state->name.s);
|
||||
archive_string_sprintf(&b64encode->encoded_buff, "begin-base64 %o %s\n",
|
||||
(unsigned int)b64encode->mode, b64encode->name.s);
|
||||
|
||||
f->data = state;
|
||||
return (0);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -213,39 +229,39 @@ static int
|
||||
archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
struct private_b64encode *state = (struct private_b64encode *)f->data;
|
||||
struct b64encode *b64encode = f->data;
|
||||
const unsigned char *p = buff;
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
if (length == 0)
|
||||
return (ret);
|
||||
|
||||
if (state->hold_len) {
|
||||
while (state->hold_len < LBYTES && length > 0) {
|
||||
state->hold[state->hold_len++] = *p++;
|
||||
if (b64encode->hold_len) {
|
||||
while (b64encode->hold_len < LBYTES && length > 0) {
|
||||
b64encode->hold[b64encode->hold_len++] = *p++;
|
||||
length--;
|
||||
}
|
||||
if (state->hold_len < LBYTES)
|
||||
if (b64encode->hold_len < LBYTES)
|
||||
return (ret);
|
||||
la_b64_encode(&state->encoded_buff, state->hold, LBYTES);
|
||||
state->hold_len = 0;
|
||||
la_b64_encode(&b64encode->encoded_buff, b64encode->hold, LBYTES);
|
||||
b64encode->hold_len = 0;
|
||||
}
|
||||
|
||||
for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
|
||||
la_b64_encode(&state->encoded_buff, p, LBYTES);
|
||||
la_b64_encode(&b64encode->encoded_buff, p, LBYTES);
|
||||
|
||||
/* Save remaining bytes. */
|
||||
if (length > 0) {
|
||||
memcpy(state->hold, p, length);
|
||||
state->hold_len = length;
|
||||
memcpy(b64encode->hold, p, length);
|
||||
b64encode->hold_len = length;
|
||||
}
|
||||
while (archive_strlen(&state->encoded_buff) >= state->bs) {
|
||||
while (archive_strlen(&b64encode->encoded_buff) >= b64encode->bs) {
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
state->encoded_buff.s, state->bs);
|
||||
memmove(state->encoded_buff.s,
|
||||
state->encoded_buff.s + state->bs,
|
||||
state->encoded_buff.length - state->bs);
|
||||
state->encoded_buff.length -= state->bs;
|
||||
b64encode->encoded_buff.s, b64encode->bs);
|
||||
memmove(b64encode->encoded_buff.s,
|
||||
b64encode->encoded_buff.s + b64encode->bs,
|
||||
b64encode->encoded_buff.length - b64encode->bs);
|
||||
b64encode->encoded_buff.length -= b64encode->bs;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
@@ -258,26 +274,24 @@ archive_filter_b64encode_write(struct archive_write_filter *f, const void *buff,
|
||||
static int
|
||||
archive_filter_b64encode_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_b64encode *state = (struct private_b64encode *)f->data;
|
||||
struct b64encode *b64encode = f->data;
|
||||
|
||||
/* Flush remaining bytes. */
|
||||
if (state->hold_len != 0)
|
||||
la_b64_encode(&state->encoded_buff, state->hold, state->hold_len);
|
||||
archive_string_sprintf(&state->encoded_buff, "====\n");
|
||||
if (b64encode->hold_len != 0)
|
||||
la_b64_encode(&b64encode->encoded_buff, b64encode->hold,
|
||||
b64encode->hold_len);
|
||||
archive_string_sprintf(&b64encode->encoded_buff, "====\n");
|
||||
/* Write the last block */
|
||||
archive_write_set_bytes_in_last_block(f->archive, 1);
|
||||
return __archive_write_filter(f->next_filter,
|
||||
state->encoded_buff.s, archive_strlen(&state->encoded_buff));
|
||||
b64encode->encoded_buff.s, archive_strlen(&b64encode->encoded_buff));
|
||||
}
|
||||
|
||||
static int
|
||||
archive_filter_b64encode_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_b64encode *state = (struct private_b64encode *)f->data;
|
||||
|
||||
archive_string_free(&state->name);
|
||||
archive_string_free(&state->encoded_buff);
|
||||
free(state);
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -286,17 +300,30 @@ atol8(const char *p, size_t char_cnt)
|
||||
{
|
||||
int64_t l;
|
||||
int digit;
|
||||
|
||||
|
||||
if (char_cnt == 0)
|
||||
return (-1);
|
||||
|
||||
l = 0;
|
||||
while (char_cnt-- > 0) {
|
||||
if (*p >= '0' && *p <= '7')
|
||||
digit = *p - '0';
|
||||
else
|
||||
break;
|
||||
return (-1);
|
||||
p++;
|
||||
l <<= 3;
|
||||
l |= digit;
|
||||
if (archive_ckd_mul_i64(&l, l, 8) ||
|
||||
archive_ckd_add_i64(&l, l, digit))
|
||||
return (-1);
|
||||
}
|
||||
return (l);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct b64encode *b64encode)
|
||||
{
|
||||
if (b64encode != NULL) {
|
||||
archive_string_free(&b64encode->name);
|
||||
archive_string_free(&b64encode->encoded_buff);
|
||||
free(b64encode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,11 +53,10 @@ archive_write_set_compression_bzip2(struct archive *a)
|
||||
}
|
||||
#endif
|
||||
|
||||
struct private_data {
|
||||
struct bzip2 {
|
||||
int compression_level;
|
||||
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
|
||||
bz_stream stream;
|
||||
int64_t total_in;
|
||||
char *compressed;
|
||||
size_t compressed_buffer_size;
|
||||
#else
|
||||
@@ -72,48 +71,64 @@ static int archive_compressor_bzip2_options(struct archive_write_filter *,
|
||||
const char *, const char *);
|
||||
static int archive_compressor_bzip2_write(struct archive_write_filter *,
|
||||
const void *, size_t);
|
||||
static void free_data(struct bzip2 *);
|
||||
|
||||
/*
|
||||
* Add a bzip2 compression filter to this write handle.
|
||||
*/
|
||||
int
|
||||
archive_write_add_filter_bzip2(struct archive *_a)
|
||||
archive_write_add_filter_bzip2(struct archive *a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct private_data *data;
|
||||
struct archive_write_filter *f;
|
||||
struct bzip2 *bzip2;
|
||||
int r;
|
||||
|
||||
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_bzip2");
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if (data == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->compression_level = 9; /* default */
|
||||
|
||||
f->data = data;
|
||||
f->options = &archive_compressor_bzip2_options;
|
||||
f->close = &archive_compressor_bzip2_close;
|
||||
f->free = &archive_compressor_bzip2_free;
|
||||
f->open = &archive_compressor_bzip2_open;
|
||||
f->code = ARCHIVE_FILTER_BZIP2;
|
||||
f->name = "bzip2";
|
||||
bzip2 = calloc(1, sizeof(*bzip2));
|
||||
if (bzip2 == NULL)
|
||||
goto memerr;
|
||||
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
|
||||
return (ARCHIVE_OK);
|
||||
bzip2->compression_level = 9;
|
||||
|
||||
r = ARCHIVE_OK;
|
||||
#else
|
||||
data->pdata = __archive_write_program_allocate("bzip2");
|
||||
if (data->pdata == NULL) {
|
||||
free(data);
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->compression_level = 0;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
bzip2->pdata = __archive_write_program_allocate("bzip2");
|
||||
if (bzip2->pdata == NULL)
|
||||
goto memerr;
|
||||
bzip2->compression_level = 0;
|
||||
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Using external bzip2 program");
|
||||
return (ARCHIVE_WARN);
|
||||
r = ARCHIVE_WARN;
|
||||
#endif
|
||||
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "bzip2";
|
||||
f->code = ARCHIVE_FILTER_BZIP2;
|
||||
f->data = bzip2;
|
||||
f->options = archive_compressor_bzip2_options;
|
||||
f->open = archive_compressor_bzip2_open;
|
||||
f->write = archive_compressor_bzip2_write;
|
||||
f->close = archive_compressor_bzip2_close;
|
||||
f->free = archive_compressor_bzip2_free;
|
||||
|
||||
return (r);
|
||||
memerr:
|
||||
free_data(bzip2);
|
||||
archive_set_error(a, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_bzip2_free(struct archive_write_filter *f)
|
||||
{
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -123,18 +138,21 @@ static int
|
||||
archive_compressor_bzip2_options(struct archive_write_filter *f,
|
||||
const char *key, const char *value)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
|
||||
if (strcmp(key, "compression-level") == 0) {
|
||||
if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
|
||||
value[1] != '\0')
|
||||
return (ARCHIVE_WARN);
|
||||
data->compression_level = value[0] - '0';
|
||||
value[1] != '\0') {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"compression-level invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
bzip2->compression_level = value[0] - '0';
|
||||
/* Make '0' be a synonym for '1'. */
|
||||
/* This way, bzip2 compressor supports the same 0..9
|
||||
* range of levels as gzip. */
|
||||
if (data->compression_level < 1)
|
||||
data->compression_level = 1;
|
||||
if (bzip2->compression_level < 1)
|
||||
bzip2->compression_level = 1;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -154,7 +172,7 @@ archive_compressor_bzip2_options(struct archive_write_filter *f,
|
||||
#define SET_NEXT_IN(st,src) \
|
||||
(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
|
||||
static int drive_compressor(struct archive_write_filter *,
|
||||
struct private_data *, int finishing);
|
||||
struct bzip2 *, int finishing);
|
||||
|
||||
/*
|
||||
* Setup callback.
|
||||
@@ -162,10 +180,10 @@ static int drive_compressor(struct archive_write_filter *,
|
||||
static int
|
||||
archive_compressor_bzip2_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
int ret;
|
||||
|
||||
if (data->compressed == NULL) {
|
||||
if (bzip2->compressed == NULL) {
|
||||
size_t bs = 65536, bpb;
|
||||
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
|
||||
/* Buffer size should be a multiple number of the bytes
|
||||
@@ -176,25 +194,23 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
|
||||
else if (bpb != 0)
|
||||
bs -= bs % bpb;
|
||||
}
|
||||
data->compressed_buffer_size = bs;
|
||||
data->compressed = malloc(data->compressed_buffer_size);
|
||||
if (data->compressed == NULL) {
|
||||
bzip2->compressed_buffer_size = bs;
|
||||
bzip2->compressed = malloc(bzip2->compressed_buffer_size);
|
||||
if (bzip2->compressed == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&data->stream, 0, sizeof(data->stream));
|
||||
data->stream.next_out = data->compressed;
|
||||
data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
|
||||
f->write = archive_compressor_bzip2_write;
|
||||
memset(&bzip2->stream, 0, sizeof(bzip2->stream));
|
||||
bzip2->stream.next_out = bzip2->compressed;
|
||||
bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size;
|
||||
|
||||
/* Initialize compression library */
|
||||
ret = BZ2_bzCompressInit(&(data->stream),
|
||||
data->compression_level, 0, 30);
|
||||
ret = BZ2_bzCompressInit(&(bzip2->stream),
|
||||
bzip2->compression_level, 0, 30);
|
||||
if (ret == BZ_OK) {
|
||||
f->data = data;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -234,15 +250,12 @@ static int
|
||||
archive_compressor_bzip2_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
|
||||
/* Update statistics */
|
||||
data->total_in += length;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
|
||||
/* Compress input data to output buffer */
|
||||
SET_NEXT_IN(data, buff);
|
||||
data->stream.avail_in = (uint32_t)length;
|
||||
if (drive_compressor(f, data, 0))
|
||||
SET_NEXT_IN(bzip2, buff);
|
||||
bzip2->stream.avail_in = (uint32_t)length;
|
||||
if (drive_compressor(f, bzip2, 0))
|
||||
return (ARCHIVE_FATAL);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -254,19 +267,19 @@ archive_compressor_bzip2_write(struct archive_write_filter *f,
|
||||
static int
|
||||
archive_compressor_bzip2_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
int ret;
|
||||
|
||||
/* Finish compression cycle. */
|
||||
ret = drive_compressor(f, data, 1);
|
||||
ret = drive_compressor(f, bzip2, 1);
|
||||
if (ret == ARCHIVE_OK) {
|
||||
/* Write the last block */
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
data->compressed,
|
||||
data->compressed_buffer_size - data->stream.avail_out);
|
||||
bzip2->compressed,
|
||||
bzip2->compressed_buffer_size - bzip2->stream.avail_out);
|
||||
}
|
||||
|
||||
switch (BZ2_bzCompressEnd(&(data->stream))) {
|
||||
switch (BZ2_bzCompressEnd(&(bzip2->stream))) {
|
||||
case BZ_OK:
|
||||
break;
|
||||
default:
|
||||
@@ -277,20 +290,6 @@ archive_compressor_bzip2_close(struct archive_write_filter *f)
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility function to push input data through compressor, writing
|
||||
* full output blocks as necessary.
|
||||
@@ -300,35 +299,35 @@ archive_compressor_bzip2_free(struct archive_write_filter *f)
|
||||
*/
|
||||
static int
|
||||
drive_compressor(struct archive_write_filter *f,
|
||||
struct private_data *data, int finishing)
|
||||
struct bzip2 *bzip2, int finishing)
|
||||
{
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
if (data->stream.avail_out == 0) {
|
||||
if (bzip2->stream.avail_out == 0) {
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
data->compressed,
|
||||
data->compressed_buffer_size);
|
||||
bzip2->compressed,
|
||||
bzip2->compressed_buffer_size);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
/* TODO: Handle this write failure */
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->stream.next_out = data->compressed;
|
||||
data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
|
||||
bzip2->stream.next_out = bzip2->compressed;
|
||||
bzip2->stream.avail_out = (uint32_t)bzip2->compressed_buffer_size;
|
||||
}
|
||||
|
||||
/* If there's nothing to do, we're done. */
|
||||
if (!finishing && data->stream.avail_in == 0)
|
||||
if (!finishing && bzip2->stream.avail_in == 0)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
ret = BZ2_bzCompress(&(data->stream),
|
||||
ret = BZ2_bzCompress(&(bzip2->stream),
|
||||
finishing ? BZ_FINISH : BZ_RUN);
|
||||
|
||||
switch (ret) {
|
||||
case BZ_RUN_OK:
|
||||
/* In non-finishing case, did compressor
|
||||
* consume everything? */
|
||||
if (!finishing && data->stream.avail_in == 0)
|
||||
if (!finishing && bzip2->stream.avail_in == 0)
|
||||
return (ARCHIVE_OK);
|
||||
break;
|
||||
case BZ_FINISH_OK: /* Finishing: There's more work to do */
|
||||
@@ -348,12 +347,24 @@ drive_compressor(struct archive_write_filter *f,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct bzip2 *bzip2)
|
||||
{
|
||||
if (bzip2 != NULL) {
|
||||
/* May already have been called, but not necessarily. */
|
||||
(void)BZ2_bzCompressEnd(&(bzip2->stream));
|
||||
|
||||
free(bzip2->compressed);
|
||||
free(bzip2);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
|
||||
|
||||
static int
|
||||
archive_compressor_bzip2_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
struct archive_string as;
|
||||
int r;
|
||||
|
||||
@@ -361,13 +372,12 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
|
||||
archive_strcpy(&as, "bzip2");
|
||||
|
||||
/* Specify compression level. */
|
||||
if (data->compression_level > 0) {
|
||||
if (bzip2->compression_level > 0) {
|
||||
archive_strcat(&as, " -");
|
||||
archive_strappend_char(&as, '0' + data->compression_level);
|
||||
archive_strappend_char(&as, '0' + bzip2->compression_level);
|
||||
}
|
||||
f->write = archive_compressor_bzip2_write;
|
||||
|
||||
r = __archive_write_program_open(f, data->pdata, as.s);
|
||||
r = __archive_write_program_open(f, bzip2->pdata, as.s);
|
||||
archive_string_free(&as);
|
||||
return (r);
|
||||
}
|
||||
@@ -376,27 +386,26 @@ static int
|
||||
archive_compressor_bzip2_write(struct archive_write_filter *f, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
|
||||
return __archive_write_program_write(f, data->pdata, buff, length);
|
||||
return __archive_write_program_write(f, bzip2->pdata, buff, length);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_bzip2_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct bzip2 *bzip2 = f->data;
|
||||
|
||||
return __archive_write_program_close(f, data->pdata);
|
||||
return __archive_write_program_close(f, bzip2->pdata);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_bzip2_free(struct archive_write_filter *f)
|
||||
static void
|
||||
free_data(struct bzip2 *bzip2)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
|
||||
__archive_write_program_free(data->pdata);
|
||||
free(data);
|
||||
return (ARCHIVE_OK);
|
||||
if (bzip2 != NULL) {
|
||||
__archive_write_program_free(bzip2->pdata);
|
||||
free(bzip2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
#define FIRST 257 /* First free entry. */
|
||||
#define CLEAR 256 /* Table clear output code. */
|
||||
|
||||
struct private_data {
|
||||
struct compress {
|
||||
int64_t in_count, out_count, checkpoint;
|
||||
|
||||
int code_len; /* Number of bits/code. */
|
||||
@@ -111,6 +111,7 @@ static int archive_compressor_compress_write(struct archive_write_filter *,
|
||||
const void *, size_t);
|
||||
static int archive_compressor_compress_close(struct archive_write_filter *);
|
||||
static int archive_compressor_compress_free(struct archive_write_filter *);
|
||||
static void free_data(struct compress *);
|
||||
|
||||
#if ARCHIVE_VERSION_NUMBER < 4000000
|
||||
int
|
||||
@@ -125,17 +126,35 @@ archive_write_set_compression_compress(struct archive *a)
|
||||
* Add a compress filter to this write handle.
|
||||
*/
|
||||
int
|
||||
archive_write_add_filter_compress(struct archive *_a)
|
||||
archive_write_add_filter_compress(struct archive *a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct archive_write_filter *f;
|
||||
struct compress *compress;
|
||||
|
||||
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_compress");
|
||||
f->open = &archive_compressor_compress_open;
|
||||
f->code = ARCHIVE_FILTER_COMPRESS;
|
||||
|
||||
compress = calloc(1, sizeof(*compress));
|
||||
if (compress == NULL)
|
||||
goto memerr;
|
||||
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "compress";
|
||||
f->code = ARCHIVE_FILTER_COMPRESS;
|
||||
f->data = compress;
|
||||
f->open = archive_compressor_compress_open;
|
||||
f->write = archive_compressor_compress_write;
|
||||
f->close = archive_compressor_compress_close;
|
||||
f->free = archive_compressor_compress_free;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
memerr:
|
||||
free_data(compress);
|
||||
archive_set_error(a, ENOMEM,
|
||||
"Can't allocate data for compression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -144,19 +163,9 @@ archive_write_add_filter_compress(struct archive *_a)
|
||||
static int
|
||||
archive_compressor_compress_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *state;
|
||||
struct compress *compress = f->data;
|
||||
size_t bs = 65536, bpb;
|
||||
|
||||
f->code = ARCHIVE_FILTER_COMPRESS;
|
||||
f->name = "compress";
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
if (state == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
|
||||
/* Buffer size should be a multiple number of the bytes
|
||||
* per block for performance. */
|
||||
@@ -166,41 +175,38 @@ archive_compressor_compress_open(struct archive_write_filter *f)
|
||||
else if (bpb != 0)
|
||||
bs -= bs % bpb;
|
||||
}
|
||||
state->compressed_buffer_size = bs;
|
||||
state->compressed = malloc(state->compressed_buffer_size);
|
||||
compress->compressed_buffer_size = bs;
|
||||
compress->compressed = malloc(compress->compressed_buffer_size);
|
||||
|
||||
if (state->compressed == NULL) {
|
||||
if (compress->compressed == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression buffer");
|
||||
free(state);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
f->write = archive_compressor_compress_write;
|
||||
f->close = archive_compressor_compress_close;
|
||||
f->free = archive_compressor_compress_free;
|
||||
/* Should NEVER generate this code. */
|
||||
compress->max_maxcode = 0x10000;
|
||||
/* Length of input. */
|
||||
compress->in_count = 0;
|
||||
compress->bit_buf = 0;
|
||||
compress->bit_offset = 0;
|
||||
/* Includes 3-byte header mojo. */
|
||||
compress->out_count = 3;
|
||||
compress->compress_ratio = 0;
|
||||
compress->checkpoint = CHECK_GAP;
|
||||
compress->code_len = 9;
|
||||
compress->cur_maxcode = MAXCODE(compress->code_len);
|
||||
compress->first_free = FIRST;
|
||||
|
||||
state->max_maxcode = 0x10000; /* Should NEVER generate this code. */
|
||||
state->in_count = 0; /* Length of input. */
|
||||
state->bit_buf = 0;
|
||||
state->bit_offset = 0;
|
||||
state->out_count = 3; /* Includes 3-byte header mojo. */
|
||||
state->compress_ratio = 0;
|
||||
state->checkpoint = CHECK_GAP;
|
||||
state->code_len = 9;
|
||||
state->cur_maxcode = MAXCODE(state->code_len);
|
||||
state->first_free = FIRST;
|
||||
|
||||
memset(state->hashtab, 0xff, sizeof(state->hashtab));
|
||||
memset(compress->hashtab, 0xff, sizeof(compress->hashtab));
|
||||
|
||||
/* Prime output buffer with a gzip header. */
|
||||
state->compressed[0] = 0x1f; /* Compress */
|
||||
state->compressed[1] = 0x9d;
|
||||
state->compressed[2] = 0x90; /* Block mode, 16bit max */
|
||||
state->compressed_offset = 3;
|
||||
compress->compressed[0] = 0x1f; /* Compress */
|
||||
compress->compressed[1] = 0x9d;
|
||||
compress->compressed[2] = 0x90; /* Block mode, 16bit max */
|
||||
compress->compressed_offset = 3;
|
||||
|
||||
f->data = state;
|
||||
return (0);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*-
|
||||
@@ -224,17 +230,17 @@ static const unsigned char rmask[9] =
|
||||
static int
|
||||
output_byte(struct archive_write_filter *f, unsigned char c)
|
||||
{
|
||||
struct private_data *state = f->data;
|
||||
struct compress *compress = f->data;
|
||||
|
||||
state->compressed[state->compressed_offset++] = c;
|
||||
++state->out_count;
|
||||
compress->compressed[compress->compressed_offset++] = c;
|
||||
++compress->out_count;
|
||||
|
||||
if (state->compressed_buffer_size == state->compressed_offset) {
|
||||
if (compress->compressed_buffer_size == compress->compressed_offset) {
|
||||
int ret = __archive_write_filter(f->next_filter,
|
||||
state->compressed, state->compressed_buffer_size);
|
||||
compress->compressed, compress->compressed_buffer_size);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ARCHIVE_FATAL;
|
||||
state->compressed_offset = 0;
|
||||
compress->compressed_offset = 0;
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
@@ -243,7 +249,7 @@ output_byte(struct archive_write_filter *f, unsigned char c)
|
||||
static int
|
||||
output_code(struct archive_write_filter *f, int ocode)
|
||||
{
|
||||
struct private_data *state = f->data;
|
||||
struct compress *compress = f->data;
|
||||
int bits, ret, clear_flg, bit_offset;
|
||||
|
||||
clear_flg = ocode == CLEAR;
|
||||
@@ -252,11 +258,11 @@ output_code(struct archive_write_filter *f, int ocode)
|
||||
* Since ocode is always >= 8 bits, only need to mask the first
|
||||
* hunk on the left.
|
||||
*/
|
||||
bit_offset = state->bit_offset % 8;
|
||||
state->bit_buf |= (ocode << bit_offset) & 0xff;
|
||||
output_byte(f, state->bit_buf);
|
||||
bit_offset = compress->bit_offset % 8;
|
||||
compress->bit_buf |= (ocode << bit_offset) & 0xff;
|
||||
output_byte(f, compress->bit_buf);
|
||||
|
||||
bits = state->code_len - (8 - bit_offset);
|
||||
bits = compress->code_len - (8 - bit_offset);
|
||||
ocode >>= 8 - bit_offset;
|
||||
/* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
|
||||
if (bits >= 8) {
|
||||
@@ -265,41 +271,41 @@ output_code(struct archive_write_filter *f, int ocode)
|
||||
bits -= 8;
|
||||
}
|
||||
/* Last bits. */
|
||||
state->bit_offset += state->code_len;
|
||||
state->bit_buf = ocode & rmask[bits];
|
||||
if (state->bit_offset == state->code_len * 8)
|
||||
state->bit_offset = 0;
|
||||
compress->bit_offset += compress->code_len;
|
||||
compress->bit_buf = ocode & rmask[bits];
|
||||
if (compress->bit_offset == compress->code_len * 8)
|
||||
compress->bit_offset = 0;
|
||||
|
||||
/*
|
||||
* If the next entry is going to be too big for the ocode size,
|
||||
* then increase it, if possible.
|
||||
*/
|
||||
if (clear_flg || state->first_free > state->cur_maxcode) {
|
||||
if (clear_flg || compress->first_free > compress->cur_maxcode) {
|
||||
/*
|
||||
* Write the whole buffer, because the input side won't
|
||||
* discover the size increase until after it has read it.
|
||||
*/
|
||||
if (state->bit_offset > 0) {
|
||||
while (state->bit_offset < state->code_len * 8) {
|
||||
ret = output_byte(f, state->bit_buf);
|
||||
if (compress->bit_offset > 0) {
|
||||
while (compress->bit_offset < compress->code_len * 8) {
|
||||
ret = output_byte(f, compress->bit_buf);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
state->bit_offset += 8;
|
||||
state->bit_buf = 0;
|
||||
compress->bit_offset += 8;
|
||||
compress->bit_buf = 0;
|
||||
}
|
||||
}
|
||||
state->bit_buf = 0;
|
||||
state->bit_offset = 0;
|
||||
compress->bit_buf = 0;
|
||||
compress->bit_offset = 0;
|
||||
|
||||
if (clear_flg) {
|
||||
state->code_len = 9;
|
||||
state->cur_maxcode = MAXCODE(state->code_len);
|
||||
compress->code_len = 9;
|
||||
compress->cur_maxcode = MAXCODE(compress->code_len);
|
||||
} else {
|
||||
state->code_len++;
|
||||
if (state->code_len == 16)
|
||||
state->cur_maxcode = state->max_maxcode;
|
||||
compress->code_len++;
|
||||
if (compress->code_len == 16)
|
||||
compress->cur_maxcode = compress->max_maxcode;
|
||||
else
|
||||
state->cur_maxcode = MAXCODE(state->code_len);
|
||||
compress->cur_maxcode = MAXCODE(compress->code_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,13 +315,13 @@ output_code(struct archive_write_filter *f, int ocode)
|
||||
static int
|
||||
output_flush(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *state = f->data;
|
||||
struct compress *compress = f->data;
|
||||
int ret;
|
||||
|
||||
/* At EOF, write the rest of the buffer. */
|
||||
if (state->bit_offset % 8) {
|
||||
state->code_len = (state->bit_offset % 8 + 7) / 8;
|
||||
ret = output_byte(f, state->bit_buf);
|
||||
if (compress->bit_offset % 8) {
|
||||
compress->code_len = (compress->bit_offset % 8 + 7) / 8;
|
||||
ret = output_byte(f, compress->bit_buf);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
}
|
||||
@@ -330,7 +336,7 @@ static int
|
||||
archive_compressor_compress_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)f->data;
|
||||
struct compress *compress = f->data;
|
||||
int i;
|
||||
int ratio;
|
||||
int c, disp, ret;
|
||||
@@ -341,23 +347,24 @@ archive_compressor_compress_write(struct archive_write_filter *f,
|
||||
|
||||
bp = buff;
|
||||
|
||||
if (state->in_count == 0) {
|
||||
state->cur_code = *bp++;
|
||||
++state->in_count;
|
||||
if (compress->in_count == 0) {
|
||||
compress->cur_code = *bp++;
|
||||
++compress->in_count;
|
||||
--length;
|
||||
}
|
||||
|
||||
while (length--) {
|
||||
c = *bp++;
|
||||
state->in_count++;
|
||||
state->cur_fcode = (c << 16) | state->cur_code;
|
||||
i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */
|
||||
compress->in_count++;
|
||||
compress->cur_fcode = (c << 16) | compress->cur_code;
|
||||
/* Xor hashing. */
|
||||
i = ((c << HSHIFT) ^ compress->cur_code);
|
||||
|
||||
if (state->hashtab[i] == state->cur_fcode) {
|
||||
state->cur_code = state->codetab[i];
|
||||
if (compress->hashtab[i] == compress->cur_fcode) {
|
||||
compress->cur_code = compress->codetab[i];
|
||||
continue;
|
||||
}
|
||||
if (state->hashtab[i] < 0) /* Empty slot. */
|
||||
if (compress->hashtab[i] < 0) /* Empty slot. */
|
||||
goto nomatch;
|
||||
/* Secondary hash (after G. Knott). */
|
||||
if (i == 0)
|
||||
@@ -368,40 +375,40 @@ archive_compressor_compress_write(struct archive_write_filter *f,
|
||||
if ((i -= disp) < 0)
|
||||
i += HSIZE;
|
||||
|
||||
if (state->hashtab[i] == state->cur_fcode) {
|
||||
state->cur_code = state->codetab[i];
|
||||
if (compress->hashtab[i] == compress->cur_fcode) {
|
||||
compress->cur_code = compress->codetab[i];
|
||||
continue;
|
||||
}
|
||||
if (state->hashtab[i] >= 0)
|
||||
if (compress->hashtab[i] >= 0)
|
||||
goto probe;
|
||||
nomatch:
|
||||
ret = output_code(f, state->cur_code);
|
||||
ret = output_code(f, compress->cur_code);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
state->cur_code = c;
|
||||
if (state->first_free < state->max_maxcode) {
|
||||
state->codetab[i] = state->first_free++; /* code -> hashtable */
|
||||
state->hashtab[i] = state->cur_fcode;
|
||||
compress->cur_code = c;
|
||||
if (compress->first_free < compress->max_maxcode) {
|
||||
compress->codetab[i] = compress->first_free++; /* code -> hashtable */
|
||||
compress->hashtab[i] = compress->cur_fcode;
|
||||
continue;
|
||||
}
|
||||
if (state->in_count < state->checkpoint)
|
||||
if (compress->in_count < compress->checkpoint)
|
||||
continue;
|
||||
|
||||
state->checkpoint = state->in_count + CHECK_GAP;
|
||||
compress->checkpoint = compress->in_count + CHECK_GAP;
|
||||
|
||||
if (state->in_count <= 0x007fffff && state->out_count != 0)
|
||||
ratio = (int)(state->in_count * 256 / state->out_count);
|
||||
else if ((ratio = (int)(state->out_count / 256)) == 0)
|
||||
if (compress->in_count <= 0x007fffff && compress->out_count != 0)
|
||||
ratio = (int)(compress->in_count * 256 / compress->out_count);
|
||||
else if ((ratio = (int)(compress->out_count / 256)) == 0)
|
||||
ratio = 0x7fffffff;
|
||||
else
|
||||
ratio = (int)(state->in_count / ratio);
|
||||
ratio = (int)(compress->in_count / ratio);
|
||||
|
||||
if (ratio > state->compress_ratio)
|
||||
state->compress_ratio = ratio;
|
||||
if (ratio > compress->compress_ratio)
|
||||
compress->compress_ratio = ratio;
|
||||
else {
|
||||
state->compress_ratio = 0;
|
||||
memset(state->hashtab, 0xff, sizeof(state->hashtab));
|
||||
state->first_free = FIRST;
|
||||
compress->compress_ratio = 0;
|
||||
memset(compress->hashtab, 0xff, sizeof(compress->hashtab));
|
||||
compress->first_free = FIRST;
|
||||
ret = output_code(f, CLEAR);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
@@ -418,10 +425,10 @@ archive_compressor_compress_write(struct archive_write_filter *f,
|
||||
static int
|
||||
archive_compressor_compress_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)f->data;
|
||||
struct compress *compress = f->data;
|
||||
int ret;
|
||||
|
||||
ret = output_code(f, state->cur_code);
|
||||
ret = output_code(f, compress->cur_code);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
ret = output_flush(f);
|
||||
@@ -430,16 +437,23 @@ archive_compressor_compress_close(struct archive_write_filter *f)
|
||||
|
||||
/* Write the last block */
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
state->compressed, state->compressed_offset);
|
||||
compress->compressed, compress->compressed_offset);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_compress_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *state = (struct private_data *)f->data;
|
||||
|
||||
free(state->compressed);
|
||||
free(state);
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct compress *compress)
|
||||
{
|
||||
if (compress != NULL) {
|
||||
free(compress->compressed);
|
||||
free(compress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "archive.h"
|
||||
#include "archive_write_private.h"
|
||||
|
||||
struct write_grzip {
|
||||
struct grzip {
|
||||
struct archive_write_program_data *pdata;
|
||||
};
|
||||
|
||||
@@ -46,42 +46,45 @@ static int archive_write_grzip_write(struct archive_write_filter *,
|
||||
const void *, size_t);
|
||||
static int archive_write_grzip_close(struct archive_write_filter *);
|
||||
static int archive_write_grzip_free(struct archive_write_filter *);
|
||||
static void free_data(struct grzip *);
|
||||
|
||||
int
|
||||
archive_write_add_filter_grzip(struct archive *_a)
|
||||
archive_write_add_filter_grzip(struct archive *a)
|
||||
{
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct write_grzip *data;
|
||||
struct archive_write_filter *f;
|
||||
struct grzip *grzip;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_grzip");
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if (data == NULL) {
|
||||
archive_set_error(_a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->pdata = __archive_write_program_allocate("grzip");
|
||||
if (data->pdata == NULL) {
|
||||
free(data);
|
||||
archive_set_error(_a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
grzip = calloc(1, sizeof(*grzip));
|
||||
if (grzip == NULL)
|
||||
goto memerr;
|
||||
grzip->pdata = __archive_write_program_allocate("grzip");
|
||||
if (grzip->pdata == NULL)
|
||||
goto memerr;
|
||||
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "grzip";
|
||||
f->code = ARCHIVE_FILTER_GRZIP;
|
||||
f->data = data;
|
||||
f->open = archive_write_grzip_open;
|
||||
f->data = grzip;
|
||||
f->options = archive_write_grzip_options;
|
||||
f->open = archive_write_grzip_open;
|
||||
f->write = archive_write_grzip_write;
|
||||
f->close = archive_write_grzip_close;
|
||||
f->free = archive_write_grzip_free;
|
||||
|
||||
/* Note: This filter always uses an external program, so we
|
||||
* return "warn" to inform of the fact. */
|
||||
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Using external grzip program for grzip compression");
|
||||
return (ARCHIVE_WARN);
|
||||
memerr:
|
||||
free_data(grzip);
|
||||
archive_set_error(a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -100,34 +103,41 @@ archive_write_grzip_options(struct archive_write_filter *f, const char *key,
|
||||
static int
|
||||
archive_write_grzip_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_grzip *data = (struct write_grzip *)f->data;
|
||||
struct grzip *grzip = f->data;
|
||||
|
||||
return __archive_write_program_open(f, data->pdata, "grzip");
|
||||
return __archive_write_program_open(f, grzip->pdata, "grzip");
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_grzip_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct write_grzip *data = (struct write_grzip *)f->data;
|
||||
struct grzip *grzip = f->data;
|
||||
|
||||
return __archive_write_program_write(f, data->pdata, buff, length);
|
||||
return __archive_write_program_write(f, grzip->pdata, buff, length);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_grzip_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_grzip *data = (struct write_grzip *)f->data;
|
||||
struct grzip *grzip = f->data;
|
||||
|
||||
return __archive_write_program_close(f, data->pdata);
|
||||
return __archive_write_program_close(f, grzip->pdata);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_grzip_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_grzip *data = (struct write_grzip *)f->data;
|
||||
|
||||
__archive_write_program_free(data->pdata);
|
||||
free(data);
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct grzip *grzip)
|
||||
{
|
||||
if (grzip != NULL) {
|
||||
__archive_write_program_free(grzip->pdata);
|
||||
free(grzip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_endian.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_string.h"
|
||||
#include "archive_write_private.h"
|
||||
@@ -55,13 +56,13 @@ archive_write_set_compression_gzip(struct archive *a)
|
||||
|
||||
/* Don't compile this if we don't have zlib. */
|
||||
|
||||
struct private_data {
|
||||
struct gzip {
|
||||
int compression_level;
|
||||
int timestamp;
|
||||
char *original_filename;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
z_stream stream;
|
||||
int64_t total_in;
|
||||
uint64_t total_in;
|
||||
unsigned char *compressed;
|
||||
size_t compressed_buffer_size;
|
||||
unsigned long crc;
|
||||
@@ -86,65 +87,66 @@ static int archive_compressor_gzip_close(struct archive_write_filter *);
|
||||
static int archive_compressor_gzip_free(struct archive_write_filter *);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
static int drive_compressor(struct archive_write_filter *,
|
||||
struct private_data *, int finishing);
|
||||
struct gzip *, int finishing);
|
||||
#endif
|
||||
static void free_data(struct gzip *);
|
||||
|
||||
|
||||
/*
|
||||
* Add a gzip compression filter to this write handle.
|
||||
*/
|
||||
int
|
||||
archive_write_add_filter_gzip(struct archive *_a)
|
||||
archive_write_add_filter_gzip(struct archive *a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct private_data *data;
|
||||
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
|
||||
struct archive_write_filter *f;
|
||||
struct gzip *gzip;
|
||||
int r;
|
||||
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip");
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if (data == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
f->data = data;
|
||||
f->open = &archive_compressor_gzip_open;
|
||||
f->options = &archive_compressor_gzip_options;
|
||||
f->close = &archive_compressor_gzip_close;
|
||||
f->free = &archive_compressor_gzip_free;
|
||||
f->code = ARCHIVE_FILTER_GZIP;
|
||||
f->name = "gzip";
|
||||
|
||||
data->original_filename = NULL;
|
||||
gzip = calloc(1, sizeof(*gzip));
|
||||
if (gzip == NULL)
|
||||
goto memerr;
|
||||
gzip->original_filename = NULL;
|
||||
#ifdef HAVE_ZLIB_H
|
||||
data->compression_level = Z_DEFAULT_COMPRESSION;
|
||||
return (ARCHIVE_OK);
|
||||
gzip->compression_level = Z_DEFAULT_COMPRESSION;
|
||||
|
||||
r = ARCHIVE_OK;
|
||||
#else
|
||||
data->pdata = __archive_write_program_allocate("gzip");
|
||||
if (data->pdata == NULL) {
|
||||
free(data);
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->compression_level = 0;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
gzip->pdata = __archive_write_program_allocate("gzip");
|
||||
if (gzip->pdata == NULL)
|
||||
goto memerr;
|
||||
gzip->compression_level = 0;
|
||||
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Using external gzip program");
|
||||
return (ARCHIVE_WARN);
|
||||
r = ARCHIVE_WARN;
|
||||
#endif
|
||||
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "gzip";
|
||||
f->code = ARCHIVE_FILTER_GZIP;
|
||||
f->data = gzip;
|
||||
f->options = archive_compressor_gzip_options;
|
||||
f->open = archive_compressor_gzip_open;
|
||||
f->write = archive_compressor_gzip_write;
|
||||
f->close = archive_compressor_gzip_close;
|
||||
f->free = archive_compressor_gzip_free;
|
||||
|
||||
return (r);
|
||||
memerr:
|
||||
free_data(gzip);
|
||||
archive_set_error(a, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_gzip_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
free(data->compressed);
|
||||
#else
|
||||
__archive_write_program_free(data->pdata);
|
||||
#endif
|
||||
free((void*)data->original_filename);
|
||||
free(data);
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -156,24 +158,30 @@ static int
|
||||
archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct gzip *gzip = f->data;
|
||||
|
||||
if (strcmp(key, "compression-level") == 0) {
|
||||
if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
|
||||
value[1] != '\0')
|
||||
return (ARCHIVE_WARN);
|
||||
data->compression_level = value[0] - '0';
|
||||
value[1] != '\0') {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"compression-level invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
gzip->compression_level = value[0] - '0';
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (strcmp(key, "timestamp") == 0) {
|
||||
data->timestamp = (value == NULL)?-1:1;
|
||||
gzip->timestamp = (value == NULL)?-1:1;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (strcmp(key, "original-filename") == 0) {
|
||||
free((void*)data->original_filename);
|
||||
data->original_filename = NULL;
|
||||
if (value)
|
||||
data->original_filename = strdup(value);
|
||||
free((void*)gzip->original_filename);
|
||||
gzip->original_filename = NULL;
|
||||
if (value) {
|
||||
gzip->original_filename = strdup(value);
|
||||
if (gzip->original_filename == NULL)
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -190,11 +198,11 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
|
||||
static int
|
||||
archive_compressor_gzip_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct gzip *gzip = f->data;
|
||||
int ret = ARCHIVE_OK;
|
||||
int init_success;
|
||||
|
||||
if (data->compressed == NULL) {
|
||||
if (gzip->compressed == NULL) {
|
||||
size_t bs = 65536, bpb;
|
||||
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
|
||||
/* Buffer size should be a multiple number of
|
||||
@@ -205,63 +213,60 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
|
||||
else if (bpb != 0)
|
||||
bs -= bs % bpb;
|
||||
}
|
||||
data->compressed_buffer_size = bs;
|
||||
data->compressed = malloc(data->compressed_buffer_size);
|
||||
if (data->compressed == NULL) {
|
||||
gzip->compressed_buffer_size = bs;
|
||||
gzip->compressed = malloc(gzip->compressed_buffer_size);
|
||||
if (gzip->compressed == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
|
||||
data->crc = crc32(0L, NULL, 0);
|
||||
data->stream.next_out = data->compressed;
|
||||
data->stream.avail_out = (uInt)data->compressed_buffer_size;
|
||||
gzip->crc = crc32(0L, NULL, 0);
|
||||
gzip->stream.next_out = gzip->compressed;
|
||||
gzip->stream.avail_out = (uInt)gzip->compressed_buffer_size;
|
||||
|
||||
/* Prime output buffer with a gzip header. */
|
||||
data->compressed[0] = 0x1f; /* GZip signature bytes */
|
||||
data->compressed[1] = 0x8b;
|
||||
data->compressed[2] = 0x08; /* "Deflate" compression */
|
||||
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;
|
||||
gzip->compressed[0] = 0x1f; /* GZip signature bytes */
|
||||
gzip->compressed[1] = 0x8b;
|
||||
gzip->compressed[2] = 0x08; /* "Deflate" compression */
|
||||
gzip->compressed[3] = 0x00; /* Flags */
|
||||
if (gzip->timestamp >= 0) {
|
||||
uint32_t t = (uint32_t)time(NULL);
|
||||
archive_le32enc(gzip->compressed + 4, t); /* Timestamp */
|
||||
} else {
|
||||
memset(&data->compressed[4], 0, 4);
|
||||
memset(&gzip->compressed[4], 0, 4);
|
||||
}
|
||||
if (data->compression_level == 9) {
|
||||
data->compressed[8] = 2;
|
||||
} else if(data->compression_level == 1) {
|
||||
data->compressed[8] = 4;
|
||||
if (gzip->compression_level == 9) {
|
||||
gzip->compressed[8] = 2;
|
||||
} else if(gzip->compression_level == 1) {
|
||||
gzip->compressed[8] = 4;
|
||||
} else {
|
||||
data->compressed[8] = 0;
|
||||
gzip->compressed[8] = 0;
|
||||
}
|
||||
data->compressed[9] = 3; /* OS=Unix */
|
||||
data->stream.next_out += 10;
|
||||
data->stream.avail_out -= 10;
|
||||
gzip->compressed[9] = 3; /* OS=Unix */
|
||||
gzip->stream.next_out += 10;
|
||||
gzip->stream.avail_out -= 10;
|
||||
|
||||
if (data->original_filename != NULL) {
|
||||
if (gzip->original_filename != NULL) {
|
||||
/* 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
|
||||
size_t ofn_length = strlen(gzip->original_filename);
|
||||
size_t ofn_max_length = 32768;
|
||||
size_t ofn_space_available = gzip->compressed
|
||||
+ gzip->compressed_buffer_size
|
||||
- gzip->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;
|
||||
gzip->compressed[3] |= 0x8;
|
||||
strcpy((char*)gzip->compressed + 10,
|
||||
gzip->original_filename);
|
||||
gzip->stream.next_out += ofn_length + 1;
|
||||
gzip->stream.avail_out -= ofn_length + 1;
|
||||
} else {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Gzip 'Original Filename' ignored because it is too long");
|
||||
@@ -269,18 +274,15 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
|
||||
}
|
||||
}
|
||||
|
||||
f->write = archive_compressor_gzip_write;
|
||||
|
||||
/* Initialize compression library. */
|
||||
init_success = deflateInit2(&(data->stream),
|
||||
data->compression_level,
|
||||
init_success = deflateInit2(&(gzip->stream),
|
||||
gzip->compression_level,
|
||||
Z_DEFLATED,
|
||||
-15 /* < 0 to suppress zlib header */,
|
||||
8,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
|
||||
if (init_success == Z_OK) {
|
||||
f->data = data;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -316,17 +318,17 @@ static int
|
||||
archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct gzip *gzip = f->data;
|
||||
int ret;
|
||||
|
||||
/* Update statistics */
|
||||
data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length);
|
||||
data->total_in += length;
|
||||
gzip->crc = crc32(gzip->crc, (const Bytef *)buff, (uInt)length);
|
||||
gzip->total_in += length;
|
||||
|
||||
/* Compress input data to output buffer */
|
||||
SET_NEXT_IN(data, buff);
|
||||
data->stream.avail_in = (uInt)length;
|
||||
if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
|
||||
SET_NEXT_IN(gzip, buff);
|
||||
gzip->stream.avail_in = (uInt)length;
|
||||
if ((ret = drive_compressor(f, gzip, 0)) != ARCHIVE_OK)
|
||||
return (ret);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
@@ -338,32 +340,26 @@ archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
|
||||
static int
|
||||
archive_compressor_gzip_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct gzip *gzip = f->data;
|
||||
unsigned char trailer[8];
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
int ret;
|
||||
|
||||
/* Finish compression cycle */
|
||||
ret = drive_compressor(f, data, 1);
|
||||
ret = drive_compressor(f, gzip, 1);
|
||||
if (ret == ARCHIVE_OK) {
|
||||
/* Write the last compressed data. */
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
data->compressed,
|
||||
data->compressed_buffer_size - data->stream.avail_out);
|
||||
gzip->compressed,
|
||||
gzip->compressed_buffer_size - gzip->stream.avail_out);
|
||||
}
|
||||
if (ret == ARCHIVE_OK) {
|
||||
/* Build and write out 8-byte trailer. */
|
||||
trailer[0] = (uint8_t)(data->crc)&0xff;
|
||||
trailer[1] = (uint8_t)(data->crc >> 8)&0xff;
|
||||
trailer[2] = (uint8_t)(data->crc >> 16)&0xff;
|
||||
trailer[3] = (uint8_t)(data->crc >> 24)&0xff;
|
||||
trailer[4] = (uint8_t)(data->total_in)&0xff;
|
||||
trailer[5] = (uint8_t)(data->total_in >> 8)&0xff;
|
||||
trailer[6] = (uint8_t)(data->total_in >> 16)&0xff;
|
||||
trailer[7] = (uint8_t)(data->total_in >> 24)&0xff;
|
||||
archive_le32enc(trailer, gzip->crc);
|
||||
archive_le32enc(trailer + 4, gzip->total_in);
|
||||
ret = __archive_write_filter(f->next_filter, trailer, 8);
|
||||
}
|
||||
|
||||
switch (deflateEnd(&(data->stream))) {
|
||||
switch (deflateEnd(&(gzip->stream))) {
|
||||
case Z_OK:
|
||||
break;
|
||||
default:
|
||||
@@ -383,34 +379,34 @@ archive_compressor_gzip_close(struct archive_write_filter *f)
|
||||
*/
|
||||
static int
|
||||
drive_compressor(struct archive_write_filter *f,
|
||||
struct private_data *data, int finishing)
|
||||
struct gzip *gzip, int finishing)
|
||||
{
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
if (data->stream.avail_out == 0) {
|
||||
if (gzip->stream.avail_out == 0) {
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
data->compressed,
|
||||
data->compressed_buffer_size);
|
||||
gzip->compressed,
|
||||
gzip->compressed_buffer_size);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
data->stream.next_out = data->compressed;
|
||||
data->stream.avail_out =
|
||||
(uInt)data->compressed_buffer_size;
|
||||
gzip->stream.next_out = gzip->compressed;
|
||||
gzip->stream.avail_out =
|
||||
(uInt)gzip->compressed_buffer_size;
|
||||
}
|
||||
|
||||
/* If there's nothing to do, we're done. */
|
||||
if (!finishing && data->stream.avail_in == 0)
|
||||
if (!finishing && gzip->stream.avail_in == 0)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
ret = deflate(&(data->stream),
|
||||
ret = deflate(&(gzip->stream),
|
||||
finishing ? Z_FINISH : Z_NO_FLUSH );
|
||||
|
||||
switch (ret) {
|
||||
case Z_OK:
|
||||
/* In non-finishing case, check if compressor
|
||||
* consumed everything */
|
||||
if (!finishing && data->stream.avail_in == 0)
|
||||
if (!finishing && gzip->stream.avail_in == 0)
|
||||
return (ARCHIVE_OK);
|
||||
/* In finishing case, this return always means
|
||||
* there's more work */
|
||||
@@ -429,12 +425,22 @@ drive_compressor(struct archive_write_filter *f,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct gzip *gzip)
|
||||
{
|
||||
if (gzip != NULL) {
|
||||
free(gzip->compressed);
|
||||
free(gzip->original_filename);
|
||||
free(gzip);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* HAVE_ZLIB_H */
|
||||
|
||||
static int
|
||||
archive_compressor_gzip_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct gzip *gzip = f->data;
|
||||
struct archive_string as;
|
||||
int r;
|
||||
|
||||
@@ -442,19 +448,18 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
|
||||
archive_strcpy(&as, "gzip");
|
||||
|
||||
/* Specify compression level. */
|
||||
if (data->compression_level > 0) {
|
||||
if (gzip->compression_level > 0) {
|
||||
archive_strcat(&as, " -");
|
||||
archive_strappend_char(&as, '0' + data->compression_level);
|
||||
archive_strappend_char(&as, '0' + gzip->compression_level);
|
||||
}
|
||||
if (data->timestamp < 0)
|
||||
if (gzip->timestamp < 0)
|
||||
/* Do not save timestamp. */
|
||||
archive_strcat(&as, " -n");
|
||||
else if (data->timestamp > 0)
|
||||
else if (gzip->timestamp > 0)
|
||||
/* Save timestamp. */
|
||||
archive_strcat(&as, " -N");
|
||||
|
||||
f->write = archive_compressor_gzip_write;
|
||||
r = __archive_write_program_open(f, data->pdata, as.s);
|
||||
r = __archive_write_program_open(f, gzip->pdata, as.s);
|
||||
archive_string_free(&as);
|
||||
return (r);
|
||||
}
|
||||
@@ -463,17 +468,26 @@ static int
|
||||
archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct gzip *gzip = f->data;
|
||||
|
||||
return __archive_write_program_write(f, data->pdata, buff, length);
|
||||
return __archive_write_program_write(f, gzip->pdata, buff, length);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_gzip_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct gzip *gzip = f->data;
|
||||
|
||||
return __archive_write_program_close(f, data->pdata);
|
||||
return __archive_write_program_close(f, gzip->pdata);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct gzip *gzip)
|
||||
{
|
||||
if (gzip != NULL) {
|
||||
__archive_write_program_free(gzip->pdata);
|
||||
free(gzip->original_filename);
|
||||
free(gzip);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_ZLIB_H */
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include "archive_string.h"
|
||||
#include "archive_write_private.h"
|
||||
|
||||
struct write_lrzip {
|
||||
struct lrzip {
|
||||
struct archive_write_program_data *pdata;
|
||||
int compression_level;
|
||||
enum { lzma = 0, bzip2, gzip, lzo, none, zpaq } compression;
|
||||
@@ -52,71 +52,83 @@ static int archive_write_lrzip_write(struct archive_write_filter *,
|
||||
const void *, size_t);
|
||||
static int archive_write_lrzip_close(struct archive_write_filter *);
|
||||
static int archive_write_lrzip_free(struct archive_write_filter *);
|
||||
static void free_data(struct lrzip *);
|
||||
|
||||
int
|
||||
archive_write_add_filter_lrzip(struct archive *_a)
|
||||
archive_write_add_filter_lrzip(struct archive *a)
|
||||
{
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct write_lrzip *data;
|
||||
struct archive_write_filter *f;
|
||||
struct lrzip *lrzip;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_lrzip");
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if (data == NULL) {
|
||||
archive_set_error(_a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->pdata = __archive_write_program_allocate("lrzip");
|
||||
if (data->pdata == NULL) {
|
||||
free(data);
|
||||
archive_set_error(_a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
lrzip = calloc(1, sizeof(*lrzip));
|
||||
if (lrzip == NULL)
|
||||
goto memerr;
|
||||
lrzip->pdata = __archive_write_program_allocate("lrzip");
|
||||
if (lrzip->pdata == NULL)
|
||||
goto memerr;
|
||||
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "lrzip";
|
||||
f->code = ARCHIVE_FILTER_LRZIP;
|
||||
f->data = data;
|
||||
f->open = archive_write_lrzip_open;
|
||||
f->data = lrzip;
|
||||
f->options = archive_write_lrzip_options;
|
||||
f->open = archive_write_lrzip_open;
|
||||
f->write = archive_write_lrzip_write;
|
||||
f->close = archive_write_lrzip_close;
|
||||
f->free = archive_write_lrzip_free;
|
||||
|
||||
/* Note: This filter always uses an external program, so we
|
||||
* return "warn" to inform of the fact. */
|
||||
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Using external lrzip program for lrzip compression");
|
||||
return (ARCHIVE_WARN);
|
||||
memerr:
|
||||
free_data(lrzip);
|
||||
archive_set_error(a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
struct write_lrzip *data = (struct write_lrzip *)f->data;
|
||||
struct lrzip *lrzip = f->data;
|
||||
|
||||
if (strcmp(key, "compression") == 0) {
|
||||
if (value == NULL)
|
||||
return (ARCHIVE_WARN);
|
||||
if (value == NULL) {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"compression option requires an argument");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
else if (strcmp(value, "bzip2") == 0)
|
||||
data->compression = bzip2;
|
||||
lrzip->compression = bzip2;
|
||||
else if (strcmp(value, "gzip") == 0)
|
||||
data->compression = gzip;
|
||||
lrzip->compression = gzip;
|
||||
else if (strcmp(value, "lzo") == 0)
|
||||
data->compression = lzo;
|
||||
lrzip->compression = lzo;
|
||||
else if (strcmp(value, "none") == 0)
|
||||
data->compression = none;
|
||||
lrzip->compression = none;
|
||||
else if (strcmp(value, "zpaq") == 0)
|
||||
data->compression = zpaq;
|
||||
else
|
||||
return (ARCHIVE_WARN);
|
||||
lrzip->compression = zpaq;
|
||||
else {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"compression invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
} else if (strcmp(key, "compression-level") == 0) {
|
||||
if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
|
||||
value[1] != '\0')
|
||||
return (ARCHIVE_WARN);
|
||||
data->compression_level = value[0] - '0';
|
||||
value[1] != '\0') {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"compression-level invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lrzip->compression_level = value[0] - '0';
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
/* Note: The "warn" return is just to inform the options
|
||||
@@ -128,7 +140,7 @@ archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
|
||||
static int
|
||||
archive_write_lrzip_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lrzip *data = (struct write_lrzip *)f->data;
|
||||
struct lrzip *lrzip = f->data;
|
||||
struct archive_string as;
|
||||
int r;
|
||||
|
||||
@@ -136,7 +148,7 @@ archive_write_lrzip_open(struct archive_write_filter *f)
|
||||
archive_strcpy(&as, "lrzip -q");
|
||||
|
||||
/* Specify compression type. */
|
||||
switch (data->compression) {
|
||||
switch (lrzip->compression) {
|
||||
case lzma:/* default compression */
|
||||
break;
|
||||
case bzip2:
|
||||
@@ -157,12 +169,12 @@ archive_write_lrzip_open(struct archive_write_filter *f)
|
||||
}
|
||||
|
||||
/* Specify compression level. */
|
||||
if (data->compression_level > 0) {
|
||||
if (lrzip->compression_level > 0) {
|
||||
archive_strcat(&as, " -L ");
|
||||
archive_strappend_char(&as, '0' + data->compression_level);
|
||||
archive_strappend_char(&as, '0' + lrzip->compression_level);
|
||||
}
|
||||
|
||||
r = __archive_write_program_open(f, data->pdata, as.s);
|
||||
r = __archive_write_program_open(f, lrzip->pdata, as.s);
|
||||
archive_string_free(&as);
|
||||
return (r);
|
||||
}
|
||||
@@ -171,25 +183,32 @@ static int
|
||||
archive_write_lrzip_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct write_lrzip *data = (struct write_lrzip *)f->data;
|
||||
struct lrzip *lrzip = f->data;
|
||||
|
||||
return __archive_write_program_write(f, data->pdata, buff, length);
|
||||
return __archive_write_program_write(f, lrzip->pdata, buff, length);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_lrzip_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lrzip *data = (struct write_lrzip *)f->data;
|
||||
struct lrzip *lrzip = f->data;
|
||||
|
||||
return __archive_write_program_close(f, data->pdata);
|
||||
return __archive_write_program_close(f, lrzip->pdata);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_lrzip_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lrzip *data = (struct write_lrzip *)f->data;
|
||||
|
||||
__archive_write_program_free(data->pdata);
|
||||
free(data);
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct lrzip *lrzip)
|
||||
{
|
||||
if (lrzip != NULL) {
|
||||
__archive_write_program_free(lrzip->pdata);
|
||||
free(lrzip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
#define LZ4_MAGICNUMBER 0x184d2204
|
||||
|
||||
struct private_data {
|
||||
struct lz4 {
|
||||
int compression_level;
|
||||
unsigned header_written:1;
|
||||
unsigned version_number:1;
|
||||
@@ -61,7 +61,6 @@ struct private_data {
|
||||
unsigned preset_dictionary:1;
|
||||
unsigned block_maximum_size:3;
|
||||
#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2
|
||||
int64_t total_in;
|
||||
char *out;
|
||||
char *out_buffer;
|
||||
size_t out_buffer_size;
|
||||
@@ -86,66 +85,81 @@ static int archive_filter_lz4_options(struct archive_write_filter *,
|
||||
const char *, const char *);
|
||||
static int archive_filter_lz4_write(struct archive_write_filter *,
|
||||
const void *, size_t);
|
||||
static void free_data(struct lz4 *);
|
||||
|
||||
/*
|
||||
* Add a lz4 compression filter to this write handle.
|
||||
* Add an lz4 compression filter to this write handle.
|
||||
*/
|
||||
int
|
||||
archive_write_add_filter_lz4(struct archive *_a)
|
||||
archive_write_add_filter_lz4(struct archive *a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct private_data *data;
|
||||
struct archive_write_filter *f;
|
||||
struct lz4 *lz4;
|
||||
int r;
|
||||
|
||||
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_lz4");
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if (data == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
lz4 = calloc(1, sizeof(*lz4));
|
||||
if (lz4 == NULL)
|
||||
goto memerr;
|
||||
/*
|
||||
* Setup default settings.
|
||||
*/
|
||||
data->compression_level = 1;
|
||||
data->version_number = 0x01;
|
||||
data->block_independence = 1;
|
||||
data->block_checksum = 0;
|
||||
data->stream_size = 0;
|
||||
data->stream_checksum = 1;
|
||||
data->preset_dictionary = 0;
|
||||
data->block_maximum_size = 7;
|
||||
|
||||
/*
|
||||
* Setup a filter setting.
|
||||
*/
|
||||
f->data = data;
|
||||
f->options = &archive_filter_lz4_options;
|
||||
f->close = &archive_filter_lz4_close;
|
||||
f->free = &archive_filter_lz4_free;
|
||||
f->open = &archive_filter_lz4_open;
|
||||
f->code = ARCHIVE_FILTER_LZ4;
|
||||
f->name = "lz4";
|
||||
lz4->version_number = 0x01;
|
||||
lz4->block_independence = 1;
|
||||
lz4->block_checksum = 0;
|
||||
lz4->stream_size = 0;
|
||||
lz4->stream_checksum = 1;
|
||||
lz4->preset_dictionary = 0;
|
||||
lz4->block_maximum_size = 7;
|
||||
#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2
|
||||
return (ARCHIVE_OK);
|
||||
lz4->compression_level = 1;
|
||||
|
||||
r = ARCHIVE_OK;
|
||||
#else
|
||||
/*
|
||||
* We don't have lz4 library, and execute external lz4 program
|
||||
* instead.
|
||||
*/
|
||||
data->pdata = __archive_write_program_allocate("lz4");
|
||||
if (data->pdata == NULL) {
|
||||
free(data);
|
||||
archive_set_error(&a->archive, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->compression_level = 0;
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
lz4->pdata = __archive_write_program_allocate("lz4");
|
||||
if (lz4->pdata == NULL)
|
||||
goto memerr;
|
||||
lz4->compression_level = 0;
|
||||
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Using external lz4 program");
|
||||
return (ARCHIVE_WARN);
|
||||
r = ARCHIVE_WARN;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Setup a filter setting.
|
||||
*/
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "lz4";
|
||||
f->code = ARCHIVE_FILTER_LZ4;
|
||||
f->data = lz4;
|
||||
f->options = archive_filter_lz4_options;
|
||||
f->open = archive_filter_lz4_open;
|
||||
f->write = archive_filter_lz4_write;
|
||||
f->close = archive_filter_lz4_close;
|
||||
f->free = archive_filter_lz4_free;
|
||||
|
||||
return (r);
|
||||
memerr:
|
||||
free_data(lz4);
|
||||
archive_set_error(a, ENOMEM, "Out of memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_filter_lz4_free(struct archive_write_filter *f)
|
||||
{
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -155,13 +169,16 @@ static int
|
||||
archive_filter_lz4_options(struct archive_write_filter *f,
|
||||
const char *key, const char *value)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
|
||||
if (strcmp(key, "compression-level") == 0) {
|
||||
int val;
|
||||
if (value == NULL || !((val = value[0] - '0') >= 1 && val <= 9) ||
|
||||
value[1] != '\0')
|
||||
return (ARCHIVE_WARN);
|
||||
value[1] != '\0') {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"compression-level invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
#ifndef HAVE_LZ4HC_H
|
||||
if(val >= 3)
|
||||
@@ -171,26 +188,29 @@ archive_filter_lz4_options(struct archive_write_filter *f,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
#endif
|
||||
data->compression_level = val;
|
||||
lz4->compression_level = val;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (strcmp(key, "stream-checksum") == 0) {
|
||||
data->stream_checksum = value != NULL;
|
||||
lz4->stream_checksum = value != NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (strcmp(key, "block-checksum") == 0) {
|
||||
data->block_checksum = value != NULL;
|
||||
lz4->block_checksum = value != NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (strcmp(key, "block-size") == 0) {
|
||||
if (value == NULL || !(value[0] >= '4' && value[0] <= '7') ||
|
||||
value[1] != '\0')
|
||||
return (ARCHIVE_WARN);
|
||||
data->block_maximum_size = value[0] - '0';
|
||||
value[1] != '\0') {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"block-size invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lz4->block_maximum_size = value[0] - '0';
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
if (strcmp(key, "block-dependence") == 0) {
|
||||
data->block_independence = value == NULL;
|
||||
lz4->block_independence = value == NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -220,24 +240,24 @@ static ssize_t lz4_write_one_block(struct archive_write_filter *, const char *,
|
||||
static int
|
||||
archive_filter_lz4_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
size_t required_size;
|
||||
static size_t const bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
|
||||
static const size_t bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
|
||||
4 * 1024 * 1024 };
|
||||
size_t pre_block_size;
|
||||
|
||||
if (data->block_maximum_size < 4)
|
||||
data->block_size = bkmap[0];
|
||||
if (lz4->block_maximum_size < 4)
|
||||
lz4->block_size = bkmap[0];
|
||||
else
|
||||
data->block_size = bkmap[data->block_maximum_size - 4];
|
||||
lz4->block_size = bkmap[lz4->block_maximum_size - 4];
|
||||
|
||||
required_size = 4 + 15 + 4 + data->block_size + 4 + 4;
|
||||
if (data->out_buffer_size < required_size) {
|
||||
required_size = 4 + 15 + 4 + lz4->block_size + 4 + 4;
|
||||
if (lz4->out_buffer_size < required_size) {
|
||||
size_t bs = required_size, bpb;
|
||||
free(data->out_buffer);
|
||||
free(lz4->out_buffer);
|
||||
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
|
||||
/* Buffer size should be a multiple number of
|
||||
* the of bytes per block for performance. */
|
||||
* the bytes per block for performance. */
|
||||
bpb = archive_write_get_bytes_per_block(f->archive);
|
||||
if (bpb > bs)
|
||||
bs = bpb;
|
||||
@@ -246,34 +266,32 @@ archive_filter_lz4_open(struct archive_write_filter *f)
|
||||
bs -= bs % bpb;
|
||||
}
|
||||
}
|
||||
data->out_block_size = bs;
|
||||
lz4->out_block_size = bs;
|
||||
bs += required_size;
|
||||
data->out_buffer = malloc(bs);
|
||||
data->out = data->out_buffer;
|
||||
data->out_buffer_size = bs;
|
||||
lz4->out_buffer = malloc(bs);
|
||||
lz4->out = lz4->out_buffer;
|
||||
lz4->out_buffer_size = bs;
|
||||
}
|
||||
|
||||
pre_block_size = (data->block_independence)? 0: 64 * 1024;
|
||||
if (data->in_buffer_size < data->block_size + pre_block_size) {
|
||||
free(data->in_buffer_allocated);
|
||||
data->in_buffer_size = data->block_size;
|
||||
data->in_buffer_allocated =
|
||||
malloc(data->in_buffer_size + pre_block_size);
|
||||
data->in_buffer = data->in_buffer_allocated + pre_block_size;
|
||||
if (!data->block_independence && data->compression_level >= 3)
|
||||
data->in_buffer = data->in_buffer_allocated;
|
||||
data->in = data->in_buffer;
|
||||
data->in_buffer_size = data->block_size;
|
||||
pre_block_size = (lz4->block_independence)? 0: 64 * 1024;
|
||||
if (lz4->in_buffer_size < lz4->block_size + pre_block_size) {
|
||||
free(lz4->in_buffer_allocated);
|
||||
lz4->in_buffer_size = lz4->block_size;
|
||||
lz4->in_buffer_allocated =
|
||||
malloc(lz4->in_buffer_size + pre_block_size);
|
||||
lz4->in_buffer = lz4->in_buffer_allocated + pre_block_size;
|
||||
if (!lz4->block_independence && lz4->compression_level >= 3)
|
||||
lz4->in_buffer = lz4->in_buffer_allocated;
|
||||
lz4->in = lz4->in_buffer;
|
||||
lz4->in_buffer_size = lz4->block_size;
|
||||
}
|
||||
|
||||
if (data->out_buffer == NULL || data->in_buffer_allocated == NULL) {
|
||||
if (lz4->out_buffer == NULL || lz4->in_buffer_allocated == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
f->write = archive_filter_lz4_write;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -286,23 +304,20 @@ static int
|
||||
archive_filter_lz4_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
int ret = ARCHIVE_OK;
|
||||
const char *p;
|
||||
size_t remaining;
|
||||
ssize_t size;
|
||||
|
||||
/* If we haven't written a stream descriptor, we have to do it first. */
|
||||
if (!data->header_written) {
|
||||
if (!lz4->header_written) {
|
||||
ret = lz4_write_stream_descriptor(f);
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
data->header_written = 1;
|
||||
lz4->header_written = 1;
|
||||
}
|
||||
|
||||
/* Update statistics */
|
||||
data->total_in += length;
|
||||
|
||||
p = (const char *)buff;
|
||||
remaining = length;
|
||||
while (remaining) {
|
||||
@@ -311,14 +326,14 @@ archive_filter_lz4_write(struct archive_write_filter *f,
|
||||
size = lz4_write_one_block(f, p, remaining);
|
||||
if (size < ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
l = data->out - data->out_buffer;
|
||||
if (l >= data->out_block_size) {
|
||||
l = lz4->out - lz4->out_buffer;
|
||||
if (l >= lz4->out_block_size) {
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
data->out_buffer, data->out_block_size);
|
||||
l -= data->out_block_size;
|
||||
memcpy(data->out_buffer,
|
||||
data->out_buffer + data->out_block_size, l);
|
||||
data->out = data->out_buffer + l;
|
||||
lz4->out_buffer, lz4->out_block_size);
|
||||
l -= lz4->out_block_size;
|
||||
memcpy(lz4->out_buffer,
|
||||
lz4->out_buffer + lz4->out_block_size, l);
|
||||
lz4->out = lz4->out_buffer + l;
|
||||
if (ret < ARCHIVE_WARN)
|
||||
break;
|
||||
}
|
||||
@@ -335,7 +350,7 @@ archive_filter_lz4_write(struct archive_write_filter *f,
|
||||
static int
|
||||
archive_filter_lz4_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
int ret;
|
||||
|
||||
/* Finish compression cycle. */
|
||||
@@ -346,75 +361,48 @@ archive_filter_lz4_close(struct archive_write_filter *f)
|
||||
*/
|
||||
|
||||
/* Write End Of Stream. */
|
||||
memset(data->out, 0, 4); data->out += 4;
|
||||
memset(lz4->out, 0, 4); lz4->out += 4;
|
||||
/* Write Stream checksum if needed. */
|
||||
if (data->stream_checksum) {
|
||||
if (lz4->stream_checksum) {
|
||||
unsigned int checksum;
|
||||
checksum = __archive_xxhash.XXH32_digest(
|
||||
data->xxh32_state);
|
||||
data->xxh32_state = NULL;
|
||||
archive_le32enc(data->out, checksum);
|
||||
data->out += 4;
|
||||
lz4->xxh32_state);
|
||||
lz4->xxh32_state = NULL;
|
||||
archive_le32enc(lz4->out, checksum);
|
||||
lz4->out += 4;
|
||||
}
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
data->out_buffer, data->out - data->out_buffer);
|
||||
lz4->out_buffer, lz4->out - lz4->out_buffer);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
archive_filter_lz4_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
|
||||
if (data->lz4_stream != NULL) {
|
||||
#ifdef HAVE_LZ4HC_H
|
||||
if (data->compression_level >= 3)
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
LZ4_freeStreamHC(data->lz4_stream);
|
||||
#else
|
||||
LZ4_freeHC(data->lz4_stream);
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
#if LZ4_VERSION_MINOR >= 3
|
||||
LZ4_freeStream(data->lz4_stream);
|
||||
#else
|
||||
LZ4_free(data->lz4_stream);
|
||||
#endif
|
||||
}
|
||||
free(data->out_buffer);
|
||||
free(data->in_buffer_allocated);
|
||||
free(data->xxh32_state);
|
||||
free(data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
lz4_write_stream_descriptor(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
uint8_t *sd;
|
||||
|
||||
sd = (uint8_t *)data->out;
|
||||
sd = (uint8_t *)lz4->out;
|
||||
/* Write Magic Number. */
|
||||
archive_le32enc(&sd[0], LZ4_MAGICNUMBER);
|
||||
/* FLG */
|
||||
sd[4] = (data->version_number << 6)
|
||||
| (data->block_independence << 5)
|
||||
| (data->block_checksum << 4)
|
||||
| (data->stream_size << 3)
|
||||
| (data->stream_checksum << 2)
|
||||
| (data->preset_dictionary << 0);
|
||||
sd[4] = (lz4->version_number << 6)
|
||||
| (lz4->block_independence << 5)
|
||||
| (lz4->block_checksum << 4)
|
||||
| (lz4->stream_size << 3)
|
||||
| (lz4->stream_checksum << 2)
|
||||
| (lz4->preset_dictionary << 0);
|
||||
/* BD */
|
||||
sd[5] = (data->block_maximum_size << 4);
|
||||
sd[5] = (lz4->block_maximum_size << 4);
|
||||
sd[6] = (__archive_xxhash.XXH32(&sd[4], 2, 0) >> 8) & 0xff;
|
||||
data->out += 7;
|
||||
if (data->stream_checksum)
|
||||
data->xxh32_state = __archive_xxhash.XXH32_init(0);
|
||||
else
|
||||
data->xxh32_state = NULL;
|
||||
lz4->out += 7;
|
||||
if (lz4->stream_checksum) {
|
||||
lz4->xxh32_state = __archive_xxhash.XXH32_init(0);
|
||||
if (lz4->xxh32_state == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
} else
|
||||
lz4->xxh32_state = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -422,36 +410,36 @@ static ssize_t
|
||||
lz4_write_one_block(struct archive_write_filter *f, const char *p,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
ssize_t r;
|
||||
|
||||
if (p == NULL) {
|
||||
/* Compress remaining uncompressed data. */
|
||||
if (data->in_buffer == data->in)
|
||||
if (lz4->in_buffer == lz4->in)
|
||||
return 0;
|
||||
else {
|
||||
size_t l = data->in - data->in_buffer;
|
||||
r = drive_compressor(f, data->in_buffer, l);
|
||||
size_t l = lz4->in - lz4->in_buffer;
|
||||
r = drive_compressor(f, lz4->in_buffer, l);
|
||||
if (r == ARCHIVE_OK)
|
||||
r = (ssize_t)l;
|
||||
}
|
||||
} else if ((data->block_independence || data->compression_level < 3) &&
|
||||
data->in_buffer == data->in && length >= data->block_size) {
|
||||
r = drive_compressor(f, p, data->block_size);
|
||||
} else if ((lz4->block_independence || lz4->compression_level < 3) &&
|
||||
lz4->in_buffer == lz4->in && length >= lz4->block_size) {
|
||||
r = drive_compressor(f, p, lz4->block_size);
|
||||
if (r == ARCHIVE_OK)
|
||||
r = (ssize_t)data->block_size;
|
||||
r = (ssize_t)lz4->block_size;
|
||||
} else {
|
||||
size_t remaining_size = data->in_buffer_size -
|
||||
(data->in - data->in_buffer);
|
||||
size_t remaining_size = lz4->in_buffer_size -
|
||||
(lz4->in - lz4->in_buffer);
|
||||
size_t l = (remaining_size > length)? length: remaining_size;
|
||||
memcpy(data->in, p, l);
|
||||
data->in += l;
|
||||
memcpy(lz4->in, p, l);
|
||||
lz4->in += l;
|
||||
if (l == remaining_size) {
|
||||
r = drive_compressor(f, data->in_buffer,
|
||||
data->block_size);
|
||||
r = drive_compressor(f, lz4->in_buffer,
|
||||
lz4->block_size);
|
||||
if (r == ARCHIVE_OK)
|
||||
r = (ssize_t)l;
|
||||
data->in = data->in_buffer;
|
||||
lz4->in = lz4->in_buffer;
|
||||
} else
|
||||
r = (ssize_t)l;
|
||||
}
|
||||
@@ -470,12 +458,12 @@ lz4_write_one_block(struct archive_write_filter *f, const char *p,
|
||||
static int
|
||||
drive_compressor(struct archive_write_filter *f, const char *p, size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
|
||||
if (data->stream_checksum)
|
||||
__archive_xxhash.XXH32_update(data->xxh32_state,
|
||||
if (lz4->stream_checksum)
|
||||
__archive_xxhash.XXH32_update(lz4->xxh32_state,
|
||||
p, (int)length);
|
||||
if (data->block_independence)
|
||||
if (lz4->block_independence)
|
||||
return drive_compressor_independence(f, p, length);
|
||||
else
|
||||
return drive_compressor_dependence(f, p, length);
|
||||
@@ -485,48 +473,48 @@ static int
|
||||
drive_compressor_independence(struct archive_write_filter *f, const char *p,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
unsigned int outsize;
|
||||
|
||||
#ifdef HAVE_LZ4HC_H
|
||||
if (data->compression_level >= 3)
|
||||
if (lz4->compression_level >= 3)
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
outsize = LZ4_compress_HC(p, data->out + 4,
|
||||
(int)length, (int)data->block_size,
|
||||
data->compression_level);
|
||||
outsize = LZ4_compress_HC(p, lz4->out + 4,
|
||||
(int)length, (int)lz4->block_size,
|
||||
lz4->compression_level);
|
||||
#else
|
||||
outsize = LZ4_compressHC2_limitedOutput(p, data->out + 4,
|
||||
(int)length, (int)data->block_size,
|
||||
data->compression_level);
|
||||
outsize = LZ4_compressHC2_limitedOutput(p, lz4->out + 4,
|
||||
(int)length, (int)lz4->block_size,
|
||||
lz4->compression_level);
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
outsize = LZ4_compress_default(p, data->out + 4,
|
||||
(int)length, (int)data->block_size);
|
||||
outsize = LZ4_compress_default(p, lz4->out + 4,
|
||||
(int)length, (int)lz4->block_size);
|
||||
#else
|
||||
outsize = LZ4_compress_limitedOutput(p, data->out + 4,
|
||||
(int)length, (int)data->block_size);
|
||||
outsize = LZ4_compress_limitedOutput(p, lz4->out + 4,
|
||||
(int)length, (int)lz4->block_size);
|
||||
#endif
|
||||
|
||||
if (outsize) {
|
||||
/* The buffer is compressed. */
|
||||
archive_le32enc(data->out, outsize);
|
||||
data->out += 4;
|
||||
archive_le32enc(lz4->out, outsize);
|
||||
lz4->out += 4;
|
||||
} else {
|
||||
/* The buffer is not compressed. The compressed size was
|
||||
* bigger than its uncompressed size. */
|
||||
archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
|
||||
data->out += 4;
|
||||
memcpy(data->out, p, length);
|
||||
archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));
|
||||
lz4->out += 4;
|
||||
memcpy(lz4->out, p, length);
|
||||
outsize = (uint32_t)length;
|
||||
}
|
||||
data->out += outsize;
|
||||
if (data->block_checksum) {
|
||||
lz4->out += outsize;
|
||||
if (lz4->block_checksum) {
|
||||
unsigned int checksum =
|
||||
__archive_xxhash.XXH32(data->out - outsize, outsize, 0);
|
||||
archive_le32enc(data->out, checksum);
|
||||
data->out += 4;
|
||||
__archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);
|
||||
archive_le32enc(lz4->out, checksum);
|
||||
lz4->out += 4;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -535,21 +523,21 @@ static int
|
||||
drive_compressor_dependence(struct archive_write_filter *f, const char *p,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
int outsize;
|
||||
|
||||
#define DICT_SIZE (64 * 1024)
|
||||
#ifdef HAVE_LZ4HC_H
|
||||
if (data->compression_level >= 3) {
|
||||
if (data->lz4_stream == NULL) {
|
||||
if (lz4->compression_level >= 3) {
|
||||
if (lz4->lz4_stream == NULL) {
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
data->lz4_stream = LZ4_createStreamHC();
|
||||
LZ4_resetStreamHC(data->lz4_stream, data->compression_level);
|
||||
lz4->lz4_stream = LZ4_createStreamHC();
|
||||
LZ4_resetStreamHC(lz4->lz4_stream, lz4->compression_level);
|
||||
#else
|
||||
data->lz4_stream =
|
||||
LZ4_createHC(data->in_buffer_allocated);
|
||||
lz4->lz4_stream =
|
||||
LZ4_createHC(lz4->in_buffer_allocated);
|
||||
#endif
|
||||
if (data->lz4_stream == NULL) {
|
||||
if (lz4->lz4_stream == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression"
|
||||
" buffer");
|
||||
@@ -557,23 +545,23 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p,
|
||||
}
|
||||
}
|
||||
else
|
||||
LZ4_loadDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
|
||||
LZ4_loadDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);
|
||||
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
outsize = LZ4_compress_HC_continue(
|
||||
data->lz4_stream, p, data->out + 4, (int)length,
|
||||
(int)data->block_size);
|
||||
lz4->lz4_stream, p, lz4->out + 4, (int)length,
|
||||
(int)lz4->block_size);
|
||||
#else
|
||||
outsize = LZ4_compressHC2_limitedOutput_continue(
|
||||
data->lz4_stream, p, data->out + 4, (int)length,
|
||||
(int)data->block_size, data->compression_level);
|
||||
lz4->lz4_stream, p, lz4->out + 4, (int)length,
|
||||
(int)lz4->block_size, lz4->compression_level);
|
||||
#endif
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (data->lz4_stream == NULL) {
|
||||
data->lz4_stream = LZ4_createStream();
|
||||
if (data->lz4_stream == NULL) {
|
||||
if (lz4->lz4_stream == NULL) {
|
||||
lz4->lz4_stream = LZ4_createStream();
|
||||
if (lz4->lz4_stream == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression"
|
||||
" buffer");
|
||||
@@ -581,64 +569,91 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p,
|
||||
}
|
||||
}
|
||||
else
|
||||
LZ4_loadDict(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
|
||||
LZ4_loadDict(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);
|
||||
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
outsize = LZ4_compress_fast_continue(
|
||||
data->lz4_stream, p, data->out + 4, (int)length,
|
||||
(int)data->block_size, 1);
|
||||
lz4->lz4_stream, p, lz4->out + 4, (int)length,
|
||||
(int)lz4->block_size, 1);
|
||||
#else
|
||||
outsize = LZ4_compress_limitedOutput_continue(
|
||||
data->lz4_stream, p, data->out + 4, (int)length,
|
||||
(int)data->block_size);
|
||||
lz4->lz4_stream, p, lz4->out + 4, (int)length,
|
||||
(int)lz4->block_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (outsize) {
|
||||
/* The buffer is compressed. */
|
||||
archive_le32enc(data->out, outsize);
|
||||
data->out += 4;
|
||||
archive_le32enc(lz4->out, outsize);
|
||||
lz4->out += 4;
|
||||
} else {
|
||||
/* The buffer is not compressed. The compressed size was
|
||||
* bigger than its uncompressed size. */
|
||||
archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
|
||||
data->out += 4;
|
||||
memcpy(data->out, p, length);
|
||||
archive_le32enc(lz4->out, (uint32_t)(length | 0x80000000));
|
||||
lz4->out += 4;
|
||||
memcpy(lz4->out, p, length);
|
||||
outsize = (uint32_t)length;
|
||||
}
|
||||
data->out += outsize;
|
||||
if (data->block_checksum) {
|
||||
lz4->out += outsize;
|
||||
if (lz4->block_checksum) {
|
||||
unsigned int checksum =
|
||||
__archive_xxhash.XXH32(data->out - outsize, outsize, 0);
|
||||
archive_le32enc(data->out, checksum);
|
||||
data->out += 4;
|
||||
__archive_xxhash.XXH32(lz4->out - outsize, outsize, 0);
|
||||
archive_le32enc(lz4->out, checksum);
|
||||
lz4->out += 4;
|
||||
}
|
||||
|
||||
if (length == data->block_size) {
|
||||
if (length == lz4->block_size) {
|
||||
#ifdef HAVE_LZ4HC_H
|
||||
if (data->compression_level >= 3) {
|
||||
if (lz4->compression_level >= 3) {
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
LZ4_saveDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
|
||||
LZ4_saveDictHC(lz4->lz4_stream, lz4->in_buffer_allocated, DICT_SIZE);
|
||||
#else
|
||||
LZ4_slideInputBufferHC(data->lz4_stream);
|
||||
LZ4_slideInputBufferHC(lz4->lz4_stream);
|
||||
#endif
|
||||
data->in_buffer = data->in_buffer_allocated + DICT_SIZE;
|
||||
lz4->in_buffer = lz4->in_buffer_allocated + DICT_SIZE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
LZ4_saveDict(data->lz4_stream,
|
||||
data->in_buffer_allocated, DICT_SIZE);
|
||||
LZ4_saveDict(lz4->lz4_stream,
|
||||
lz4->in_buffer_allocated, DICT_SIZE);
|
||||
#undef DICT_SIZE
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct lz4 *lz4)
|
||||
{
|
||||
if (lz4 != NULL) {
|
||||
if (lz4->lz4_stream != NULL) {
|
||||
#ifdef HAVE_LZ4HC_H
|
||||
if (lz4->compression_level >= 3)
|
||||
#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
|
||||
LZ4_freeStreamHC(lz4->lz4_stream);
|
||||
#else
|
||||
LZ4_freeHC(lz4->lz4_stream);
|
||||
#endif
|
||||
else
|
||||
#endif
|
||||
#if LZ4_VERSION_MINOR >= 3
|
||||
LZ4_freeStream(lz4->lz4_stream);
|
||||
#else
|
||||
LZ4_free(lz4->lz4_stream);
|
||||
#endif
|
||||
}
|
||||
free(lz4->out_buffer);
|
||||
free(lz4->in_buffer_allocated);
|
||||
free(lz4->xxh32_state);
|
||||
free(lz4);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* HAVE_LIBLZ4 */
|
||||
|
||||
static int
|
||||
archive_filter_lz4_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
struct archive_string as;
|
||||
int r;
|
||||
|
||||
@@ -646,24 +661,22 @@ archive_filter_lz4_open(struct archive_write_filter *f)
|
||||
archive_strcpy(&as, "lz4 -z -q -q");
|
||||
|
||||
/* Specify a compression level. */
|
||||
if (data->compression_level > 0) {
|
||||
if (lz4->compression_level > 0) {
|
||||
archive_strcat(&as, " -");
|
||||
archive_strappend_char(&as, '0' + data->compression_level);
|
||||
archive_strappend_char(&as, '0' + lz4->compression_level);
|
||||
}
|
||||
/* Specify a block size. */
|
||||
archive_strcat(&as, " -B");
|
||||
archive_strappend_char(&as, '0' + data->block_maximum_size);
|
||||
archive_strappend_char(&as, '0' + lz4->block_maximum_size);
|
||||
|
||||
if (data->block_checksum)
|
||||
if (lz4->block_checksum)
|
||||
archive_strcat(&as, " -BX");
|
||||
if (data->stream_checksum == 0)
|
||||
if (lz4->stream_checksum == 0)
|
||||
archive_strcat(&as, " --no-frame-crc");
|
||||
if (data->block_independence == 0)
|
||||
if (lz4->block_independence == 0)
|
||||
archive_strcat(&as, " -BD");
|
||||
|
||||
f->write = archive_filter_lz4_write;
|
||||
|
||||
r = __archive_write_program_open(f, data->pdata, as.s);
|
||||
r = __archive_write_program_open(f, lz4->pdata, as.s);
|
||||
archive_string_free(&as);
|
||||
return (r);
|
||||
}
|
||||
@@ -672,27 +685,26 @@ static int
|
||||
archive_filter_lz4_write(struct archive_write_filter *f, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
|
||||
return __archive_write_program_write(f, data->pdata, buff, length);
|
||||
return __archive_write_program_write(f, lz4->pdata, buff, length);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_filter_lz4_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct lz4 *lz4 = f->data;
|
||||
|
||||
return __archive_write_program_close(f, data->pdata);
|
||||
return __archive_write_program_close(f, lz4->pdata);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_filter_lz4_free(struct archive_write_filter *f)
|
||||
static void
|
||||
free_data(struct lz4 *lz4)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
|
||||
__archive_write_program_free(data->pdata);
|
||||
free(data);
|
||||
return (ARCHIVE_OK);
|
||||
if (lz4 != NULL) {
|
||||
__archive_write_program_free(lz4->pdata);
|
||||
free(lz4);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBLZ4 */
|
||||
|
||||
@@ -55,7 +55,7 @@ enum lzo_method {
|
||||
METHOD_LZO1X_1_15 = 2,
|
||||
METHOD_LZO1X_999 = 3
|
||||
};
|
||||
struct write_lzop {
|
||||
struct lzop {
|
||||
int compression_level;
|
||||
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
||||
unsigned char *uncompressed;
|
||||
@@ -80,6 +80,7 @@ static int archive_write_lzop_write(struct archive_write_filter *,
|
||||
const void *, size_t);
|
||||
static int archive_write_lzop_close(struct archive_write_filter *);
|
||||
static int archive_write_lzop_free(struct archive_write_filter *);
|
||||
static void free_data(struct lzop *);
|
||||
|
||||
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
||||
/* Maximum block size. */
|
||||
@@ -133,73 +134,72 @@ static const unsigned char header[] = {
|
||||
#endif
|
||||
|
||||
int
|
||||
archive_write_add_filter_lzop(struct archive *_a)
|
||||
archive_write_add_filter_lzop(struct archive *a)
|
||||
{
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct write_lzop *data;
|
||||
struct archive_write_filter *f;
|
||||
struct lzop *lzop;
|
||||
int r;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_lzop");
|
||||
|
||||
data = calloc(1, sizeof(*data));
|
||||
if (data == NULL) {
|
||||
archive_set_error(_a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
f->name = "lzop";
|
||||
f->code = ARCHIVE_FILTER_LZOP;
|
||||
f->data = data;
|
||||
f->open = archive_write_lzop_open;
|
||||
f->options = archive_write_lzop_options;
|
||||
f->write = archive_write_lzop_write;
|
||||
f->close = archive_write_lzop_close;
|
||||
f->free = archive_write_lzop_free;
|
||||
lzop = calloc(1, sizeof(*lzop));
|
||||
if (lzop == NULL)
|
||||
goto memerr;
|
||||
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
||||
if (lzo_init() != LZO_E_OK) {
|
||||
free(data);
|
||||
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
|
||||
free_data(lzop);
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"lzo_init(type check) failed");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (lzo_version() < 0x940) {
|
||||
free(data);
|
||||
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
|
||||
free_data(lzop);
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"liblzo library is too old(%s < 0.940)",
|
||||
lzo_version_string());
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->compression_level = 5;
|
||||
return (ARCHIVE_OK);
|
||||
lzop->compression_level = 5;
|
||||
|
||||
r = ARCHIVE_OK;
|
||||
#else
|
||||
data->pdata = __archive_write_program_allocate("lzop");
|
||||
if (data->pdata == NULL) {
|
||||
free(data);
|
||||
archive_set_error(_a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->compression_level = 0;
|
||||
lzop->pdata = __archive_write_program_allocate("lzop");
|
||||
if (lzop->pdata == NULL)
|
||||
goto memerr;
|
||||
lzop->compression_level = 0;
|
||||
|
||||
/* Note: We return "warn" to inform of using an external lzop
|
||||
* program. */
|
||||
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Using external lzop program for lzop compression");
|
||||
return (ARCHIVE_WARN);
|
||||
r = ARCHIVE_WARN;
|
||||
#endif
|
||||
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "lzop";
|
||||
f->code = ARCHIVE_FILTER_LZOP;
|
||||
f->data = lzop;
|
||||
f->options = archive_write_lzop_options;
|
||||
f->open = archive_write_lzop_open;
|
||||
f->write = archive_write_lzop_write;
|
||||
f->close = archive_write_lzop_close;
|
||||
f->free = archive_write_lzop_free;
|
||||
|
||||
return (r);
|
||||
memerr:
|
||||
free_data(lzop);
|
||||
archive_set_error(a, ENOMEM, "Can't allocate memory");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_lzop_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
|
||||
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
|
||||
free(data->uncompressed);
|
||||
free(data->compressed);
|
||||
free(data->work_buffer);
|
||||
#else
|
||||
__archive_write_program_free(data->pdata);
|
||||
#endif
|
||||
free(data);
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -207,13 +207,16 @@ static int
|
||||
archive_write_lzop_options(struct archive_write_filter *f, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
|
||||
if (strcmp(key, "compression-level") == 0) {
|
||||
if (value == NULL || !(value[0] >= '1' && value[0] <= '9') ||
|
||||
value[1] != '\0')
|
||||
return (ARCHIVE_WARN);
|
||||
data->compression_level = value[0] - '0';
|
||||
value[1] != '\0') {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"compression-level invalid");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
lzop->compression_level = value[0] - '0';
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
/* Note: The "warn" return is just to inform the options
|
||||
@@ -226,58 +229,58 @@ archive_write_lzop_options(struct archive_write_filter *f, const char *key,
|
||||
static int
|
||||
archive_write_lzop_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
|
||||
switch (data->compression_level) {
|
||||
switch (lzop->compression_level) {
|
||||
case 1:
|
||||
data->method = METHOD_LZO1X_1_15; data->level = 1; break;
|
||||
lzop->method = METHOD_LZO1X_1_15; lzop->level = 1; break;
|
||||
default:
|
||||
case 2: case 3: case 4: case 5: case 6:
|
||||
data->method = METHOD_LZO1X_1; data->level = 5; break;
|
||||
lzop->method = METHOD_LZO1X_1; lzop->level = 5; break;
|
||||
case 7:
|
||||
data->method = METHOD_LZO1X_999; data->level = 7; break;
|
||||
lzop->method = METHOD_LZO1X_999; lzop->level = 7; break;
|
||||
case 8:
|
||||
data->method = METHOD_LZO1X_999; data->level = 8; break;
|
||||
lzop->method = METHOD_LZO1X_999; lzop->level = 8; break;
|
||||
case 9:
|
||||
data->method = METHOD_LZO1X_999; data->level = 9; break;
|
||||
lzop->method = METHOD_LZO1X_999; lzop->level = 9; break;
|
||||
}
|
||||
switch (data->method) {
|
||||
switch (lzop->method) {
|
||||
case METHOD_LZO1X_1:
|
||||
data->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;
|
||||
lzop->work_buffer_size = LZO1X_1_MEM_COMPRESS; break;
|
||||
case METHOD_LZO1X_1_15:
|
||||
data->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;
|
||||
lzop->work_buffer_size = LZO1X_1_15_MEM_COMPRESS; break;
|
||||
case METHOD_LZO1X_999:
|
||||
data->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;
|
||||
lzop->work_buffer_size = LZO1X_999_MEM_COMPRESS; break;
|
||||
}
|
||||
if (data->work_buffer == NULL) {
|
||||
data->work_buffer = (lzo_voidp)malloc(data->work_buffer_size);
|
||||
if (data->work_buffer == NULL) {
|
||||
if (lzop->work_buffer == NULL) {
|
||||
lzop->work_buffer = (lzo_voidp)malloc(lzop->work_buffer_size);
|
||||
if (lzop->work_buffer == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
if (data->compressed == NULL) {
|
||||
data->compressed_buffer_size = sizeof(header) +
|
||||
if (lzop->compressed == NULL) {
|
||||
lzop->compressed_buffer_size = sizeof(header) +
|
||||
BLOCK_SIZE + (BLOCK_SIZE >> 4) + 64 + 3;
|
||||
data->compressed = (unsigned char *)
|
||||
malloc(data->compressed_buffer_size);
|
||||
if (data->compressed == NULL) {
|
||||
lzop->compressed = (unsigned char *)
|
||||
malloc(lzop->compressed_buffer_size);
|
||||
if (lzop->compressed == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
}
|
||||
if (data->uncompressed == NULL) {
|
||||
data->uncompressed_buffer_size = BLOCK_SIZE;
|
||||
data->uncompressed = (unsigned char *)
|
||||
malloc(data->uncompressed_buffer_size);
|
||||
if (data->uncompressed == NULL) {
|
||||
if (lzop->uncompressed == NULL) {
|
||||
lzop->uncompressed_buffer_size = BLOCK_SIZE;
|
||||
lzop->uncompressed = (unsigned char *)
|
||||
malloc(lzop->uncompressed_buffer_size);
|
||||
if (lzop->uncompressed == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for compression buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
data->uncompressed_avail_bytes = BLOCK_SIZE;
|
||||
lzop->uncompressed_avail_bytes = BLOCK_SIZE;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
@@ -285,68 +288,68 @@ archive_write_lzop_open(struct archive_write_filter *f)
|
||||
static int
|
||||
make_header(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
int64_t t;
|
||||
uint32_t checksum;
|
||||
|
||||
memcpy(data->compressed, header, sizeof(header));
|
||||
memcpy(lzop->compressed, header, sizeof(header));
|
||||
/* Overwrite library version. */
|
||||
data->compressed[HEADER_LIBVERSION] = (unsigned char )
|
||||
lzop->compressed[HEADER_LIBVERSION] = (unsigned char )
|
||||
(lzo_version() >> 8) & 0xff;
|
||||
data->compressed[HEADER_LIBVERSION + 1] = (unsigned char )
|
||||
lzop->compressed[HEADER_LIBVERSION + 1] = (unsigned char )
|
||||
lzo_version() & 0xff;
|
||||
/* Overwrite method and level. */
|
||||
data->compressed[HEADER_METHOD] = (unsigned char)data->method;
|
||||
data->compressed[HEADER_LEVEL] = data->level;
|
||||
lzop->compressed[HEADER_METHOD] = (unsigned char)lzop->method;
|
||||
lzop->compressed[HEADER_LEVEL] = lzop->level;
|
||||
/* Overwrite mtime with current time. */
|
||||
t = (int64_t)time(NULL);
|
||||
archive_be32enc(&data->compressed[HEADER_MTIME_LOW],
|
||||
archive_be32enc(&lzop->compressed[HEADER_MTIME_LOW],
|
||||
(uint32_t)(t & 0xffffffff));
|
||||
archive_be32enc(&data->compressed[HEADER_MTIME_HIGH],
|
||||
archive_be32enc(&lzop->compressed[HEADER_MTIME_HIGH],
|
||||
(uint32_t)((t >> 32) & 0xffffffff));
|
||||
/* Overwrite header checksum with calculated value. */
|
||||
checksum = lzo_adler32(1, data->compressed + HEADER_VERSION,
|
||||
checksum = lzo_adler32(1, lzop->compressed + HEADER_VERSION,
|
||||
(lzo_uint)(HEADER_H_CHECKSUM - HEADER_VERSION));
|
||||
archive_be32enc(&data->compressed[HEADER_H_CHECKSUM], checksum);
|
||||
archive_be32enc(&lzop->compressed[HEADER_H_CHECKSUM], checksum);
|
||||
return (sizeof(header));
|
||||
}
|
||||
|
||||
static int
|
||||
drive_compressor(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
unsigned char *p;
|
||||
const int block_info_bytes = 12;
|
||||
int header_bytes, r;
|
||||
lzo_uint usize, csize;
|
||||
uint32_t checksum;
|
||||
|
||||
if (!data->header_written) {
|
||||
if (!lzop->header_written) {
|
||||
header_bytes = make_header(f);
|
||||
data->header_written = 1;
|
||||
lzop->header_written = 1;
|
||||
} else
|
||||
header_bytes = 0;
|
||||
p = data->compressed;
|
||||
p = lzop->compressed;
|
||||
|
||||
usize = (lzo_uint)
|
||||
(data->uncompressed_buffer_size - data->uncompressed_avail_bytes);
|
||||
(lzop->uncompressed_buffer_size - lzop->uncompressed_avail_bytes);
|
||||
csize = 0;
|
||||
switch (data->method) {
|
||||
switch (lzop->method) {
|
||||
default:
|
||||
case METHOD_LZO1X_1:
|
||||
r = lzo1x_1_compress(data->uncompressed, usize,
|
||||
r = lzo1x_1_compress(lzop->uncompressed, usize,
|
||||
p + header_bytes + block_info_bytes, &csize,
|
||||
data->work_buffer);
|
||||
lzop->work_buffer);
|
||||
break;
|
||||
case METHOD_LZO1X_1_15:
|
||||
r = lzo1x_1_15_compress(data->uncompressed, usize,
|
||||
r = lzo1x_1_15_compress(lzop->uncompressed, usize,
|
||||
p + header_bytes + block_info_bytes, &csize,
|
||||
data->work_buffer);
|
||||
lzop->work_buffer);
|
||||
break;
|
||||
case METHOD_LZO1X_999:
|
||||
r = lzo1x_999_compress_level(data->uncompressed, usize,
|
||||
r = lzo1x_999_compress_level(lzop->uncompressed, usize,
|
||||
p + header_bytes + block_info_bytes, &csize,
|
||||
data->work_buffer, NULL, 0, 0, data->level);
|
||||
lzop->work_buffer, NULL, 0, 0, lzop->level);
|
||||
break;
|
||||
}
|
||||
if (r != LZO_E_OK) {
|
||||
@@ -358,13 +361,13 @@ drive_compressor(struct archive_write_filter *f)
|
||||
/* Store uncompressed size. */
|
||||
archive_be32enc(p + header_bytes, (uint32_t)usize);
|
||||
/* Store the checksum of the uncompressed data. */
|
||||
checksum = lzo_adler32(1, data->uncompressed, usize);
|
||||
checksum = lzo_adler32(1, lzop->uncompressed, usize);
|
||||
archive_be32enc(p + header_bytes + 8, checksum);
|
||||
|
||||
if (csize < usize) {
|
||||
/* Store compressed size. */
|
||||
archive_be32enc(p + header_bytes + 4, (uint32_t)csize);
|
||||
r = __archive_write_filter(f->next_filter, data->compressed,
|
||||
r = __archive_write_filter(f->next_filter, lzop->compressed,
|
||||
header_bytes + block_info_bytes + csize);
|
||||
} else {
|
||||
/*
|
||||
@@ -372,11 +375,11 @@ drive_compressor(struct archive_write_filter *f)
|
||||
*/
|
||||
/* Store uncompressed size as compressed size. */
|
||||
archive_be32enc(p + header_bytes + 4, (uint32_t)usize);
|
||||
r = __archive_write_filter(f->next_filter, data->compressed,
|
||||
r = __archive_write_filter(f->next_filter, lzop->compressed,
|
||||
header_bytes + block_info_bytes);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (ARCHIVE_FATAL);
|
||||
r = __archive_write_filter(f->next_filter, data->uncompressed,
|
||||
r = __archive_write_filter(f->next_filter, lzop->uncompressed,
|
||||
usize);
|
||||
}
|
||||
|
||||
@@ -389,30 +392,30 @@ static int
|
||||
archive_write_lzop_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
const char *p = buff;
|
||||
int r;
|
||||
|
||||
do {
|
||||
if (data->uncompressed_avail_bytes > length) {
|
||||
memcpy(data->uncompressed
|
||||
+ data->uncompressed_buffer_size
|
||||
- data->uncompressed_avail_bytes,
|
||||
if (lzop->uncompressed_avail_bytes > length) {
|
||||
memcpy(lzop->uncompressed
|
||||
+ lzop->uncompressed_buffer_size
|
||||
- lzop->uncompressed_avail_bytes,
|
||||
p, length);
|
||||
data->uncompressed_avail_bytes -= length;
|
||||
lzop->uncompressed_avail_bytes -= length;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
memcpy(data->uncompressed + data->uncompressed_buffer_size
|
||||
- data->uncompressed_avail_bytes,
|
||||
p, data->uncompressed_avail_bytes);
|
||||
length -= data->uncompressed_avail_bytes;
|
||||
p += data->uncompressed_avail_bytes;
|
||||
data->uncompressed_avail_bytes = 0;
|
||||
memcpy(lzop->uncompressed + lzop->uncompressed_buffer_size
|
||||
- lzop->uncompressed_avail_bytes,
|
||||
p, lzop->uncompressed_avail_bytes);
|
||||
length -= lzop->uncompressed_avail_bytes;
|
||||
p += lzop->uncompressed_avail_bytes;
|
||||
lzop->uncompressed_avail_bytes = 0;
|
||||
|
||||
r = drive_compressor(f);
|
||||
if (r != ARCHIVE_OK) return (r);
|
||||
data->uncompressed_avail_bytes = BLOCK_SIZE;
|
||||
lzop->uncompressed_avail_bytes = BLOCK_SIZE;
|
||||
} while (length);
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
@@ -421,11 +424,11 @@ archive_write_lzop_write(struct archive_write_filter *f,
|
||||
static int
|
||||
archive_write_lzop_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
const uint32_t endmark = 0;
|
||||
int r;
|
||||
|
||||
if (data->uncompressed_avail_bytes < BLOCK_SIZE) {
|
||||
if (lzop->uncompressed_avail_bytes < BLOCK_SIZE) {
|
||||
/* Compress and output remaining data. */
|
||||
r = drive_compressor(f);
|
||||
if (r != ARCHIVE_OK)
|
||||
@@ -436,24 +439,35 @@ archive_write_lzop_close(struct archive_write_filter *f)
|
||||
return __archive_write_filter(f->next_filter, &endmark, sizeof(endmark));
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct lzop *lzop)
|
||||
{
|
||||
if (lzop != NULL) {
|
||||
free(lzop->uncompressed);
|
||||
free(lzop->compressed);
|
||||
free(lzop->work_buffer);
|
||||
free(lzop);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
static int
|
||||
archive_write_lzop_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
struct archive_string as;
|
||||
int r;
|
||||
|
||||
archive_string_init(&as);
|
||||
archive_strcpy(&as, "lzop");
|
||||
/* Specify compression level. */
|
||||
if (data->compression_level > 0) {
|
||||
if (lzop->compression_level > 0) {
|
||||
archive_strappend_char(&as, ' ');
|
||||
archive_strappend_char(&as, '-');
|
||||
archive_strappend_char(&as, '0' + data->compression_level);
|
||||
archive_strappend_char(&as, '0' + lzop->compression_level);
|
||||
}
|
||||
|
||||
r = __archive_write_program_open(f, data->pdata, as.s);
|
||||
r = __archive_write_program_open(f, lzop->pdata, as.s);
|
||||
archive_string_free(&as);
|
||||
return (r);
|
||||
}
|
||||
@@ -462,16 +476,25 @@ static int
|
||||
archive_write_lzop_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
|
||||
return __archive_write_program_write(f, data->pdata, buff, length);
|
||||
return __archive_write_program_write(f, lzop->pdata, buff, length);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_lzop_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct write_lzop *data = (struct write_lzop *)f->data;
|
||||
struct lzop *lzop = f->data;
|
||||
|
||||
return __archive_write_program_close(f, data->pdata);
|
||||
return __archive_write_program_close(f, lzop->pdata);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct lzop *lzop)
|
||||
{
|
||||
if (lzop != NULL) {
|
||||
__archive_write_program_free(lzop->pdata);
|
||||
free(lzop);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,7 @@ struct archive_write_program_data {
|
||||
char *program_name;
|
||||
};
|
||||
|
||||
struct private_data {
|
||||
struct program {
|
||||
struct archive_write_program_data *pdata;
|
||||
struct archive_string description;
|
||||
char *cmd;
|
||||
@@ -81,51 +81,53 @@ static int archive_compressor_program_write(struct archive_write_filter *,
|
||||
const void *, size_t);
|
||||
static int archive_compressor_program_close(struct archive_write_filter *);
|
||||
static int archive_compressor_program_free(struct archive_write_filter *);
|
||||
static void free_data(struct program *);
|
||||
|
||||
/*
|
||||
* Add a filter to this write handle that passes all data through an
|
||||
* external program.
|
||||
*/
|
||||
int
|
||||
archive_write_add_filter_program(struct archive *_a, const char *cmd)
|
||||
archive_write_add_filter_program(struct archive *a, const char *cmd)
|
||||
{
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct private_data *data;
|
||||
struct archive_write_filter *f;
|
||||
struct program *program;
|
||||
static const char prefix[] = "Program: ";
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_program");
|
||||
|
||||
f->data = calloc(1, sizeof(*data));
|
||||
if (f->data == NULL)
|
||||
program = calloc(1, sizeof(*program));
|
||||
if (program == NULL)
|
||||
goto memerr;
|
||||
data = (struct private_data *)f->data;
|
||||
|
||||
data->cmd = strdup(cmd);
|
||||
if (data->cmd == NULL)
|
||||
program->cmd = strdup(cmd);
|
||||
if (program->cmd == NULL)
|
||||
goto memerr;
|
||||
|
||||
data->pdata = __archive_write_program_allocate(cmd);
|
||||
if (data->pdata == NULL)
|
||||
program->pdata = __archive_write_program_allocate(cmd);
|
||||
if (program->pdata == NULL)
|
||||
goto memerr;
|
||||
|
||||
/* Make up a description string. */
|
||||
if (archive_string_ensure(&data->description,
|
||||
if (archive_string_ensure(&program->description,
|
||||
strlen(prefix) + strlen(cmd) + 1) == NULL)
|
||||
goto memerr;
|
||||
archive_strcpy(&data->description, prefix);
|
||||
archive_strcat(&data->description, cmd);
|
||||
archive_strcpy(&program->description, prefix);
|
||||
archive_strcat(&program->description, cmd);
|
||||
|
||||
f->name = data->description.s;
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = program->description.s;
|
||||
f->code = ARCHIVE_FILTER_PROGRAM;
|
||||
f->data = program;
|
||||
f->open = archive_compressor_program_open;
|
||||
f->write = archive_compressor_program_write;
|
||||
f->close = archive_compressor_program_close;
|
||||
f->free = archive_compressor_program_free;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
memerr:
|
||||
archive_compressor_program_free(f);
|
||||
archive_set_error(_a, ENOMEM,
|
||||
free_data(program);
|
||||
archive_set_error(a, ENOMEM,
|
||||
"Can't allocate memory for filter program");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
@@ -133,40 +135,33 @@ memerr:
|
||||
static int
|
||||
archive_compressor_program_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct program *program = f->data;
|
||||
|
||||
return __archive_write_program_open(f, data->pdata, data->cmd);
|
||||
return __archive_write_program_open(f, program->pdata, program->cmd);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_program_write(struct archive_write_filter *f,
|
||||
const void *buff, size_t length)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct program *program = f->data;
|
||||
|
||||
return __archive_write_program_write(f, data->pdata, buff, length);
|
||||
return __archive_write_program_write(f, program->pdata, buff, length);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_program_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
struct program *program = f->data;
|
||||
|
||||
return __archive_write_program_close(f, data->pdata);
|
||||
return __archive_write_program_close(f, program->pdata);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_compressor_program_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_data *data = (struct private_data *)f->data;
|
||||
|
||||
if (data) {
|
||||
free(data->cmd);
|
||||
archive_string_free(&data->description);
|
||||
__archive_write_program_free(data->pdata);
|
||||
free(data);
|
||||
f->data = NULL;
|
||||
}
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -184,6 +179,10 @@ __archive_write_program_allocate(const char *program)
|
||||
data->child_stdin = -1;
|
||||
data->child_stdout = -1;
|
||||
data->program_name = strdup(program);
|
||||
if (data->program_name == NULL) {
|
||||
free(data);
|
||||
return (NULL);
|
||||
}
|
||||
return (data);
|
||||
}
|
||||
|
||||
@@ -387,3 +386,13 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct program *program)
|
||||
{
|
||||
if (program) {
|
||||
free(program->cmd);
|
||||
archive_string_free(&program->description);
|
||||
__archive_write_program_free(program->pdata);
|
||||
free(program);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
@@ -36,13 +39,14 @@
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_integer.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_string.h"
|
||||
#include "archive_write_private.h"
|
||||
|
||||
#define LBYTES 45
|
||||
|
||||
struct private_uuencode {
|
||||
struct uuencode {
|
||||
int mode;
|
||||
struct archive_string name;
|
||||
struct archive_string encoded_buff;
|
||||
@@ -60,39 +64,44 @@ static int archive_filter_uuencode_close(struct archive_write_filter *);
|
||||
static int archive_filter_uuencode_free(struct archive_write_filter *);
|
||||
static void uu_encode(struct archive_string *, const unsigned char *, size_t);
|
||||
static int64_t atol8(const char *, size_t);
|
||||
static void free_data(struct uuencode *);
|
||||
|
||||
/*
|
||||
* Add a compress filter to this write handle.
|
||||
*/
|
||||
int
|
||||
archive_write_add_filter_uuencode(struct archive *_a)
|
||||
archive_write_add_filter_uuencode(struct archive *a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct archive_write_filter *f = __archive_write_allocate_filter(_a);
|
||||
struct private_uuencode *state;
|
||||
struct archive_write_filter *f;
|
||||
struct uuencode *uuencode;
|
||||
|
||||
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_uu");
|
||||
archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_add_filter_uuencode");
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
if (state == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for uuencode filter");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
archive_strcpy(&state->name, "-");
|
||||
state->mode = 0644;
|
||||
uuencode = calloc(1, sizeof(*uuencode));
|
||||
if (uuencode == NULL)
|
||||
goto memerr;
|
||||
archive_strcpy(&uuencode->name, "-");
|
||||
uuencode->mode = 0644;
|
||||
|
||||
f->data = state;
|
||||
f = __archive_write_allocate_filter(a);
|
||||
if (f == NULL)
|
||||
goto memerr;
|
||||
f->name = "uuencode";
|
||||
f->code = ARCHIVE_FILTER_UU;
|
||||
f->open = archive_filter_uuencode_open;
|
||||
f->data = uuencode;
|
||||
f->options = archive_filter_uuencode_options;
|
||||
f->open = archive_filter_uuencode_open;
|
||||
f->write = archive_filter_uuencode_write;
|
||||
f->close = archive_filter_uuencode_close;
|
||||
f->free = archive_filter_uuencode_free;
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
memerr:
|
||||
free_data(uuencode);
|
||||
archive_set_error(a, ENOMEM,
|
||||
"Can't allocate data for uuencode filter");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -102,15 +111,23 @@ static int
|
||||
archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
|
||||
const char *value)
|
||||
{
|
||||
struct private_uuencode *state = (struct private_uuencode *)f->data;
|
||||
struct uuencode *uuencode = f->data;
|
||||
|
||||
if (strcmp(key, "mode") == 0) {
|
||||
int64_t val;
|
||||
|
||||
if (value == NULL) {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"mode option requires octal digits");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
state->mode = (int)atol8(value, strlen(value)) & 0777;
|
||||
val = atol8(value, strlen(value));
|
||||
if (val < 0 || val > INT_MAX) {
|
||||
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
|
||||
"invalid mode option");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
uuencode->mode = (int)val & 0777;
|
||||
return (ARCHIVE_OK);
|
||||
} else if (strcmp(key, "name") == 0) {
|
||||
if (value == NULL) {
|
||||
@@ -118,7 +135,7 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
|
||||
"name option requires a string");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
archive_strcpy(&state->name, value);
|
||||
archive_strcpy(&uuencode->name, value);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -134,7 +151,7 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
|
||||
static int
|
||||
archive_filter_uuencode_open(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_uuencode *state = (struct private_uuencode *)f->data;
|
||||
struct uuencode *uuencode = f->data;
|
||||
size_t bs = 65536, bpb;
|
||||
|
||||
if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
|
||||
@@ -147,18 +164,17 @@ archive_filter_uuencode_open(struct archive_write_filter *f)
|
||||
bs -= bs % bpb;
|
||||
}
|
||||
|
||||
state->bs = bs;
|
||||
if (archive_string_ensure(&state->encoded_buff, bs + 512) == NULL) {
|
||||
uuencode->bs = bs;
|
||||
if (archive_string_ensure(&uuencode->encoded_buff, bs + 512) == NULL) {
|
||||
archive_set_error(f->archive, ENOMEM,
|
||||
"Can't allocate data for uuencode buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
|
||||
(unsigned int)state->mode, state->name.s);
|
||||
archive_string_sprintf(&uuencode->encoded_buff, "begin %o %s\n",
|
||||
(unsigned int)uuencode->mode, uuencode->name.s);
|
||||
|
||||
f->data = state;
|
||||
return (0);
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -204,39 +220,39 @@ static int
|
||||
archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
|
||||
size_t length)
|
||||
{
|
||||
struct private_uuencode *state = (struct private_uuencode *)f->data;
|
||||
struct uuencode *uuencode = f->data;
|
||||
const unsigned char *p = buff;
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
if (length == 0)
|
||||
return (ret);
|
||||
|
||||
if (state->hold_len) {
|
||||
while (state->hold_len < LBYTES && length > 0) {
|
||||
state->hold[state->hold_len++] = *p++;
|
||||
if (uuencode->hold_len) {
|
||||
while (uuencode->hold_len < LBYTES && length > 0) {
|
||||
uuencode->hold[uuencode->hold_len++] = *p++;
|
||||
length--;
|
||||
}
|
||||
if (state->hold_len < LBYTES)
|
||||
if (uuencode->hold_len < LBYTES)
|
||||
return (ret);
|
||||
uu_encode(&state->encoded_buff, state->hold, LBYTES);
|
||||
state->hold_len = 0;
|
||||
uu_encode(&uuencode->encoded_buff, uuencode->hold, LBYTES);
|
||||
uuencode->hold_len = 0;
|
||||
}
|
||||
|
||||
for (; length >= LBYTES; length -= LBYTES, p += LBYTES)
|
||||
uu_encode(&state->encoded_buff, p, LBYTES);
|
||||
uu_encode(&uuencode->encoded_buff, p, LBYTES);
|
||||
|
||||
/* Save remaining bytes. */
|
||||
if (length > 0) {
|
||||
memcpy(state->hold, p, length);
|
||||
state->hold_len = length;
|
||||
memcpy(uuencode->hold, p, length);
|
||||
uuencode->hold_len = length;
|
||||
}
|
||||
while (archive_strlen(&state->encoded_buff) >= state->bs) {
|
||||
while (archive_strlen(&uuencode->encoded_buff) >= uuencode->bs) {
|
||||
ret = __archive_write_filter(f->next_filter,
|
||||
state->encoded_buff.s, state->bs);
|
||||
memmove(state->encoded_buff.s,
|
||||
state->encoded_buff.s + state->bs,
|
||||
state->encoded_buff.length - state->bs);
|
||||
state->encoded_buff.length -= state->bs;
|
||||
uuencode->encoded_buff.s, uuencode->bs);
|
||||
memmove(uuencode->encoded_buff.s,
|
||||
uuencode->encoded_buff.s + uuencode->bs,
|
||||
uuencode->encoded_buff.length - uuencode->bs);
|
||||
uuencode->encoded_buff.length -= uuencode->bs;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
@@ -249,26 +265,24 @@ archive_filter_uuencode_write(struct archive_write_filter *f, const void *buff,
|
||||
static int
|
||||
archive_filter_uuencode_close(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_uuencode *state = (struct private_uuencode *)f->data;
|
||||
struct uuencode *uuencode = f->data;
|
||||
|
||||
/* Flush remaining bytes. */
|
||||
if (state->hold_len != 0)
|
||||
uu_encode(&state->encoded_buff, state->hold, state->hold_len);
|
||||
archive_string_sprintf(&state->encoded_buff, "`\nend\n");
|
||||
if (uuencode->hold_len != 0)
|
||||
uu_encode(&uuencode->encoded_buff, uuencode->hold,
|
||||
uuencode->hold_len);
|
||||
archive_string_sprintf(&uuencode->encoded_buff, "`\nend\n");
|
||||
/* Write the last block */
|
||||
archive_write_set_bytes_in_last_block(f->archive, 1);
|
||||
return __archive_write_filter(f->next_filter,
|
||||
state->encoded_buff.s, archive_strlen(&state->encoded_buff));
|
||||
uuencode->encoded_buff.s, archive_strlen(&uuencode->encoded_buff));
|
||||
}
|
||||
|
||||
static int
|
||||
archive_filter_uuencode_free(struct archive_write_filter *f)
|
||||
{
|
||||
struct private_uuencode *state = (struct private_uuencode *)f->data;
|
||||
|
||||
archive_string_free(&state->name);
|
||||
archive_string_free(&state->encoded_buff);
|
||||
free(state);
|
||||
free_data(f->data);
|
||||
f->data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
@@ -277,17 +291,30 @@ atol8(const char *p, size_t char_cnt)
|
||||
{
|
||||
int64_t l;
|
||||
int digit;
|
||||
|
||||
|
||||
if (char_cnt == 0)
|
||||
return (-1);
|
||||
|
||||
l = 0;
|
||||
while (char_cnt-- > 0) {
|
||||
if (*p >= '0' && *p <= '7')
|
||||
digit = *p - '0';
|
||||
else
|
||||
break;
|
||||
return (-1);
|
||||
p++;
|
||||
l <<= 3;
|
||||
l |= digit;
|
||||
if (archive_ckd_mul_i64(&l, l, 8) ||
|
||||
archive_ckd_add_i64(&l, l, digit))
|
||||
return (-1);
|
||||
}
|
||||
return (l);
|
||||
}
|
||||
|
||||
static void
|
||||
free_data(struct uuencode *uuencode)
|
||||
{
|
||||
if (uuencode != NULL) {
|
||||
archive_string_free(&uuencode->name);
|
||||
archive_string_free(&uuencode->encoded_buff);
|
||||
free(uuencode);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user