From d6b8ac5e3051f863463df5ff03c295df984245cc Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 20 Sep 2022 14:18:00 -0700 Subject: [PATCH] Port to 32-bit long + 64-bit time_t Don't assume that time_t fits in long, as some hosts (e.g., glibc x86 -D_TIME_BITS=64) have 32-bit long and 64-bit time_t. * bootstrap.conf (gnulib_modules): Add largefile, to support files with timestamps after Y2038 on hosts with 32-bit long. * configure.ac: Do not call AC_SYS_LARGEFILE, as the largefile module does that for us. * src/ar.c: Include intprops.h, for TYPE_MAXIMUM, as INTEGER_TYPE_MAXIMUM does not work on time_t without issuing a bunch of warnings. (ar_member_date): Check that result is in time_t range. * src/ar.c (ar_member_date, ar_glob_match): * src/arscan.c (VMS_function, VMS_function_ret, ar_scan) (parse_int, ar_scan, ar_member_pos, ar_member_touch) (describe_member): * src/file.c (file_timestamp_sprintf): Use intmax_t/uintmax_t instead of long/unsigned long for values that might be time_t. * src/arscan.c (ar_member_touch): Fix buffer overrun if the timestamp is too large. * src/makeint.h (PRIdMAX, PRIuMAX, SCNdMAX): Define if not already defined, via an intermediate _PRI64_PREFIX macro, taken from Gnulib. (This would not be needed if 'make' used Gnulib's inttypes module.) --- bootstrap.conf | 1 + configure.ac | 5 ----- src/ar.c | 15 ++++++++------- src/arscan.c | 44 ++++++++++++++++++++++++-------------------- src/file.c | 13 ++++++++----- src/makeint.h | 21 ++++++++++++++++++--- 6 files changed, 59 insertions(+), 40 deletions(-) diff --git a/bootstrap.conf b/bootstrap.conf index b1ee947d..1dc096db 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -60,5 +60,6 @@ fdl findprog-in getloadavg host-cpu-c-abi +largefile make-glob make-macros" diff --git a/configure.ac b/configure.ac index e08e75ad..11e9ed12 100644 --- a/configure.ac +++ b/configure.ac @@ -57,11 +57,6 @@ AC_C_BIGENDIAN AM_GNU_GETTEXT_VERSION([0.19.4]) AM_GNU_GETTEXT([external]) -# This test must come as early as possible after the compiler configuration -# tests, because the choice of the file model can (in principle) affect -# whether functions and headers are available, whether they work, etc. -AC_SYS_LARGEFILE - # Checks for libraries. AC_SEARCH_LIBS([strerror],[cposix]) AC_SEARCH_LIBS([getpwnam], [sun]) diff --git a/src/ar.c b/src/ar.c index 7a26662c..48ef5e44 100644 --- a/src/ar.c +++ b/src/ar.c @@ -22,6 +22,7 @@ this program. If not, see . */ #include "filedef.h" #include "dep.h" #include +#include /* Return nonzero if NAME is an archive-member reference, zero if not. An archive-member reference is a name like 'lib(member)' where member is a @@ -69,10 +70,10 @@ ar_parse_name (const char *name, char **arname_p, char **memname_p) /* This function is called by 'ar_scan' to find which member to look at. */ /* ARGSUSED */ -static long int +static intmax_t ar_member_date_1 (int desc UNUSED, const char *mem, int truncated, long int hdrpos UNUSED, long int datapos UNUSED, - long int size UNUSED, long int date, + long int size UNUSED, intmax_t date, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *name) { @@ -86,7 +87,7 @@ ar_member_date (const char *name) { char *arname; char *memname; - long int val; + intmax_t val; ar_parse_name (name, &arname, &memname); @@ -111,7 +112,7 @@ ar_member_date (const char *name) free (arname); - return (val <= 0 ? (time_t) -1 : (time_t) val); + return 0 < val && val <= TYPE_MAXIMUM (time_t) ? val : -1; } /* Set the archive-member NAME's modtime to now. */ @@ -194,10 +195,10 @@ struct ar_glob_state /* This function is called by 'ar_scan' to match one archive element against the pattern in STATE. */ -static long int +static intmax_t ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, long int hdrpos UNUSED, long int datapos UNUSED, - long int size UNUSED, long int date UNUSED, int uid UNUSED, + long int size UNUSED, intmax_t date UNUSED, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *arg) { struct ar_glob_state *state = (struct ar_glob_state *)arg; @@ -218,7 +219,7 @@ ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, ++state->n; } - return 0L; + return 0; } /* Return nonzero if PATTERN contains any metacharacters. diff --git a/src/arscan.c b/src/arscan.c index f22d21aa..49c52da4 100644 --- a/src/arscan.c +++ b/src/arscan.c @@ -75,9 +75,9 @@ static void *VMS_lib_idx; static const void *VMS_saved_arg; -static long int (*VMS_function) (); +static intmax_t (*VMS_function) (); -static long int VMS_function_ret; +static intmax_t VMS_function_ret; /* This is a callback procedure for lib$get_index */ @@ -203,7 +203,7 @@ VMS_get_member_info(struct dsc$descriptor_s *module, unsigned long *rfa) Returns -2 if archive has invalid format. Returns 0 if have scanned successfully. */ -long int +intmax_t ar_scan (const char *archive, ar_member_func_t function, const void *varg) { char *vms_archive; @@ -379,13 +379,13 @@ struct ar_hdr #include "output.h" -static unsigned long int +static uintmax_t parse_int (const char *ptr, const size_t len, const int base, const char *type, const char *archive, const char *name) { const char *const ep = ptr + len; const char max = '0' + base - 1; - long int val = 0; + uintmax_t val = 0; /* In all the versions I know of the spaces come last, but be safe. */ while (ptr < ep && *ptr == ' ') @@ -430,7 +430,7 @@ parse_int (const char *ptr, const size_t len, const int base, Returns -2 if archive has invalid format. Returns 0 if have scanned successfully. */ -long int +intmax_t ar_scan (const char *archive, ar_member_func_t function, const void *arg) { #ifdef AIAMAG @@ -550,7 +550,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) # define ARNAME_MAX 255 char name[ARNAME_MAX + 1]; int name_len; - long int dateval; + intmax_t dateval; int uidval, gidval; long int data_offset; #else @@ -562,7 +562,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) #endif long int eltsize; unsigned int eltmode; - long int fnval; + intmax_t fnval; off_t o; memset(&member_header, '\0', sizeof (member_header)); @@ -593,7 +593,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) name[name_len] = '\0'; - sscanf (member_header_big.ar_date, "%12ld", &dateval); + sscanf (member_header_big.ar_date, "%12"SCNdMAX, &dateval); sscanf (member_header_big.ar_uid, "%12d", &uidval); sscanf (member_header_big.ar_gid, "%12d", &gidval); sscanf (member_header_big.ar_mode, "%12o", &eltmode); @@ -621,7 +621,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) name[name_len] = '\0'; - sscanf (member_header.ar_date, "%12ld", &dateval); + sscanf (member_header.ar_date, "%12"SCNdMAX, &dateval); sscanf (member_header.ar_uid, "%12d", &uidval); sscanf (member_header.ar_gid, "%12d", &gidval); sscanf (member_header.ar_mode, "%12o", &eltmode); @@ -887,10 +887,10 @@ ar_name_equal (const char *name, const char *mem, int truncated) #ifndef VMS /* ARGSUSED */ -static long int +static intmax_t ar_member_pos (int desc UNUSED, const char *mem, int truncated, long int hdrpos, long int datapos UNUSED, long int size UNUSED, - long int date UNUSED, int uid UNUSED, int gid UNUSED, + intmax_t date UNUSED, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, const void *name) { if (!ar_name_equal (name, mem, truncated)) @@ -913,7 +913,7 @@ ar_member_touch (const char *arname, const char *memname) struct ar_hdr ar_hdr; off_t o; int r; - unsigned int ui; + int datelen; struct stat statbuf; if (pos < 0) @@ -937,10 +937,11 @@ ar_member_touch (const char *arname, const char *memname) goto lose; /* Advance member's time to that time */ #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32) - for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++) - ar_hdr.ar_date[ui] = ' '; - sprintf (TOCHAR (ar_hdr.ar_date), "%lu", (long unsigned) statbuf.st_mtime); - ar_hdr.ar_date[strlen ((char *) ar_hdr.ar_date)] = ' '; + datelen = snprintf (TOCHAR (ar_hdr.ar_date), sizeof ar_hdr.ar_date, + "%"PRIdMAX, (intmax_t) statbuf.st_mtime); + if (! (0 <= datelen && datelen < (int) sizeof ar_hdr.ar_date)) + goto lose; + memset (ar_hdr.ar_date + datelen, ' ', sizeof ar_hdr.ar_date - datelen); #else ar_hdr.ar_date = statbuf.st_mtime; #endif @@ -964,18 +965,21 @@ ar_member_touch (const char *arname, const char *memname) #ifdef TEST -long int +intmax_t describe_member (int desc, const char *name, int truncated, long int hdrpos, long int datapos, long int size, - long int date, int uid, int gid, unsigned int mode, + intmax_t date, int uid, int gid, unsigned int mode, const void *arg) { extern char *ctime (); + time_t d = date; + char const *ds; printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"), name, truncated ? _(" (name might be truncated)") : "", size, hdrpos, datapos); - printf (_(" Date %s"), ctime (&date)); + ds = ctime (&d); + printf (_(" Date %s"), ds ? ds : "?"); printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode); return 0; diff --git a/src/file.c b/src/file.c index 6b7c52a2..581fb42a 100644 --- a/src/file.c +++ b/src/file.c @@ -1018,13 +1018,16 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts) struct tm *tm = localtime (&t); if (tm) - sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + { + intmax_t year = tm->tm_year; + sprintf (p, "%04"PRIdMAX"-%02d-%02d %02d:%02d:%02d", + year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + } else if (t < 0) - sprintf (p, "%ld", (long) t); + sprintf (p, "%"PRIdMAX, (intmax_t) t); else - sprintf (p, "%lu", (unsigned long) t); + sprintf (p, "%"PRIuMAX, (uintmax_t) t); p += strlen (p); /* Append nanoseconds as a fraction, but remove trailing zeros. We don't diff --git a/src/makeint.h b/src/makeint.h index d941ff3d..e7c6fbf4 100644 --- a/src/makeint.h +++ b/src/makeint.h @@ -294,6 +294,20 @@ char *strerror (int errnum); #if HAVE_STDINT_H # include #endif +#if defined _MSC_VER || defined __MINGW32__ +# define _PRI64_PREFIX "I64" +#else +# define _PRI64_PREFIX "ll" +#endif +#ifndef PRIdMAX +# define PRIdMAX _PRI64_PREFIX "d" +#endif +#ifndef PRIuMAX +# define PRIuMAX _PRI64_PREFIX "u" +#endif +#ifndef SCNdMAX +# define SCNdMAX PRIdMAX +#endif #define FILE_TIMESTAMP uintmax_t #if !defined(HAVE_STRSIGNAL) @@ -566,13 +580,14 @@ void ar_parse_name (const char *, char **, char **); int ar_touch (const char *); time_t ar_member_date (const char *); -typedef long int (*ar_member_func_t) (int desc, const char *mem, int truncated, +typedef intmax_t (*ar_member_func_t) (int desc, const char *mem, int truncated, long int hdrpos, long int datapos, - long int size, long int date, int uid, + long int size, intmax_t date, int uid, int gid, unsigned int mode, const void *arg); -long int ar_scan (const char *archive, ar_member_func_t function, const void *arg); +intmax_t ar_scan (const char *archive, ar_member_func_t function, + const void *arg); int ar_name_equal (const char *name, const char *mem, int truncated); #ifndef VMS int ar_member_touch (const char *arname, const char *memname); -- 2.37.3