diff options
Diffstat (limited to 'time/tzfile.c')
-rw-r--r-- | time/tzfile.c | 492 |
1 files changed, 248 insertions, 244 deletions
diff --git a/time/tzfile.c b/time/tzfile.c index 9290dc620b..aa7f5034b4 100644 --- a/time/tzfile.c +++ b/time/tzfile.c @@ -26,41 +26,9 @@ #include <sys/stat.h> #include <stdint.h> -#include <time/time-variables.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> @@ -96,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 @@ -138,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 != '/') @@ -148,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. */ @@ -168,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); @@ -191,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. */ @@ -209,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) @@ -221,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; @@ -242,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; @@ -277,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)) @@ -324,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; @@ -347,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) @@ -380,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') { @@ -449,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; @@ -519,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; @@ -552,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. */ ; @@ -589,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. */ @@ -605,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) { @@ -642,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 @@ -674,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; @@ -682,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. */ @@ -690,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; @@ -709,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; } @@ -731,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; } @@ -756,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; @@ -780,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; } @@ -808,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); +} |