/** * Returns the difference in seconds between the given GMT time * and 1970-01-01 00:00:00 GMT. * * \param year the year (since 1970) * \param month the month (1 - 12) * \param day the day (1 - 31) * \param hour the hour (0 - 23) * \param minute the minute (0 - 59) * \param second the second (0 - 59) * * \return the difference in seconds between the given GMT time * and 1970-01-01 00:00:00 GMT. */ static int64_t mkgmtime( uint32_t year, uint32_t month, uint32_t day, uint32_t hour, uint32_t minute, uint32_t second) { int64_t result; /* * FIXME: It does not check whether the specified days * is valid based on the specified months. */ assert(year >= 1970 && month > 0 && month <= 12 && day > 0 && day <= 31 && hour < 24 && minute < 60 && second < 60); /* Set 'day' to the number of days into the year. */ day += ydays[month - 1] + (month > 2 && leap (year)) - 1; /* Now calculate 'day' to the number of days since Jan 1, 1970. */ day = day + 365 * (year - 1970) + nleap(year); int64_mul(result, int64_const(day), int64_const(SECONDS_PER_DAY)); int64_add(result, result, int64_const( SECONDS_PER_HOUR * hour + SECONDS_PER_MINUTE * minute + second)); return result; }
/* ----------------------------------------------------------------------------- Function: FS_FileTimeToUnixTime() -Converts file time to UNIX time format. Parameters: FILETIME -[in] Pointer to a FILETIME structure containing the file time to convert to UNIX date and time format. Returns: On success nonzero, otherwise zero. Notes: ----------------------------------------------------------------------------- */ PRIVATE W32 FS_FileTimeToUnixTime( FILETIME *ft ) { time_t days; SYSTEMTIME st; static const W16 ydays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; if( ! FileTimeToSystemTime( ft, &st ) ) { return 0; } // Protection from overflow if( (ft->dwHighDateTime < 0x019DB1DEUL) || ((ft->dwHighDateTime == 0x019DB1DEUL) && (ft->dwLowDateTime < 0xD53E8000UL)) ) { return 0; } if( (ft->dwHighDateTime > 0x0236485EUL) || ((ft->dwHighDateTime == 0x0236485EUL) && (ft->dwLowDateTime > 0xD4A5E980UL)) ) { return 0; } #define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0) #define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400) // set 'days' to the number of days into the year days = st.wDay - 1 + ydays[ st.wMonth-1 ] + (st.wMonth > 2 && leap( st.wYear )); // now set 'days' to the number of days since 1 Jan 1970 days += 365 * (time_t)(st.wYear - 1970) + (time_t)(nleap(st.wYear)); return (time_t)(86400L * days + 3600L * (time_t)st.wHour + (time_t)(60 * st.wMinute + st.wSecond)); }
time_t mktime(struct tm *brokentime) { int year = brokentime->tm_year + 1900; int months = brokentime->tm_mon; int days = brokentime->tm_mday-1; if(months > 1 && leap (year)) days++; while (months-- > 0) days += __monthdays[months]; brokentime->tm_yday = days; days += 365 * (year - 1970) + nleap (year); brokentime->tm_wday = (days + 4) % 7; brokentime->tm_isdst = 0; return (60*60*24 * days) + (60*60 * brokentime->tm_hour) + (60 * brokentime->tm_min) + brokentime->tm_sec; }
local int FileTime2utime(FILETIME *pft, time_t *ut) { #ifndef NO_INT64 ULLNG64 NTtime; NTtime = ((ULLNG64)pft->dwLowDateTime + ((ULLNG64)pft->dwHighDateTime << 32)); /* underflow and overflow handling */ #ifdef CHECK_UTIME_SIGNED_UNSIGNED if ((time_t)0x80000000L < (time_t)0L) { if (NTtime < ((ULLNG64)UNIX_TIME_SMIN_LO + ((ULLNG64)UNIX_TIME_SMIN_HI << 32))) { *ut = (time_t)LONG_MIN; return FALSE; } if (NTtime > ((ULLNG64)UNIX_TIME_SMAX_LO + ((ULLNG64)UNIX_TIME_SMAX_HI << 32))) { *ut = (time_t)LONG_MAX; return FALSE; } } else #endif /* CHECK_UTIME_SIGNED_UNSIGNED */ { if (NTtime < ((ULLNG64)UNIX_TIME_ZERO_LO + ((ULLNG64)UNIX_TIME_ZERO_HI << 32))) { *ut = (time_t)0; return FALSE; } if (NTtime > ((ULLNG64)UNIX_TIME_UMAX_LO + ((ULLNG64)UNIX_TIME_UMAX_HI << 32))) { *ut = (time_t)ULONG_MAX; return FALSE; } } NTtime -= ((ULLNG64)UNIX_TIME_ZERO_LO + ((ULLNG64)UNIX_TIME_ZERO_HI << 32)); *ut = (time_t)(NTtime / (unsigned long)NT_QUANTA_PER_UNIX); return TRUE; #else /* NO_INT64 (64-bit integer arithmetics may not be supported) */ /* nonzero if `y' is a leap year, else zero */ # define leap(y) (((y)%4 == 0 && (y)%100 != 0) || (y)%400 == 0) /* number of leap years from 1970 to `y' (not including `y' itself) */ # define nleap(y) (((y)-1969)/4 - ((y)-1901)/100 + ((y)-1601)/400) /* daycount at the end of month[m-1] */ static ZCONST ush ydays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; time_t days; SYSTEMTIME w32tm; /* underflow and overflow handling */ #ifdef CHECK_UTIME_SIGNED_UNSIGNED if ((time_t)0x80000000L < (time_t)0L) { if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) || ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) && (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) { *ut = (time_t)LONG_MIN; return FALSE; if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) || ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) && (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) { *ut = (time_t)LONG_MAX; return FALSE; } } else #endif /* CHECK_UTIME_SIGNED_UNSIGNED */ { if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) || ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) && (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) { *ut = (time_t)0; return FALSE; } if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) || ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) && (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) { *ut = (time_t)ULONG_MAX; return FALSE; } } FileTimeToSystemTime(pft, &w32tm); /* set `days' to the number of days into the year */ days = w32tm.wDay - 1 + ydays[w32tm.wMonth-1] + (w32tm.wMonth > 2 && leap (w32tm.wYear)); /* now set `days' to the number of days since 1 Jan 1970 */ days += 365 * (time_t)(w32tm.wYear - 1970) + (time_t)(nleap(w32tm.wYear)); *ut = (time_t)(86400L * days + 3600L * (time_t)w32tm.wHour + (time_t)(60 * w32tm.wMinute + w32tm.wSecond)); return TRUE; #endif /* ?NO_INT64 */ } /* end function FileTime2utime() */ #endif /* USE_EF_UT_TIME || NT_TZBUG_WORKAROUND */ #if (defined(NT_TZBUG_WORKAROUND) && defined(W32_STAT_BANDAID)) local int VFatFileTime2utime(const FILETIME *pft, time_t *ut) { FILETIME lft; SYSTEMTIME w32tm; struct tm ltm; FileTimeToLocalFileTime(pft, &lft); FileTimeToSystemTime(&lft, &w32tm); /* underflow and overflow handling */ /* TODO: The range checks are not accurate, the actual limits may * be off by one daylight-saving-time shift (typically 1 hour), * depending on the current state of "is_dst". */ #ifdef CHECK_UTIME_SIGNED_UNSIGNED if ((time_t)0x80000000L < (time_t)0L) { if ((pft->dwHighDateTime < UNIX_TIME_SMIN_HI) || ((pft->dwHighDateTime == UNIX_TIME_SMIN_HI) && (pft->dwLowDateTime < UNIX_TIME_SMIN_LO))) { *ut = (time_t)LONG_MIN; return FALSE; if ((pft->dwHighDateTime > UNIX_TIME_SMAX_HI) || ((pft->dwHighDateTime == UNIX_TIME_SMAX_HI) && (pft->dwLowDateTime > UNIX_TIME_SMAX_LO))) { *ut = (time_t)LONG_MAX; return FALSE; } } else #endif /* CHECK_UTIME_SIGNED_UNSIGNED */ { if ((pft->dwHighDateTime < UNIX_TIME_ZERO_HI) || ((pft->dwHighDateTime == UNIX_TIME_ZERO_HI) && (pft->dwLowDateTime < UNIX_TIME_ZERO_LO))) { *ut = (time_t)0; return FALSE; } if ((pft->dwHighDateTime > UNIX_TIME_UMAX_HI) || ((pft->dwHighDateTime == UNIX_TIME_UMAX_HI) && (pft->dwLowDateTime > UNIX_TIME_UMAX_LO))) { *ut = (time_t)ULONG_MAX; return FALSE; } } ltm.tm_year = w32tm.wYear - 1900; ltm.tm_mon = w32tm.wMonth - 1; ltm.tm_mday = w32tm.wDay; ltm.tm_hour = w32tm.wHour; ltm.tm_min = w32tm.wMinute; ltm.tm_sec = w32tm.wSecond; ltm.tm_isdst = -1; /* let mktime determine if DST is in effect */ *ut = mktime(<m); /* a cheap error check: mktime returns "(time_t)-1L" on conversion errors. * Normally, we would have to apply a consistency check because "-1" * could also be a valid time. But, it is quite unlikely to read back odd * time numbers from file systems that store time stamps in DOS format. * (The only known exception is creation time on VFAT partitions.) */ return (*ut != (time_t)-1L); } /* end function VFatFileTime2utime() */ #endif /* NT_TZBUG_WORKAROUND && W32_STAT_BANDAID */ #if 0 /* Currently, this is not used at all */ long GetTheFileTime(char *name, iztimes *z_ut) { HANDLE h; FILETIME Modft, Accft, Creft, lft; WORD dh, dl; #ifdef __RSXNT__ /* RSXNT/EMX C rtl uses OEM charset */ char *ansi_name = (char *)alloca(strlen(name) + 1); OemToAnsi(name, ansi_name); name = ansi_name; #endif h = CreateFile(name, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if ( h != INVALID_HANDLE_VALUE ) { BOOL ftOK = GetFileTime(h, &Creft, &Accft, &Modft); CloseHandle(h); #ifdef USE_EF_UT_TIME if (ftOK && (z_ut != NULL)) { FileTime2utime(&Modft, &(z_ut->mtime)); if (Accft.dwLowDateTime != 0 || Accft.dwHighDateTime != 0) FileTime2utime(&Accft, &(z_ut->atime)); else z_ut->atime = z_ut->mtime; if (Creft.dwLowDateTime != 0 || Creft.dwHighDateTime != 0) FileTime2utime(&Creft, &(z_ut->ctime)); else z_ut->ctime = z_ut->mtime; } #endif FileTimeToLocalFileTime(&ft, &lft); FileTimeToDosDateTime(&lft, &dh, &dl); return(dh<<16) | dl; } else return 0L; }