Просмотр исходного кода

LibArchive 2020-12-26 (227a4b97)

Code extracted from:

    https://github.com/libarchive/libarchive.git

at commit 227a4b9719a7fbeba6ba46e377ff7d953f405cd5 (v3.5.1).
LibArchive Upstream 5 лет назад
Родитель
Сommit
dadea0e5ce
66 измененных файлов с 1182 добавлено и 379 удалено
  1. 19 9
      CMakeLists.txt
  2. 0 1
      COPYING
  3. 2 2
      build/cmake/CreatePkgConfigFile.cmake
  4. 4 0
      build/cmake/config.h.in
  5. 1 1
      build/version
  6. 9 2
      libarchive/archive.h
  7. 5 5
      libarchive/archive_acl.c
  8. 1 1
      libarchive/archive_check_magic.c
  9. 23 0
      libarchive/archive_cryptor.c
  10. 9 0
      libarchive/archive_cryptor_private.h
  11. 116 116
      libarchive/archive_digest.c
  12. 4 0
      libarchive/archive_digest_private.h
  13. 77 8
      libarchive/archive_entry.c
  14. 14 1
      libarchive/archive_entry.h
  15. 16 0
      libarchive/archive_entry_private.h
  16. 2 2
      libarchive/archive_entry_stat.3
  17. 1 1
      libarchive/archive_ppmd7.c
  18. 9 8
      libarchive/archive_read.c
  19. 4 0
      libarchive/archive_read_add_passphrase.c
  20. 44 4
      libarchive/archive_read_disk_entry_from_file.c
  21. 23 23
      libarchive/archive_read_disk_posix.c
  22. 11 1
      libarchive/archive_read_filter.3
  23. 4 0
      libarchive/archive_read_open_filename.c
  24. 9 0
      libarchive/archive_read_set_format.c
  25. 83 0
      libarchive/archive_read_support_filter_by_code.c
  26. 4 19
      libarchive/archive_read_support_filter_program.c
  27. 4 0
      libarchive/archive_read_support_filter_zstd.c
  28. 15 0
      libarchive/archive_read_support_format_by_code.c
  29. 1 1
      libarchive/archive_read_support_format_cab.c
  30. 1 1
      libarchive/archive_read_support_format_empty.c
  31. 125 12
      libarchive/archive_read_support_format_mtree.c
  32. 10 4
      libarchive/archive_read_support_format_rar.c
  33. 5 8
      libarchive/archive_read_support_format_rar5.c
  34. 18 0
      libarchive/archive_read_support_format_tar.c
  35. 18 2
      libarchive/archive_read_support_format_warc.c
  36. 13 4
      libarchive/archive_read_support_format_xar.c
  37. 126 5
      libarchive/archive_read_support_format_zip.c
  38. 34 18
      libarchive/archive_string.c
  39. 1 1
      libarchive/archive_string.h
  40. 6 0
      libarchive/archive_util.c
  41. 33 9
      libarchive/archive_write.c
  42. 4 22
      libarchive/archive_write_add_filter_program.c
  43. 2 2
      libarchive/archive_write_add_filter_xz.c
  44. 73 6
      libarchive/archive_write_add_filter_zstd.c
  45. 49 3
      libarchive/archive_write_disk_posix.c
  46. 14 5
      libarchive/archive_write_disk_windows.c
  47. 31 6
      libarchive/archive_write_open.3
  48. 6 4
      libarchive/archive_write_open_fd.c
  49. 6 4
      libarchive/archive_write_open_file.c
  50. 19 2
      libarchive/archive_write_open_filename.c
  51. 6 4
      libarchive/archive_write_open_memory.c
  52. 1 0
      libarchive/archive_write_private.h
  53. 1 1
      libarchive/archive_write_set_format.c
  54. 2 2
      libarchive/archive_write_set_format_7zip.c
  55. 2 2
      libarchive/archive_write_set_format_cpio.c
  56. 1 1
      libarchive/archive_write_set_format_cpio_newc.c
  57. 2 1
      libarchive/archive_write_set_format_iso9660.c
  58. 19 30
      libarchive/archive_write_set_format_mtree.c
  59. 4 3
      libarchive/archive_write_set_format_xar.c
  60. 5 0
      libarchive/archive_write_set_format_zip.c
  61. 2 1
      libarchive/archive_write_set_options.3
  62. 2 0
      libarchive/config_freebsd.h
  63. 1 1
      libarchive/cpio.5
  64. 7 2
      libarchive/filter_fork.h
  65. 6 4
      libarchive/filter_fork_posix.c
  66. 13 4
      libarchive/filter_fork_windows.c

+ 19 - 9
CMakeLists.txt

@@ -157,32 +157,32 @@ IF (MSVC)
   # This is added into CMAKE_C_FLAGS when CMAKE_BUILD_TYPE is "Debug"
   # Enable level 4 C4062: The enumerate has no associated handler in a switch
   #                       statement and there is no default that can catch it.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4062")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14062")
   # Enable level 4 C4254: A larger bit field was assigned to a smaller bit
   #                       field.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4254")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14254")
   # Enable level 4 C4295: An array was initialized but the last character in
   #                       the array is not a null; accessing the array may
   #                       produce unexpected results.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4295")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14295")
   # Enable level 4 C4296: An unsigned variable was used in a comparison
   #                       operation with zero.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4296")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14296")
   # Enable level 4 C4389: An operation involved signed and unsigned variables.
   #                       This could result in a loss of data.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4389")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14389")
   # Enable level 4 C4505: The given function is local and not referenced in
   #                       the body of the module; therefore, the function is
   #                       dead code.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4505")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14505")
   # Enable level 4 C4514: The optimizer removed an inline function that is not
   #                       called.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4514")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14514")
   # Enable level 4 C4702: Unreachable code.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4702")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14702")
   # Enable level 4 C4706: The test value in a conditional expression was the
   #                       result of an assignment.
-  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /we4706")
+  SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /w14706")
   # /Oi option enables built-in functions.
   SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Oi")
   #################################################################
@@ -1378,6 +1378,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(strchr HAVE_STRCHR)
 CHECK_FUNCTION_EXISTS_GLIBC(strdup HAVE_STRDUP)
 CHECK_FUNCTION_EXISTS_GLIBC(strerror HAVE_STRERROR)
 CHECK_FUNCTION_EXISTS_GLIBC(strncpy_s HAVE_STRNCPY_S)
+CHECK_FUNCTION_EXISTS_GLIBC(strnlen HAVE_STRNLEN)
 CHECK_FUNCTION_EXISTS_GLIBC(strrchr HAVE_STRRCHR)
 CHECK_FUNCTION_EXISTS_GLIBC(symlink HAVE_SYMLINK)
 CHECK_FUNCTION_EXISTS_GLIBC(timegm HAVE_TIMEGM)
@@ -1449,9 +1450,13 @@ CHECK_C_SOURCE_COMPILES(
   "#include <sys/sysmacros.h>\nint main() { return major(256); }"
   MAJOR_IN_SYSMACROS)
 
+IF(ENABLE_LZMA)
 CHECK_C_SOURCE_COMPILES(
   "#include <lzma.h>\n#if LZMA_VERSION < 50020000\n#error unsupported\n#endif\nint main(void){lzma_stream_encoder_mt(0, 0); return 0;}"
   HAVE_LZMA_STREAM_ENCODER_MT)
+ELSE()
+  SET(HAVE_LZMA_STREAM_ENCODER_MT 0)
+ENDIF(ENABLE_LZMA)
 
 IF(HAVE_STRERROR_R)
   SET(HAVE_DECL_STRERROR_R 1)
@@ -2036,6 +2041,11 @@ IF(MSVC)
   ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
 ENDIF(MSVC)
 
+IF(APPLE)
+  # CC_MD5_Init() functions are deprecated on macOS 10.15, but we want to use them
+  ADD_DEFINITIONS(-Wno-deprecated-declarations)
+ENDIF(APPLE)
+
 IF(ENABLE_TEST)
   ADD_CUSTOM_TARGET(run_all_tests)
 ENDIF(ENABLE_TEST)

+ 0 - 1
COPYING

@@ -15,7 +15,6 @@ the actual statements in the files are controlling.
 * The following source files are also subject in whole or in part to
   a 3-clause UC Regents copyright; please read the individual source
   files for details:
-   libarchive/archive_entry.c
    libarchive/archive_read_support_filter_compress.c
    libarchive/archive_write_add_filter_compress.c
    libarchive/mtree.5

+ 2 - 2
build/cmake/CreatePkgConfigFile.cmake

@@ -24,10 +24,10 @@ ENDFOREACH()
 #	 thus there's a good chance it'll make some binutils versions unhappy...
 #	 This only affects Libs.private (looked up for static builds) though.
 CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in
-		${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc
+		${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc
 		@ONLY)
 # And install it, of course ;).
 IF(ENABLE_INSTALL)
-  INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc
+  INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc
           DESTINATION "lib/pkgconfig")
 ENDIF()

+ 4 - 0
build/cmake/config.h.in

@@ -1,4 +1,5 @@
 /* config.h.  Generated from build/cmake/config.h.in by cmake configure */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 
 /*
  * Ensure we have C99-style int64_t, etc, all defined.
@@ -958,6 +959,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the `strchr' function. */
 #cmakedefine HAVE_STRCHR 1
 
+/* Define to 1 if you have the `strnlen' function. */
+#cmakedefine HAVE_STRNLEN 1
+
 /* Define to 1 if you have the `strdup' function. */
 #cmakedefine HAVE_STRDUP 1
 

+ 1 - 1
build/version

@@ -1 +1 @@
-3004002
+3005001

+ 9 - 2
libarchive/archive.h

@@ -36,7 +36,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3004002
+#define	ARCHIVE_VERSION_NUMBER 3005001
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -155,7 +155,7 @@ __LA_DECL int		archive_version_number(void);
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_ONLY_STRING "3.4.2"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.5.1"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
@@ -246,6 +246,8 @@ typedef int	archive_open_callback(struct archive *, void *_client_data);
 
 typedef int	archive_close_callback(struct archive *, void *_client_data);
 
+typedef int	archive_free_callback(struct archive *, void *_client_data);
+
 /* Switches from one client data object to the next/prev client data object.
  * This is useful for reading from different data blocks such as a set of files
  * that make up one large file.
@@ -418,6 +420,7 @@ __LA_DECL int archive_read_support_compression_xz(struct archive *)
 #endif
 
 __LA_DECL int archive_read_support_filter_all(struct archive *);
+__LA_DECL int archive_read_support_filter_by_code(struct archive *, int);
 __LA_DECL int archive_read_support_filter_bzip2(struct archive *);
 __LA_DECL int archive_read_support_filter_compress(struct archive *);
 __LA_DECL int archive_read_support_filter_gzip(struct archive *);
@@ -817,9 +820,13 @@ __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 *);
+/* Deprecated; use archive_write_open2 instead */
 __LA_DECL int archive_write_open(struct archive *, void *,
 		     archive_open_callback *, archive_write_callback *,
 		     archive_close_callback *);
+__LA_DECL int archive_write_open2(struct archive *, void *,
+		     archive_open_callback *, archive_write_callback *,
+		     archive_close_callback *, archive_free_callback *);
 __LA_DECL int archive_write_open_fd(struct archive *, int _fd);
 __LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
 __LA_DECL int archive_write_open_filename_w(struct archive *,

+ 5 - 5
libarchive/archive_acl.c

@@ -595,7 +595,7 @@ archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
 				else
 					length += sizeof(uid_t) * 3 + 1;
 			} else {
-				r = archive_mstring_get_mbs_l(&ap->name, &name,
+				r = archive_mstring_get_mbs_l(a, &ap->name, &name,
 				    &len, sc);
 				if (r != 0)
 					return (0);
@@ -968,7 +968,7 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
 		else
 			prefix = NULL;
 		r = archive_mstring_get_mbs_l(
-		    &ap->name, &name, &len, sc);
+		    NULL, &ap->name, &name, &len, sc);
 		if (r != 0) {
 			free(s);
 			return (NULL);
@@ -1402,14 +1402,14 @@ isint_w(const wchar_t *start, const wchar_t *end, int *result)
 	if (start >= end)
 		return (0);
 	while (start < end) {
-		if (*start < '0' || *start > '9')
+		if (*start < L'0' || *start > L'9')
 			return (0);
 		if (n > (INT_MAX / 10) ||
-		    (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
+		    (n == INT_MAX / 10 && (*start - L'0') > INT_MAX % 10)) {
 			n = INT_MAX;
 		} else {
 			n *= 10;
-			n += *start - '0';
+			n += *start - L'0';
 		}
 		start++;
 	}

+ 1 - 1
libarchive/archive_check_magic.c

@@ -54,7 +54,7 @@ errmsg(const char *m)
 	ssize_t written;
 
 	while (s > 0) {
-		written = write(2, m, strlen(m));
+		written = write(2, m, s);
 		if (written <= 0)
 			return;
 		m += written;

+ 23 - 0
libarchive/archive_cryptor.c

@@ -347,8 +347,31 @@ aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
 static int
 aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
 {
+#if NETTLE_VERSION_MAJOR < 3
 	aes_set_encrypt_key(&ctx->ctx, ctx->key_len, ctx->key);
 	aes_encrypt(&ctx->ctx, AES_BLOCK_SIZE, ctx->encr_buf, ctx->nonce);
+#else
+	switch(ctx->key_len) {
+	case AES128_KEY_SIZE:
+		aes128_set_encrypt_key(&ctx->ctx.c128, ctx->key);
+		aes128_encrypt(&ctx->ctx.c128, AES_BLOCK_SIZE, ctx->encr_buf,
+		    ctx->nonce);
+		break;
+	case AES192_KEY_SIZE:
+		aes192_set_encrypt_key(&ctx->ctx.c192, ctx->key);
+		aes192_encrypt(&ctx->ctx.c192, AES_BLOCK_SIZE, ctx->encr_buf,
+		    ctx->nonce);
+		break;
+	case AES256_KEY_SIZE:
+		aes256_set_encrypt_key(&ctx->ctx.c256, ctx->key);
+		aes256_encrypt(&ctx->ctx.c256, AES_BLOCK_SIZE, ctx->encr_buf,
+		    ctx->nonce);
+		break;
+	default:
+		return -1;
+		break;
+	}
+#endif
 	return 0;
 }
 

+ 9 - 0
libarchive/archive_cryptor_private.h

@@ -104,9 +104,18 @@ typedef struct {
 #include <nettle/pbkdf2.h>
 #endif
 #include <nettle/aes.h>
+#include <nettle/version.h>
 
 typedef struct {
+#if NETTLE_VERSION_MAJOR < 3
 	struct aes_ctx	ctx;
+#else
+	union {
+		struct aes128_ctx c128;
+		struct aes192_ctx c192;
+		struct aes256_ctx c256;
+	}		ctx;
+#endif
 	uint8_t		key[AES_MAX_KEY_SIZE];
 	unsigned	key_len;
 	uint8_t		nonce[AES_BLOCK_SIZE];

Разница между файлами не показана из-за своего большого размера
+ 116 - 116
libarchive/archive_digest.c


+ 4 - 0
libarchive/archive_digest_private.h

@@ -30,6 +30,10 @@
 #ifndef __LIBARCHIVE_BUILD
 #error This header is only to be used internally to libarchive.
 #endif
+#ifndef __LIBARCHIVE_CONFIG_H_INCLUDED
+#error "Should have include config.h first!"
+#endif
+
 /*
  * Crypto support in various Operating Systems:
  *

+ 77 - 8
libarchive/archive_entry.c

@@ -208,6 +208,19 @@ archive_entry_clone(struct archive_entry *entry)
 
 	/* Copy encryption status */
 	entry2->encryption = entry->encryption;
+
+	/* Copy digests */
+#define copy_digest(_e2, _e, _t) \
+	memcpy(_e2->digest._t, _e->digest._t, sizeof(_e2->digest._t))
+
+	copy_digest(entry2, entry, md5);
+	copy_digest(entry2, entry, rmd160);
+	copy_digest(entry2, entry, sha1);
+	copy_digest(entry2, entry, sha256);
+	copy_digest(entry2, entry, sha384);
+	copy_digest(entry2, entry, sha512);
+
+#undef copy_digest
 	
 	/* Copy ACL data over. */
 	archive_acl_copy(&entry2->acl, &entry->acl);
@@ -353,7 +366,7 @@ archive_entry_devminor(struct archive_entry *entry)
 		return minor(entry->ae_stat.aest_dev);
 }
 
-mode_t
+__LA_MODE_T
 archive_entry_filetype(struct archive_entry *entry)
 {
 	return (AE_IFMT & entry->acl.mode);
@@ -450,7 +463,7 @@ int
 _archive_entry_gname_l(struct archive_entry *entry,
     const char **p, size_t *len, struct archive_string_conv *sc)
 {
-	return (archive_mstring_get_mbs_l(&entry->ae_gname, p, len, sc));
+	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_gname, p, len, sc));
 }
 
 const char *
@@ -504,7 +517,7 @@ _archive_entry_hardlink_l(struct archive_entry *entry,
 		*len = 0;
 		return (0);
 	}
-	return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc));
+	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_hardlink, p, len, sc));
 }
 
 la_int64_t
@@ -525,7 +538,7 @@ archive_entry_ino64(struct archive_entry *entry)
 	return (entry->ae_stat.aest_ino);
 }
 
-mode_t
+__LA_MODE_T
 archive_entry_mode(struct archive_entry *entry)
 {
 	return (entry->acl.mode);
@@ -595,10 +608,10 @@ int
 _archive_entry_pathname_l(struct archive_entry *entry,
     const char **p, size_t *len, struct archive_string_conv *sc)
 {
-	return (archive_mstring_get_mbs_l(&entry->ae_pathname, p, len, sc));
+	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_pathname, p, len, sc));
 }
 
-mode_t
+__LA_MODE_T
 archive_entry_perm(struct archive_entry *entry)
 {
 	return (~AE_IFMT & entry->acl.mode);
@@ -723,7 +736,7 @@ _archive_entry_symlink_l(struct archive_entry *entry,
 		*len = 0;
 		return (0);
 	}
-	return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc));
+	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_symlink, p, len, sc));
 }
 
 la_int64_t
@@ -769,7 +782,7 @@ int
 _archive_entry_uname_l(struct archive_entry *entry,
     const char **p, size_t *len, struct archive_string_conv *sc)
 {
-	return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc));
+	return (archive_mstring_get_mbs_l(entry->archive, &entry->ae_uname, p, len, sc));
 }
 
 int
@@ -1416,6 +1429,62 @@ archive_entry_copy_mac_metadata(struct archive_entry *entry,
   }
 }
 
+/* Digest handling */
+const unsigned char *
+archive_entry_digest(struct archive_entry *entry, int type)
+{
+	switch (type) {
+	case ARCHIVE_ENTRY_DIGEST_MD5:
+		return entry->digest.md5;
+	case ARCHIVE_ENTRY_DIGEST_RMD160:
+		return entry->digest.rmd160;
+	case ARCHIVE_ENTRY_DIGEST_SHA1:
+		return entry->digest.sha1;
+	case ARCHIVE_ENTRY_DIGEST_SHA256:
+		return entry->digest.sha256;
+	case ARCHIVE_ENTRY_DIGEST_SHA384:
+		return entry->digest.sha384;
+	case ARCHIVE_ENTRY_DIGEST_SHA512:
+		return entry->digest.sha512;
+	default:
+		return NULL;
+	}
+}
+
+int
+archive_entry_set_digest(struct archive_entry *entry, int type,
+    const unsigned char *digest)
+{
+#define copy_digest(_e, _t, _d)\
+	memcpy(_e->digest._t, _d, sizeof(_e->digest._t))
+
+	switch (type) {
+	case ARCHIVE_ENTRY_DIGEST_MD5:
+		copy_digest(entry, md5, digest);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_RMD160:
+		copy_digest(entry, rmd160, digest);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA1:
+		copy_digest(entry, sha1, digest);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA256:
+		copy_digest(entry, sha256, digest);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA384:
+		copy_digest(entry, sha384, digest);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA512:
+		copy_digest(entry, sha512, digest);
+		break;
+	default:
+		return ARCHIVE_WARN;
+	}
+
+	return ARCHIVE_OK;
+#undef copy_digest
+}
+
 /*
  * ACL management.  The following would, of course, be a lot simpler
  * if: 1) the last draft of POSIX.1e were a really thorough and

+ 14 - 1
libarchive/archive_entry.h

@@ -30,7 +30,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3004002
+#define	ARCHIVE_VERSION_NUMBER 3005001
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
@@ -396,6 +396,19 @@ __LA_DECL void	archive_entry_copy_stat(struct archive_entry *, const struct stat
 __LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);
 __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
 
+/*
+ * Digest routine. This is used to query the raw hex digest for the
+ * given entry. The type of digest is provided as an argument.
+ */
+#define ARCHIVE_ENTRY_DIGEST_MD5              0x00000001
+#define ARCHIVE_ENTRY_DIGEST_RMD160           0x00000002
+#define ARCHIVE_ENTRY_DIGEST_SHA1             0x00000003
+#define ARCHIVE_ENTRY_DIGEST_SHA256           0x00000004
+#define ARCHIVE_ENTRY_DIGEST_SHA384           0x00000005
+#define ARCHIVE_ENTRY_DIGEST_SHA512           0x00000006
+
+__LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */);
+
 /*
  * ACL routines.  This used to simply store and return text-format ACL
  * strings, but that proved insufficient for a number of reasons:

+ 16 - 0
libarchive/archive_entry_private.h

@@ -50,6 +50,15 @@ struct ae_sparse {
 	int64_t	 length;
 };
 
+struct ae_digest {
+	unsigned char md5[16];
+	unsigned char rmd160[20];
+	unsigned char sha1[20];
+	unsigned char sha256[32];
+	unsigned char sha384[48];
+	unsigned char sha512[64];
+};
+
 /*
  * Description of an archive entry.
  *
@@ -162,6 +171,9 @@ struct archive_entry {
 	void *mac_metadata;
 	size_t mac_metadata_size;
 
+	/* Digest support. */
+	struct ae_digest digest;
+
 	/* ACL support. */
 	struct archive_acl    acl;
 
@@ -181,4 +193,8 @@ 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 */

+ 2 - 2
libarchive/archive_entry_stat.3

@@ -215,9 +215,9 @@ and
 set and unset the size, respectively.
 .Pp
 The number of references (hardlinks) can be obtained by calling
-.Fn archive_entry_nlinks
+.Fn archive_entry_nlink
 and set with
-.Fn archive_entry_set_nlinks .
+.Fn archive_entry_set_nlink .
 .Ss Identifying unique files
 The functions
 .Fn archive_entry_dev

+ 1 - 1
libarchive/archive_ppmd7.c

@@ -4,7 +4,7 @@ This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
 
 #include "archive_platform.h"
 
-#include <memory.h>
+#include <stdlib.h>
 
 #include "archive_ppmd7_private.h"
 

+ 9 - 8
libarchive/archive_read.c

@@ -892,15 +892,16 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 			len = a->read_data_remaining;
 			if (len > s)
 				len = s;
-			if (len)
+			if (len) {
 				memcpy(dest, a->read_data_block, len);
-			s -= len;
-			a->read_data_block += len;
-			a->read_data_remaining -= len;
-			a->read_data_output_offset += len;
-			a->read_data_offset += len;
-			dest += len;
-			bytes_read += len;
+				s -= len;
+				a->read_data_block += len;
+				a->read_data_remaining -= len;
+				a->read_data_output_offset += len;
+				a->read_data_offset += len;
+				dest += len;
+				bytes_read += len;
+			}
 		}
 	}
 	a->read_data_is_posix_read = 0;

+ 4 - 0
libarchive/archive_read_add_passphrase.c

@@ -57,6 +57,10 @@ insert_passphrase_to_head(struct archive_read *a,
 {
 	p->next = a->passphrases.first;
 	a->passphrases.first = p;
+	if (&a->passphrases.first == a->passphrases.last) {
+		a->passphrases.last = &p->next;
+		p->next = NULL;
+	}
 }
 
 static struct archive_read_passphrase *

+ 44 - 4
libarchive/archive_read_disk_entry_from_file.c

@@ -103,6 +103,10 @@ __FBSDID("$FreeBSD");
 
 static int setup_mac_metadata(struct archive_read_disk *,
     struct archive_entry *, int *fd);
+#ifdef ARCHIVE_XATTR_FREEBSD
+static int setup_xattrs_namespace(struct archive_read_disk *,
+    struct archive_entry *, int *, int);
+#endif
 static int setup_xattrs(struct archive_read_disk *,
     struct archive_entry *, int *fd);
 static int setup_sparse(struct archive_read_disk *,
@@ -701,14 +705,13 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
 }
 
 static int
-setup_xattrs(struct archive_read_disk *a,
-    struct archive_entry *entry, int *fd)
+setup_xattrs_namespace(struct archive_read_disk *a,
+    struct archive_entry *entry, int *fd, int namespace)
 {
 	char buff[512];
 	char *list, *p;
 	ssize_t list_size;
 	const char *path;
-	int namespace = EXTATTR_NAMESPACE_USER;
 
 	path = NULL;
 
@@ -727,6 +730,8 @@ setup_xattrs(struct archive_read_disk *a,
 
 	if (list_size == -1 && errno == EOPNOTSUPP)
 		return (ARCHIVE_OK);
+	if (list_size == -1 && errno == EPERM)
+		return (ARCHIVE_OK);
 	if (list_size == -1) {
 		archive_set_error(&a->archive, errno,
 			"Couldn't list extended attributes");
@@ -760,7 +765,17 @@ setup_xattrs(struct archive_read_disk *a,
 		size_t len = 255 & (int)*p;
 		char *name;
 
-		strcpy(buff, "user.");
+		if (namespace == EXTATTR_NAMESPACE_SYSTEM) {
+			if (!strcmp(p + 1, "nfs4.acl") ||
+			    !strcmp(p + 1, "posix1e.acl_access") ||
+			    !strcmp(p + 1, "posix1e.acl_default")) {
+				p += 1 + len;
+				continue;
+			}
+			strcpy(buff, "system.");
+		} else {
+			strcpy(buff, "user.");
+		}
 		name = buff + strlen(buff);
 		memcpy(name, p + 1, len);
 		name[len] = '\0';
@@ -772,6 +787,31 @@ setup_xattrs(struct archive_read_disk *a,
 	return (ARCHIVE_OK);
 }
 
+static int
+setup_xattrs(struct archive_read_disk *a,
+    struct archive_entry *entry, int *fd)
+{
+	int namespaces[2];
+	int i, res;
+
+	namespaces[0] = EXTATTR_NAMESPACE_USER;
+	namespaces[1] = EXTATTR_NAMESPACE_SYSTEM;
+
+	for (i = 0; i < 2; i++) {
+		res = setup_xattrs_namespace(a, entry, fd,
+		    namespaces[i]);
+		switch (res) {
+			case (ARCHIVE_OK):
+			case (ARCHIVE_WARN):
+				break;
+			default:
+				return (res);
+		}
+	}
+
+	return (ARCHIVE_OK);
+}
+
 #else
 
 /*

+ 23 - 23
libarchive/archive_read_disk_posix.c

@@ -1658,7 +1658,7 @@ static int
 setup_current_filesystem(struct archive_read_disk *a)
 {
 	struct tree *t = a->tree;
-	struct statvfs sfs;
+	struct statvfs svfs;
 	int r, xr = 0;
 
 	t->current_filesystem->synthetic = -1;
@@ -1667,16 +1667,16 @@ setup_current_filesystem(struct archive_read_disk *a)
 		return (ARCHIVE_FAILED);
 	}
 	if (tree_current_is_symblic_link_target(t)) {
-		r = statvfs(tree_current_access_path(t), &sfs);
+		r = statvfs(tree_current_access_path(t), &svfs);
 		if (r == 0)
 			xr = get_xfer_size(t, -1, tree_current_access_path(t));
 	} else {
 #ifdef HAVE_FSTATVFS
-		r = fstatvfs(tree_current_dir_fd(t), &sfs);
+		r = fstatvfs(tree_current_dir_fd(t), &svfs);
 		if (r == 0)
 			xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
 #else
-		r = statvfs(".", &sfs);
+		r = statvfs(".", &svfs);
 		if (r == 0)
 			xr = get_xfer_size(t, -1, ".");
 #endif
@@ -1688,30 +1688,30 @@ setup_current_filesystem(struct archive_read_disk *a)
 	} else if (xr == 1) {
 		/* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN
 		 * for pathconf() function. */
-		t->current_filesystem->xfer_align = sfs.f_frsize;
+		t->current_filesystem->xfer_align = svfs.f_frsize;
 		t->current_filesystem->max_xfer_size = -1;
 #if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
-		t->current_filesystem->min_xfer_size = sfs.f_iosize;
-		t->current_filesystem->incr_xfer_size = sfs.f_iosize;
+		t->current_filesystem->min_xfer_size = svfs.f_iosize;
+		t->current_filesystem->incr_xfer_size = svfs.f_iosize;
 #else
-		t->current_filesystem->min_xfer_size = sfs.f_bsize;
-		t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+		t->current_filesystem->min_xfer_size = svfs.f_bsize;
+		t->current_filesystem->incr_xfer_size = svfs.f_bsize;
 #endif
 	}
-	if (sfs.f_flag & ST_LOCAL)
+	if (svfs.f_flag & ST_LOCAL)
 		t->current_filesystem->remote = 0;
 	else
 		t->current_filesystem->remote = 1;
 
 #if defined(ST_NOATIME)
-	if (sfs.f_flag & ST_NOATIME)
+	if (svfs.f_flag & ST_NOATIME)
 		t->current_filesystem->noatime = 1;
 	else
 #endif
 		t->current_filesystem->noatime = 0;
 
 	/* Set maximum filename length. */
-	t->current_filesystem->name_max = sfs.f_namemax;
+	t->current_filesystem->name_max = svfs.f_namemax;
 	return (ARCHIVE_OK);
 }
 
@@ -1840,7 +1840,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 #if defined(HAVE_STATVFS)
 	if (svfs.f_flag & ST_NOATIME)
 #else
-	if (sfs.f_flag & ST_NOATIME)
+	if (sfs.f_flags & ST_NOATIME)
 #endif
 		t->current_filesystem->noatime = 1;
 	else
@@ -1864,7 +1864,7 @@ static int
 setup_current_filesystem(struct archive_read_disk *a)
 {
 	struct tree *t = a->tree;
-	struct statvfs sfs;
+	struct statvfs svfs;
 	int r, xr = 0;
 
 	t->current_filesystem->synthetic = -1;/* Not supported */
@@ -1883,7 +1883,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 			    "openat failed");
 			return (ARCHIVE_FAILED);
 		}
-		r = fstatvfs(fd, &sfs);
+		r = fstatvfs(fd, &svfs);
 		if (r == 0)
 			xr = get_xfer_size(t, fd, NULL);
 		close(fd);
@@ -1892,13 +1892,13 @@ setup_current_filesystem(struct archive_read_disk *a)
 			archive_set_error(&a->archive, errno, "fchdir failed");
 			return (ARCHIVE_FAILED);
 		}
-		r = statvfs(tree_current_access_path(t), &sfs);
+		r = statvfs(tree_current_access_path(t), &svfs);
 		if (r == 0)
 			xr = get_xfer_size(t, -1, tree_current_access_path(t));
 #endif
 	} else {
 #ifdef HAVE_FSTATVFS
-		r = fstatvfs(tree_current_dir_fd(t), &sfs);
+		r = fstatvfs(tree_current_dir_fd(t), &svfs);
 		if (r == 0)
 			xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
 #else
@@ -1906,7 +1906,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 			archive_set_error(&a->archive, errno, "fchdir failed");
 			return (ARCHIVE_FAILED);
 		}
-		r = statvfs(".", &sfs);
+		r = statvfs(".", &svfs);
 		if (r == 0)
 			xr = get_xfer_size(t, -1, ".");
 #endif
@@ -1918,14 +1918,14 @@ setup_current_filesystem(struct archive_read_disk *a)
 		return (ARCHIVE_FAILED);
 	} else if (xr == 1) {
 		/* pathconf(_PC_REX_*) operations are not supported. */
-		t->current_filesystem->xfer_align = sfs.f_frsize;
+		t->current_filesystem->xfer_align = svfs.f_frsize;
 		t->current_filesystem->max_xfer_size = -1;
-		t->current_filesystem->min_xfer_size = sfs.f_bsize;
-		t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+		t->current_filesystem->min_xfer_size = svfs.f_bsize;
+		t->current_filesystem->incr_xfer_size = svfs.f_bsize;
 	}
 
 #if defined(ST_NOATIME)
-	if (sfs.f_flag & ST_NOATIME)
+	if (svfs.f_flag & ST_NOATIME)
 		t->current_filesystem->noatime = 1;
 	else
 #endif
@@ -1933,7 +1933,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 
 #if defined(USE_READDIR_R)
 	/* Set maximum filename length. */
-	t->current_filesystem->name_max = sfs.f_namemax;
+	t->current_filesystem->name_max = svfs.f_namemax;
 #endif
 	return (ARCHIVE_OK);
 }

+ 11 - 1
libarchive/archive_read_filter.3

@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 14, 2014
+.Dd June 9, 2020
 .Dt ARCHIVE_READ_FILTER 3
 .Os
 .Sh NAME
@@ -50,6 +50,8 @@ Streaming Archive Library (libarchive, -larchive)
 .Ft int
 .Fn archive_read_support_filter_all "struct archive *"
 .Ft int
+.Fn archive_read_support_filter_by_code "struct archive *" "int"
+.Ft int
 .Fn archive_read_support_filter_bzip2 "struct archive *"
 .Ft int
 .Fn archive_read_support_filter_compress "struct archive *"
@@ -116,6 +118,14 @@ Note that
 is always enabled by default.
 .It Fn archive_read_support_filter_all
 Enables all available decompression filters.
+.It Fn archive_read_support_filter_by_code
+Enables a single filter specified by the filter code.
+This function does not work with
+.Cm ARCHIVE_FILTER_PROGRAM .
+Note: In statically-linked executables, this will cause
+your program to include support for every filter.
+If executable size is a concern, you may wish to avoid
+using this function.
 .It Fn archive_read_support_filter_program
 Data is fed through the specified external program before being dearchived.
 Note that this disables automatic detection of the compression format,

+ 4 - 0
libarchive/archive_read_open_filename.c

@@ -221,7 +221,9 @@ file_open(struct archive *a, void *client_data)
 	struct read_file_data *mine = (struct read_file_data *)client_data;
 	void *buffer;
 	const char *filename = NULL;
+#if defined(_WIN32) && !defined(__CYGWIN__)
 	const wchar_t *wfilename = NULL;
+#endif
 	int fd = -1;
 	int is_disk_like = 0;
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -281,10 +283,12 @@ file_open(struct archive *a, void *client_data)
 #endif
 	}
 	if (fstat(fd, &st) != 0) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
 		if (mine->filename_type == FNT_WCS)
 			archive_set_error(a, errno, "Can't stat '%S'",
 			    wfilename);
 		else
+#endif
 			archive_set_error(a, errno, "Can't stat '%s'",
 			    filename);
 		goto fail;

+ 9 - 0
libarchive/archive_read_set_format.c

@@ -61,6 +61,9 @@ archive_read_set_format(struct archive *_a, int code)
     case ARCHIVE_FORMAT_CPIO:
       strcpy(str, "cpio");
       break;
+    case ARCHIVE_FORMAT_EMPTY:
+      strcpy(str, "empty");
+      break;
     case ARCHIVE_FORMAT_ISO9660:
       strcpy(str, "iso9660");
       break;
@@ -76,9 +79,15 @@ archive_read_set_format(struct archive *_a, int code)
     case ARCHIVE_FORMAT_RAR_V5:
       strcpy(str, "rar5");
       break;
+    case ARCHIVE_FORMAT_RAW:
+      strcpy(str, "raw");
+      break;
     case ARCHIVE_FORMAT_TAR:
       strcpy(str, "tar");
       break;
+    case ARCHIVE_FORMAT_WARC:
+      strcpy(str, "warc");
+      break;
     case ARCHIVE_FORMAT_XAR:
       strcpy(str, "xar");
       break;

+ 83 - 0
libarchive/archive_read_support_filter_by_code.c

@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2020 Martin Matuska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive.h"
+#include "archive_private.h"
+
+int
+archive_read_support_filter_by_code(struct archive *a, int filter_code)
+{
+	archive_check_magic(a, ARCHIVE_READ_MAGIC,
+	    ARCHIVE_STATE_NEW, "archive_read_support_filter_by_code");
+
+	switch (filter_code) {
+	case ARCHIVE_FILTER_NONE:
+		return archive_read_support_filter_none(a);
+		break;
+	case ARCHIVE_FILTER_GZIP:
+		return archive_read_support_filter_gzip(a);
+		break;
+	case ARCHIVE_FILTER_BZIP2:
+		return archive_read_support_filter_bzip2(a);
+		break;
+	case ARCHIVE_FILTER_COMPRESS:
+		return archive_read_support_filter_compress(a);
+		break;
+	case ARCHIVE_FILTER_LZMA:
+		return archive_read_support_filter_lzma(a);
+		break;
+	case ARCHIVE_FILTER_XZ:
+		return archive_read_support_filter_xz(a);
+		break;
+	case ARCHIVE_FILTER_UU:
+		return archive_read_support_filter_uu(a);
+		break;
+	case ARCHIVE_FILTER_RPM:
+		return archive_read_support_filter_rpm(a);
+		break;
+	case ARCHIVE_FILTER_LZIP:
+		return archive_read_support_filter_lzip(a);
+		break;
+	case ARCHIVE_FILTER_LRZIP:
+		return archive_read_support_filter_lrzip(a);
+		break;
+	case ARCHIVE_FILTER_LZOP:
+		return archive_read_support_filter_lzop(a);
+		break;
+	case ARCHIVE_FILTER_GRZIP:
+		return archive_read_support_filter_grzip(a);
+		break;
+	case ARCHIVE_FILTER_LZ4:
+		return archive_read_support_filter_lz4(a);
+		break;
+	case ARCHIVE_FILTER_ZSTD:
+		return archive_read_support_filter_zstd(a);
+		break;
+	}
+	return (ARCHIVE_FATAL);
+}

+ 4 - 19
libarchive/archive_read_support_filter_program.c

@@ -400,7 +400,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
 	static const size_t out_buf_len = 65536;
 	char *out_buf;
 	const char *prefix = "Program: ";
-	pid_t child;
+	int ret;
 	size_t l;
 
 	l = strlen(prefix) + strlen(cmd) + 1;
@@ -426,9 +426,9 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
 	state->out_buf = out_buf;
 	state->out_buf_len = out_buf_len;
 
-	child = __archive_create_child(cmd, &state->child_stdin,
-	    &state->child_stdout);
-	if (child == -1) {
+	ret = __archive_create_child(cmd, &state->child_stdin,
+	    &state->child_stdout, &state->child);
+	if (ret != ARCHIVE_OK) {
 		free(state->out_buf);
 		archive_string_free(&state->description);
 		free(state);
@@ -437,21 +437,6 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
 		    cmd);
 		return (ARCHIVE_FATAL);
 	}
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
-	if (state->child == NULL) {
-		child_stop(self, state);
-		free(state->out_buf);
-		archive_string_free(&state->description);
-		free(state);
-		archive_set_error(&self->archive->archive, EINVAL,
-		    "Can't initialize filter; unable to run program \"%s\"",
-		    cmd);
-		return (ARCHIVE_FATAL);
-	}
-#else
-	state->child = child;
-#endif
 
 	self->data = state;
 	self->read = program_filter_read;

+ 4 - 0
libarchive/archive_read_support_filter_zstd.c

@@ -119,6 +119,8 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
 
 	/* Zstd frame magic values */
 	const unsigned zstd_magic = 0xFD2FB528U;
+	const unsigned zstd_magic_skippable_start = 0x184D2A50U;
+	const unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
 
 	(void) self; /* UNUSED */
 
@@ -129,6 +131,8 @@ zstd_bidder_bid(struct archive_read_filter_bidder *self,
 	prefix = archive_le32dec(buffer);
 	if (prefix == zstd_magic)
 		return (32);
+	if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start)
+		return (32);
 
 	return (0);
 }

+ 15 - 0
libarchive/archive_read_support_format_by_code.c

@@ -26,6 +26,10 @@
 #include "archive_platform.h"
 __FBSDID("$FreeBSD$");
 
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
 #include "archive.h"
 #include "archive_private.h"
 
@@ -48,6 +52,9 @@ archive_read_support_format_by_code(struct archive *a, int format_code)
 	case ARCHIVE_FORMAT_CPIO:
 		return archive_read_support_format_cpio(a);
 		break;
+	case ARCHIVE_FORMAT_EMPTY:
+		return archive_read_support_format_empty(a);
+		break;
 	case ARCHIVE_FORMAT_ISO9660:
 		return archive_read_support_format_iso9660(a);
 		break;
@@ -63,9 +70,15 @@ archive_read_support_format_by_code(struct archive *a, int format_code)
 	case ARCHIVE_FORMAT_RAR_V5:
 		return archive_read_support_format_rar5(a);
 		break;
+	case ARCHIVE_FORMAT_RAW:
+		return archive_read_support_format_raw(a);
+		break;
 	case ARCHIVE_FORMAT_TAR:
 		return archive_read_support_format_tar(a);
 		break;
+	case ARCHIVE_FORMAT_WARC:
+		return archive_read_support_format_warc(a);
+		break;
 	case ARCHIVE_FORMAT_XAR:
 		return archive_read_support_format_xar(a);
 		break;
@@ -73,5 +86,7 @@ archive_read_support_format_by_code(struct archive *a, int format_code)
 		return archive_read_support_format_zip(a);
 		break;
 	}
+	archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+	    "Invalid format code specified");
 	return (ARCHIVE_FATAL);
 }

+ 1 - 1
libarchive/archive_read_support_format_cab.c

@@ -1172,7 +1172,7 @@ cab_checksum_finish(struct archive_read *a)
 	    cfdata->memimage + CFDATA_cbData, l, cfdata->sum_calculated);
 	if (cfdata->sum_calculated != cfdata->sum) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Checksum error CFDATA[%d] %x:%x in %d bytes",
+		    "Checksum error CFDATA[%d] %" PRIx32 ":%" PRIx32 " in %d bytes",
 		    cab->entry_cffolder->cfdata_index -1,
 		    cfdata->sum, cfdata->sum_calculated,
 		    cfdata->compressed_size);

+ 1 - 1
libarchive/archive_read_support_format_empty.c

@@ -47,7 +47,7 @@ archive_read_support_format_empty(struct archive *_a)
 
 	r = __archive_read_register_format(a,
 	    NULL,
-	    NULL,
+	    "empty",
 	    archive_read_format_empty_bid,
 	    NULL,
 	    archive_read_format_empty_read_header,

+ 125 - 12
libarchive/archive_read_support_format_mtree.c

@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
 
 #include "archive.h"
 #include "archive_entry.h"
+#include "archive_entry_private.h"
 #include "archive_private.h"
 #include "archive_rb.h"
 #include "archive_read_private.h"
@@ -135,6 +136,9 @@ static int	skip(struct archive_read *a);
 static int	read_header(struct archive_read *,
 		    struct archive_entry *);
 static int64_t	mtree_atol(char **, int base);
+#ifndef HAVE_STRNLEN
+static size_t	mtree_strnlen(const char *, size_t);
+#endif
 
 /*
  * There's no standard for TIME_T_MAX/TIME_T_MIN.  So we compute them
@@ -186,6 +190,24 @@ get_time_t_min(void)
 #endif
 }
 
+#ifdef HAVE_STRNLEN
+#define mtree_strnlen(a,b) strnlen(a,b)
+#else
+static size_t
+mtree_strnlen(const char *p, size_t maxlen)
+{
+	size_t i;
+
+	for (i = 0; i <= maxlen; i++) {
+		if (p[i] == 0)
+			break;
+	}
+	if (i > maxlen)
+		return (-1);/* invalid */
+	return (i);
+}
+#endif
+
 static int
 archive_read_format_mtree_options(struct archive_read *a,
     const char *key, const char *val)
@@ -1482,6 +1504,84 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
 #undef MAX_PACK_ARGS
 }
 
+static int
+parse_hex_nibble(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return 10 + c - 'a';
+#if 0
+	/* XXX: Is uppercase something we should support? */
+	if (c >= 'A' && c <= 'F')
+		return 10 + c - 'A';
+#endif
+
+	return -1;
+}
+
+static int
+parse_digest(struct archive_read *a, struct archive_entry *entry,
+    const char *digest, int type)
+{
+	unsigned char digest_buf[64];
+	int high, low;
+	size_t i, j, len;
+
+	switch (type) {
+	case ARCHIVE_ENTRY_DIGEST_MD5:
+		len = sizeof(entry->digest.md5);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_RMD160:
+		len = sizeof(entry->digest.rmd160);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA1:
+		len = sizeof(entry->digest.sha1);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA256:
+		len = sizeof(entry->digest.sha256);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA384:
+		len = sizeof(entry->digest.sha384);
+		break;
+	case ARCHIVE_ENTRY_DIGEST_SHA512:
+		len = sizeof(entry->digest.sha512);
+		break;
+	default:
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+			"Internal error: Unknown digest type");
+		return ARCHIVE_FATAL;
+	}
+
+	if (len > sizeof(digest_buf)) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+			"Internal error: Digest storage too large");
+		return ARCHIVE_FATAL;
+	}
+
+	len *= 2;
+
+	if (mtree_strnlen(digest, len+1) != len) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+				  "incorrect digest length, ignoring");
+		return ARCHIVE_WARN;
+	}
+
+	for (i = 0, j = 0; i < len; i += 2, j++) {
+		high = parse_hex_nibble(digest[i]);
+		low = parse_hex_nibble(digest[i+1]);
+		if (high == -1 || low == -1) {
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+					  "invalid digest data, ignoring");
+			return ARCHIVE_WARN;
+		}
+
+		digest_buf[j] = high << 4 | low;
+	}
+
+	return archive_entry_set_digest(entry, type, digest_buf);
+}
+
 /*
  * Parse a single keyword and its value.
  */
@@ -1580,8 +1680,10 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		}
 		__LA_FALLTHROUGH;
 	case 'm':
-		if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
-			break;
+		if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) {
+			return parse_digest(a, entry, val,
+			    ARCHIVE_ENTRY_DIGEST_MD5);
+		}
 		if (strcmp(key, "mode") == 0) {
 			if (val[0] >= '0' && val[0] <= '7') {
 				*parsed_kws |= MTREE_HAS_PERM;
@@ -1617,21 +1719,32 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 			return r;
 		}
 		if (strcmp(key, "rmd160") == 0 ||
-		    strcmp(key, "rmd160digest") == 0)
-			break;
+		    strcmp(key, "rmd160digest") == 0) {
+			return parse_digest(a, entry, val,
+			    ARCHIVE_ENTRY_DIGEST_RMD160);
+		}
 		__LA_FALLTHROUGH;
 	case 's':
-		if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0)
-			break;
+		if (strcmp(key, "sha1") == 0 ||
+		    strcmp(key, "sha1digest") == 0) {
+			return parse_digest(a, entry, val,
+			    ARCHIVE_ENTRY_DIGEST_SHA1);
+		}
 		if (strcmp(key, "sha256") == 0 ||
-		    strcmp(key, "sha256digest") == 0)
-			break;
+		    strcmp(key, "sha256digest") == 0) {
+			return parse_digest(a, entry, val,
+			    ARCHIVE_ENTRY_DIGEST_SHA256);
+		}
 		if (strcmp(key, "sha384") == 0 ||
-		    strcmp(key, "sha384digest") == 0)
-			break;
+		    strcmp(key, "sha384digest") == 0) {
+			return parse_digest(a, entry, val,
+			    ARCHIVE_ENTRY_DIGEST_SHA384);
+		}
 		if (strcmp(key, "sha512") == 0 ||
-		    strcmp(key, "sha512digest") == 0)
-			break;
+		    strcmp(key, "sha512digest") == 0) {
+			return parse_digest(a, entry, val,
+			    ARCHIVE_ENTRY_DIGEST_SHA512);
+		}
 		if (strcmp(key, "size") == 0) {
 			archive_entry_set_size(entry, mtree_atol(&val, 10));
 			break;

+ 10 - 4
libarchive/archive_read_support_format_rar.c

@@ -151,6 +151,9 @@
 #undef minimum
 #define minimum(a, b)	((a)<(b)?(a):(b))
 
+/* Stack overflow check */
+#define MAX_COMPRESS_DEPTH 1024
+
 /* Fields common to all headers */
 struct rar_header
 {
@@ -340,7 +343,7 @@ static int read_symlink_stored(struct archive_read *, struct archive_entry *,
 static int read_data_stored(struct archive_read *, const void **, size_t *,
                             int64_t *);
 static int read_data_compressed(struct archive_read *, const void **, size_t *,
-                          int64_t *);
+                          int64_t *, size_t);
 static int rar_br_preparation(struct archive_read *, struct rar_br *);
 static int parse_codes(struct archive_read *);
 static void free_codes(struct archive_read *);
@@ -1026,7 +1029,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
   case COMPRESS_METHOD_NORMAL:
   case COMPRESS_METHOD_GOOD:
   case COMPRESS_METHOD_BEST:
-    ret = read_data_compressed(a, buff, size, offset);
+    ret = read_data_compressed(a, buff, size, offset, 0);
     if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN) {
       __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
       rar->start_new_table = 1;
@@ -1883,8 +1886,11 @@ read_data_stored(struct archive_read *a, const void **buff, size_t *size,
 
 static int
 read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
-               int64_t *offset)
+               int64_t *offset, size_t looper)
 {
+  if (looper++ > MAX_COMPRESS_DEPTH)
+    return (ARCHIVE_FATAL);
+
   struct rar *rar;
   int64_t start, end, actualend;
   size_t bs;
@@ -1982,7 +1988,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
         {
           case 0:
             rar->start_new_table = 1;
-            return read_data_compressed(a, buff, size, offset);
+            return read_data_compressed(a, buff, size, offset, looper);
 
           case 2:
             rar->ppmd_eod = 1;/* End Of ppmd Data. */

+ 5 - 8
libarchive/archive_read_support_format_rar5.c

@@ -3084,12 +3084,6 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
 
 			continue;
 		}
-
-		/* The program counter shouldn't reach here. */
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Unsupported block code: 0x%x", num);
-
-		return ARCHIVE_FATAL;
 	}
 
 	return ARCHIVE_OK;
@@ -3837,7 +3831,7 @@ static int verify_checksums(struct archive_read* a) {
 
 				DEBUG_CODE {
 					printf("Checksum error: CRC32 "
-					    "(was: %08x, expected: %08x)\n",
+					    "(was: %08" PRIx32 ", expected: %08" PRIx32 ")\n",
 					    rar->file.calculated_crc32,
 					    rar->file.stored_crc32);
 				}
@@ -3851,7 +3845,7 @@ static int verify_checksums(struct archive_read* a) {
 			} else {
 				DEBUG_CODE {
 					printf("Checksum OK: CRC32 "
-					    "(%08x/%08x)\n",
+					    "(%08" PRIx32 "/%08" PRIx32 ")\n",
 					    rar->file.stored_crc32,
 					    rar->file.calculated_crc32);
 				}
@@ -3912,6 +3906,9 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
 	int ret;
 	struct rar5* rar = get_context(a);
 
+	if (size)
+		*size = 0;
+
 	if(rar->file.dir > 0) {
 		/* Don't process any data if this file entry was declared
 		 * as a directory. This is needed, because entries marked as

+ 18 - 0
libarchive/archive_read_support_format_tar.c

@@ -1796,6 +1796,16 @@ pax_attribute_schily_xattr(struct archive_entry *entry,
 	return 0;
 }
 
+static int
+pax_attribute_rht_security_selinux(struct archive_entry *entry,
+	const char *value, size_t value_length)
+{
+	archive_entry_xattr_add_entry(entry, "security.selinux",
+            value, value_length);
+
+	return 0;
+}
+
 static int
 pax_attribute_acl(struct archive_read *a, struct tar *tar,
     struct archive_entry *entry, const char *value, int type)
@@ -1966,6 +1976,14 @@ pax_attribute(struct archive_read *a, struct tar *tar,
 		if (memcmp(key, "LIBARCHIVE.xattr.", 17) == 0)
 			pax_attribute_xattr(entry, key, value);
 		break;
+	case 'R':
+		/* GNU tar uses RHT.security header to store SELinux xattrs
+		 * SCHILY.xattr.security.selinux == RHT.security.selinux */
+		if (strcmp(key, "RHT.security.selinux") == 0) {
+			pax_attribute_rht_security_selinux(entry, value,
+			    value_length);
+			}
+		break;
 	case 'S':
 		/* We support some keys used by the "star" archiver */
 		if (strcmp(key, "SCHILY.acl.access") == 0) {

+ 18 - 2
libarchive/archive_read_support_format_warc.c

@@ -127,7 +127,7 @@ static int _warc_skip(struct archive_read *a);
 static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);
 
 /* private routines */
-static unsigned int _warc_rdver(const char buf[10], size_t bsz);
+static unsigned int _warc_rdver(const char *buf, size_t bsz);
 static unsigned int _warc_rdtyp(const char *buf, size_t bsz);
 static warc_string_t _warc_rduri(const char *buf, size_t bsz);
 static ssize_t _warc_rdlen(const char *buf, size_t bsz);
@@ -337,6 +337,14 @@ start_over:
 			mtime = rtime;
 		}
 		break;
+	case WT_NONE:
+	case WT_INFO:
+	case WT_META:
+	case WT_REQ:
+	case WT_RVIS:
+	case WT_CONV:
+	case WT_CONT:
+	case LAST_WT:
 	default:
 		fnam.len = 0U;
 		fnam.str = NULL;
@@ -361,6 +369,14 @@ start_over:
 			break;
 		}
 		/* FALLTHROUGH */
+	case WT_NONE:
+	case WT_INFO:
+	case WT_META:
+	case WT_REQ:
+	case WT_RVIS:
+	case WT_CONV:
+	case WT_CONT:
+	case LAST_WT:
 	default:
 		/* consume the content and start over */
 		_warc_skip(a);
@@ -427,7 +443,7 @@ _warc_skip(struct archive_read *a)
 static void*
 deconst(const void *c)
 {
-	return (char *)0x1 + (((const char *)c) - (const char *)0x1);
+	return (void *)(uintptr_t)c;
 }
 
 static char*

+ 13 - 4
libarchive/archive_read_support_format_xar.c

@@ -458,6 +458,11 @@ archive_read_support_format_xar(struct archive *_a)
 		return (ARCHIVE_FATAL);
 	}
 
+	/* initialize xar->file_queue */
+	xar->file_queue.allocated = 0;
+	xar->file_queue.used = 0;
+	xar->file_queue.files = NULL;
+
 	r = __archive_read_register_format(a,
 	    xar,
 	    "xar",
@@ -1221,10 +1226,12 @@ heap_add_entry(struct archive_read *a,
 	/* Expand our pending files list as necessary. */
 	if (heap->used >= heap->allocated) {
 		struct xar_file **new_pending_files;
-		int new_size = heap->allocated * 2;
+		int new_size;
 
 		if (heap->allocated < 1024)
 			new_size = 1024;
+		else
+			new_size = heap->allocated * 2;
 		/* Overflow might keep us from growing the list. */
 		if (new_size <= heap->allocated) {
 			archive_set_error(&a->archive,
@@ -1238,9 +1245,11 @@ heap_add_entry(struct archive_read *a,
 			    ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 		}
-		memcpy(new_pending_files, heap->files,
-		    heap->allocated * sizeof(new_pending_files[0]));
-		free(heap->files);
+		if (heap->allocated) {
+			memcpy(new_pending_files, heap->files,
+			    heap->allocated * sizeof(new_pending_files[0]));
+			free(heap->files);
+		}
 		heap->files = new_pending_files;
 		heap->allocated = new_size;
 	}

+ 126 - 5
libarchive/archive_read_support_format_zip.c

@@ -899,6 +899,81 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
 	return ARCHIVE_OK;
 }
 
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+/*
+ * Auxiliary function to uncompress data chunk from zipx archive
+ * (zip with lzma compression).
+ */
+static int
+zipx_lzma_uncompress_buffer(const char *compressed_buffer,
+	size_t compressed_buffer_size,
+	char *uncompressed_buffer,
+	size_t uncompressed_buffer_size)
+{
+	int status = ARCHIVE_FATAL;
+	// length of 'lzma properties data' in lzma compressed
+	// data segment (stream) inside zip archive
+	const size_t lzma_params_length = 5;
+	// offset of 'lzma properties data' from the beginning of lzma stream
+	const size_t lzma_params_offset = 4;
+	// end position of 'lzma properties data' in lzma stream
+	const size_t lzma_params_end = lzma_params_offset + lzma_params_length;
+	if (compressed_buffer == NULL ||
+			compressed_buffer_size < lzma_params_end ||
+			uncompressed_buffer == NULL)
+		return status;
+
+	// prepare header for lzma_alone_decoder to replace zipx header
+	// (see comments in 'zipx_lzma_alone_init' for justification)
+#pragma pack(push)
+#pragma pack(1)
+	struct _alone_header
+	{
+		uint8_t bytes[5]; // lzma_params_length
+		uint64_t uncompressed_size;
+	} alone_header;
+#pragma pack(pop)
+	// copy 'lzma properties data' blob
+	memcpy(&alone_header.bytes[0], compressed_buffer + lzma_params_offset,
+		lzma_params_length);
+	alone_header.uncompressed_size = UINT64_MAX;
+
+	// prepare new compressed buffer, see 'zipx_lzma_alone_init' for details
+	const size_t lzma_alone_buffer_size =
+		compressed_buffer_size - lzma_params_end + sizeof(alone_header);
+	unsigned char *lzma_alone_compressed_buffer =
+		(unsigned char*) malloc(lzma_alone_buffer_size);
+	if (lzma_alone_compressed_buffer == NULL)
+		return status;
+	// copy lzma_alone header into new buffer
+	memcpy(lzma_alone_compressed_buffer, (void*) &alone_header,
+		sizeof(alone_header));
+	// copy compressed data into new buffer
+	memcpy(lzma_alone_compressed_buffer + sizeof(alone_header),
+		compressed_buffer + lzma_params_end,
+		compressed_buffer_size - lzma_params_end);
+
+	// create and fill in lzma_alone_decoder stream
+	lzma_stream stream = LZMA_STREAM_INIT;
+	lzma_ret ret = lzma_alone_decoder(&stream, UINT64_MAX);
+	if (ret == LZMA_OK)
+	{
+		stream.next_in = lzma_alone_compressed_buffer;
+		stream.avail_in = lzma_alone_buffer_size;
+		stream.total_in = 0;
+		stream.next_out = (unsigned char*)uncompressed_buffer;
+		stream.avail_out = uncompressed_buffer_size;
+		stream.total_out = 0;
+		ret = lzma_code(&stream, LZMA_RUN);
+		if (ret == LZMA_OK || ret == LZMA_STREAM_END)
+			status = ARCHIVE_OK;
+	}
+	lzma_end(&stream);
+	free(lzma_alone_compressed_buffer);
+	return status;
+}
+#endif
+
 /*
  * Assumes file pointer is at beginning of local file header.
  */
@@ -1173,18 +1248,64 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
 			    "Truncated Zip file");
 			return ARCHIVE_FATAL;
 		}
+		// take into account link compression if any
+		size_t linkname_full_length = linkname_length;
+		if (zip->entry->compression != 0)
+		{
+			// symlink target string appeared to be compressed
+			int status = ARCHIVE_FATAL;
+			char *uncompressed_buffer =
+				(char*) malloc(zip_entry->uncompressed_size);
+			if (uncompressed_buffer == NULL)
+			{
+				archive_set_error(&a->archive, ENOMEM,
+					"No memory for lzma decompression");
+				return status;
+			}
+
+			switch (zip->entry->compression)
+			{
+#if HAVE_LZMA_H && HAVE_LIBLZMA
+				case 14: /* ZIPx LZMA compression. */
+					/*(see zip file format specification, section 4.4.5)*/
+					status = zipx_lzma_uncompress_buffer(p,
+						linkname_length,
+						uncompressed_buffer,
+						(size_t)zip_entry->uncompressed_size);
+					break;
+#endif
+				default: /* Unsupported compression. */
+					break;
+			}
+			if (status == ARCHIVE_OK)
+			{
+				p = uncompressed_buffer;
+				linkname_full_length =
+					(size_t)zip_entry->uncompressed_size;
+			}
+			else
+			{
+				archive_set_error(&a->archive,
+					ARCHIVE_ERRNO_FILE_FORMAT,
+					"Unsupported ZIP compression method "
+					"during decompression of link entry (%d: %s)",
+					zip->entry->compression,
+					compression_name(zip->entry->compression));
+				return ARCHIVE_FAILED;
+			}
+		}
 
 		sconv = zip->sconv;
 		if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME))
 			sconv = zip->sconv_utf8;
 		if (sconv == NULL)
 			sconv = zip->sconv_default;
-		if (archive_entry_copy_symlink_l(entry, p, linkname_length,
+		if (archive_entry_copy_symlink_l(entry, p, linkname_full_length,
 		    sconv) != 0) {
 			if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
 			    (zip->entry->zip_flags & ZIP_UTF8_NAME))
 			    archive_entry_copy_symlink_l(entry, p,
-				linkname_length, NULL);
+				linkname_full_length, NULL);
 			if (errno == ENOMEM) {
 				archive_set_error(&a->archive, ENOMEM,
 				    "Can't allocate memory for Symlink");
@@ -1901,15 +2022,15 @@ zipx_ppmd8_init(struct archive_read *a, struct zip *zip)
 
 	if(order < 2 || restore_method > 2) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Invalid parameter set in PPMd8 stream (order=%d, "
-		    "restore=%d)", order, restore_method);
+		    "Invalid parameter set in PPMd8 stream (order=%" PRId32 ", "
+		    "restore=%" PRId32 ")", order, restore_method);
 		return (ARCHIVE_FAILED);
 	}
 
 	/* Allocate the memory needed to properly decompress the file. */
 	if(!__archive_ppmd8_functions.Ppmd8_Alloc(&zip->ppmd8, mem << 20)) {
 		archive_set_error(&a->archive, ENOMEM,
-		    "Unable to allocate memory for PPMd8 stream: %d bytes",
+		    "Unable to allocate memory for PPMd8 stream: %" PRId32 " bytes",
 		    mem << 20);
 		return (ARCHIVE_FATAL);
 	}

+ 34 - 18
libarchive/archive_string.c

@@ -3881,6 +3881,11 @@ archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes,
 	}
 
 	*p = NULL;
+	/* Try converting WCS to MBS first if MBS does not exist yet. */
+	if ((aes->aes_set & AES_SET_MBS) == 0) {
+		const char *pm; /* unused */
+		archive_mstring_get_mbs(a, aes, &pm); /* ignore errors, we'll handle it later */
+	}
 	if (aes->aes_set & AES_SET_MBS) {
 		sc = archive_string_conversion_to_charset(a, "UTF-8", 1);
 		if (sc == NULL)
@@ -3903,9 +3908,9 @@ int
 archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes,
     const char **p)
 {
+	struct archive_string_conv *sc;
 	int r, ret = 0;
 
-	(void)a; /* UNUSED */
 	/* If we already have an MBS form, return that immediately. */
 	if (aes->aes_set & AES_SET_MBS) {
 		*p = aes->aes_mbs.s;
@@ -3926,10 +3931,23 @@ archive_mstring_get_mbs(struct archive *a, struct archive_mstring *aes,
 			ret = -1;
 	}
 
-	/*
-	 * Only a UTF-8 form cannot avail because its conversion already
-	 * failed at archive_mstring_update_utf8().
-	 */
+	/* If there's a UTF-8 form, try converting with the native locale. */
+	if (aes->aes_set & AES_SET_UTF8) {
+		archive_string_empty(&(aes->aes_mbs));
+		sc = archive_string_conversion_from_charset(a, "UTF-8", 1);
+		if (sc == NULL)
+			return (-1);/* Couldn't allocate memory for sc. */
+		r = archive_strncpy_l(&(aes->aes_mbs),
+			aes->aes_utf8.s, aes->aes_utf8.length, sc);
+		if (a == NULL)
+			free_sconv_object(sc);
+		*p = aes->aes_mbs.s;
+		if (r == 0) {
+			aes->aes_set |= AES_SET_MBS;
+			ret = 0;/* success; overwrite previous error. */
+		} else
+			ret = -1;/* failure. */
+	}
 	return (ret);
 }
 
@@ -3947,6 +3965,11 @@ archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes,
 	}
 
 	*wp = NULL;
+	/* Try converting UTF8 to MBS first if MBS does not exist yet. */
+	if ((aes->aes_set & AES_SET_MBS) == 0) {
+		const char *p; /* unused */
+		archive_mstring_get_mbs(a, aes, &p); /* ignore errors, we'll handle it later */
+	}
 	/* Try converting MBS to WCS using native locale. */
 	if (aes->aes_set & AES_SET_MBS) {
 		archive_wstring_empty(&(aes->aes_wcs));
@@ -3962,11 +3985,12 @@ archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes,
 }
 
 int
-archive_mstring_get_mbs_l(struct archive_mstring *aes,
+archive_mstring_get_mbs_l(struct archive *a, struct archive_mstring *aes,
     const char **p, size_t *length, struct archive_string_conv *sc)
 {
 	int r, ret = 0;
 
+	(void)r; /* UNUSED */
 #if defined(_WIN32) && !defined(__CYGWIN__)
 	/*
 	 * Internationalization programming on Windows must use Wide
@@ -3989,20 +4013,12 @@ archive_mstring_get_mbs_l(struct archive_mstring *aes,
 	}
 #endif
 
-	/* If there is not an MBS form but is a WCS form, try converting
+	/* If there is not an MBS form but there is a WCS or UTF8 form, try converting
 	 * with the native locale to be used for translating it to specified
 	 * character-set. */
-	if ((aes->aes_set & AES_SET_MBS) == 0 &&
-	    (aes->aes_set & AES_SET_WCS) != 0) {
-		archive_string_empty(&(aes->aes_mbs));
-		r = archive_string_append_from_wcs(&(aes->aes_mbs),
-		    aes->aes_wcs.s, aes->aes_wcs.length);
-		if (r == 0)
-			aes->aes_set |= AES_SET_MBS;
-		else if (errno == ENOMEM)
-			return (-1);
-		else
-			ret = -1;
+	if ((aes->aes_set & AES_SET_MBS) == 0) {
+		const char *pm; /* unused */
+		archive_mstring_get_mbs(a, aes, &pm); /* ignore errors, we'll handle it later */
 	}
 	/* If we already have an MBS form, use it to be translated to
 	 * specified character-set. */

+ 1 - 1
libarchive/archive_string.h

@@ -226,7 +226,7 @@ void	archive_mstring_copy(struct archive_mstring *dest, struct archive_mstring *
 int archive_mstring_get_mbs(struct archive *, struct archive_mstring *, const char **);
 int archive_mstring_get_utf8(struct archive *, struct archive_mstring *, const char **);
 int archive_mstring_get_wcs(struct archive *, struct archive_mstring *, const wchar_t **);
-int	archive_mstring_get_mbs_l(struct archive_mstring *, const char **,
+int	archive_mstring_get_mbs_l(struct archive *, struct archive_mstring *, const char **,
 	    size_t *, struct archive_string_conv *);
 int	archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs);
 int	archive_mstring_copy_mbs_len(struct archive_mstring *, const char *mbs,

+ 6 - 0
libarchive/archive_util.c

@@ -365,6 +365,7 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
 		}
 		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
 		if (fd == -1) {
+			la_dosmaperr(GetLastError());
 			CloseHandle(h);
 			goto exit_tmpfile;
 		} else
@@ -432,6 +433,11 @@ __archive_mktemp(const char *tmpdir)
 		if (temp_name.s[temp_name.length-1] != '/')
 			archive_strappend_char(&temp_name, '/');
 	}
+#ifdef O_TMPFILE
+	fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600); 
+	if(fd >= 0)
+		goto exit_tmpfile;
+#endif
 	archive_strcat(&temp_name, "libarchive_XXXXXX");
 	fd = mkstemp(temp_name.s);
 	if (fd < 0)

+ 33 - 9
libarchive/archive_write.c

@@ -455,6 +455,25 @@ archive_write_client_write(struct archive_write_filter *f,
 	return (ARCHIVE_OK);
 }
 
+static int
+archive_write_client_free(struct archive_write_filter *f)
+{
+	struct archive_write *a = (struct archive_write *)f->archive;
+
+	if (a->client_freer)
+		(*a->client_freer)(&a->archive, a->client_data);
+	a->client_data = NULL;
+
+	/* Clear passphrase. */
+	if (a->passphrase != NULL) {
+		memset(a->passphrase, 0, strlen(a->passphrase));
+		free(a->passphrase);
+		a->passphrase = NULL;
+	}
+
+	return (ARCHIVE_OK);
+}
+
 static int
 archive_write_client_close(struct archive_write_filter *f)
 {
@@ -493,13 +512,7 @@ archive_write_client_close(struct archive_write_filter *f)
 		(*a->client_closer)(&a->archive, a->client_data);
 	free(state->buffer);
 	free(state);
-	a->client_data = NULL;
-	/* Clear passphrase. */
-	if (a->passphrase != NULL) {
-		memset(a->passphrase, 0, strlen(a->passphrase));
-		free(a->passphrase);
-		a->passphrase = NULL;
-	}
+
 	/* Clear the close handler myself not to be called again. */
 	f->state = ARCHIVE_WRITE_FILTER_STATE_CLOSED;
 	return (ret);
@@ -509,9 +522,9 @@ archive_write_client_close(struct archive_write_filter *f)
  * Open the archive using the current settings.
  */
 int
-archive_write_open(struct archive *_a, void *client_data,
+archive_write_open2(struct archive *_a, void *client_data,
     archive_open_callback *opener, archive_write_callback *writer,
-    archive_close_callback *closer)
+    archive_close_callback *closer, archive_free_callback *freer)
 {
 	struct archive_write *a = (struct archive_write *)_a;
 	struct archive_write_filter *client_filter;
@@ -524,12 +537,14 @@ archive_write_open(struct archive *_a, void *client_data,
 	a->client_writer = writer;
 	a->client_opener = opener;
 	a->client_closer = closer;
+	a->client_freer = freer;
 	a->client_data = client_data;
 
 	client_filter = __archive_write_allocate_filter(_a);
 	client_filter->open = archive_write_client_open;
 	client_filter->write = archive_write_client_write;
 	client_filter->close = archive_write_client_close;
+	client_filter->free = archive_write_client_free;
 
 	ret = __archive_write_filters_open(a);
 	if (ret < ARCHIVE_WARN) {
@@ -544,6 +559,15 @@ archive_write_open(struct archive *_a, void *client_data,
 	return (ret);
 }
 
+int
+archive_write_open(struct archive *_a, void *client_data,
+    archive_open_callback *opener, archive_write_callback *writer,
+    archive_close_callback *closer)
+{
+	return archive_write_open2(_a, client_data, opener, writer,
+	    closer, NULL);
+}
+
 /*
  * Close out the archive.
  */

+ 4 - 22
libarchive/archive_write_add_filter_program.c

@@ -196,10 +196,6 @@ __archive_write_program_free(struct archive_write_program_data *data)
 {
 
 	if (data) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-		if (data->child)
-			CloseHandle(data->child);
-#endif
 		free(data->program_name);
 		free(data->child_buf);
 		free(data);
@@ -211,7 +207,7 @@ int
 __archive_write_program_open(struct archive_write_filter *f,
     struct archive_write_program_data *data, const char *cmd)
 {
-	pid_t child;
+	int ret;
 
 	if (data->child_buf == NULL) {
 		data->child_buf_len = 65536;
@@ -225,27 +221,13 @@ __archive_write_program_open(struct archive_write_filter *f,
 		}
 	}
 
-	child = __archive_create_child(cmd, &data->child_stdin,
-		    &data->child_stdout);
-	if (child == -1) {
+	ret = __archive_create_child(cmd, &data->child_stdin,
+		    &data->child_stdout, &data->child);
+	if (ret != ARCHIVE_OK) {
 		archive_set_error(f->archive, EINVAL,
 		    "Can't launch external program: %s", cmd);
 		return (ARCHIVE_FATAL);
 	}
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	data->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
-	if (data->child == NULL) {
-		close(data->child_stdin);
-		data->child_stdin = -1;
-		close(data->child_stdout);
-		data->child_stdout = -1;
-		archive_set_error(f->archive, EINVAL,
-		    "Can't launch external program: %s", cmd);
-		return (ARCHIVE_FATAL);
-	}
-#else
-	data->child = child;
-#endif
 	return (ARCHIVE_OK);
 }
 

+ 2 - 2
libarchive/archive_write_add_filter_xz.c

@@ -382,8 +382,8 @@ archive_compressor_xz_options(struct archive_write_filter *f,
 		    value[1] != '\0')
 			return (ARCHIVE_WARN);
 		data->compression_level = value[0] - '0';
-		if (data->compression_level > 6)
-			data->compression_level = 6;
+		if (data->compression_level > 9)
+			data->compression_level = 9;
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "threads") == 0) {
 		char *endptr;

+ 73 - 6
libarchive/archive_write_add_filter_zstd.c

@@ -59,6 +59,16 @@ struct private_data {
 #endif
 };
 
+/* If we don't have the library use default range values (zstdcli.c v1.4.0) */
+#define CLEVEL_MIN -99
+#define CLEVEL_STD_MIN 0 /* prior to 1.3.4 and more recent without using --fast */
+#define CLEVEL_DEFAULT 3
+#define CLEVEL_STD_MAX 19 /* without using --ultra */
+#define CLEVEL_MAX 22
+
+#define MINVER_NEGCLEVEL 10304
+#define MINVER_MINCLEVEL 10306
+
 static int archive_compressor_zstd_options(struct archive_write_filter *,
 		    const char *, const char *);
 static int archive_compressor_zstd_open(struct archive_write_filter *);
@@ -96,7 +106,7 @@ archive_write_add_filter_zstd(struct archive *_a)
 	f->free = &archive_compressor_zstd_free;
 	f->code = ARCHIVE_FILTER_ZSTD;
 	f->name = "zstd";
-	data->compression_level = 3; /* Default level used by the zstd CLI */
+	data->compression_level = CLEVEL_DEFAULT;
 #if HAVE_ZSTD_H && HAVE_LIBZSTD
 	data->cstream = ZSTD_createCStream();
 	if (data->cstream == NULL) {
@@ -135,6 +145,31 @@ archive_compressor_zstd_free(struct archive_write_filter *f)
 	return (ARCHIVE_OK);
 }
 
+static int string_is_numeric (const char* value)
+{
+       size_t len = strlen(value);
+       size_t i;
+
+       if (len == 0) {
+               return (ARCHIVE_WARN);
+       }
+       else if (len == 1 && !(value[0] >= '0' && value[0] <= '9')) {
+               return (ARCHIVE_WARN);
+       }
+       else if (!(value[0] >= '0' && value[0] <= '9') &&
+                value[0] != '-' && value[0] != '+') {
+               return (ARCHIVE_WARN);
+       }
+
+       for (i = 1; i < len; i++) {
+               if (!(value[i] >= '0' && value[i] <= '9')) {
+                       return (ARCHIVE_WARN);
+               }
+       }
+
+       return (ARCHIVE_OK);
+}
+
 /*
  * Set write options.
  */
@@ -146,12 +181,25 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
 
 	if (strcmp(key, "compression-level") == 0) {
 		int level = atoi(value);
-#if HAVE_ZSTD_H && HAVE_LIBZSTD
-		if (level < 1 || level > ZSTD_maxCLevel()) {
-#else
 		/* If we don't have the library, hard-code the max level */
-		if (level < 1 || level > 22) {
+		int minimum = CLEVEL_MIN;
+		int maximum = CLEVEL_MAX;
+		if (string_is_numeric(value) != ARCHIVE_OK) {
+			return (ARCHIVE_WARN);
+		}
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+		maximum = ZSTD_maxCLevel();
+#if ZSTD_VERSION_NUMBER >= MINVER_MINCLEVEL
+		if (ZSTD_versionNumber() >= MINVER_MINCLEVEL) {
+			minimum = ZSTD_minCLevel();
+		}
+		else
+#endif
+		if (ZSTD_versionNumber() < MINVER_NEGCLEVEL) {
+			minimum = CLEVEL_STD_MIN;
+		}
 #endif
+		if (level < minimum || level > maximum) {
 			return (ARCHIVE_WARN);
 		}
 		data->compression_level = level;
@@ -297,7 +345,26 @@ archive_compressor_zstd_open(struct archive_write_filter *f)
 	int r;
 
 	archive_string_init(&as);
-	archive_string_sprintf(&as, "zstd -%d", data->compression_level);
+	/* --no-check matches library default */
+	archive_strcpy(&as, "zstd --no-check");
+
+	if (data->compression_level < CLEVEL_STD_MIN) {
+		struct archive_string as2;
+		archive_string_init(&as2);
+		archive_string_sprintf(&as2, " --fast=%d", -data->compression_level);
+		archive_string_concat(&as, &as2);
+		archive_string_free(&as2);
+	} else {
+		struct archive_string as2;
+		archive_string_init(&as2);
+		archive_string_sprintf(&as2, " -%d", data->compression_level);
+		archive_string_concat(&as, &as2);
+		archive_string_free(&as2);
+	}
+
+	if (data->compression_level > CLEVEL_STD_MAX) {
+		archive_strcat(&as, " --ultra");
+	}
 
 	f->write = archive_compressor_zstd_write;
 	r = __archive_write_program_open(f, data->pdata, as.s);

+ 49 - 3
libarchive/archive_write_disk_posix.c

@@ -546,6 +546,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 {
 	struct archive_write_disk *a = (struct archive_write_disk *)_a;
 	struct fixup_entry *fe;
+	const char *linkname;
 	int ret, r;
 
 	archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -590,6 +591,17 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 	if (ret != ARCHIVE_OK)
 		return (ret);
 
+	/*
+	 * Check if we have a hardlink that points to itself.
+	 */
+	linkname = archive_entry_hardlink(a->entry);
+	if (linkname != NULL && strcmp(a->name, linkname) == 0) {
+		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+		    "Skipping hardlink pointing to itself: %s",
+		    a->name);
+		return (ARCHIVE_WARN);
+	}
+
 	/*
 	 * Query the umask so we get predictable mode settings.
 	 * This gets done on every call to _write_header in case the
@@ -1856,8 +1868,9 @@ finish_metadata:
 		if (a->tmpname) {
 			if (rename(a->tmpname, a->name) == -1) {
 				archive_set_error(&a->archive, errno,
-				    "rename failed");
-				ret = ARCHIVE_FATAL;
+				    "Failed to rename temporary file");
+				ret = ARCHIVE_FAILED;
+				unlink(a->tmpname);
 			}
 			a->tmpname = NULL;
 		}
@@ -2144,8 +2157,11 @@ restore_entry(struct archive_write_disk *a)
 			if ((a->flags & ARCHIVE_EXTRACT_SAFE_WRITES) &&
 			    S_ISREG(a->st.st_mode)) {
 				/* Use a temporary file to extract */
-				if ((a->fd = la_mktemp(a)) == -1)
+				if ((a->fd = la_mktemp(a)) == -1) {
+					archive_set_error(&a->archive, errno,
+					    "Can't create temporary file");
 					return ARCHIVE_FAILED;
+				}
 				a->pst = NULL;
 				en = 0;
 			} else {
@@ -4407,10 +4423,19 @@ set_xattrs(struct archive_write_disk *a)
 			int e;
 			int namespace;
 
+			namespace = EXTATTR_NAMESPACE_USER;
+
 			if (strncmp(name, "user.", 5) == 0) {
 				/* "user." attributes go to user namespace */
 				name += 5;
 				namespace = EXTATTR_NAMESPACE_USER;
+			} else if (strncmp(name, "system.", 7) == 0) {
+				name += 7;
+				namespace = EXTATTR_NAMESPACE_SYSTEM;
+				if (!strcmp(name, "nfs4.acl") ||
+				    !strcmp(name, "posix1e.acl_access") ||
+				    !strcmp(name, "posix1e.acl_default"))
+					continue;
 			} else {
 				/* Other namespaces are unsupported */
 				archive_strcat(&errlist, name);
@@ -4421,8 +4446,29 @@ set_xattrs(struct archive_write_disk *a)
 			}
 
 			if (a->fd >= 0) {
+				/*
+				 * On FreeBSD, extattr_set_fd does not
+				 * return the same as
+				 * extattr_set_file. It returns zero
+				 * on success, non-zero on failure.
+				 *
+				 * We can detect the failure by
+				 * manually setting errno prior to the
+				 * call and checking after.
+				 *
+				 * If errno remains zero, fake the
+				 * return value by setting e to size.
+				 *
+				 * This is a hack for now until I
+				 * (Shawn Webb) get FreeBSD to fix the
+				 * issue, if that's even possible.
+				 */
+				errno = 0;
 				e = extattr_set_fd(a->fd, namespace, name,
 				    value, size);
+				if (e == 0 && errno == 0) {
+					e = size;
+				}
 			} else {
 				e = extattr_set_link(
 				    archive_entry_pathname(entry), namespace,

+ 14 - 5
libarchive/archive_write_disk_windows.c

@@ -549,6 +549,8 @@ la_mktemp(struct archive_write_disk *a)
 	a->tmpname = a->_tmpname_data.s;
 
 	fd = __archive_mkstemp(a->tmpname);
+	if (fd == -1)
+		return -1;
 
 	mode = a->mode & 0777 & ~a->user_umask;
 	if (la_chmod(a->tmpname, mode) == -1) {
@@ -1281,9 +1283,11 @@ _archive_write_disk_finish_entry(struct archive *_a)
 			/* Windows does not support atomic rename */
 			disk_unlink(a->name);
 			if (_wrename(a->tmpname, a->name) != 0) {
+				la_dosmaperr(GetLastError());
 				archive_set_error(&a->archive, errno,
-				    "rename failed");
-				ret = ARCHIVE_FATAL;
+				    "Failed to rename temporary file");
+				ret = ARCHIVE_FAILED;
+				disk_unlink(a->tmpname);
 			}
 			a->tmpname = NULL;
 		}
@@ -1573,12 +1577,17 @@ restore_entry(struct archive_write_disk *a)
 				S_ISREG(st_mode)) {
 				int fd = la_mktemp(a);
 
-				if (fd == -1)
+				if (fd == -1) {
+					la_dosmaperr(GetLastError());
+					archive_set_error(&a->archive, errno,
+					    "Can't create temporary file");
 					return (ARCHIVE_FAILED);
+				}
 				a->fh = (HANDLE)_get_osfhandle(fd);
-				if (a->fh == INVALID_HANDLE_VALUE)
+				if (a->fh == INVALID_HANDLE_VALUE) {
+					la_dosmaperr(GetLastError());
 					return (ARCHIVE_FAILED);
-
+				}
 				a->pst = NULL;
 				en = 0;
 			} else {

+ 31 - 6
libarchive/archive_write_open.3

@@ -24,11 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd November 12, 2020
 .Dt ARCHIVE_WRITE_OPEN 3
 .Os
 .Sh NAME
 .Nm archive_write_open ,
+.Nm archive_write_open2 ,
 .Nm archive_write_open_fd ,
 .Nm archive_write_open_FILE ,
 .Nm archive_write_open_filename ,
@@ -47,6 +48,15 @@ Streaming Archive Library (libarchive, -larchive)
 .Fa "archive_close_callback *"
 .Fc
 .Ft int
+.Fo archive_write_open2
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_open_callback *"
+.Fa "archive_write_callback *"
+.Fa "archive_close_callback *"
+.Fa "archive_free_callback *"
+.Fc
+.Ft int
 .Fn archive_write_open_fd "struct archive *" "int fd"
 .Ft int
 .Fn archive_write_open_FILE "struct archive *" "FILE *file"
@@ -67,6 +77,11 @@ This is the most generic form of this function, which accepts
 pointers to three callback functions which will be invoked by
 the compression layer to write the constructed archive.
 This does not alter the default archive padding.
+.It Fn archive_write_open2
+Same as
+.Fn archive_write_open
+with an additional fourth free callback. This function should be preferred to
+.Fn archive_write_open .
 .It Fn archive_write_open_fd
 A convenience form of
 .Fn archive_write_open
@@ -106,14 +121,14 @@ to a character or block device node, it will disable padding otherwise.
 You can override this by manually invoking
 .Fn archive_write_set_bytes_in_last_block
 before calling
-.Fn archive_write_open .
+.Fn archive_write_open2 .
 The
 .Fn archive_write_open_filename
 function is safe for use with tape drives or other
 block-oriented devices.
 .It Fn archive_write_open_memory
 A convenience form of
-.Fn archive_write_open
+.Fn archive_write_open2
 that accepts a pointer to a block of memory that will receive
 the archive.
 The final
@@ -145,7 +160,7 @@ To use this library, you will need to define and register
 callback functions that will be invoked to write data to the
 resulting archive.
 These functions are registered by calling
-.Fn archive_write_open :
+.Fn archive_write_open2 :
 .Bl -item -offset indent
 .It
 .Ft typedef int
@@ -162,6 +177,8 @@ If the open fails, it should call
 .Fn archive_set_error
 to register an error code and message and return
 .Cm ARCHIVE_FATAL .
+Please note that if open fails, close is not called and resources must be
+freed inside the open callback or with the free callback.
 .Bl -item -offset indent
 .It
 .Ft typedef la_ssize_t
@@ -192,7 +209,8 @@ to register an error code and message and return -1.
 .El
 .Pp
 The close callback is invoked by archive_close when
-the archive processing is complete.
+the archive processing is complete. If the open callback fails, the close
+callback is not invoked.
 The callback should return
 .Cm ARCHIVE_OK
 on success.
@@ -200,7 +218,14 @@ On failure, the callback should invoke
 .Fn archive_set_error
 to register an error code and message and
 return
-.Cm ARCHIVE_FATAL .
+.Bl -item -offset indent
+.It
+.Ft typedef int
+.Fn archive_free_callback "struct archive *" "void *client_data"
+.El
+.Pp
+The free callback is always invoked on archive_free.
+The return code of this callback is not processed.
 .Pp
 Note that if the client-provided write callback function
 returns a non-zero value, that error will be propagated back to the caller

+ 6 - 4
libarchive/archive_write_open_fd.c

@@ -54,7 +54,7 @@ struct write_fd_data {
 	int		fd;
 };
 
-static int	file_close(struct archive *, void *);
+static int	file_free(struct archive *, void *);
 static int	file_open(struct archive *, void *);
 static ssize_t	file_write(struct archive *, void *, const void *buff, size_t);
 
@@ -72,8 +72,8 @@ archive_write_open_fd(struct archive *a, int fd)
 #if defined(__CYGWIN__) || defined(_WIN32)
 	setmode(mine->fd, O_BINARY);
 #endif
-	return (archive_write_open(a, mine,
-		    file_open, file_write, file_close));
+	return (archive_write_open2(a, mine,
+		    file_open, file_write, NULL, file_free));
 }
 
 static int
@@ -134,11 +134,13 @@ file_write(struct archive *a, void *client_data, const void *buff, size_t length
 }
 
 static int
-file_close(struct archive *a, void *client_data)
+file_free(struct archive *a, void *client_data)
 {
 	struct write_fd_data	*mine = (struct write_fd_data *)client_data;
 
 	(void)a; /* UNUSED */
+	if (mine == NULL)
+		return (ARCHIVE_OK);
 	free(mine);
 	return (ARCHIVE_OK);
 }

+ 6 - 4
libarchive/archive_write_open_file.c

@@ -51,7 +51,7 @@ struct write_FILE_data {
 	FILE		*f;
 };
 
-static int	file_close(struct archive *, void *);
+static int	file_free(struct archive *, void *);
 static int	file_open(struct archive *, void *);
 static ssize_t	file_write(struct archive *, void *, const void *buff, size_t);
 
@@ -66,8 +66,8 @@ archive_write_open_FILE(struct archive *a, FILE *f)
 		return (ARCHIVE_FATAL);
 	}
 	mine->f = f;
-	return (archive_write_open(a, mine,
-		    file_open, file_write, file_close));
+	return (archive_write_open2(a, mine, file_open, file_write,
+	    NULL, file_free));
 }
 
 static int
@@ -99,11 +99,13 @@ file_write(struct archive *a, void *client_data, const void *buff, size_t length
 }
 
 static int
-file_close(struct archive *a, void *client_data)
+file_free(struct archive *a, void *client_data)
 {
 	struct write_FILE_data	*mine = client_data;
 
 	(void)a; /* UNUSED */
+	if (mine == NULL)
+		return (ARCHIVE_OK);
 	free(mine);
 	return (ARCHIVE_OK);
 }

+ 19 - 2
libarchive/archive_write_open_filename.c

@@ -62,6 +62,7 @@ struct write_file_data {
 };
 
 static int	file_close(struct archive *, void *);
+static int	file_free(struct archive *, void *);
 static int	file_open(struct archive *, void *);
 static ssize_t	file_write(struct archive *, void *, const void *buff, size_t);
 static int	open_filename(struct archive *, int, const void *);
@@ -123,8 +124,8 @@ open_filename(struct archive *a, int mbs_fn, const void *filename)
 		return (ARCHIVE_FAILED);
 	}
 	mine->fd = -1;
-	return (archive_write_open(a, mine,
-		file_open, file_write, file_close));
+	return (archive_write_open2(a, mine,
+		    file_open, file_write, file_close, file_free));
 }
 
 static int
@@ -244,9 +245,25 @@ file_close(struct archive *a, void *client_data)
 
 	(void)a; /* UNUSED */
 
+	if (mine == NULL)
+		return (ARCHIVE_FATAL);
+
 	if (mine->fd >= 0)
 		close(mine->fd);
 
+	return (ARCHIVE_OK);
+}
+
+static int
+file_free(struct archive *a, void *client_data)
+{
+	struct write_file_data	*mine = (struct write_file_data *)client_data;
+
+	(void)a; /* UNUSED */
+
+	if (mine == NULL)
+		return (ARCHIVE_OK);
+
 	archive_mstring_clean(&mine->filename);
 	free(mine);
 	return (ARCHIVE_OK);

+ 6 - 4
libarchive/archive_write_open_memory.c

@@ -39,7 +39,7 @@ struct write_memory_data {
 	unsigned char * buff;
 };
 
-static int	memory_write_close(struct archive *, void *);
+static int	memory_write_free(struct archive *, void *);
 static int	memory_write_open(struct archive *, void *);
 static ssize_t	memory_write(struct archive *, void *, const void *buff, size_t);
 
@@ -61,8 +61,8 @@ archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t
 	mine->buff = buff;
 	mine->size = buffSize;
 	mine->client_size = used;
-	return (archive_write_open(a, mine,
-		    memory_write_open, memory_write, memory_write_close));
+	return (archive_write_open2(a, mine,
+		    memory_write_open, memory_write, NULL, memory_write_free));
 }
 
 static int
@@ -103,11 +103,13 @@ memory_write(struct archive *a, void *client_data, const void *buff, size_t leng
 }
 
 static int
-memory_write_close(struct archive *a, void *client_data)
+memory_write_free(struct archive *a, void *client_data)
 {
 	struct write_memory_data *mine;
 	(void)a; /* UNUSED */
 	mine = client_data;
+	if (mine == NULL)
+		return (ARCHIVE_OK);
 	free(mine);
 	return (ARCHIVE_OK);
 }

+ 1 - 0
libarchive/archive_write_private.h

@@ -89,6 +89,7 @@ struct archive_write {
 	archive_open_callback	*client_opener;
 	archive_write_callback	*client_writer;
 	archive_close_callback	*client_closer;
+	archive_free_callback	*client_freer;
 	void			*client_data;
 
 	/*

+ 1 - 1
libarchive/archive_write_set_format.c

@@ -82,7 +82,7 @@ void
 __archive_write_entry_filetype_unsupported(struct archive *a,
     struct archive_entry *entry, const char *format)
 {
-	char *name = NULL;
+	const char *name = NULL;
 
 	switch (archive_entry_filetype(entry)) {
 	/*

+ 2 - 2
libarchive/archive_write_set_format_7zip.c

@@ -1927,8 +1927,8 @@ compression_init_encoder_lzma(struct archive *a,
 		return (ARCHIVE_FATAL);
 	}
 	lzmafilters = (lzma_filter *)(strm+1);
-	if (level > 6)
-		level = 6;
+	if (level > 9)
+		level = 9;
 	if (lzma_lzma_preset(&lzma_opt, level)) {
 		free(strm);
 		lastrm->real_stream = NULL;

+ 2 - 2
libarchive/archive_write_set_format_cpio.c

@@ -250,7 +250,7 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
 	const char *path;
 	size_t len;
 
-	if (archive_entry_filetype(entry) == 0) {
+	if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
 		archive_set_error(&a->archive, -1, "Filetype required");
 		return (ARCHIVE_FAILED);
 	}
@@ -348,7 +348,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
 	format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
 	if (archive_entry_filetype(entry) == AE_IFBLK
 	    || archive_entry_filetype(entry) == AE_IFCHR)
-	    format_octal(archive_entry_dev(entry), h + c_rdev_offset, c_rdev_size);
+	    format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size);
 	else
 	    format_octal(0, h + c_rdev_offset, c_rdev_size);
 	format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);

+ 1 - 1
libarchive/archive_write_set_format_cpio_newc.c

@@ -190,7 +190,7 @@ archive_write_newc_header(struct archive_write *a, struct archive_entry *entry)
 	const char *path;
 	size_t len;
 
-	if (archive_entry_filetype(entry) == 0) {
+	if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
 		archive_set_error(&a->archive, -1, "Filetype required");
 		return (ARCHIVE_FAILED);
 	}

+ 2 - 1
libarchive/archive_write_set_format_iso9660.c

@@ -2178,7 +2178,8 @@ get_system_identitier(char *system_id, size_t size)
 	strncpy(system_id, "Windows", size-1);
 	system_id[size-1] = '\0';
 #else
-#error no way to get the system identifier on your platform.
+	strncpy(system_id, "Unknown", size-1);
+	system_id[size-1] = '\0';
 #endif
 }
 

+ 19 - 30
libarchive/archive_write_set_format_mtree.c

@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171
 #include "archive.h"
 #include "archive_digest_private.h"
 #include "archive_entry.h"
+#include "archive_entry_private.h"
 #include "archive_private.h"
 #include "archive_rb.h"
 #include "archive_string.h"
@@ -82,24 +83,7 @@ struct dir_info {
 struct reg_info {
 	int compute_sum;
 	uint32_t crc;
-#ifdef ARCHIVE_HAS_MD5
-	unsigned char buf_md5[16];
-#endif
-#ifdef ARCHIVE_HAS_RMD160
-	unsigned char buf_rmd160[20];
-#endif
-#ifdef ARCHIVE_HAS_SHA1
-	unsigned char buf_sha1[20];
-#endif
-#ifdef ARCHIVE_HAS_SHA256
-	unsigned char buf_sha256[32];
-#endif
-#ifdef ARCHIVE_HAS_SHA384
-	unsigned char buf_sha384[48];
-#endif
-#ifdef ARCHIVE_HAS_SHA512
-	unsigned char buf_sha512[64];
-#endif
+	struct ae_digest digest;
 };
 
 struct mtree_entry {
@@ -1571,27 +1555,27 @@ sum_final(struct mtree_writer *mtree, struct reg_info *reg)
 	}
 #ifdef ARCHIVE_HAS_MD5
 	if (mtree->compute_sum & F_MD5)
-		archive_md5_final(&mtree->md5ctx, reg->buf_md5);
+		archive_md5_final(&mtree->md5ctx, reg->digest.md5);
 #endif
 #ifdef ARCHIVE_HAS_RMD160
 	if (mtree->compute_sum & F_RMD160)
-		archive_rmd160_final(&mtree->rmd160ctx, reg->buf_rmd160);
+		archive_rmd160_final(&mtree->rmd160ctx, reg->digest.rmd160);
 #endif
 #ifdef ARCHIVE_HAS_SHA1
 	if (mtree->compute_sum & F_SHA1)
-		archive_sha1_final(&mtree->sha1ctx, reg->buf_sha1);
+		archive_sha1_final(&mtree->sha1ctx, reg->digest.sha1);
 #endif
 #ifdef ARCHIVE_HAS_SHA256
 	if (mtree->compute_sum & F_SHA256)
-		archive_sha256_final(&mtree->sha256ctx, reg->buf_sha256);
+		archive_sha256_final(&mtree->sha256ctx, reg->digest.sha256);
 #endif
 #ifdef ARCHIVE_HAS_SHA384
 	if (mtree->compute_sum & F_SHA384)
-		archive_sha384_final(&mtree->sha384ctx, reg->buf_sha384);
+		archive_sha384_final(&mtree->sha384ctx, reg->digest.sha384);
 #endif
 #ifdef ARCHIVE_HAS_SHA512
 	if (mtree->compute_sum & F_SHA512)
-		archive_sha512_final(&mtree->sha512ctx, reg->buf_sha512);
+		archive_sha512_final(&mtree->sha512ctx, reg->digest.sha512);
 #endif
 	/* Save what types of sum are computed. */
 	reg->compute_sum = mtree->compute_sum;
@@ -1621,42 +1605,47 @@ sum_write(struct archive_string *str, struct reg_info *reg)
 		archive_string_sprintf(str, " cksum=%ju",
 		    (uintmax_t)reg->crc);
 	}
+
+#define append_digest(_s, _r, _t) \
+	strappend_bin(_s, _r->digest._t, sizeof(_r->digest._t))
+
 #ifdef ARCHIVE_HAS_MD5
 	if (reg->compute_sum & F_MD5) {
 		archive_strcat(str, " md5digest=");
-		strappend_bin(str, reg->buf_md5, sizeof(reg->buf_md5));
+		append_digest(str, reg, md5);
 	}
 #endif
 #ifdef ARCHIVE_HAS_RMD160
 	if (reg->compute_sum & F_RMD160) {
 		archive_strcat(str, " rmd160digest=");
-		strappend_bin(str, reg->buf_rmd160, sizeof(reg->buf_rmd160));
+		append_digest(str, reg, rmd160);
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA1
 	if (reg->compute_sum & F_SHA1) {
 		archive_strcat(str, " sha1digest=");
-		strappend_bin(str, reg->buf_sha1, sizeof(reg->buf_sha1));
+		append_digest(str, reg, sha1);
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA256
 	if (reg->compute_sum & F_SHA256) {
 		archive_strcat(str, " sha256digest=");
-		strappend_bin(str, reg->buf_sha256, sizeof(reg->buf_sha256));
+		append_digest(str, reg, sha256);
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA384
 	if (reg->compute_sum & F_SHA384) {
 		archive_strcat(str, " sha384digest=");
-		strappend_bin(str, reg->buf_sha384, sizeof(reg->buf_sha384));
+		append_digest(str, reg, sha384);
 	}
 #endif
 #ifdef ARCHIVE_HAS_SHA512
 	if (reg->compute_sum & F_SHA512) {
 		archive_strcat(str, " sha512digest=");
-		strappend_bin(str, reg->buf_sha512, sizeof(reg->buf_sha512));
+		append_digest(str, reg, sha512);
 	}
 #endif
+#undef append_digest
 }
 
 static int

+ 4 - 3
libarchive/archive_write_set_format_xar.c

@@ -681,7 +681,8 @@ xar_write_data(struct archive_write *a, const void *buff, size_t s)
 {
 	struct xar *xar;
 	enum la_zaction run;
-	size_t size, rsize;
+	size_t size = 0;
+	size_t rsize;
 	int r;
 
 	xar = (struct xar *)a->format_data;
@@ -2930,8 +2931,8 @@ compression_init_encoder_xz(struct archive *a,
 		return (ARCHIVE_FATAL);
 	}
 	lzmafilters = (lzma_filter *)(strm+1);
-	if (level > 6)
-		level = 6;
+	if (level > 9)
+		level = 9;
 	if (lzma_lzma_preset(&lzma_opt, level)) {
 		free(strm);
 		lastrm->real_stream = NULL;

+ 5 - 0
libarchive/archive_write_set_format_zip.c

@@ -584,6 +584,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 			zip->entry_flags |= ZIP_ENTRY_FLAG_ENCRYPTED;
 			zip->entry_encryption = zip->encryption_type;
 			break;
+		case ENCRYPTION_NONE:
 		default:
 			break;
 		}
@@ -710,6 +711,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 				    + AUTH_CODE_SIZE;
 				version_needed = 20;
 				break;
+			case ENCRYPTION_NONE:
 			default:
 				break;
 			}
@@ -762,6 +764,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
 				if (version_needed < 20)
 					version_needed = 20;
 				break;
+			case ENCRYPTION_NONE:
 			default:
 				break;
 			}
@@ -1029,6 +1032,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 				zip->cctx_valid = zip->hctx_valid = 1;
 			}
 			break;
+		case ENCRYPTION_NONE:
 		default:
 			break;
 		}
@@ -1117,6 +1121,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
 		break;
 #endif
 
+	case COMPRESSION_UNSPECIFIED:
 	default:
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Invalid ZIP compression type");

+ 2 - 1
libarchive/archive_write_set_options.3

@@ -255,7 +255,8 @@ If supported, the default value is read from
 .Bl -tag -compact -width indent
 .It Cm compression-level
 The value is interpreted as a decimal integer specifying the
-compression level. Supported values are from 1 to 22.
+compression level. Supported values depend on the library version,
+common values are from 1 to 22.
 .El
 .It Format 7zip
 .Bl -tag -compact -width indent

+ 2 - 0
libarchive/config_freebsd.h

@@ -24,6 +24,7 @@
  *
  * $FreeBSD$
  */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 
 #include <osreldate.h>
 
@@ -183,6 +184,7 @@
 #define HAVE_STRFTIME 1
 #define HAVE_STRINGS_H 1
 #define HAVE_STRING_H 1
+#define HAVE_STRNLEN 1
 #define HAVE_STRRCHR 1
 #define HAVE_STRUCT_STATFS_F_NAMEMAX 1
 #define HAVE_STRUCT_STAT_ST_BIRTHTIME 1

+ 1 - 1
libarchive/cpio.5

@@ -244,7 +244,7 @@ Note that this format supports only 4 gigabyte files (unlike the
 older ASCII format, which supports 8 gigabyte files).
 .Pp
 In this format, hardlinked files are handled by setting the
-filesize to zero for each entry except the last one that
+filesize to zero for each entry except the first one that
 appears in the archive.
 .Ss New CRC Format
 The CRC format is identical to the new ASCII format described

+ 7 - 2
libarchive/filter_fork.h

@@ -32,8 +32,13 @@
 #error This header is only to be used internally to libarchive.
 #endif
 
-pid_t
-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout);
+int
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
+#if defined(_WIN32) && !defined(__CYGWIN__)
+	HANDLE *out_child);
+#else
+	pid_t *out_child);
+#endif
 
 void
 __archive_check_child(int in, int out);

+ 6 - 4
libarchive/filter_fork_posix.c

@@ -72,8 +72,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/filter_fork.c 182958 2008-09-12 05:33:00
 
 #include "filter_fork.h"
 
-pid_t
-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
+int
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
+		pid_t *out_child)
 {
 	pid_t child;
 	int stdin_pipe[2], stdout_pipe[2], tmp;
@@ -177,7 +178,8 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
 	fcntl(*child_stdout, F_SETFL, O_NONBLOCK);
 	__archive_cmdline_free(cmdline);
 
-	return child;
+	*out_child = child;
+	return ARCHIVE_OK;
 
 #if HAVE_POSIX_SPAWNP
 actions_inited:
@@ -192,7 +194,7 @@ stdin_opened:
 	close(stdin_pipe[1]);
 state_allocated:
 	__archive_cmdline_free(cmdline);
-	return -1;
+	return ARCHIVE_FAILED;
 }
 
 void

+ 13 - 4
libarchive/filter_fork_windows.c

@@ -31,8 +31,9 @@
 
 #include "filter_fork.h"
 
-pid_t
-__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
+int
+__archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
+		HANDLE *out_child)
 {
 	HANDLE childStdout[2], childStdin[2],childStderr;
 	SECURITY_ATTRIBUTES secAtts;
@@ -44,6 +45,7 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
 	char *arg0, *ext;
 	int i, l;
 	DWORD fl, fl_old;
+	HANDLE child;
 
 	childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE;
 	childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE;
@@ -154,13 +156,20 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
 	*child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY);
 	*child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY);
 	
+	child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
+		childInfo.dwProcessId);
+	if (child == NULL) // INVALID_HANDLE_VALUE ?
+		goto fail;
+
+	*out_child = child;
+
 	CloseHandle(childStdout[1]);
 	CloseHandle(childStdin[0]);
 
 	archive_string_free(&cmdline);
 	archive_string_free(&fullpath);
 	__archive_cmdline_free(acmd);
-	return (childInfo.dwProcessId);
+	return ARCHIVE_OK;
 
 fail:
 	if (childStdout[0] != INVALID_HANDLE_VALUE)
@@ -176,7 +185,7 @@ fail:
 	archive_string_free(&cmdline);
 	archive_string_free(&fullpath);
 	__archive_cmdline_free(acmd);
-	return (-1);
+	return ARCHIVE_FAILED;
 }
 
 void

Некоторые файлы не были показаны из-за большого количества измененных файлов