blob: 49ec1257bb85b147dc31536ffc045254aef41c1b [file] [log] [blame] [raw]
#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;
}