]> git.ipfire.org Git - thirdparty/glibc.git/blob - time/tzfile.c
2.5-18.1
[thirdparty/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991-1993,1995-2001,2003,2004 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
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.
8
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.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA. */
18
19 #include <assert.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdio_ext.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28
29 #define NOID
30 #include <timezone/tzfile.h>
31
32 int __use_tzfile;
33 static dev_t tzfile_dev;
34 static ino64_t tzfile_ino;
35 static time_t tzfile_mtime;
36
37 struct ttinfo
38 {
39 long 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. */
44 };
45
46 struct leap
47 {
48 time_t transition; /* Time the transition takes effect. */
49 long int change; /* Seconds of correction to apply. */
50 };
51
52 static struct ttinfo *find_transition (time_t timer) internal_function;
53 static void compute_tzname_max (size_t) internal_function;
54
55 static size_t num_transitions;
56 libc_freeres_ptr (static time_t *transitions);
57 static unsigned char *type_idxs;
58 static size_t num_types;
59 static struct ttinfo *types;
60 static char *zone_names;
61 static long int rule_stdoff;
62 static long int rule_dstoff;
63 static size_t num_leaps;
64 static struct leap *leaps;
65
66 #include <endian.h>
67 #include <byteswap.h>
68
69 /* Decode the four bytes at PTR as a signed integer in network byte order. */
70 static inline int
71 __attribute ((always_inline))
72 decode (const void *ptr)
73 {
74 if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
75 return *(const int *) ptr;
76 if (sizeof (int) == 4)
77 return bswap_32 (*(const int *) ptr);
78
79 const unsigned char *p = ptr;
80 int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
81
82 result = (result << 8) | *p++;
83 result = (result << 8) | *p++;
84 result = (result << 8) | *p++;
85 result = (result << 8) | *p++;
86
87 return result;
88 }
89
90
91 static inline int64_t
92 __attribute ((always_inline))
93 decode64 (const void *ptr)
94 {
95 if ((BYTE_ORDER == BIG_ENDIAN))
96 return *(const int64_t *) ptr;
97
98 return bswap_64 (*(const int64_t *) ptr);
99 }
100
101
102 void
103 __tzfile_read (const char *file, size_t extra, char **extrap)
104 {
105 static const char default_tzdir[] = TZDIR;
106 size_t num_isstd, num_isgmt;
107 register FILE *f;
108 struct tzhead tzhead;
109 size_t chars;
110 register size_t i;
111 size_t total_size;
112 size_t types_idx;
113 size_t leaps_idx;
114 int was_using_tzfile = __use_tzfile;
115 int trans_width = 4;
116
117 if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
118 abort ();
119
120 __use_tzfile = 0;
121
122 if (file == NULL)
123 /* No user specification; use the site-wide default. */
124 file = TZDEFAULT;
125 else if (*file == '\0')
126 /* User specified the empty string; use UTC with no leap seconds. */
127 goto ret_free_transitions;
128 else
129 {
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
135 && ((*file == '/'
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;
142 }
143
144 if (*file != '/')
145 {
146 const char *tzdir;
147 unsigned int len, tzdir_len;
148 char *new, *tmp;
149
150 tzdir = getenv ("TZDIR");
151 if (tzdir == NULL || *tzdir == '\0')
152 {
153 tzdir = default_tzdir;
154 tzdir_len = sizeof (default_tzdir) - 1;
155 }
156 else
157 tzdir_len = strlen (tzdir);
158 len = strlen (file) + 1;
159 new = (char *) __alloca (tzdir_len + 1 + len);
160 tmp = __mempcpy (new, tzdir, tzdir_len);
161 *tmp++ = '/';
162 memcpy (tmp, file, len);
163 file = new;
164 }
165
166 /* If we were already using tzfile, check whether the file changed. */
167 struct stat64 st;
168 if (was_using_tzfile
169 && stat64 (file, &st) == 0
170 && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
171 && tzfile_mtime == st.st_mtime)
172 {
173 /* Nothing to do. */
174 __use_tzfile = 1;
175 return;
176 }
177
178 /* Note the file is opened with cancellation in the I/O functions
179 disabled. */
180 f = fopen (file, "rc");
181 if (f == NULL)
182 goto ret_free_transitions;
183
184 /* Get information about the file we are actually using. */
185 if (fstat64 (fileno (f), &st) != 0)
186 {
187 fclose (f);
188 goto ret_free_transitions;
189 }
190
191 free ((void *) transitions);
192 transitions = NULL;
193
194 /* Remember the inode and device number and modification time. */
195 tzfile_dev = st.st_dev;
196 tzfile_ino = st.st_ino;
197 tzfile_mtime = st.st_mtime;
198
199 /* No threads reading this stream. */
200 __fsetlocking (f, FSETLOCKING_BYCALLER);
201
202 read_again:
203 if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),
204 1, f) != 1, 0)
205 || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
206 goto lose;
207
208 num_transitions = (size_t) decode (tzhead.tzh_timecnt);
209 num_types = (size_t) decode (tzhead.tzh_typecnt);
210 chars = (size_t) decode (tzhead.tzh_charcnt);
211 num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
212 num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
213 num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
214
215 /* For platforms with 64-bit time_t we use the new format if available. */
216 if (sizeof (time_t) == 8 && trans_width == 4
217 && tzhead.tzh_version[0] != '\0')
218 {
219 /* We use the 8-byte format. */
220 trans_width = 8;
221
222 /* Position the stream before the second header. */
223 size_t to_skip = (num_transitions * (4 + 1)
224 + num_types * 6
225 + chars
226 + num_leaps * 8
227 + num_isstd
228 + num_isgmt);
229 if (fseek (f, to_skip, SEEK_CUR) != 0)
230 goto lose;
231
232 goto read_again;
233 }
234
235 total_size = num_transitions * (sizeof (time_t) + 1);
236 total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
237 & ~(__alignof__ (struct ttinfo) - 1));
238 types_idx = total_size;
239 total_size += num_types * sizeof (struct ttinfo) + chars;
240 total_size = ((total_size + __alignof__ (struct leap) - 1)
241 & ~(__alignof__ (struct leap) - 1));
242 leaps_idx = total_size;
243 total_size += num_leaps * sizeof (struct leap);
244
245 /* Allocate enough memory including the extra block requested by the
246 caller. */
247 transitions = (time_t *) malloc (total_size + extra);
248 if (transitions == NULL)
249 goto lose;
250
251 type_idxs = (unsigned char *) transitions + (num_transitions
252 * sizeof (time_t));
253 types = (struct ttinfo *) ((char *) transitions + types_idx);
254 zone_names = (char *) types + num_types * sizeof (struct ttinfo);
255 leaps = (struct leap *) ((char *) transitions + leaps_idx);
256 if (extra > 0)
257 *extrap = (char *) &leaps[num_leaps];
258
259 if (sizeof (time_t) == 4 || trans_width == 8)
260 {
261 if (__builtin_expect (fread_unlocked (transitions, trans_width + 1,
262 num_transitions, f)
263 != num_transitions, 0))
264 goto lose;
265 }
266 else
267 {
268 if (__builtin_expect (fread_unlocked (transitions, 4, num_transitions, f)
269 != num_transitions, 0)
270 || __builtin_expect (fread_unlocked (type_idxs, 1, num_transitions,
271 f) != num_transitions, 0))
272 goto lose;
273 }
274
275 /* Check for bogus indices in the data file, so we can hereafter
276 safely use type_idxs[T] as indices into `types' and never crash. */
277 for (i = 0; i < num_transitions; ++i)
278 if (__builtin_expect (type_idxs[i] >= num_types, 0))
279 goto lose;
280
281 if ((BYTE_ORDER != BIG_ENDIAN && (sizeof (time_t) == 4 || trans_width == 4))
282 || (BYTE_ORDER == BIG_ENDIAN && sizeof (time_t) == 8
283 && trans_width == 4))
284 {
285 /* Decode the transition times, stored as 4-byte integers in
286 network (big-endian) byte order. We work from the end of
287 the array so as not to clobber the next element to be
288 processed when sizeof (time_t) > 4. */
289 i = num_transitions;
290 while (i-- > 0)
291 transitions[i] = decode ((char *) transitions + i * 4);
292 }
293 else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8)
294 {
295 /* Decode the transition times, stored as 8-byte integers in
296 network (big-endian) byte order. */
297 for (i = 0; i < num_transitions; ++i)
298 transitions[i] = decode64 ((char *) transitions + i * 8);
299 }
300
301 for (i = 0; i < num_types; ++i)
302 {
303 unsigned char x[4];
304 int c;
305 if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
306 0))
307 goto lose;
308 c = getc_unlocked (f);
309 if (__builtin_expect ((unsigned int) c > 1u, 0))
310 goto lose;
311 types[i].isdst = c;
312 c = getc_unlocked (f);
313 if (__builtin_expect ((size_t) c > chars, 0))
314 /* Bogus index in data file. */
315 goto lose;
316 types[i].idx = c;
317 types[i].offset = (long int) decode (x);
318 }
319
320 if (__builtin_expect (fread_unlocked (zone_names, 1, chars, f) != chars, 0))
321 goto lose;
322
323 for (i = 0; i < num_leaps; ++i)
324 {
325 unsigned char x[8];
326 if (__builtin_expect (fread_unlocked (x, 1, trans_width, f)
327 != trans_width, 0))
328 goto lose;
329 if (sizeof (time_t) == 4 || trans_width == 4)
330 leaps[i].transition = (time_t) decode (x);
331 else
332 leaps[i].transition = (time_t) decode64 (x);
333
334 if (__builtin_expect (fread_unlocked (x, 1, 4, f) != 4, 0))
335 goto lose;
336 leaps[i].change = (long int) decode (x);
337 }
338
339 for (i = 0; i < num_isstd; ++i)
340 {
341 int c = getc_unlocked (f);
342 if (__builtin_expect (c == EOF, 0))
343 goto lose;
344 types[i].isstd = c != 0;
345 }
346 while (i < num_types)
347 types[i++].isstd = 0;
348
349 for (i = 0; i < num_isgmt; ++i)
350 {
351 int c = getc_unlocked (f);
352 if (__builtin_expect (c == EOF, 0))
353 goto lose;
354 types[i].isgmt = c != 0;
355 }
356 while (i < num_types)
357 types[i++].isgmt = 0;
358
359 /* XXX When a version 2 file is available it can contain a POSIX TZ-style
360 formatted string which specifies how times past the last one specified
361 are supposed to be handled. We might want to handle this at some
362 point. But it might be overhead since most/all? files have an
363 open-ended last entry. */
364
365 fclose (f);
366
367 /* First "register" all timezone names. */
368 for (i = 0; i < num_types; ++i)
369 (void) __tzstring (&zone_names[types[i].idx]);
370
371 /* Find the standard and daylight time offsets used by the rule file.
372 We choose the offsets in the types of each flavor that are
373 transitioned to earliest in time. */
374 __tzname[0] = NULL;
375 __tzname[1] = NULL;
376 for (i = num_transitions; i > 0; )
377 {
378 int type = type_idxs[--i];
379 int dst = types[type].isdst;
380
381 if (__tzname[dst] == NULL)
382 {
383 int idx = types[type].idx;
384
385 __tzname[dst] = __tzstring (&zone_names[idx]);
386
387 if (__tzname[1 - dst] != NULL)
388 break;
389 }
390 }
391 if (__tzname[0] == NULL)
392 {
393 /* This should only happen if there are no transition rules.
394 In this case there should be only one single type. */
395 assert (num_types == 1);
396 __tzname[0] = __tzstring (zone_names);
397 }
398 if (__tzname[1] == NULL)
399 __tzname[1] = __tzname[0];
400
401 compute_tzname_max (chars);
402
403 if (num_transitions == 0)
404 /* Use the first rule (which should also be the only one). */
405 rule_stdoff = rule_dstoff = types[0].offset;
406 else
407 {
408 int stdoff_set = 0, dstoff_set = 0;
409 rule_stdoff = rule_dstoff = 0;
410 i = num_transitions - 1;
411 do
412 {
413 if (!stdoff_set && !types[type_idxs[i]].isdst)
414 {
415 stdoff_set = 1;
416 rule_stdoff = types[type_idxs[i]].offset;
417 }
418 else if (!dstoff_set && types[type_idxs[i]].isdst)
419 {
420 dstoff_set = 1;
421 rule_dstoff = types[type_idxs[i]].offset;
422 }
423 if (stdoff_set && dstoff_set)
424 break;
425 }
426 while (i-- > 0);
427
428 if (!dstoff_set)
429 rule_dstoff = rule_stdoff;
430 }
431
432 __daylight = rule_stdoff != rule_dstoff;
433 __timezone = -rule_stdoff;
434
435 __use_tzfile = 1;
436 return;
437
438 lose:
439 fclose (f);
440 ret_free_transitions:
441 free ((void *) transitions);
442 transitions = NULL;
443 }
444 \f
445 /* The user specified a hand-made timezone, but not its DST rules.
446 We will use the names and offsets from the user, and the rules
447 from the TZDEFRULES file. */
448
449 void
450 __tzfile_default (const char *std, const char *dst,
451 long int stdoff, long int dstoff)
452 {
453 size_t stdlen = strlen (std) + 1;
454 size_t dstlen = strlen (dst) + 1;
455 size_t i;
456 int isdst;
457 char *cp;
458
459 __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
460 if (!__use_tzfile)
461 return;
462
463 if (num_types < 2)
464 {
465 __use_tzfile = 0;
466 return;
467 }
468
469 /* Ignore the zone names read from the file and use the given ones
470 instead. */
471 __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
472 zone_names = cp;
473
474 /* Now there are only two zones, regardless of what the file contained. */
475 num_types = 2;
476
477 /* Now correct the transition times for the user-specified standard and
478 daylight offsets from GMT. */
479 isdst = 0;
480 for (i = 0; i < num_transitions; ++i)
481 {
482 struct ttinfo *trans_type = &types[type_idxs[i]];
483
484 /* We will use only types 0 (standard) and 1 (daylight).
485 Fix up this transition to point to whichever matches
486 the flavor of its original type. */
487 type_idxs[i] = trans_type->isdst;
488
489 if (trans_type->isgmt)
490 /* The transition time is in GMT. No correction to apply. */ ;
491 else if (isdst && !trans_type->isstd)
492 /* The type says this transition is in "local wall clock time", and
493 wall clock time as of the previous transition was DST. Correct
494 for the difference between the rule's DST offset and the user's
495 DST offset. */
496 transitions[i] += dstoff - rule_dstoff;
497 else
498 /* This transition is in "local wall clock time", and wall clock
499 time as of this iteration is non-DST. Correct for the
500 difference between the rule's standard offset and the user's
501 standard offset. */
502 transitions[i] += stdoff - rule_stdoff;
503
504 /* The DST state of "local wall clock time" for the next iteration is
505 as specified by this transition. */
506 isdst = trans_type->isdst;
507 }
508
509 /* Now that we adjusted the transitions to the requested offsets,
510 reset the rule_stdoff and rule_dstoff values appropriately. They
511 are used elsewhere. */
512 rule_stdoff = stdoff;
513 rule_dstoff = dstoff;
514
515 /* Reset types 0 and 1 to describe the user's settings. */
516 types[0].idx = 0;
517 types[0].offset = stdoff;
518 types[0].isdst = 0;
519 types[1].idx = stdlen;
520 types[1].offset = dstoff;
521 types[1].isdst = 1;
522
523 /* Reset the zone names to point to the user's names. */
524 __tzname[0] = (char *) std;
525 __tzname[1] = (char *) dst;
526
527 /* Set the timezone. */
528 __timezone = -types[0].offset;
529
530 compute_tzname_max (stdlen + dstlen);
531 }
532 \f
533 static struct ttinfo *
534 internal_function
535 find_transition (time_t timer)
536 {
537 size_t i;
538
539 if (num_transitions == 0 || timer < transitions[0])
540 {
541 /* TIMER is before any transition (or there are no transitions).
542 Choose the first non-DST type
543 (or the first if they're all DST types). */
544 i = 0;
545 while (i < num_types && types[i].isdst)
546 ++i;
547 if (i == num_types)
548 i = 0;
549 }
550 else
551 {
552 /* Find the first transition after TIMER, and
553 then pick the type of the transition before it. */
554 for (i = 1; i < num_transitions; ++i)
555 if (timer < transitions[i])
556 break;
557 i = type_idxs[i - 1];
558 }
559
560 return &types[i];
561 }
562 \f
563 void
564 __tzfile_compute (time_t timer, int use_localtime,
565 long int *leap_correct, int *leap_hit,
566 struct tm *tp)
567 {
568 register size_t i;
569
570 if (use_localtime)
571 {
572 struct ttinfo *info = find_transition (timer);
573 __daylight = rule_stdoff != rule_dstoff;
574 __timezone = -rule_stdoff;
575 __tzname[0] = NULL;
576 __tzname[1] = NULL;
577 for (i = num_transitions; i > 0; )
578 {
579 int type = type_idxs[--i];
580 int dst = types[type].isdst;
581 int idx = types[type].idx;
582
583 if (__tzname[dst] == NULL)
584 {
585 __tzname[dst] = __tzstring (&zone_names[idx]);
586
587 if (__tzname[1 - dst] != NULL)
588 break;
589 }
590 }
591 if (__tzname[0] == NULL)
592 {
593 /* This should only happen if there are no transition rules.
594 In this case there should be only one single type. */
595 assert (num_types == 1);
596 __tzname[0] = __tzstring (zone_names);
597 }
598 if (__tzname[1] == NULL)
599 /* There is no daylight saving time. */
600 __tzname[1] = __tzname[0];
601 tp->tm_isdst = info->isdst;
602 tp->tm_zone = __tzstring (&zone_names[info->idx]);
603 tp->tm_gmtoff = info->offset;
604 }
605
606 *leap_correct = 0L;
607 *leap_hit = 0;
608
609 /* Find the last leap second correction transition time before TIMER. */
610 i = num_leaps;
611 do
612 if (i-- == 0)
613 return;
614 while (timer < leaps[i].transition);
615
616 /* Apply its correction. */
617 *leap_correct = leaps[i].change;
618
619 if (timer == leaps[i].transition && /* Exactly at the transition time. */
620 ((i == 0 && leaps[i].change > 0) ||
621 leaps[i].change > leaps[i - 1].change))
622 {
623 *leap_hit = 1;
624 while (i > 0
625 && leaps[i].transition == leaps[i - 1].transition + 1
626 && leaps[i].change == leaps[i - 1].change + 1)
627 {
628 ++*leap_hit;
629 --i;
630 }
631 }
632 }
633 \f
634 static void
635 internal_function
636 compute_tzname_max (size_t chars)
637 {
638 const char *p;
639
640 p = zone_names;
641 do
642 {
643 const char *start = p;
644 while (*p != '\0')
645 ++p;
646 if ((size_t) (p - start) > __tzname_cur_max)
647 __tzname_cur_max = p - start;
648 }
649 while (++p < &zone_names[chars]);
650 }