2 Unix SMB/CIFS implementation.
3 time handling functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Stefan (metze) Metzmacher 2002
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com>
28 int extra_time_offset
= 0;
35 #define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \
36 : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
39 #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
42 /*******************************************************************
43 External access to time_t_min and time_t_max.
44 ********************************************************************/
46 time_t get_time_t_max(void)
51 /*******************************************************************
52 A gettimeofday wrapper.
53 ********************************************************************/
55 void GetTimeOfDay(struct timeval
*tval
)
57 #ifdef HAVE_GETTIMEOFDAY_TZ
58 gettimeofday(tval
,NULL
);
64 #define TM_YEAR_BASE 1900
66 /*******************************************************************
67 Yield the difference between *A and *B, in seconds, ignoring leap seconds.
68 ********************************************************************/
70 static int tm_diff(struct tm
*a
, struct tm
*b
)
72 int ay
= a
->tm_year
+ (TM_YEAR_BASE
- 1);
73 int by
= b
->tm_year
+ (TM_YEAR_BASE
- 1);
74 int intervening_leap_days
= (ay
/4 - by
/4) - (ay
/100 - by
/100) + (ay
/400 - by
/400);
76 int days
= 365*years
+ intervening_leap_days
+ (a
->tm_yday
- b
->tm_yday
);
77 int hours
= 24*days
+ (a
->tm_hour
- b
->tm_hour
);
78 int minutes
= 60*hours
+ (a
->tm_min
- b
->tm_min
);
79 int seconds
= 60*minutes
+ (a
->tm_sec
- b
->tm_sec
);
84 /*******************************************************************
85 Return the UTC offset in seconds west of UTC, or 0 if it cannot be determined.
86 ******************************************************************/
88 int get_time_zone(time_t t
)
90 struct tm
*tm
= gmtime(&t
);
101 return tm_diff(&tm_utc
,tm
) + 60*extra_time_offset
;
104 /*******************************************************************
105 Accessor function for the server time zone offset.
106 set_server_zone_offset() must have been called first.
107 ******************************************************************/
109 static int server_zone_offset
;
111 int get_server_zone_offset(void)
113 return server_zone_offset
;
116 /*******************************************************************
117 Initialize the server time zone offset. Called when a client connects.
118 ******************************************************************/
120 int set_server_zone_offset(time_t t
)
122 server_zone_offset
= get_time_zone(t
);
123 return server_zone_offset
;
126 /*******************************************************************
127 Re-read the smb serverzone value.
128 ******************************************************************/
130 static struct timeval start_time_hires
;
134 set_server_zone_offset(time(NULL
));
136 DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset
));
138 /* Save the start time of this process. */
139 if (start_time_hires
.tv_sec
== 0 && start_time_hires
.tv_usec
== 0) {
140 GetTimeOfDay(&start_time_hires
);
144 /**********************************************************************
145 Return a timeval struct of the uptime of this process. As TimeInit is
146 done before a daemon fork then this is the start time from the parent
148 ***********************************************************************/
150 void get_process_uptime(struct timeval
*ret_time
)
152 struct timeval time_now_hires
;
154 GetTimeOfDay(&time_now_hires
);
155 ret_time
->tv_sec
= time_now_hires
.tv_sec
- start_time_hires
.tv_sec
;
156 if (time_now_hires
.tv_usec
< start_time_hires
.tv_usec
) {
157 ret_time
->tv_sec
-= 1;
158 ret_time
->tv_usec
= 1000000 + (time_now_hires
.tv_usec
- start_time_hires
.tv_usec
);
160 ret_time
->tv_usec
= time_now_hires
.tv_usec
- start_time_hires
.tv_usec
;
165 /****************************************************************************
166 Return the UTC offset in seconds west of UTC, adjusted for extra time offset.
167 **************************************************************************/
169 int TimeDiff(time_t t
)
171 return get_time_zone(t
);
175 time_t convert_timespec_to_time_t(struct timespec ts
)
177 /* 1 ns == 1,000,000,000 - one thousand millionths of a second.
178 increment if it's greater than 500 millionth of a second. */
179 if (ts
.tv_nsec
> 500000000) {
180 return ts
.tv_sec
+ 1;
185 struct timespec
convert_time_t_to_timespec(time_t t
)
195 #if (SIZEOF_LONG == 8)
196 #define TIME_FIXUP_CONSTANT_INT 11644473600L
197 #elif (SIZEOF_LONG_LONG == 8)
198 #define TIME_FIXUP_CONSTANT_INT 11644473600LL
201 /****************************************************************************
202 Interpret an 8 byte "filetime" structure to a time_t
203 It's originally in "100ns units since jan 1st 1601"
205 An 8 byte value of 0xffffffffffffffff will be returned as a timespec of
211 ****************************************************************************/
213 /* Large integer version. */
214 static struct timespec
nt_time_to_unix_timespec(NTTIME
*nt
)
219 if ((nt
->high
== 0 && nt
->low
== 0 )||
220 (nt
->high
== 0xffffffff && nt
->low
== 0xffffffff)) {
226 d
= (((uint64
)nt
->high
) << 32 ) + ((uint64
)nt
->low
);
227 /* d is now in 100ns units, since jan 1st 1601".
228 Save off the ns fraction. */
230 ret
.tv_nsec
= (long) ((d
% 100) * 100);
232 /* Convert to seconds */
235 /* Now adjust by 369 years to make the secs since 1970 */
236 d
-= TIME_FIXUP_CONSTANT_INT
;
238 if (((time_t)d
) <= TIME_T_MIN
) {
239 ret
.tv_sec
= TIME_T_MIN
;
244 if (((time_t)d
) >= TIME_T_MAX
) {
245 ret
.tv_sec
= TIME_T_MAX
;
250 ret
.tv_sec
= (time_t)d
;
254 /****************************************************************************
255 Convert a NTTIME structure to a time_t.
256 It's originally in "100ns units".
258 This is an absolute version of the one above.
259 By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
260 if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
261 ****************************************************************************/
263 time_t nt_time_to_unix_abs(const NTTIME
*nt
)
272 if (nt
->high
==0x80000000 && nt
->low
==0) {
276 /* reverse the time */
277 /* it's a negative value, turn it to positive */
278 neg_nt
.high
=~nt
->high
;
281 d
= (((uint64
)neg_nt
.high
) << 32 ) + ((uint64
)neg_nt
.low
);
286 if (!(TIME_T_MIN
<= ((time_t)d
) && ((time_t)d
) <= TIME_T_MAX
)) {
293 /****************************************************************************
294 Put a 8 byte filetime from a struct timespec. Uses GMT.
295 ****************************************************************************/
297 void unix_timespec_to_nt_time(NTTIME
*nt
, struct timespec ts
)
301 if (ts
.tv_sec
==0 && ts
.tv_nsec
== 0) {
306 if (ts
.tv_sec
== TIME_T_MAX
) {
307 nt
->low
= 0xffffffff;
308 nt
->high
= 0x7fffffff;
311 if (ts
.tv_sec
== (time_t)-1) {
312 nt
->low
= 0xffffffff;
313 nt
->high
= 0xffffffff;
318 d
+= TIME_FIXUP_CONSTANT_INT
;
320 /* d is now in 100ns units. */
321 d
+= (ts
.tv_nsec
/ 100);
323 nt
->low
= (uint32
)(d
& 0xFFFFFFFF);
324 nt
->high
= (uint32
)(d
>> 32 );
329 /* No 64-bit datatype. Use double float. */
330 #define TIME_FIXUP_CONSTANT_DOUBLE (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60))
332 /* Floating point double versions. */
333 static struct timespec
nt_time_to_unix_timespec(NTTIME
*nt
)
338 if ((nt
->high
== 0 && nt
->low
== 0 )||
339 (nt
->high
== 0xffffffff && nt
->low
== 0xffffffff)) {
345 d
= ((double)nt
->high
)*4.0*(double)(1<<30);
346 d
+= (nt
->low
&0xFFF00000);
349 /* now adjust by 369 years to make the secs since 1970 */
350 d
-= TIME_FIXUP_CONSTANT_DOUBLE
;
352 if (d
<= TIME_T_MIN
) {
353 ret
.tv_sec
= TIME_T_MIN
;
358 if (d
>= TIME_T_MAX
) {
359 ret
.tv_sec
= TIME_T_MAX
;
364 ret
.tv_sec
= (time_t)d
;
365 ret
.tv_nsec
= (long) ((d
- (double)ret
.tv_sec
)*1.0e9
);
369 /****************************************************************************
370 Convert a NTTIME structure to a time_t.
371 It's originally in "100ns units".
373 This is an absolute version of the one above.
374 By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970
375 if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM
376 ****************************************************************************/
378 time_t nt_time_to_unix_abs(const NTTIME
*nt
)
388 if (nt
->high
==0x80000000 && nt
->low
==0) {
392 /* reverse the time */
393 /* it's a negative value, turn it to positive */
394 neg_nt
.high
=~nt
->high
;
397 d
= ((double)neg_nt
.high
)*4.0*(double)(1<<30);
398 d
+= (neg_nt
.low
&0xFFF00000);
401 if (!(TIME_T_MIN
<= d
&& d
<= TIME_T_MAX
)) {
405 ret
= (time_t)(d
+0.5);
409 /****************************************************************************
410 Put a 8 byte filetime from a struct timespec. Uses GMT.
411 ****************************************************************************/
413 void unix_timespec_to_nt_time(NTTIME
*nt
, struct timespec ts
)
417 if (ts
.tv_sec
==0 && ts
.tv_nsec
== 0) {
422 if (ts
.tv_sec
== TIME_T_MAX
) {
423 nt
->low
= 0xffffffff;
424 nt
->high
= 0x7fffffff;
427 if (ts
.tv_sec
== (time_t)-1) {
428 nt
->low
= 0xffffffff;
429 nt
->high
= 0xffffffff;
433 d
= (double)(ts
.tv_sec
);
434 d
+= TIME_FIXUP_CONSTANT_DOUBLE
;
436 d
+= ((double)ts
.tv_nsec
/ 100.0);
438 nt
->high
= (uint32
)(d
* (1.0/(4.0*(double)(1<<30))));
439 nt
->low
= (uint32
)(d
- ((double)nt
->high
)*4.0*(double)(1<<30));
443 time_t nt_time_to_unix(NTTIME
*nt
)
445 return convert_timespec_to_time_t(nt_time_to_unix_timespec(nt
));
448 /****************************************************************************
449 Interprets an nt time into a unix struct timespec.
450 Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff
451 will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case.
452 ****************************************************************************/
454 struct timespec
interpret_long_date(char *p
)
459 if (nt
.low
== 0xFFFFFFFF && nt
.high
== 0xFFFFFFFF) {
461 ret
.tv_sec
= (time_t)-1;
465 return nt_time_to_unix_timespec(&nt
);
468 /****************************************************************************
469 Put a 8 byte filetime from a time_t. Uses GMT.
470 ****************************************************************************/
472 void unix_to_nt_time(NTTIME
*nt
, time_t t
)
477 unix_timespec_to_nt_time(nt
, ts
);
480 /****************************************************************************
481 Convert a time_t to a NTTIME structure
483 This is an absolute version of the one above.
484 By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601
485 If the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM
486 ****************************************************************************/
488 void unix_to_nt_time_abs(NTTIME
*nt
, time_t t
)
498 if (t
== TIME_T_MAX
) {
499 nt
->low
= 0xffffffff;
500 nt
->high
= 0x7fffffff;
504 if (t
== (time_t)-1) {
505 /* that's what NT uses for infinite */
507 nt
->high
= 0x80000000;
514 nt
->high
= (uint32
)(d
* (1.0/(4.0*(double)(1<<30))));
515 nt
->low
= (uint32
)(d
- ((double)nt
->high
)*4.0*(double)(1<<30));
517 /* convert to a negative value */
522 /****************************************************************************
523 Take a Unix time and convert to an NTTIME structure and place in buffer
525 ****************************************************************************/
527 void put_long_date_timespec(char *p
, struct timespec ts
)
530 unix_timespec_to_nt_time(&nt
, ts
);
532 SIVAL(p
, 4, nt
.high
);
535 void put_long_date(char *p
, time_t t
)
540 put_long_date_timespec(p
, ts
);
543 /****************************************************************************
544 Check if it's a null mtime.
545 ****************************************************************************/
547 BOOL
null_mtime(time_t mtime
)
549 if (mtime
== 0 || mtime
== (time_t)0xFFFFFFFF || mtime
== (time_t)-1)
554 /*******************************************************************
555 Create a 16 bit dos packed date.
556 ********************************************************************/
558 static uint16
make_dos_date1(struct tm
*t
)
561 ret
= (((unsigned)(t
->tm_mon
+1)) >> 3) | ((t
->tm_year
-80) << 1);
562 ret
= ((ret
&0xFF)<<8) | (t
->tm_mday
| (((t
->tm_mon
+1) & 0x7) << 5));
566 /*******************************************************************
567 Create a 16 bit dos packed time.
568 ********************************************************************/
570 static uint16
make_dos_time1(struct tm
*t
)
573 ret
= ((((unsigned)t
->tm_min
>> 3)&0x7) | (((unsigned)t
->tm_hour
) << 3));
574 ret
= ((ret
&0xFF)<<8) | ((t
->tm_sec
/2) | ((t
->tm_min
& 0x7) << 5));
578 /*******************************************************************
579 Create a 32 bit dos packed date/time from some parameters.
580 This takes a GMT time and returns a packed localtime structure.
581 ********************************************************************/
583 static uint32
make_dos_date(time_t unixdate
, int zone_offset
)
592 unixdate
-= zone_offset
;
593 t
= gmtime(&unixdate
);
598 ret
= make_dos_date1(t
);
599 ret
= ((ret
&0xFFFF)<<16) | make_dos_time1(t
);
604 /*******************************************************************
605 Put a dos date into a buffer (time/date format).
606 This takes GMT time and puts local time in the buffer.
607 ********************************************************************/
609 static void put_dos_date(char *buf
,int offset
,time_t unixdate
, int zone_offset
)
611 uint32 x
= make_dos_date(unixdate
, zone_offset
);
615 /*******************************************************************
616 Put a dos date into a buffer (date/time format).
617 This takes GMT time and puts local time in the buffer.
618 ********************************************************************/
620 static void put_dos_date2(char *buf
,int offset
,time_t unixdate
, int zone_offset
)
622 uint32 x
= make_dos_date(unixdate
, zone_offset
);
623 x
= ((x
&0xFFFF)<<16) | ((x
&0xFFFF0000)>>16);
627 /*******************************************************************
628 Put a dos 32 bit "unix like" date into a buffer. This routine takes
629 GMT and converts it to LOCAL time before putting it (most SMBs assume
630 localtime for this sort of date)
631 ********************************************************************/
633 static void put_dos_date3(char *buf
,int offset
,time_t unixdate
, int zone_offset
)
635 if (!null_mtime(unixdate
)) {
636 unixdate
-= zone_offset
;
638 SIVAL(buf
,offset
,unixdate
);
641 /*******************************************************************
642 Interpret a 32 bit dos packed date/time to some parameters.
643 ********************************************************************/
645 static void interpret_dos_date(uint32 date
,int *year
,int *month
,int *day
,int *hour
,int *minute
,int *second
)
649 p0
=date
&0xFF; p1
=((date
&0xFF00)>>8)&0xFF;
650 p2
=((date
&0xFF0000)>>16)&0xFF; p3
=((date
&0xFF000000)>>24)&0xFF;
652 *second
= 2*(p0
& 0x1F);
653 *minute
= ((p0
>>5)&0xFF) + ((p1
&0x7)<<3);
654 *hour
= (p1
>>3)&0xFF;
656 *month
= ((p2
>>5)&0xFF) + ((p3
&0x1)<<3) - 1;
657 *year
= ((p3
>>1)&0xFF) + 80;
660 /*******************************************************************
661 Create a unix date (int GMT) from a dos date (which is actually in
663 ********************************************************************/
665 static time_t make_unix_date(void *date_ptr
, int zone_offset
)
671 dos_date
= IVAL(date_ptr
,0);
677 interpret_dos_date(dos_date
,&t
.tm_year
,&t
.tm_mon
,
678 &t
.tm_mday
,&t
.tm_hour
,&t
.tm_min
,&t
.tm_sec
);
688 /*******************************************************************
689 Like make_unix_date() but the words are reversed.
690 ********************************************************************/
692 static time_t make_unix_date2(void *date_ptr
, int zone_offset
)
696 x
= IVAL(date_ptr
,0);
697 x2
= ((x
&0xFFFF)<<16) | ((x
&0xFFFF0000)>>16);
700 return(make_unix_date((void *)&x
, zone_offset
));
703 /*******************************************************************
704 Create a unix GMT date from a dos date in 32 bit "unix like" format
705 these generally arrive as localtimes, with corresponding DST.
706 ******************************************************************/
708 static time_t make_unix_date3(void *date_ptr
, int zone_offset
)
710 time_t t
= (time_t)IVAL(date_ptr
,0);
711 if (!null_mtime(t
)) {
717 /***************************************************************************
718 Server versions of the above functions.
719 ***************************************************************************/
721 void srv_put_dos_date(char *buf
,int offset
,time_t unixdate
)
723 put_dos_date(buf
, offset
, unixdate
, server_zone_offset
);
726 void srv_put_dos_date2(char *buf
,int offset
, time_t unixdate
)
728 put_dos_date2(buf
, offset
, unixdate
, server_zone_offset
);
731 void srv_put_dos_date3(char *buf
,int offset
,time_t unixdate
)
733 put_dos_date3(buf
, offset
, unixdate
, server_zone_offset
);
736 time_t srv_make_unix_date(void *date_ptr
)
738 return make_unix_date(date_ptr
, server_zone_offset
);
741 time_t srv_make_unix_date2(void *date_ptr
)
743 return make_unix_date2(date_ptr
, server_zone_offset
);
746 time_t srv_make_unix_date3(void *date_ptr
)
748 return make_unix_date3(date_ptr
, server_zone_offset
);
751 /***************************************************************************
752 Client versions of the above functions.
753 ***************************************************************************/
755 void cli_put_dos_date(struct cli_state
*cli
, char *buf
, int offset
, time_t unixdate
)
757 put_dos_date(buf
, offset
, unixdate
, cli
->serverzone
);
760 void cli_put_dos_date2(struct cli_state
*cli
, char *buf
, int offset
, time_t unixdate
)
762 put_dos_date2(buf
, offset
, unixdate
, cli
->serverzone
);
765 void cli_put_dos_date3(struct cli_state
*cli
, char *buf
, int offset
, time_t unixdate
)
767 put_dos_date3(buf
, offset
, unixdate
, cli
->serverzone
);
770 time_t cli_make_unix_date(struct cli_state
*cli
, void *date_ptr
)
772 return make_unix_date(date_ptr
, cli
->serverzone
);
775 time_t cli_make_unix_date2(struct cli_state
*cli
, void *date_ptr
)
777 return make_unix_date2(date_ptr
, cli
->serverzone
);
780 time_t cli_make_unix_date3(struct cli_state
*cli
, void *date_ptr
)
782 return make_unix_date3(date_ptr
, cli
->serverzone
);
785 /***************************************************************************
786 Return a HTTP/1.0 time string.
787 ***************************************************************************/
789 char *http_timestring(time_t t
)
792 struct tm
*tm
= localtime(&t
);
795 slprintf(buf
,sizeof(buf
)-1,"%ld seconds since the Epoch",(long)t
);
797 #ifndef HAVE_STRFTIME
798 const char *asct
= asctime(tm
);
799 fstrcpy(buf
, asct
? asct
: "unknown");
801 if(buf
[strlen(buf
)-1] == '\n') {
802 buf
[strlen(buf
)-1] = 0;
803 #else /* !HAVE_STRFTIME */
804 strftime(buf
, sizeof(buf
)-1, "%a, %d %b %Y %H:%M:%S %Z", tm
);
805 #endif /* !HAVE_STRFTIME */
810 /****************************************************************************
811 Return the date and time as a string
812 ****************************************************************************/
814 char *current_timestring(BOOL hires
)
816 static fstring TimeBuf
;
823 t
= (time_t)tp
.tv_sec
;
832 "%ld.%06ld seconds since the Epoch",
838 "%ld seconds since the Epoch",
844 strftime(TimeBuf
,sizeof(TimeBuf
)-1,"%Y/%m/%d %H:%M:%S",tm
);
845 slprintf(TimeBuf
+strlen(TimeBuf
),
846 sizeof(TimeBuf
)-1 - strlen(TimeBuf
),
850 strftime(TimeBuf
,sizeof(TimeBuf
)-1,"%Y/%m/%d %H:%M:%S",tm
);
854 const char *asct
= asctime(tm
);
858 asct
? asct
: "unknown",
861 const char *asct
= asctime(tm
);
862 fstrcpy(TimeBuf
, asct
? asct
: "unknown");
869 /****************************************************************************
870 Return the best approximation to a 'create time' under UNIX from a stat
872 ****************************************************************************/
874 time_t get_create_time(SMB_STRUCT_STAT
*st
,BOOL fake_dirs
)
878 if(S_ISDIR(st
->st_mode
) && fake_dirs
) {
879 return (time_t)315493200L; /* 1/1/1980 */
882 ret
= MIN(st
->st_ctime
, st
->st_mtime
);
883 ret1
= MIN(ret
, st
->st_atime
);
885 if(ret1
!= (time_t)0) {
890 * One of ctime, mtime or atime was zero (probably atime).
891 * Just return MIN(ctime, mtime).
896 struct timespec
get_create_timespec(SMB_STRUCT_STAT
*st
,BOOL fake_dirs
)
899 ts
.tv_sec
= get_create_time(st
, fake_dirs
);
904 /****************************************************************************
905 Initialise an NTTIME to -1, which means "unknown" or "don't expire".
906 ****************************************************************************/
908 void init_nt_time(NTTIME
*nt
)
910 nt
->high
= 0x7FFFFFFF;
911 nt
->low
= 0xFFFFFFFF;
914 BOOL
nt_time_is_set(const NTTIME
*nt
)
916 if ((nt
->high
== 0x7FFFFFFF) && (nt
->low
== 0xFFFFFFFF)) {
920 if ((nt
->high
== 0x80000000) && (nt
->low
== 0)) {
927 /****************************************************************************
928 Check if NTTIME is 0.
929 ****************************************************************************/
931 BOOL
nt_time_is_zero(const NTTIME
*nt
)
939 /****************************************************************************
940 Check if two NTTIMEs are the same.
941 ****************************************************************************/
943 BOOL
nt_time_equals(const NTTIME
*nt1
, const NTTIME
*nt2
)
945 return (nt1
->high
== nt2
->high
&& nt1
->low
== nt2
->low
);
948 /****************************************************************************
949 Return a timeval difference in usec.
950 ****************************************************************************/
952 SMB_BIG_INT
usec_time_diff(const struct timeval
*larget
, const struct timeval
*smallt
)
954 SMB_BIG_INT sec_diff
= larget
->tv_sec
- smallt
->tv_sec
;
955 return (sec_diff
* 1000000) + (SMB_BIG_INT
)(larget
->tv_usec
- smallt
->tv_usec
);
958 /****************************************************************************
959 Return a timeval struct with the given elements.
960 ****************************************************************************/
962 struct timeval
timeval_set(uint32_t secs
, uint32_t usecs
)
970 /****************************************************************************
971 Return a zero timeval.
972 ****************************************************************************/
974 struct timeval
timeval_zero(void)
976 return timeval_set(0,0);
979 /****************************************************************************
980 Return True if a timeval is zero.
981 ****************************************************************************/
983 BOOL
timeval_is_zero(const struct timeval
*tv
)
985 return tv
->tv_sec
== 0 && tv
->tv_usec
== 0;
988 /****************************************************************************
989 Return a timeval for the current time.
990 ****************************************************************************/
992 struct timeval
timeval_current(void)
999 /****************************************************************************
1000 Return a timeval ofs microseconds after tv.
1001 ****************************************************************************/
1003 struct timeval
timeval_add(const struct timeval
*tv
,
1004 uint32_t secs
, uint32_t usecs
)
1006 struct timeval tv2
= *tv
;
1008 tv2
.tv_usec
+= usecs
;
1009 tv2
.tv_sec
+= tv2
.tv_usec
/ 1000000;
1010 tv2
.tv_usec
= tv2
.tv_usec
% 1000000;
1014 /****************************************************************************
1015 Return the sum of two timeval structures.
1016 ****************************************************************************/
1018 struct timeval
timeval_sum(const struct timeval
*tv1
,
1019 const struct timeval
*tv2
)
1021 return timeval_add(tv1
, tv2
->tv_sec
, tv2
->tv_usec
);
1024 /****************************************************************************
1025 Return a timeval secs/usecs into the future.
1026 ****************************************************************************/
1028 struct timeval
timeval_current_ofs(uint32_t secs
, uint32_t usecs
)
1030 struct timeval tv
= timeval_current();
1031 return timeval_add(&tv
, secs
, usecs
);
1034 /****************************************************************************
1035 Compare two timeval structures.
1036 Return -1 if tv1 < tv2
1037 Return 0 if tv1 == tv2
1038 Return 1 if tv1 > tv2
1039 ****************************************************************************/
1041 int timeval_compare(const struct timeval
*tv1
, const struct timeval
*tv2
)
1043 if (tv1
->tv_sec
> tv2
->tv_sec
) {
1046 if (tv1
->tv_sec
< tv2
->tv_sec
) {
1049 if (tv1
->tv_usec
> tv2
->tv_usec
) {
1052 if (tv1
->tv_usec
< tv2
->tv_usec
) {
1058 /****************************************************************************
1059 Return the difference between two timevals as a timeval.
1060 If tv1 comes after tv2, then return a zero timeval
1061 (this is *tv2 - *tv1).
1062 ****************************************************************************/
1064 struct timeval
timeval_until(const struct timeval
*tv1
,
1065 const struct timeval
*tv2
)
1068 if (timeval_compare(tv1
, tv2
) >= 0) {
1069 return timeval_zero();
1071 t
.tv_sec
= tv2
->tv_sec
- tv1
->tv_sec
;
1072 if (tv1
->tv_usec
> tv2
->tv_usec
) {
1074 t
.tv_usec
= 1000000 - (tv1
->tv_usec
- tv2
->tv_usec
);
1076 t
.tv_usec
= tv2
->tv_usec
- tv1
->tv_usec
;
1081 /****************************************************************************
1082 Return the lesser of two timevals.
1083 ****************************************************************************/
1085 struct timeval
timeval_min(const struct timeval
*tv1
,
1086 const struct timeval
*tv2
)
1088 if (tv1
->tv_sec
< tv2
->tv_sec
) {
1091 if (tv1
->tv_sec
> tv2
->tv_sec
) {
1094 if (tv1
->tv_usec
< tv2
->tv_usec
) {
1100 /****************************************************************************
1101 Return the greater of two timevals.
1102 ****************************************************************************/
1104 struct timeval
timeval_max(const struct timeval
*tv1
,
1105 const struct timeval
*tv2
)
1107 if (tv1
->tv_sec
> tv2
->tv_sec
) {
1110 if (tv1
->tv_sec
< tv2
->tv_sec
) {
1113 if (tv1
->tv_usec
> tv2
->tv_usec
) {
1119 /****************************************************************************
1120 Convert ASN.1 GeneralizedTime string to unix-time.
1121 Returns 0 on failure; Currently ignores timezone.
1122 ****************************************************************************/
1124 time_t generalized_to_unix_time(const char *str
)
1130 if (sscanf(str
, "%4d%2d%2d%2d%2d%2d",
1131 &tm
.tm_year
, &tm
.tm_mon
, &tm
.tm_mday
,
1132 &tm
.tm_hour
, &tm
.tm_min
, &tm
.tm_sec
) != 6) {
1141 /****************************************************************************
1142 Get/Set all the possible time fields from a stat struct as a timespec.
1143 ****************************************************************************/
1145 struct timespec
get_atimespec(SMB_STRUCT_STAT
*pst
)
1147 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
1148 struct timespec ret
;
1150 /* Old system - no ns timestamp. */
1151 ret
.tv_sec
= pst
->st_atime
;
1155 #if defined(HAVE_STAT_ST_ATIM)
1156 return pst
->st_atim
;
1157 #elif defined(HAVE_STAT_ST_ATIMENSEC)
1158 struct timespec ret
;
1159 ret
.tv_sec
= pst
->st_atime
;
1160 ret
.tv_nsec
= pst
->st_atimensec
;
1163 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
1168 void set_atimespec(SMB_STRUCT_STAT
*pst
, struct timespec ts
)
1170 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
1171 /* Old system - no ns timestamp. */
1172 pst
->st_atime
= ts
.tv_sec
;
1174 #if defined(HAVE_STAT_ST_ATIM)
1176 #elif defined(HAVE_STAT_ST_ATIMENSEC)
1177 pst
->st_atime
= ts
.tv_sec
;
1178 pst
->st_atimensec
= ts
.tv_nsec
1180 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
1185 struct timespec
get_mtimespec(SMB_STRUCT_STAT
*pst
)
1187 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
1188 struct timespec ret
;
1190 /* Old system - no ns timestamp. */
1191 ret
.tv_sec
= pst
->st_mtime
;
1195 #if defined(HAVE_STAT_ST_MTIM)
1196 return pst
->st_mtim
;
1197 #elif defined(HAVE_STAT_ST_MTIMENSEC)
1198 struct timespec ret
;
1199 ret
.tv_sec
= pst
->st_mtime
;
1200 ret
.tv_nsec
= pst
->st_mtimensec
;
1203 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
1208 void set_mtimespec(SMB_STRUCT_STAT
*pst
, struct timespec ts
)
1210 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
1211 /* Old system - no ns timestamp. */
1212 pst
->st_mtime
= ts
.tv_sec
;
1214 #if defined(HAVE_STAT_ST_MTIM)
1216 #elif defined(HAVE_STAT_ST_MTIMENSEC)
1217 pst
->st_mtime
= ts
.tv_sec
;
1218 pst
->st_mtimensec
= ts
.tv_nsec
1220 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
1225 struct timespec
get_ctimespec(SMB_STRUCT_STAT
*pst
)
1227 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
1228 struct timespec ret
;
1230 /* Old system - no ns timestamp. */
1231 ret
.tv_sec
= pst
->st_ctime
;
1235 #if defined(HAVE_STAT_ST_CTIM)
1236 return pst
->st_ctim
;
1237 #elif defined(HAVE_STAT_ST_CTIMENSEC)
1238 struct timespec ret
;
1239 ret
.tv_sec
= pst
->st_ctime
;
1240 ret
.tv_nsec
= pst
->st_ctimensec
;
1243 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
1248 void set_ctimespec(SMB_STRUCT_STAT
*pst
, struct timespec ts
)
1250 #if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
1251 /* Old system - no ns timestamp. */
1252 pst
->st_ctime
= ts
.tv_sec
;
1254 #if defined(HAVE_STAT_ST_CTIM)
1256 #elif defined(HAVE_STAT_ST_CTIMENSEC)
1257 pst
->st_ctime
= ts
.tv_sec
;
1258 pst
->st_ctimensec
= ts
.tv_nsec
1260 #error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
1266 /****************************************************************************
1267 Return the best approximation to a 'create time' under UNIX from a stat
1269 ****************************************************************************/
1271 struct timespec
get_create_timespec(SMB_STRUCT_STAT
*st
,BOOL fake_dirs
)
1275 if(S_ISDIR(st
->st_mode
) && fake_dirs
) {
1276 return (time_t)315493200L; /* 1/1/1980 */
1279 ret
= MIN(st
->st_ctime
, st
->st_mtime
);
1280 ret1
= MIN(ret
, st
->st_atime
);
1282 if(ret1
!= (time_t)0) {
1287 * One of ctime, mtime or atime was zero (probably atime).
1288 * Just return MIN(ctime, mtime).
1294 void dos_filetime_timespec(struct timespec
*tsp
)
1301 Return the date and time as a string
1303 char *timestring(TALLOC_CTX
*mem_ctx
, time_t t
)
1311 return talloc_asprintf(mem_ctx
,
1312 "%ld seconds since the Epoch",
1316 #ifdef HAVE_STRFTIME
1317 /* some versions of gcc complain about using %c. This is a bug
1318 in the gcc warning, not a bug in this code. See a recent
1319 strftime() manual page for details.
1321 strftime(tempTime
,sizeof(tempTime
)-1,"%c %Z",tm
);
1322 TimeBuf
= talloc_strdup(mem_ctx
, tempTime
);
1324 TimeBuf
= talloc_strdup(mem_ctx
, asctime(tm
));
1332 return a talloced string representing a NTTIME for human consumption
1334 const char *nt_time_string(TALLOC_CTX
*mem_ctx
, NTTIME nt
)
1337 if (nt
.low
== 0 && nt
.high
== 0) {
1340 t
= nt_time_to_unix(&nt
);
1341 return timestring(mem_ctx
, t
);
1344 /****************************************************************************
1345 Utility function that always returns a const string even if localtime
1347 ****************************************************************************/
1349 const char *time_to_asc(const time_t *t
)
1352 struct tm
*lt
= localtime(t
);
1355 return "unknown time";
1360 return "unknown time";