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 __time64_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
;
64 /* Used to restore the daylight variable during time conversion, as if
65 tzset had been called. */
66 static int daylight_saved
;
71 /* Decode the four bytes at PTR as a signed integer in network byte order. */
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
++;
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
);
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
;
110 struct tzhead tzhead
;
113 int was_using_tzfile
= __use_tzfile
;
117 _Static_assert (sizeof (__time64_t
) == 8,
118 "__time64_t must be eight bytes");
123 /* No user specification; use the site-wide default. */
125 else if (*file
== '\0')
126 /* User specified the empty string; use UTC with no leap seconds. */
127 goto ret_free_transitions
;
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
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
;
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
;
156 /* If we were already using tzfile, check whether the file changed. */
157 struct __stat64_t64 st
;
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");
168 goto ret_free_transitions
;
170 /* Get information about the file we are actually using. */
171 if (__fstat64_time64 (__fileno (f
), &st
) != 0)
174 free ((void *) transitions
);
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
);
186 if (__builtin_expect (__fread_unlocked ((void *) &tzhead
, sizeof (tzhead
),
188 || memcmp (tzhead
.tzh_magic
, TZ_MAGIC
, sizeof (tzhead
.tzh_magic
)) != 0)
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
))
201 if (trans_width
== 4 && tzhead
.tzh_version
[0] != '\0')
203 /* We use the 8-byte format. */
206 /* Position the stream before the second header. */
207 size_t to_skip
= (num_transitions
* (4 + 1)
213 if (fseek (f
, to_skip
, SEEK_CUR
) != 0)
219 /* Compute the size of the POSIX time zone specification in the
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)
230 tzspec_len
= (size_t) rem
- (num_transitions
* (8 + 1)
233 if (__builtin_expect (num_leaps
> SIZE_MAX
/ 12
234 || tzspec_len
< num_leaps
* 12, 0))
236 tzspec_len
-= num_leaps
* 12;
237 if (__glibc_unlikely (tzspec_len
< num_isstd
))
239 tzspec_len
-= num_isstd
;
240 if (__glibc_unlikely (tzspec_len
== 0 || tzspec_len
- 1 < num_isgmt
))
242 tzspec_len
-= num_isgmt
+ 1;
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
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
)
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
);
297 *extrap
= alloc_buffer_alloc_array (&buf
, char, extra
);
298 if (alloc_buffer_has_failed (&buf
))
301 if (__glibc_unlikely (__fread_unlocked (transitions
, trans_width
,
304 || __glibc_unlikely (__fread_unlocked (type_idxs
, 1, num_transitions
, f
)
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
))
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
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
)
336 if (__builtin_expect (__fread_unlocked (x
, 1,
337 sizeof (x
), f
) != sizeof (x
),
340 c
= __getc_unlocked (f
);
341 if (__glibc_unlikely ((unsigned int) c
> 1u))
344 c
= __getc_unlocked (f
);
345 if (__glibc_unlikely ((size_t) c
> chars
))
346 /* Bogus index in data file. */
349 types
[i
].offset
= decode (x
);
352 if (__glibc_unlikely (__fread_unlocked (zone_names
, 1, chars
, f
) != chars
))
355 for (i
= 0; i
< num_leaps
; ++i
)
358 if (__builtin_expect (__fread_unlocked (x
, 1, trans_width
, f
)
361 if (trans_width
== 4)
362 leaps
[i
].transition
= decode (x
);
364 leaps
[i
].transition
= decode64 (x
);
366 if (__glibc_unlikely (__fread_unlocked (x
, 1, 4, f
) != 4))
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
))
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
))
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. */
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
)
401 tzspec
[tzspec_len
- 1] = '\0';
404 /* Don't use an empty TZ string. */
405 if (tzspec
!= NULL
&& tzspec
[0] == '\0')
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. */
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
)
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];
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
;
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
;
466 /* Keep searching to see if there is a DST rule. This
467 information will be used to set the global daylight
469 while (i
-- > 0 && !daylight_saved
)
470 daylight_saved
= types
[type_idxs
[i
]].isdst
;
473 __daylight
= daylight_saved
;
474 __timezone
= -rule_stdoff
;
483 ret_free_transitions
:
485 free ((void *) transitions
);
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. */
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;
503 __tzfile_read (TZDEFRULES
, stdlen
+ dstlen
, &cp
);
513 /* Ignore the zone names read from the file and use the given ones
515 __mempcpy (__mempcpy (cp
, std
, stdlen
), dst
, dstlen
);
518 /* Now there are only two zones, regardless of what the file contained. */
521 /* Now correct the transition times for the user-specified standard and
522 daylight offsets from GMT. */
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
540 transitions
[i
] += dstoff
- rule_dstoff
;
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
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. */
561 types
[0].offset
= stdoff
;
563 types
[1].idx
= stdlen
;
564 types
[1].offset
= dstoff
;
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. */
582 __tzfile_compute (__time64_t timer
, int use_localtime
,
583 long int *leap_correct
, int *leap_hit
,
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). */
599 while (i
< num_types
&& types
[i
].isdst
)
601 if (__tzname
[1] == NULL
)
602 __tzname
[1] = __tzstring (&zone_names
[types
[i
].idx
]);
609 __tzname
[0] = __tzstring (&zone_names
[types
[i
].idx
]);
610 if (__tzname
[1] == NULL
)
613 while (j
< num_types
)
616 __tzname
[1] = __tzstring (&zone_names
[types
[j
].idx
]);
623 else if (__glibc_unlikely (timer
>= transitions
[num_transitions
- 1]))
625 if (__glibc_unlikely (tzspec
== NULL
))
632 /* Parse the POSIX TZ-style string. */
633 __tzset_parse_tz (tzspec
);
635 /* Convert to broken down structure. If this fails do not
637 if (__glibc_unlikely (! __offtime (timer
, 0, tp
)))
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]);
657 /* Find the first transition after TIMER, and
658 then pick the type of the transition before it. */
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
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])
676 while (timer
< transitions
[i
- 1])
684 if (i
+ 10 >= num_transitions
|| timer
< transitions
[i
+ 10])
687 while (timer
>= transitions
[i
])
696 /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
700 if (timer
< transitions
[i
])
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
]);
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
)
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
;
760 /* Find the last leap second correction transition time before TIMER. */
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
)))
775 && leaps
[i
].transition
== leaps
[i
- 1].transition
+ 1
776 && leaps
[i
].change
== leaps
[i
- 1].change
+ 1)