From 21ebff3b800aa4adefa676c07d0b1affe6b4aa02 Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Fri, 14 May 2010 10:23:59 -0400 Subject: [PATCH] Fix a return-value mixup when time restore failed. Restore ACLs after restoring time. (NFS4 ACLs can prohibit the owner from setting time on a file.) SVN-Revision: 2401 --- libarchive/archive_write_disk.c | 37 +++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/libarchive/archive_write_disk.c b/libarchive/archive_write_disk.c index 047a5184a..cdfcef611 100644 --- a/libarchive/archive_write_disk.c +++ b/libarchive/archive_write_disk.c @@ -255,7 +255,7 @@ static int set_fflags_platform(struct archive_write_disk *, int fd, static int set_ownership(struct archive_write_disk *); static int set_mode(struct archive_write_disk *, int mode); static int set_time(int, int, const char *, time_t, long, time_t, long); -static int set_times(int, int, const char *, +static int set_times(struct archive_write_disk *, int, int, const char *, time_t, long, time_t, long, time_t, long); static int set_times_from_entry(struct archive_write_disk *); static struct fixup_entry *sort_dir_list(struct fixup_entry *p); @@ -812,10 +812,6 @@ _archive_write_disk_finish_entry(struct archive *_a) int r2 = set_mode(a, a->mode); if (r2 < ret) ret = r2; } - if (a->todo & TODO_ACLS) { - int r2 = set_acls(a); - if (r2 < ret) ret = r2; - } /* * Security-related extended attributes (such as @@ -844,6 +840,15 @@ _archive_write_disk_finish_entry(struct archive *_a) if (r2 < ret) ret = r2; } + /* + * ACLs must be restored after timestamps because there are + * ACLs that prevent attribute changes (including time). + */ + if (a->todo & TODO_ACLS) { + int r2 = set_acls(a); + if (r2 < ret) ret = r2; + } + /* If there's an fd, we can close it now. */ if (a->fd >= 0) { close(a->fd); @@ -1322,7 +1327,7 @@ _archive_write_disk_close(struct archive *_a) while (p != NULL) { a->pst = NULL; /* Mark stat cache as out-of-date. */ if (p->fixup & TODO_TIMES) { - set_times(-1, p->mode, p->name, + set_times(a, -1, p->mode, p->name, p->atime, p->atime_nanos, p->birthtime, p->birthtime_nanos, p->mtime, p->mtime_nanos); @@ -1893,7 +1898,9 @@ set_ownership(struct archive_write_disk *a) return (ARCHIVE_WARN); } - +/* + * Note: Returns 0 on success, non-zero on failure. + */ static int set_time(int fd, int mode, const char *name, time_t atime, long atime_nsec, @@ -1973,12 +1980,15 @@ set_time(int fd, int mode, const char *name, } static int -set_times(int fd, int mode, const char *name, +set_times(struct archive_write_disk *a, + int fd, int mode, const char *name, time_t atime, long atime_nanos, time_t birthtime, long birthtime_nanos, time_t mtime, long mtime_nanos) { - int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK; + /* Note: set_time doesn't use libarchive return conventions! + * It uses syscall conventions. So 0 here instead of ARCHIVE_OK. */ + int r1 = 0, r2 = 0; #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME /* @@ -1998,7 +2008,12 @@ set_times(int fd, int mode, const char *name, r2 = set_time(fd, mode, name, atime, atime_nanos, mtime, mtime_nanos); - return (r1 < r2) ? r1 : r2; + if (r1 != 0 || r2 != 0) { + archive_set_error(&a->archive, errno, + "Can't restore time"); + return (ARCHIVE_WARN); + } + return (ARCHIVE_OK); } static int @@ -2032,7 +2047,7 @@ set_times_from_entry(struct archive_write_disk *a) mtime_nsec = archive_entry_mtime_nsec(a->entry); } - return set_times(a->fd, a->mode, a->name, + return set_times(a, a->fd, a->mode, a->name, atime, atime_nsec, birthtime, birthtime_nsec, mtime, mtime_nsec); -- 2.47.3