--- tar.c | 69 +++++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/tar.c b/tar.c index de58247..e8dd26a 100644 --- a/tar.c +++ b/tar.c _AT_@ -48,12 +48,12 @@ struct header { char prefix[155]; }; -static struct ent { +static struct dirtime { char *name; time_t mtime; -} *ents; +} *dirtimes; -static size_t entslen; +static size_t dirtimeslen; static int tarfd; static ino_t tarinode; _AT_@ -72,20 +72,20 @@ static const char *filtertools[] = { }; static void -pushent(char *name, time_t mtime) +pushdirtime(char *name, time_t mtime) { - ents = reallocarray(ents, entslen + 1, sizeof(*ents)); - ents[entslen].name = strdup(name); - ents[entslen].mtime = mtime; - entslen++; + dirtimes = reallocarray(dirtimes, dirtimeslen + 1, sizeof(*dirtimes)); + dirtimes[dirtimeslen].name = strdup(name); + dirtimes[dirtimeslen].mtime = mtime; + dirtimeslen++; } -static struct ent * -popent(void) +static struct dirtime * +popdirtime(void) { - if (entslen) { - entslen--; - return &ents[entslen]; + if (dirtimeslen) { + dirtimeslen--; + return &dirtimes[dirtimeslen]; } return NULL; } _AT_@ -254,6 +254,7 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ]) long mode, major, minor, type, mtime, uid, gid; struct header *h = (struct header *)b; int fd = -1; + struct timespec times[2]; if (!mflag && ((mtime = strtol(h->mtime, &p, 8)) < 0 || *p != '\0')) eprintf("strtol %s: invalid number\n", h->mtime); _AT_@ -273,8 +274,6 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ]) fd = open(fname, O_WRONLY | O_TRUNC | O_CREAT, 0600); if (fd < 0) eprintf("open %s:", fname); - if (fchmod(fd, mode) < 0) - eprintf("fchmod %s:", fname); break; case HARDLINK: case SYMLINK: _AT_@ -290,6 +289,7 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ]) eprintf("strtol %s: invalid number\n", h->mode); if (mkdir(fname, (mode_t)mode) < 0 && errno != EEXIST) eprintf("mkdir %s:", fname); + pushdirtime(fname, mtime); break; case CHARDEV: case BLOCKDEV: _AT_@ -317,8 +317,6 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ]) eprintf("strtol %s: invalid number\n", h->uid); if ((gid = strtol(h->gid, &p, 8)) < 0 || *p != '\0') eprintf("strtol %s: invalid number\n", h->gid); - if (!getuid() && chown(fname, uid, gid)) - weprintf("chown %s:", fname); if (fd != -1) { for (; l > 0; l -= BLKSIZ) _AT_@ -327,7 +325,20 @@ unarchive(char *fname, ssize_t l, char b[BLKSIZ]) close(fd); } - pushent(fname, mtime); + times[0].tv_sec = times[1].tv_sec = mtime; + times[0].tv_nsec = times[1].tv_nsec = 0; + if (!mflag && utimensat(AT_FDCWD, fname, times, AT_SYMLINK_NOFOLLOW) < 0) + weprintf("utimensat %s:\n", fname); + if (h->type == SYMLINK) { + if (!getuid() && lchown(fname, uid, gid)) + weprintf("lchown %s:\n", fname); + } else { + if (!getuid() && chown(fname, uid, gid)) + weprintf("chown %s:\n", fname); + if (chmod(fname, mode) < 0) + eprintf("fchmod %s:\n", fname); + } + return 0; } _AT_@ -420,9 +431,9 @@ static void xt(int argc, char *argv[], int mode) { char b[BLKSIZ], fname[256 + 1], *p; - struct timeval times[2]; + struct timespec times[2]; struct header *h = (struct header *)b; - struct ent *ent; + struct dirtime *dirtime; long size; int i, n; int (*fn)(char *, ssize_t, char[BLKSIZ]) = (mode == 'x') ? unarchive : print; _AT_@ -463,16 +474,16 @@ xt(int argc, char *argv[], int mode) puts(fname); } - if (!mflag) { - while ((ent = popent())) { - times[0].tv_sec = times[1].tv_sec = ent->mtime; - times[0].tv_usec = times[1].tv_usec = 0; - if (utimes(ent->name, times) < 0) - weprintf("utimes %s:", ent->name); - free(ent->name); + if (mode == 'x' && !mflag) { + while ((dirtime = popdirtime())) { + times[0].tv_sec = times[1].tv_sec = dirtime->mtime; + times[0].tv_nsec = times[1].tv_nsec = 0; + if (utimensat(AT_FDCWD, dirtime->name, times, 0) < 0) + eprintf("utimensat %s:", fname); + free(dirtime->name); } - free(ents); - ents = NULL; + free(dirtimes); + dirtimes = NULL; } } -- 2.3.6 --PEIAKu/WMn1b1Hv9--Received on Mon Sep 17 2001 - 00:00:00 CEST
This archive was generated by hypermail 2.3.0 : Thu Nov 19 2015 - 09:36:10 CET