v3-4-ctdb: Bump ctdb vendor patch level to 17
[obnox/samba-ctdb.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 #if (SIZEOF_LONG == 8)
42 #define TIME_FIXUP_CONSTANT_INT 11644473600L
43 #elif (SIZEOF_LONG_LONG == 8)
44 #define TIME_FIXUP_CONSTANT_INT 11644473600LL
45 #endif
46
47 /*******************************************************************
48   create a 16 bit dos packed date
49 ********************************************************************/
50 static uint16_t make_dos_date1(struct tm *t)
51 {
52         uint16_t ret=0;
53         ret = (((unsigned int)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
54         ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
55         return ret;
56 }
57
58 /*******************************************************************
59   create a 16 bit dos packed time
60 ********************************************************************/
61 static uint16_t make_dos_time1(struct tm *t)
62 {
63         uint16_t ret=0;
64         ret = ((((unsigned int)t->tm_min >> 3)&0x7) | (((unsigned int)t->tm_hour) << 3));
65         ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
66         return ret;
67 }
68
69 /*******************************************************************
70   create a 32 bit dos packed date/time from some parameters
71   This takes a GMT time and returns a packed localtime structure
72 ********************************************************************/
73 static uint32_t make_dos_date(time_t unixdate, int zone_offset)
74 {
75         struct tm *t;
76         uint32_t ret=0;
77
78         if (unixdate == 0) {
79                 return 0;
80         }
81
82         unixdate -= zone_offset;
83
84         t = gmtime(&unixdate);
85         if (!t) {
86                 return 0xFFFFFFFF;
87         }
88
89         ret = make_dos_date1(t);
90         ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
91
92         return ret;
93 }
94
95 /**
96   parse a nttime as a large integer in a string and return a NTTIME
97 */
98 NTTIME nttime_from_string(const char *s)
99 {
100         return strtoull(s, NULL, 0);
101 }
102
103 /**************************************************************
104  Handle conversions between time_t and uint32, taking care to
105  preserve the "special" values.
106 **************************************************************/
107
108 uint32_t convert_time_t_to_uint32(time_t t)
109 {
110 #if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
111         /* time_t is 64-bit. */
112         if (t == 0x8000000000000000LL) {
113                 return 0x80000000;
114         } else if (t == 0x7FFFFFFFFFFFFFFFLL) {
115                 return 0x7FFFFFFF;
116         }
117 #endif
118         return (uint32_t)t;
119 }
120
121 time_t convert_uint32_to_time_t(uint32_t u)
122 {
123 #if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
124         /* time_t is 64-bit. */
125         if (u == 0x80000000) {
126                 return (time_t)0x8000000000000000LL;
127         } else if (u == 0x7FFFFFFF) {
128                 return (time_t)0x7FFFFFFFFFFFFFFFLL;
129         }
130 #endif
131         return (time_t)u;
132 }
133
134 /****************************************************************************
135  Check if NTTIME is 0.
136 ****************************************************************************/
137
138 bool nt_time_is_zero(const NTTIME *nt)
139 {
140         return (*nt == 0);
141 }
142
143 /****************************************************************************
144  Convert ASN.1 GeneralizedTime string to unix-time.
145  Returns 0 on failure; Currently ignores timezone. 
146 ****************************************************************************/
147
148 time_t generalized_to_unix_time(const char *str)
149
150         struct tm tm;
151
152         ZERO_STRUCT(tm);
153
154         if (sscanf(str, "%4d%2d%2d%2d%2d%2d", 
155                    &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
156                    &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
157                 return 0;
158         }
159         tm.tm_year -= 1900;
160         tm.tm_mon -= 1;
161
162         return timegm(&tm);
163 }
164
165 /*******************************************************************
166  Accessor function for the server time zone offset.
167  set_server_zone_offset() must have been called first.
168 ******************************************************************/
169
170 static int server_zone_offset;
171
172 int get_server_zone_offset(void)
173 {
174         return server_zone_offset;
175 }
176
177 /*******************************************************************
178  Initialize the server time zone offset. Called when a client connects.
179 ******************************************************************/
180
181 int set_server_zone_offset(time_t t)
182 {
183         server_zone_offset = get_time_zone(t);
184         return server_zone_offset;
185 }
186
187 /****************************************************************************
188  Return the date and time as a string
189 ****************************************************************************/
190
191 char *timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires)
192 {
193         fstring TimeBuf;
194         time_t t;
195         struct tm *tm;
196
197         t = (time_t)tp->tv_sec;
198         tm = localtime(&t);
199         if (!tm) {
200                 if (hires) {
201                         slprintf(TimeBuf,
202                                  sizeof(TimeBuf)-1,
203                                  "%ld.%06ld seconds since the Epoch",
204                                  (long)tp->tv_sec,
205                                  (long)tp->tv_usec);
206                 } else {
207                         slprintf(TimeBuf,
208                                  sizeof(TimeBuf)-1,
209                                  "%ld seconds since the Epoch",
210                                  (long)t);
211                 }
212         } else {
213 #ifdef HAVE_STRFTIME
214                 if (hires) {
215                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
216                         slprintf(TimeBuf+strlen(TimeBuf),
217                                  sizeof(TimeBuf)-1 - strlen(TimeBuf), 
218                                  ".%06ld", 
219                                  (long)tp->tv_usec);
220                 } else {
221                         strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
222                 }
223 #else
224                 if (hires) {
225                         const char *asct = asctime(tm);
226                         slprintf(TimeBuf, 
227                                  sizeof(TimeBuf)-1, 
228                                  "%s.%06ld", 
229                                  asct ? asct : "unknown", 
230                                  (long)tp->tv_usec);
231                 } else {
232                         const char *asct = asctime(tm);
233                         fstrcpy(TimeBuf, asct ? asct : "unknown");
234                 }
235 #endif
236         }
237         return talloc_strdup(ctx, TimeBuf);
238 }
239
240 char *current_timestring(TALLOC_CTX *ctx, bool hires)
241 {
242         struct timeval tv;
243
244         GetTimeOfDay(&tv);
245         return timeval_string(ctx, &tv, hires);
246 }
247
248 /*******************************************************************
249  Put a dos date into a buffer (time/date format).
250  This takes GMT time and puts local time in the buffer.
251 ********************************************************************/
252
253 static void put_dos_date(char *buf,int offset,time_t unixdate, int zone_offset)
254 {
255         uint32_t x = make_dos_date(unixdate, zone_offset);
256         SIVAL(buf,offset,x);
257 }
258
259 /*******************************************************************
260  Put a dos date into a buffer (date/time format).
261  This takes GMT time and puts local time in the buffer.
262 ********************************************************************/
263
264 static void put_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset)
265 {
266         uint32_t x = make_dos_date(unixdate, zone_offset);
267         x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
268         SIVAL(buf,offset,x);
269 }
270
271 /*******************************************************************
272  Put a dos 32 bit "unix like" date into a buffer. This routine takes
273  GMT and converts it to LOCAL time before putting it (most SMBs assume
274  localtime for this sort of date)
275 ********************************************************************/
276
277 static void put_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset)
278 {
279         if (!null_mtime(unixdate)) {
280                 unixdate -= zone_offset;
281         }
282         SIVAL(buf,offset,unixdate);
283 }
284
285
286 /***************************************************************************
287  Server versions of the above functions.
288 ***************************************************************************/
289
290 void srv_put_dos_date(char *buf,int offset,time_t unixdate)
291 {
292         put_dos_date(buf, offset, unixdate, server_zone_offset);
293 }
294
295 void srv_put_dos_date2(char *buf,int offset, time_t unixdate)
296 {
297         put_dos_date2(buf, offset, unixdate, server_zone_offset);
298 }
299
300 void srv_put_dos_date3(char *buf,int offset,time_t unixdate)
301 {
302         put_dos_date3(buf, offset, unixdate, server_zone_offset);
303 }
304
305 void round_timespec(enum timestamp_set_resolution res, struct timespec *ts)
306 {
307         switch (res) {
308                 case TIMESTAMP_SET_SECONDS:
309                         round_timespec_to_sec(ts);
310                         break;
311                 case TIMESTAMP_SET_MSEC:
312                         round_timespec_to_usec(ts);
313                         break;
314                 case TIMESTAMP_SET_NT_OR_BETTER:
315                         /* No rounding needed. */
316                         break;
317         }
318 }
319
320 /****************************************************************************
321  Take a Unix time and convert to an NTTIME structure and place in buffer 
322  pointed to by p.
323 ****************************************************************************/
324
325 void put_long_date_timespec(enum timestamp_set_resolution res, char *p, struct timespec ts)
326 {
327         NTTIME nt;
328         round_timespec(res, &ts);
329         unix_timespec_to_nt_time(&nt, ts);
330         SIVAL(p, 0, nt & 0xFFFFFFFF);
331         SIVAL(p, 4, nt >> 32);
332 }
333
334 void put_long_date(char *p, time_t t)
335 {
336         struct timespec ts;
337         ts.tv_sec = t;
338         ts.tv_nsec = 0;
339         put_long_date_timespec(TIMESTAMP_SET_SECONDS, p, ts);
340 }
341
342 void dos_filetime_timespec(struct timespec *tsp)
343 {
344         tsp->tv_sec &= ~1;
345         tsp->tv_nsec = 0;
346 }
347
348 /*******************************************************************
349  Create a unix date (int GMT) from a dos date (which is actually in
350  localtime).
351 ********************************************************************/
352
353 static time_t make_unix_date(const void *date_ptr, int zone_offset)
354 {
355         uint32_t dos_date=0;
356         struct tm t;
357         time_t ret;
358
359         dos_date = IVAL(date_ptr,0);
360
361         if (dos_date == 0) {
362                 return 0;
363         }
364   
365         interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
366                         &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
367         t.tm_isdst = -1;
368   
369         ret = timegm(&t);
370
371         ret += zone_offset;
372
373         return(ret);
374 }
375
376 /*******************************************************************
377  Like make_unix_date() but the words are reversed.
378 ********************************************************************/
379
380 static time_t make_unix_date2(const void *date_ptr, int zone_offset)
381 {
382         uint32_t x,x2;
383
384         x = IVAL(date_ptr,0);
385         x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
386         SIVAL(&x,0,x2);
387
388         return(make_unix_date((const void *)&x, zone_offset));
389 }
390
391 /*******************************************************************
392  Create a unix GMT date from a dos date in 32 bit "unix like" format
393  these generally arrive as localtimes, with corresponding DST.
394 ******************************************************************/
395
396 static time_t make_unix_date3(const void *date_ptr, int zone_offset)
397 {
398         time_t t = (time_t)IVAL(date_ptr,0);
399         if (!null_mtime(t)) {
400                 t += zone_offset;
401         }
402         return(t);
403 }
404
405 time_t srv_make_unix_date(const void *date_ptr)
406 {
407         return make_unix_date(date_ptr, server_zone_offset);
408 }
409
410 time_t srv_make_unix_date2(const void *date_ptr)
411 {
412         return make_unix_date2(date_ptr, server_zone_offset);
413 }
414
415 time_t srv_make_unix_date3(const void *date_ptr)
416 {
417         return make_unix_date3(date_ptr, server_zone_offset);
418 }
419
420 /****************************************************************************
421  Convert a normalized timeval to a timespec.
422 ****************************************************************************/
423
424 struct timespec convert_timeval_to_timespec(const struct timeval tv)
425 {
426         struct timespec ts;
427         ts.tv_sec = tv.tv_sec;
428         ts.tv_nsec = tv.tv_usec * 1000;
429         return ts;
430 }
431
432 /****************************************************************************
433  Convert a normalized timespec to a timeval.
434 ****************************************************************************/
435
436 struct timeval convert_timespec_to_timeval(const struct timespec ts)
437 {
438         struct timeval tv;
439         tv.tv_sec = ts.tv_sec;
440         tv.tv_usec = ts.tv_nsec / 1000;
441         return tv;
442 }
443
444 /****************************************************************************
445  Return a timespec for the current time
446 ****************************************************************************/
447
448 struct timespec timespec_current(void)
449 {
450         struct timeval tv;
451         struct timespec ts;
452         GetTimeOfDay(&tv);
453         ts.tv_sec = tv.tv_sec;
454         ts.tv_nsec = tv.tv_usec * 1000;
455         return ts;
456 }
457
458 /****************************************************************************
459  Return the lesser of two timespecs.
460 ****************************************************************************/
461
462 struct timespec timespec_min(const struct timespec *ts1,
463                            const struct timespec *ts2)
464 {
465         if (ts1->tv_sec < ts2->tv_sec) return *ts1;
466         if (ts1->tv_sec > ts2->tv_sec) return *ts2;
467         if (ts1->tv_nsec < ts2->tv_nsec) return *ts1;
468         return *ts2;
469 }
470
471 /****************************************************************************
472   compare two timespec structures. 
473   Return -1 if ts1 < ts2
474   Return 0 if ts1 == ts2
475   Return 1 if ts1 > ts2
476 ****************************************************************************/
477
478 int timespec_compare(const struct timespec *ts1, const struct timespec *ts2)
479 {
480         if (ts1->tv_sec  > ts2->tv_sec)  return 1;
481         if (ts1->tv_sec  < ts2->tv_sec)  return -1;
482         if (ts1->tv_nsec > ts2->tv_nsec) return 1;
483         if (ts1->tv_nsec < ts2->tv_nsec) return -1;
484         return 0;
485 }
486
487 /****************************************************************************
488  Round up a timespec if nsec > 500000000, round down if lower,
489  then zero nsec.
490 ****************************************************************************/
491
492 void round_timespec_to_sec(struct timespec *ts)
493 {
494         ts->tv_sec = convert_timespec_to_time_t(*ts);
495         ts->tv_nsec = 0;
496 }
497
498 /****************************************************************************
499  Round a timespec to usec value.
500 ****************************************************************************/
501
502 void round_timespec_to_usec(struct timespec *ts)
503 {
504         struct timeval tv = convert_timespec_to_timeval(*ts);
505         *ts = convert_timeval_to_timespec(tv);
506 }
507
508 /****************************************************************************
509  Interprets an nt time into a unix struct timespec.
510  Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff
511  will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case.
512 ****************************************************************************/
513
514 struct timespec interpret_long_date(const char *p)
515 {
516         NTTIME nt;
517         nt = IVAL(p,0) + ((uint64_t)IVAL(p,4) << 32);
518         if (nt == (uint64_t)-1) {
519                 struct timespec ret;
520                 ret.tv_sec = (time_t)-1;
521                 ret.tv_nsec = 0;
522                 return ret;
523         }
524         return nt_time_to_unix_timespec(&nt);
525 }
526
527 /***************************************************************************
528  Client versions of the above functions.
529 ***************************************************************************/
530
531 void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate)
532 {
533         put_dos_date(buf, offset, unixdate, cli->serverzone);
534 }
535
536 void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate)
537 {
538         put_dos_date2(buf, offset, unixdate, cli->serverzone);
539 }
540
541 void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate)
542 {
543         put_dos_date3(buf, offset, unixdate, cli->serverzone);
544 }
545
546 time_t cli_make_unix_date(struct cli_state *cli, const void *date_ptr)
547 {
548         return make_unix_date(date_ptr, cli->serverzone);
549 }
550
551 time_t cli_make_unix_date2(struct cli_state *cli, const void *date_ptr)
552 {
553         return make_unix_date2(date_ptr, cli->serverzone);
554 }
555
556 time_t cli_make_unix_date3(struct cli_state *cli, const void *date_ptr)
557 {
558         return make_unix_date3(date_ptr, cli->serverzone);
559 }
560
561 /****************************************************************************
562  Check if two NTTIMEs are the same.
563 ****************************************************************************/
564
565 bool nt_time_equals(const NTTIME *nt1, const NTTIME *nt2)
566 {
567         return (*nt1 == *nt2);
568 }
569
570 /*******************************************************************
571  Re-read the smb serverzone value.
572 ******************************************************************/
573
574 static struct timeval start_time_hires;
575
576 void TimeInit(void)
577 {
578         set_server_zone_offset(time(NULL));
579
580         DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset));
581
582         /* Save the start time of this process. */
583         if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) {
584                 GetTimeOfDay(&start_time_hires);
585         }
586 }
587
588 /**********************************************************************
589  Return a timeval struct of the uptime of this process. As TimeInit is
590  done before a daemon fork then this is the start time from the parent
591  daemon start. JRA.
592 ***********************************************************************/
593
594 void get_process_uptime(struct timeval *ret_time)
595 {
596         struct timeval time_now_hires;
597
598         GetTimeOfDay(&time_now_hires);
599         ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec;
600         if (time_now_hires.tv_usec < start_time_hires.tv_usec) {
601                 ret_time->tv_sec -= 1;
602                 ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec);
603         } else {
604                 ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec;
605         }
606 }
607
608 /****************************************************************************
609  Convert a NTTIME structure to a time_t.
610  It's originally in "100ns units".
611
612  This is an absolute version of the one above.
613  By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
614  if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
615 ****************************************************************************/
616
617 time_t nt_time_to_unix_abs(const NTTIME *nt)
618 {
619         uint64_t d;
620
621         if (*nt == 0) {
622                 return (time_t)0;
623         }
624
625         if (*nt == (uint64_t)-1) {
626                 return (time_t)-1;
627         }
628
629         if (*nt == NTTIME_INFINITY) {
630                 return (time_t)-1;
631         }
632
633         /* reverse the time */
634         /* it's a negative value, turn it to positive */
635         d=~*nt;
636
637         d += 1000*1000*10/2;
638         d /= 1000*1000*10;
639
640         if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) {
641                 return (time_t)0;
642         }
643
644         return (time_t)d;
645 }
646
647 time_t uint64s_nt_time_to_unix_abs(const uint64_t *src)
648 {
649         NTTIME nttime;
650         nttime = *src;
651         return nt_time_to_unix_abs(&nttime);
652 }
653
654 /****************************************************************************
655  Put a 8 byte filetime from a struct timespec. Uses GMT.
656 ****************************************************************************/
657
658 void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts)
659 {
660         uint64_t d;
661
662         if (ts.tv_sec ==0 && ts.tv_nsec == 0) {
663                 *nt = 0;
664                 return;
665         }
666         if (ts.tv_sec == TIME_T_MAX) {
667                 *nt = 0x7fffffffffffffffLL;
668                 return;
669         }               
670         if (ts.tv_sec == (time_t)-1) {
671                 *nt = (uint64_t)-1;
672                 return;
673         }               
674
675         d = ts.tv_sec;
676         d += TIME_FIXUP_CONSTANT_INT;
677         d *= 1000*1000*10;
678         /* d is now in 100ns units. */
679         d += (ts.tv_nsec / 100);
680
681         *nt = d;
682 }
683
684 /****************************************************************************
685  Convert a time_t to a NTTIME structure
686
687  This is an absolute version of the one above.
688  By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
689  If the time_t was 5 seconds, the NTTIME is 5 seconds. JFM
690 ****************************************************************************/
691
692 void unix_to_nt_time_abs(NTTIME *nt, time_t t)
693 {
694         double d;
695
696         if (t==0) {
697                 *nt = 0;
698                 return;
699         }
700
701         if (t == TIME_T_MAX) {
702                 *nt = 0x7fffffffffffffffLL;
703                 return;
704         }
705                 
706         if (t == (time_t)-1) {
707                 /* that's what NT uses for infinite */
708                 *nt = NTTIME_INFINITY;
709                 return;
710         }               
711
712         d = (double)(t);
713         d *= 1.0e7;
714
715         *nt = (NTTIME)d;
716
717         /* convert to a negative value */
718         *nt=~*nt;
719 }
720
721
722 /****************************************************************************
723  Check if it's a null mtime.
724 ****************************************************************************/
725
726 bool null_mtime(time_t mtime)
727 {
728         if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
729                 return true;
730         return false;
731 }
732
733 /****************************************************************************
734  Utility function that always returns a const string even if localtime
735  and asctime fail.
736 ****************************************************************************/
737
738 const char *time_to_asc(const time_t t)
739 {
740         const char *asct;
741         struct tm *lt = localtime(&t);
742
743         if (!lt) {
744                 return "unknown time";
745         }
746
747         asct = asctime(lt);
748         if (!asct) {
749                 return "unknown time";
750         }
751         return asct;
752 }
753
754 const char *display_time(NTTIME nttime)
755 {
756         float high;
757         float low;
758         int sec;
759         int days, hours, mins, secs;
760
761         if (nttime==0)
762                 return "Now";
763
764         if (nttime==NTTIME_INFINITY)
765                 return "Never";
766
767         high = 65536;   
768         high = high/10000;
769         high = high*65536;
770         high = high/1000;
771         high = high * (~(nttime >> 32));
772
773         low = ~(nttime & 0xFFFFFFFF);
774         low = low/(1000*1000*10);
775
776         sec=(int)(high+low);
777
778         days=sec/(60*60*24);
779         hours=(sec - (days*60*60*24)) / (60*60);
780         mins=(sec - (days*60*60*24) - (hours*60*60) ) / 60;
781         secs=sec - (days*60*60*24) - (hours*60*60) - (mins*60);
782
783         return talloc_asprintf(talloc_tos(), "%u days, %u hours, %u minutes, "
784                                "%u seconds", days, hours, mins, secs);
785 }
786
787 bool nt_time_is_set(const NTTIME *nt)
788 {
789         if (*nt == 0x7FFFFFFFFFFFFFFFLL) {
790                 return false;
791         }
792
793         if (*nt == NTTIME_INFINITY) {
794                 return false;
795         }
796
797         return true;
798 }