mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
common: New functions timegm_u64, isotime2epoch_u64.
* common/mischelp.c (timegm): Move to ... * common/gettime.c (timegm): here. On Windows use timegm_u32. (timegm_u32): New. (isotime2epoch): Factor code out to ... (isotime_make_tm): new helper. (isotime2epoch_u64): New. (_win32_timegm): Remove duplicated code. (parse_timestamp): Use of timegm. (scan_isodatestr): Fallback to isotime2epoch_u64. -- This mainly helps on 32 bit Windows. For Unix we assume everyone is using 64 bit or shall wait until the libc hackers finally provide a time64_t. GnuPG-bug-id: 6736
This commit is contained in:
parent
2c3c049fd8
commit
164c687cb6
239
common/gettime.c
239
common/gettime.c
@ -37,6 +37,10 @@
|
|||||||
#ifdef HAVE_LANGINFO_H
|
#ifdef HAVE_LANGINFO_H
|
||||||
#include <langinfo.h>
|
#include <langinfo.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
#endif /*!HAVE_W32_SYSTEM*/
|
||||||
#include <stdint.h> /* We use uint64_t. */
|
#include <stdint.h> /* We use uint64_t. */
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -62,6 +66,111 @@ static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
|
|||||||
#define JD_DIFF 1721060L
|
#define JD_DIFF 1721060L
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
timegm() is a GNU function that might not be available everywhere.
|
||||||
|
It's basically the inverse of gmtime() - you give it a struct tm,
|
||||||
|
and get back a time_t. It differs from mktime() in that it handles
|
||||||
|
the case where the struct tm is UTC and the local environment isn't.
|
||||||
|
|
||||||
|
Note, that this replacement implementation might not be thread-safe!
|
||||||
|
|
||||||
|
Some BSDs don't handle the putenv("foo") case properly, so we use
|
||||||
|
unsetenv if the platform has it to remove environment variables.
|
||||||
|
*/
|
||||||
|
#ifndef HAVE_TIMEGM
|
||||||
|
time_t
|
||||||
|
timegm (struct tm *tm)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
uint64_t val = timegm_u64 (tm);
|
||||||
|
if (val == (uint64_t)(-1))
|
||||||
|
return (time_t)(-1);
|
||||||
|
return (time_t)val;
|
||||||
|
#else /* (Non thread safe implementation!) */
|
||||||
|
|
||||||
|
time_t answer;
|
||||||
|
char *zone;
|
||||||
|
|
||||||
|
zone=getenv("TZ");
|
||||||
|
putenv("TZ=UTC");
|
||||||
|
tzset();
|
||||||
|
answer=mktime(tm);
|
||||||
|
if(zone)
|
||||||
|
{
|
||||||
|
static char *old_zone;
|
||||||
|
|
||||||
|
if (!old_zone)
|
||||||
|
{
|
||||||
|
old_zone = malloc(3+strlen(zone)+1);
|
||||||
|
if (old_zone)
|
||||||
|
{
|
||||||
|
strcpy(old_zone,"TZ=");
|
||||||
|
strcat(old_zone,zone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (old_zone)
|
||||||
|
putenv (old_zone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gnupg_unsetenv("TZ");
|
||||||
|
|
||||||
|
tzset();
|
||||||
|
return answer;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif /*!HAVE_TIMEGM*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Version of the GNU timegm which returns an unsigned 64 bit integer
|
||||||
|
* instead of the usually signed time_t. On error (uint64_t)(-1) is
|
||||||
|
* returned. This function is mostly here becuase on 32 bit Windows
|
||||||
|
* we have an internal API to get the system time even after
|
||||||
|
* 2023-01-19. For 32 bit Unix we need to suffer from the too short
|
||||||
|
* time_t and no system function to construct the time from a tm. */
|
||||||
|
uint64_t
|
||||||
|
timegm_u64 (struct tm *tm)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_W32_SYSTEM
|
||||||
|
/* This one is thread safe. */
|
||||||
|
SYSTEMTIME st;
|
||||||
|
FILETIME ft;
|
||||||
|
unsigned long long cnsecs;
|
||||||
|
|
||||||
|
st.wYear = tm->tm_year + 1900;
|
||||||
|
st.wMonth = tm->tm_mon + 1;
|
||||||
|
st.wDay = tm->tm_mday;
|
||||||
|
st.wHour = tm->tm_hour;
|
||||||
|
st.wMinute = tm->tm_min;
|
||||||
|
st.wSecond = tm->tm_sec;
|
||||||
|
st.wMilliseconds = 0; /* Not available. */
|
||||||
|
st.wDayOfWeek = 0; /* Ignored. */
|
||||||
|
|
||||||
|
/* System time is UTC thus the conversion is pretty easy. */
|
||||||
|
if (!SystemTimeToFileTime (&st, &ft))
|
||||||
|
{
|
||||||
|
gpg_err_set_errno (EINVAL);
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
||||||
|
| ft.dwLowDateTime);
|
||||||
|
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
||||||
|
return (uint64_t)(cnsecs / 10000000ULL);
|
||||||
|
|
||||||
|
#else /*Unix*/
|
||||||
|
|
||||||
|
time_t t = timegm (tm);
|
||||||
|
if (t == (time_t)(-1))
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
if ((int64_t)t < 0)
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
return (uint64_t)t;
|
||||||
|
|
||||||
|
#endif /*Unix*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Wrapper for the time(3). We use this here so we can fake the time
|
/* Wrapper for the time(3). We use this here so we can fake the time
|
||||||
for tests */
|
for tests */
|
||||||
time_t
|
time_t
|
||||||
@ -231,7 +340,21 @@ scan_isodatestr( const char *string )
|
|||||||
tmbuf.tm_isdst = -1;
|
tmbuf.tm_isdst = -1;
|
||||||
stamp = mktime( &tmbuf );
|
stamp = mktime( &tmbuf );
|
||||||
if( stamp == (time_t)-1 )
|
if( stamp == (time_t)-1 )
|
||||||
return 0;
|
{
|
||||||
|
/* mktime did not work. Construct an ISO timestring for noon
|
||||||
|
* of the given day instead. We keep the use of mktime for 64
|
||||||
|
* bit system to limit the risk of regressions. */
|
||||||
|
gnupg_isotime_t isobuf;
|
||||||
|
uint64_t tmp64;
|
||||||
|
|
||||||
|
snprintf (isobuf, 16, "%04d%02d%02dT120000", year, month, day);
|
||||||
|
tmp64 = isotime2epoch_u64 (isobuf);
|
||||||
|
if (tmp64 == (uint64_t)(-1))
|
||||||
|
return 0; /* Error. */
|
||||||
|
if (tmp64 >= (u32)(-1))
|
||||||
|
return 0; /* Error. */
|
||||||
|
return (u32)tmp64;
|
||||||
|
}
|
||||||
return stamp;
|
return stamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,18 +509,14 @@ string2isotime (gnupg_isotime_t atime, const char *string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Scan an ISO timestamp and return an Epoch based timestamp. The
|
/* Helper for isotime2epoch. Returns 0 on success. */
|
||||||
only supported format is "yyyymmddThhmmss[Z]" delimited by white
|
static int
|
||||||
space, nul, a colon or a comma. Returns (time_t)(-1) for an
|
isotime_make_tm (const char *string, struct tm *tmbuf)
|
||||||
invalid string. */
|
|
||||||
time_t
|
|
||||||
isotime2epoch (const char *string)
|
|
||||||
{
|
{
|
||||||
int year, month, day, hour, minu, sec;
|
int year, month, day, hour, minu, sec;
|
||||||
struct tm tmbuf;
|
|
||||||
|
|
||||||
if (!isotime_p (string))
|
if (!isotime_p (string))
|
||||||
return (time_t)(-1);
|
return -1;
|
||||||
|
|
||||||
year = atoi_4 (string);
|
year = atoi_4 (string);
|
||||||
month = atoi_2 (string + 4);
|
month = atoi_2 (string + 4);
|
||||||
@ -409,20 +528,48 @@ isotime2epoch (const char *string)
|
|||||||
/* Basic checks. */
|
/* Basic checks. */
|
||||||
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|
||||||
|| hour > 23 || minu > 59 || sec > 61 )
|
|| hour > 23 || minu > 59 || sec > 61 )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset (tmbuf, 0, sizeof *tmbuf);
|
||||||
|
tmbuf->tm_sec = sec;
|
||||||
|
tmbuf->tm_min = minu;
|
||||||
|
tmbuf->tm_hour = hour;
|
||||||
|
tmbuf->tm_mday = day;
|
||||||
|
tmbuf->tm_mon = month-1;
|
||||||
|
tmbuf->tm_year = year - 1900;
|
||||||
|
tmbuf->tm_isdst = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Scan an ISO timestamp and return an Epoch based timestamp. The
|
||||||
|
only supported format is "yyyymmddThhmmss[Z]" delimited by white
|
||||||
|
space, nul, a colon or a comma. Returns (time_t)(-1) for an
|
||||||
|
invalid string. */
|
||||||
|
time_t
|
||||||
|
isotime2epoch (const char *string)
|
||||||
|
{
|
||||||
|
struct tm tmbuf;
|
||||||
|
|
||||||
|
if (isotime_make_tm (string, &tmbuf))
|
||||||
return (time_t)(-1);
|
return (time_t)(-1);
|
||||||
|
|
||||||
memset (&tmbuf, 0, sizeof tmbuf);
|
|
||||||
tmbuf.tm_sec = sec;
|
|
||||||
tmbuf.tm_min = minu;
|
|
||||||
tmbuf.tm_hour = hour;
|
|
||||||
tmbuf.tm_mday = day;
|
|
||||||
tmbuf.tm_mon = month-1;
|
|
||||||
tmbuf.tm_year = year - 1900;
|
|
||||||
tmbuf.tm_isdst = -1;
|
|
||||||
return timegm (&tmbuf);
|
return timegm (&tmbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
isotime2epoch_u64 (const char *string)
|
||||||
|
{
|
||||||
|
struct tm tmbuf;
|
||||||
|
|
||||||
|
if (isotime_make_tm (string, &tmbuf))
|
||||||
|
return (uint64_t)(-1);
|
||||||
|
|
||||||
|
return timegm_u64 (&tmbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Convert an Epoch time to an iso time stamp. */
|
/* Convert an Epoch time to an iso time stamp. */
|
||||||
void
|
void
|
||||||
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
|
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
|
||||||
@ -476,41 +623,6 @@ isodate_human_to_tm (const char *string, struct tm *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
|
|
||||||
If you change it, then update the other one too. */
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
static time_t
|
|
||||||
_win32_timegm (struct tm *tm)
|
|
||||||
{
|
|
||||||
/* This one is thread safe. */
|
|
||||||
SYSTEMTIME st;
|
|
||||||
FILETIME ft;
|
|
||||||
unsigned long long cnsecs;
|
|
||||||
|
|
||||||
st.wYear = tm->tm_year + 1900;
|
|
||||||
st.wMonth = tm->tm_mon + 1;
|
|
||||||
st.wDay = tm->tm_mday;
|
|
||||||
st.wHour = tm->tm_hour;
|
|
||||||
st.wMinute = tm->tm_min;
|
|
||||||
st.wSecond = tm->tm_sec;
|
|
||||||
st.wMilliseconds = 0; /* Not available. */
|
|
||||||
st.wDayOfWeek = 0; /* Ignored. */
|
|
||||||
|
|
||||||
/* System time is UTC thus the conversion is pretty easy. */
|
|
||||||
if (!SystemTimeToFileTime (&st, &ft))
|
|
||||||
{
|
|
||||||
gpg_err_set_errno (EINVAL);
|
|
||||||
return (time_t)(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
|
||||||
| ft.dwLowDateTime);
|
|
||||||
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
|
||||||
return (time_t)(cnsecs / 10000000ULL);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Parse the string TIMESTAMP into a time_t. The string may either be
|
/* Parse the string TIMESTAMP into a time_t. The string may either be
|
||||||
seconds since Epoch or in the ISO 8601 format like
|
seconds since Epoch or in the ISO 8601 format like
|
||||||
"20390815T143012". Returns 0 for an empty string or seconds since
|
"20390815T143012". Returns 0 for an empty string or seconds since
|
||||||
@ -519,7 +631,11 @@ _win32_timegm (struct tm *tm)
|
|||||||
|
|
||||||
This function is a copy of
|
This function is a copy of
|
||||||
gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
|
gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
|
||||||
then update the other one too. */
|
then update the other one too.
|
||||||
|
|
||||||
|
FIXME: Replace users of this function by one of the more modern
|
||||||
|
functions or change the return type to u64.
|
||||||
|
*/
|
||||||
time_t
|
time_t
|
||||||
parse_timestamp (const char *timestamp, char **endp)
|
parse_timestamp (const char *timestamp, char **endp)
|
||||||
{
|
{
|
||||||
@ -555,24 +671,7 @@ parse_timestamp (const char *timestamp, char **endp)
|
|||||||
buf.tm_min = atoi_2 (timestamp+11);
|
buf.tm_min = atoi_2 (timestamp+11);
|
||||||
buf.tm_sec = atoi_2 (timestamp+13);
|
buf.tm_sec = atoi_2 (timestamp+13);
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
return _win32_timegm (&buf);
|
|
||||||
#else
|
|
||||||
#ifdef HAVE_TIMEGM
|
|
||||||
return timegm (&buf);
|
return timegm (&buf);
|
||||||
#else
|
|
||||||
{
|
|
||||||
time_t tim;
|
|
||||||
|
|
||||||
putenv ("TZ=UTC");
|
|
||||||
tim = mktime (&buf);
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
|
|
||||||
#endif
|
|
||||||
return tim;
|
|
||||||
}
|
|
||||||
#endif /* !HAVE_TIMEGM */
|
|
||||||
#endif /* !HAVE_W32_SYSTEM */
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return (time_t)strtoul (timestamp, endp, 10);
|
return (time_t)strtoul (timestamp, endp, 10);
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
#include <time.h> /* We need time_t. */
|
#include <time.h> /* We need time_t. */
|
||||||
#include <gpg-error.h> /* We need gpg_error_t. */
|
#include <gpg-error.h> /* We need gpg_error_t. */
|
||||||
|
#include <stdint.h> /* We use uint64_t. */
|
||||||
|
|
||||||
/* A type to hold the ISO time. Note that this is the same as
|
/* A type to hold the ISO time. Note that this is the same as
|
||||||
the KSBA type ksba_isotime_t. */
|
the KSBA type ksba_isotime_t. */
|
||||||
@ -43,6 +43,11 @@ typedef char gnupg_isotime_t[16];
|
|||||||
#define GNUPG_ISOTIME_NONE \
|
#define GNUPG_ISOTIME_NONE \
|
||||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
|
||||||
|
#ifndef HAVE_TIMEGM
|
||||||
|
time_t timegm (struct tm *tm);
|
||||||
|
#endif /*!HAVE_TIMEGM*/
|
||||||
|
uint64_t timegm_u64 (struct tm *tm);
|
||||||
|
|
||||||
time_t gnupg_get_time (void);
|
time_t gnupg_get_time (void);
|
||||||
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
|
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
|
||||||
void gnupg_get_isotime (gnupg_isotime_t timebuf);
|
void gnupg_get_isotime (gnupg_isotime_t timebuf);
|
||||||
@ -57,6 +62,7 @@ int isotime_p (const char *string);
|
|||||||
int isotime_human_p (const char *string, int date_only);
|
int isotime_human_p (const char *string, int date_only);
|
||||||
size_t string2isotime (gnupg_isotime_t atime, const char *string);
|
size_t string2isotime (gnupg_isotime_t atime, const char *string);
|
||||||
time_t isotime2epoch (const char *string);
|
time_t isotime2epoch (const char *string);
|
||||||
|
uint64_t isotime2epoch_u64 (const char *string);
|
||||||
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
|
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
|
||||||
int isodate_human_to_tm (const char *string, struct tm *t);
|
int isodate_human_to_tm (const char *string, struct tm *t);
|
||||||
time_t parse_timestamp (const char *timestamp, char **endp);
|
time_t parse_timestamp (const char *timestamp, char **endp);
|
||||||
|
@ -126,80 +126,3 @@ same_file_p (const char *name1, const char *name2)
|
|||||||
}
|
}
|
||||||
return yes;
|
return yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
timegm() is a GNU function that might not be available everywhere.
|
|
||||||
It's basically the inverse of gmtime() - you give it a struct tm,
|
|
||||||
and get back a time_t. It differs from mktime() in that it handles
|
|
||||||
the case where the struct tm is UTC and the local environment isn't.
|
|
||||||
|
|
||||||
Note, that this replacement implementation might not be thread-safe!
|
|
||||||
|
|
||||||
Some BSDs don't handle the putenv("foo") case properly, so we use
|
|
||||||
unsetenv if the platform has it to remove environment variables.
|
|
||||||
*/
|
|
||||||
#ifndef HAVE_TIMEGM
|
|
||||||
time_t
|
|
||||||
timegm (struct tm *tm)
|
|
||||||
{
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
|
||||||
/* This one is thread safe. */
|
|
||||||
SYSTEMTIME st;
|
|
||||||
FILETIME ft;
|
|
||||||
unsigned long long cnsecs;
|
|
||||||
|
|
||||||
st.wYear = tm->tm_year + 1900;
|
|
||||||
st.wMonth = tm->tm_mon + 1;
|
|
||||||
st.wDay = tm->tm_mday;
|
|
||||||
st.wHour = tm->tm_hour;
|
|
||||||
st.wMinute = tm->tm_min;
|
|
||||||
st.wSecond = tm->tm_sec;
|
|
||||||
st.wMilliseconds = 0; /* Not available. */
|
|
||||||
st.wDayOfWeek = 0; /* Ignored. */
|
|
||||||
|
|
||||||
/* System time is UTC thus the conversion is pretty easy. */
|
|
||||||
if (!SystemTimeToFileTime (&st, &ft))
|
|
||||||
{
|
|
||||||
gpg_err_set_errno (EINVAL);
|
|
||||||
return (time_t)(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
|
||||||
| ft.dwLowDateTime);
|
|
||||||
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
|
||||||
return (time_t)(cnsecs / 10000000ULL);
|
|
||||||
|
|
||||||
#else /* (Non thread safe implementation!) */
|
|
||||||
|
|
||||||
time_t answer;
|
|
||||||
char *zone;
|
|
||||||
|
|
||||||
zone=getenv("TZ");
|
|
||||||
putenv("TZ=UTC");
|
|
||||||
tzset();
|
|
||||||
answer=mktime(tm);
|
|
||||||
if(zone)
|
|
||||||
{
|
|
||||||
static char *old_zone;
|
|
||||||
|
|
||||||
if (!old_zone)
|
|
||||||
{
|
|
||||||
old_zone = malloc(3+strlen(zone)+1);
|
|
||||||
if (old_zone)
|
|
||||||
{
|
|
||||||
strcpy(old_zone,"TZ=");
|
|
||||||
strcat(old_zone,zone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (old_zone)
|
|
||||||
putenv (old_zone);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gnupg_unsetenv("TZ");
|
|
||||||
|
|
||||||
tzset();
|
|
||||||
return answer;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif /*!HAVE_TIMEGM*/
|
|
||||||
|
@ -38,12 +38,6 @@
|
|||||||
int same_file_p (const char *name1, const char *name2);
|
int same_file_p (const char *name1, const char *name2);
|
||||||
|
|
||||||
|
|
||||||
#ifndef HAVE_TIMEGM
|
|
||||||
#include <time.h>
|
|
||||||
time_t timegm (struct tm *tm);
|
|
||||||
#endif /*!HAVE_TIMEGM*/
|
|
||||||
|
|
||||||
|
|
||||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user