3abe233c4ffcdbac9648f4d43b4e0435635c7ec9
[sfrench/samba-autobuild/.git] / source3 / lib / time.c
1 /* 
2    Unix SMB/CIFS implementation.
3    time handling functions
4
5    Copyright (C) Andrew Tridgell                1992-2004
6    Copyright (C) Stefan (metze) Metzmacher      2002   
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /**
26  * @file
27  * @brief time handling functions
28  */
29
30
31 #ifndef TIME_T_MIN
32 #define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \
33                     : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
34 #endif
35 #ifndef TIME_T_MAX
36 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
37 #endif
38
39 #define NTTIME_INFINITY (NTTIME)0x8000000000000000LL
40
41 /**
42  External access to time_t_min and time_t_max.
43 **/
44 time_t get_time_t_max(void)
45 {
46         return TIME_T_MAX;
47 }
48
49 /**
50 a gettimeofday wrapper
51 **/
52 void GetTimeOfDay(struct timeval *tval)
53 {
54 #ifdef HAVE_GETTIMEOFDAY_TZ
55         gettimeofday(tval,NULL);
56 #else
57         gettimeofday(tval);
58 #endif
59 }
60
61 struct timespec convert_time_t_to_timespec(time_t t)
62 {
63         struct timespec ts;
64         ts.tv_sec = t;
65         ts.tv_nsec = 0;
66         return ts;
67 }
68
69 #if (SIZEOF_LONG == 8)
70 #define TIME_FIXUP_CONSTANT_INT 11644473600L
71 #elif (SIZEOF_LONG_LONG == 8)
72 #define TIME_FIXUP_CONSTANT_INT 11644473600LL
73 #endif
74
75 /****************************************************************************
76  Interpret an 8 byte "filetime" structure to a time_t
77  It's originally in "100ns units since jan 1st 1601"
78
79  An 8 byte value of 0xffffffffffffffff will be returned as a timespec of
80
81         tv_sec = 0
82         tv_nsec = 0;
83
84  Returns GMT.
85 ****************************************************************************/
86
87 time_t nt_time_to_unix(NTTIME nt)
88 {
89         return convert_timespec_to_time_t(nt_time_to_unix_timespec(&nt));
90 }
91
92 /****************************************************************************
93  Put a 8 byte filetime from a time_t. Uses GMT.
94 ****************************************************************************/
95
96 void unix_to_nt_time(NTTIME *nt, time_t t)
97 {
98         uint64_t t2; 
99
100         if (t == (time_t)-1) {
101                 *nt = (NTTIME)-1LL;
102                 return;
103         }               
104         if (t == 0) {
105                 *nt = 0;
106                 return;
107         }               
108
109         t2 = t;
110         t2 += TIME_FIXUP_CONSTANT_INT;
111         t2 *= 1000*1000*10;
112
113         *nt = t2;
114 }
115
116
117 /**
118 check if it's a null unix time
119 **/
120 BOOL null_time(time_t t)
121 {
122         return t == 0 || 
123                 t == (time_t)0xFFFFFFFF || 
124                 t == (time_t)-1;
125 }
126
127
128 /**
129 check if it's a null NTTIME
130 **/
131 BOOL null_nttime(NTTIME t)
132 {
133         return t == 0 || t == (NTTIME)-1;
134 }
135
136 /*******************************************************************
137   create a 16 bit dos packed date
138 ********************************************************************/
139 static uint16_t make_dos_date1(struct tm *t)
140 {
141         uint16_t ret=0;
142         ret = (((unsigned int)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
143         ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
144         return ret;
145 }
146
147 /*******************************************************************
148   create a 16 bit dos packed time
149 ********************************************************************/
150 static uint16_t make_dos_time1(struct tm *t)
151 {
152         uint16_t ret=0;
153         ret = ((((unsigned int)t->tm_min >> 3)&0x7) | (((unsigned int)t->tm_hour) << 3));
154         ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
155         return ret;
156 }
157
158 /*******************************************************************
159   create a 32 bit dos packed date/time from some parameters
160   This takes a GMT time and returns a packed localtime structure
161 ********************************************************************/
162 static uint32_t make_dos_date(time_t unixdate, int zone_offset)
163 {
164         struct tm *t;
165         uint32_t ret=0;
166
167         if (unixdate == 0) {
168                 return 0;
169         }
170
171         unixdate -= zone_offset;
172
173         t = gmtime(&unixdate);
174         if (!t) {
175                 return 0xFFFFFFFF;
176         }
177
178         ret = make_dos_date1(t);
179         ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
180
181         return ret;
182 }
183
184 /**
185 put a dos date into a buffer (time/date format)
186 This takes GMT time and puts local time in the buffer
187 **/
188 void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset)
189 {
190         uint32_t x = make_dos_date(unixdate, zone_offset);
191         SIVAL(buf,offset,x);
192 }
193
194 /**
195 put a dos date into a buffer (date/time format)
196 This takes GMT time and puts local time in the buffer
197 **/
198 void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
199 {
200         uint32_t x;
201         x = make_dos_date(unixdate, zone_offset);
202         x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
203         SIVAL(buf,offset,x);
204 }
205
206 /**
207 put a dos 32 bit "unix like" date into a buffer. This routine takes
208 GMT and converts it to LOCAL time before putting it (most SMBs assume
209 localtime for this sort of date)
210 **/
211 void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
212 {
213         if (!null_time(unixdate)) {
214                 unixdate -= zone_offset;
215         }
216         SIVAL(buf,offset,unixdate);
217 }
218
219 /*******************************************************************
220   interpret a 32 bit dos packed date/time to some parameters
221 ********************************************************************/
222 static void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
223 {
224         uint32_t p0,p1,p2,p3;
225
226         p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; 
227         p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
228
229         *second = 2*(p0 & 0x1F);
230         *minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
231         *hour = (p1>>3)&0xFF;
232         *day = (p2&0x1F);
233         *month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
234         *year = ((p3>>1)&0xFF) + 80;
235 }
236
237 /**
238   create a unix date (int GMT) from a dos date (which is actually in
239   localtime)
240 **/
241 time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset)
242 {
243         uint32_t dos_date=0;
244         struct tm t;
245         time_t ret;
246
247         dos_date = IVAL(date_ptr,0);
248
249         if (dos_date == 0) return (time_t)0;
250   
251         interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
252                            &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
253         t.tm_isdst = -1;
254   
255         ret = timegm(&t);
256
257         ret += zone_offset;
258
259         return ret;
260 }
261
262 /**
263 like make_unix_date() but the words are reversed
264 **/
265 time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset)
266 {
267         uint32_t x,x2;
268
269         x = IVAL(date_ptr,0);
270         x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
271         SIVAL(&x,0,x2);
272
273         return pull_dos_date((const uint8_t *)&x, zone_offset);
274 }
275
276 /**
277   create a unix GMT date from a dos date in 32 bit "unix like" format
278   these generally arrive as localtimes, with corresponding DST
279 **/
280 time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset)
281 {
282         time_t t = (time_t)IVAL(date_ptr,0);
283         if (!null_time(t)) {
284                 t += zone_offset;
285         }
286         return t;
287 }
288
289 /***************************************************************************
290  Return a HTTP/1.0 time string.
291 ***************************************************************************/
292
293 char *http_timestring(time_t t)
294 {
295         static fstring buf;
296         struct tm *tm = localtime(&t);
297
298         if (!tm) {
299                 slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t);
300         } else {
301 #ifndef HAVE_STRFTIME
302                 const char *asct = asctime(tm);
303                 fstrcpy(buf, asct ? asct : "unknown");
304         }
305         if(buf[strlen(buf)-1] == '\n') {
306                 buf[strlen(buf)-1] = 0;
307 #else /* !HAVE_STRFTIME */
308                 strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
309 #endif /* !HAVE_STRFTIME */
310         }
311         return buf;
312 }
313
314
315 /**
316  Return the date and time as a string
317 **/
318 char *timestring(TALLOC_CTX *mem_ctx, time_t t)
319 {
320         char *TimeBuf;
321         char tempTime[80];
322         struct tm *tm;
323
324         tm = localtime(&t);
325         if (!tm) {
326                 return talloc_asprintf(mem_ctx,
327                                        "%ld seconds since the Epoch",
328                                        (long)t);
329         }
330
331 #ifdef HAVE_STRFTIME
332         /* some versions of gcc complain about using %c. This is a bug
333            in the gcc warning, not a bug in this code. See a recent
334            strftime() manual page for details.
335          */
336         strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
337         TimeBuf = talloc_strdup(mem_ctx, tempTime);
338 #else
339         TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
340 #endif
341
342         return TimeBuf;
343 }
344
345 /**
346   return a talloced string representing a NTTIME for human consumption
347 */
348 const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt)
349 {
350         time_t t;
351         if (nt == 0) {
352                 return "NTTIME(0)";
353         }
354         t = nt_time_to_unix(nt);
355         return timestring(mem_ctx, t);
356 }
357
358
359 /**
360   parse a nttime as a large integer in a string and return a NTTIME
361 */
362 NTTIME nttime_from_string(const char *s)
363 {
364         return strtoull(s, NULL, 0);
365 }
366
367 /**
368   return (tv1 - tv2) in microseconds
369 */
370 int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2)
371 {
372         int64_t sec_diff = tv1->tv_sec - tv2->tv_sec;
373         return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
374 }
375
376
377 /**
378   return a zero timeval
379 */
380 struct timeval timeval_zero(void)
381 {
382         struct timeval tv;
383         tv.tv_sec = 0;
384         tv.tv_usec = 0;
385         return tv;
386 }
387
388 /**
389   return True if a timeval is zero
390 */
391 BOOL timeval_is_zero(const struct timeval *tv)
392 {
393         return tv->tv_sec == 0 && tv->tv_usec == 0;
394 }
395
396 /**
397   return a timeval for the current time
398 */
399 struct timeval timeval_current(void)
400 {
401         struct timeval tv;
402         GetTimeOfDay(&tv);
403         return tv;
404 }
405
406 /**
407   return a timeval struct with the given elements
408 */
409 struct timeval timeval_set(uint32_t secs, uint32_t usecs)
410 {
411         struct timeval tv;
412         tv.tv_sec = secs;
413         tv.tv_usec = usecs;
414         return tv;
415 }
416
417
418 /**
419   return a timeval ofs microseconds after tv
420 */
421 struct timeval timeval_add(const struct timeval *tv,
422                            uint32_t secs, uint32_t usecs)
423 {
424         struct timeval tv2 = *tv;
425         const unsigned int million = 1000000;
426         tv2.tv_sec += secs;
427         tv2.tv_usec += usecs;
428         tv2.tv_sec += tv2.tv_usec / million;
429         tv2.tv_usec = tv2.tv_usec % million;
430         return tv2;
431 }
432
433 /**
434   return the sum of two timeval structures
435 */
436 struct timeval timeval_sum(const struct timeval *tv1,
437                            const struct timeval *tv2)
438 {
439         return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
440 }
441
442 /**
443   return a timeval secs/usecs into the future
444 */
445 struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
446 {
447         struct timeval tv = timeval_current();
448         return timeval_add(&tv, secs, usecs);
449 }
450
451 /**
452   compare two timeval structures. 
453   Return -1 if tv1 < tv2
454   Return 0 if tv1 == tv2
455   Return 1 if tv1 > tv2
456 */
457 int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
458 {
459         if (tv1->tv_sec  > tv2->tv_sec)  return 1;
460         if (tv1->tv_sec  < tv2->tv_sec)  return -1;
461         if (tv1->tv_usec > tv2->tv_usec) return 1;
462         if (tv1->tv_usec < tv2->tv_usec) return -1;
463         return 0;
464 }
465
466 /**
467   return True if a timer is in the past
468 */
469 BOOL timeval_expired(const struct timeval *tv)
470 {
471         struct timeval tv2 = timeval_current();
472         if (tv2.tv_sec > tv->tv_sec) return True;
473         if (tv2.tv_sec < tv->tv_sec) return False;
474         return (tv2.tv_usec >= tv->tv_usec);
475 }
476
477 /**
478   return the number of seconds elapsed between two times
479 */
480 double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2)
481 {
482         return (tv2->tv_sec - tv1->tv_sec) + 
483                (tv2->tv_usec - tv1->tv_usec)*1.0e-6;
484 }
485
486 /**
487   return the number of seconds elapsed since a given time
488 */
489 double timeval_elapsed(const struct timeval *tv)
490 {
491         struct timeval tv2 = timeval_current();
492         return timeval_elapsed2(tv, &tv2);
493 }
494
495 /**
496   return the lesser of two timevals
497 */
498 struct timeval timeval_min(const struct timeval *tv1,
499                            const struct timeval *tv2)
500 {
501         if (tv1->tv_sec < tv2->tv_sec) return *tv1;
502         if (tv1->tv_sec > tv2->tv_sec) return *tv2;
503         if (tv1->tv_usec < tv2->tv_usec) return *tv1;
504         return *tv2;
505 }
506
507 /**
508   return the greater of two timevals
509 */
510 struct timeval timeval_max(const struct timeval *tv1,
511                            const struct timeval *tv2)
512 {
513         if (tv1->tv_sec > tv2->tv_sec) return *tv1;
514         if (tv1->tv_sec < tv2->tv_sec) return *tv2;
515         if (tv1->tv_usec > tv2->tv_usec) return *tv1;
516         return *tv2;
517 }
518
519 /**
520   return the difference between two timevals as a timeval
521   if tv1 comes after tv2, then return a zero timeval
522   (this is *tv2 - *tv1)
523 */
524 struct timeval timeval_until(const struct timeval *tv1,
525                              const struct timeval *tv2)
526 {
527         struct timeval t;
528         if (timeval_compare(tv1, tv2) >= 0) {
529                 return timeval_zero();
530         }
531         t.tv_sec = tv2->tv_sec - tv1->tv_sec;
532         if (tv1->tv_usec > tv2->tv_usec) {
533                 t.tv_sec--;
534                 t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
535         } else {
536                 t.tv_usec = tv2->tv_usec - tv1->tv_usec;
537         }
538         return t;
539 }
540
541
542 /**
543   convert a timeval to a NTTIME
544 */
545 NTTIME timeval_to_nttime(const struct timeval *tv)
546 {
547         return 10*(tv->tv_usec + 
548                   ((TIME_FIXUP_CONSTANT_INT + (uint64_t)tv->tv_sec) * 1000000));
549 }
550
551 /*******************************************************************
552 yield the difference between *A and *B, in seconds, ignoring leap seconds
553 ********************************************************************/
554 static int tm_diff(struct tm *a, struct tm *b)
555 {
556         int ay = a->tm_year + (1900 - 1);
557         int by = b->tm_year + (1900 - 1);
558         int intervening_leap_days =
559                 (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
560         int years = ay - by;
561         int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
562         int hours = 24*days + (a->tm_hour - b->tm_hour);
563         int minutes = 60*hours + (a->tm_min - b->tm_min);
564         int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
565
566         return seconds;
567 }
568
569 int extra_time_offset=0;
570
571 /**
572   return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
573  */
574 int get_time_zone(time_t t)
575 {
576         struct tm *tm = gmtime(&t);
577         struct tm tm_utc;
578         if (!tm)
579                 return 0;
580         tm_utc = *tm;
581         tm = localtime(&t);
582         if (!tm)
583                 return 0;
584         return tm_diff(&tm_utc,tm)+60*extra_time_offset;
585 }
586
587 /****************************************************************************
588  Check if NTTIME is 0.
589 ****************************************************************************/
590
591 BOOL nt_time_is_zero(const NTTIME *nt)
592 {
593         return (*nt == 0);
594 }
595
596 /****************************************************************************
597  Convert ASN.1 GeneralizedTime string to unix-time.
598  Returns 0 on failure; Currently ignores timezone. 
599 ****************************************************************************/
600
601 time_t generalized_to_unix_time(const char *str)
602
603         struct tm tm;
604
605         ZERO_STRUCT(tm);
606
607         if (sscanf(str, "%4d%2d%2d%2d%2d%2d", 
608                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
609                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
610                 return 0;
611         }
612         tm.tm_year -= 1900;
613         tm.tm_mon -= 1;
614
615         return timegm(&tm);
616 }
617
618 /*******************************************************************
619  Accessor function for the server time zone offset.
620  set_server_zone_offset() must have been called first.
621 ******************************************************************/
622
623 static int server_zone_offset;
624
625 int get_server_zone_offset(void)
626 {
627         return server_zone_offset;
628 }
629
630 /*******************************************************************
631  Initialize the server time zone offset. Called when a client connects.
632 ******************************************************************/
633
634 int set_server_zone_offset(time_t t)
635 {
636         server_zone_offset = get_time_zone(t);
637         return server_zone_offset;
638 }
639
640 /****************************************************************************
641  Return the date and time as a string
642 ****************************************************************************/
643
644 char *current_timestring(BOOL hires)
645 {
646         static fstring TimeBuf;
647         struct timeval tp;
648         time_t t;
649         struct tm *tm;
650
651         if (hires) {
652                 GetTimeOfDay(&tp);
653                 t = (time_t)tp.tv_sec;
654         } else {
655                 t = time(NULL);
656         }
657         tm = localtime(&t);
658         if (!tm) {
659                 if (hires) {
660                         slprintf(TimeBuf,
661                                  sizeof(TimeBuf)-1,
662                                  "%ld.%06ld seconds since the Epoch",
663                                  (long)tp.tv_sec, 
664                                  (long)tp.tv_usec);
665                 } else {
666                         slprintf(TimeBuf,
667                                  sizeof(TimeBuf)-1,
668                                  "%ld seconds since the Epoch",
669                                  (long)t);
670                 }
671         } else {
672 #ifdef HAVE_STRFTIME
673                 if (hires) {
674                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
675                         slprintf(TimeBuf+strlen(TimeBuf),
676                                  sizeof(TimeBuf)-1 - strlen(TimeBuf), 
677                                  ".%06ld", 
678                                  (long)tp.tv_usec);
679                 } else {
680                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
681                 }
682 #else
683                 if (hires) {
684                         const char *asct = asctime(tm);
685                         slprintf(TimeBuf, 
686                                  sizeof(TimeBuf)-1, 
687                                  "%s.%06ld", 
688                                  asct ? asct : "unknown", 
689                                  (long)tp.tv_usec);
690                 } else {
691                         const char *asct = asctime(tm);
692                         fstrcpy(TimeBuf, asct ? asct : "unknown");
693                 }
694 #endif
695         }
696         return(TimeBuf);
697 }
698
699
700 /*******************************************************************
701  Put a dos date into a buffer (time/date format).
702  This takes GMT time and puts local time in the buffer.
703 ********************************************************************/
704
705 static void put_dos_date(char *buf,int offset,time_t unixdate, int zone_offset)
706 {
707         uint32 x = make_dos_date(unixdate, zone_offset);
708         SIVAL(buf,offset,x);
709 }
710
711 /*******************************************************************
712  Put a dos date into a buffer (date/time format).
713  This takes GMT time and puts local time in the buffer.
714 ********************************************************************/
715
716 static void put_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset)
717 {
718         uint32 x = make_dos_date(unixdate, zone_offset);
719         x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
720         SIVAL(buf,offset,x);
721 }
722
723 /*******************************************************************
724  Put a dos 32 bit "unix like" date into a buffer. This routine takes
725  GMT and converts it to LOCAL time before putting it (most SMBs assume
726  localtime for this sort of date)
727 ********************************************************************/
728
729 static void put_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset)
730 {
731         if (!null_mtime(unixdate)) {
732                 unixdate -= zone_offset;
733         }
734         SIVAL(buf,offset,unixdate);
735 }
736
737
738 /***************************************************************************
739  Server versions of the above functions.
740 ***************************************************************************/
741
742 void srv_put_dos_date(char *buf,int offset,time_t unixdate)
743 {
744         put_dos_date(buf, offset, unixdate, server_zone_offset);
745 }
746
747 void srv_put_dos_date2(char *buf,int offset, time_t unixdate)
748 {
749         put_dos_date2(buf, offset, unixdate, server_zone_offset);
750 }
751
752 void srv_put_dos_date3(char *buf,int offset,time_t unixdate)
753 {
754         put_dos_date3(buf, offset, unixdate, server_zone_offset);
755 }
756
757 /****************************************************************************
758  Take a Unix time and convert to an NTTIME structure and place in buffer 
759  pointed to by p.
760 ****************************************************************************/
761
762 void put_long_date_timespec(char *p, struct timespec ts)
763 {
764         NTTIME nt;
765         unix_timespec_to_nt_time(&nt, ts);
766         SIVAL(p, 0, nt & 0xFFFFFFFF);
767         SIVAL(p, 4, nt >> 32);
768 }
769
770 void put_long_date(char *p, time_t t)
771 {
772         struct timespec ts;
773         ts.tv_sec = t;
774         ts.tv_nsec = 0;
775         put_long_date_timespec(p, ts);
776 }
777
778 /****************************************************************************
779  Return the best approximation to a 'create time' under UNIX from a stat
780  structure.
781 ****************************************************************************/
782
783 time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs)
784 {
785         time_t ret, ret1;
786
787         if(S_ISDIR(st->st_mode) && fake_dirs) {
788                 return (time_t)315493200L;          /* 1/1/1980 */
789         }
790     
791         ret = MIN(st->st_ctime, st->st_mtime);
792         ret1 = MIN(ret, st->st_atime);
793
794         if(ret1 != (time_t)0) {
795                 return ret1;
796         }
797
798         /*
799          * One of ctime, mtime or atime was zero (probably atime).
800          * Just return MIN(ctime, mtime).
801          */
802         return ret;
803 }
804
805 struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs)
806 {
807         struct timespec ts;
808         ts.tv_sec = get_create_time(st, fake_dirs);
809         ts.tv_nsec = 0;
810         return ts;
811 }
812
813 /****************************************************************************
814  Get/Set all the possible time fields from a stat struct as a timespec.
815 ****************************************************************************/
816
817 struct timespec get_atimespec(SMB_STRUCT_STAT *pst)
818 {
819 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
820         struct timespec ret;
821
822         /* Old system - no ns timestamp. */
823         ret.tv_sec = pst->st_atime;
824         ret.tv_nsec = 0;
825         return ret;
826 #else
827 #if defined(HAVE_STAT_ST_ATIM)
828         return pst->st_atim;
829 #elif defined(HAVE_STAT_ST_ATIMENSEC)
830         struct timespec ret;
831         ret.tv_sec = pst->st_atime;
832         ret.tv_nsec = pst->st_atimensec;
833         return ret;
834 #else
835 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
836 #endif
837 #endif
838 }
839
840 void set_atimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
841 {
842 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
843         /* Old system - no ns timestamp. */
844         pst->st_atime = ts.tv_sec;
845 #else
846 #if defined(HAVE_STAT_ST_ATIM)
847         pst->st_atim = ts;
848 #elif defined(HAVE_STAT_ST_ATIMENSEC)
849         pst->st_atime = ts.tv_sec;
850         pst->st_atimensec = ts.tv_nsec
851 #else
852 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
853 #endif
854 #endif
855 }
856
857 struct timespec get_mtimespec(SMB_STRUCT_STAT *pst)
858 {
859 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
860         struct timespec ret;
861
862         /* Old system - no ns timestamp. */
863         ret.tv_sec = pst->st_mtime;
864         ret.tv_nsec = 0;
865         return ret;
866 #else
867 #if defined(HAVE_STAT_ST_MTIM)
868         return pst->st_mtim;
869 #elif defined(HAVE_STAT_ST_MTIMENSEC)
870         struct timespec ret;
871         ret.tv_sec = pst->st_mtime;
872         ret.tv_nsec = pst->st_mtimensec;
873         return ret;
874 #else
875 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
876 #endif
877 #endif
878 }
879
880 void set_mtimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
881 {
882 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
883         /* Old system - no ns timestamp. */
884         pst->st_mtime = ts.tv_sec;
885 #else
886 #if defined(HAVE_STAT_ST_MTIM)
887         pst->st_mtim = ts;
888 #elif defined(HAVE_STAT_ST_MTIMENSEC)
889         pst->st_mtime = ts.tv_sec;
890         pst->st_mtimensec = ts.tv_nsec
891 #else
892 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
893 #endif
894 #endif
895 }
896
897 struct timespec get_ctimespec(SMB_STRUCT_STAT *pst)
898 {
899 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
900         struct timespec ret;
901
902         /* Old system - no ns timestamp. */
903         ret.tv_sec = pst->st_ctime;
904         ret.tv_nsec = 0;
905         return ret;
906 #else
907 #if defined(HAVE_STAT_ST_CTIM)
908         return pst->st_ctim;
909 #elif defined(HAVE_STAT_ST_CTIMENSEC)
910         struct timespec ret;
911         ret.tv_sec = pst->st_ctime;
912         ret.tv_nsec = pst->st_ctimensec;
913         return ret;
914 #else
915 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
916 #endif
917 #endif
918 }
919
920 void set_ctimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
921 {
922 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
923         /* Old system - no ns timestamp. */
924         pst->st_ctime = ts.tv_sec;
925 #else
926 #if defined(HAVE_STAT_ST_CTIM)
927         pst->st_ctim = ts;
928 #elif defined(HAVE_STAT_ST_CTIMENSEC)
929         pst->st_ctime = ts.tv_sec;
930         pst->st_ctimensec = ts.tv_nsec
931 #else
932 #error  CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT 
933 #endif
934 #endif
935 }
936
937 void dos_filetime_timespec(struct timespec *tsp)
938 {
939         tsp->tv_sec &= ~1;
940         tsp->tv_nsec = 0;
941 }
942
943 /*******************************************************************
944  Create a unix date (int GMT) from a dos date (which is actually in
945  localtime).
946 ********************************************************************/
947
948 static time_t make_unix_date(const void *date_ptr, int zone_offset)
949 {
950         uint32 dos_date=0;
951         struct tm t;
952         time_t ret;
953
954         dos_date = IVAL(date_ptr,0);
955
956         if (dos_date == 0) {
957                 return 0;
958         }
959   
960         interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
961                         &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
962         t.tm_isdst = -1;
963   
964         ret = timegm(&t);
965
966         ret += zone_offset;
967
968         return(ret);
969 }
970
971 /*******************************************************************
972  Like make_unix_date() but the words are reversed.
973 ********************************************************************/
974
975 static time_t make_unix_date2(const void *date_ptr, int zone_offset)
976 {
977         uint32 x,x2;
978
979         x = IVAL(date_ptr,0);
980         x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
981         SIVAL(&x,0,x2);
982
983         return(make_unix_date((const void *)&x, zone_offset));
984 }
985
986 /*******************************************************************
987  Create a unix GMT date from a dos date in 32 bit "unix like" format
988  these generally arrive as localtimes, with corresponding DST.
989 ******************************************************************/
990
991 static time_t make_unix_date3(const void *date_ptr, int zone_offset)
992 {
993         time_t t = (time_t)IVAL(date_ptr,0);
994         if (!null_mtime(t)) {
995                 t += zone_offset;
996         }
997         return(t);
998 }
999
1000 time_t srv_make_unix_date(const void *date_ptr)
1001 {
1002         return make_unix_date(date_ptr, server_zone_offset);
1003 }
1004
1005 time_t srv_make_unix_date2(const void *date_ptr)
1006 {
1007         return make_unix_date2(date_ptr, server_zone_offset);
1008 }
1009
1010 time_t srv_make_unix_date3(const void *date_ptr)
1011 {
1012         return make_unix_date3(date_ptr, server_zone_offset);
1013 }
1014
1015 time_t convert_timespec_to_time_t(struct timespec ts)
1016 {
1017         /* 1 ns == 1,000,000,000 - one thousand millionths of a second.
1018            increment if it's greater than 500 millionth of a second. */
1019         if (ts.tv_nsec > 500000000) {
1020                 return ts.tv_sec + 1;
1021         }
1022         return ts.tv_sec;
1023 }
1024
1025 /****************************************************************************
1026  Interprets an nt time into a unix struct timespec.
1027  Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff
1028  will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case.
1029 ****************************************************************************/
1030
1031 struct timespec interpret_long_date(const char *p)
1032 {
1033         NTTIME nt;
1034         nt = IVAL(p,0) + ((uint64_t)IVAL(p,4) << 32);
1035         if (nt == (uint64_t)-1) {
1036                 struct timespec ret;
1037                 ret.tv_sec = (time_t)-1;
1038                 ret.tv_nsec = 0;
1039                 return ret;
1040         }
1041         return nt_time_to_unix_timespec(&nt);
1042 }
1043
1044 /***************************************************************************
1045  Client versions of the above functions.
1046 ***************************************************************************/
1047
1048 void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate)
1049 {
1050         put_dos_date(buf, offset, unixdate, cli->serverzone);
1051 }
1052
1053 void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate)
1054 {
1055         put_dos_date2(buf, offset, unixdate, cli->serverzone);
1056 }
1057
1058 void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate)
1059 {
1060         put_dos_date3(buf, offset, unixdate, cli->serverzone);
1061 }
1062
1063 time_t cli_make_unix_date(struct cli_state *cli, void *date_ptr)
1064 {
1065         return make_unix_date(date_ptr, cli->serverzone);
1066 }
1067
1068 time_t cli_make_unix_date2(struct cli_state *cli, void *date_ptr)
1069 {
1070         return make_unix_date2(date_ptr, cli->serverzone);
1071 }
1072
1073 time_t cli_make_unix_date3(struct cli_state *cli, void *date_ptr)
1074 {
1075         return make_unix_date3(date_ptr, cli->serverzone);
1076 }
1077
1078 /* Large integer version. */
1079 struct timespec nt_time_to_unix_timespec(NTTIME *nt)
1080 {
1081         int64 d;
1082         struct timespec ret;
1083
1084         if (*nt == 0 || *nt == (int64)-1) {
1085                 ret.tv_sec = 0;
1086                 ret.tv_nsec = 0;
1087                 return ret;
1088         }
1089
1090         d = (int64)*nt;
1091         /* d is now in 100ns units, since jan 1st 1601".
1092            Save off the ns fraction. */
1093         
1094         ret.tv_nsec = (long) ((d % 100) * 100);
1095
1096         /* Convert to seconds */
1097         d /= 1000*1000*10;
1098
1099         /* Now adjust by 369 years to make the secs since 1970 */
1100         d -= TIME_FIXUP_CONSTANT_INT;
1101
1102         if (d <= (int64)TIME_T_MIN) {
1103                 ret.tv_sec = TIME_T_MIN;
1104                 ret.tv_nsec = 0;
1105                 return ret;
1106         }
1107
1108         if (d >= (int64)TIME_T_MAX) {
1109                 ret.tv_sec = TIME_T_MAX;
1110                 ret.tv_nsec = 0;
1111                 return ret;
1112         }
1113
1114         ret.tv_sec = (time_t)d;
1115         return ret;
1116 }
1117 /****************************************************************************
1118  Check if two NTTIMEs are the same.
1119 ****************************************************************************/
1120
1121 BOOL nt_time_equals(const NTTIME *nt1, const NTTIME *nt2)
1122 {
1123         return (*nt1 == *nt2);
1124 }
1125
1126 /*******************************************************************
1127  Re-read the smb serverzone value.
1128 ******************************************************************/
1129
1130 static struct timeval start_time_hires;
1131
1132 void TimeInit(void)
1133 {
1134         set_server_zone_offset(time(NULL));
1135
1136         DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset));
1137
1138         /* Save the start time of this process. */
1139         if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) {
1140                 GetTimeOfDay(&start_time_hires);
1141         }
1142 }
1143
1144 /**********************************************************************
1145  Return a timeval struct of the uptime of this process. As TimeInit is
1146  done before a daemon fork then this is the start time from the parent
1147  daemon start. JRA.
1148 ***********************************************************************/
1149
1150 void get_process_uptime(struct timeval *ret_time)
1151 {
1152         struct timeval time_now_hires;
1153
1154         GetTimeOfDay(&time_now_hires);
1155         ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
1156         if (time_now_hires.tv_usec < start_time_hires.tv_usec) {
1157                 ret_time->tv_sec -= 1;
1158                 ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec);
1159         } else {
1160                 ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
1161         }
1162 }
1163
1164 /****************************************************************************
1165  Convert a NTTIME structure to a time_t.
1166  It's originally in "100ns units".
1167
1168  This is an absolute version of the one above.
1169  By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
1170  if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
1171 ****************************************************************************/
1172
1173 time_t nt_time_to_unix_abs(const NTTIME *nt)
1174 {
1175         uint64 d;
1176
1177         if (*nt == 0) {
1178                 return (time_t)0;
1179         }
1180
1181         if (*nt == (uint64)-1) {
1182                 return (time_t)-1;
1183         }
1184
1185         if (*nt == NTTIME_INFINITY) {
1186                 return (time_t)-1;
1187         }
1188
1189         /* reverse the time */
1190         /* it's a negative value, turn it to positive */
1191         d=~*nt;
1192
1193         d += 1000*1000*10/2;
1194         d /= 1000*1000*10;
1195
1196         if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) {
1197                 return (time_t)0;
1198         }
1199
1200         return (time_t)d;
1201 }
1202
1203 /****************************************************************************
1204  Put a 8 byte filetime from a struct timespec. Uses GMT.
1205 ****************************************************************************/
1206
1207 void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts)
1208 {
1209         uint64 d;
1210
1211         if (ts.tv_sec ==0 && ts.tv_nsec == 0) {
1212                 *nt = 0;
1213                 return;
1214         }
1215         if (ts.tv_sec == TIME_T_MAX) {
1216                 *nt = 0x7fffffffffffffffLL;
1217                 return;
1218         }               
1219         if (ts.tv_sec == (time_t)-1) {
1220                 *nt = (uint64)-1;
1221                 return;
1222         }               
1223
1224         d = ts.tv_sec;
1225         d += TIME_FIXUP_CONSTANT_INT;
1226         d *= 1000*1000*10;
1227         /* d is now in 100ns units. */
1228         d += (ts.tv_nsec / 100);
1229
1230         *nt = d;
1231 }
1232
1233 /****************************************************************************
1234  Convert a time_t to a NTTIME structure
1235
1236  This is an absolute version of the one above.
1237  By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
1238  If the time_t was 5 seconds, the NTTIME is 5 seconds. JFM
1239 ****************************************************************************/
1240
1241 void unix_to_nt_time_abs(NTTIME *nt, time_t t)
1242 {
1243         double d;
1244
1245         if (t==0) {
1246                 *nt = 0;
1247                 return;
1248         }
1249
1250         if (t == TIME_T_MAX) {
1251                 *nt = 0x7fffffffffffffffLL;
1252                 return;
1253         }
1254                 
1255         if (t == (time_t)-1) {
1256                 /* that's what NT uses for infinite */
1257                 *nt = NTTIME_INFINITY;
1258                 return;
1259         }               
1260
1261         d = (double)(t);
1262         d *= 1.0e7;
1263
1264         *nt = d;
1265
1266         /* convert to a negative value */
1267         *nt=~*nt;
1268 }
1269
1270
1271 /****************************************************************************
1272  Check if it's a null mtime.
1273 ****************************************************************************/
1274
1275 BOOL null_mtime(time_t mtime)
1276 {
1277         if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
1278                 return(True);
1279         return(False);
1280 }
1281
1282 /****************************************************************************
1283  Utility function that always returns a const string even if localtime
1284  and asctime fail.
1285 ****************************************************************************/
1286
1287 const char *time_to_asc(const time_t *t)
1288 {
1289         const char *asct;
1290         struct tm *lt = localtime(t);
1291
1292         if (!lt) {
1293                 return "unknown time";
1294         }
1295
1296         asct = asctime(lt);
1297         if (!asct) {
1298                 return "unknown time";
1299         }
1300         return asct;
1301 }
1302
1303 const char *display_time(NTTIME nttime)
1304 {
1305         static fstring string;
1306
1307         float high;
1308         float low;
1309         int sec;
1310         int days, hours, mins, secs;
1311
1312         if (nttime==0)
1313                 return "Now";
1314
1315         if (nttime==NTTIME_INFINITY)
1316                 return "Never";
1317
1318         high = 65536;   
1319         high = high/10000;
1320         high = high*65536;
1321         high = high/1000;
1322         high = high * (~(nttime >> 32));
1323
1324         low = ~(nttime & 0xFFFFFFFF);
1325         low = low/(1000*1000*10);
1326
1327         sec=high+low;
1328
1329         days=sec/(60*60*24);
1330         hours=(sec - (days*60*60*24)) / (60*60);
1331         mins=(sec - (days*60*60*24) - (hours*60*60) ) / 60;
1332         secs=sec - (days*60*60*24) - (hours*60*60) - (mins*60);
1333
1334         fstr_sprintf(string, "%u days, %u hours, %u minutes, %u seconds", days, hours, mins, secs);
1335         return (string);
1336 }
1337
1338 BOOL nt_time_is_set(const NTTIME *nt)
1339 {
1340         if (*nt == 0x7FFFFFFFFFFFFFFFLL) {
1341                 return False;
1342         }
1343
1344         if (*nt == NTTIME_INFINITY) {
1345                 return False;
1346         }
1347
1348         return True;
1349 }
1350