mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60a91a23d6 | ||
|
|
c9611e6f0e |
@@ -1,3 +1,35 @@
|
||||
2017-03-08 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
Isolate global timezone variables in <time/time-variables.h>.
|
||||
* time/time-variables.h: New file.
|
||||
* time/time.h (__tzname, __daylight, __timezone): Remove private
|
||||
declarations.
|
||||
(tzname, daylight, timezone): Update comments.
|
||||
(__isleap): Remove definition.
|
||||
* include/time.h (__time_isleap): Declare.
|
||||
* time/Makefile (routines): Add isleap.
|
||||
(tests): Add tst-isleap.
|
||||
* time/Versions (GLIBC_PRIVATE): Export __time_isleap.
|
||||
* time/dysize.c (dysize): Call __time_isleap
|
||||
instead of __isleap.
|
||||
* time/getdate.c (check_mday): Likewise.
|
||||
* time/offtime.c (__offtime): Likewise.
|
||||
* time/gmtime.c: Include <time/time-variables.h>.
|
||||
* time/localtime.c: Likewise.
|
||||
* time/tzfile.c: Likewise.
|
||||
* time/tzset.c: Likewise.
|
||||
(__tzname, __daylight, __timezone): Turn into compat symbols.
|
||||
(compute_change): Call __time_isleap instead of __isleap.
|
||||
* time/strftime_l.c: Include <time/time-variables.h>. Reorganize
|
||||
includes.
|
||||
(tzname): Declare for !_LIBC only.
|
||||
(__isleap): Define as __time_isleap.
|
||||
* time/isleap.c: New file.
|
||||
* time/tst-isleap.c: Likewise.
|
||||
* locale/programs/ld-time.c (time_finish): Call __time_isleap
|
||||
instead of __isleap.
|
||||
* sysdeps/posix/gettimeofday.c: Include <time/time-variables.h>.
|
||||
|
||||
2017-03-08 Yury Norov <ynorov@caviumnetworks.com>
|
||||
Zack Weinberg <zackw@panix.com>
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ Version 2.26
|
||||
transliteration tables are all updated to Unicode 9.0.0, using
|
||||
generator scripts contributed by Mike FABIAN (Red Hat).
|
||||
|
||||
* The private identifiers __daylight, __isleap, __timezone, __tzname have
|
||||
been removed from the <time.h> header file.
|
||||
|
||||
Security related changes:
|
||||
|
||||
[Add security related changes here]
|
||||
|
||||
+3
-18
@@ -3,6 +3,7 @@
|
||||
|
||||
#ifndef _ISOMAC
|
||||
# include <xlocale.h>
|
||||
# include <stdbool.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
@@ -31,25 +32,12 @@ struct tm;
|
||||
/* Defined in mktime.c. */
|
||||
extern const unsigned short int __mon_yday[2][13] attribute_hidden;
|
||||
|
||||
/* Defined in localtime.c. */
|
||||
extern struct tm _tmbuf attribute_hidden;
|
||||
bool __time_isleap (int year) internal_function;
|
||||
libc_hidden_proto (__time_isleap)
|
||||
|
||||
/* Defined in tzset.c. */
|
||||
extern char *__tzstring (const char *string);
|
||||
|
||||
extern int __use_tzfile attribute_hidden;
|
||||
|
||||
extern void __tzfile_read (const char *file, size_t extra,
|
||||
char **extrap);
|
||||
extern void __tzfile_compute (time_t timer, int use_localtime,
|
||||
long int *leap_correct, int *leap_hit,
|
||||
struct tm *tp);
|
||||
extern void __tzfile_default (const char *std, const char *dst,
|
||||
long int stdoff, long int dstoff);
|
||||
extern void __tzset_parse_tz (const char *tz);
|
||||
extern void __tz_compute (time_t timer, struct tm *tm, int use_localtime)
|
||||
__THROW internal_function;
|
||||
|
||||
/* Subroutine of `mktime'. Return the `time_t' representation of TP and
|
||||
normalize TP, given that a `struct tm *' maps to a `time_t' as performed
|
||||
by FUNC. Keep track of next guess for time_t offset in *OFFSET. */
|
||||
@@ -75,9 +63,6 @@ extern int __offtime (const time_t *__timer,
|
||||
extern char *__asctime_r (const struct tm *__tp, char *__buf);
|
||||
extern void __tzset (void);
|
||||
|
||||
/* Prototype for the internal function to get information based on TZ. */
|
||||
extern struct tm *__tz_convert (const time_t *timer, int use_localtime, struct tm *tp);
|
||||
|
||||
extern int __nanosleep (const struct timespec *__requested_time,
|
||||
struct timespec *__remaining);
|
||||
libc_hidden_proto (__nanosleep)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <wchar.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -353,7 +354,8 @@ No definition for %s category found"), "LC_TIME"));
|
||||
> days_per_month[time->era_entries[idx].start_date[1]])
|
||||
|| (time->era_entries[idx].start_date[1] == 2
|
||||
&& time->era_entries[idx].start_date[2] == 29
|
||||
&& !__isleap (time->era_entries[idx].start_date[0])))
|
||||
&& !__time_isleap (time->era_entries[idx]
|
||||
.start_date[0])))
|
||||
&& !be_quiet)
|
||||
WITH_CUR_LOCALE (error (0, 0, _("\
|
||||
%s: starting date is invalid in string %Zd in `era' field"),
|
||||
@@ -430,7 +432,8 @@ No definition for %s category found"), "LC_TIME"));
|
||||
> days_per_month[time->era_entries[idx].stop_date[1]])
|
||||
|| (time->era_entries[idx].stop_date[1] == 2
|
||||
&& time->era_entries[idx].stop_date[2] == 29
|
||||
&& !__isleap (time->era_entries[idx].stop_date[0])))
|
||||
&& !__time_isleap (time->era_entries[idx]
|
||||
.stop_date[0])))
|
||||
&& !be_quiet)
|
||||
WITH_CUR_LOCALE (error (0, 0, _("\
|
||||
%s: invalid stopping date in string %Zd in `era' field"),
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* For __tzname, __timezone, __daylight. */
|
||||
#include <time/time-variables.h>
|
||||
|
||||
/* Get the current time of day and timezone information,
|
||||
putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
|
||||
Returns 0 on success, -1 on errors. */
|
||||
|
||||
+2
-2
@@ -36,14 +36,14 @@ routines := offtime asctime clock ctime ctime_r difftime \
|
||||
stime dysize timegm ftime \
|
||||
getdate strptime strptime_l \
|
||||
strftime wcsftime strftime_l wcsftime_l \
|
||||
timespec_get
|
||||
timespec_get isleap
|
||||
aux := era alt_digit lc-time-cleanup
|
||||
|
||||
tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
|
||||
tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
|
||||
tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
|
||||
tst-strptime3 bug-getdate1 tst-strptime-whitespace tst-ftime \
|
||||
tst-tzname
|
||||
tst-tzname tst-isleap
|
||||
|
||||
include ../Rules
|
||||
|
||||
|
||||
@@ -65,4 +65,7 @@ libc {
|
||||
GLIBC_2.16 {
|
||||
timespec_get;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
__time_isleap;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -20,5 +20,5 @@
|
||||
int
|
||||
dysize (int year)
|
||||
{
|
||||
return __isleap (year) ? 366 : 365;
|
||||
return __time_isleap (year) ? 366 : 365;
|
||||
}
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ check_mday (int year, int mon, int mday)
|
||||
return 1;
|
||||
break;
|
||||
case 1:
|
||||
if (mday >= 1 && mday <= (__isleap (year) ? 29 : 28))
|
||||
if (mday >= 1 && mday <= (__time_isleap (year) ? 29 : 28))
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
+5
-2
@@ -17,13 +17,15 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <time.h>
|
||||
#include <time/time-variables.h>
|
||||
#include <time/time-private.h>
|
||||
|
||||
/* Return the `struct tm' representation of *T in UTC,
|
||||
using *TP to store the result. */
|
||||
struct tm *
|
||||
__gmtime_r (const time_t *t, struct tm *tp)
|
||||
{
|
||||
return __tz_convert (t, 0, tp);
|
||||
return __tz_convert (t, /* reentrant */ true, /* localtime */ false, tp);
|
||||
}
|
||||
libc_hidden_def (__gmtime_r)
|
||||
weak_alias (__gmtime_r, gmtime_r)
|
||||
@@ -33,5 +35,6 @@ weak_alias (__gmtime_r, gmtime_r)
|
||||
struct tm *
|
||||
gmtime (const time_t *t)
|
||||
{
|
||||
return __tz_convert (t, 0, &_tmbuf);
|
||||
return __tz_convert (t, /* reentrant */ false, /* localtime */ false,
|
||||
&_tmbuf);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Leap year detection.
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <time.h>
|
||||
|
||||
bool
|
||||
internal_function
|
||||
__time_isleap (int year)
|
||||
{
|
||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||
}
|
||||
libc_hidden_def (__time_isleap)
|
||||
+5
-2
@@ -17,6 +17,8 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <time.h>
|
||||
#include <time/time-variables.h>
|
||||
#include <time/time-private.h>
|
||||
|
||||
/* The C Standard says that localtime and gmtime return the same pointer. */
|
||||
struct tm _tmbuf;
|
||||
@@ -27,7 +29,7 @@ struct tm _tmbuf;
|
||||
struct tm *
|
||||
__localtime_r (const time_t *t, struct tm *tp)
|
||||
{
|
||||
return __tz_convert (t, 1, tp);
|
||||
return __tz_convert (t, /* reentrant */ true, /* localtime */ true, tp);
|
||||
}
|
||||
weak_alias (__localtime_r, localtime_r)
|
||||
|
||||
@@ -36,6 +38,7 @@ weak_alias (__localtime_r, localtime_r)
|
||||
struct tm *
|
||||
localtime (const time_t *t)
|
||||
{
|
||||
return __tz_convert (t, 1, &_tmbuf);
|
||||
return __tz_convert (t, /* reentrant */ false, /* localtime */ true,
|
||||
&_tmbuf);
|
||||
}
|
||||
libc_hidden_def (localtime)
|
||||
|
||||
+2
-2
@@ -57,7 +57,7 @@ __offtime (const time_t *t, long int offset, struct tm *tp)
|
||||
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
|
||||
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
|
||||
|
||||
while (days < 0 || days >= (__isleap (y) ? 366 : 365))
|
||||
while (days < 0 || days >= (__time_isleap (y) ? 366 : 365))
|
||||
{
|
||||
/* Guess a corrected year, assuming 365 days per year. */
|
||||
time_t yg = y + days / 365 - (days % 365 < 0);
|
||||
@@ -76,7 +76,7 @@ __offtime (const time_t *t, long int offset, struct tm *tp)
|
||||
return 0;
|
||||
}
|
||||
tp->tm_yday = days;
|
||||
ip = __mon_yday[__isleap(y)];
|
||||
ip = __mon_yday[__time_isleap (y)];
|
||||
for (y = 11; days < (long int) ip[y]; --y)
|
||||
continue;
|
||||
days -= ip[y];
|
||||
|
||||
+14
-12
@@ -33,28 +33,30 @@
|
||||
# define MULTIBYTE_IS_FORMAT_SAFE 1
|
||||
# define STDC_HEADERS 1
|
||||
# include "../locale/localeinfo.h"
|
||||
#endif
|
||||
|
||||
#if defined emacs && !defined HAVE_BCOPY
|
||||
# define HAVE_MEMCPY 1
|
||||
# define __isleap(year) __time_isleap (year)
|
||||
# include <time.h>
|
||||
# include <time/time-variables.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h> /* Some systems define `time_t' here. */
|
||||
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
#ifndef _LIBC
|
||||
# ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# else
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if HAVE_TZNAME
|
||||
# if HAVE_TZNAME
|
||||
extern char *tzname[];
|
||||
#endif
|
||||
# endif
|
||||
#endif /* !_LIBC */
|
||||
|
||||
/* Do multibyte processing if multibytes are supported, unless
|
||||
multibyte sequences are safe in formats. Multibyte sequences are
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/* Private declarations for the time subsystem.
|
||||
Copyright (C) 1991-2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef TIME_PRIVATE_H
|
||||
#define TIME_PRIVATE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
struct ttinfo
|
||||
{
|
||||
long int offset; /* Seconds east of GMT. */
|
||||
unsigned char isdst; /* Used to set tm_isdst. */
|
||||
unsigned char idx; /* Index into `zone_names'. */
|
||||
unsigned char isstd; /* Transition times are in standard time. */
|
||||
unsigned char isgmt; /* Transition times are in GMT. */
|
||||
};
|
||||
|
||||
struct leap
|
||||
{
|
||||
time_t transition; /* Time the transition takes effect. */
|
||||
long int change; /* Seconds of correction to apply. */
|
||||
};
|
||||
|
||||
/* This structure contains all the information about a
|
||||
timezone given in the POSIX standard TZ envariable. */
|
||||
struct tz_rule
|
||||
{
|
||||
const char *name;
|
||||
|
||||
/* When to change. */
|
||||
enum { J0, J1, M } type; /* Interpretation of: */
|
||||
unsigned short int m, n, d; /* Month, week, day. */
|
||||
int secs; /* Time of day. */
|
||||
|
||||
long int offset; /* Seconds east of GMT (west if < 0). */
|
||||
};
|
||||
|
||||
struct tzdata
|
||||
{
|
||||
/* Updated by tzfile.c. */
|
||||
|
||||
/* Used to recognize unchanged tzdata files. */
|
||||
dev_t tzfile_dev;
|
||||
ino64_t tzfile_ino;
|
||||
time_t tzfile_mtime;
|
||||
|
||||
size_t num_transitions;
|
||||
time_t *transitions;
|
||||
unsigned char *type_idxs;
|
||||
size_t num_types;
|
||||
struct ttinfo *types;
|
||||
char *zone_names;
|
||||
long int rule_stdoff;
|
||||
long int rule_dstoff;
|
||||
size_t num_leaps;
|
||||
struct leap *leaps;
|
||||
char *tzspec;
|
||||
bool use_tzfile;
|
||||
|
||||
/* Updated by tzset.c. */
|
||||
|
||||
/* Used to recognize an unchanged TZ environment variable. */
|
||||
char *old_tz;
|
||||
|
||||
/* tz_rules[0] is standard, tz_rules[1] is daylight. */
|
||||
struct tz_rule tz_rules[2];
|
||||
|
||||
/* The remaining members correspond to the global variables of the
|
||||
same name (with a __ prefix within glibc). */
|
||||
|
||||
bool daylight;
|
||||
int timezone;
|
||||
char *tzname[2];
|
||||
};
|
||||
|
||||
/* Determine the actual location of the timezone file based on FILE.
|
||||
Return a newly allocated string (which the caller should free), and
|
||||
NULL on memory allocation failure. */
|
||||
char *__tzfile_determine_path (const char *file)
|
||||
internal_function attribute_hidden;
|
||||
|
||||
/* Return true if the timezone data in *TZDATA is up-to-date with
|
||||
regards to the modification time of the file at PATH. */
|
||||
bool __tzfile_is_current (const char *path, const struct tzdata *tzdata)
|
||||
internal_function attribute_hidden __nonnull ((1, 2));
|
||||
|
||||
/* Load the timezone data specified by FILE in *TZDATA. All errors
|
||||
result in a tzdata object for the UTC time zone without any leap
|
||||
seconds. */
|
||||
void __tzfile_read (struct tzdata *tzdata, const char *file,
|
||||
size_t extra, char **extrap)
|
||||
internal_function attribute_hidden __nonnull ((1));
|
||||
|
||||
/* Deallocate the data in the struct tzdata object, but not the object
|
||||
itself. */
|
||||
void __tzdata_free (struct tzdata *tzdata)
|
||||
internal_function attribute_hidden __nonnull ((1));
|
||||
|
||||
/* The user specified a hand-made timezone, but not its DST rules. We
|
||||
will use the names and offsets from the user, and the rules from
|
||||
the TZDEFRULES file. */
|
||||
void __tzfile_default (struct tzdata *tzdata,
|
||||
const char *std, const char *dst,
|
||||
long int stdoff, long int dstoff)
|
||||
internal_function attribute_hidden __nonnull ((1, 2, 3));
|
||||
|
||||
/* Parse the POSIX TZ-style string. */
|
||||
void __tzset_parse_tz (struct tzdata *tzdata, const char *tz)
|
||||
internal_function attribute_hidden __nonnull ((1, 2));
|
||||
|
||||
/* Figure out the correct timezone for TM and set TM->tm_zone,
|
||||
TM->tm_isdst, and TM->tm_gmtoff accordingly. */
|
||||
void __tz_compute (const struct tzdata *tzdata,
|
||||
time_t timer, struct tm *tm, int use_localtime)
|
||||
internal_function attribute_hidden __nonnull ((1, 3));
|
||||
|
||||
/* Write the struct tm representation of *TIMER in the local timezone
|
||||
to *TP. Use local time if USE_LOCALTIME, UTC otherwise. If
|
||||
USE_REENTRANT, the global timezone variables are not updated.
|
||||
Return TP. */
|
||||
struct tm *__tz_convert (const time_t *timer, bool use_reentrant,
|
||||
bool use_localtime, struct tm *tp)
|
||||
internal_function attribute_hidden __nonnull ((1, 4));
|
||||
|
||||
extern void __tzfile_compute (const struct tzdata *tzdata,
|
||||
time_t timer, int use_localtime,
|
||||
long int *leap_correct, int *leap_hit,
|
||||
struct tm *tp);
|
||||
internal_function attribute_hidden __nonnull ((1, 4, 5, 6));
|
||||
|
||||
|
||||
#endif /* TIME_PRIVATE_H */
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Global variables used by the time subsystem.
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This header should only be used within the time subsystem, but
|
||||
there are some historic external references. The global variables
|
||||
declared here cannot be accessed in a thread-safe manner. */
|
||||
|
||||
#ifndef TIME_VARIABLES_H
|
||||
#define TIME_VARIABLES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
/* Global variables updated by tzset, localtime. Their counterparts
|
||||
without the __ prefix are weak aliases of them. The static linker
|
||||
will ensure that dynamically-linked programs which do not define
|
||||
their own variable (without the __ prefix) use the variable from
|
||||
glibc (which is updated by the glibc code through the __-prefixed
|
||||
alias). If the application defines its own variable, it will be
|
||||
separate from the glibc variable. */
|
||||
extern char *__tzname[2];
|
||||
extern int __daylight;
|
||||
extern long int __timezone;
|
||||
|
||||
/* Defined in localtime.c. Used by localtime and gmtime. */
|
||||
extern struct tm _tmbuf attribute_hidden;
|
||||
|
||||
#endif /* TIME_VARIABLES_H */
|
||||
+3
-18
@@ -160,16 +160,8 @@ extern char *ctime_r (const time_t *__restrict __timer,
|
||||
char *__restrict __buf) __THROW;
|
||||
#endif /* POSIX */
|
||||
|
||||
|
||||
/* Defined in localtime.c. */
|
||||
extern char *__tzname[2]; /* Current timezone names. */
|
||||
extern int __daylight; /* If daylight-saving time is ever in use. */
|
||||
extern long int __timezone; /* Seconds west of UTC. */
|
||||
|
||||
|
||||
#ifdef __USE_POSIX
|
||||
/* Same as above. */
|
||||
extern char *tzname[2];
|
||||
extern char *tzname[2]; /* Current timezone names. */
|
||||
|
||||
/* Set time conversion information from the TZ environment variable.
|
||||
If TZ is not defined, a locale-dependent default is used. */
|
||||
@@ -177,8 +169,8 @@ extern void tzset (void) __THROW;
|
||||
#endif
|
||||
|
||||
#if defined __USE_MISC || defined __USE_XOPEN
|
||||
extern int daylight;
|
||||
extern long int timezone;
|
||||
extern int daylight; /* If daylight-saving time is ever in use. */
|
||||
extern long int timezone; /* Seconds west of UTC. */
|
||||
#endif
|
||||
|
||||
#ifdef __USE_MISC
|
||||
@@ -187,13 +179,6 @@ extern long int timezone;
|
||||
extern int stime (const time_t *__when) __THROW;
|
||||
#endif
|
||||
|
||||
|
||||
/* Nonzero if YEAR is a leap year (every 4 years,
|
||||
except every 100th isn't, and every 400th is). */
|
||||
#define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||||
|
||||
|
||||
#ifdef __USE_MISC
|
||||
/* Miscellaneous functions many Unices inherited from the public domain
|
||||
localtime package. These are included only for compatibility. */
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Test leap year processing.
|
||||
Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <time.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
TEST_VERIFY (!__time_isleap (-100));
|
||||
TEST_VERIFY (__time_isleap (0));
|
||||
TEST_VERIFY (!__time_isleap (100));
|
||||
TEST_VERIFY (!__time_isleap (200));
|
||||
TEST_VERIFY (!__time_isleap (300));
|
||||
TEST_VERIFY (__time_isleap (400));
|
||||
TEST_VERIFY (!__time_isleap (1900));
|
||||
TEST_VERIFY (__time_isleap (1996));
|
||||
TEST_VERIFY (__time_isleap (2000));
|
||||
TEST_VERIFY (__time_isleap (2004));
|
||||
TEST_VERIFY (__time_isleap (2008));
|
||||
TEST_VERIFY (!__time_isleap (2100));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
+248
-243
@@ -26,40 +26,9 @@
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <time/time-private.h>
|
||||
#include <timezone/tzfile.h>
|
||||
|
||||
int __use_tzfile;
|
||||
static dev_t tzfile_dev;
|
||||
static ino64_t tzfile_ino;
|
||||
static time_t tzfile_mtime;
|
||||
|
||||
struct ttinfo
|
||||
{
|
||||
long int offset; /* Seconds east of GMT. */
|
||||
unsigned char isdst; /* Used to set tm_isdst. */
|
||||
unsigned char idx; /* Index into `zone_names'. */
|
||||
unsigned char isstd; /* Transition times are in standard time. */
|
||||
unsigned char isgmt; /* Transition times are in GMT. */
|
||||
};
|
||||
|
||||
struct leap
|
||||
{
|
||||
time_t transition; /* Time the transition takes effect. */
|
||||
long int change; /* Seconds of correction to apply. */
|
||||
};
|
||||
|
||||
static size_t num_transitions;
|
||||
libc_freeres_ptr (static time_t *transitions);
|
||||
static unsigned char *type_idxs;
|
||||
static size_t num_types;
|
||||
static struct ttinfo *types;
|
||||
static char *zone_names;
|
||||
static long int rule_stdoff;
|
||||
static long int rule_dstoff;
|
||||
static size_t num_leaps;
|
||||
static struct leap *leaps;
|
||||
static char *tzspec;
|
||||
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
|
||||
@@ -95,35 +64,17 @@ decode64 (const void *ptr)
|
||||
return bswap_64 (*(const int64_t *) ptr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
char *
|
||||
internal_function
|
||||
__tzfile_determine_path (const char *file)
|
||||
{
|
||||
static const char default_tzdir[] = TZDIR;
|
||||
size_t num_isstd, num_isgmt;
|
||||
FILE *f;
|
||||
struct tzhead tzhead;
|
||||
size_t chars;
|
||||
size_t i;
|
||||
size_t total_size;
|
||||
size_t types_idx;
|
||||
size_t leaps_idx;
|
||||
int was_using_tzfile = __use_tzfile;
|
||||
int trans_width = 4;
|
||||
size_t tzspec_len;
|
||||
char *new = NULL;
|
||||
|
||||
if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
|
||||
abort ();
|
||||
|
||||
__use_tzfile = 0;
|
||||
|
||||
if (file == NULL)
|
||||
/* No user specification; use the site-wide default. */
|
||||
file = TZDEFAULT;
|
||||
else if (*file == '\0')
|
||||
/* User specified the empty string; use UTC with no leap seconds. */
|
||||
goto ret_free_transitions;
|
||||
;
|
||||
else
|
||||
{
|
||||
/* We must not allow to read an arbitrary file in a setuid
|
||||
@@ -137,7 +88,7 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
|| strstr (file, "../") != NULL))
|
||||
/* This test is certainly a bit too restrictive but it should
|
||||
catch all critical cases. */
|
||||
goto ret_free_transitions;
|
||||
file = ""; /* Use UTC. */
|
||||
}
|
||||
|
||||
if (*file != '/')
|
||||
@@ -147,18 +98,45 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
tzdir = getenv ("TZDIR");
|
||||
if (tzdir == NULL || *tzdir == '\0')
|
||||
tzdir = default_tzdir;
|
||||
char *new;
|
||||
if (__asprintf (&new, "%s/%s", tzdir, file) == -1)
|
||||
goto ret_free_transitions;
|
||||
file = new;
|
||||
return NULL;
|
||||
return new;
|
||||
}
|
||||
|
||||
return strdup (file);
|
||||
}
|
||||
|
||||
bool
|
||||
internal_function
|
||||
__tzfile_is_current (const char *path, const struct tzdata *tzdata)
|
||||
{
|
||||
/* If we were already using tzfile, check whether the file changed. */
|
||||
struct stat64 st;
|
||||
if (was_using_tzfile
|
||||
&& stat64 (file, &st) == 0
|
||||
&& tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
|
||||
&& tzfile_mtime == st.st_mtime)
|
||||
goto done; /* Nothing to do. */
|
||||
return tzdata->use_tzfile
|
||||
&& stat64 (path, &st) == 0
|
||||
&& tzdata->tzfile_ino == st.st_ino
|
||||
&& tzdata->tzfile_dev == st.st_dev
|
||||
&& tzdata->tzfile_mtime == st.st_mtime;
|
||||
}
|
||||
|
||||
void
|
||||
internal_function
|
||||
__tzfile_read (struct tzdata *tzdata, const char *file,
|
||||
size_t extra, char **extrap)
|
||||
{
|
||||
size_t num_isstd, num_isgmt;
|
||||
FILE *f;
|
||||
struct tzhead tzhead;
|
||||
size_t chars;
|
||||
size_t i;
|
||||
size_t total_size;
|
||||
size_t types_idx;
|
||||
size_t leaps_idx;
|
||||
int trans_width = 4;
|
||||
size_t tzspec_len;
|
||||
|
||||
tzdata->use_tzfile = false;
|
||||
|
||||
/* Note the file is opened with cancellation in the I/O functions
|
||||
disabled and if available FD_CLOEXEC set. */
|
||||
@@ -167,19 +145,20 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
goto ret_free_transitions;
|
||||
|
||||
/* Get information about the file we are actually using. */
|
||||
struct stat64 st;
|
||||
if (fstat64 (__fileno (f), &st) != 0)
|
||||
{
|
||||
fclose (f);
|
||||
goto ret_free_transitions;
|
||||
}
|
||||
|
||||
free ((void *) transitions);
|
||||
transitions = NULL;
|
||||
free (tzdata->transitions);
|
||||
tzdata->transitions = NULL;
|
||||
|
||||
/* Remember the inode and device number and modification time. */
|
||||
tzfile_dev = st.st_dev;
|
||||
tzfile_ino = st.st_ino;
|
||||
tzfile_mtime = st.st_mtime;
|
||||
tzdata->tzfile_dev = st.st_dev;
|
||||
tzdata->tzfile_ino = st.st_ino;
|
||||
tzdata->tzfile_mtime = st.st_mtime;
|
||||
|
||||
/* No threads reading this stream. */
|
||||
__fsetlocking (f, FSETLOCKING_BYCALLER);
|
||||
@@ -190,14 +169,15 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
|| memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
|
||||
goto lose;
|
||||
|
||||
num_transitions = (size_t) decode (tzhead.tzh_timecnt);
|
||||
num_types = (size_t) decode (tzhead.tzh_typecnt);
|
||||
tzdata->num_transitions = (size_t) decode (tzhead.tzh_timecnt);
|
||||
tzdata->num_types = (size_t) decode (tzhead.tzh_typecnt);
|
||||
chars = (size_t) decode (tzhead.tzh_charcnt);
|
||||
num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
|
||||
tzdata->num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
|
||||
num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
|
||||
num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
|
||||
|
||||
if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
|
||||
if (__glibc_unlikely (num_isstd > tzdata->num_types
|
||||
|| num_isgmt > tzdata->num_types))
|
||||
goto lose;
|
||||
|
||||
/* For platforms with 64-bit time_t we use the new format if available. */
|
||||
@@ -208,10 +188,10 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
trans_width = 8;
|
||||
|
||||
/* Position the stream before the second header. */
|
||||
size_t to_skip = (num_transitions * (4 + 1)
|
||||
+ num_types * 6
|
||||
size_t to_skip = (tzdata->num_transitions * (4 + 1)
|
||||
+ tzdata->num_types * 6
|
||||
+ chars
|
||||
+ num_leaps * 8
|
||||
+ tzdata->num_leaps * 8
|
||||
+ num_isstd
|
||||
+ num_isgmt);
|
||||
if (fseek (f, to_skip, SEEK_CUR) != 0)
|
||||
@@ -220,18 +200,18 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
goto read_again;
|
||||
}
|
||||
|
||||
if (__builtin_expect (num_transitions
|
||||
if (__builtin_expect (tzdata->num_transitions
|
||||
> ((SIZE_MAX - (__alignof__ (struct ttinfo) - 1))
|
||||
/ (sizeof (time_t) + 1)), 0))
|
||||
goto lose;
|
||||
total_size = num_transitions * (sizeof (time_t) + 1);
|
||||
total_size = tzdata->num_transitions * (sizeof (time_t) + 1);
|
||||
total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
|
||||
& ~(__alignof__ (struct ttinfo) - 1));
|
||||
types_idx = total_size;
|
||||
if (__builtin_expect (num_types
|
||||
if (__builtin_expect (tzdata->num_types
|
||||
> (SIZE_MAX - total_size) / sizeof (struct ttinfo), 0))
|
||||
goto lose;
|
||||
total_size += num_types * sizeof (struct ttinfo);
|
||||
total_size += tzdata->num_types * sizeof (struct ttinfo);
|
||||
if (__glibc_unlikely (chars > SIZE_MAX - total_size))
|
||||
goto lose;
|
||||
total_size += chars;
|
||||
@@ -241,26 +221,26 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
total_size = ((total_size + __alignof__ (struct leap) - 1)
|
||||
& ~(__alignof__ (struct leap) - 1));
|
||||
leaps_idx = total_size;
|
||||
if (__builtin_expect (num_leaps
|
||||
if (__builtin_expect (tzdata->num_leaps
|
||||
> (SIZE_MAX - total_size) / sizeof (struct leap), 0))
|
||||
goto lose;
|
||||
total_size += num_leaps * sizeof (struct leap);
|
||||
total_size += tzdata->num_leaps * sizeof (struct leap);
|
||||
tzspec_len = 0;
|
||||
if (sizeof (time_t) == 8 && trans_width == 8)
|
||||
{
|
||||
off_t rem = st.st_size - __ftello (f);
|
||||
if (__builtin_expect (rem < 0
|
||||
|| (size_t) rem < (num_transitions * (8 + 1)
|
||||
+ num_types * 6
|
||||
|| (size_t) rem < (tzdata->num_transitions * (8 + 1)
|
||||
+ tzdata->num_types * 6
|
||||
+ chars), 0))
|
||||
goto lose;
|
||||
tzspec_len = (size_t) rem - (num_transitions * (8 + 1)
|
||||
+ num_types * 6
|
||||
tzspec_len = (size_t) rem - (tzdata->num_transitions * (8 + 1)
|
||||
+ tzdata->num_types * 6
|
||||
+ chars);
|
||||
if (__builtin_expect (num_leaps > SIZE_MAX / 12
|
||||
|| tzspec_len < num_leaps * 12, 0))
|
||||
if (__builtin_expect (tzdata->num_leaps > SIZE_MAX / 12
|
||||
|| tzspec_len < tzdata->num_leaps * 12, 0))
|
||||
goto lose;
|
||||
tzspec_len -= num_leaps * 12;
|
||||
tzspec_len -= tzdata->num_leaps * 12;
|
||||
if (__glibc_unlikely (tzspec_len < num_isstd))
|
||||
goto lose;
|
||||
tzspec_len -= num_isstd;
|
||||
@@ -276,43 +256,47 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
|
||||
/* Allocate enough memory including the extra block requested by the
|
||||
caller. */
|
||||
transitions = (time_t *) malloc (total_size + tzspec_len + extra);
|
||||
if (transitions == NULL)
|
||||
tzdata->transitions = (time_t *) malloc (total_size + tzspec_len + extra);
|
||||
if (tzdata->transitions == NULL)
|
||||
goto lose;
|
||||
|
||||
type_idxs = (unsigned char *) transitions + (num_transitions
|
||||
* sizeof (time_t));
|
||||
types = (struct ttinfo *) ((char *) transitions + types_idx);
|
||||
zone_names = (char *) types + num_types * sizeof (struct ttinfo);
|
||||
leaps = (struct leap *) ((char *) transitions + leaps_idx);
|
||||
tzdata->type_idxs = (unsigned char *) tzdata->transitions
|
||||
+ (tzdata->num_transitions * sizeof (time_t));
|
||||
tzdata->types = (struct ttinfo *) ((char *) tzdata->transitions + types_idx);
|
||||
tzdata->zone_names = (char *) tzdata->types
|
||||
+ tzdata->num_types * sizeof (struct ttinfo);
|
||||
tzdata->leaps = (struct leap *) ((char *) tzdata->transitions + leaps_idx);
|
||||
if (sizeof (time_t) == 8 && trans_width == 8)
|
||||
tzspec = (char *) leaps + num_leaps * sizeof (struct leap) + extra;
|
||||
tzdata->tzspec = (char *) tzdata->leaps
|
||||
+ tzdata->num_leaps * sizeof (struct leap) + extra;
|
||||
else
|
||||
tzspec = NULL;
|
||||
tzdata->tzspec = NULL;
|
||||
if (extra > 0)
|
||||
*extrap = (char *) &leaps[num_leaps];
|
||||
*extrap = (char *) &tzdata->leaps[tzdata->num_leaps];
|
||||
|
||||
if (sizeof (time_t) == 4 || __builtin_expect (trans_width == 8, 1))
|
||||
{
|
||||
if (__builtin_expect (__fread_unlocked (transitions, trans_width + 1,
|
||||
num_transitions, f)
|
||||
!= num_transitions, 0))
|
||||
if (__builtin_expect (__fread_unlocked
|
||||
(tzdata->transitions, trans_width + 1,
|
||||
tzdata->num_transitions, f)
|
||||
!= tzdata->num_transitions, 0))
|
||||
goto lose;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (__builtin_expect (__fread_unlocked (transitions, 4,
|
||||
num_transitions, f)
|
||||
!= num_transitions, 0)
|
||||
|| __builtin_expect (__fread_unlocked (type_idxs, 1, num_transitions,
|
||||
f) != num_transitions, 0))
|
||||
if (__builtin_expect (__fread_unlocked (tzdata->transitions, 4,
|
||||
tzdata->num_transitions, f)
|
||||
!= tzdata->num_transitions, 0)
|
||||
|| __builtin_expect (__fread_unlocked
|
||||
(tzdata->type_idxs, 1, tzdata->num_transitions,
|
||||
f) != tzdata->num_transitions, 0))
|
||||
goto lose;
|
||||
}
|
||||
|
||||
/* Check for bogus indices in the data file, so we can hereafter
|
||||
safely use type_idxs[T] as indices into `types' and never crash. */
|
||||
for (i = 0; i < num_transitions; ++i)
|
||||
if (__glibc_unlikely (type_idxs[i] >= num_types))
|
||||
for (i = 0; i < tzdata->num_transitions; ++i)
|
||||
if (__glibc_unlikely (tzdata->type_idxs[i] >= tzdata->num_types))
|
||||
goto lose;
|
||||
|
||||
if ((BYTE_ORDER != BIG_ENDIAN && (sizeof (time_t) == 4 || trans_width == 4))
|
||||
@@ -323,19 +307,20 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
network (big-endian) byte order. We work from the end of
|
||||
the array so as not to clobber the next element to be
|
||||
processed when sizeof (time_t) > 4. */
|
||||
i = num_transitions;
|
||||
i = tzdata->num_transitions;
|
||||
while (i-- > 0)
|
||||
transitions[i] = decode ((char *) transitions + i * 4);
|
||||
tzdata->transitions[i] = decode ((char *) tzdata->transitions + i * 4);
|
||||
}
|
||||
else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8)
|
||||
{
|
||||
/* Decode the transition times, stored as 8-byte integers in
|
||||
network (big-endian) byte order. */
|
||||
for (i = 0; i < num_transitions; ++i)
|
||||
transitions[i] = decode64 ((char *) transitions + i * 8);
|
||||
for (i = 0; i < tzdata->num_transitions; ++i)
|
||||
tzdata->transitions[i]
|
||||
= decode64 ((char *) tzdata->transitions + i * 8);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_types; ++i)
|
||||
for (i = 0; i < tzdata->num_types; ++i)
|
||||
{
|
||||
unsigned char x[4];
|
||||
int c;
|
||||
@@ -346,32 +331,33 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
c = getc_unlocked (f);
|
||||
if (__glibc_unlikely ((unsigned int) c > 1u))
|
||||
goto lose;
|
||||
types[i].isdst = c;
|
||||
tzdata->types[i].isdst = c;
|
||||
c = getc_unlocked (f);
|
||||
if (__glibc_unlikely ((size_t) c > chars))
|
||||
/* Bogus index in data file. */
|
||||
goto lose;
|
||||
types[i].idx = c;
|
||||
types[i].offset = (long int) decode (x);
|
||||
tzdata->types[i].idx = c;
|
||||
tzdata->types[i].offset = (long int) decode (x);
|
||||
}
|
||||
|
||||
if (__glibc_unlikely (__fread_unlocked (zone_names, 1, chars, f) != chars))
|
||||
if (__glibc_unlikely (__fread_unlocked (tzdata->zone_names, 1, chars, f)
|
||||
!= chars))
|
||||
goto lose;
|
||||
|
||||
for (i = 0; i < num_leaps; ++i)
|
||||
for (i = 0; i < tzdata->num_leaps; ++i)
|
||||
{
|
||||
unsigned char x[8];
|
||||
if (__builtin_expect (__fread_unlocked (x, 1, trans_width, f)
|
||||
!= trans_width, 0))
|
||||
goto lose;
|
||||
if (sizeof (time_t) == 4 || trans_width == 4)
|
||||
leaps[i].transition = (time_t) decode (x);
|
||||
tzdata->leaps[i].transition = (time_t) decode (x);
|
||||
else
|
||||
leaps[i].transition = (time_t) decode64 (x);
|
||||
tzdata->leaps[i].transition = (time_t) decode64 (x);
|
||||
|
||||
if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4))
|
||||
goto lose;
|
||||
leaps[i].change = (long int) decode (x);
|
||||
tzdata->leaps[i].change = (long int) decode (x);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_isstd; ++i)
|
||||
@@ -379,31 +365,31 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
int c = getc_unlocked (f);
|
||||
if (__glibc_unlikely (c == EOF))
|
||||
goto lose;
|
||||
types[i].isstd = c != 0;
|
||||
tzdata->types[i].isstd = c != 0;
|
||||
}
|
||||
while (i < num_types)
|
||||
types[i++].isstd = 0;
|
||||
while (i < tzdata->num_types)
|
||||
tzdata->types[i++].isstd = 0;
|
||||
|
||||
for (i = 0; i < num_isgmt; ++i)
|
||||
{
|
||||
int c = getc_unlocked (f);
|
||||
if (__glibc_unlikely (c == EOF))
|
||||
goto lose;
|
||||
types[i].isgmt = c != 0;
|
||||
tzdata->types[i].isgmt = c != 0;
|
||||
}
|
||||
while (i < num_types)
|
||||
types[i++].isgmt = 0;
|
||||
while (i < tzdata->num_types)
|
||||
tzdata->types[i++].isgmt = 0;
|
||||
|
||||
/* Read the POSIX TZ-style information if possible. */
|
||||
if (sizeof (time_t) == 8 && tzspec != NULL)
|
||||
if (sizeof (time_t) == 8 && tzdata->tzspec != NULL)
|
||||
{
|
||||
/* Skip over the newline first. */
|
||||
if (getc_unlocked (f) != '\n'
|
||||
|| (__fread_unlocked (tzspec, 1, tzspec_len - 1, f)
|
||||
|| (__fread_unlocked (tzdata->tzspec, 1, tzspec_len - 1, f)
|
||||
!= tzspec_len - 1))
|
||||
tzspec = NULL;
|
||||
tzdata->tzspec = NULL;
|
||||
else
|
||||
tzspec[tzspec_len - 1] = '\0';
|
||||
tzdata->tzspec[tzspec_len - 1] = '\0';
|
||||
}
|
||||
else if (sizeof (time_t) == 4 && tzhead.tzh_version[0] != '\0')
|
||||
{
|
||||
@@ -448,69 +434,69 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
goto lose;
|
||||
}
|
||||
tzstr[tzspec_len - 1] = '\0';
|
||||
tzspec = __tzstring (tzstr);
|
||||
tzdata->tzspec = __tzstring (tzstr);
|
||||
free (tzstr);
|
||||
}
|
||||
|
||||
/* Don't use an empty TZ string. */
|
||||
if (tzspec != NULL && tzspec[0] == '\0')
|
||||
tzspec = NULL;
|
||||
if (tzdata->tzspec != NULL && tzdata->tzspec[0] == '\0')
|
||||
tzdata->tzspec = NULL;
|
||||
|
||||
fclose (f);
|
||||
|
||||
/* First "register" all timezone names. */
|
||||
for (i = 0; i < num_types; ++i)
|
||||
(void) __tzstring (&zone_names[types[i].idx]);
|
||||
for (i = 0; i < tzdata->num_types; ++i)
|
||||
(void) __tzstring (&tzdata->zone_names[tzdata->types[i].idx]);
|
||||
|
||||
/* Find the standard and daylight time offsets used by the rule file.
|
||||
We choose the offsets in the types of each flavor that are
|
||||
transitioned to earliest in time. */
|
||||
__tzname[0] = NULL;
|
||||
__tzname[1] = NULL;
|
||||
for (i = num_transitions; i > 0; )
|
||||
tzdata->tzname[0] = NULL;
|
||||
tzdata->tzname[1] = NULL;
|
||||
for (i = tzdata->num_transitions; i > 0; )
|
||||
{
|
||||
int type = type_idxs[--i];
|
||||
int dst = types[type].isdst;
|
||||
int type = tzdata->type_idxs[--i];
|
||||
int dst = tzdata->types[type].isdst;
|
||||
|
||||
if (__tzname[dst] == NULL)
|
||||
if (tzdata->tzname[dst] == NULL)
|
||||
{
|
||||
int idx = types[type].idx;
|
||||
int idx = tzdata->types[type].idx;
|
||||
|
||||
__tzname[dst] = __tzstring (&zone_names[idx]);
|
||||
tzdata->tzname[dst] = __tzstring (&tzdata->zone_names[idx]);
|
||||
|
||||
if (__tzname[1 - dst] != NULL)
|
||||
if (tzdata->tzname[1 - dst] != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (__tzname[0] == NULL)
|
||||
if (tzdata->tzname[0] == NULL)
|
||||
{
|
||||
/* This should only happen if there are no transition rules.
|
||||
In this case there should be only one single type. */
|
||||
assert (num_types == 1);
|
||||
__tzname[0] = __tzstring (zone_names);
|
||||
assert (tzdata->num_types == 1);
|
||||
tzdata->tzname[0] = __tzstring (tzdata->zone_names);
|
||||
}
|
||||
if (__tzname[1] == NULL)
|
||||
__tzname[1] = __tzname[0];
|
||||
if (tzdata->tzname[1] == NULL)
|
||||
tzdata->tzname[1] = tzdata->tzname[0];
|
||||
|
||||
if (num_transitions == 0)
|
||||
if (tzdata->num_transitions == 0)
|
||||
/* Use the first rule (which should also be the only one). */
|
||||
rule_stdoff = rule_dstoff = types[0].offset;
|
||||
tzdata->rule_stdoff = tzdata->rule_dstoff = tzdata->types[0].offset;
|
||||
else
|
||||
{
|
||||
int stdoff_set = 0, dstoff_set = 0;
|
||||
rule_stdoff = rule_dstoff = 0;
|
||||
i = num_transitions - 1;
|
||||
tzdata->rule_stdoff = tzdata->rule_dstoff = 0;
|
||||
i = tzdata->num_transitions - 1;
|
||||
do
|
||||
{
|
||||
if (!stdoff_set && !types[type_idxs[i]].isdst)
|
||||
if (!stdoff_set && !tzdata->types[tzdata->type_idxs[i]].isdst)
|
||||
{
|
||||
stdoff_set = 1;
|
||||
rule_stdoff = types[type_idxs[i]].offset;
|
||||
tzdata->rule_stdoff = tzdata->types[tzdata->type_idxs[i]].offset;
|
||||
}
|
||||
else if (!dstoff_set && types[type_idxs[i]].isdst)
|
||||
else if (!dstoff_set && tzdata->types[tzdata->type_idxs[i]].isdst)
|
||||
{
|
||||
dstoff_set = 1;
|
||||
rule_dstoff = types[type_idxs[i]].offset;
|
||||
tzdata->rule_dstoff = tzdata->types[tzdata->type_idxs[i]].offset;
|
||||
}
|
||||
if (stdoff_set && dstoff_set)
|
||||
break;
|
||||
@@ -518,31 +504,28 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
|
||||
while (i-- > 0);
|
||||
|
||||
if (!dstoff_set)
|
||||
rule_dstoff = rule_stdoff;
|
||||
tzdata->rule_dstoff = tzdata->rule_stdoff;
|
||||
}
|
||||
|
||||
__daylight = rule_stdoff != rule_dstoff;
|
||||
__timezone = -rule_stdoff;
|
||||
|
||||
done:
|
||||
__use_tzfile = 1;
|
||||
free (new);
|
||||
tzdata->daylight = tzdata->rule_stdoff != tzdata->rule_dstoff;
|
||||
tzdata->timezone = -tzdata->rule_stdoff;
|
||||
tzdata->use_tzfile = true;
|
||||
return;
|
||||
|
||||
lose:
|
||||
fclose (f);
|
||||
ret_free_transitions:
|
||||
free (new);
|
||||
free ((void *) transitions);
|
||||
transitions = NULL;
|
||||
free (tzdata->transitions);
|
||||
tzdata->transitions = NULL;
|
||||
}
|
||||
|
||||
/* The user specified a hand-made timezone, but not its DST rules.
|
||||
We will use the names and offsets from the user, and the rules
|
||||
from the TZDEFRULES file. */
|
||||
|
||||
void
|
||||
__tzfile_default (const char *std, const char *dst,
|
||||
internal_function
|
||||
__tzfile_default (struct tzdata *tzdata,
|
||||
const char *std, const char *dst,
|
||||
long int stdoff, long int dstoff)
|
||||
{
|
||||
size_t stdlen = strlen (std) + 1;
|
||||
@@ -551,35 +534,39 @@ __tzfile_default (const char *std, const char *dst,
|
||||
int isdst;
|
||||
char *cp;
|
||||
|
||||
__tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
|
||||
if (!__use_tzfile)
|
||||
__tzfile_read (tzdata, TZDEFRULES, stdlen + dstlen, &cp);
|
||||
if (!tzdata->use_tzfile)
|
||||
return;
|
||||
|
||||
if (num_types < 2)
|
||||
if (tzdata->num_types < 2)
|
||||
{
|
||||
__use_tzfile = 0;
|
||||
tzdata->use_tzfile = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore the zone names read from the file and use the given ones
|
||||
instead. */
|
||||
__mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
|
||||
zone_names = cp;
|
||||
tzdata->zone_names = cp;
|
||||
|
||||
/* Now there are only two zones, regardless of what the file contained. */
|
||||
num_types = 2;
|
||||
tzdata->num_types = 2;
|
||||
|
||||
/* Reset the zone names to point to the user's names. */
|
||||
tzdata->tzname[0] = tzdata->zone_names;
|
||||
tzdata->tzname[1] = tzdata->zone_names + stdlen;
|
||||
|
||||
/* Now correct the transition times for the user-specified standard and
|
||||
daylight offsets from GMT. */
|
||||
isdst = 0;
|
||||
for (i = 0; i < num_transitions; ++i)
|
||||
for (i = 0; i < tzdata->num_transitions; ++i)
|
||||
{
|
||||
struct ttinfo *trans_type = &types[type_idxs[i]];
|
||||
struct ttinfo *trans_type = &tzdata->types[tzdata->type_idxs[i]];
|
||||
|
||||
/* We will use only types 0 (standard) and 1 (daylight).
|
||||
Fix up this transition to point to whichever matches
|
||||
the flavor of its original type. */
|
||||
type_idxs[i] = trans_type->isdst;
|
||||
tzdata->type_idxs[i] = trans_type->isdst;
|
||||
|
||||
if (trans_type->isgmt)
|
||||
/* The transition time is in GMT. No correction to apply. */ ;
|
||||
@@ -588,13 +575,13 @@ __tzfile_default (const char *std, const char *dst,
|
||||
wall clock time as of the previous transition was DST. Correct
|
||||
for the difference between the rule's DST offset and the user's
|
||||
DST offset. */
|
||||
transitions[i] += dstoff - rule_dstoff;
|
||||
tzdata->transitions[i] += dstoff - tzdata->rule_dstoff;
|
||||
else
|
||||
/* This transition is in "local wall clock time", and wall clock
|
||||
time as of this iteration is non-DST. Correct for the
|
||||
difference between the rule's standard offset and the user's
|
||||
standard offset. */
|
||||
transitions[i] += stdoff - rule_stdoff;
|
||||
tzdata->transitions[i] += stdoff - tzdata->rule_stdoff;
|
||||
|
||||
/* The DST state of "local wall clock time" for the next iteration is
|
||||
as specified by this transition. */
|
||||
@@ -604,33 +591,30 @@ __tzfile_default (const char *std, const char *dst,
|
||||
/* Now that we adjusted the transitions to the requested offsets,
|
||||
reset the rule_stdoff and rule_dstoff values appropriately. They
|
||||
are used elsewhere. */
|
||||
rule_stdoff = stdoff;
|
||||
rule_dstoff = dstoff;
|
||||
tzdata->rule_stdoff = stdoff;
|
||||
tzdata->rule_dstoff = dstoff;
|
||||
|
||||
/* Reset types 0 and 1 to describe the user's settings. */
|
||||
types[0].idx = 0;
|
||||
types[0].offset = stdoff;
|
||||
types[0].isdst = 0;
|
||||
types[1].idx = stdlen;
|
||||
types[1].offset = dstoff;
|
||||
types[1].isdst = 1;
|
||||
|
||||
/* Reset the zone names to point to the user's names. */
|
||||
__tzname[0] = (char *) std;
|
||||
__tzname[1] = (char *) dst;
|
||||
tzdata->types[0].idx = 0;
|
||||
tzdata->types[0].offset = stdoff;
|
||||
tzdata->types[0].isdst = 0;
|
||||
tzdata->types[1].idx = stdlen;
|
||||
tzdata->types[1].offset = dstoff;
|
||||
tzdata->types[1].isdst = 1;
|
||||
|
||||
/* Set the timezone. */
|
||||
__timezone = -types[0].offset;
|
||||
__timezone = -tzdata->types[0].offset;
|
||||
|
||||
/* Invalidate the tzfile attribute cache to force rereading
|
||||
TZDEFRULES the next time it is used. */
|
||||
tzfile_dev = 0;
|
||||
tzfile_ino = 0;
|
||||
tzfile_mtime = 0;
|
||||
tzdata->tzfile_dev = 0;
|
||||
tzdata->tzfile_ino = 0;
|
||||
tzdata->tzfile_mtime = 0;
|
||||
}
|
||||
|
||||
void
|
||||
__tzfile_compute (time_t timer, int use_localtime,
|
||||
internal_function
|
||||
__tzfile_compute (const struct tzdata *tzdata, time_t timer, int use_localtime,
|
||||
long int *leap_correct, int *leap_hit,
|
||||
struct tm *tp)
|
||||
{
|
||||
@@ -641,30 +625,34 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
__tzname[0] = NULL;
|
||||
__tzname[1] = NULL;
|
||||
|
||||
if (__glibc_unlikely (num_transitions == 0 || timer < transitions[0]))
|
||||
if (__glibc_unlikely (tzdata->num_transitions == 0
|
||||
|| timer < tzdata->transitions[0]))
|
||||
{
|
||||
/* TIMER is before any transition (or there are no transitions).
|
||||
Choose the first non-DST type
|
||||
(or the first if they're all DST types). */
|
||||
i = 0;
|
||||
while (i < num_types && types[i].isdst)
|
||||
while (i < tzdata->num_types && tzdata->types[i].isdst)
|
||||
{
|
||||
if (__tzname[1] == NULL)
|
||||
__tzname[1] = __tzstring (&zone_names[types[i].idx]);
|
||||
__tzname[1] = __tzstring
|
||||
(&tzdata->zone_names[tzdata->types[i].idx]);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (i == num_types)
|
||||
if (i == tzdata->num_types)
|
||||
i = 0;
|
||||
__tzname[0] = __tzstring (&zone_names[types[i].idx]);
|
||||
__tzname[0] = __tzstring
|
||||
(&tzdata->zone_names[tzdata->types[i].idx]);
|
||||
if (__tzname[1] == NULL)
|
||||
{
|
||||
size_t j = i;
|
||||
while (j < num_types)
|
||||
if (types[j].isdst)
|
||||
while (j < tzdata->num_types)
|
||||
if (tzdata->types[j].isdst)
|
||||
{
|
||||
__tzname[1] = __tzstring (&zone_names[types[j].idx]);
|
||||
__tzname[1] = __tzstring
|
||||
(&tzdata->zone_names[tzdata->types[j].idx]);
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -673,7 +661,7 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
}
|
||||
else if (__glibc_unlikely (timer >= transitions[num_transitions - 1]))
|
||||
{
|
||||
if (__glibc_unlikely (tzspec == NULL))
|
||||
if (__glibc_unlikely (tzdata->tzspec == NULL))
|
||||
{
|
||||
use_last:
|
||||
i = num_transitions;
|
||||
@@ -681,7 +669,7 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
}
|
||||
|
||||
/* Parse the POSIX TZ-style string. */
|
||||
__tzset_parse_tz (tzspec);
|
||||
__tzset_parse_tz (tzdata, tzdata->tzspec);
|
||||
|
||||
/* Convert to broken down structure. If this fails do not
|
||||
use the string. */
|
||||
@@ -689,16 +677,18 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
goto use_last;
|
||||
|
||||
/* Use the rules from the TZ string to compute the change. */
|
||||
__tz_compute (timer, tp, 1);
|
||||
__tz_compute (tzdata, timer, tp, 1);
|
||||
|
||||
/* If tzspec comes from posixrules loaded by __tzfile_default,
|
||||
override the STD and DST zone names with the ones user
|
||||
requested in TZ envvar. */
|
||||
if (__glibc_unlikely (zone_names == (char *) &leaps[num_leaps]))
|
||||
if (__glibc_unlikely (tzdata->zone_names
|
||||
== (char *) &tzdata->leaps[tzdata->num_leaps]))
|
||||
{
|
||||
assert (num_types == 2);
|
||||
__tzname[0] = __tzstring (zone_names);
|
||||
__tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
|
||||
assert (tzdata->num_types == 2);
|
||||
__tzname[0] = __tzstring (tzdata->zone_names);
|
||||
__tzname[1] = __tzstring
|
||||
(&tzdata->zone_names[strlen (tzdata->zone_names) + 1]);
|
||||
}
|
||||
|
||||
goto leap;
|
||||
@@ -708,21 +698,22 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
/* Find the first transition after TIMER, and
|
||||
then pick the type of the transition before it. */
|
||||
size_t lo = 0;
|
||||
size_t hi = num_transitions - 1;
|
||||
size_t hi = tzdata->num_transitions - 1;
|
||||
/* Assume that DST is changing twice a year and guess initial
|
||||
search spot from it.
|
||||
Half of a gregorian year has on average 365.2425 * 86400 / 2
|
||||
= 15778476 seconds. */
|
||||
i = (transitions[num_transitions - 1] - timer) / 15778476;
|
||||
if (i < num_transitions)
|
||||
i = (tzdata->transitions[tzdata->num_transitions - 1] - timer)
|
||||
/ 15778476;
|
||||
if (i < tzdata->num_transitions)
|
||||
{
|
||||
i = num_transitions - 1 - i;
|
||||
if (timer < transitions[i])
|
||||
if (timer < tzdata->transitions[i])
|
||||
{
|
||||
if (i < 10 || timer >= transitions[i - 10])
|
||||
if (i < 10 || timer >= tzdata->transitions[i - 10])
|
||||
{
|
||||
/* Linear search. */
|
||||
while (timer < transitions[i - 1])
|
||||
while (timer < tzdata->transitions[i - 1])
|
||||
--i;
|
||||
goto found;
|
||||
}
|
||||
@@ -730,10 +721,11 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i + 10 >= num_transitions || timer < transitions[i + 10])
|
||||
if (i + 10 >= tzdata->num_transitions
|
||||
|| timer < tzdata->transitions[i + 10])
|
||||
{
|
||||
/* Linear search. */
|
||||
while (timer >= transitions[i])
|
||||
while (timer >= tzdata->transitions[i])
|
||||
++i;
|
||||
goto found;
|
||||
}
|
||||
@@ -755,19 +747,20 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
|
||||
found:
|
||||
/* assert (timer >= transitions[i - 1]
|
||||
&& (i == num_transitions || timer < transitions[i])); */
|
||||
__tzname[types[type_idxs[i - 1]].isdst]
|
||||
= __tzstring (&zone_names[types[type_idxs[i - 1]].idx]);
|
||||
&& (i == tzdata->num_transitions || timer < transitions[i])); */
|
||||
__tzname[tzdata->types[tzdata->type_idxs[i - 1]].isdst]
|
||||
= __tzstring (&tzdata->zone_names
|
||||
[tzdata->types[tzdata->type_idxs[i - 1]].idx]);
|
||||
size_t j = i;
|
||||
while (j < num_transitions)
|
||||
while (j < tzdata->num_transitions)
|
||||
{
|
||||
int type = type_idxs[j];
|
||||
int dst = types[type].isdst;
|
||||
int idx = types[type].idx;
|
||||
int type = tzdata->type_idxs[j];
|
||||
int dst = tzdata->types[type].isdst;
|
||||
int idx = tzdata->types[type].idx;
|
||||
|
||||
if (__tzname[dst] == NULL)
|
||||
{
|
||||
__tzname[dst] = __tzstring (&zone_names[idx]);
|
||||
__tzname[dst] = __tzstring (&tzdata->zone_names[idx]);
|
||||
|
||||
if (__tzname[1 - dst] != NULL)
|
||||
break;
|
||||
@@ -779,25 +772,26 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
if (__glibc_unlikely (__tzname[0] == NULL))
|
||||
__tzname[0] = __tzname[1];
|
||||
|
||||
i = type_idxs[i - 1];
|
||||
i = tzdata->type_idxs[i - 1];
|
||||
}
|
||||
|
||||
struct ttinfo *info = &types[i];
|
||||
__daylight = rule_stdoff != rule_dstoff;
|
||||
__timezone = -rule_stdoff;
|
||||
struct ttinfo *info = &tzdata->types[i];
|
||||
__daylight = tzdata->rule_stdoff != tzdata->rule_dstoff;
|
||||
__timezone = -tzdata->rule_stdoff;
|
||||
|
||||
if (__tzname[0] == NULL)
|
||||
{
|
||||
/* This should only happen if there are no transition rules.
|
||||
In this case there should be only one single type. */
|
||||
assert (num_types == 1);
|
||||
__tzname[0] = __tzstring (zone_names);
|
||||
assert (tzdata->num_types == 1);
|
||||
__tzname[0] = __tzstring (tzdata->zone_names);
|
||||
}
|
||||
if (__tzname[1] == NULL)
|
||||
/* There is no daylight saving time. */
|
||||
__tzname[1] = __tzname[0];
|
||||
tp->tm_isdst = info->isdst;
|
||||
assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0);
|
||||
assert (strcmp (&tzdata->zone_names[info->idx],
|
||||
__tzname[tp->tm_isdst]) == 0);
|
||||
tp->tm_zone = __tzname[tp->tm_isdst];
|
||||
tp->tm_gmtoff = info->offset;
|
||||
}
|
||||
@@ -807,26 +801,37 @@ __tzfile_compute (time_t timer, int use_localtime,
|
||||
*leap_hit = 0;
|
||||
|
||||
/* Find the last leap second correction transition time before TIMER. */
|
||||
i = num_leaps;
|
||||
i = tzdata->num_leaps;
|
||||
do
|
||||
if (i-- == 0)
|
||||
return;
|
||||
while (timer < leaps[i].transition);
|
||||
while (timer < tzdata->leaps[i].transition);
|
||||
|
||||
/* Apply its correction. */
|
||||
*leap_correct = leaps[i].change;
|
||||
*leap_correct = tzdata->leaps[i].change;
|
||||
|
||||
if (timer == leaps[i].transition && /* Exactly at the transition time. */
|
||||
((i == 0 && leaps[i].change > 0) ||
|
||||
leaps[i].change > leaps[i - 1].change))
|
||||
if (/* Exactly at the transition time. */
|
||||
timer == tzdata->leaps[i].transition
|
||||
&& ((i == 0 && tzdata->leaps[i].change > 0) ||
|
||||
tzdata->leaps[i].change > tzdata->leaps[i - 1].change))
|
||||
{
|
||||
*leap_hit = 1;
|
||||
while (i > 0
|
||||
&& leaps[i].transition == leaps[i - 1].transition + 1
|
||||
&& leaps[i].change == leaps[i - 1].change + 1)
|
||||
&& (tzdata->leaps[i].transition
|
||||
== tzdata->leaps[i - 1].transition + 1)
|
||||
&& tzdata->leaps[i].change == tzdata->leaps[i - 1].change + 1)
|
||||
{
|
||||
++*leap_hit;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
internal_function
|
||||
__tzdata_free (struct tzdata *tzdata)
|
||||
{
|
||||
free (tzdata->transitions);
|
||||
free (tzdata->old_tz);
|
||||
free (tzdata);
|
||||
}
|
||||
|
||||
+119
-126
@@ -24,44 +24,32 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <libc-symbols.h>
|
||||
#include <shlib-compat.h>
|
||||
|
||||
#include <time/time-private.h>
|
||||
#include <timezone/tzfile.h>
|
||||
|
||||
char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
|
||||
int __daylight = 0;
|
||||
long int __timezone = 0L;
|
||||
static void update_vars (const struct tzdata *tzdata);
|
||||
|
||||
weak_alias (__tzname, tzname)
|
||||
weak_alias (__daylight, daylight)
|
||||
weak_alias (__timezone, timezone)
|
||||
/* Global time zone data object. Contains parsed timezone file and
|
||||
timezone rule data. */
|
||||
static struct tzdata global_tzdata;
|
||||
|
||||
/* This locks all the state variables in tzfile.c and this file. */
|
||||
/* Access to global_tzdata is protected by this lock. Also covers the
|
||||
other global variables in this file. */
|
||||
__libc_lock_define_initialized (static, tzset_lock)
|
||||
|
||||
/* This structure contains all the information about a
|
||||
timezone given in the POSIX standard TZ envariable. */
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
/* We cache the computed time of change for a
|
||||
given year so we don't have to recompute it. */
|
||||
struct tzrule_cache
|
||||
{
|
||||
time_t change; /* When to change to this zone. */
|
||||
int computed_for; /* Year above is computed for. */
|
||||
};
|
||||
|
||||
/* When to change. */
|
||||
enum { J0, J1, M } type; /* Interpretation of: */
|
||||
unsigned short int m, n, d; /* Month, week, day. */
|
||||
int secs; /* Time of day. */
|
||||
static struct tzrule_cache global_tzrule_cache[2];
|
||||
|
||||
long int offset; /* Seconds east of GMT (west if < 0). */
|
||||
|
||||
/* We cache the computed time of change for a
|
||||
given year so we don't have to recompute it. */
|
||||
time_t change; /* When to change to this zone. */
|
||||
int computed_for; /* Year above is computed for. */
|
||||
} tz_rule;
|
||||
|
||||
/* tz_rules[0] is standard, tz_rules[1] is daylight. */
|
||||
static tz_rule tz_rules[2];
|
||||
|
||||
|
||||
static void compute_change (tz_rule *rule, int year) __THROW internal_function;
|
||||
static void tzset_internal (int always);
|
||||
|
||||
/* List of buffers containing time zone strings. */
|
||||
@@ -120,19 +108,6 @@ __tzstring (const char *s)
|
||||
return __tzstring_len (s, strlen (s));
|
||||
}
|
||||
|
||||
static char *old_tz;
|
||||
|
||||
static void
|
||||
internal_function
|
||||
update_vars (void)
|
||||
{
|
||||
__daylight = tz_rules[0].offset != tz_rules[1].offset;
|
||||
__timezone = -tz_rules[0].offset;
|
||||
__tzname[0] = (char *) tz_rules[0].name;
|
||||
__tzname[1] = (char *) tz_rules[1].name;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
compute_offset (unsigned int ss, unsigned int mm, unsigned int hh)
|
||||
{
|
||||
@@ -146,10 +121,10 @@ compute_offset (unsigned int ss, unsigned int mm, unsigned int hh)
|
||||
}
|
||||
|
||||
/* Parses the time zone name at *TZP, and writes a pointer to an
|
||||
interned string to tz_rules[WHICHRULE].name. On success, advances
|
||||
*TZP, and returns true. Returns false otherwise. */
|
||||
interned string to TZDATA->tz_rules[WHICHRULE].name. On success,
|
||||
advances *TZP, and returns true. Returns false otherwise. */
|
||||
static bool
|
||||
parse_tzname (const char **tzp, int whichrule)
|
||||
parse_tzname (struct tzdata *tzdata, const char **tzp, int whichrule)
|
||||
{
|
||||
const char *start = *tzp;
|
||||
const char *p = start;
|
||||
@@ -176,17 +151,17 @@ parse_tzname (const char **tzp, int whichrule)
|
||||
const char *name = __tzstring_len (start, len);
|
||||
if (name == NULL)
|
||||
return false;
|
||||
tz_rules[whichrule].name = name;
|
||||
tzdata->tz_rules[whichrule].name = name;
|
||||
|
||||
*tzp = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Parses the time zone offset at *TZP, and writes it to
|
||||
tz_rules[WHICHRULE].offset. Returns true if the parse was
|
||||
TZDATA->tz_rules[WHICHRULE].offset. Returns true if the parse was
|
||||
successful. */
|
||||
static bool
|
||||
parse_offset (const char **tzp, int whichrule)
|
||||
parse_offset (struct tzdata *tzdata, const char **tzp, int whichrule)
|
||||
{
|
||||
const char *tz = *tzp;
|
||||
if (whichrule == 0
|
||||
@@ -206,30 +181,30 @@ parse_offset (const char **tzp, int whichrule)
|
||||
int consumed = 0;
|
||||
if (sscanf (tz, "%hu%n:%hu%n:%hu%n",
|
||||
&hh, &consumed, &mm, &consumed, &ss, &consumed) > 0)
|
||||
tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh);
|
||||
tzdata->tz_rules[whichrule].offset = sign * compute_offset (ss, mm, hh);
|
||||
else
|
||||
/* Nothing could be parsed. */
|
||||
if (whichrule == 0)
|
||||
{
|
||||
/* Standard time defaults to offset zero. */
|
||||
tz_rules[0].offset = 0;
|
||||
tzdata->tz_rules[0].offset = 0;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
/* DST defaults to one hour later than standard time. */
|
||||
tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
|
||||
tzdata->tz_rules[1].offset = tzdata->tz_rules[0].offset + (60 * 60);
|
||||
*tzp = tz + consumed;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Parses the standard <-> DST rules at *TZP. Updates
|
||||
tz_rule[WHICHRULE]. On success, advances *TZP and returns true.
|
||||
Otherwise, returns false. */
|
||||
TZDATA->tz_rule[WHICHRULE]. On success, advances *TZP and returns
|
||||
true. Otherwise, returns false. */
|
||||
static bool
|
||||
parse_rule (const char **tzp, int whichrule)
|
||||
parse_rule (struct tzdata *tzdata, const char **tzp, int whichrule)
|
||||
{
|
||||
const char *tz = *tzp;
|
||||
tz_rule *tzr = &tz_rules[whichrule];
|
||||
struct tz_rule *tzr = &tzdata->tz_rules[whichrule];
|
||||
|
||||
/* Ignore comma to support string following the incorrect
|
||||
specification in early POSIX.1 printings. */
|
||||
@@ -270,7 +245,7 @@ parse_rule (const char **tzp, int whichrule)
|
||||
Below is the equivalent of "M3.2.0,M11.1.0" [/2 not needed
|
||||
since 2:00AM is the default]. */
|
||||
tzr->type = M;
|
||||
if (tzr == &tz_rules[0])
|
||||
if (tzr == &tzdata->tz_rules[0])
|
||||
{
|
||||
tzr->m = 3;
|
||||
tzr->n = 2;
|
||||
@@ -311,55 +286,51 @@ parse_rule (const char **tzp, int whichrule)
|
||||
/* Default to 2:00 AM. */
|
||||
tzr->secs = 2 * 60 * 60;
|
||||
|
||||
tzr->computed_for = -1;
|
||||
*tzp = tz;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Parse the POSIX TZ-style string. */
|
||||
void
|
||||
__tzset_parse_tz (const char *tz)
|
||||
internal_function
|
||||
__tzset_parse_tz (struct tzdata *tzdata, const char *tz)
|
||||
{
|
||||
/* Clear out old state and reset to unnamed UTC. */
|
||||
memset (tz_rules, '\0', sizeof tz_rules);
|
||||
tz_rules[0].name = tz_rules[1].name = "";
|
||||
/* Set to unnamed UTC. */
|
||||
tzdata->tz_rules[0].name = tzdata->tz_rules[1].name = "";
|
||||
|
||||
/* Get the standard timezone name. */
|
||||
if (parse_tzname (&tz, 0) && parse_offset (&tz, 0))
|
||||
if (parse_tzname (tzdata, &tz, 0) && parse_offset (tzdata, &tz, 0))
|
||||
{
|
||||
/* Get the DST timezone name (if any). */
|
||||
if (*tz != '\0')
|
||||
{
|
||||
if (parse_tzname (&tz, 1))
|
||||
if (parse_tzname (tzdata, &tz, 1))
|
||||
{
|
||||
parse_offset (&tz, 1);
|
||||
parse_offset (tzdata, &tz, 1);
|
||||
if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
|
||||
{
|
||||
/* There is no rule. See if there is a default rule
|
||||
file. */
|
||||
__tzfile_default (tz_rules[0].name, tz_rules[1].name,
|
||||
tz_rules[0].offset, tz_rules[1].offset);
|
||||
if (__use_tzfile)
|
||||
__tzfile_default (tzdata, tzdata->tz_rules[0].name, tzdata->tz_rules[1].name,
|
||||
tzdata->tz_rules[0].offset, tzdata->tz_rules[1].offset);
|
||||
if (tzdata->use_tzfile)
|
||||
{
|
||||
free (old_tz);
|
||||
old_tz = NULL;
|
||||
free (tzdata->old_tz);
|
||||
tzdata->old_tz = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Figure out the standard <-> DST rules. */
|
||||
if (parse_rule (&tz, 0))
|
||||
parse_rule (&tz, 1);
|
||||
if (parse_rule (tzdata, &tz, 0))
|
||||
parse_rule (tzdata, &tz, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There is no DST. */
|
||||
tz_rules[1].name = tz_rules[0].name;
|
||||
tz_rules[1].offset = tz_rules[0].offset;
|
||||
tzdata->tz_rules[1].name = tzdata->tz_rules[0].name;
|
||||
tzdata->tz_rules[1].offset = tzdata->tz_rules[0].offset;
|
||||
}
|
||||
}
|
||||
|
||||
update_vars ();
|
||||
}
|
||||
|
||||
/* Interpret the TZ envariable. */
|
||||
@@ -386,7 +357,8 @@ tzset_internal (int always)
|
||||
++tz;
|
||||
|
||||
/* Check whether the value changed since the last run. */
|
||||
if (old_tz != NULL && tz != NULL && strcmp (tz, old_tz) == 0)
|
||||
if (global_tzdata.old_tz != NULL && tz != NULL
|
||||
&& strcmp (tz, global_tzdata.old_tz) == 0)
|
||||
/* No change, simply return. */
|
||||
return;
|
||||
|
||||
@@ -394,45 +366,47 @@ tzset_internal (int always)
|
||||
/* No user specification; use the site-wide default. */
|
||||
tz = TZDEFAULT;
|
||||
|
||||
tz_rules[0].name = NULL;
|
||||
tz_rules[1].name = NULL;
|
||||
global_tzdata.tz_rules[0].name = NULL;
|
||||
global_tzdata.tz_rules[1].name = NULL;
|
||||
|
||||
/* Invalidate the tzrule cache. */
|
||||
global_tzrule_cache[0].computed_for = -1;
|
||||
global_tzrule_cache[1].computed_for = -1;
|
||||
|
||||
/* Save the value of `tz'. */
|
||||
free (old_tz);
|
||||
old_tz = tz ? __strdup (tz) : NULL;
|
||||
free (global_tzdata.old_tz);
|
||||
global_tzdata.old_tz = tz ? __strdup (tz) : NULL;
|
||||
|
||||
/* Try to read a data file. */
|
||||
__tzfile_read (tz, 0, NULL);
|
||||
if (__use_tzfile)
|
||||
__tzfile_read (&global_tzdata, tz, 0, NULL);
|
||||
if (global_tzdata.use_tzfile)
|
||||
return;
|
||||
|
||||
/* No data file found. Default to UTC if nothing specified. */
|
||||
|
||||
if (tz == NULL || *tz == '\0'
|
||||
|| (TZDEFAULT != NULL && strcmp (tz, TZDEFAULT) == 0))
|
||||
{
|
||||
memset (tz_rules, '\0', sizeof tz_rules);
|
||||
tz_rules[0].name = tz_rules[1].name = "UTC";
|
||||
if (J0 != 0)
|
||||
tz_rules[0].type = tz_rules[1].type = J0;
|
||||
tz_rules[0].change = tz_rules[1].change = (time_t) -1;
|
||||
update_vars ();
|
||||
memset (global_tzdata.tz_rules, '\0', sizeof (global_tzdata.tz_rules));
|
||||
global_tzdata.tz_rules[0].name = global_tzdata.tz_rules[1].name = "UTC";
|
||||
global_tzrule_cache[0].change = global_tzrule_cache[1].change = -1;
|
||||
update_vars (&global_tzdata);
|
||||
return;
|
||||
}
|
||||
|
||||
__tzset_parse_tz (tz);
|
||||
__tzset_parse_tz (&global_tzdata, tz);
|
||||
update_vars (&global_tzdata);
|
||||
}
|
||||
|
||||
/* Figure out the exact time (as a time_t) in YEAR
|
||||
when the change described by RULE will occur and
|
||||
put it in RULE->change, saving YEAR in RULE->computed_for. */
|
||||
static void
|
||||
internal_function
|
||||
compute_change (tz_rule *rule, int year)
|
||||
compute_change (const struct tz_rule *rule,
|
||||
struct tzrule_cache *cache,
|
||||
int year)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
if (year != -1 && rule->computed_for == year)
|
||||
if (year != -1 && cache->computed_for == year)
|
||||
/* Operations on times in 2 BC will be slower. Oh well. */
|
||||
return;
|
||||
|
||||
@@ -457,7 +431,7 @@ compute_change (tz_rule *rule, int year)
|
||||
add SECSPERDAY times the day number-1 to the time of
|
||||
January 1, midnight, to get the day. */
|
||||
t += (rule->d - 1) * SECSPERDAY;
|
||||
if (rule->d >= 60 && __isleap (year))
|
||||
if (rule->d >= 60 && __time_isleap (year))
|
||||
t += SECSPERDAY;
|
||||
break;
|
||||
|
||||
@@ -473,7 +447,7 @@ compute_change (tz_rule *rule, int year)
|
||||
unsigned int i;
|
||||
int d, m1, yy0, yy1, yy2, dow;
|
||||
const unsigned short int *myday =
|
||||
&__mon_yday[__isleap (year)][rule->m];
|
||||
&__mon_yday[__time_isleap (year)][rule->m];
|
||||
|
||||
/* First add SECSPERDAY for each day in months before M. */
|
||||
t += myday[-1] * SECSPERDAY;
|
||||
@@ -508,8 +482,8 @@ compute_change (tz_rule *rule, int year)
|
||||
/* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
|
||||
Just add the time of day and local offset from GMT, and we're done. */
|
||||
|
||||
rule->change = t - rule->offset + rule->secs;
|
||||
rule->computed_for = year;
|
||||
cache->change = t - rule->offset + rule->secs;
|
||||
cache->computed_for = year;
|
||||
}
|
||||
|
||||
|
||||
@@ -517,10 +491,13 @@ compute_change (tz_rule *rule, int year)
|
||||
`__timezone', and `__daylight' accordingly. */
|
||||
void
|
||||
internal_function
|
||||
__tz_compute (time_t timer, struct tm *tm, int use_localtime)
|
||||
__tz_compute (const struct tzdata *tzdata,
|
||||
time_t timer, struct tm *tm, int use_localtime)
|
||||
{
|
||||
compute_change (&tz_rules[0], 1900 + tm->tm_year);
|
||||
compute_change (&tz_rules[1], 1900 + tm->tm_year);
|
||||
compute_change (&tzdata->tz_rules[0], &global_tzrule_cache[0],
|
||||
1900 + tm->tm_year);
|
||||
compute_change (&tzdata->tz_rules[1], &global_tzrule_cache[1],
|
||||
1900 + tm->tm_year);
|
||||
|
||||
if (use_localtime)
|
||||
{
|
||||
@@ -529,16 +506,16 @@ __tz_compute (time_t timer, struct tm *tm, int use_localtime)
|
||||
/* We have to distinguish between northern and southern
|
||||
hemisphere. For the latter the daylight saving time
|
||||
ends in the next year. */
|
||||
if (__builtin_expect (tz_rules[0].change
|
||||
> tz_rules[1].change, 0))
|
||||
isdst = (timer < tz_rules[1].change
|
||||
|| timer >= tz_rules[0].change);
|
||||
if (__builtin_expect (global_tzrule_cache[0].change
|
||||
> global_tzrule_cache[1].change, 0))
|
||||
isdst = (timer < global_tzrule_cache[1].change
|
||||
|| timer >= global_tzrule_cache[0].change);
|
||||
else
|
||||
isdst = (timer >= tz_rules[0].change
|
||||
&& timer < tz_rules[1].change);
|
||||
isdst = (timer >= global_tzrule_cache[0].change
|
||||
&& timer < global_tzrule_cache[1].change);
|
||||
tm->tm_isdst = isdst;
|
||||
tm->tm_zone = __tzname[isdst];
|
||||
tm->tm_gmtoff = tz_rules[isdst].offset;
|
||||
tm->tm_zone = tzdata->tzname[isdst];
|
||||
tm->tm_gmtoff = tzdata->tz_rules[isdst].offset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,21 +529,17 @@ __tzset (void)
|
||||
|
||||
tzset_internal (1);
|
||||
|
||||
if (!__use_tzfile)
|
||||
{
|
||||
/* Set `tzname'. */
|
||||
__tzname[0] = (char *) tz_rules[0].name;
|
||||
__tzname[1] = (char *) tz_rules[1].name;
|
||||
}
|
||||
if (!global_tzdata.use_tzfile)
|
||||
update_vars (&global_tzdata);
|
||||
|
||||
__libc_lock_unlock (tzset_lock);
|
||||
}
|
||||
weak_alias (__tzset, tzset)
|
||||
|
||||
/* Return the `struct tm' representation of *TIMER in the local timezone.
|
||||
Use local time if USE_LOCALTIME is nonzero, UTC otherwise. */
|
||||
|
||||
struct tm *
|
||||
__tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
|
||||
internal_function
|
||||
__tz_convert (const time_t *timer, bool use_reentrant,
|
||||
bool use_localtime, struct tm *tp)
|
||||
{
|
||||
long int leap_correction;
|
||||
int leap_extra_secs;
|
||||
@@ -582,17 +555,17 @@ __tz_convert (const time_t *timer, int use_localtime, struct tm *tp)
|
||||
/* Update internal database according to current TZ setting.
|
||||
POSIX.1 8.3.7.2 says that localtime_r is not required to set tzname.
|
||||
This is a good idea since this allows at least a bit more parallelism. */
|
||||
tzset_internal (tp == &_tmbuf && use_localtime);
|
||||
tzset_internal (!use_reentrant && use_localtime);
|
||||
|
||||
if (__use_tzfile)
|
||||
__tzfile_compute (*timer, use_localtime, &leap_correction,
|
||||
if (global_tzdata.use_tzfile)
|
||||
__tzfile_compute (&global_tzdata, *timer, use_localtime, &leap_correction,
|
||||
&leap_extra_secs, tp);
|
||||
else
|
||||
{
|
||||
if (! __offtime (timer, 0, tp))
|
||||
tp = NULL;
|
||||
else
|
||||
__tz_compute (*timer, tp, use_localtime);
|
||||
__tz_compute (&global_tzdata, *timer, tp, use_localtime);
|
||||
leap_correction = 0L;
|
||||
leap_extra_secs = 0;
|
||||
}
|
||||
@@ -627,6 +600,26 @@ libc_freeres_fn (free_mem)
|
||||
tzstring_list = tzstring_list->next;
|
||||
free (old);
|
||||
}
|
||||
free (old_tz);
|
||||
old_tz = NULL;
|
||||
}
|
||||
|
||||
/* Do this at the very end, so that the code above does not
|
||||
accidentally use any of these global variables. */
|
||||
|
||||
#include <time/time-variables.h>
|
||||
|
||||
char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
|
||||
int __daylight = 0;
|
||||
long int __timezone = 0L;
|
||||
|
||||
weak_alias (__tzname, tzname)
|
||||
weak_alias (__daylight, daylight)
|
||||
weak_alias (__timezone, timezone)
|
||||
|
||||
static void
|
||||
update_vars (const struct tzdata *tzdata)
|
||||
{
|
||||
__daylight = tzdata->tz_rules[0].offset != tzdata->tz_rules[1].offset;
|
||||
__timezone = -tzdata->tz_rules[0].offset;
|
||||
__tzname[0] = (char *) tzdata->tz_rules[0].name;
|
||||
__tzname[1] = (char *) tzdata->tz_rules[1].name;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user