LCOV - code coverage report
Current view: top level - common - gettime.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 209 443 47.2 %
Date: 2016-09-12 12:29:17 Functions: 17 30 56.7 %

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

Generated by: LCOV version 1.11