Blame time/tzfile.c

Packit Service 82fcde
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
#include <limits.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdio_ext.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <time.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/stat.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
Packit Service 82fcde
#include <timezone/tzfile.h>
Packit Service 82fcde
Packit Service 82fcde
int __use_tzfile;
Packit Service 82fcde
static dev_t tzfile_dev;
Packit Service 82fcde
static ino64_t tzfile_ino;
Packit Service 82fcde
static time_t tzfile_mtime;
Packit Service 82fcde
Packit Service 82fcde
struct ttinfo
Packit Service 82fcde
  {
Packit Service 82fcde
    long int offset;		/* Seconds east of GMT.  */
Packit Service 82fcde
    unsigned char isdst;	/* Used to set tm_isdst.  */
Packit Service 82fcde
    unsigned char idx;		/* Index into `zone_names'.  */
Packit Service 82fcde
    unsigned char isstd;	/* Transition times are in standard time.  */
Packit Service 82fcde
    unsigned char isgmt;	/* Transition times are in GMT.  */
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
struct leap
Packit Service 82fcde
  {
Packit Service 82fcde
    internal_time_t transition;	/* Time the transition takes effect.  */
Packit Service 82fcde
    long int change;		/* Seconds of correction to apply.  */
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
static size_t num_transitions;
Packit Service 82fcde
libc_freeres_ptr (static internal_time_t *transitions);
Packit Service 82fcde
static unsigned char *type_idxs;
Packit Service 82fcde
static size_t num_types;
Packit Service 82fcde
static struct ttinfo *types;
Packit Service 82fcde
static char *zone_names;
Packit Service 82fcde
static long int rule_stdoff;
Packit Service 82fcde
static long int rule_dstoff;
Packit Service 82fcde
static size_t num_leaps;
Packit Service 82fcde
static struct leap *leaps;
Packit Service 82fcde
static char *tzspec;
Packit Service 82fcde
Packit Service 82fcde
#include <endian.h>
Packit Service 82fcde
#include <byteswap.h>
Packit Service 82fcde
Packit Service 82fcde
/* Decode the four bytes at PTR as a signed integer in network byte order.  */
Packit Service 82fcde
static inline int
Packit Service 82fcde
__attribute ((always_inline))
Packit Service 82fcde
decode (const void *ptr)
Packit Service 82fcde
{
Packit Service 82fcde
  if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
Packit Service 82fcde
    return *(const int *) ptr;
Packit Service 82fcde
  if (sizeof (int) == 4)
Packit Service 82fcde
    return bswap_32 (*(const int *) ptr);
Packit Service 82fcde
Packit Service 82fcde
  const unsigned char *p = ptr;
Packit Service 82fcde
  int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
Packit Service 82fcde
Packit Service 82fcde
  result = (result << 8) | *p++;
Packit Service 82fcde
  result = (result << 8) | *p++;
Packit Service 82fcde
  result = (result << 8) | *p++;
Packit Service 82fcde
  result = (result << 8) | *p++;
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static inline int64_t
Packit Service 82fcde
__attribute ((always_inline))
Packit Service 82fcde
decode64 (const void *ptr)
Packit Service 82fcde
{
Packit Service 82fcde
  if ((BYTE_ORDER == BIG_ENDIAN))
Packit Service 82fcde
    return *(const int64_t *) ptr;
Packit Service 82fcde
Packit Service 82fcde
  return bswap_64 (*(const int64_t *) ptr);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__tzfile_read (const char *file, size_t extra, char **extrap)
Packit Service 82fcde
{
Packit Service 82fcde
  static const char default_tzdir[] = TZDIR;
Packit Service 82fcde
  size_t num_isstd, num_isgmt;
Packit Service 82fcde
  FILE *f;
Packit Service 82fcde
  struct tzhead tzhead;
Packit Service 82fcde
  size_t chars;
Packit Service 82fcde
  size_t i;
Packit Service 82fcde
  size_t total_size;
Packit Service 82fcde
  size_t types_idx;
Packit Service 82fcde
  size_t leaps_idx;
Packit Service 82fcde
  int was_using_tzfile = __use_tzfile;
Packit Service 82fcde
  int trans_width = 4;
Packit Service 82fcde
  size_t tzspec_len;
Packit Service 82fcde
  char *new = NULL;
Packit Service 82fcde
Packit Service 82fcde
  _Static_assert (sizeof (internal_time_t) == 8,
Packit Service 82fcde
		  "internal_time_t must be eight bytes");
Packit Service 82fcde
Packit Service 82fcde
  __use_tzfile = 0;
Packit Service 82fcde
Packit Service 82fcde
  if (file == NULL)
Packit Service 82fcde
    /* No user specification; use the site-wide default.  */
Packit Service 82fcde
    file = TZDEFAULT;
Packit Service 82fcde
  else if (*file == '\0')
Packit Service 82fcde
    /* User specified the empty string; use UTC with no leap seconds.  */
Packit Service 82fcde
    goto ret_free_transitions;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We must not allow to read an arbitrary file in a setuid
Packit Service 82fcde
	 program.  So we fail for any file which is not in the
Packit Service 82fcde
	 directory hierachy starting at TZDIR
Packit Service 82fcde
	 and which is not the system wide default TZDEFAULT.  */
Packit Service 82fcde
      if (__libc_enable_secure
Packit Service 82fcde
	  && ((*file == '/'
Packit Service 82fcde
	       && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
Packit Service 82fcde
	       && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
Packit Service 82fcde
	      || strstr (file, "../") != NULL))
Packit Service 82fcde
	/* This test is certainly a bit too restrictive but it should
Packit Service 82fcde
	   catch all critical cases.  */
Packit Service 82fcde
	goto ret_free_transitions;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (*file != '/')
Packit Service 82fcde
    {
Packit Service 82fcde
      const char *tzdir;
Packit Service 82fcde
Packit Service 82fcde
      tzdir = getenv ("TZDIR");
Packit Service 82fcde
      if (tzdir == NULL || *tzdir == '\0')
Packit Service 82fcde
	tzdir = default_tzdir;
Packit Service 82fcde
      if (__asprintf (&new, "%s/%s", tzdir, file) == -1)
Packit Service 82fcde
	goto ret_free_transitions;
Packit Service 82fcde
      file = new;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* If we were already using tzfile, check whether the file changed.  */
Packit Service 82fcde
  struct stat64 st;
Packit Service 82fcde
  if (was_using_tzfile
Packit Service 82fcde
      && stat64 (file, &st) == 0
Packit Service 82fcde
      && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
Packit Service 82fcde
      && tzfile_mtime == st.st_mtime)
Packit Service 82fcde
    goto done;  /* Nothing to do.  */
Packit Service 82fcde
Packit Service 82fcde
  /* Note the file is opened with cancellation in the I/O functions
Packit Service 82fcde
     disabled and if available FD_CLOEXEC set.  */
Packit Service 82fcde
  f = fopen (file, "rce");
Packit Service 82fcde
  if (f == NULL)
Packit Service 82fcde
    goto ret_free_transitions;
Packit Service 82fcde
Packit Service 82fcde
  /* Get information about the file we are actually using.  */
Packit Service 82fcde
  if (fstat64 (__fileno (f), &st) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      fclose (f);
Packit Service 82fcde
      goto ret_free_transitions;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  free ((void *) transitions);
Packit Service 82fcde
  transitions = NULL;
Packit Service 82fcde
Packit Service 82fcde
  /* Remember the inode and device number and modification time.  */
Packit Service 82fcde
  tzfile_dev = st.st_dev;
Packit Service 82fcde
  tzfile_ino = st.st_ino;
Packit Service 82fcde
  tzfile_mtime = st.st_mtime;
Packit Service 82fcde
Packit Service 82fcde
  /* No threads reading this stream.  */
Packit Service 82fcde
  __fsetlocking (f, FSETLOCKING_BYCALLER);
Packit Service 82fcde
Packit Service 82fcde
 read_again:
Packit Service 82fcde
  if (__builtin_expect (__fread_unlocked ((void *) &tzhead, sizeof (tzhead),
Packit Service 82fcde
					  1, f) != 1, 0)
Packit Service 82fcde
      || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
Packit Service 82fcde
  num_transitions = (size_t) decode (tzhead.tzh_timecnt);
Packit Service 82fcde
  num_types = (size_t) decode (tzhead.tzh_typecnt);
Packit Service 82fcde
  chars = (size_t) decode (tzhead.tzh_charcnt);
Packit Service 82fcde
  num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
Packit Service 82fcde
  num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
Packit Service 82fcde
  num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
Packit Service 82fcde
Packit Service 82fcde
  if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
Packit Service 82fcde
  if (trans_width == 4 && tzhead.tzh_version[0] != '\0')
Packit Service 82fcde
    {
Packit Service 82fcde
      /* We use the 8-byte format.  */
Packit Service 82fcde
      trans_width = 8;
Packit Service 82fcde
Packit Service 82fcde
      /* Position the stream before the second header.  */
Packit Service 82fcde
      size_t to_skip = (num_transitions * (4 + 1)
Packit Service 82fcde
			+ num_types * 6
Packit Service 82fcde
			+ chars
Packit Service 82fcde
			+ num_leaps * 8
Packit Service 82fcde
			+ num_isstd
Packit Service 82fcde
			+ num_isgmt);
Packit Service 82fcde
      if (fseek (f, to_skip, SEEK_CUR) != 0)
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
Packit Service 82fcde
      goto read_again;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (__builtin_expect (num_transitions
Packit Service 82fcde
			> ((SIZE_MAX - (__alignof__ (struct ttinfo) - 1))
Packit Service 82fcde
			   / (sizeof (internal_time_t) + 1)), 0))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
  total_size = num_transitions * (sizeof (internal_time_t) + 1);
Packit Service 82fcde
  total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
Packit Service 82fcde
		& ~(__alignof__ (struct ttinfo) - 1));
Packit Service 82fcde
  types_idx = total_size;
Packit Service 82fcde
  if (__builtin_expect (num_types
Packit Service 82fcde
			> (SIZE_MAX - total_size) / sizeof (struct ttinfo), 0))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
  total_size += num_types * sizeof (struct ttinfo);
Packit Service 82fcde
  if (__glibc_unlikely (chars > SIZE_MAX - total_size))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
  total_size += chars;
Packit Service 82fcde
  if (__builtin_expect (__alignof__ (struct leap) - 1
Packit Service 82fcde
			> SIZE_MAX - total_size, 0))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
  total_size = ((total_size + __alignof__ (struct leap) - 1)
Packit Service 82fcde
		& ~(__alignof__ (struct leap) - 1));
Packit Service 82fcde
  leaps_idx = total_size;
Packit Service 82fcde
  if (__builtin_expect (num_leaps
Packit Service 82fcde
			> (SIZE_MAX - total_size) / sizeof (struct leap), 0))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
  total_size += num_leaps * sizeof (struct leap);
Packit Service 82fcde
  tzspec_len = 0;
Packit Service 82fcde
  if (trans_width == 8)
Packit Service 82fcde
    {
Packit Service 82fcde
      off_t rem = st.st_size - __ftello (f);
Packit Service 82fcde
      if (__builtin_expect (rem < 0
Packit Service 82fcde
			    || (size_t) rem < (num_transitions * (8 + 1)
Packit Service 82fcde
					       + num_types * 6
Packit Service 82fcde
					       + chars), 0))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      tzspec_len = (size_t) rem - (num_transitions * (8 + 1)
Packit Service 82fcde
				   + num_types * 6
Packit Service 82fcde
				   + chars);
Packit Service 82fcde
      if (__builtin_expect (num_leaps > SIZE_MAX / 12
Packit Service 82fcde
			    || tzspec_len < num_leaps * 12, 0))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      tzspec_len -= num_leaps * 12;
Packit Service 82fcde
      if (__glibc_unlikely (tzspec_len < num_isstd))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      tzspec_len -= num_isstd;
Packit Service 82fcde
      if (__glibc_unlikely (tzspec_len == 0 || tzspec_len - 1 < num_isgmt))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      tzspec_len -= num_isgmt + 1;
Packit Service 82fcde
      if (__glibc_unlikely (tzspec_len == 0
Packit Service 82fcde
			    || SIZE_MAX - total_size < tzspec_len))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (__glibc_unlikely (SIZE_MAX - total_size - tzspec_len < extra))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
Packit Service 82fcde
  /* Allocate enough memory including the extra block requested by the
Packit Service 82fcde
     caller.  */
Packit Service 82fcde
  transitions = malloc (total_size + tzspec_len + extra);
Packit Service 82fcde
  if (transitions == NULL)
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
Packit Service 82fcde
  type_idxs = (unsigned char *) transitions + (num_transitions
Packit Service 82fcde
					       * sizeof (internal_time_t));
Packit Service 82fcde
  types = (struct ttinfo *) ((char *) transitions + types_idx);
Packit Service 82fcde
  zone_names = (char *) types + num_types * sizeof (struct ttinfo);
Packit Service 82fcde
  leaps = (struct leap *) ((char *) transitions + leaps_idx);
Packit Service 82fcde
  if (trans_width == 8)
Packit Service 82fcde
    tzspec = (char *) leaps + num_leaps * sizeof (struct leap) + extra;
Packit Service 82fcde
  else
Packit Service 82fcde
    tzspec = NULL;
Packit Service 82fcde
  if (extra > 0)
Packit Service 82fcde
    *extrap = (char *) &leaps[num_leaps];
Packit Service 82fcde
Packit Service 82fcde
  if (__builtin_expect (trans_width == 8, 1))
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__builtin_expect (__fread_unlocked (transitions, trans_width + 1,
Packit Service 82fcde
					      num_transitions, f)
Packit Service 82fcde
			    != num_transitions, 0))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      if (__builtin_expect (__fread_unlocked (transitions, 4,
Packit Service 82fcde
					      num_transitions, f)
Packit Service 82fcde
			    != num_transitions, 0)
Packit Service 82fcde
	  || __builtin_expect (__fread_unlocked (type_idxs, 1, num_transitions,
Packit Service 82fcde
						 f) != num_transitions, 0))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Check for bogus indices in the data file, so we can hereafter
Packit Service 82fcde
     safely use type_idxs[T] as indices into `types' and never crash.  */
Packit Service 82fcde
  for (i = 0; i < num_transitions; ++i)
Packit Service 82fcde
    if (__glibc_unlikely (type_idxs[i] >= num_types))
Packit Service 82fcde
      goto lose;
Packit Service 82fcde
Packit Service 82fcde
  if (trans_width == 4)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Decode the transition times, stored as 4-byte integers in
Packit Service 82fcde
	 network (big-endian) byte order.  We work from the end of the
Packit Service 82fcde
	 array so as not to clobber the next element to be
Packit Service 82fcde
	 processed.  */
Packit Service 82fcde
      i = num_transitions;
Packit Service 82fcde
      while (i-- > 0)
Packit Service 82fcde
	transitions[i] = decode ((char *) transitions + i * 4);
Packit Service 82fcde
    }
Packit Service 82fcde
  else if (BYTE_ORDER != BIG_ENDIAN)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Decode the transition times, stored as 8-byte integers in
Packit Service 82fcde
	 network (big-endian) byte order.  */
Packit Service 82fcde
      for (i = 0; i < num_transitions; ++i)
Packit Service 82fcde
	transitions[i] = decode64 ((char *) transitions + i * 8);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  for (i = 0; i < num_types; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      unsigned char x[4];
Packit Service 82fcde
      int c;
Packit Service 82fcde
      if (__builtin_expect (__fread_unlocked (x, 1,
Packit Service 82fcde
					      sizeof (x), f) != sizeof (x),
Packit Service 82fcde
			    0))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      c = __getc_unlocked (f);
Packit Service 82fcde
      if (__glibc_unlikely ((unsigned int) c > 1u))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      types[i].isdst = c;
Packit Service 82fcde
      c = __getc_unlocked (f);
Packit Service 82fcde
      if (__glibc_unlikely ((size_t) c > chars))
Packit Service 82fcde
	/* Bogus index in data file.  */
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      types[i].idx = c;
Packit Service 82fcde
      types[i].offset = (long int) decode (x);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (__glibc_unlikely (__fread_unlocked (zone_names, 1, chars, f) != chars))
Packit Service 82fcde
    goto lose;
Packit Service 82fcde
Packit Service 82fcde
  for (i = 0; i < num_leaps; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      unsigned char x[8];
Packit Service 82fcde
      if (__builtin_expect (__fread_unlocked (x, 1, trans_width, f)
Packit Service 82fcde
			    != trans_width, 0))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      if (trans_width == 4)
Packit Service 82fcde
	leaps[i].transition = decode (x);
Packit Service 82fcde
      else
Packit Service 82fcde
	leaps[i].transition = decode64 (x);
Packit Service 82fcde
Packit Service 82fcde
      if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      leaps[i].change = (long int) decode (x);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  for (i = 0; i < num_isstd; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      int c = __getc_unlocked (f);
Packit Service 82fcde
      if (__glibc_unlikely (c == EOF))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      types[i].isstd = c != 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  while (i < num_types)
Packit Service 82fcde
    types[i++].isstd = 0;
Packit Service 82fcde
Packit Service 82fcde
  for (i = 0; i < num_isgmt; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      int c = __getc_unlocked (f);
Packit Service 82fcde
      if (__glibc_unlikely (c == EOF))
Packit Service 82fcde
	goto lose;
Packit Service 82fcde
      types[i].isgmt = c != 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  while (i < num_types)
Packit Service 82fcde
    types[i++].isgmt = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Read the POSIX TZ-style information if possible.  */
Packit Service 82fcde
  if (tzspec != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Skip over the newline first.  */
Packit Service 82fcde
      if (__getc_unlocked (f) != '\n'
Packit Service 82fcde
	  || (__fread_unlocked (tzspec, 1, tzspec_len - 1, f)
Packit Service 82fcde
	      != tzspec_len - 1))
Packit Service 82fcde
	tzspec = NULL;
Packit Service 82fcde
      else
Packit Service 82fcde
	tzspec[tzspec_len - 1] = '\0';
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Don't use an empty TZ string.  */
Packit Service 82fcde
  if (tzspec != NULL && tzspec[0] == '\0')
Packit Service 82fcde
    tzspec = NULL;
Packit Service 82fcde
Packit Service 82fcde
  fclose (f);
Packit Service 82fcde
Packit Service 82fcde
  /* First "register" all timezone names.  */
Packit Service 82fcde
  for (i = 0; i < num_types; ++i)
Packit Service 05ca94
    if (__tzstring (&zone_names[types[i].idx]) == NULL)
Packit Service 05ca94
      goto ret_free_transitions;
Packit Service 82fcde
Packit Service 82fcde
  /* Find the standard and daylight time offsets used by the rule file.
Packit Service 82fcde
     We choose the offsets in the types of each flavor that are
Packit Service 82fcde
     transitioned to earliest in time.  */
Packit Service 82fcde
  __tzname[0] = NULL;
Packit Service 82fcde
  __tzname[1] = NULL;
Packit Service 82fcde
  for (i = num_transitions; i > 0; )
Packit Service 82fcde
    {
Packit Service 82fcde
      int type = type_idxs[--i];
Packit Service 82fcde
      int dst = types[type].isdst;
Packit Service 82fcde
Packit Service 82fcde
      if (__tzname[dst] == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  int idx = types[type].idx;
Packit Service 82fcde
Packit Service 82fcde
	  __tzname[dst] = __tzstring (&zone_names[idx]);
Packit Service 82fcde
Packit Service 82fcde
	  if (__tzname[1 - dst] != NULL)
Packit Service 82fcde
	    break;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  if (__tzname[0] == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* This should only happen if there are no transition rules.
Packit Service 82fcde
	 In this case there should be only one single type.  */
Packit Service 82fcde
      assert (num_types == 1);
Packit Service 82fcde
      __tzname[0] = __tzstring (zone_names);
Packit Service 82fcde
    }
Packit Service 82fcde
  if (__tzname[1] == NULL)
Packit Service 82fcde
    __tzname[1] = __tzname[0];
Packit Service 82fcde
Packit Service 82fcde
  if (num_transitions == 0)
Packit Service 82fcde
    /* Use the first rule (which should also be the only one).  */
Packit Service 82fcde
    rule_stdoff = rule_dstoff = types[0].offset;
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      int stdoff_set = 0, dstoff_set = 0;
Packit Service 82fcde
      rule_stdoff = rule_dstoff = 0;
Packit Service 82fcde
      i = num_transitions - 1;
Packit Service 82fcde
      do
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (!stdoff_set && !types[type_idxs[i]].isdst)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      stdoff_set = 1;
Packit Service 82fcde
	      rule_stdoff = types[type_idxs[i]].offset;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  else if (!dstoff_set && types[type_idxs[i]].isdst)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      dstoff_set = 1;
Packit Service 82fcde
	      rule_dstoff = types[type_idxs[i]].offset;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  if (stdoff_set && dstoff_set)
Packit Service 82fcde
	    break;
Packit Service 82fcde
	}
Packit Service 82fcde
      while (i-- > 0);
Packit Service 82fcde
Packit Service 82fcde
      if (!dstoff_set)
Packit Service 82fcde
	rule_dstoff = rule_stdoff;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __daylight = rule_stdoff != rule_dstoff;
Packit Service 82fcde
  __timezone = -rule_stdoff;
Packit Service 82fcde
Packit Service 82fcde
 done:
Packit Service 82fcde
  __use_tzfile = 1;
Packit Service 82fcde
  free (new);
Packit Service 82fcde
  return;
Packit Service 82fcde
Packit Service 82fcde
 lose:
Packit Service 82fcde
  fclose (f);
Packit Service 82fcde
 ret_free_transitions:
Packit Service 82fcde
  free (new);
Packit Service 82fcde
  free ((void *) transitions);
Packit Service 82fcde
  transitions = NULL;
Packit Service 82fcde
}
Packit Service 82fcde

Packit Service 82fcde
/* The user specified a hand-made timezone, but not its DST rules.
Packit Service 82fcde
   We will use the names and offsets from the user, and the rules
Packit Service 82fcde
   from the TZDEFRULES file.  */
Packit Service 82fcde
Packit Service 82fcde
void
Packit Service 82fcde
__tzfile_default (const char *std, const char *dst,
Packit Service 82fcde
		  long int stdoff, long int dstoff)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t stdlen = strlen (std) + 1;
Packit Service 82fcde
  size_t dstlen = strlen (dst) + 1;
Packit Service 82fcde
  size_t i;
Packit Service 82fcde
  int isdst;
Packit Service 82fcde
  char *cp;
Packit Service 82fcde
Packit Service 82fcde
  __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp;;
Packit Service 82fcde
  if (!__use_tzfile)
Packit Service 82fcde
    return;
Packit Service 82fcde
Packit Service 82fcde
  if (num_types < 2)
Packit Service 82fcde
    {
Packit Service 82fcde
      __use_tzfile = 0;
Packit Service 82fcde
      return;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Ignore the zone names read from the file and use the given ones
Packit Service 82fcde
     instead.  */
Packit Service 82fcde
  __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
Packit Service 82fcde
  zone_names = cp;
Packit Service 82fcde
Packit Service 82fcde
  /* Now there are only two zones, regardless of what the file contained.  */
Packit Service 82fcde
  num_types = 2;
Packit Service 82fcde
Packit Service 82fcde
  /* Now correct the transition times for the user-specified standard and
Packit Service 82fcde
     daylight offsets from GMT.  */
Packit Service 82fcde
  isdst = 0;
Packit Service 82fcde
  for (i = 0; i < num_transitions; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      struct ttinfo *trans_type = &types[type_idxs[i]];
Packit Service 82fcde
Packit Service 82fcde
      /* We will use only types 0 (standard) and 1 (daylight).
Packit Service 82fcde
	 Fix up this transition to point to whichever matches
Packit Service 82fcde
	 the flavor of its original type.  */
Packit Service 82fcde
      type_idxs[i] = trans_type->isdst;
Packit Service 82fcde
Packit Service 82fcde
      if (trans_type->isgmt)
Packit Service 82fcde
	/* The transition time is in GMT.  No correction to apply.  */ ;
Packit Service 82fcde
      else if (isdst && !trans_type->isstd)
Packit Service 82fcde
	/* The type says this transition is in "local wall clock time", and
Packit Service 82fcde
	   wall clock time as of the previous transition was DST.  Correct
Packit Service 82fcde
	   for the difference between the rule's DST offset and the user's
Packit Service 82fcde
	   DST offset.  */
Packit Service 82fcde
	transitions[i] += dstoff - rule_dstoff;
Packit Service 82fcde
      else
Packit Service 82fcde
	/* This transition is in "local wall clock time", and wall clock
Packit Service 82fcde
	   time as of this iteration is non-DST.  Correct for the
Packit Service 82fcde
	   difference between the rule's standard offset and the user's
Packit Service 82fcde
	   standard offset.  */
Packit Service 82fcde
	transitions[i] += stdoff - rule_stdoff;
Packit Service 82fcde
Packit Service 82fcde
      /* The DST state of "local wall clock time" for the next iteration is
Packit Service 82fcde
	 as specified by this transition.  */
Packit Service 82fcde
      isdst = trans_type->isdst;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Now that we adjusted the transitions to the requested offsets,
Packit Service 82fcde
     reset the rule_stdoff and rule_dstoff values appropriately.  They
Packit Service 82fcde
     are used elsewhere.  */
Packit Service 82fcde
  rule_stdoff = stdoff;
Packit Service 82fcde
  rule_dstoff = dstoff;
Packit Service 82fcde
Packit Service 82fcde
  /* Reset types 0 and 1 to describe the user's settings.  */
Packit Service 82fcde
  types[0].idx = 0;
Packit Service 82fcde
  types[0].offset = stdoff;
Packit Service 82fcde
  types[0].isdst = 0;
Packit Service 82fcde
  types[1].idx = stdlen;
Packit Service 82fcde
  types[1].offset = dstoff;
Packit Service 82fcde
  types[1].isdst = 1;
Packit Service 82fcde
Packit Service 82fcde
  /* Reset the zone names to point to the user's names.  */
Packit Service 82fcde
  __tzname[0] = (char *) std;
Packit Service 82fcde
  __tzname[1] = (char *) dst;
Packit Service 82fcde
Packit Service 82fcde
  /* Set the timezone.  */
Packit Service 82fcde
  __timezone = -types[0].offset;
Packit Service 82fcde
Packit Service 82fcde
  /* Invalidate the tzfile attribute cache to force rereading
Packit Service 82fcde
     TZDEFRULES the next time it is used.  */
Packit Service 82fcde
  tzfile_dev = 0;
Packit Service 82fcde
  tzfile_ino = 0;
Packit Service 82fcde
  tzfile_mtime = 0;
Packit Service 82fcde
}
Packit Service 82fcde

Packit Service 82fcde
void
Packit Service 82fcde
__tzfile_compute (internal_time_t timer, int use_localtime,
Packit Service 82fcde
		  long int *leap_correct, int *leap_hit,
Packit Service 82fcde
		  struct tm *tp)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t i;
Packit Service 82fcde
Packit Service 82fcde
  if (use_localtime)
Packit Service 82fcde
    {
Packit Service 82fcde
      __tzname[0] = NULL;
Packit Service 82fcde
      __tzname[1] = NULL;
Packit Service 82fcde
Packit Service 82fcde
      if (__glibc_unlikely (num_transitions == 0 || timer < transitions[0]))
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* TIMER is before any transition (or there are no transitions).
Packit Service 82fcde
	     Choose the first non-DST type
Packit Service 82fcde
	     (or the first if they're all DST types).  */
Packit Service 82fcde
	  i = 0;
Packit Service 82fcde
	  while (i < num_types && types[i].isdst)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      if (__tzname[1] == NULL)
Packit Service 82fcde
		__tzname[1] = __tzstring (&zone_names[types[i].idx]);
Packit Service 82fcde
Packit Service 82fcde
	      ++i;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  if (i == num_types)
Packit Service 82fcde
	    i = 0;
Packit Service 82fcde
	  __tzname[0] = __tzstring (&zone_names[types[i].idx]);
Packit Service 82fcde
	  if (__tzname[1] == NULL)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      size_t j = i;
Packit Service 82fcde
	      while (j < num_types)
Packit Service 82fcde
		if (types[j].isdst)
Packit Service 82fcde
		  {
Packit Service 82fcde
		    __tzname[1] = __tzstring (&zone_names[types[j].idx]);
Packit Service 82fcde
		    break;
Packit Service 82fcde
		  }
Packit Service 82fcde
		else
Packit Service 82fcde
		  ++j;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
      else if (__glibc_unlikely (timer >= transitions[num_transitions - 1]))
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (__glibc_unlikely (tzspec == NULL))
Packit Service 82fcde
	    {
Packit Service 82fcde
	    use_last:
Packit Service 82fcde
	      i = num_transitions;
Packit Service 82fcde
	      goto found;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Parse the POSIX TZ-style string.  */
Packit Service 82fcde
	  __tzset_parse_tz (tzspec);
Packit Service 82fcde
Packit Service 82fcde
	  /* Convert to broken down structure.  If this fails do not
Packit Service 82fcde
	     use the string.  */
Packit Service 82fcde
	  {
Packit Service 82fcde
	    time_t truncated = timer;
Packit Service 82fcde
	    if (__glibc_unlikely (truncated != timer
Packit Service 82fcde
				  || ! __offtime (&truncated, 0, tp)))
Packit Service 82fcde
	      goto use_last;
Packit Service 82fcde
	  }
Packit Service 82fcde
Packit Service 82fcde
	  /* Use the rules from the TZ string to compute the change.
Packit Service 82fcde
	     timer fits into time_t due to the truncation check
Packit Service 82fcde
	     above.  */
Packit Service 82fcde
	  __tz_compute (timer, tp, 1);
Packit Service 82fcde
Packit Service 82fcde
	  /* If tzspec comes from posixrules loaded by __tzfile_default,
Packit Service 82fcde
	     override the STD and DST zone names with the ones user
Packit Service 82fcde
	     requested in TZ envvar.  */
Packit Service 82fcde
	  if (__glibc_unlikely (zone_names == (char *) &leaps[num_leaps]))
Packit Service 82fcde
	    {
Packit Service 82fcde
	      assert (num_types == 2);
Packit Service 82fcde
	      __tzname[0] = __tzstring (zone_names);
Packit Service 82fcde
	      __tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  goto leap;
Packit Service 82fcde
	}
Packit Service 82fcde
      else
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* Find the first transition after TIMER, and
Packit Service 82fcde
	     then pick the type of the transition before it.  */
Packit Service 82fcde
	  size_t lo = 0;
Packit Service 82fcde
	  size_t hi = num_transitions - 1;
Packit Service 82fcde
	  /* Assume that DST is changing twice a year and guess
Packit Service 82fcde
	     initial search spot from it.  Half of a gregorian year
Packit Service 82fcde
	     has on average 365.2425 * 86400 / 2 = 15778476 seconds.
Packit Service 82fcde
	     The value i can be truncated if size_t is smaller than
Packit Service 82fcde
	     internal_time_t, but this is harmless because it is just
Packit Service 82fcde
	     a guess.  */
Packit Service 82fcde
	  i = (transitions[num_transitions - 1] - timer) / 15778476;
Packit Service 82fcde
	  if (i < num_transitions)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      i = num_transitions - 1 - i;
Packit Service 82fcde
	      if (timer < transitions[i])
Packit Service 82fcde
		{
Packit Service 82fcde
		  if (i < 10 || timer >= transitions[i - 10])
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* Linear search.  */
Packit Service 82fcde
		      while (timer < transitions[i - 1])
Packit Service 82fcde
			--i;
Packit Service 82fcde
		      goto found;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  hi = i - 10;
Packit Service 82fcde
		}
Packit Service 82fcde
	      else
Packit Service 82fcde
		{
Packit Service 82fcde
		  if (i + 10 >= num_transitions || timer < transitions[i + 10])
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* Linear search.  */
Packit Service 82fcde
		      while (timer >= transitions[i])
Packit Service 82fcde
			++i;
Packit Service 82fcde
		      goto found;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  lo = i + 10;
Packit Service 82fcde
		}
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Binary search.  */
Packit Service 82fcde
	  /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
Packit Service 82fcde
	  while (lo + 1 < hi)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      i = (lo + hi) / 2;
Packit Service 82fcde
	      if (timer < transitions[i])
Packit Service 82fcde
		hi = i;
Packit Service 82fcde
	      else
Packit Service 82fcde
		lo = i;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  i = hi;
Packit Service 82fcde
Packit Service 82fcde
	found:
Packit Service 82fcde
	  /* assert (timer >= transitions[i - 1]
Packit Service 82fcde
	     && (i == num_transitions || timer < transitions[i])); */
Packit Service 82fcde
	  __tzname[types[type_idxs[i - 1]].isdst]
Packit Service 82fcde
	    = __tzstring (&zone_names[types[type_idxs[i - 1]].idx]);
Packit Service 82fcde
	  size_t j = i;
Packit Service 82fcde
	  while (j < num_transitions)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      int type = type_idxs[j];
Packit Service 82fcde
	      int dst = types[type].isdst;
Packit Service 82fcde
	      int idx = types[type].idx;
Packit Service 82fcde
Packit Service 82fcde
	      if (__tzname[dst] == NULL)
Packit Service 82fcde
		{
Packit Service 82fcde
		  __tzname[dst] = __tzstring (&zone_names[idx]);
Packit Service 82fcde
Packit Service 82fcde
		  if (__tzname[1 - dst] != NULL)
Packit Service 82fcde
		    break;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      ++j;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  if (__glibc_unlikely (__tzname[0] == NULL))
Packit Service 82fcde
	    __tzname[0] = __tzname[1];
Packit Service 82fcde
Packit Service 82fcde
	  i = type_idxs[i - 1];
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      struct ttinfo *info = &types[i];
Packit Service 82fcde
      __daylight = rule_stdoff != rule_dstoff;
Packit Service 82fcde
      __timezone = -rule_stdoff;
Packit Service 82fcde
Packit Service 82fcde
      if (__tzname[0] == NULL)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* This should only happen if there are no transition rules.
Packit Service 82fcde
	     In this case there should be only one single type.  */
Packit Service 82fcde
	  assert (num_types == 1);
Packit Service 82fcde
	  __tzname[0] = __tzstring (zone_names);
Packit Service 82fcde
	}
Packit Service 82fcde
      if (__tzname[1] == NULL)
Packit Service 82fcde
	/* There is no daylight saving time.  */
Packit Service 82fcde
	__tzname[1] = __tzname[0];
Packit Service 82fcde
      tp->tm_isdst = info->isdst;
Packit Service 82fcde
      assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0);
Packit Service 82fcde
      tp->tm_zone = __tzname[tp->tm_isdst];
Packit Service 82fcde
      tp->tm_gmtoff = info->offset;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
 leap:
Packit Service 82fcde
  *leap_correct = 0L;
Packit Service 82fcde
  *leap_hit = 0;
Packit Service 82fcde
Packit Service 82fcde
  /* Find the last leap second correction transition time before TIMER.  */
Packit Service 82fcde
  i = num_leaps;
Packit Service 82fcde
  do
Packit Service 82fcde
    if (i-- == 0)
Packit Service 82fcde
      return;
Packit Service 82fcde
  while (timer < leaps[i].transition);
Packit Service 82fcde
Packit Service 82fcde
  /* Apply its correction.  */
Packit Service 82fcde
  *leap_correct = leaps[i].change;
Packit Service 82fcde
Packit Service 82fcde
  if (timer == leaps[i].transition && /* Exactly at the transition time.  */
Packit Service 82fcde
      ((i == 0 && leaps[i].change > 0) ||
Packit Service 82fcde
       leaps[i].change > leaps[i - 1].change))
Packit Service 82fcde
    {
Packit Service 82fcde
      *leap_hit = 1;
Packit Service 82fcde
      while (i > 0
Packit Service 82fcde
	     && leaps[i].transition == leaps[i - 1].transition + 1
Packit Service 82fcde
	     && leaps[i].change == leaps[i - 1].change + 1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  ++*leap_hit;
Packit Service 82fcde
	  --i;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
}