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