ia64: Regenerate ulps
[glibc.git] / time / tzfile.c
blob55508c154b64313ad99700f888171aeed83cf29c
1 /* Copyright (C) 1991-2023 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 __time64_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 /* Used to restore the daylight variable during time conversion, as if
65 tzset had been called. */
66 static int daylight_saved;
68 #include <endian.h>
69 #include <byteswap.h>
71 /* Decode the four bytes at PTR as a signed integer in network byte order. */
72 static inline int
73 __attribute ((always_inline))
74 decode (const void *ptr)
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);
81 const unsigned char *p = ptr;
82 int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
84 result = (result << 8) | *p++;
85 result = (result << 8) | *p++;
86 result = (result << 8) | *p++;
87 result = (result << 8) | *p++;
89 return result;
93 static inline int64_t
94 __attribute ((always_inline))
95 decode64 (const void *ptr)
97 if ((BYTE_ORDER == BIG_ENDIAN))
98 return *(const int64_t *) ptr;
100 return bswap_64 (*(const int64_t *) ptr);
104 void
105 __tzfile_read (const char *file, size_t extra, char **extrap)
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;
117 _Static_assert (sizeof (__time64_t) == 8,
118 "__time64_t must be eight bytes");
120 __use_tzfile = 0;
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
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;
144 if (*file != '/')
146 const char *tzdir;
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;
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. */
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;
170 /* Get information about the file we are actually using. */
171 if (__fstat64_time64 (__fileno (f), &st) != 0)
172 goto lose;
174 free ((void *) transitions);
175 transitions = NULL;
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;
182 /* No threads reading this stream. */
183 __fsetlocking (f, FSETLOCKING_BYCALLER);
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;
191 num_transitions = (size_t) decode (tzhead.tzh_timecnt);
192 num_types = (size_t) decode (tzhead.tzh_typecnt);
193 chars = (size_t) decode (tzhead.tzh_charcnt);
194 num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
195 num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
196 num_isgmt = (size_t) decode (tzhead.tzh_ttisutcnt);
198 if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
199 goto lose;
201 if (trans_width == 4 && tzhead.tzh_version[0] != '\0')
203 /* We use the 8-byte format. */
204 trans_width = 8;
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;
216 goto read_again;
219 /* Compute the size of the POSIX time zone specification in the
220 file. */
221 size_t tzspec_len;
222 if (trans_width == 8)
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;
246 else
247 tzspec_len = 0;
249 /* The file is parsed into a single heap allocation, comprising of
250 the following arrays:
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.
260 The piece-wise allocations from buf below verify that no
261 overflow/wraparound occurred in these computations.
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;
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 (total_size);
280 if (transitions == NULL)
281 goto lose;
282 buf = alloc_buffer_create (transitions, total_size);
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))
299 goto lose;
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;
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;
314 if (trans_width == 4)
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 ((char *) transitions + i * 4);
324 else if (BYTE_ORDER != BIG_ENDIAN)
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 ((char *) transitions + i * 8);
332 for (i = 0; i < num_types; ++i)
334 unsigned char x[4];
335 int c;
336 if (__builtin_expect (__fread_unlocked (x, 1,
337 sizeof (x), f) != sizeof (x),
339 goto lose;
340 c = __getc_unlocked (f);
341 if (__glibc_unlikely ((unsigned int) c > 1u))
342 goto lose;
343 types[i].isdst = c;
344 c = __getc_unlocked (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 (x);
352 if (__glibc_unlikely (__fread_unlocked (zone_names, 1, chars, f) != chars))
353 goto lose;
355 for (i = 0; i < num_leaps; ++i)
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 (x);
363 else
364 leaps[i].transition = decode64 (x);
366 if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4))
367 goto lose;
368 leaps[i].change = (long int) decode (x);
371 for (i = 0; i < num_isstd; ++i)
373 int c = __getc_unlocked (f);
374 if (__glibc_unlikely (c == EOF))
375 goto lose;
376 types[i].isstd = c != 0;
378 while (i < num_types)
379 types[i++].isstd = 0;
381 for (i = 0; i < num_isgmt; ++i)
383 int c = __getc_unlocked (f);
384 if (__glibc_unlikely (c == EOF))
385 goto lose;
386 types[i].isgmt = c != 0;
388 while (i < num_types)
389 types[i++].isgmt = 0;
391 /* Read the POSIX TZ-style information if possible. */
392 if (tzspec != NULL)
394 assert (tzspec_len > 0);
395 /* Skip over the newline first. */
396 if (__getc_unlocked (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';
404 /* Don't use an empty TZ string. */
405 if (tzspec != NULL && tzspec[0] == '\0')
406 tzspec = NULL;
408 fclose (f);
410 /* First "register" all timezone names. */
411 for (i = 0; i < num_types; ++i)
412 if (__tzstring (&zone_names[types[i].idx]) == NULL)
413 goto ret_free_transitions;
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; )
422 int type = type_idxs[--i];
423 int dst = types[type].isdst;
425 if (__tzname[dst] == NULL)
427 int idx = types[type].idx;
429 __tzname[dst] = __tzstring (&zone_names[idx]);
431 if (__tzname[1 - dst] != NULL)
432 break;
435 if (__tzname[0] == NULL)
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 (zone_names);
442 if (__tzname[1] == NULL)
443 __tzname[1] = __tzname[0];
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
451 rule_stdoff = 0;
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;
457 if (!types[type_idxs[i]].isdst)
459 rule_stdoff = types[type_idxs[i]].offset;
460 break;
462 else
463 daylight_saved = 1;
464 while (i-- > 0);
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;
473 __daylight = daylight_saved;
474 __timezone = -rule_stdoff;
476 done:
477 __use_tzfile = 1;
478 free (new);
479 return;
481 lose:
482 fclose (f);
483 ret_free_transitions:
484 free (new);
485 free ((void *) transitions);
486 transitions = NULL;
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. */
493 void
494 __tzfile_default (const char *std, const char *dst,
495 int stdoff, int dstoff)
497 size_t stdlen = strlen (std) + 1;
498 size_t dstlen = strlen (dst) + 1;
499 size_t i;
500 int isdst;
501 char *cp;
503 __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
504 if (!__use_tzfile)
505 return;
507 if (num_types < 2)
509 __use_tzfile = 0;
510 return;
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;
518 /* Now there are only two zones, regardless of what the file contained. */
519 num_types = 2;
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)
526 struct ttinfo *trans_type = &types[type_idxs[i]];
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;
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;
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;
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;
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;
567 /* Reset the zone names to point to the user's names. */
568 __tzname[0] = (char *) std;
569 __tzname[1] = (char *) dst;
571 /* Set the timezone. */
572 __timezone = -types[0].offset;
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;
581 void
582 __tzfile_compute (__time64_t timer, int use_localtime,
583 long int *leap_correct, int *leap_hit,
584 struct tm *tp)
586 size_t i;
588 if (use_localtime)
590 __tzname[0] = NULL;
591 __tzname[1] = NULL;
593 if (__glibc_unlikely (num_transitions == 0 || timer < transitions[0]))
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)
601 if (__tzname[1] == NULL)
602 __tzname[1] = __tzstring (&zone_names[types[i].idx]);
604 ++i;
607 if (i == num_types)
608 i = 0;
609 __tzname[0] = __tzstring (&zone_names[types[i].idx]);
610 if (__tzname[1] == NULL)
612 size_t j = i;
613 while (j < num_types)
614 if (types[j].isdst)
616 __tzname[1] = __tzstring (&zone_names[types[j].idx]);
617 break;
619 else
620 ++j;
623 else if (__glibc_unlikely (timer >= transitions[num_transitions - 1]))
625 if (__glibc_unlikely (tzspec == NULL))
627 use_last:
628 i = num_transitions;
629 goto found;
632 /* Parse the POSIX TZ-style string. */
633 __tzset_parse_tz (tzspec);
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;
640 /* Use the rules from the TZ string to compute the change. */
641 __tz_compute (timer, tp, 1);
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]))
648 assert (num_types == 2);
649 __tzname[0] = __tzstring (zone_names);
650 __tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
653 goto leap;
655 else
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)
670 i = num_transitions - 1 - i;
671 if (timer < transitions[i])
673 if (i < 10 || timer >= transitions[i - 10])
675 /* Linear search. */
676 while (timer < transitions[i - 1])
677 --i;
678 goto found;
680 hi = i - 10;
682 else
684 if (i + 10 >= num_transitions || timer < transitions[i + 10])
686 /* Linear search. */
687 while (timer >= transitions[i])
688 ++i;
689 goto found;
691 lo = i + 10;
695 /* Binary search. */
696 /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
697 while (lo + 1 < hi)
699 i = (lo + hi) / 2;
700 if (timer < transitions[i])
701 hi = i;
702 else
703 lo = i;
705 i = hi;
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 (&zone_names[types[type_idxs[i - 1]].idx]);
712 size_t j = i;
713 while (j < num_transitions)
715 int type = type_idxs[j];
716 int dst = types[type].isdst;
717 int idx = types[type].idx;
719 if (__tzname[dst] == NULL)
721 __tzname[dst] = __tzstring (&zone_names[idx]);
723 if (__tzname[1 - dst] != NULL)
724 break;
727 ++j;
730 if (__glibc_unlikely (__tzname[0] == NULL))
731 __tzname[0] = __tzname[1];
733 i = type_idxs[i - 1];
736 struct ttinfo *info = &types[i];
737 __daylight = daylight_saved;
738 __timezone = -rule_stdoff;
740 if (__tzname[0] == NULL)
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 (zone_names);
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;
756 leap:
757 *leap_correct = 0L;
758 *leap_hit = 0;
760 /* Find the last leap second correction transition time before TIMER. */
761 i = num_leaps;
763 if (i-- == 0)
764 return;
765 while (timer < leaps[i].transition);
767 /* Apply its correction. */
768 *leap_correct = leaps[i].change;
770 if (timer == leaps[i].transition /* Exactly at the transition time. */
771 && (leaps[i].change > (i == 0 ? 0 : leaps[i - 1].change)))
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)
778 ++*leap_hit;
779 --i;