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/>. */
21 #include <stdio_ext.h>
28 #include <alloc_buffer.h>
30 #include <timezone/tzfile.h>
33 static dev_t tzfile_dev
;
34 static ino64_t tzfile_ino
;
35 static time_t tzfile_mtime
;
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. */
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
;
67 /* Decode the four bytes at PTR as a signed integer in network byte order. */
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
++;
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
);
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
;
106 struct tzhead tzhead
;
109 int was_using_tzfile
= __use_tzfile
;
113 _Static_assert (sizeof (__time64_t
) == 8,
114 "__time64_t must be eight bytes");
119 /* No user specification; use the site-wide default. */
121 else if (*file
== '\0')
122 /* User specified the empty string; use UTC with no leap seconds. */
123 goto ret_free_transitions
;
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
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
;
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
;
152 /* If we were already using tzfile, check whether the file changed. */
153 struct __stat64_t64 st
;
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");
164 goto ret_free_transitions
;
166 /* Get information about the file we are actually using. */
167 if (__fstat64_time64 (__fileno (f
), &st
) != 0)
170 free ((void *) transitions
);
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
);
182 if (__builtin_expect (__fread_unlocked ((void *) &tzhead
, sizeof (tzhead
),
184 || memcmp (tzhead
.tzh_magic
, TZ_MAGIC
, sizeof (tzhead
.tzh_magic
)) != 0)
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
))
197 if (trans_width
== 4 && tzhead
.tzh_version
[0] != '\0')
199 /* We use the 8-byte format. */
202 /* Position the stream before the second header. */
203 size_t to_skip
= (num_transitions
* (4 + 1)
209 if (fseek (f
, to_skip
, SEEK_CUR
) != 0)
215 /* Compute the size of the POSIX time zone specification in the
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)
226 tzspec_len
= (size_t) rem
- (num_transitions
* (8 + 1)
229 if (__builtin_expect (num_leaps
> SIZE_MAX
/ 12
230 || tzspec_len
< num_leaps
* 12, 0))
232 tzspec_len
-= num_leaps
* 12;
233 if (__glibc_unlikely (tzspec_len
< num_isstd
))
235 tzspec_len
-= num_isstd
;
236 if (__glibc_unlikely (tzspec_len
== 0 || tzspec_len
- 1 < num_isgmt
))
238 tzspec_len
-= num_isgmt
+ 1;
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
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
)
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
);
293 *extrap
= alloc_buffer_alloc_array (&buf
, char, extra
);
294 if (alloc_buffer_has_failed (&buf
))
297 if (__glibc_unlikely (__fread_unlocked (transitions
, trans_width
,
300 || __glibc_unlikely (__fread_unlocked (type_idxs
, 1, num_transitions
, f
)
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
))
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
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
)
332 if (__builtin_expect (__fread_unlocked (x
, 1,
333 sizeof (x
), f
) != sizeof (x
),
336 c
= __getc_unlocked (f
);
337 if (__glibc_unlikely ((unsigned int) c
> 1u))
340 c
= __getc_unlocked (f
);
341 if (__glibc_unlikely ((size_t) c
> chars
))
342 /* Bogus index in data file. */
345 types
[i
].offset
= decode (x
);
348 if (__glibc_unlikely (__fread_unlocked (zone_names
, 1, chars
, f
) != chars
))
351 for (i
= 0; i
< num_leaps
; ++i
)
354 if (__builtin_expect (__fread_unlocked (x
, 1, trans_width
, f
)
357 if (trans_width
== 4)
358 leaps
[i
].transition
= decode (x
);
360 leaps
[i
].transition
= decode64 (x
);
362 if (__glibc_unlikely (__fread_unlocked (x
, 1, 4, f
) != 4))
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
))
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
))
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. */
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
)
397 tzspec
[tzspec_len
- 1] = '\0';
400 /* Don't use an empty TZ string. */
401 if (tzspec
!= NULL
&& tzspec
[0] == '\0')
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. */
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
)
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
;
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
)
454 rule_stdoff
= types
[type_idxs
[i
]].offset
;
456 else if (!dstoff_set
&& types
[type_idxs
[i
]].isdst
)
459 rule_dstoff
= types
[type_idxs
[i
]].offset
;
461 if (stdoff_set
&& dstoff_set
)
467 rule_dstoff
= rule_stdoff
;
470 __daylight
= rule_stdoff
!= rule_dstoff
;
471 __timezone
= -rule_stdoff
;
480 ret_free_transitions
:
482 free ((void *) transitions
);
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. */
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;
500 __tzfile_read (TZDEFRULES
, stdlen
+ dstlen
, &cp
);
510 /* Ignore the zone names read from the file and use the given ones
512 __mempcpy (__mempcpy (cp
, std
, stdlen
), dst
, dstlen
);
515 /* Now there are only two zones, regardless of what the file contained. */
518 /* Now correct the transition times for the user-specified standard and
519 daylight offsets from GMT. */
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
537 transitions
[i
] += dstoff
- rule_dstoff
;
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
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. */
558 types
[0].offset
= stdoff
;
560 types
[1].idx
= stdlen
;
561 types
[1].offset
= dstoff
;
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. */
579 __tzfile_compute (__time64_t timer
, int use_localtime
,
580 long int *leap_correct
, int *leap_hit
,
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). */
596 while (i
< num_types
&& types
[i
].isdst
)
598 if (__tzname
[1] == NULL
)
599 __tzname
[1] = __tzstring (&zone_names
[types
[i
].idx
]);
606 __tzname
[0] = __tzstring (&zone_names
[types
[i
].idx
]);
607 if (__tzname
[1] == NULL
)
610 while (j
< num_types
)
613 __tzname
[1] = __tzstring (&zone_names
[types
[j
].idx
]);
620 else if (__glibc_unlikely (timer
>= transitions
[num_transitions
- 1]))
622 if (__glibc_unlikely (tzspec
== NULL
))
629 /* Parse the POSIX TZ-style string. */
630 __tzset_parse_tz (tzspec
);
632 /* Convert to broken down structure. If this fails do not
634 if (__glibc_unlikely (! __offtime (timer
, 0, tp
)))
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]);
654 /* Find the first transition after TIMER, and
655 then pick the type of the transition before it. */
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
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])
673 while (timer
< transitions
[i
- 1])
681 if (i
+ 10 >= num_transitions
|| timer
< transitions
[i
+ 10])
684 while (timer
>= transitions
[i
])
693 /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
697 if (timer
< transitions
[i
])
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
]);
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
)
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
;
757 /* Find the last leap second correction transition time before TIMER. */
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
)))
772 && leaps
[i
].transition
== leaps
[i
- 1].transition
+ 1
773 && leaps
[i
].change
== leaps
[i
- 1].change
+ 1)