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