Support systems with 32-bit long and 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/makeint.h (PRIdMAX, PRIuMAX, SCNdMAX): Define if not already
defined (taken from gnulib).
* 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.
(ar_member_date_1): Use intmax_t to hold the date.
(ar_glob_match): Ditto.
* src/arscan.c (VMS_function, VMS_function_ret, ar_scan)
(parse_int, ar_scan, ar_member_pos, ar_member_touch)
(describe_member): Convert long int to intmax_t.
* 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.
This commit is contained in:
Paul Eggert 2022-10-02 17:24:53 -04:00 committed by Paul Smith
parent 01142a53c9
commit ae80eefe65
6 changed files with 60 additions and 40 deletions

View file

@ -60,5 +60,6 @@ fdl
findprog-in
getloadavg
host-cpu-c-abi
largefile
make-glob
make-macros"

View file

@ -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])

View file

@ -22,6 +22,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "filedef.h"
#include "dep.h"
#include <fnmatch.h>
#include <intprops.h>
/* 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.

View file

@ -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);
@ -885,10 +885,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))
@ -911,7 +911,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)
@ -935,10 +935,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
@ -962,18 +963,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;

View file

@ -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

View file

@ -294,6 +294,21 @@ char *strerror (int errnum);
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#if defined _MSC_VER || defined __MINGW32__
# define MK_PRI64_PREFIX "I64"
#else
# define MK_PRI64_PREFIX "ll"
#endif
#ifndef PRIdMAX
# define PRIdMAX MK_PRI64_PREFIX "d"
#endif
#ifndef PRIuMAX
# define PRIuMAX MK_PRI64_PREFIX "u"
#endif
#ifndef SCNdMAX
# define SCNdMAX PRIdMAX
#endif
#define FILE_TIMESTAMP uintmax_t
#if !defined(HAVE_STRSIGNAL)
@ -570,13 +585,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);