aboutsummaryrefslogtreecommitdiff
path: root/time
diff options
context:
space:
mode:
Diffstat (limited to 'time')
-rw-r--r--time/tzfile.c63
1 files changed, 57 insertions, 6 deletions
diff --git a/time/tzfile.c b/time/tzfile.c
index 6a8bf89f9e..d19b7e9b4f 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -371,15 +371,53 @@ __tzfile_read (const char *file, size_t extra, char **extrap)
types[i++].isgmt = 0;
/* Read the POSIX TZ-style information if possible. */
- if (tzspec != NULL)
+ if (sizeof (time_t) == 8 && tzspec != NULL)
{
/* Skip over the newline first. */
if (getc_unlocked (f) != '\n'
- || fread_unlocked (tzspec, 1, tzspec_len - 1, f) != tzspec_len - 1)
+ || (fread_unlocked (tzspec, 1, tzspec_len - 1, f)
+ != tzspec_len - 1))
tzspec = NULL;
else
tzspec[tzspec_len - 1] = '\0';
}
+ else if (sizeof (time_t) == 4 && tzhead.tzh_version != '\0')
+ {
+ /* Get the TZ string. */
+ if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),
+ 1, f) != 1, 0)
+ || (memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic))
+ != 0))
+ goto lose;
+
+ size_t num_transitions2 = (size_t) decode (tzhead.tzh_timecnt);
+ size_t num_types2 = (size_t) decode (tzhead.tzh_typecnt);
+ size_t chars2 = (size_t) decode (tzhead.tzh_charcnt);
+ size_t num_leaps2 = (size_t) decode (tzhead.tzh_leapcnt);
+ size_t num_isstd2 = (size_t) decode (tzhead.tzh_ttisstdcnt);
+ size_t num_isgmt2 = (size_t) decode (tzhead.tzh_ttisgmtcnt);
+
+ /* Position the stream before the second header. */
+ size_t to_skip = (num_transitions2 * (8 + 1)
+ + num_types2 * 6
+ + chars2
+ + num_leaps2 * 12
+ + num_isstd2
+ + num_isgmt2);
+ off_t off;
+ if (fseek (f, to_skip, SEEK_CUR) != 0
+ || (off = ftello (f)) < 0
+ || st.st_size < off + 2)
+ goto lose;
+
+ tzspec_len = st.st_size - off - 1;
+ char *tzstr = alloca (tzspec_len);
+ if (getc_unlocked (f) != '\n'
+ || (fread_unlocked (tzstr, 1, tzspec_len - 1, f) != tzspec_len - 1))
+ goto lose;
+ tzstr[tzspec_len - 1] = '\0';
+ tzspec = __tzstring (tzstr);
+ }
fclose (f);
@@ -561,7 +599,7 @@ __tzfile_compute (time_t timer, int use_localtime,
__tzname[0] = NULL;
__tzname[1] = NULL;
- if (num_transitions == 0 || timer < transitions[0])
+ if (__builtin_expect (num_transitions == 0 || timer < transitions[0], 0))
{
/* TIMER is before any transition (or there are no transitions).
Choose the first non-DST type
@@ -591,9 +629,9 @@ __tzfile_compute (time_t timer, int use_localtime,
++j;
}
}
- else if (timer >= transitions[num_transitions - 1])
+ else if (__builtin_expect (timer >= transitions[num_transitions - 1], 0))
{
- if (tzspec == NULL)
+ if (__builtin_expect (tzspec == NULL, 0))
{
use_last:
i = num_transitions;
@@ -605,12 +643,22 @@ __tzfile_compute (time_t timer, int use_localtime,
/* Convert to broken down structure. If this fails do not
use the string. */
- if (! __offtime (&timer, 0, tp))
+ if (__builtin_expect (! __offtime (&timer, 0, tp), 0))
goto use_last;
/* Use the rules from the TZ string to compute the change. */
__tz_compute (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 (__builtin_expect (zone_names == (char *) &leaps[num_leaps], 0))
+ {
+ assert (num_types == 2);
+ __tzname[0] = __tzstring (zone_names);
+ __tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
+ }
+
*leap_correct = 0L;
*leap_hit = 0;
return;
@@ -688,6 +736,9 @@ __tzfile_compute (time_t timer, int use_localtime,
++j;
}
+ if (__builtin_expect (__tzname[0] == NULL, 0))
+ __tzname[0] = __tzname[1];
+
i = type_idxs[i - 1];
}