From 87a07d9d6c9aca33aa7189ddf8dc13fd4ed795e9 Mon Sep 17 00:00:00 2001
From: Martin Matuska <mm@FreeBSD.org>
Date: Wed, 3 May 2017 23:55:12 +0000
Subject: [PATCH] Update vendor/libarchive to git
 c253f0aae9ac86a617b4f814137e07757df72391

Vendor changes (FreeBSD-related):
  PR 897: test for ZIP archives with invalid EOCD headers
  PR 901: fix invalid renaming of sparse files
  OSS-Fuzz issue 497: remove fallback tree in LZX decoder
  OSS-Fuzz issue 527: rewrite expressions in lz4 filter
  OSS-Fuzz issue 577: fix integer overflow in cpio reader
  OSS-Fuzz issue 862: fix numerc parsing in mtree reader
  OSS-Fuzz issue 1097: fix undefined shift in rar reader
  cpio: various optimizations and memory leak fixes
---
 CMakeLists.txt                                |   5 +-
 Makefile.am                                   |   1 +
 configure.ac                                  |   9 +-
 cpio/cpio.c                                   |  13 +-
 cpio/test/test_option_Z_upper.c               |   5 +-
 cpio/test/test_option_a.c                     |   3 +-
 cpio/test/test_option_b64encode.c             |   2 +
 cpio/test/test_option_grzip.c                 |   3 +-
 cpio/test/test_option_lrzip.c                 |   3 +-
 cpio/test/test_option_lz4.c                   |   7 +
 cpio/test/test_option_lzma.c                  |   4 +
 cpio/test/test_option_lzop.c                  |   3 +-
 cpio/test/test_option_uuencode.c              |   2 +
 cpio/test/test_option_xz.c                    |   4 +
 cpio/test/test_option_y.c                     |   6 +-
 cpio/test/test_option_z.c                     |   3 +-
 libarchive/archive_entry_sparse.c             |   4 +-
 libarchive/archive_getdate.c                  |   2 +-
 libarchive/archive_openssl_hmac_private.h     |   2 +-
 libarchive/archive_read.c                     |   3 +-
 .../archive_read_disk_entry_from_file.c       |   9 +-
 libarchive/archive_read_support_filter_lz4.c  |   6 +-
 libarchive/archive_read_support_format_cab.c  | 154 ++---------------
 libarchive/archive_read_support_format_cpio.c |   2 +-
 .../archive_read_support_format_iso9660.c     |   5 +-
 .../archive_read_support_format_mtree.c       | 161 ++++++------------
 libarchive/archive_read_support_format_rar.c  |   2 +-
 libarchive/archive_string.c                   |   3 +-
 libarchive/archive_write_set_format_pax.c     |  17 +-
 libarchive/libarchive_changes.3               |   1 +
 libarchive/test/CMakeLists.txt                |   1 +
 libarchive/test/test_read_format_mtree.c      |   2 +-
 ...format_zip_with_invalid_traditional_eocd.c |  60 +++++++
 ...t_zip_with_invalid_traditional_eocd.zip.uu |  14 ++
 libarchive/test/test_write_format_pax.c       |  14 +-
 .../test_write_format_zip_compression_store.c |  15 +-
 libarchive/test/test_write_format_zip_large.c |  14 +-
 libarchive/xxhash.c                           |  12 +-
 test_utils/test_main.c                        |   2 +
 39 files changed, 266 insertions(+), 312 deletions(-)
 create mode 100644 libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c
 create mode 100644 libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.zip.uu

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 49537ce2c8e5..4c818b083069 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1203,7 +1203,6 @@ CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
 CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
 CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
-CHECK_FUNCTION_EXISTS_GLIBC(dirfd HAVE_DIRFD)
 CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
 CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
@@ -1303,6 +1302,10 @@ CHECK_C_SOURCE_COMPILES(
   "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
   HAVE_READDIR_R)
 
+# dirfd can be either a function or a macro.
+CHECK_C_SOURCE_COMPILES(
+  "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); return dirfd(d);}"
+  HAVE_DIRFD)
 
 # Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 # NOTE: linux requires fcntl.h for AT_FDCWD.
diff --git a/Makefile.am b/Makefile.am
index cc6f6befbed7..2469b4ed769a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -515,6 +515,7 @@ libarchive_test_SOURCES= \
 	libarchive/test/test_read_format_zip_winzip_aes.c \
 	libarchive/test/test_read_format_zip_winzip_aes_large.c \
 	libarchive/test/test_read_format_zip_zip64.c \
+	libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c \
 	libarchive/test/test_read_large.c \
 	libarchive/test/test_read_pax_schily_xattr.c \
 	libarchive/test/test_read_pax_truncated.c \
diff --git a/configure.ac b/configure.ac
index 2545299ec6f0..1730f451374d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -605,7 +605,7 @@ AC_FUNC_VPRINTF
 # To avoid necessity for including windows.h or special forward declaration
 # workarounds, we use 'void *' for 'struct SECURITY_ATTRIBUTES *'
 AC_CHECK_STDCALL_FUNC([CreateHardLinkA],[const char *, const char *, void *])
-AC_CHECK_FUNCS([arc4random_buf chflags chown chroot ctime_r dirfd])
+AC_CHECK_FUNCS([arc4random_buf chflags chown chroot ctime_r])
 AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fdopendir fork])
 AC_CHECK_FUNCS([fstat fstatat fstatfs fstatvfs ftruncate])
 AC_CHECK_FUNCS([futimens futimes futimesat])
@@ -648,6 +648,13 @@ AC_COMPILE_IFELSE(
 		    return(readdir_r(dir, &e, &r));]])],
  [AC_DEFINE(HAVE_READDIR_R,1,[Define to 1 if you have a POSIX compatible readdir_r])]
 )
+# dirfd can be either a function or a macro.
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[#include <dirent.h>
+                    DIR *dir;]],
+                  [[return(dirfd(dir));]])],
+ [AC_DEFINE(HAVE_DIRFD,1,[Define to 1 if you have a dirfd function or macro])]
+)
 
 # FreeBSD's nl_langinfo supports an option to specify whether the
 # current locale uses month/day or day/month ordering.  It makes the
diff --git a/cpio/cpio.c b/cpio/cpio.c
index 1691c756599e..5beedd0d16bc 100644
--- a/cpio/cpio.c
+++ b/cpio/cpio.c
@@ -628,6 +628,7 @@ mode_out(struct cpio *cpio)
 		    blocks == 1 ? "block" : "blocks");
 	}
 	archive_write_free(cpio->archive);
+	archive_entry_linkresolver_free(cpio->linkresolver);
 }
 
 static const char *
@@ -1194,12 +1195,15 @@ mode_pass(struct cpio *cpio, const char *destdir)
 	struct lafe_line_reader *lr;
 	const char *p;
 	int r;
+	size_t destdir_len;
 
 	/* Ensure target dir has a trailing '/' to simplify path surgery. */
-	cpio->destdir = malloc(strlen(destdir) + 8);
-	strcpy(cpio->destdir, destdir);
-	if (destdir[strlen(destdir) - 1] != '/')
-		strcat(cpio->destdir, "/");
+	destdir_len = strlen(destdir);
+	cpio->destdir = malloc(destdir_len + 8);
+	memcpy(cpio->destdir, destdir, destdir_len);
+	if (destdir_len == 0 || destdir[destdir_len - 1] != '/')
+		cpio->destdir[destdir_len++] = '/';
+	cpio->destdir[destdir_len++] = '\0';
 
 	cpio->archive = archive_write_disk_new();
 	if (cpio->archive == NULL)
@@ -1240,6 +1244,7 @@ mode_pass(struct cpio *cpio, const char *destdir)
 	}
 
 	archive_write_free(cpio->archive);
+	free(cpio->pass_destpath);
 }
 
 /*
diff --git a/cpio/test/test_option_Z_upper.c b/cpio/test/test_option_Z_upper.c
index d69a85ea58ae..ff388427e372 100644
--- a/cpio/test/test_option_Z_upper.c
+++ b/cpio/test/test_option_Z_upper.c
@@ -43,17 +43,18 @@ DEFINE_TEST(test_option_Z_upper)
 		if (strstr(p, "compression not available") != NULL) {
 			skipping("This version of bsdcpio was compiled "
 			    "without compress support");
+			free(p);
 			return;
 		}
 		failure("-Z option is broken");
 		assertEqualInt(r, 0);
-		goto done;
+		free(p);
+		return;
 	}
 	free(p);
 	/* Check that the archive file has a compress signature. */
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "\x1f\x9d", 2);
-done:
 	free(p);
 }
diff --git a/cpio/test/test_option_a.c b/cpio/test/test_option_a.c
index 606de606e2c5..296387777ccf 100644
--- a/cpio/test/test_option_a.c
+++ b/cpio/test/test_option_a.c
@@ -96,7 +96,8 @@ DEFINE_TEST(test_option_a)
 	test_create();
 
 	/* Sanity check; verify that atimes really do get modified. */
-	assert((p = slurpfile(NULL, "f0")) != NULL);
+	p = slurpfile(NULL, "f0");
+	assert(p != NULL);
 	free(p);
 	assertEqualInt(0, stat("f0", &st));
 	if (st.st_atime == files[0].atime_sec) {
diff --git a/cpio/test/test_option_b64encode.c b/cpio/test/test_option_b64encode.c
index 8f6b4157c01c..7c15a8230606 100644
--- a/cpio/test/test_option_b64encode.c
+++ b/cpio/test/test_option_b64encode.c
@@ -42,6 +42,7 @@ DEFINE_TEST(test_option_b64encode)
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "begin-base64 644", 16);
+	free(p);
 
 	/* Archive it with uuencode only. */
 	assertEqualInt(0,
@@ -51,4 +52,5 @@ DEFINE_TEST(test_option_b64encode)
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "begin-base64 644", 16);
+	free(p);
 }
diff --git a/cpio/test/test_option_grzip.c b/cpio/test/test_option_grzip.c
index dfce2e064e07..7e7dd2c8e6f3 100644
--- a/cpio/test/test_option_grzip.c
+++ b/cpio/test/test_option_grzip.c
@@ -44,9 +44,10 @@ DEFINE_TEST(test_option_grzip)
 	    systemf("echo f | %s -o --grzip >archive.out 2>archive.err",
 	    testprog));
 	p = slurpfile(&s, "archive.err");
-	p[s] = '\0';
+	free(p);
 	/* Check that the archive file has an grzip signature. */
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "GRZipII\x00\x02\x04:)", 12);
+	free(p);
 }
diff --git a/cpio/test/test_option_lrzip.c b/cpio/test/test_option_lrzip.c
index a84f75157a4c..8d9c0d576cc3 100644
--- a/cpio/test/test_option_lrzip.c
+++ b/cpio/test/test_option_lrzip.c
@@ -44,9 +44,10 @@ DEFINE_TEST(test_option_lrzip)
 	    systemf("echo f | %s -o --lrzip >archive.out 2>archive.err",
 	    testprog));
 	p = slurpfile(&s, "archive.err");
-	p[s] = '\0';
+	free(p);
 	/* Check that the archive file has an lzma signature. */
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "LRZI\x00", 5);
+	free(p);
 }
diff --git a/cpio/test/test_option_lz4.c b/cpio/test/test_option_lz4.c
index afd683ddc773..88dfbd63bae9 100644
--- a/cpio/test/test_option_lz4.c
+++ b/cpio/test/test_option_lz4.c
@@ -43,6 +43,7 @@ DEFINE_TEST(test_option_lz4)
 		if (strstr(p, "compression not available") != NULL) {
 			skipping("This version of bsdcpio was compiled "
 			    "without lz4 support");
+			free(p);
 			return;
 		}
 		/* POSIX permits different handling of the spawnp
@@ -52,6 +53,7 @@ DEFINE_TEST(test_option_lz4)
 		if (strstr(p, "Can't launch") != NULL && !canLz4()) {
 			skipping("This version of bsdcpio uses an external lz4 program "
 			    "but no such program is available on this system.");
+			free(p);
 			return;
 		}
 		/* Some systems successfully spawn the new process,
@@ -61,6 +63,7 @@ DEFINE_TEST(test_option_lz4)
 		if (strstr(p, "Can't write") != NULL && !canLz4()) {
 			skipping("This version of bsdcpio uses an external lz4 program "
 			    "but no such program is available on this system.");
+			free(p);
 			return;
 		}
 		/* On some systems the error won't be detected until closing
@@ -68,14 +71,18 @@ DEFINE_TEST(test_option_lz4)
 		if (strstr(p, "Error closing") != NULL && !canLz4()) {
 			skipping("This version of bsdcpio uses an external lz4 program "
 			    "but no such program is available on this system.");
+			free(p);
 			return;
 		}
+		free(p);
 		failure("--lz4 option is broken: %s", p);
 		assertEqualInt(r, 0);
 		return;
 	}
+	free(p);
 	/* Check that the archive file has an lz4 signature. */
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "\x04\x22\x4d\x18", 4);
+	free(p);
 }
diff --git a/cpio/test/test_option_lzma.c b/cpio/test/test_option_lzma.c
index c6e335301505..b7cad3d1e99a 100644
--- a/cpio/test/test_option_lzma.c
+++ b/cpio/test/test_option_lzma.c
@@ -43,14 +43,18 @@ DEFINE_TEST(test_option_lzma)
 		if (strstr(p, "compression not available") != NULL) {
 			skipping("This version of bsdcpio was compiled "
 			    "without lzma support");
+			free(p);
 			return;
 		}
 		failure("--lzma option is broken");
 		assertEqualInt(r, 0);
+		free(p);
 		return;
 	}
+	free(p);
 	/* Check that the archive file has an lzma signature. */
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "\x5d\00\00", 3);
+	free(p);
 }
diff --git a/cpio/test/test_option_lzop.c b/cpio/test/test_option_lzop.c
index 9f1666e9c5b9..aa40ef5b6392 100644
--- a/cpio/test/test_option_lzop.c
+++ b/cpio/test/test_option_lzop.c
@@ -39,7 +39,7 @@ DEFINE_TEST(test_option_lzop)
 	r = systemf("echo f | %s -o --lzop >archive.out 2>archive.err",
 	    testprog);
 	p = slurpfile(&s, "archive.err");
-	p[s] = '\0';
+	free(p);
 	if (r != 0) {
 		if (!canLzop()) {
 			skipping("lzop is not supported on this platform");
@@ -53,4 +53,5 @@ DEFINE_TEST(test_option_lzop)
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a", 9);
+	free(p);
 }
diff --git a/cpio/test/test_option_uuencode.c b/cpio/test/test_option_uuencode.c
index ecf354f8f391..a42a0e03096f 100644
--- a/cpio/test/test_option_uuencode.c
+++ b/cpio/test/test_option_uuencode.c
@@ -42,6 +42,7 @@ DEFINE_TEST(test_option_uuencode)
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "begin 644", 9);
+	free(p);
 
 	/* Archive it with uuencode only. */
 	assertEqualInt(0,
@@ -51,4 +52,5 @@ DEFINE_TEST(test_option_uuencode)
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "begin 644", 9);
+	free(p);
 }
diff --git a/cpio/test/test_option_xz.c b/cpio/test/test_option_xz.c
index 02b5dfaad4a1..f0d3b33d45b8 100644
--- a/cpio/test/test_option_xz.c
+++ b/cpio/test/test_option_xz.c
@@ -44,14 +44,18 @@ DEFINE_TEST(test_option_xz)
 		if (strstr(p, "compression not available") != NULL) {
 			skipping("This version of bsdcpio was compiled "
 			    "without xz support");
+			free(p);
 			return;
 		}
+		free(p);
 		failure("--xz option is broken");
 		assertEqualInt(r, 0);
 		return;
 	}
+	free(p);
 	/* Check that the archive file has an xz signature. */
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "\xFD\x37\x7A\x58\x5A\x00", 6);
+	free(p);
 }
diff --git a/cpio/test/test_option_y.c b/cpio/test/test_option_y.c
index 0397b3d1bf45..989b5f1aaf6e 100644
--- a/cpio/test/test_option_y.c
+++ b/cpio/test/test_option_y.c
@@ -38,7 +38,7 @@ DEFINE_TEST(test_option_y)
 	r = systemf("echo f | %s -oy >archive.out 2>archive.err",
 	    testprog);
 	p = slurpfile(&s, "archive.err");
-	p[s] = '\0';
+	free(p);
 	if (r != 0) {
 		if (!canBzip2()) {
 			skipping("bzip2 is not supported on this platform");
@@ -46,14 +46,12 @@ DEFINE_TEST(test_option_y)
 		}
 		failure("-y option is broken");
 		assertEqualInt(r, 0);
-		goto done;
+		return;
 	}
 	assertTextFileContents("1 block\n", "archive.err");
 	/* Check that the archive file has a bzip2 signature. */
-	free(p);
 	p = slurpfile(&s, "archive.out");
 	assert(s > 2);
 	assertEqualMem(p, "BZh9", 4);
-done:
 	free(p);
 }
diff --git a/cpio/test/test_option_z.c b/cpio/test/test_option_z.c
index 0b68a42babbf..803232d045c2 100644
--- a/cpio/test/test_option_z.c
+++ b/cpio/test/test_option_z.c
@@ -38,7 +38,7 @@ DEFINE_TEST(test_option_z)
 	r = systemf("echo f | %s -oz >archive.out 2>archive.err",
 	    testprog);
 	p = slurpfile(&s, "archive.err");
-	p[s] = '\0';
+	free(p);
 	if (r != 0) {
 		if (!canGzip()) {
 			skipping("gzip is not supported on this platform");
@@ -52,4 +52,5 @@ DEFINE_TEST(test_option_z)
 	p = slurpfile(&s, "archive.out");
 	assert(s > 4);
 	assertEqualMem(p, "\x1f\x8b\x08\x00", 4);
+	free(p);
 }
diff --git a/libarchive/archive_entry_sparse.c b/libarchive/archive_entry_sparse.c
index fed74f5121d7..74917b37b804 100644
--- a/libarchive/archive_entry_sparse.c
+++ b/libarchive/archive_entry_sparse.c
@@ -51,7 +51,7 @@ archive_entry_sparse_clear(struct archive_entry *entry)
 
 void
 archive_entry_sparse_add_entry(struct archive_entry *entry,
-	int64_t offset, int64_t length)
+	la_int64_t offset, la_int64_t length)
 {
 	struct ae_sparse *sp;
 
@@ -135,7 +135,7 @@ archive_entry_sparse_reset(struct archive_entry * entry)
 
 int
 archive_entry_sparse_next(struct archive_entry * entry,
-	int64_t *offset, int64_t *length)
+	la_int64_t *offset, la_int64_t *length)
 {
 	if (entry->sparse_p) {
 		*offset = entry->sparse_p->offset;
diff --git a/libarchive/archive_getdate.c b/libarchive/archive_getdate.c
index fe43ae820aee..030c083ce716 100644
--- a/libarchive/archive_getdate.c
+++ b/libarchive/archive_getdate.c
@@ -691,7 +691,7 @@ Convert(time_t Month, time_t Day, time_t Year,
 	time_t Hours, time_t Minutes, time_t Seconds,
 	time_t Timezone, enum DSTMODE DSTmode)
 {
-	int DaysInMonth[12] = {
+	signed char DaysInMonth[12] = {
 		31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 	};
 	time_t	Julian;
diff --git a/libarchive/archive_openssl_hmac_private.h b/libarchive/archive_openssl_hmac_private.h
index 2deeb5f55900..59f95b80af83 100644
--- a/libarchive/archive_openssl_hmac_private.h
+++ b/libarchive/archive_openssl_hmac_private.h
@@ -28,7 +28,7 @@
 #include <openssl/hmac.h>
 #include <openssl/opensslv.h>
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 #include <stdlib.h> /* malloc, free */
 #include <string.h> /* memset */
 static inline HMAC_CTX *HMAC_CTX_new(void)
diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c
index d1fecebfd09f..a642a336def6 100644
--- a/libarchive/archive_read.c
+++ b/libarchive/archive_read.c
@@ -881,7 +881,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 			len = a->read_data_remaining;
 			if (len > s)
 				len = s;
-			memcpy(dest, a->read_data_block, len);
+			if (len)
+				memcpy(dest, a->read_data_block, len);
 			s -= len;
 			a->read_data_block += len;
 			a->read_data_remaining -= len;
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index 700f9e3ae1af..548ba89ef3db 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -928,11 +928,10 @@ setup_sparse(struct archive_read_disk *a,
 		return (ARCHIVE_OK);
 
 	/* Does filesystem support the reporting of hole ? */
-	if (*fd < 0) {
+	if (*fd < 0)
 		path = archive_read_disk_entry_setup_path(a, entry, fd);
-		if (path == NULL)
-			return (ARCHIVE_FAILED);
-	}
+	else
+		path = NULL;
 
 	if (*fd >= 0) {
 #ifdef _PC_MIN_HOLE_SIZE
@@ -943,6 +942,8 @@ setup_sparse(struct archive_read_disk *a,
 		if (initial_off != 0)
 			lseek(*fd, 0, SEEK_SET);
 	} else {
+		if (path == NULL)
+			return (ARCHIVE_FAILED);
 #ifdef _PC_MIN_HOLE_SIZE
 		if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
 			return (ARCHIVE_OK);
diff --git a/libarchive/archive_read_support_filter_lz4.c b/libarchive/archive_read_support_filter_lz4.c
index 663e2d3d601f..147f5027ff4d 100644
--- a/libarchive/archive_read_support_filter_lz4.c
+++ b/libarchive/archive_read_support_filter_lz4.c
@@ -494,7 +494,7 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
 	if (read_buf == NULL)
 		goto truncated_error;
 	compressed_size = archive_le32dec(read_buf);
-	if ((compressed_size & ~(1 << 31)) > state->flags.block_maximum_size)
+	if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size)
 		goto malformed_error;
 	/* A compressed size == 0 means the end of stream blocks. */
 	if (compressed_size == 0) {
@@ -504,8 +504,8 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
 
 	checksum_size = state->flags.block_checksum;
 	/* Check if the block is uncompressed. */
-	if (compressed_size & (1 << 31)) {
-		compressed_size &= ~(1 << 31);
+	if (compressed_size & 0x80000000U) {
+		compressed_size &= 0x7fffffff;
 		uncompressed_size = compressed_size;
 	} else
 		uncompressed_size = 0;/* Unknown yet. */
diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c
index 2cf0d453abdc..e5ff5a12cd9b 100644
--- a/libarchive/archive_read_support_format_cab.c
+++ b/libarchive/archive_read_support_format_cab.c
@@ -116,19 +116,11 @@ struct lzx_dec {
 		 * coding tree, which is a binary tree. But a use of a large
 		 * index table causes L1 cache read miss many times.
 		 */
-#define HTBL_BITS	10
 		int		 max_bits;
-		int		 shift_bits;
 		int		 tbl_bits;
 		int		 tree_used;
-		int		 tree_avail;
 		/* Direct access table. */
 		uint16_t	*tbl;
-		/* Binary tree table for extra bits over the direct access. */
-		struct htree_t {
-			uint16_t left;
-			uint16_t right;
-		}		*tree;
 	}			 at, lt, mt, pt;
 
 	int			 loop;
@@ -352,7 +344,6 @@ static int	lzx_huffman_init(struct huffman *, size_t, int);
 static void	lzx_huffman_free(struct huffman *);
 static int	lzx_make_huffman_table(struct huffman *);
 static inline int lzx_decode_huffman(struct huffman *, unsigned);
-static int	lzx_decode_huffman_tree(struct huffman *, unsigned, int);
 
 
 int
@@ -3127,7 +3118,6 @@ getdata:
 static int
 lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 {
-	int bits;
 
 	if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
 		free(hf->bitlen);
@@ -3138,21 +3128,11 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 	} else
 		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
 	if (hf->tbl == NULL) {
-		if (tbl_bits < HTBL_BITS)
-			bits = tbl_bits;
-		else
-			bits = HTBL_BITS;
-		hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
+		hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));
 		if (hf->tbl == NULL)
 			return (ARCHIVE_FATAL);
 		hf->tbl_bits = tbl_bits;
 	}
-	if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
-		hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
-		hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
-		if (hf->tree == NULL)
-			return (ARCHIVE_FATAL);
-	}
 	return (ARCHIVE_OK);
 }
 
@@ -3161,7 +3141,6 @@ lzx_huffman_free(struct huffman *hf)
 {
 	free(hf->bitlen);
 	free(hf->tbl);
-	free(hf->tree);
 }
 
 /*
@@ -3174,7 +3153,7 @@ lzx_make_huffman_table(struct huffman *hf)
 	const unsigned char *bitlen;
 	int bitptn[17], weight[17];
 	int i, maxbits = 0, ptn, tbl_size, w;
-	int diffbits, len_avail;
+	int len_avail;
 
 	/*
 	 * Initialize bit patterns.
@@ -3205,28 +3184,11 @@ lzx_make_huffman_table(struct huffman *hf)
 			weight[i] >>= ebits;
 		}
 	}
-	if (maxbits > HTBL_BITS) {
-		int htbl_max;
-		uint16_t *p;
-
-		diffbits = maxbits - HTBL_BITS;
-		for (i = 1; i <= HTBL_BITS; i++) {
-			bitptn[i] >>= diffbits;
-			weight[i] >>= diffbits;
-		}
-		htbl_max = bitptn[HTBL_BITS] +
-		    weight[HTBL_BITS] * hf->freq[HTBL_BITS];
-		p = &(hf->tbl[htbl_max]);
-		while (p < &hf->tbl[1U<<HTBL_BITS])
-			*p++ = 0;
-	} else
-		diffbits = 0;
-	hf->shift_bits = diffbits;
 
 	/*
 	 * Make the table.
 	 */
-	tbl_size = 1 << HTBL_BITS;
+	tbl_size = 1 << hf->tbl_bits;
 	tbl = hf->tbl;
 	bitlen = hf->bitlen;
 	len_avail = hf->len_size;
@@ -3234,120 +3196,32 @@ lzx_make_huffman_table(struct huffman *hf)
 	for (i = 0; i < len_avail; i++) {
 		uint16_t *p;
 		int len, cnt;
-		uint16_t bit;
-		int extlen;
-		struct htree_t *ht;
 
 		if (bitlen[i] == 0)
 			continue;
 		/* Get a bit pattern */
 		len = bitlen[i];
+		if (len > tbl_size)
+			return (0);
 		ptn = bitptn[len];
 		cnt = weight[len];
-		if (len <= HTBL_BITS) {
-			/* Calculate next bit pattern */
-			if ((bitptn[len] = ptn + cnt) > tbl_size)
-				return (0);/* Invalid */
-			/* Update the table */
-			p = &(tbl[ptn]);
-			while (--cnt >= 0)
-				p[cnt] = (uint16_t)i;
-			continue;
-		}
-
-		/*
-		 * A bit length is too big to be housed to a direct table,
-		 * so we use a tree model for its extra bits.
-		 */
-		bitptn[len] = ptn + cnt;
-		bit = 1U << (diffbits -1);
-		extlen = len - HTBL_BITS;
-		
-		p = &(tbl[ptn >> diffbits]);
-		if (*p == 0) {
-			*p = len_avail + hf->tree_used;
-			ht = &(hf->tree[hf->tree_used++]);
-			if (hf->tree_used > hf->tree_avail)
-				return (0);/* Invalid */
-			ht->left = 0;
-			ht->right = 0;
-		} else {
-			if (*p < len_avail ||
-			    *p >= (len_avail + hf->tree_used))
-				return (0);/* Invalid */
-			ht = &(hf->tree[*p - len_avail]);
-		}
-		while (--extlen > 0) {
-			if (ptn & bit) {
-				if (ht->left < len_avail) {
-					ht->left = len_avail + hf->tree_used;
-					ht = &(hf->tree[hf->tree_used++]);
-					if (hf->tree_used > hf->tree_avail)
-						return (0);/* Invalid */
-					ht->left = 0;
-					ht->right = 0;
-				} else {
-					ht = &(hf->tree[ht->left - len_avail]);
-				}
-			} else {
-				if (ht->right < len_avail) {
-					ht->right = len_avail + hf->tree_used;
-					ht = &(hf->tree[hf->tree_used++]);
-					if (hf->tree_used > hf->tree_avail)
-						return (0);/* Invalid */
-					ht->left = 0;
-					ht->right = 0;
-				} else {
-					ht = &(hf->tree[ht->right - len_avail]);
-				}
-			}
-			bit >>= 1;
-		}
-		if (ptn & bit) {
-			if (ht->left != 0)
-				return (0);/* Invalid */
-			ht->left = (uint16_t)i;
-		} else {
-			if (ht->right != 0)
-				return (0);/* Invalid */
-			ht->right = (uint16_t)i;
-		}
+		/* Calculate next bit pattern */
+		if ((bitptn[len] = ptn + cnt) > tbl_size)
+			return (0);/* Invalid */
+		/* Update the table */
+		p = &(tbl[ptn]);
+		while (--cnt >= 0)
+			p[cnt] = (uint16_t)i;
 	}
 	return (1);
 }
 
-static int
-lzx_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
-{
-	struct htree_t *ht;
-	int extlen;
-
-	ht = hf->tree;
-	extlen = hf->shift_bits;
-	while (c >= hf->len_size) {
-		c -= hf->len_size;
-		if (extlen-- <= 0 || c >= hf->tree_used)
-			return (0);
-		if (rbits & (1U << extlen))
-			c = ht[c].left;
-		else
-			c = ht[c].right;
-	}
-	return (c);
-}
-
 static inline int
 lzx_decode_huffman(struct huffman *hf, unsigned rbits)
 {
 	int c;
-	/*
-	 * At first search an index table for a bit pattern.
-	 * If it fails, search a huffman tree for.
-	 */
-	c = hf->tbl[rbits >> hf->shift_bits];
+	c = hf->tbl[rbits];
 	if (c < hf->len_size)
 		return (c);
-	/* This bit pattern needs to be found out at a huffman tree. */
-	return (lzx_decode_huffman_tree(hf, rbits, c));
+	return (0);
 }
-
diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c
index ffd4a8580ab4..ad9f782de488 100644
--- a/libarchive/archive_read_support_format_cpio.c
+++ b/libarchive/archive_read_support_format_cpio.c
@@ -165,7 +165,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_cpio.c 20116
 struct links_entry {
         struct links_entry      *next;
         struct links_entry      *previous;
-        int                      links;
+        unsigned int             links;
         dev_t                    dev;
         int64_t                  ino;
         char                    *name;
diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c
index 76da4069ef13..f01d37bf682e 100644
--- a/libarchive/archive_read_support_format_iso9660.c
+++ b/libarchive/archive_read_support_format_iso9660.c
@@ -3021,8 +3021,9 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
 			    ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 		}
-		memcpy(new_pending_files, heap->files,
-		    heap->allocated * sizeof(new_pending_files[0]));
+		if (heap->allocated)
+			memcpy(new_pending_files, heap->files,
+			    heap->allocated * sizeof(new_pending_files[0]));
 		if (heap->files != NULL)
 			free(heap->files);
 		heap->files = new_pending_files;
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index 1590187febe5..44b6083cb2f2 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -130,9 +130,7 @@ static ssize_t	readline(struct archive_read *, struct mtree *, char **, ssize_t)
 static int	skip(struct archive_read *a);
 static int	read_header(struct archive_read *,
 		    struct archive_entry *);
-static int64_t	mtree_atol10(char **);
-static int64_t	mtree_atol8(char **);
-static int64_t	mtree_atol(char **);
+static int64_t	mtree_atol(char **, int base);
 
 /*
  * There's no standard for TIME_T_MAX/TIME_T_MIN.  So we compute them
@@ -1418,7 +1416,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
 				    "Too many arguments");
 				return ARCHIVE_WARN;
 			}
-			numbers[argc++] = (unsigned long)mtree_atol(&p);
+			numbers[argc++] = (unsigned long)mtree_atol(&p, 0);
 		}
 		if (argc < 2) {
 			archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1433,7 +1431,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
 		}
 	} else {
 		/* file system raw value. */
-		result = (dev_t)mtree_atol(&val);
+		result = (dev_t)mtree_atol(&val, 0);
 	}
 	*pdev = result;
 	return ARCHIVE_OK;
@@ -1513,7 +1511,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	case 'g':
 		if (strcmp(key, "gid") == 0) {
 			*parsed_kws |= MTREE_HAS_GID;
-			archive_entry_set_gid(entry, mtree_atol10(&val));
+			archive_entry_set_gid(entry, mtree_atol(&val, 10));
 			break;
 		}
 		if (strcmp(key, "gname") == 0) {
@@ -1523,7 +1521,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		}
 	case 'i':
 		if (strcmp(key, "inode") == 0) {
-			archive_entry_set_ino(entry, mtree_atol10(&val));
+			archive_entry_set_ino(entry, mtree_atol(&val, 10));
 			break;
 		}
 	case 'l':
@@ -1535,14 +1533,14 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
 			break;
 		if (strcmp(key, "mode") == 0) {
-			if (val[0] >= '0' && val[0] <= '9') {
+			if (val[0] >= '0' && val[0] <= '7') {
 				*parsed_kws |= MTREE_HAS_PERM;
 				archive_entry_set_perm(entry,
-				    (mode_t)mtree_atol8(&val));
+				    (mode_t)mtree_atol(&val, 8));
 			} else {
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_FILE_FORMAT,
-				    "Symbolic mode \"%s\" unsupported", val);
+				    "Symbolic or non-octal mode \"%s\" unsupported", val);
 				return ARCHIVE_WARN;
 			}
 			break;
@@ -1551,7 +1549,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		if (strcmp(key, "nlink") == 0) {
 			*parsed_kws |= MTREE_HAS_NLINK;
 			archive_entry_set_nlink(entry,
-				(unsigned int)mtree_atol10(&val));
+				(unsigned int)mtree_atol(&val, 10));
 			break;
 		}
 	case 'r':
@@ -1582,7 +1580,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		    strcmp(key, "sha512digest") == 0)
 			break;
 		if (strcmp(key, "size") == 0) {
-			archive_entry_set_size(entry, mtree_atol10(&val));
+			archive_entry_set_size(entry, mtree_atol(&val, 10));
 			break;
 		}
 	case 't':
@@ -1601,13 +1599,13 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 			long ns = 0;
 
 			*parsed_kws |= MTREE_HAS_MTIME;
-			m = mtree_atol10(&val);
+			m = mtree_atol(&val, 10);
 			/* Replicate an old mtree bug:
 			 * 123456789.1 represents 123456789
 			 * seconds and 1 nanosecond. */
 			if (*val == '.') {
 				++val;
-				ns = (long)mtree_atol10(&val);
+				ns = (long)mtree_atol(&val, 10);
 				if (ns < 0)
 					ns = 0;
 				else if (ns > 999999999)
@@ -1670,7 +1668,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	case 'u':
 		if (strcmp(key, "uid") == 0) {
 			*parsed_kws |= MTREE_HAS_UID;
-			archive_entry_set_uid(entry, mtree_atol10(&val));
+			archive_entry_set_uid(entry, mtree_atol(&val, 10));
 			break;
 		}
 		if (strcmp(key, "uname") == 0) {
@@ -1825,77 +1823,9 @@ parse_escapes(char *src, struct mtree_entry *mentry)
 	*dest = '\0';
 }
 
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-static int64_t
-mtree_atol8(char **p)
-{
-	int64_t	l, limit, last_digit_limit;
-	int digit, base;
-
-	base = 8;
-	limit = INT64_MAX / base;
-	last_digit_limit = INT64_MAX % base;
-
-	l = 0;
-	digit = **p - '0';
-	while (digit >= 0 && digit < base) {
-		if (l>limit || (l == limit && digit > last_digit_limit)) {
-			l = INT64_MAX; /* Truncate on overflow. */
-			break;
-		}
-		l = (l * base) + digit;
-		digit = *++(*p) - '0';
-	}
-	return (l);
-}
-
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- *
- * Convert the number pointed to by 'p' into a 64-bit signed integer.
- * On return, 'p' points to the first non-digit following the number.
- * On overflow, the function returns INT64_MIN or INT64_MAX.
- */
-static int64_t
-mtree_atol10(char **p)
-{
-	const int base = 10;
-	const int64_t limit = INT64_MAX / base;
-	const int64_t last_digit_limit = INT64_MAX % base;
-	int64_t l;
-	int sign;
-
-	if (**p == '-') {
-		sign = -1;
-		++(*p);
-	} else {
-		sign = 1;
-	}
-
-	l = 0;
-	while (**p >= '0' && **p < '0' + base) {
-		int digit = **p - '0';
-		if (l > limit || (l == limit && digit > last_digit_limit)) {
-			while (**p >= '0' && **p < '0' + base) {
-				++(*p);
-			}
-			return (sign < 0) ? INT64_MIN : INT64_MAX;
-		}
-		l = (l * base) + digit;
-		++(*p);
-	}
-	return (sign < 0) ? -l : l;
-}
-
 /* Parse a hex digit. */
 static int
-parsehex(char c)
+parsedigit(char c)
 {
 	if (c >= '0' && c <= '9')
 		return c - '0';
@@ -1913,45 +1843,50 @@ parsehex(char c)
  * it does obey locale.
  */
 static int64_t
-mtree_atol16(char **p)
+mtree_atol(char **p, int base)
 {
-	int64_t l, limit, last_digit_limit;
-	int base, digit, sign;
+	int64_t l, limit;
+	int digit, last_digit_limit;
 
-	base = 16;
+	if (base == 0) {
+		if (**p != '0')
+			base = 10;
+		else if ((*p)[1] == 'x' || (*p)[1] == 'X') {
+			*p += 2;
+			base = 16;
+		} else {
+			base = 8;
+		}
+	}
 
 	if (**p == '-') {
-		sign = -1;
-		limit = ((uint64_t)(INT64_MAX) + 1) / base;
-		last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
+		limit = INT64_MIN / base;
+		last_digit_limit = INT64_MIN % base;
 		++(*p);
+
+		l = 0;
+		digit = parsedigit(**p);
+		while (digit >= 0 && digit < base) {
+			if (l < limit || (l == limit && digit > last_digit_limit))
+				return INT64_MIN;
+			l = (l * base) - digit;
+			digit = parsedigit(*++(*p));
+		}
+		return l;
 	} else {
-		sign = 1;
 		limit = INT64_MAX / base;
 		last_digit_limit = INT64_MAX % base;
-	}
 
-	l = 0;
-	digit = parsehex(**p);
-	while (digit >= 0 && digit < base) {
-		if (l > limit || (l == limit && digit > last_digit_limit))
-			return (sign < 0) ? INT64_MIN : INT64_MAX;
-		l = (l * base) + digit;
-		digit = parsehex(*++(*p));
+		l = 0;
+		digit = parsedigit(**p);
+		while (digit >= 0 && digit < base) {
+			if (l > limit || (l == limit && digit > last_digit_limit))
+				return INT64_MAX;
+			l = (l * base) + digit;
+			digit = parsedigit(*++(*p));
+		}
+		return l;
 	}
-	return (sign < 0) ? -l : l;
-}
-
-static int64_t
-mtree_atol(char **p)
-{
-	if (**p != '0')
-		return mtree_atol10(p);
-	if ((*p)[1] == 'x' || (*p)[1] == 'X') {
-		*p += 2;
-		return mtree_atol16(p);
-	}
-	return mtree_atol8(p);
 }
 
 /*
diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
index 1e9849fdd629..cbb14c32dc3b 100644
--- a/libarchive/archive_read_support_format_rar.c
+++ b/libarchive/archive_read_support_format_rar.c
@@ -1750,7 +1750,7 @@ read_exttime(const char *p, struct rar *rar, const char *endp)
         return (-1);
       for (j = 0; j < count; j++)
       {
-        rem = ((*p) << 16) | (rem >> 8);
+        rem = (((unsigned)(unsigned char)*p) << 16) | (rem >> 8);
         p++;
       }
       tm = localtime(&t);
diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c
index 592ead2bdd58..5ae09b626cbc 100644
--- a/libarchive/archive_string.c
+++ b/libarchive/archive_string.c
@@ -202,7 +202,8 @@ archive_string_append(struct archive_string *as, const char *p, size_t s)
 {
 	if (archive_string_ensure(as, as->length + s + 1) == NULL)
 		return (NULL);
-	memmove(as->s + as->length, p, s);
+	if (s)
+		memmove(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
 	return (as);
diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c
index 6a301ac2d196..0eaf733cd9aa 100644
--- a/libarchive/archive_write_set_format_pax.c
+++ b/libarchive/archive_write_set_format_pax.c
@@ -1196,8 +1196,12 @@ archive_write_pax_header(struct archive_write *a,
 			    "GNU.sparse.major", 1);
 			add_pax_attr_int(&(pax->pax_header),
 			    "GNU.sparse.minor", 0);
+			/*
+			 * Make sure to store the original path, since
+			 * truncation to ustar limit happened already.
+			 */
 			add_pax_attr(&(pax->pax_header),
-			    "GNU.sparse.name", entry_name.s);
+			    "GNU.sparse.name", path);
 			add_pax_attr_int(&(pax->pax_header),
 			    "GNU.sparse.realsize",
 			    archive_entry_size(entry_main));
@@ -1650,13 +1654,14 @@ build_pax_attribute_name(char *dest, const char *src)
  * GNU PAX Format 1.0 requires the special name, which pattern is:
  * <dir>/GNUSparseFile.<pid>/<original file name>
  *
+ * Since reproducable archives are more important, use 0 as pid.
+ *
  * This function is used for only Sparse file, a file type of which
  * is regular file.
  */
 static char *
 build_gnu_sparse_name(char *dest, const char *src)
 {
-	char buff[64];
 	const char *p;
 
 	/* Handle the null filename case. */
@@ -1682,15 +1687,9 @@ build_gnu_sparse_name(char *dest, const char *src)
 		break;
 	}
 
-#if HAVE_GETPID && 0  /* Disable this as pax attribute name. */
-	sprintf(buff, "GNUSparseFile.%d", getpid());
-#else
-	/* If the platform can't fetch the pid, don't include it. */
-	strcpy(buff, "GNUSparseFile");
-#endif
 	/* General case: build a ustar-compatible name adding
 	 * "/GNUSparseFile/". */
-	build_ustar_entry_name(dest, src, p - src, buff);
+	build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0");
 
 	return (dest);
 }
diff --git a/libarchive/libarchive_changes.3 b/libarchive/libarchive_changes.3
index 881a67cdd41d..adc87febd71d 100644
--- a/libarchive/libarchive_changes.3
+++ b/libarchive/libarchive_changes.3
@@ -28,6 +28,7 @@
 .Dt LIBARCHIVE_CHANGES 3
 .Os
 .Sh NAME
+.Nm libarchive_changes
 .Nd changes in libarchive interface
 .\"
 .Sh CHANGES IN LIBARCHIVE 3
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index e6018b55035d..ee8686bae984 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -182,6 +182,7 @@ IF(ENABLE_TEST)
     test_read_format_zip_winzip_aes.c
     test_read_format_zip_winzip_aes_large.c
     test_read_format_zip_zip64.c
+    test_read_format_zip_with_invalid_traditional_eocd.c
     test_read_large.c
     test_read_pax_schily_xattr.c
     test_read_pax_truncated.c
diff --git a/libarchive/test/test_read_format_mtree.c b/libarchive/test/test_read_format_mtree.c
index a8342f55790e..8576d579f9c6 100644
--- a/libarchive/test/test_read_format_mtree.c
+++ b/libarchive/test/test_read_format_mtree.c
@@ -183,7 +183,7 @@ test_read_format_mtree1(void)
 	min_time = archive_entry_mtime(ae);
 	assert(min_time <= 0);
 	/* Simply asserting min_time - 1 > 0 breaks with some compiler optimizations. */
-	t = min_time - 1;
+	t = (time_t)((uintmax_t)min_time - 1);
 	assert(t > 0);
 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
diff --git a/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c b/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c
new file mode 100644
index 000000000000..dc94f94f1571
--- /dev/null
+++ b/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.c
@@ -0,0 +1,60 @@
+/*-
+ * Copyright (c) 2017 Phillip Berndt
+ * 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 "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Issue 869: zip files without a valid EOCD header aren't loaded even if they
+ * have a valid ZIP64 version of said header.
+ */
+
+DEFINE_TEST(test_read_format_zip_with_invalid_traditional_eocd)
+{
+	const char *refname = "test_read_format_zip_with_invalid_traditional_eocd.zip";
+	char *p;
+	size_t s;
+	struct archive *a;
+	struct archive_entry *ae;
+
+	extract_reference_file(refname);
+	p = slurpfile(&s, refname);
+
+	assert((a = archive_read_new()) != NULL);
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip_seekable(a));
+	assertEqualIntA(a, ARCHIVE_OK, read_open_memory_seek(a, p, s, 1));
+
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+	assertEqualString("test1.txt", archive_entry_pathname(ae));
+	assertEqualInt(0, archive_entry_size(ae));
+
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+	assertEqualString("test2.txt", archive_entry_pathname(ae));
+	assertEqualInt(0, archive_entry_size(ae));
+
+	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+	assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
+	free(p);
+}
diff --git a/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.zip.uu b/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.zip.uu
new file mode 100644
index 000000000000..63744f145ea2
--- /dev/null
+++ b/libarchive/test/test_read_format_zip_with_invalid_traditional_eocd.zip.uu
@@ -0,0 +1,14 @@
+begin 644 test_read_format_zip_without_eocd.zip
+M4$L#!"T`"````-IT@DH`````__________\)`"``=&5S=#$N='AT`0`<````
+M````````````````````````````````````````````````````````````
+M`%!+`P0M``@```#:=()*`````/__________"0`@`'1E<W0R+G1X=`$`'```
+M````````````````````6P``````````````````````````````````````
+M``!02P$"+0,M``@```#:=()*`````/__________"0`@````__\`````I('_
+M____=&5S=#$N='AT`0`<``````````````````````````````````````!0
+M2P$"+0,M``@```#:=()*`````/__________"0`@````__\`````I('_____
+M=&5S=#(N='AT`0`<``````````````````````!;``````````````!02P8&
+M+``````````M`RT````````````"``````````(`````````K@````````"V
+M`````````%!+!@<`````9`$````````!````4$L%!O__________________
+$__\`````
+`
+end
diff --git a/libarchive/test/test_write_format_pax.c b/libarchive/test/test_write_format_pax.c
index 1bae0050f081..41a423a96a0e 100644
--- a/libarchive/test/test_write_format_pax.c
+++ b/libarchive/test/test_write_format_pax.c
@@ -80,13 +80,19 @@ DEFINE_TEST(test_write_format_pax)
 	/*
 	 * "file3" is sparse file and has hole size of which is
 	 * 1024000 bytes, and has 8 bytes data after the hole.
+	 *
+	 * Pad the filename to make it larger than the ustar limit.
+	 * It should still read back correctly.
 	 */
 	assert((ae = archive_entry_new()) != NULL);
 	archive_entry_set_atime(ae, 2, 20);
 	archive_entry_set_birthtime(ae, 3, 30);
 	archive_entry_set_ctime(ae, 4, 40);
 	archive_entry_set_mtime(ae, 5, 50);
-	archive_entry_copy_pathname(ae, "file3");
+	archive_entry_copy_pathname(ae, "file3"
+	    "_123456789_123456789_123456789_123456789_123456789"
+	    "_123456789_123456789_123456789_123456789_123456789"
+	    "_123456789_123456789_123456789_123456789_123456789");
 	archive_entry_set_mode(ae, S_IFREG | 0755);
 	archive_entry_set_size(ae, 1024008);
 	archive_entry_sparse_add_entry(ae, 1024000, 8);
@@ -171,7 +177,11 @@ DEFINE_TEST(test_write_format_pax)
 	assertEqualInt(40, archive_entry_ctime_nsec(ae));
 	assertEqualInt(5, archive_entry_mtime(ae));
 	assertEqualInt(50, archive_entry_mtime_nsec(ae));
-	assertEqualString("file3", archive_entry_pathname(ae));
+	assertEqualString("file3"
+	    "_123456789_123456789_123456789_123456789_123456789"
+	    "_123456789_123456789_123456789_123456789_123456789"
+	    "_123456789_123456789_123456789_123456789_123456789",
+	    archive_entry_pathname(ae));
 	assert((S_IFREG | 0755) == archive_entry_mode(ae));
 	assertEqualInt(1024008, archive_entry_size(ae));
 	assertEqualInt(1, archive_entry_sparse_reset(ae));
diff --git a/libarchive/test/test_write_format_zip_compression_store.c b/libarchive/test/test_write_format_zip_compression_store.c
index 281de1befe26..466aa40d9e04 100644
--- a/libarchive/test/test_write_format_zip_compression_store.c
+++ b/libarchive/test/test_write_format_zip_compression_store.c
@@ -108,8 +108,19 @@ static void verify_write_uncompressed(struct archive *a)
 }
 
 /* Quick and dirty: Read 2-byte and 4-byte integers from Zip file. */
-static int i2(const char *p) { return ((p[0] & 0xff) | ((p[1] & 0xff) << 8)); }
-static int i4(const char *p) { return (i2(p) | (i2(p + 2) << 16)); }
+static unsigned int
+i2(const void *p_)
+{
+	const unsigned char *p = p_;
+	return (p[0] | (p[1] << 8));
+}
+
+static unsigned int
+i4(const void *p_)
+{
+	const unsigned char *p = p_;
+	return (i2(p) | (i2(p + 2) << 16));
+}
 
 static void verify_uncompressed_contents(const char *buff, size_t used)
 {
diff --git a/libarchive/test/test_write_format_zip_large.c b/libarchive/test/test_write_format_zip_large.c
index 88788b56d50d..2f98c6d4db8a 100644
--- a/libarchive/test/test_write_format_zip_large.c
+++ b/libarchive/test/test_write_format_zip_large.c
@@ -67,21 +67,19 @@ static int64_t	memory_read_skip(struct archive *, void *, int64_t request);
 static ssize_t	memory_read(struct archive *, void *, const void **buff);
 static ssize_t	memory_write(struct archive *, void *, const void *, size_t);
 
-static int16_t le16(const void *_p) {
+static uint16_t le16(const void *_p) {
 	const uint8_t *p = _p;
-	return (0xff & (int16_t)p[0]) | ((0xff & (int16_t)p[1]) << 8);
+	return p[0] | (p[1] << 8);
 }
 
-static int32_t le32(const void *_p) {
+static uint32_t le32(const void *_p) {
 	const uint8_t *p = _p;
-	int32_t v = 0xffff & (int32_t)le16(_p);
-	return v + ((0xffff & (int32_t)le16(p + 2)) << 16);
+	return le16(p) | ((uint32_t)le16(p + 2) << 16);
 }
 
-static int64_t le64(const void *_p) {
+static uint64_t le64(const void *_p) {
 	const uint8_t *p = _p;
-	int64_t v = 0xffffffff & (int64_t)le32(_p);
-	return v + ((0xffffffff & (int64_t)le32(p + 4)) << 32);
+	return le32(p) | ((uint64_t)le32(p + 4) << 32);
 }
 
 static ssize_t
diff --git a/libarchive/xxhash.c b/libarchive/xxhash.c
index 6f5ba52fac32..70750bae0863 100644
--- a/libarchive/xxhash.c
+++ b/libarchive/xxhash.c
@@ -141,13 +141,19 @@ typedef struct _U32_S { U32 v; } _PACKED U32_S;
 #  pragma pack(pop)
 #endif
 
-#define A32(x) (((const U32_S *)(x))->v)
-
 
 /****************************************
 ** Compiler-specific Functions and Macros
 *****************************************/
-#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#define GCC_VERSION ((__GNUC__-0) * 100 + (__GNUC_MINOR__ - 0))
+
+#if GCC_VERSION >= 409
+__attribute__((__no_sanitize_undefined__))
+#endif
+static inline U32 A32(const void * x)
+{
+    return (((const U32_S *)(x))->v);
+}
 
 /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
 #if defined(_MSC_VER)
diff --git a/test_utils/test_main.c b/test_utils/test_main.c
index d74045934bec..0e1413693f4a 100644
--- a/test_utils/test_main.c
+++ b/test_utils/test_main.c
@@ -1102,6 +1102,7 @@ assertion_file_contains_lines_any_order(const char *file, int line,
 			failure_start(pathname, line, "Can't allocate memory");
 			failure_finish(NULL);
 			free(expected);
+			free(buff);
 			return (0);
 		}
 		for (i = 0; lines[i] != NULL; ++i) {
@@ -1124,6 +1125,7 @@ assertion_file_contains_lines_any_order(const char *file, int line,
 			failure_start(pathname, line, "Can't allocate memory");
 			failure_finish(NULL);
 			free(expected);
+			free(buff);
 			return (0);
 		}
 		for (j = 0, p = buff; p < buff + buff_size;