1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Timezone file reading code from glibc 2.16.
8 Copyright (C) 1991-2012 Free Software Foundation, Inc.
9 Copyright 2012 Kay Sievers
11 systemd is free software; you can redistribute it and/or modify it
12 under the terms of the GNU Lesser General Public License as published by
13 the Free Software Foundation; either version 2.1 of the License, or
14 (at your option) any later version.
16 systemd is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public License
22 along with systemd; If not, see <http://www.gnu.org/licenses/>.
43 * If tzh_version is '2' or greater, the above is followed by a second instance
44 * of tzhead and a second instance of the data in which each coded transition
45 * time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style
46 * string for use in handling instants after the last transition time stored in
47 * the file * (with nothing between the newlines if there is no POSIX
48 * representation for such instants).
50 #define TZ_MAGIC "TZif"
52 char tzh_magic[4]; /* TZ_MAGIC */
53 char tzh_version[1]; /* '\0' or '2' as of 2005 */
54 char tzh_reserved[15]; /* reserved--must be zero */
55 char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
56 char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
57 char tzh_leapcnt[4]; /* coded number of leap seconds */
58 char tzh_timecnt[4]; /* coded number of transition times */
59 char tzh_typecnt[4]; /* coded number of local time types */
60 char tzh_charcnt[4]; /* coded number of abbr. chars */
64 long int offset; /* Seconds east of GMT. */
65 unsigned char isdst; /* Used to set tm_isdst. */
66 unsigned char idx; /* Index into `zone_names'. */
67 unsigned char isstd; /* Transition times are in standard time. */
68 unsigned char isgmt; /* Transition times are in GMT. */
72 time_t transition; /* Time the transition takes effect. */
73 long int change; /* Seconds of correction to apply. */
76 static inline int decode(const void *ptr) {
77 return be32toh(*(int *)ptr);
80 static inline int64_t decode64(const void *ptr) {
81 return be64toh(*(int64_t *)ptr);
84 int time_get_dst(time_t date, const char *tzfile,
85 time_t *switch_cur, char **zone_cur, bool *dst_cur,
86 time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next) {
87 time_t *transitions = NULL;
88 size_t num_transitions = 0;
89 unsigned char *type_idxs = 0;
91 struct ttinfo *types = NULL;
92 char *zone_names = NULL;
94 size_t num_isstd, num_isgmt;
107 f = fopen(tzfile, "re");
111 if (fstat(fileno(f), &st) < 0) {
118 if (fread((void *)&tzhead, sizeof(tzhead), 1, f) != 1 ||
119 memcmp(tzhead.tzh_magic, TZ_MAGIC, sizeof(tzhead.tzh_magic)) != 0)
122 num_transitions = (size_t)decode(tzhead.tzh_timecnt);
123 num_types = (size_t)decode(tzhead.tzh_typecnt);
124 chars = (size_t)decode(tzhead.tzh_charcnt);
125 num_leaps = (size_t)decode(tzhead.tzh_leapcnt);
126 num_isstd = (size_t)decode(tzhead.tzh_ttisstdcnt);
127 num_isgmt = (size_t)decode(tzhead.tzh_ttisgmtcnt);
129 /* For platforms with 64-bit time_t we use the new format if available. */
130 if (sizeof(time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') {
133 /* We use the 8-byte format. */
136 /* Position the stream before the second header. */
137 to_skip = (num_transitions * (4 + 1)
140 + num_leaps * 8 + num_isstd + num_isgmt);
141 if (fseek(f, to_skip, SEEK_CUR) != 0)
147 if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1)))
150 total_size = num_transitions * (sizeof(time_t) + 1);
151 total_size = ((total_size + __alignof__(struct ttinfo) - 1) & ~(__alignof__(struct ttinfo) - 1));
152 types_idx = total_size;
153 if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo))
156 total_size += num_types * sizeof(struct ttinfo);
157 if (chars > SIZE_MAX - total_size)
161 if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size)
164 total_size = ((total_size + __alignof__(struct leap) - 1) & ~(__alignof__(struct leap) - 1));
165 if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct leap))
168 total_size += num_leaps * sizeof(struct leap);
170 if (sizeof(time_t) == 8 && trans_width == 8) {
171 off_t rem = st.st_size - ftello(f);
173 if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars))
175 tzspec_len = (size_t) rem - (num_transitions * (8 + 1) + num_types * 6 + chars);
176 if (num_leaps > SIZE_MAX / 12 || tzspec_len < num_leaps * 12)
178 tzspec_len -= num_leaps * 12;
179 if (tzspec_len < num_isstd)
181 tzspec_len -= num_isstd;
182 if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt)
184 tzspec_len -= num_isgmt + 1;
185 if (SIZE_MAX - total_size < tzspec_len)
189 transitions = (time_t *)calloc(total_size + tzspec_len, 1);
190 if (transitions == NULL)
193 type_idxs = (unsigned char *)transitions + (num_transitions
195 types = (struct ttinfo *)((char *)transitions + types_idx);
196 zone_names = (char *)types + num_types * sizeof(struct ttinfo);
198 if (sizeof(time_t) == 4 || trans_width == 8) {
199 if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions)
202 if (fread(transitions, 4, num_transitions, f) != num_transitions ||
203 fread(type_idxs, 1, num_transitions, f) != num_transitions)
207 /* Check for bogus indices in the data file, so we can hereafter
208 safely use type_idxs[T] as indices into `types' and never crash. */
209 for (i = 0; i < num_transitions; ++i)
210 if (type_idxs[i] >= num_types)
213 if ((BYTE_ORDER != BIG_ENDIAN && (sizeof(time_t) == 4 || trans_width == 4)) ||
214 (BYTE_ORDER == BIG_ENDIAN && sizeof(time_t) == 8 && trans_width == 4)) {
215 /* Decode the transition times, stored as 4-byte integers in
216 network (big-endian) byte order. We work from the end of
217 the array so as not to clobber the next element to be
218 processed when sizeof (time_t) > 4. */
221 transitions[i] = decode((char *)transitions + i * 4);
222 } else if (BYTE_ORDER != BIG_ENDIAN && sizeof(time_t) == 8) {
223 /* Decode the transition times, stored as 8-byte integers in
224 network (big-endian) byte order. */
225 for (i = 0; i < num_transitions; ++i)
226 transitions[i] = decode64((char *)transitions + i * 8);
229 for (i = 0; i < num_types; ++i) {
233 if (fread(x, 1, sizeof(x), f) != sizeof(x))
236 if ((unsigned int)c > 1u)
240 if ((size_t) c > chars)
241 /* Bogus index in data file. */
244 types[i].offset = (long int)decode(x);
247 if (fread(zone_names, 1, chars, f) != chars)
250 for (i = 0; i < num_isstd; ++i) {
254 types[i].isstd = c != 0;
257 while (i < num_types)
258 types[i++].isstd = 0;
260 for (i = 0; i < num_isgmt; ++i) {
264 types[i].isgmt = c != 0;
267 while (i < num_types)
268 types[i++].isgmt = 0;
270 if (num_transitions == 0)
273 if (date < transitions[0] || date >= transitions[num_transitions - 1])
276 /* Find the first transition after TIMER, and
277 then pick the type of the transition before it. */
279 hi = num_transitions - 1;
281 /* Assume that DST is changing twice a year and guess initial
283 Half of a gregorian year has on average 365.2425 * 86400 / 2
284 = 15778476 seconds. */
285 i = (transitions[num_transitions - 1] - date) / 15778476;
286 if (i < num_transitions) {
287 i = num_transitions - 1 - i;
288 if (date < transitions[i]) {
289 if (i < 10 || date >= transitions[i - 10]) {
291 while (date < transitions[i - 1])
297 if (i + 10 >= num_transitions || date < transitions[i + 10]) {
299 while (date >= transitions[i])
308 while (lo + 1 < hi) {
310 if (date < transitions[i])
319 *switch_cur = transitions[i-1];
321 *zone_cur = strdup(&zone_names[types[type_idxs[i - 1]].idx]);
323 *dst_cur = types[type_idxs[i-1]].isdst;
326 *switch_next = transitions[i];
328 *delta_next = (types[type_idxs[i]].offset - types[type_idxs[i-1]].offset) / 60;
330 *zone_next = strdup(&zone_names[types[type_idxs[i]].idx]);
332 *dst_next = types[type_idxs[i]].isdst;