]>
git.ipfire.org Git - thirdparty/glibc.git/blob - 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.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
22 #include <stdio_ext.h>
30 #include <timezone/tzfile.h>
33 static dev_t tzfile_dev
;
34 static ino64_t tzfile_ino
;
35 static time_t tzfile_mtime
;
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. */
48 time_t transition
; /* Time the transition takes effect. */
49 long int change
; /* Seconds of correction to apply. */
52 static struct ttinfo
*find_transition (time_t timer
) internal_function
;
53 static void compute_tzname_max (size_t) internal_function
;
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
;
69 /* Decode the four bytes at PTR as a signed integer in network byte order. */
71 __attribute ((always_inline
))
72 decode (const void *ptr
)
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
);
79 const unsigned char *p
= ptr
;
80 int result
= *p
& (1 << (CHAR_BIT
- 1)) ? ~0 : 0;
82 result
= (result
<< 8) | *p
++;
83 result
= (result
<< 8) | *p
++;
84 result
= (result
<< 8) | *p
++;
85 result
= (result
<< 8) | *p
++;
92 __attribute ((always_inline
))
93 decode64 (const void *ptr
)
95 if ((BYTE_ORDER
== BIG_ENDIAN
))
96 return *(const int64_t *) ptr
;
98 return bswap_64 (*(const int64_t *) ptr
);
103 __tzfile_read (const char *file
, size_t extra
, char **extrap
)
105 static const char default_tzdir
[] = TZDIR
;
106 size_t num_isstd
, num_isgmt
;
108 struct tzhead tzhead
;
114 int was_using_tzfile
= __use_tzfile
;
117 if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
123 /* No user specification; use the site-wide default. */
125 else if (*file
== '\0')
126 /* User specified the empty string; use UTC with no leap seconds. */
127 goto ret_free_transitions
;
130 /* We must not allow to read an arbitrary file in a setuid
131 program. So we fail for any file which is not in the
132 directory hierachy starting at TZDIR
133 and which is not the system wide default TZDEFAULT. */
134 if (__libc_enable_secure
136 && memcmp (file
, TZDEFAULT
, sizeof TZDEFAULT
)
137 && memcmp (file
, default_tzdir
, sizeof (default_tzdir
) - 1))
138 || strstr (file
, "../") != NULL
))
139 /* This test is certainly a bit too restrictive but it should
140 catch all critical cases. */
141 goto ret_free_transitions
;
147 unsigned int len
, tzdir_len
;
150 tzdir
= getenv ("TZDIR");
151 if (tzdir
== NULL
|| *tzdir
== '\0')
153 tzdir
= default_tzdir
;
154 tzdir_len
= sizeof (default_tzdir
) - 1;
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
);
162 memcpy (tmp
, file
, len
);
166 /* If we were already using tzfile, check whether the file changed. */
169 && stat64 (file
, &st
) == 0
170 && tzfile_ino
== st
.st_ino
&& tzfile_dev
== st
.st_dev
171 && tzfile_mtime
== st
.st_mtime
)
178 /* Note the file is opened with cancellation in the I/O functions
180 f
= fopen (file
, "rc");
182 goto ret_free_transitions
;
184 /* Get information about the file we are actually using. */
185 if (fstat64 (fileno (f
), &st
) != 0)
188 goto ret_free_transitions
;
191 free ((void *) transitions
);
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
;
199 /* No threads reading this stream. */
200 __fsetlocking (f
, FSETLOCKING_BYCALLER
);
203 if (__builtin_expect (fread_unlocked ((void *) &tzhead
, sizeof (tzhead
),
205 || memcmp (tzhead
.tzh_magic
, TZ_MAGIC
, sizeof (tzhead
.tzh_magic
)) != 0)
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
);
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')
219 /* We use the 8-byte format. */
222 /* Position the stream before the second header. */
223 size_t to_skip
= (num_transitions
* (4 + 1)
229 if (fseek (f
, to_skip
, SEEK_CUR
) != 0)
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
);
245 /* Allocate enough memory including the extra block requested by the
247 transitions
= (time_t *) malloc (total_size
+ extra
);
248 if (transitions
== NULL
)
251 type_idxs
= (unsigned char *) transitions
+ (num_transitions
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
);
257 *extrap
= (char *) &leaps
[num_leaps
];
259 if (sizeof (time_t) == 4 || trans_width
== 8)
261 if (__builtin_expect (fread_unlocked (transitions
, trans_width
+ 1,
263 != num_transitions
, 0))
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))
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))
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))
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. */
291 transitions
[i
] = decode ((char *) transitions
+ i
* 4);
293 else if (BYTE_ORDER
!= BIG_ENDIAN
&& sizeof (time_t) == 8)
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);
301 for (i
= 0; i
< num_types
; ++i
)
305 if (__builtin_expect (fread_unlocked (x
, 1, sizeof (x
), f
) != sizeof (x
),
308 c
= getc_unlocked (f
);
309 if (__builtin_expect ((unsigned int) c
> 1u, 0))
312 c
= getc_unlocked (f
);
313 if (__builtin_expect ((size_t) c
> chars
, 0))
314 /* Bogus index in data file. */
317 types
[i
].offset
= (long int) decode (x
);
320 if (__builtin_expect (fread_unlocked (zone_names
, 1, chars
, f
) != chars
, 0))
323 for (i
= 0; i
< num_leaps
; ++i
)
326 if (__builtin_expect (fread_unlocked (x
, 1, trans_width
, f
)
329 if (sizeof (time_t) == 4 || trans_width
== 4)
330 leaps
[i
].transition
= (time_t) decode (x
);
332 leaps
[i
].transition
= (time_t) decode64 (x
);
334 if (__builtin_expect (fread_unlocked (x
, 1, 4, f
) != 4, 0))
336 leaps
[i
].change
= (long int) decode (x
);
339 for (i
= 0; i
< num_isstd
; ++i
)
341 int c
= getc_unlocked (f
);
342 if (__builtin_expect (c
== EOF
, 0))
344 types
[i
].isstd
= c
!= 0;
346 while (i
< num_types
)
347 types
[i
++].isstd
= 0;
349 for (i
= 0; i
< num_isgmt
; ++i
)
351 int c
= getc_unlocked (f
);
352 if (__builtin_expect (c
== EOF
, 0))
354 types
[i
].isgmt
= c
!= 0;
356 while (i
< num_types
)
357 types
[i
++].isgmt
= 0;
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. */
367 /* First "register" all timezone names. */
368 for (i
= 0; i
< num_types
; ++i
)
369 (void) __tzstring (&zone_names
[types
[i
].idx
]);
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. */
376 for (i
= num_transitions
; i
> 0; )
378 int type
= type_idxs
[--i
];
379 int dst
= types
[type
].isdst
;
381 if (__tzname
[dst
] == NULL
)
383 int idx
= types
[type
].idx
;
385 __tzname
[dst
] = __tzstring (&zone_names
[idx
]);
387 if (__tzname
[1 - dst
] != NULL
)
391 if (__tzname
[0] == NULL
)
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
);
398 if (__tzname
[1] == NULL
)
399 __tzname
[1] = __tzname
[0];
401 compute_tzname_max (chars
);
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
;
408 int stdoff_set
= 0, dstoff_set
= 0;
409 rule_stdoff
= rule_dstoff
= 0;
410 i
= num_transitions
- 1;
413 if (!stdoff_set
&& !types
[type_idxs
[i
]].isdst
)
416 rule_stdoff
= types
[type_idxs
[i
]].offset
;
418 else if (!dstoff_set
&& types
[type_idxs
[i
]].isdst
)
421 rule_dstoff
= types
[type_idxs
[i
]].offset
;
423 if (stdoff_set
&& dstoff_set
)
429 rule_dstoff
= rule_stdoff
;
432 __daylight
= rule_stdoff
!= rule_dstoff
;
433 __timezone
= -rule_stdoff
;
440 ret_free_transitions
:
441 free ((void *) transitions
);
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. */
450 __tzfile_default (const char *std
, const char *dst
,
451 long int stdoff
, long int dstoff
)
453 size_t stdlen
= strlen (std
) + 1;
454 size_t dstlen
= strlen (dst
) + 1;
459 __tzfile_read (TZDEFRULES
, stdlen
+ dstlen
, &cp
);
469 /* Ignore the zone names read from the file and use the given ones
471 __mempcpy (__mempcpy (cp
, std
, stdlen
), dst
, dstlen
);
474 /* Now there are only two zones, regardless of what the file contained. */
477 /* Now correct the transition times for the user-specified standard and
478 daylight offsets from GMT. */
480 for (i
= 0; i
< num_transitions
; ++i
)
482 struct ttinfo
*trans_type
= &types
[type_idxs
[i
]];
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
;
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
496 transitions
[i
] += dstoff
- rule_dstoff
;
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
502 transitions
[i
] += stdoff
- rule_stdoff
;
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
;
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
;
515 /* Reset types 0 and 1 to describe the user's settings. */
517 types
[0].offset
= stdoff
;
519 types
[1].idx
= stdlen
;
520 types
[1].offset
= dstoff
;
523 /* Reset the zone names to point to the user's names. */
524 __tzname
[0] = (char *) std
;
525 __tzname
[1] = (char *) dst
;
527 /* Set the timezone. */
528 __timezone
= -types
[0].offset
;
530 compute_tzname_max (stdlen
+ dstlen
);
533 static struct ttinfo
*
535 find_transition (time_t timer
)
539 if (num_transitions
== 0 || timer
< transitions
[0])
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). */
545 while (i
< num_types
&& types
[i
].isdst
)
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
])
557 i
= type_idxs
[i
- 1];
564 __tzfile_compute (time_t timer
, int use_localtime
,
565 long int *leap_correct
, int *leap_hit
,
572 struct ttinfo
*info
= find_transition (timer
);
573 __daylight
= rule_stdoff
!= rule_dstoff
;
574 __timezone
= -rule_stdoff
;
577 for (i
= num_transitions
; i
> 0; )
579 int type
= type_idxs
[--i
];
580 int dst
= types
[type
].isdst
;
581 int idx
= types
[type
].idx
;
583 if (__tzname
[dst
] == NULL
)
585 __tzname
[dst
] = __tzstring (&zone_names
[idx
]);
587 if (__tzname
[1 - dst
] != NULL
)
591 if (__tzname
[0] == NULL
)
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
);
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
;
609 /* Find the last leap second correction transition time before TIMER. */
614 while (timer
< leaps
[i
].transition
);
616 /* Apply its correction. */
617 *leap_correct
= leaps
[i
].change
;
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
))
625 && leaps
[i
].transition
== leaps
[i
- 1].transition
+ 1
626 && leaps
[i
].change
== leaps
[i
- 1].change
+ 1)
636 compute_tzname_max (size_t chars
)
643 const char *start
= p
;
646 if ((size_t) (p
- start
) > __tzname_cur_max
)
647 __tzname_cur_max
= p
- start
;
649 while (++p
< &zone_names
[chars
]);