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

source code of glibc/time/tzfile.c