Deal with systems that don't initialize birthtime correctly.
[tprouty/samba.git] / source / lib / time.c
index e98f8232abc58fa2beb3c552f40ccf21843cb7cb..425539c3b0d4ea32db9af86b530e8054676d47d8 100644 (file)
@@ -8,7 +8,7 @@
 
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -17,8 +17,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -95,7 +94,13 @@ void unix_to_nt_time(NTTIME *nt, time_t t)
        if (t == (time_t)-1) {
                *nt = (NTTIME)-1LL;
                return;
-       }               
+       }       
+
+       if (t == TIME_T_MAX) {
+               *nt = 0x7fffffffffffffffLL;
+               return;
+       }
+
        if (t == 0) {
                *nt = 0;
                return;
@@ -112,7 +117,7 @@ void unix_to_nt_time(NTTIME *nt, time_t t)
  Check if it's a null unix time.
 ****************************************************************************/
 
-BOOL null_time(time_t t)
+bool null_time(time_t t)
 {
        return t == 0 || 
                t == (time_t)0xFFFFFFFF || 
@@ -123,7 +128,7 @@ BOOL null_time(time_t t)
  Check if it's a null NTTIME.
 ****************************************************************************/
 
-BOOL null_nttime(NTTIME t)
+bool null_nttime(NTTIME t)
 {
        return t == 0 || t == (NTTIME)-1;
 }
@@ -132,7 +137,7 @@ BOOL null_nttime(NTTIME t)
  Check if it's a null timespec.
 ****************************************************************************/
 
-BOOL null_timespec(struct timespec ts)
+bool null_timespec(struct timespec ts)
 {
        return ts.tv_sec == 0 || 
                ts.tv_sec == (time_t)0xFFFFFFFF || 
@@ -298,11 +303,13 @@ time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset)
 
 char *http_timestring(time_t t)
 {
-       static fstring buf;
+       fstring buf;
        struct tm *tm = localtime(&t);
 
-       if (!tm) {
-               slprintf(buf,sizeof(buf)-1,"%ld seconds since the Epoch",(long)t);
+       if (t == TIME_T_MAX) {
+               fstrcpy(buf, "never");
+       } else if (!tm) {
+               fstr_sprintf(buf, "%ld seconds since the Epoch", (long)t);
        } else {
 #ifndef HAVE_STRFTIME
                const char *asct = asctime(tm);
@@ -314,7 +321,7 @@ char *http_timestring(time_t t)
                strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
 #endif /* !HAVE_STRFTIME */
        }
-       return buf;
+       return talloc_strdup(talloc_tos(), buf);
 }
 
 
@@ -394,7 +401,7 @@ struct timeval timeval_zero(void)
 /**
   return True if a timeval is zero
 */
-BOOL timeval_is_zero(const struct timeval *tv)
+bool timeval_is_zero(const struct timeval *tv)
 {
        return tv->tv_sec == 0 && tv->tv_usec == 0;
 }
@@ -472,7 +479,7 @@ int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
 /**
   return True if a timer is in the past
 */
-BOOL timeval_expired(const struct timeval *tv)
+bool timeval_expired(const struct timeval *tv)
 {
        struct timeval tv2 = timeval_current();
        if (tv2.tv_sec > tv->tv_sec) return True;
@@ -554,6 +561,37 @@ NTTIME timeval_to_nttime(const struct timeval *tv)
                  ((TIME_FIXUP_CONSTANT_INT + (uint64_t)tv->tv_sec) * 1000000));
 }
 
+/**************************************************************
+ Handle conversions between time_t and uint32, taking care to
+ preserve the "special" values.
+**************************************************************/
+
+uint32 convert_time_t_to_uint32(time_t t)
+{
+#if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
+       /* time_t is 64-bit. */
+       if (t == 0x8000000000000000LL) {
+               return 0x80000000;
+       } else if (t == 0x7FFFFFFFFFFFFFFFLL) {
+               return 0x7FFFFFFF;
+       }
+#endif
+       return (uint32)t;
+}
+
+time_t convert_uint32_to_time_t(uint32 u)
+{
+#if (defined(SIZEOF_TIME_T) && (SIZEOF_TIME_T == 8))
+       /* time_t is 64-bit. */
+       if (u == 0x80000000) {
+               return (time_t)0x8000000000000000LL;
+       } else if (u == 0x7FFFFFFF) {
+               return (time_t)0x7FFFFFFFFFFFFFFFLL;
+       }
+#endif
+       return (time_t)u;
+}
+
 /*******************************************************************
  Yield the difference between *A and *B, in seconds, ignoring leap seconds.
 ********************************************************************/
@@ -596,7 +634,7 @@ int get_time_zone(time_t t)
  Check if NTTIME is 0.
 ****************************************************************************/
 
-BOOL nt_time_is_zero(const NTTIME *nt)
+bool nt_time_is_zero(const NTTIME *nt)
 {
        return (*nt == 0);
 }
@@ -649,9 +687,9 @@ int set_server_zone_offset(time_t t)
  Return the date and time as a string
 ****************************************************************************/
 
-char *current_timestring(BOOL hires)
+char *current_timestring(TALLOC_CTX *ctx, bool hires)
 {
-       static fstring TimeBuf;
+       fstring TimeBuf;
        struct timeval tp;
        time_t t;
        struct tm *tm;
@@ -701,7 +739,7 @@ char *current_timestring(BOOL hires)
                }
 #endif
        }
-       return(TimeBuf);
+       return talloc_strdup(ctx, TimeBuf);
 }
 
 
@@ -788,14 +826,10 @@ void put_long_date(char *p, time_t t)
  structure.
 ****************************************************************************/
 
-time_t get_create_time(const SMB_STRUCT_STAT *st,BOOL fake_dirs)
+static time_t calc_create_time(const SMB_STRUCT_STAT *st)
 {
        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);
 
@@ -810,12 +844,42 @@ time_t get_create_time(const SMB_STRUCT_STAT *st,BOOL fake_dirs)
        return ret;
 }
 
-struct timespec get_create_timespec(const SMB_STRUCT_STAT *st,BOOL fake_dirs)
+/****************************************************************************
+ Return the 'create time' from a stat struct if it exists (birthtime) or else
+ use the best approximation.
+****************************************************************************/
+
+struct timespec get_create_timespec(const SMB_STRUCT_STAT *pst,bool fake_dirs)
 {
-       struct timespec ts;
-       ts.tv_sec = get_create_time(st, fake_dirs);
-       ts.tv_nsec = 0;
-       return ts;
+       struct timespec ret;
+
+       if(S_ISDIR(pst->st_mode) && fake_dirs) {
+               ret.tv_sec = 315493200L;          /* 1/1/1980 */
+               ret.tv_nsec = 0;
+               return ret;
+       }
+
+#if defined(HAVE_STAT_ST_BIRTHTIMESPEC)
+       ret = pst->st_birthtimespec;
+#elif defined(HAVE_STAT_ST_BIRTHTIMENSEC)
+       ret.tv_sec = pst->st_birthtime;
+       ret.tv_nsec = pst->st_birthtimenspec;
+#elif defined(HAVE_STAT_ST_BIRTHTIME)
+       ret.tv_sec = pst->st_birthtime;
+       ret.tv_nsec = 0;
+#else
+       ret.tv_sec = calc_create_time(pst);
+       ret.tv_nsec = 0;
+#endif
+
+       /* Deal with systems that don't initialize birthtime correctly.
+        * Pointed out by SATOH Fumiyasu <fumiyas@osstech.jp>.
+        */
+       if (null_timespec(ret)) {
+               ret.tv_sec = calc_create_time(pst);
+               ret.tv_nsec = 0;
+       }
+       return ret;
 }
 
 /****************************************************************************
@@ -1072,7 +1136,7 @@ struct timespec timespec_current(void)
        struct timespec ts;
        GetTimeOfDay(&tv);
        ts.tv_sec = tv.tv_sec;
-       ts.tv_nsec = tv.tv_sec * 1000;
+       ts.tv_nsec = tv.tv_usec * 1000;
        return ts;
 }
 
@@ -1143,17 +1207,17 @@ void cli_put_dos_date3(struct cli_state *cli, char *buf, int offset, time_t unix
        put_dos_date3(buf, offset, unixdate, cli->serverzone);
 }
 
-time_t cli_make_unix_date(struct cli_state *cli, void *date_ptr)
+time_t cli_make_unix_date(struct cli_state *cli, const void *date_ptr)
 {
        return make_unix_date(date_ptr, cli->serverzone);
 }
 
-time_t cli_make_unix_date2(struct cli_state *cli, void *date_ptr)
+time_t cli_make_unix_date2(struct cli_state *cli, const void *date_ptr)
 {
        return make_unix_date2(date_ptr, cli->serverzone);
 }
 
-time_t cli_make_unix_date3(struct cli_state *cli, void *date_ptr)
+time_t cli_make_unix_date3(struct cli_state *cli, const void *date_ptr)
 {
        return make_unix_date3(date_ptr, cli->serverzone);
 }
@@ -1173,8 +1237,12 @@ struct timespec nt_time_to_unix_timespec(NTTIME *nt)
        d = (int64)*nt;
        /* d is now in 100ns units, since jan 1st 1601".
           Save off the ns fraction. */
-       
-       ret.tv_nsec = (long) ((d % 100) * 100);
+
+       /*
+        * Take the last seven decimal digits and multiply by 100.
+        * to convert from 100ns units to 1ns units.
+        */
+        ret.tv_nsec = (long) ((d % (1000 * 1000 * 10)) * 100);
 
        /* Convert to seconds */
        d /= 1000*1000*10;
@@ -1201,7 +1269,7 @@ struct timespec nt_time_to_unix_timespec(NTTIME *nt)
  Check if two NTTIMEs are the same.
 ****************************************************************************/
 
-BOOL nt_time_equals(const NTTIME *nt1, const NTTIME *nt2)
+bool nt_time_equals(const NTTIME *nt1, const NTTIME *nt2)
 {
        return (*nt1 == *nt2);
 }
@@ -1344,7 +1412,7 @@ void unix_to_nt_time_abs(NTTIME *nt, time_t t)
        d = (double)(t);
        d *= 1.0e7;
 
-       *nt = d;
+       *nt = (NTTIME)d;
 
        /* convert to a negative value */
        *nt=~*nt;
@@ -1355,7 +1423,7 @@ void unix_to_nt_time_abs(NTTIME *nt, time_t t)
  Check if it's a null mtime.
 ****************************************************************************/
 
-BOOL null_mtime(time_t mtime)
+bool null_mtime(time_t mtime)
 {
        if (mtime == 0 || mtime == (time_t)0xFFFFFFFF || mtime == (time_t)-1)
                return(True);
@@ -1385,8 +1453,6 @@ const char *time_to_asc(const time_t t)
 
 const char *display_time(NTTIME nttime)
 {
-       static fstring string;
-
        float high;
        float low;
        int sec;
@@ -1407,18 +1473,18 @@ const char *display_time(NTTIME nttime)
        low = ~(nttime & 0xFFFFFFFF);
        low = low/(1000*1000*10);
 
-       sec=high+low;
+       sec=(int)(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);
+       return talloc_asprintf(talloc_tos(), "%u days, %u hours, %u minutes, "
+                              "%u seconds", days, hours, mins, secs);
 }
 
-BOOL nt_time_is_set(const NTTIME *nt)
+bool nt_time_is_set(const NTTIME *nt)
 {
        if (*nt == 0x7FFFFFFFFFFFFFFFLL) {
                return False;