summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2023-10-26 09:59:40 +0200
committerWerner Koch <wk@gnupg.org>2023-10-26 12:39:43 +0200
commit164c687cb6a1cafe6c1c47456a1837046a3f00f1 (patch)
treed7725ee9b929afccbce2c16412469668bffd08eb /common
parentsm: Flag Brainpool curves as compliant for all other operations. (diff)
downloadgnupg2-164c687cb6a1cafe6c1c47456a1837046a3f00f1.tar.xz
gnupg2-164c687cb6a1cafe6c1c47456a1837046a3f00f1.zip
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
Diffstat (limited to 'common')
-rw-r--r--common/gettime.c239
-rw-r--r--common/gettime.h8
-rw-r--r--common/mischelp.c77
-rw-r--r--common/mischelp.h6
4 files changed, 176 insertions, 154 deletions
diff --git a/common/gettime.c b/common/gettime.c
index c3b0c6c6c..3f1ce0c5a 100644
--- a/common/gettime.c
+++ b/common/gettime.c
@@ -37,6 +37,10 @@
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#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 "util.h"
@@ -62,6 +66,111 @@ static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
#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
for tests */
time_t
@@ -231,7 +340,21 @@ scan_isodatestr( const char *string )
tmbuf.tm_isdst = -1;
stamp = mktime( &tmbuf );
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;
}
@@ -386,18 +509,14 @@ string2isotime (gnupg_isotime_t atime, const char *string)
}
-/* 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)
+/* Helper for isotime2epoch. Returns 0 on success. */
+static int
+isotime_make_tm (const char *string, struct tm *tmbuf)
{
int year, month, day, hour, minu, sec;
- struct tm tmbuf;
if (!isotime_p (string))
- return (time_t)(-1);
+ return -1;
year = atoi_4 (string);
month = atoi_2 (string + 4);
@@ -409,20 +528,48 @@ isotime2epoch (const char *string)
/* Basic checks. */
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|| 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);
- 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);
}
+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. */
void
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
seconds since Epoch or in the ISO 8601 format like
"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
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
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_sec = atoi_2 (timestamp+13);
-#ifdef HAVE_W32_SYSTEM
- return _win32_timegm (&buf);
-#else
-#ifdef HAVE_TIMEGM
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
return (time_t)strtoul (timestamp, endp, 10);
diff --git a/common/gettime.h b/common/gettime.h
index 18f65ab1a..e216ddd36 100644
--- a/common/gettime.h
+++ b/common/gettime.h
@@ -32,7 +32,7 @@
#include <time.h> /* We need time_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
the KSBA type ksba_isotime_t. */
@@ -43,6 +43,11 @@ typedef char gnupg_isotime_t[16];
#define GNUPG_ISOTIME_NONE \
"\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);
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
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);
size_t string2isotime (gnupg_isotime_t atime, 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);
int isodate_human_to_tm (const char *string, struct tm *t);
time_t parse_timestamp (const char *timestamp, char **endp);
diff --git a/common/mischelp.c b/common/mischelp.c
index ee8500297..ef70c9d83 100644
--- a/common/mischelp.c
+++ b/common/mischelp.c
@@ -126,80 +126,3 @@ same_file_p (const char *name1, const char *name2)
}
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*/
diff --git a/common/mischelp.h b/common/mischelp.h
index bdee5a443..7359ec29e 100644
--- a/common/mischelp.h
+++ b/common/mischelp.h
@@ -38,12 +38,6 @@
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 DIMof(type,member) DIM(((type *)0)->member)