LCOV - code coverage report
Current view: top level - common - gettime.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 203 433 46.9 %
Date: 2015-11-05 17:10:59 Functions: 16 29 55.2 %

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

Generated by: LCOV version 1.11