Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/external/bsd/libarchive/dist Introduce ARCHIVE_EXTRACT_ATOMI...



details:   https://anonhg.NetBSD.org/src/rev/0f69dfa78b4a
branches:  trunk
changeset: 968319:0f69dfa78b4a
user:      christos <christos%NetBSD.org@localhost>
date:      Sun Jan 12 16:08:31 2020 +0000

description:
Introduce ARCHIVE_EXTRACT_ATOMIC and set it by default on bsdtar.

This flag changes the way that regular files are extracted:

Instead of removing existing files first and re-creating them in
order to replace their contents, a temporary file is created and
when writing to the temporary file is completed, the file is
rename(2)d to the final destination name.

This has the effect of presenting a consistent view of the file to
the system (either the file with the new contents or the file with
the old contents). Removing and overwriting the file has the
undesired side effect that the the system can either not see the
file at all (from the time it is being removed till the time it is
being re-created), or worse it can see partial file contents. This
is problematic when extracting system files (for example shared
libraries).

Perhaps there should be a flag to disable it, when for example it
is not desirable because of space constraints, but then again
one can specify to unlink the file before.

(this is pull request 1289)

diffstat:

 external/bsd/libarchive/dist/libarchive/archive.h                  |   2 +
 external/bsd/libarchive/dist/libarchive/archive_private.h          |   1 +
 external/bsd/libarchive/dist/libarchive/archive_util.c             |  93 ++++++---
 external/bsd/libarchive/dist/libarchive/archive_write_disk_posix.c |  63 +++++-
 external/bsd/libarchive/dist/tar/bsdtar.c                          |   3 +
 5 files changed, 119 insertions(+), 43 deletions(-)

diffs (292 lines):

diff -r 02d5f22bf566 -r 0f69dfa78b4a external/bsd/libarchive/dist/libarchive/archive.h
--- a/external/bsd/libarchive/dist/libarchive/archive.h Sun Jan 12 13:51:12 2020 +0000
+++ b/external/bsd/libarchive/dist/libarchive/archive.h Sun Jan 12 16:08:31 2020 +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);
diff -r 02d5f22bf566 -r 0f69dfa78b4a external/bsd/libarchive/dist/libarchive/archive_private.h
--- a/external/bsd/libarchive/dist/libarchive/archive_private.h Sun Jan 12 13:51:12 2020 +0000
+++ b/external/bsd/libarchive/dist/libarchive/archive_private.h Sun Jan 12 16:08:31 2020 +0000
@@ -153,6 +153,7 @@
 
 void   __archive_ensure_cloexec_flag(int fd);
 int    __archive_mktemp(const char *tmpdir);
+int    __archive_mktempx(const char *tmpdir, struct archive_string *template);
 
 int    __archive_clean(struct archive *);
 
diff -r 02d5f22bf566 -r 0f69dfa78b4a external/bsd/libarchive/dist/libarchive/archive_util.c
--- a/external/bsd/libarchive/dist/libarchive/archive_util.c    Sun Jan 12 13:51:12 2020 +0000
+++ b/external/bsd/libarchive/dist/libarchive/archive_util.c    Sun Jan 12 16:08:31 2020 +0000
@@ -389,28 +389,33 @@
  */
 
 int
-__archive_mktemp(const char *tmpdir)
+__archive_mktempx(const char *tmpdir, struct archive_string *template)
 {
        struct archive_string temp_name;
        int fd = -1;
 
-       archive_string_init(&temp_name);
-       if (tmpdir == NULL) {
-               if (get_tempdir(&temp_name) != ARCHIVE_OK)
-                       goto exit_tmpfile;
-       } else {
-               archive_strcpy(&temp_name, tmpdir);
-               if (temp_name.s[temp_name.length-1] != '/')
-                       archive_strappend_char(&temp_name, '/');
+       if (template == NULL) {
+               archive_string_init(template = &temp_name);
+               if (tmpdir == NULL) {
+                       if (get_tempdir(&temp_name) != ARCHIVE_OK)
+                               goto exit_tmpfile;
+               } else {
+                       archive_strcpy(&temp_name, tmpdir);
+                       if (temp_name.s[temp_name.length-1] != '/')
+                               archive_strappend_char(&temp_name, '/');
+               }
+               archive_strcat(&temp_name, "libarchive_XXXXXX");
        }
-       archive_strcat(&temp_name, "libarchive_XXXXXX");
-       fd = mkstemp(temp_name.s);
+       fd = mkstemp(template->s);
        if (fd < 0)
                goto exit_tmpfile;
        __archive_ensure_cloexec_flag(fd);
-       unlink(temp_name.s);
+
+       if (template == &temp_name)
+               unlink(temp_name.s);
 exit_tmpfile:
-       archive_string_free(&temp_name);
+       if (template == &temp_name)
+               archive_string_free(&temp_name);
        return (fd);
 }
 
@@ -421,7 +426,7 @@
  */
 
 int
-__archive_mktemp(const char *tmpdir)
+__archive_mktempx(const char *tmpdir, struct archive_string *template)
 {
         static const char num[] = {
                '0', '1', '2', '3', '4', '5', '6', '7',
@@ -439,26 +444,36 @@
        char *tp, *ep;
 
        fd = -1;
-       archive_string_init(&temp_name);
-       if (tmpdir == NULL) {
-               if (get_tempdir(&temp_name) != ARCHIVE_OK)
+       if (template == NULL) {
+               archive_string_init(template = &temp_name);
+               if (tmpdir == NULL) {
+                       if (get_tempdir(&temp_name) != ARCHIVE_OK)
+                               goto exit_tmpfile;
+               } else
+                       archive_strcpy(&temp_name, tmpdir);
+               if (temp_name.s[temp_name.length-1] == '/') {
+                       temp_name.s[temp_name.length-1] = '\0';
+                       temp_name.length --;
+               }
+               if (la_stat(temp_name.s, &st) < 0)
                        goto exit_tmpfile;
-       } else
-               archive_strcpy(&temp_name, tmpdir);
-       if (temp_name.s[temp_name.length-1] == '/') {
-               temp_name.s[temp_name.length-1] = '\0';
-               temp_name.length --;
+               if (!S_ISDIR(st.st_mode)) {
+                       errno = ENOTDIR;
+                       goto exit_tmpfile;
+               }
+               archive_strcat(&temp_name, "/libarchive_");
+               tp = temp_name.s + archive_strlen(&temp_name);
+               archive_strcat(&temp_name, "XXXXXXXXXX");
+               ep = temp_name.s + archive_strlen(&temp_name);
+       } else {
+               tp = strchr(template->s, 'X');
+               if (tp == NULL) /* No X, programming error */
+                       abort();
+               for (ep = *tp; *ep == 'X'; ep++)
+                       continue;
+               if (*ep)        /* X followed by non X, programming error */
+                       abort();
        }
-       if (la_stat(temp_name.s, &st) < 0)
-               goto exit_tmpfile;
-       if (!S_ISDIR(st.st_mode)) {
-               errno = ENOTDIR;
-               goto exit_tmpfile;
-       }
-       archive_strcat(&temp_name, "/libarchive_");
-       tp = temp_name.s + archive_strlen(&temp_name);
-       archive_strcat(&temp_name, "XXXXXXXXXX");
-       ep = temp_name.s + archive_strlen(&temp_name);
 
        do {
                char *p;
@@ -469,19 +484,27 @@
                        int d = *((unsigned char *)p) % sizeof(num);
                        *p++ = num[d];
                }
-               fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
+               fd = open(template->s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
                          0600);
        } while (fd < 0 && errno == EEXIST);
        if (fd < 0)
                goto exit_tmpfile;
        __archive_ensure_cloexec_flag(fd);
-       unlink(temp_name.s);
+       if (template == &temp_name)
+               unlink(temp_name.s);
 exit_tmpfile:
-       archive_string_free(&temp_name);
+       if (template == &temp_name)
+               archive_string_free(&temp_name);
        return (fd);
 }
 
 #endif /* HAVE_MKSTEMP */
+
+int
+__archive_mktemp(const char *tmpdir)
+{
+       return __archive_mktempx(tmpdir, NULL);
+}
 #endif /* !_WIN32 || __CYGWIN__ */
 
 /*
diff -r 02d5f22bf566 -r 0f69dfa78b4a external/bsd/libarchive/dist/libarchive/archive_write_disk_posix.c
--- a/external/bsd/libarchive/dist/libarchive/archive_write_disk_posix.c        Sun Jan 12 13:51:12 2020 +0000
+++ b/external/bsd/libarchive/dist/libarchive/archive_write_disk_posix.c        Sun Jan 12 16:08:31 2020 +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. */
@@ -407,6 +409,30 @@
                    size_t, int64_t);
 
 static int
+la_mktemp(struct archive_write_disk *a)
+{
+       int oerrno, fd;
+       mode_t mode;
+
+       archive_string_empty(&a->_tmpname_data);
+       archive_string_sprintf(&a->_tmpname_data, "%sXXXXXX", a->name);
+       a->tmpname = a->_tmpname_data.s;
+
+       fd = __archive_mktempx(NULL, &a->_tmpname_data);
+       if (fd == -1)
+               return -1;
+
+       mode = a->mode & 0777 & ~a->user_umask;
+       if (fchmod(fd, mode) == -1) {
+               oerrno = errno;
+               close(fd);
+               errno = oerrno;
+               return -1;
+       }
+       return fd;
+}
+
+static int
 la_opendirat(int fd, const char *path) {
        const int flags = O_CLOEXEC
 #if defined(O_BINARY)
@@ -1826,6 +1852,14 @@
        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;
+                       }
+                       a->tmpname = NULL;
+               }
        }
        /* If there's an entry, we can release it now. */
        archive_entry_free(a->entry);
@@ -2103,17 +2137,28 @@
                }
 
                if (!S_ISDIR(a->st.st_mode)) {
-                       /* A non-dir is in the way, unlink it. */
                        if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
                                (void)clear_nochange_fflags(a);
-                       if (unlink(a->name) != 0) {
-                               archive_set_error(&a->archive, errno,
-                                   "Can't unlink already-existing object");
-                               return (ARCHIVE_FAILED);
+
+                       if ((a->flags & ARCHIVE_EXTRACT_ATOMIC) &&
+                           S_ISREG(a->st.st_mode)) {
+                               /* Use a temporary file to extract */
+                               if ((a->fd = la_mktemp(a)) == -1)
+                                       return ARCHIVE_FAILED;
+                               a->pst = NULL;
+                               en = 0;
+                       } else {
+                               /* A non-dir is in the way, unlink it. */
+                               if (unlink(a->name) != 0) {
+                                       archive_set_error(&a->archive, errno,
+                                           "Can't unlink already-existing "
+                                           "object");
+                                       return (ARCHIVE_FAILED);
+                               }
+                               a->pst = NULL;
+                               /* Try again. */
+                               en = create_filesystem_object(a);
                        }
-                       a->pst = NULL;
-                       /* Try again. */
-                       en = create_filesystem_object(a);
                } else if (!S_ISDIR(a->mode)) {
                        /* A dir is in the way of a non-dir, rmdir it. */
                        if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
@@ -2288,6 +2333,7 @@
                /* POSIX requires that we fall through here. */
                /* FALLTHROUGH */
        case AE_IFREG:
+               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);
@@ -2449,6 +2495,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;
diff -r 02d5f22bf566 -r 0f69dfa78b4a external/bsd/libarchive/dist/tar/bsdtar.c
--- a/external/bsd/libarchive/dist/tar/bsdtar.c Sun Jan 12 13:51:12 2020 +0000
+++ b/external/bsd/libarchive/dist/tar/bsdtar.c Sun Jan 12 16:08:31 2020 +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. */



Home | Main Index | Thread Index | Old Index