]> git.ipfire.org Git - thirdparty/glibc.git/blame - time/tzfile.c
time: Use struct alloc_buffer in __tzfile_read
[thirdparty/glibc.git] / time / tzfile.c
CommitLineData
04277e02 1/* Copyright (C) 1991-2019 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
PE
15 License along with the GNU C Library; if not, see
16 <http://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
155 && stat64 (file, &st) == 0
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. */
5a6fa4d7 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);
192 num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
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];
249 struct ttinfo types[num_types];
250 unsigned char type_idxs[num_types];
251 char zone_names[chars];
252 struct leap leaps[num_leaps];
253 char extra_array[extra]; // Stored into *pextras if requested.
254 char tzspec[tzspec_len];
255
256 The piece-wise allocations from buf below verify that no
257 overflow/wraparound occurred in these computations. */
258 struct alloc_buffer buf;
259 {
260 size_t total_size = num_transitions * (sizeof (__time64_t) + 1);
261 total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
262 & ~(__alignof__ (struct ttinfo) - 1));
263 total_size += num_types * sizeof (struct ttinfo) + chars;
264 total_size = ((total_size + __alignof__ (struct leap) - 1)
265 & ~(__alignof__ (struct leap) - 1));
266 total_size += num_leaps * sizeof (struct leap) + tzspec_len + extra;
267
268 transitions = malloc (total_size);
269 if (transitions == NULL)
270 goto lose;
271 buf = alloc_buffer_create (transitions, total_size);
272 }
273
274 /* The address of the first allocation is already stored in the
275 pointer transitions. */
276 (void) alloc_buffer_alloc_array (&buf, __time64_t, num_transitions);
277 type_idxs = alloc_buffer_alloc_array (&buf, unsigned char, num_transitions);
278 types = alloc_buffer_alloc_array (&buf, struct ttinfo, num_types);
279 zone_names = alloc_buffer_alloc_array (&buf, char, chars);
280 leaps = alloc_buffer_alloc_array (&buf, struct leap, num_leaps);
281 if (extra > 0)
282 *extrap = alloc_buffer_alloc_array (&buf, char, extra);
fc79706a 283 if (trans_width == 8)
b8c72381 284 tzspec = alloc_buffer_alloc_array (&buf, char, tzspec_len);
fa76dde2
UD
285 else
286 tzspec = NULL;
b8c72381
FW
287 if (alloc_buffer_has_failed (&buf))
288 goto lose;
c4563d2d 289
fc79706a 290 if (__builtin_expect (trans_width == 8, 1))
28f540f4 291 {
5a6fa4d7
JM
292 if (__builtin_expect (__fread_unlocked (transitions, trans_width + 1,
293 num_transitions, f)
11bf311e 294 != num_transitions, 0))
28f540f4
RM
295 goto lose;
296 }
c4563d2d 297 else
28f540f4 298 {
5a6fa4d7
JM
299 if (__builtin_expect (__fread_unlocked (transitions, 4,
300 num_transitions, f)
9c7ff11a 301 != num_transitions, 0)
5a6fa4d7
JM
302 || __builtin_expect (__fread_unlocked (type_idxs, 1, num_transitions,
303 f) != num_transitions, 0))
28f540f4
RM
304 goto lose;
305 }
306
5290baf0
UD
307 /* Check for bogus indices in the data file, so we can hereafter
308 safely use type_idxs[T] as indices into `types' and never crash. */
309 for (i = 0; i < num_transitions; ++i)
a1ffb40e 310 if (__glibc_unlikely (type_idxs[i] >= num_types))
5290baf0
UD
311 goto lose;
312
fc79706a 313 if (trans_width == 4)
a2cafe30
RM
314 {
315 /* Decode the transition times, stored as 4-byte integers in
fc79706a
FW
316 network (big-endian) byte order. We work from the end of the
317 array so as not to clobber the next element to be
318 processed. */
a2cafe30 319 i = num_transitions;
b20e47cb 320 while (i-- > 0)
a3e0e9ae 321 transitions[i] = decode ((char *) transitions + i * 4);
a2cafe30 322 }
fc79706a 323 else if (BYTE_ORDER != BIG_ENDIAN)
11bf311e
UD
324 {
325 /* Decode the transition times, stored as 8-byte integers in
326 network (big-endian) byte order. */
327 for (i = 0; i < num_transitions; ++i)
328 transitions[i] = decode64 ((char *) transitions + i * 8);
329 }
28f540f4
RM
330
331 for (i = 0; i < num_types; ++i)
332 {
333 unsigned char x[4];
c4563d2d 334 int c;
5a6fa4d7
JM
335 if (__builtin_expect (__fread_unlocked (x, 1,
336 sizeof (x), f) != sizeof (x),
9c7ff11a 337 0))
28f540f4 338 goto lose;
30ac923d 339 c = __getc_unlocked (f);
a1ffb40e 340 if (__glibc_unlikely ((unsigned int) c > 1u))
8b7fb588 341 goto lose;
c4563d2d 342 types[i].isdst = c;
30ac923d 343 c = __getc_unlocked (f);
a1ffb40e 344 if (__glibc_unlikely ((size_t) c > chars))
9c7ff11a 345 /* Bogus index in data file. */
5290baf0 346 goto lose;
c4563d2d 347 types[i].idx = c;
77c7d55e 348 types[i].offset = decode (x);
28f540f4
RM
349 }
350
5a6fa4d7 351 if (__glibc_unlikely (__fread_unlocked (zone_names, 1, chars, f) != chars))
28f540f4
RM
352 goto lose;
353
354 for (i = 0; i < num_leaps; ++i)
355 {
11bf311e 356 unsigned char x[8];
5a6fa4d7 357 if (__builtin_expect (__fread_unlocked (x, 1, trans_width, f)
11bf311e 358 != trans_width, 0))
28f540f4 359 goto lose;
fc79706a
FW
360 if (trans_width == 4)
361 leaps[i].transition = decode (x);
11bf311e 362 else
fc79706a 363 leaps[i].transition = decode64 (x);
11bf311e 364
5a6fa4d7 365 if (__glibc_unlikely (__fread_unlocked (x, 1, 4, f) != 4))
28f540f4 366 goto lose;
a2cafe30 367 leaps[i].change = (long int) decode (x);
28f540f4
RM
368 }
369
370 for (i = 0; i < num_isstd; ++i)
371 {
30ac923d 372 int c = __getc_unlocked (f);
a1ffb40e 373 if (__glibc_unlikely (c == EOF))
28f540f4
RM
374 goto lose;
375 types[i].isstd = c != 0;
376 }
377 while (i < num_types)
378 types[i++].isstd = 0;
379
98fa1d6e
RM
380 for (i = 0; i < num_isgmt; ++i)
381 {
30ac923d 382 int c = __getc_unlocked (f);
a1ffb40e 383 if (__glibc_unlikely (c == EOF))
98fa1d6e
RM
384 goto lose;
385 types[i].isgmt = c != 0;
386 }
387 while (i < num_types)
388 types[i++].isgmt = 0;
389
fa76dde2 390 /* Read the POSIX TZ-style information if possible. */
fc79706a 391 if (tzspec != NULL)
fa76dde2 392 {
b8c72381 393 assert (tzspec_len > 0);
fa76dde2 394 /* Skip over the newline first. */
30ac923d 395 if (__getc_unlocked (f) != '\n'
5a6fa4d7 396 || (__fread_unlocked (tzspec, 1, tzspec_len - 1, f)
c6d381d3 397 != tzspec_len - 1))
fa76dde2
UD
398 tzspec = NULL;
399 else
400 tzspec[tzspec_len - 1] = '\0';
401 }
11bf311e 402
7a7c2c24
AS
403 /* Don't use an empty TZ string. */
404 if (tzspec != NULL && tzspec[0] == '\0')
405 tzspec = NULL;
406
860d3729
UD
407 fclose (f);
408
a3e0e9ae
UD
409 /* First "register" all timezone names. */
410 for (i = 0; i < num_types; ++i)
e4e4fde5
PE
411 if (__tzstring (&zone_names[types[i].idx]) == NULL)
412 goto ret_free_transitions;
a3e0e9ae 413
ff152e3f
UD
414 /* Find the standard and daylight time offsets used by the rule file.
415 We choose the offsets in the types of each flavor that are
416 transitioned to earliest in time. */
a3e0e9ae 417 __tzname[0] = NULL;
ff152e3f 418 __tzname[1] = NULL;
a3e0e9ae
UD
419 for (i = num_transitions; i > 0; )
420 {
421 int type = type_idxs[--i];
422 int dst = types[type].isdst;
a3e0e9ae
UD
423
424 if (__tzname[dst] == NULL)
425 {
d3345073
UD
426 int idx = types[type].idx;
427
a3e0e9ae
UD
428 __tzname[dst] = __tzstring (&zone_names[idx]);
429
430 if (__tzname[1 - dst] != NULL)
431 break;
432 }
433 }
434 if (__tzname[0] == NULL)
435 {
436 /* This should only happen if there are no transition rules.
437 In this case there should be only one single type. */
438 assert (num_types == 1);
439 __tzname[0] = __tzstring (zone_names);
440 }
ff152e3f
UD
441 if (__tzname[1] == NULL)
442 __tzname[1] = __tzname[0];
28f540f4 443
90865aa8 444 if (num_transitions == 0)
0155a773 445 /* Use the first rule (which should also be the only one). */
90865aa8
UD
446 rule_stdoff = rule_dstoff = types[0].offset;
447 else
ff152e3f 448 {
d16e36e0 449 int stdoff_set = 0, dstoff_set = 0;
90865aa8 450 rule_stdoff = rule_dstoff = 0;
d3345073
UD
451 i = num_transitions - 1;
452 do
90865aa8 453 {
d16e36e0
AS
454 if (!stdoff_set && !types[type_idxs[i]].isdst)
455 {
456 stdoff_set = 1;
457 rule_stdoff = types[type_idxs[i]].offset;
458 }
d3345073 459 else if (!dstoff_set && types[type_idxs[i]].isdst)
d16e36e0
AS
460 {
461 dstoff_set = 1;
462 rule_dstoff = types[type_idxs[i]].offset;
463 }
464 if (stdoff_set && dstoff_set)
90865aa8
UD
465 break;
466 }
d3345073
UD
467 while (i-- > 0);
468
d16e36e0
AS
469 if (!dstoff_set)
470 rule_dstoff = rule_stdoff;
ff152e3f
UD
471 }
472
473 __daylight = rule_stdoff != rule_dstoff;
474 __timezone = -rule_stdoff;
475
45c30c61 476 done:
28f540f4 477 __use_tzfile = 1;
45c30c61 478 free (new);
28f540f4
RM
479 return;
480
ba9234d9
UD
481 lose:
482 fclose (f);
640b76b7 483 ret_free_transitions:
45c30c61 484 free (new);
640b76b7
UD
485 free ((void *) transitions);
486 transitions = NULL;
28f540f4
RM
487}
488\f
98fa1d6e
RM
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. */
492
28f540f4 493void
cd6ede75 494__tzfile_default (const char *std, const char *dst,
77c7d55e 495 int stdoff, int dstoff)
28f540f4 496{
c4563d2d
UD
497 size_t stdlen = strlen (std) + 1;
498 size_t dstlen = strlen (dst) + 1;
499 size_t i;
98fa1d6e 500 int isdst;
c4563d2d 501 char *cp;
28f540f4 502
c4563d2d 503 __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
28f540f4
RM
504 if (!__use_tzfile)
505 return;
506
507 if (num_types < 2)
508 {
509 __use_tzfile = 0;
510 return;
511 }
512
c4563d2d
UD
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;
28f540f4 517
88455219
UD
518 /* Now there are only two zones, regardless of what the file contained. */
519 num_types = 2;
520
98fa1d6e
RM
521 /* Now correct the transition times for the user-specified standard and
522 daylight offsets from GMT. */
523 isdst = 0;
98fa1d6e
RM
524 for (i = 0; i < num_transitions; ++i)
525 {
526 struct ttinfo *trans_type = &types[type_idxs[i]];
527
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;
532
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;
547
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;
551 }
552
4c326621
UD
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;
558
98fa1d6e
RM
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;
28f540f4 566
5290baf0 567 /* Reset the zone names to point to the user's names. */
cd6ede75
UD
568 __tzname[0] = (char *) std;
569 __tzname[1] = (char *) dst;
5290baf0 570
90865aa8
UD
571 /* Set the timezone. */
572 __timezone = -types[0].offset;
573
c83196b0
AS
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;
28f540f4
RM
579}
580\f
fa76dde2 581void
d51f99ce 582__tzfile_compute (__time64_t timer, int use_localtime,
fa76dde2
UD
583 long int *leap_correct, int *leap_hit,
584 struct tm *tp)
28f540f4 585{
2e09a79a 586 size_t i;
89dc9d4c 587
fa76dde2 588 if (use_localtime)
28f540f4 589 {
fa76dde2
UD
590 __tzname[0] = NULL;
591 __tzname[1] = NULL;
592
a1ffb40e 593 if (__glibc_unlikely (num_transitions == 0 || timer < transitions[0]))
89dc9d4c 594 {
fa76dde2
UD
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)
600 {
601 if (__tzname[1] == NULL)
602 __tzname[1] = __tzstring (&zone_names[types[i].idx]);
89dc9d4c 603
fa76dde2
UD
604 ++i;
605 }
89dc9d4c 606
fa76dde2
UD
607 if (i == num_types)
608 i = 0;
609 __tzname[0] = __tzstring (&zone_names[types[i].idx]);
610 if (__tzname[1] == NULL)
611 {
612 size_t j = i;
613 while (j < num_types)
614 if (types[j].isdst)
615 {
616 __tzname[1] = __tzstring (&zone_names[types[j].idx]);
617 break;
618 }
619 else
620 ++j;
621 }
622 }
a1ffb40e 623 else if (__glibc_unlikely (timer >= transitions[num_transitions - 1]))
89dc9d4c 624 {
a1ffb40e 625 if (__glibc_unlikely (tzspec == NULL))
fa76dde2
UD
626 {
627 use_last:
e2cceb5a 628 i = num_transitions;
fa76dde2
UD
629 goto found;
630 }
631
632 /* Parse the POSIX TZ-style string. */
633 __tzset_parse_tz (tzspec);
634
635 /* Convert to broken down structure. If this fails do not
636 use the string. */
72b8692d
AA
637 if (__glibc_unlikely (! __offtime (timer, 0, tp)))
638 goto use_last;
639
640 /* Use the rules from the TZ string to compute the change. */
fa76dde2
UD
641 __tz_compute (timer, tp, 1);
642
c6d381d3
UD
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. */
a1ffb40e 646 if (__glibc_unlikely (zone_names == (char *) &leaps[num_leaps]))
c6d381d3
UD
647 {
648 assert (num_types == 2);
649 __tzname[0] = __tzstring (zone_names);
650 __tzname[1] = __tzstring (&zone_names[strlen (zone_names) + 1]);
651 }
652
29143408 653 goto leap;
89dc9d4c 654 }
fa76dde2 655 else
13252678 656 {
fa76dde2
UD
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;
fc79706a
FW
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
d51f99ce 665 __time64_t, but this is harmless because it is just
fc79706a 666 a guess. */
fa76dde2
UD
667 i = (transitions[num_transitions - 1] - timer) / 15778476;
668 if (i < num_transitions)
13252678 669 {
fa76dde2
UD
670 i = num_transitions - 1 - i;
671 if (timer < transitions[i])
13252678 672 {
fa76dde2
UD
673 if (i < 10 || timer >= transitions[i - 10])
674 {
675 /* Linear search. */
676 while (timer < transitions[i - 1])
677 --i;
678 goto found;
679 }
680 hi = i - 10;
13252678 681 }
fa76dde2 682 else
13252678 683 {
fa76dde2
UD
684 if (i + 10 >= num_transitions || timer < transitions[i + 10])
685 {
686 /* Linear search. */
687 while (timer >= transitions[i])
688 ++i;
689 goto found;
690 }
691 lo = i + 10;
13252678 692 }
13252678 693 }
13252678 694
fa76dde2
UD
695 /* Binary search. */
696 /* assert (timer >= transitions[lo] && timer < transitions[hi]); */
697 while (lo + 1 < hi)
698 {
699 i = (lo + hi) / 2;
700 if (timer < transitions[i])
701 hi = i;
702 else
703 lo = i;
704 }
705 i = hi;
89dc9d4c 706
fa76dde2 707 found:
e2cceb5a
UD
708 /* assert (timer >= transitions[i - 1]
709 && (i == num_transitions || timer < transitions[i])); */
fa76dde2
UD
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)
89dc9d4c 714 {
fa76dde2
UD
715 int type = type_idxs[j];
716 int dst = types[type].isdst;
717 int idx = types[type].idx;
89dc9d4c 718
fa76dde2
UD
719 if (__tzname[dst] == NULL)
720 {
721 __tzname[dst] = __tzstring (&zone_names[idx]);
89dc9d4c 722
fa76dde2
UD
723 if (__tzname[1 - dst] != NULL)
724 break;
725 }
89dc9d4c 726
fa76dde2
UD
727 ++j;
728 }
28f540f4 729
a1ffb40e 730 if (__glibc_unlikely (__tzname[0] == NULL))
c6d381d3
UD
731 __tzname[0] = __tzname[1];
732
fa76dde2
UD
733 i = type_idxs[i - 1];
734 }
860d3729 735
fa76dde2 736 struct ttinfo *info = &types[i];
ff152e3f
UD
737 __daylight = rule_stdoff != rule_dstoff;
738 __timezone = -rule_stdoff;
a3e0e9ae 739
a3e0e9ae
UD
740 if (__tzname[0] == NULL)
741 {
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);
746 }
ff152e3f
UD
747 if (__tzname[1] == NULL)
748 /* There is no daylight saving time. */
749 __tzname[1] = __tzname[0];
a709dd43 750 tp->tm_isdst = info->isdst;
89dc9d4c
UD
751 assert (strcmp (&zone_names[info->idx], __tzname[tp->tm_isdst]) == 0);
752 tp->tm_zone = __tzname[tp->tm_isdst];
a709dd43 753 tp->tm_gmtoff = info->offset;
9a0a462c 754 }
28f540f4 755
29143408 756 leap:
28f540f4
RM
757 *leap_correct = 0L;
758 *leap_hit = 0;
759
760 /* Find the last leap second correction transition time before TIMER. */
761 i = num_leaps;
762 do
763 if (i-- == 0)
38e68573 764 return;
28f540f4
RM
765 while (timer < leaps[i].transition);
766
767 /* Apply its correction. */
768 *leap_correct = leaps[i].change;
769
770 if (timer == leaps[i].transition && /* Exactly at the transition time. */
771 ((i == 0 && leaps[i].change > 0) ||
772 leaps[i].change > leaps[i - 1].change))
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}