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