summaryrefslogtreecommitdiff
path: root/bin/pax
diff options
context:
space:
mode:
authorJeremie Courreges-Anglas <jca@cvs.openbsd.org>2023-12-27 08:29:42 +0000
committerJeremie Courreges-Anglas <jca@cvs.openbsd.org>2023-12-27 08:29:42 +0000
commit2ed490b7e7ec259d02de1b86c809f53312cf8839 (patch)
treedea094303ec899a86bf00a787ffea2e576038fcf /bin/pax
parent9ff3c309e2bf917a369c1654afce35505e1fb553 (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.c68
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)