From 995205fc60f87e1a02aa1c6f309db55ae18e908a Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 6 Sep 2006 18:32:20 +0000 Subject: r18188: merge 3.0-libndr branch (This used to be commit 1115745caed3093c25d6be01ffee21819fb0a675) --- source3/lib/time.c | 1972 ++++++++++++++++++++++++++-------------------------- 1 file changed, 981 insertions(+), 991 deletions(-) (limited to 'source3/lib') 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 - 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,441 +84,144 @@ 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) +time_t nt_time_to_unix(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; + return convert_timespec_to_time_t(nt_time_to_unix_timespec(&nt)); } /**************************************************************************** - 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 + Put a 8 byte filetime from a time_t. Uses GMT. ****************************************************************************/ -time_t nt_time_to_unix_abs(const NTTIME *nt) +void unix_to_nt_time(NTTIME *nt, time_t t) { - 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); + uint64_t t2; - d += 1000*1000*10/2; - d /= 1000*1000*10; + if (t == (time_t)-1) { + *nt = (NTTIME)-1LL; + return; + } + if (t == 0) { + *nt = 0; + return; + } - if (!(TIME_T_MIN <= ((time_t)d) && ((time_t)d) <= TIME_T_MAX)) { - return (time_t)0; - } + t2 = t; + t2 += TIME_FIXUP_CONSTANT; + t2 *= 1000*1000*10; - return (time_t)d; + *nt = t2; } -/**************************************************************************** - Put a 8 byte filetime from a struct timespec. Uses GMT. -****************************************************************************/ -void unix_timespec_to_nt_time(NTTIME *nt, struct timespec ts) +/** +check if it's a null unix time +**/ +BOOL null_time(time_t t) { - 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; - } + return t == 0 || + t == (time_t)0xFFFFFFFF || + t == (time_t)-1; +} - 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 ); +/** +check if it's a null NTTIME +**/ +BOOL null_nttime(NTTIME t) +{ + return t == 0 || t == (NTTIME)-1; } -#else +/******************************************************************* + create a 16 bit dos packed date +********************************************************************/ +static uint16_t make_dos_date1(struct tm *t) +{ + 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; +} -/* 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)) +/******************************************************************* + create a 16 bit dos packed time +********************************************************************/ +static uint16_t make_dos_time1(struct tm *t) +{ + 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; +} -/* Floating point double versions. */ -static struct timespec nt_time_to_unix_timespec(NTTIME *nt) +/******************************************************************* + create a 32 bit dos packed date/time from some parameters + This takes a GMT time and returns a packed localtime structure +********************************************************************/ +static uint32_t make_dos_date(time_t unixdate, int zone_offset) { - double d; - struct timespec ret; + struct tm *t; + uint32_t ret=0; - if ((nt->high == 0 && nt->low == 0 )|| - (nt->high == 0xffffffff && nt->low == 0xffffffff)) { - ret.tv_sec = 0; - ret.tv_nsec = 0; - return ret; + if (unixdate == 0) { + return 0; } - 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; + unixdate -= zone_offset; - if (d <= TIME_T_MIN) { - ret.tv_sec = TIME_T_MIN; - ret.tv_nsec = 0; - return ret; + t = gmtime(&unixdate); + if (!t) { + return 0xFFFFFFFF; } - if (d >= TIME_T_MAX) { - ret.tv_sec = TIME_T_MAX; - ret.tv_nsec = 0; - return ret; - } + ret = make_dos_date1(t); + ret = ((ret&0xFFFF)<<16) | make_dos_time1(t); - 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); -} - -/**************************************************************************** - Put a 8 byte filetime from a time_t. Uses GMT. -****************************************************************************/ - -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; - } - - 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; - 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)); - - /* convert to a negative value */ - nt->high=~nt->high; - nt->low=~nt->low; -} - -/**************************************************************************** - 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) -{ - struct timespec ts; - ts.tv_sec = t; - ts.tv_nsec = 0; - put_long_date_timespec(p, ts); -} - -/**************************************************************************** - 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); -} - -/******************************************************************* - Create a 16 bit dos packed date. -********************************************************************/ - -static uint16 make_dos_date1(struct tm *t) -{ - uint16 ret=0; - ret = (((unsigned)(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); -} - -/******************************************************************* - Create a 16 bit dos packed time. -********************************************************************/ - -static uint16 make_dos_time1(struct tm *t) -{ - uint16 ret=0; - ret = ((((unsigned)t->tm_min >> 3)&0x7) | (((unsigned)t->tm_hour) << 3)); - ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5)); - return(ret); -} - -/******************************************************************* - 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) -{ - struct tm *t; - uint32 ret=0; - - if (unixdate == 0) { - return 0; - } - - unixdate -= zone_offset; - t = gmtime(&unixdate); - if (!t) { - return 0xFFFFFFFF; - } - - ret = make_dos_date1(t); - ret = ((ret&0xFFFF)<<16) | make_dos_time1(t); - - 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,139 +234,66 @@ 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) -{ - put_dos_date(buf, offset, unixdate, server_zone_offset); -} - -void srv_put_dos_date2(char *buf,int offset, time_t unixdate) +char *http_timestring(time_t t) { - put_dos_date2(buf, offset, unixdate, server_zone_offset); -} - -void srv_put_dos_date3(char *buf,int offset,time_t unixdate) -{ - put_dos_date3(buf, offset, unixdate, server_zone_offset); -} - -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); -} - -/*************************************************************************** - 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); -} - -/*************************************************************************** - Return a HTTP/1.0 time string. -***************************************************************************/ - -char *http_timestring(time_t t) -{ - static fstring buf; - struct tm *tm = localtime(&t); + static fstring buf; + struct tm *tm = localtime(&t); if (!tm) { slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t); @@ -807,188 +311,91 @@ char *http_timestring(time_t t) return buf; } -/**************************************************************************** - Return the date and time as a string -****************************************************************************/ -char *current_timestring(BOOL hires) +/** + Return the date and time as a string +**/ +char *timestring(TALLOC_CTX *mem_ctx, time_t t) { - static fstring TimeBuf; - struct timeval tp; - time_t t; + char *TimeBuf; + char tempTime[80]; struct tm *tm; - if (hires) { - GetTimeOfDay(&tp); - t = (time_t)tp.tv_sec; - } else { - t = time(NULL); - } tm = localtime(&t); if (!tm) { - if (hires) { - slprintf(TimeBuf, - sizeof(TimeBuf)-1, - "%ld.%06ld seconds since the Epoch", - (long)tp.tv_sec, - (long)tp.tv_usec); - } else { - slprintf(TimeBuf, - sizeof(TimeBuf)-1, - "%ld seconds since the Epoch", - (long)t); - } - } else { -#ifdef HAVE_STRFTIME - if (hires) { - strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm); - slprintf(TimeBuf+strlen(TimeBuf), - sizeof(TimeBuf)-1 - strlen(TimeBuf), - ".%06ld", - (long)tp.tv_usec); - } else { - strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm); - } -#else - if (hires) { - const char *asct = asctime(tm); - slprintf(TimeBuf, - sizeof(TimeBuf)-1, - "%s.%06ld", - asct ? asct : "unknown", - (long)tp.tv_usec); - } else { - const char *asct = asctime(tm); - fstrcpy(TimeBuf, asct ? asct : "unknown"); - } -#endif - } - 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; + return talloc_asprintf(mem_ctx, + "%ld seconds since the Epoch", + (long)t); } - /* - * One of ctime, mtime or atime was zero (probably atime). - * Just return MIN(ctime, mtime). +#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. */ - return ret; -} - -struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) -{ - struct timespec ts; - ts.tv_sec = get_create_time(st, fake_dirs); - ts.tv_nsec = 0; - return ts; -} - -/**************************************************************************** - Initialise an NTTIME to -1, which means "unknown" or "don't expire". -****************************************************************************/ - -void init_nt_time(NTTIME *nt) -{ - nt->high = 0x7FFFFFFF; - nt->low = 0xFFFFFFFF; -} - -BOOL nt_time_is_set(const NTTIME *nt) -{ - if ((nt->high == 0x7FFFFFFF) && (nt->low == 0xFFFFFFFF)) { - return False; - } - - if ((nt->high == 0x80000000) && (nt->low == 0)) { - return False; - } + strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm); + TimeBuf = talloc_strdup(mem_ctx, tempTime); +#else + TimeBuf = talloc_strdup(mem_ctx, asctime(tm)); +#endif - return True; + return TimeBuf; } -/**************************************************************************** - Check if NTTIME is 0. -****************************************************************************/ - -BOOL nt_time_is_zero(const NTTIME *nt) +/** + return a talloced string representing a NTTIME for human consumption +*/ +const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt) { - if(nt->high==0) { - return True; + time_t t; + if (nt == 0) { + return "NTTIME(0)"; } - return False; + t = nt_time_to_unix(nt); + return timestring(mem_ctx, t); } -/**************************************************************************** - Check if two NTTIMEs are the same. -****************************************************************************/ -BOOL nt_time_equals(const NTTIME *nt1, const NTTIME *nt2) +/** + parse a nttime as a large integer in a string and return a NTTIME +*/ +NTTIME nttime_from_string(const char *s) { - return (nt1->high == nt2->high && nt1->low == nt2->low); + return strtoull(s, NULL, 0); } -/**************************************************************************** - Return a timeval difference in usec. -****************************************************************************/ - -SMB_BIG_INT usec_time_diff(const struct timeval *larget, const struct timeval *smallt) +/** + return (tv1 - tv2) in microseconds +*/ +int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2) { - SMB_BIG_INT sec_diff = larget->tv_sec - smallt->tv_sec; - return (sec_diff * 1000000) + (SMB_BIG_INT)(larget->tv_usec - smallt->tv_usec); + int64_t sec_diff = tv1->tv_sec - tv2->tv_sec; + return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec); } -/**************************************************************************** - Return a timeval struct with the given elements. -****************************************************************************/ -struct timeval timeval_set(uint32_t secs, uint32_t usecs) +/** + return a zero timeval +*/ +struct timeval timeval_zero(void) { struct timeval tv; - tv.tv_sec = secs; - tv.tv_usec = usecs; + tv.tv_sec = 0; + tv.tv_usec = 0; return tv; } -/**************************************************************************** - Return a zero timeval. -****************************************************************************/ - -struct timeval timeval_zero(void) -{ - return timeval_set(0,0); -} - -/**************************************************************************** - Return True if a timeval is zero. -****************************************************************************/ - +/** + return True if a timeval is zero +*/ BOOL timeval_is_zero(const struct timeval *tv) { return tv->tv_sec == 0 && tv->tv_usec == 0; } -/**************************************************************************** - Return a timeval for the current time. -****************************************************************************/ - +/** + return a timeval for the current time +*/ struct timeval timeval_current(void) { struct timeval tv; @@ -996,71 +403,124 @@ struct timeval timeval_current(void) return tv; } -/**************************************************************************** - Return a timeval ofs microseconds after tv. -****************************************************************************/ +/** + 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 timeval ofs microseconds after tv +*/ struct timeval timeval_add(const struct timeval *tv, uint32_t secs, uint32_t usecs) { struct timeval tv2 = *tv; + const unsigned int million = 1000000; tv2.tv_sec += secs; tv2.tv_usec += usecs; - tv2.tv_sec += tv2.tv_usec / 1000000; - tv2.tv_usec = tv2.tv_usec % 1000000; + tv2.tv_sec += tv2.tv_usec / million; + tv2.tv_usec = tv2.tv_usec % million; return tv2; } -/**************************************************************************** - Return the sum of two timeval structures. -****************************************************************************/ - +/** + return the sum of two timeval structures +*/ struct timeval timeval_sum(const struct timeval *tv1, const struct timeval *tv2) { return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec); } -/**************************************************************************** - Return a timeval secs/usecs into the future. -****************************************************************************/ - +/** + return a timeval secs/usecs into the future +*/ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs) { 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 -****************************************************************************/ - -int timeval_compare(const struct timeval *tv1, const struct timeval *tv2) +/** + 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) { - 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 (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 the difference between two timevals as a timeval. - If tv1 comes after tv2, then return a zero timeval - (this is *tv2 - *tv1). -****************************************************************************/ +/** + 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); +} + +/** + return the number of seconds elapsed between two times +*/ +double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2) +{ + return (tv2->tv_sec - tv1->tv_sec) + + (tv2->tv_usec - tv1->tv_usec)*1.0e-6; +} + +/** + 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) { @@ -1078,42 +538,59 @@ struct timeval timeval_until(const struct timeval *tv1, return t; } -/**************************************************************************** - Return the lesser of two timevals. -****************************************************************************/ -struct timeval timeval_min(const struct timeval *tv1, - const struct timeval *tv2) +/** + convert a timeval to a NTTIME +*/ +NTTIME timeval_to_nttime(const struct timeval *tv) { - 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 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; } /**************************************************************************** - Return the greater of two timevals. + Check if NTTIME is 0. ****************************************************************************/ -struct timeval timeval_max(const struct timeval *tv1, - const struct timeval *tv2) +BOOL nt_time_is_zero(const NTTIME *nt) { - 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 (*nt == 0); } /**************************************************************************** @@ -1138,137 +615,172 @@ time_t generalized_to_unix_time(const char *str) return timegm(&tm); } -/**************************************************************************** - Get/Set all the possible time fields from a stat struct as a timespec. -****************************************************************************/ +/******************************************************************* + Accessor function for the server time zone offset. + set_server_zone_offset() must have been called first. +******************************************************************/ -struct timespec get_atimespec(SMB_STRUCT_STAT *pst) -{ -#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) - struct timespec ret; +static int server_zone_offset; - /* Old system - no ns timestamp. */ - ret.tv_sec = pst->st_atime; - ret.tv_nsec = 0; - return ret; -#else -#if defined(HAVE_STAT_ST_ATIM) - return pst->st_atim; -#elif defined(HAVE_STAT_ST_ATIMENSEC) - struct timespec ret; - ret.tv_sec = pst->st_atime; - ret.tv_nsec = pst->st_atimensec; - return ret; -#else -#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT -#endif -#endif +int get_server_zone_offset(void) +{ + return server_zone_offset; } -void set_atimespec(SMB_STRUCT_STAT *pst, struct timespec ts) +/******************************************************************* + Initialize the server time zone offset. Called when a client connects. +******************************************************************/ + +int set_server_zone_offset(time_t t) { -#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) - /* Old system - no ns timestamp. */ - pst->st_atime = ts.tv_sec; -#else -#if defined(HAVE_STAT_ST_ATIM) - pst->st_atim = ts; -#elif defined(HAVE_STAT_ST_ATIMENSEC) - pst->st_atime = ts.tv_sec; - pst->st_atimensec = ts.tv_nsec -#else -#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT -#endif -#endif + server_zone_offset = get_time_zone(t); + return server_zone_offset; } -struct timespec get_mtimespec(SMB_STRUCT_STAT *pst) +/**************************************************************************** + Return the date and time as a string +****************************************************************************/ + +char *current_timestring(BOOL hires) { -#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) - struct timespec ret; + static fstring TimeBuf; + struct timeval tp; + time_t t; + struct tm *tm; - /* Old system - no ns timestamp. */ - ret.tv_sec = pst->st_mtime; - ret.tv_nsec = 0; - return ret; -#else -#if defined(HAVE_STAT_ST_MTIM) - return pst->st_mtim; -#elif defined(HAVE_STAT_ST_MTIMENSEC) - struct timespec ret; - ret.tv_sec = pst->st_mtime; - ret.tv_nsec = pst->st_mtimensec; - return ret; + if (hires) { + GetTimeOfDay(&tp); + t = (time_t)tp.tv_sec; + } else { + t = time(NULL); + } + tm = localtime(&t); + if (!tm) { + if (hires) { + slprintf(TimeBuf, + sizeof(TimeBuf)-1, + "%ld.%06ld seconds since the Epoch", + (long)tp.tv_sec, + (long)tp.tv_usec); + } else { + slprintf(TimeBuf, + sizeof(TimeBuf)-1, + "%ld seconds since the Epoch", + (long)t); + } + } else { +#ifdef HAVE_STRFTIME + if (hires) { + strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm); + slprintf(TimeBuf+strlen(TimeBuf), + sizeof(TimeBuf)-1 - strlen(TimeBuf), + ".%06ld", + (long)tp.tv_usec); + } else { + strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm); + } #else -#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT -#endif + if (hires) { + const char *asct = asctime(tm); + slprintf(TimeBuf, + sizeof(TimeBuf)-1, + "%s.%06ld", + asct ? asct : "unknown", + (long)tp.tv_usec); + } else { + const char *asct = asctime(tm); + fstrcpy(TimeBuf, asct ? asct : "unknown"); + } #endif + } + return(TimeBuf); } -void set_mtimespec(SMB_STRUCT_STAT *pst, struct timespec ts) + +/******************************************************************* + 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) { -#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) - /* Old system - no ns timestamp. */ - pst->st_mtime = ts.tv_sec; -#else -#if defined(HAVE_STAT_ST_MTIM) - pst->st_mtim = ts; -#elif defined(HAVE_STAT_ST_MTIMENSEC) - pst->st_mtime = ts.tv_sec; - pst->st_mtimensec = ts.tv_nsec -#else -#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT -#endif -#endif + uint32 x = make_dos_date(unixdate, zone_offset); + SIVAL(buf,offset,x); } -struct timespec get_ctimespec(SMB_STRUCT_STAT *pst) +/******************************************************************* + 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) { -#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) - struct timespec ret; + uint32 x = make_dos_date(unixdate, zone_offset); + x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16); + SIVAL(buf,offset,x); +} - /* Old system - no ns timestamp. */ - ret.tv_sec = pst->st_ctime; - ret.tv_nsec = 0; - return ret; -#else -#if defined(HAVE_STAT_ST_CTIM) - return pst->st_ctim; -#elif defined(HAVE_STAT_ST_CTIMENSEC) - struct timespec ret; - ret.tv_sec = pst->st_ctime; - ret.tv_nsec = pst->st_ctimensec; - return ret; -#else -#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT -#endif -#endif +/******************************************************************* + 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) +{ + if (!null_mtime(unixdate)) { + unixdate -= zone_offset; + } + SIVAL(buf,offset,unixdate); } -void set_ctimespec(SMB_STRUCT_STAT *pst, struct timespec ts) + +/*************************************************************************** + Server versions of the above functions. +***************************************************************************/ + +void srv_put_dos_date(char *buf,int offset,time_t unixdate) { -#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) - /* Old system - no ns timestamp. */ - pst->st_ctime = ts.tv_sec; -#else -#if defined(HAVE_STAT_ST_CTIM) - pst->st_ctim = ts; -#elif defined(HAVE_STAT_ST_CTIMENSEC) - pst->st_ctime = ts.tv_sec; - pst->st_ctimensec = ts.tv_nsec -#else -#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT -#endif -#endif + put_dos_date(buf, offset, unixdate, server_zone_offset); +} + +void srv_put_dos_date2(char *buf,int offset, time_t unixdate) +{ + put_dos_date2(buf, offset, unixdate, server_zone_offset); +} + +void srv_put_dos_date3(char *buf,int offset,time_t unixdate) +{ + put_dos_date3(buf, offset, unixdate, server_zone_offset); +} + +/**************************************************************************** + 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 & 0xFFFFFFFF); + SIVAL(p, 4, nt >> 32); +} + +void put_long_date(char *p, time_t t) +{ + struct timespec ts; + ts.tv_sec = t; + ts.tv_nsec = 0; + put_long_date_timespec(p, ts); } -#if 0 /**************************************************************************** Return the best approximation to a 'create time' under UNIX from a stat structure. ****************************************************************************/ -struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) +time_t get_create_time(SMB_STRUCT_STAT *st,BOOL fake_dirs) { time_t ret, ret1; @@ -1289,75 +801,553 @@ struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) */ return ret; } + +struct timespec get_create_timespec(SMB_STRUCT_STAT *st,BOOL fake_dirs) +{ + struct timespec ts; + ts.tv_sec = get_create_time(st, fake_dirs); + ts.tv_nsec = 0; + return ts; +} + +/**************************************************************************** + Get/Set all the possible time fields from a stat struct as a timespec. +****************************************************************************/ + +struct timespec get_atimespec(SMB_STRUCT_STAT *pst) +{ +#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) + struct timespec ret; + + /* Old system - no ns timestamp. */ + ret.tv_sec = pst->st_atime; + ret.tv_nsec = 0; + return ret; +#else +#if defined(HAVE_STAT_ST_ATIM) + return pst->st_atim; +#elif defined(HAVE_STAT_ST_ATIMENSEC) + struct timespec ret; + ret.tv_sec = pst->st_atime; + ret.tv_nsec = pst->st_atimensec; + return ret; +#else +#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT #endif +#endif +} -void dos_filetime_timespec(struct timespec *tsp) +void set_atimespec(SMB_STRUCT_STAT *pst, struct timespec ts) { - tsp->tv_sec &= ~1; - tsp->tv_nsec = 0; +#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) + /* Old system - no ns timestamp. */ + pst->st_atime = ts.tv_sec; +#else +#if defined(HAVE_STAT_ST_ATIM) + pst->st_atim = ts; +#elif defined(HAVE_STAT_ST_ATIMENSEC) + pst->st_atime = ts.tv_sec; + pst->st_atimensec = ts.tv_nsec +#else +#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT +#endif +#endif } -/** - Return the date and time as a string -**/ -char *timestring(TALLOC_CTX *mem_ctx, time_t t) +struct timespec get_mtimespec(SMB_STRUCT_STAT *pst) { - char *TimeBuf; - char tempTime[80]; - struct tm *tm; +#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) + struct timespec ret; - tm = localtime(&t); - if (!tm) { - return talloc_asprintf(mem_ctx, - "%ld seconds since the Epoch", - (long)t); - } + /* Old system - no ns timestamp. */ + ret.tv_sec = pst->st_mtime; + ret.tv_nsec = 0; + return ret; +#else +#if defined(HAVE_STAT_ST_MTIM) + return pst->st_mtim; +#elif defined(HAVE_STAT_ST_MTIMENSEC) + struct timespec ret; + ret.tv_sec = pst->st_mtime; + ret.tv_nsec = pst->st_mtimensec; + return ret; +#else +#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT +#endif +#endif +} -#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); +void set_mtimespec(SMB_STRUCT_STAT *pst, struct timespec ts) +{ +#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) + /* Old system - no ns timestamp. */ + pst->st_mtime = ts.tv_sec; #else - TimeBuf = talloc_strdup(mem_ctx, asctime(tm)); +#if defined(HAVE_STAT_ST_MTIM) + pst->st_mtim = ts; +#elif defined(HAVE_STAT_ST_MTIMENSEC) + pst->st_mtime = ts.tv_sec; + pst->st_mtimensec = ts.tv_nsec +#else +#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT #endif +#endif +} - return TimeBuf; +struct timespec get_ctimespec(SMB_STRUCT_STAT *pst) +{ +#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) + struct timespec ret; + + /* Old system - no ns timestamp. */ + ret.tv_sec = pst->st_ctime; + ret.tv_nsec = 0; + return ret; +#else +#if defined(HAVE_STAT_ST_CTIM) + return pst->st_ctim; +#elif defined(HAVE_STAT_ST_CTIMENSEC) + struct timespec ret; + ret.tv_sec = pst->st_ctime; + ret.tv_nsec = pst->st_ctimensec; + return ret; +#else +#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT +#endif +#endif } +void set_ctimespec(SMB_STRUCT_STAT *pst, struct timespec ts) +{ +#if !defined(HAVE_STAT_HIRES_TIMESTAMPS) + /* Old system - no ns timestamp. */ + pst->st_ctime = ts.tv_sec; +#else +#if defined(HAVE_STAT_ST_CTIM) + pst->st_ctim = ts; +#elif defined(HAVE_STAT_ST_CTIMENSEC) + pst->st_ctime = ts.tv_sec; + pst->st_ctimensec = ts.tv_nsec +#else +#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT +#endif +#endif +} -/** - return a talloced string representing a NTTIME for human consumption -*/ -const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt) +void dos_filetime_timespec(struct timespec *tsp) { - time_t t; - if (nt.low == 0 && nt.high == 0) { - return "NTTIME(0)"; - } - t = nt_time_to_unix(&nt); - return timestring(mem_ctx, t); + tsp->tv_sec &= ~1; + tsp->tv_nsec = 0; } -/**************************************************************************** - Utility function that always returns a const string even if localtime - and asctime fail. -****************************************************************************/ +/******************************************************************* + Create a unix date (int GMT) from a dos date (which is actually in + localtime). +********************************************************************/ -const char *time_to_asc(const time_t *t) +static time_t make_unix_date(void *date_ptr, int zone_offset) { - const char *asct; - struct tm *lt = localtime(t); + uint32 dos_date=0; + struct tm t; + time_t ret; - if (!lt) { - return "unknown time"; - } + dos_date = IVAL(date_ptr,0); - asct = asctime(lt); - if (!asct) { - return "unknown time"; + if (dos_date == 0) { + return 0; } - return asct; -} + + 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; +} + +/**************************************************************************** + 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 = 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); +} + +/*************************************************************************** + 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; + } + + 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; + } + + 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; +} +/**************************************************************************** + Check if two NTTIMEs are the same. +****************************************************************************/ + +BOOL nt_time_equals(const NTTIME *nt1, const NTTIME *nt2) +{ + return (*nt1 == *nt2); +} + +/******************************************************************* + 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; + } +} + +/**************************************************************************** + 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; + + if (*nt == 0) { + return (time_t)0; + } + + 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); +} + +/**************************************************************************** + Utility function that always returns a const string even if localtime + and asctime fail. +****************************************************************************/ + +const char *time_to_asc(const time_t *t) +{ + const char *asct; + struct tm *lt = localtime(t); + + if (!lt) { + return "unknown time"; + } + + asct = asctime(lt); + if (!asct) { + return "unknown time"; + } + 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; +} + -- cgit