struct stat64 st; if (fstat64 (fileno (f), &st) != 0) { fclose (f); return; } if (was_using_tzfile && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev) {  fclose (f); __use_tzfile = 1; return; }   tzfile_dev = st.st_dev; tzfile_ino = st.st_ino;
__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;  __use_tzfile = 0;  if (transitions != NULL)    free ((void *) transitions);  transitions = NULL;  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.  */    return;  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.  */	return;    }  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;    }  /* Note the file is opened with cancellation in the I/O functions     disabled.  */  f = fopen (file, "rc");  if (f == NULL)    return;  /* No threads reading this stream.  */  __fsetlocking (f, FSETLOCKING_BYCALLER);  if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),					1, f) != 1, 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);  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);  /* This is for the extra memory required by the caller.  */  total_size += extra;  transitions = (time_t *) malloc (total_size);  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 (extra > 0)    *extrap = (char *) &leaps[num_leaps];  if (sizeof (time_t) < 4)    abort ();  if (sizeof (time_t) == 4)    {      if (__builtin_expect (fread_unlocked (transitions, 1,					    (4 + 1) * num_transitions, f)			    != (4 + 1) * 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)    {      /* 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);    }  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[4];      if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),			    0))	goto lose;      leaps[i].transition = (time_t) decode (x);      if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),			    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;  fclose (f);  /* First "register" all timezone names.  */  for (i = 0; i < num_types; ++i)    (void) __tzstring (&zone_names[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; )    {      int type = type_idxs[--i];      int dst = types[type].isdst;      if (__tzname[dst] == NULL)	{	  int idx = types[type].idx;	  __tzname[dst] = __tzstring (&zone_names[idx]);	  if (__tzname[1 - dst] != NULL)	    break;	}    }  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);    }  if (__tzname[1] == NULL)    __tzname[1] = __tzname[0];  compute_tzname_max (chars);  if (num_transitions == 0)    /* Use the first rule (which should also be the only one).  */    rule_stdoff = rule_dstoff = types[0].offset;  else    {      int stdoff_set = 0, dstoff_set = 0;      rule_stdoff = rule_dstoff = 0;      i = num_transitions - 1;      do	{	  if (!stdoff_set && !types[type_idxs[i]].isdst)	    {	      stdoff_set = 1;	      rule_stdoff = types[type_idxs[i]].offset;	    }	  else if (!dstoff_set && types[type_idxs[i]].isdst)	    {	      dstoff_set = 1;	      rule_dstoff = types[type_idxs[i]].offset;	    }	  if (stdoff_set && dstoff_set)	    break;	}      while (i-- > 0);      if (!dstoff_set)	rule_dstoff = rule_stdoff;    }  __daylight = rule_stdoff != rule_dstoff;  __timezone = -rule_stdoff;  __use_tzfile = 1;  return; lose:  fclose (f);}