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