[v3,0/7] Fix some libm static issues
[platform/upstream/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991-2024 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17
18 #include <assert.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdio_ext.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <stdint.h>
28 #include <alloc_buffer.h>
29 #include <set-freeres.h>
30
31 #include <timezone/tzfile.h>
32
33 int __use_tzfile;
34 static dev_t tzfile_dev;
35 static ino64_t tzfile_ino;
36 static __time64_t tzfile_mtime;
37
38 struct ttinfo
39   {
40     int offset;                 /* Seconds east of GMT.  */
41     unsigned char isdst;        /* Used to set tm_isdst.  */
42     unsigned char idx;          /* Index into `zone_names'.  */
43     unsigned char isstd;        /* Transition times are in standard time.  */
44     unsigned char isgmt;        /* Transition times are in GMT.  */
45   };
46
47 struct leap
48   {
49     __time64_t transition;      /* Time the transition takes effect.  */
50     long int change;            /* Seconds of correction to apply.  */
51   };
52
53 static size_t num_transitions;
54 static __time64_t *transitions;
55 static unsigned char *type_idxs;
56 static size_t num_types;
57 static struct ttinfo *types;
58 static char *zone_names;
59 static long int rule_stdoff;
60 static long int rule_dstoff;
61 static size_t num_leaps;
62 static struct leap *leaps;
63 static char *tzspec;
64
65 /* Used to restore the daylight variable during time conversion, as if
66    tzset had been called.  */
67 static int daylight_saved;
68
69 #include <endian.h>
70 #include <byteswap.h>
71
72 /* Decode the four bytes at PTR as a signed integer in network byte order.  */
73 static inline int
74 __attribute ((always_inline))
75 decode (const void *ptr)
76 {
77   if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
78     return *(const int *) ptr;
79   if (sizeof (int) == 4)
80     return bswap_32 (*(const int *) ptr);
81
82   const unsigned char *p = ptr;
83   int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
84
85   result = (result << 8) | *p++;
86   result = (result << 8) | *p++;
87   result = (result << 8) | *p++;
88   result = (result << 8) | *p++;
89
90   return result;
91 }
92
93
94 static inline int64_t
95 __attribute ((always_inline))
96 decode64 (const void *ptr)
97 {
98   if ((BYTE_ORDER == BIG_ENDIAN))
99     return *(const int64_t *) ptr;
100
101   return bswap_64 (*(const int64_t *) ptr);
102 }
103
104
105 void
106 __tzfile_read (const char *file, size_t extra, char **extrap)
107 {
108   static const char default_tzdir[] = TZDIR;
109   size_t num_isstd, num_isgmt;
110   FILE *f;
111   struct tzhead tzhead;
112   size_t chars;
113   size_t i;
114   int was_using_tzfile = __use_tzfile;
115   int trans_width = 4;
116   char *new = NULL;
117
118   _Static_assert (sizeof (__time64_t) == 8,
119                   "__time64_t must be eight bytes");
120
121   __use_tzfile = 0;
122
123   if (file == NULL)
124     /* No user specification; use the site-wide default.  */
125     file = TZDEFAULT;
126   else if (*file == '\0')
127     /* User specified the empty string; use UTC with no leap seconds.  */
128     goto ret_free_transitions;
129   else
130     {
131       /* We must not allow to read an arbitrary file in a setuid
132          program.  So we fail for any file which is not in the
133          directory hierarchy starting at TZDIR
134          and which is not the system wide default TZDEFAULT.  */
135       if (__libc_enable_secure
136           && ((*file == '/'
137                && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
138                && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
139               || strstr (file, "../") != NULL))
140         /* This test is certainly a bit too restrictive but it should
141            catch all critical cases.  */
142         goto ret_free_transitions;
143     }
144
145   if (*file != '/')
146     {
147       const char *tzdir;
148
149       tzdir = getenv ("TZDIR");
150       if (tzdir == NULL || *tzdir == '\0')
151         tzdir = default_tzdir;
152       if (__asprintf (&new, "%s/%s", tzdir, file) == -1)
153         goto ret_free_transitions;
154       file = new;
155     }
156
157   /* If we were already using tzfile, check whether the file changed.  */
158   struct __stat64_t64 st;
159   if (was_using_tzfile
160       && __stat64_time64 (file, &st) == 0
161       && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
162       && tzfile_mtime == st.st_mtime)
163     goto done;  /* Nothing to do.  */
164
165   /* Note the file is opened with cancellation in the I/O functions
166      disabled and if available FD_CLOEXEC set.  */
167   f = fopen (file, "rce");
168   if (f == NULL)
169     goto ret_free_transitions;
170
171   /* Get information about the file we are actually using.  */
172   if (__fstat64_time64 (__fileno (f), &st) != 0)
173     goto lose;
174
175   free ((void *) transitions);
176   transitions = NULL;
177
178   /* Remember the inode and device number and modification time.  */
179   tzfile_dev = st.st_dev;
180   tzfile_ino = st.st_ino;
181   tzfile_mtime = st.st_mtime;
182
183   /* No threads reading this stream.  */
184   __fsetlocking (f, FSETLOCKING_BYCALLER);
185
186  read_again:
187   if (__builtin_expect (__fread_unlocked ((void *) &tzhead, sizeof (tzhead),
188                                           1, f) != 1, 0)
189       || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
190     goto lose;
191
192   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
193   num_types = (size_t) decode (tzhead.tzh_typecnt);
194   chars = (size_t) decode (tzhead.tzh_charcnt);
195   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
196   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
197   num_isgmt = (size_t) decode (tzhead.tzh_ttisutcnt);
198
199   if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
200     goto lose;
201
202   if (trans_width == 4 && tzhead.tzh_version[0] != '\0')
203     {
204       /* We use the 8-byte format.  */
205       trans_width = 8;
206
207       /* Position the stream before the second header.  */
208       size_t to_skip = (num_transitions * (4 + 1)
209                         + num_types * 6
210                         + chars
211                         + num_leaps * 8
212                         + num_isstd
213                         + num_isgmt);
214       if (fseek (f, to_skip, SEEK_CUR) != 0)
215         goto lose;
216
217       goto read_again;
218     }
219
220   /* Compute the size of the POSIX time zone specification in the
221      file.  */
222   size_t tzspec_len;
223   if (trans_width == 8)
224     {
225       off_t rem = st.st_size - __ftello (f);
226       if (__builtin_expect (rem < 0
227                             || (size_t) rem < (num_transitions * (8 + 1)
228                                                + num_types * 6
229                                                + chars), 0))
230         goto lose;
231       tzspec_len = (size_t) rem - (num_transitions * (8 + 1)
232                                    + num_types * 6
233                                    + chars);
234       if (__builtin_expect (num_leaps > SIZE_MAX / 12
235                             || tzspec_len < num_leaps * 12, 0))
236         goto lose;
237       tzspec_len -= num_leaps * 12;
238       if (__glibc_unlikely (tzspec_len < num_isstd))
239         goto lose;
240       tzspec_len -= num_isstd;
241       if (__glibc_unlikely (tzspec_len == 0 || tzspec_len - 1 < num_isgmt))
242         goto lose;
243       tzspec_len -= num_isgmt + 1;
244       if (tzspec_len == 0)
245         goto lose;
246     }
247   else
248     tzspec_len = 0;
249
250   /* The file is parsed into a single heap allocation, comprising of
251      the following arrays:
252
253      __time64_t transitions[num_transitions];
254      struct leap leaps[num_leaps];
255      struct ttinfo types[num_types];
256      unsigned char type_idxs[num_types];
257      char zone_names[chars];
258      char tzspec[tzspec_len];
259      char extra_array[extra]; // Stored into *pextras if requested.
260
261      The piece-wise allocations from buf below verify that no
262      overflow/wraparound occurred in these computations.
263
264      The order of the suballocations is important for alignment
265      purposes.  __time64_t outside a struct may require more alignment
266      then inside a struct on some architectures, so it must come
267      first. */
268   _Static_assert (__alignof (__time64_t) >= __alignof (struct leap),
269                   "alignment of __time64_t");
270   _Static_assert (__alignof (struct leap) >= __alignof (struct ttinfo),
271                   "alignment of struct leap");
272   struct alloc_buffer buf;
273   {
274     size_t total_size = (num_transitions * sizeof (__time64_t)
275                          + num_leaps * sizeof (struct leap)
276                          + num_types * sizeof (struct ttinfo)
277                          + num_transitions /* type_idxs */
278                          + chars /* zone_names */
279                          + tzspec_len + extra);
280     transitions = malloc (total_size);
281     if (transitions == NULL)
282       goto lose;
283     buf = alloc_buffer_create (transitions, total_size);
284   }
285
286   /* The address of the first allocation is already stored in the
287      pointer transitions.  */
288   (void) alloc_buffer_alloc_array (&buf, __time64_t, num_transitions);
289   leaps = alloc_buffer_alloc_array (&buf, struct leap, num_leaps);
290   types = alloc_buffer_alloc_array (&buf, struct ttinfo, num_types);
291   type_idxs = alloc_buffer_alloc_array (&buf, unsigned char, num_transitions);
292   zone_names = alloc_buffer_alloc_array (&buf, char, chars);
293   if (trans_width == 8)
294     tzspec = alloc_buffer_alloc_array (&buf, char, tzspec_len);
295   else
296     tzspec = NULL;
297   if (extra > 0)
298     *extrap = alloc_buffer_alloc_array (&buf, char, extra);
299   if (alloc_buffer_has_failed (&buf))
300     goto lose;
301
302   if (__glibc_unlikely (__fread_unlocked (transitions, trans_width,
303                                           num_transitions, f)
304                         != num_transitions)
305       || __glibc_unlikely (__fread_unlocked (type_idxs, 1, num_transitions, f)
306                            != num_transitions))
307         goto lose;
308
309   /* Check for bogus indices in the data file, so we can hereafter
310      safely use type_idxs[T] as indices into `types' and never crash.  */
311   for (i = 0; i < num_transitions; ++i)
312     if (__glibc_unlikely (type_idxs[i] >= num_types))
313       goto lose;
314
315   if (trans_width == 4)
316     {
317       /* Decode the transition times, stored as 4-byte integers in
318          network (big-endian) byte order.  We work from the end of the
319          array so as not to clobber the next element to be
320          processed.  */
321       i = num_transitions;
322       while (i-- > 0)
323         transitions[i] = decode ((char *) transitions + i * 4);
324     }
325   else if (BYTE_ORDER != BIG_ENDIAN)
326     {
327       /* Decode the transition times, stored as 8-byte integers in
328          network (big-endian) byte order.  */
329       for (i = 0; i < num_transitions; ++i)
330         transitions[i] = decode64 ((char *) transitions + i * 8);
331     }
332
333   for (i = 0; i < num_types; ++i)
334     {
335       unsigned char x[4];
336       int c;
337       if (__builtin_expect (__fread_unlocked (x, 1,
338                                               sizeof (x), f) != sizeof (x),
339                             0))
340         goto lose;
341       c = __getc_unlocked (f);
342       if (__glibc_unlikely ((unsigned int) c > 1u))
343         goto lose;
344       types[i].isdst = c;
345       c = __getc_unlocked (f);
346       if (__glibc_unlikely ((size_t) c > chars))
347         /* Bogus index in data file.  */
348         goto lose;
349       types[i].idx = c;
350       types[i].offset = decode (x);
351     }
352
353   if (__glibc_unlikely (__fread_unlocked (zone_names, 1, chars, f) != chars))
354     goto lose;
355
356   for (i = 0; i < num_leaps; ++i)
357     {
358       unsigned char x[8];
359       if (__builtin_expect (__fread_unlocked (x, 1, trans_width, f)
360                             != trans_width, 0))
361         goto lose;
362       if (trans_width == 4)
363         leaps[i].transition = decode (x);
364       else
365         leaps[i].transition = decode64 (x);
366
367       if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4))
368         goto lose;
369       leaps[i].change = (long int) decode (x);
370     }
371
372   for (i = 0; i < num_isstd; ++i)
373     {
374       int c = __getc_unlocked (f);
375       if (__glibc_unlikely (c == EOF))
376         goto lose;
377       types[i].isstd = c != 0;
378     }
379   while (i < num_types)
380     types[i++].isstd = 0;
381
382   for (i = 0; i < num_isgmt; ++i)
383     {
384       int c = __getc_unlocked (f);
385       if (__glibc_unlikely (c == EOF))
386         goto lose;
387       types[i].isgmt = c != 0;
388     }
389   while (i < num_types)
390     types[i++].isgmt = 0;
391
392   /* Read the POSIX TZ-style information if possible.  */
393   if (tzspec != NULL)
394     {
395       assert (tzspec_len > 0);
396       /* Skip over the newline first.  */
397       if (__getc_unlocked (f) != '\n'
398           || (__fread_unlocked (tzspec, 1, tzspec_len - 1, f)
399               != tzspec_len - 1))
400         tzspec = NULL;
401       else
402         tzspec[tzspec_len - 1] = '\0';
403     }
404
405   /* Don't use an empty TZ string.  */
406   if (tzspec != NULL && tzspec[0] == '\0')
407     tzspec = NULL;
408
409   fclose (f);
410
411   /* First "register" all time zone abbreviations.  */
412   for (i = 0; i < num_types; ++i)
413     if (__tzstring (&zone_names[types[i].idx]) == NULL)
414       goto ret_free_transitions;
415
416   /* Find the standard and daylight time offsets used by the rule file.
417      We choose the offsets in the types of each flavor that are
418      transitioned to earliest in time.  */
419   __tzname[0] = NULL;
420   __tzname[1] = NULL;
421   for (i = num_transitions; i > 0; )
422     {
423       int type = type_idxs[--i];
424       int dst = types[type].isdst;
425
426       if (__tzname[dst] == NULL)
427         {
428           int idx = types[type].idx;
429
430           __tzname[dst] = __tzstring (&zone_names[idx]);
431
432           if (__tzname[1 - dst] != NULL)
433             break;
434         }
435     }
436   if (__tzname[0] == NULL)
437     {
438       /* This should only happen if there are no transition rules.
439          In this case there's usually only one single type, unless
440          e.g. the data file has a truncated time-range.  */
441       __tzname[0] = __tzstring (zone_names);
442     }
443   if (__tzname[1] == NULL)
444     __tzname[1] = __tzname[0];
445
446   daylight_saved = 0;
447   if (num_transitions == 0)
448     /* Use the first rule (which should also be the only one).  */
449     rule_stdoff = rule_dstoff = types[0].offset;
450   else
451     {
452       rule_stdoff = 0;
453
454       /* Search for the last rule with a standard time offset.  This
455          will be used for the global timezone variable.  */
456       i = num_transitions - 1;
457       do
458         if (!types[type_idxs[i]].isdst)
459           {
460             rule_stdoff = types[type_idxs[i]].offset;
461             break;
462           }
463         else
464           daylight_saved = 1;
465       while (i-- > 0);
466
467       /* Keep searching to see if there is a DST rule.  This
468          information will be used to set the global daylight
469          variable.  */
470       while (i-- > 0 && !daylight_saved)
471         daylight_saved = types[type_idxs[i]].isdst;
472     }
473
474   __daylight = daylight_saved;
475   __timezone = -rule_stdoff;
476
477  done:
478   __use_tzfile = 1;
479   free (new);
480   return;
481
482  lose:
483   fclose (f);
484  ret_free_transitions:
485   free (new);
486   free ((void *) transitions);
487   transitions = NULL;
488 }
489 \f
490 /* The user specified a hand-made timezone, but not its DST rules.
491    We will use the names and offsets from the user, and the rules
492    from the TZDEFRULES file.  */
493
494 void
495 __tzfile_default (const char *std, const char *dst,
496                   int stdoff, int dstoff)
497 {
498   size_t stdlen = strlen (std) + 1;
499   size_t dstlen = strlen (dst) + 1;
500   size_t i;
501   int isdst;
502   char *cp;
503
504   __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
505   if (!__use_tzfile)
506     return;
507
508   if (num_types < 2)
509     {
510       __use_tzfile = 0;
511       return;
512     }
513
514   /* Ignore the zone names read from the file and use the given ones
515      instead.  */
516   __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
517   zone_names = cp;
518
519   /* Now there are only two zones, regardless of what the file contained.  */
520   num_types = 2;
521
522   /* Now correct the transition times for the user-specified standard and
523      daylight offsets from GMT.  */
524   isdst = 0;
525   for (i = 0; i < num_transitions; ++i)
526     {
527       struct ttinfo *trans_type = &types[type_idxs[i]];
528
529       /* We will use only types 0 (standard) and 1 (daylight).
530          Fix up this transition to point to whichever matches
531          the flavor of its original type.  */
532       type_idxs[i] = trans_type->isdst;
533
534       if (trans_type->isgmt)
535         /* The transition time is in GMT.  No correction to apply.  */ ;
536       else if (isdst && !trans_type->isstd)
537         /* The type says this transition is in "local wall clock time", and
538            wall clock time as of the previous transition was DST.  Correct
539            for the difference between the rule's DST offset and the user's
540            DST offset.  */
541         transitions[i] += dstoff - rule_dstoff;
542       else
543         /* This transition is in "local wall clock time", and wall clock
544            time as of this iteration is non-DST.  Correct for the
545            difference between the rule's standard offset and the user's
546            standard offset.  */
547         transitions[i] += stdoff - rule_stdoff;
548
549       /* The DST state of "local wall clock time" for the next iteration is
550          as specified by this transition.  */
551       isdst = trans_type->isdst;
552     }
553
554   /* Now that we adjusted the transitions to the requested offsets,
555      reset the rule_stdoff and rule_dstoff values appropriately.  They
556      are used elsewhere.  */
557   rule_stdoff = stdoff;
558   rule_dstoff = dstoff;
559
560   /* Reset types 0 and 1 to describe the user's settings.  */
561   types[0].idx = 0;
562   types[0].offset = stdoff;
563   types[0].isdst = 0;
564   types[1].idx = stdlen;
565   types[1].offset = dstoff;
566   types[1].isdst = 1;
567
568   /* Reset time zone abbreviations to point to the user's abbreviations.  */
569   __tzname[0] = (char *) std;
570   __tzname[1] = (char *) dst;
571
572   /* Set the timezone.  */
573   __timezone = -types[0].offset;
574
575   /* Invalidate the tzfile attribute cache to force rereading
576      TZDEFRULES the next time it is used.  */
577   tzfile_dev = 0;
578   tzfile_ino = 0;
579   tzfile_mtime = 0;
580 }
581 \f
582 void
583 __tzfile_compute (__time64_t timer, int use_localtime,
584                   long int *leap_correct, int *leap_hit,
585                   struct tm *tp)
586 {
587   size_t i;
588
589   if (use_localtime)
590     {
591       __tzname[0] = NULL;
592       __tzname[1] = NULL;
593
594       if (__glibc_unlikely (num_transitions == 0 || timer < transitions[0]))
595         {
596           /* TIMER is before any transition (or there are no transitions).
597              Choose the first non-DST type
598              (or the first if they're all DST types).  */
599           i = 0;
600           while (i < num_types && types[i].isdst)
601             {
602               if (__tzname[1] == NULL)
603                 __tzname[1] = __tzstring (&zone_names[types[i].idx]);
604
605               ++i;
606             }
607
608           if (i == num_types)
609             i = 0;
610           __tzname[0] = __tzstring (&zone_names[types[i].idx]);
611           if (__tzname[1] == NULL)
612             {
613               size_t j = i;
614               while (j < num_types)
615                 if (types[j].isdst)
616                   {
617                     __tzname[1] = __tzstring (&zone_names[types[j].idx]);
618                     break;
619                   }
620                 else
621                   ++j;
622             }
623         }
624       else if (__glibc_unlikely (timer >= transitions[num_transitions - 1]))
625         {
626           if (__glibc_unlikely (tzspec == NULL))
627             {
628             use_last:
629               i = num_transitions;
630               goto found;
631             }
632
633           /* Parse the POSIX TZ-style string.  */
634           __tzset_parse_tz (tzspec);
635
636           /* Convert to broken down structure.  If this fails do not
637              use the string.  */
638           if (__glibc_unlikely (! __offtime (timer, 0, tp)))
639             goto use_last;
640
641           /* Use the rules from the TZ string to compute the change.  */
642           __tz_compute (timer, tp, 1);
643
644           /* If tzspec comes from posixrules loaded by __tzfile_default,
645              override the STD and DST zone names with the ones user
646              requested in TZ envvar.  */
647           if (__glibc_unlikely (zone_names == (char *) &leaps[num_leaps]))
648             {
649               assert (num_types == 2);
650               __tzname[0] = __tzstring (zone_names);
651               __tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
652             }
653
654           goto leap;
655         }
656       else
657         {
658           /* Find the first transition after TIMER, and
659              then pick the type of the transition before it.  */
660           size_t lo = 0;
661           size_t hi = num_transitions - 1;
662           /* Assume that DST is changing twice a year and guess
663              initial search spot from it.  Half of a gregorian year
664              has on average 365.2425 * 86400 / 2 = 15778476 seconds.
665              The value i can be truncated if size_t is smaller than
666              __time64_t, but this is harmless because it is just
667              a guess.  */
668           i = (transitions[num_transitions - 1] - timer) / 15778476;
669           if (i < num_transitions)
670             {
671               i = num_transitions - 1 - i;
672               if (timer < transitions[i])
673                 {
674                   if (i < 10 || timer >= transitions[i - 10])
675                     {
676                       /* Linear search.  */
677                       while (timer < transitions[i - 1])
678                         --i;
679                       goto found;
680                     }
681                   hi = i - 10;
682                 }
683               else
684                 {
685                   if (i + 10 >= num_transitions || timer < transitions[i + 10])
686                     {
687                       /* Linear search.  */
688                       while (timer >= transitions[i])
689                         ++i;
690                       goto found;
691                     }
692                   lo = i + 10;
693                 }
694             }
695
696           /* Binary search.  */
697           /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
698           while (lo + 1 < hi)
699             {
700               i = (lo + hi) / 2;
701               if (timer < transitions[i])
702                 hi = i;
703               else
704                 lo = i;
705             }
706           i = hi;
707
708         found:
709           /* assert (timer >= transitions[i - 1]
710              && (i == num_transitions || timer < transitions[i])); */
711           __tzname[types[type_idxs[i - 1]].isdst]
712             = __tzstring (&zone_names[types[type_idxs[i - 1]].idx]);
713           size_t j = i;
714           while (j < num_transitions)
715             {
716               int type = type_idxs[j];
717               int dst = types[type].isdst;
718               int idx = types[type].idx;
719
720               if (__tzname[dst] == NULL)
721                 {
722                   __tzname[dst] = __tzstring (&zone_names[idx]);
723
724                   if (__tzname[1 - dst] != NULL)
725                     break;
726                 }
727
728               ++j;
729             }
730
731           if (__glibc_unlikely (__tzname[0] == NULL))
732             __tzname[0] = __tzname[1];
733
734           i = type_idxs[i - 1];
735         }
736
737       struct ttinfo *info = &types[i];
738       __daylight = daylight_saved;
739       __timezone = -rule_stdoff;
740
741       if (__tzname[0] == NULL)
742         {
743           /* This should only happen if there are no transition rules.
744              In this case there should be only one single type.  */
745           assert (num_types == 1);
746           __tzname[0] = __tzstring (zone_names);
747         }
748       if (__tzname[1] == NULL)
749         /* There is no daylight saving time.  */
750         __tzname[1] = __tzname[0];
751       tp->tm_isdst = info->isdst;
752       assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0);
753       tp->tm_zone = __tzname[tp->tm_isdst];
754       tp->tm_gmtoff = info->offset;
755     }
756
757  leap:
758   *leap_correct = 0L;
759   *leap_hit = 0;
760
761   /* Find the last leap second correction transition time before TIMER.  */
762   i = num_leaps;
763   do
764     if (i-- == 0)
765       return;
766   while (timer < leaps[i].transition);
767
768   /* Apply its correction.  */
769   *leap_correct = leaps[i].change;
770
771   if (timer == leaps[i].transition /* Exactly at the transition time.  */
772       && (leaps[i].change > (i == 0 ? 0 : leaps[i - 1].change)))
773     {
774       *leap_hit = 1;
775       while (i > 0
776              && leaps[i].transition == leaps[i - 1].transition + 1
777              && leaps[i].change == leaps[i - 1].change + 1)
778         {
779           ++*leap_hit;
780           --i;
781         }
782     }
783 }
784
785 weak_alias (transitions, __libc_tzfile_freemem_ptr)