]> git.ipfire.org Git - thirdparty/tar.git/commitdiff
Support gnulib-style timestamps in checkpoint logs master
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 23 Nov 2025 17:44:03 +0000 (09:44 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sun, 23 Nov 2025 17:51:31 +0000 (09:51 -0800)
* gnulib.modules: Add nstrftime-limited, time_rz.  Sort.
* src/checkpoint.c: Include <strftime.h>.
(format_checkpoint_string): Use nstrftime instead of strftime.
Also fix an obscure bug on platforms that lack tm_gmtoff+tm_zone by
calling tzalloc on those platforms; if it fails, fall back on gmtime.
Also, use fwrite instead of fprintf, since we typically know the
length already and this gives us a more-accurate byte count
in case there are partial writes.

gnulib.modules
src/checkpoint.c

index 93c88934e37cf5736e52d97aabdcba5267ef6d4c..fbfc251b1c7d7cfa0557a51663122c3a8635ea81 100644 (file)
@@ -37,8 +37,8 @@ dup2
 errno-h
 error
 exclude
-extern-inline
 exitfail
+extern-inline
 faccessat
 fchmodat
 fchownat
@@ -52,6 +52,7 @@ fnmatch-gnu
 free-posix
 fseeko
 fstatat
+full-read
 full-write
 futimens
 gendocs
@@ -81,6 +82,7 @@ mkdirat
 mkdtemp
 mkfifoat
 modechange
+nstrftime-limited
 obstack
 openat
 openat2
@@ -94,7 +96,6 @@ reallocarray
 renameat
 root-uid
 rpmatch
-full-read
 safe-read
 same-inode
 savedir
@@ -105,22 +106,23 @@ std-gnu23
 stdcountof-h
 stddef-h
 stdint-h
-stpcpy
 stdopen
+stpcpy
 strdup-posix
 strerror
 stringeq
 strnlen
 symlinkat
 sys_stat-h
+time_rz
 timespec
 timespec-sub
 unlinkat
 unlinkdir
 unlocked-io
 utimensat
-version-etc-fsf
 verror
+version-etc-fsf
 xalignalloc
 xalloc
 xalloc-die
index 534e0d5b3e71ba5cb6a09dc64e51a6c37a0baef7..9bd9fa055c1fb928633891d4e97797bd1468e1e6 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <wordsplit.h>
 #include <flexmember.h>
+#include <strftime.h>
 
 #include <sys/ioctl.h>
 #include <termios.h>
@@ -306,22 +307,41 @@ format_checkpoint_string (FILE *fp, intmax_t len,
              {
                struct timespec ts = current_timespec ();
                struct tm *tm = localtime (&ts.tv_sec);
-               char const *tmstr = NULL;
 
+#if HAVE_STRUCT_TM_TM_GMTOFF && HAVE_STRUCT_TM_TM_ZONE
+               /* struct tm has POSIX.1-2024 tm_gmtoff and tm_zone,
+                  so nstrftime ignores tz and any tz value will do.  */
+               timezone_t tz = 0;
+#else
+               static timezone_t tz;
+               if (tm && !tz)
+                 {
+                   tz = tzalloc (getenv ("TZ"));
+                   if (!tz)
+                     tm = NULL;
+                 }
+#endif
                /* Keep BUF relatively small, as any text timestamp
                   not fitting into BUF is likely a DoS attack.  */
-               char buf[max (SYSINT_BUFSIZE, 256)];
-
-               if (tm)
+               char buf[max (TIMESPEC_STRSIZE_BOUND, 256)];
+               ptrdiff_t buflen =
+                 (tm
+                  ? nstrftime (buf, sizeof buf, arg ? arg : "%c",
+                               tm, tz, ts.tv_nsec)
+                  : -1);
+               char const *tmstr;
+               idx_t tmstrlen;
+               if (buflen < 0)
+                 {
+                   tmstr = code_timespec (ts, buf);
+                   tmstrlen = strlen (tmstr);
+                 }
+               else
                  {
-                   buf[0] = '\0';
-                   char const *fmt = arg ? arg : "%c";
-                   if (strftime (buf, sizeof buf, fmt, tm) != 0 || !buf[0])
-                     tmstr = buf;
+                   tmstr = buf;
+                   tmstrlen = buflen;
                  }
-               if (!tmstr)
-                 tmstr = timetostr (ts.tv_sec, buf);
-               len = add_printf (len, fprintf (fp, "%s", tmstr));
+               len = add_printf (len, fwrite (tmstr, 1, tmstrlen, stdout));
              }
              break;