r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[kai/samba.git] / source3 / 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 /*******************************************************************
43  External access to time_t_min and time_t_max.
44 ********************************************************************/
45
46 time_t get_time_t_max(void)
47 {
48         return TIME_T_MAX;
49 }
50
51 /*******************************************************************
52  A gettimeofday wrapper.
53 ********************************************************************/
54
55 void GetTimeOfDay(struct timeval *tval)
56 {
57 #ifdef HAVE_GETTIMEOFDAY_TZ
58         gettimeofday(tval,NULL);
59 #else
60         gettimeofday(tval);
61 #endif
62 }
63
64 #define TM_YEAR_BASE 1900
65
66 /*******************************************************************
67  Yield the difference between *A and *B, in seconds, ignoring leap seconds.
68 ********************************************************************/
69
70 static int tm_diff(struct tm *a, struct tm *b)
71 {
72         int ay = a->tm_year + (TM_YEAR_BASE - 1);
73         int by = b->tm_year + (TM_YEAR_BASE - 1);
74         int intervening_leap_days = (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
75         int years = ay - by;
76         int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
77         int hours = 24*days + (a->tm_hour - b->tm_hour);
78         int minutes = 60*hours + (a->tm_min - b->tm_min);
79         int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
80
81         return seconds;
82 }
83
84 /*******************************************************************
85  Return the UTC offset in seconds west of UTC, or 0 if it cannot be determined.
86 ******************************************************************/
87
88 int get_time_zone(time_t t)
89 {
90         struct tm *tm = gmtime(&t);
91         struct tm tm_utc;
92
93         if (!tm) {
94                 return 0;
95         }
96         tm_utc = *tm;
97         tm = localtime(&t);
98         if (!tm) {
99                 return 0;
100         }
101         return tm_diff(&tm_utc,tm) + 60*extra_time_offset;
102 }
103
104 /*******************************************************************
105  Accessor function for the server time zone offset.
106  set_server_zone_offset() must have been called first.
107 ******************************************************************/
108
109 static int server_zone_offset;
110
111 int get_server_zone_offset(void)
112 {
113         return server_zone_offset;
114 }
115
116 /*******************************************************************
117  Initialize the server time zone offset. Called when a client connects.
118 ******************************************************************/
119
120 int set_server_zone_offset(time_t t)
121 {
122         server_zone_offset = get_time_zone(t);
123         return server_zone_offset;
124 }
125
126 /*******************************************************************
127  Re-read the smb serverzone value.
128 ******************************************************************/
129
130 static struct timeval start_time_hires;
131
132 void TimeInit(void)
133 {
134         set_server_zone_offset(time(NULL));
135
136         DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset));
137
138         /* Save the start time of this process. */
139         if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) {
140                 GetTimeOfDay(&start_time_hires);
141         }
142 }
143
144 /**********************************************************************
145  Return a timeval struct of the uptime of this process. As TimeInit is
146  done before a daemon fork then this is the start time from the parent
147  daemon start. JRA.
148 ***********************************************************************/
149
150 void get_process_uptime(struct timeval *ret_time)
151 {
152         struct timeval time_now_hires;
153
154         GetTimeOfDay(&time_now_hires);
155         ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
156         if (time_now_hires.tv_usec < start_time_hires.tv_usec) {
157                 ret_time->tv_sec -= 1;
158                 ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec);
159         } else {
160                 ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
161         }
162 }
163
164 #if 0
165 /****************************************************************************
166  Return the UTC offset in seconds west of UTC, adjusted for extra time offset.
167 **************************************************************************/
168
169 int TimeDiff(time_t t)
170 {
171         return get_time_zone(t);
172 }
173 #endif
174
175 #define TIME_FIXUP_CONSTANT (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
176
177 /****************************************************************************
178  Interpret an 8 byte "filetime" structure to a time_t
179  It's originally in "100ns units since jan 1st 1601"
180
181  An 8 byte value of 0xffffffffffffffff will be returned as (time_t)0.
182
183  Returns GMT.
184 ****************************************************************************/
185
186 time_t nt_time_to_unix(NTTIME *nt)
187 {
188         double d;
189         time_t ret;
190         /* The next two lines are a fix needed for the 
191                 broken SCO compiler. JRA. */
192         time_t l_time_min = TIME_T_MIN;
193         time_t l_time_max = TIME_T_MAX;
194
195         if (nt->high == 0 || (nt->high == 0xffffffff && nt->low == 0xffffffff)) {
196                 return(0);
197         }
198
199         d = ((double)nt->high)*4.0*(double)(1<<30);
200         d += (nt->low&0xFFF00000);
201         d *= 1.0e-7;
202  
203         /* now adjust by 369 years to make the secs since 1970 */
204         d -= TIME_FIXUP_CONSTANT;
205
206         if (d <= l_time_min) {
207                 return (l_time_min);
208         }
209
210         if (d >= l_time_max) {
211                 return (l_time_max);
212         }
213
214         ret = (time_t)(d+0.5);
215         return(ret);
216 }
217
218 /****************************************************************************
219  Convert a NTTIME structure to a time_t.
220  It's originally in "100ns units".
221
222  This is an absolute version of the one above.
223  By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
224  if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
225 ****************************************************************************/
226
227 time_t nt_time_to_unix_abs(const NTTIME *nt)
228 {
229         double d;
230         time_t ret;
231         /* The next two lines are a fix needed for the 
232            broken SCO compiler. JRA. */
233         time_t l_time_min = TIME_T_MIN;
234         time_t l_time_max = TIME_T_MAX;
235         NTTIME neg_nt;
236
237         if (nt->high == 0) {
238                 return(0);
239         }
240
241         if (nt->high==0x80000000 && nt->low==0) {
242                 return (time_t)-1;
243         }
244
245         /* reverse the time */
246         /* it's a negative value, turn it to positive */
247         neg_nt.high=~nt->high;
248         neg_nt.low=~nt->low;
249
250         d = ((double)neg_nt.high)*4.0*(double)(1<<30);
251         d += (neg_nt.low&0xFFF00000);
252         d *= 1.0e-7;
253   
254         if (!(l_time_min <= d && d <= l_time_max)) {
255                 return(0);
256         }
257
258         ret = (time_t)(d+0.5);
259
260         return(ret);
261 }
262
263 /****************************************************************************
264  Interprets an nt time into a unix time_t.
265  Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff
266  will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case.
267 ****************************************************************************/
268
269 time_t interpret_long_date(char *p)
270 {
271         NTTIME nt;
272         nt.low = IVAL(p,0);
273         nt.high = IVAL(p,4);
274         if (nt.low == 0xFFFFFFFF && nt.high == 0xFFFFFFFF) {
275                 return (time_t)-1;
276         }
277         return nt_time_to_unix(&nt);
278 }
279
280 /****************************************************************************
281  Put a 8 byte filetime from a time_t. Uses GMT.
282 ****************************************************************************/
283
284 void unix_to_nt_time(NTTIME *nt, time_t t)
285 {
286         double d;
287
288         if (t==0) {
289                 nt->low = 0;
290                 nt->high = 0;
291                 return;
292         }
293         if (t == TIME_T_MAX) {
294                 nt->low = 0xffffffff;
295                 nt->high = 0x7fffffff;
296                 return;
297         }               
298         if (t == (time_t)-1) {
299                 nt->low = 0xffffffff;
300                 nt->high = 0xffffffff;
301                 return;
302         }               
303
304         d = (double)(t);
305         d += TIME_FIXUP_CONSTANT;
306         d *= 1.0e7;
307
308         nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
309         nt->low  = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
310 }
311
312 /****************************************************************************
313  Convert a time_t to a NTTIME structure
314
315  This is an absolute version of the one above.
316  By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
317  If the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM
318 ****************************************************************************/
319
320 void unix_to_nt_time_abs(NTTIME *nt, time_t t)
321 {
322         double d;
323
324         if (t==0) {
325                 nt->low = 0;
326                 nt->high = 0;
327                 return;
328         }
329
330         if (t == TIME_T_MAX) {
331                 nt->low = 0xffffffff;
332                 nt->high = 0x7fffffff;
333                 return;
334         }
335                 
336         if (t == (time_t)-1) {
337                 /* that's what NT uses for infinite */
338                 nt->low = 0x0;
339                 nt->high = 0x80000000;
340                 return;
341         }               
342
343         d = (double)(t);
344         d *= 1.0e7;
345
346         nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30))));
347         nt->low  = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30));
348
349         /* convert to a negative value */
350         nt->high=~nt->high;
351         nt->low=~nt->low;
352 }
353
354 /****************************************************************************
355  Take a Unix time and convert to an NTTIME structure and place in buffer 
356  pointed to by p.
357 ****************************************************************************/
358
359 void put_long_date(char *p, time_t t)
360 {
361         NTTIME nt;
362         unix_to_nt_time(&nt, t);
363         SIVAL(p, 0, nt.low);
364         SIVAL(p, 4, nt.high);
365 }
366
367 /****************************************************************************
368  Check if it's a null mtime.
369 ****************************************************************************/
370
371 BOOL null_mtime(time_t mtime)
372 {
373         if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
374                 return(True);
375         return(False);
376 }
377
378 /*******************************************************************
379  Create a 16 bit dos packed date.
380 ********************************************************************/
381
382 static uint16 make_dos_date1(struct tm *t)
383 {
384         uint16 ret=0;
385         ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
386         ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
387         return(ret);
388 }
389
390 /*******************************************************************
391  Create a 16 bit dos packed time.
392 ********************************************************************/
393
394 static uint16 make_dos_time1(struct tm *t)
395 {
396         uint16 ret=0;
397         ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3));
398         ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
399         return(ret);
400 }
401
402 /*******************************************************************
403  Create a 32 bit dos packed date/time from some parameters.
404  This takes a GMT time and returns a packed localtime structure.
405 ********************************************************************/
406
407 static uint32 make_dos_date(time_t unixdate, int zone_offset)
408 {
409         struct tm *t;
410         uint32 ret=0;
411
412         if (unixdate == 0) {
413                 return 0;
414         }
415
416         unixdate -= zone_offset;
417         t = gmtime(&unixdate);
418         if (!t) {
419                 return 0xFFFFFFFF;
420         }
421
422         ret = make_dos_date1(t);
423         ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
424
425         return(ret);
426 }
427
428 /*******************************************************************
429  Put a dos date into a buffer (time/date format).
430  This takes GMT time and puts local time in the buffer.
431 ********************************************************************/
432
433 static void put_dos_date(char *buf,int offset,time_t unixdate, int zone_offset)
434 {
435         uint32 x = make_dos_date(unixdate, zone_offset);
436         SIVAL(buf,offset,x);
437 }
438
439 /*******************************************************************
440  Put a dos date into a buffer (date/time format).
441  This takes GMT time and puts local time in the buffer.
442 ********************************************************************/
443
444 static void put_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset)
445 {
446         uint32 x = make_dos_date(unixdate, zone_offset);
447         x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
448         SIVAL(buf,offset,x);
449 }
450
451 /*******************************************************************
452  Put a dos 32 bit "unix like" date into a buffer. This routine takes
453  GMT and converts it to LOCAL time before putting it (most SMBs assume
454  localtime for this sort of date)
455 ********************************************************************/
456
457 static void put_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset)
458 {
459         if (!null_mtime(unixdate)) {
460                 unixdate -= zone_offset;
461         }
462         SIVAL(buf,offset,unixdate);
463 }
464
465 /*******************************************************************
466  Interpret a 32 bit dos packed date/time to some parameters.
467 ********************************************************************/
468
469 static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second)
470 {
471         uint32 p0,p1,p2,p3;
472
473         p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; 
474         p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
475
476         *second = 2*(p0 & 0x1F);
477         *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
478         *hour = (p1>>3)&0xFF;
479         *day = (p2&0x1F);
480         *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
481         *year = ((p3>>1)&0xFF) + 80;
482 }
483
484 /*******************************************************************
485  Create a unix date (int GMT) from a dos date (which is actually in
486  localtime).
487 ********************************************************************/
488
489 static time_t make_unix_date(void *date_ptr, int zone_offset)
490 {
491         uint32 dos_date=0;
492         struct tm t;
493         time_t ret;
494
495         dos_date = IVAL(date_ptr,0);
496
497         if (dos_date == 0) {
498                 return 0;
499         }
500   
501         interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
502                         &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
503         t.tm_isdst = -1;
504   
505         ret = timegm(&t);
506
507         ret += zone_offset;
508
509         return(ret);
510 }
511
512 /*******************************************************************
513  Like make_unix_date() but the words are reversed.
514 ********************************************************************/
515
516 static time_t make_unix_date2(void *date_ptr, int zone_offset)
517 {
518         uint32 x,x2;
519
520         x = IVAL(date_ptr,0);
521         x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
522         SIVAL(&x,0,x2);
523
524         return(make_unix_date((void *)&x, zone_offset));
525 }
526
527 /*******************************************************************
528  Create a unix GMT date from a dos date in 32 bit "unix like" format
529  these generally arrive as localtimes, with corresponding DST.
530 ******************************************************************/
531
532 static time_t make_unix_date3(void *date_ptr, int zone_offset)
533 {
534         time_t t = (time_t)IVAL(date_ptr,0);
535         if (!null_mtime(t)) {
536                 t += zone_offset;
537         }
538         return(t);
539 }
540
541 /***************************************************************************
542  Server versions of the above functions.
543 ***************************************************************************/
544
545 void srv_put_dos_date(char *buf,int offset,time_t unixdate)
546 {
547         put_dos_date(buf, offset, unixdate, server_zone_offset);
548 }
549
550 void srv_put_dos_date2(char *buf,int offset, time_t unixdate)
551 {
552         put_dos_date2(buf, offset, unixdate, server_zone_offset);
553 }
554
555 void srv_put_dos_date3(char *buf,int offset,time_t unixdate)
556 {
557         put_dos_date3(buf, offset, unixdate, server_zone_offset);
558 }
559
560 time_t srv_make_unix_date(void *date_ptr)
561 {
562         return make_unix_date(date_ptr, server_zone_offset);
563 }
564
565 time_t srv_make_unix_date2(void *date_ptr)
566 {
567         return make_unix_date2(date_ptr, server_zone_offset);
568 }
569
570 time_t srv_make_unix_date3(void *date_ptr)
571 {
572         return make_unix_date3(date_ptr, server_zone_offset);
573 }
574
575 /***************************************************************************
576  Client versions of the above functions.
577 ***************************************************************************/
578
579 void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate)
580 {
581         put_dos_date(buf, offset, unixdate, cli->serverzone);
582 }
583
584 void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate)
585 {
586         put_dos_date2(buf, offset, unixdate, cli->serverzone);
587 }
588
589 void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate)
590 {
591         put_dos_date3(buf, offset, unixdate, cli->serverzone);
592 }
593
594 time_t cli_make_unix_date(struct cli_state *cli, void *date_ptr)
595 {
596         return make_unix_date(date_ptr, cli->serverzone);
597 }
598
599 time_t cli_make_unix_date2(struct cli_state *cli, void *date_ptr)
600 {
601         return make_unix_date2(date_ptr, cli->serverzone);
602 }
603
604 time_t cli_make_unix_date3(struct cli_state *cli, void *date_ptr)
605 {
606         return make_unix_date3(date_ptr, cli->serverzone);
607 }
608
609 /***************************************************************************
610  Return a HTTP/1.0 time string.
611 ***************************************************************************/
612
613 char *http_timestring(time_t t)
614 {
615         static fstring buf;
616         struct tm *tm = localtime(&t);
617
618         if (!tm) {
619                 slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t);
620         } else {
621 #ifndef HAVE_STRFTIME
622                 const char *asct = asctime(tm);
623                 fstrcpy(buf, asct ? asct : "unknown");
624         }
625         if(buf[strlen(buf)-1] == '\n') {
626                 buf[strlen(buf)-1] = 0;
627 #else /* !HAVE_STRFTIME */
628                 strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
629 #endif /* !HAVE_STRFTIME */
630         }
631         return buf;
632 }
633
634 /****************************************************************************
635  Return the date and time as a string
636 ****************************************************************************/
637
638 char *current_timestring(BOOL hires)
639 {
640         static fstring TimeBuf;
641         struct timeval tp;
642         time_t t;
643         struct tm *tm;
644
645         if (hires) {
646                 GetTimeOfDay(&tp);
647                 t = (time_t)tp.tv_sec;
648         } else {
649                 t = time(NULL);
650         }
651         tm = localtime(&t);
652         if (!tm) {
653                 if (hires) {
654                         slprintf(TimeBuf,
655                                  sizeof(TimeBuf)-1,
656                                  "%ld.%06ld seconds since the Epoch",
657                                  (long)tp.tv_sec, 
658                                  (long)tp.tv_usec);
659                 } else {
660                         slprintf(TimeBuf,
661                                  sizeof(TimeBuf)-1,
662                                  "%ld seconds since the Epoch",
663                                  (long)t);
664                 }
665         } else {
666 #ifdef HAVE_STRFTIME
667                 if (hires) {
668                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
669                         slprintf(TimeBuf+strlen(TimeBuf),
670                                  sizeof(TimeBuf)-1 - strlen(TimeBuf), 
671                                  ".%06ld", 
672                                  (long)tp.tv_usec);
673                 } else {
674                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
675                 }
676 #else
677                 if (hires) {
678                         const char *asct = asctime(tm);
679                         slprintf(TimeBuf, 
680                                  sizeof(TimeBuf)-1, 
681                                  "%s.%06ld", 
682                                  asct ? asct : "unknown", 
683                                  (long)tp.tv_usec);
684                 } else {
685                         const char *asct = asctime(tm);
686                         fstrcpy(TimeBuf, asct ? asct : "unknown");
687                 }
688 #endif
689         }
690         return(TimeBuf);
691 }
692
693 /****************************************************************************
694  Return the best approximation to a 'create time' under UNIX from a stat
695  structure.
696 ****************************************************************************/
697
698 time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs)
699 {
700         time_t ret, ret1;
701
702         if(S_ISDIR(st->st_mode) && fake_dirs) {
703                 return (time_t)315493200L;          /* 1/1/1980 */
704         }
705     
706         ret = MIN(st->st_ctime, st->st_mtime);
707         ret1 = MIN(ret, st->st_atime);
708
709         if(ret1 != (time_t)0) {
710                 return ret1;
711         }
712
713         /*
714          * One of ctime, mtime or atime was zero (probably atime).
715          * Just return MIN(ctime, mtime).
716          */
717         return ret;
718 }
719
720 /****************************************************************************
721  Initialise an NTTIME to -1, which means "unknown" or "don't expire".
722 ****************************************************************************/
723
724 void init_nt_time(NTTIME *nt)
725 {
726         nt->high = 0x7FFFFFFF;
727         nt->low = 0xFFFFFFFF;
728 }
729
730 BOOL nt_time_is_set(const NTTIME *nt)
731 {
732         if ((nt->high == 0x7FFFFFFF) && (nt->low == 0xFFFFFFFF)) {
733                 return False;
734         }
735
736         if ((nt->high == 0x80000000) && (nt->low == 0)) {
737                 return False;
738         }
739
740         return True;
741 }
742
743 /****************************************************************************
744  Check if NTTIME is 0.
745 ****************************************************************************/
746
747 BOOL nt_time_is_zero(const NTTIME *nt)
748 {
749         if(nt->high==0) {
750                 return True;
751         }
752         return False;
753 }
754
755 /****************************************************************************
756  Check if two NTTIMEs are the same.
757 ****************************************************************************/
758
759 BOOL nt_time_equals(const NTTIME *nt1, const NTTIME *nt2)
760 {
761         return (nt1->high == nt2->high && nt1->low == nt2->low);
762 }
763
764 /****************************************************************************
765  Return a timeval difference in usec.
766 ****************************************************************************/
767
768 SMB_BIG_INT usec_time_diff(const struct timeval *larget, const struct timeval *smallt)
769 {
770         SMB_BIG_INT sec_diff = larget->tv_sec - smallt->tv_sec;
771         return (sec_diff * 1000000) + (SMB_BIG_INT)(larget->tv_usec - smallt->tv_usec);
772 }
773
774 /****************************************************************************
775  Return a timeval struct with the given elements.
776 ****************************************************************************/
777
778 struct timeval timeval_set(uint32_t secs, uint32_t usecs)
779 {
780         struct timeval tv;
781         tv.tv_sec = secs;
782         tv.tv_usec = usecs;
783         return tv;
784 }
785
786 /****************************************************************************
787  Return a zero timeval.
788 ****************************************************************************/
789
790 struct timeval timeval_zero(void)
791 {
792         return timeval_set(0,0);
793 }
794
795 /****************************************************************************
796  Return True if a timeval is zero.
797 ****************************************************************************/
798
799 BOOL timeval_is_zero(const struct timeval *tv)
800 {
801         return tv->tv_sec == 0 && tv->tv_usec == 0;
802 }
803
804 /****************************************************************************
805  Return a timeval for the current time.
806 ****************************************************************************/
807
808 struct timeval timeval_current(void)
809 {
810         struct timeval tv;
811         GetTimeOfDay(&tv);
812         return tv;
813 }
814
815 /****************************************************************************
816  Return a timeval ofs microseconds after tv.
817 ****************************************************************************/
818
819 struct timeval timeval_add(const struct timeval *tv,
820                            uint32_t secs, uint32_t usecs)
821 {
822         struct timeval tv2 = *tv;
823         tv2.tv_sec += secs;
824         tv2.tv_usec += usecs;
825         tv2.tv_sec += tv2.tv_usec / 1000000;
826         tv2.tv_usec = tv2.tv_usec % 1000000;
827         return tv2;
828 }
829
830 /****************************************************************************
831  Return the sum of two timeval structures.
832 ****************************************************************************/
833
834 struct timeval timeval_sum(const struct timeval *tv1,
835                            const struct timeval *tv2)
836 {
837         return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
838 }
839
840 /****************************************************************************
841  Return a timeval secs/usecs into the future.
842 ****************************************************************************/
843
844 struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
845 {
846         struct timeval tv = timeval_current();
847         return timeval_add(&tv, secs, usecs);
848 }
849
850 /****************************************************************************
851  Compare two timeval structures. 
852  Return -1 if tv1 < tv2
853  Return 0 if tv1 == tv2
854  Return 1 if tv1 > tv2
855 ****************************************************************************/
856
857 int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
858 {
859         if (tv1->tv_sec  > tv2->tv_sec) {
860                 return 1;
861         }
862         if (tv1->tv_sec  < tv2->tv_sec) {
863                 return -1;
864         }
865         if (tv1->tv_usec > tv2->tv_usec) {
866                 return 1;
867         }
868         if (tv1->tv_usec < tv2->tv_usec) {
869                 return -1;
870         }
871         return 0;
872 }
873
874 /****************************************************************************
875  Return the difference between two timevals as a timeval.
876  If tv1 comes after tv2, then return a zero timeval
877  (this is *tv2 - *tv1).
878 ****************************************************************************/
879
880 struct timeval timeval_until(const struct timeval *tv1,
881                              const struct timeval *tv2)
882 {
883         struct timeval t;
884         if (timeval_compare(tv1, tv2) >= 0) {
885                 return timeval_zero();
886         }
887         t.tv_sec = tv2->tv_sec - tv1->tv_sec;
888         if (tv1->tv_usec > tv2->tv_usec) {
889                 t.tv_sec--;
890                 t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
891         } else {
892                 t.tv_usec = tv2->tv_usec - tv1->tv_usec;
893         }
894         return t;
895 }
896
897 /****************************************************************************
898  Return the lesser of two timevals.
899 ****************************************************************************/
900
901 struct timeval timeval_min(const struct timeval *tv1,
902                            const struct timeval *tv2)
903 {
904         if (tv1->tv_sec < tv2->tv_sec) {
905                 return *tv1;
906         }
907         if (tv1->tv_sec > tv2->tv_sec) {
908                 return *tv2;
909         }
910         if (tv1->tv_usec < tv2->tv_usec) {
911                 return *tv1;
912         }
913         return *tv2;
914 }
915
916 /****************************************************************************
917  Return the greater of two timevals.
918 ****************************************************************************/
919
920 struct timeval timeval_max(const struct timeval *tv1,
921                            const struct timeval *tv2)
922 {
923         if (tv1->tv_sec > tv2->tv_sec) {
924                 return *tv1;
925         }
926         if (tv1->tv_sec < tv2->tv_sec) {
927                 return *tv2;
928         }
929         if (tv1->tv_usec > tv2->tv_usec) {
930                 return *tv1;
931         }
932         return *tv2;
933 }
934
935 /****************************************************************************
936  Convert ASN.1 GeneralizedTime string to unix-time.
937  Returns 0 on failure; Currently ignores timezone. 
938 ****************************************************************************/
939
940 time_t generalized_to_unix_time(const char *str)
941
942         struct tm tm;
943
944         ZERO_STRUCT(tm);
945
946         if (sscanf(str, "%4d%2d%2d%2d%2d%2d", 
947                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
948                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
949                 return 0;
950         }
951         tm.tm_year -= 1900;
952         tm.tm_mon -= 1;
953
954         return timegm(&tm);
955 }
956
957 /****************************************************************************
958  Return all the possible time fields from a stat struct as a timespec.
959 ****************************************************************************/
960
961 struct timespec get_atimespec(SMB_STRUCT_STAT *pst)
962 {
963 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
964         struct timespec ret;
965
966         /* Old system - no ns timestamp. */
967         ret.tv_sec = pst->st_atime;
968         ret.tv_nsec = 0;
969         return ret;
970 #else
971 #if defined(HAVE_STAT_ST_ATIM)
972         return pst->st_atim;
973 #elif defined(HAVE_STAT_ST_ATIMENSEC)
974         struct timespec ret;
975         ret.tv_sec = pst->st_atime;
976         ret.tv_nsec = pst->st_atimensec;
977         return ret;
978 #else
979 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
980 #endif
981 #endif
982 }
983
984 struct timespec get_mtimespec(SMB_STRUCT_STAT *pst)
985 {
986 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
987         struct timespec ret;
988
989         /* Old system - no ns timestamp. */
990         ret.tv_sec = pst->st_mtime;
991         ret.tv_nsec = 0;
992         return ret;
993 #else
994 #if defined(HAVE_STAT_ST_MTIM)
995         return pst->st_mtim;
996 #elif defined(HAVE_STAT_ST_MTIMENSEC)
997         struct timespec ret;
998         ret.tv_sec = pst->st_mtime;
999         ret.tv_nsec = pst->st_mtimensec;
1000         return ret;
1001 #else
1002 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
1003 #endif
1004 #endif
1005 }
1006
1007 struct timespec get_ctimespec(SMB_STRUCT_STAT *pst)
1008 {
1009 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
1010         struct timespec ret;
1011
1012         /* Old system - no ns timestamp. */
1013         ret.tv_sec = pst->st_ctime;
1014         ret.tv_nsec = 0;
1015         return ret;
1016 #else
1017 #if defined(HAVE_STAT_ST_CTIM)
1018         return pst->st_ctim;
1019 #elif defined(HAVE_STAT_ST_CTIMENSEC)
1020         struct timespec ret;
1021         ret.tv_sec = pst->st_ctime;
1022         ret.tv_nsec = pst->st_ctimensec;
1023         return ret;
1024 #else
1025 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
1026 #endif
1027 #endif
1028 }
1029
1030 #if 0
1031 /****************************************************************************
1032  Return the best approximation to a 'create time' under UNIX from a stat
1033  structure.
1034 ****************************************************************************/
1035
1036 struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs)
1037 {
1038         time_t ret, ret1;
1039
1040         if(S_ISDIR(st->st_mode) && fake_dirs) {
1041                 return (time_t)315493200L;          /* 1/1/1980 */
1042         }
1043     
1044         ret = MIN(st->st_ctime, st->st_mtime);
1045         ret1 = MIN(ret, st->st_atime);
1046
1047         if(ret1 != (time_t)0) {
1048                 return ret1;
1049         }
1050
1051         /*
1052          * One of ctime, mtime or atime was zero (probably atime).
1053          * Just return MIN(ctime, mtime).
1054          */
1055         return ret;
1056 }
1057 #endif
1058
1059
1060 /**
1061  Return the date and time as a string
1062 **/
1063 char *timestring(TALLOC_CTX *mem_ctx, time_t t)
1064 {
1065         char *TimeBuf;
1066         char tempTime[80];
1067         struct tm *tm;
1068
1069         tm = localtime(&t);
1070         if (!tm) {
1071                 return talloc_asprintf(mem_ctx,
1072                                        "%ld seconds since the Epoch",
1073                                        (long)t);
1074         }
1075
1076 #ifdef HAVE_STRFTIME
1077         /* some versions of gcc complain about using %c. This is a bug
1078            in the gcc warning, not a bug in this code. See a recent
1079            strftime() manual page for details.
1080          */
1081         strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
1082         TimeBuf = talloc_strdup(mem_ctx, tempTime);
1083 #else
1084         TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
1085 #endif
1086
1087         return TimeBuf;
1088 }
1089
1090
1091 /**
1092   return a talloced string representing a NTTIME for human consumption
1093 */
1094 const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt)
1095 {
1096         time_t t;
1097         if (nt.low == 0 && nt.high == 0) {
1098                 return "NTTIME(0)";
1099         }
1100         t = nt_time_to_unix(&nt);
1101         return timestring(mem_ctx, t);
1102 }
1103
1104 /****************************************************************************
1105  Utility function that always returns a const string even if localtime
1106  and asctime fail.
1107 ****************************************************************************/
1108
1109 const char *time_to_asc(const time_t *t)
1110 {
1111         const char *asct;
1112         struct tm *lt = localtime(t);
1113
1114         if (!lt) {
1115                 return "unknown time";
1116         }
1117
1118         asct = asctime(lt);
1119         if (!asct) {
1120                 return "unknown time";
1121         }
1122         return asct;
1123 }