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