Initial import
[samba] / source / lib / time.c
1 /* 
2    Unix SMB/CIFS implementation.
3    time handling functions
4    Copyright (C) Andrew Tridgell                1992-1998
5    Copyright (C) Stefan (metze) Metzmacher      2002   
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /*
24   This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com>
25   in May 1996 
26   */
27
28 int extra_time_offset = 0;
29
30 #ifndef CHAR_BIT
31 #define CHAR_BIT 8
32 #endif
33
34 #ifndef TIME_T_MIN
35 #define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \
36                     : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
37 #endif
38 #ifndef TIME_T_MAX
39 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
40 #endif
41
42 void get_nttime_max(NTTIME *t)
43 {
44         /* FIXME: This is incorrect */
45         unix_to_nt_time(t, get_time_t_max());
46 }
47
48 /*******************************************************************
49  External access to time_t_min and time_t_max.
50 ********************************************************************/
51
52 time_t get_time_t_max(void)
53 {
54         return TIME_T_MAX;
55 }
56
57 /*******************************************************************
58  A gettimeofday wrapper.
59 ********************************************************************/
60
61 void GetTimeOfDay(struct timeval *tval)
62 {
63 #ifdef HAVE_GETTIMEOFDAY_TZ
64         gettimeofday(tval,NULL);
65 #else
66         gettimeofday(tval);
67 #endif
68 }
69
70 #define TM_YEAR_BASE 1900
71
72 /*******************************************************************
73  Yield the difference between *A and *B, in seconds, ignoring leap seconds.
74 ********************************************************************/
75
76 static int tm_diff(struct tm *a, struct tm *b)
77 {
78         int ay = a->tm_year + (TM_YEAR_BASE - 1);
79         int by = b->tm_year + (TM_YEAR_BASE - 1);
80         int intervening_leap_days = (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
81         int years = ay - by;
82         int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
83         int hours = 24*days + (a->tm_hour - b->tm_hour);
84         int minutes = 60*hours + (a->tm_min - b->tm_min);
85         int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
86
87         return seconds;
88 }
89
90 /*******************************************************************
91  Return the UTC offset in seconds west of UTC, or 0 if it cannot be determined.
92 ******************************************************************/
93
94 int get_time_zone(time_t t)
95 {
96         struct tm *tm = gmtime(&t);
97         struct tm tm_utc;
98
99         if (!tm) {
100                 return 0;
101         }
102         tm_utc = *tm;
103         tm = localtime(&t);
104         if (!tm) {
105                 return 0;
106         }
107         return tm_diff(&tm_utc,tm) + 60*extra_time_offset;
108 }
109
110 /*******************************************************************
111  Accessor function for the server time zone offset.
112  set_server_zone_offset() must have been called first.
113 ******************************************************************/
114
115 static int server_zone_offset;
116
117 int get_server_zone_offset(void)
118 {
119         return server_zone_offset;
120 }
121
122 /*******************************************************************
123  Initialize the server time zone offset. Called when a client connects.
124 ******************************************************************/
125
126 int set_server_zone_offset(time_t t)
127 {
128         server_zone_offset = get_time_zone(t);
129         return server_zone_offset;
130 }
131
132 /*******************************************************************
133  Re-read the smb serverzone value.
134 ******************************************************************/
135
136 static struct timeval start_time_hires;
137
138 void TimeInit(void)
139 {
140         set_server_zone_offset(time(NULL));
141
142         DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset));
143
144         /* Save the start time of this process. */
145         if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) {
146                 GetTimeOfDay(&start_time_hires);
147         }
148 }
149
150 /**********************************************************************
151  Return a timeval struct of the uptime of this process. As TimeInit is
152  done before a daemon fork then this is the start time from the parent
153  daemon start. JRA.
154 ***********************************************************************/
155
156 void get_process_uptime(struct timeval *ret_time)
157 {
158         struct timeval time_now_hires;
159
160         GetTimeOfDay(&time_now_hires);
161         ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
162         ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
163         if (time_now_hires.tv_usec < start_time_hires.tv_usec) {
164                 ret_time->tv_sec -= 1;
165                 ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec);
166         } else {
167                 ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
168         }
169 }
170
171 #if 0
172 /****************************************************************************
173  Return the UTC offset in seconds west of UTC, adjusted for extra time offset.
174 **************************************************************************/
175
176 int TimeDiff(time_t t)
177 {
178         return get_time_zone(t);
179 }
180 #endif
181
182 #define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
183
184 /****************************************************************************
185  Interpret an 8 byte "filetime" structure to a time_t
186  It's originally in "100ns units since jan 1st 1601"
187
188  An 8 byte value of 0xffffffffffffffff will be returned as (time_t)0.
189
190  Returns GMT.
191 ****************************************************************************/
192
193 time_t nt_time_to_unix(NTTIME *nt)
194 {
195         double d;
196         time_t ret;
197         /* The next two lines are a fix needed for the 
198                 broken SCO compiler. JRA. */
199         time_t l_time_min = TIME_T_MIN;
200         time_t l_time_max = TIME_T_MAX;
201
202         if (nt->high == 0 || (nt->high == 0xffffffff && nt->low == 0xffffffff)) {
203                 return(0);
204         }
205
206         d = ((double)nt->high)*4.0*(double)(1<<30);
207         d += (nt->low&0xFFF00000);
208         d *= 1.0e-7;
209  
210         /* now adjust by 369 years to make the secs since 1970 */
211         d -= TIME_FIXUP_CONSTANT;
212
213         if (d <= l_time_min) {
214                 return (l_time_min);
215         }
216
217         if (d >= l_time_max) {
218                 return (l_time_max);
219         }
220
221         ret = (time_t)(d+0.5);
222         return(ret);
223 }
224
225 /****************************************************************************
226  Convert a NTTIME structure to a time_t.
227  It's originally in "100ns units".
228
229  This is an absolute version of the one above.
230  By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
231  if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
232 ****************************************************************************/
233
234 time_t nt_time_to_unix_abs(NTTIME *nt)
235 {
236         double d;
237         time_t ret;
238         /* The next two lines are a fix needed for the 
239            broken SCO compiler. JRA. */
240         time_t l_time_min = TIME_T_MIN;
241         time_t l_time_max = TIME_T_MAX;
242
243         if (nt->high == 0) {
244                 return(0);
245         }
246
247         if (nt->high==0x80000000 && nt->low==0) {
248                 return (time_t)-1;
249         }
250
251         /* reverse the time */
252         /* it's a negative value, turn it to positive */
253         nt->high=~nt->high;
254         nt->low=~nt->low;
255
256         d = ((double)nt->high)*4.0*(double)(1<<30);
257         d += (nt->low&0xFFF00000);
258         d *= 1.0e-7;
259   
260         if (!(l_time_min <= d && d <= l_time_max)) {
261                 return(0);
262         }
263
264         ret = (time_t)(d+0.5);
265
266         return(ret);
267 }
268
269 /****************************************************************************
270  Interprets an nt time into a unix time_t.
271  Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff
272  will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case.
273 ****************************************************************************/
274
275 time_t interpret_long_date(char *p)
276 {
277         NTTIME nt;
278         nt.low = IVAL(p,0);
279         nt.high = IVAL(p,4);
280         if (nt.low == 0xFFFFFFFF && nt.high == 0xFFFFFFFF) {
281                 return (time_t)-1;
282         }
283         return nt_time_to_unix(&nt);
284 }
285
286 /****************************************************************************
287  Put a 8 byte filetime from a time_t. Uses GMT.
288 ****************************************************************************/
289
290 void unix_to_nt_time(NTTIME *nt, time_t t)
291 {
292         double d;
293
294         if (t==0) {
295                 nt->low = 0;
296                 nt->high = 0;
297                 return;
298         }
299         if (t == TIME_T_MAX) {
300                 nt->low = 0xffffffff;
301                 nt->high = 0x7fffffff;
302                 return;
303         }               
304         if (t == (time_t)-1) {
305                 nt->low = 0xffffffff;
306                 nt->high = 0xffffffff;
307                 return;
308         }               
309
310         d = (double)(t);
311         d += TIME_FIXUP_CONSTANT;
312         d *= 1.0e7;
313
314         nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
315         nt->low  = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
316 }
317
318 /****************************************************************************
319  Convert a time_t to a NTTIME structure
320
321  This is an absolute version of the one above.
322  By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
323  If the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM
324 ****************************************************************************/
325
326 void unix_to_nt_time_abs(NTTIME *nt, time_t t)
327 {
328         double d;
329
330         if (t==0) {
331                 nt->low = 0;
332                 nt->high = 0;
333                 return;
334         }
335
336         if (t == TIME_T_MAX) {
337                 nt->low = 0xffffffff;
338                 nt->high = 0x7fffffff;
339                 return;
340         }
341                 
342         if (t == (time_t)-1) {
343                 /* that's what NT uses for infinite */
344                 nt->low = 0x0;
345                 nt->high = 0x80000000;
346                 return;
347         }               
348
349         d = (double)(t);
350         d *= 1.0e7;
351
352         nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
353         nt->low  = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
354
355         /* convert to a negative value */
356         nt->high=~nt->high;
357         nt->low=~nt->low;
358 }
359
360 /****************************************************************************
361  Take a Unix time and convert to an NTTIME structure and place in buffer 
362  pointed to by p.
363 ****************************************************************************/
364
365 void put_long_date(char *p, time_t t)
366 {
367         NTTIME nt;
368         unix_to_nt_time(&nt, t);
369         SIVAL(p, 0, nt.low);
370         SIVAL(p, 4, nt.high);
371 }
372
373 /****************************************************************************
374  Check if it's a null mtime.
375 ****************************************************************************/
376
377 BOOL null_mtime(time_t mtime)
378 {
379         if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
380                 return(True);
381         return(False);
382 }
383
384 /*******************************************************************
385  Create a 16 bit dos packed date.
386 ********************************************************************/
387
388 static uint16 make_dos_date1(struct tm *t)
389 {
390         uint16 ret=0;
391         ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
392         ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
393         return(ret);
394 }
395
396 /*******************************************************************
397  Create a 16 bit dos packed time.
398 ********************************************************************/
399
400 static uint16 make_dos_time1(struct tm *t)
401 {
402         uint16 ret=0;
403         ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
404         ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
405         return(ret);
406 }
407
408 /*******************************************************************
409  Create a 32 bit dos packed date/time from some parameters.
410  This takes a GMT time and returns a packed localtime structure.
411 ********************************************************************/
412
413 static uint32 make_dos_date(time_t unixdate, int zone_offset)
414 {
415         struct tm *t;
416         uint32 ret=0;
417
418         if (unixdate == 0) {
419                 return 0;
420         }
421
422         unixdate -= zone_offset;
423         t = gmtime(&unixdate);
424         if (!t) {
425                 return 0xFFFFFFFF;
426         }
427
428         ret = make_dos_date1(t);
429         ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
430
431         return(ret);
432 }
433
434 /*******************************************************************
435  Put a dos date into a buffer (time/date format).
436  This takes GMT time and puts local time in the buffer.
437 ********************************************************************/
438
439 static void put_dos_date(char *buf,int offset,time_t unixdate, int zone_offset)
440 {
441         uint32 x = make_dos_date(unixdate, zone_offset);
442         SIVAL(buf,offset,x);
443 }
444
445 /*******************************************************************
446  Put a dos date into a buffer (date/time format).
447  This takes GMT time and puts local time in the buffer.
448 ********************************************************************/
449
450 static void put_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset)
451 {
452         uint32 x = make_dos_date(unixdate, zone_offset);
453         x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
454         SIVAL(buf,offset,x);
455 }
456
457 /*******************************************************************
458  Put a dos 32 bit "unix like" date into a buffer. This routine takes
459  GMT and converts it to LOCAL time before putting it (most SMBs assume
460  localtime for this sort of date)
461 ********************************************************************/
462
463 static void put_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset)
464 {
465         if (!null_mtime(unixdate)) {
466                 unixdate -= zone_offset;
467         }
468         SIVAL(buf,offset,unixdate);
469 }
470
471 /*******************************************************************
472  Interpret a 32 bit dos packed date/time to some parameters.
473 ********************************************************************/
474
475 static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
476 {
477         uint32 p0,p1,p2,p3;
478
479         p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; 
480         p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
481
482         *second = 2*(p0 & 0x1F);
483         *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
484         *hour = (p1>>3)&0xFF;
485         *day = (p2&0x1F);
486         *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
487         *year = ((p3>>1)&0xFF) + 80;
488 }
489
490 /*******************************************************************
491  Create a unix date (int GMT) from a dos date (which is actually in
492  localtime).
493 ********************************************************************/
494
495 static time_t make_unix_date(void *date_ptr, int zone_offset)
496 {
497         uint32 dos_date=0;
498         struct tm t;
499         time_t ret;
500
501         dos_date = IVAL(date_ptr,0);
502
503         if (dos_date == 0) {
504                 return 0;
505         }
506   
507         interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
508                         &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
509         t.tm_isdst = -1;
510   
511         ret = timegm(&t);
512
513         ret += zone_offset;
514
515         return(ret);
516 }
517
518 /*******************************************************************
519  Like make_unix_date() but the words are reversed.
520 ********************************************************************/
521
522 static time_t make_unix_date2(void *date_ptr, int zone_offset)
523 {
524         uint32 x,x2;
525
526         x = IVAL(date_ptr,0);
527         x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
528         SIVAL(&x,0,x2);
529
530         return(make_unix_date((void *)&x, zone_offset));
531 }
532
533 /*******************************************************************
534  Create a unix GMT date from a dos date in 32 bit "unix like" format
535  these generally arrive as localtimes, with corresponding DST.
536 ******************************************************************/
537
538 static time_t make_unix_date3(void *date_ptr, int zone_offset)
539 {
540         time_t t = (time_t)IVAL(date_ptr,0);
541         if (!null_mtime(t)) {
542                 t += zone_offset;
543         }
544         return(t);
545 }
546
547 /***************************************************************************
548  Server versions of the above functions.
549 ***************************************************************************/
550
551 void srv_put_dos_date(char *buf,int offset,time_t unixdate)
552 {
553         put_dos_date(buf, offset, unixdate, server_zone_offset);
554 }
555
556 void srv_put_dos_date2(char *buf,int offset, time_t unixdate)
557 {
558         put_dos_date2(buf, offset, unixdate, server_zone_offset);
559 }
560
561 void srv_put_dos_date3(char *buf,int offset,time_t unixdate)
562 {
563         put_dos_date3(buf, offset, unixdate, server_zone_offset);
564 }
565
566 time_t srv_make_unix_date(void *date_ptr)
567 {
568         return make_unix_date(date_ptr, server_zone_offset);
569 }
570
571 time_t srv_make_unix_date2(void *date_ptr)
572 {
573         return make_unix_date2(date_ptr, server_zone_offset);
574 }
575
576 time_t srv_make_unix_date3(void *date_ptr)
577 {
578         return make_unix_date3(date_ptr, server_zone_offset);
579 }
580
581 /***************************************************************************
582  Client versions of the above functions.
583 ***************************************************************************/
584
585 void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate)
586 {
587         put_dos_date(buf, offset, unixdate, cli->serverzone);
588 }
589
590 void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate)
591 {
592         put_dos_date2(buf, offset, unixdate, cli->serverzone);
593 }
594
595 void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate)
596 {
597         put_dos_date3(buf, offset, unixdate, cli->serverzone);
598 }
599
600 time_t cli_make_unix_date(struct cli_state *cli, void *date_ptr)
601 {
602         return make_unix_date(date_ptr, cli->serverzone);
603 }
604
605 time_t cli_make_unix_date2(struct cli_state *cli, void *date_ptr)
606 {
607         return make_unix_date2(date_ptr, cli->serverzone);
608 }
609
610 time_t cli_make_unix_date3(struct cli_state *cli, void *date_ptr)
611 {
612         return make_unix_date3(date_ptr, cli->serverzone);
613 }
614
615 /***************************************************************************
616  Return a HTTP/1.0 time string.
617 ***************************************************************************/
618
619 char *http_timestring(time_t t)
620 {
621         static fstring buf;
622         struct tm *tm = localtime(&t);
623
624         if (!tm)
625                 slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t);
626         else
627 #ifndef HAVE_STRFTIME
628                 fstrcpy(buf, asctime(tm));
629         if(buf[strlen(buf)-1] == '\n')
630                 buf[strlen(buf)-1] = 0;
631 #else /* !HAVE_STRFTIME */
632                 strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
633 #endif /* !HAVE_STRFTIME */
634         return buf;
635 }
636
637 /****************************************************************************
638  Return the date and time as a string
639 ****************************************************************************/
640
641 char *timestring(BOOL hires)
642 {
643         static fstring TimeBuf;
644         struct timeval tp;
645         time_t t;
646         struct tm *tm;
647
648         if (hires) {
649                 GetTimeOfDay(&tp);
650                 t = (time_t)tp.tv_sec;
651         } else {
652                 t = time(NULL);
653         }
654         tm = localtime(&t);
655         if (!tm) {
656                 if (hires) {
657                         slprintf(TimeBuf,
658                                  sizeof(TimeBuf)-1,
659                                  "%ld.%06ld seconds since the Epoch",
660                                  (long)tp.tv_sec, 
661                                  (long)tp.tv_usec);
662                 } else {
663                         slprintf(TimeBuf,
664                                  sizeof(TimeBuf)-1,
665                                  "%ld seconds since the Epoch",
666                                  (long)t);
667                 }
668         } else {
669 #ifdef HAVE_STRFTIME
670                 if (hires) {
671                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
672                         slprintf(TimeBuf+strlen(TimeBuf),
673                                  sizeof(TimeBuf)-1 - strlen(TimeBuf), 
674                                  ".%06ld", 
675                                  (long)tp.tv_usec);
676                 } else {
677                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
678                 }
679 #else
680                 if (hires) {
681                         slprintf(TimeBuf, 
682                                  sizeof(TimeBuf)-1, 
683                                  "%s.%06ld", 
684                                  asctime(tm), 
685                                  (long)tp.tv_usec);
686                 } else {
687                         fstrcpy(TimeBuf, asctime(tm));
688                 }
689 #endif
690         }
691         return(TimeBuf);
692 }
693
694 /****************************************************************************
695  Return the best approximation to a 'create time' under UNIX from a stat
696  structure.
697 ****************************************************************************/
698
699 time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs)
700 {
701         time_t ret, ret1;
702
703         if(S_ISDIR(st->st_mode) && fake_dirs) {
704                 return (time_t)315493200L;          /* 1/1/1980 */
705         }
706     
707         ret = MIN(st->st_ctime, st->st_mtime);
708         ret1 = MIN(ret, st->st_atime);
709
710         if(ret1 != (time_t)0) {
711                 return ret1;
712         }
713
714         /*
715          * One of ctime, mtime or atime was zero (probably atime).
716          * Just return MIN(ctime, mtime).
717          */
718         return ret;
719 }
720
721 /****************************************************************************
722  Initialise an NTTIME to -1, which means "unknown" or "don't expire".
723 ****************************************************************************/
724
725 void init_nt_time(NTTIME *nt)
726 {
727         nt->high = 0x7FFFFFFF;
728         nt->low = 0xFFFFFFFF;
729 }
730
731 /****************************************************************************
732  Check if NTTIME is 0.
733 ****************************************************************************/
734
735 BOOL nt_time_is_zero(NTTIME *nt)
736 {
737         if(nt->high==0) {
738                 return True;
739         }
740         return False;
741 }
742
743 /****************************************************************************
744  Check if two NTTIMEs are the same.
745 ****************************************************************************/
746
747 BOOL nt_time_equals(NTTIME *nt1, NTTIME *nt2)
748 {
749         return (nt1->high == nt2->high && nt1->low == nt2->low);
750 }
751
752 /****************************************************************************
753  Return a timeval difference in usec.
754 ****************************************************************************/
755
756 SMB_BIG_INT usec_time_diff(const struct timeval *larget, const struct timeval *smallt)
757 {
758         SMB_BIG_INT sec_diff = larget->tv_sec - smallt->tv_sec;
759         return (sec_diff * 1000000) + (SMB_BIG_INT)(larget->tv_usec - smallt->tv_usec);
760 }
761
762 /****************************************************************************
763  Return a timeval struct with the given elements.
764 ****************************************************************************/
765
766 struct timeval timeval_set(uint32_t secs, uint32_t usecs)
767 {
768         struct timeval tv;
769         tv.tv_sec = secs;
770         tv.tv_usec = usecs;
771         return tv;
772 }
773
774 /****************************************************************************
775  Return a zero timeval.
776 ****************************************************************************/
777
778 struct timeval timeval_zero(void)
779 {
780         return timeval_set(0,0);
781 }
782
783 /****************************************************************************
784  Return True if a timeval is zero.
785 ****************************************************************************/
786
787 BOOL timeval_is_zero(const struct timeval *tv)
788 {
789         return tv->tv_sec == 0 && tv->tv_usec == 0;
790 }
791
792 /****************************************************************************
793  Return a timeval for the current time.
794 ****************************************************************************/
795
796 struct timeval timeval_current(void)
797 {
798         struct timeval tv;
799         GetTimeOfDay(&tv);
800         return tv;
801 }
802
803 /****************************************************************************
804  Return a timeval ofs microseconds after tv.
805 ****************************************************************************/
806
807 struct timeval timeval_add(const struct timeval *tv,
808                            uint32_t secs, uint32_t usecs)
809 {
810         struct timeval tv2 = *tv;
811         tv2.tv_sec += secs;
812         tv2.tv_usec += usecs;
813         tv2.tv_sec += tv2.tv_usec / 1000000;
814         tv2.tv_usec = tv2.tv_usec % 1000000;
815         return tv2;
816 }
817
818 /****************************************************************************
819  Return the sum of two timeval structures.
820 ****************************************************************************/
821
822 struct timeval timeval_sum(const struct timeval *tv1,
823                            const struct timeval *tv2)
824 {
825         return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
826 }
827
828 /****************************************************************************
829  Return a timeval secs/usecs into the future.
830 ****************************************************************************/
831
832 struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
833 {
834         struct timeval tv = timeval_current();
835         return timeval_add(&tv, secs, usecs);
836 }
837
838 /****************************************************************************
839  Compare two timeval structures. 
840  Return -1 if tv1 < tv2
841  Return 0 if tv1 == tv2
842  Return 1 if tv1 > tv2
843 ****************************************************************************/
844
845 int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
846 {
847         if (tv1->tv_sec  > tv2->tv_sec) {
848                 return 1;
849         }
850         if (tv1->tv_sec  < tv2->tv_sec) {
851                 return -1;
852         }
853         if (tv1->tv_usec > tv2->tv_usec) {
854                 return 1;
855         }
856         if (tv1->tv_usec < tv2->tv_usec) {
857                 return -1;
858         }
859         return 0;
860 }
861
862 /****************************************************************************
863  Return the difference between two timevals as a timeval.
864  If tv1 comes after tv2, then return a zero timeval
865  (this is *tv2 - *tv1).
866 ****************************************************************************/
867
868 struct timeval timeval_until(const struct timeval *tv1,
869                              const struct timeval *tv2)
870 {
871         struct timeval t;
872         if (timeval_compare(tv1, tv2) >= 0) {
873                 return timeval_zero();
874         }
875         t.tv_sec = tv2->tv_sec - tv1->tv_sec;
876         if (tv1->tv_usec > tv2->tv_usec) {
877                 t.tv_sec--;
878                 t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
879         } else {
880                 t.tv_usec = tv2->tv_usec - tv1->tv_usec;
881         }
882         return t;
883 }
884
885 /****************************************************************************
886  Return the lesser of two timevals.
887 ****************************************************************************/
888
889 struct timeval timeval_min(const struct timeval *tv1,
890                            const struct timeval *tv2)
891 {
892         if (tv1->tv_sec < tv2->tv_sec) {
893                 return *tv1;
894         }
895         if (tv1->tv_sec > tv2->tv_sec) {
896                 return *tv2;
897         }
898         if (tv1->tv_usec < tv2->tv_usec) {
899                 return *tv1;
900         }
901         return *tv2;
902 }
903
904 /****************************************************************************
905  Return the greater of two timevals.
906 ****************************************************************************/
907
908 struct timeval timeval_max(const struct timeval *tv1,
909                            const struct timeval *tv2)
910 {
911         if (tv1->tv_sec > tv2->tv_sec) {
912                 return *tv1;
913         }
914         if (tv1->tv_sec < tv2->tv_sec) {
915                 return *tv2;
916         }
917         if (tv1->tv_usec > tv2->tv_usec) {
918                 return *tv1;
919         }
920         return *tv2;
921 }
922
923 /****************************************************************************
924  Convert ASN.1 GeneralizedTime string to unix-time.
925  Returns 0 on failure; Currently ignores timezone. 
926 ****************************************************************************/
927
928 time_t generalized_to_unix_time(const char *str)
929
930         struct tm tm;
931
932         ZERO_STRUCT(tm);
933
934         if (sscanf(str, "%4d%2d%2d%2d%2d%2d", 
935                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
936                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
937                 return 0;
938         }
939         tm.tm_year -= 1900;
940         tm.tm_mon -= 1;
941
942         return timegm(&tm);
943 }