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