diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c2f7100b4..4c1f8770ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,9 @@ set(MACHO_CURRENT_VERSION "${MACHO_COMPATIBILITY_VERSION}.${_revision}") # saving and restoring the state of the variables. INCLUDE(CMakePushCheckState) +# Enable the pkg-config helpers. +INCLUDE(FindPkgConfig) + # Initialize the state of the variables. This initialization is not # necessary but this shows you what value the variables initially have. SET(CMAKE_REQUIRED_DEFINITIONS) @@ -225,6 +228,7 @@ OPTION(ENABLE_ZLIB "Enable the use of the system ZLIB library if found" ON) OPTION(ENABLE_BZip2 "Enable the use of the system BZip2 library if found" ON) OPTION(ENABLE_LIBXML2 "Enable the use of the system libxml2 library if found" ON) OPTION(ENABLE_EXPAT "Enable the use of the system EXPAT library if found" ON) +OPTION(ENABLE_WIN32_XMLLITE "Enable the use of the Windows XmlLite library if found" ON) OPTION(ENABLE_PCREPOSIX "Enable the use of the system PCREPOSIX library if found" ON) OPTION(ENABLE_PCRE2POSIX "Enable the use of the system PCRE2POSIX library if found" ON) OPTION(ENABLE_LIBGCC "Enable the use of the system LibGCC library if found" ON) @@ -353,10 +357,12 @@ ENDMACRO (GENERATE_LIST_H) # Generate installation rules for man pages. # MACRO (INSTALL_MAN __mans) - FOREACH (_man ${ARGV}) - STRING(REGEX REPLACE "^.+[.]([1-9])" "\\1" _mansect ${_man}) - INSTALL(FILES ${_man} DESTINATION "share/man/man${_mansect}") - ENDFOREACH (_man) + IF(ENABLE_INSTALL) + FOREACH (_man ${ARGV}) + STRING(REGEX REPLACE "^.+[.]([1-9])" "\\1" _mansect ${_man}) + INSTALL(FILES ${_man} DESTINATION "share/man/man${_mansect}") + ENDFOREACH (_man) + ENDIF(ENABLE_INSTALL) ENDMACRO (INSTALL_MAN __mans) # # Find out what macro is needed to use libraries on Windows. @@ -581,6 +587,7 @@ IF(ENABLE_LIBB2) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBB2 DEFAULT_MSG LIBB2_LIBRARY LIBB2_INCLUDE_DIR) ELSE(ENABLE_LIBB2) SET(LIBB2_FOUND FALSE) # Override cached value + UNSET(LIBB2_PKGCONFIG_VERSION CACHE) ENDIF(ENABLE_LIBB2) IF(LIBB2_FOUND) SET(HAVE_LIBB2 1) @@ -593,8 +600,13 @@ IF(LIBB2_FOUND) SET(CMAKE_REQUIRED_INCLUDES ${LIBB2_INCLUDE_DIR}) CHECK_FUNCTION_EXISTS(blake2sp_init HAVE_LIBB2) CMAKE_POP_CHECK_STATE() + pkg_check_modules(LIBB2 libb2) + IF(LIBB2_VERSION) + SET(LIBB2_PKGCONFIG_VERSION LIBB2_VERSION) + ENDIF(LIBB2_VERSION) ELSE(LIBB2_FOUND) SET(ARCHIVE_BLAKE2 TRUE) + UNSET(LIBB2_PKGCONFIG_VERSION CACHE) ENDIF(LIBB2_FOUND) # # Find LZ4 @@ -657,6 +669,7 @@ IF(ZSTD_FOUND) SET(CMAKE_REQUIRED_INCLUDES ${ZSTD_INCLUDE_DIR}) CHECK_FUNCTION_EXISTS(ZSTD_decompressStream HAVE_LIBZSTD) CHECK_FUNCTION_EXISTS(ZSTD_compressStream HAVE_ZSTD_compressStream) + CHECK_FUNCTION_EXISTS(ZSTD_minCLevel HAVE_ZSTD_minCLevel) # # TODO: test for static library. # @@ -665,7 +678,6 @@ ENDIF(ZSTD_FOUND) MARK_AS_ADVANCED(CLEAR ZSTD_INCLUDE_DIR) MARK_AS_ADVANCED(CLEAR ZSTD_LIBRARY) - # # Check headers # @@ -796,7 +808,7 @@ IF(ENABLE_MBEDTLS) LA_CHECK_INCLUDE_FILE("mbedtls/aes.h" HAVE_MBEDTLS_AES_H) LA_CHECK_INCLUDE_FILE("mbedtls/md.h" HAVE_MBEDTLS_MD_H) LA_CHECK_INCLUDE_FILE("mbedtls/pkcs5.h" HAVE_MBEDTLS_PKCS5_H) - + LA_CHECK_INCLUDE_FILE("mbedtls/version.h" HAVE_MBEDTLS_VERSION_H) ENDIF(MBEDTLS_FOUND) MARK_AS_ADVANCED(CLEAR MBEDTLS_INCLUDE_DIRS) MARK_AS_ADVANCED(CLEAR MBEDCRYPTO_LIBRARY) @@ -819,7 +831,7 @@ IF(ENABLE_NETTLE) LA_CHECK_INCLUDE_FILE("nettle/pbkdf2.h" HAVE_NETTLE_PBKDF2_H) LA_CHECK_INCLUDE_FILE("nettle/ripemd160.h" HAVE_NETTLE_RIPEMD160_H) LA_CHECK_INCLUDE_FILE("nettle/sha.h" HAVE_NETTLE_SHA_H) - + LA_CHECK_INCLUDE_FILE("nettle/version.h" HAVE_NETTLE_VERSION_H) ENDIF(NETTLE_FOUND) MARK_AS_ADVANCED(CLEAR NETTLE_INCLUDE_DIR) MARK_AS_ADVANCED(CLEAR NETTLE_LIBRARIES) @@ -838,6 +850,7 @@ IF(ENABLE_OPENSSL AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin") SET(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY}) SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR}) LA_CHECK_INCLUDE_FILE("openssl/evp.h" HAVE_OPENSSL_EVP_H) + LA_CHECK_INCLUDE_FILE("openssl/opensslv.h" HAVE_OPENSSL_OPENSSLV_H) CHECK_FUNCTION_EXISTS(PKCS5_PBKDF2_HMAC_SHA1 HAVE_PKCS5_PBKDF2_HMAC_SHA1) ENDIF(OPENSSL_FOUND) ELSE() @@ -1045,7 +1058,6 @@ main(int argc, char **argv) "${OUTPUT}\n" "Source file was:\n${SOURCE}\n") ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN) - ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN) ENDIF(NOT ARCHIVE_CRYPTO_${CRYPTO}) ENDFOREACH(CRYPTO) @@ -1138,6 +1150,7 @@ IF(ENABLE_ICONV) CHECK_ICONV("libiconv" "const") CHECK_ICONV("libiconv" "") IF (HAVE_ICONV) + SET(HAVE_LIBICONV 1) LIST(APPEND ADDITIONAL_LIBS ${LIBICONV_PATH}) ENDIF(HAVE_ICONV) ENDIF(NOT HAVE_ICONV AND LIBICONV_PATH) @@ -1181,6 +1194,7 @@ ELSE(ENABLE_ICONV) # (once enabled). UNSET(HAVE_LOCALE_CHARSET CACHE) UNSET(HAVE_ICONV CACHE) + UNSET(HAVE_LIBICONV CACHE) UNSET(HAVE_ICONV_libc_ CACHE) UNSET(HAVE_ICONV_libc_const CACHE) UNSET(HAVE_ICONV_libiconv_ CACHE) @@ -1210,6 +1224,7 @@ IF(LIBXML2_FOUND) SET(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) CHECK_INCLUDE_FILES("libxml/xmlreader.h" HAVE_LIBXML_XMLREADER_H) CHECK_INCLUDE_FILES("libxml/xmlwriter.h" HAVE_LIBXML_XMLWRITER_H) + CHECK_INCLUDE_FILES("libxml/xmlversion.h" HAVE_LIBXML_XMLVERSION_H) # Test if a macro is needed for the library. TRY_MACRO_FOR_LIBRARY( "${ICONV_INCLUDE_DIR};${LIBXML2_INCLUDE_DIR}" @@ -1237,6 +1252,25 @@ ELSE(LIBXML2_FOUND) SET(HAVE_LIBEXPAT 1) LA_CHECK_INCLUDE_FILE("expat.h" HAVE_EXPAT_H) CMAKE_POP_CHECK_STATE() # Restore the state of the variables + ELSE(EXPAT_FOUND) + IF(WIN32 AND ENABLE_WIN32_XMLLITE) + # Check linkage as well; versions of mingw-w64 before v11.0.0 + # do not contain an import library for xmllite. + cmake_push_check_state() + SET(CMAKE_REQUIRED_LIBRARIES "xmllite" "uuid") + check_c_source_compiles(" + #include + #include + int main() { + return CreateXmlReader(&IID_IXmlReader, NULL, NULL); + } + " HAVE_XMLLITE_H) + cmake_pop_check_state() + IF(HAVE_XMLLITE_H) + SET(XMLLITE_FOUND TRUE) + LIST(APPEND ADDITIONAL_LIBS "xmllite" "uuid") + ENDIF() + ENDIF() ENDIF(EXPAT_FOUND) ENDIF(LIBXML2_FOUND) MARK_AS_ADVANCED(CLEAR LIBXML2_INCLUDE_DIR) @@ -1790,11 +1824,16 @@ IF(ENABLE_XATTR) CHECK_LIBRARY_EXISTS(attr "setxattr" "" HAVE_LIBATTR) IF(HAVE_LIBATTR) SET(CMAKE_REQUIRED_LIBRARIES "attr") - ELSE() + pkg_check_modules(LIBATTR libattr) + IF(LIBATTR_VERSION) + SET(LIBATTR_PKGCONFIG_VERSION ${LIBATTR_VERSION}) + ENDIF(LIBATTR_VERSION) + ELSE(HAVE_LIBATTR) CHECK_LIBRARY_EXISTS(gnu "setxattr" "" HAVE_LIBATTR_GNU) IF(HAVE_LIBATTR_GNU) SET(CMAKE_REQUIRED_LIBRARIES "gnu") ENDIF() + UNSET(LIBATTR_PKGCONFIG_VERSION CACHE) ENDIF(HAVE_LIBATTR) CHECK_SYMBOL_EXISTS(EXTATTR_NAMESPACE_USER "sys/types.h;sys/extattr.h" HAVE_DECL_EXTATTR_NAMESPACE_USER) CHECK_SYMBOL_EXISTS(XATTR_NOFOLLOW "sys/xattr.h" HAVE_DECL_XATTR_NOFOLLOW) @@ -1912,6 +1951,12 @@ IF(ENABLE_ACL) SET(CMAKE_REQUIRED_LIBRARIES "acl") FIND_LIBRARY(ACL_LIBRARY NAMES acl) LIST(APPEND ADDITIONAL_LIBS ${ACL_LIBRARY}) + pkg_check_modules(LIBACL libacl) + IF(LIBACL_VERSION) + SET(LIBACL_PKGCONFIG_VERSION ${LIBACL_VERSION}) + ENDIF(LIBACL_VERSION) + ELSE(HAVE_LIBACL) + UNSET(LIBACL_PKGCONFIG_VERSION CACHE) ENDIF(HAVE_LIBACL) CHECK_TYPE_EXISTS(acl_t "sys/types.h;sys/acl.h" HAVE_ACL_T) @@ -2051,6 +2096,12 @@ int main(void) { return ACL_SYNCHRONIZE; }" HAVE_DECL_ACL_SYNCHRONIZE) SET(CMAKE_REQUIRED_LIBRARIES "richacl") FIND_LIBRARY(RICHACL_LIBRARY NAMES richacl) LIST(APPEND ADDITIONAL_LIBS ${RICHACL_LIBRARY}) + pkg_check_modules(LIBRICHACL librichacl) + IF(LIBRICHACL_VERSION) + SET(LIBRICHACL_PKGCONFIG_VERSION ${LIBRICHACL_VERSION}) + ENDIF(LIBRICHACL_VERSION) + ELSE(HAVE_LIBRICHACL) + UNSET(LIBRICHACL_PKGCONFIG_VERSION CACHE) ENDIF(HAVE_LIBRICHACL) CHECK_STRUCT_HAS_MEMBER("struct richace" e_type "sys/richacl.h" @@ -2150,7 +2201,7 @@ INCLUDE(CreatePkgConfigFile) # # Register installation of PDF documents. # -IF(WIN32 AND NOT CYGWIN) +IF(WIN32 AND NOT CYGWIN AND ENABLE_INSTALL) # # On Windows platform, It's better that we install PDF documents # on one's computer. @@ -2162,7 +2213,7 @@ IF(WIN32 AND NOT CYGWIN) FILES_MATCHING PATTERN "*.pdf" ) ENDIF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/doc/pdf) -ENDIF(WIN32 AND NOT CYGWIN) +ENDIF(WIN32 AND NOT CYGWIN AND ENABLE_INSTALL) # # # diff --git a/COPYING b/COPYING index 1b9723574a..9d0bcf81ff 100644 --- a/COPYING +++ b/COPYING @@ -20,7 +20,7 @@ the actual statements in the files are controlling. libarchive/mtree.5 * The following source files are in the public domain: - libarchive/archive_getdate.c + libarchive/archive_parse_date.c * The following source files are triple-licensed with the ability to choose from CC0 1.0 Universal, OpenSSL or Apache 2.0 licenses: diff --git a/build/cmake/CreatePkgConfigFile.cmake b/build/cmake/CreatePkgConfigFile.cmake index bc5a43f72a..50caa5e850 100644 --- a/build/cmake/CreatePkgConfigFile.cmake +++ b/build/cmake/CreatePkgConfigFile.cmake @@ -29,5 +29,5 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in # And install it, of course ;). IF(ENABLE_INSTALL) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc - DESTINATION "lib/pkgconfig") + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") ENDIF() diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in index 1f6b0c2122..692d4516ab 100644 --- a/build/cmake/config.h.in +++ b/build/cmake/config.h.in @@ -729,6 +729,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `gcc' library (-lgcc). */ #cmakedefine HAVE_LIBGCC 1 +/* Define to 1 if you have the `iconv' library (-liconv). */ +#cmakedefine HAVE_LIBICONV 1 + /* Define to 1 if you have the `lz4' library (-llz4). */ #cmakedefine HAVE_LIBLZ4 1 @@ -765,6 +768,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LIBXML_XMLWRITER_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBXML_XMLVERSION_H 1 + /* Define to 1 if you have the `z' library (-lz). */ #cmakedefine HAVE_LIBZ 1 @@ -774,6 +780,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the ZSTD_compressStream function. */ #cmakedefine HAVE_ZSTD_compressStream 1 +/* Define to 1 if you have the ZSTD_minCLevel function. */ +#cmakedefine HAVE_ZSTD_minCLevel 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LIMITS_H 1 @@ -865,6 +874,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MBEDTLS_PKCS5_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MBEDTLS_VERSION_H 1 + /* Define to 1 if you have the `mbrtowc' function. */ #cmakedefine HAVE_MBRTOWC 1 @@ -910,6 +922,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_NETTLE_SHA_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETTLE_VERSION_H 1 + /* Define to 1 if you have the `nl_langinfo' function. */ #cmakedefine HAVE_NL_LANGINFO 1 @@ -919,6 +934,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OPENSSL_EVP_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_OPENSSL_OPENSSLV_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_PATHS_H 1 @@ -1141,7 +1159,6 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H 1 - /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SYSMACROS_H 1 @@ -1265,6 +1282,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have a working FS_IOC_GETFLAGS */ #cmakedefine HAVE_WORKING_FS_IOC_GETFLAGS 1 +/* Define to 1 if you have the Windows `xmllite' library (-lxmllite). */ +#cmakedefine HAVE_XMLLITE_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ZLIB_H 1 @@ -1322,6 +1342,15 @@ typedef uint64_t uintmax_t; /* Define to 1 if you can safely include both and . */ #cmakedefine TIME_WITH_SYS_TIME 1 +/* Version number of package */ +#cmakedefine LIBATTR_PKGCONFIG_VERSION "@LIBATTR_PKGCONFIG_VERSION@" + +/* Version number of package */ +#cmakedefine LIBACL_PKGCONFIG_VERSION "@LIBACL_PKGCONFIG_VERSION@" + +/* Version number of package */ +#cmakedefine LIBRICHACL_PKGCONFIG_VERSION "@LIBRICHACL_PKGCONFIG_VERSION@" + /* * Some platform requires a macro to use extension functions. */ diff --git a/build/utils/gen_archive_string_composition_h.sh b/build/utils/gen_archive_string_composition_h.sh index 93012fe68f..6500de8df2 100755 --- a/build/utils/gen_archive_string_composition_h.sh +++ b/build/utils/gen_archive_string_composition_h.sh @@ -1,4 +1,12 @@ #!/bin/sh +set -eu + +if [ $# != 1 ] +then + echo "Usage: $0 path/to/UnicodeData.txt" + exit 1 +fi + # # This needs http://unicode.org/Public/6.0.0/ucd/UnicodeData.txt # diff --git a/build/version b/build/version index cbbb0be849..f08c8c42bf 100644 --- a/build/version +++ b/build/version @@ -1 +1 @@ -3007009 +3008001 diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt index dd0b2808d9..fd997db411 100644 --- a/libarchive/CMakeLists.txt +++ b/libarchive/CMakeLists.txt @@ -38,8 +38,6 @@ SET(libarchive_SOURCES archive_entry_stat.c archive_entry_strmode.c archive_entry_xattr.c - archive_getdate.c - archive_getdate.h archive_hmac.c archive_hmac_private.h archive_match.c @@ -49,6 +47,7 @@ SET(libarchive_SOURCES archive_options_private.h archive_pack_dev.h archive_pack_dev.c + archive_parse_date.c archive_pathmatch.c archive_pathmatch.h archive_platform.h @@ -117,6 +116,8 @@ SET(libarchive_SOURCES archive_string.h archive_string_composition.h archive_string_sprintf.c + archive_time.c + archive_time_private.h archive_util.c archive_version_details.c archive_virtual.c @@ -247,7 +248,7 @@ IF(BUILD_SHARED_LIBS) ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS}) TARGET_INCLUDE_DIRECTORIES(archive PUBLIC .) TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS}) - SET_TARGET_PROPERTIES(archive PROPERTIES + SET_TARGET_PROPERTIES(archive PROPERTIES VERSION ${SOVERSION_FULL} SOVERSION ${SOVERSION} MACHO_COMPATIBILITY_VERSION ${MACHO_COMPATIBILITY_VERSION} @@ -265,18 +266,22 @@ IF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS) SET_TARGET_PROPERTIES(archive_static PROPERTIES OUTPUT_NAME archive) ENDIF(NOT WIN32 OR CYGWIN OR NOT BUILD_SHARED_LIBS) +if(NOT DEFINED CMAKE_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR "lib") +endif() + IF(ENABLE_INSTALL) # How to install the libraries IF(BUILD_SHARED_LIBS) INSTALL(TARGETS archive RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ENDIF(BUILD_SHARED_LIBS) INSTALL(TARGETS archive_static RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib) + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) INSTALL_MAN(${libarchive_MANS}) INSTALL(FILES ${include_HEADERS} DESTINATION include) ENDIF() diff --git a/libarchive/archive.h b/libarchive/archive.h index ddbf66c112..002190a246 100644 --- a/libarchive/archive.h +++ b/libarchive/archive.h @@ -34,12 +34,15 @@ * assert that ARCHIVE_VERSION_NUMBER >= 2012108. */ /* Note: Compiler will complain if this does not match archive_entry.h! */ -#define ARCHIVE_VERSION_NUMBER 3007009 +#define ARCHIVE_VERSION_NUMBER 3008001 #include #include /* for wchar_t */ #include /* For FILE * */ +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* time_t is slated to be removed from public includes in 4.0 */ #include /* For time_t */ +#endif /* * Note: archive.h is for use outside of libarchive; the configuration @@ -63,12 +66,15 @@ #define __LA_INT64_T_DEFINED # if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) typedef __int64 la_int64_t; +typedef unsigned __int64 la_uint64_t; # else # include /* ssize_t */ # if defined(_SCO_DS) || defined(__osf__) typedef long long la_int64_t; +typedef unsigned long long la_uint64_t; # else typedef int64_t la_int64_t; +typedef uint64_t la_uint64_t; # endif # endif #endif @@ -94,6 +100,22 @@ typedef ssize_t la_ssize_t; # endif #endif +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Use the platform types for time_t */ +#define __LA_TIME_T time_t +#else +/* Use 64-bits integer types for time_t */ +#define __LA_TIME_T la_int64_t +#endif + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Use the platform types for dev_t */ +#define __LA_DEV_T dev_t +#else +/* Use 64-bits integer types for dev_t */ +#define __LA_DEV_T la_int64_t +#endif + /* Large file support for Android */ #if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__) #include "android_lf.h" @@ -155,7 +177,7 @@ __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_ONLY_STRING "3.7.9" +#define ARCHIVE_VERSION_ONLY_STRING "3.8.1" #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char * archive_version_string(void); @@ -178,6 +200,23 @@ __LA_DECL const char * archive_liblzma_version(void); __LA_DECL const char * archive_bzlib_version(void); __LA_DECL const char * archive_liblz4_version(void); __LA_DECL const char * archive_libzstd_version(void); +__LA_DECL const char * archive_liblzo2_version(void); +__LA_DECL const char * archive_libexpat_version(void); +__LA_DECL const char * archive_libbsdxml_version(void); +__LA_DECL const char * archive_libxml2_version(void); +__LA_DECL const char * archive_mbedtls_version(void); +__LA_DECL const char * archive_nettle_version(void); +__LA_DECL const char * archive_openssl_version(void); +__LA_DECL const char * archive_libmd_version(void); +__LA_DECL const char * archive_commoncrypto_version(void); +__LA_DECL const char * archive_cng_version(void); +__LA_DECL const char * archive_wincrypt_version(void); +__LA_DECL const char * archive_librichacl_version(void); +__LA_DECL const char * archive_libacl_version(void); +__LA_DECL const char * archive_libattr_version(void); +__LA_DECL const char * archive_libiconv_version(void); +__LA_DECL const char * archive_libpcre_version(void); +__LA_DECL const char * archive_libpcre2_version(void); /* Declare our basic types. */ struct archive; @@ -449,6 +488,8 @@ __LA_DECL int archive_read_support_format_by_code(struct archive *, int); __LA_DECL int archive_read_support_format_cab(struct archive *); __LA_DECL int archive_read_support_format_cpio(struct archive *); __LA_DECL int archive_read_support_format_empty(struct archive *); +/* archive_read_support_format_gnutar() is an alias for historical reasons + * of archive_read_support_format_tar(). */ __LA_DECL int archive_read_support_format_gnutar(struct archive *); __LA_DECL int archive_read_support_format_iso9660(struct archive *); __LA_DECL int archive_read_support_format_lha(struct archive *); @@ -828,6 +869,10 @@ __LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const ch __LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext); __LA_DECL int archive_write_zip_set_compression_deflate(struct archive *); __LA_DECL int archive_write_zip_set_compression_store(struct archive *); +__LA_DECL int archive_write_zip_set_compression_lzma(struct archive *); +__LA_DECL int archive_write_zip_set_compression_xz(struct archive *); +__LA_DECL int archive_write_zip_set_compression_bzip2(struct archive *); +__LA_DECL int archive_write_zip_set_compression_zstd(struct archive *); /* Deprecated; use archive_write_open2 instead */ __LA_DECL int archive_write_open(struct archive *, void *, archive_open_callback *, archive_write_callback *, @@ -1083,6 +1128,10 @@ __LA_DECL int archive_compression(struct archive *) __LA_DEPRECATED; #endif +/* Parses a date string relative to the current time. + * NOTE: This is not intended for general date parsing, and the resulting timestamp should only be used for libarchive. */ +__LA_DECL time_t archive_parse_date(time_t now, const char *datestr); + __LA_DECL int archive_errno(struct archive *); __LA_DECL const char *archive_error_string(struct archive *); __LA_DECL const char *archive_format_name(struct archive *); @@ -1201,8 +1250,10 @@ __LA_DECL int archive_match_include_gname_w(struct archive *, const wchar_t *); /* Utility functions */ +#if ARCHIVE_VERSION_NUMBER < 4000000 /* Convenience function to sort a NULL terminated list of strings */ __LA_DECL int archive_utility_string_sort(char **); +#endif #ifdef __cplusplus } diff --git a/libarchive/archive_acl.c b/libarchive/archive_acl.c index bbb085afe7..9e71f5ee56 100644 --- a/libarchive/archive_acl.c +++ b/libarchive/archive_acl.c @@ -1185,8 +1185,13 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, /* Set remaining fields to blank. */ for (n = fields; n < numfields; ++n) field[n].start = field[n].end = NULL; + + if (field[0].start == NULL || field[0].end == NULL) { + /* This should never happen */ + return (ARCHIVE_FATAL); + } - if (field[0].start != NULL && *(field[0].start) == L'#') { + if (*(field[0].start) == L'#') { /* Comment, skip entry */ continue; } @@ -1676,7 +1681,12 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text, for (n = fields; n < numfields; ++n) field[n].start = field[n].end = NULL; - if (field[0].start != NULL && *(field[0].start) == '#') { + if (field[0].start == NULL || field[0].end == NULL) { + /* This should never happen */ + return (ARCHIVE_FATAL); + } + + if (*(field[0].start) == '#') { /* Comment, skip entry */ continue; } diff --git a/libarchive/archive_acl_private.h b/libarchive/archive_acl_private.h index 2c9b505343..54e4439692 100644 --- a/libarchive/archive_acl_private.h +++ b/libarchive/archive_acl_private.h @@ -80,4 +80,4 @@ int archive_acl_from_text_l(struct archive_acl *, const char * /* text */, int archive_acl_from_text_nl(struct archive_acl *, const char * /* text */, size_t /* size of text */, int /* type */, struct archive_string_conv *); -#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ +#endif /* !ARCHIVE_ACL_PRIVATE_H_INCLUDED */ diff --git a/libarchive/archive_cmdline.c b/libarchive/archive_cmdline.c index 2e5428cae5..23bb05d642 100644 --- a/libarchive/archive_cmdline.c +++ b/libarchive/archive_cmdline.c @@ -71,7 +71,7 @@ get_argument(struct archive_string *as, const char *p) archive_string_empty(as); /* Skip beginning space characters. */ - while (*s != '\0' && *s == ' ') + while (*s == ' ') s++; /* Copy non-space characters. */ while (*s != '\0' && *s != ' ') { diff --git a/libarchive/archive_cryptor_private.h b/libarchive/archive_cryptor_private.h index c13f29260a..4b3c6c1614 100644 --- a/libarchive/archive_cryptor_private.h +++ b/libarchive/archive_cryptor_private.h @@ -64,6 +64,7 @@ typedef struct { #elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA #include +#define ARCHIVE_CRYPTOR_USE_CNG 1 /* Common in other bcrypt implementations, but missing from VS2008. */ #ifndef BCRYPT_SUCCESS @@ -86,6 +87,7 @@ typedef struct { #include #include #include +#define ARCHIVE_CRYPTOR_USE_MBED 1 #define AES_MAX_KEY_SIZE 32 #define AES_BLOCK_SIZE 16 @@ -105,6 +107,7 @@ typedef struct { #endif #include #include +#define ARCHIVE_CRYPTOR_USE_NETTLE 1 typedef struct { #if NETTLE_VERSION_MAJOR < 3 @@ -125,6 +128,7 @@ typedef struct { #elif defined(HAVE_LIBCRYPTO) #include "archive_openssl_evp_private.h" +#define ARCHIVE_CRYPTOR_USE_OPENSSL 1 #define AES_BLOCK_SIZE 16 #define AES_MAX_KEY_SIZE 32 @@ -140,6 +144,10 @@ typedef struct { #else +#if defined(_WIN32) && !defined(__CYGWIN__) && !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA) +#define ARCHIVE_CRYPTOR_USE_WINCRYPT 1 +#endif + #define AES_BLOCK_SIZE 16 #define AES_MAX_KEY_SIZE 32 typedef int archive_crypto_ctx; diff --git a/libarchive/archive_digest.c b/libarchive/archive_digest.c index 3351874083..45fc36af11 100644 --- a/libarchive/archive_digest.c +++ b/libarchive/archive_digest.c @@ -229,13 +229,42 @@ __archive_md5final(archive_md5_ctx *ctx, void *md) #pragma clang diagnostic pop #endif +#elif defined(ARCHIVE_CRYPTO_MD5_WIN) + +static int +__archive_md5init(archive_md5_ctx *ctx) +{ +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM)); +#else + return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5)); +#endif +} + +static int +__archive_md5update(archive_md5_ctx *ctx, const void *indata, + size_t insize) +{ + return (win_crypto_Update(ctx, indata, insize)); +} + +static int +__archive_md5final(archive_md5_ctx *ctx, void *md) +{ + return (win_crypto_Final(md, 16, ctx)); +} + #elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS) static int __archive_md5init(archive_md5_ctx *ctx) { mbedtls_md5_init(ctx); +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_md5_starts(ctx) == 0) +#else if (mbedtls_md5_starts_ret(ctx) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -245,7 +274,11 @@ static int __archive_md5update(archive_md5_ctx *ctx, const void *indata, size_t insize) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_md5_update(ctx, indata, insize) == 0) +#else if (mbedtls_md5_update_ret(ctx, indata, insize) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -254,7 +287,11 @@ __archive_md5update(archive_md5_ctx *ctx, const void *indata, static int __archive_md5final(archive_md5_ctx *ctx, void *md) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_md5_finish(ctx, md) == 0) { +#else if (mbedtls_md5_finish_ret(ctx, md) == 0) { +#endif mbedtls_md5_free(ctx); return (ARCHIVE_OK); } else { @@ -322,31 +359,6 @@ __archive_md5final(archive_md5_ctx *ctx, void *md) return (ARCHIVE_OK); } -#elif defined(ARCHIVE_CRYPTO_MD5_WIN) - -static int -__archive_md5init(archive_md5_ctx *ctx) -{ -#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA - return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM)); -#else - return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5)); -#endif -} - -static int -__archive_md5update(archive_md5_ctx *ctx, const void *indata, - size_t insize) -{ - return (win_crypto_Update(ctx, indata, insize)); -} - -static int -__archive_md5final(archive_md5_ctx *ctx, void *md) -{ - return (win_crypto_Final(md, 16, ctx)); -} - #else static int @@ -431,7 +443,11 @@ static int __archive_ripemd160init(archive_rmd160_ctx *ctx) { mbedtls_ripemd160_init(ctx); +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_ripemd160_starts(ctx) == 0) +#else if (mbedtls_ripemd160_starts_ret(ctx) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -441,7 +457,11 @@ static int __archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata, size_t insize) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_ripemd160_update(ctx, indata, insize) == 0) +#else if (mbedtls_ripemd160_update_ret(ctx, indata, insize) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -450,7 +470,11 @@ __archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata, static int __archive_ripemd160final(archive_rmd160_ctx *ctx, void *md) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_ripemd160_finish(ctx, md) == 0) { +#else if (mbedtls_ripemd160_finish_ret(ctx, md) == 0) { +#endif mbedtls_ripemd160_free(ctx); return (ARCHIVE_OK); } else { @@ -616,13 +640,42 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md) return (ARCHIVE_OK); } +#elif defined(ARCHIVE_CRYPTO_SHA1_WIN) + +static int +__archive_sha1init(archive_sha1_ctx *ctx) +{ +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM)); +#else + return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1)); +#endif +} + +static int +__archive_sha1update(archive_sha1_ctx *ctx, const void *indata, + size_t insize) +{ + return (win_crypto_Update(ctx, indata, insize)); +} + +static int +__archive_sha1final(archive_sha1_ctx *ctx, void *md) +{ + return (win_crypto_Final(md, 20, ctx)); +} + #elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS) static int __archive_sha1init(archive_sha1_ctx *ctx) { mbedtls_sha1_init(ctx); +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha1_starts(ctx) == 0) +#else if (mbedtls_sha1_starts_ret(ctx) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -632,7 +685,11 @@ static int __archive_sha1update(archive_sha1_ctx *ctx, const void *indata, size_t insize) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha1_update(ctx, indata, insize) == 0) +#else if (mbedtls_sha1_update_ret(ctx, indata, insize) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -641,7 +698,11 @@ __archive_sha1update(archive_sha1_ctx *ctx, const void *indata, static int __archive_sha1final(archive_sha1_ctx *ctx, void *md) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha1_finish(ctx, md) == 0) { +#else if (mbedtls_sha1_finish_ret(ctx, md) == 0) { +#endif mbedtls_sha1_free(ctx); return (ARCHIVE_OK); } else { @@ -709,31 +770,6 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md) return (ARCHIVE_OK); } -#elif defined(ARCHIVE_CRYPTO_SHA1_WIN) - -static int -__archive_sha1init(archive_sha1_ctx *ctx) -{ -#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA - return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM)); -#else - return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1)); -#endif -} - -static int -__archive_sha1update(archive_sha1_ctx *ctx, const void *indata, - size_t insize) -{ - return (win_crypto_Update(ctx, indata, insize)); -} - -static int -__archive_sha1final(archive_sha1_ctx *ctx, void *md) -{ - return (win_crypto_Final(md, 20, ctx)); -} - #else static int @@ -884,13 +920,42 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md) return (ARCHIVE_OK); } +#elif defined(ARCHIVE_CRYPTO_SHA256_WIN) + +static int +__archive_sha256init(archive_sha256_ctx *ctx) +{ +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM)); +#else + return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256)); +#endif +} + +static int +__archive_sha256update(archive_sha256_ctx *ctx, const void *indata, + size_t insize) +{ + return (win_crypto_Update(ctx, indata, insize)); +} + +static int +__archive_sha256final(archive_sha256_ctx *ctx, void *md) +{ + return (win_crypto_Final(md, 32, ctx)); +} + #elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS) static int __archive_sha256init(archive_sha256_ctx *ctx) { mbedtls_sha256_init(ctx); +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha256_starts(ctx, 0) == 0) +#else if (mbedtls_sha256_starts_ret(ctx, 0) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -900,7 +965,11 @@ static int __archive_sha256update(archive_sha256_ctx *ctx, const void *indata, size_t insize) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha256_update(ctx, indata, insize) == 0) +#else if (mbedtls_sha256_update_ret(ctx, indata, insize) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -909,7 +978,11 @@ __archive_sha256update(archive_sha256_ctx *ctx, const void *indata, static int __archive_sha256final(archive_sha256_ctx *ctx, void *md) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha256_finish(ctx, md) == 0) { +#else if (mbedtls_sha256_finish_ret(ctx, md) == 0) { +#endif mbedtls_sha256_free(ctx); return (ARCHIVE_OK); } else { @@ -973,31 +1046,6 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md) return (ARCHIVE_OK); } -#elif defined(ARCHIVE_CRYPTO_SHA256_WIN) - -static int -__archive_sha256init(archive_sha256_ctx *ctx) -{ -#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA - return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM)); -#else - return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256)); -#endif -} - -static int -__archive_sha256update(archive_sha256_ctx *ctx, const void *indata, - size_t insize) -{ - return (win_crypto_Update(ctx, indata, insize)); -} - -static int -__archive_sha256final(archive_sha256_ctx *ctx, void *md) -{ - return (win_crypto_Final(md, 32, ctx)); -} - #else static int @@ -1124,13 +1172,42 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md) return (ARCHIVE_OK); } +#elif defined(ARCHIVE_CRYPTO_SHA384_WIN) + +static int +__archive_sha384init(archive_sha384_ctx *ctx) +{ +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM)); +#else + return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384)); +#endif +} + +static int +__archive_sha384update(archive_sha384_ctx *ctx, const void *indata, + size_t insize) +{ + return (win_crypto_Update(ctx, indata, insize)); +} + +static int +__archive_sha384final(archive_sha384_ctx *ctx, void *md) +{ + return (win_crypto_Final(md, 48, ctx)); +} + #elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS) static int __archive_sha384init(archive_sha384_ctx *ctx) { mbedtls_sha512_init(ctx); +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha512_starts(ctx, 1) == 0) +#else if (mbedtls_sha512_starts_ret(ctx, 1) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -1140,7 +1217,11 @@ static int __archive_sha384update(archive_sha384_ctx *ctx, const void *indata, size_t insize) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha512_update(ctx, indata, insize) == 0) +#else if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -1149,7 +1230,11 @@ __archive_sha384update(archive_sha384_ctx *ctx, const void *indata, static int __archive_sha384final(archive_sha384_ctx *ctx, void *md) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha512_finish(ctx, md) == 0) { +#else if (mbedtls_sha512_finish_ret(ctx, md) == 0) { +#endif mbedtls_sha512_free(ctx); return (ARCHIVE_OK); } else { @@ -1213,31 +1298,6 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md) return (ARCHIVE_OK); } -#elif defined(ARCHIVE_CRYPTO_SHA384_WIN) - -static int -__archive_sha384init(archive_sha384_ctx *ctx) -{ -#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA - return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM)); -#else - return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384)); -#endif -} - -static int -__archive_sha384update(archive_sha384_ctx *ctx, const void *indata, - size_t insize) -{ - return (win_crypto_Update(ctx, indata, insize)); -} - -static int -__archive_sha384final(archive_sha384_ctx *ctx, void *md) -{ - return (win_crypto_Final(md, 48, ctx)); -} - #else static int @@ -1388,13 +1448,42 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md) return (ARCHIVE_OK); } +#elif defined(ARCHIVE_CRYPTO_SHA512_WIN) + +static int +__archive_sha512init(archive_sha512_ctx *ctx) +{ +#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA + return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM)); +#else + return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512)); +#endif +} + +static int +__archive_sha512update(archive_sha512_ctx *ctx, const void *indata, + size_t insize) +{ + return (win_crypto_Update(ctx, indata, insize)); +} + +static int +__archive_sha512final(archive_sha512_ctx *ctx, void *md) +{ + return (win_crypto_Final(md, 64, ctx)); +} + #elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS) static int __archive_sha512init(archive_sha512_ctx *ctx) { mbedtls_sha512_init(ctx); +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha512_starts(ctx, 0) == 0) +#else if (mbedtls_sha512_starts_ret(ctx, 0) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -1404,7 +1493,11 @@ static int __archive_sha512update(archive_sha512_ctx *ctx, const void *indata, size_t insize) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha512_update(ctx, indata, insize) == 0) +#else if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0) +#endif return (ARCHIVE_OK); else return (ARCHIVE_FATAL); @@ -1413,7 +1506,11 @@ __archive_sha512update(archive_sha512_ctx *ctx, const void *indata, static int __archive_sha512final(archive_sha512_ctx *ctx, void *md) { +#if MBEDTLS_VERSION_NUMBER > 0x03000000 + if (mbedtls_sha512_finish(ctx, md) == 0) { +#else if (mbedtls_sha512_finish_ret(ctx, md) == 0) { +#endif mbedtls_sha512_free(ctx); return (ARCHIVE_OK); } else { @@ -1477,31 +1574,6 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md) return (ARCHIVE_OK); } -#elif defined(ARCHIVE_CRYPTO_SHA512_WIN) - -static int -__archive_sha512init(archive_sha512_ctx *ctx) -{ -#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA - return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM)); -#else - return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512)); -#endif -} - -static int -__archive_sha512update(archive_sha512_ctx *ctx, const void *indata, - size_t insize) -{ - return (win_crypto_Update(ctx, indata, insize)); -} - -static int -__archive_sha512final(archive_sha512_ctx *ctx, void *md) -{ - return (win_crypto_Final(md, 64, ctx)); -} - #else static int @@ -1536,11 +1608,12 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md) * 1. libc * 2. libc2 * 3. libc3 - * 4. libSystem - * 5. Nettle - * 6. OpenSSL - * 7. libmd - * 8. Windows API + * 4. libmd + * 5. libSystem + * 6. Windows API + * 7. mbedTLS + * 8. Nettle + * 9. OpenSSL */ const struct archive_digest __archive_digest = { diff --git a/libarchive/archive_digest_private.h b/libarchive/archive_digest_private.h index 339b4edca4..deb134e4f8 100644 --- a/libarchive/archive_digest_private.h +++ b/libarchive/archive_digest_private.h @@ -113,6 +113,7 @@ defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\ defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) #include +#define ARCHIVE_CRYPTO_CommonCrypto 1 #endif /* mbed TLS crypto headers */ @@ -167,6 +168,7 @@ #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA /* don't use bcrypt when XP needs to be supported */ #include +#define ARCHIVE_CRYPTO_CNG 1 typedef struct { int valid; BCRYPT_ALG_HANDLE hAlg; @@ -175,6 +177,7 @@ typedef struct { #else #include #include +#define ARCHIVE_CRYPTO_WINCRYPT 1 typedef struct { int valid; HCRYPTPROV cryptProv; @@ -190,14 +193,16 @@ typedef MD5_CTX archive_md5_ctx; typedef MD5_CTX archive_md5_ctx; #elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) typedef CC_MD5_CTX archive_md5_ctx; +#elif defined(ARCHIVE_CRYPTO_MD5_WIN) +typedef Digest_CTX archive_md5_ctx; #elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS) +#define ARCHIVE_CRYPTO_MBED 1 typedef mbedtls_md5_context archive_md5_ctx; #elif defined(ARCHIVE_CRYPTO_MD5_NETTLE) +#define ARCHIVE_CRYPTO_NETTLE 1 typedef struct md5_ctx archive_md5_ctx; #elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL) typedef EVP_MD_CTX *archive_md5_ctx; -#elif defined(ARCHIVE_CRYPTO_MD5_WIN) -typedef Digest_CTX archive_md5_ctx; #else typedef unsigned char archive_md5_ctx; #endif @@ -207,8 +212,10 @@ typedef RMD160_CTX archive_rmd160_ctx; #elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD) typedef RIPEMD160_CTX archive_rmd160_ctx; #elif defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS) +#define ARCHIVE_CRYPTO_MBED 1 typedef mbedtls_ripemd160_context archive_rmd160_ctx; #elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE) +#define ARCHIVE_CRYPTO_NETTLE 1 typedef struct ripemd160_ctx archive_rmd160_ctx; #elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL) typedef EVP_MD_CTX *archive_rmd160_ctx; @@ -222,14 +229,16 @@ typedef SHA1_CTX archive_sha1_ctx; typedef SHA1_CTX archive_sha1_ctx; #elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) typedef CC_SHA1_CTX archive_sha1_ctx; +#elif defined(ARCHIVE_CRYPTO_SHA1_WIN) +typedef Digest_CTX archive_sha1_ctx; #elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS) +#define ARCHIVE_CRYPTO_MBED 1 typedef mbedtls_sha1_context archive_sha1_ctx; #elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE) +#define ARCHIVE_CRYPTO_NETTLE 1 typedef struct sha1_ctx archive_sha1_ctx; #elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) typedef EVP_MD_CTX *archive_sha1_ctx; -#elif defined(ARCHIVE_CRYPTO_SHA1_WIN) -typedef Digest_CTX archive_sha1_ctx; #else typedef unsigned char archive_sha1_ctx; #endif @@ -244,14 +253,16 @@ typedef SHA2_CTX archive_sha256_ctx; typedef SHA256_CTX archive_sha256_ctx; #elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) typedef CC_SHA256_CTX archive_sha256_ctx; +#elif defined(ARCHIVE_CRYPTO_SHA256_WIN) +typedef Digest_CTX archive_sha256_ctx; #elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS) +#define ARCHIVE_CRYPTO_MBED 1 typedef mbedtls_sha256_context archive_sha256_ctx; #elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE) +#define ARCHIVE_CRYPTO_NETTLE 1 typedef struct sha256_ctx archive_sha256_ctx; #elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) typedef EVP_MD_CTX *archive_sha256_ctx; -#elif defined(ARCHIVE_CRYPTO_SHA256_WIN) -typedef Digest_CTX archive_sha256_ctx; #else typedef unsigned char archive_sha256_ctx; #endif @@ -264,14 +275,16 @@ typedef SHA384_CTX archive_sha384_ctx; typedef SHA2_CTX archive_sha384_ctx; #elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) typedef CC_SHA512_CTX archive_sha384_ctx; +#elif defined(ARCHIVE_CRYPTO_SHA384_WIN) +typedef Digest_CTX archive_sha384_ctx; #elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS) +#define ARCHIVE_CRYPTO_MBED 1 typedef mbedtls_sha512_context archive_sha384_ctx; #elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE) +#define ARCHIVE_CRYPTO_NETTLE 1 typedef struct sha384_ctx archive_sha384_ctx; #elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) typedef EVP_MD_CTX *archive_sha384_ctx; -#elif defined(ARCHIVE_CRYPTO_SHA384_WIN) -typedef Digest_CTX archive_sha384_ctx; #else typedef unsigned char archive_sha384_ctx; #endif @@ -286,14 +299,16 @@ typedef SHA2_CTX archive_sha512_ctx; typedef SHA512_CTX archive_sha512_ctx; #elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) typedef CC_SHA512_CTX archive_sha512_ctx; +#elif defined(ARCHIVE_CRYPTO_SHA512_WIN) +typedef Digest_CTX archive_sha512_ctx; #elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS) +#define ARCHIVE_CRYPTO_MBED 1 typedef mbedtls_sha512_context archive_sha512_ctx; #elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE) +#define ARCHIVE_CRYPTO_NETTLE 1 typedef struct sha512_ctx archive_sha512_ctx; #elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) typedef EVP_MD_CTX *archive_sha512_ctx; -#elif defined(ARCHIVE_CRYPTO_SHA512_WIN) -typedef Digest_CTX archive_sha512_ctx; #else typedef unsigned char archive_sha512_ctx; #endif diff --git a/libarchive/archive_disk_acl_darwin.c b/libarchive/archive_disk_acl_darwin.c index 48ad016512..12c3587c53 100644 --- a/libarchive/archive_disk_acl_darwin.c +++ b/libarchive/archive_disk_acl_darwin.c @@ -195,7 +195,7 @@ add_trivial_nfs4_acl(struct archive_entry *entry) } else if ((mode & 0010) || (mode & 0001)) tacl_entry[1].permset |= eperm; - for (i = 0; i < 6; i++) { + for (i = 0; i < sizeof(tacl_entry) / sizeof(tacl_entry[0]); i++) { if (tacl_entry[i].permset != 0) { archive_entry_acl_add_entry(entry, tacl_entry[i].type, tacl_entry[i].permset, diff --git a/libarchive/archive_disk_acl_freebsd.c b/libarchive/archive_disk_acl_freebsd.c index ed4e7a7896..2fbdb17aa5 100644 --- a/libarchive/archive_disk_acl_freebsd.c +++ b/libarchive/archive_disk_acl_freebsd.c @@ -262,7 +262,7 @@ translate_acl(struct archive_read_disk *a, } for (i = 0; i < acl_nfs4_flag_map_size; ++i) { r = acl_get_flag_np(acl_flagset, - acl_nfs4_flag_map[i].p_perm); + (acl_flag_t)acl_nfs4_flag_map[i].p_perm); if (r == -1) { archive_set_error(&a->archive, errno, "Failed to check flag in a NFSv4 " @@ -517,7 +517,7 @@ set_acl(struct archive *a, int fd, const char *name, for (i = 0; i < acl_nfs4_flag_map_size; ++i) { if (ae_permset & acl_nfs4_flag_map[i].a_perm) { if (acl_add_flag_np(acl_flagset, - acl_nfs4_flag_map[i].p_perm) != 0) { + (acl_flag_t)acl_nfs4_flag_map[i].p_perm) != 0) { archive_set_error(a, errno, "Failed to add flag to " "NFSv4 ACL flagset"); diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c index 4ebfc5fa63..dc74430f80 100644 --- a/libarchive/archive_entry.c +++ b/libarchive/archive_entry.c @@ -275,7 +275,7 @@ archive_entry_new2(struct archive *a) * Functions for reading fields from an archive_entry. */ -time_t +__LA_TIME_T archive_entry_atime(struct archive_entry *entry) { return (entry->ae_stat.aest_atime); @@ -293,7 +293,7 @@ archive_entry_atime_is_set(struct archive_entry *entry) return (entry->ae_set & AE_SET_ATIME); } -time_t +__LA_TIME_T archive_entry_birthtime(struct archive_entry *entry) { return (entry->ae_stat.aest_birthtime); @@ -311,7 +311,7 @@ archive_entry_birthtime_is_set(struct archive_entry *entry) return (entry->ae_set & AE_SET_BIRTHTIME); } -time_t +__LA_TIME_T archive_entry_ctime(struct archive_entry *entry) { return (entry->ae_stat.aest_ctime); @@ -329,7 +329,7 @@ archive_entry_ctime_nsec(struct archive_entry *entry) return (entry->ae_stat.aest_ctime_nsec); } -dev_t +__LA_DEV_T archive_entry_dev(struct archive_entry *entry) { if (entry->ae_stat.aest_dev_is_broken_down) @@ -345,7 +345,7 @@ archive_entry_dev_is_set(struct archive_entry *entry) return (entry->ae_set & AE_SET_DEV); } -dev_t +__LA_DEV_T archive_entry_devmajor(struct archive_entry *entry) { if (entry->ae_stat.aest_dev_is_broken_down) @@ -354,7 +354,7 @@ archive_entry_devmajor(struct archive_entry *entry) return major(entry->ae_stat.aest_dev); } -dev_t +__LA_DEV_T archive_entry_devminor(struct archive_entry *entry) { if (entry->ae_stat.aest_dev_is_broken_down) @@ -568,7 +568,7 @@ archive_entry_mode(struct archive_entry *entry) return (entry->acl.mode); } -time_t +__LA_TIME_T archive_entry_mtime(struct archive_entry *entry) { return (entry->ae_stat.aest_mtime); @@ -667,7 +667,7 @@ archive_entry_rdev_is_set(struct archive_entry *entry) return (entry->ae_set & AE_SET_RDEV); } -dev_t +__LA_DEV_T archive_entry_rdev(struct archive_entry *entry) { if (archive_entry_rdev_is_set(entry)) { @@ -681,7 +681,7 @@ archive_entry_rdev(struct archive_entry *entry) } } -dev_t +__LA_DEV_T archive_entry_rdevmajor(struct archive_entry *entry) { if (archive_entry_rdev_is_set(entry)) { @@ -694,7 +694,7 @@ archive_entry_rdevmajor(struct archive_entry *entry) } } -dev_t +__LA_DEV_T archive_entry_rdevminor(struct archive_entry *entry) { if (archive_entry_rdev_is_set(entry)) { @@ -984,7 +984,9 @@ void archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino) { if (ino < 0) { - ino = 0; + entry->stat_valid = 0; + entry->ae_set &= ~AE_SET_INO; + return; } entry->stat_valid = 0; entry->ae_set |= AE_SET_INO; @@ -995,7 +997,9 @@ void archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino) { if (ino < 0) { - ino = 0; + entry->stat_valid = 0; + entry->ae_set &= ~AE_SET_INO; + return; } entry->stat_valid = 0; entry->ae_set |= AE_SET_INO; @@ -1088,7 +1092,7 @@ _archive_entry_copy_hardlink_l(struct archive_entry *entry, } void -archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns) +archive_entry_set_atime(struct archive_entry *entry, __LA_TIME_T t, long ns) { FIX_NS(t, ns); entry->stat_valid = 0; @@ -1105,7 +1109,7 @@ archive_entry_unset_atime(struct archive_entry *entry) } void -archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns) +archive_entry_set_birthtime(struct archive_entry *entry, __LA_TIME_T t, long ns) { FIX_NS(t, ns); entry->stat_valid = 0; @@ -1122,7 +1126,7 @@ archive_entry_unset_birthtime(struct archive_entry *entry) } void -archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns) +archive_entry_set_ctime(struct archive_entry *entry, __LA_TIME_T t, long ns) { FIX_NS(t, ns); entry->stat_valid = 0; @@ -1139,7 +1143,7 @@ archive_entry_unset_ctime(struct archive_entry *entry) } void -archive_entry_set_dev(struct archive_entry *entry, dev_t d) +archive_entry_set_dev(struct archive_entry *entry, __LA_DEV_T d) { entry->stat_valid = 0; entry->ae_set |= AE_SET_DEV; @@ -1148,7 +1152,7 @@ archive_entry_set_dev(struct archive_entry *entry, dev_t d) } void -archive_entry_set_devmajor(struct archive_entry *entry, dev_t m) +archive_entry_set_devmajor(struct archive_entry *entry, __LA_DEV_T m) { entry->stat_valid = 0; entry->ae_set |= AE_SET_DEV; @@ -1157,7 +1161,7 @@ archive_entry_set_devmajor(struct archive_entry *entry, dev_t m) } void -archive_entry_set_devminor(struct archive_entry *entry, dev_t m) +archive_entry_set_devminor(struct archive_entry *entry, __LA_DEV_T m) { entry->stat_valid = 0; entry->ae_set |= AE_SET_DEV; @@ -1243,7 +1247,7 @@ archive_entry_set_mode(struct archive_entry *entry, mode_t m) } void -archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns) +archive_entry_set_mtime(struct archive_entry *entry, __LA_TIME_T t, long ns) { FIX_NS(t, ns); entry->stat_valid = 0; @@ -1319,7 +1323,7 @@ archive_entry_set_perm(struct archive_entry *entry, mode_t p) } void -archive_entry_set_rdev(struct archive_entry *entry, dev_t m) +archive_entry_set_rdev(struct archive_entry *entry, __LA_DEV_T m) { entry->stat_valid = 0; entry->ae_stat.aest_rdev = m; @@ -1330,7 +1334,7 @@ archive_entry_set_rdev(struct archive_entry *entry, dev_t m) } void -archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m) +archive_entry_set_rdevmajor(struct archive_entry *entry, __LA_DEV_T m) { entry->stat_valid = 0; entry->ae_stat.aest_rdev_is_broken_down = 1; @@ -1340,7 +1344,7 @@ archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m) } void -archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m) +archive_entry_set_rdevminor(struct archive_entry *entry, __LA_DEV_T m) { entry->stat_valid = 0; entry->ae_stat.aest_rdev_is_broken_down = 1; @@ -1603,21 +1607,27 @@ archive_entry_set_digest(struct archive_entry *entry, int type, switch (type) { case ARCHIVE_ENTRY_DIGEST_MD5: copy_digest(entry, md5, digest); + entry->mset_digest |= AE_MSET_DIGEST_MD5; break; case ARCHIVE_ENTRY_DIGEST_RMD160: copy_digest(entry, rmd160, digest); + entry->mset_digest |= AE_MSET_DIGEST_RMD160; break; case ARCHIVE_ENTRY_DIGEST_SHA1: copy_digest(entry, sha1, digest); + entry->mset_digest |= AE_MSET_DIGEST_SHA1; break; case ARCHIVE_ENTRY_DIGEST_SHA256: copy_digest(entry, sha256, digest); + entry->mset_digest |= AE_MSET_DIGEST_SHA256; break; case ARCHIVE_ENTRY_DIGEST_SHA384: copy_digest(entry, sha384, digest); + entry->mset_digest |= AE_MSET_DIGEST_SHA384; break; case ARCHIVE_ENTRY_DIGEST_SHA512: copy_digest(entry, sha512, digest); + entry->mset_digest |= AE_MSET_DIGEST_SHA512; break; default: return ARCHIVE_WARN; diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h index eff8a7690b..2b917b3fde 100644 --- a/libarchive/archive_entry.h +++ b/libarchive/archive_entry.h @@ -28,7 +28,7 @@ #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3007009 +#define ARCHIVE_VERSION_NUMBER 3008001 /* * Note: archive_entry.h is for use outside of libarchive; the @@ -40,8 +40,11 @@ #include #include /* for wchar_t */ -#include +#include /* for C99 int64_t, etc. */ +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* time_t is slated to be removed from public includes in 4.0 */ #include +#endif #if defined(_WIN32) && !defined(__CYGWIN__) #include @@ -55,12 +58,15 @@ #define __LA_INT64_T_DEFINED # if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) typedef __int64 la_int64_t; +typedef unsigned __int64 la_uint64_t; # else #include # if defined(_SCO_DS) || defined(__osf__) typedef long long la_int64_t; +typedef unsigned long long la_uint64_t; # else typedef int64_t la_int64_t; +typedef uint64_t la_uint64_t; # endif # endif #endif @@ -96,6 +102,30 @@ typedef ssize_t la_ssize_t; # define __LA_MODE_T mode_t #endif +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Use the platform types for time_t */ +#define __LA_TIME_T time_t +#else +/* Use 64-bits integer types for time_t */ +#define __LA_TIME_T la_int64_t +#endif + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Use the platform types for dev_t */ +#define __LA_DEV_T dev_t +#else +/* Use 64-bits integer types for dev_t */ +#define __LA_DEV_T la_int64_t +#endif + +#if ARCHIVE_VERSION_NUMBER < 4000000 +/* Libarchive 3.x used signed int64 for inode numbers */ +#define __LA_INO_T la_int64_t +#else +/* Switch to unsigned for libarchive 4.0 */ +#define __LA_INO_T la_uint64_t +#endif + /* Large file support for Android */ #if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__) #include "android_lf.h" @@ -236,19 +266,19 @@ __LA_DECL struct archive_entry *archive_entry_new2(struct archive *); * also return NULL when implicit character set conversions fail. * This is usually what you want. */ -__LA_DECL time_t archive_entry_atime(struct archive_entry *); +__LA_DECL __LA_TIME_T archive_entry_atime(struct archive_entry *); __LA_DECL long archive_entry_atime_nsec(struct archive_entry *); __LA_DECL int archive_entry_atime_is_set(struct archive_entry *); -__LA_DECL time_t archive_entry_birthtime(struct archive_entry *); +__LA_DECL __LA_TIME_T archive_entry_birthtime(struct archive_entry *); __LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *); __LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *); -__LA_DECL time_t archive_entry_ctime(struct archive_entry *); +__LA_DECL __LA_TIME_T archive_entry_ctime(struct archive_entry *); __LA_DECL long archive_entry_ctime_nsec(struct archive_entry *); __LA_DECL int archive_entry_ctime_is_set(struct archive_entry *); -__LA_DECL dev_t archive_entry_dev(struct archive_entry *); +__LA_DECL __LA_DEV_T archive_entry_dev(struct archive_entry *); __LA_DECL int archive_entry_dev_is_set(struct archive_entry *); -__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *); -__LA_DECL dev_t archive_entry_devminor(struct archive_entry *); +__LA_DECL __LA_DEV_T archive_entry_devmajor(struct archive_entry *); +__LA_DECL __LA_DEV_T archive_entry_devminor(struct archive_entry *); __LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *); __LA_DECL int archive_entry_filetype_is_set(struct archive_entry *); __LA_DECL void archive_entry_fflags(struct archive_entry *, @@ -265,8 +295,8 @@ __LA_DECL const char *archive_entry_hardlink(struct archive_entry *); __LA_DECL const char *archive_entry_hardlink_utf8(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *); __LA_DECL int archive_entry_hardlink_is_set(struct archive_entry *); -__LA_DECL la_int64_t archive_entry_ino(struct archive_entry *); -__LA_DECL la_int64_t archive_entry_ino64(struct archive_entry *); +__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *); +__LA_DECL __LA_INO_T archive_entry_ino64(struct archive_entry *); __LA_DECL int archive_entry_ino_is_set(struct archive_entry *); __LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *); __LA_DECL time_t archive_entry_mtime(struct archive_entry *); @@ -279,9 +309,9 @@ __LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *); __LA_DECL __LA_MODE_T archive_entry_perm(struct archive_entry *); __LA_DECL int archive_entry_perm_is_set(struct archive_entry *); __LA_DECL int archive_entry_rdev_is_set(struct archive_entry *); -__LA_DECL dev_t archive_entry_rdev(struct archive_entry *); -__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *); -__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *); +__LA_DECL __LA_DEV_T archive_entry_rdev(struct archive_entry *); +__LA_DECL __LA_DEV_T archive_entry_rdevmajor(struct archive_entry *); +__LA_DECL __LA_DEV_T archive_entry_rdevminor(struct archive_entry *); __LA_DECL const char *archive_entry_sourcepath(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *); __LA_DECL la_int64_t archive_entry_size(struct archive_entry *); @@ -310,18 +340,18 @@ __LA_DECL int archive_entry_is_encrypted(struct archive_entry *); * always copied. */ -__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_set_atime(struct archive_entry *, __LA_TIME_T, long); __LA_DECL void archive_entry_unset_atime(struct archive_entry *); #if defined(_WIN32) && !defined(__CYGWIN__) __LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *); #endif -__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, __LA_TIME_T, long); __LA_DECL void archive_entry_unset_birthtime(struct archive_entry *); -__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_set_ctime(struct archive_entry *, __LA_TIME_T, long); __LA_DECL void archive_entry_unset_ctime(struct archive_entry *); -__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_dev(struct archive_entry *, __LA_DEV_T); +__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, __LA_DEV_T); +__LA_DECL void archive_entry_set_devminor(struct archive_entry *, __LA_DEV_T); __LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int); __LA_DECL void archive_entry_set_fflags(struct archive_entry *, unsigned long /* set */, unsigned long /* clear */); @@ -344,15 +374,15 @@ __LA_DECL void archive_entry_set_hardlink_utf8(struct archive_entry *, const cha __LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); __LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *); -__LA_DECL void archive_entry_set_ino(struct archive_entry *, la_int64_t); -__LA_DECL void archive_entry_set_ino64(struct archive_entry *, la_int64_t); +__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INO_T); +__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INO_T); __LA_DECL void archive_entry_set_link(struct archive_entry *, const char *); __LA_DECL void archive_entry_set_link_utf8(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *); __LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *); __LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T); -__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_set_mtime(struct archive_entry *, __LA_TIME_T, long); __LA_DECL void archive_entry_unset_mtime(struct archive_entry *); __LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int); __LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *); @@ -361,9 +391,9 @@ __LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *) __LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *); __LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *); __LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T); -__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t); -__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_rdev(struct archive_entry *, __LA_DEV_T); +__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, __LA_DEV_T); +__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, __LA_DEV_T); __LA_DECL void archive_entry_set_size(struct archive_entry *, la_int64_t); __LA_DECL void archive_entry_unset_size(struct archive_entry *); __LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *); @@ -419,6 +449,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi #define ARCHIVE_ENTRY_DIGEST_SHA512 0x00000006 __LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */); +__LA_DECL int archive_entry_set_digest(struct archive_entry *, int, const unsigned char *); /* * ACL routines. This used to simply store and return text-format ACL diff --git a/libarchive/archive_entry_copy_bhfi.c b/libarchive/archive_entry_copy_bhfi.c index d5317a5eab..0708838cae 100644 --- a/libarchive/archive_entry_copy_bhfi.c +++ b/libarchive/archive_entry_copy_bhfi.c @@ -24,43 +24,24 @@ */ #include "archive_platform.h" - +#include "archive_time_private.h" #include "archive_private.h" #include "archive_entry.h" #if defined(_WIN32) && !defined(__CYGWIN__) -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) - -__inline static void -fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ - } else { - *t = 0; - *ns = 0; - } -} - void archive_entry_copy_bhfi(struct archive_entry *entry, BY_HANDLE_FILE_INFORMATION *bhfi) { - time_t secs; - long nsecs; + int64_t secs; + uint32_t nsecs; - fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs); + ntfs_to_unix(FILETIME_to_ntfs(&bhfi->ftLastAccessTime), &secs, &nsecs); archive_entry_set_atime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs); + ntfs_to_unix(FILETIME_to_ntfs(&bhfi->ftLastWriteTime), &secs, &nsecs); archive_entry_set_mtime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs); + ntfs_to_unix(FILETIME_to_ntfs(&bhfi->ftCreationTime), &secs, &nsecs); archive_entry_set_birthtime(entry, secs, nsecs); archive_entry_set_ctime(entry, secs, nsecs); archive_entry_set_dev(entry, bhfi->dwVolumeSerialNumber); diff --git a/libarchive/archive_entry_link_resolver.c b/libarchive/archive_entry_link_resolver.c index c2fd6895f2..77fcad61fd 100644 --- a/libarchive/archive_entry_link_resolver.c +++ b/libarchive/archive_entry_link_resolver.c @@ -280,6 +280,10 @@ find_entry(struct archive_entry_linkresolver *res, dev_t dev; int64_t ino; + if (!archive_entry_ino_is_set(entry) || !archive_entry_dev_is_set(entry)) { + return (NULL); + } + /* Free a held entry. */ if (res->spare != NULL) { archive_entry_free(res->spare->canonical); @@ -369,6 +373,10 @@ insert_entry(struct archive_entry_linkresolver *res, struct links_entry *le; size_t hash, bucket; + if (!archive_entry_ino_is_set(entry) || !archive_entry_dev_is_set(entry)) { + return (NULL); + } + /* Add this entry to the links cache. */ le = calloc(1, sizeof(struct links_entry)); if (le == NULL) diff --git a/libarchive/archive_entry_locale.h b/libarchive/archive_entry_locale.h index 1b90c57eab..e31a0f2ff1 100644 --- a/libarchive/archive_entry_locale.h +++ b/libarchive/archive_entry_locale.h @@ -87,4 +87,4 @@ int _archive_entry_copy_symlink_l(struct archive_entry *, int _archive_entry_copy_uname_l(struct archive_entry *, const char *, size_t, struct archive_string_conv *); -#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */ +#endif /* !ARCHIVE_ENTRY_LOCALE_H_INCLUDED */ diff --git a/libarchive/archive_entry_private.h b/libarchive/archive_entry_private.h index 15f2a8ee28..9736f7716e 100644 --- a/libarchive/archive_entry_private.h +++ b/libarchive/archive_entry_private.h @@ -174,6 +174,13 @@ struct archive_entry { size_t mac_metadata_size; /* Digest support. */ +#define AE_MSET_DIGEST_MD5 1 +#define AE_MSET_DIGEST_RMD160 2 +#define AE_MSET_DIGEST_SHA1 4 +#define AE_MSET_DIGEST_SHA256 8 +#define AE_MSET_DIGEST_SHA384 16 +#define AE_MSET_DIGEST_SHA512 32 + uint_least32_t mset_digest; struct ae_digest digest; /* ACL support. */ @@ -195,8 +202,4 @@ struct archive_entry { int ae_symlink_type; }; -int -archive_entry_set_digest(struct archive_entry *entry, int type, - const unsigned char *digest); - -#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ +#endif /* !ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ diff --git a/libarchive/archive_hmac_private.h b/libarchive/archive_hmac_private.h index 1b24ddd1bc..36b8e3320e 100644 --- a/libarchive/archive_hmac_private.h +++ b/libarchive/archive_hmac_private.h @@ -116,4 +116,4 @@ struct archive_hmac { }; extern const struct archive_hmac __archive_hmac; -#endif /* ARCHIVE_HMAC_PRIVATE_H_INCLUDED */ +#endif /* !ARCHIVE_HMAC_PRIVATE_H_INCLUDED */ diff --git a/libarchive/archive_match.c b/libarchive/archive_match.c index 446417a9a2..51a0e3fd57 100644 --- a/libarchive/archive_match.c +++ b/libarchive/archive_match.c @@ -35,14 +35,17 @@ #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_LIMITS_H +#include +#endif #include "archive.h" #include "archive_private.h" #include "archive_entry.h" -#include "archive_getdate.h" #include "archive_pathmatch.h" #include "archive_rb.h" #include "archive_string.h" +#include "archive_time_private.h" struct match { struct match *next; @@ -53,8 +56,7 @@ struct match { struct match_list { struct match *first; struct match **last; - int count; - int unmatched_count; + size_t unmatched_count; struct match *unmatched_next; int unmatched_eof; }; @@ -73,7 +75,6 @@ struct match_file { struct entry_list { struct match_file *first; struct match_file **last; - int count; }; struct id_array { @@ -144,12 +145,15 @@ static int add_pattern_mbs(struct archive_match *, struct match_list *, const char *); static int add_pattern_wcs(struct archive_match *, struct match_list *, const wchar_t *); +#if !defined(_WIN32) || defined(__CYGWIN__) static int cmp_key_mbs(const struct archive_rb_node *, const void *); -static int cmp_key_wcs(const struct archive_rb_node *, const void *); static int cmp_node_mbs(const struct archive_rb_node *, const struct archive_rb_node *); +#else +static int cmp_key_wcs(const struct archive_rb_node *, const void *); static int cmp_node_wcs(const struct archive_rb_node *, const struct archive_rb_node *); +#endif static void entry_list_add(struct entry_list *, struct match_file *); static void entry_list_free(struct entry_list *); static void entry_list_init(struct entry_list *); @@ -187,14 +191,14 @@ static int time_excluded(struct archive_match *, struct archive_entry *); static int validate_time_flag(struct archive *, int, const char *); -#define get_date __archive_get_date +#define get_date archive_parse_date -static const struct archive_rb_tree_ops rb_ops_mbs = { +static const struct archive_rb_tree_ops rb_ops = { +#if !defined(_WIN32) || defined(__CYGWIN__) cmp_node_mbs, cmp_key_mbs -}; - -static const struct archive_rb_tree_ops rb_ops_wcs = { +#else cmp_node_wcs, cmp_key_wcs +#endif }; /* @@ -228,7 +232,7 @@ archive_match_new(void) a->recursive_include = 1; match_list_init(&(a->inclusions)); match_list_init(&(a->exclusions)); - __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs); + __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops); entry_list_init(&(a->exclusion_entry_list)); match_list_init(&(a->inclusion_unames)); match_list_init(&(a->inclusion_gnames)); @@ -507,7 +511,9 @@ archive_match_path_unmatched_inclusions(struct archive *_a) ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions"); a = (struct archive_match *)_a; - return (a->inclusions.unmatched_count); + if (a->inclusions.unmatched_count > (size_t)INT_MAX) + return INT_MAX; + return (int)(a->inclusions.unmatched_count); } int @@ -650,7 +656,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist, break; } } else { - if (*b == 0x0d || *b == 0x0a) { + if (*b == 0x0d || *b == 0x0a) { found_separator = 1; break; } @@ -735,7 +741,7 @@ path_excluded(struct archive_match *a, int mbs, const void *pathname) } } - /* Exclusions take priority */ + /* Exclusions take priority. */ for (match = a->exclusions.first; match != NULL; match = match->next){ r = match_path_exclusion(a, match, mbs, pathname); @@ -834,7 +840,6 @@ match_list_init(struct match_list *list) { list->first = NULL; list->last = &(list->first); - list->count = 0; } static void @@ -855,7 +860,6 @@ match_list_add(struct match_list *list, struct match *m) { *list->last = m; list->last = &(m->next); - list->count++; list->unmatched_count++; } @@ -1145,36 +1149,15 @@ set_timefilter_date_w(struct archive_match *a, int timetype, } #if defined(_WIN32) && !defined(__CYGWIN__) -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) static int set_timefilter_find_data(struct archive_match *a, int timetype, - DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime, - DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime) + const FILETIME* ftLastWriteTime, const FILETIME* ftCreationTime) { - ULARGE_INTEGER utc; time_t ctime_sec, mtime_sec; - long ctime_ns, mtime_ns; + uint32_t ctime_ns, mtime_ns; - utc.HighPart = ftCreationTime_dwHighDateTime; - utc.LowPart = ftCreationTime_dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - ctime_sec = (time_t)(utc.QuadPart / 10000000); - ctime_ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - ctime_sec = 0; - ctime_ns = 0; - } - utc.HighPart = ftLastWriteTime_dwHighDateTime; - utc.LowPart = ftLastWriteTime_dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - mtime_sec = (time_t)(utc.QuadPart / 10000000); - mtime_ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - mtime_sec = 0; - mtime_ns = 0; - } + ntfs_to_unix(FILETIME_to_ntfs(ftLastWriteTime), &mtime_sec, &mtime_ns); + ntfs_to_unix(FILETIME_to_ntfs(ftCreationTime), &ctime_sec, &ctime_ns); return set_timefilter(a, timetype, mtime_sec, mtime_ns, ctime_sec, ctime_ns); } @@ -1199,9 +1182,7 @@ set_timefilter_pathname_mbs(struct archive_match *a, int timetype, return (ARCHIVE_FAILED); } FindClose(h); - return set_timefilter_find_data(a, timetype, - d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, - d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); + return set_timefilter_find_data(a, timetype, &d.ftLastWriteTime, &d.ftCreationTime); } static int @@ -1223,9 +1204,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype, return (ARCHIVE_FAILED); } FindClose(h); - return set_timefilter_find_data(a, timetype, - d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime, - d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime); + return set_timefilter_find_data(a, timetype, &d.ftLastWriteTime, &d.ftCreationTime); } #else /* _WIN32 && !__CYGWIN__ */ @@ -1300,6 +1279,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype, /* * Call back functions for archive_rb. */ +#if !defined(_WIN32) || defined(__CYGWIN__) static int cmp_node_mbs(const struct archive_rb_node *n1, const struct archive_rb_node *n2) @@ -1316,7 +1296,7 @@ cmp_node_mbs(const struct archive_rb_node *n1, return (-1); return (strcmp(p1, p2)); } - + static int cmp_key_mbs(const struct archive_rb_node *n, const void *key) { @@ -1328,7 +1308,7 @@ cmp_key_mbs(const struct archive_rb_node *n, const void *key) return (-1); return (strcmp(p, (const char *)key)); } - +#else static int cmp_node_wcs(const struct archive_rb_node *n1, const struct archive_rb_node *n2) @@ -1345,7 +1325,7 @@ cmp_node_wcs(const struct archive_rb_node *n1, return (-1); return (wcscmp(p1, p2)); } - + static int cmp_key_wcs(const struct archive_rb_node *n, const void *key) { @@ -1357,13 +1337,13 @@ cmp_key_wcs(const struct archive_rb_node *n, const void *key) return (-1); return (wcscmp(p, (const wchar_t *)key)); } +#endif static void entry_list_init(struct entry_list *list) { list->first = NULL; list->last = &(list->first); - list->count = 0; } static void @@ -1384,7 +1364,6 @@ entry_list_add(struct entry_list *list, struct match_file *file) { *list->last = file; list->last = &(file->next); - list->count++; } static int @@ -1407,9 +1386,7 @@ add_entry(struct archive_match *a, int flag, return (ARCHIVE_FAILED); } archive_mstring_copy_wcs(&(f->pathname), pathname); - a->exclusion_tree.rbt_ops = &rb_ops_wcs; #else - (void)rb_ops_wcs; pathname = archive_entry_pathname(entry); if (pathname == NULL) { free(f); @@ -1417,7 +1394,6 @@ add_entry(struct archive_match *a, int flag, return (ARCHIVE_FAILED); } archive_mstring_copy_mbs(&(f->pathname), pathname); - a->exclusion_tree.rbt_ops = &rb_ops_mbs; #endif f->flag = flag; f->mtime_sec = archive_entry_mtime(entry); @@ -1542,16 +1518,13 @@ time_excluded(struct archive_match *a, struct archive_entry *entry) } /* If there is no exclusion list, include the file. */ - if (a->exclusion_entry_list.count == 0) + if (a->exclusion_entry_list.first == NULL) return (0); #if defined(_WIN32) && !defined(__CYGWIN__) pathname = archive_entry_pathname_w(entry); - a->exclusion_tree.rbt_ops = &rb_ops_wcs; #else - (void)rb_ops_wcs; pathname = archive_entry_pathname(entry); - a->exclusion_tree.rbt_ops = &rb_ops_mbs; #endif if (pathname == NULL) return (0); @@ -1707,7 +1680,7 @@ archive_match_owner_excluded(struct archive *_a, static int add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) { - unsigned i; + size_t i; if (ids->count + 1 >= ids->size) { void *p; @@ -1744,10 +1717,10 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) static int match_owner_id(struct id_array *ids, int64_t id) { - unsigned b, m, t; + size_t b, m, t; t = 0; - b = (unsigned)ids->count; + b = ids->count; while (t < b) { m = (t + b)>>1; if (ids->ids[m] == id) @@ -1842,7 +1815,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry) return (1); } - if (a->inclusion_unames.count) { + if (a->inclusion_unames.first != NULL) { #if defined(_WIN32) && !defined(__CYGWIN__) r = match_owner_name_wcs(a, &(a->inclusion_unames), archive_entry_uname_w(entry)); @@ -1856,7 +1829,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry) return (r); } - if (a->inclusion_gnames.count) { + if (a->inclusion_gnames.first != NULL) { #if defined(_WIN32) && !defined(__CYGWIN__) r = match_owner_name_wcs(a, &(a->inclusion_gnames), archive_entry_gname_w(entry)); @@ -1871,4 +1844,3 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry) } return (0); } - diff --git a/libarchive/archive_options.c b/libarchive/archive_options.c index 92647c9b41..6e2c0d2a59 100644 --- a/libarchive/archive_options.c +++ b/libarchive/archive_options.c @@ -38,7 +38,7 @@ parse_option(const char **str, int _archive_set_option(struct archive *a, const char *m, const char *o, const char *v, - int magic, const char *fn, option_handler use_option) + unsigned int magic, const char *fn, option_handler use_option) { const char *mp, *op, *vp; int r; @@ -97,7 +97,7 @@ _archive_set_either_option(struct archive *a, const char *m, const char *o, cons int _archive_set_options(struct archive *a, const char *options, - int magic, const char *fn, option_handler use_option) + unsigned int magic, const char *fn, option_handler use_option) { int allok = 1, anyok = 0, ignore_mod_err = 0, r; char *data; diff --git a/libarchive/archive_options_private.h b/libarchive/archive_options_private.h index 3e49222dab..f07d242ee6 100644 --- a/libarchive/archive_options_private.h +++ b/libarchive/archive_options_private.h @@ -35,11 +35,11 @@ typedef int (*option_handler)(struct archive *a, int _archive_set_option(struct archive *a, const char *mod, const char *opt, const char *val, - int magic, const char *fn, option_handler use_option); + unsigned int magic, const char *fn, option_handler use_option); int _archive_set_options(struct archive *a, const char *options, - int magic, const char *fn, option_handler use_option); + unsigned int magic, const char *fn, option_handler use_option); int _archive_set_either_option(struct archive *a, diff --git a/libarchive/archive_pack_dev.h b/libarchive/archive_pack_dev.h index eaf23e3883..953af21da3 100644 --- a/libarchive/archive_pack_dev.h +++ b/libarchive/archive_pack_dev.h @@ -46,4 +46,4 @@ pack_t pack_native; (((y) << 12) & 0xfff00000) | \ (((y) << 0) & 0x000000ff))) -#endif /* ARCHIVE_PACK_DEV_H */ +#endif /* !ARCHIVE_PACK_DEV_H */ diff --git a/libarchive/archive_getdate.c b/libarchive/archive_parse_date.c similarity index 96% rename from libarchive/archive_getdate.c rename to libarchive/archive_parse_date.c index 69eebb0a07..cda0b11a55 100644 --- a/libarchive/archive_getdate.c +++ b/libarchive/archive_parse_date.c @@ -35,8 +35,7 @@ #include #include -#define __LIBARCHIVE_BUILD 1 -#include "archive_getdate.h" +#include "archive.h" /* Basic time units. */ #define EPOCH 1970 @@ -820,6 +819,23 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth) Timezone, DSTmaybe)); } +/* + * Parses and consumes an unsigned number. + * Returns 1 if any number is parsed. Otherwise, *value is unchanged. + */ +static char +consume_unsigned_number(const char **in, time_t *value) +{ + char c; + if (isdigit((unsigned char)(c = **in))) { + for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); ) + *value = 10 * *value + c - '0'; + (*in)--; + return 1; + } + return 0; +} + /* * Tokenizer. */ @@ -861,7 +877,8 @@ nexttoken(const char **in, time_t *value) && i < sizeof(buff)-1) { if (*src != '.') { if (isupper((unsigned char)*src)) - buff[i++] = tolower((unsigned char)*src); + buff[i++] = (char)tolower( + (unsigned char)*src); else buff[i++] = *src; } @@ -895,10 +912,7 @@ nexttoken(const char **in, time_t *value) * Because '-' and '+' have other special meanings, I * don't deal with signed numbers here. */ - if (isdigit((unsigned char)(c = **in))) { - for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); ) - *value = 10 * *value + c - '0'; - (*in)--; + if (consume_unsigned_number(in, value)) { return (tUNUMBER); } @@ -914,7 +928,7 @@ difftm (struct tm *a, struct tm *b) { int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); int by = b->tm_year + (TM_YEAR_ORIGIN - 1); - int days = ( + long days = ( /* difference in day of year */ a->tm_yday - b->tm_yday /* + intervening leap days */ @@ -929,6 +943,32 @@ difftm (struct tm *a, struct tm *b) + (a->tm_sec - b->tm_sec)); } +/* + * Parses a Unix epoch timestamp (seconds). + * This supports a subset of what GNU tar accepts from black box testing, + * but covers common use cases. + */ +static time_t +parse_unix_epoch(const char *p) +{ + time_t epoch; + + /* may begin with + */ + if (*p == '+') { + p++; + } + + /* followed by some number */ + if (!consume_unsigned_number(&p, &epoch)) + return (time_t)-1; + + /* ...and nothing else */ + if (*p != '\0') + return (time_t)-1; + + return epoch; +} + /* * * The public function. @@ -936,7 +976,7 @@ difftm (struct tm *a, struct tm *b) * TODO: tokens[] array should be dynamically sized. */ time_t -__archive_get_date(time_t now, const char *p) +archive_parse_date(time_t now, const char *p) { struct token tokens[256]; struct gdstate _gds; @@ -948,6 +988,13 @@ __archive_get_date(time_t now, const char *p) time_t tod; long tzone; + /* + * @-prefixed Unix epoch timestamps (seconds) + * Skip the complex tokenizer - We do not want to accept strings like "@tenth" + */ + if (*p == '@') + return parse_unix_epoch(p + 1); + /* Clear out the parsed token array. */ memset(tokens, 0, sizeof(tokens)); /* Initialize the parser state. */ diff --git a/libarchive/archive_platform_acl.h b/libarchive/archive_platform_acl.h index 48556f87fe..a3599a4913 100644 --- a/libarchive/archive_platform_acl.h +++ b/libarchive/archive_platform_acl.h @@ -50,4 +50,4 @@ #define ARCHIVE_ACL_SUPPORT 1 #endif -#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */ +#endif /* !ARCHIVE_PLATFORM_ACL_H_INCLUDED */ diff --git a/libarchive/archive_platform_xattr.h b/libarchive/archive_platform_xattr.h index 2ae222f61e..f427d93b55 100644 --- a/libarchive/archive_platform_xattr.h +++ b/libarchive/archive_platform_xattr.h @@ -42,4 +42,4 @@ #define ARCHIVE_XATTR_SUPPORT 1 #endif -#endif /* ARCHIVE_PLATFORM_XATTR_H_INCLUDED */ +#endif /* !ARCHIVE_PLATFORM_XATTR_H_INCLUDED */ diff --git a/libarchive/archive_random_private.h b/libarchive/archive_random_private.h index 08b91b3b7a..de23964979 100644 --- a/libarchive/archive_random_private.h +++ b/libarchive/archive_random_private.h @@ -33,4 +33,4 @@ /* Random number generator. */ int archive_random(void *buf, size_t nbytes); -#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */ +#endif /* !ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */ diff --git a/libarchive/archive_rb.h b/libarchive/archive_rb.h index 8851f10818..2fffe796ae 100644 --- a/libarchive/archive_rb.h +++ b/libarchive/archive_rb.h @@ -110,4 +110,4 @@ struct archive_rb_node * __archive_rb_tree_iterate(struct archive_rb_tree *, struct archive_rb_node *, const unsigned int); -#endif /* ARCHIVE_RB_H_*/ +#endif /* !ARCHIVE_RB_H_INCLUDED */ diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index 822c534b86..50db870177 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -176,15 +176,9 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request) return 0; if (self->archive->client.skipper != NULL) { - /* Seek requests over 1GiB are broken down into - * multiple seeks. This avoids overflows when the - * requests get passed through 32-bit arguments. */ - int64_t skip_limit = (int64_t)1 << 30; int64_t total = 0; for (;;) { int64_t get, ask = request; - if (ask > skip_limit) - ask = skip_limit; get = (self->archive->client.skipper) (&self->archive->archive, self->data, ask); total += get; diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c index 09965eb98a..a7a98e9cb1 100644 --- a/libarchive/archive_read_disk_posix.c +++ b/libarchive/archive_read_disk_posix.c @@ -276,7 +276,7 @@ tree_dir_next_posix(struct tree *t); #endif /* Initiate/terminate a tree traversal. */ -static struct tree *tree_open(const char *, int, int); +static struct tree *tree_open(const char *, char, int); static struct tree *tree_reopen(struct tree *, const char *, int); static void tree_close(struct tree *); static void tree_free(struct tree *); @@ -514,7 +514,7 @@ _archive_read_close(struct archive *_a) static void setup_symlink_mode(struct archive_read_disk *a, char symlink_mode, - int follow_symlinks) + char follow_symlinks) { a->symlink_mode = symlink_mode; a->follow_symlinks = follow_symlinks; @@ -778,7 +778,8 @@ _archive_read_data_block(struct archive *_a, const void **buff, */ if (t->current_sparse->offset > t->entry_total) { if (lseek(t->entry_fd, - (off_t)t->current_sparse->offset, SEEK_SET) < 0) { + (off_t)t->current_sparse->offset, SEEK_SET) != + t->current_sparse->offset) { archive_set_error(&a->archive, errno, "Seek error"); r = ARCHIVE_FATAL; a->archive.state = ARCHIVE_STATE_FATAL; @@ -2180,7 +2181,7 @@ tree_append(struct tree *t, const char *name, size_t name_length) * Open a directory tree for traversal. */ static struct tree * -tree_open(const char *path, int symlink_mode, int restore_time) +tree_open(const char *path, char symlink_mode, int restore_time) { struct tree *t; diff --git a/libarchive/archive_read_disk_private.h b/libarchive/archive_read_disk_private.h index cf8da99a02..891ffd437e 100644 --- a/libarchive/archive_read_disk_private.h +++ b/libarchive/archive_read_disk_private.h @@ -52,10 +52,11 @@ struct archive_read_disk { /* * Since symlink interaction changes, we need to track whether - * we're following symlinks for the current item. 'L' mode above - * sets this true, 'P' sets it false, 'H' changes it as we traverse. + * we're following symlinks for the current item, governed by the above + * symlink_mode. 'L' sets this true, 'P' sets it false, 'H' changes it + * as we traverse. */ - char follow_symlinks; /* Either 'L' or 'P'. */ + char follow_symlinks; /* Either 0 or 1. */ /* Directory traversals. */ struct tree *tree; diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c index cb59b51606..689a45958c 100644 --- a/libarchive/archive_read_disk_windows.c +++ b/libarchive/archive_read_disk_windows.c @@ -41,6 +41,7 @@ #include "archive_entry.h" #include "archive_private.h" #include "archive_read_disk_private.h" +#include "archive_time_private.h" #ifndef O_BINARY #define O_BINARY 0 @@ -49,7 +50,7 @@ /* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */ #define IO_REPARSE_TAG_SYMLINK 0xA000000CL #endif -/* To deal with absolute symlink isuues */ +/* To deal with absolute symlink issues */ #define START_ABSOLUTE_SYMLINK_REPARSE L"\\??\\" /*- @@ -602,7 +603,7 @@ _archive_read_close(struct archive *_a) static void setup_symlink_mode(struct archive_read_disk *a, char symlink_mode, - int follow_symlinks) + char follow_symlinks) { a->symlink_mode = symlink_mode; a->follow_symlinks = follow_symlinks; @@ -1651,7 +1652,7 @@ tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path, /* * Append a name to the current dir path. */ -static void +static int tree_append(struct tree *t, const wchar_t *name, size_t name_length) { size_t size_needed; @@ -1664,7 +1665,8 @@ tree_append(struct tree *t, const wchar_t *name, size_t name_length) /* Resize pathname buffer as needed. */ size_needed = name_length + t->dirname_length + 2; - archive_wstring_ensure(&t->path, size_needed); + if (archive_wstring_ensure(&t->path, size_needed) == NULL) + return (TREE_ERROR_FATAL); /* Add a separating '/' if it's needed. */ if (t->dirname_length > 0 && t->path.s[archive_strlen(&t->path)-1] != L'/') @@ -1676,13 +1678,15 @@ tree_append(struct tree *t, const wchar_t *name, size_t name_length) t->full_path.s[t->full_path_dir_length] = L'\0'; t->full_path.length = t->full_path_dir_length; size_needed = name_length + t->full_path_dir_length + 2; - archive_wstring_ensure(&t->full_path, size_needed); + if (archive_wstring_ensure(&t->full_path, size_needed) == NULL) + return (TREE_ERROR_FATAL); /* Add a separating '\' if it's needed. */ if (t->full_path.s[archive_strlen(&t->full_path)-1] != L'\\') archive_wstrappend_wchar(&t->full_path, L'\\'); archive_wstrncat(&t->full_path, name, name_length); t->restore_time.full_path = t->full_path.s; } + return (0); } /* @@ -1696,7 +1700,10 @@ tree_open(const wchar_t *path, int symlink_mode, int restore_time) t = calloc(1, sizeof(*t)); archive_string_init(&(t->full_path)); archive_string_init(&t->path); - archive_wstring_ensure(&t->path, 15); + if (archive_wstring_ensure(&t->path, 15) == NULL) { + free(t); + return (NULL); + } t->initial_symlink_mode = symlink_mode; return (tree_reopen(t, path, restore_time)); } @@ -1755,7 +1762,8 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time) p = wcsrchr(base, L'/'); if (p != NULL) { *p = L'\0'; - tree_append(t, base, p - base); + if (tree_append(t, base, p - base)) + goto failed; t->dirname_length = archive_strlen(&t->path); base = p + 1; } @@ -1891,8 +1899,10 @@ tree_next(struct tree *t) } /* Top stack item needs a regular visit. */ t->current = t->stack; - tree_append(t, t->stack->name.s, + r = tree_append(t, t->stack->name.s, archive_strlen(&(t->stack->name))); + if (r != 0) + return (r); //t->dirname_length = t->path_length; //tree_pop(t); t->stack->flags &= ~needsFirstVisit; @@ -1900,8 +1910,10 @@ tree_next(struct tree *t) } else if (t->stack->flags & needsDescent) { /* Top stack item is dir to descend into. */ t->current = t->stack; - tree_append(t, t->stack->name.s, + r = tree_append(t, t->stack->name.s, archive_strlen(&(t->stack->name))); + if (r != 0) + return (r); t->stack->flags &= ~needsDescent; r = tree_descent(t); if (r != 0) { @@ -1944,9 +1956,10 @@ tree_dir_next_windows(struct tree *t, const wchar_t *pattern) struct archive_wstring pt; archive_string_init(&pt); - archive_wstring_ensure(&pt, + if (archive_wstring_ensure(&pt, archive_strlen(&(t->full_path)) - + 2 + wcslen(pattern)); + + 2 + wcslen(pattern)) == NULL) + return (TREE_ERROR_FATAL); archive_wstring_copy(&pt, &(t->full_path)); archive_wstrappend_wchar(&pt, L'\\'); archive_wstrcat(&pt, pattern); @@ -1978,45 +1991,27 @@ tree_dir_next_windows(struct tree *t, const wchar_t *pattern) continue; if (name[0] == L'.' && name[1] == L'.' && name[2] == L'\0') continue; - tree_append(t, name, namelen); + r = tree_append(t, name, namelen); + if (r != 0) + return (r); return (t->visit_type = TREE_REGULAR); } } -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -static void -fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - /* milli seconds base */ - *t = (time_t)(utc.QuadPart / 10000000); - /* nano seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - *t = 0; - *ns = 0; - } -} - static void entry_copy_bhfi(struct archive_entry *entry, const wchar_t *path, const WIN32_FIND_DATAW *findData, const BY_HANDLE_FILE_INFORMATION *bhfi) { - time_t secs; - long nsecs; + int64_t secs; + uint32_t nsecs; mode_t mode; - fileTimeToUtc(&bhfi->ftLastAccessTime, &secs, &nsecs); + ntfs_to_unix(FILETIME_to_ntfs(&bhfi->ftLastAccessTime), &secs, &nsecs); archive_entry_set_atime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftLastWriteTime, &secs, &nsecs); + ntfs_to_unix(FILETIME_to_ntfs(&bhfi->ftLastWriteTime), &secs, &nsecs); archive_entry_set_mtime(entry, secs, nsecs); - fileTimeToUtc(&bhfi->ftCreationTime, &secs, &nsecs); + ntfs_to_unix(FILETIME_to_ntfs(&bhfi->ftCreationTime), &secs, &nsecs); archive_entry_set_birthtime(entry, secs, nsecs); archive_entry_set_ctime(entry, secs, nsecs); archive_entry_set_dev(entry, bhfi_dev(bhfi)); diff --git a/libarchive/archive_read_format.3 b/libarchive/archive_read_format.3 index 990293c831..660cc74acb 100644 --- a/libarchive/archive_read_format.3 +++ b/libarchive/archive_read_format.3 @@ -37,8 +37,10 @@ .Nm archive_read_support_format_lha , .Nm archive_read_support_format_mtree , .Nm archive_read_support_format_rar , +.Nm archive_read_support_format_rar5 , .Nm archive_read_support_format_raw , .Nm archive_read_support_format_tar , +.Nm archive_read_support_format_warc , .Nm archive_read_support_format_xar , .Nm archive_read_support_format_zip .Nd functions for reading streaming archives @@ -70,10 +72,14 @@ Streaming Archive Library (libarchive, -larchive) .Ft int .Fn archive_read_support_format_rar "struct archive *" .Ft int +.Fn archive_read_support_format_rar5 "struct archive *" +.Ft int .Fn archive_read_support_format_raw "struct archive *" .Ft int .Fn archive_read_support_format_tar "struct archive *" .Ft int +.Fn archive_read_support_format_warc "struct archive *" +.Ft int .Fn archive_read_support_format_xar "struct archive *" .Ft int .Fn archive_read_support_format_zip "struct archive *" @@ -89,8 +95,10 @@ Streaming Archive Library (libarchive, -larchive) .Fn archive_read_support_format_lha , .Fn archive_read_support_format_mtree , .Fn archive_read_support_format_rar , +.Fn archive_read_support_format_rar5 , .Fn archive_read_support_format_raw , .Fn archive_read_support_format_tar , +.Fn archive_read_support_format_warc , .Fn archive_read_support_format_xar , .Fn archive_read_support_format_zip .Xc @@ -100,6 +108,13 @@ For example, .Fn archive_read_support_format_tar enables support for a variety of standard tar formats, old-style tar, ustar, pax interchange format, and many common variants. +.Fn archive_read_support_format_zip +enables support for both the streaming and the seeking zip readers, +which can separately be enabled by respectively +.Fn archive_read_support_format_zip_streamable +and +.Fn archive_read_support_format_zip_seekable +. .It Fn archive_read_support_format_all Enables support for all available formats except the .Dq raw diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c index debfde2086..dc7c9e52c6 100644 --- a/libarchive/archive_read_open_fd.c +++ b/libarchive/archive_read_open_fd.c @@ -52,6 +52,7 @@ struct read_fd_data { int fd; size_t block_size; + int64_t size; char use_lseek; void *buffer; }; @@ -95,6 +96,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size) if (S_ISREG(st.st_mode)) { archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); mine->use_lseek = 1; + mine->size = st.st_size; } #if defined(__CYGWIN__) || defined(_WIN32) setmode(mine->fd, O_BINARY); @@ -131,7 +133,7 @@ static int64_t file_skip(struct archive *a, void *client_data, int64_t request) { struct read_fd_data *mine = (struct read_fd_data *)client_data; - int64_t skip = request; + off_t skip = (off_t)request; int64_t old_offset, new_offset; int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */ @@ -140,20 +142,25 @@ file_skip(struct archive *a, void *client_data, int64_t request) /* Reduce a request that would overflow the 'skip' variable. */ if (sizeof(request) > sizeof(skip)) { - int64_t max_skip = + const int64_t max_skip = (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; if (request > max_skip) - skip = max_skip; + skip = (off_t)max_skip; } - /* Reduce request to the next smallest multiple of block_size */ - request = (request / mine->block_size) * mine->block_size; - if (request == 0) + /* Reduce 'skip' to the next smallest multiple of block_size */ + skip = (off_t)(((int64_t)skip / mine->block_size) * mine->block_size); + if (skip == 0) return (0); - if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) && - ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)) - return (new_offset - old_offset); + if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) { + if (old_offset >= mine->size || + skip > mine->size - old_offset) { + /* Do not seek past end of file. */ + errno = ESPIPE; + } else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0) + return (new_offset - old_offset); + } /* If seek failed once, it will probably fail again. */ mine->use_lseek = 0; @@ -178,11 +185,24 @@ static int64_t file_seek(struct archive *a, void *client_data, int64_t request, int whence) { struct read_fd_data *mine = (struct read_fd_data *)client_data; + off_t seek = (off_t)request; int64_t r; + int seek_bits = sizeof(seek) * 8 - 1; /* off_t is a signed type. */ /* We use off_t here because lseek() is declared that way. */ - /* See above for notes about when off_t is less than 64 bits. */ - r = lseek(mine->fd, request, whence); + + /* Reduce a request that would overflow the 'seek' variable. */ + if (sizeof(request) > sizeof(seek)) { + const int64_t max_seek = + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; + const int64_t min_seek = ~max_seek; + if (request > max_seek) + seek = (off_t)max_seek; + else if (request < min_seek) + seek = (off_t)min_seek; + } + + r = lseek(mine->fd, seek, whence); if (r >= 0) return r; diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c index 276b274238..ede2b4b8c2 100644 --- a/libarchive/archive_read_open_file.c +++ b/libarchive/archive_read_open_file.c @@ -52,6 +52,7 @@ struct read_FILE_data { FILE *f; size_t block_size; + int64_t size; void *buffer; char can_skip; }; @@ -91,6 +92,7 @@ archive_read_open_FILE(struct archive *a, FILE *f) archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); /* Enable the seek optimization only for regular files. */ mine->can_skip = 1; + mine->size = st.st_size; } #if defined(__CYGWIN__) || defined(_WIN32) @@ -130,6 +132,7 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) #else long skip = (long)request; #endif + int64_t old_offset, new_offset = -1; int skip_bits = sizeof(skip) * 8 - 1; (void)a; /* UNUSED */ @@ -145,7 +148,7 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) /* If request is too big for a long or an off_t, reduce it. */ if (sizeof(request) > sizeof(skip)) { - int64_t max_skip = + const int64_t max_skip = (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; if (request > max_skip) skip = max_skip; @@ -153,19 +156,36 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) #ifdef __ANDROID__ /* fileno() isn't safe on all platforms ... see above. */ - if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0) + old_offset = lseek(fileno(mine->f), 0, SEEK_CUR); #elif HAVE__FSEEKI64 - if (_fseeki64(mine->f, skip, SEEK_CUR) != 0) + old_offset = _ftelli64(mine->f); #elif HAVE_FSEEKO - if (fseeko(mine->f, skip, SEEK_CUR) != 0) + old_offset = ftello(mine->f); #else - if (fseek(mine->f, skip, SEEK_CUR) != 0) + old_offset = ftell(mine->f); #endif - { - mine->can_skip = 0; - return (0); + if (old_offset >= 0) { + if (old_offset < mine->size && + skip <= mine->size - old_offset) { +#ifdef __ANDROID__ + new_offset = lseek(fileno(mine->f), skip, SEEK_CUR); +#elif HAVE__FSEEKI64 + if (_fseeki64(mine->f, skip, SEEK_CUR) == 0) + new_offset = _ftelli64(mine->f); +#elif HAVE_FSEEKO + if (fseeko(mine->f, skip, SEEK_CUR) == 0) + new_offset = ftello(mine->f); +#else + if (fseek(mine->f, skip, SEEK_CUR) == 0) + new_offset = ftell(mine->f); +#endif + if (new_offset >= 0) + return (new_offset - old_offset); + } } - return (request); + + mine->can_skip = 0; + return (0); } /* @@ -176,39 +196,42 @@ FILE_seek(struct archive *a, void *client_data, int64_t request, int whence) { struct read_FILE_data *mine = (struct read_FILE_data *)client_data; #if HAVE__FSEEKI64 - int64_t skip = request; + int64_t seek = request; #elif HAVE_FSEEKO - off_t skip = (off_t)request; + off_t seek = (off_t)request; #else - long skip = (long)request; + long seek = (long)request; #endif - int skip_bits = sizeof(skip) * 8 - 1; + int seek_bits = sizeof(seek) * 8 - 1; (void)a; /* UNUSED */ - /* If request is too big for a long or an off_t, reduce it. */ - if (sizeof(request) > sizeof(skip)) { - int64_t max_skip = - (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; - if (request > max_skip) - skip = max_skip; + /* Reduce a request that would overflow the 'seek' variable. */ + if (sizeof(request) > sizeof(seek)) { + const int64_t max_seek = + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; + const int64_t min_seek = ~max_seek; + if (request > max_seek) + seek = max_seek; + else if (request < min_seek) + seek = min_seek; } #ifdef __ANDROID__ /* Newer Android versions have fseeko...to meditate. */ - int64_t ret = lseek(fileno(mine->f), skip, whence); + int64_t ret = lseek(fileno(mine->f), seek, whence); if (ret >= 0) { return ret; } #elif HAVE__FSEEKI64 - if (_fseeki64(mine->f, skip, whence) == 0) { + if (_fseeki64(mine->f, seek, whence) == 0) { return _ftelli64(mine->f); } #elif HAVE_FSEEKO - if (fseeko(mine->f, skip, whence) == 0) { + if (fseeko(mine->f, seek, whence) == 0) { return ftello(mine->f); } #else - if (fseek(mine->f, skip, whence) == 0) { + if (fseek(mine->f, seek, whence) == 0) { return ftell(mine->f); } #endif @@ -227,3 +250,4 @@ FILE_close(struct archive *a, void *client_data) free(mine); return (ARCHIVE_OK); } + diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c index 05f0ffbd94..5f5b3f1f72 100644 --- a/libarchive/archive_read_open_filename.c +++ b/libarchive/archive_read_open_filename.c @@ -74,6 +74,7 @@ struct read_file_data { size_t block_size; void *buffer; mode_t st_mode; /* Mode bits for opened file. */ + int64_t size; char use_lseek; enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type; union { @@ -400,8 +401,10 @@ file_open(struct archive *a, void *client_data) mine->st_mode = st.st_mode; /* Disk-like inputs can use lseek(). */ - if (is_disk_like) + if (is_disk_like) { mine->use_lseek = 1; + mine->size = st.st_size; + } return (ARCHIVE_OK); fail: @@ -479,21 +482,30 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request) struct read_file_data *mine = (struct read_file_data *)client_data; #if defined(_WIN32) && !defined(__CYGWIN__) /* We use _lseeki64() on Windows. */ - int64_t old_offset, new_offset; + int64_t old_offset, new_offset, skip = request; #else - off_t old_offset, new_offset; + off_t old_offset, new_offset, skip = (off_t)request; #endif + int skip_bits = sizeof(skip) * 8 - 1; /* We use off_t here because lseek() is declared that way. */ - /* TODO: Deal with case where off_t isn't 64 bits. - * This shouldn't be a problem on Linux or other POSIX - * systems, since the configuration logic for libarchive - * tries to obtain a 64-bit off_t. - */ - if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 && - (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0) - return (new_offset - old_offset); + /* Reduce a request that would overflow the 'skip' variable. */ + if (sizeof(request) > sizeof(skip)) { + const int64_t max_skip = + (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; + if (request > max_skip) + skip = max_skip; + } + + if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) { + if (old_offset >= mine->size || + skip > mine->size - old_offset) { + /* Do not seek past end of file. */ + errno = ESPIPE; + } else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0) + return (new_offset - old_offset); + } /* If lseek() fails, don't bother trying again. */ mine->use_lseek = 0; @@ -540,11 +552,24 @@ static int64_t file_seek(struct archive *a, void *client_data, int64_t request, int whence) { struct read_file_data *mine = (struct read_file_data *)client_data; + off_t seek = (off_t)request; int64_t r; + int seek_bits = sizeof(seek) * 8 - 1; /* We use off_t here because lseek() is declared that way. */ - /* See above for notes about when off_t is less than 64 bits. */ - r = lseek(mine->fd, request, whence); + + /* Reduce a request that would overflow the 'seek' variable. */ + if (sizeof(request) > sizeof(seek)) { + const int64_t max_seek = + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; + const int64_t min_seek = ~max_seek; + if (request > max_seek) + seek = (off_t)max_seek; + else if (request < min_seek) + seek = (off_t)min_seek; + } + + r = lseek(mine->fd, seek, whence); if (r >= 0) return r; diff --git a/libarchive/archive_read_support_filter_compress.c b/libarchive/archive_read_support_filter_compress.c index b6e9816dfe..b89eaabe52 100644 --- a/libarchive/archive_read_support_filter_compress.c +++ b/libarchive/archive_read_support_filter_compress.c @@ -328,6 +328,7 @@ next_code(struct archive_read_filter *self) static int debug_buff[1024]; static unsigned debug_index; +again: code = newcode = getbits(self, state->bits); if (code < 0) return (code); @@ -360,7 +361,7 @@ next_code(struct archive_read_filter *self) state->section_end_code = (1 << state->bits) - 1; state->free_ent = 257; state->oldcode = -1; - return (next_code(self)); + goto again; } if (code > state->free_ent diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index 1707fe9306..f273f84be5 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -53,6 +53,7 @@ #include "archive_ppmd7_private.h" #include "archive_private.h" #include "archive_read_private.h" +#include "archive_time_private.h" #include "archive_endian.h" #ifndef HAVE_ZLIB_H @@ -62,7 +63,26 @@ #define _7ZIP_SIGNATURE "7z\xBC\xAF\x27\x1C" #define SFX_MIN_ADDR 0x27000 #define SFX_MAX_ADDR 0x60000 +#define SFX_MAX_OFFSET (SFX_MAX_ADDR - SFX_MIN_ADDR) +/* + * PE format + */ +#define PE_DOS_HDR_LEN 0x40 +#define PE_DOS_HDR_ELFANEW_OFFSET 0x3c +#define PE_COFF_HDR_LEN 0x18 +#define PE_COFF_HDR_SEC_CNT_OFFSET 0x6 +#define PE_COFF_HDR_OPT_SZ_OFFSET 0x14 +#define PE_SEC_HDR_LEN 0x28 +#define PE_SEC_HDR_RAW_ADDR_OFFSET 0x14 +#define PE_SEC_HDR_RAW_SZ_OFFSET 0x10 + +/* + * ELF format + */ +#define ELF_HDR_MIN_LEN 0x34 +#define ELF_HDR_EI_CLASS_OFFSET 0x04 +#define ELF_HDR_EI_DATA_OFFSET 0x05 /* * Codec ID @@ -86,6 +106,7 @@ #define _7Z_ARM 0x03030501 #define _7Z_ARMTHUMB 0x03030701 #define _7Z_ARM64 0xa +#define _7Z_RISCV 0xb #define _7Z_SPARC 0x03030805 #define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */ @@ -147,7 +168,6 @@ struct _7z_digests { uint32_t *digests; }; - struct _7z_folder { uint64_t numCoders; struct _7z_coder { @@ -227,13 +247,13 @@ struct _7zip_entry { #define CRC32_IS_SET (1<<3) #define HAS_STREAM (1<<4) - time_t mtime; - time_t atime; - time_t ctime; - long mtime_ns; - long atime_ns; - long ctime_ns; - uint32_t mode; + int64_t mtime; + int64_t atime; + int64_t ctime; + uint32_t mtime_ns; + uint32_t atime_ns; + uint32_t ctime_ns; + __LA_MODE_T mode; uint32_t attr; }; @@ -391,7 +411,6 @@ static int decode_encoded_header_info(struct archive_read *, static int decompress(struct archive_read *, struct _7zip *, void *, size_t *, const void *, size_t *); static ssize_t extract_pack_stream(struct archive_read *, size_t); -static void fileTimeToUtc(uint64_t, time_t *, long *); static uint64_t folder_uncompressed_size(struct _7z_folder *); static void free_CodersInfo(struct _7z_coders_info *); static void free_Digest(struct _7z_digests *); @@ -427,7 +446,9 @@ static ssize_t read_stream(struct archive_read *, const void **, size_t, size_t); static int seek_pack(struct archive_read *); static int64_t skip_stream(struct archive_read *, size_t); -static int skip_sfx(struct archive_read *, ssize_t); +static int skip_sfx(struct archive_read *, const ssize_t); +static ssize_t find_pe_overlay(struct archive_read *); +static ssize_t find_elf_data_sec(struct archive_read *); static int slurp_central_directory(struct archive_read *, struct _7zip *, struct _7z_header_info *); static int setup_decode_folder(struct archive_read *, struct _7z_folder *, @@ -527,15 +548,17 @@ archive_read_format_7zip_bid(struct archive_read *a, int best_bid) * It may a 7-Zip SFX archive file. If first two bytes are * 'M' and 'Z' available on Windows or first four bytes are * "\x7F\x45LF" available on posix like system, seek the 7-Zip - * signature. Although we will perform a seek when reading - * a header, what we do not use __archive_read_seek() here is - * due to a bidding performance. + * signature. While find_pe_overlay can be performed without + * performing a seek, find_elf_data_sec requires one, + * thus a performance difference between the two is expected. */ if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) { - ssize_t offset = SFX_MIN_ADDR; + const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) : + find_elf_data_sec(a); + ssize_t offset = min_addr; ssize_t window = 4096; ssize_t bytes_avail; - while (offset + window <= (SFX_MAX_ADDR)) { + while (offset + window <= (min_addr + SFX_MAX_OFFSET)) { const char *buff = __archive_read_ahead(a, offset + window, &bytes_avail); if (buff == NULL) { @@ -585,21 +608,14 @@ check_7zip_header_in_sfx(const char *p) } static int -skip_sfx(struct archive_read *a, ssize_t bytes_avail) +skip_sfx(struct archive_read *a, const ssize_t min_addr) { const void *h; const char *p, *q; size_t skip, offset; ssize_t bytes, window; - /* - * If bytes_avail > SFX_MIN_ADDR we do not have to call - * __archive_read_seek() at this time since we have - * already had enough data. - */ - if (bytes_avail > SFX_MIN_ADDR) - __archive_read_consume(a, SFX_MIN_ADDR); - else if (__archive_read_seek(a, SFX_MIN_ADDR, SEEK_SET) < 0) + if (__archive_read_seek(a, min_addr, SEEK_SET) < 0) return (ARCHIVE_FATAL); offset = 0; @@ -632,7 +648,7 @@ skip_sfx(struct archive_read *a, ssize_t bytes_avail) (struct _7zip *)a->format->data; skip = p - (const char *)h; __archive_read_consume(a, skip); - zip->seek_base = SFX_MIN_ADDR + offset + skip; + zip->seek_base = min_addr + offset + skip; return (ARCHIVE_OK); } p += step; @@ -649,6 +665,207 @@ fatal: return (ARCHIVE_FATAL); } +static ssize_t +find_pe_overlay(struct archive_read *a) +{ + const char *h; + ssize_t bytes, max_offset, offset, sec_end; + ssize_t opt_hdr_sz, sec_cnt; + + for (;;) { + /* + * Read Dos header to find e_lfanew + */ + h = __archive_read_ahead(a, PE_DOS_HDR_LEN, &bytes); + if (h == NULL || h[0] != 'M' || h[1] != 'Z') { + break; + } + offset = archive_le32dec(h + PE_DOS_HDR_ELFANEW_OFFSET); + + /* + * Read COFF header to find opt header size and sec cnt + */ + if (bytes < offset + PE_COFF_HDR_LEN) { + h = __archive_read_ahead(a, offset + PE_COFF_HDR_LEN, + &bytes); + if (h == NULL || h[offset] != 'P' || + h[offset + 1] != 'E') { + break; + } + } + sec_cnt = archive_le16dec( + h + offset + PE_COFF_HDR_SEC_CNT_OFFSET); + opt_hdr_sz = archive_le16dec( + h + offset + PE_COFF_HDR_OPT_SZ_OFFSET); + + /* + * Skip optional header + */ + if (opt_hdr_sz != 0) { + offset += PE_COFF_HDR_LEN + opt_hdr_sz; + } else { + break; + } + + /* + * Traverse sec table to find max raw offset (i.e., overlay) + */ + if (bytes < offset + sec_cnt * PE_SEC_HDR_LEN) { + h = __archive_read_ahead(a, + offset + sec_cnt * PE_SEC_HDR_LEN, NULL); + if (h == NULL) { + break; + } + } + max_offset = offset; + while (sec_cnt > 0) { + sec_end = archive_le32dec( + h + offset + PE_SEC_HDR_RAW_SZ_OFFSET) + + archive_le32dec( + h + offset + PE_SEC_HDR_RAW_ADDR_OFFSET); + if (sec_end > max_offset) { + max_offset = sec_end; + } + offset += PE_SEC_HDR_LEN; + sec_cnt--; + } + return (max_offset); + } + + /* + * If encounter any weirdness, revert to old brute-force style search + */ + return (SFX_MIN_ADDR); +} + +static ssize_t +find_elf_data_sec(struct archive_read *a) +{ + const char *h; + char big_endian, format_64; + ssize_t bytes, min_addr = SFX_MIN_ADDR; + uint64_t e_shoff, strtab_offset, strtab_size; + uint16_t e_shentsize, e_shnum, e_shstrndx; + uint16_t (*dec16)(const void *); + uint32_t (*dec32)(const void *); + uint64_t (*dec64)(const void *); + + for (;;) { + /* + * Read Elf header to find bitness & endianness + */ + h = __archive_read_ahead(a, ELF_HDR_MIN_LEN, &bytes); + if (h == NULL || memcmp(h, "\x7F\x45LF", 4) != 0) { + break; + } + format_64 = h[ELF_HDR_EI_CLASS_OFFSET] == 0x2; + big_endian = h[ELF_HDR_EI_DATA_OFFSET] == 0x2; + if (big_endian) { + dec16 = &archive_be16dec; + dec32 = &archive_be32dec; + dec64 = &archive_be64dec; + } else { + dec16 = &archive_le16dec; + dec32 = &archive_le32dec; + dec64 = &archive_le64dec; + } + + /* + * Read section header table info + */ + if (format_64) { + e_shoff = (*dec64)(h + 0x28); + e_shentsize = (*dec16)(h + 0x3A); + e_shnum = (*dec16)(h + 0x3C); + e_shstrndx = (*dec16)(h + 0x3E); + if (e_shnum < e_shstrndx || e_shentsize < 0x28) + break; + + } else { + e_shoff = (*dec32)(h + 0x20); + e_shentsize = (*dec16)(h + 0x2E); + e_shnum = (*dec16)(h + 0x30); + e_shstrndx = (*dec16)(h + 0x32); + if (e_shnum < e_shstrndx || e_shentsize < 0x18) + break; + } + + /* + * Reading the section table to find strtab section + */ + if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) { + break; + } + h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL); + if (h == NULL) { + break; + } + if (format_64) { + strtab_offset = (*dec64)( + h + e_shstrndx * e_shentsize + 0x18); + strtab_size = (*dec64)( + h + e_shstrndx * e_shentsize + 0x20); + } else { + strtab_offset = (*dec32)( + h + e_shstrndx * e_shentsize + 0x10); + strtab_size = (*dec32)( + h + e_shstrndx * e_shentsize + 0x14); + } + + /* + * Read the STRTAB section to find the .data offset + */ + if (__archive_read_seek(a, strtab_offset, SEEK_SET) < 0) { + break; + } + h = __archive_read_ahead(a, strtab_size, NULL); + if (h == NULL) { + break; + } + ssize_t data_sym_offset = -1; + for (size_t offset = 0; offset < strtab_size - 6; offset++) { + if (memcmp(h + offset, ".data\00", 6) == 0) { + data_sym_offset = offset; + break; + } + } + if (data_sym_offset == -1) { + break; + } + + /* + * Find the section with the .data name + */ + if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) { + break; + } + h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL); + if (h == NULL) { + break; + } + ssize_t sec_tbl_offset = 0, name_offset; + while (e_shnum > 0) { + name_offset = (*dec32)(h + sec_tbl_offset); + if (name_offset == data_sym_offset) { + if (format_64) { + min_addr = (*dec64)( + h + sec_tbl_offset + 0x18); + } else { + min_addr = (*dec32)( + h + sec_tbl_offset + 0x10); + } + break; + } + sec_tbl_offset += e_shentsize; + e_shnum--; + } + break; + } + + __archive_read_seek(a, 0, SEEK_SET); + return (min_addr); +} + static int archive_read_format_7zip_read_header(struct archive_read *a, struct archive_entry *entry) @@ -1230,6 +1447,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip, filters[fi].id = LZMA_FILTER_ARM64; fi++; break; +#endif +#ifdef LZMA_FILTER_RISCV + case _7Z_RISCV: + filters[fi].id = LZMA_FILTER_RISCV; + fi++; + break; #endif case _7Z_SPARC: filters[fi].id = LZMA_FILTER_SPARC; @@ -1403,6 +1626,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, case _7Z_ARM: case _7Z_ARMTHUMB: case _7Z_ARM64: + case _7Z_RISCV: case _7Z_SPARC: case _7Z_DELTA: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -2852,23 +3076,6 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, return (0); } -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -static void -fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns) -{ - - if (fileTime >= EPOC_TIME) { - fileTime -= EPOC_TIME; - /* milli seconds base */ - *timep = (time_t)(fileTime / 10000000); - /* nano seconds base */ - *ns = (long)(fileTime % 10000000) * 100; - } else { - *timep = 0; - *ns = 0; - } -} - static int read_Times(struct archive_read *a, struct _7z_header_info *h, int type) { @@ -2911,19 +3118,19 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type) goto failed; switch (type) { case kCTime: - fileTimeToUtc(archive_le64dec(p), + ntfs_to_unix(archive_le64dec(p), &(entries[i].ctime), &(entries[i].ctime_ns)); entries[i].flg |= CTIME_IS_SET; break; case kATime: - fileTimeToUtc(archive_le64dec(p), + ntfs_to_unix(archive_le64dec(p), &(entries[i].atime), &(entries[i].atime_ns)); entries[i].flg |= ATIME_IS_SET; break; case kMTime: - fileTimeToUtc(archive_le64dec(p), + ntfs_to_unix(archive_le64dec(p), &(entries[i].mtime), &(entries[i].mtime_ns)); entries[i].flg |= MTIME_IS_SET; @@ -3018,7 +3225,9 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip, if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) { /* This is an executable ? Must be self-extracting... */ - r = skip_sfx(a, bytes_avail); + const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) : + find_elf_data_sec(a); + r = skip_sfx(a, min_addr); if (r < ARCHIVE_WARN) return (r); if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL) @@ -4312,4 +4521,3 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize) return ((ssize_t)outPos); } - diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c index e012248a5b..a96f7d3139 100644 --- a/libarchive/archive_read_support_format_cab.c +++ b/libarchive/archive_read_support_format_cab.c @@ -363,7 +363,12 @@ archive_read_support_format_cab(struct archive *_a) return (ARCHIVE_FATAL); } archive_string_init(&cab->ws); - archive_wstring_ensure(&cab->ws, 256); + if (archive_wstring_ensure(&cab->ws, 256) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + free(cab); + return (ARCHIVE_FATAL); + } r = __archive_read_register_format(a, cab, diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c index 42a89c1b69..74f3549d15 100644 --- a/libarchive/archive_read_support_format_cpio.c +++ b/libarchive/archive_read_support_format_cpio.c @@ -189,6 +189,7 @@ struct cpio { }; static int64_t atol16(const char *, unsigned); +static uint64_t atol16u(const char *, unsigned); static int64_t atol8(const char *, unsigned); static int archive_read_format_cpio_bid(struct archive_read *, int); static int archive_read_format_cpio_options(struct archive_read *, @@ -835,6 +836,7 @@ header_afiol(struct archive_read *a, struct cpio *cpio, struct archive_entry *entry, size_t *namelength, size_t *name_pad) { int64_t t; + uint64_t u; const void *h; const char *header; @@ -851,12 +853,12 @@ header_afiol(struct archive_read *a, struct cpio *cpio, archive_entry_set_dev(entry, (dev_t)atol16(header + afiol_dev_offset, afiol_dev_size)); - t = atol16(header + afiol_ino_offset, afiol_ino_size); - if (t < 0) { - archive_set_error(&a->archive, 0, "Nonsensical ino value"); - return (ARCHIVE_FATAL); - } - archive_entry_set_ino(entry, t); + u = atol16u(header + afiol_ino_offset, afiol_ino_size); +#if ARCHIVE_VERSION_NUMBER < 4000000 + archive_entry_set_ino(entry, (int64_t)(u & INT64_MAX)); +#else + archive_entry_set_ino(entry, u); +#endif archive_entry_set_mode(entry, (mode_t)atol8(header + afiol_mode_offset, afiol_mode_size)); archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size)); @@ -1030,6 +1032,12 @@ atol8(const char *p, unsigned char_cnt) static int64_t atol16(const char *p, unsigned char_cnt) +{ + return ((int64_t)atol16u(p, char_cnt)); +} + +static uint64_t +atol16u(const char *p, unsigned char_cnt) { uint64_t l; int digit; @@ -1048,7 +1056,7 @@ atol16(const char *p, unsigned char_cnt) l <<= 4; l |= digit; } - return ((int64_t)l); + return (l); } static int diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c index 7d3655a951..1635228d50 100644 --- a/libarchive/archive_read_support_format_iso9660.c +++ b/libarchive/archive_read_support_format_iso9660.c @@ -2273,7 +2273,7 @@ parse_rockridge(struct archive_read *a, struct file_info *file, if (version == 1) { if (data_length >= 8) file->mode - = toi(data, 4); + = (__LA_MODE_T)toi(data, 4); if (data_length >= 16) file->nlinks = toi(data + 8, 4); diff --git a/libarchive/archive_read_support_format_lha.c b/libarchive/archive_read_support_format_lha.c index c7cbad272e..2a84ad9dd3 100644 --- a/libarchive/archive_read_support_format_lha.c +++ b/libarchive/archive_read_support_format_lha.c @@ -43,6 +43,7 @@ #include "archive_entry_locale.h" #include "archive_private.h" #include "archive_read_private.h" +#include "archive_time_private.h" #include "archive_endian.h" @@ -162,12 +163,12 @@ struct lha { #define ATIME_IS_SET 2 #define UNIX_MODE_IS_SET 4 #define CRC_IS_SET 8 - time_t birthtime; - long birthtime_tv_nsec; - time_t mtime; - long mtime_tv_nsec; - time_t atime; - long atime_tv_nsec; + int64_t birthtime; + uint32_t birthtime_tv_nsec; + int64_t mtime; + uint32_t mtime_tv_nsec; + int64_t atime; + uint32_t atime_tv_nsec; mode_t mode; int64_t uid; int64_t gid; @@ -230,8 +231,6 @@ static int lha_read_file_extended_header(struct archive_read *, struct lha *, uint16_t *, int, uint64_t, size_t *); static size_t lha_check_header_format(const void *); static int lha_skip_sfx(struct archive_read *); -static time_t lha_dos_time(const unsigned char *); -static time_t lha_win_time(uint64_t, long *); static unsigned char lha_calcsum(unsigned char, const void *, int, size_t); static int lha_parse_linkname(struct archive_wstring *, @@ -819,7 +818,7 @@ lha_read_file_header_0(struct archive_read *a, struct lha *lha) headersum = p[H0_HEADER_SUM_OFFSET]; lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET); lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET); - lha->mtime = lha_dos_time(p + H0_DOS_TIME_OFFSET); + lha->mtime = dos_to_unix(archive_le32dec(p + H0_DOS_TIME_OFFSET)); namelen = p[H0_NAME_LEN_OFFSET]; extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen; if ((namelen > 221 || extdsize < 0) && extdsize != -2) { @@ -919,7 +918,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha) /* Note: An extended header size is included in a compsize. */ lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET); lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET); - lha->mtime = lha_dos_time(p + H1_DOS_TIME_OFFSET); + lha->mtime = dos_to_unix(archive_le32dec(p + H1_DOS_TIME_OFFSET)); namelen = p[H1_NAME_LEN_OFFSET]; /* Calculate a padding size. The result will be normally 0 only(?) */ padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen; @@ -1090,7 +1089,7 @@ lha_read_file_header_3(struct archive_read *a, struct lha *lha) if (archive_le16dec(p + H3_FIELD_LEN_OFFSET) != 4) goto invalid; - lha->header_size =archive_le32dec(p + H3_HEADER_SIZE_OFFSET); + lha->header_size = archive_le32dec(p + H3_HEADER_SIZE_OFFSET); lha->compsize = archive_le32dec(p + H3_COMP_SIZE_OFFSET); lha->origsize = archive_le32dec(p + H3_ORIG_SIZE_OFFSET); lha->mtime = archive_le32dec(p + H3_TIME_OFFSET); @@ -1326,16 +1325,16 @@ lha_read_file_extended_header(struct archive_read *a, struct lha *lha, break; case EXT_TIMESTAMP: if (datasize == (sizeof(uint64_t) * 3)) { - lha->birthtime = lha_win_time( - archive_le64dec(extdheader), + ntfs_to_unix(archive_le64dec(extdheader), + &lha->birthtime, &lha->birthtime_tv_nsec); extdheader += sizeof(uint64_t); - lha->mtime = lha_win_time( - archive_le64dec(extdheader), + ntfs_to_unix(archive_le64dec(extdheader), + &lha->mtime, &lha->mtime_tv_nsec); extdheader += sizeof(uint64_t); - lha->atime = lha_win_time( - archive_le64dec(extdheader), + ntfs_to_unix(archive_le64dec(extdheader), + &lha->atime, &lha->atime_tv_nsec); lha->setflag |= BIRTHTIME_IS_SET | ATIME_IS_SET; @@ -1716,45 +1715,6 @@ lha_parse_linkname(struct archive_wstring *linkname, return (0); } -/* Convert an MSDOS-style date/time into Unix-style time. */ -static time_t -lha_dos_time(const unsigned char *p) -{ - int msTime, msDate; - struct tm ts; - - msTime = archive_le16dec(p); - msDate = archive_le16dec(p+2); - - memset(&ts, 0, sizeof(ts)); - ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */ - ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */ - ts.tm_mday = msDate & 0x1f; /* Day of month. */ - ts.tm_hour = (msTime >> 11) & 0x1f; - ts.tm_min = (msTime >> 5) & 0x3f; - ts.tm_sec = (msTime << 1) & 0x3e; - ts.tm_isdst = -1; - return (mktime(&ts)); -} - -/* Convert an MS-Windows-style date/time into Unix-style time. */ -static time_t -lha_win_time(uint64_t wintime, long *ns) -{ -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) - - if (wintime >= EPOC_TIME) { - wintime -= EPOC_TIME; /* 1970-01-01 00:00:00 (UTC) */ - if (ns != NULL) - *ns = (long)(wintime % 10000000) * 100; - return (wintime / 10000000); - } else { - if (ns != NULL) - *ns = 0; - return (0); - } -} - static unsigned char lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size) { @@ -2917,4 +2877,3 @@ lzh_decode_huffman(struct huffman *hf, unsigned rbits) /* This bit pattern needs to be found out at a huffman tree. */ return (lzh_decode_huffman_tree(hf, rbits, c)); } - diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c index 9d155c66d0..923ae5c65e 100644 --- a/libarchive/archive_read_support_format_rar.c +++ b/libarchive/archive_read_support_format_rar.c @@ -335,8 +335,8 @@ struct rar int found_first_header; char has_endarc_header; struct data_block_offsets *dbo; - unsigned int cursor; - unsigned int nodes; + size_t cursor; + size_t nodes; char filename_must_match; /* LZSS members */ @@ -451,7 +451,7 @@ 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 int copy_from_lzss_window(struct archive_read *, uint8_t *, 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); @@ -741,11 +741,11 @@ archive_read_support_format_rar(struct archive *_a) return (ARCHIVE_FATAL); } - /* - * Until enough data has been read, we cannot tell about - * any encrypted entries yet. - */ - rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; + /* + * Until enough data has been read, we cannot tell about + * any encrypted entries yet. + */ + rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; r = __archive_read_register_format(a, rar, @@ -768,21 +768,21 @@ archive_read_support_format_rar(struct archive *_a) static int archive_read_support_format_rar_capabilities(struct archive_read * a) { - (void)a; /* UNUSED */ - return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA - | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); + (void)a; /* UNUSED */ + return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA + | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA); } static int archive_read_format_rar_has_encrypted_entries(struct archive_read *_a) { - if (_a && _a->format) { - struct rar * rar = (struct rar *)_a->format->data; - if (rar) { - return rar->has_encrypted_entries; - } - } - return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; + if (_a && _a->format) { + struct rar * rar = (struct rar *)_a->format->data; + if (rar) { + return rar->has_encrypted_entries; + } + } + return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW; } @@ -793,7 +793,7 @@ archive_read_format_rar_bid(struct archive_read *a, int best_bid) /* If there's already a bid > 30, we'll never win. */ if (best_bid > 30) - return (-1); + return (-1); if ((p = __archive_read_ahead(a, 7, NULL)) == NULL) return (-1); @@ -865,7 +865,7 @@ skip_sfx(struct archive_read *a) } skip = p - (const char *)h; __archive_read_consume(a, skip); - total += skip; + total += skip; } fatal: archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -910,7 +910,7 @@ archive_read_format_rar_read_header(struct archive_read *a, const void *h; const char *p; struct rar *rar; - size_t skip; + int64_t skip; char head_type; int ret; unsigned flags; @@ -930,7 +930,7 @@ archive_read_format_rar_read_header(struct archive_read *a, * as well. */ if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { - rar->has_encrypted_entries = 0; + rar->has_encrypted_entries = 0; } /* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if @@ -953,8 +953,11 @@ archive_read_format_rar_read_header(struct archive_read *a, { unsigned long crc32_val; - if ((h = __archive_read_ahead(a, 7, NULL)) == NULL) + if ((h = __archive_read_ahead(a, 7, NULL)) == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Failed to read next header."); return (ARCHIVE_FATAL); + } p = h; head_type = p[2]; @@ -972,7 +975,7 @@ archive_read_format_rar_read_header(struct archive_read *a, case MAIN_HEAD: rar->main_flags = archive_le16dec(p + 3); skip = archive_le16dec(p + 5); - if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) { + if ((size_t)skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid header size"); return (ARCHIVE_FATAL); @@ -984,7 +987,8 @@ archive_read_format_rar_read_header(struct archive_read *a, memcpy(rar->reserved2, p + 7 + sizeof(rar->reserved1), sizeof(rar->reserved2)); if (rar->main_flags & MHD_ENCRYPTVER) { - if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)+1) { + if ((size_t)skip < + 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2) + 1) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid header size"); return (ARCHIVE_FATAL); @@ -1053,28 +1057,30 @@ archive_read_format_rar_read_header(struct archive_read *a, /* Skim the entire header and compute the CRC. */ crc32_val = 0; while (skip > 0) { - size_t to_read = skip; - if (to_read > 32 * 1024) - to_read = 32 * 1024; - 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 int)to_read); - __archive_read_consume(a, to_read); - skip -= to_read; + unsigned to_read; + if (skip > 32 * 1024) + to_read = 32 * 1024; + else + to_read = (unsigned)skip; + 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, to_read); + __archive_read_consume(a, to_read); + skip -= to_read; } if ((crc32_val & 0xffff) != crc32_expected) { #ifndef DONT_FAIL_ON_CRC_ERROR - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Header CRC error"); - return (ARCHIVE_FATAL); + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Header CRC error"); + return (ARCHIVE_FATAL); #endif } if (head_type == ENDARC_HEAD) - return (ARCHIVE_EOF); + return (ARCHIVE_EOF); break; case NEWSUB_HEAD: @@ -1083,7 +1089,7 @@ archive_read_format_rar_read_header(struct archive_read *a, break; default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Bad RAR file"); return (ARCHIVE_FATAL); } @@ -1098,7 +1104,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff, int ret; if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) { - rar->has_encrypted_entries = 0; + rar->has_encrypted_entries = 0; } if (rar->bytes_unconsumed > 0) { @@ -1186,7 +1192,7 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset, int whence) { int64_t client_offset, ret; - unsigned int i; + size_t i; struct rar *rar = (struct rar *)(a->format->data); if (rar->compression_method == COMPRESS_METHOD_STORE) @@ -1433,7 +1439,11 @@ read_header(struct archive_read *a, struct archive_entry *entry, } if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Failed to read full header content."); return (ARCHIVE_FATAL); + } /* File Header CRC check. */ crc32_computed = crc32(crc32_computed, h, (unsigned)(header_size - 7)); @@ -1460,8 +1470,8 @@ read_header(struct archive_read *a, struct archive_entry *entry, if (rar->file_flags & FHD_PASSWORD) { - archive_entry_set_is_data_encrypted(entry, 1); - rar->has_encrypted_entries = 1; + archive_entry_set_is_data_encrypted(entry, 1); + rar->has_encrypted_entries = 1; archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "RAR encryption support unavailable."); /* Since it is only the data part itself that is encrypted we can at least @@ -1506,10 +1516,23 @@ read_header(struct archive_read *a, struct archive_entry *entry, */ if (head_type == NEWSUB_HEAD) { size_t distance = p - (const char *)h; + if (rar->packed_size > INT64_MAX - header_size) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Extended header size too large."); + return (ARCHIVE_FATAL); + } header_size += rar->packed_size; + if ((uintmax_t)header_size > SIZE_MAX) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unable to read extended header data."); + return (ARCHIVE_FATAL); + } /* Make sure we have the extended data. */ - if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) - return (ARCHIVE_FATAL); + if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Failed to read extended header data."); + return (ARCHIVE_FATAL); + } p = h; endp = p + header_size - 7; p += distance; @@ -1670,6 +1693,8 @@ read_header(struct archive_read *a, struct archive_entry *entry, !memcmp(rar->filename, rar->filename_save, filename_size + 1)) { __archive_read_consume(a, header_size - 7); + rar->br.avail_in = 0; + rar->br.next_in = NULL; rar->cursor++; if (rar->cursor >= rar->nodes) { @@ -1689,6 +1714,12 @@ read_header(struct archive_read *a, struct archive_entry *entry, } if (rar->dbo[rar->cursor].start_offset < 0) { + if (rar->packed_size > INT64_MAX - a->filter->position) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unable to store offsets."); + return (ARCHIVE_FATAL); + } rar->dbo[rar->cursor].start_offset = a->filter->position; rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset + rar->packed_size; @@ -1745,6 +1776,11 @@ read_header(struct archive_read *a, struct archive_entry *entry, } __archive_read_consume(a, header_size - 7); + if (rar->packed_size > INT64_MAX - a->filter->position) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unable to store offsets."); + return (ARCHIVE_FATAL); + } rar->dbo[0].start_offset = a->filter->position; rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size; @@ -1753,7 +1789,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, case OS_MSDOS: case OS_OS2: case OS_WIN32: - rar->mode = archive_le32dec(file_header.file_attr); + rar->mode = (__LA_MODE_T)archive_le32dec(file_header.file_attr); if (rar->mode & FILE_ATTRIBUTE_DIRECTORY) rar->mode = AE_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; else @@ -1764,7 +1800,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, case OS_UNIX: case OS_MAC_OS: case OS_BEOS: - rar->mode = archive_le32dec(file_header.file_attr); + rar->mode = (__LA_MODE_T)archive_le32dec(file_header.file_attr); break; default: @@ -1780,6 +1816,7 @@ read_header(struct archive_read *a, struct archive_entry *entry, rar->offset_outgoing = 0; rar->br.cache_avail = 0; rar->br.avail_in = 0; + rar->br.next_in = NULL; rar->crc_calculated = 0; rar->entry_eof = 0; rar->valid = 1; @@ -1941,8 +1978,18 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry, int ret = (ARCHIVE_OK); rar = (struct rar *)(a->format->data); - if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL) + if ((uintmax_t)rar->packed_size > SIZE_MAX) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Unable to read link."); return (ARCHIVE_FATAL); + } + if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Failed to read link."); + return (ARCHIVE_FATAL); + } p = h; if (archive_entry_copy_symlink_l(entry, @@ -2224,7 +2271,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size, ret = expand(a, &end); if (ret != ARCHIVE_OK) - return (ret); + return (ret); rar->bytes_uncopied = end - start; rar->filters.lastend = end; @@ -2332,9 +2379,9 @@ parse_codes(struct archive_read *a) __archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context); if (rar->dictionary_size == 0) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Invalid zero dictionary size"); - return (ARCHIVE_FATAL); + return (ARCHIVE_FATAL); } if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context, @@ -2929,11 +2976,11 @@ expand(struct archive_read *a, int64_t *end) } if ((symbol = read_next_symbol(a, &rar->maincode)) < 0) - return (ARCHIVE_FATAL); + goto bad_data; if (symbol < 256) { - lzss_emit_literal(rar, symbol); + lzss_emit_literal(rar, (uint8_t)symbol); continue; } else if (symbol == 256) @@ -2956,14 +3003,14 @@ expand(struct archive_read *a, int64_t *end) else { if (parse_codes(a) != ARCHIVE_OK) - return (ARCHIVE_FATAL); + goto bad_data; continue; } } else if(symbol==257) { if (!read_filter(a, end)) - return (ARCHIVE_FATAL); + goto bad_data; continue; } else if(symbol==258) @@ -3048,7 +3095,7 @@ expand(struct archive_read *a, int64_t *end) { if ((lowoffsetsymbol = read_next_symbol(a, &rar->lowoffsetcode)) < 0) - return (ARCHIVE_FATAL); + goto bad_data; if(lowoffsetsymbol == 16) { rar->numlowoffsetrepeats = 15; @@ -3096,7 +3143,7 @@ bad_data: } static int -copy_from_lzss_window(struct archive_read *a, void *buffer, +copy_from_lzss_window(struct archive_read *a, uint8_t *buffer, int64_t startpos, int length) { int windowoffs, firstpart; @@ -3111,7 +3158,7 @@ copy_from_lzss_window(struct archive_read *a, void *buffer, } if (firstpart < length) { memcpy(buffer, &rar->lzss.window[windowoffs], firstpart); - memcpy(buffer, &rar->lzss.window[0], length - firstpart); + memcpy(buffer + firstpart, &rar->lzss.window[0], length - firstpart); } else { memcpy(buffer, &rar->lzss.window[windowoffs], length); } @@ -3180,8 +3227,12 @@ static const void * rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) { struct rar *rar = (struct rar *)(a->format->data); - const void *h = __archive_read_ahead(a, min, avail); + const void *h; int ret; + +again: + h = __archive_read_ahead(a, min, avail); + if (avail) { if (a->archive.read_data_is_posix_read && *avail > (ssize_t)a->archive.read_data_requested) @@ -3203,7 +3254,7 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail) rar->filename_must_match = 0; if (ret != (ARCHIVE_OK)) return NULL; - return rar_read_ahead(a, min, avail); + goto again; } } return h; @@ -3266,6 +3317,9 @@ parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint else blocklength = prog ? prog->oldfilterlength : 0; + if (blocklength > rar->dictionary_size) + return 0; + registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS; registers[4] = blocklength; registers[5] = prog ? prog->usagecount : 0; diff --git a/libarchive/archive_read_support_format_rar5.c b/libarchive/archive_read_support_format_rar5.c index 1dd0d88d67..48dde0c2e8 100644 --- a/libarchive/archive_read_support_format_rar5.c +++ b/libarchive/archive_read_support_format_rar5.c @@ -46,6 +46,7 @@ #include "archive_entry_locale.h" #include "archive_ppmd7_private.h" #include "archive_entry_private.h" +#include "archive_time_private.h" #ifdef HAVE_BLAKE2_H #include @@ -100,10 +101,12 @@ struct file_header { uint8_t dir : 1; /* Is this file entry a directory? */ /* Optional time fields. */ - uint64_t e_mtime; - uint64_t e_ctime; - uint64_t e_atime; - uint32_t e_unix_ns; + int64_t e_mtime; + int64_t e_ctime; + int64_t e_atime; + uint32_t e_mtime_ns; + uint32_t e_ctime_ns; + uint32_t e_atime_ns; /* Optional hash fields. */ uint32_t stored_crc32; @@ -1101,22 +1104,22 @@ static int read_consume_bits(struct archive_read* a, struct rar5* rar, return ARCHIVE_OK; } -static int read_u32(struct archive_read* a, uint32_t* pvalue) { +static char read_u32(struct archive_read* a, uint32_t* pvalue) { const uint8_t* p; if(!read_ahead(a, 4, &p)) return 0; *pvalue = archive_le32dec(p); - return ARCHIVE_OK == consume(a, 4) ? 1 : 0; + return ARCHIVE_OK == consume(a, 4); } -static int read_u64(struct archive_read* a, uint64_t* pvalue) { +static char read_u64(struct archive_read* a, uint64_t* pvalue) { const uint8_t* p; if(!read_ahead(a, 8, &p)) return 0; *pvalue = archive_le64dec(p); - return ARCHIVE_OK == consume(a, 8) ? 1 : 0; + return ARCHIVE_OK == consume(a, 8); } static int bid_standard(struct archive_read* a) { @@ -1301,14 +1304,8 @@ static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar, return ARCHIVE_OK; } -static uint64_t time_win_to_unix(uint64_t win_time) { - const size_t ns_in_sec = 10000000; - const uint64_t sec_to_unix = 11644473600LL; - return win_time / ns_in_sec - sec_to_unix; -} - static int parse_htime_item(struct archive_read* a, char unix_time, - uint64_t* where, int64_t* extra_data_size) + int64_t* sec, uint32_t* nsec, int64_t* extra_data_size) { if(unix_time) { uint32_t time_val; @@ -1316,13 +1313,13 @@ static int parse_htime_item(struct archive_read* a, char unix_time, return ARCHIVE_EOF; *extra_data_size -= 4; - *where = (uint64_t) time_val; + *sec = (int64_t) time_val; } else { uint64_t windows_time; if(!read_u64(a, &windows_time)) return ARCHIVE_EOF; - *where = time_win_to_unix(windows_time); + ntfs_to_unix(windows_time, sec, nsec); *extra_data_size -= 8; } @@ -1386,7 +1383,7 @@ static int parse_file_extra_version(struct archive_read* a, static int parse_file_extra_htime(struct archive_read* a, struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size) { - char unix_time = 0; + char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime; size_t flags = 0; size_t value_len; @@ -1407,32 +1404,62 @@ static int parse_file_extra_htime(struct archive_read* a, } unix_time = flags & IS_UNIX; + has_unix_ns = unix_time && (flags & HAS_UNIX_NS); + has_mtime = flags & HAS_MTIME; + has_atime = flags & HAS_ATIME; + has_ctime = flags & HAS_CTIME; + rar->file.e_atime_ns = rar->file.e_ctime_ns = rar->file.e_mtime_ns = 0; - if(flags & HAS_MTIME) { + if(has_mtime) { parse_htime_item(a, unix_time, &rar->file.e_mtime, - extra_data_size); - archive_entry_set_mtime(e, rar->file.e_mtime, 0); + &rar->file.e_mtime_ns, extra_data_size); } - if(flags & HAS_CTIME) { + if(has_ctime) { parse_htime_item(a, unix_time, &rar->file.e_ctime, - extra_data_size); - archive_entry_set_ctime(e, rar->file.e_ctime, 0); + &rar->file.e_ctime_ns, extra_data_size); } - if(flags & HAS_ATIME) { + if(has_atime) { parse_htime_item(a, unix_time, &rar->file.e_atime, - extra_data_size); - archive_entry_set_atime(e, rar->file.e_atime, 0); + &rar->file.e_atime_ns, extra_data_size); } - if(flags & HAS_UNIX_NS) { - if(!read_u32(a, &rar->file.e_unix_ns)) + if(has_mtime && has_unix_ns) { + if(!read_u32(a, &rar->file.e_mtime_ns)) return ARCHIVE_EOF; *extra_data_size -= 4; } + if(has_ctime && has_unix_ns) { + if(!read_u32(a, &rar->file.e_ctime_ns)) + return ARCHIVE_EOF; + + *extra_data_size -= 4; + } + + if(has_atime && has_unix_ns) { + if(!read_u32(a, &rar->file.e_atime_ns)) + return ARCHIVE_EOF; + + *extra_data_size -= 4; + } + + /* The seconds and nanoseconds are either together, or separated in two + * fields so we parse them, then set the archive_entry's times. */ + if(has_mtime) { + archive_entry_set_mtime(e, rar->file.e_mtime, rar->file.e_mtime_ns); + } + + if(has_ctime) { + archive_entry_set_ctime(e, rar->file.e_ctime, rar->file.e_ctime_ns); + } + + if(has_atime) { + archive_entry_set_atime(e, rar->file.e_atime, rar->file.e_atime_ns); + } + return ARCHIVE_OK; } @@ -3095,7 +3122,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) { * can be stored in the output buffer directly. * * - Code 256 defines a new filter, which is later used to - * ransform the data block accordingly to the filter type. + * transform the data block accordingly to the filter type. * The data block needs to be fully uncompressed first. * * - Code bigger than 257 and smaller than 262 define diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index 7615d7cd78..0c87bc6d73 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -169,36 +169,36 @@ static int gnu_add_sparse_entry(struct archive_read *, struct tar *, static void gnu_clear_sparse_list(struct tar *); static int gnu_sparse_old_read(struct archive_read *, struct tar *, - const struct archive_entry_header_gnutar *header, size_t *); + const struct archive_entry_header_gnutar *header, int64_t *); static int gnu_sparse_old_parse(struct archive_read *, struct tar *, const struct gnu_sparse *sparse, int length); static int gnu_sparse_01_parse(struct archive_read *, struct tar *, const char *, size_t); -static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *, - size_t *); +static int64_t gnu_sparse_10_read(struct archive_read *, struct tar *, + int64_t *); static int header_Solaris_ACL(struct archive_read *, struct tar *, - struct archive_entry *, const void *, size_t *); + struct archive_entry *, const void *, int64_t *); static int header_common(struct archive_read *, struct tar *, struct archive_entry *, const void *); static int header_old_tar(struct archive_read *, struct tar *, struct archive_entry *, const void *); static int header_pax_extension(struct archive_read *, struct tar *, - struct archive_entry *, const void *, size_t *); + struct archive_entry *, const void *, int64_t *); static int header_pax_global(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); + struct archive_entry *, const void *h, int64_t *); static int header_gnu_longlink(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); + struct archive_entry *, const void *h, int64_t *); static int header_gnu_longname(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); + struct archive_entry *, const void *h, int64_t *); static int is_mac_metadata_entry(struct archive_entry *entry); static int read_mac_metadata_blob(struct archive_read *, - struct archive_entry *, size_t *); + struct archive_entry *, int64_t *); static int header_volume(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); + struct archive_entry *, const void *h, int64_t *); static int header_ustar(struct archive_read *, struct tar *, struct archive_entry *, const void *h); static int header_gnutar(struct archive_read *, struct tar *, - struct archive_entry *, const void *h, size_t *); + struct archive_entry *, const void *h, int64_t *); static int archive_read_format_tar_bid(struct archive_read *, int); static int archive_read_format_tar_options(struct archive_read *, const char *, const char *); @@ -211,7 +211,7 @@ static int archive_read_format_tar_read_header(struct archive_read *, static int checksum(struct archive_read *, const void *); static int pax_attribute(struct archive_read *, struct tar *, struct archive_entry *, const char *key, size_t key_length, - size_t value_length, size_t *unconsumed); + size_t value_length, int64_t *unconsumed); static int pax_attribute_LIBARCHIVE_xattr(struct archive_entry *, const char *, size_t, const char *, size_t); static int pax_attribute_SCHILY_acl(struct archive_read *, struct tar *, @@ -220,20 +220,20 @@ static int pax_attribute_SUN_holesdata(struct archive_read *, struct tar *, struct archive_entry *, const char *, size_t); static void pax_time(const char *, size_t, int64_t *sec, long *nanos); static ssize_t readline(struct archive_read *, struct tar *, const char **, - ssize_t limit, size_t *); + ssize_t limit, int64_t *); static int read_body_to_string(struct archive_read *, struct tar *, - struct archive_string *, const void *h, size_t *); + struct archive_string *, const void *h, int64_t *); static int read_bytes_to_string(struct archive_read *, - struct archive_string *, size_t, size_t *); + struct archive_string *, size_t, int64_t *); static int64_t tar_atol(const char *, size_t); static int64_t tar_atol10(const char *, size_t); static int64_t tar_atol256(const char *, size_t); static int64_t tar_atol8(const char *, size_t); static int tar_read_header(struct archive_read *, struct tar *, - struct archive_entry *, size_t *); + struct archive_entry *, int64_t *); static int tohex(int c); static char *url_decode(const char *, size_t); -static void tar_flush_unconsumed(struct archive_read *, size_t *); +static void tar_flush_unconsumed(struct archive_read *, int64_t *); /* Sanity limits: These numbers should be low enough to * prevent a maliciously-crafted archive from forcing us to @@ -478,7 +478,7 @@ archive_read_format_tar_options(struct archive_read *a, * anything outstanding since we're going to do read_aheads */ static void -tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed) +tar_flush_unconsumed(struct archive_read *a, int64_t *unconsumed) { if (*unconsumed) { /* @@ -526,7 +526,8 @@ archive_read_format_tar_read_header(struct archive_read *a, const char *p; const wchar_t *wp; int r; - size_t l, unconsumed = 0; + size_t l; + int64_t unconsumed = 0; /* Assign default device/inode values. */ archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */ @@ -627,7 +628,10 @@ archive_read_format_tar_read_data(struct archive_read *a, /* If we're at end of file, return EOF. */ if (tar->sparse_list == NULL || tar->entry_bytes_remaining == 0) { - if (__archive_read_consume(a, tar->entry_padding) < 0) + int64_t request = tar->entry_bytes_remaining + + tar->entry_padding; + + if (__archive_read_consume(a, request) != request) return (ARCHIVE_FATAL); tar->entry_padding = 0; *buff = NULL; @@ -665,29 +669,15 @@ archive_read_format_tar_read_data(struct archive_read *a, static int archive_read_format_tar_skip(struct archive_read *a) { - int64_t bytes_skipped; int64_t request; - struct sparse_block *p; struct tar* tar; tar = (struct tar *)(a->format->data); - /* Do not consume the hole of a sparse file. */ - request = 0; - for (p = tar->sparse_list; p != NULL; p = p->next) { - if (!p->hole) { - if (p->remaining >= INT64_MAX - request) { - return ARCHIVE_FATAL; - } - request += p->remaining; - } - } - if (request > tar->entry_bytes_remaining) - request = tar->entry_bytes_remaining; - request += tar->entry_padding + tar->entry_bytes_unconsumed; + request = tar->entry_bytes_remaining + tar->entry_padding + + tar->entry_bytes_unconsumed; - bytes_skipped = __archive_read_consume(a, request); - if (bytes_skipped < 0) + if (__archive_read_consume(a, request) != request) return (ARCHIVE_FATAL); tar->entry_bytes_remaining = 0; @@ -700,13 +690,29 @@ archive_read_format_tar_skip(struct archive_read *a) return (ARCHIVE_OK); } +/* + * This function resets the accumulated state while reading + * a header. + */ +static void +tar_reset_header_state(struct tar *tar) +{ + tar->pax_hdrcharset_utf8 = 1; + tar->sparse_gnu_attributes_seen = 0; + archive_string_empty(&(tar->entry_gname)); + archive_string_empty(&(tar->entry_pathname)); + archive_string_empty(&(tar->entry_pathname_override)); + archive_string_empty(&(tar->entry_uname)); + archive_string_empty(&tar->entry_linkpath); +} + /* * This function reads and interprets all of the headers associated * with a single entry. */ static int tar_read_header(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, size_t *unconsumed) + struct archive_entry *entry, int64_t *unconsumed) { ssize_t bytes; int err = ARCHIVE_OK, err2; @@ -725,13 +731,7 @@ tar_read_header(struct archive_read *a, struct tar *tar, static const int32_t seen_x_header = 32; /* Also X */ static const int32_t seen_mac_metadata = 512; - tar->pax_hdrcharset_utf8 = 1; - tar->sparse_gnu_attributes_seen = 0; - archive_string_empty(&(tar->entry_gname)); - archive_string_empty(&(tar->entry_pathname)); - archive_string_empty(&(tar->entry_pathname_override)); - archive_string_empty(&(tar->entry_uname)); - archive_string_empty(&tar->entry_linkpath); + tar_reset_header_state(tar); /* Ensure format is set. */ if (a->archive.archive_format_name == NULL) { @@ -815,6 +815,8 @@ tar_read_header(struct archive_read *a, struct tar *tar, switch(header->typeflag[0]) { case 'A': /* Solaris tar ACL */ if (seen_headers & seen_A_header) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Redundant 'A' header"); return (ARCHIVE_FATAL); } seen_headers |= seen_A_header; @@ -824,6 +826,8 @@ tar_read_header(struct archive_read *a, struct tar *tar, break; case 'g': /* POSIX-standard 'g' header. */ if (seen_headers & seen_g_header) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Redundant 'g' header"); return (ARCHIVE_FATAL); } seen_headers |= seen_g_header; @@ -833,27 +837,41 @@ tar_read_header(struct archive_read *a, struct tar *tar, break; case 'K': /* Long link name (GNU tar, others) */ if (seen_headers & seen_K_header) { - return (ARCHIVE_FATAL); + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Damaged archive: Redundant 'K' headers may cause linknames to be incorrect"); + err = err_combine(err, ARCHIVE_WARN); } seen_headers |= seen_K_header; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; + a->archive.archive_format_name = "GNU tar format"; err2 = header_gnu_longlink(a, tar, entry, h, unconsumed); break; case 'L': /* Long filename (GNU tar, others) */ if (seen_headers & seen_L_header) { - return (ARCHIVE_FATAL); + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Damaged archive: Redundant 'L' headers may cause filenames to be incorrect"); + err = err_combine(err, ARCHIVE_WARN); } seen_headers |= seen_L_header; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; + a->archive.archive_format_name = "GNU tar format"; err2 = header_gnu_longname(a, tar, entry, h, unconsumed); break; case 'V': /* GNU volume header */ if (seen_headers & seen_V_header) { - return (ARCHIVE_FATAL); + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Redundant 'V' header"); + err = err_combine(err, ARCHIVE_WARN); } seen_headers |= seen_V_header; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; + a->archive.archive_format_name = "GNU tar format"; err2 = header_volume(a, tar, entry, h, unconsumed); break; case 'X': /* Used by SUN tar; same as 'x'. */ if (seen_headers & seen_x_header) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Redundant 'X'/'x' header"); return (ARCHIVE_FATAL); } seen_headers |= seen_x_header; @@ -864,6 +882,8 @@ tar_read_header(struct archive_read *a, struct tar *tar, break; case 'x': /* POSIX-standard 'x' header. */ if (seen_headers & seen_x_header) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Redundant 'x' header"); return (ARCHIVE_FATAL); } seen_headers |= seen_x_header; @@ -915,6 +935,7 @@ tar_read_header(struct archive_read *a, struct tar *tar, err = err_combine(err, err2); /* Note: Other headers can appear again. */ seen_headers = seen_mac_metadata; + tar_reset_header_state(tar); break; } @@ -1043,7 +1064,7 @@ archive_block_is_null(const char *p) */ static int header_Solaris_ACL(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) + struct archive_entry *entry, const void *h, int64_t *unconsumed) { const struct archive_entry_header_ustar *header; struct archive_string acl_text; @@ -1097,8 +1118,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, break; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Malformed Solaris ACL attribute (unsupported type %" - PRIo64 ")", type); + "Malformed Solaris ACL attribute (unsupported type %llu)", + (unsigned long long)type); archive_string_free(&acl_text); return (ARCHIVE_WARN); } @@ -1149,7 +1170,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, */ static int header_gnu_longlink(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) + struct archive_entry *entry, const void *h, int64_t *unconsumed) { int err; @@ -1183,7 +1204,7 @@ set_conversion_failed_error(struct archive_read *a, */ static int header_gnu_longname(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) + struct archive_entry *entry, const void *h, int64_t *unconsumed) { int err; struct archive_string longname; @@ -1204,7 +1225,7 @@ header_gnu_longname(struct archive_read *a, struct tar *tar, */ static int header_volume(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) + struct archive_entry *entry, const void *h, int64_t *unconsumed) { const struct archive_entry_header_ustar *header; int64_t size, to_consume; @@ -1230,7 +1251,7 @@ header_volume(struct archive_read *a, struct tar *tar, static int read_bytes_to_string(struct archive_read *a, struct archive_string *as, size_t size, - size_t *unconsumed) { + int64_t *unconsumed) { const void *src; /* Fail if we can't make our buffer big enough. */ @@ -1263,7 +1284,7 @@ read_bytes_to_string(struct archive_read *a, */ static int read_body_to_string(struct archive_read *a, struct tar *tar, - struct archive_string *as, const void *h, size_t *unconsumed) + struct archive_string *as, const void *h, int64_t *unconsumed) { int64_t size; const struct archive_entry_header_ustar *header; @@ -1272,18 +1293,21 @@ read_body_to_string(struct archive_read *a, struct tar *tar, (void)tar; /* UNUSED */ header = (const struct archive_entry_header_ustar *)h; size = tar_atol(header->size, sizeof(header->size)); - if (size > entry_limit) { + if (size < 0 || size > entry_limit) { + archive_set_error(&a->archive, EINVAL, + "Special header has invalid size: %lld", + (long long)size); return (ARCHIVE_FATAL); } - if ((size > (int64_t)pathname_limit) || (size < 0)) { + if (size > (int64_t)pathname_limit) { archive_string_empty(as); int64_t to_consume = ((size + 511) & ~511); if (to_consume != __archive_read_consume(a, to_consume)) { return (ARCHIVE_FATAL); } archive_set_error(&a->archive, EINVAL, - "Special header too large: %d > 1MiB", - (int)size); + "Special header too large: %lld > 1MiB", + (long long)size); return (ARCHIVE_WARN); } r = read_bytes_to_string(a, as, size, unconsumed); @@ -1654,7 +1678,7 @@ is_mac_metadata_entry(struct archive_entry *entry) { */ static int read_mac_metadata_blob(struct archive_read *a, - struct archive_entry *entry, size_t *unconsumed) + struct archive_entry *entry, int64_t *unconsumed) { int64_t size; size_t msize; @@ -1711,7 +1735,7 @@ read_mac_metadata_blob(struct archive_read *a, */ static int header_pax_global(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) + struct archive_entry *entry, const void *h, int64_t *unconsumed) { const struct archive_entry_header_ustar *header; int64_t size, to_consume; @@ -1722,7 +1746,10 @@ header_pax_global(struct archive_read *a, struct tar *tar, header = (const struct archive_entry_header_ustar *)h; size = tar_atol(header->size, sizeof(header->size)); - if (size > entry_limit) { + if (size < 0 || size > entry_limit) { + archive_set_error(&a->archive, EINVAL, + "Special header has invalid size: %lld", + (long long)size); return (ARCHIVE_FATAL); } to_consume = ((size + 511) & ~511); @@ -1818,7 +1845,7 @@ header_ustar(struct archive_read *a, struct tar *tar, static int header_pax_extension(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) + struct archive_entry *entry, const void *h, int64_t *unconsumed) { /* Sanity checks: The largest `x` body I've ever heard of was * a little over 4MB. So I doubt there has ever been a @@ -1869,8 +1896,8 @@ header_pax_extension(struct archive_read *a, struct tar *tar, return (ARCHIVE_FATAL); } archive_set_error(&a->archive, EINVAL, - "Ignoring oversized pax extensions: %d > %d", - (int)ext_size, (int)ext_size_limit); + "Ignoring oversized pax extensions: %lld > %lld", + (long long)ext_size, (long long)ext_size_limit); return (ARCHIVE_WARN); } tar_flush_unconsumed(a, unconsumed); @@ -1969,6 +1996,13 @@ header_pax_extension(struct archive_read *a, struct tar *tar, *unconsumed += p - attr_start; tar_flush_unconsumed(a, unconsumed); + if (value_length == 0) { + archive_set_error(&a->archive, EINVAL, + "Malformed pax attributes"); + *unconsumed += ext_size + ext_padding; + return (ARCHIVE_WARN); + } + /* pax_attribute will consume value_length - 1 */ r = pax_attribute(a, tar, entry, attr_name.s, archive_strlen(&attr_name), value_length - 1, unconsumed); ext_size -= value_length - 1; @@ -2178,8 +2212,9 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar, if (value_length > acl_limit) { __archive_read_consume(a, value_length); archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Unreasonably large ACL: %d > %d", - (int)value_length, (int)acl_limit); + "Unreasonably large ACL: %llu > %llu", + (unsigned long long)value_length, + (unsigned long long)acl_limit); return (ARCHIVE_WARN); } @@ -2211,7 +2246,7 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar, } static int -pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, size_t *unconsumed) { +pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, int64_t *unconsumed) { struct archive_string as; int r; @@ -2226,12 +2261,16 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps r = read_bytes_to_string(a, &as, value_length, unconsumed); if (r < ARCHIVE_OK) { archive_string_free(&as); + *ps = 0; + *pn = 0; return (r); } pax_time(as.s, archive_strlen(&as), ps, pn); archive_string_free(&as); - if (*ps < 0 || *ps == INT64_MAX) { + if (*ps == INT64_MIN) { + *ps = 0; + *pn = 0; return (ARCHIVE_WARN); } return (ARCHIVE_OK); @@ -2240,7 +2279,7 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps static int pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *result) { struct archive_string as; - size_t unconsumed = 0; + int64_t unconsumed = 0; int r; if (value_length > 64) { @@ -2254,6 +2293,7 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t * tar_flush_unconsumed(a, &unconsumed); if (r < ARCHIVE_OK) { archive_string_free(&as); + *result = 0; return (r); } @@ -2280,7 +2320,7 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t * */ static int pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *entry, - const char *key, size_t key_length, size_t value_length, size_t *unconsumed) + const char *key, size_t key_length, size_t value_length, int64_t *unconsumed) { int64_t t; long n; @@ -2364,8 +2404,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent tar->sparse_gnu_minor = 1; if (value_length > sparse_map_limit) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Unreasonably large sparse map: %d > %d", - (int)value_length, (int)sparse_map_limit); + "Unreasonably large sparse map: %llu > %llu", + (unsigned long long)value_length, + (unsigned long long)sparse_map_limit); err = ARCHIVE_FAILED; } else { p = __archive_read_ahead(a, value_length, &bytes_read); @@ -2472,8 +2513,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "symlink type is very long" - "(longest recognized value is 4 bytes, this is %d)", - (int)value_length); + "(longest recognized value is 4 bytes, this is %llu)", + (unsigned long long)value_length); err = ARCHIVE_WARN; } __archive_read_consume(a, value_length); @@ -2509,8 +2550,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent if (value_length > xattr_limit) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Ignoring unreasonably large security.selinux attribute:" - " %d > %d", - (int)value_length, (int)xattr_limit); + " %llu > %llu", + (unsigned long long)value_length, + (unsigned long long)xattr_limit); /* TODO: Should this be FAILED instead? */ err = ARCHIVE_WARN; } else { @@ -2627,8 +2669,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent } } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Unreasonably large xattr: %d > %d", - (int)value_length, (int)xattr_limit); + "Unreasonably large xattr: %llu > %llu", + (unsigned long long)value_length, + (unsigned long long)xattr_limit); err = ARCHIVE_WARN; } __archive_read_consume(a, value_length); @@ -2658,8 +2701,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent } } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Unreasonably large sparse map: %d > %d", - (int)value_length, (int)sparse_map_limit); + "Unreasonably large sparse map: %llu > %llu", + (unsigned long long)value_length, + (unsigned long long)sparse_map_limit); err = ARCHIVE_FAILED; } __archive_read_consume(a, value_length); @@ -2728,8 +2772,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent } } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "hdrcharset attribute is unreasonably large (%d bytes)", - (int)value_length); + "hdrcharset attribute is unreasonably large (%llu bytes)", + (unsigned long long)value_length); err = ARCHIVE_WARN; } __archive_read_consume(a, value_length); @@ -2816,7 +2860,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent /* - * parse a decimal time value, which may include a fractional portion + * Parse a decimal time value, which may include a fractional portion + * + * Sets ps to INT64_MIN on error. */ static void pax_time(const char *p, size_t length, int64_t *ps, long *pn) @@ -2832,6 +2878,7 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn) if (length <= 0) { *ps = 0; + *pn = 0; return; } s = 0; @@ -2845,8 +2892,9 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn) digit = *p - '0'; if (s > limit || (s == limit && digit > last_digit_limit)) { - s = INT64_MAX; - break; + *ps = INT64_MIN; + *pn = 0; + return; } s = (s * 10) + digit; ++p; @@ -2877,7 +2925,7 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn) */ static int header_gnutar(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const void *h, size_t *unconsumed) + struct archive_entry *entry, const void *h, int64_t *unconsumed) { const struct archive_entry_header_gnutar *header; int64_t t; @@ -3028,7 +3076,7 @@ gnu_clear_sparse_list(struct tar *tar) static int gnu_sparse_old_read(struct archive_read *a, struct tar *tar, - const struct archive_entry_header_gnutar *header, size_t *unconsumed) + const struct archive_entry_header_gnutar *header, int64_t *unconsumed) { ssize_t bytes_read; const void *data; @@ -3162,7 +3210,7 @@ gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p, size */ static int64_t gnu_sparse_10_atol(struct archive_read *a, struct tar *tar, - int64_t *remaining, size_t *unconsumed) + int64_t *remaining, int64_t *unconsumed) { int64_t l, limit, last_digit_limit; const char *p; @@ -3207,12 +3255,10 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar, * Returns length (in bytes) of the sparse data description * that was read. */ -static ssize_t -gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) +static int64_t +gnu_sparse_10_read(struct archive_read *a, struct tar *tar, int64_t *unconsumed) { - ssize_t bytes_read; - int entries; - int64_t offset, size, to_skip, remaining; + int64_t bytes_read, entries, offset, size, to_skip, remaining; /* Clear out the existing sparse list. */ gnu_clear_sparse_list(tar); @@ -3220,7 +3266,7 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) remaining = tar->entry_bytes_remaining; /* Parse entries. */ - entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed); + entries = gnu_sparse_10_atol(a, tar, &remaining, unconsumed); if (entries < 0) return (ARCHIVE_FATAL); /* Parse the individual entries. */ @@ -3238,14 +3284,14 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) } /* Skip rest of block... */ tar_flush_unconsumed(a, unconsumed); - bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining); + bytes_read = tar->entry_bytes_remaining - remaining; to_skip = 0x1ff & -bytes_read; /* Fail if tar->entry_bytes_remaing would get negative */ if (to_skip > remaining) return (ARCHIVE_FATAL); if (to_skip != __archive_read_consume(a, to_skip)) return (ARCHIVE_FATAL); - return ((ssize_t)(bytes_read + to_skip)); + return (bytes_read + to_skip); } /* @@ -3455,7 +3501,7 @@ tar_atol256(const char *_p, size_t char_cnt) */ static ssize_t readline(struct archive_read *a, struct tar *tar, const char **start, - ssize_t limit, size_t *unconsumed) + ssize_t limit, int64_t *unconsumed) { ssize_t bytes_read; ssize_t total_size = 0; diff --git a/libarchive/archive_read_support_format_warc.c b/libarchive/archive_read_support_format_warc.c index fcec5bc4cb..696f959c34 100644 --- a/libarchive/archive_read_support_format_warc.c +++ b/libarchive/archive_read_support_format_warc.c @@ -386,7 +386,8 @@ start_over: case LAST_WT: default: /* consume the content and start over */ - _warc_skip(a); + if (_warc_skip(a) < 0) + return (ARCHIVE_FATAL); goto start_over; } return (ARCHIVE_OK); @@ -439,7 +440,9 @@ _warc_skip(struct archive_read *a) { struct warc_s *w = a->format->data; - __archive_read_consume(a, w->cntlen + 4U/*\r\n\r\n separator*/); + if (__archive_read_consume(a, w->cntlen) < 0 || + __archive_read_consume(a, 4U/*\r\n\r\n separator*/) < 0) + return (ARCHIVE_FATAL); w->cntlen = 0U; w->cntoff = 0U; return (ARCHIVE_OK); diff --git a/libarchive/archive_read_support_format_xar.c b/libarchive/archive_read_support_format_xar.c index 8084c5a043..b4e1192ef7 100644 --- a/libarchive/archive_read_support_format_xar.c +++ b/libarchive/archive_read_support_format_xar.c @@ -36,6 +36,10 @@ #include #elif HAVE_EXPAT_H #include +#elif HAVE_XMLLITE_H +#include +#include +#include #endif #ifdef HAVE_BZLIB_H #include @@ -56,12 +60,13 @@ #include "archive_read_private.h" #if (!defined(HAVE_LIBXML_XMLREADER_H) && \ - !defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H)) ||\ + !defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H) && \ + !defined(HAVE_XMLLITE_H)) ||\ !defined(HAVE_ZLIB_H) || \ !defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1) /* * xar needs several external libraries. - * o libxml2 or expat --- XML parser + * o libxml2, expat or (Windows only) xmllite --- XML parser * o openssl or MD5/SHA1 hash function * o zlib * o bzlib2 (option) @@ -438,6 +443,8 @@ static void expat_start_cb(void *, const XML_Char *, const XML_Char **); static void expat_end_cb(void *, const XML_Char *); static void expat_data_cb(void *, const XML_Char *, int); static int expat_read_toc(struct archive_read *); +#elif defined(HAVE_XMLLITE_H) +static int xmllite_read_toc(struct archive_read *); #endif int @@ -589,6 +596,8 @@ read_toc(struct archive_read *a) r = xml2_read_toc(a); #elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) r = expat_read_toc(a); +#elif defined(HAVE_XMLLITE_H) + r = xmllite_read_toc(a); #endif if (r != ARCHIVE_OK) return (r); @@ -1110,17 +1119,17 @@ atohex(unsigned char *b, size_t bsize, const char *p, size_t psize) while (bsize && psize > 1) { unsigned char x; - if (p[0] >= 'a' && p[0] <= 'z') + if (p[0] >= 'a' && p[0] <= 'f') x = (p[0] - 'a' + 0x0a) << 4; - else if (p[0] >= 'A' && p[0] <= 'Z') + else if (p[0] >= 'A' && p[0] <= 'F') x = (p[0] - 'A' + 0x0a) << 4; else if (p[0] >= '0' && p[0] <= '9') x = (p[0] - '0') << 4; else return (-1); - if (p[1] >= 'a' && p[1] <= 'z') + if (p[1] >= 'a' && p[1] <= 'f') x |= p[1] - 'a' + 0x0a; - else if (p[1] >= 'A' && p[1] <= 'Z') + else if (p[1] >= 'A' && p[1] <= 'F') x |= p[1] - 'A' + 0x0a; else if (p[1] >= '0' && p[1] <= '9') x |= p[1] - '0'; @@ -3333,6 +3342,326 @@ expat_read_toc(struct archive_read *a) XML_ParserFree(parser); return (ud.state); } -#endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */ + +#elif defined(HAVE_XMLLITE_H) + +struct ArchiveStreamAdapter { + const ISequentialStreamVtbl *lpVtbl; /* see asaStaticVtable */ + struct archive_read *a; +}; + +static HRESULT STDMETHODCALLTYPE +asaQueryInterface(ISequentialStream *this, REFIID riid, void **ppv) +{ + if (!IsEqualIID(riid, &IID_ISequentialStream)) { + *ppv = NULL; + return E_NOINTERFACE; + } + *ppv = this; + return S_OK; +} + +/* + * We can dispense with reference counting as we tightly manage the lifetime + * of an ArchiveStreamAdapter. + */ +static ULONG STDMETHODCALLTYPE +asaAddRef(ISequentialStream *this) +{ + (void)this; /* UNUSED */ + return ULONG_MAX; +} + +static ULONG STDMETHODCALLTYPE +asaRelease(ISequentialStream *this) +{ + (void)this; /* UNUSED */ + return ULONG_MAX; +} + +static HRESULT STDMETHODCALLTYPE +asaRead(ISequentialStream *this, void *pv, ULONG cb, ULONG *pcbRead) +{ + struct ArchiveStreamAdapter *asa = (struct ArchiveStreamAdapter *)this; + struct archive_read *a; + struct xar *xar; + const void *d = pv; + size_t outbytes = cb; + size_t used = 0; + int r; + + a = asa->a; + xar = (struct xar *)(a->format->data); + + *pcbRead = 0; + + if (xar->toc_remaining <= 0) + return cb != 0 ? S_FALSE : S_OK; + + r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining); + if (r != ARCHIVE_OK) + return E_FAIL; + __archive_read_consume(a, used); + xar->toc_remaining -= used; + xar->offset += used; + xar->toc_total += outbytes; + PRINT_TOC(pv, outbytes); + + *pcbRead = (ULONG)outbytes; + return outbytes < cb ? S_FALSE : S_OK; +} + +static HRESULT STDMETHODCALLTYPE +asaWrite(ISequentialStream *this, const void *pv, ULONG cb, ULONG *pcbWritten) +{ + (void)this; /* UNUSED */ + (void)pv; /* UNUSED */ + (void)cb; /* UNUSED */ + if (!pcbWritten) return E_INVALIDARG; + *pcbWritten = 0; + return E_NOTIMPL; +} + +static const ISequentialStreamVtbl asaStaticVtable = { + .QueryInterface = asaQueryInterface, + .AddRef = asaAddRef, + .Release = asaRelease, + .Read = asaRead, + .Write = asaWrite, +}; + +static int +xmllite_create_stream_adapter(struct archive_read *a, + struct ArchiveStreamAdapter **pasa) +{ + struct ArchiveStreamAdapter *asa = + calloc(1, sizeof(struct ArchiveStreamAdapter)); + if (!asa) { + archive_set_error(&(a->archive), ENOMEM, "Out of memory"); + return (ARCHIVE_FATAL); + } + asa->lpVtbl = &asaStaticVtable; + asa->a = a; + *pasa = asa; + return (ARCHIVE_OK); +} + +typedef HRESULT(STDMETHODCALLTYPE *xmllite_wstr_func)(IXmlReader *, LPCWSTR *, + UINT *); + +/* + * Returns an narrow-char archive_string in *as after calling + * the wide-char COM API callee() on the XmlReader reader. + * Sets an appropriate error on the archive if it fails. + */ +static int +xmllite_call_return_as(struct archive_read *a, struct archive_string *as, + IXmlReader *reader, xmllite_wstr_func callee) +{ + LPCWSTR wcs; + UINT wlen; + + if (FAILED(callee(reader, &wcs, &wlen))) { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "Failed to read XML data"); + return (ARCHIVE_FATAL); + } + + archive_string_init(as); + if (archive_string_append_from_wcs(as, wcs, (size_t)wlen) < 0) { + archive_string_free(as); + archive_set_error(&(a->archive), ENOMEM, "Out of memory"); + return (ARCHIVE_FATAL); + } + + return (ARCHIVE_OK); +} + +static char * +xmllite_call_return_mbs(struct archive_read *a, IXmlReader *reader, + xmllite_wstr_func callee) +{ + char *ret; + struct archive_string as; + + if (xmllite_call_return_as(a, &as, reader, callee) < 0) { + return NULL; + } + + ret = strdup(as.s); + archive_string_free(&as); + if (ret == NULL) { + archive_set_error(&(a->archive), ENOMEM, "Out of memory"); + return NULL; + } + return ret; +} + +static int +xmllite_xmlattr_setup(struct archive_read *a, + struct xmlattr_list *list, IXmlReader *reader) +{ + struct xmlattr *attr; + HRESULT hr; + + list->first = NULL; + list->last = &(list->first); + hr = reader->lpVtbl->MoveToFirstAttribute(reader); + /* Contrary to other checks, we're not using SUCCEEDED/FAILED + * because MoveToNextAttribute returns *S_FALSE* (success!) + * when it runs out of attributes. + */ + while (hr == S_OK) { + /* Attributes implied as being default by the DTD are ignored */ + if (reader->lpVtbl->IsDefault(reader)) + continue; + + attr = malloc(sizeof*(attr)); + if (attr == NULL) { + archive_set_error(&(a->archive), ENOMEM, + "Out of memory"); + return (ARCHIVE_FATAL); + } + + attr->name = xmllite_call_return_mbs(a, reader, + reader->lpVtbl->GetLocalName); + if (attr->name == NULL) { + free(attr); + /* xmllite_call_return_mbs sets an appropriate error */ + return (ARCHIVE_FATAL); + } + + attr->value = xmllite_call_return_mbs(a, reader, + reader->lpVtbl->GetValue); + if (attr->value == NULL) { + free(attr->name); + free(attr); + /* xmllite_call_return_mbs sets an appropriate error */ + return (ARCHIVE_FATAL); + } + + attr->next = NULL; + *list->last = attr; + list->last = &(attr->next); + hr = reader->lpVtbl->MoveToNextAttribute(reader); + } + + if (FAILED(hr)) { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_FILE_FORMAT, + "Failed to parse XML document"); + return (ARCHIVE_FAILED); + } + + return (ARCHIVE_OK); +} + +static int +xmllite_read_toc(struct archive_read *a) +{ + struct ArchiveStreamAdapter *asa = NULL; + char *name; + struct archive_string as; + BOOL empty; + XmlNodeType type; + struct xmlattr_list list; + IXmlReader *reader = NULL; + int r = ARCHIVE_OK; + + if ((r = xmllite_create_stream_adapter(a, &asa)) < 0) { + goto out; + } + + if (FAILED(CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL))) { + r = ARCHIVE_FATAL; + goto out; + } + + if (FAILED(reader->lpVtbl->SetInput(reader, (IUnknown *)asa))) { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "Failed to prepare XML stream"); + r = ARCHIVE_FATAL; + goto out; + } + + while (!reader->lpVtbl->IsEOF(reader)) { + if (FAILED(reader->lpVtbl->Read(reader, &type))) { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "Failed to read XML stream"); + r = ARCHIVE_FATAL; + goto out; + } + + switch (type) { + case XmlNodeType_Element: + empty = reader->lpVtbl->IsEmptyElement(reader); + + name = xmllite_call_return_mbs(a, reader, + reader->lpVtbl->GetLocalName); + if (name == NULL) { + /* xmllite_call_return_mbs sets an appropriate error */ + r = ARCHIVE_FATAL; + goto out; + } + + r = xmllite_xmlattr_setup(a, &list, reader); + if (r == ARCHIVE_OK) { + r = xml_start(a, name, &list); + } + xmlattr_cleanup(&list); + if (r == ARCHIVE_OK && empty) { + xml_end(a, name); + } + + free(name); + if (r != ARCHIVE_OK) { + goto out; + } + + break; + case XmlNodeType_EndElement: + name = xmllite_call_return_mbs(a, reader, + reader->lpVtbl->GetLocalName); + if (name == NULL) { + /* xmllite_call_return_mbs sets an appropriate error */ + r = ARCHIVE_FATAL; + goto out; + } + + xml_end(a, name); + free(name); + break; + case XmlNodeType_Text: + r = xmllite_call_return_as(a, &as, reader, + reader->lpVtbl->GetValue); + if (r != ARCHIVE_OK) { + /* xmllite_call_return_as sets an appropriate error */ + goto out; + } + + xml_data(a, as.s, (int)archive_strlen(&as)); + archive_string_free(&as); + + case XmlNodeType_None: + case XmlNodeType_Attribute: + case XmlNodeType_CDATA: + case XmlNodeType_ProcessingInstruction: + case XmlNodeType_Comment: + case XmlNodeType_DocumentType: + case XmlNodeType_Whitespace: + case XmlNodeType_XmlDeclaration: + default: + break; + } + } + +out: + if (reader) + reader->lpVtbl->Release(reader); + + free(asa); + + return r; +} +#endif /* defined(XMLLITE) */ #endif /* Support xar format */ diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 27e6bc051f..daf51933d6 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -71,6 +71,7 @@ #include "archive_private.h" #include "archive_rb.h" #include "archive_read_private.h" +#include "archive_time_private.h" #include "archive_ppmd8_private.h" #ifndef HAVE_ZLIB_H @@ -465,27 +466,6 @@ compression_name(const int compression) return "??"; } -/* Convert an MSDOS-style date/time into Unix-style time. */ -static time_t -zip_time(const char *p) -{ - int msTime, msDate; - struct tm ts; - - msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]); - msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]); - - memset(&ts, 0, sizeof(ts)); - ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */ - ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */ - ts.tm_mday = msDate & 0x1f; /* Day of month. */ - ts.tm_hour = (msTime >> 11) & 0x1f; - ts.tm_min = (msTime >> 5) & 0x3f; - ts.tm_sec = (msTime << 1) & 0x3e; - ts.tm_isdst = -1; - return mktime(&ts); -} - /* * The extra data is stored as a list of * id1+size1+data1 + id2+size2+data2 ... @@ -978,7 +958,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, } zip->init_decryption = (zip_entry->zip_flags & ZIP_ENCRYPTED); zip_entry->compression = (char)archive_le16dec(p + 8); - zip_entry->mtime = zip_time(p + 10); + zip_entry->mtime = dos_to_unix(archive_le32dec(p + 10)); zip_entry->crc32 = archive_le32dec(p + 14); if (zip_entry->zip_flags & ZIP_LENGTH_AT_END) zip_entry->decdat = p[11]; @@ -3986,7 +3966,7 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry, zip->has_encrypted_entries = 1; } zip_entry->compression = (char)archive_le16dec(p + 10); - zip_entry->mtime = zip_time(p + 12); + zip_entry->mtime = dos_to_unix(archive_le32dec(p + 12)); zip_entry->crc32 = archive_le32dec(p + 16); if (zip_entry->zip_flags & ZIP_LENGTH_AT_END) zip_entry->decdat = p[13]; diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 8ab3b994b4..7437715f91 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -472,7 +472,8 @@ static int archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, const char *s, size_t length, struct archive_string_conv *sc) { - int count, ret = 0; + int ret = 0; + size_t count; UINT from_cp; if (sc != NULL) @@ -494,7 +495,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, ws = dest->s + dest->length; mp = (const unsigned char *)s; count = 0; - while (count < (int)length && *mp) { + while (count < length && *mp) { *ws++ = (wchar_t)*mp++; count++; } @@ -517,13 +518,13 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, * UTF-16BE/LE NFD ===> UTF-16 NFC * UTF-16BE/LE NFC ===> UTF-16 NFD */ - count = (int)utf16nbytes(s, length); + count = utf16nbytes(s, length); } else { /* * UTF-8 NFD ===> UTF-16 NFC * UTF-8 NFC ===> UTF-16 NFD */ - count = (int)mbsnbytes(s, length); + count = mbsnbytes(s, length); } u16.s = (char *)dest->s; u16.length = dest->length << 1; @@ -538,7 +539,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, sc->flag = saved_flag;/* restore the saved flag. */ return (ret); } else if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) { - count = (int)utf16nbytes(s, length); + count = utf16nbytes(s, length); count >>= 1; /* to be WCS length */ /* Allocate memory for WCS. */ if (NULL == archive_wstring_ensure(dest, @@ -547,14 +548,14 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, wmemcpy(dest->s + dest->length, (const wchar_t *)s, count); if ((sc->flag & SCONV_FROM_UTF16BE) && !IS_BIG_ENDIAN) { uint16_t *u16 = (uint16_t *)(dest->s + dest->length); - int b; + size_t b; for (b = 0; b < count; b++) { uint16_t val = archive_le16dec(u16+b); archive_be16enc(u16+b, val); } } else if ((sc->flag & SCONV_FROM_UTF16LE) && IS_BIG_ENDIAN) { uint16_t *u16 = (uint16_t *)(dest->s + dest->length); - int b; + size_t b; for (b = 0; b < count; b++) { uint16_t val = archive_be16dec(u16+b); archive_le16enc(u16+b, val); @@ -578,21 +579,28 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, buffsize = dest->length + length + 1; do { + int r; + + /* MultiByteToWideChar is limited to int. */ + if (length > (size_t)INT_MAX || + (dest->buffer_length >> 1) > (size_t)INT_MAX) + return (-1); /* Allocate memory for WCS. */ if (NULL == archive_wstring_ensure(dest, buffsize)) return (-1); /* Convert MBS to WCS. */ - count = MultiByteToWideChar(from_cp, + r = MultiByteToWideChar(from_cp, mbflag, s, (int)length, dest->s + dest->length, (int)(dest->buffer_length >> 1) -1); - if (count == 0 && + if (r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { /* Expand the WCS buffer. */ buffsize = dest->buffer_length << 1; continue; } - if (count == 0 && length != 0) + if (r == 0 && length != 0) ret = -1; + count = (size_t)r; break; } while (1); } @@ -701,9 +709,9 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as, const wchar_t *ws, size_t len, struct archive_string_conv *sc) { BOOL defchar_used, *dp; - int count, ret = 0; + int ret = 0; UINT to_cp; - int wslen = (int)len; + size_t count, wslen = len; if (sc != NULL) to_cp = sc->to_cp; @@ -742,13 +750,13 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as, count = 0; defchar_used = 0; if (sc->flag & SCONV_TO_UTF16BE) { - while (count < (int)len && *ws) { + while (count < len && *ws) { archive_be16enc(u16+count, *ws); ws++; count++; } } else { - while (count < (int)len && *ws) { + while (count < len && *ws) { archive_le16enc(u16+count, *ws); ws++; count++; @@ -761,15 +769,21 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as, archive_string_ensure(as, as->length + len * 2 + 1)) return (-1); do { + int r; + defchar_used = 0; if (to_cp == CP_UTF8 || sc == NULL) dp = NULL; else dp = &defchar_used; - count = WideCharToMultiByte(to_cp, 0, ws, wslen, + /* WideCharToMultiByte is limited to int. */ + if (as->buffer_length - as->length - 1 > (size_t)INT_MAX || + wslen > (size_t)INT_MAX) + return (-1); + r = WideCharToMultiByte(to_cp, 0, ws, (int)wslen, as->s + as->length, - (int)as->buffer_length - (int)as->length - 1, NULL, dp); - if (count == 0 && + (int)(as->buffer_length - as->length - 1), NULL, dp); + if (r == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { /* Expand the MBS buffer and retry. */ if (NULL == archive_string_ensure(as, @@ -777,8 +791,9 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as, return (-1); continue; } - if (count == 0) + if (r == 0) ret = -1; + count = (size_t)r; break; } while (1); } @@ -2054,7 +2069,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p, char *outp; size_t avail, bs; int return_value = 0; /* success */ - int to_size, from_size; + size_t to_size, from_size; if (sc->flag & SCONV_TO_UTF16) to_size = 2; @@ -2073,7 +2088,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p, remaining = length; outp = as->s + as->length; avail = as->buffer_length - as->length - to_size; - while (remaining >= (size_t)from_size) { + while (remaining >= from_size) { size_t result = iconv(cd, &itp, &remaining, &outp, &avail); if (result != (size_t)-1) @@ -2196,6 +2211,8 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc) if (codepage != CP_UTF8) mbflag |= MB_PRECOMPOSED; + if (n > (size_t)INT_MAX) + return (-1); /* Invalid */ if (MultiByteToWideChar(codepage, mbflag, p, (int)n, NULL, 0) == 0) return (-1); /* Invalid */ return (0); /* Okay */ @@ -2349,7 +2366,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) cnt = utf8_count[ch]; /* Invalid sequence or there are not plenty bytes. */ - if ((int)n < cnt) { + if (n < (size_t)cnt) { cnt = (int)n; for (i = 1; i < cnt; i++) { if ((s[i] & 0xc0) != 0x80) { @@ -2418,7 +2435,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) cnt = 6; else cnt = 1; - if ((int)n < cnt) + if (n < (size_t)cnt) cnt = (int)n; for (i = 1; i < cnt; i++) { if ((s[i] & 0xc0) != 0x80) { @@ -2634,7 +2651,7 @@ unicode_to_utf16be(char *p, size_t remaining, uint32_t uc) } else { if (remaining < 2) return (0); - archive_be16enc(utf16, uc); + archive_be16enc(utf16, (uint16_t)uc); return (2); } } @@ -2656,7 +2673,7 @@ unicode_to_utf16le(char *p, size_t remaining, uint32_t uc) } else { if (remaining < 2) return (0); - archive_le16enc(utf16, uc); + archive_le16enc(utf16, (uint16_t)uc); return (2); } } @@ -3521,10 +3538,9 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes, { struct archive_string tmp; const char *u16; - int ll; BOOL defchar; char *mbs; - size_t mbs_size, b; + size_t mbs_size, b, ll; int ret = 0; bytes &= ~1; @@ -3588,18 +3604,24 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes, } do { + int r; defchar = 0; - ll = WideCharToMultiByte(sc->to_cp, 0, + /* WideCharToMultiByte is limited to int. */ + if (bytes > (size_t)INT_MAX || mbs_size > (size_t)INT_MAX) + return (-1); + r = WideCharToMultiByte(sc->to_cp, 0, (LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size, NULL, &defchar); /* Exit loop if we succeeded */ - if (ll != 0 || + if (r != 0 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + ll = (size_t)r; break; } /* Else expand buffer and loop to try again. */ - ll = WideCharToMultiByte(sc->to_cp, 0, + r = WideCharToMultiByte(sc->to_cp, 0, (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL); + ll = (size_t)r; if (archive_string_ensure(as, ll +1) == NULL) return (-1); mbs = as->s + as->length; @@ -3665,16 +3687,21 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p, return (0); } do { - count = MultiByteToWideChar(sc->from_cp, + int r; + if (length > (size_t)INT_MAX || (avail >> 1) > (size_t)INT_MAX) + return (-1); + r = MultiByteToWideChar(sc->from_cp, MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1); /* Exit loop if we succeeded */ - if (count != 0 || + if (r != 0 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + count = (size_t)r; break; } /* Expand buffer and try again */ - count = MultiByteToWideChar(sc->from_cp, + r = MultiByteToWideChar(sc->from_cp, MB_PRECOMPOSED, s, (int)length, NULL, 0); + count = (size_t)r; if (archive_string_ensure(as16, (count +1) * 2) == NULL) return (-1); @@ -3825,9 +3852,9 @@ best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p, ret = -1; } if (bigendian) - archive_be16enc(utf16, c); + archive_be16enc(utf16, (uint16_t)c); else - archive_le16enc(utf16, c); + archive_le16enc(utf16, (uint16_t)c); utf16 += 2; } as16->length = utf16 - as16->s; diff --git a/libarchive/archive_string_composition.h b/libarchive/archive_string_composition.h index e917036f11..7f5b77a1d8 100644 --- a/libarchive/archive_string_composition.h +++ b/libarchive/archive_string_composition.h @@ -2286,5 +2286,4 @@ static const struct unicode_decomposition_table u_decomposition_table[] = { { 0x110AB , 0x110A5 , 0x110BA }, }; -#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */ - +#endif /* !ARCHIVE_STRING_COMPOSITION_H_INCLUDED */ diff --git a/libarchive/archive_string_sprintf.c b/libarchive/archive_string_sprintf.c index c785e12bdf..1c5910e0b2 100644 --- a/libarchive/archive_string_sprintf.c +++ b/libarchive/archive_string_sprintf.c @@ -116,8 +116,14 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, long_flag = '\0'; switch(*p) { - case 'j': case 'l': + if (p[1] == 'l') { + long_flag = 'L'; + p += 2; + break; + } + __LA_FALLTHROUGH; + case 'j': case 'z': long_flag = *p; p++; @@ -136,6 +142,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, switch(long_flag) { case 'j': s = va_arg(ap, intmax_t); break; case 'l': s = va_arg(ap, long); break; + case 'L': s = va_arg(ap, long long); break; case 'z': s = va_arg(ap, ssize_t); break; default: s = va_arg(ap, int); break; } @@ -144,6 +151,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, case 's': switch(long_flag) { case 'l': + case 'L': pw = va_arg(ap, wchar_t *); if (pw == NULL) pw = L"(null)"; @@ -172,6 +180,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt, switch(long_flag) { case 'j': u = va_arg(ap, uintmax_t); break; case 'l': u = va_arg(ap, unsigned long); break; + case 'L': u = va_arg(ap, unsigned long long); break; case 'z': u = va_arg(ap, size_t); break; default: u = va_arg(ap, unsigned int); break; } diff --git a/libarchive/archive_time.c b/libarchive/archive_time.c new file mode 100644 index 0000000000..3352c809bd --- /dev/null +++ b/libarchive/archive_time.c @@ -0,0 +1,163 @@ +/*- + * Copyright © 2025 ARJANEN Loïc Jean David + * 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" +#include "archive_private.h" +#include "archive_time_private.h" +#include +#include +#include + +#define NTFS_EPOC_TIME ARCHIVE_LITERAL_ULL(11644473600) +#define NTFS_TICKS ARCHIVE_LITERAL_ULL(10000000) +#define NTFS_EPOC_TICKS (NTFS_EPOC_TIME * NTFS_TICKS) +#define DOS_MIN_TIME 0x00210000U +#define DOS_MAX_TIME 0xff9fbf7dU + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +/* Windows FILETIME to NTFS time. */ +uint64_t +FILETIME_to_ntfs(const FILETIME* filetime) +{ + ULARGE_INTEGER utc; + utc.HighPart = filetime->dwHighDateTime; + utc.LowPart = filetime->dwLowDateTime; + return utc.QuadPart; +} +#endif + +/* Convert an MSDOS-style date/time into Unix-style time. */ +int64_t +dos_to_unix(uint32_t dos_time) +{ + uint16_t msTime, msDate; + struct tm ts; + time_t t; + + msTime = (0xFFFF & dos_time); + msDate = (dos_time >> 16); + + memset(&ts, 0, sizeof(ts)); + ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */ + ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */ + ts.tm_mday = msDate & 0x1f; /* Day of month. */ + ts.tm_hour = (msTime >> 11) & 0x1f; + ts.tm_min = (msTime >> 5) & 0x3f; + ts.tm_sec = (msTime << 1) & 0x3e; + ts.tm_isdst = -1; + t = mktime(&ts); + return (int64_t)(t == (time_t)-1 ? INT32_MAX : t); +} + +/* Convert into MSDOS-style date/time. */ +uint32_t +unix_to_dos(int64_t unix_time) +{ + struct tm *t; + uint32_t dt; + time_t ut = unix_time; +#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S) + struct tm tmbuf; +#endif + + if (sizeof(time_t) < sizeof(int64_t) && (int64_t)ut != unix_time) { + ut = (time_t)(unix_time > 0 ? INT32_MAX : INT32_MIN); + } + +#if defined(HAVE_LOCALTIME_S) + t = localtime_s(&tmbuf, &ut) ? NULL : &tmbuf; +#elif defined(HAVE_LOCALTIME_R) + t = localtime_r(&ut, &tmbuf); +#else + t = localtime(&ut); +#endif + dt = 0; + if (t != NULL && t->tm_year >= INT_MIN + 80) { + const int year = t->tm_year - 80; + + if (year & ~0x7f) { + dt = year > 0 ? DOS_MAX_TIME : DOS_MIN_TIME; + } + else { + dt += (year & 0x7f) << 9; + dt += ((t->tm_mon + 1) & 0x0f) << 5; + dt += (t->tm_mday & 0x1f); + dt <<= 16; + dt += (t->tm_hour & 0x1f) << 11; + dt += (t->tm_min & 0x3f) << 5; + /* Only counting every 2 seconds. */ + dt += (t->tm_sec & 0x3e) >> 1; + } + } + if (dt > DOS_MAX_TIME) { + dt = DOS_MAX_TIME; + } + else if (dt < DOS_MIN_TIME) { + dt = DOS_MIN_TIME; + } + return dt; +} + +/* Convert NTFS time to Unix sec/nsec */ +void +ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs) +{ + if (ntfs > INT64_MAX) { + ntfs -= NTFS_EPOC_TICKS; + *secs = ntfs / NTFS_TICKS; + *nsecs = 100 * (ntfs % NTFS_TICKS); + } + else { + lldiv_t tdiv; + int64_t value = (int64_t)ntfs - (int64_t)NTFS_EPOC_TICKS; + + tdiv = lldiv(value, NTFS_TICKS); + *secs = tdiv.quot; + *nsecs = (uint32_t)(tdiv.rem * 100); + } +} + +/* Convert Unix sec/nsec to NTFS time */ +uint64_t +unix_to_ntfs(int64_t secs, uint32_t nsecs) +{ + uint64_t ntfs; + + if (secs < -(int64_t)NTFS_EPOC_TIME) + return 0; + + ntfs = secs + NTFS_EPOC_TIME; + + if (ntfs > UINT64_MAX / NTFS_TICKS) + return UINT64_MAX; + + ntfs *= NTFS_TICKS; + + if (ntfs > UINT64_MAX - nsecs/100) + return UINT64_MAX; + + return ntfs + nsecs/100; +} diff --git a/libarchive/archive_getdate.h b/libarchive/archive_time_private.h similarity index 67% rename from libarchive/archive_getdate.h rename to libarchive/archive_time_private.h index cfd49ddf7e..f802607c30 100644 --- a/libarchive/archive_getdate.h +++ b/libarchive/archive_time_private.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2015 Tim Kientzle + * Copyright © 2025 ARJANEN Loïc Jean David * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,16 +22,26 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef ARCHIVE_GETDATE_H_INCLUDED -#define ARCHIVE_GETDATE_H_INCLUDED +#ifndef ARCHIVE_TIME_PRIVATE_H_INCLUDED +#define ARCHIVE_TIME_PRIVATE_H_INCLUDED #ifndef __LIBARCHIVE_BUILD #error This header is only to be used internally to libarchive. #endif +#include -#include - -time_t __archive_get_date(time_t now, const char *); - +/* NTFS time to Unix sec/nsec. */ +void ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs); +/* DOS time to Unix sec. */ +int64_t dos_to_unix(uint32_t dos); +/* Unix sec/nsec to NTFS time. */ +uint64_t unix_to_ntfs(int64_t secs, uint32_t nsecs); +/* Unix sec to DOS time. */ +uint32_t unix_to_dos(int64_t secs); +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#include +/* Windows FILETIME to NTFS time. */ +uint64_t FILETIME_to_ntfs(const FILETIME* filetime); #endif +#endif /* ARCHIVE_TIME_PRIVATE_H_INCLUDED */ diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c index 3a8caad526..900abd0c3c 100644 --- a/libarchive/archive_util.c +++ b/libarchive/archive_util.c @@ -77,7 +77,9 @@ #define O_CLOEXEC 0 #endif -static int archive_utility_string_sort_helper(char **, unsigned int); +#if ARCHIVE_VERSION_NUMBER < 4000000 +static int __LA_LIBC_CC archive_utility_string_sort_helper(const void *, const void *); +#endif /* Generic initialization of 'struct archive' objects. */ int @@ -629,74 +631,28 @@ __archive_ensure_cloexec_flag(int fd) #endif } +#if ARCHIVE_VERSION_NUMBER < 4000000 /* - * Utility function to sort a group of strings using quicksort. + * Utility functions to sort a group of strings using quicksort. */ static int -archive_utility_string_sort_helper(char **strings, unsigned int n) +__LA_LIBC_CC +archive_utility_string_sort_helper(const void *p1, const void *p2) { - unsigned int i, lesser_count, greater_count; - char **lesser, **greater, **tmp, *pivot; - int retval1, retval2; + const char * const * const s1 = p1; + const char * const * const s2 = p2; - /* A list of 0 or 1 elements is already sorted */ - if (n <= 1) - return (ARCHIVE_OK); - - lesser_count = greater_count = 0; - lesser = greater = NULL; - pivot = strings[0]; - for (i = 1; i < n; i++) - { - if (strcmp(strings[i], pivot) < 0) - { - lesser_count++; - tmp = realloc(lesser, lesser_count * sizeof(*tmp)); - if (!tmp) { - free(greater); - free(lesser); - return (ARCHIVE_FATAL); - } - lesser = tmp; - lesser[lesser_count - 1] = strings[i]; - } - else - { - greater_count++; - tmp = realloc(greater, greater_count * sizeof(*tmp)); - if (!tmp) { - free(greater); - free(lesser); - return (ARCHIVE_FATAL); - } - greater = tmp; - greater[greater_count - 1] = strings[i]; - } - } - - /* quicksort(lesser) */ - retval1 = archive_utility_string_sort_helper(lesser, lesser_count); - for (i = 0; i < lesser_count; i++) - strings[i] = lesser[i]; - free(lesser); - - /* pivot */ - strings[lesser_count] = pivot; - - /* quicksort(greater) */ - retval2 = archive_utility_string_sort_helper(greater, greater_count); - for (i = 0; i < greater_count; i++) - strings[lesser_count + 1 + i] = greater[i]; - free(greater); - - return (retval1 < retval2) ? retval1 : retval2; + return strcmp(*s1, *s2); } int archive_utility_string_sort(char **strings) { - unsigned int size = 0; - while (strings[size] != NULL) + size_t size = 0; + while (strings[size] != NULL) size++; - return archive_utility_string_sort_helper(strings, size); + qsort(strings, size, sizeof(char *), + archive_utility_string_sort_helper); + return (ARCHIVE_OK); } +#endif diff --git a/libarchive/archive_version_details.c b/libarchive/archive_version_details.c index 29be24f322..0cf92db731 100644 --- a/libarchive/archive_version_details.c +++ b/libarchive/archive_version_details.c @@ -46,11 +46,125 @@ #endif #ifdef HAVE_ZSTD_H #include +#include +#endif +#ifdef HAVE_LZO_LZOCONF_H +#include +#endif +#if HAVE_LIBXML_XMLVERSION_H +#include +#elif HAVE_BSDXML_H +#include +#elif HAVE_EXPAT_H +#include +#endif +#if HAVE_MBEDTLS_VERSION_H +#include +#endif +#if HAVE_NETTLE_VERSION_H +#include +#include +#endif +#if HAVE_OPENSSL_OPENSSLV_H +#include +#include +#endif +#if HAVE_ICONV_H +#include +#endif +#if HAVE_PCRE_H +#include +#endif +#if HAVE_PCRE2_H +#include #endif #include "archive.h" #include "archive_private.h" #include "archive_string.h" +#include "archive_cryptor_private.h" +#include "archive_digest_private.h" + +static void +archive_regex_version(struct archive_string* str) +{ +#if HAVE_LIBPCREPOSIX && HAVE_PCRE_H + archive_strcat(str, " libpcre/"); + archive_strcat(str, archive_libpcre_version()); +#elif HAVE_LIBPCRE2POSIX && HAVE_PCRE2_H + archive_strcat(str, " libpcre2/"); + archive_strcat(str, archive_libpcre2_version()); +#else + (void)str; /* UNUSED */ +#endif +} + +static void +archive_xml_version(struct archive_string* str) +{ +#if HAVE_LIBXML_XMLVERSION_H && HAVE_LIBXML2 + archive_strcat(str, " libxml2/"); + archive_strcat(str, archive_libxml2_version()); +#elif HAVE_BSDXML_H && HAVE_LIBBSDXML + archive_strcat(str, " bsdxml/"); + archive_strcat(str, archive_libbsdxml_version()); +#elif HAVE_EXPAT_H && HAVE_LIBEXPAT + archive_strcat(str, " expat/"); + archive_strcat(str, archive_libexpat_version()); +#else + (void)str; /* UNUSED */ +#endif +} + +static void +archive_libb2_version(struct archive_string* str) +{ + archive_strcat(str, " libb2/"); +#if HAVE_BLAKE2_H && HAVE_LIBB2 +#if defined(LIBB2_PKGCONFIG_VERSION) + archive_strcat(str, LIBB2_PKGCONFIG_VERSION); +#else + archive_strcat(str, "system"); +#endif +#else + archive_strcat(str, "bundled"); +#endif +} + +static void +archive_crypto_version(struct archive_string* str) +{ +#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto) + archive_strcat(str, " CommonCrypto/"); + archive_strcat(str, archive_commoncrypto_version()); +#endif +#if defined(ARCHIVE_CRYPTOR_USE_CNG) + archive_strcat(str, " cng/"); + archive_strcat(str, archive_cng_version()); +#endif +#if defined(ARCHIVE_CRYPTOR_USE_MBED) + archive_strcat(str, " mbedtls/"); + archive_strcat(str, archive_mbedtls_version()); +#endif +#if defined(ARCHIVE_CRYPTOR_USE_NETTLE) + archive_strcat(str, " nettle/"); + archive_strcat(str, archive_nettle_version()); +#endif +#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL) + archive_strcat(str, " openssl/"); + archive_strcat(str, archive_openssl_version()); +#endif +#if defined(ARCHIVE_CRYPTOR_USE_LIBMD) + archive_strcat(str, " libmd/"); + archive_strcat(str, archive_libmd_version()); +#endif +#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT) + archive_strcat(str, " WinCrypt/"); + archive_strcat(str, archive_wincrypt_version()); +#endif + // Just in case + (void)str; /* UNUSED */ +} const char * archive_version_details(void) @@ -62,12 +176,17 @@ archive_version_details(void) const char *bzlib = archive_bzlib_version(); const char *liblz4 = archive_liblz4_version(); const char *libzstd = archive_libzstd_version(); + const char *liblzo = archive_liblzo2_version(); + const char *libiconv = archive_libiconv_version(); + const char *libacl = archive_libacl_version(); + const char *librichacl = archive_librichacl_version(); + const char *libattr = archive_libacl_version(); if (!init) { archive_string_init(&str); archive_strcat(&str, ARCHIVE_VERSION_STRING); - if (zlib != NULL) { + if (zlib) { archive_strcat(&str, " zlib/"); archive_strcat(&str, zlib); } @@ -91,6 +210,30 @@ archive_version_details(void) archive_strcat(&str, " libzstd/"); archive_strcat(&str, libzstd); } + if (liblzo) { + archive_strcat(&str, " liblzo2/"); + archive_strcat(&str, liblzo); + } + archive_xml_version(&str); + archive_regex_version(&str); + archive_crypto_version(&str); + archive_libb2_version(&str); + if (librichacl) { + archive_strcat(&str, " librichacl/"); + archive_strcat(&str, librichacl); + } + if (libacl) { + archive_strcat(&str, " libacl/"); + archive_strcat(&str, libacl); + } + if (libattr) { + archive_strcat(&str, " libattr/"); + archive_strcat(&str, libattr); + } + if (libiconv) { + archive_strcat(&str, " libiconv/"); + archive_strcat(&str, libiconv); + } } return str.s; } @@ -98,8 +241,8 @@ archive_version_details(void) const char * archive_zlib_version(void) { -#ifdef HAVE_ZLIB_H - return ZLIB_VERSION; +#if HAVE_ZLIB_H && HAVE_LIBZ + return zlibVersion(); #else return NULL; #endif @@ -108,8 +251,8 @@ archive_zlib_version(void) const char * archive_liblzma_version(void) { -#ifdef HAVE_LZMA_H - return LZMA_VERSION_STRING; +#if HAVE_LZMA_H && HAVE_LIBLZMA + return lzma_version_string(); #else return NULL; #endif @@ -118,7 +261,7 @@ archive_liblzma_version(void) const char * archive_bzlib_version(void) { -#ifdef HAVE_BZLIB_H +#if HAVE_BZLIB_H && HAVE_LIBBZ2 return BZ2_bzlibVersion(); #else return NULL; @@ -128,12 +271,22 @@ archive_bzlib_version(void) const char * archive_liblz4_version(void) { -#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4) +#if HAVE_LZ4_H && HAVE_LIBLZ4 +#if LZ4_VERSION_NUMBER > 10705 + return LZ4_versionString(); +#elif LZ4_VERSION_NUMBER > 10300 + div_t major = div(LZ4_versionNumber(), 10000); + div_t minor = div(major.rem, 100); + static char lz4_version[9]; + snprintf(lz4_version, 9, "%d.%d.%d", major.quot, minor.quot, minor.rem); + return lz4_version; +#else #define str(s) #s #define NUMBER(x) str(x) return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE); #undef NUMBER #undef str +#endif #else return NULL; #endif @@ -143,7 +296,243 @@ const char * archive_libzstd_version(void) { #if HAVE_ZSTD_H && HAVE_LIBZSTD - return ZSTD_VERSION_STRING; +#if ZSTD_VERSION_NUMBER > 10300 + return ZSTD_versionString(); +#else + div_t major = div(ZSTD_versionNumber(), 10000); + div_t minor = div(major.rem, 100); + static char zstd_version[9]; + snprintf(zstd_version, 9, "%d.%d.%d", major.quot, minor.quot, minor.rem); + return zstd_version; +#endif +#else + return NULL; +#endif +} + +const char * +archive_liblzo2_version(void) +{ +#if HAVE_LZO_LZOCONF_H && HAVE_LIBLZO2 + return LZO_VERSION_STRING; +#else + return NULL; +#endif +} + +const char * +archive_libbsdxml_version(void) +{ +#if HAVE_BSDXML_H && HAVE_LIBBSDXML + return XML_ExpatVersion(); +#else + return NULL; +#endif +} + +const char * +archive_libxml2_version(void) +{ +#if HAVE_LIBXML_XMLREADER_H && HAVE_LIBXML2 + return LIBXML_DOTTED_VERSION; +#else + return NULL; +#endif +} + +const char * +archive_libexpat_version(void) +{ +#if HAVE_EXPAT_H && HAVE_LIBEXPAT + return XML_ExpatVersion(); +#else + return NULL; +#endif +} + +const char * +archive_mbedtls_version(void) +{ +#if defined(ARCHIVE_CRYPTOR_USE_MBED) || defined(ARCHIVE_CRYPTO_MBED) + static char mbed_version[9]; + mbedtls_version_get_string(mbed_version); + return mbed_version; +#else + return NULL; +#endif +} + +const char * +archive_nettle_version(void) +{ +#if defined(ARCHIVE_CRYPTOR_USE_NETTLE) || defined(ARCHIVE_CRYPTO_NETTLE) + static char nettle_version[6]; + snprintf(nettle_version, 6, "%d.%d", nettle_version_major(), nettle_version_minor()); + return nettle_version; +#else + return NULL; +#endif +} + +const char * +archive_openssl_version(void) +{ +#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL) || defined(ARCHIVE_CRYPTO_OPENSSL) +#ifdef OPENSSL_VERSION_STR + return OPENSSL_VERSION_STR; +#else +#define OPENSSL_MAJOR (OPENSSL_VERSION_NUMBER >> 28) +#define OPENSSL_MINOR ((OPENSSL_VERSION_NUMBER >> 20) & 0xFF) + static char openssl_version[6]; + snprintf(openssl_version, 6, "%ld.%ld", OPENSSL_MAJOR, OPENSSL_MINOR); + return openssl_version; +#undef OPENSSL_MAJOR +#undef OPENSSL_MINOR +#endif +#else + return NULL; +#endif +} + +const char * +archive_libmd_version(void) +{ +#if defined(ARCHIVE_CRYPTOR_USE_LIBMD) || defined(ARCHIVE_CRYPTO_LIBMD) + return "system"; +#else + return NULL; +#endif +} + +const char * +archive_commoncrypto_version(void) +{ +#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto) || defined(ARCHIVE_CRYPTO_CommonCrypto) + return "system"; +#else + return NULL; +#endif +} + +const char * +archive_cng_version(void) +{ +#if defined(ARCHIVE_CRYPTOR_USE_CNG) || defined(ARCHIVE_CRYPTO_CNG) +#ifdef BCRYPT_HASH_INTERFACE_MAJORVERSION_2 + return "2.0"; +#else + return "1.0"; +#endif +#else + return NULL; +#endif +} + +const char * +archive_wincrypt_version(void) +{ +#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT) || defined(ARCHIVE_CRYPTO_WINCRYPT) + HCRYPTPROV prov; + if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + if (GetLastError() != (DWORD)NTE_BAD_KEYSET) + return NULL; + if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + return NULL; + } + DWORD version, length = sizeof(version); + if (!CryptGetProvParam(prov, PP_VERSION, (BYTE *)&version, &length, 0)) { + return NULL; + } else { + char major = (version >> 8) & 0xFF; + char minor = version & 0xFF; + static char wincrypt_version[6]; + snprintf(wincrypt_version, 6, "%hhd.%hhd", major, minor); + return wincrypt_version; + } +#else + return NULL; +#endif +} + +const char * +archive_librichacl_version(void) +{ +#if HAVE_LIBRICHACL +#if defined(LIBRICHACL_PKGCONFIG_VERSION) + return LIBRICHACL_PKGCONFIG_VERSION; +#else + return "system"; +#endif +#else + return NULL; +#endif +} + +const char * +archive_libacl_version(void) +{ +#if HAVE_LIBACL +#if defined(LIBACL_PKGCONFIG_VERSION) + return LIBACL_PKGCONFIG_VERSION; +#else + return "system"; +#endif +#else + return NULL; +#endif +} + +const char * +archive_libattr_version(void) +{ +#if HAVE_LIBATTR +#if defined(LIBATTR_PKGCONFIG_VERSION) + return LIBATTR_PKGCONFIG_VERSION; +#else + return "system"; +#endif +#else + return NULL; +#endif +} + +const char * +archive_libiconv_version(void) +{ +#if HAVE_LIBCHARSET && HAVE_ICONV_H + char major = _libiconv_version >> 8; + char minor = _libiconv_version & 0xFF; + static char charset_version[6]; + snprintf(charset_version, 6, "%hhd.%hhd", major, minor); + return charset_version; +#else + return NULL; +#endif +} + +const char * +archive_libpcre_version(void) +{ +#if HAVE_LIBPCREPOSIX && HAVE_PCRE_H +#define str(s) #s +#define NUMBER(x) str(x) + return NUMBER(PCRE_MAJOR) "." NUMBER(PCRE_MINOR); +#undef NUMBER +#undef str +#else + return NULL; +#endif +} + +const char * +archive_libpcre2_version(void) +{ +#if HAVE_LIBPCRE2POSIX && HAVE_PCRE2_H +#define str(s) #s +#define NUMBER(x) str(x) + return NUMBER(PCRE2_MAJOR) "." NUMBER(PCRE2_MINOR); +#undef NUMBER +#undef str #else return NULL; #endif diff --git a/libarchive/archive_windows.c b/libarchive/archive_windows.c index bb540da011..03c9736c06 100644 --- a/libarchive/archive_windows.c +++ b/libarchive/archive_windows.c @@ -47,6 +47,7 @@ #include "archive_platform.h" #include "archive_private.h" #include "archive_entry.h" +#include "archive_time_private.h" #include #include #include @@ -61,8 +62,6 @@ #include #include -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) - #if defined(__LA_LSEEK_NEEDED) static BOOL SetFilePointerEx_perso(HANDLE hFile, LARGE_INTEGER liDistanceToMove, @@ -450,24 +449,6 @@ __la_read(int fd, void *buf, size_t nbytes) return ((ssize_t)bytes_read); } -/* Convert Windows FILETIME to UTC */ -__inline static void -fileTimeToUTC(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - *t = (time_t)(utc.QuadPart / 10000000); /* milli seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100;/* nano seconds base */ - } else { - *t = 0; - *ns = 0; - } -} - /* Stat by handle * Windows' stat() does not accept the path added "\\?\" especially "?" * character. @@ -487,8 +468,6 @@ __hstat(HANDLE handle, struct ustat *st) ULARGE_INTEGER ino64; DWORD ftype; mode_t mode; - time_t t; - long ns; switch (ftype = GetFileType(handle)) { case FILE_TYPE_UNKNOWN: @@ -544,15 +523,9 @@ __hstat(HANDLE handle, struct ustat *st) mode |= S_IFREG; st->st_mode = mode; - fileTimeToUTC(&info.ftLastAccessTime, &t, &ns); - st->st_atime = t; - st->st_atime_nsec = ns; - fileTimeToUTC(&info.ftLastWriteTime, &t, &ns); - st->st_mtime = t; - st->st_mtime_nsec = ns; - fileTimeToUTC(&info.ftCreationTime, &t, &ns); - st->st_ctime = t; - st->st_ctime_nsec = ns; + ntfs_to_unix(FILETIME_to_ntfs(&info.ftLastAccessTime), &st->st_atime, &st->st_atime_nsec); + ntfs_to_unix(FILETIME_to_ntfs(&info.ftLastWriteTime), &st->st_mtime, &st->st_mtime_nsec); + ntfs_to_unix(FILETIME_to_ntfs(&info.ftCreationTime), &st->st_ctime, &st->st_ctime_nsec); st->st_size = ((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1)) + (int64_t)(info.nFileSizeLow); diff --git a/libarchive/archive_windows.h b/libarchive/archive_windows.h index 14909da162..4dc8c2b3ad 100644 --- a/libarchive/archive_windows.h +++ b/libarchive/archive_windows.h @@ -315,4 +315,4 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER { # endif #endif -#endif /* LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */ +#endif /* !LIBARCHIVE_ARCHIVE_WINDOWS_H_INCLUDED */ diff --git a/libarchive/archive_write.c b/libarchive/archive_write.c index 303c686881..a8e7b63b5b 100644 --- a/libarchive/archive_write.c +++ b/libarchive/archive_write.c @@ -283,7 +283,7 @@ __archive_write_filters_open(struct archive_write *a) } /* - * Close all filtes + * Close all filters */ static int __archive_write_filters_close(struct archive_write *a) diff --git a/libarchive/archive_write_add_filter_gzip.c b/libarchive/archive_write_add_filter_gzip.c index 71d7891261..5ef43c1936 100644 --- a/libarchive/archive_write_add_filter_gzip.c +++ b/libarchive/archive_write_add_filter_gzip.c @@ -58,6 +58,7 @@ archive_write_set_compression_gzip(struct archive *a) struct private_data { int compression_level; int timestamp; + char *original_filename; #ifdef HAVE_ZLIB_H z_stream stream; int64_t total_in; @@ -113,6 +114,8 @@ archive_write_add_filter_gzip(struct archive *_a) f->free = &archive_compressor_gzip_free; f->code = ARCHIVE_FILTER_GZIP; f->name = "gzip"; + + data->original_filename = NULL; #ifdef HAVE_ZLIB_H data->compression_level = Z_DEFAULT_COMPRESSION; return (ARCHIVE_OK); @@ -140,6 +143,7 @@ archive_compressor_gzip_free(struct archive_write_filter *f) #else __archive_write_program_free(data->pdata); #endif + free((void*)data->original_filename); free(data); f->data = NULL; return (ARCHIVE_OK); @@ -165,6 +169,13 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key, data->timestamp = (value == NULL)?-1:1; return (ARCHIVE_OK); } + if (strcmp(key, "original-filename") == 0) { + free((void*)data->original_filename); + data->original_filename = NULL; + if (value) + data->original_filename = strdup(value); + return (ARCHIVE_OK); + } /* Note: The "warn" return is just to inform the options * supervisor that we didn't handle it. It will generate @@ -210,7 +221,7 @@ archive_compressor_gzip_open(struct archive_write_filter *f) data->compressed[0] = 0x1f; /* GZip signature bytes */ data->compressed[1] = 0x8b; data->compressed[2] = 0x08; /* "Deflate" compression */ - data->compressed[3] = 0; /* No options */ + data->compressed[3] = data->original_filename == NULL ? 0 : 0x8; if (data->timestamp >= 0) { time_t t = time(NULL); data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */ @@ -229,6 +240,12 @@ archive_compressor_gzip_open(struct archive_write_filter *f) data->stream.next_out += 10; data->stream.avail_out -= 10; + if (data->original_filename != NULL) { + strcpy((char*)data->compressed + 10, data->original_filename); + data->stream.next_out += strlen(data->original_filename) + 1; + data->stream.avail_out -= strlen(data->original_filename) + 1; + } + f->write = archive_compressor_gzip_write; /* Initialize compression library. */ diff --git a/libarchive/archive_write_disk_windows.c b/libarchive/archive_write_disk_windows.c index b42fc7d357..c7339c4ec1 100644 --- a/libarchive/archive_write_disk_windows.c +++ b/libarchive/archive_write_disk_windows.c @@ -60,6 +60,7 @@ #include "archive_string.h" #include "archive_entry.h" #include "archive_private.h" +#include "archive_time_private.h" #ifndef O_BINARY #define O_BINARY 0 @@ -407,7 +408,11 @@ permissive_name_w(struct archive_write_disk *a) wn = _wcsdup(wnp); if (wn == NULL) return (-1); - archive_wstring_ensure(&(a->_name_data), 4 + wcslen(wn) + 1); + if (archive_wstring_ensure(&(a->_name_data), + 4 + wcslen(wn) + 1) == NULL) { + free(wn); + return (-1); + } a->name = a->_name_data.s; /* Prepend "\\?\" */ archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); @@ -437,8 +442,11 @@ permissive_name_w(struct archive_write_disk *a) wn = _wcsdup(wnp); if (wn == NULL) return (-1); - archive_wstring_ensure(&(a->_name_data), - 8 + wcslen(wn) + 1); + if (archive_wstring_ensure(&(a->_name_data), + 8 + wcslen(wn) + 1) == NULL) { + free(wn); + return (-1); + } a->name = a->_name_data.s; /* Prepend "\\?\UNC\" */ archive_wstrncpy(&(a->_name_data), @@ -470,10 +478,16 @@ permissive_name_w(struct archive_write_disk *a) */ if (wnp[0] == L'\\') { wn = _wcsdup(wnp); - if (wn == NULL) + if (wn == NULL) { + free(wsp); return (-1); - archive_wstring_ensure(&(a->_name_data), - 4 + 2 + wcslen(wn) + 1); + } + if (archive_wstring_ensure(&(a->_name_data), + 4 + 2 + wcslen(wn) + 1) == NULL) { + free(wsp); + free(wn); + return (-1); + } a->name = a->_name_data.s; /* Prepend "\\?\" and drive name. */ archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4); @@ -485,9 +499,16 @@ permissive_name_w(struct archive_write_disk *a) } wn = _wcsdup(wnp); - if (wn == NULL) + if (wn == NULL) { + free(wsp); return (-1); - archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1); + } + if (archive_wstring_ensure(&(a->_name_data), + 4 + l + 1 + wcslen(wn) + 1) == NULL) { + free(wsp); + free(wn); + return (-1); + } a->name = a->_name_data.s; /* Prepend "\\?\" and drive name if not already added. */ if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' && @@ -637,7 +658,7 @@ la_CreateHardLinkW(wchar_t *linkname, wchar_t *target) } /* - * Create file or directory symolic link + * Create file or directory symbolic link * * If linktype is AE_SYMLINK_TYPE_UNDEFINED (or unknown), guess linktype from * the link target @@ -2605,10 +2626,6 @@ set_times(struct archive_write_disk *a, time_t mtime, long mtime_nanos, time_t ctime_sec, long ctime_nanos) { -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -#define WINTIME(sec, nsec) (((sec * 10000000LL) + EPOC_TIME)\ - + ((nsec)/100)) - HANDLE hw = 0; ULARGE_INTEGER wintm; FILETIME *pfbtime; @@ -2646,17 +2663,17 @@ set_times(struct archive_write_disk *a, h = hw; } - wintm.QuadPart = WINTIME(atime, atime_nanos); + wintm.QuadPart = unix_to_ntfs(atime, atime_nanos); fatime.dwLowDateTime = wintm.LowPart; fatime.dwHighDateTime = wintm.HighPart; - wintm.QuadPart = WINTIME(mtime, mtime_nanos); + wintm.QuadPart = unix_to_ntfs(mtime, mtime_nanos); fmtime.dwLowDateTime = wintm.LowPart; fmtime.dwHighDateTime = wintm.HighPart; /* * SetFileTime() supports birthtime. */ if (birthtime > 0 || birthtime_nanos > 0) { - wintm.QuadPart = WINTIME(birthtime, birthtime_nanos); + wintm.QuadPart = unix_to_ntfs(birthtime, birthtime_nanos); fbtime.dwLowDateTime = wintm.LowPart; fbtime.dwHighDateTime = wintm.HighPart; pfbtime = &fbtime; @@ -2878,34 +2895,16 @@ set_xattrs(struct archive_write_disk *a) return (ARCHIVE_OK); } -static void -fileTimeToUtc(const FILETIME *filetime, time_t *t, long *ns) -{ - ULARGE_INTEGER utc; - - utc.HighPart = filetime->dwHighDateTime; - utc.LowPart = filetime->dwLowDateTime; - if (utc.QuadPart >= EPOC_TIME) { - utc.QuadPart -= EPOC_TIME; - /* milli seconds base */ - *t = (time_t)(utc.QuadPart / 10000000); - /* nano seconds base */ - *ns = (long)(utc.QuadPart % 10000000) * 100; - } else { - *t = 0; - *ns = 0; - } -} /* * Test if file on disk is older than entry. */ static int older(BY_HANDLE_FILE_INFORMATION *st, struct archive_entry *entry) { - time_t sec; - long nsec; + int64_t sec; + uint32_t nsec; - fileTimeToUtc(&st->ftLastWriteTime, &sec, &nsec); + ntfs_to_unix(FILETIME_to_ntfs(&st->ftLastWriteTime), &sec, &nsec); /* First, test the seconds and return if we have a definite answer. */ /* Definitely older. */ if (sec < archive_entry_mtime(entry)) @@ -2913,11 +2912,10 @@ older(BY_HANDLE_FILE_INFORMATION *st, struct archive_entry *entry) /* Definitely younger. */ if (sec > archive_entry_mtime(entry)) return (0); - if (nsec < archive_entry_mtime_nsec(entry)) + if ((long)nsec < archive_entry_mtime_nsec(entry)) return (1); /* Same age or newer, so not older. */ return (0); } #endif /* _WIN32 && !__CYGWIN__ */ - diff --git a/libarchive/archive_write_set_format_7zip.c b/libarchive/archive_write_set_format_7zip.c index b870338fc0..902d03f6a8 100644 --- a/libarchive/archive_write_set_format_7zip.c +++ b/libarchive/archive_write_set_format_7zip.c @@ -28,7 +28,12 @@ #ifdef HAVE_ERRNO_H #include #endif +#ifdef HAVE_STDLIB_H #include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif #ifdef HAVE_BZLIB_H #include #endif @@ -38,6 +43,9 @@ #ifdef HAVE_ZLIB_H #include #endif +#ifdef HAVE_ZSTD_H +#include +#endif #include "archive.h" #ifndef HAVE_ZLIB_H @@ -50,6 +58,7 @@ #include "archive_private.h" #include "archive_rb.h" #include "archive_string.h" +#include "archive_time_private.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h" @@ -63,6 +72,8 @@ #define _7Z_BZIP2 0x040202 #define _7Z_PPMD 0x030401 +#define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */ + /* * 7-Zip header property IDs. */ @@ -110,6 +121,9 @@ // the attr field along with the unix permissions. #define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 +// Many systems define min or MIN, but not all. +#define sevenzipmin(a,b) ((a) < (b) ? (a) : (b)) + enum la_zaction { ARCHIVE_Z_FINISH, ARCHIVE_Z_RUN @@ -209,7 +223,11 @@ struct _7zip { #define ENCODED_CRC32 2 unsigned opt_compression; + int opt_compression_level; + int opt_zstd_compression_level; // This requires a different default value. + + int opt_threads; struct la_zstream stream; struct coder coder; @@ -285,12 +303,19 @@ static int compression_code_lzma(struct archive *, static int compression_end_lzma(struct archive *, struct la_zstream *); #endif static int compression_init_encoder_ppmd(struct archive *, - struct la_zstream *, unsigned, uint32_t); + struct la_zstream *, uint8_t, uint32_t); static int compression_code_ppmd(struct archive *, struct la_zstream *, enum la_zaction); static int compression_end_ppmd(struct archive *, struct la_zstream *); static int _7z_compression_init_encoder(struct archive_write *, unsigned, int); +static int compression_init_encoder_zstd(struct archive *, + struct la_zstream *, int, int); +#if defined(HAVE_ZSTD_H) +static int compression_code_zstd(struct archive *, + struct la_zstream *, enum la_zaction); +static int compression_end_zstd(struct archive *, struct la_zstream *); +#endif static int compression_code(struct archive *, struct la_zstream *, enum la_zaction); static int compression_end(struct archive *, @@ -301,6 +326,21 @@ static int make_header(struct archive_write *, uint64_t, uint64_t, static int make_streamsInfo(struct archive_write *, uint64_t, uint64_t, uint64_t, int, struct coder *, int, uint32_t); +static int +string_to_number(const char *string, intmax_t *numberp) +{ + char *end; + + if (string == NULL || *string == '\0') + return (ARCHIVE_WARN); + *numberp = strtoimax(string, &end, 10); + if (end == string || *end != '\0' || errno == EOVERFLOW) { + *numberp = 0; + return (ARCHIVE_WARN); + } + return (ARCHIVE_OK); +} + int archive_write_set_format_7zip(struct archive *_a) { @@ -335,11 +375,24 @@ archive_write_set_format_7zip(struct archive *_a) zip->opt_compression = _7Z_BZIP2; #elif defined(HAVE_ZLIB_H) zip->opt_compression = _7Z_DEFLATE; +#elif HAVE_ZSTD_H + zip->opt_compression = _7Z_ZSTD; #else zip->opt_compression = _7Z_COPY; #endif + zip->opt_compression_level = 6; +#ifdef ZSTD_CLEVEL_DEFAULT + // Zstandard compression needs a different default + // value than other encoders. + zip->opt_zstd_compression_level = ZSTD_CLEVEL_DEFAULT; +#else + zip->opt_zstd_compression_level = 3; +#endif + + zip->opt_threads = 1; + a->format_data = zip; a->format_name = "7zip"; @@ -397,6 +450,13 @@ _7z_options(struct archive_write *a, const char *key, const char *value) zip->opt_compression = _7Z_LZMA2; #else name = "lzma2"; +#endif + else if (strcmp(value, "zstd") == 0 || + strcmp(value, "ZSTD") == 0) +#if HAVE_ZSTD_H + zip->opt_compression = _7Z_ZSTD; +#else + name = "zstd"; #endif else if (strcmp(value, "ppmd") == 0 || strcmp(value, "PPMD") == 0 || @@ -420,16 +480,68 @@ _7z_options(struct archive_write *a, const char *key, const char *value) return (ARCHIVE_OK); } if (strcmp(key, "compression-level") == 0) { - if (value == NULL || - !(value[0] >= '0' && value[0] <= '9') || - value[1] != '\0') { - archive_set_error(&(a->archive), - ARCHIVE_ERRNO_MISC, - "Illegal value `%s'", - value); + if (value == NULL || *value == '\0') { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "Invalid compression-level option value `%s'", value); return (ARCHIVE_FAILED); } - zip->opt_compression_level = value[0] - '0'; + + char *end = NULL; + long lvl = strtol(value, &end, 10); + if (end == NULL || *end != '\0') { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "parsing compression-level option value failed `%s'", value); + return (ARCHIVE_FAILED); + } + +#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream && HAVE_ZSTD_minCLevel + int min_level = sevenzipmin(0, ZSTD_minCLevel()); +#else + const int min_level = 0; +#endif + +#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream + int max_level = ZSTD_maxCLevel(); +#else + const int max_level = 9; +#endif + + if (lvl < min_level || lvl > max_level) { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "compression-level option value `%ld' out of range", lvl); + return (ARCHIVE_FAILED); + } + + // Note: we don't know here if this value is for zstd (negative to ~22), + // or zlib-style 0-9. If zstd is enabled but not in use, we will need to + // validate opt_compression_level before use. + zip->opt_compression_level = (int)lvl; + + zip->opt_zstd_compression_level = (int)lvl; + return (ARCHIVE_OK); + } + if (strcmp(key, "threads") == 0) { + intmax_t threads; + if (string_to_number(value, &threads) != ARCHIVE_OK) { + return (ARCHIVE_WARN); + } + if (threads < 0) { + return (ARCHIVE_WARN); + } + if (threads == 0) { +#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) + threads = sysconf(_SC_NPROCESSORS_ONLN); +#elif !defined(__CYGWIN__) && defined(_WIN32_WINNT) && \ + _WIN32_WINNT >= 0x0601 /* _WIN32_WINNT_WIN7 */ + DWORD winCores = GetActiveProcessorCount( + ALL_PROCESSOR_GROUPS); + threads = (intmax_t)winCores; +#else + threads = 1; +#endif + } + + zip->opt_threads = (int)threads; return (ARCHIVE_OK); } @@ -495,8 +607,20 @@ _7z_write_header(struct archive_write *a, struct archive_entry *entry) * Init compression. */ if ((zip->total_number_entry - zip->total_number_empty_entry) == 1) { - r = _7z_compression_init_encoder(a, zip->opt_compression, - zip->opt_compression_level); + + int level = zip->opt_compression_level; +#if HAVE_ZSTD_H + if (zip->opt_compression == _7Z_ZSTD) { + level = zip->opt_zstd_compression_level; + } else if (level < 0 || level > 9) { + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "compression-level option value `%d' out of range 0-9", level); + file_free(file); + return (ARCHIVE_FATAL); + } +#endif + + r = _7z_compression_init_encoder(a, zip->opt_compression, level); if (r < 0) { file_free(file); return (ARCHIVE_FATAL); @@ -785,8 +909,12 @@ _7z_close(struct archive_write *a) #else header_compression = _7Z_COPY; #endif - r = _7z_compression_init_encoder(a, header_compression, - zip->opt_compression_level); + + int level = zip->opt_compression_level; + if (level < 0) level = 0; + else if (level > 9) level = 9; + + r = _7z_compression_init_encoder(a, header_compression, level); if (r < 0) return (r); zip->crc32flg = PRECODE_CRC32; @@ -844,7 +972,7 @@ _7z_close(struct archive_write *a) header_offset = header_size = 0; header_crc32 = 0; } - + length = zip->temp_offset; /* @@ -1164,20 +1292,6 @@ make_streamsInfo(struct archive_write *a, uint64_t offset, uint64_t pack_size, return (ARCHIVE_OK); } - -#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000) -static uint64_t -utcToFiletime(time_t t, long ns) -{ - uint64_t fileTime; - - fileTime = t; - fileTime *= 10000000; - fileTime += ns / 100; - fileTime += EPOC_TIME; - return (fileTime); -} - static int make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti) { @@ -1249,7 +1363,6 @@ make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti) if (r < 0) return (r); - /* * Make Times. */ @@ -1257,7 +1370,7 @@ make_time(struct archive_write *a, uint8_t type, unsigned flg, int ti) for (;file != NULL; file = file->next) { if ((file->flg & flg) == 0) continue; - archive_le64enc(filetime, utcToFiletime(file->times[ti].time, + archive_le64enc(filetime, unix_to_ntfs(file->times[ti].time, file->times[ti].time_ns)); r = (int)compress_out(a, filetime, 8, ARCHIVE_Z_RUN); if (r < 0) @@ -1504,7 +1617,7 @@ file_cmp_node(const struct archive_rb_node *n1, return (memcmp(f1->utf16name, f2->utf16name, f1->name_len)); return (f1->name_len > f2->name_len)?1:-1; } - + static int file_cmp_key(const struct archive_rb_node *n, const void *key) { @@ -1646,7 +1759,8 @@ file_init_register_empty(struct _7zip *zip) } #if !defined(HAVE_ZLIB_H) || !defined(HAVE_BZLIB_H) ||\ - !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H) + !defined(BZ_CONFIG_ERROR) || !defined(HAVE_LZMA_H) ||\ + !(HAVE_ZSTD_H && HAVE_ZSTD_compressStream) static int compression_unsupported_encoder(struct archive *a, struct la_zstream *lastrm, const char *name) @@ -2159,7 +2273,7 @@ ppmd_write(void *p, Byte b) static int compression_init_encoder_ppmd(struct archive *a, - struct la_zstream *lastrm, unsigned maxOrder, uint32_t msize) + struct la_zstream *lastrm, uint8_t maxOrder, uint32_t msize) { struct ppmd_stream *strm; uint8_t *props; @@ -2279,6 +2393,117 @@ compression_end_ppmd(struct archive *a, struct la_zstream *lastrm) return (ARCHIVE_OK); } +#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream +static int +compression_init_encoder_zstd(struct archive *a, struct la_zstream *lastrm, int level, int threads) +{ + if (lastrm->valid) + compression_end(a, lastrm); + + ZSTD_CStream *strm = ZSTD_createCStream(); + if (strm == NULL) { + archive_set_error(a, ENOMEM, + "Can't allocate memory for zstd stream"); + return (ARCHIVE_FATAL); + } + + if (ZSTD_isError(ZSTD_initCStream(strm, level))) { + ZSTD_freeCStream(strm); + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Internal error initializing zstd compressor object"); + return (ARCHIVE_FATAL); + } + + ZSTD_CCtx_setParameter(strm, ZSTD_c_nbWorkers, threads); + + // p7zip-zstd fails to unpack archives that don't have prop_size 5. + // 7-Zip-zstd fails to unpack archives that don't have prop_size 3 or 5. + // So let's use 5... + lastrm->prop_size = 5; + lastrm->props = calloc(5, 1); + if (lastrm->props == NULL) { + ZSTD_freeCStream(strm); + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Internal error initializing zstd compressor properties"); + return (ARCHIVE_FATAL); + } + + // Refer to the DProps struct in 7-Zip-zstd's ZstdDecoder.h: + // https://github.com/mcmilk/7-Zip-zstd/blob/79b2c78e9e7735ddf90147129b75cf2797ff6522/CPP/7zip/Compress/ZstdDecoder.h#L34S + lastrm->props[0] = ZSTD_VERSION_MAJOR; + lastrm->props[1] = ZSTD_VERSION_MINOR; + lastrm->props[2] = level; + // lastrm->props[3] and lastrm->props[4] are reserved. Leave them as 0. + + lastrm->real_stream = strm; + lastrm->valid = 1; + lastrm->code = compression_code_zstd; + lastrm->end = compression_end_zstd; + + return (ARCHIVE_OK); +} + +static int +compression_code_zstd(struct archive *a, + struct la_zstream *lastrm, enum la_zaction action) +{ + ZSTD_CStream *strm = (ZSTD_CStream *)lastrm->real_stream; + + ZSTD_outBuffer out = { .dst = lastrm->next_out, .size = lastrm->avail_out, .pos = 0 }; + ZSTD_inBuffer in = { .src = lastrm->next_in, .size = lastrm->avail_in, .pos = 0 }; + + size_t zret; + + ZSTD_EndDirective mode = (action == ARCHIVE_Z_RUN) ? ZSTD_e_continue : ZSTD_e_end; + + zret = ZSTD_compressStream2(strm, &out, &in, mode); + if (ZSTD_isError(zret)) { + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "zstd compression failed, ZSTD_compressStream2 returned: %s", + ZSTD_getErrorName(zret)); + return (ARCHIVE_FATAL); + } + + lastrm->next_in += in.pos; + lastrm->avail_in -= in.pos; + lastrm->total_in += in.pos; + + lastrm->next_out += out.pos; + lastrm->avail_out -= out.pos; + lastrm->total_out += out.pos; + + if (action == ARCHIVE_Z_FINISH && zret == 0) + return (ARCHIVE_EOF); // All done. + + return (ARCHIVE_OK); // More work to do. +} + +static int +compression_end_zstd(struct archive *a, struct la_zstream *lastrm) +{ + ZSTD_CStream *strm; + + (void)a; /* UNUSED */ + strm = (ZSTD_CStream *)lastrm->real_stream; + ZSTD_freeCStream(strm); + lastrm->valid = 0; + lastrm->real_stream = NULL; + return (ARCHIVE_OK); +} + +#else + +static int +compression_init_encoder_zstd(struct archive *a, struct la_zstream *lastrm, int level, int threads) +{ + (void) level; /* UNUSED */ + (void) threads; /* UNUSED */ + if (lastrm->valid) + compression_end(a, lastrm); + return (compression_unsupported_encoder(a, lastrm, "zstd")); +} +#endif + /* * Universal compressor initializer. */ @@ -2316,6 +2541,11 @@ _7z_compression_init_encoder(struct archive_write *a, unsigned compression, &(a->archive), &(zip->stream), PPMD7_DEFAULT_ORDER, PPMD7_DEFAULT_MEM_SIZE); break; + case _7Z_ZSTD: + r = compression_init_encoder_zstd( + &(a->archive), &(zip->stream), + compression_level, zip->opt_threads); + break; case _7Z_COPY: default: r = compression_init_encoder_copy( @@ -2352,5 +2582,3 @@ compression_end(struct archive *a, struct la_zstream *lastrm) } return (ARCHIVE_OK); } - - diff --git a/libarchive/archive_write_set_format_gnutar.c b/libarchive/archive_write_set_format_gnutar.c index 04b190de44..14ef4cd244 100644 --- a/libarchive/archive_write_set_format_gnutar.c +++ b/libarchive/archive_write_set_format_gnutar.c @@ -153,7 +153,7 @@ static const char template_header[] = { static int archive_write_gnutar_options(struct archive_write *, const char *, const char *); static int archive_format_gnutar_header(struct archive_write *, char h[512], - struct archive_entry *, int tartype); + struct archive_entry *, char tartype); static int archive_write_gnutar_header(struct archive_write *, struct archive_entry *entry); static ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff, @@ -274,7 +274,7 @@ archive_write_gnutar_header(struct archive_write *a, { char buff[512]; int r, ret, ret2 = ARCHIVE_OK; - int tartype; + char tartype; struct gnutar *gnutar; struct archive_string_conv *sconv; struct archive_entry *entry_main; @@ -504,7 +504,7 @@ archive_write_gnutar_header(struct archive_write *a, archive_entry_set_uname(temp, "root"); archive_entry_set_gname(temp, "wheel"); - archive_entry_set_pathname(temp, "././@LongLink"); + archive_entry_set_pathname(temp, "././@LongName"); archive_entry_set_size(temp, length); ret = archive_format_gnutar_header(a, buff, temp, 'L'); archive_entry_free(temp); @@ -562,7 +562,7 @@ exit_write_header: static int archive_format_gnutar_header(struct archive_write *a, char h[512], - struct archive_entry *entry, int tartype) + struct archive_entry *entry, char tartype) { unsigned int checksum; int i, ret; @@ -640,7 +640,7 @@ archive_format_gnutar_header(struct archive_write *a, char h[512], if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset, GNUTAR_uid_size, GNUTAR_uid_max_size)) { archive_set_error(&a->archive, ERANGE, - "Numeric user ID %jd too large", + "Numeric user ID %jd too large for gnutar format", (intmax_t)archive_entry_uid(entry)); ret = ARCHIVE_FAILED; } @@ -649,7 +649,7 @@ archive_format_gnutar_header(struct archive_write *a, char h[512], if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset, GNUTAR_gid_size, GNUTAR_gid_max_size)) { archive_set_error(&a->archive, ERANGE, - "Numeric group ID %jd too large", + "Numeric group ID %jd too large for gnutar format", (intmax_t)archive_entry_gid(entry)); ret = ARCHIVE_FAILED; } @@ -672,7 +672,7 @@ archive_format_gnutar_header(struct archive_write *a, char h[512], h + GNUTAR_rdevmajor_offset, GNUTAR_rdevmajor_size)) { archive_set_error(&a->archive, ERANGE, - "Major device number too large"); + "Major device number too large for gnutar format"); ret = ARCHIVE_FAILED; } @@ -680,7 +680,7 @@ archive_format_gnutar_header(struct archive_write *a, char h[512], h + GNUTAR_rdevminor_offset, GNUTAR_rdevminor_size)) { archive_set_error(&a->archive, ERANGE, - "Minor device number too large"); + "Minor device number too large for gnutar format"); ret = ARCHIVE_FAILED; } } diff --git a/libarchive/archive_write_set_format_iso9660.c b/libarchive/archive_write_set_format_iso9660.c index 3c5b889943..c275c1ec92 100644 --- a/libarchive/archive_write_set_format_iso9660.c +++ b/libarchive/archive_write_set_format_iso9660.c @@ -1167,7 +1167,12 @@ archive_write_set_format_iso9660(struct archive *_a) iso9660->primary.rootent->parent = iso9660->primary.rootent; iso9660->cur_dirent = iso9660->primary.rootent; archive_string_init(&(iso9660->cur_dirstr)); - archive_string_ensure(&(iso9660->cur_dirstr), 1); + if (archive_string_ensure(&(iso9660->cur_dirstr), 1) == NULL) { + free(iso9660); + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + return (ARCHIVE_FATAL); + } iso9660->cur_dirstr.s[0] = 0; iso9660->sconv_to_utf16be = NULL; iso9660->sconv_from_utf16be = NULL; @@ -5666,9 +5671,15 @@ isoent_tree(struct archive_write *a, struct isoent **isoentpp) * inserted. */ iso9660->cur_dirent = dent; archive_string_empty(&(iso9660->cur_dirstr)); - archive_string_ensure(&(iso9660->cur_dirstr), + if (archive_string_ensure(&(iso9660->cur_dirstr), archive_strlen(&(dent->file->parentdir)) + - archive_strlen(&(dent->file->basename)) + 2); + archive_strlen(&(dent->file->basename)) + 2) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + _isoent_free(isoent); + *isoentpp = NULL; + return (ARCHIVE_FATAL); + } if (archive_strlen(&(dent->file->parentdir)) + archive_strlen(&(dent->file->basename)) == 0) iso9660->cur_dirstr.s[0] = 0; diff --git a/libarchive/archive_write_set_format_mtree.c b/libarchive/archive_write_set_format_mtree.c index 14d68516fb..02fbb2d2f5 100644 --- a/libarchive/archive_write_set_format_mtree.c +++ b/libarchive/archive_write_set_format_mtree.c @@ -82,6 +82,7 @@ struct dir_info { struct reg_info { int compute_sum; uint32_t crc; + uint_least32_t mset_digest; struct ae_digest digest; }; @@ -862,6 +863,50 @@ mtree_entry_free(struct mtree_entry *me) free(me); } +static void +mtree_copy_ae_digests(struct reg_info *reg, struct archive_entry *entry, int compute_sum) +{ + reg->compute_sum = compute_sum; + reg->mset_digest = entry->mset_digest; + + if ((reg->compute_sum & F_MD5) + && (reg->mset_digest & AE_MSET_DIGEST_MD5)) { + + memcpy(®->digest.md5, entry->digest.md5, + sizeof(reg->digest.md5)); + } + if ((reg->compute_sum & F_RMD160) + && (reg->mset_digest & AE_MSET_DIGEST_RMD160)) { + + memcpy(®->digest.rmd160, entry->digest.rmd160, + sizeof(reg->digest.rmd160)); + } + if ((reg->compute_sum & F_SHA1) + && (reg->mset_digest & AE_MSET_DIGEST_SHA1)) { + + memcpy(®->digest.sha1, entry->digest.sha1, + sizeof(reg->digest.sha1)); + } + if ((reg->compute_sum & F_SHA256) + && (reg->mset_digest & AE_MSET_DIGEST_SHA256)) { + + memcpy(®->digest.sha256, entry->digest.sha256, + sizeof(reg->digest.sha256)); + } + if ((reg->compute_sum & F_SHA384) + && (reg->mset_digest & AE_MSET_DIGEST_SHA384)) { + + memcpy(®->digest.sha384, entry->digest.sha384, + sizeof(reg->digest.sha384)); + } + if ((reg->compute_sum & F_SHA512) + && (reg->mset_digest & AE_MSET_DIGEST_SHA512)) { + + memcpy(®->digest.sha512, entry->digest.sha512, + sizeof(reg->digest.sha512)); + } +} + static int archive_write_mtree_header(struct archive_write *a, struct archive_entry *entry) @@ -896,8 +941,12 @@ archive_write_mtree_header(struct archive_write *a, /* If the current file is a regular file, we have to * compute the sum of its content. * Initialize a bunch of checksum context. */ - if (mtree_entry->reg_info) + if (mtree_entry->reg_info) { sum_init(mtree); + /* honor archive_entry_set_digest() calls. These values will be + * overwritten if archive_write_mtree_data() is called */ + mtree_copy_ae_digests(mtree_entry->reg_info, entry, mtree->compute_sum); + } return (r2); } @@ -1516,28 +1565,46 @@ sum_update(struct mtree_writer *mtree, const void *buff, size_t n) mtree->crc_len += n; } #ifdef ARCHIVE_HAS_MD5 - if (mtree->compute_sum & F_MD5) + if (mtree->compute_sum & F_MD5) { archive_md5_update(&mtree->md5ctx, buff, n); + mtree->mtree_entry->reg_info->mset_digest &= + ~AE_MSET_DIGEST_MD5; + } #endif #ifdef ARCHIVE_HAS_RMD160 - if (mtree->compute_sum & F_RMD160) + if (mtree->compute_sum & F_RMD160) { archive_rmd160_update(&mtree->rmd160ctx, buff, n); + mtree->mtree_entry->reg_info->mset_digest &= + ~AE_MSET_DIGEST_RMD160; + } #endif #ifdef ARCHIVE_HAS_SHA1 - if (mtree->compute_sum & F_SHA1) + if (mtree->compute_sum & F_SHA1) { archive_sha1_update(&mtree->sha1ctx, buff, n); + mtree->mtree_entry->reg_info->mset_digest &= + ~AE_MSET_DIGEST_SHA1; + } #endif #ifdef ARCHIVE_HAS_SHA256 - if (mtree->compute_sum & F_SHA256) + if (mtree->compute_sum & F_SHA256) { archive_sha256_update(&mtree->sha256ctx, buff, n); + mtree->mtree_entry->reg_info->mset_digest &= + ~AE_MSET_DIGEST_SHA256; + } #endif #ifdef ARCHIVE_HAS_SHA384 - if (mtree->compute_sum & F_SHA384) + if (mtree->compute_sum & F_SHA384) { archive_sha384_update(&mtree->sha384ctx, buff, n); + mtree->mtree_entry->reg_info->mset_digest &= + ~AE_MSET_DIGEST_SHA384; + } #endif #ifdef ARCHIVE_HAS_SHA512 - if (mtree->compute_sum & F_SHA512) + if (mtree->compute_sum & F_SHA512) { archive_sha512_update(&mtree->sha512ctx, buff, n); + mtree->mtree_entry->reg_info->mset_digest &= + ~AE_MSET_DIGEST_SHA512; + } #endif } @@ -1553,27 +1620,39 @@ sum_final(struct mtree_writer *mtree, struct reg_info *reg) reg->crc = ~mtree->crc; } #ifdef ARCHIVE_HAS_MD5 - if (mtree->compute_sum & F_MD5) + if ((mtree->compute_sum & F_MD5) + && !(reg->mset_digest & AE_MSET_DIGEST_MD5)) + archive_md5_final(&mtree->md5ctx, reg->digest.md5); #endif #ifdef ARCHIVE_HAS_RMD160 - if (mtree->compute_sum & F_RMD160) + if ((mtree->compute_sum & F_RMD160) + && !(reg->mset_digest & AE_MSET_DIGEST_RMD160)) + archive_rmd160_final(&mtree->rmd160ctx, reg->digest.rmd160); #endif #ifdef ARCHIVE_HAS_SHA1 - if (mtree->compute_sum & F_SHA1) + if ((mtree->compute_sum & F_SHA1) + && !(reg->mset_digest & AE_MSET_DIGEST_SHA1)) + archive_sha1_final(&mtree->sha1ctx, reg->digest.sha1); #endif #ifdef ARCHIVE_HAS_SHA256 - if (mtree->compute_sum & F_SHA256) + if ((mtree->compute_sum & F_SHA256) + && !(reg->mset_digest & AE_MSET_DIGEST_SHA256)) + archive_sha256_final(&mtree->sha256ctx, reg->digest.sha256); #endif #ifdef ARCHIVE_HAS_SHA384 - if (mtree->compute_sum & F_SHA384) + if ((mtree->compute_sum & F_SHA384) + && !(reg->mset_digest & AE_MSET_DIGEST_SHA384)) + archive_sha384_final(&mtree->sha384ctx, reg->digest.sha384); #endif #ifdef ARCHIVE_HAS_SHA512 - if (mtree->compute_sum & F_SHA512) + if ((mtree->compute_sum & F_SHA512) + && !(reg->mset_digest & AE_MSET_DIGEST_SHA512)) + archive_sha512_final(&mtree->sha512ctx, reg->digest.sha512); #endif /* Save what types of sum are computed. */ @@ -2130,9 +2209,13 @@ mtree_entry_tree_add(struct archive_write *a, struct mtree_entry **filep) * inserted. */ mtree->cur_dirent = dent; archive_string_empty(&(mtree->cur_dirstr)); - archive_string_ensure(&(mtree->cur_dirstr), + if (archive_string_ensure(&(mtree->cur_dirstr), archive_strlen(&(dent->parentdir)) + - archive_strlen(&(dent->basename)) + 2); + archive_strlen(&(dent->basename)) + 2) == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate memory"); + return (ARCHIVE_FATAL); + } if (archive_strlen(&(dent->parentdir)) + archive_strlen(&(dent->basename)) == 0) mtree->cur_dirstr.s[0] = 0; diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c index 6e35f705e1..66e6d75196 100644 --- a/libarchive/archive_write_set_format_pax.c +++ b/libarchive/archive_write_set_format_pax.c @@ -1414,7 +1414,7 @@ archive_write_pax_header(struct archive_write *a, struct archive_entry *pax_attr_entry; time_t s; int64_t uid, gid; - int mode; + __LA_MODE_T mode; pax_attr_entry = archive_entry_new2(&a->archive); p = entry_name.s; @@ -1571,7 +1571,7 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length, const char *filename, *filename_end; char *p; int need_slash = 0; /* Was there a trailing slash? */ - size_t suffix_length = 99; + size_t suffix_length = 98; /* 99 - 1 for trailing slash */ size_t insert_length; /* Length of additional dir element to be added. */ @@ -1623,7 +1623,7 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length, /* Step 2: Locate the "prefix" section of the dirname, including * trailing '/'. */ prefix = src; - prefix_end = prefix + 155; + prefix_end = prefix + 154 /* 155 - 1 for trailing / */; if (prefix_end > filename) prefix_end = filename; while (prefix_end > prefix && *prefix_end != '/') diff --git a/libarchive/archive_write_set_format_xar.c b/libarchive/archive_write_set_format_xar.c index 96ef85c694..3775e9f581 100644 --- a/libarchive/archive_write_set_format_xar.c +++ b/libarchive/archive_write_set_format_xar.c @@ -34,6 +34,14 @@ #include #if HAVE_LIBXML_XMLWRITER_H #include +#if defined(LIBXML_VERSION) && LIBXML_VERSION >= 20703 +#define XAR_WRITER_HAS_XML +#endif /* LIBXML_VERSION */ +#elif HAVE_XMLLITE_H +#include +#include +#include +#define XAR_WRITER_HAS_XML #endif #ifdef HAVE_BZLIB_H #include @@ -70,13 +78,12 @@ * */ -#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\ - LIBXML_VERSION >= 20703) ||\ +#if !defined(XAR_WRITER_HAS_XML) ||\ !defined(HAVE_ZLIB_H) || \ !defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1) /* * xar needs several external libraries. - * o libxml2 + * o libxml2 or xmllite (on Windows) * o openssl or MD5/SHA1 hash function * o zlib * o bzlib2 (option) @@ -94,9 +101,26 @@ archive_write_set_format_xar(struct archive *_a) #else /* Support xar format */ -/*#define DEBUG_PRINT_TOC 1 */ +struct xml_writer; +static int xml_writer_create(struct xml_writer **pctx); +static int xml_writer_start_document(struct xml_writer *ctx); +static int xml_writer_end_document(struct xml_writer *ctx); +static int xml_writer_set_indent(struct xml_writer *ctx, unsigned int indent); +static int xml_writer_start_element(struct xml_writer *ctx, + const char *localName); +static int xml_writer_write_attribute(struct xml_writer *ctx, const char *key, + const char *value); +static int xml_writer_write_attributef(struct xml_writer *ctx, const char *key, + const char *format, ...); +static int xml_writer_write_string(struct xml_writer *ctx, const char *string); +static int xml_writer_write_base64(struct xml_writer* ctx, + const char *data, size_t start, size_t len); +static int xml_writer_end_element(struct xml_writer *ctx); +static int xml_writer_get_final_content_and_length(struct xml_writer *ctx, + const char **out, size_t *size); +static int xml_writer_destroy(struct xml_writer *ctx); -#define BAD_CAST_CONST (const xmlChar *) +/*#define DEBUG_PRINT_TOC 1 */ #define HEADER_MAGIC 0x78617221 #define HEADER_SIZE 28 @@ -807,50 +831,49 @@ xar_finish_entry(struct archive_write *a) } static int -xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer, +xmlwrite_string_attr(struct archive_write *a, struct xml_writer *writer, const char *key, const char *value, const char *attrkey, const char *attrvalue) { int r; - r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key)); + r = xml_writer_start_element(writer, key); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } if (attrkey != NULL && attrvalue != NULL) { - r = xmlTextWriterWriteAttribute(writer, - BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue)); + r = xml_writer_write_attribute(writer, attrkey, attrvalue); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteAttribute() failed: %d", r); + "xml_writer_write_attribute() failed: %d", r); return (ARCHIVE_FATAL); } } if (value != NULL) { - r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value)); + r = xml_writer_write_string(writer, value); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteString() failed: %d", r); + "xml_writer_write_string() failed: %d", r); return (ARCHIVE_FATAL); } } - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } return (ARCHIVE_OK); } static int -xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer, +xmlwrite_string(struct archive_write *a, struct xml_writer *writer, const char *key, const char *value) { int r; @@ -858,34 +881,34 @@ xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer, if (value == NULL) return (ARCHIVE_OK); - r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key)); + r = xml_writer_start_element(writer, key); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } if (value != NULL) { - r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value)); + r = xml_writer_write_string(writer, value); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteString() failed: %d", r); + "xml_writer_write_string() failed: %d", r); return (ARCHIVE_FATAL); } } - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } return (ARCHIVE_OK); } static int -xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer, +xmlwrite_fstring(struct archive_write *a, struct xml_writer *writer, const char *key, const char *fmt, ...) { struct xar *xar; @@ -900,7 +923,7 @@ xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer, } static int -xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer, +xmlwrite_time(struct archive_write *a, struct xml_writer *writer, const char *key, time_t t, int z) { char timestr[100]; @@ -922,7 +945,7 @@ xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer, } static int -xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer, +xmlwrite_mode(struct archive_write *a, struct xml_writer *writer, const char *key, mode_t mode) { char ms[5]; @@ -937,7 +960,7 @@ xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer, } static int -xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer, +xmlwrite_sum(struct archive_write *a, struct xml_writer *writer, const char *key, struct chksumval *sum) { const char *algname; @@ -971,7 +994,7 @@ xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer, } static int -xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer, +xmlwrite_heap(struct archive_write *a, struct xml_writer *writer, struct heap_data *heap) { const char *encname; @@ -1029,7 +1052,7 @@ xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer, * Our implements records both and if it's necessary. */ static int -make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer, +make_fflags_entry(struct archive_write *a, struct xml_writer *writer, const char *element, const char *fflags_text) { static const struct flagentry { @@ -1119,11 +1142,11 @@ make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer, } while (p != NULL); if (n > 0) { - r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element)); + r = xml_writer_start_element(writer, element); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } for (i = 0; i < n; i++) { @@ -1133,29 +1156,59 @@ make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer, return (r); } - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } } return (ARCHIVE_OK); } +/* + * This function determines whether a UTF-8 string contains + * only codepoints that are convertible to Latin-1. Strings + * beyond Latin-1 are stored base64-encoded in the XAR TOC. + */ static int -make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, +is_u8_zstring_latin1(const char *in) +{ + unsigned int c; + while (*in) { + c = *in++; + if (c < 0x80) continue; + /* + * Filter out non-continuation, any continuation of 2-3 + * bytes, and any continuation of 1 byte whose high 3 bits + * are non-zero. Recall, 1-byte continuations can store 11 + * bits whereas Latin-1 codepoints are only 8 bits wide. + */ + if ((c & 0xFC) != 0xC0) + return (0); + c = *in++; + /* + * If we get any non-continuation byte (including 0x00!), + * the string is not valid UTF-8. + */ + if ((c & 0xC0) != 0x80) + return (0); /* invalid unicode */ + } + return (1); +} + +static int +make_file_entry(struct archive_write *a, struct xml_writer *writer, struct file *file) { struct xar *xar; const char *filetype, *filelink, *fflags; struct archive_string linkto; struct heap_data *heap; - unsigned char *tmp; const char *p; size_t len; - int r, r2, l, ll; + int r, r2; xar = (struct xar *)a->format_data; r2 = ARCHIVE_OK; @@ -1163,44 +1216,35 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, /* * Make a file name entry, "". */ - l = ll = (int)archive_strlen(&(file->basename)); - tmp = malloc(l); - if (tmp == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory"); - return (ARCHIVE_FATAL); - } - r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll); - free(tmp); - if (r < 0) { - r = xmlTextWriterStartElement(writer, BAD_CAST("name")); + if (!is_u8_zstring_latin1(file->basename.s)) { + r = xml_writer_start_element(writer, "name"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } - r = xmlTextWriterWriteAttribute(writer, - BAD_CAST("enctype"), BAD_CAST("base64")); + r = xml_writer_write_attribute(writer, + "enctype", "base64"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteAttribute() failed: %d", r); + "xml_writer_write_attribute() failed: %d", r); return (ARCHIVE_FATAL); } - r = xmlTextWriterWriteBase64(writer, file->basename.s, + r = xml_writer_write_base64(writer, file->basename.s, 0, (int)archive_strlen(&(file->basename))); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteBase64() failed: %d", r); + "xml_writer_write_base64() failed: %d", r); return (ARCHIVE_FATAL); } - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } } else { @@ -1281,11 +1325,11 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, break; case AE_IFCHR: case AE_IFBLK: - r = xmlTextWriterStartElement(writer, BAD_CAST("device")); + r = xml_writer_start_element(writer, "device"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } r = xmlwrite_fstring(a, writer, "major", @@ -1296,11 +1340,11 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, "%d", archive_entry_rdevminor(file->entry)); if (r < 0) return (ARCHIVE_FATAL); - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } break; @@ -1436,19 +1480,19 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, archive_entry_xattr_next(file->entry, &name, &value, &size); - r = xmlTextWriterStartElement(writer, BAD_CAST("ea")); + r = xml_writer_start_element(writer, "ea"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } - r = xmlTextWriterWriteFormatAttribute(writer, - BAD_CAST("id"), "%d", heap->id); + r = xml_writer_write_attributef(writer, + "id", "%d", heap->id); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteAttribute() failed: %d", r); + "xml_writer_write_attributef() failed: %d", r); return (ARCHIVE_FATAL); } r = xmlwrite_heap(a, writer, heap); @@ -1458,11 +1502,11 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, if (r < 0) return (ARCHIVE_FATAL); - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } } @@ -1471,11 +1515,11 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, * Make a file data entry, "". */ if (file->data.length > 0) { - r = xmlTextWriterStartElement(writer, BAD_CAST("data")); + r = xml_writer_start_element(writer, "data"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } @@ -1483,21 +1527,21 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, if (r < 0) return (ARCHIVE_FATAL); - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } } if (archive_strlen(&file->script) > 0) { - r = xmlTextWriterStartElement(writer, BAD_CAST("content")); + r = xml_writer_start_element(writer, "content"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); return (ARCHIVE_FATAL); } @@ -1510,11 +1554,11 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, if (r < 0) return (ARCHIVE_FATAL); - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); return (ARCHIVE_FATAL); } } @@ -1530,8 +1574,9 @@ make_toc(struct archive_write *a) { struct xar *xar; struct file *np; - xmlBufferPtr bp; - xmlTextWriterPtr writer; + struct xml_writer *writer; + const char* content; + size_t use; int algsize; int r, ret; @@ -1543,51 +1588,43 @@ make_toc(struct archive_write *a) * Initialize xml writer. */ writer = NULL; - bp = xmlBufferCreate(); - if (bp == NULL) { - archive_set_error(&a->archive, ENOMEM, - "xmlBufferCreate() " - "couldn't create xml buffer"); - goto exit_toc; - } - writer = xmlNewTextWriterMemory(bp, 0); - if (writer == NULL) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "xmlNewTextWriterMemory() " - "couldn't create xml writer"); - goto exit_toc; - } - r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); + r = xml_writer_create(&writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartDocument() failed: %d", r); + "xml_writer_create() failed: %d", r); goto exit_toc; } - r = xmlTextWriterSetIndent(writer, 4); + r = xml_writer_set_indent(writer, 4); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterSetIndent() failed: %d", r); + "xml_writer_set_indent() failed: %d", r); + goto exit_toc; + } + r = xml_writer_start_document(writer); + if (r < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "xml_writer_start_document() failed: %d", r); goto exit_toc; } /* * Start recording TOC */ - r = xmlTextWriterStartElement(writer, BAD_CAST("xar")); + r = xml_writer_start_element(writer, "xar"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); goto exit_toc; } - r = xmlTextWriterStartElement(writer, BAD_CAST("toc")); + r = xml_writer_start_element(writer, "toc"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartDocument() failed: %d", r); + "xml_writer_start_element() failed: %d", r); goto exit_toc; } @@ -1606,19 +1643,19 @@ make_toc(struct archive_write *a) /* * Record TOC checksum */ - r = xmlTextWriterStartElement(writer, BAD_CAST("checksum")); + r = xml_writer_start_element(writer, "checksum"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() failed: %d", r); + "xml_writer_start_element() failed: %d", r); goto exit_toc; } - r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"), - BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg))); + r = xml_writer_write_attribute(writer, "style", + getalgname(xar->opt_toc_sumalg)); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteAttribute() failed: %d", r); + "xml_writer_write_attribute() failed: %d", r); goto exit_toc; } @@ -1636,11 +1673,11 @@ make_toc(struct archive_write *a) if (r < 0) goto exit_toc; - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() failed: %d", r); + "xml_writer_end_element() failed: %d", r); goto exit_toc; } } @@ -1656,32 +1693,32 @@ make_toc(struct archive_write *a) if (np->dir && np->children.first != NULL) { /* Enter to sub directories. */ np = np->children.first; - r = xmlTextWriterStartElement(writer, - BAD_CAST("file")); + r = xml_writer_start_element(writer, + "file"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() " + "xml_writer_start_element() " "failed: %d", r); goto exit_toc; } - r = xmlTextWriterWriteFormatAttribute( - writer, BAD_CAST("id"), "%d", np->id); + r = xml_writer_write_attributef( + writer, "id", "%d", np->id); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteAttribute() " + "xml_writer_write_attributef() " "failed: %d", r); goto exit_toc; } continue; } while (np != np->parent) { - r = xmlTextWriterEndElement(writer); + r = xml_writer_end_element(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndElement() " + "xml_writer_end_element() " "failed: %d", r); goto exit_toc; } @@ -1690,21 +1727,21 @@ make_toc(struct archive_write *a) np = np->parent; } else { np = np->chnext; - r = xmlTextWriterStartElement(writer, - BAD_CAST("file")); + r = xml_writer_start_element(writer, + "file"); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterStartElement() " + "xml_writer_start_element() " "failed: %d", r); goto exit_toc; } - r = xmlTextWriterWriteFormatAttribute( - writer, BAD_CAST("id"), "%d", np->id); + r = xml_writer_write_attributef( + writer, "id", "%d", np->id); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterWriteAttribute() " + "xml_writer_write_attributef() " "failed: %d", r); goto exit_toc; } @@ -1713,31 +1750,40 @@ make_toc(struct archive_write *a) } } while (np != np->parent); - r = xmlTextWriterEndDocument(writer); + r = xml_writer_end_document(writer); if (r < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "xmlTextWriterEndDocument() failed: %d", r); + "xml_writer_end_document() failed: %d", r); goto exit_toc; } + + r = xml_writer_get_final_content_and_length(writer, &content, &use); + if (r < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "xml_writer_get_final_content_and_length() failed: %d", r); + goto exit_toc; + } + #if DEBUG_PRINT_TOC fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n", - strlen((const char *)bp->content), bp->content); + (int)strlen(content), content); #endif /* * Compress the TOC and calculate the sum of the TOC. */ xar->toc.temp_offset = xar->temp_offset; - xar->toc.size = bp->use; + xar->toc.size = (uint64_t)use; checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg); r = compression_init_encoder_gzip(&(a->archive), &(xar->stream), 6, 1); if (r != ARCHIVE_OK) goto exit_toc; - xar->stream.next_in = bp->content; - xar->stream.avail_in = bp->use; + xar->stream.next_in = (const unsigned char *)content; + xar->stream.avail_in = use; xar->stream.total_in = 0; xar->stream.next_out = xar->wbuff; xar->stream.avail_out = sizeof(xar->wbuff); @@ -1768,9 +1814,7 @@ make_toc(struct archive_write *a) ret = ARCHIVE_OK; exit_toc: if (writer) - xmlFreeTextWriter(writer); - if (bp) - xmlBufferFree(bp); + xml_writer_destroy(writer); return (ret); } @@ -3251,4 +3295,404 @@ getalgname(enum sumalg sumalg) } } +#if HAVE_LIBXML_XMLWRITER_H + +#define BAD_CAST_CONST (const xmlChar *) + +struct xml_writer { + xmlTextWriterPtr writer; + xmlBufferPtr bp; + unsigned int indent; +}; + +static int +xml_writer_create(struct xml_writer **pctx) +{ + struct xml_writer *ctx = calloc(1, sizeof(struct xml_writer)); + if (ctx == NULL) { + return (-1); + } + + ctx->bp = xmlBufferCreate(); + if (ctx->bp == NULL) { + free(ctx); + return (-1); + } + + ctx->writer = xmlNewTextWriterMemory(ctx->bp, 0); + if (ctx->writer == NULL) { + xmlBufferFree(ctx->bp); + free(ctx); + return (-1); + } + + *pctx = ctx; + return (0); +} + +static int +xml_writer_destroy(struct xml_writer *ctx) +{ + xmlFreeTextWriter(ctx->writer); + xmlBufferFree(ctx->bp); + free(ctx); + return (0); +} + +static int +xml_writer_start_document(struct xml_writer *ctx) +{ + int r; + r = xmlTextWriterStartDocument(ctx->writer, "1.0", "UTF-8", NULL); + if (r < 0) { + return (r); + } + + r = xmlTextWriterSetIndent(ctx->writer, (int)ctx->indent); + return (r); +} + +static int +xml_writer_end_document(struct xml_writer *ctx) +{ + return (xmlTextWriterEndDocument(ctx->writer)); +} + +static int +xml_writer_set_indent(struct xml_writer *ctx, unsigned int indent) +{ + /* libxml2 only lets you set the indent after starting the document */ + ctx->indent = indent; + return (0); +} + +static int +xml_writer_start_element(struct xml_writer *ctx, const char *localName) +{ + return (xmlTextWriterStartElement(ctx->writer, + BAD_CAST_CONST(localName))); +} + +static int +xml_writer_write_attribute(struct xml_writer *ctx, + const char *key, const char *value) +{ + return (xmlTextWriterWriteAttribute(ctx->writer, + BAD_CAST_CONST(key), BAD_CAST_CONST(value))); +} + +static int +xml_writer_write_attributef(struct xml_writer *ctx, + const char *key, const char *format, ...) +{ + va_list ap; + int ret; + va_start(ap, format); + ret = xmlTextWriterWriteVFormatAttribute(ctx->writer, + BAD_CAST_CONST(key), format, ap); + va_end(ap); + return (ret); +} + +static int +xml_writer_write_string(struct xml_writer *ctx, const char *string) +{ + return (xmlTextWriterWriteString(ctx->writer, BAD_CAST_CONST(string))); +} + +static int +xml_writer_write_base64(struct xml_writer* ctx, + const char *data, size_t start, size_t len) +{ + return (xmlTextWriterWriteBase64(ctx->writer, data, + (int)start, (int)len)); +} + +static int +xml_writer_end_element(struct xml_writer *ctx) +{ + return (xmlTextWriterEndElement(ctx->writer)); +} + +static int +xml_writer_get_final_content_and_length(struct xml_writer *ctx, + const char **out, size_t *size) +{ + *out = (const char*)ctx->bp->content; + *size = (size_t)ctx->bp->use; + return (0); +} + +#elif HAVE_XMLLITE_H + +struct xml_writer { + IXmlWriter *writer; + IStream *stream; + HGLOBAL global; +}; + +static int +xml_writer_create(struct xml_writer **pctx) +{ + struct xml_writer *ctx; + HRESULT hr; + + ctx = calloc(1, sizeof(struct xml_writer)); + if (ctx == NULL) { + return (E_OUTOFMEMORY); + } + + hr = CreateStreamOnHGlobal(NULL, TRUE, &ctx->stream); + if (FAILED(hr)) { + free(ctx); + return (hr); + } + + hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&ctx->writer, NULL); + if (FAILED(hr)) { + ctx->stream->lpVtbl->Release(ctx->stream); + free(ctx); + return (hr); + } + + hr = ctx->writer->lpVtbl->SetOutput(ctx->writer, + (IUnknown *)ctx->stream); + if (FAILED(hr)) { + ctx->writer->lpVtbl->Release(ctx->writer); + ctx->stream->lpVtbl->Release(ctx->stream); + free(ctx); + return (hr); + } + + *pctx = ctx; + return (S_OK); +} + +static int +xml_writer_destroy(struct xml_writer *ctx) +{ + if (ctx->global) + GlobalUnlock(ctx->global); + ctx->writer->lpVtbl->Release(ctx->writer); /* Destroys only writer */ + ctx->stream->lpVtbl->Release(ctx->stream); /* Destroys stream, global */ + free(ctx); + return (S_OK); +} + +static int +xml_writer_start_document(struct xml_writer *ctx) +{ + return ctx->writer->lpVtbl->WriteStartDocument(ctx->writer, + XmlStandalone_Omit); +} + +static int +xml_writer_end_document(struct xml_writer *ctx) +{ + return ctx->writer->lpVtbl->WriteEndDocument(ctx->writer); +} + +static int +xml_writer_set_indent(struct xml_writer *ctx, unsigned int indent) +{ + /* Windows' xmllite does not support indent sizes; will always be 2 */ + (void)indent; + return ctx->writer->lpVtbl->SetProperty(ctx->writer, + XmlWriterProperty_Indent, (LONG_PTR)TRUE); +} + +static int +xml_writer_start_element(struct xml_writer *ctx, const char *localName) +{ + struct archive_wstring as; + HRESULT hr; + archive_string_init(&as); + if (archive_wstring_append_from_mbs(&as, localName, + strlen(localName))) { + hr = E_OUTOFMEMORY; + goto exit_hr; + } + hr = ctx->writer->lpVtbl->WriteStartElement(ctx->writer, NULL, + as.s, NULL); + +exit_hr: + archive_wstring_free(&as); + return hr; +} + +static int +xml_writer_write_attribute(struct xml_writer *ctx, + const char *key, const char *value) +{ + struct archive_wstring ask, asv; + HRESULT hr; + archive_string_init(&ask); + archive_string_init(&asv); + if (archive_wstring_append_from_mbs(&ask, key, strlen(key))) { + hr = E_OUTOFMEMORY; + goto exit_hr; + } + if (archive_wstring_append_from_mbs(&asv, value, strlen(value))) { + hr = E_OUTOFMEMORY; + goto exit_hr; + } + hr = ctx->writer->lpVtbl->WriteAttributeString(ctx->writer, NULL, + ask.s, NULL, asv.s); + +exit_hr: + archive_wstring_free(&asv); + archive_wstring_free(&ask); + return hr; +} + +static int +xml_writer_write_attributef(struct xml_writer *ctx, + const char *key, const char *format, ...) +{ + struct archive_wstring ask, asv; + struct archive_string asf; + HRESULT hr; + va_list ap; + + va_start(ap, format); + archive_string_init(&ask); + archive_string_init(&asv); + archive_string_init(&asf); + + if (archive_wstring_append_from_mbs(&ask, key, strlen(key))) { + hr = E_OUTOFMEMORY; + goto exit_hr; + } + + archive_string_vsprintf(&asf, format, ap); + if (archive_wstring_append_from_mbs(&asv, asf.s, asf.length)) { + hr = E_OUTOFMEMORY; + goto exit_hr; + } + + hr = ctx->writer->lpVtbl->WriteAttributeString(ctx->writer, NULL, + ask.s, NULL, asv.s); + +exit_hr: + archive_string_free(&asf); + archive_wstring_free(&asv); + archive_wstring_free(&ask); + va_end(ap); + + return hr; +} + +static int +xml_writer_write_string(struct xml_writer *ctx, const char *string) +{ + struct archive_wstring as; + HRESULT hr; + archive_string_init(&as); + if (archive_wstring_append_from_mbs(&as, string, strlen(string))) { + hr = E_OUTOFMEMORY; + goto exit_hr; + } + hr = ctx->writer->lpVtbl->WriteString(ctx->writer, as.s); + +exit_hr: + archive_wstring_free(&as); + return hr; +} + +static const wchar_t base64[] = { + L'A', L'B', L'C', L'D', L'E', L'F', L'G', L'H', + L'I', L'J', L'K', L'L', L'M', L'N', L'O', L'P', + L'Q', L'R', L'S', L'T', L'U', L'V', L'W', L'X', + L'Y', L'Z', L'a', L'b', L'c', L'd', L'e', L'f', + L'g', L'h', L'i', L'j', L'k', L'l', L'm', L'n', + L'o', L'p', L'q', L'r', L's', L't', L'u', L'v', + L'w', L'x', L'y', L'z', L'0', L'1', L'2', L'3', + L'4', L'5', L'6', L'7', L'8', L'9', L'+', L'/' +}; + +static void +la_b64_wencode(struct archive_wstring *as, const unsigned char *p, size_t len) +{ + int c; + + for (; len >= 3; p += 3, len -= 3) { + c = p[0] >> 2; + archive_wstrappend_wchar(as, base64[c]); + c = ((p[0] & 0x03) << 4) | ((p[1] & 0xf0) >> 4); + archive_wstrappend_wchar(as, base64[c]); + c = ((p[1] & 0x0f) << 2) | ((p[2] & 0xc0) >> 6); + archive_wstrappend_wchar(as, base64[c]); + c = p[2] & 0x3f; + archive_wstrappend_wchar(as, base64[c]); + } + if (len > 0) { + c = p[0] >> 2; + archive_wstrappend_wchar(as, base64[c]); + c = (p[0] & 0x03) << 4; + if (len == 1) { + archive_wstrappend_wchar(as, base64[c]); + archive_wstrappend_wchar(as, '='); + archive_wstrappend_wchar(as, '='); + } else { + c |= (p[1] & 0xf0) >> 4; + archive_wstrappend_wchar(as, base64[c]); + c = (p[1] & 0x0f) << 2; + archive_wstrappend_wchar(as, base64[c]); + archive_wstrappend_wchar(as, '='); + } + } +} + +static int +xml_writer_write_base64(struct xml_writer* ctx, + const char *data, size_t start, size_t len) +{ + struct archive_wstring as; + HRESULT hr; + archive_string_init(&as); + la_b64_wencode(&as, (const unsigned char *)data + start, len - start); + hr = ctx->writer->lpVtbl->WriteString(ctx->writer, as.s); + archive_wstring_free(&as); + return hr; +} + +static int +xml_writer_end_element(struct xml_writer *ctx) +{ + return ctx->writer->lpVtbl->WriteEndElement(ctx->writer); +} + +static int +xml_writer_get_final_content_and_length(struct xml_writer *ctx, + const char **out, size_t *size) +{ + HGLOBAL gbl; + HRESULT hr; + + hr = ctx->writer->lpVtbl->Flush(ctx->writer); + if (FAILED(hr)) { + return (hr); + } + + hr = GetHGlobalFromStream(ctx->stream, &gbl); + if (FAILED(hr)) { + return (hr); + } + + *out = (const char *)GlobalLock(gbl); + if (*out == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + return (hr); + } + + /* GlobalUnlock is called in + * xml_writer_destroy. + */ + *size = (size_t)GlobalSize(gbl); + ctx->global = gbl; + return (hr); +} + +#endif /* HAVE_LIBXML_XMLWRITER_H */ + #endif /* Support xar format */ diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c index e3b13701f2..3630b9f2b3 100644 --- a/libarchive/archive_write_set_format_zip.c +++ b/libarchive/archive_write_set_format_zip.c @@ -43,9 +43,24 @@ #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif #ifdef HAVE_ZLIB_H #include #endif +#ifdef HAVE_LZMA_H +#include +#endif +#ifdef HAVE_BZLIB_H +#include +#endif +#ifdef HAVE_ZSTD_H +#include +#endif #include "archive.h" #include "archive_cryptor_private.h" @@ -55,6 +70,7 @@ #include "archive_hmac_private.h" #include "archive_private.h" #include "archive_random_private.h" +#include "archive_time_private.h" #include "archive_write_private.h" #include "archive_write_set_format_private.h" @@ -62,8 +78,12 @@ #include "archive_crc32.h" #endif -#define ZIP_ENTRY_FLAG_ENCRYPTED (1<<0) -#define ZIP_ENTRY_FLAG_LENGTH_AT_END (1<<3) +#define ZIP_ENTRY_FLAG_ENCRYPTED (1 << 0) +#define ZIP_ENTRY_FLAG_LZMA_EOPM (1 << 1) +#define ZIP_ENTRY_FLAG_DEFLATE_MAX (1 << 1) /* i.e. compression levels 8 & 9 */ +#define ZIP_ENTRY_FLAG_DEFLATE_FAST (1 << 2) /* i.e. compression levels 3 & 4 */ +#define ZIP_ENTRY_FLAG_DEFLATE_SUPER_FAST (1 << 1) | (1 << 2) /* i.e. compression levels 1 & 2 */ +#define ZIP_ENTRY_FLAG_LENGTH_AT_END (1 << 3) #define ZIP_ENTRY_FLAG_UTF8_NAME (1 << 11) #define ZIP_4GB_MAX ARCHIVE_LITERAL_LL(0xffffffff) @@ -72,7 +92,11 @@ enum compression { COMPRESSION_UNSPECIFIED = -1, COMPRESSION_STORE = 0, - COMPRESSION_DEFLATE = 8 + COMPRESSION_DEFLATE = 8, + COMPRESSION_BZIP2 = 12, + COMPRESSION_LZMA = 14, + COMPRESSION_ZSTD = 93, + COMPRESSION_XZ = 95 }; #ifdef HAVE_ZLIB_H @@ -119,7 +143,6 @@ struct trad_enc_ctx { }; struct zip { - int64_t entry_offset; int64_t entry_compressed_size; int64_t entry_uncompressed_size; @@ -155,17 +178,45 @@ struct zip { struct archive_string_conv *opt_sconv; struct archive_string_conv *sconv_default; enum compression requested_compression; - int deflate_compression_level; + short compression_level; int init_default_conversion; - enum encryption encryption_type; + enum encryption encryption_type; + short threads; #define ZIP_FLAG_AVOID_ZIP64 1 #define ZIP_FLAG_FORCE_ZIP64 2 #define ZIP_FLAG_EXPERIMENT_xl 4 int flags; - +#if defined(HAVE_LZMA_H) || defined(HAVE_ZLIB_H) || defined(HAVE_BZLIB_H) || defined(HAVE_ZSTD_H) + union { +#ifdef HAVE_LZMA_H + /* ZIP's XZ format (id 95) is easy enough: copy Deflate, mutatis + * mutandis the library changes. ZIP's LZMA format (id 14), + * however, is rather more involved, starting here: it being a + * modified LZMA Alone format requires a bit more + * book-keeping. */ + struct { + char headers_to_write; + lzma_options_lzma options; + lzma_stream context; + } lzma; +#endif #ifdef HAVE_ZLIB_H - z_stream stream; + z_stream deflate; +#endif +#ifdef HAVE_BZLIB_H + bz_stream bzip2; +#endif +#if defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream + struct { + /* Libzstd's init function gives a pointer to a memory area + * it manages rather than asking for memory to initialise. */ + ZSTD_CStream* context; + ZSTD_inBuffer in; + ZSTD_outBuffer out; + } zstd; +#endif + } stream; #endif size_t len_buf; unsigned char *buf; @@ -184,7 +235,6 @@ static int archive_write_zip_header(struct archive_write *, struct archive_entry *); static int archive_write_zip_options(struct archive_write *, const char *, const char *); -static unsigned int dos_time(const time_t); static size_t path_length(struct archive_entry *); static int write_path(struct archive_entry *, struct archive_write *); static void copy_path(struct archive_entry *, unsigned char *); @@ -197,6 +247,44 @@ static int is_traditional_pkware_encryption_supported(void); static int init_winzip_aes_encryption(struct archive_write *); static int is_winzip_aes_encryption_supported(int encryption); +#ifdef HAVE_LZMA_H +/* ZIP's LZMA format requires the use of a alas not exposed in LibLZMA + * function to write the ZIP header. Given our internal version never + * fails, no need for a non-void return type. */ +static void +lzma_lzma_props_encode(const lzma_options_lzma* options, uint8_t* out) +{ + out[0] = (options->pb * 5 + options->lp) * 9 + options->lc; + archive_le32enc(out + 1, options->dict_size); +} +#endif + +#if defined(HAVE_LZMA_H) && !defined(HAVE_LZMA_STREAM_ENCODER_MT) +/* Dummy mt declarations, to avoid spaghetti includes below. Defined with + * macros being renamed afterwards to shadow liblzma's types in order to + * avoid some compiler errors. */ +#define lzma_stream_encoder_mt(str, opt) dummy_mt(str, opt) +#define lzma_mt dummy_options + +typedef struct { + void* filters; + uint32_t preset; + lzma_check check; + short threads; + char flags; + char block_size; + char timeout; +} dummy_options; + +static inline lzma_ret +dummy_mt(lzma_stream* stream, const lzma_mt* options) +{ + (void)stream; /* UNUSED */ + (void)options; /* UNUSED */ + return LZMA_PROG_ERROR; +} +#endif + static unsigned char * cd_alloc(struct zip *zip, size_t length) { @@ -274,26 +362,104 @@ archive_write_zip_options(struct archive_write *a, const char *key, } else if (strcmp(val, "store") == 0) { zip->requested_compression = COMPRESSION_STORE; ret = ARCHIVE_OK; + } else if (strcmp(val, "bzip2") == 0) { +#ifdef HAVE_BZLIB_H + zip->requested_compression = COMPRESSION_BZIP2; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "bzip2 compression not supported"); +#endif + } else if (strcmp(val, "lzma") == 0) { +#ifdef HAVE_LZMA_H + zip->requested_compression = COMPRESSION_LZMA; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "lzma compression not supported"); +#endif + } else if (strcmp(val, "xz") == 0) { +#ifdef HAVE_LZMA_H + zip->requested_compression = COMPRESSION_XZ; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "xz compression not supported"); +#endif + } else if (strcmp(val, "zstd") == 0) { +#if defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream + zip->requested_compression = COMPRESSION_ZSTD; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "zstd compression not supported"); +#endif } return (ret); } else if (strcmp(key, "compression-level") == 0) { - if (val == NULL || !(val[0] >= '0' && val[0] <= '9') || val[1] != '\0') { - return ARCHIVE_WARN; + char *endptr; + + if (val == NULL) + return (ARCHIVE_WARN); + errno = 0; + zip->compression_level = (short)strtoul(val, &endptr, 10); + if (errno != 0 || *endptr != '\0' || zip->compression_level < 0 || + zip->compression_level > 9) { + zip->compression_level = 6; // set to default + return (ARCHIVE_WARN); } - if (val[0] == '0') { + if (zip->compression_level == 0) { zip->requested_compression = COMPRESSION_STORE; return ARCHIVE_OK; } else { +#if defined(HAVE_ZLIB_H) || defined(HAVE_LZMA_H) || defined(HAVE_BZLIB_H) || (defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream) + // Not forcing an already specified compression algorithm + if (zip->requested_compression == COMPRESSION_UNSPECIFIED) { #ifdef HAVE_ZLIB_H - zip->requested_compression = COMPRESSION_DEFLATE; - zip->deflate_compression_level = val[0] - '0'; + zip->requested_compression = COMPRESSION_DEFLATE; +#elif defined(HAVE_BZLIB_H) + zip->requested_compression = COMPRESSION_BZIP2; +#elif defined(HAVE_LZMA_H) + // Arbitrarily choosing LZMA of the two LZMA methods + zip->requested_compression = COMPRESSION_LZMA; +#else + zip->requested_compression = COMPRESSION_ZSTD; +#endif + } return ARCHIVE_OK; #else archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "deflate compression not supported"); + "compression not supported"); #endif } + } else if (strcmp(key, "threads") == 0) { + char *endptr; + + if (val == NULL) + return (ARCHIVE_FAILED); + errno = 0; + zip->threads = (short)strtoul(val, &endptr, 10); + if (errno != 0 || *endptr != '\0') { + zip->threads = 1; + archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC, + "Illegal value `%s'", val); + return (ARCHIVE_FAILED); + } + if (zip->threads == 0) { +#ifdef HAVE_LZMA_STREAM_ENCODER_MT + zip->threads = lzma_cputhreads(); +#elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) + zip->threads = sysconf(_SC_NPROCESSORS_ONLN); +#elif !defined(__CYGWIN__) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0601 + /* Windows 7 and up */ + DWORD activeProcs = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); + zip->threads = activeProcs <= SHRT_MAX ? (short)activeProcs : SHRT_MAX; +#else + zip->threads = 1; +#endif + } + return (ARCHIVE_OK); } else if (strcmp(key, "encryption") == 0) { if (val == NULL) { zip->encryption_type = ENCRYPTION_NONE; @@ -305,8 +471,7 @@ archive_write_zip_options(struct archive_write *a, const char *key, zip->encryption_type = ENCRYPTION_TRADITIONAL; ret = ARCHIVE_OK; } else { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "encryption not supported"); } } else if (strcmp(val, "aes128") == 0) { @@ -315,8 +480,7 @@ archive_write_zip_options(struct archive_write *a, const char *key, zip->encryption_type = ENCRYPTION_WINZIP_AES128; ret = ARCHIVE_OK; } else { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "encryption not supported"); } } else if (strcmp(val, "aes256") == 0) { @@ -325,14 +489,12 @@ archive_write_zip_options(struct archive_write *a, const char *key, zip->encryption_type = ENCRYPTION_WINZIP_AES256; ret = ARCHIVE_OK; } else { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "encryption not supported"); } } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "%s: unknown encryption '%s'", - a->format_name, val); + "%s: unknown encryption '%s'", a->format_name, val); } return (ret); } else if (strcmp(key, "experimental") == 0) { @@ -421,6 +583,118 @@ archive_write_zip_set_compression_deflate(struct archive *_a) return (ret); } +int +archive_write_zip_set_compression_bzip2(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int ret = ARCHIVE_FAILED; + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_zip_set_compression_bzip2"); + if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can only use archive_write_zip_set_compression_bzip2" + " with zip format"); + ret = ARCHIVE_FATAL; + } else { +#ifdef HAVE_BZLIB_H + struct zip *zip = a->format_data; + zip->requested_compression = COMPRESSION_BZIP2; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "bzip2 compression not supported"); + ret = ARCHIVE_FAILED; +#endif + } + return (ret); +} + +int +archive_write_zip_set_compression_zstd(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int ret = ARCHIVE_FAILED; + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_zip_set_compression_zstd"); + if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can only use archive_write_zip_set_compression_zstd" + " with zip format"); + ret = ARCHIVE_FATAL; + } else { +#if defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream + struct zip *zip = a->format_data; + zip->requested_compression = COMPRESSION_ZSTD; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "zstd compression not supported"); + ret = ARCHIVE_FAILED; +#endif + } + return (ret); +} + +int +archive_write_zip_set_compression_lzma(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int ret = ARCHIVE_FAILED; + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_zip_set_compression_lzma"); + if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can only use archive_write_zip_set_compression_lzma" + " with zip format"); + ret = ARCHIVE_FATAL; + } else { +#ifdef HAVE_LZMA_H + struct zip *zip = a->format_data; + zip->requested_compression = COMPRESSION_LZMA; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "lzma compression not supported"); + ret = ARCHIVE_FAILED; +#endif + } + return (ret); +} + +int +archive_write_zip_set_compression_xz(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + int ret = ARCHIVE_FAILED; + + archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, + "archive_write_zip_set_compression_xz"); + if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Can only use archive_write_zip_set_compression_xz" + " with zip format"); + ret = ARCHIVE_FATAL; + } else { +#ifdef HAVE_LZMA_H + struct zip *zip = a->format_data; + zip->requested_compression = COMPRESSION_XZ; + ret = ARCHIVE_OK; +#else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "xz compression not supported"); + ret = ARCHIVE_FAILED; +#endif + } + return (ret); +} + int archive_write_zip_set_compression_store(struct archive *_a) { @@ -430,7 +704,7 @@ archive_write_zip_set_compression_store(struct archive *_a) archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, - "archive_write_zip_set_compression_deflate"); + "archive_write_zip_set_compression_store"); if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Can only use archive_write_zip_set_compression_store" @@ -465,9 +739,14 @@ archive_write_set_format_zip(struct archive *_a) /* "Unspecified" lets us choose the appropriate compression. */ zip->requested_compression = COMPRESSION_UNSPECIFIED; -#ifdef HAVE_ZLIB_H - zip->deflate_compression_level = Z_DEFAULT_COMPRESSION; -#endif + /* Following the 7-zip write support's lead, setting the default + * compression level explicitly to 6 no matter what. */ + zip->compression_level = 6; + /* Following the xar write support's lead, the default number of + * threads is 1 (i.e. the xz compression, the only one caring about + * that, not being multi-threaded even if the multi-threaded encoder + * were available) */ + zip->threads = 1; zip->crc32func = real_crc32; /* A buffer used for both compression and encryption. */ @@ -552,7 +831,6 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) if (type != AE_IFREG) archive_entry_set_size(entry, 0); - /* Reset information from last entry. */ zip->entry_offset = zip->written_bytes; zip->entry_uncompressed_limit = INT64_MAX; @@ -589,7 +867,6 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) } } - #if defined(_WIN32) && !defined(__CYGWIN__) /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ @@ -685,13 +962,49 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) if (zip->entry_compression == COMPRESSION_UNSPECIFIED) { zip->entry_compression = COMPRESSION_DEFAULT; } - if (zip->entry_compression == COMPRESSION_STORE) { + switch (zip->entry_compression) { + case COMPRESSION_STORE: zip->entry_compressed_size = size; zip->entry_uncompressed_size = size; MIN_VERSION_NEEDED(10); - } else { + break; + case COMPRESSION_ZSTD: zip->entry_uncompressed_size = size; + MIN_VERSION_NEEDED(63); + break; + case COMPRESSION_LZMA: + zip->entry_uncompressed_size = size; + zip->entry_flags |= ZIP_ENTRY_FLAG_LZMA_EOPM; + MIN_VERSION_NEEDED(63); + break; + case COMPRESSION_XZ: + zip->entry_uncompressed_size = size; + MIN_VERSION_NEEDED(63); + break; + case COMPRESSION_BZIP2: + zip->entry_uncompressed_size = size; + MIN_VERSION_NEEDED(46); + break; + default: // i.e. deflate compression + zip->entry_uncompressed_size = size; + switch (zip->compression_level) { + case 1: + case 2: + zip->entry_flags |= ZIP_ENTRY_FLAG_DEFLATE_SUPER_FAST; + break; + case 3: + case 4: + zip->entry_flags |= ZIP_ENTRY_FLAG_DEFLATE_FAST; + break; + case 8: + case 9: + zip->entry_flags |= ZIP_ENTRY_FLAG_DEFLATE_MAX; + break; + default: + break; + } MIN_VERSION_NEEDED(20); + break; } if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) { @@ -741,9 +1054,8 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) /* We don't know the size. Use the default * compression unless specified otherwise. */ - zip->entry_compression = zip->requested_compression; - if(zip->entry_compression == COMPRESSION_UNSPECIFIED){ + if (zip->entry_compression == COMPRESSION_UNSPECIFIED) { zip->entry_compression = COMPRESSION_DEFAULT; } @@ -751,10 +1063,43 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) if ((zip->flags & ZIP_FLAG_AVOID_ZIP64) == 0) { /* We might use zip64 extensions, so require 4.5 */ MIN_VERSION_NEEDED(45); - } else if (zip->entry_compression == COMPRESSION_STORE) { + } + switch (zip->entry_compression) { + case COMPRESSION_STORE: MIN_VERSION_NEEDED(10); - } else { + break; + case COMPRESSION_ZSTD: + MIN_VERSION_NEEDED(63); + break; + case COMPRESSION_LZMA: + zip->entry_flags |= ZIP_ENTRY_FLAG_LZMA_EOPM; + MIN_VERSION_NEEDED(63); + break; + case COMPRESSION_XZ: + MIN_VERSION_NEEDED(63); + break; + case COMPRESSION_BZIP2: + MIN_VERSION_NEEDED(46); + break; + default: // i.e. deflate compression + switch (zip->compression_level) { + case 1: + case 2: + zip->entry_flags |= ZIP_ENTRY_FLAG_DEFLATE_SUPER_FAST; + break; + case 3: + case 4: + zip->entry_flags |= ZIP_ENTRY_FLAG_DEFLATE_FAST; + break; + case 8: + case 9: + zip->entry_flags |= ZIP_ENTRY_FLAG_DEFLATE_MAX; + break; + default: + break; + } MIN_VERSION_NEEDED(20); + break; } if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) { @@ -782,7 +1127,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) else archive_le16enc(local_header + 8, zip->entry_compression); archive_le32enc(local_header + 10, - dos_time(archive_entry_mtime(zip->entry))); + unix_to_dos(archive_entry_mtime(zip->entry))); if ((zip->entry_flags & ZIP_ENTRY_FLAG_LENGTH_AT_END) == 0) { archive_le32enc(local_header + 14, zip->entry_crc32); archive_le32enc(local_header + 18, (uint32_t)zip->entry_compressed_size); @@ -813,7 +1158,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) else archive_le16enc(zip->file_header + 10, zip->entry_compression); archive_le32enc(zip->file_header + 12, - dos_time(archive_entry_mtime(zip->entry))); + unix_to_dos(archive_entry_mtime(zip->entry))); archive_le16enc(zip->file_header + 28, (uint16_t)filename_length); /* Following Info-Zip, store mode in the "external attributes" field. */ archive_le32enc(zip->file_header + 38, @@ -983,21 +1328,147 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) zip->written_bytes += slink_size; } + switch (zip->entry_compression) { #ifdef HAVE_ZLIB_H - if (zip->entry_compression == COMPRESSION_DEFLATE) { - zip->stream.zalloc = Z_NULL; - zip->stream.zfree = Z_NULL; - zip->stream.opaque = Z_NULL; - zip->stream.next_out = zip->buf; - zip->stream.avail_out = (uInt)zip->len_buf; - if (deflateInit2(&zip->stream, zip->deflate_compression_level, + case COMPRESSION_DEFLATE: + zip->stream.deflate.zalloc = Z_NULL; + zip->stream.deflate.zfree = Z_NULL; + zip->stream.deflate.opaque = Z_NULL; + zip->stream.deflate.next_out = zip->buf; + zip->stream.deflate.avail_out = (uInt)zip->len_buf; + if (deflateInit2(&zip->stream.deflate, zip->compression_level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) { archive_set_error(&a->archive, ENOMEM, "Can't init deflate compressor"); return (ARCHIVE_FATAL); } - } + break; #endif +#ifdef HAVE_BZLIB_H + case COMPRESSION_BZIP2: + memset(&zip->stream.bzip2, 0, sizeof(bz_stream)); + zip->stream.bzip2.next_out = (char*)zip->buf; + zip->stream.bzip2.avail_out = (unsigned int)zip->len_buf; + if (BZ2_bzCompressInit(&zip->stream.bzip2, zip->compression_level, 0, 0) != BZ_OK) { + archive_set_error(&a->archive, ENOMEM, + "Can't init bzip2 compressor"); + return (ARCHIVE_FATAL); + } + break; +#endif +#if defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream + case COMPRESSION_ZSTD: + {/* Libzstd, contrary to many compression libraries, doesn't use + * zlib's 0 to 9 scale and its negative scale is way bigger than + * its positive one. So setting 1 as the lowest allowed compression + * level and rescaling to 2 to 9 to libzstd's positive scale. */ + int zstd_compression_level = zip->compression_level == 1 + ? ZSTD_minCLevel() // ZSTD_minCLevel is negative ! + : (zip->compression_level - 1) * ZSTD_maxCLevel() / 8; + zip->stream.zstd.context = ZSTD_createCStream(); + size_t zret = ZSTD_initCStream(zip->stream.zstd.context, zstd_compression_level); + if (ZSTD_isError(zret)) { + archive_set_error(&a->archive, ENOMEM, + "Can't init zstd compressor"); + return (ARCHIVE_FATAL); + } + /* Asking for the multi-threaded compressor is a no-op in zstd if + * it's not supported, so no need to explicitly check for it */ + ZSTD_CCtx_setParameter(zip->stream.zstd.context, ZSTD_c_nbWorkers, zip->threads); + zip->stream.zstd.out.dst = zip->buf; + zip->stream.zstd.out.size = zip->len_buf; + zip->stream.zstd.out.pos = 0; + break;} +#endif +#ifdef HAVE_LZMA_H + case COMPRESSION_LZMA: + {/* Set compression level 9 as the no-holds barred one */ + uint32_t lzma_compression_level = zip->compression_level == 9 + ? LZMA_PRESET_EXTREME | zip->compression_level + : (uint32_t)zip->compression_level; + /* Forcibly setting up the encoder to use the LZMA1 variant, as + * it is the one LZMA Alone uses. */ + lzma_filter filters[2] = { + { + .id = LZMA_FILTER_LZMA1, + .options = &zip->stream.lzma.options + }, + { + .id = LZMA_VLI_UNKNOWN + } + }; + memset(&zip->stream.lzma.context, 0, sizeof(lzma_stream)); + lzma_lzma_preset(&zip->stream.lzma.options, lzma_compression_level); + zip->stream.lzma.headers_to_write = 1; + /* We'll be writing the headers ourselves, so using the raw + * encoder */ + if (lzma_raw_encoder(&zip->stream.lzma.context, filters) != LZMA_OK) { + archive_set_error(&a->archive, ENOMEM, + "Can't init lzma compressor"); + return (ARCHIVE_FATAL); + } + zip->stream.lzma.context.next_out = zip->buf; + zip->stream.lzma.context.avail_out = (unsigned int)zip->len_buf; + break;} + case COMPRESSION_XZ: + {/* Set compression level 9 as the no-holds barred one */ + uint32_t lzma_compression_level = zip->compression_level == 9 + ? LZMA_PRESET_EXTREME | zip->compression_level + : (uint32_t)zip->compression_level; + lzma_ret retval; +#ifndef HAVE_LZMA_STREAM_ENCODER_MT + /* Force the number of threads to one, and thus to a mono-threaded + * encoder in case we don't have the multi-threaded one */ + zip->threads = 1; +#endif + memset(&zip->stream.lzma.context, 0, sizeof(lzma_stream)); + /* The XZ check will be arbitrarily set to none: ZIP already has + * a CRC-32 check of its own */ + if (zip->threads == 1) { + /* XZ uses LZMA2. */ + lzma_filter filters[2] = { + { + .id = LZMA_FILTER_LZMA2, + .options = &zip->stream.lzma.options + }, + { + .id = LZMA_VLI_UNKNOWN + } + }; + /* Might as well use the lzma_options we already allocated, + * even if we'll never use it after the initialisation */ + lzma_lzma_preset(&zip->stream.lzma.options, lzma_compression_level); + /* 1 thread requested, so non multi-threaded encoder */ + retval = lzma_stream_encoder(&zip->stream.lzma.context, + filters, LZMA_CHECK_NONE); + } + else { + lzma_mt options = { + .flags = 0, + .block_size = 0, + .timeout = 0, + .filters = NULL, + .check = LZMA_CHECK_NONE, + .preset = lzma_compression_level, + .threads = zip->threads + }; + /* More than 1 thread requested, so multi-threaded encoder + * which always outputs XZ */ + retval = lzma_stream_encoder_mt(&zip->stream.lzma.context, + &options); + } + if (retval != LZMA_OK) { + archive_set_error(&a->archive, ENOMEM, + "Can't init xz compressor"); + return (ARCHIVE_FATAL); + } + zip->stream.lzma.context.next_out = zip->buf; + zip->stream.lzma.context.avail_out = (unsigned int)zip->len_buf; + break;} +#endif + default: + break; + } return (ret2); } @@ -1082,15 +1553,15 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) zip->entry_compressed_written += s; } break; -#if HAVE_ZLIB_H +#ifdef HAVE_ZLIB_H case COMPRESSION_DEFLATE: - zip->stream.next_in = (unsigned char*)(uintptr_t)buff; - zip->stream.avail_in = (uInt)s; + zip->stream.deflate.next_in = (unsigned char*)(uintptr_t)buff; + zip->stream.deflate.avail_in = (uInt)s; do { - ret = deflate(&zip->stream, Z_NO_FLUSH); + ret = deflate(&zip->stream.deflate, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR) return (ARCHIVE_FATAL); - if (zip->stream.avail_out == 0) { + if (zip->stream.deflate.avail_out == 0) { if (zip->tctx_valid) { trad_enc_encrypt_update(&zip->tctx, zip->buf, zip->len_buf, @@ -1116,13 +1587,223 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) return (ret); zip->entry_compressed_written += zip->len_buf; zip->written_bytes += zip->len_buf; - zip->stream.next_out = zip->buf; - zip->stream.avail_out = (uInt)zip->len_buf; + zip->stream.deflate.next_out = zip->buf; + zip->stream.deflate.avail_out = (uInt)zip->len_buf; } - } while (zip->stream.avail_in != 0); + } while (zip->stream.deflate.avail_in != 0); break; #endif +#if defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream + case COMPRESSION_ZSTD: + zip->stream.zstd.in.src = buff; + zip->stream.zstd.in.size = s; + zip->stream.zstd.in.pos = 0; + do { + size_t zret = ZSTD_compressStream(zip->stream.zstd.context, + &zip->stream.zstd.out, &zip->stream.zstd.in); + if (ZSTD_isError(zret)) + return (ARCHIVE_FATAL); + if (zip->stream.zstd.out.pos == zip->stream.zstd.out.size) { + if (zip->tctx_valid) { + trad_enc_encrypt_update(&zip->tctx, + zip->buf, zip->len_buf, + zip->buf, zip->len_buf); + } else if (zip->cctx_valid) { + size_t outl = zip->len_buf; + ret = archive_encrypto_aes_ctr_update( + &zip->cctx, + zip->buf, zip->len_buf, + zip->buf, &outl); + if (ret < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to encrypt file"); + return (ARCHIVE_FAILED); + } + archive_hmac_sha1_update(&zip->hctx, + zip->buf, zip->len_buf); + } + ret = __archive_write_output(a, zip->buf, + zip->len_buf); + if (ret != ARCHIVE_OK) + return (ret); + zip->entry_compressed_written += zip->len_buf; + zip->written_bytes += zip->len_buf; + zip->stream.zstd.out.dst = zip->buf; + zip->stream.zstd.out.size = zip->len_buf; + zip->stream.zstd.out.pos = 0; + } + } while (zip->stream.zstd.in.pos != zip->stream.zstd.in.size); + break; +#endif +#ifdef HAVE_BZLIB_H + case COMPRESSION_BZIP2: + zip->stream.bzip2.next_in = (char*)(uintptr_t)buff; + zip->stream.bzip2.avail_in = (unsigned int)s; + do { + ret = BZ2_bzCompress(&zip->stream.bzip2, BZ_RUN); + if (ret != BZ_RUN_OK) + return (ARCHIVE_FATAL); + if (zip->stream.bzip2.avail_out == 0) { + if (zip->tctx_valid) { + trad_enc_encrypt_update(&zip->tctx, + zip->buf, zip->len_buf, + zip->buf, zip->len_buf); + } else if (zip->cctx_valid) { + size_t outl = zip->len_buf; + ret = archive_encrypto_aes_ctr_update( + &zip->cctx, + zip->buf, zip->len_buf, + zip->buf, &outl); + if (ret < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to encrypt file"); + return (ARCHIVE_FAILED); + } + archive_hmac_sha1_update(&zip->hctx, + zip->buf, zip->len_buf); + } + ret = __archive_write_output(a, zip->buf, + zip->len_buf); + if (ret != ARCHIVE_OK) + return (ret); + zip->entry_compressed_written += zip->len_buf; + zip->written_bytes += zip->len_buf; + zip->stream.bzip2.next_out = (char*)zip->buf; + zip->stream.bzip2.avail_out = (unsigned int)zip->len_buf; + } + } while (zip->stream.bzip2.avail_in != 0); + break; +#endif +#ifdef HAVE_LZMA_H + case COMPRESSION_LZMA: + if (zip->stream.lzma.headers_to_write) { + /* LZMA Alone and ZIP's LZMA format (i.e. id 14) are almost + * the same. Here's an example of a structure of LZMA Alone: + * + * $ cat /bin/ls | lzma | xxd | head -n 1 + * 00000000: 5d00 0080 00ff ffff ffff ffff ff00 2814 + * + * 5 bytes 8 bytes n bytes + * + * + * lzma_params is a 5-byte blob that has to be decoded to + * extract parameters of this LZMA stream. The + * uncompressed_size field is an uint64_t value that contains + * information about the size of the uncompressed file, or + * UINT64_MAX if this value is unknown. The part is + * the actual LZMA-compressed data stream. + * + * Now here's the structure of ZIP's LZMA format: + * + * $ cat stream_inside_zipx | xxd | head -n 1 + * 00000000: 0914 0500 5d00 8000 0000 2814 .... .... + * + * 2byte 2byte 5 bytes n bytes + * + * + * This means that ZIP's LZMA format contains an additional + * magic1 and magic2 headers, the lzma_params field contains + * the same parameter set as in LZMA Alone, and the + * field is the same as in LZMA Alone as well. However, note + * that ZIP's format is missing the uncompressed_size field. + * + * So we need to write a raw LZMA stream, set up for LZMA1 + * (i.e. the algorithm variant LZMA Alone uses), which was + * done above in the initialisation but first we need to + * write ZIP's LZMA header, as if it were Stored data. Then + * we can use the raw stream as if it were any other. magic1 + * being version numbers and magic2 being lzma_params's size, + * they get written in without further ado but lzma_params + * requires to use other functions than the usual lzma_stream + * manipulating ones, hence the additional book-keeping + * required alongside the lzma_stream. + */ + uint8_t buf[9] = { LZMA_VERSION_MAJOR, LZMA_VERSION_MINOR, 5, 0 }; + lzma_lzma_props_encode(&zip->stream.lzma.options, buf + 4); + const size_t sh = 9; + if (zip->tctx_valid || zip->cctx_valid) { + uint8_t* header = buf; + const uint8_t * const rh = header + sh; + while (header < rh) { + size_t l; + + if (zip->tctx_valid) { + l = trad_enc_encrypt_update(&zip->tctx, + header, rh - header, + zip->buf, zip->len_buf); + } else { + l = zip->len_buf; + ret = archive_encrypto_aes_ctr_update( + &zip->cctx, + header, rh - header, zip->buf, &l); + if (ret < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to encrypt file"); + return (ARCHIVE_FAILED); + } + archive_hmac_sha1_update(&zip->hctx, + zip->buf, l); + } + ret = __archive_write_output(a, zip->buf, l); + if (ret != ARCHIVE_OK) + return (ret); + zip->entry_compressed_written += l; + zip->written_bytes += l; + header += l; + } + } else { + ret = __archive_write_output(a, buf, sh); + if (ret != ARCHIVE_OK) + return (ret); + zip->written_bytes += sh; + zip->entry_compressed_written += sh; + } + zip->stream.lzma.headers_to_write = 0; + } + /* FALLTHROUGH */ + case COMPRESSION_XZ: + zip->stream.lzma.context.next_in = (unsigned char*)(uintptr_t)buff; + zip->stream.lzma.context.avail_in = (unsigned int)s; + do { + ret = lzma_code(&zip->stream.lzma.context, LZMA_RUN); + if (ret == LZMA_MEM_ERROR) + return (ARCHIVE_FATAL); + if (zip->stream.lzma.context.avail_out == 0) { + if (zip->tctx_valid) { + trad_enc_encrypt_update(&zip->tctx, + zip->buf, zip->len_buf, + zip->buf, zip->len_buf); + } else if (zip->cctx_valid) { + size_t outl = zip->len_buf; + ret = archive_encrypto_aes_ctr_update( + &zip->cctx, + zip->buf, zip->len_buf, + zip->buf, &outl); + if (ret < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to encrypt file"); + return (ARCHIVE_FAILED); + } + archive_hmac_sha1_update(&zip->hctx, + zip->buf, zip->len_buf); + } + ret = __archive_write_output(a, zip->buf, + zip->len_buf); + if (ret != ARCHIVE_OK) + return (ret); + zip->entry_compressed_written += zip->len_buf; + zip->written_bytes += zip->len_buf; + zip->stream.lzma.context.next_out = zip->buf; + zip->stream.lzma.context.avail_out = (unsigned int)zip->len_buf; + } + } while (zip->stream.lzma.context.avail_in != 0); + break; +#endif case COMPRESSION_UNSPECIFIED: default: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -1135,7 +1816,6 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) zip->entry_crc32 = zip->crc32func(zip->entry_crc32, buff, (unsigned)s); return (s); - } static int @@ -1143,16 +1823,20 @@ archive_write_zip_finish_entry(struct archive_write *a) { struct zip *zip = a->format_data; int ret; +#if defined(HAVE_BZLIB_H) || (defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream) || HAVE_LZMA_H + char finishing; +#endif -#if HAVE_ZLIB_H - if (zip->entry_compression == COMPRESSION_DEFLATE) { + switch (zip->entry_compression) { +#ifdef HAVE_ZLIB_H + case COMPRESSION_DEFLATE: for (;;) { size_t remainder; - ret = deflate(&zip->stream, Z_FINISH); + ret = deflate(&zip->stream.deflate, Z_FINISH); if (ret == Z_STREAM_ERROR) return (ARCHIVE_FATAL); - remainder = zip->len_buf - zip->stream.avail_out; + remainder = zip->len_buf - zip->stream.deflate.avail_out; if (zip->tctx_valid) { trad_enc_encrypt_update(&zip->tctx, zip->buf, remainder, zip->buf, remainder); @@ -1175,14 +1859,145 @@ archive_write_zip_finish_entry(struct archive_write *a) return (ret); zip->entry_compressed_written += remainder; zip->written_bytes += remainder; - zip->stream.next_out = zip->buf; - if (zip->stream.avail_out != 0) + zip->stream.deflate.next_out = zip->buf; + if (zip->stream.deflate.avail_out != 0) break; - zip->stream.avail_out = (uInt)zip->len_buf; + zip->stream.deflate.avail_out = (uInt)zip->len_buf; } - deflateEnd(&zip->stream); - } + deflateEnd(&zip->stream.deflate); + break; #endif +#ifdef HAVE_BZLIB_H + case COMPRESSION_BZIP2: + finishing = 1; + do { + size_t remainder; + + ret = BZ2_bzCompress(&zip->stream.bzip2, BZ_FINISH); + if (ret == BZ_STREAM_END) + finishing = 0; + else if (ret != BZ_RUN_OK && ret != BZ_FINISH_OK) + return (ARCHIVE_FATAL); + remainder = zip->len_buf - zip->stream.bzip2.avail_out; + if (zip->tctx_valid) { + trad_enc_encrypt_update(&zip->tctx, + zip->buf, remainder, zip->buf, remainder); + } else if (zip->cctx_valid) { + size_t outl = remainder; + ret = archive_encrypto_aes_ctr_update( + &zip->cctx, zip->buf, remainder, + zip->buf, &outl); + if (ret < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to encrypt file"); + return (ARCHIVE_FAILED); + } + archive_hmac_sha1_update(&zip->hctx, + zip->buf, remainder); + } + ret = __archive_write_output(a, zip->buf, remainder); + if (ret != ARCHIVE_OK) + return (ret); + zip->entry_compressed_written += remainder; + zip->written_bytes += remainder; + zip->stream.bzip2.next_out = (char*)zip->buf; + if (zip->stream.bzip2.avail_out != 0) + finishing = 0; + zip->stream.bzip2.avail_out = (unsigned int)zip->len_buf; + } while (finishing); + BZ2_bzCompressEnd(&zip->stream.bzip2); + break; +#endif +#if defined(HAVE_ZSTD_H) && HAVE_ZSTD_compressStream + case COMPRESSION_ZSTD: + finishing = 1; + do { + size_t remainder; + + size_t zret = ZSTD_endStream(zip->stream.zstd.context, &zip->stream.zstd.out); + if (zret == 0) + finishing = 0; + else if (ZSTD_isError(zret)) + return (ARCHIVE_FATAL); + remainder = zip->len_buf - (zip->stream.zstd.out.size - zip->stream.zstd.out.pos); + if (zip->tctx_valid) { + trad_enc_encrypt_update(&zip->tctx, + zip->buf, remainder, zip->buf, remainder); + } else if (zip->cctx_valid) { + size_t outl = remainder; + ret = archive_encrypto_aes_ctr_update( + &zip->cctx, zip->buf, remainder, + zip->buf, &outl); + if (ret < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to encrypt file"); + return (ARCHIVE_FAILED); + } + archive_hmac_sha1_update(&zip->hctx, + zip->buf, remainder); + } + ret = __archive_write_output(a, zip->buf, remainder); + if (ret != ARCHIVE_OK) + return (ret); + zip->entry_compressed_written += remainder; + zip->written_bytes += remainder; + zip->stream.zstd.out.dst = zip->buf; + if (zip->stream.zstd.out.pos != zip->stream.zstd.out.size) + finishing = 0; + zip->stream.zstd.out.size = zip->len_buf; + } while (finishing); + ZSTD_freeCStream(zip->stream.zstd.context); + break; +#endif +#ifdef HAVE_LZMA_H + /* XZ and LZMA share clean-up code */ + case COMPRESSION_LZMA: + case COMPRESSION_XZ: + finishing = 1; + do { + size_t remainder; + + ret = lzma_code(&zip->stream.lzma.context, LZMA_FINISH); + if (ret == LZMA_STREAM_END) + finishing = 0; + else if (ret == LZMA_MEM_ERROR) + return (ARCHIVE_FATAL); + remainder = zip->len_buf - zip->stream.lzma.context.avail_out; + if (zip->tctx_valid) { + trad_enc_encrypt_update(&zip->tctx, + zip->buf, remainder, zip->buf, remainder); + } else if (zip->cctx_valid) { + size_t outl = remainder; + ret = archive_encrypto_aes_ctr_update( + &zip->cctx, zip->buf, remainder, + zip->buf, &outl); + if (ret < 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "Failed to encrypt file"); + return (ARCHIVE_FAILED); + } + archive_hmac_sha1_update(&zip->hctx, + zip->buf, remainder); + } + ret = __archive_write_output(a, zip->buf, remainder); + if (ret != ARCHIVE_OK) + return (ret); + zip->entry_compressed_written += remainder; + zip->written_bytes += remainder; + zip->stream.lzma.context.next_out = zip->buf; + if (zip->stream.lzma.context.avail_out != 0) + finishing = 0; + zip->stream.lzma.context.avail_out = (unsigned int)zip->len_buf; + } while (finishing); + lzma_end(&zip->stream.lzma.context); + break; +#endif + default: + break; + } if (zip->hctx_valid) { uint8_t hmac[20]; size_t hmac_len = 20; @@ -1366,7 +2181,6 @@ archive_write_zip_close(struct archive_write *a) if (ret != ARCHIVE_OK) return (ARCHIVE_FATAL); zip->written_bytes += 20; - } /* Format and write end of central directory. */ @@ -1413,44 +2227,6 @@ archive_write_zip_free(struct archive_write *a) return (ARCHIVE_OK); } -/* Convert into MSDOS-style date/time. */ -static unsigned int -dos_time(const time_t unix_time) -{ - struct tm *t; - unsigned int dt; -#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S) - struct tm tmbuf; -#endif - -#if defined(HAVE_LOCALTIME_S) - t = localtime_s(&tmbuf, &unix_time) ? NULL : &tmbuf; -#elif defined(HAVE_LOCALTIME_R) - t = localtime_r(&unix_time, &tmbuf); -#else - t = localtime(&unix_time); -#endif - - /* MSDOS-style date/time is only between 1980-01-01 and 2107-12-31 */ - if (t->tm_year < 1980 - 1900) - /* Set minimum date/time '1980-01-01 00:00:00'. */ - dt = 0x00210000U; - else if (t->tm_year > 2107 - 1900) - /* Set maximum date/time '2107-12-31 23:59:58'. */ - dt = 0xff9fbf7dU; - else { - dt = 0; - dt += ((t->tm_year - 80) & 0x7f) << 9; - dt += ((t->tm_mon + 1) & 0x0f) << 5; - dt += (t->tm_mday & 0x1f); - dt <<= 16; - dt += (t->tm_hour & 0x1f) << 11; - dt += (t->tm_min & 0x3f) << 5; - dt += (t->tm_sec & 0x3e) >> 1; /* Only counting every 2 seconds. */ - } - return dt; -} - static size_t path_length(struct archive_entry *entry) { @@ -1518,7 +2294,6 @@ copy_path(struct archive_entry *entry, unsigned char *p) p[pathlen] = '/'; } - static struct archive_string_conv * get_sconv(struct archive_write *a, struct zip *zip) { @@ -1576,7 +2351,6 @@ trad_enc_encrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in, static int trad_enc_init(struct trad_enc_ctx *ctx, const char *pw, size_t pw_len) { - ctx->keys[0] = 305419896L; ctx->keys[1] = 591751049L; ctx->keys[2] = 878082192L; diff --git a/libarchive/archive_write_set_options.3 b/libarchive/archive_write_set_options.3 index 454c79671b..c3de50c8fe 100644 --- a/libarchive/archive_write_set_options.3 +++ b/libarchive/archive_write_set_options.3 @@ -263,7 +263,7 @@ decimal integer specifying log2 window size in bytes. Values from The value is interpreted as a decimal integer specifying the number of threads for multi-threaded zstd compression. If set to 0, zstd will attempt to detect and use the number -of physical CPU cores. +of active physical CPU cores. .El .It Format 7zip .Bl -tag -compact -width indent @@ -274,9 +274,10 @@ The value is one of .Dq deflate , .Dq bzip2 , .Dq lzma1 , -.Dq lzma2 +.Dq lzma2 , +.Dq ppmd , or -.Dq ppmd +.Dq zstd to indicate how the following entries should be compressed. The values .Dq store @@ -289,9 +290,16 @@ and other special entries. The value is interpreted as a decimal integer specifying the compression level. Values between 0 and 9 are supported, with the exception of bzip2 -which only supports values between 1 and 9. +which only supports values between 1 and 9, and zstd which may +support negative values depending on the library version and +commonly used values 1 through 22. The interpretation of the compression level depends on the chosen compression method. +.It Cm threads +The value is interpreted as a decimal integer specifying the +number of threads for multi-threaded compression (for compressors +like zstd that support it). If set to 0, an attempt will be made +to discover the number of CPU cores. .El .It Format bin .Bl -tag -compact -width indent @@ -632,9 +640,13 @@ and .Bl -tag -compact -width indent .It Cm compression The value is either -.Dq store +.Dq store , +.Dq deflate , +.Dq bzip2 , +.Dq lzma , +.Dq xz , or -.Dq deflate +.Dq zstd to indicate how the following entries should be compressed. Note that this setting is ignored for directories, symbolic links, and other special entries. @@ -645,8 +657,23 @@ Values between 0 and 9 are supported. A compression level of 0 switches the compression method to .Dq store , other values will enable -.Dq deflate -compression with the given level. +.Dq deflate , +.Dq bzip2 , +.Dq lzma , +or +.Dq zstd +compression (in order of priority, depending on what libraries +are linked) with the given level. +.It Cm threads +The value is interpreted as a decimal integer specifying the +number of threads to use for compression. +It is supported only for +.Dq xz +or +.Dq zstd +compression and ignored for any other. +A threads value of 0 is a special one requesting to detect and use as +many threads as the number of active physical CPU cores. .It Cm encryption Enable encryption using traditional zip encryption. .It Cm encryption Ns = Ns Ar type diff --git a/libarchive/libarchive-formats.5 b/libarchive/libarchive-formats.5 index fab2f86602..1b057b4da0 100644 --- a/libarchive/libarchive-formats.5 +++ b/libarchive/libarchive-formats.5 @@ -327,10 +327,26 @@ by the usual environment variables. Libarchive can read and write zip format archives that have uncompressed entries and entries compressed with the .Dq deflate +, +.Dq LZMA +, +.Dq XZ +, +.Dq BZIP2 +and +.Dq ZSTD +algorithms. +Libarchive can also read, but not write, zip format archives that +have entries compressed with the +.Dq PPMd algorithm. Other zip compression algorithms are not supported. -It can extract jar archives, archives that use Zip64 extensions and -self-extracting zip archives. +The extensions supported by libarchive are Zip64, Libarchive's +extensions to better support streaming, PKZIP's traditional +ZIP encryption, Info-ZIP's Unix extra fields, extra time, and +Unicode path, as well as WinZIP's AES encryption. +It can extract jar archives, __MACOSX resource forks extension +for OS X, and self-extracting zip archives. Libarchive can use either of two different strategies for reading Zip archives: a streaming strategy which is fast and can handle extremely