diff options
author | Jeremie Courreges-Anglas <jca@cvs.openbsd.org> | 2023-12-27 08:29:42 +0000 |
---|---|---|
committer | Jeremie Courreges-Anglas <jca@cvs.openbsd.org> | 2023-12-27 08:29:42 +0000 |
commit | 2ed490b7e7ec259d02de1b86c809f53312cf8839 (patch) | |
tree | dea094303ec899a86bf00a787ffea2e576038fcf /bin/pax | |
parent | 9ff3c309e2bf917a369c1654afce35505e1fb553 (diff) |
'pax' format support for mtime and atime
Access time can't be represented by ustar, so always include it when
using the pax format. Also include an extended header record for mtime
if the file modification time can't be fully represented by ustar (eg
subsecond resolution).
Input & ok millert@
Diffstat (limited to 'bin/pax')
-rw-r--r-- | bin/pax/tar.c | 68 |
1 files changed, 64 insertions, 4 deletions
diff --git a/bin/pax/tar.c b/bin/pax/tar.c index a41a6d4d0a0..949e9ce4ec1 100644 --- a/bin/pax/tar.c +++ b/bin/pax/tar.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tar.c,v 1.77 2023/12/22 20:32:29 jca Exp $ */ +/* $OpenBSD: tar.c,v 1.78 2023/12/27 08:29:41 jca Exp $ */ /* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */ /*- @@ -978,6 +978,39 @@ xheader_add_ull(struct xheader *xhdr, const char *keyword, return 0; } +static int +xheader_add_ts(struct xheader *xhdr, const char *keyword, + const struct timespec *value) +{ + struct xheader_record *rec; + int reclen, tmplen; + char *s; + + tmplen = MINXHDRSZ; + do { + reclen = tmplen; + tmplen = snprintf(NULL, 0, "%d %s=%lld.%09ld\n", reclen, + keyword, (long long)value->tv_sec, (long)value->tv_nsec); + } while (tmplen >= 0 && tmplen != reclen); + if (tmplen < 0) + return -1; + + rec = calloc(1, sizeof(*rec)); + if (rec == NULL) + return -1; + rec->reclen = reclen; + if (asprintf(&s, "%d %s=%lld.%09ld\n", reclen, keyword, + (long long)value->tv_sec, (long)value->tv_nsec) < 0) { + free(rec); + return -1; + } + rec->record = s; + + SLIST_INSERT_HEAD(xhdr, rec, entry); + + return 0; +} + static void xheader_free(struct xheader *xhdr) { @@ -1060,6 +1093,7 @@ wr_ustar_or_pax(ARCHD *arcn, int ustar) #ifndef SMALL struct xheader xhdr = SLIST_HEAD_INITIALIZER(xhdr); #endif + int bad_mtime; /* * check for those file system types ustar cannot store @@ -1249,9 +1283,35 @@ wr_ustar_or_pax(ARCHD *arcn, int ustar) if (ul_oct(gid_nobody, hd->gid, sizeof(hd->gid), 3)) goto out; } - if (ull_oct(arcn->sb.st_mtime < 0 ? 0 : arcn->sb.st_mtime, hd->mtime, - sizeof(hd->mtime), 3) || - ul_oct(arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3)) + bad_mtime = ull_oct(arcn->sb.st_mtime < 0 ? 0 : arcn->sb.st_mtime, + hd->mtime, sizeof(hd->mtime), 3); + if (bad_mtime && ustar) + goto out; +#ifndef SMALL + if (!ustar) { + /* + * The pax format can preserve atime and store + * a possibly more accurate mtime. + * + * ctime isn't specified by POSIX so omit it. + */ + if (xheader_add_ts(&xhdr, "atime", &arcn->sb.st_atim) == -1) { + paxwarn(1, "Couldn't preserve %s in pax format for %s", + "atime", arcn->org_name); + xheader_free(&xhdr); + return (1); + } + if ((bad_mtime || arcn->sb.st_mtime < 0 || + arcn->sb.st_mtim.tv_nsec != 0) && + xheader_add_ts(&xhdr, "mtime", &arcn->sb.st_mtim) == -1) { + paxwarn(1, "Couldn't preserve %s in pax format for %s", + "mtime", arcn->org_name); + xheader_free(&xhdr); + return (1); + } + } +#endif + if (ul_oct(arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3)) goto out; if (!Nflag) { if ((name = user_from_uid(arcn->sb.st_uid, 1)) != NULL) |