? o
Index: libarchive/archive.h
===================================================================
RCS file: /cvsroot/src/external/bsd/libarchive/dist/libarchive/archive.h,v
retrieving revision 1.4
diff -u -u -r1.4 archive.h
--- libarchive/archive.h	24 Jul 2019 14:03:57 -0000	1.4
+++ libarchive/archive.h	13 Nov 2019 22:06:25 -0000
@@ -693,6 +693,8 @@
 #define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000)
 /* Default: Do not clear no-change flags when unlinking object */
 #define	ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS	(0x20000)
+/* Default: Do not extract atomically (using rename) */
+#define	ARCHIVE_EXTRACT_ATOMIC			(0x40000)
 
 __LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
 		     int flags);
Index: libarchive/archive_write_disk_posix.c
===================================================================
RCS file: /cvsroot/src/external/bsd/libarchive/dist/libarchive/archive_write_disk_posix.c,v
retrieving revision 1.1.1.2
diff -u -u -r1.1.1.2 archive_write_disk_posix.c
--- libarchive/archive_write_disk_posix.c	24 Jul 2019 13:50:21 -0000	1.1.1.2
+++ libarchive/archive_write_disk_posix.c	13 Nov 2019 22:06:25 -0000
@@ -253,6 +253,8 @@
 	struct archive_entry	*entry; /* Entry being extracted. */
 	char			*name; /* Name of entry, possibly edited. */
 	struct archive_string	 _name_data; /* backing store for 'name' */
+	char			*tmpname; /* Temporary name * */
+	struct archive_string	 _tmpname_data; /* backing store for 'tmpname' */
 	/* Tasks remaining for this object. */
 	int			 todo;
 	/* Tasks deferred until end-of-archive. */
@@ -1826,6 +1828,13 @@
 	if (a->fd >= 0) {
 		close(a->fd);
 		a->fd = -1;
+		if (a->tmpname) {
+			if (rename(a->tmpname, a->name) == -1) {
+				archive_set_error(&a->archive, errno,
+				    "rename failed");
+				ret = ARCHIVE_FATAL;
+			}
+		}
 	}
 	/* If there's an entry, we can release it now. */
 	archive_entry_free(a->entry);
@@ -2288,8 +2297,24 @@
 		/* POSIX requires that we fall through here. */
 		/* FALLTHROUGH */
 	case AE_IFREG:
-		a->fd = open(a->name,
-		    O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, mode);
+		if (a->flags & ARCHIVE_EXTRACT_ATOMIC) {
+			archive_string_empty(&a->_tmpname_data);
+			archive_string_sprintf(&a->_tmpname_data, "%sXXXXXX",
+			    a->name);
+			a->tmpname = a->_tmpname_data.s;
+			a->fd = mkostemp(a->tmpname, O_CLOEXEC);
+			if (a->fd >= 0 && fchmod(a->fd, mode) == -1) {
+				int oerrno = errno;
+				close(a->fd);
+				errno = oerrno;
+				a->fd = -1;
+			}
+		} else {
+			a->tmpname = NULL;
+			a->fd = open(a->name,
+			    O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC,
+			    mode);
+		}
 		__archive_ensure_cloexec_flag(a->fd);
 		r = (a->fd < 0);
 		break;
@@ -2449,6 +2474,7 @@
 	archive_write_disk_set_user_lookup(&a->archive, NULL, NULL, NULL);
 	archive_entry_free(a->entry);
 	archive_string_free(&a->_name_data);
+	archive_string_free(&a->_tmpname_data);
 	archive_string_free(&a->archive.error_string);
 	archive_string_free(&a->path_safe);
 	a->archive.magic = 0;
Index: tar/bsdtar.c
===================================================================
RCS file: /cvsroot/src/external/bsd/libarchive/dist/tar/bsdtar.c,v
retrieving revision 1.1.1.4
diff -u -u -r1.1.1.4 bsdtar.c
--- tar/bsdtar.c	24 Jul 2019 13:50:41 -0000	1.1.1.4
+++ tar/bsdtar.c	13 Nov 2019 22:06:25 -0000
@@ -231,6 +231,9 @@
 	/* Default: Perform basic security checks. */
 	bsdtar->extract_flags |= SECURITY;
 
+	/* Default: Extract atomically if possible */
+	bsdtar->extract_flags |= ARCHIVE_EXTRACT_ATOMIC;
+
 #ifndef _WIN32
 	/* On POSIX systems, assume --same-owner and -p when run by
 	 * the root user.  This doesn't make any sense on Windows. */