diff --git a/c/archive.h b/c/archive.h
--- a/c/archive.h
+++ b/c/archive.h
@@ -34,7 +34,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3008002
+#define	ARCHIVE_VERSION_NUMBER 3008005
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -177,7 +177,7 @@
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_ONLY_STRING "3.8.2"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.8.5"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
diff --git a/c/archive_cryptor.c b/c/archive_cryptor.c
--- a/c/archive_cryptor.c
+++ b/c/archive_cryptor.c
@@ -490,9 +490,9 @@
     size_t in_len, uint8_t * const out, size_t *out_len)
 {
 	uint8_t *const ebuf = ctx->encr_buf;
-	unsigned pos = ctx->encr_pos;
-	unsigned max = (unsigned)((in_len < *out_len)? in_len: *out_len);
-	unsigned i;
+	size_t pos = ctx->encr_pos;
+	size_t max = (in_len < *out_len)? in_len: *out_len;
+	size_t i;
 
 	for (i = 0; i < max; ) {
 		if (pos == AES_BLOCK_SIZE) {
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
@@ -56,10 +56,10 @@
 typedef struct {
 	CCCryptorRef	ctx;
 	uint8_t		key[AES_MAX_KEY_SIZE];
-	unsigned	key_len;
+	size_t		key_len;
 	uint8_t		nonce[AES_BLOCK_SIZE];
 	uint8_t		encr_buf[AES_BLOCK_SIZE];
-	unsigned	encr_pos;
+	size_t		encr_pos;
 } archive_crypto_ctx;
 
 #elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
diff --git a/c/archive_disk_acl_darwin.c b/c/archive_disk_acl_darwin.c
--- a/c/archive_disk_acl_darwin.c
+++ b/c/archive_disk_acl_darwin.c
@@ -124,7 +124,6 @@
 add_trivial_nfs4_acl(struct archive_entry *entry)
 {
 	mode_t mode;
-	int i;
 	const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
 	const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
 	    ARCHIVE_ENTRY_ACL_APPEND_DATA;
@@ -195,7 +194,7 @@
 	} else if ((mode & 0010) || (mode & 0001))
 		tacl_entry[1].permset |= eperm;
 
-	for (i = 0; i < sizeof(tacl_entry) / sizeof(tacl_entry[0]); i++) {
+	for (size_t i = 0; i < sizeof(tacl_entry) / sizeof(tacl_entry[0]); i++) {
 		if (tacl_entry[i].permset != 0) {
 			archive_entry_acl_add_entry(entry,
 			    tacl_entry[i].type, tacl_entry[i].permset,
diff --git a/c/archive_entry.h b/c/archive_entry.h
--- a/c/archive_entry.h
+++ b/c/archive_entry.h
@@ -28,7 +28,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3008002
+#define	ARCHIVE_VERSION_NUMBER 3008005
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
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
@@ -254,7 +254,7 @@
 	if (S_ISLNK(st->st_mode)) {
 		size_t linkbuffer_len = st->st_size;
 		char *linkbuffer;
-		int lnklen;
+		ssize_t lnklen;
 
 		linkbuffer = malloc(linkbuffer_len + 1);
 		if (linkbuffer == NULL) {
@@ -358,12 +358,10 @@
 		return (ARCHIVE_OK);
 
 	archive_string_init(&tempfile);
-	if (__archive_get_tempdir(&tempfile) != ARCHIVE_OK) {
-		ret = ARCHIVE_WARN;
-		goto cleanup;
-	}
-	archive_strcat(&tempfile, "tar.md.XXXXXX");
-	tempfd = mkstemp(tempfile.s);
+	archive_strcpy(&tempfile, name);
+	archive_string_dirname(&tempfile);
+	archive_strcat(&tempfile, "/tar.XXXXXXXX");
+	tempfd = __archive_mkstemp(tempfile.s);
 	if (tempfd < 0) {
 		archive_set_error(&a->archive, errno,
 		    "Could not open extended attribute file");
@@ -894,7 +892,7 @@
 	for (iters = 0; ; ++iters) {
 		int i, r;
 
-		r = ioctl(*fd, FS_IOC_FIEMAP, fm); 
+		r = ioctl(*fd, FS_IOC_FIEMAP, fm);
 		if (r < 0) {
 			/* When something error happens, it is better we
 			 * should return ARCHIVE_OK because an earlier
@@ -1081,4 +1079,3 @@
 #endif
 
 #endif /* !defined(_WIN32) || defined(__CYGWIN__) */
-
diff --git a/c/archive_read_disk_posix.c b/c/archive_read_disk_posix.c
--- a/c/archive_read_disk_posix.c
+++ b/c/archive_read_disk_posix.c
@@ -107,6 +107,8 @@
 #define O_CLOEXEC	0
 #endif
 
+#define MAX_FILESYSTEM_ID 1000000
+
 #if defined(__hpux) && !defined(HAVE_DIRFD)
 #define dirfd(x) ((x)->__dd_fd)
 #define HAVE_DIRFD
@@ -1412,8 +1414,12 @@
 	 * This is the new filesystem which we have to generate a new ID for.
 	 */
 	fid = t->max_filesystem_id++;
+	if (fid > MAX_FILESYSTEM_ID) {
+		archive_set_error(&a->archive, ENOMEM, "Too many filesystems");
+		return (ARCHIVE_FATAL);
+	}
 	if (t->max_filesystem_id > t->allocated_filesystem) {
-		size_t s;
+		int s;
 		void *p;
 
 		s = t->max_filesystem_id * 2;
@@ -1693,8 +1699,6 @@
 #endif
 		t->current_filesystem->noatime = 0;
 
-	/* Set maximum filename length. */
-	t->current_filesystem->name_max = svfs.f_namemax;
 	return (ARCHIVE_OK);
 }
 
@@ -2014,11 +2018,8 @@
 	}
 #endif /* F_DUPFD_CLOEXEC */
 	new_fd = dup(fd);
-	if (new_fd != -1) {
-		__archive_ensure_cloexec_flag(new_fd);
-		return (new_fd);
-	}
-	return (-1);
+	__archive_ensure_cloexec_flag(new_fd);
+	return (new_fd);
 }
 
 /*
@@ -2140,16 +2141,11 @@
 	 * so try again for execute. The consequences of not opening this are
 	 * unhelpful and unnecessary errors later.
 	 */
-	if (t->initial_dir_fd < 0) {
+	if (t->initial_dir_fd < 0)
 		t->initial_dir_fd = open(".", o_flag | O_CLOEXEC);
-		if (t->initial_dir_fd < 0)
-			return NULL;
-	}
 #endif
 	__archive_ensure_cloexec_flag(t->initial_dir_fd);
 	t->working_dir_fd = tree_dup(t->initial_dir_fd);
-	if (t->working_dir_fd < 0)
-		return NULL;
 	return (t);
 }
 
@@ -2355,15 +2351,20 @@
 tree_dir_next_posix(struct tree *t)
 {
 	int r;
+#if defined(HAVE_FDOPENDIR)
+	int fd;
+#endif
 	const char *name;
 	size_t namelen;
 
 	if (t->d == NULL) {
 
 #if defined(HAVE_FDOPENDIR)
-		int fd = tree_dup(t->working_dir_fd);
-		if (fd != -1)
-			t->d = fdopendir(fd);
+		if (t->working_dir_fd >= 0) {
+			fd = tree_dup(t->working_dir_fd);
+			if (fd != -1)
+				t->d = fdopendir(fd);
+		}
 #else /* HAVE_FDOPENDIR */
 		if (tree_enter_working_dir(t) == 0) {
 			t->d = opendir(".");
diff --git a/c/archive_read_disk_windows.c b/c/archive_read_disk_windows.c
--- a/c/archive_read_disk_windows.c
+++ b/c/archive_read_disk_windows.c
@@ -53,6 +53,8 @@
 /* To deal with absolute symlink issues */
 #define START_ABSOLUTE_SYMLINK_REPARSE L"\\??\\"
 
+#define MAX_FILESYSTEM_ID 1000000
+
 /*-
  * This is a new directory-walking system that addresses a number
  * of problems I've had with fts(3).  In particular, it has no
@@ -1449,8 +1451,12 @@
 	 * There is a new filesystem, we generate a new ID for.
 	 */
 	fid = t->max_filesystem_id++;
+	if (fid > MAX_FILESYSTEM_ID) {
+		archive_set_error(&a->archive, ENOMEM, "Too many filesystems");
+		return (ARCHIVE_FATAL);
+	}
 	if (t->max_filesystem_id > t->allocated_filesystem) {
-		size_t s;
+		int s;
 		void *p;
 
 		s = t->max_filesystem_id * 2;
@@ -1462,7 +1468,7 @@
 			return (ARCHIVE_FATAL);
 		}
 		t->filesystem_table = (struct filesystem *)p;
-		t->allocated_filesystem = (int)s;
+		t->allocated_filesystem = s;
 	}
 	t->current_filesystem_id = fid;
 	t->current_filesystem = &(t->filesystem_table[fid]);
diff --git a/c/archive_read_support_filter_lz4.c b/c/archive_read_support_filter_lz4.c
--- a/c/archive_read_support_filter_lz4.c
+++ b/c/archive_read_support_filter_lz4.c
@@ -49,9 +49,12 @@
 #include "archive_xxhash.h"
 
 #define LZ4_MAGICNUMBER		0x184d2204
-#define LZ4_SKIPPABLED		0x184d2a50
 #define LZ4_LEGACY		0x184c2102
 
+// Note: LZ4 and zstd share the same skippable frame format with the same magic numbers.
+#define LZ4_SKIPPABLE_START 0x184D2A50
+#define LZ4_SKIPPABLE_MASK 0xFFFFFFF0
+
 #if defined(HAVE_LIBLZ4)
 struct private_data {
 	enum {  SELECT_STREAM,
@@ -141,19 +144,67 @@
 {
 	const unsigned char *buffer;
 	ssize_t avail;
-	int bits_checked;
-	uint32_t number;
+	int bits_checked = 0;
+	ssize_t min_lz4_archive_size = 11;
 
-	(void)self; /* UNUSED */
+	// LZ4 skippable frames contain a 4 byte magic number followed by
+	// a 4 byte frame data size, then that number of bytes of data. Regular
+	// frames contain a 4 byte magic number followed by a 2-14 byte frame
+	// header, some data, and a 3 byte end marker.
+	ssize_t min_lz4_frame_size = 8;
 
-	/* Minimal lz4 archive is 11 bytes. */
-	buffer = __archive_read_filter_ahead(filter, 11, &avail);
+	ssize_t offset_in_buffer = 0;
+	ssize_t max_lookahead = 64 * 1024;
+
+	(void)self; // UNUSED
+
+	// Zstd and LZ4 skippable frame magic numbers are identical. To
+	// differentiate these two, we need to look for a non-skippable
+	// frame.
+
+	// Minimal lz4 archive is 11 bytes.
+	buffer = __archive_read_filter_ahead(filter, min_lz4_archive_size, &avail);
 	if (buffer == NULL)
 		return (0);
 
-	/* First four bytes must be LZ4 magic numbers. */
-	bits_checked = 0;
-	if ((number = archive_le32dec(buffer)) == LZ4_MAGICNUMBER) {
+	uint32_t magic_number = archive_le32dec(buffer);
+
+	while ((magic_number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
+
+		offset_in_buffer += 4; // Skip over the magic number
+
+		// Ensure that we can read another 4 bytes.
+		if (offset_in_buffer + 4 > avail) {
+			buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
+			if (buffer == NULL)
+				return (0);
+		}
+
+		uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
+
+		// Skip over the 4 frame data size bytes, plus the value stored there.
+		offset_in_buffer += 4 + frame_data_size;
+
+		// There should be at least one more frame if this is LZ4 data.
+		if (offset_in_buffer + min_lz4_frame_size > avail) { // TODO: should this be >= ?
+			if (offset_in_buffer + min_lz4_frame_size > max_lookahead)
+				return (0); 
+
+			buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_lz4_frame_size, &avail);
+			if (buffer == NULL)
+				return (0); 
+		}
+
+		magic_number = archive_le32dec(buffer + offset_in_buffer);
+	}
+
+	// We have skipped over any skippable frames. Either a regular LZ4 frame
+	// follows, or this isn't LZ4 data.
+
+	bits_checked = offset_in_buffer;
+	buffer = buffer + offset_in_buffer;
+
+	if (magic_number == LZ4_MAGICNUMBER) {
 		unsigned char flag, BD;
 
 		bits_checked += 32;
@@ -175,11 +226,16 @@
 		if (BD & ~0x70)
 			return (0);
 		bits_checked += 8;
-	} else if (number == LZ4_LEGACY) {
+
+		return (bits_checked);
+	}
+
+	if (magic_number == LZ4_LEGACY) {
 		bits_checked += 32;
+		return (bits_checked);
 	}
-	
-	return (bits_checked);
+
+	return (0);
 }
 
 #if !defined(HAVE_LIBLZ4)
@@ -342,7 +398,7 @@
 			return lz4_filter_read_default_stream(self, p);
 		else if (number == LZ4_LEGACY)
 			return lz4_filter_read_legacy_stream(self, p);
-		else if ((number & ~0xF) == LZ4_SKIPPABLED) {
+		else if ((number & LZ4_SKIPPABLE_MASK) == LZ4_SKIPPABLE_START) {
 			read_buf = __archive_read_filter_ahead(
 				self->upstream, 4, NULL);
 			if (read_buf == NULL) {
diff --git a/c/archive_read_support_filter_uu.c b/c/archive_read_support_filter_uu.c
--- a/c/archive_read_support_filter_uu.c
+++ b/c/archive_read_support_filter_uu.c
@@ -232,8 +232,8 @@
 		size_t nbytes_req = (*ravail+1023) & ~1023U;
 		ssize_t tested;
 
-		/* Increase reading bytes if it is not enough to at least
-		 * new two lines. */
+		/* Increase reading bytes if it is not enough for at least
+		 * two new lines. */
 		if (nbytes_req < (size_t)*ravail + 160)
 			nbytes_req <<= 1;
 
@@ -411,7 +411,7 @@
 
 		/*
 		 * Calculate a new buffer size for in_buff.
-		 * Increase its value until it has enough size we need.
+		 * Increase its value until it is enough for our needs.
 		 */
 		newsize = uudecode->in_allocated;
 		do {
@@ -494,7 +494,7 @@
 		}
 		/*
 		 * If there is remaining data which is saved by
-		 * previous calling, use it first.
+		 * a previous call, use it first.
 		 */
 		if (ensure_in_buff_size(self, uudecode,
 		    avail_in + uudecode->in_cnt) != ARCHIVE_OK)
diff --git a/c/archive_read_support_filter_zstd.c b/c/archive_read_support_filter_zstd.c
--- a/c/archive_read_support_filter_zstd.c
+++ b/c/archive_read_support_filter_zstd.c
@@ -110,24 +110,67 @@
 {
 	const unsigned char *buffer;
 	ssize_t avail;
-	unsigned prefix;
 
-	/* Zstd frame magic values */
-	unsigned zstd_magic = 0xFD2FB528U;
-	unsigned zstd_magic_skippable_start = 0x184D2A50U;
-	unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
+	// Zstandard skippable frames contain a 4 byte magic number followed by
+	// a 4 byte frame data size, then that number of bytes of data. Regular
+	// frames contain a 4 byte magic number followed by a 2-14 byte frame
+	// header, some data, and a 3 byte end marker.
+	ssize_t min_zstd_frame_size = 8;
 
-	(void) self; /* UNUSED */
+	ssize_t offset_in_buffer = 0;
+	ssize_t max_lookahead = 64 * 1024;
 
-	buffer = __archive_read_filter_ahead(filter, 4, &avail);
+	// Zstd regular frame magic number.
+	uint32_t zstd_magic = 0xFD2FB528U;
+
+	// Note: Zstd and LZ4 skippable frame magic numbers are identical.
+	// To differentiate these two, we need to look for a non-skippable
+	// frame.
+	uint32_t zstd_magic_skippable_start = 0x184D2A50;
+	uint32_t zstd_magic_skippable_mask  = 0xFFFFFFF0;
+
+	(void) self; // UNUSED
+
+	buffer = __archive_read_filter_ahead(filter, min_zstd_frame_size, &avail);
 	if (buffer == NULL)
 		return (0);
 
-	prefix = archive_le32dec(buffer);
-	if (prefix == zstd_magic)
-		return (32);
-	if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start)
-		return (32);
+	uint32_t magic_number = archive_le32dec(buffer);
+
+	while ((magic_number & zstd_magic_skippable_mask) == zstd_magic_skippable_start) {
+
+		offset_in_buffer += 4; // Skip over the magic number
+
+		// Ensure that we can read another 4 bytes.
+		if (offset_in_buffer + 4 > avail) {
+			buffer = __archive_read_filter_ahead(filter, offset_in_buffer + 4, &avail);
+			if (buffer == NULL)
+				return (0);
+		}
+
+		uint32_t frame_data_size = archive_le32dec(buffer + offset_in_buffer);
+
+		// Skip over the 4 frame data size bytes, plus the value stored there.
+		offset_in_buffer += 4 + frame_data_size;
+
+		// There should be at least one more frame if this is zstd data.
+		if (offset_in_buffer + min_zstd_frame_size > avail) {
+			if (offset_in_buffer + min_zstd_frame_size > max_lookahead)
+				return (0);
+
+			buffer = __archive_read_filter_ahead(filter, offset_in_buffer + min_zstd_frame_size, &avail);
+			if (buffer == NULL)
+				return (0);
+		}
+
+		magic_number = archive_le32dec(buffer + offset_in_buffer);
+	}
+
+	// We have skipped over any skippable frames. Either a regular zstd frame
+	// follows, or this isn't zstd data.
+
+	if (magic_number == zstd_magic)
+		return (offset_in_buffer + 4);
 
 	return (0);
 }
diff --git a/c/archive_read_support_format_7zip.c b/c/archive_read_support_format_7zip.c
--- a/c/archive_read_support_format_7zip.c
+++ b/c/archive_read_support_format_7zip.c
@@ -744,6 +744,7 @@
 	const char *h;
 	char big_endian, format_64;
 	ssize_t bytes, min_addr = SFX_MIN_ADDR;
+	ssize_t request;
 	uint64_t e_shoff, strtab_offset, strtab_size;
 	uint16_t e_shentsize, e_shnum, e_shstrndx;
 	uint16_t (*dec16)(const void *);
@@ -796,7 +797,12 @@
 		if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
 			break;
 		}
-		h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
+		if (format_64) {
+		  request = (size_t)e_shnum * (size_t)e_shentsize + 0x28;
+		} else {
+		  request = (size_t)e_shnum * (size_t)e_shentsize + 0x18;
+		}
+		h = __archive_read_ahead(a, request, &bytes);
 		if (h == NULL) {
 			break;
 		}
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
@@ -2813,7 +2813,7 @@
 					      lzx_br_bits(&bre, mt_max_bits));
 					lzx_br_consume(&bre, mt_bitlen[c]);
 				}
-				if (c > UCHAR_MAX)
+				if ((unsigned int)c > UCHAR_MAX)
 					break;
 				/*
 				 * 'c' is exactly literal code.
diff --git a/c/archive_read_support_format_cpio.c b/c/archive_read_support_format_cpio.c
--- a/c/archive_read_support_format_cpio.c
+++ b/c/archive_read_support_format_cpio.c
@@ -825,9 +825,9 @@
 }
 
 /*
- * NOTE: if a filename suffix is ".z", it is the file gziped by afio.
- * it would be nice that we can show uncompressed file size and we can
- * uncompressed file contents automatically, unfortunately we have nothing
+ * NOTE: if a filename suffix is ".z", it is a file gzipped by afio.
+ * it would be nice if we could show uncompressed file size and
+ * uncompress file contents automatically, unfortunately we have nothing
  * to get a uncompressed file size while reading each header. It means
  * we also cannot uncompress file contents under our framework.
  */
diff --git a/c/archive_read_support_format_lha.c b/c/archive_read_support_format_lha.c
--- a/c/archive_read_support_format_lha.c
+++ b/c/archive_read_support_format_lha.c
@@ -689,7 +689,7 @@
 	 * a pathname and a symlink has '\' character, a directory
 	 * separator in DOS/Windows. So we should convert it to '/'.
 	 */
-	if (p[H_LEVEL_OFFSET] == 0)
+	if (lha->level == 0)
 		lha_replace_path_separator(lha, entry);
 
 	archive_entry_set_mode(entry, lha->mode);
@@ -2374,7 +2374,7 @@
 					lzh_br_consume(&bre, lt_bitlen[c]);
 				}
 				blocks_avail--;
-				if (c > UCHAR_MAX)
+				if ((unsigned int)c > UCHAR_MAX)
 					/* Current block is a match data. */
 					break;
 				/*
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
@@ -392,8 +392,8 @@
 		if (len >= MAX_LINE_LEN)
 			return (-1);
 
-		/* Increase reading bytes if it is not enough to at least
-		 * new two lines. */
+		/* Increase reading bytes if it is not enough for at least
+		 * two new lines. */
 		if (nbytes_req < (size_t)*ravail + 160)
 			nbytes_req <<= 1;
 
@@ -568,8 +568,8 @@
 				--len;
 				value = 1;
 			}
-			/* A keyword should have a its value unless
-			 * "/unset" operation. */ 
+			/* A keyword should have a value unless this is
+			 * an "/unset" operation. */ 
 			if (!unset && value == 0)
 				return (-1);
 		}
@@ -752,7 +752,7 @@
 				} else if (form_D == 1) {
 					if (!last_is_path && keywords > 0)
 						/* This this is not `form D'
-						 * and We cannot accept mixed
+						 * and we cannot accept mixed
 						 * format. */
 						break;
 				}
@@ -805,7 +805,7 @@
  * to read the entire mtree file into memory up front.
  *
  * The parsing is done in two steps.  First, it is decided if a line
- * changes the global defaults and if it is, processed accordingly.
+ * changes the global defaults and if it does, it is processed accordingly.
  * Otherwise, the options of the line are merged with the current
  * global options.
  */
@@ -1254,7 +1254,7 @@
 				archive_entry_filetype(entry) == AE_IFDIR) {
 			mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
 			__archive_ensure_cloexec_flag(mtree->fd);
-			if (mtree->fd < 0 && (
+			if (mtree->fd == -1 && (
 #if defined(_WIN32) && !defined(__CYGWIN__)
         /*
          * On Windows, attempting to open a file with an
diff --git a/c/archive_read_support_format_tar.c b/c/archive_read_support_format_tar.c
--- a/c/archive_read_support_format_tar.c
+++ b/c/archive_read_support_format_tar.c
@@ -2311,6 +2311,7 @@
 	archive_string_init(&as);
 	r = read_bytes_to_string(a, &as, value_length, &unconsumed);
 	if (tar_flush_unconsumed(a, &unconsumed) != ARCHIVE_OK) {
+		*result = 0;
 		return (ARCHIVE_FATAL);
 	}
 	if (r < ARCHIVE_OK) {
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
@@ -78,6 +78,12 @@
 #include "archive_crc32.h"
 #endif
 
+/* length of local file header, not including filename and extra */
+#define ZIP_LOCHDR_LEN		30U
+
+/* maximum length of Mac metadata in MiB */
+#define ZIP_MAX_METADATA	10U
+
 struct zip_entry {
 	struct archive_rb_node	node;
 	struct zip_entry	*next;
@@ -933,7 +939,7 @@
 		zip->init_default_conversion = 1;
 	}
 
-	if ((p = __archive_read_ahead(a, 30, NULL)) == NULL) {
+	if ((p = __archive_read_ahead(a, ZIP_LOCHDR_LEN, NULL)) == NULL) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Truncated ZIP file header");
 		return (ARCHIVE_FATAL);
@@ -969,7 +975,7 @@
 	filename_length = archive_le16dec(p + 26);
 	extra_length = archive_le16dec(p + 28);
 
-	__archive_read_consume(a, 30);
+	__archive_read_consume(a, ZIP_LOCHDR_LEN);
 
 	/* Read the filename. */
 	if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {
@@ -3637,7 +3643,7 @@
 {
 	uint16_t disk_num;
 	uint32_t cd_size, cd_offset;
-	
+
 	disk_num = archive_le16dec(p + 4);
 	cd_size = archive_le32dec(p + 12);
 	cd_offset = archive_le32dec(p + 16);
@@ -4097,7 +4103,7 @@
 	const char *p;
 	ssize_t filename_length, extra_length;
 
-	if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
+	if ((p = __archive_read_ahead(a, extra + ZIP_LOCHDR_LEN, NULL)) == NULL) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
 		    "Truncated ZIP file header");
 		return (ARCHIVE_WARN);
@@ -4111,7 +4117,7 @@
 	filename_length = archive_le16dec(p + 26);
 	extra_length = archive_le16dec(p + 28);
 
-	return (30 + filename_length + extra_length);
+	return (ZIP_LOCHDR_LEN + filename_length + extra_length);
 }
 
 static int
@@ -4148,16 +4154,16 @@
 		return (ARCHIVE_WARN);
 	}
 
-	if (rsrc->uncompressed_size > (4 * 1024 * 1024)) {
+	if (rsrc->uncompressed_size > ZIP_MAX_METADATA * 1048576U) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Mac metadata is too large: %jd > 4M bytes",
-		    (intmax_t)rsrc->uncompressed_size);
+		    "Mac metadata is too large: %jd > %u MiB",
+		    (intmax_t)rsrc->uncompressed_size, ZIP_MAX_METADATA);
 		return (ARCHIVE_WARN);
 	}
-	if (rsrc->compressed_size > (4 * 1024 * 1024)) {
+	if (rsrc->compressed_size > ZIP_MAX_METADATA * 1048576U) {
 		archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-		    "Mac metadata is too large: %jd > 4M bytes",
-		    (intmax_t)rsrc->compressed_size);
+		    "Mac metadata is too large: %jd > %u MiB",
+		    (intmax_t)rsrc->compressed_size, ZIP_MAX_METADATA);
 		return (ARCHIVE_WARN);
 	}
 
diff --git a/c/archive_string.c b/c/archive_string.c
--- a/c/archive_string.c
+++ b/c/archive_string.c
@@ -2054,6 +2054,26 @@
 	return (r);
 }
 
+struct archive_string *
+archive_string_dirname(struct archive_string *as)
+{
+	/* strip trailing separators */
+	while (as->length > 1 && as->s[as->length - 1] == '/')
+		as->length--;
+	/* strip final component */
+	while (as->length > 0 && as->s[as->length - 1] != '/')
+		as->length--;
+	/* empty path -> cwd */
+	if (as->length == 0)
+		return (archive_strcat(as, "."));
+	/* strip separator(s) */
+	while (as->length > 1 && as->s[as->length - 1] == '/')
+		as->length--;
+	/* terminate */
+	as->s[as->length] = '\0';
+	return (as);
+}
+
 #if HAVE_ICONV
 
 /*
@@ -3553,7 +3573,7 @@
 
 	if (sc->to_cp == CP_C_LOCALE) {
 		/*
-		 * "C" locale special process.
+		 * "C" locale special processing.
 		 */
 		u16 = _p;
 		ll = 0;
@@ -3670,7 +3690,7 @@
 	avail = as16->buffer_length - 2;
 	if (sc->from_cp == CP_C_LOCALE) {
 		/*
-		 * "C" locale special process.
+		 * "C" locale special processing.
 		 */
 		count = 0;
 		while (count < length && *s) {
diff --git a/c/archive_string.h b/c/archive_string.h
--- a/c/archive_string.h
+++ b/c/archive_string.h
@@ -192,6 +192,10 @@
 void	archive_string_sprintf(struct archive_string *, const char *, ...)
 	    __LA_PRINTF(2, 3);
 
+/* Equivalent to dirname(3) */
+struct archive_string *
+archive_string_dirname(struct archive_string *);
+
 /* Translates from MBS to Unicode. */
 /* Returns non-zero if conversion failed in any way. */
 int archive_wstring_append_from_mbs(struct archive_wstring *dest,
diff --git a/c/archive_util.c b/c/archive_util.c
--- a/c/archive_util.c
+++ b/c/archive_util.c
@@ -456,7 +456,7 @@
 		return (-1);
 	if (ruid != euid || ruid != suid)
 		return (1);
-	if (getresgid(&ruid, &egid, &sgid) != 0)
+	if (getresgid(&rgid, &egid, &sgid) != 0)
 		return (-1);
 	if (rgid != egid || rgid != sgid)
 		return (1);
diff --git a/c/archive_version_details.c b/c/archive_version_details.c
--- a/c/archive_version_details.c
+++ b/c/archive_version_details.c
@@ -333,7 +333,7 @@
 const char *
 archive_libxml2_version(void)
 {
-#if HAVE_LIBXML_XMLREADER_H && HAVE_LIBXML2
+#if HAVE_LIBXML_XMLVERSION_H && HAVE_LIBXML2
 	return LIBXML_DOTTED_VERSION;
 #else
 	return NULL;
diff --git a/c/archive_windows.c b/c/archive_windows.c
--- a/c/archive_windows.c
+++ b/c/archive_windows.c
@@ -253,7 +253,7 @@
 	createExParams.dwSize = sizeof(createExParams);
 	createExParams.dwFileAttributes = dwFlagsAndAttributes & 0xFFFF;
 	createExParams.dwFileFlags = dwFlagsAndAttributes & 0xFFF00000;
-	createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F00000;
+	createExParams.dwSecurityQosFlags = dwFlagsAndAttributes & 0x000F0000;
 	createExParams.lpSecurityAttributes = lpSecurityAttributes;
 	createExParams.hTemplateFile = hTemplateFile;
 	handle = CreateFile2(wpath, dwDesiredAccess, dwShareMode,
@@ -747,7 +747,8 @@
 	int ret;
 
 	ret = __hstat((HANDLE)_get_osfhandle(fd), &u);
-	copy_seek_stat(st, &u);
+	if (ret >= 0)
+		copy_seek_stat(st, &u);
 	return (ret);
 }
 
diff --git a/c/archive_write.c b/c/archive_write.c
--- a/c/archive_write.c
+++ b/c/archive_write.c
@@ -821,7 +821,7 @@
 {
 	struct archive_write *a = (struct archive_write *)_a;
 	const size_t max_write = INT_MAX;
-	int ret;
+	ssize_t ret;
 
 	archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
 	    ARCHIVE_STATE_DATA, "archive_write_data");
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
@@ -412,12 +412,14 @@
 static int
 la_mktemp(struct archive_write_disk *a)
 {
+	struct archive_string *tmp = &a->_tmpname_data;
 	int oerrno, fd;
 	mode_t mode;
 
-	archive_string_empty(&a->_tmpname_data);
-	archive_string_sprintf(&a->_tmpname_data, "%s.XXXXXX", a->name);
-	a->tmpname = a->_tmpname_data.s;
+	archive_strcpy(tmp, a->name);
+	archive_string_dirname(tmp);
+	archive_strcat(tmp, "/tar.XXXXXXXX");
+	a->tmpname = tmp->s;
 
 	fd = __archive_mkstemp(a->tmpname);
 	if (fd == -1)
@@ -2559,9 +2561,9 @@
 			 * for directories. For other file types
 			 * we need to verify via fstat() or lstat()
 			 */
-			if (fd < 0 || p->filetype != AE_IFDIR) {
+			if (fd == -1 || p->filetype != AE_IFDIR) {
 #if HAVE_FSTAT
-				if (fd >= 0 && (
+				if (fd > 0 && (
 				    fstat(fd, &st) != 0 ||
 				    la_verify_filetype(st.st_mode,
 				    p->filetype) == 0)) {
@@ -4287,8 +4289,10 @@
 	int tmpfd;
 
 	archive_string_init(&tmpdatafork);
-	archive_strcpy(&tmpdatafork, "tar.md.XXXXXX");
-	tmpfd = mkstemp(tmpdatafork.s);
+	archive_strcpy(&tmpdatafork, pathname);
+	archive_string_dirname(&tmpdatafork);
+	archive_strcat(&tmpdatafork, "/tar.XXXXXXXX");
+	tmpfd = __archive_mkstemp(tmpdatafork.s);
 	if (tmpfd < 0) {
 		archive_set_error(&a->archive, errno,
 		    "Failed to mkstemp");
@@ -4367,8 +4371,10 @@
 	 * silly dance of writing the data to disk just so that
 	 * copyfile() can read it back in again. */
 	archive_string_init(&tmp);
-	archive_strcpy(&tmp, "tar.mmd.XXXXXX");
-	fd = mkstemp(tmp.s);
+	archive_strcpy(&tmp, pathname);
+	archive_string_dirname(&tmp);
+	archive_strcat(&tmp, "/tar.XXXXXXXX");
+	fd = __archive_mkstemp(tmp.s);
 
 	if (fd < 0) {
 		archive_set_error(&a->archive, errno,
@@ -4441,7 +4447,7 @@
 	 */
 	fd = open(pathname, O_RDONLY | O_BINARY | O_CLOEXEC);
 	__archive_ensure_cloexec_flag(fd);
-	if (fd < 0) {
+	if (fd == -1) {
 		archive_set_error(&a->archive, errno,
 		    "Failed to open a restoring file");
 		ret = ARCHIVE_WARN;
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
@@ -135,11 +135,7 @@
 static int
 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);
+	free(client_data);
 	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
@@ -96,11 +96,7 @@
 static int
 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);
+	free(client_data);
 	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
@@ -191,6 +191,8 @@
 			archive_set_error(a, errno, "Couldn't stat '%s'", mbs);
 		else
 			archive_set_error(a, errno, "Couldn't stat '%ls'", wcs);
+		close(mine->fd);
+		mine->fd = -1;
 		return (ARCHIVE_FATAL);
 	}
 
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
@@ -104,11 +104,7 @@
 static int
 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);
+	free(client_data);
 	return (ARCHIVE_OK);
 }
diff --git a/c/archive_write_set_format_shar.c b/c/archive_write_set_format_shar.c
--- a/c/archive_write_set_format_shar.c
+++ b/c/archive_write_set_format_shar.c
@@ -144,7 +144,9 @@
 	struct archive_write *a = (struct archive_write *)_a;
 	struct shar *shar;
 
-	archive_write_set_format_shar(&a->archive);
+	int ret = archive_write_set_format_shar(&a->archive);
+	if (ret != ARCHIVE_OK)
+		return ret;
 	shar = (struct shar *)a->format_data;
 	shar->dump = 1;
 	a->format_write_data = archive_write_shar_data_uuencode;
@@ -240,6 +242,7 @@
 				shar_quote(&shar->work, p, 1);
 				archive_strcat(&shar->work,
 				    " > /dev/null 2>&1\n");
+				free(shar->last_dir);
 				shar->last_dir = p;
 			}
 		} else {
diff --git a/c/archive_write_set_format_ustar.c b/c/archive_write_set_format_ustar.c
--- a/c/archive_write_set_format_ustar.c
+++ b/c/archive_write_set_format_ustar.c
@@ -539,7 +539,7 @@
 		ret = ARCHIVE_WARN;
 	}
 	if (copy_length > 0) {
-		if (strlen(p) > USTAR_gname_size) {
+		if (copy_length > USTAR_gname_size) {
 			if (tartype != 'x') {
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_MISC, "Group name too long");
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
@@ -1000,13 +1000,13 @@
 	const char *encname;
 	int r;
 
-	r = xmlwrite_fstring(a, writer, "length", "%ju", heap->length);
+	r = xmlwrite_fstring(a, writer, "length", "%ju", (uintmax_t)heap->length);
 	if (r < 0)
 		return (ARCHIVE_FATAL);
-	r = xmlwrite_fstring(a, writer, "offset", "%ju", heap->temp_offset);
+	r = xmlwrite_fstring(a, writer, "offset", "%ju", (uintmax_t)heap->temp_offset);
 	if (r < 0)
 		return (ARCHIVE_FATAL);
-	r = xmlwrite_fstring(a, writer, "size", "%ju", heap->size);
+	r = xmlwrite_fstring(a, writer, "size", "%ju", (uintmax_t)heap->size);
 	if (r < 0)
 		return (ARCHIVE_FATAL);
 	switch (heap->compression) {
@@ -1356,7 +1356,7 @@
 	 * Make a inode entry, "<inode>".
 	 */
 	r = xmlwrite_fstring(a, writer, "inode",
-	    "%jd", archive_entry_ino64(file->entry));
+	    "%jd", (intmax_t)archive_entry_ino64(file->entry));
 	if (r < 0)
 		return (ARCHIVE_FATAL);
 	if (archive_entry_dev(file->entry) != 0) {
@@ -1378,7 +1378,7 @@
 	 * Make a user entry, "<uid>" and "<user>.
 	 */
 	r = xmlwrite_fstring(a, writer, "uid",
-	    "%d", archive_entry_uid(file->entry));
+	    "%jd", (intmax_t)archive_entry_uid(file->entry));
 	if (r < 0)
 		return (ARCHIVE_FATAL);
 	r = archive_entry_uname_l(file->entry, &p, &len, xar->sconv);
@@ -1404,7 +1404,7 @@
 	 * Make a group entry, "<gid>" and "<group>.
 	 */
 	r = xmlwrite_fstring(a, writer, "gid",
-	    "%d", archive_entry_gid(file->entry));
+	    "%jd", (intmax_t)archive_entry_gid(file->entry));
 	if (r < 0)
 		return (ARCHIVE_FATAL);
 	r = archive_entry_gname_l(file->entry, &p, &len, xar->sconv);
diff --git a/libarchive-clib.cabal b/libarchive-clib.cabal
--- a/libarchive-clib.cabal
+++ b/libarchive-clib.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.0
 name:               libarchive-clib
-version:            3.8.2
+version:            3.8.5
 license:            OtherLicense
 license-file:       LICENSE
 copyright:          Copyright: (c) 2018-2020 Vanessa McHale
