From: Paul Eggert Date: Sun, 23 Nov 2025 17:44:03 +0000 (-0800) Subject: Support gnulib-style timestamps in checkpoint logs X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=HEAD;p=thirdparty%2Ftar.git Support gnulib-style timestamps in checkpoint logs * gnulib.modules: Add nstrftime-limited, time_rz. Sort. * src/checkpoint.c: Include . (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. --- diff --git a/gnulib.modules b/gnulib.modules index 93c88934..fbfc251b 100644 --- a/gnulib.modules +++ b/gnulib.modules @@ -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 diff --git a/src/checkpoint.c b/src/checkpoint.c index 534e0d5b..9bd9fa05 100644 --- a/src/checkpoint.c +++ b/src/checkpoint.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -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;