diff options
Diffstat (limited to 'source3/lib/time.c')
-rw-r--r-- | source3/lib/time.c | 1686 |
1 files changed, 838 insertions, 848 deletions
diff --git a/source3/lib/time.c b/source3/lib/time.c index 0fb35bd977..715c1a1bcc 100644 --- a/source3/lib/time.c +++ b/source3/lib/time.c @@ -1,8 +1,10 @@ /* Unix SMB/CIFS implementation. time handling functions - Copyright (C) Andrew Tridgell 1992-1998 + + Copyright (C) Andrew Tridgell 1992-2004 Copyright (C) Stefan (metze) Metzmacher 2002 + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -20,16 +22,11 @@ #include "includes.h" -/* - This stuff was largely rewritten by Paul Eggert <eggert@twinsun.com> - in May 1996 - */ - -int extra_time_offset = 0; +/** + * @file + * @brief time handling functions + */ -#ifndef CHAR_BIT -#define CHAR_BIT 8 -#endif #ifndef TIME_T_MIN #define TIME_T_MIN ((time_t)0 < (time_t) -1 ? (time_t) 0 \ @@ -39,19 +36,17 @@ int extra_time_offset = 0; #define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN) #endif -/******************************************************************* +/** External access to time_t_min and time_t_max. -********************************************************************/ - +**/ time_t get_time_t_max(void) { return TIME_T_MAX; } -/******************************************************************* - A gettimeofday wrapper. -********************************************************************/ - +/** +a gettimeofday wrapper +**/ void GetTimeOfDay(struct timeval *tval) { #ifdef HAVE_GETTIMEOFDAY_TZ @@ -61,126 +56,7 @@ void GetTimeOfDay(struct timeval *tval) #endif } -#define TM_YEAR_BASE 1900 - -/******************************************************************* - Yield the difference between *A and *B, in seconds, ignoring leap seconds. -********************************************************************/ - -static int tm_diff(struct tm *a, struct tm *b) -{ - int ay = a->tm_year + (TM_YEAR_BASE - 1); - int by = b->tm_year + (TM_YEAR_BASE - 1); - int intervening_leap_days = (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400); - int years = ay - by; - int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday); - int hours = 24*days + (a->tm_hour - b->tm_hour); - int minutes = 60*hours + (a->tm_min - b->tm_min); - int seconds = 60*minutes + (a->tm_sec - b->tm_sec); - - return seconds; -} - -/******************************************************************* - Return the UTC offset in seconds west of UTC, or 0 if it cannot be determined. -******************************************************************/ - -int get_time_zone(time_t t) -{ - struct tm *tm = gmtime(&t); - struct tm tm_utc; - - if (!tm) { - return 0; - } - tm_utc = *tm; - tm = localtime(&t); - if (!tm) { - return 0; - } - return tm_diff(&tm_utc,tm) + 60*extra_time_offset; -} - -/******************************************************************* - Accessor function for the server time zone offset. - set_server_zone_offset() must have been called first. -******************************************************************/ - -static int server_zone_offset; - -int get_server_zone_offset(void) -{ - return server_zone_offset; -} - -/******************************************************************* - Initialize the server time zone offset. Called when a client connects. -******************************************************************/ - -int set_server_zone_offset(time_t t) -{ - server_zone_offset = get_time_zone(t); - return server_zone_offset; -} - -/******************************************************************* - Re-read the smb serverzone value. -******************************************************************/ - -static struct timeval start_time_hires; - -void TimeInit(void) -{ - set_server_zone_offset(time(NULL)); - - DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset)); - - /* Save the start time of this process. */ - if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) { - GetTimeOfDay(&start_time_hires); - } -} - -/********************************************************************** - Return a timeval struct of the uptime of this process. As TimeInit is - done before a daemon fork then this is the start time from the parent - daemon start. JRA. -***********************************************************************/ - -void get_process_uptime(struct timeval *ret_time) -{ - struct timeval time_now_hires; - - GetTimeOfDay(&time_now_hires); - ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec; - if (time_now_hires.tv_usec < start_time_hires.tv_usec) { - ret_time->tv_sec -= 1; - ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec); - } else { - ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec; - } -} - -#if 0 -/**************************************************************************** - Return the UTC offset in seconds west of UTC, adjusted for extra time offset. -**************************************************************************/ - -int TimeDiff(time_t t) -{ - return get_time_zone(t); -} -#endif - -time_t convert_timespec_to_time_t(struct timespec ts) -{ - /* 1 ns == 1,000,000,000 - one thousand millionths of a second. - increment if it's greater than 500 millionth of a second. */ - if (ts.tv_nsec > 500000000) { - return ts.tv_sec + 1; - } - return ts.tv_sec; -} +#define TIME_FIXUP_CONSTANT 11644473600LL struct timespec convert_time_t_to_timespec(time_t t) { @@ -190,8 +66,6 @@ struct timespec convert_time_t_to_timespec(time_t t) return ts; } -#ifdef uint64 - #if (SIZEOF_LONG == 8) #define TIME_FIXUP_CONSTANT_INT 11644473600L #elif (SIZEOF_LONG_LONG == 8) @@ -210,259 +84,9 @@ struct timespec convert_time_t_to_timespec(time_t t) Returns GMT. ****************************************************************************/ -/* Large integer version. */ -static struct timespec nt_time_to_unix_timespec(NTTIME *nt) -{ - uint64 d; - struct timespec ret; - - if ((nt->high == 0 && nt->low == 0 )|| - (nt->high == 0xffffffff && nt->low == 0xffffffff)) { - ret.tv_sec = 0; - ret.tv_nsec = 0; - return ret; - } - - d = (((uint64)nt->high) << 32 ) + ((uint64)nt->low); - /* d is now in 100ns units, since jan 1st 1601". - Save off the ns fraction. */ - - ret.tv_nsec = (long) ((d % 100) * 100); - - /* Convert to seconds */ - d /= 1000*1000*10; - - /* Now adjust by 369 years to make the secs since 1970 */ - d -= TIME_FIXUP_CONSTANT_INT; - - if (((time_t)d) <= TIME_T_MIN) { - ret.tv_sec = TIME_T_MIN; - ret.tv_nsec = 0; - return ret; - } - - if ((d >= (uint64)TIME_T_MAX)) { - ret.tv_sec = TIME_T_MAX; - ret.tv_nsec = 0; - return ret; - } - - ret.tv_sec = (time_t)d; - return ret; -} - -/**************************************************************************** - Convert a NTTIME structure to a time_t. - It's originally in "100ns units". - - This is an absolute version of the one above. - By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970 - if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM -****************************************************************************/ - -time_t nt_time_to_unix_abs(const NTTIME *nt) -{ - uint64 d; - NTTIME neg_nt; - - if (nt->high == 0) { - return (time_t)0; - } - - if (nt->high==0x80000000 && nt->low==0) { - return (time_t)-1; - } - - /* reverse the time */ - /* it's a negative value, turn it to positive */ - neg_nt.high=~nt->high; - neg_nt.low=~nt->low; - - d = (((uint64)neg_nt.high) << 32 ) + ((uint64)neg_nt.low); - - d += 1000*1000*10/2; - d /= 1000*1000*10; - - if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) { - return (time_t)0; - } - - return (time_t)d; -} - -/**************************************************************************** - Put a 8 byte filetime from a struct timespec. Uses GMT. -****************************************************************************/ - -void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts) -{ - uint64 d; - - if (ts.tv_sec ==0 && ts.tv_nsec == 0) { - nt->low = 0; - nt->high = 0; - return; - } - if (ts.tv_sec == TIME_T_MAX) { - nt->low = 0xffffffff; - nt->high = 0x7fffffff; - return; - } - if (ts.tv_sec == (time_t)-1) { - nt->low = 0xffffffff; - nt->high = 0xffffffff; - return; - } - - d = ts.tv_sec; - d += TIME_FIXUP_CONSTANT_INT; - d *= 1000*1000*10; - /* d is now in 100ns units. */ - d += (ts.tv_nsec / 100); - - nt->low = (uint32)(d & 0xFFFFFFFF); - nt->high = (uint32)(d >> 32 ); -} - -#else - -/* No 64-bit datatype. Use double float. */ -#define TIME_FIXUP_CONSTANT_DOUBLE (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60)) - -/* Floating point double versions. */ -static struct timespec nt_time_to_unix_timespec(NTTIME *nt) +time_t nt_time_to_unix(NTTIME nt) { - double d; - struct timespec ret; - - if ((nt->high == 0 && nt->low == 0 )|| - (nt->high == 0xffffffff && nt->low == 0xffffffff)) { - ret.tv_sec = 0; - ret.tv_nsec = 0; - return ret; - } - - d = ((double)nt->high)*4.0*(double)(1<<30); - d += (nt->low&0xFFF00000); - d *= 1.0e-7; - - /* now adjust by 369 years to make the secs since 1970 */ - d -= TIME_FIXUP_CONSTANT_DOUBLE; - - if (d <= TIME_T_MIN) { - ret.tv_sec = TIME_T_MIN; - ret.tv_nsec = 0; - return ret; - } - - if (d >= TIME_T_MAX) { - ret.tv_sec = TIME_T_MAX; - ret.tv_nsec = 0; - return ret; - } - - ret.tv_sec = (time_t)d; - ret.tv_nsec = (long) ((d - (double)ret.tv_sec)*1.0e9); - return ret; -} - -/**************************************************************************** - Convert a NTTIME structure to a time_t. - It's originally in "100ns units". - - This is an absolute version of the one above. - By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970 - if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM -****************************************************************************/ - -time_t nt_time_to_unix_abs(const NTTIME *nt) -{ - double d; - time_t ret; - NTTIME neg_nt; - - if (nt->high == 0) { - return (time_t)0; - } - - if (nt->high==0x80000000 && nt->low==0) { - return (time_t)-1; - } - - /* reverse the time */ - /* it's a negative value, turn it to positive */ - neg_nt.high=~nt->high; - neg_nt.low=~nt->low; - - d = ((double)neg_nt.high)*4.0*(double)(1<<30); - d += (neg_nt.low&0xFFF00000); - d *= 1.0e-7; - - if (!(TIME_T_MIN <= d && d <= TIME_T_MAX)) { - return (time_t)0; - } - - ret = (time_t)(d+0.5); - return ret; -} - -/**************************************************************************** - Put a 8 byte filetime from a struct timespec. Uses GMT. -****************************************************************************/ - -void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts) -{ - double d; - - if (ts.tv_sec ==0 && ts.tv_nsec == 0) { - nt->low = 0; - nt->high = 0; - return; - } - if (ts.tv_sec == TIME_T_MAX) { - nt->low = 0xffffffff; - nt->high = 0x7fffffff; - return; - } - if (ts.tv_sec == (time_t)-1) { - nt->low = 0xffffffff; - nt->high = 0xffffffff; - return; - } - - d = (double)(ts.tv_sec); - d += TIME_FIXUP_CONSTANT_DOUBLE; - d *= 1.0e7; - d += ((double)ts.tv_nsec / 100.0); - - nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30)))); - nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30)); -} -#endif - -time_t nt_time_to_unix(NTTIME *nt) -{ - return convert_timespec_to_time_t(nt_time_to_unix_timespec(nt)); -} - -/**************************************************************************** - Interprets an nt time into a unix struct timespec. - Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff - will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case. -****************************************************************************/ - -struct timespec interpret_long_date(char *p) -{ - NTTIME nt; - nt.low = IVAL(p,0); - nt.high = IVAL(p,4); - if (nt.low == 0xFFFFFFFF && nt.high == 0xFFFFFFFF) { - struct timespec ret; - ret.tv_sec = (time_t)-1; - ret.tv_nsec = 0; - return ret; - } - return nt_time_to_unix_timespec(&nt); + return convert_timespec_to_time_t(nt_time_to_unix_timespec(&nt)); } /**************************************************************************** @@ -471,125 +95,81 @@ struct timespec interpret_long_date(char *p) void unix_to_nt_time(NTTIME *nt, time_t t) { - struct timespec ts; - ts.tv_sec = t; - ts.tv_nsec = 0; - unix_timespec_to_nt_time(nt, ts); -} - -/**************************************************************************** - Convert a time_t to a NTTIME structure - - This is an absolute version of the one above. - By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601 - If the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM -****************************************************************************/ - -void unix_to_nt_time_abs(NTTIME *nt, time_t t) -{ - double d; - - if (t==0) { - nt->low = 0; - nt->high = 0; - return; - } + uint64_t t2; - if (t == TIME_T_MAX) { - nt->low = 0xffffffff; - nt->high = 0x7fffffff; - return; - } - if (t == (time_t)-1) { - /* that's what NT uses for infinite */ - nt->low = 0x0; - nt->high = 0x80000000; + *nt = (NTTIME)-1LL; + return; + } + if (t == 0) { + *nt = 0; return; } - d = (double)(t); - d *= 1.0e7; - - nt->high = (uint32)(d * (1.0/(4.0*(double)(1<<30)))); - nt->low = (uint32)(d - ((double)nt->high)*4.0*(double)(1<<30)); + t2 = t; + t2 += TIME_FIXUP_CONSTANT; + t2 *= 1000*1000*10; - /* convert to a negative value */ - nt->high=~nt->high; - nt->low=~nt->low; + *nt = t2; } -/**************************************************************************** - Take a Unix time and convert to an NTTIME structure and place in buffer - pointed to by p. -****************************************************************************/ - -void put_long_date_timespec(char *p, struct timespec ts) -{ - NTTIME nt; - unix_timespec_to_nt_time(&nt, ts); - SIVAL(p, 0, nt.low); - SIVAL(p, 4, nt.high); -} -void put_long_date(char *p, time_t t) +/** +check if it's a null unix time +**/ +BOOL null_time(time_t t) { - struct timespec ts; - ts.tv_sec = t; - ts.tv_nsec = 0; - put_long_date_timespec(p, ts); + return t == 0 || + t == (time_t)0xFFFFFFFF || + t == (time_t)-1; } -/**************************************************************************** - Check if it's a null mtime. -****************************************************************************/ -BOOL null_mtime(time_t mtime) +/** +check if it's a null NTTIME +**/ +BOOL null_nttime(NTTIME t) { - if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1) - return(True); - return(False); + return t == 0 || t == (NTTIME)-1; } /******************************************************************* - Create a 16 bit dos packed date. + create a 16 bit dos packed date ********************************************************************/ - -static uint16 make_dos_date1(struct tm *t) +static uint16_t make_dos_date1(struct tm *t) { - uint16 ret=0; - ret = (((unsigned)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1); + uint16_t ret=0; + ret = (((unsigned int)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1); ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5)); - return(ret); + return ret; } /******************************************************************* - Create a 16 bit dos packed time. + create a 16 bit dos packed time ********************************************************************/ - -static uint16 make_dos_time1(struct tm *t) +static uint16_t make_dos_time1(struct tm *t) { - uint16 ret=0; - ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3)); + uint16_t ret=0; + ret = ((((unsigned int)t->tm_min >> 3)&0x7) | (((unsigned int)t->tm_hour) << 3)); ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5)); - return(ret); + return ret; } /******************************************************************* - Create a 32 bit dos packed date/time from some parameters. - This takes a GMT time and returns a packed localtime structure. + create a 32 bit dos packed date/time from some parameters + This takes a GMT time and returns a packed localtime structure ********************************************************************/ - -static uint32 make_dos_date(time_t unixdate, int zone_offset) +static uint32_t make_dos_date(time_t unixdate, int zone_offset) { struct tm *t; - uint32 ret=0; + uint32_t ret=0; if (unixdate == 0) { return 0; } unixdate -= zone_offset; + t = gmtime(&unixdate); if (!t) { return 0xFFFFFFFF; @@ -598,53 +178,50 @@ static uint32 make_dos_date(time_t unixdate, int zone_offset) ret = make_dos_date1(t); ret = ((ret&0xFFFF)<<16) | make_dos_time1(t); - return(ret); + return ret; } -/******************************************************************* - Put a dos date into a buffer (time/date format). - This takes GMT time and puts local time in the buffer. -********************************************************************/ - -static void put_dos_date(char *buf,int offset,time_t unixdate, int zone_offset) +/** +put a dos date into a buffer (time/date format) +This takes GMT time and puts local time in the buffer +**/ +void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset) { - uint32 x = make_dos_date(unixdate, zone_offset); + uint32_t x = make_dos_date(unixdate, zone_offset); SIVAL(buf,offset,x); } -/******************************************************************* - Put a dos date into a buffer (date/time format). - This takes GMT time and puts local time in the buffer. -********************************************************************/ - -static void put_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset) +/** +put a dos date into a buffer (date/time format) +This takes GMT time and puts local time in the buffer +**/ +void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset) { - uint32 x = make_dos_date(unixdate, zone_offset); + uint32_t x; + x = make_dos_date(unixdate, zone_offset); x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); SIVAL(buf,offset,x); } -/******************************************************************* - Put a dos 32 bit "unix like" date into a buffer. This routine takes - GMT and converts it to LOCAL time before putting it (most SMBs assume - localtime for this sort of date) -********************************************************************/ - -static void put_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset) +/** +put a dos 32 bit "unix like" date into a buffer. This routine takes +GMT and converts it to LOCAL time before putting it (most SMBs assume +localtime for this sort of date) +**/ +void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset) { - if (!null_mtime(unixdate)) { + if (!null_time(unixdate)) { unixdate -= zone_offset; } SIVAL(buf,offset,unixdate); } /******************************************************************* - Interpret a 32 bit dos packed date/time to some parameters. + interpret a 32 bit dos packed date/time to some parameters ********************************************************************/ - -static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *hour,int *minute,int *second) +static void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second) { - uint32 p0,p1,p2,p3; + uint32_t p0,p1,p2,p3; p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF; p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF; @@ -657,154 +234,407 @@ static void interpret_dos_date(uint32 date,int *year,int *month,int *day,int *ho *year = ((p3>>1)&0xFF) + 80; } -/******************************************************************* - Create a unix date (int GMT) from a dos date (which is actually in - localtime). -********************************************************************/ - -static time_t make_unix_date(void *date_ptr, int zone_offset) +/** + create a unix date (int GMT) from a dos date (which is actually in + localtime) +**/ +time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset) { - uint32 dos_date=0; + uint32_t dos_date=0; struct tm t; time_t ret; dos_date = IVAL(date_ptr,0); - if (dos_date == 0) { - return 0; - } + if (dos_date == 0) return (time_t)0; interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon, - &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); + &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); t.tm_isdst = -1; ret = timegm(&t); ret += zone_offset; - return(ret); + return ret; } -/******************************************************************* - Like make_unix_date() but the words are reversed. -********************************************************************/ - -static time_t make_unix_date2(void *date_ptr, int zone_offset) +/** +like make_unix_date() but the words are reversed +**/ +time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset) { - uint32 x,x2; + uint32_t x,x2; x = IVAL(date_ptr,0); x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); SIVAL(&x,0,x2); - return(make_unix_date((void *)&x, zone_offset)); + return pull_dos_date((void *)&x, zone_offset); } -/******************************************************************* - Create a unix GMT date from a dos date in 32 bit "unix like" format - these generally arrive as localtimes, with corresponding DST. -******************************************************************/ - -static time_t make_unix_date3(void *date_ptr, int zone_offset) +/** + create a unix GMT date from a dos date in 32 bit "unix like" format + these generally arrive as localtimes, with corresponding DST +**/ +time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset) { time_t t = (time_t)IVAL(date_ptr,0); - if (!null_mtime(t)) { + if (!null_time(t)) { t += zone_offset; } - return(t); + return t; } /*************************************************************************** - Server versions of the above functions. + Return a HTTP/1.0 time string. ***************************************************************************/ -void srv_put_dos_date(char *buf,int offset,time_t unixdate) +char *http_timestring(time_t t) { - put_dos_date(buf, offset, unixdate, server_zone_offset); + static fstring buf; + struct tm *tm = localtime(&t); + + if (!tm) { + slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t); + } else { +#ifndef HAVE_STRFTIME + const char *asct = asctime(tm); + fstrcpy(buf, asct ? asct : "unknown"); + } + if(buf[strlen(buf)-1] == '\n') { + buf[strlen(buf)-1] = 0; +#else /* !HAVE_STRFTIME */ + strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm); +#endif /* !HAVE_STRFTIME */ + } + return buf; } -void srv_put_dos_date2(char *buf,int offset, time_t unixdate) + +/** + Return the date and time as a string +**/ +char *timestring(TALLOC_CTX *mem_ctx, time_t t) { - put_dos_date2(buf, offset, unixdate, server_zone_offset); + char *TimeBuf; + char tempTime[80]; + struct tm *tm; + + tm = localtime(&t); + if (!tm) { + return talloc_asprintf(mem_ctx, + "%ld seconds since the Epoch", + (long)t); + } + +#ifdef HAVE_STRFTIME + /* some versions of gcc complain about using %c. This is a bug + in the gcc warning, not a bug in this code. See a recent + strftime() manual page for details. + */ + strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm); + TimeBuf = talloc_strdup(mem_ctx, tempTime); +#else + TimeBuf = talloc_strdup(mem_ctx, asctime(tm)); +#endif + + return TimeBuf; } -void srv_put_dos_date3(char *buf,int offset,time_t unixdate) +/** + return a talloced string representing a NTTIME for human consumption +*/ +const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt) { - put_dos_date3(buf, offset, unixdate, server_zone_offset); + time_t t; + if (nt == 0) { + return "NTTIME(0)"; + } + t = nt_time_to_unix(nt); + return timestring(mem_ctx, t); } -time_t srv_make_unix_date(void *date_ptr) + +/** + parse a nttime as a large integer in a string and return a NTTIME +*/ +NTTIME nttime_from_string(const char *s) { - return make_unix_date(date_ptr, server_zone_offset); + return strtoull(s, NULL, 0); } -time_t srv_make_unix_date2(void *date_ptr) +/** + return (tv1 - tv2) in microseconds +*/ +int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2) { - return make_unix_date2(date_ptr, server_zone_offset); + int64_t sec_diff = tv1->tv_sec - tv2->tv_sec; + return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec); } -time_t srv_make_unix_date3(void *date_ptr) + +/** + return a zero timeval +*/ +struct timeval timeval_zero(void) { - return make_unix_date3(date_ptr, server_zone_offset); + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + return tv; } -/*************************************************************************** - Client versions of the above functions. -***************************************************************************/ +/** + return True if a timeval is zero +*/ +BOOL timeval_is_zero(const struct timeval *tv) +{ + return tv->tv_sec == 0 && tv->tv_usec == 0; +} -void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate) +/** + return a timeval for the current time +*/ +struct timeval timeval_current(void) { - put_dos_date(buf, offset, unixdate, cli->serverzone); + struct timeval tv; + GetTimeOfDay(&tv); + return tv; } -void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate) +/** + return a timeval struct with the given elements +*/ +struct timeval timeval_set(uint32_t secs, uint32_t usecs) { - put_dos_date2(buf, offset, unixdate, cli->serverzone); + struct timeval tv; + tv.tv_sec = secs; + tv.tv_usec = usecs; + return tv; } -void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate) + +/** + return a timeval ofs microseconds after tv +*/ +struct timeval timeval_add(const struct timeval *tv, + uint32_t secs, uint32_t usecs) { - put_dos_date3(buf, offset, unixdate, cli->serverzone); + struct timeval tv2 = *tv; + const unsigned int million = 1000000; + tv2.tv_sec += secs; + tv2.tv_usec += usecs; + tv2.tv_sec += tv2.tv_usec / million; + tv2.tv_usec = tv2.tv_usec % million; + return tv2; } -time_t cli_make_unix_date(struct cli_state *cli, void *date_ptr) +/** + return the sum of two timeval structures +*/ +struct timeval timeval_sum(const struct timeval *tv1, + const struct timeval *tv2) { - return make_unix_date(date_ptr, cli->serverzone); + return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec); } -time_t cli_make_unix_date2(struct cli_state *cli, void *date_ptr) +/** + return a timeval secs/usecs into the future +*/ +struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs) { - return make_unix_date2(date_ptr, cli->serverzone); + struct timeval tv = timeval_current(); + return timeval_add(&tv, secs, usecs); } -time_t cli_make_unix_date3(struct cli_state *cli, void *date_ptr) +/** + compare two timeval structures. + Return -1 if tv1 < tv2 + Return 0 if tv1 == tv2 + Return 1 if tv1 > tv2 +*/ +int timeval_compare(const struct timeval *tv1, const struct timeval *tv2) { - return make_unix_date3(date_ptr, cli->serverzone); + if (tv1->tv_sec > tv2->tv_sec) return 1; + if (tv1->tv_sec < tv2->tv_sec) return -1; + if (tv1->tv_usec > tv2->tv_usec) return 1; + if (tv1->tv_usec < tv2->tv_usec) return -1; + return 0; } -/*************************************************************************** - Return a HTTP/1.0 time string. -***************************************************************************/ +/** + return True if a timer is in the past +*/ +BOOL timeval_expired(const struct timeval *tv) +{ + struct timeval tv2 = timeval_current(); + if (tv2.tv_sec > tv->tv_sec) return True; + if (tv2.tv_sec < tv->tv_sec) return False; + return (tv2.tv_usec >= tv->tv_usec); +} -char *http_timestring(time_t t) +/** + return the number of seconds elapsed between two times +*/ +double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2) { - static fstring buf; - struct tm *tm = localtime(&t); + return (tv2->tv_sec - tv1->tv_sec) + + (tv2->tv_usec - tv1->tv_usec)*1.0e-6; +} - if (!tm) { - slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t); +/** + return the number of seconds elapsed since a given time +*/ +double timeval_elapsed(const struct timeval *tv) +{ + struct timeval tv2 = timeval_current(); + return timeval_elapsed2(tv, &tv2); +} + +/** + return the lesser of two timevals +*/ +struct timeval timeval_min(const struct timeval *tv1, + const struct timeval *tv2) +{ + if (tv1->tv_sec < tv2->tv_sec) return *tv1; + if (tv1->tv_sec > tv2->tv_sec) return *tv2; + if (tv1->tv_usec < tv2->tv_usec) return *tv1; + return *tv2; +} + +/** + return the greater of two timevals +*/ +struct timeval timeval_max(const struct timeval *tv1, + const struct timeval *tv2) +{ + if (tv1->tv_sec > tv2->tv_sec) return *tv1; + if (tv1->tv_sec < tv2->tv_sec) return *tv2; + if (tv1->tv_usec > tv2->tv_usec) return *tv1; + return *tv2; +} + +/** + return the difference between two timevals as a timeval + if tv1 comes after tv2, then return a zero timeval + (this is *tv2 - *tv1) +*/ +struct timeval timeval_until(const struct timeval *tv1, + const struct timeval *tv2) +{ + struct timeval t; + if (timeval_compare(tv1, tv2) >= 0) { + return timeval_zero(); + } + t.tv_sec = tv2->tv_sec - tv1->tv_sec; + if (tv1->tv_usec > tv2->tv_usec) { + t.tv_sec--; + t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec); } else { -#ifndef HAVE_STRFTIME - const char *asct = asctime(tm); - fstrcpy(buf, asct ? asct : "unknown"); + t.tv_usec = tv2->tv_usec - tv1->tv_usec; } - if(buf[strlen(buf)-1] == '\n') { - buf[strlen(buf)-1] = 0; -#else /* !HAVE_STRFTIME */ - strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm); -#endif /* !HAVE_STRFTIME */ + return t; +} + + +/** + convert a timeval to a NTTIME +*/ +NTTIME timeval_to_nttime(const struct timeval *tv) +{ + return 10*(tv->tv_usec + + ((TIME_FIXUP_CONSTANT + (uint64_t)tv->tv_sec) * 1000000)); +} + +/******************************************************************* +yield the difference between *A and *B, in seconds, ignoring leap seconds +********************************************************************/ +static int tm_diff(struct tm *a, struct tm *b) +{ + int ay = a->tm_year + (1900 - 1); + int by = b->tm_year + (1900 - 1); + int intervening_leap_days = + (ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400); + int years = ay - by; + int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday); + int hours = 24*days + (a->tm_hour - b->tm_hour); + int minutes = 60*hours + (a->tm_min - b->tm_min); + int seconds = 60*minutes + (a->tm_sec - b->tm_sec); + + return seconds; +} + +int extra_time_offset=0; + +/** + return the UTC offset in seconds west of UTC, or 0 if it cannot be determined + */ +int get_time_zone(time_t t) +{ + struct tm *tm = gmtime(&t); + struct tm tm_utc; + if (!tm) + return 0; + tm_utc = *tm; + tm = localtime(&t); + if (!tm) + return 0; + return tm_diff(&tm_utc,tm)+60*extra_time_offset; +} + +/**************************************************************************** + Check if NTTIME is 0. +****************************************************************************/ + +BOOL nt_time_is_zero(const NTTIME *nt) +{ + return (*nt == 0); +} + +/**************************************************************************** + Convert ASN.1 GeneralizedTime string to unix-time. + Returns 0 on failure; Currently ignores timezone. +****************************************************************************/ + +time_t generalized_to_unix_time(const char *str) +{ + struct tm tm; + + ZERO_STRUCT(tm); + + if (sscanf(str, "%4d%2d%2d%2d%2d%2d", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { + return 0; } - return buf; + tm.tm_year -= 1900; + tm.tm_mon -= 1; + + return timegm(&tm); +} + +/******************************************************************* + Accessor function for the server time zone offset. + set_server_zone_offset() must have been called first. +******************************************************************/ + +static int server_zone_offset; + +int get_server_zone_offset(void) +{ + return server_zone_offset; +} + +/******************************************************************* + Initialize the server time zone offset. Called when a client connects. +******************************************************************/ + +int set_server_zone_offset(time_t t) +{ + server_zone_offset = get_time_zone(t); + return server_zone_offset; } /**************************************************************************** @@ -866,276 +696,118 @@ char *current_timestring(BOOL hires) return(TimeBuf); } -/**************************************************************************** - Return the best approximation to a 'create time' under UNIX from a stat - structure. -****************************************************************************/ - -time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs) -{ - time_t ret, ret1; - - if(S_ISDIR(st->st_mode) && fake_dirs) { - return (time_t)315493200L; /* 1/1/1980 */ - } - - ret = MIN(st->st_ctime, st->st_mtime); - ret1 = MIN(ret, st->st_atime); - if(ret1 != (time_t)0) { - return ret1; - } - - /* - * One of ctime, mtime or atime was zero (probably atime). - * Just return MIN(ctime, mtime). - */ - return ret; -} +/******************************************************************* + Put a dos date into a buffer (time/date format). + This takes GMT time and puts local time in the buffer. +********************************************************************/ -struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) +static void put_dos_date(char *buf,int offset,time_t unixdate, int zone_offset) { - struct timespec ts; - ts.tv_sec = get_create_time(st, fake_dirs); - ts.tv_nsec = 0; - return ts; + uint32 x = make_dos_date(unixdate, zone_offset); + SIVAL(buf,offset,x); } -/**************************************************************************** - Initialise an NTTIME to -1, which means "unknown" or "don't expire". -****************************************************************************/ - -void init_nt_time(NTTIME *nt) -{ - nt->high = 0x7FFFFFFF; - nt->low = 0xFFFFFFFF; -} +/******************************************************************* + Put a dos date into a buffer (date/time format). + This takes GMT time and puts local time in the buffer. +********************************************************************/ -BOOL nt_time_is_set(const NTTIME *nt) +static void put_dos_date2(char *buf,int offset,time_t unixdate, int zone_offset) { - if ((nt->high == 0x7FFFFFFF) && (nt->low == 0xFFFFFFFF)) { - return False; - } - - if ((nt->high == 0x80000000) && (nt->low == 0)) { - return False; - } - - return True; + uint32 x = make_dos_date(unixdate, zone_offset); + x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); + SIVAL(buf,offset,x); } -/**************************************************************************** - Check if NTTIME is 0. -****************************************************************************/ +/******************************************************************* + Put a dos 32 bit "unix like" date into a buffer. This routine takes + GMT and converts it to LOCAL time before putting it (most SMBs assume + localtime for this sort of date) +********************************************************************/ -BOOL nt_time_is_zero(const NTTIME *nt) +static void put_dos_date3(char *buf,int offset,time_t unixdate, int zone_offset) { - if(nt->high==0) { - return True; + if (!null_mtime(unixdate)) { + unixdate -= zone_offset; } - return False; -} - -/**************************************************************************** - Check if two NTTIMEs are the same. -****************************************************************************/ - -BOOL nt_time_equals(const NTTIME *nt1, const NTTIME *nt2) -{ - return (nt1->high == nt2->high && nt1->low == nt2->low); -} - -/**************************************************************************** - Return a timeval difference in usec. -****************************************************************************/ - -SMB_BIG_INT usec_time_diff(const struct timeval *larget, const struct timeval *smallt) -{ - SMB_BIG_INT sec_diff = larget->tv_sec - smallt->tv_sec; - return (sec_diff * 1000000) + (SMB_BIG_INT)(larget->tv_usec - smallt->tv_usec); + SIVAL(buf,offset,unixdate); } -/**************************************************************************** - Return a timeval struct with the given elements. -****************************************************************************/ -struct timeval timeval_set(uint32_t secs, uint32_t usecs) -{ - struct timeval tv; - tv.tv_sec = secs; - tv.tv_usec = usecs; - return tv; -} - -/**************************************************************************** - Return a zero timeval. -****************************************************************************/ +/*************************************************************************** + Server versions of the above functions. +***************************************************************************/ -struct timeval timeval_zero(void) +void srv_put_dos_date(char *buf,int offset,time_t unixdate) { - return timeval_set(0,0); + put_dos_date(buf, offset, unixdate, server_zone_offset); } -/**************************************************************************** - Return True if a timeval is zero. -****************************************************************************/ - -BOOL timeval_is_zero(const struct timeval *tv) +void srv_put_dos_date2(char *buf,int offset, time_t unixdate) { - return tv->tv_sec == 0 && tv->tv_usec == 0; + put_dos_date2(buf, offset, unixdate, server_zone_offset); } -/**************************************************************************** - Return a timeval for the current time. -****************************************************************************/ - -struct timeval timeval_current(void) +void srv_put_dos_date3(char *buf,int offset,time_t unixdate) { - struct timeval tv; - GetTimeOfDay(&tv); - return tv; + put_dos_date3(buf, offset, unixdate, server_zone_offset); } /**************************************************************************** - Return a timeval ofs microseconds after tv. + Take a Unix time and convert to an NTTIME structure and place in buffer + pointed to by p. ****************************************************************************/ -struct timeval timeval_add(const struct timeval *tv, - uint32_t secs, uint32_t usecs) +void put_long_date_timespec(char *p, struct timespec ts) { - struct timeval tv2 = *tv; - tv2.tv_sec += secs; - tv2.tv_usec += usecs; - tv2.tv_sec += tv2.tv_usec / 1000000; - tv2.tv_usec = tv2.tv_usec % 1000000; - return tv2; + NTTIME nt; + unix_timespec_to_nt_time(&nt, ts); + SIVAL(p, 0, nt & 0xFFFFFFFF); + SIVAL(p, 4, nt >> 32); } -/**************************************************************************** - Return the sum of two timeval structures. -****************************************************************************/ - -struct timeval timeval_sum(const struct timeval *tv1, - const struct timeval *tv2) +void put_long_date(char *p, time_t t) { - return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec); + struct timespec ts; + ts.tv_sec = t; + ts.tv_nsec = 0; + put_long_date_timespec(p, ts); } /**************************************************************************** - Return a timeval secs/usecs into the future. + Return the best approximation to a 'create time' under UNIX from a stat + structure. ****************************************************************************/ -struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs) +time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs) { - struct timeval tv = timeval_current(); - return timeval_add(&tv, secs, usecs); -} - -/**************************************************************************** - Compare two timeval structures. - Return -1 if tv1 < tv2 - Return 0 if tv1 == tv2 - Return 1 if tv1 > tv2 -****************************************************************************/ + time_t ret, ret1; -int timeval_compare(const struct timeval *tv1, const struct timeval *tv2) -{ - if (tv1->tv_sec > tv2->tv_sec) { - return 1; - } - if (tv1->tv_sec < tv2->tv_sec) { - return -1; - } - if (tv1->tv_usec > tv2->tv_usec) { - return 1; - } - if (tv1->tv_usec < tv2->tv_usec) { - return -1; + if(S_ISDIR(st->st_mode) && fake_dirs) { + return (time_t)315493200L; /* 1/1/1980 */ } - return 0; -} - -/**************************************************************************** - Return the difference between two timevals as a timeval. - If tv1 comes after tv2, then return a zero timeval - (this is *tv2 - *tv1). -****************************************************************************/ + + ret = MIN(st->st_ctime, st->st_mtime); + ret1 = MIN(ret, st->st_atime); -struct timeval timeval_until(const struct timeval *tv1, - const struct timeval *tv2) -{ - struct timeval t; - if (timeval_compare(tv1, tv2) >= 0) { - return timeval_zero(); - } - t.tv_sec = tv2->tv_sec - tv1->tv_sec; - if (tv1->tv_usec > tv2->tv_usec) { - t.tv_sec--; - t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec); - } else { - t.tv_usec = tv2->tv_usec - tv1->tv_usec; + if(ret1 != (time_t)0) { + return ret1; } - return t; -} -/**************************************************************************** - Return the lesser of two timevals. -****************************************************************************/ - -struct timeval timeval_min(const struct timeval *tv1, - const struct timeval *tv2) -{ - if (tv1->tv_sec < tv2->tv_sec) { - return *tv1; - } - if (tv1->tv_sec > tv2->tv_sec) { - return *tv2; - } - if (tv1->tv_usec < tv2->tv_usec) { - return *tv1; - } - return *tv2; + /* + * One of ctime, mtime or atime was zero (probably atime). + * Just return MIN(ctime, mtime). + */ + return ret; } -/**************************************************************************** - Return the greater of two timevals. -****************************************************************************/ - -struct timeval timeval_max(const struct timeval *tv1, - const struct timeval *tv2) +struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) { - if (tv1->tv_sec > tv2->tv_sec) { - return *tv1; - } - if (tv1->tv_sec < tv2->tv_sec) { - return *tv2; - } - if (tv1->tv_usec > tv2->tv_usec) { - return *tv1; - } - return *tv2; -} - -/**************************************************************************** - Convert ASN.1 GeneralizedTime string to unix-time. - Returns 0 on failure; Currently ignores timezone. -****************************************************************************/ - -time_t generalized_to_unix_time(const char *str) -{ - struct tm tm; - - ZERO_STRUCT(tm); - - if (sscanf(str, "%4d%2d%2d%2d%2d%2d", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { - return 0; - } - tm.tm_year -= 1900; - tm.tm_mon -= 1; - - return timegm(&tm); + struct timespec ts; + ts.tv_sec = get_create_time(st, fake_dirs); + ts.tv_nsec = 0; + return ts; } /**************************************************************************** @@ -1262,83 +934,352 @@ void set_ctimespec(SMB_STRUCT_STAT *pst, struct timespec ts) #endif } -#if 0 +void dos_filetime_timespec(struct timespec *tsp) +{ + tsp->tv_sec &= ~1; + tsp->tv_nsec = 0; +} + +/******************************************************************* + Create a unix date (int GMT) from a dos date (which is actually in + localtime). +********************************************************************/ + +static time_t make_unix_date(void *date_ptr, int zone_offset) +{ + uint32 dos_date=0; + struct tm t; + time_t ret; + + dos_date = IVAL(date_ptr,0); + + if (dos_date == 0) { + return 0; + } + + interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon, + &t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec); + t.tm_isdst = -1; + + ret = timegm(&t); + + ret += zone_offset; + + return(ret); +} + +/******************************************************************* + Like make_unix_date() but the words are reversed. +********************************************************************/ + +static time_t make_unix_date2(void *date_ptr, int zone_offset) +{ + uint32 x,x2; + + x = IVAL(date_ptr,0); + x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); + SIVAL(&x,0,x2); + + return(make_unix_date((void *)&x, zone_offset)); +} + +/******************************************************************* + Create a unix GMT date from a dos date in 32 bit "unix like" format + these generally arrive as localtimes, with corresponding DST. +******************************************************************/ + +static time_t make_unix_date3(void *date_ptr, int zone_offset) +{ + time_t t = (time_t)IVAL(date_ptr,0); + if (!null_mtime(t)) { + t += zone_offset; + } + return(t); +} + +time_t srv_make_unix_date(void *date_ptr) +{ + return make_unix_date(date_ptr, server_zone_offset); +} + +time_t srv_make_unix_date2(void *date_ptr) +{ + return make_unix_date2(date_ptr, server_zone_offset); +} + +time_t srv_make_unix_date3(void *date_ptr) +{ + return make_unix_date3(date_ptr, server_zone_offset); +} + +time_t convert_timespec_to_time_t(struct timespec ts) +{ + /* 1 ns == 1,000,000,000 - one thousand millionths of a second. + increment if it's greater than 500 millionth of a second. */ + if (ts.tv_nsec > 500000000) { + return ts.tv_sec + 1; + } + return ts.tv_sec; +} + /**************************************************************************** - Return the best approximation to a 'create time' under UNIX from a stat - structure. + Interprets an nt time into a unix struct timespec. + Differs from nt_time_to_unix in that an 8 byte value of 0xffffffffffffffff + will be returned as (time_t)-1, whereas nt_time_to_unix returns 0 in this case. ****************************************************************************/ -struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) +struct timespec interpret_long_date(char *p) { - time_t ret, ret1; + NTTIME nt; + nt = IVAL(p,0) + ((uint64_t)IVAL(p,4) << 32); + if (nt == (uint64_t)-1) { + struct timespec ret; + ret.tv_sec = (time_t)-1; + ret.tv_nsec = 0; + return ret; + } + return nt_time_to_unix_timespec(&nt); +} - if(S_ISDIR(st->st_mode) && fake_dirs) { - return (time_t)315493200L; /* 1/1/1980 */ +/*************************************************************************** + Client versions of the above functions. +***************************************************************************/ + +void cli_put_dos_date(struct cli_state *cli, char *buf, int offset, time_t unixdate) +{ + put_dos_date(buf, offset, unixdate, cli->serverzone); +} + +void cli_put_dos_date2(struct cli_state *cli, char *buf, int offset, time_t unixdate) +{ + put_dos_date2(buf, offset, unixdate, cli->serverzone); +} + +void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unixdate) +{ + put_dos_date3(buf, offset, unixdate, cli->serverzone); +} + +time_t cli_make_unix_date(struct cli_state *cli, void *date_ptr) +{ + return make_unix_date(date_ptr, cli->serverzone); +} + +time_t cli_make_unix_date2(struct cli_state *cli, void *date_ptr) +{ + return make_unix_date2(date_ptr, cli->serverzone); +} + +time_t cli_make_unix_date3(struct cli_state *cli, void *date_ptr) +{ + return make_unix_date3(date_ptr, cli->serverzone); +} + +#if (SIZEOF_LONG == 8) +#define TIME_FIXUP_CONSTANT_INT 11644473600L +#elif (SIZEOF_LONG_LONG == 8) +#define TIME_FIXUP_CONSTANT_INT 11644473600LL +#endif + + +/* Large integer version. */ +struct timespec nt_time_to_unix_timespec(NTTIME *nt) +{ + uint64 d; + struct timespec ret; + + if (*nt == 0 || *nt == (uint64)-1) { + ret.tv_sec = 0; + ret.tv_nsec = 0; + return ret; } - - ret = MIN(st->st_ctime, st->st_mtime); - ret1 = MIN(ret, st->st_atime); - if(ret1 != (time_t)0) { - return ret1; + d = *nt; + /* d is now in 100ns units, since jan 1st 1601". + Save off the ns fraction. */ + + ret.tv_nsec = (long) ((d % 100) * 100); + + /* Convert to seconds */ + d /= 1000*1000*10; + + /* Now adjust by 369 years to make the secs since 1970 */ + d -= TIME_FIXUP_CONSTANT_INT; + + if (((time_t)d) <= TIME_T_MIN) { + ret.tv_sec = TIME_T_MIN; + ret.tv_nsec = 0; + return ret; } - /* - * One of ctime, mtime or atime was zero (probably atime). - * Just return MIN(ctime, mtime). - */ - return ret; + if (((time_t)d) >= TIME_T_MAX) { + ret.tv_sec = TIME_T_MAX; + ret.tv_nsec = 0; + return ret; + } + + ret.tv_sec = (time_t)d; + return ret; } -#endif +/**************************************************************************** + Check if two NTTIMEs are the same. +****************************************************************************/ -void dos_filetime_timespec(struct timespec *tsp) +BOOL nt_time_equals(const NTTIME *nt1, const NTTIME *nt2) { - tsp->tv_sec &= ~1; - tsp->tv_nsec = 0; + return (*nt1 == *nt2); } -/** - Return the date and time as a string -**/ -char *timestring(TALLOC_CTX *mem_ctx, time_t t) +/******************************************************************* + Re-read the smb serverzone value. +******************************************************************/ + +static struct timeval start_time_hires; + +void TimeInit(void) { - char *TimeBuf; - char tempTime[80]; - struct tm *tm; + set_server_zone_offset(time(NULL)); - tm = localtime(&t); - if (!tm) { - return talloc_asprintf(mem_ctx, - "%ld seconds since the Epoch", - (long)t); + DEBUG(4,("TimeInit: Serverzone is %d\n", server_zone_offset)); + + /* Save the start time of this process. */ + if (start_time_hires.tv_sec == 0 && start_time_hires.tv_usec == 0) { + GetTimeOfDay(&start_time_hires); } +} -#ifdef HAVE_STRFTIME - /* some versions of gcc complain about using %c. This is a bug - in the gcc warning, not a bug in this code. See a recent - strftime() manual page for details. - */ - strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm); - TimeBuf = talloc_strdup(mem_ctx, tempTime); -#else - TimeBuf = talloc_strdup(mem_ctx, asctime(tm)); -#endif +/********************************************************************** + Return a timeval struct of the uptime of this process. As TimeInit is + done before a daemon fork then this is the start time from the parent + daemon start. JRA. +***********************************************************************/ - return TimeBuf; +void get_process_uptime(struct timeval *ret_time) +{ + struct timeval time_now_hires; + + GetTimeOfDay(&time_now_hires); + ret_time->tv_sec = time_now_hires.tv_sec - start_time_hires.tv_sec; + if (time_now_hires.tv_usec < start_time_hires.tv_usec) { + ret_time->tv_sec -= 1; + ret_time->tv_usec = 1000000 + (time_now_hires.tv_usec - start_time_hires.tv_usec); + } else { + ret_time->tv_usec = time_now_hires.tv_usec - start_time_hires.tv_usec; + } } +/**************************************************************************** + Convert a NTTIME structure to a time_t. + It's originally in "100ns units". + + This is an absolute version of the one above. + By absolute I mean, it doesn't adjust from 1/1/1601 to 1/1/1970 + if the NTTIME was 5 seconds, the time_t is 5 seconds. JFM +****************************************************************************/ -/** - return a talloced string representing a NTTIME for human consumption -*/ -const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt) +time_t nt_time_to_unix_abs(const NTTIME *nt) { - time_t t; - if (nt.low == 0 && nt.high == 0) { - return "NTTIME(0)"; + uint64 d; + + if (*nt == 0) { + return (time_t)0; } - t = nt_time_to_unix(&nt); - return timestring(mem_ctx, t); + + if (*nt == (uint64)-1) { + return (time_t)-1; + } + + /* reverse the time */ + /* it's a negative value, turn it to positive */ + d=~*nt; + + d += 1000*1000*10/2; + d /= 1000*1000*10; + + if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) { + return (time_t)0; + } + + return (time_t)d; +} + +/**************************************************************************** + Put a 8 byte filetime from a struct timespec. Uses GMT. +****************************************************************************/ + +void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts) +{ + uint64 d; + + if (ts.tv_sec ==0 && ts.tv_nsec == 0) { + *nt = 0; + return; + } + if (ts.tv_sec == TIME_T_MAX) { + *nt = 0x7fffffffffffffffLL; + return; + } + if (ts.tv_sec == (time_t)-1) { + *nt = (uint64)-1; + return; + } + + d = ts.tv_sec; + d += TIME_FIXUP_CONSTANT_INT; + d *= 1000*1000*10; + /* d is now in 100ns units. */ + d += (ts.tv_nsec / 100); + + *nt = d; +} + +/**************************************************************************** + Convert a time_t to a NTTIME structure + + This is an absolute version of the one above. + By absolute I mean, it doesn't adjust from 1/1/1970 to 1/1/1601 + If the nttime_t was 5 seconds, the NTTIME is 5 seconds. JFM +****************************************************************************/ + +void unix_to_nt_time_abs(NTTIME *nt, time_t t) +{ + double d; + + if (t==0) { + *nt = 0; + return; + } + + if (t == TIME_T_MAX) { + *nt = 0x7fffffffffffffffLL; + return; + } + + if (t == (time_t)-1) { + /* that's what NT uses for infinite */ + *nt = 0x8000000000000000LL; + return; + } + + d = (double)(t); + d *= 1.0e7; + + *nt = d; + + /* convert to a negative value */ + *nt=~*nt; +} + + +/**************************************************************************** + Check if it's a null mtime. +****************************************************************************/ + +BOOL null_mtime(time_t mtime) +{ + if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1) + return(True); + return(False); } /**************************************************************************** @@ -1361,3 +1302,52 @@ const char *time_to_asc(const time_t *t) } return asct; } + +const char *display_time(NTTIME nttime) +{ + static fstring string; + + float high; + float low; + int sec; + int days, hours, mins, secs; + + if (nttime==0) + return "Now"; + + if (nttime==0x8000000000000000LL) + return "Never"; + + high = 65536; + high = high/10000; + high = high*65536; + high = high/1000; + high = high * (~(nttime >> 32)); + + low = ~(nttime & 0xFFFFFFFF); + low = low/(1000*1000*10); + + sec=high+low; + + days=sec/(60*60*24); + hours=(sec - (days*60*60*24)) / (60*60); + mins=(sec - (days*60*60*24) - (hours*60*60) ) / 60; + secs=sec - (days*60*60*24) - (hours*60*60) - (mins*60); + + fstr_sprintf(string, "%u days, %u hours, %u minutes, %u seconds", days, hours, mins, secs); + return (string); +} + +BOOL nt_time_is_set(const NTTIME *nt) +{ + if (*nt == 0x7FFFFFFFFFFFFFFFLL) { + return False; + } + + if (*nt == 0x8000000000000000LL) { + return False; + } + + return True; +} + |