Coverage Report

Created: 2026-01-09 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/gettime.c
Line
Count
Source
1
/* gettime.c - Wrapper for time functions
2
 * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc.
3
 *
4
 * This file is part of GnuPG.
5
 *
6
 * This file is free software; you can redistribute it and/or modify
7
 * it under the terms of either
8
 *
9
 *   - the GNU Lesser General Public License as published by the Free
10
 *     Software Foundation; either version 3 of the License, or (at
11
 *     your option) any later version.
12
 *
13
 * or
14
 *
15
 *   - the GNU General Public License as published by the Free
16
 *     Software Foundation; either version 2 of the License, or (at
17
 *     your option) any later version.
18
 *
19
 * or both in parallel, as here.
20
 *
21
 * This file is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU General Public License
27
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
28
 */
29
30
#include <config.h>
31
#include <stdlib.h>
32
#include <time.h>
33
#include <ctype.h>
34
#ifdef HAVE_LOCALE_H
35
#include <locale.h>
36
#endif
37
#ifdef HAVE_LANGINFO_H
38
#include <langinfo.h>
39
#endif
40
#ifdef HAVE_W32_SYSTEM
41
# define WIN32_LEAN_AND_MEAN
42
# include <windows.h>
43
#endif /*!HAVE_W32_SYSTEM*/
44
#include <stdint.h>    /* We use uint64_t.  */
45
46
#include "util.h"
47
#include "i18n.h"
48
#include "gettime.h"
49
50
#ifdef HAVE_W32_SYSTEM
51
#include <windows.h>
52
#endif
53
54
#ifdef HAVE_UNSIGNED_TIME_T
55
# define IS_INVALID_TIME_T(a) ((a) == (time_t)(-1))
56
#else
57
  /* Error or 32 bit time_t and value after 2038-01-19.  */
58
10.2k
# define IS_INVALID_TIME_T(a) ((a) < 0)
59
#endif
60
61
62
static unsigned long timewarp;
63
static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
64
65
/* Correction used to map to real Julian days. */
66
0
#define JD_DIFF 1721060L
67
68
69
70
/*
71
  timegm() is a GNU function that might not be available everywhere.
72
  It's basically the inverse of gmtime() - you give it a struct tm,
73
  and get back a time_t.  It differs from mktime() in that it handles
74
  the case where the struct tm is UTC and the local environment isn't.
75
76
  Note, that this replacement implementation might not be thread-safe!
77
78
  Some BSDs don't handle the putenv("foo") case properly, so we use
79
  unsetenv if the platform has it to remove environment variables.
80
*/
81
#ifndef HAVE_TIMEGM
82
time_t
83
timegm (struct tm *tm)
84
{
85
#ifdef HAVE_W32_SYSTEM
86
  uint64_t val = timegm_u64 (tm);
87
  if (val == (uint64_t)(-1))
88
    return (time_t)(-1);
89
  return (time_t)val;
90
#else /* (Non thread safe implementation!) */
91
92
  time_t answer;
93
  char *zone;
94
95
  zone=getenv("TZ");
96
  putenv("TZ=UTC");
97
  tzset();
98
  answer=mktime(tm);
99
  if(zone)
100
    {
101
      static char *old_zone;
102
103
      if (!old_zone)
104
        {
105
          old_zone = malloc(3+strlen(zone)+1);
106
          if (old_zone)
107
            {
108
              strcpy(old_zone,"TZ=");
109
              strcat(old_zone,zone);
110
            }
111
  }
112
      if (old_zone)
113
        putenv (old_zone);
114
    }
115
  else
116
    gnupg_unsetenv("TZ");
117
118
  tzset();
119
  return answer;
120
#endif
121
}
122
#endif /*!HAVE_TIMEGM*/
123
124
125
/* Version of the GNU timegm which returns an unsigned 64 bit integer
126
 * instead of the usually signed time_t.  On error (uint64_t)(-1) is
127
 * returned.  This function is mostly here because on 32 bit Windows
128
 * we have an internal API to get the system time even after
129
 * 2023-01-19.  For 32 bit Unix we need to suffer from the too short
130
 * time_t and no system function to construct the time from a tm.  */
131
uint64_t
132
timegm_u64 (struct tm *tm)
133
0
{
134
#ifdef HAVE_W32_SYSTEM
135
  /* This one is thread safe.  */
136
  SYSTEMTIME st;
137
  FILETIME ft;
138
  unsigned long long cnsecs;
139
140
  st.wYear   = tm->tm_year + 1900;
141
  st.wMonth  = tm->tm_mon  + 1;
142
  st.wDay    = tm->tm_mday;
143
  st.wHour   = tm->tm_hour;
144
  st.wMinute = tm->tm_min;
145
  st.wSecond = tm->tm_sec;
146
  st.wMilliseconds = 0; /* Not available.  */
147
  st.wDayOfWeek = 0;    /* Ignored.  */
148
149
  /* System time is UTC thus the conversion is pretty easy.  */
150
  if (!SystemTimeToFileTime (&st, &ft))
151
    {
152
      gpg_err_set_errno (EINVAL);
153
      return (uint64_t)(-1);
154
    }
155
156
  cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
157
            | ft.dwLowDateTime);
158
  cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01.  */
159
  return (uint64_t)(cnsecs / 10000000ULL);
160
161
#else /*Unix*/
162
163
0
  time_t t = timegm (tm);
164
0
  if (t == (time_t)(-1))
165
0
    return (uint64_t)(-1);
166
0
  if ((int64_t)t < 0)
167
0
    return (uint64_t)(-1);
168
0
  return (uint64_t)t;
169
170
0
#endif /*Unix*/
171
0
}
172
173
174
/* Wrapper for the time(3).  We use this here so we can fake the time
175
   for tests */
176
time_t
177
gnupg_get_time (void)
178
17.1k
{
179
17.1k
  time_t current = time (NULL);
180
17.1k
  if (current == (time_t)(-1))
181
17.1k
    log_fatal ("time() failed\n");
182
183
17.1k
  if (timemode == NORMAL)
184
17.1k
    return current;
185
0
  else if (timemode == FROZEN)
186
0
    return timewarp;
187
0
  else if (timemode == FUTURE)
188
0
    return current + timewarp;
189
0
  else
190
0
    return current - timewarp;
191
17.1k
}
192
193
194
/* Wrapper around gmtime_r.
195
196
   On systems without gmtime_r this implementation works within gnupg
197
   because we use only one thread a time.  FIXME: An independent
198
   library may use gmtime in one of its own thread (or via
199
   npth_enter/npth_leave) - in this case we run into a problem.  The
200
   solution would be to use a mutex here.  */
201
struct tm *
202
gnupg_gmtime (const time_t *timep, struct tm *result)
203
0
{
204
0
#ifdef HAVE_GMTIME_R
205
0
  return gmtime_r (timep, result);
206
#else
207
  struct tm *tp;
208
209
  tp = gmtime (timep);
210
  if (tp)
211
    memcpy (result, tp, sizeof *result);
212
  return tp;
213
#endif
214
0
}
215
216
217
/* Return the current time (possibly faked) in ISO format. */
218
void
219
gnupg_get_isotime (gnupg_isotime_t timebuf)
220
0
{
221
0
  time_t atime = gnupg_get_time ();
222
0
  struct tm *tp;
223
0
  struct tm tmbuf;
224
225
0
  tp = gnupg_gmtime (&atime, &tmbuf);
226
0
  if (!tp)
227
0
    *timebuf = 0;
228
0
  else
229
0
    snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
230
0
              1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
231
0
              tp->tm_hour, tp->tm_min, tp->tm_sec);
232
0
}
233
234
235
/* Set the time to NEWTIME so that gnupg_get_time returns a time
236
   starting with this one.  With FREEZE set to 1 the returned time
237
   will never change.  Just for completeness, a value of (time_t)-1
238
   for NEWTIME gets you back to reality.  Note that this is obviously
239
   not thread-safe but this is not required. */
240
void
241
gnupg_set_time (time_t newtime, int freeze)
242
0
{
243
0
  time_t current = time (NULL);
244
245
0
  if ( newtime == (time_t)-1 || current == newtime)
246
0
    {
247
0
      timemode = NORMAL;
248
0
      timewarp = 0;
249
0
    }
250
0
  else if (freeze)
251
0
    {
252
0
      timemode = FROZEN;
253
0
      timewarp = newtime == (time_t)-1 ? current : newtime;
254
0
    }
255
0
  else if (newtime > current)
256
0
    {
257
0
      timemode = FUTURE;
258
0
      timewarp = newtime - current;
259
0
    }
260
0
  else
261
0
    {
262
0
      timemode = PAST;
263
0
      timewarp = current - newtime;
264
0
    }
265
0
}
266
267
/* Returns true when we are in timewarp mode */
268
int
269
gnupg_faked_time_p (void)
270
0
{
271
0
  return timemode;
272
0
}
273
274
275
/* This function is used by gpg because OpenPGP defines the timestamp
276
   as an unsigned 32 bit value. */
277
u32
278
make_timestamp (void)
279
17.1k
{
280
17.1k
  time_t t = gnupg_get_time ();
281
17.1k
  return (u32)t;
282
17.1k
}
283
284
285
/* Specialized version of atoi which returns an u32 instead of an int
286
 * and caps the result at 2^32-2.  Leading white space is skipped,
287
 * scanning stops at at the first non-convertable byte.  Note that we
288
 * do not cap at 2^32-1 because that value is often used as error
289
 * return. */
290
u32
291
scan_secondsstr (const char *string)
292
0
{
293
0
  uint64_t value = 0;
294
295
0
  while (*string == ' ' || *string == '\t')
296
0
    string++;
297
0
  for (; *string >= '0' && *string <= '9'; string++)
298
0
    {
299
0
      value *= 10;
300
0
      value += atoi_1 (string);
301
0
      if (value >= (u32)(-1))
302
0
        return (u32)(-1) - 1;
303
0
    }
304
0
  return (u32)value;
305
0
}
306
307
308
/****************
309
 * Scan a date string and return a timestamp.
310
 * The only supported format is "yyyy-mm-dd"
311
 * Returns 0 for an invalid date.
312
 */
313
u32
314
scan_isodatestr( const char *string )
315
0
{
316
0
    int year, month, day;
317
0
    struct tm tmbuf;
318
0
    time_t stamp;
319
0
    int i;
320
321
0
    if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' )
322
0
  return 0;
323
0
    for( i=0; i < 4; i++ )
324
0
  if( !digitp (string+i) )
325
0
      return 0;
326
0
    if( !digitp (string+5) || !digitp(string+6) )
327
0
  return 0;
328
0
    if( !digitp(string+8) || !digitp(string+9) )
329
0
  return 0;
330
0
    year = atoi(string);
331
0
    month = atoi(string+5);
332
0
    day = atoi(string+8);
333
    /* some basic checks */
334
0
    if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 )
335
0
  return 0;
336
0
    memset( &tmbuf, 0, sizeof tmbuf );
337
0
    tmbuf.tm_mday = day;
338
0
    tmbuf.tm_mon = month-1;
339
0
    tmbuf.tm_year = year - 1900;
340
0
    tmbuf.tm_isdst = -1;
341
0
    stamp = mktime( &tmbuf );
342
0
    if( stamp == (time_t)-1 )
343
0
      {
344
        /* mktime did not work.  Construct an ISO timestring for noon
345
         * of the given day instead.  We keep the use of mktime for 64
346
         * bit system to limit the risk of regressions. */
347
0
        gnupg_isotime_t isobuf;
348
0
        uint64_t tmp64;
349
350
0
        snprintf (isobuf, 16, "%04d%02d%02dT120000", year, month, day);
351
0
        tmp64 = isotime2epoch_u64 (isobuf);
352
0
        if (tmp64 == (uint64_t)(-1))
353
0
          return 0;  /* Error.  */
354
0
        if (tmp64 >= (u32)(-1))
355
0
          return 0;   /* Error.  */
356
0
        return (u32)tmp64;
357
0
      }
358
0
    return stamp;
359
0
}
360
361
362
int
363
isotime_p (const char *string)
364
0
{
365
0
  const char *s;
366
0
  int i;
367
368
0
  if (!*string)
369
0
    return 0;
370
0
  for (s=string, i=0; i < 8; i++, s++)
371
0
    if (!digitp (s))
372
0
      return 0;
373
0
  if (*s != 'T')
374
0
      return 0;
375
0
  for (s++, i=9; i < 15; i++, s++)
376
0
    if (!digitp (s))
377
0
      return 0;
378
0
  if (*s == 'Z')
379
0
    s++;
380
0
  if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ','))
381
0
    return 0;  /* Wrong delimiter.  */
382
383
0
  return 1;
384
0
}
385
386
387
/* Scan a string and return true if the string represents the human
388
   readable format of an ISO time.  This format is:
389
      yyyy-mm-dd[ hh[:mm[:ss]]]
390
   Scanning stops at the second space or at a comma.  If DATE_ONLY is
391
   true the time part is not expected and the scanning stops at the
392
   first space or at a comma. */
393
int
394
isotime_human_p (const char *string, int date_only)
395
0
{
396
0
  const char *s;
397
0
  int i;
398
399
0
  if (!*string)
400
0
    return 0;
401
0
  for (s=string, i=0; i < 4; i++, s++)
402
0
    if (!digitp (s))
403
0
      return 0;
404
0
  if (*s != '-')
405
0
    return 0;
406
0
  s++;
407
0
  if (!digitp (s) || !digitp (s+1) || s[2] != '-')
408
0
    return 0;
409
0
  i = atoi_2 (s);
410
0
  if (i < 1 || i > 12)
411
0
    return 0;
412
0
  s += 3;
413
0
  if (!digitp (s) || !digitp (s+1))
414
0
    return 0;
415
0
  i = atoi_2 (s);
416
0
  if (i < 1 || i > 31)
417
0
    return 0;
418
0
  s += 2;
419
0
  if (!*s || *s == ',')
420
0
    return 1; /* Okay; only date given.  */
421
0
  if (!spacep (s))
422
0
    return 0;
423
0
  if (date_only)
424
0
    return 1; /* Okay; only date was requested.  */
425
0
  s++;
426
0
  if (spacep (s))
427
0
    return 1; /* Okay, second space stops scanning.  */
428
0
  if (!digitp (s) || !digitp (s+1))
429
0
    return 0;
430
0
  i = atoi_2 (s);
431
0
  if (i < 0 || i > 23)
432
0
    return 0;
433
0
  s += 2;
434
0
  if (!*s || *s == ',')
435
0
    return 1; /* Okay; only date and hour given.  */
436
0
  if (*s != ':')
437
0
    return 0;
438
0
  s++;
439
0
  if (!digitp (s) || !digitp (s+1))
440
0
    return 0;
441
0
  i = atoi_2 (s);
442
0
  if (i < 0 || i > 59)
443
0
    return 0;
444
0
  s += 2;
445
0
  if (!*s || *s == ',')
446
0
    return 1; /* Okay; only date, hour and minute given.  */
447
0
  if (*s != ':')
448
0
    return 0;
449
0
  s++;
450
0
  if (!digitp (s) || !digitp (s+1))
451
0
    return 0;
452
0
  i = atoi_2 (s);
453
0
  if (i < 0 || i > 60)
454
0
    return 0;
455
0
  s += 2;
456
0
  if (!*s || *s == ',' || spacep (s))
457
0
    return 1; /* Okay; date, hour and minute and second given.  */
458
459
0
  return 0; /* Unexpected delimiter.  */
460
0
}
461
462
/* Convert a standard isotime or a human readable variant into an
463
   isotime structure.  The allowed formats are those described by
464
   isotime_p and isotime_human_p.  The function returns 0 on failure
465
   or the length of the scanned string on success.  */
466
size_t
467
string2isotime (gnupg_isotime_t atime, const char *string)
468
0
{
469
0
  gnupg_isotime_t dummyatime;
470
471
0
  if (!atime)
472
0
    atime = dummyatime;
473
474
0
  atime[0] = 0;
475
0
  if (isotime_p (string))
476
0
    {
477
0
      memcpy (atime, string, 15);
478
0
      atime[15] = 0;
479
0
      return 15;
480
0
    }
481
0
  if (!isotime_human_p (string, 0))
482
0
    return 0;
483
0
  atime[0] = string[0];
484
0
  atime[1] = string[1];
485
0
  atime[2] = string[2];
486
0
  atime[3] = string[3];
487
0
  atime[4] = string[5];
488
0
  atime[5] = string[6];
489
0
  atime[6] = string[8];
490
0
  atime[7] = string[9];
491
0
  atime[8] = 'T';
492
0
  memset (atime+9, '0', 6);
493
0
  atime[15] = 0;
494
0
  if (!spacep (string+10))
495
0
    return 10;
496
0
  if (spacep (string+11))
497
0
    return 11; /* As per def, second space stops scanning.  */
498
0
  atime[9] = string[11];
499
0
  atime[10] = string[12];
500
0
  if (string[13] != ':')
501
0
    return 13;
502
0
  atime[11] = string[14];
503
0
  atime[12] = string[15];
504
0
  if (string[16] != ':')
505
0
    return 16;
506
0
  atime[13] = string[17];
507
0
  atime[14] = string[18];
508
0
  return 19;
509
0
}
510
511
512
/* Helper for isotime2epoch.  Returns 0 on success. */
513
static int
514
isotime_make_tm (const char *string, struct tm *tmbuf)
515
0
{
516
0
  int year, month, day, hour, minu, sec;
517
518
0
  if (!isotime_p (string))
519
0
    return -1;
520
521
0
  year  = atoi_4 (string);
522
0
  month = atoi_2 (string + 4);
523
0
  day   = atoi_2 (string + 6);
524
0
  hour  = atoi_2 (string + 9);
525
0
  minu  = atoi_2 (string + 11);
526
0
  sec   = atoi_2 (string + 13);
527
528
  /* Basic checks.  */
529
0
  if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
530
0
      || hour > 23 || minu > 59 || sec > 61 )
531
0
    return -1;
532
533
0
  memset (tmbuf, 0, sizeof *tmbuf);
534
0
  tmbuf->tm_sec  = sec;
535
0
  tmbuf->tm_min  = minu;
536
0
  tmbuf->tm_hour = hour;
537
0
  tmbuf->tm_mday = day;
538
0
  tmbuf->tm_mon  = month-1;
539
0
  tmbuf->tm_year = year - 1900;
540
0
  tmbuf->tm_isdst = -1;
541
0
  return 0;
542
0
}
543
544
545
/* Scan an ISO timestamp and return an Epoch based timestamp.  The
546
   only supported format is "yyyymmddThhmmss[Z]" delimited by white
547
   space, nul, a colon or a comma.  Returns (time_t)(-1) for an
548
   invalid string.  */
549
time_t
550
isotime2epoch (const char *string)
551
0
{
552
0
  struct tm tmbuf;
553
554
0
  if (isotime_make_tm (string, &tmbuf))
555
0
    return (time_t)(-1);
556
557
0
  return timegm (&tmbuf);
558
0
}
559
560
561
uint64_t
562
isotime2epoch_u64 (const char *string)
563
0
{
564
0
  struct tm tmbuf;
565
566
0
  if (isotime_make_tm (string, &tmbuf))
567
0
    return (uint64_t)(-1);
568
569
0
  return timegm_u64 (&tmbuf);
570
0
}
571
572
573
/* Convert an Epoch time to an iso time stamp. */
574
void
575
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
576
0
{
577
0
  if (atime == (time_t)(-1))
578
0
    *timebuf = 0;
579
0
  else
580
0
    {
581
0
      struct tm *tp;
582
0
#ifdef HAVE_GMTIME_R
583
0
      struct tm tmbuf;
584
585
0
      tp = gmtime_r (&atime, &tmbuf);
586
#else
587
      tp = gmtime (&atime);
588
#endif
589
0
      snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
590
0
                1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
591
0
                tp->tm_hour, tp->tm_min, tp->tm_sec);
592
0
    }
593
0
}
594
595
596
/* Parse a short ISO date string (YYYY-MM-DD) into a TM structure.
597
   Returns 0 on success.  */
598
int
599
isodate_human_to_tm (const char *string, struct tm *t)
600
0
{
601
0
  int year, month, day;
602
603
0
  if (!isotime_human_p (string, 1))
604
0
    return -1;
605
606
0
  year  = atoi_4 (string);
607
0
  month = atoi_2 (string + 5);
608
0
  day   = atoi_2 (string + 8);
609
610
  /* Basic checks.  */
611
0
  if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31)
612
0
    return -1;
613
614
0
  memset (t, 0, sizeof *t);
615
0
  t->tm_sec  = 0;
616
0
  t->tm_min  = 0;
617
0
  t->tm_hour = 0;
618
0
  t->tm_mday = day;
619
0
  t->tm_mon  = month-1;
620
0
  t->tm_year = year - 1900;
621
0
  t->tm_isdst = -1;
622
0
  return 0;
623
0
}
624
625
626
/* Parse the string TIMESTAMP into a time_t.  The string may either be
627
   seconds since Epoch or in the ISO 8601 format like
628
   "20390815T143012".  Returns 0 for an empty string or seconds since
629
   Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
630
   point to the next non-parsed character in TIMESTRING.
631
632
   This function is a copy of
633
   gpgme/src/conversion.c:_gpgme_parse_timestamp.  If you change it,
634
   then update the other one too.
635
636
   FIXME: Replace users of this function by one of the more modern
637
          functions or change the return type to u64.
638
*/
639
time_t
640
parse_timestamp (const char *timestamp, char **endp)
641
0
{
642
  /* Need to skip leading spaces, because that is what strtoul does
643
     but not our ISO 8601 checking code. */
644
0
  while (*timestamp && *timestamp== ' ')
645
0
    timestamp++;
646
0
  if (!*timestamp)
647
0
    return 0;
648
649
0
  if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
650
0
    {
651
0
      struct tm buf;
652
0
      int year;
653
654
0
      year = atoi_4 (timestamp);
655
0
      if (year < 1900)
656
0
        return (time_t)(-1);
657
658
0
      if (endp)
659
0
        *endp = (char*)(timestamp + 15);
660
661
      /* Fixme: We would better use a configure test to see whether
662
         mktime can handle dates beyond 2038. */
663
0
      if (sizeof (time_t) <= 4 && year >= 2038)
664
0
        return (time_t)2145914603; /* 2037-12-31 23:23:23 */
665
666
0
      memset (&buf, 0, sizeof buf);
667
0
      buf.tm_year = year - 1900;
668
0
      buf.tm_mon = atoi_2 (timestamp+4) - 1;
669
0
      buf.tm_mday = atoi_2 (timestamp+6);
670
0
      buf.tm_hour = atoi_2 (timestamp+9);
671
0
      buf.tm_min = atoi_2 (timestamp+11);
672
0
      buf.tm_sec = atoi_2 (timestamp+13);
673
674
0
      return timegm (&buf);
675
0
    }
676
0
  else
677
0
    return (time_t)strtoul (timestamp, endp, 10);
678
0
}
679
680
681
682
u32
683
add_days_to_timestamp( u32 stamp, u16 days )
684
0
{
685
0
    return stamp + days*86400L;
686
0
}
687
688
689
/****************
690
 * Return a string with a time value in the form: x Y, n D, n H
691
 */
692
693
const char *
694
strtimevalue( u32 value )
695
0
{
696
0
    static char buffer[30];
697
0
    unsigned int years, days, hours, minutes;
698
699
0
    value /= 60;
700
0
    minutes = value % 60;
701
0
    value /= 60;
702
0
    hours = value % 24;
703
0
    value /= 24;
704
0
    days = value % 365;
705
0
    value /= 365;
706
0
    years = value;
707
708
0
    sprintf(buffer,"%uy%ud%uh%um", years, days, hours, minutes );
709
0
    if( years )
710
0
  return buffer;
711
0
    if( days )
712
0
  return strchr( buffer, 'y' ) + 1;
713
0
    return strchr( buffer, 'd' ) + 1;
714
0
}
715
716
717
718
/* Return a malloced string with the time elapsed between NOW and
719
   SINCE.  May return NULL on error. */
720
char *
721
elapsed_time_string (time_t since, time_t now)
722
0
{
723
0
  char *result;
724
0
  double diff;
725
0
  unsigned long value;
726
0
  unsigned int days, hours, minutes, seconds;
727
728
0
  if (!now)
729
0
    now = gnupg_get_time ();
730
731
0
  diff = difftime (now, since);
732
0
  if (diff < 0)
733
0
    return xtrystrdup ("time-warp");
734
735
0
  seconds = (unsigned long)diff % 60;
736
0
  value = (unsigned long)(diff / 60);
737
0
  minutes = value % 60;
738
0
  value /= 60;
739
0
  hours = value % 24;
740
0
  value /= 24;
741
0
  days = value % 365;
742
743
0
  if (days)
744
0
    result = xtryasprintf ("%ud%uh%um%us", days, hours, minutes, seconds);
745
0
  else if (hours)
746
0
    result = xtryasprintf ("%uh%um%us", hours, minutes, seconds);
747
0
  else if (minutes)
748
0
    result = xtryasprintf ("%um%us", minutes, seconds);
749
0
  else
750
0
    result = xtryasprintf ("%us", seconds);
751
752
0
  return result;
753
0
}
754
755
756
/*
757
 * Note: this function returns GMT
758
 */
759
const char *
760
strtimestamp (u32 stamp)
761
0
{
762
0
  static char buffer[11+5];
763
0
  struct tm *tp;
764
0
  time_t atime = stamp;
765
766
0
  if (IS_INVALID_TIME_T (atime))
767
0
    {
768
0
      strcpy (buffer, "????" "-??" "-??");
769
0
    }
770
0
  else
771
0
    {
772
0
      tp = gmtime( &atime );
773
0
      snprintf (buffer, sizeof buffer, "%04d-%02d-%02d",
774
0
                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
775
0
    }
776
0
  return buffer;
777
0
}
778
779
780
/*
781
 * Note: this function returns GMT
782
 */
783
const char *
784
isotimestamp (u32 stamp)
785
0
{
786
0
  static char buffer[25+5];
787
0
  struct tm *tp;
788
0
  time_t atime = stamp;
789
790
0
  if (IS_INVALID_TIME_T (atime))
791
0
    {
792
0
      strcpy (buffer, "????" "-??" "-??" " " "??" ":" "??" ":" "??");
793
0
    }
794
0
  else
795
0
    {
796
0
      tp = gmtime ( &atime );
797
0
      snprintf (buffer, sizeof buffer, "%04d-%02d-%02d %02d:%02d:%02d",
798
0
                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
799
0
                tp->tm_hour, tp->tm_min, tp->tm_sec);
800
0
    }
801
0
  return buffer;
802
0
}
803
804
805
/****************
806
 * Note: this function returns local time
807
 */
808
const char *
809
asctimestamp (u32 stamp)
810
10.2k
{
811
10.2k
  static char buffer[80];
812
10.2k
#if defined (HAVE_STRFTIME) && defined (HAVE_NL_LANGINFO)
813
10.2k
  static char fmt[80];
814
10.2k
#endif
815
10.2k
  struct tm *tp;
816
10.2k
  time_t atime = stamp;
817
818
10.2k
  if (IS_INVALID_TIME_T (atime))
819
0
    {
820
0
      strcpy (buffer, "????" "-??" "-??");
821
0
      return buffer;
822
0
    }
823
824
10.2k
  tp = localtime( &atime );
825
10.2k
#ifdef HAVE_STRFTIME
826
10.2k
# if defined(HAVE_NL_LANGINFO)
827
10.2k
  mem2str( fmt, nl_langinfo(D_T_FMT), DIM(fmt)-3 );
828
10.2k
  if (!strstr( fmt, "%Z" ))
829
10.2k
    strcat( fmt, " %Z");
830
  /* NOTE: gcc -Wformat-noliteral will complain here.  I have found no
831
     way to suppress this warning.  */
832
10.2k
  strftime (buffer, DIM(buffer)-1, fmt, tp);
833
# else
834
#  if HAVE_W32_SYSTEM
835
  {
836
    static int done;
837
838
    if (!done)
839
      {
840
        /* The locale names as used by Windows are in the form
841
         * "German_Germany.1252" or "German_Austria.1252" with
842
         * alternate names similar to Unix, e.g. "de-DE".  However
843
         * that is the theory.  On current Windows and Mingw the
844
         * alternate names do not work.  We would need a table to map
845
         * them from the short names as provided by gpgrt to the long
846
         * names and append some code page.  For now we use "" and
847
         * take the locale from the user's system settings.  Thus the
848
         * standard Unix envvars don't work for time and may mismatch
849
         * with the string translations.  The new UCRT available since
850
         * 2018 has a lot of additional support but that will for sure
851
         * break other things.  We should move to ISO strings to get
852
         * rid of such problems.  */
853
        setlocale (LC_TIME, ".UTF8");
854
        done = 1;
855
        /* log_debug ("LC_ALL  now '%s'\n", setlocale (LC_ALL, NULL)); */
856
        /* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */
857
      }
858
  }
859
#  endif
860
   /* FIXME: we should check whether the locale appends a " %Z" These
861
    * locales from glibc don't put the " %Z": fi_FI hr_HR ja_JP lt_LT
862
    * lv_LV POSIX ru_RU ru_SU sv_FI sv_SE zh_CN.  */
863
  strftime (buffer, DIM(buffer)-1, "%c %Z", tp);
864
# endif
865
10.2k
  buffer[DIM(buffer)-1] = 0;
866
#else
867
  mem2str( buffer, asctime(tp), DIM(buffer) );
868
#endif
869
10.2k
  return buffer;
870
10.2k
}
871
872
873
/* Return the timestamp STAMP in RFC-2822 format.  This is always done
874
 * in the C locale.  We return the gmtime to avoid computing the
875
 * timezone. The caller must release the returned string.
876
 *
877
 * Example: "Mon, 27 Jun 2016 1:42:00 +0000".
878
 */
879
char *
880
rfctimestamp (u32 stamp)
881
0
{
882
0
  time_t atime = stamp;
883
0
  struct tm tmbuf, *tp;
884
885
886
0
  if (IS_INVALID_TIME_T (atime))
887
0
    {
888
0
      gpg_err_set_errno (EINVAL);
889
0
      return NULL;
890
0
    }
891
892
0
  tp = gnupg_gmtime (&atime, &tmbuf);
893
0
  if (!tp)
894
0
    return NULL;
895
0
  return xtryasprintf ("%.3s, %02d %.3s %04d %02d:%02d:%02d +0000",
896
0
                       &"SunMonTueWedThuFriSat"[(tp->tm_wday%7)*3],
897
0
                       tp->tm_mday,
898
0
                       &"JanFebMarAprMayJunJulAugSepOctNovDec"
899
0
                       [(tp->tm_mon%12)*3],
900
0
                       tp->tm_year + 1900,
901
0
                       tp->tm_hour,
902
0
                       tp->tm_min,
903
0
                       tp->tm_sec);
904
0
}
905
906
907
static int
908
days_per_year (int y)
909
0
{
910
0
  int s ;
911
912
0
  s = !(y % 4);
913
0
  if ( !(y % 100))
914
0
    if ((y%400))
915
0
      s = 0;
916
0
  return s ? 366 : 365;
917
0
}
918
919
static int
920
days_per_month (int y, int m)
921
0
{
922
0
  int s;
923
924
0
  switch(m)
925
0
    {
926
0
    case 1: case 3: case 5: case 7: case 8: case 10: case 12:
927
0
      return 31 ;
928
0
    case 2:
929
0
      s = !(y % 4);
930
0
      if (!(y % 100))
931
0
        if ((y % 400))
932
0
          s = 0;
933
0
      return s? 29 : 28 ;
934
0
    case 4: case 6: case 9: case 11:
935
0
      return 30;
936
0
    }
937
0
  BUG();
938
0
}
939
940
941
/* Convert YEAR, MONTH and DAY into the Julian date.  We assume that
942
   it is already noon.  We do not support dates before 1582-10-15. */
943
static unsigned long
944
date2jd (int year, int month, int day)
945
0
{
946
0
  unsigned long jd;
947
948
0
  jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
949
0
  if (month < 3)
950
0
    year-- ;
951
0
  else
952
0
    jd -= (4 * month + 23) / 10;
953
954
0
  jd += year / 4 - ((year / 100 + 1) *3) / 4;
955
956
0
  return jd ;
957
0
}
958
959
/* Convert a Julian date back to YEAR, MONTH and DAY.  Return day of
960
   the year or 0 on error.  This function uses some more or less
961
   arbitrary limits, most important is that days before 1582 are not
962
   supported. */
963
static int
964
jd2date (unsigned long jd, int *year, int *month, int *day)
965
0
{
966
0
  int y, m, d;
967
0
  long delta;
968
969
0
  if (!jd)
970
0
    return 0 ;
971
0
  if (jd < 1721425 || jd > 2843085)
972
0
    return 0;
973
974
0
  y = (jd - JD_DIFF) / 366;
975
0
  d = m = 1;
976
977
0
  while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
978
0
    y++;
979
980
0
  m = (delta / 31) + 1;
981
0
  while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
982
0
    if (++m > 12)
983
0
      {
984
0
        m = 1;
985
0
        y++;
986
0
      }
987
988
0
  d = delta + 1 ;
989
0
  if (d > days_per_month (y, m))
990
0
    {
991
0
      d = 1;
992
0
      m++;
993
0
    }
994
0
  if (m > 12)
995
0
    {
996
0
      m = 1;
997
0
      y++;
998
0
    }
999
1000
0
  if (year)
1001
0
    *year = y;
1002
0
  if (month)
1003
0
    *month = m;
1004
0
  if (day)
1005
0
    *day = d ;
1006
1007
0
  return (jd - date2jd (y, 1, 1)) + 1;
1008
0
}
1009
1010
1011
/* Check that the 15 bytes in ATIME represent a valid ISO time.  Note
1012
   that this function does not expect a string but a plain 15 byte
1013
   isotime buffer. */
1014
gpg_error_t
1015
check_isotime (const gnupg_isotime_t atime)
1016
0
{
1017
0
  int i;
1018
0
  const char *s;
1019
1020
0
  if (!*atime)
1021
0
    return gpg_error (GPG_ERR_NO_VALUE);
1022
1023
0
  for (s=atime, i=0; i < 8; i++, s++)
1024
0
    if (!digitp (s))
1025
0
      return gpg_error (GPG_ERR_INV_TIME);
1026
0
  if (*s != 'T')
1027
0
      return gpg_error (GPG_ERR_INV_TIME);
1028
0
  for (s++, i=9; i < 15; i++, s++)
1029
0
    if (!digitp (s))
1030
0
      return gpg_error (GPG_ERR_INV_TIME);
1031
0
  return 0;
1032
0
}
1033
1034
1035
/* Dump the ISO time T to the log stream without a LF.  */
1036
void
1037
dump_isotime (const gnupg_isotime_t t)
1038
0
{
1039
0
  if (!t || !*t)
1040
0
    log_printf ("%s", _("[none]"));
1041
0
  else
1042
0
    log_printf ("%.4s-%.2s-%.2s %.2s:%.2s:%s",
1043
0
                t, t+4, t+6, t+9, t+11, t+13);
1044
0
}
1045
1046
1047
/* Copy one ISO date to another, this is inline so that we can do a
1048
   minimal sanity check.  A null date (empty string) is allowed.  */
1049
void
1050
gnupg_copy_time (gnupg_isotime_t d, const gnupg_isotime_t s)
1051
0
{
1052
0
  if (*s)
1053
0
    {
1054
0
      if ((strlen (s) != 15 || s[8] != 'T'))
1055
0
        BUG();
1056
0
      memcpy (d, s, 15);
1057
0
      d[15] = 0;
1058
0
    }
1059
0
  else
1060
0
    *d = 0;
1061
0
}
1062
1063
1064
/* Add SECONDS to ATIME.  SECONDS may not be negative and is limited
1065
   to about the equivalent of 62 years which should be more then
1066
   enough for our purposes. */
1067
gpg_error_t
1068
add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
1069
0
{
1070
0
  gpg_error_t err;
1071
0
  int year, month, day, hour, minute, sec, ndays;
1072
0
  unsigned long jd;
1073
1074
0
  err = check_isotime (atime);
1075
0
  if (err)
1076
0
    return err;
1077
1078
0
  if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
1079
0
    return gpg_error (GPG_ERR_INV_VALUE);
1080
1081
0
  year  = atoi_4 (atime+0);
1082
0
  month = atoi_2 (atime+4);
1083
0
  day   = atoi_2 (atime+6);
1084
0
  hour  = atoi_2 (atime+9);
1085
0
  minute= atoi_2 (atime+11);
1086
0
  sec   = atoi_2 (atime+13);
1087
1088
0
  if (year <= 1582) /* The julian date functions don't support this. */
1089
0
    return gpg_error (GPG_ERR_INV_VALUE);
1090
1091
0
  sec    += nseconds;
1092
0
  minute += sec/60;
1093
0
  sec    %= 60;
1094
0
  hour   += minute/60;
1095
0
  minute %= 60;
1096
0
  ndays  = hour/24;
1097
0
  hour   %= 24;
1098
1099
0
  jd = date2jd (year, month, day) + ndays;
1100
0
  jd2date (jd, &year, &month, &day);
1101
1102
0
  if (year > 9999 || month > 12 || day > 31
1103
0
      || year < 0 || month < 1 || day < 1)
1104
0
    return gpg_error (GPG_ERR_INV_VALUE);
1105
1106
0
  snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
1107
0
            year, month, day, hour, minute, sec);
1108
0
  return 0;
1109
0
}
1110
1111
1112
gpg_error_t
1113
add_days_to_isotime (gnupg_isotime_t atime, int ndays)
1114
0
{
1115
0
  gpg_error_t err;
1116
0
  int year, month, day, hour, minute, sec;
1117
0
  unsigned long jd;
1118
1119
0
  err = check_isotime (atime);
1120
0
  if (err)
1121
0
    return err;
1122
1123
0
  if (ndays < 0 || ndays >= 9999*366 )
1124
0
    return gpg_error (GPG_ERR_INV_VALUE);
1125
1126
0
  year  = atoi_4 (atime+0);
1127
0
  month = atoi_2 (atime+4);
1128
0
  day   = atoi_2 (atime+6);
1129
0
  hour  = atoi_2 (atime+9);
1130
0
  minute= atoi_2 (atime+11);
1131
0
  sec   = atoi_2 (atime+13);
1132
1133
0
  if (year <= 1582) /* The julian date functions don't support this. */
1134
0
    return gpg_error (GPG_ERR_INV_VALUE);
1135
1136
0
  jd = date2jd (year, month, day) + ndays;
1137
0
  jd2date (jd, &year, &month, &day);
1138
1139
0
  if (year > 9999 || month > 12 || day > 31
1140
0
      || year < 0 || month < 1 || day < 1)
1141
0
    return gpg_error (GPG_ERR_INV_VALUE);
1142
1143
0
  snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
1144
0
            year, month, day, hour, minute, sec);
1145
0
  return 0;
1146
0
}