📄 tzfile.c
字号:
/* Copyright (C) 1991-1993,1995-2001,2003,2004,2006, 2007 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */#include <assert.h>#include <limits.h>#include <stdio.h>#include <stdio_ext.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <sys/stat.h>#define NOID#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 void compute_tzname_max (size_t) internal_function;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>/* Decode the four bytes at PTR as a signed integer in network byte order. */static inline int__attribute ((always_inline))decode (const void *ptr){ if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4) return *(const int *) ptr; if (sizeof (int) == 4) return bswap_32 (*(const int *) ptr); const unsigned char *p = ptr; int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0; result = (result << 8) | *p++; result = (result << 8) | *p++; result = (result << 8) | *p++; result = (result << 8) | *p++; return result;}static inline int64_t__attribute ((always_inline))decode64 (const void *ptr){ if ((BYTE_ORDER == BIG_ENDIAN)) return *(const int64_t *) ptr; return bswap_64 (*(const int64_t *) ptr);}void__tzfile_read (const char *file, size_t extra, char **extrap){ static const char default_tzdir[] = TZDIR; size_t num_isstd, num_isgmt; register FILE *f; struct tzhead tzhead; size_t chars; register 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; 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 program. So we fail for any file which is not in the directory hierachy starting at TZDIR and which is not the system wide default TZDEFAULT. */ if (__libc_enable_secure && ((*file == '/' && memcmp (file, TZDEFAULT, sizeof TZDEFAULT) && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1)) || strstr (file, "../") != NULL)) /* This test is certainly a bit too restrictive but it should catch all critical cases. */ goto ret_free_transitions; } if (*file != '/') { const char *tzdir; unsigned int len, tzdir_len; char *new, *tmp; tzdir = getenv ("TZDIR"); if (tzdir == NULL || *tzdir == '\0') { tzdir = default_tzdir; tzdir_len = sizeof (default_tzdir) - 1; } else tzdir_len = strlen (tzdir); len = strlen (file) + 1; new = (char *) __alloca (tzdir_len + 1 + len); tmp = __mempcpy (new, tzdir, tzdir_len); *tmp++ = '/'; memcpy (tmp, file, len); file = new; } /* 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) { /* Nothing to do. */ __use_tzfile = 1; return; } /* Note the file is opened with cancellation in the I/O functions disabled. */ f = fopen (file, "rc"); if (f == NULL) goto ret_free_transitions; /* Get information about the file we are actually using. */ if (fstat64 (fileno (f), &st) != 0) { fclose (f); goto ret_free_transitions; } free ((void *) transitions); 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; /* No threads reading this stream. */ __fsetlocking (f, FSETLOCKING_BYCALLER); read_again: 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; num_transitions = (size_t) decode (tzhead.tzh_timecnt); num_types = (size_t) decode (tzhead.tzh_typecnt); chars = (size_t) decode (tzhead.tzh_charcnt); num_leaps = (size_t) decode (tzhead.tzh_leapcnt); num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt); num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt); /* For platforms with 64-bit time_t we use the new format if available. */ if (sizeof (time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') { /* We use the 8-byte format. */ trans_width = 8; /* Position the stream before the second header. */ size_t to_skip = (num_transitions * (4 + 1) + num_types * 6 + chars + num_leaps * 8 + num_isstd + num_isgmt); if (fseek (f, to_skip, SEEK_CUR) != 0) goto lose; goto read_again; } total_size = num_transitions * (sizeof (time_t) + 1); total_size = ((total_size + __alignof__ (struct ttinfo) - 1) & ~(__alignof__ (struct ttinfo) - 1)); types_idx = total_size; total_size += num_types * sizeof (struct ttinfo) + chars; total_size = ((total_size + __alignof__ (struct leap) - 1) & ~(__alignof__ (struct leap) - 1)); leaps_idx = total_size; total_size += num_leaps * sizeof (struct leap); tzspec_len = (sizeof (time_t) == 8 && trans_width == 8 ? st.st_size - (ftello (f) + num_transitions * (8 + 1) + num_types * 6 + chars + num_leaps * 8 + num_isstd + num_isgmt) - 1 : 0); /* Allocate enough memory including the extra block requested by the caller. */ transitions = (time_t *) malloc (total_size + tzspec_len + extra); if (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); if (sizeof (time_t) == 8 && trans_width == 8) tzspec = (char *) leaps + num_leaps * sizeof (struct leap) + extra; else tzspec = NULL; if (extra > 0) *extrap = (char *) &leaps[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)) 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)) 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 (__builtin_expect (type_idxs[i] >= num_types, 0)) goto lose; if ((BYTE_ORDER != BIG_ENDIAN && (sizeof (time_t) == 4 || trans_width == 4)) || (BYTE_ORDER == BIG_ENDIAN && sizeof (time_t) == 8 && trans_width == 4)) { /* Decode the transition times, stored as 4-byte integers in 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; while (i-- > 0) transitions[i] = decode ((char *) 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 < num_types; ++i) { unsigned char x[4]; int c; if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x), 0)) goto lose; c = getc_unlocked (f); if (__builtin_expect ((unsigned int) c > 1u, 0)) goto lose; types[i].isdst = c; c = getc_unlocked (f); if (__builtin_expect ((size_t) c > chars, 0)) /* Bogus index in data file. */ goto lose; types[i].idx = c; types[i].offset = (long int) decode (x); } if (__builtin_expect (fread_unlocked (zone_names, 1, chars, f) != chars, 0)) goto lose; for (i = 0; i < 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); else leaps[i].transition = (time_t) decode64 (x); if (__builtin_expect (fread_unlocked (x, 1, 4, f) != 4, 0)) goto lose; leaps[i].change = (long int) decode (x); } for (i = 0; i < num_isstd; ++i) { int c = getc_unlocked (f); if (__builtin_expect (c == EOF, 0)) goto lose; types[i].isstd = c != 0; } while (i < num_types) types[i++].isstd = 0; for (i = 0; i < num_isgmt; ++i) { int c = getc_unlocked (f); if (__builtin_expect (c == EOF, 0)) goto lose; types[i].isgmt = c != 0; } while (i < num_types) types[i++].isgmt = 0; /* Read the POSIX TZ-style information if possible. */ 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)) 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -