[PATCH] stat: fix negative %X/%Y/%Z timestamps after Y2038 on 32-bit builds
Benjamin Robin via busybox <[email protected]>
| Newsgroups | gmane.linux.busybox |
|---|---|
| Message-ID | <20260822-fix-stat-seconds-since-epoch-v1-1-8446c0e92abe@bootlin.com> |
Introduce a utility function to always print `time_t` values using either `long long` or `unsigned long long`, depending on whether `time_t` is signed. This fixes the bug reported in [1]. Previously, `time_t` values were cast to `long`, which is a 32-bit value on 32-bit builds. [1]: https://lists.busybox.net/pipermail/busybox/2026-August/092413.html Signed-off-by: Benjamin Robin <[email protected]> --- coreutils/stat.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/coreutils/stat.c b/coreutils/stat.c index 2c2909e7e45b..e504ab1ab7f2 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -303,12 +303,25 @@ static void FAST_FUNC print_statfs(char *pformat, const char m, } #endif +static void FAST_FUNC print_time_t(char *pformat, time_t val) +{ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + + if (TYPE_SIGNED(time_t)) { + strcat(pformat, "lld"); + printf(pformat, (long long) val); + } + else { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) val); + } +} + /* print stat info */ static void FAST_FUNC print_stat(char *pformat, const char m, const char *const filename, const void *data IF_SELINUX(, security_context_t scontext)) { -#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) struct stat *statbuf = (struct stat *) data; struct passwd *pw_ent; struct group *gw_ent; @@ -382,20 +395,15 @@ static void FAST_FUNC print_stat(char *pformat, const char m, } else if (m == 'x') { printfs(pformat, human_time(&statbuf->st_atim)); } else if (m == 'X') { - strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu"); - /* note: (unsigned long) would be wrong: - * imagine (unsigned long64)int32 */ - printf(pformat, (long) statbuf->st_atime); + print_time_t(pformat, statbuf->st_atime); } else if (m == 'y') { printfs(pformat, human_time(&statbuf->st_mtim)); } else if (m == 'Y') { - strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu"); - printf(pformat, (long) statbuf->st_mtime); + print_time_t(pformat, statbuf->st_mtime); } else if (m == 'z') { printfs(pformat, human_time(&statbuf->st_ctim)); } else if (m == 'Z') { - strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu"); - printf(pformat, (long) statbuf->st_ctime); + print_time_t(pformat, statbuf->st_ctime); # if ENABLE_SELINUX } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) { printfs(pformat, scontext); --- base-commit: 7473045ad3504db9b421427a452fd9b146346306 change-id: 20260822-fix-stat-seconds-since-epoch-b80c5eb17371 Best regards, -- Benjamin Robin <[email protected]>