]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/tzfile.c
tst: Add test for settimeofday
[thirdparty/glibc.git] / time / tzfile.c
CommitLineData
2b778ceb 1/* Copyright (C) 1991-2021 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>
28f540f4 29
14ea22e9 30#include <timezone/tzfile.h>
28f540f4 31
c4563d2d 32int __use_tzfile;
fe6cc2ae
UD
33static dev_t tzfile_dev;
34static ino64_t tzfile_ino;
8930fcf9 35static time_t tzfile_mtime;
28f540f4
RM
36
37struct ttinfo
38 {
77c7d55e 39 int offset; /* Seconds east of GMT. */
28f540f4
RM
40 unsigned char isdst; /* Used to set tm_isdst. */
41 unsigned char idx; /* Index into `zone_names'. */
98fa1d6e
RM
42 unsigned char isstd; /* Transition times are in standard time. */
43 unsigned char isgmt; /* Transition times are in GMT. */
28f540f4
RM
44 };
45
46struct leap
47 {
d51f99ce 48 __time64_t transition; /* Time the transition takes effect. */
28f540f4
RM
49 long int change; /* Seconds of correction to apply. */
50 };
51
28f540f4 52static size_t num_transitions;
d51f99ce 53libc_freeres_ptr (static __time64_t *transitions);
c4563d2d 54static unsigned char *type_idxs;
28f540f4 55static size_t num_types;
c4563d2d
UD
56static struct ttinfo *types;
57static char *zone_names;
ff152e3f
UD
58static long int rule_stdoff;
59static long int rule_dstoff;
28f540f4 60static size_t num_leaps;
c4563d2d 61static struct leap *leaps;
fa76dde2 62static char *tzspec;
28f540f4 63
a2cafe30 64#include <endian.h>
ba9234d9 65#include <byteswap.h>
a2cafe30
RM
66
67/* Decode the four bytes at PTR as a signed integer in network byte order. */
68static inline int
9c7ff11a 69__attribute ((always_inline))
a2cafe30
RM
70decode (const void *ptr)
71{
11bf311e 72 if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
b20e47cb 73 return *(const int *) ptr;
11bf311e 74 if (sizeof (int) == 4)
ba9234d9 75 return bswap_32 (*(const int *) ptr);
b20e47cb 76
11bf311e
UD
77 const unsigned char *p = ptr;
78 int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
064737fb 79
11bf311e
UD
80 result = (result << 8) | *p++;
81 result = (result << 8) | *p++;
82 result = (result << 8) | *p++;
83 result = (result << 8) | *p++;
84
85 return result;
064737fb
UD
86}
87
11bf311e
UD
88
89static inline int64_t
90__attribute ((always_inline))
91decode64 (const void *ptr)
92{
93 if ((BYTE_ORDER == BIG_ENDIAN))
94 return *(const int64_t *) ptr;
95
96 return bswap_64 (*(const int64_t *) ptr);
97}
98
99
28f540f4 100void
c4563d2d 101__tzfile_read (const char *file, size_t extra, char **extrap)
28f540f4 102{
9d187dd4 103 static const char default_tzdir[] = TZDIR;
98fa1d6e 104 size_t num_isstd, num_isgmt;
2e09a79a 105 FILE *f;
28f540f4
RM
106 struct tzhead tzhead;
107 size_t chars;
2e09a79a 108 size_t i;
fe6cc2ae 109 int was_using_tzfile = __use_tzfile;
11bf311e 110 int trans_width = 4;
45c30c61 111 char *new = NULL;
11bf311e 112
d51f99ce
AA
113 _Static_assert (sizeof (__time64_t) == 8,
114 "__time64_t must be eight bytes");
28f540f4
RM
115
116 __use_tzfile = 0;
117
a3b58440
RM
118 if (file == NULL)
119 /* No user specification; use the site-wide default. */
28f540f4 120 file = TZDEFAULT;
a3b58440 121 else if (*file == '\0')
9a0a462c 122 /* User specified the empty string; use UTC with no leap seconds. */
640b76b7 123 goto ret_free_transitions;
1228ed5c
UD
124 else
125 {
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
7434ccad
UD
128 directory hierachy starting at TZDIR
129 and which is not the system wide default TZDEFAULT. */
1228ed5c
UD
130 if (__libc_enable_secure
131 && ((*file == '/'
4cca6b86 132 && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
1228ed5c
UD
133 && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
134 || strstr (file, "../") != NULL))
7434ccad
UD
135 /* This test is certainly a bit too restrictive but it should
136 catch all critical cases. */
640b76b7 137 goto ret_free_transitions;
1228ed5c 138 }
9d187dd4 139
28f540f4
RM
140 if (*file != '/')
141 {
5290baf0 142 const char *tzdir;
5290baf0 143
74955460 144 tzdir = getenv ("TZDIR");
5290baf0 145 if (tzdir == NULL || *tzdir == '\0')
45c30c61
OB
146 tzdir = default_tzdir;
147 if (__asprintf (&new, "%s/%s", tzdir, file) == -1)
148 goto ret_free_transitions;
28f540f4
RM
149 file = new;
150 }
151
250ecb48
UD
152 /* If we were already using tzfile, check whether the file changed. */
153 struct stat64 st;
154 if (was_using_tzfile
04986243 155 && __stat64 (file, &st) == 0
250ecb48
UD
156 && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
157 && tzfile_mtime == st.st_mtime)
45c30c61 158 goto done; /* Nothing to do. */
250ecb48 159
ee8449f7 160 /* Note the file is opened with cancellation in the I/O functions
82af0fa8
UD
161 disabled and if available FD_CLOEXEC set. */
162 f = fopen (file, "rce");
28f540f4 163 if (f == NULL)
640b76b7 164 goto ret_free_transitions;
28f540f4 165
250ecb48 166 /* Get information about the file we are actually using. */
04986243 167 if (__fstat64 (__fileno (f), &st) != 0)
dab9c348 168 goto lose;
fe6cc2ae 169
640b76b7
UD
170 free ((void *) transitions);
171 transitions = NULL;
172
8930fcf9 173 /* Remember the inode and device number and modification time. */
fe6cc2ae
UD
174 tzfile_dev = st.st_dev;
175 tzfile_ino = st.st_ino;
8930fcf9 176 tzfile_mtime = st.st_mtime;
fe6cc2ae 177
2706ee38
UD
178 /* No threads reading this stream. */
179 __fsetlocking (f, FSETLOCKING_BYCALLER);
180
11bf311e 181 read_again:
5a6fa4d7
JM
182 if (__builtin_expect (__fread_unlocked ((void *) &tzhead, sizeof (tzhead),
183 1, f) != 1, 0)
11bf311e 184 || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
28f540f4
RM
185 goto lose;
186
a2cafe30
RM
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);
61d64408 192 num_isgmt = (size_t) decode (tzhead.tzh_ttisutcnt);
28f540f4 193
42261ad7
FW
194 if (__glibc_unlikely (num_isstd > num_types || num_isgmt > num_types))
195 goto lose;
196
fc79706a 197 if (trans_width == 4 && tzhead.tzh_version[0] != '\0')
11bf311e
UD
198 {
199 /* We use the 8-byte format. */
200 trans_width = 8;
201
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;
211
212 goto read_again;
213 }
214
b8c72381
FW
215 /* Compute the size of the POSIX time zone specification in the
216 file. */
217 size_t tzspec_len;
fc79706a 218 if (trans_width == 8)
97ac2654 219 {
5a6fa4d7 220 off_t rem = st.st_size - __ftello (f);
97ac2654
UD
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;
a1ffb40e 233 if (__glibc_unlikely (tzspec_len < num_isstd))
97ac2654
UD
234 goto lose;
235 tzspec_len -= num_isstd;
a1ffb40e 236 if (__glibc_unlikely (tzspec_len == 0 || tzspec_len - 1 < num_isgmt))
97ac2654
UD
237 goto lose;
238 tzspec_len -= num_isgmt + 1;
b8c72381 239 if (tzspec_len == 0)
97ac2654
UD
240 goto lose;
241 }
b8c72381
FW
242 else
243 tzspec_len = 0;
244
245 /* The file is parsed into a single heap allocation, comprising of
246 the following arrays:
247
248 __time64_t transitions[num_transitions];
221baae0 249 struct leap leaps[num_leaps];
b8c72381
FW
250 struct ttinfo types[num_types];
251 unsigned char type_idxs[num_types];
252 char zone_names[chars];
b8c72381 253 char tzspec[tzspec_len];
221baae0 254 char extra_array[extra]; // Stored into *pextras if requested.
b8c72381
FW
255
256 The piece-wise allocations from buf below verify that no
221baae0
FW
257 overflow/wraparound occurred in these computations.
258
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");
b8c72381
FW
267 struct alloc_buffer buf;
268 {
221baae0
FW
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);
b8c72381
FW
275 transitions = malloc (total_size);
276 if (transitions == NULL)
277 goto lose;
278 buf = alloc_buffer_create (transitions, total_size);
279 }
280
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);
221baae0 284 leaps = alloc_buffer_alloc_array (&buf, struct leap, num_leaps);
b8c72381 285 types = alloc_buffer_alloc_array (&buf, struct ttinfo, num_types);
221baae0 286 type_idxs = alloc_buffer_alloc_array (&buf, unsigned char, num_transitions);
b8c72381 287 zone_names = alloc_buffer_alloc_array (&buf, char, chars);
fc79706a 288 if (trans_width == 8)
b8c72381 289 tzspec = alloc_buffer_alloc_array (&buf, char, tzspec_len);
fa76dde2
UD
290 else
291 tzspec = NULL;
221baae0
FW
292 if (extra > 0)
293 *extrap = alloc_buffer_alloc_array (&buf, char, extra);
b8c72381
FW
294 if (alloc_buffer_has_failed (&buf))
295 goto lose;
c4563d2d 296
221baae0
FW
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))
28f540f4 302 goto lose;
28f540f4 303
5290baf0
UD
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)
a1ffb40e 307 if (__glibc_unlikely (type_idxs[i] >= num_types))
5290baf0
UD
308 goto lose;
309
fc79706a 310 if (trans_width == 4)
a2cafe30
RM
311 {
312 /* Decode the transition times, stored as 4-byte integers in
fc79706a
FW
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. */
a2cafe30 316 i = num_transitions;
b20e47cb 317 while (i-- > 0)
a3e0e9ae 318 transitions[i] = decode ((char *) transitions + i * 4);
a2cafe30 319 }
fc79706a 320 else if (BYTE_ORDER != BIG_ENDIAN)
11bf311e
UD
321 {
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);
326 }
28f540f4
RM
327
328 for (i = 0; i < num_types; ++i)
329 {
330 unsigned char x[4];
c4563d2d 331 int c;
5a6fa4d7
JM
332 if (__builtin_expect (__fread_unlocked (x, 1,
333 sizeof (x), f) != sizeof (x),
9c7ff11a 334 0))
28f540f4 335 goto lose;
30ac923d 336 c = __getc_unlocked (f);
a1ffb40e 337 if (__glibc_unlikely ((unsigned int) c > 1u))
8b7fb588 338 goto lose;
c4563d2d 339 types[i].isdst = c;
30ac923d 340 c = __getc_unlocked (f);
a1ffb40e 341 if (__glibc_unlikely ((size_t) c > chars))
9c7ff11a 342 /* Bogus index in data file. */
5290baf0 343 goto lose;
c4563d2d 344 types[i].idx = c;
77c7d55e 345 types[i].offset = decode (x);
28f540f4
RM
346 }
347
5a6fa4d7 348 if (__glibc_unlikely (__fread_unlocked (zone_names, 1, chars, f) != chars))
28f540f4
RM
349 goto lose;
350
351 for (i = 0; i < num_leaps; ++i)
352 {
11bf311e 353 unsigned char x[8];
5a6fa4d7 354 if (__builtin_expect (__fread_unlocked (x, 1, trans_width, f)
11bf311e 355 != trans_width, 0))
28f540f4 356 goto lose;
fc79706a
FW
357 if (trans_width == 4)
358 leaps[i].transition = decode (x);
11bf311e 359 else
fc79706a 360 leaps[i].transition = decode64 (x);
11bf311e 361
5a6fa4d7 362 if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4))
28f540f4 363 goto lose;
a2cafe30 364 leaps[i].change = (long int) decode (x);
28f540f4
RM
365 }
366
367 for (i = 0; i < num_isstd; ++i)
368 {
30ac923d 369 int c = __getc_unlocked (f);
a1ffb40e 370 if (__glibc_unlikely (c == EOF))
28f540f4
RM
371 goto lose;
372 types[i].isstd = c != 0;
373 }
374 while (i < num_types)
375 types[i++].isstd = 0;
376
98fa1d6e
RM
377 for (i = 0; i < num_isgmt; ++i)
378 {
30ac923d 379 int c = __getc_unlocked (f);
a1ffb40e 380 if (__glibc_unlikely (c == EOF))
98fa1d6e
RM
381 goto lose;
382 types[i].isgmt = c != 0;
383 }
384 while (i < num_types)
385 types[i++].isgmt = 0;
386
fa76dde2 387 /* Read the POSIX TZ-style information if possible. */
fc79706a 388 if (tzspec != NULL)
fa76dde2 389 {
b8c72381 390 assert (tzspec_len > 0);
fa76dde2 391 /* Skip over the newline first. */
30ac923d 392 if (__getc_unlocked (f) != '\n'
5a6fa4d7 393 || (__fread_unlocked (tzspec, 1, tzspec_len - 1, f)
c6d381d3 394 != tzspec_len - 1))
fa76dde2
UD
395 tzspec = NULL;
396 else
397 tzspec[tzspec_len - 1] = '\0';
398 }
11bf311e 399
7a7c2c24
AS
400 /* Don't use an empty TZ string. */
401 if (tzspec != NULL && tzspec[0] == '\0')
402 tzspec = NULL;
403
860d3729
UD
404 fclose (f);
405
a3e0e9ae
UD
406 /* First "register" all timezone names. */
407 for (i = 0; i < num_types; ++i)
e4e4fde5
PE
408 if (__tzstring (&zone_names[types[i].idx]) == NULL)
409 goto ret_free_transitions;
a3e0e9ae 410
ff152e3f
UD
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. */
a3e0e9ae 414 __tzname[0] = NULL;
ff152e3f 415 __tzname[1] = NULL;
a3e0e9ae
UD
416 for (i = num_transitions; i > 0; )
417 {
418 int type = type_idxs[--i];
419 int dst = types[type].isdst;
a3e0e9ae
UD
420
421 if (__tzname[dst] == NULL)
422 {
d3345073
UD
423 int idx = types[type].idx;
424
a3e0e9ae
UD
425 __tzname[dst] = __tzstring (&zone_names[idx]);
426
427 if (__tzname[1 - dst] != NULL)
428 break;
429 }
430 }
431 if (__tzname[0] == NULL)
432 {
433 /* This should only happen if there are no transition rules.
434 In this case there should be only one single type. */
435 assert (num_types == 1);
436 __tzname[0] = __tzstring (zone_names);
437 }
ff152e3f
UD
438 if (__tzname[1] == NULL)
439 __tzname[1] = __tzname[0];
28f540f4 440
90865aa8 441 if (num_transitions == 0)
0155a773 442 /* Use the first rule (which should also be the only one). */
90865aa8
UD
443 rule_stdoff = rule_dstoff = types[0].offset;
444 else
ff152e3f 445 {
d16e36e0 446 int stdoff_set = 0, dstoff_set = 0;
90865aa8 447 rule_stdoff = rule_dstoff = 0;
d3345073
UD
448 i = num_transitions - 1;
449 do
90865aa8 450 {
d16e36e0
AS
451 if (!stdoff_set && !types[type_idxs[i]].isdst)
452 {
453 stdoff_set = 1;
454 rule_stdoff = types[type_idxs[i]].offset;
455 }
d3345073 456 else if (!dstoff_set && types[type_idxs[i]].isdst)
d16e36e0
AS
457 {
458 dstoff_set = 1;
459 rule_dstoff = types[type_idxs[i]].offset;
460 }
461 if (stdoff_set && dstoff_set)
90865aa8
UD
462 break;
463 }
d3345073
UD
464 while (i-- > 0);
465
d16e36e0
AS
466 if (!dstoff_set)
467 rule_dstoff = rule_stdoff;
ff152e3f
UD
468 }
469
470 __daylight = rule_stdoff != rule_dstoff;
471 __timezone = -rule_stdoff;
472
45c30c61 473 done:
28f540f4 474 __use_tzfile = 1;
45c30c61 475 free (new);
28f540f4
RM
476 return;
477
ba9234d9
UD
478 lose:
479 fclose (f);
640b76b7 480 ret_free_transitions:
45c30c61 481 free (new);
640b76b7
UD
482 free ((void *) transitions);
483 transitions = NULL;
28f540f4
RM
484}
485\f
98fa1d6e
RM
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. */
489
28f540f4 490void
cd6ede75 491__tzfile_default (const char *std, const char *dst,
77c7d55e 492 int stdoff, int dstoff)
28f540f4 493{
c4563d2d
UD
494 size_t stdlen = strlen (std) + 1;
495 size_t dstlen = strlen (dst) + 1;
496 size_t i;
98fa1d6e 497 int isdst;
c4563d2d 498 char *cp;
28f540f4 499
c4563d2d 500 __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
28f540f4
RM
501 if (!__use_tzfile)
502 return;
503
504 if (num_types < 2)
505 {
506 __use_tzfile = 0;
507 return;
508 }
509
c4563d2d
UD
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;
28f540f4 514
88455219
UD
515 /* Now there are only two zones, regardless of what the file contained. */
516 num_types = 2;
517
98fa1d6e
RM
518 /* Now correct the transition times for the user-specified standard and
519 daylight offsets from GMT. */
520 isdst = 0;
98fa1d6e
RM
521 for (i = 0; i < num_transitions; ++i)
522 {
523 struct ttinfo *trans_type = &types[type_idxs[i]];
524
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;
529
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;
544
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;
548 }
549
4c326621
UD
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;
555
98fa1d6e
RM
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;
28f540f4 563
5290baf0 564 /* Reset the zone names to point to the user's names. */
cd6ede75
UD
565 __tzname[0] = (char *) std;
566 __tzname[1] = (char *) dst;
5290baf0 567
90865aa8
UD
568 /* Set the timezone. */
569 __timezone = -types[0].offset;
570
c83196b0
AS
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;
28f540f4
RM
576}
577\f
fa76dde2 578void
d51f99ce 579__tzfile_compute (__time64_t timer, int use_localtime,
fa76dde2
UD
580 long int *leap_correct, int *leap_hit,
581 struct tm *tp)
28f540f4 582{
2e09a79a 583 size_t i;
89dc9d4c 584
fa76dde2 585 if (use_localtime)
28f540f4 586 {
fa76dde2
UD
587 __tzname[0] = NULL;
588 __tzname[1] = NULL;
589
a1ffb40e 590 if (__glibc_unlikely (num_transitions == 0 || timer < transitions[0]))
89dc9d4c 591 {
fa76dde2
UD
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)
597 {
598 if (__tzname[1] == NULL)
599 __tzname[1] = __tzstring (&zone_names[types[i].idx]);
89dc9d4c 600
fa76dde2
UD
601 ++i;
602 }
89dc9d4c 603
fa76dde2
UD
604 if (i == num_types)
605 i = 0;
606 __tzname[0] = __tzstring (&zone_names[types[i].idx]);
607 if (__tzname[1] == NULL)
608 {
609 size_t j = i;
610 while (j < num_types)
611 if (types[j].isdst)
612 {
613 __tzname[1] = __tzstring (&zone_names[types[j].idx]);
614 break;
615 }
616 else
617 ++j;
618 }
619 }
a1ffb40e 620 else if (__glibc_unlikely (timer >= transitions[num_transitions - 1]))
89dc9d4c 621 {
a1ffb40e 622 if (__glibc_unlikely (tzspec == NULL))
fa76dde2
UD
623 {
624 use_last:
e2cceb5a 625 i = num_transitions;
fa76dde2
UD
626 goto found;
627 }
628
629 /* Parse the POSIX TZ-style string. */
630 __tzset_parse_tz (tzspec);
631
632 /* Convert to broken down structure. If this fails do not
633 use the string. */
72b8692d
AA
634 if (__glibc_unlikely (! __offtime (timer, 0, tp)))
635 goto use_last;
636
637 /* Use the rules from the TZ string to compute the change. */
fa76dde2
UD
638 __tz_compute (timer, tp, 1);
639
c6d381d3
UD
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. */
a1ffb40e 643 if (__glibc_unlikely (zone_names == (char *) &leaps[num_leaps]))
c6d381d3
UD
644 {
645 assert (num_types == 2);
646 __tzname[0] = __tzstring (zone_names);
647 __tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
648 }
649
29143408 650 goto leap;
89dc9d4c 651 }
fa76dde2 652 else
13252678 653 {
fa76dde2
UD
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;
fc79706a
FW
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
d51f99ce 662 __time64_t, but this is harmless because it is just
fc79706a 663 a guess. */
fa76dde2
UD
664 i = (transitions[num_transitions - 1] - timer) / 15778476;
665 if (i < num_transitions)
13252678 666 {
fa76dde2
UD
667 i = num_transitions - 1 - i;
668 if (timer < transitions[i])
13252678 669 {
fa76dde2
UD
670 if (i < 10 || timer >= transitions[i - 10])
671 {
672 /* Linear search. */
673 while (timer < transitions[i - 1])
674 --i;
675 goto found;
676 }
677 hi = i - 10;
13252678 678 }
fa76dde2 679 else
13252678 680 {
fa76dde2
UD
681 if (i + 10 >= num_transitions || timer < transitions[i + 10])
682 {
683 /* Linear search. */
684 while (timer >= transitions[i])
685 ++i;
686 goto found;
687 }
688 lo = i + 10;
13252678 689 }
13252678 690 }
13252678 691
fa76dde2
UD
692 /* Binary search. */
693 /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
694 while (lo + 1 < hi)
695 {
696 i = (lo + hi) / 2;
697 if (timer < transitions[i])
698 hi = i;
699 else
700 lo = i;
701 }
702 i = hi;
89dc9d4c 703
fa76dde2 704 found:
e2cceb5a
UD
705 /* assert (timer >= transitions[i - 1]
706 && (i == num_transitions || timer < transitions[i])); */
fa76dde2
UD
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)
89dc9d4c 711 {
fa76dde2
UD
712 int type = type_idxs[j];
713 int dst = types[type].isdst;
714 int idx = types[type].idx;
89dc9d4c 715
fa76dde2
UD
716 if (__tzname[dst] == NULL)
717 {
718 __tzname[dst] = __tzstring (&zone_names[idx]);
89dc9d4c 719
fa76dde2
UD
720 if (__tzname[1 - dst] != NULL)
721 break;
722 }
89dc9d4c 723
fa76dde2
UD
724 ++j;
725 }
28f540f4 726
a1ffb40e 727 if (__glibc_unlikely (__tzname[0] == NULL))
c6d381d3
UD
728 __tzname[0] = __tzname[1];
729
fa76dde2
UD
730 i = type_idxs[i - 1];
731 }
860d3729 732
fa76dde2 733 struct ttinfo *info = &types[i];
ff152e3f
UD
734 __daylight = rule_stdoff != rule_dstoff;
735 __timezone = -rule_stdoff;
a3e0e9ae 736
a3e0e9ae
UD
737 if (__tzname[0] == NULL)
738 {
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);
743 }
ff152e3f
UD
744 if (__tzname[1] == NULL)
745 /* There is no daylight saving time. */
746 __tzname[1] = __tzname[0];
a709dd43 747 tp->tm_isdst = info->isdst;
89dc9d4c
UD
748 assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0);
749 tp->tm_zone = __tzname[tp->tm_isdst];
a709dd43 750 tp->tm_gmtoff = info->offset;
9a0a462c 751 }
28f540f4 752
29143408 753 leap:
28f540f4
RM
754 *leap_correct = 0L;
755 *leap_hit = 0;
756
757 /* Find the last leap second correction transition time before TIMER. */
758 i = num_leaps;
759 do
760 if (i-- == 0)
38e68573 761 return;
28f540f4
RM
762 while (timer < leaps[i].transition);
763
764 /* Apply its correction. */
765 *leap_correct = leaps[i].change;
766
a04549c1
JM
767 if (timer == leaps[i].transition /* Exactly at the transition time. */
768 && ((i == 0 && leaps[i].change > 0)
769 || leaps[i].change > leaps[i - 1].change))
28f540f4
RM
770 {
771 *leap_hit = 1;
ba9234d9
UD
772 while (i > 0
773 && leaps[i].transition == leaps[i - 1].transition + 1
774 && leaps[i].change == leaps[i - 1].change + 1)
28f540f4
RM
775 {
776 ++*leap_hit;
777 --i;
778 }
779 }
28f540f4 780}