| #include "local.h" |
| #include "lock.h" |
| #include "stat.h" |
| #include <errno.h> |
| #include <stdio.h> |
| #include <windows.h> |
| |
| void GetCurrentFT(FILETIME *); |
| |
| int _daylight; |
| long int _timezone; |
| char *_tzname[2]; |
| |
| static char __tzname_std[11]; |
| static char __tzname_dst[11]; |
| static char *prev_tzenv = NULL; |
| unsigned long _dstbias; |
| |
| typedef struct __tzrule_struct |
| { |
| char ch; |
| int m; |
| int n; |
| int d; |
| int s; |
| time_t change; |
| long offset; /* Match type of _timezone. */ |
| } __tzrule_type; |
| typedef struct __tzinfo_struct |
| { |
| int __tznorth; |
| int __tzyear; |
| __tzrule_type __tzrule[2]; |
| } __tzinfo_type; |
| |
| static __tzinfo_type tzinfo = {1, 0, |
| { {'J', 0, 0, 0, 0, (time_t)0, 0L }, |
| {'J', 0, 0, 0, 0, (time_t)0, 0L } |
| } |
| }; |
| |
| static const int mon_lengths[2][MONSPERYEAR] = { |
| {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, |
| {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} |
| } ; |
| |
| static const int year_lengths[2] = { |
| 365, |
| 366 |
| } ; |
| |
| static void __tz_lock(){ |
| #ifndef __SINGLE_THREAD__ |
| __lock_acquire(__tz_lock_object); |
| #endif |
| } |
| |
| static void __tz_unlock(){ |
| #ifndef __SINGLE_THREAD__ |
| __lock_release(__tz_lock_object); |
| #endif |
| } |
| |
| static __tzinfo_type *_gettzinfo () |
| { |
| return &tzinfo; |
| } |
| |
| static int __tzcalc_limits(int year) |
| { |
| int days, year_days, years; |
| int i, j; |
| __tzinfo_type *tz = _gettzinfo (); |
| |
| if (year < EPOCH_YEAR) |
| return 0; |
| |
| tz->__tzyear = year; |
| |
| years = (year - EPOCH_YEAR); |
| |
| year_days = years * 365 + |
| (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + |
| (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; |
| |
| for (i = 0; i < 2; ++i) |
| { |
| if (tz->__tzrule[i].ch == 'J') |
| days = year_days + tz->__tzrule[i].d + |
| (isleap(year) && tz->__tzrule[i].d >= 60); |
| else if (tz->__tzrule[i].ch == 'D') |
| days = year_days + tz->__tzrule[i].d; |
| else |
| { |
| int yleap = isleap(year); |
| int m_day, m_wday, wday_diff; |
| const int *ip = mon_lengths[yleap]; |
| |
| days = year_days; |
| |
| for (j = 1; j < tz->__tzrule[i].m; ++j) |
| days += ip[j-1]; |
| |
| m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; |
| |
| wday_diff = tz->__tzrule[i].d - m_wday; |
| if (wday_diff < 0) |
| wday_diff += DAYSPERWEEK; |
| m_day = (tz->__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; |
| |
| while (m_day >= ip[j-1]) |
| m_day -= DAYSPERWEEK; |
| |
| days += m_day; |
| } |
| |
| /* store the change-over time in GMT form by adding offset */ |
| tz->__tzrule[i].change = days * SECSPERDAY + |
| tz->__tzrule[i].s + tz->__tzrule[i].offset; |
| } |
| |
| tz->__tznorth = (tz->__tzrule[0].change < tz->__tzrule[1].change); |
| |
| return 1; |
| } |
| |
| static void _tzset_hook(){ |
| TIME_ZONE_INFORMATION tzinfo; |
| int defused; |
| |
| /* No race condition here, because this function is called |
| wrapped in a lock. see _tzset_r. */ |
| static int alloced = 0; |
| if (!alloced) |
| { |
| static char tzname0[64]; |
| static char tzname1[64]; |
| strcpy(tzname0, _tzname[0]); |
| strcpy(tzname1, _tzname[1]); |
| _tzname[0] = tzname0; |
| _tzname[1] = tzname1; |
| alloced = 1; |
| } |
| |
| if ( GetTimeZoneInformation( &tzinfo ) == 0xFFFFFFFF ) |
| return; |
| |
| _timezone = tzinfo.Bias * 60L; |
| |
| if ( tzinfo.StandardDate.wMonth != 0 ) |
| _timezone += (tzinfo.StandardBias * 60L); |
| |
| if ( (tzinfo.DaylightDate.wMonth != 0) && |
| (tzinfo.DaylightBias != 0) ) |
| { |
| _daylight = 1; |
| _dstbias = (tzinfo.DaylightBias - tzinfo.StandardBias) * 60L; |
| } |
| else { |
| _daylight = 0; |
| _dstbias = 0; |
| } |
| |
| if ( (WideCharToMultiByte( CP_ACP, |
| WC_COMPOSITECHECK | WC_SEPCHARS, |
| tzinfo.StandardName, -1, _tzname[0], 63, NULL, &defused ) != 0) && |
| (!defused)) { |
| _tzname[0][63] = '\0'; |
| } |
| else { |
| _tzname[0][0] = '\0'; |
| } |
| |
| if ( (WideCharToMultiByte( CP_ACP, |
| WC_COMPOSITECHECK | WC_SEPCHARS, |
| tzinfo.DaylightName, -1, _tzname[1], 63, NULL, &defused ) != 0) && |
| (!defused) |
| ) { |
| _tzname[1][63] = '\0'; |
| } |
| else { |
| _tzname[1][0] = '\0'; |
| } |
| } |
| |
| void tzset() { |
| char *tzenv; |
| unsigned short hh, mm, ss, m, w, d; |
| int sign, n; |
| int i, ch; |
| __tzinfo_type *tz = _gettzinfo (); |
| |
| if ((tzenv = getenv("TZ")) == NULL){ |
| __tz_lock(); |
| _tzset_hook(); |
| __tz_unlock(); |
| return; |
| } |
| |
| __tz_lock(); |
| |
| if (prev_tzenv != NULL && strcmp(tzenv, prev_tzenv) == 0) |
| { |
| __tz_unlock(); |
| return; |
| } |
| |
| free(prev_tzenv); |
| prev_tzenv = malloc(strlen(tzenv) + 1); |
| if (prev_tzenv != NULL) |
| strcpy (prev_tzenv, tzenv); |
| |
| /* ignore implementation-specific format specifier */ |
| if (*tzenv == ':') |
| ++tzenv; |
| |
| if (sscanf (tzenv, "%10[^0-9,+-]%n", __tzname_std, &n) <= 0) |
| { |
| __tz_unlock(); |
| return; |
| } |
| |
| tzenv += n; |
| |
| sign = 1; |
| if (*tzenv == '-') |
| { |
| sign = -1; |
| ++tzenv; |
| } |
| else if (*tzenv == '+') |
| ++tzenv; |
| |
| mm = 0; |
| ss = 0; |
| |
| if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) < 1) |
| { |
| __tz_unlock(); |
| return; |
| } |
| |
| tz->__tzrule[0].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh); |
| _tzname[0] = __tzname_std; |
| tzenv += n; |
| |
| if (sscanf (tzenv, "%10[^0-9,+-]%n", __tzname_dst, &n) <= 0) |
| { |
| _tzname[1] = _tzname[0]; |
| __tz_unlock(); |
| return; |
| } |
| else |
| _tzname[1] = __tzname_dst; |
| |
| tzenv += n; |
| |
| /* otherwise we have a dst name, look for the offset */ |
| sign = 1; |
| if (*tzenv == '-') |
| { |
| sign = -1; |
| ++tzenv; |
| } |
| else if (*tzenv == '+') |
| ++tzenv; |
| |
| hh = 0; |
| mm = 0; |
| ss = 0; |
| |
| if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) <= 0) |
| tz->__tzrule[1].offset = tz->__tzrule[0].offset - 3600; |
| else |
| tz->__tzrule[1].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh); |
| |
| tzenv += n; |
| |
| for (i = 0; i < 2; ++i) |
| { |
| if (*tzenv == ',') |
| ++tzenv; |
| |
| if (*tzenv == 'M') |
| { |
| if (sscanf (tzenv, "M%hu%n.%hu%n.%hu%n", &m, &n, &w, &n, &d, &n) != 3 || |
| m < 1 || m > 12 || w < 1 || w > 5 || d > 6) |
| { |
| __tz_unlock(); |
| return; |
| } |
| |
| tz->__tzrule[i].ch = 'M'; |
| tz->__tzrule[i].m = m; |
| tz->__tzrule[i].n = w; |
| tz->__tzrule[i].d = d; |
| |
| tzenv += n; |
| } |
| else |
| { |
| char *end; |
| if (*tzenv == 'J') |
| { |
| ch = 'J'; |
| ++tzenv; |
| } |
| else |
| ch = 'D'; |
| |
| d = strtoul (tzenv, &end, 10); |
| |
| /* if unspecified, default to US settings */ |
| if (end == tzenv) |
| { |
| if (i == 0) |
| { |
| tz->__tzrule[0].ch = 'M'; |
| tz->__tzrule[0].m = 4; |
| tz->__tzrule[0].n = 1; |
| tz->__tzrule[0].d = 0; |
| } |
| else |
| { |
| tz->__tzrule[1].ch = 'M'; |
| tz->__tzrule[1].m = 10; |
| tz->__tzrule[1].n = 5; |
| tz->__tzrule[1].d = 0; |
| } |
| } |
| else |
| { |
| tz->__tzrule[i].ch = ch; |
| tz->__tzrule[i].d = d; |
| } |
| |
| tzenv = end; |
| } |
| |
| /* default time is 02:00:00 am */ |
| hh = 2; |
| mm = 0; |
| ss = 0; |
| n = 0; |
| |
| if (*tzenv == '/') |
| sscanf (tzenv, "/%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n); |
| |
| tz->__tzrule[i].s = ss + SECSPERMIN * mm + SECSPERHOUR * hh; |
| |
| tzenv += n; |
| } |
| |
| __tzcalc_limits (tz->__tzyear); |
| _timezone = tz->__tzrule[0].offset; |
| _daylight = tz->__tzrule[0].offset != tz->__tzrule[1].offset; |
| |
| __tz_unlock(); |
| } |
| |
| |
| static time_t filetime_to_time_t( const FILETIME ft ) |
| { |
| ULARGE_INTEGER li; |
| li.LowPart = ft.dwLowDateTime; |
| li.HighPart = ft.dwHighDateTime; |
| |
| // 100-nanosec to seconds |
| li.QuadPart /= 10000000; |
| |
| // FILETIME is from 1601-01-01 T 00:00:00 |
| // time_t is from 1970-01-01 T 00:00:00 |
| // 1970 - 1601 = 369 year (89 leap years) |
| // |
| // ((369y*365d) + 89d) *24h *60min *60sec |
| // = 11644473600 seconds |
| li.QuadPart -= 11644473600LL; |
| return li.LowPart; |
| } |
| |
| static FILETIME to_filetime(time_t tt/*, int flag*/) |
| { |
| ULARGE_INTEGER li; |
| li.QuadPart = tt; |
| li.QuadPart += 11644473600LL; |
| /*if(!flag) */li.QuadPart *= 10000000; |
| |
| FILETIME ft; |
| ft.dwLowDateTime = li.LowPart; |
| ft.dwHighDateTime = li.HighPart; |
| return ft; |
| } |
| |
| /* |
| Change the access time of FILE to TSP[0] and |
| the modification time of FILE to TSP[1]. |
| */ |
| int utimensat(int fd, const char *file, const struct timespec *tsp, int flags) { |
| if (file == NULL){ |
| errno = EINVAL; |
| return -1; |
| } |
| size_t len = strlen(file) + 1; |
| wchar_t *FileW = (wchar_t *)malloc(len * sizeof(wchar_t)); |
| mbstowcs(FileW, file, len); |
| HANDLE FileH = CreateFileW(FileW, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| //char *FileH = CreateFileW(FileW, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| free(FileW); |
| |
| FILETIME ft[2];// = { to_filetime(tsp[0].tv_sec), to_filetime(tsp[1].tv_sec) }; |
| if(tsp[0].tv_nsec != 0) ft[0] = to_filetime(tsp[0].tv_sec + tsp[0].tv_nsec / 10000000); |
| else ft[0] = to_filetime(tsp[0].tv_sec); |
| if(tsp[1].tv_nsec != 0) ft[1] = to_filetime(tsp[1].tv_sec + tsp[1].tv_nsec / 10000000); |
| else ft[1] = to_filetime(tsp[1].tv_sec); |
| //ft[0] = to_filetime(tsp[0].tv_sec, 0) + to_filetime(tsp[0].tv_nsec, 1); |
| //ft[1] = to_filetime(tsp[1].tv_sec, 0) + to_filetime(tsp[1].tv_nsec, 1); |
| //printf("celibc debug:\nft[0].dwLowDateTime = %d\nft[1].dwLowDateTime = %d\n", ft[0].dwLowDateTime, ft[1].dwLowDateTime); |
| /* |
| struct timespec ft[2] = { tsp[0], tsp[1] }; |
| if(ft[0].tv_nsec == 0) ft[0] = to_filetime(tsp[0].tv_sec); |
| if(ft[1].tv_nsec == 0) ft[1] = to_filetime(tsp[1].tv_sec); |
| */ |
| int OK = SetFileTime(FileH, NULL, &ft[0], &ft[1]); |
| return OK? 0:-1; |
| } |
| |
| time_t time(time_t *t) { |
| time_t r; |
| if(!t) t = &r; |
| //SYSTEMTIME st; |
| //GetSystemTime(&st); |
| FILETIME ft; |
| //if(!SystemTimeToFileTime(&st, &ft)) return (time_t)-1; |
| GetCurrentFT(&ft); |
| *t = filetime_to_time_t(ft); |
| return *t; |
| } |