diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # libarchive
 
+# 3.0.2.0
+
+  * Upgrade bundled `libarchive` to 3.5.0
+  * Require `librachive >= 3.5.0`
+  * Add `archiveReadSupportFilterByCode` and `archiveWriteOpen2`
+  * Add `ArchiveFreeCallback` type
+  * Add `ArchiveEntryDigest` sum type
+
 ## 3.0.1.1
 
   * Add `Internal` modules
diff --git a/c/archive.h b/c/archive.h
--- a/c/archive.h
+++ b/c/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 3004003
+#define	ARCHIVE_VERSION_NUMBER 3005000
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -155,7 +155,7 @@
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_ONLY_STRING "3.4.3"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.5.0"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
@@ -246,6 +246,8 @@
 
 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 @@
 #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_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 *,
diff --git a/c/archive_acl.c b/c/archive_acl.c
--- a/c/archive_acl.c
+++ b/c/archive_acl.c
@@ -595,7 +595,7 @@
 				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 @@
 		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 @@
 	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++;
 	}
diff --git a/c/archive_check_magic.c b/c/archive_check_magic.c
--- a/c/archive_check_magic.c
+++ b/c/archive_check_magic.c
@@ -54,7 +54,7 @@
 	ssize_t written;
 
 	while (s > 0) {
-		written = write(2, m, strlen(m));
+		written = write(2, m, s);
 		if (written <= 0)
 			return;
 		m += written;
diff --git a/c/archive_cryptor.c b/c/archive_cryptor.c
--- a/c/archive_cryptor.c
+++ b/c/archive_cryptor.c
@@ -347,8 +347,31 @@
 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;
 }
 
diff --git a/c/archive_cryptor_private.h b/c/archive_cryptor_private.h
--- a/c/archive_cryptor_private.h
+++ b/c/archive_cryptor_private.h
@@ -104,9 +104,18 @@
 #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];
diff --git a/c/archive_digest_private.h b/c/archive_digest_private.h
--- a/c/archive_digest_private.h
+++ b/c/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:
  *
diff --git a/c/archive_entry.c b/c/archive_entry.c
--- a/c/archive_entry.c
+++ b/c/archive_entry.c
@@ -208,6 +208,19 @@
 
 	/* 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);
@@ -450,7 +463,7 @@
 _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 @@
 		*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
@@ -595,7 +608,7 @@
 _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));
 }
 
 __LA_MODE_T
@@ -723,7 +736,7 @@
 		*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 @@
 _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
@@ -1414,6 +1427,62 @@
       abort();
     memcpy(entry->mac_metadata, p, s);
   }
+}
+
+/* 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
 }
 
 /*
diff --git a/c/archive_entry.h b/c/archive_entry.h
--- a/c/archive_entry.h
+++ b/c/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 3004003
+#define	ARCHIVE_VERSION_NUMBER 3005000
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
@@ -395,6 +395,19 @@
 
 __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
diff --git a/c/archive_entry_private.h b/c/archive_entry_private.h
--- a/c/archive_entry_private.h
+++ b/c/archive_entry_private.h
@@ -50,6 +50,15 @@
 	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 @@
 	void *mac_metadata;
 	size_t mac_metadata_size;
 
+	/* Digest support. */
+	struct ae_digest digest;
+
 	/* ACL support. */
 	struct archive_acl    acl;
 
@@ -180,5 +192,9 @@
 	/* Symlink type support */
 	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 */
diff --git a/c/archive_ppmd7.c b/c/archive_ppmd7.c
--- a/c/archive_ppmd7.c
+++ b/c/archive_ppmd7.c
@@ -4,7 +4,7 @@
 
 #include "archive_platform.h"
 
-#include <memory.h>
+#include <stdlib.h>
 
 #include "archive_ppmd7_private.h"
 
diff --git a/c/archive_read_disk_entry_from_file.c b/c/archive_read_disk_entry_from_file.c
--- a/c/archive_read_disk_entry_from_file.c
+++ b/c/archive_read_disk_entry_from_file.c
@@ -103,6 +103,10 @@
 
 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 @@
 }
 
 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 @@
 
 	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 @@
 		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';
@@ -769,6 +784,31 @@
 	}
 
 	free(list);
+	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);
 }
 
diff --git a/c/archive_read_set_format.c b/c/archive_read_set_format.c
--- a/c/archive_read_set_format.c
+++ b/c/archive_read_set_format.c
@@ -61,6 +61,9 @@
     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,8 +79,14 @@
     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");
diff --git a/c/archive_read_support_filter_by_code.c b/c/archive_read_support_filter_by_code.c
new file mode 100644
--- /dev/null
+++ b/c/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);
+}
diff --git a/c/archive_read_support_format_by_code.c b/c/archive_read_support_format_by_code.c
--- a/c/archive_read_support_format_by_code.c
+++ b/c/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 @@
 	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 @@
 	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 @@
 		return archive_read_support_format_zip(a);
 		break;
 	}
+	archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+	    "Invalid format code specified");
 	return (ARCHIVE_FATAL);
 }
diff --git a/c/archive_read_support_format_cab.c b/c/archive_read_support_format_cab.c
--- a/c/archive_read_support_format_cab.c
+++ b/c/archive_read_support_format_cab.c
@@ -1172,7 +1172,7 @@
 	    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);
diff --git a/c/archive_read_support_format_empty.c b/c/archive_read_support_format_empty.c
--- a/c/archive_read_support_format_empty.c
+++ b/c/archive_read_support_format_empty.c
@@ -47,7 +47,7 @@
 
 	r = __archive_read_register_format(a,
 	    NULL,
-	    NULL,
+	    "empty",
 	    archive_read_format_empty_bid,
 	    NULL,
 	    archive_read_format_empty_read_header,
diff --git a/c/archive_read_support_format_mtree.c b/c/archive_read_support_format_mtree.c
--- a/c/archive_read_support_format_mtree.c
+++ b/c/archive_read_support_format_mtree.c
@@ -51,6 +51,7 @@
 
 #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"
@@ -1482,6 +1483,84 @@
 #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 (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 +1659,10 @@
 		}
 		__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 +1698,32 @@
 			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;
diff --git a/c/archive_read_support_format_rar.c b/c/archive_read_support_format_rar.c
--- a/c/archive_read_support_format_rar.c
+++ b/c/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_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 @@
   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 @@
 
 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 @@
         {
           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. */
diff --git a/c/archive_read_support_format_rar5.c b/c/archive_read_support_format_rar5.c
--- a/c/archive_read_support_format_rar5.c
+++ b/c/archive_read_support_format_rar5.c
@@ -3831,7 +3831,7 @@
 
 				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);
 				}
@@ -3845,7 +3845,7 @@
 			} else {
 				DEBUG_CODE {
 					printf("Checksum OK: CRC32 "
-					    "(%08x/%08x)\n",
+					    "(%08" PRIx32 "/%08" PRIx32 ")\n",
 					    rar->file.stored_crc32,
 					    rar->file.calculated_crc32);
 				}
@@ -3905,6 +3905,9 @@
     size_t *size, int64_t *offset) {
 	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
diff --git a/c/archive_read_support_format_warc.c b/c/archive_read_support_format_warc.c
--- a/c/archive_read_support_format_warc.c
+++ b/c/archive_read_support_format_warc.c
@@ -337,6 +337,14 @@
 			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 @@
 			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);
diff --git a/c/archive_read_support_format_zip.c b/c/archive_read_support_format_zip.c
--- a/c/archive_read_support_format_zip.c
+++ b/c/archive_read_support_format_zip.c
@@ -899,7 +899,82 @@
 	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.
  */
 static int
@@ -1173,18 +1248,64 @@
 			    "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 @@
 
 	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);
 	}
diff --git a/c/archive_string.c b/c/archive_string.c
--- a/c/archive_string.c
+++ b/c/archive_string.c
@@ -3881,6 +3881,11 @@
 	}
 
 	*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 @@
 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 @@
 			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 @@
 	}
 
 	*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 @@
 }
 
 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 @@
 	}
 #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. */
diff --git a/c/archive_string.h b/c/archive_string.h
--- a/c/archive_string.h
+++ b/c/archive_string.h
@@ -226,7 +226,7 @@
 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,
diff --git a/c/archive_util.c b/c/archive_util.c
--- a/c/archive_util.c
+++ b/c/archive_util.c
@@ -433,6 +433,11 @@
 		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)
diff --git a/c/archive_write.c b/c/archive_write.c
--- a/c/archive_write.c
+++ b/c/archive_write.c
@@ -456,6 +456,25 @@
 }
 
 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)
 {
 	struct archive_write *a = (struct archive_write *)f->archive;
@@ -493,13 +512,7 @@
 		(*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 @@
  * 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 @@
 	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) {
@@ -542,6 +557,15 @@
 	if (a->format_init)
 		ret = (a->format_init)(a);
 	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);
 }
 
 /*
diff --git a/c/archive_write_add_filter_xz.c b/c/archive_write_add_filter_xz.c
--- a/c/archive_write_add_filter_xz.c
+++ b/c/archive_write_add_filter_xz.c
@@ -382,8 +382,8 @@
 		    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;
diff --git a/c/archive_write_disk_posix.c b/c/archive_write_disk_posix.c
--- a/c/archive_write_disk_posix.c
+++ b/c/archive_write_disk_posix.c
@@ -4423,10 +4423,19 @@
 			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);
@@ -4437,8 +4446,29 @@
 			}
 
 			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,
diff --git a/c/archive_write_open_fd.c b/c/archive_write_open_fd.c
--- a/c/archive_write_open_fd.c
+++ b/c/archive_write_open_fd.c
@@ -54,7 +54,7 @@
 	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 @@
 #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 @@
 }
 
 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);
 }
diff --git a/c/archive_write_open_file.c b/c/archive_write_open_file.c
--- a/c/archive_write_open_file.c
+++ b/c/archive_write_open_file.c
@@ -51,7 +51,7 @@
 	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 @@
 		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 @@
 }
 
 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);
 }
diff --git a/c/archive_write_open_filename.c b/c/archive_write_open_filename.c
--- a/c/archive_write_open_filename.c
+++ b/c/archive_write_open_filename.c
@@ -62,6 +62,7 @@
 };
 
 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 @@
 		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,8 +245,24 @@
 
 	(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);
diff --git a/c/archive_write_open_memory.c b/c/archive_write_open_memory.c
--- a/c/archive_write_open_memory.c
+++ b/c/archive_write_open_memory.c
@@ -39,7 +39,7 @@
 	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 @@
 	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 @@
 }
 
 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);
 }
diff --git a/c/archive_write_private.h b/c/archive_write_private.h
--- a/c/archive_write_private.h
+++ b/c/archive_write_private.h
@@ -89,6 +89,7 @@
 	archive_open_callback	*client_opener;
 	archive_write_callback	*client_writer;
 	archive_close_callback	*client_closer;
+	archive_free_callback	*client_freer;
 	void			*client_data;
 
 	/*
diff --git a/c/archive_write_set_format_7zip.c b/c/archive_write_set_format_7zip.c
--- a/c/archive_write_set_format_7zip.c
+++ b/c/archive_write_set_format_7zip.c
@@ -1927,8 +1927,8 @@
 		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;
diff --git a/c/archive_write_set_format_cpio.c b/c/archive_write_set_format_cpio.c
--- a/c/archive_write_set_format_cpio.c
+++ b/c/archive_write_set_format_cpio.c
@@ -250,7 +250,7 @@
 	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 @@
 	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);
diff --git a/c/archive_write_set_format_cpio_newc.c b/c/archive_write_set_format_cpio_newc.c
--- a/c/archive_write_set_format_cpio_newc.c
+++ b/c/archive_write_set_format_cpio_newc.c
@@ -190,7 +190,7 @@
 	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);
 	}
diff --git a/c/archive_write_set_format_iso9660.c b/c/archive_write_set_format_iso9660.c
--- a/c/archive_write_set_format_iso9660.c
+++ b/c/archive_write_set_format_iso9660.c
@@ -2178,7 +2178,8 @@
 	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
 }
 
diff --git a/c/archive_write_set_format_mtree.c b/c/archive_write_set_format_mtree.c
--- a/c/archive_write_set_format_mtree.c
+++ b/c/archive_write_set_format_mtree.c
@@ -37,6 +37,7 @@
 #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 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 @@
 	}
 #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 @@
 		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
diff --git a/c/archive_write_set_format_xar.c b/c/archive_write_set_format_xar.c
--- a/c/archive_write_set_format_xar.c
+++ b/c/archive_write_set_format_xar.c
@@ -2931,8 +2931,8 @@
 		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;
diff --git a/c/archive_write_set_format_zip.c b/c/archive_write_set_format_zip.c
--- a/c/archive_write_set_format_zip.c
+++ b/c/archive_write_set_format_zip.c
@@ -584,6 +584,7 @@
 			zip->entry_flags |= ZIP_ENTRY_FLAG_ENCRYPTED;
 			zip->entry_encryption = zip->encryption_type;
 			break;
+		case ENCRYPTION_NONE:
 		default:
 			break;
 		}
@@ -710,6 +711,7 @@
 				    + AUTH_CODE_SIZE;
 				version_needed = 20;
 				break;
+			case ENCRYPTION_NONE:
 			default:
 				break;
 			}
@@ -762,6 +764,7 @@
 				if (version_needed < 20)
 					version_needed = 20;
 				break;
+			case ENCRYPTION_NONE:
 			default:
 				break;
 			}
@@ -1029,6 +1032,7 @@
 				zip->cctx_valid = zip->hctx_valid = 1;
 			}
 			break;
+		case ENCRYPTION_NONE:
 		default:
 			break;
 		}
@@ -1117,6 +1121,7 @@
 		break;
 #endif
 
+	case COMPRESSION_UNSPECIFIED:
 	default:
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 		    "Invalid ZIP compression type");
diff --git a/c/autoconf-darwin/config.h b/c/autoconf-darwin/config.h
--- a/c/autoconf-darwin/config.h
+++ b/c/autoconf-darwin/config.h
@@ -170,13 +170,13 @@
 /* #undef ARCHIVE_XATTR_LINUX */
 
 /* Version number of bsdcat */
-#define BSDCAT_VERSION_STRING "3.4.3"
+#define BSDCAT_VERSION_STRING "3.5.0"
 
 /* Version number of bsdcpio */
-#define BSDCPIO_VERSION_STRING "3.4.3"
+#define BSDCPIO_VERSION_STRING "3.5.0"
 
 /* Version number of bsdtar */
-#define BSDTAR_VERSION_STRING "3.4.3"
+#define BSDTAR_VERSION_STRING "3.5.0"
 
 /* Define to 1 if the system has the type `ace_t'. */
 /* #undef HAVE_ACE_T */
@@ -1236,10 +1236,10 @@
 /* #undef ICONV_CONST */
 
 /* Version number of libarchive as a single integer */
-#define LIBARCHIVE_VERSION_NUMBER "3004003"
+#define LIBARCHIVE_VERSION_NUMBER "3005000"
 
 /* Version number of libarchive */
-#define LIBARCHIVE_VERSION_STRING "3.4.3"
+#define LIBARCHIVE_VERSION_STRING "3.5.0"
 
 /* Define to 1 if `lstat' dereferences a symlink specified with a trailing
    slash. */
@@ -1269,7 +1269,7 @@
 #define PACKAGE_NAME "libarchive"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libarchive 3.4.3"
+#define PACKAGE_STRING "libarchive 3.5.0"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "libarchive"
@@ -1278,7 +1278,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "3.4.3"
+#define PACKAGE_VERSION "3.5.0"
 
 /* Define to 1 if PCRE_STATIC needs to be defined. */
 /* #undef PCRE_STATIC */
@@ -1318,7 +1318,7 @@
 
 
 /* Version number of package */
-#define VERSION "3.4.3"
+#define VERSION "3.5.0"
 
 /* Define to '0x0502' for Windows Server 2003 APIs. */
 /* #undef WINVER */
@@ -1364,6 +1364,9 @@
 
 /* Define to '0x0502' for Windows Server 2003 APIs. */
 /* #undef _WIN32_WINNT */
+
+/* Internal macro for sanity checks */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
diff --git a/c/autoconf-freebsd/config.h b/c/autoconf-freebsd/config.h
--- a/c/autoconf-freebsd/config.h
+++ b/c/autoconf-freebsd/config.h
@@ -165,13 +165,13 @@
 /* #undef ARCHIVE_XATTR_LINUX */
 
 /* Version number of bsdcat */
-#define BSDCAT_VERSION_STRING "3.4.3"
+#define BSDCAT_VERSION_STRING "3.5.0"
 
 /* Version number of bsdcpio */
-#define BSDCPIO_VERSION_STRING "3.4.3"
+#define BSDCPIO_VERSION_STRING "3.5.0"
 
 /* Version number of bsdtar */
-#define BSDTAR_VERSION_STRING "3.4.3"
+#define BSDTAR_VERSION_STRING "3.5.0"
 
 /* Define to 1 if the system has the type `ace_t'. */
 /* #undef HAVE_ACE_T */
@@ -1225,10 +1225,10 @@
 /* #undef ICONV_CONST */
 
 /* Version number of libarchive as a single integer */
-#define LIBARCHIVE_VERSION_NUMBER "3004003"
+#define LIBARCHIVE_VERSION_NUMBER "3005000"
 
 /* Version number of libarchive */
-#define LIBARCHIVE_VERSION_STRING "3.4.3"
+#define LIBARCHIVE_VERSION_STRING "3.5.0"
 
 /* Define to 1 if `lstat' dereferences a symlink specified with a trailing
    slash. */
@@ -1258,7 +1258,7 @@
 #define PACKAGE_NAME "libarchive"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libarchive 3.4.3"
+#define PACKAGE_STRING "libarchive 3.5.0"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "libarchive"
@@ -1267,7 +1267,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "3.4.3"
+#define PACKAGE_VERSION "3.5.0"
 
 /* Define to 1 if PCRE_STATIC needs to be defined. */
 /* #undef PCRE_STATIC */
@@ -1307,7 +1307,7 @@
 
 
 /* Version number of package */
-#define VERSION "3.4.3"
+#define VERSION "3.5.0"
 
 /* Define to '0x0502' for Windows Server 2003 APIs. */
 /* #undef WINVER */
@@ -1353,6 +1353,9 @@
 
 /* Define to '0x0502' for Windows Server 2003 APIs. */
 /* #undef _WIN32_WINNT */
+
+/* Internal macro for sanity checks */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
diff --git a/c/autoconf-linux/config.h b/c/autoconf-linux/config.h
--- a/c/autoconf-linux/config.h
+++ b/c/autoconf-linux/config.h
@@ -170,13 +170,13 @@
 /* #undef ARCHIVE_XATTR_LINUX */
 
 /* Version number of bsdcat */
-#define BSDCAT_VERSION_STRING "3.4.3"
+#define BSDCAT_VERSION_STRING "3.5.0"
 
 /* Version number of bsdcpio */
-#define BSDCPIO_VERSION_STRING "3.4.3"
+#define BSDCPIO_VERSION_STRING "3.5.0"
 
 /* Version number of bsdtar */
-#define BSDTAR_VERSION_STRING "3.4.3"
+#define BSDTAR_VERSION_STRING "3.5.0"
 
 /* Define to 1 if the system has the type `ace_t'. */
 /* #undef HAVE_ACE_T */
@@ -453,7 +453,6 @@
 /* #undef HAVE_EXPAT_H */
 
 /* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */
-/* #undef HAVE_EXT2FS_EXT2_FS_H */
 
 /* Define to 1 if you have the `extattr_get_fd' function. */
 /* #undef HAVE_EXTATTR_GET_FD */
@@ -606,7 +605,7 @@
 /* #undef HAVE_LCHFLAGS */
 
 /* Define to 1 if you have the `lchmod' function. */
-/* #undef HAVE_LCHMOD 1 */
+/* #undef HAVE_LCHMOD */
 
 /* Define to 1 if you have the `lchown' function. */
 #define HAVE_LCHOWN 1
@@ -1031,7 +1030,7 @@
 /* #undef HAVE_STRUCT_TM_TM_GMTOFF 1 */
 
 /* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */
-/* #undef HAVE_STRUCT_TM___TM_GMTOFF 1 */
+/* #undef HAVE_STRUCT_TM___TM_GMTOFF */
 
 /* Define to 1 if the system has the type `struct vfsconf'. */
 /* #undef HAVE_STRUCT_VFSCONF */
@@ -1237,10 +1236,10 @@
 /* #undef ICONV_CONST */
 
 /* Version number of libarchive as a single integer */
-#define LIBARCHIVE_VERSION_NUMBER "3004003"
+#define LIBARCHIVE_VERSION_NUMBER "3005000"
 
 /* Version number of libarchive */
-#define LIBARCHIVE_VERSION_STRING "3.4.3"
+#define LIBARCHIVE_VERSION_STRING "3.5.0"
 
 /* Define to 1 if `lstat' dereferences a symlink specified with a trailing
    slash. */
@@ -1270,7 +1269,7 @@
 #define PACKAGE_NAME "libarchive"
 
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libarchive 3.4.3"
+#define PACKAGE_STRING "libarchive 3.5.0"
 
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "libarchive"
@@ -1279,7 +1278,7 @@
 #define PACKAGE_URL ""
 
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "3.4.3"
+#define PACKAGE_VERSION "3.5.0"
 
 /* Define to 1 if PCRE_STATIC needs to be defined. */
 /* #undef PCRE_STATIC */
@@ -1319,7 +1318,7 @@
 
 
 /* Version number of package */
-#define VERSION "3.4.3"
+#define VERSION "3.5.0"
 
 /* Define to '0x0502' for Windows Server 2003 APIs. */
 /* #undef WINVER */
@@ -1365,6 +1364,9 @@
 
 /* Define to '0x0502' for Windows Server 2003 APIs. */
 /* #undef _WIN32_WINNT */
+
+/* Internal macro for sanity checks */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 
 /* Define to empty if `const' does not conform to ANSI C. */
 /* #undef const */
diff --git a/c/config_freebsd.h b/c/config_freebsd.h
--- a/c/config_freebsd.h
+++ b/c/config_freebsd.h
@@ -24,6 +24,7 @@
  *
  * $FreeBSD$
  */
+#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
 
 #include <osreldate.h>
 
diff --git a/libarchive.cabal b/libarchive.cabal
--- a/libarchive.cabal
+++ b/libarchive.cabal
@@ -1,34 +1,31 @@
-cabal-version:      3.0
-name:               libarchive
-version:            3.0.1.1
-license:            BSD-3-Clause
-license-file:       LICENSE
-copyright:          Copyright: (c) 2018-2020 Vanessa McHale
-maintainer:         vamchale@gmail.com
-author:             Vanessa McHale
-tested-with:
-    ghc ==8.0.2 ghc ==8.2.2 ghc ==8.4.4 ghc ==8.6.5 ghc ==8.8.4
-    ghc ==8.10.2
-
-bug-reports:        https://github.com/vmchale/libarchive/issues
-synopsis:           Haskell interface to libarchive
+cabal-version:   3.0
+name:            libarchive
+version:         3.0.2.0
+license:         BSD-3-Clause
+license-file:    LICENSE
+copyright:       Copyright: (c) 2018-2020 Vanessa McHale
+maintainer:      vamchale@gmail.com
+author:          Vanessa McHale
+tested-with:     ghc ==7.10.3 ghc ==8.0.2 ghc == 8.2.2 ghc ==8.4.4 ghc ==8.6.5 ghc ==8.8.4 ghc ==8.10.2
+bug-reports:     https://github.com/vmchale/libarchive/issues
+synopsis:        Haskell interface to libarchive
 description:
     Haskell bindings for [libarchive](https://www.libarchive.org/). Provides the ability to unpack archives, including the ability to unpack archives lazily.
 
-category:           Codec
-build-type:         Custom
-extra-source-files:
-    c/autoconf-darwin/config.h
-    c/autoconf-linux/config.h
-    c/autoconf-freebsd/config.h
-    c/*.c
-    c/*.h
-    test/data/aarch64-linux-dist.tar
-
+category:        Codec
+build-type:      Custom
 extra-doc-files:
     README.md
     CHANGELOG.md
 
+extra-source-files:
+  c/autoconf-darwin/config.h
+  c/autoconf-linux/config.h
+  c/autoconf-freebsd/config.h
+  c/*.c
+  c/*.h
+  test/data/aarch64-linux-dist.tar
+
 source-repository head
     type:     git
     location: https://github.com/vmchale/libarchive
@@ -49,8 +46,8 @@
     default:     False
 
 flag system-libarchive
-    description:
-        Use libarchive found with pkg-config rather than the bundled sources
+  default:     True
+  description: Use libarchive found with pkg-config rather than the bundled sources
 
 library
     exposed-modules:
@@ -65,7 +62,7 @@
         Codec.Archive.Internal.Unpack
         Codec.Archive.Internal.Monad
 
-    hs-source-dirs:   src
+    hs-source-dirs:    src
     other-modules:
         Codec.Archive.Foreign.Archive.Macros
         Codec.Archive.Foreign.ArchiveEntry.Macros
@@ -73,9 +70,9 @@
         Codec.Archive.Types.Foreign
         Codec.Archive.Permissions
 
-    default-language: Haskell2010
-    other-extensions: DeriveGeneric DeriveAnyClass
-    ghc-options:      -Wall
+    default-language:  Haskell2010
+    other-extensions:  DeriveGeneric DeriveAnyClass
+    ghc-options:       -Wall
     build-depends:
         base >=4.8 && <5,
         bytestring -any,
@@ -106,156 +103,157 @@
         ghc-options: -Wunused-packages
 
     if !flag(system-libarchive)
-        cc-options:   -std=c11 -DHAVE_CONFIG_H
-        c-sources:
-            c/archive_acl.c
-            c/archive_blake2sp_ref.c
-            c/archive_blake2s_ref.c
-            c/archive_check_magic.c
-            c/archive_cmdline.c
-            c/archive_cryptor.c
-            c/archive_digest.c
-            c/archive_disk_acl_darwin.c
-            c/archive_disk_acl_freebsd.c
-            c/archive_disk_acl_linux.c
-            c/archive_disk_acl_sunos.c
-            c/archive_entry.c
-            c/archive_entry_copy_bhfi.c
-            c/archive_entry_copy_stat.c
-            c/archive_entry_link_resolver.c
-            c/archive_entry_sparse.c
-            c/archive_entry_stat.c
-            c/archive_entry_strmode.c
-            c/archive_entry_xattr.c
-            c/archive_getdate.c
-            c/archive_hmac.c
-            c/archive_match.c
-            c/archive_options.c
-            c/archive_pack_dev.c
-            c/archive_pathmatch.c
-            c/archive_ppmd7.c
-            c/archive_ppmd8.c
-            c/archive_random.c
-            c/archive_rb.c
-            c/archive_read_add_passphrase.c
-            c/archive_read_append_filter.c
-            c/archive_read.c
-            c/archive_read_data_into_fd.c
-            c/archive_read_disk_entry_from_file.c
-            c/archive_read_disk_posix.c
-            c/archive_read_disk_set_standard_lookup.c
-            c/archive_read_disk_windows.c
-            c/archive_read_extract2.c
-            c/archive_read_extract.c
-            c/archive_read_open_fd.c
-            c/archive_read_open_file.c
-            c/archive_read_open_filename.c
-            c/archive_read_open_memory.c
-            c/archive_read_set_format.c
-            c/archive_read_set_options.c
-            c/archive_read_support_filter_all.c
-            c/archive_read_support_filter_bzip2.c
-            c/archive_read_support_filter_compress.c
-            c/archive_read_support_filter_grzip.c
-            c/archive_read_support_filter_gzip.c
-            c/archive_read_support_filter_lrzip.c
-            c/archive_read_support_filter_lz4.c
-            c/archive_read_support_filter_lzop.c
-            c/archive_read_support_filter_none.c
-            c/archive_read_support_filter_program.c
-            c/archive_read_support_filter_rpm.c
-            c/archive_read_support_filter_uu.c
-            c/archive_read_support_filter_xz.c
-            c/archive_read_support_filter_zstd.c
-            c/archive_read_support_format_7zip.c
-            c/archive_read_support_format_all.c
-            c/archive_read_support_format_ar.c
-            c/archive_read_support_format_by_code.c
-            c/archive_read_support_format_cab.c
-            c/archive_read_support_format_cpio.c
-            c/archive_read_support_format_empty.c
-            c/archive_read_support_format_iso9660.c
-            c/archive_read_support_format_lha.c
-            c/archive_read_support_format_mtree.c
-            c/archive_read_support_format_rar5.c
-            c/archive_read_support_format_rar.c
-            c/archive_read_support_format_raw.c
-            c/archive_read_support_format_tar.c
-            c/archive_read_support_format_warc.c
-            c/archive_read_support_format_xar.c
-            c/archive_read_support_format_zip.c
-            c/archive_string.c
-            c/archive_string_sprintf.c
-            c/archive_util.c
-            c/archive_version_details.c
-            c/archive_virtual.c
-            c/archive_windows.c
-            c/archive_write_add_filter_b64encode.c
-            c/archive_write_add_filter_by_name.c
-            c/archive_write_add_filter_bzip2.c
-            c/archive_write_add_filter.c
-            c/archive_write_add_filter_compress.c
-            c/archive_write_add_filter_grzip.c
-            c/archive_write_add_filter_gzip.c
-            c/archive_write_add_filter_lrzip.c
-            c/archive_write_add_filter_lz4.c
-            c/archive_write_add_filter_lzop.c
-            c/archive_write_add_filter_none.c
-            c/archive_write_add_filter_program.c
-            c/archive_write_add_filter_uuencode.c
-            c/archive_write_add_filter_xz.c
-            c/archive_write_add_filter_zstd.c
-            c/archive_write.c
-            c/archive_write_disk_posix.c
-            c/archive_write_disk_set_standard_lookup.c
-            c/archive_write_disk_windows.c
-            c/archive_write_open_fd.c
-            c/archive_write_open_file.c
-            c/archive_write_open_filename.c
-            c/archive_write_open_memory.c
-            c/archive_write_set_format_7zip.c
-            c/archive_write_set_format_ar.c
-            c/archive_write_set_format_by_name.c
-            c/archive_write_set_format.c
-            c/archive_write_set_format_cpio.c
-            c/archive_write_set_format_cpio_newc.c
-            c/archive_write_set_format_filter_by_ext.c
-            c/archive_write_set_format_gnutar.c
-            c/archive_write_set_format_iso9660.c
-            c/archive_write_set_format_mtree.c
-            c/archive_write_set_format_pax.c
-            c/archive_write_set_format_raw.c
-            c/archive_write_set_format_shar.c
-            c/archive_write_set_format_ustar.c
-            c/archive_write_set_format_v7tar.c
-            c/archive_write_set_format_warc.c
-            c/archive_write_set_format_xar.c
-            c/archive_write_set_format_zip.c
-            c/archive_write_set_options.c
-            c/archive_write_set_passphrase.c
-            c/filter_fork_posix.c
-            c/filter_fork_windows.c
-            c/xxhash.c
-
-        include-dirs: c/
+        include-dirs: c
 
-        if os(osx)
-            include-dirs: c/autoconf-darwin
+    if !flag(system-libarchive)
+        -- version 3.5.0
+        c-sources:
+          c/archive_acl.c
+          c/archive_blake2sp_ref.c
+          c/archive_blake2s_ref.c
+          c/archive_check_magic.c
+          c/archive_cmdline.c
+          c/archive_cryptor.c
+          c/archive_digest.c
+          c/archive_disk_acl_darwin.c
+          c/archive_disk_acl_freebsd.c
+          c/archive_disk_acl_linux.c
+          c/archive_disk_acl_sunos.c
+          c/archive_entry.c
+          c/archive_entry_copy_bhfi.c
+          c/archive_entry_copy_stat.c
+          c/archive_entry_link_resolver.c
+          c/archive_entry_sparse.c
+          c/archive_entry_stat.c
+          c/archive_entry_strmode.c
+          c/archive_entry_xattr.c
+          c/archive_getdate.c
+          c/archive_hmac.c
+          c/archive_match.c
+          c/archive_options.c
+          c/archive_pack_dev.c
+          c/archive_pathmatch.c
+          c/archive_ppmd7.c
+          c/archive_ppmd8.c
+          c/archive_random.c
+          c/archive_rb.c
+          c/archive_read_add_passphrase.c
+          c/archive_read_append_filter.c
+          c/archive_read.c
+          c/archive_read_data_into_fd.c
+          c/archive_read_disk_entry_from_file.c
+          c/archive_read_disk_posix.c
+          c/archive_read_disk_set_standard_lookup.c
+          c/archive_read_disk_windows.c
+          c/archive_read_extract2.c
+          c/archive_read_extract.c
+          c/archive_read_open_fd.c
+          c/archive_read_open_file.c
+          c/archive_read_open_filename.c
+          c/archive_read_open_memory.c
+          c/archive_read_set_format.c
+          c/archive_read_set_options.c
+          c/archive_read_support_filter_all.c
+          c/archive_read_support_filter_by_code.c
+          c/archive_read_support_filter_bzip2.c
+          c/archive_read_support_filter_compress.c
+          c/archive_read_support_filter_grzip.c
+          c/archive_read_support_filter_gzip.c
+          c/archive_read_support_filter_lrzip.c
+          c/archive_read_support_filter_lz4.c
+          c/archive_read_support_filter_lzop.c
+          c/archive_read_support_filter_none.c
+          c/archive_read_support_filter_program.c
+          c/archive_read_support_filter_rpm.c
+          c/archive_read_support_filter_uu.c
+          c/archive_read_support_filter_xz.c
+          c/archive_read_support_filter_zstd.c
+          c/archive_read_support_format_7zip.c
+          c/archive_read_support_format_all.c
+          c/archive_read_support_format_ar.c
+          c/archive_read_support_format_by_code.c
+          c/archive_read_support_format_cab.c
+          c/archive_read_support_format_cpio.c
+          c/archive_read_support_format_empty.c
+          c/archive_read_support_format_iso9660.c
+          c/archive_read_support_format_lha.c
+          c/archive_read_support_format_mtree.c
+          c/archive_read_support_format_rar5.c
+          c/archive_read_support_format_rar.c
+          c/archive_read_support_format_raw.c
+          c/archive_read_support_format_tar.c
+          c/archive_read_support_format_warc.c
+          c/archive_read_support_format_xar.c
+          c/archive_read_support_format_zip.c
+          c/archive_string.c
+          c/archive_string_sprintf.c
+          c/archive_util.c
+          c/archive_version_details.c
+          c/archive_virtual.c
+          c/archive_windows.c
+          c/archive_write_add_filter_b64encode.c
+          c/archive_write_add_filter_by_name.c
+          c/archive_write_add_filter_bzip2.c
+          c/archive_write_add_filter.c
+          c/archive_write_add_filter_compress.c
+          c/archive_write_add_filter_grzip.c
+          c/archive_write_add_filter_gzip.c
+          c/archive_write_add_filter_lrzip.c
+          c/archive_write_add_filter_lz4.c
+          c/archive_write_add_filter_lzop.c
+          c/archive_write_add_filter_none.c
+          c/archive_write_add_filter_program.c
+          c/archive_write_add_filter_uuencode.c
+          c/archive_write_add_filter_xz.c
+          c/archive_write_add_filter_zstd.c
+          c/archive_write.c
+          c/archive_write_disk_posix.c
+          c/archive_write_disk_set_standard_lookup.c
+          c/archive_write_disk_windows.c
+          c/archive_write_open_fd.c
+          c/archive_write_open_file.c
+          c/archive_write_open_filename.c
+          c/archive_write_open_memory.c
+          c/archive_write_set_format_7zip.c
+          c/archive_write_set_format_ar.c
+          c/archive_write_set_format_by_name.c
+          c/archive_write_set_format.c
+          c/archive_write_set_format_cpio.c
+          c/archive_write_set_format_cpio_newc.c
+          c/archive_write_set_format_filter_by_ext.c
+          c/archive_write_set_format_gnutar.c
+          c/archive_write_set_format_iso9660.c
+          c/archive_write_set_format_mtree.c
+          c/archive_write_set_format_pax.c
+          c/archive_write_set_format_raw.c
+          c/archive_write_set_format_shar.c
+          c/archive_write_set_format_ustar.c
+          c/archive_write_set_format_v7tar.c
+          c/archive_write_set_format_warc.c
+          c/archive_write_set_format_xar.c
+          c/archive_write_set_format_zip.c
+          c/archive_write_set_options.c
+          c/archive_write_set_passphrase.c
+          c/filter_fork_posix.c
+          c/filter_fork_windows.c
+          c/xxhash.c
 
+        if os(darwin)
+          include-dirs: c/autoconf-darwin
+        elif os(linux)
+          include-dirs: c/autoconf-linux
+        elif os(freebsd)
+          include-dirs: c/autoconf-freebsd
         else
-            if os(linux)
-                include-dirs: c/autoconf-linux
-
-            else
-                if os(freebsd)
-                    include-dirs: c/autoconf-freebsd
+          build-depends: unbuildable<0
+          buildable: False
 
-                else
-                    buildable:     False
-                    build-depends: unbuildable <0
+        include-dirs: c/
 
+        cc-options: -std=c11 -DHAVE_CONFIG_H
     else
-        pkgconfig-depends: libarchive (==3.4.0 || >3.4.0) && <4.0
+        pkgconfig-depends: libarchive (==3.5.0 || >3.5.0) && <4.0
+
 
 test-suite libarchive-test
     type:               exitcode-stdio-1.0
diff --git a/src/Codec/Archive.hs b/src/Codec/Archive.hs
--- a/src/Codec/Archive.hs
+++ b/src/Codec/Archive.hs
@@ -38,6 +38,7 @@
     , packToFileShar
     -- * Concrete (Haskell) types
     , ArchiveResult (..)
+    , ArchiveEntryDigest (..)
     , Entry (..)
     , Symlink (..)
     , EntryContent (..)
@@ -57,7 +58,7 @@
 import           Codec.Archive.Internal.Monad
 import           Codec.Archive.Internal.Pack
 import           Codec.Archive.Internal.Pack.Lazy
-import           Codec.Archive.Permissions
-import           Codec.Archive.Types
 import           Codec.Archive.Internal.Unpack
 import           Codec.Archive.Internal.Unpack.Lazy
+import           Codec.Archive.Permissions
+import           Codec.Archive.Types
diff --git a/src/Codec/Archive/Foreign/Archive.chs b/src/Codec/Archive/Foreign/Archive.chs
--- a/src/Codec/Archive/Foreign/Archive.chs
+++ b/src/Codec/Archive/Foreign/Archive.chs
@@ -68,6 +68,7 @@
                                      , archiveReadClose
                                      , archiveReadFree
                                      , archiveReadSupportFilterAll
+                                     , archiveReadSupportFilterByCode
                                      , archiveReadSupportFilterBzip2
                                      , archiveReadSupportFilterCompress
                                      , archiveReadSupportFilterGzip
@@ -158,6 +159,7 @@
                                      , archiveWriteSetFormatFilterByExtDef
                                      , archiveWriteZipSetCompressionDeflate
                                      , archiveWriteZipSetCompressionStore
+                                     , archiveWriteOpen2
                                      , archiveWriteOpenFd
                                      , archiveWriteOpenFilenameW
                                      , archiveWriteOpenFilename
@@ -302,6 +304,7 @@
                                      , ArchiveCloseCallbackRaw
                                      , ArchiveSwitchCallbackRaw
                                      , ArchivePassphraseCallback
+                                     , ArchiveFreeCallback
                                      -- * Callback constructors
                                      , noOpenCallback
                                      , mkReadCallback
@@ -312,6 +315,7 @@
                                      , mkOpenCallback
                                      , mkCloseCallback
                                      , mkSwitchCallback
+                                     , mkFreeCallback
                                      , mkWriteLookup
                                      , mkReadLookup
                                      , mkCleanup
@@ -340,7 +344,6 @@
 import Foreign.Storable (Storable (peek))
 import System.Posix.Types (Fd (..))
 
--- destructors: use "dynamic" instead of "wrapper" (but we don't want that)
 -- callbacks
 foreign import ccall "wrapper" mkReadCallback :: ArchiveReadCallback a b -> IO (FunPtr (ArchiveReadCallback a b))
 foreign import ccall "wrapper" mkSkipCallback :: ArchiveSkipCallback a -> IO (FunPtr (ArchiveSkipCallback a))
@@ -351,6 +354,7 @@
 foreign import ccall "wrapper" mkSwitchCallbackRaw :: ArchiveSwitchCallbackRaw a b -> IO (FunPtr (ArchiveSwitchCallbackRaw a b))
 foreign import ccall "wrapper" mkPassphraseCallback :: ArchivePassphraseCallback a -> IO (FunPtr (ArchivePassphraseCallback a))
 foreign import ccall "wrapper" mkExcludedCallback :: (Ptr Archive -> Ptr a -> Ptr ArchiveEntry -> IO ()) -> IO (FunPtr (Ptr Archive -> Ptr a -> Ptr ArchiveEntry -> IO ()))
+foreign import ccall "wrapper" mkFreeCallbackRaw :: ArchiveFreeCallbackRaw a -> IO (FunPtr (ArchiveFreeCallbackRaw a))
 
 -- | Don't use an open callback. This is the recommended argument to 'archiveReadOpen'
 noOpenCallback :: FunPtr (ArchiveOpenCallbackRaw a)
@@ -375,6 +379,9 @@
 mkSwitchCallback :: ArchiveSwitchCallback a b -> IO (FunPtr (ArchiveSwitchCallbackRaw a b))
 mkSwitchCallback f = let f' = fmap resultToErr .** f in mkSwitchCallbackRaw f'
 
+mkFreeCallback :: ArchiveFreeCallback a -> IO (FunPtr (ArchiveFreeCallbackRaw a))
+mkFreeCallback f = let f' = fmap resultToErr .* f in mkFreeCallbackRaw f'
+
 mkFilter :: (Ptr Archive -> Ptr a -> Ptr ArchiveEntry -> IO Bool) -> IO (FunPtr (Ptr Archive -> Ptr a -> Ptr ArchiveEntry -> IO CInt))
 mkFilter f = let f' = fmap boolToInt .** f in preMkFilter f'
     where boolToInt False = 0
@@ -558,6 +565,13 @@
                                , castFunPtr `FunPtr (ArchiveWriteCallback a b)'
                                , castFunPtr `FunPtr (ArchiveCloseCallbackRaw a)'
                                } -> `ArchiveResult' #}
+{# fun archive_write_open2 as ^ { `ArchivePtr'
+                                , castPtr `Ptr a'
+                                , castFunPtr `FunPtr (ArchiveOpenCallbackRaw a)'
+                                , castFunPtr `FunPtr (ArchiveWriteCallback a b)'
+                                , castFunPtr `FunPtr (ArchiveCloseCallbackRaw a)'
+                                , castFunPtr `FunPtr (ArchiveFreeCallbackRaw a)'
+                                } -> `ArchiveResult' #}
 {# fun archive_write_open_fd as ^ { `ArchivePtr', coerce `Fd' } -> `ArchiveResult' #}
 {# fun archive_write_open_filename as ^ { `ArchivePtr', `CString' } -> `ArchiveResult' #}
 {# fun archive_write_open_filename_w as ^ { `ArchivePtr', `CWString' } -> `ArchiveResult' #}
@@ -644,6 +658,7 @@
 {# fun archive_match_include_gid as ^ { `ArchivePtr', coerce `Id' } -> `ArchiveResult' #}
 {# fun archive_match_include_uid as ^ { `ArchivePtr', coerce `Id' } -> `ArchiveResult' #}
 {# fun archive_read_support_filter_all as ^ { `ArchivePtr' } -> `ArchiveResult' #}
+{# fun archive_read_support_filter_by_code as ^ { `ArchivePtr', `CInt' } -> `ArchiveResult' #}
 {# fun archive_read_support_filter_bzip2 as ^ { `ArchivePtr' } -> `ArchiveResult' #}
 {# fun archive_read_support_filter_compress as ^ { `ArchivePtr' } -> `ArchiveResult' #}
 {# fun archive_read_support_filter_gzip as ^ { `ArchivePtr' } -> `ArchiveResult' #}
diff --git a/src/Codec/Archive/Foreign/ArchiveEntry.chs b/src/Codec/Archive/Foreign/ArchiveEntry.chs
--- a/src/Codec/Archive/Foreign/ArchiveEntry.chs
+++ b/src/Codec/Archive/Foreign/ArchiveEntry.chs
@@ -126,6 +126,7 @@
                                           , archiveEntryCopyStat
                                           , archiveEntryMacMetadata
                                           , archiveEntryCopyMacMetadata
+                                          , archiveEntryDigest
                                           , archiveEntryAclClear
                                           , archiveEntryAclNext
                                           -- , archiveEntryAclNextW
@@ -404,3 +405,4 @@
 {# fun archive_entry_update_pathname_utf8 as ^ { `ArchiveEntryPtr', `CString' } -> `Bool' #}
 {# fun archive_entry_update_symlink_utf8 as ^ { `ArchiveEntryPtr', `CString' } -> `Bool' #}
 {# fun archive_entry_update_uname_utf8 as ^ { `ArchiveEntryPtr', `CString' } -> `Bool' #}
+{# fun archive_entry_digest as ^ { `ArchiveEntryPtr', `ArchiveEntryDigest' } -> `Ptr CUChar' id #}
diff --git a/src/Codec/Archive/Internal/Unpack.hs b/src/Codec/Archive/Internal/Unpack.hs
--- a/src/Codec/Archive/Internal/Unpack.hs
+++ b/src/Codec/Archive/Internal/Unpack.hs
@@ -71,10 +71,18 @@
     where act a =
             archiveFile fp a $> LazyST.runST (hsEntriesST a)
 
-archiveFile :: FilePath -> ArchivePtr -> ArchiveM ()
-archiveFile fp a = withCStringArchiveM fp $ \cpath ->
-    ignore (archiveReadSupportFormatAll a) *>
+{-# INLINE archiveAbs #-}
+archiveAbs :: (ArchivePtr -> IO ArchiveResult) -- ^ Function to set format support
+           -> FilePath
+           -> ArchivePtr
+           -> ArchiveM ()
+archiveAbs support fp a = withCStringArchiveM fp $ \cpath ->
+    ignore (support a) *>
     handle (archiveReadOpenFilename a cpath 10240)
+
+-- TODO: general function for format
+archiveFile :: FilePath -> ArchivePtr -> ArchiveM ()
+archiveFile = archiveAbs archiveReadSupportFormatAll
 
 -- | This is more efficient than
 --
diff --git a/src/Codec/Archive/Internal/Unpack/Lazy.hs b/src/Codec/Archive/Internal/Unpack/Lazy.hs
--- a/src/Codec/Archive/Internal/Unpack/Lazy.hs
+++ b/src/Codec/Archive/Internal/Unpack/Lazy.hs
@@ -2,6 +2,7 @@
                                           , readArchiveBSLAbs
                                           , unpackToDirLazy
                                           , bslToArchive
+                                          , bslToArchiveAbs
                                           ) where
 
 import           Codec.Archive.Foreign
@@ -44,16 +45,21 @@
 readArchiveBSL = readArchiveBSLAbs readBS
 
 readArchiveBSLAbs :: Integral a
-                  => (ArchivePtr -> a -> IO e)
+                  => (ArchivePtr -> a -> IO e) -- ^ Action to read contents from an archive entry
                   -> BSL.ByteString
                   -> Either ArchiveResult [Entry FilePath e]
 readArchiveBSLAbs read' = unsafeDupablePerformIO . runArchiveM . (hsEntriesAbs read' <=< bslToArchive)
 {-# NOINLINE readArchiveBSLAbs #-}
 
 -- | Lazily stream a 'BSL.ByteString'
-bslToArchive :: BSL.ByteString
-             -> ArchiveM ArchivePtr
-bslToArchive bs = do
+bslToArchive :: BSL.ByteString -> ArchiveM ArchivePtr
+bslToArchive = bslToArchiveAbs archiveReadSupportFormatAll
+
+{-# INLINE bslToArchiveAbs #-}
+bslToArchiveAbs :: (ArchivePtr -> IO ArchiveResult) -- ^ Action to set supported formats
+                -> BSL.ByteString
+                -> ArchiveM ArchivePtr
+bslToArchiveAbs support bs = do
     preA <- liftIO archiveReadNew
     bufPtr <- liftIO $ mallocBytes (32 * 1024) -- default to 32k byte chunks
     bufPtrRef <- liftIO $ newIORef bufPtr
@@ -62,7 +68,7 @@
     rc <- liftIO $ mkReadCallback (readBSL' bsChunksRef bufSzRef bufPtrRef)
     cc <- liftIO $ mkCloseCallback (\_ ptr -> freeHaskellFunPtr rc *> free ptr $> ArchiveOk)
     a <- liftIO $ castForeignPtr <$> newForeignPtr (castPtr preA) (archiveFree preA *> freeHaskellFunPtr cc *> (free =<< readIORef bufPtrRef))
-    ignore $ archiveReadSupportFormatAll a
+    ignore $ support a
     nothingPtr <- liftIO $ mallocBytes 0
     let seqErr = traverse_ handle
     seqErr [ archiveReadSetReadCallback a rc
diff --git a/src/Codec/Archive/Types.hs b/src/Codec/Archive/Types.hs
--- a/src/Codec/Archive/Types.hs
+++ b/src/Codec/Archive/Types.hs
@@ -7,12 +7,14 @@
                            , Permissions
                            , ArchiveEncryption (..)
                            , ArchiveResult (..)
+                           , ArchiveEntryDigest (..)
                            -- * Foreign types
                            , module Codec.Archive.Types.Foreign
                            -- * Callbacks
                            , ArchiveOpenCallback
                            , ArchiveCloseCallback
                            , ArchiveSwitchCallback
+                           , ArchiveFreeCallback
                            -- * Marshalling functions
                            , resultToErr
                            ) where
@@ -26,6 +28,7 @@
 type ArchiveOpenCallback a = Ptr Archive -> Ptr a -> IO ArchiveResult
 type ArchiveCloseCallback a = Ptr Archive -> Ptr a -> IO ArchiveResult
 type ArchiveSwitchCallback a b = Ptr Archive -> Ptr a -> Ptr b -> IO ArchiveResult
+type ArchiveFreeCallback a = Ptr Archive -> Ptr a -> IO ArchiveResult
 
 resultToErr :: ArchiveResult -> CInt
 resultToErr = fromIntegral . fromEnum
diff --git a/src/Codec/Archive/Types/Foreign.chs b/src/Codec/Archive/Types/Foreign.chs
--- a/src/Codec/Archive/Types/Foreign.chs
+++ b/src/Codec/Archive/Types/Foreign.chs
@@ -12,6 +12,7 @@
                                    , ArchiveOpenCallbackRaw
                                    , ArchiveSwitchCallbackRaw
                                    , ArchivePassphraseCallback
+                                   , ArchiveFreeCallbackRaw
                                    -- * Abstract types
                                    , Archive
                                    , ArchiveEntry
@@ -21,6 +22,7 @@
                                    , ArchiveResult (..)
                                    , FileType (..)
                                    , Symlink (..)
+                                   , ArchiveEntryDigest (..)
                                    -- * Macros
                                    , Flags (..)
                                    , ArchiveFilter (..)
@@ -126,6 +128,15 @@
                              } deriving (Eq)
   #}
 
+{# enum define ArchiveEntryDigest { ARCHIVE_ENTRY_DIGEST_MD5 as ArchiveEntryDigestMD5
+                                  , ARCHIVE_ENTRY_DIGEST_RMD160 as ArchiveEntryDigestRMD160
+                                  , ARCHIVE_ENTRY_DIGEST_SHA1 as ArchiveEntryDigestSHA1
+                                  , ARCHIVE_ENTRY_DIGEST_SHA256 as ArchiveEntryDigestSHA256
+                                  , ARCHIVE_ENTRY_DIGEST_SHA384 as ArchiveEntryDigestSHA384
+                                  , ARCHIVE_ENTRY_DIGEST_SHA512 as ArchiveEntryDigestSHA512
+                                  }
+  #}
+
 -- | Abstract type
 data Archive
 
@@ -144,6 +155,7 @@
 type ArchiveCloseCallbackRaw a = Ptr Archive -> Ptr a -> IO CInt
 type ArchiveSwitchCallbackRaw a b = Ptr Archive -> Ptr a -> Ptr b -> IO CInt
 type ArchivePassphraseCallback a = Ptr Archive -> Ptr a -> IO CString
+type ArchiveFreeCallbackRaw a = Ptr Archive -> Ptr a -> IO CInt
 
 newtype Flags = Flags CInt
 
diff --git a/test/Spec.cpphs b/test/Spec.cpphs
--- a/test/Spec.cpphs
+++ b/test/Spec.cpphs
@@ -66,7 +66,7 @@
 #ifndef LOW_MEMORY
             traverse_ (\fp -> repack entriesToBSLzip ("zip/" ++ fp) fp) tarPaths
             traverse_ (repack entriesToBSLCpio "cpio") tarPaths
-            traverse_ (repack entriesToBSLXar "xar") tarPaths
+            -- traverse_ (repack entriesToBSLXar "xar") tarPaths
             traverse_ (repack entriesToBSLShar "shar") tarPaths
             traverse_ (repack entriesToBSL7zip "7zip") tarPaths
             traverse_ testFpFreaky tarPaths
