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/>.
38 * If tzh_version is '2' or greater, the above is followed by a second instance
39 * of tzhead and a second instance of the data in which each coded transition
40 * time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style
41 * string for use in handling instants after the last transition time stored in
42 * the file * (with nothing between the newlines if there is no POSIX
43 * representation for such instants).
45 #define TZ_MAGIC "TZif"
47 char tzh_magic[4]; /* TZ_MAGIC */
48 char tzh_version[1]; /* '\0' or '2' as of 2005 */
49 char tzh_reserved[15]; /* reserved--must be zero */
50 char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
51 char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
52 char tzh_leapcnt[4]; /* coded number of leap seconds */
53 char tzh_timecnt[4]; /* coded number of transition times */
54 char tzh_typecnt[4]; /* coded number of local time types */
55 char tzh_charcnt[4]; /* coded number of abbr. chars */
59 long int offset; /* Seconds east of GMT. */
60 unsigned char isdst; /* Used to set tm_isdst. */
61 unsigned char idx; /* Index into `zone_names'. */
62 unsigned char isstd; /* Transition times are in standard time. */
63 unsigned char isgmt; /* Transition times are in GMT. */
67 time_t transition; /* Time the transition takes effect. */
68 long int change; /* Seconds of correction to apply. */
71 static inline int decode(const void *ptr) {
72 return be32toh(*(int *)ptr);
75 static inline int64_t decode64(const void *ptr) {
76 return be64toh(*(int64_t *)ptr);
79 int time_get_dst(time_t date, const char *tzfile,
80 time_t *switch_cur, char **zone_cur, bool *dst_cur,
81 time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next) {
82 unsigned char *type_idxs = 0;
84 struct ttinfo *types = NULL;
85 char *zone_names = NULL;
87 size_t num_isstd, num_isgmt;
97 size_t num_transitions = 0;
98 _cleanup_free_ time_t *transitions = NULL;
99 _cleanup_fclose_ FILE *f;
101 f = fopen(tzfile, "re");
105 if (fstat(fileno(f), &st) < 0)
109 if (fread((void *)&tzhead, sizeof(tzhead), 1, f) != 1 ||
110 memcmp(tzhead.tzh_magic, TZ_MAGIC, sizeof(tzhead.tzh_magic)) != 0)
113 num_transitions = (size_t)decode(tzhead.tzh_timecnt);
114 num_types = (size_t)decode(tzhead.tzh_typecnt);
115 chars = (size_t)decode(tzhead.tzh_charcnt);
116 num_leaps = (size_t)decode(tzhead.tzh_leapcnt);
117 num_isstd = (size_t)decode(tzhead.tzh_ttisstdcnt);
118 num_isgmt = (size_t)decode(tzhead.tzh_ttisgmtcnt);
120 /* For platforms with 64-bit time_t we use the new format if available. */
121 if (sizeof(time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') {
124 /* We use the 8-byte format. */
127 /* Position the stream before the second header. */
128 to_skip = (num_transitions * (4 + 1)
131 + num_leaps * 8 + num_isstd + num_isgmt);
132 if (fseek(f, to_skip, SEEK_CUR) != 0)
138 if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1)))
141 total_size = num_transitions * (sizeof(time_t) + 1);
142 total_size = ((total_size + __alignof__(struct ttinfo) - 1) & ~(__alignof__(struct ttinfo) - 1));
143 types_idx = total_size;
144 if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo))
147 total_size += num_types * sizeof(struct ttinfo);
148 if (chars > SIZE_MAX - total_size)
152 if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size)
155 total_size = ((total_size + __alignof__(struct leap) - 1) & ~(__alignof__(struct leap) - 1));
156 if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct leap))
159 total_size += num_leaps * sizeof(struct leap);
161 if (sizeof(time_t) == 8 && trans_width == 8) {
162 off_t rem = st.st_size - ftello(f);
164 if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars))
166 tzspec_len = (size_t) rem - (num_transitions * (8 + 1) + num_types * 6 + chars);
167 if (num_leaps > SIZE_MAX / 12 || tzspec_len < num_leaps * 12)
169 tzspec_len -= num_leaps * 12;
170 if (tzspec_len < num_isstd)
172 tzspec_len -= num_isstd;
173 if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt)
175 tzspec_len -= num_isgmt + 1;
176 if (SIZE_MAX - total_size < tzspec_len)
180 /* leave space for additional zone_names zero terminator */
181 transitions = malloc0(total_size + tzspec_len + 1);
182 if (transitions == NULL)
185 type_idxs = (unsigned char *)transitions + (num_transitions
187 types = (struct ttinfo *)((char *)transitions + types_idx);
188 zone_names = (char *)types + num_types * sizeof(struct ttinfo);
190 if (sizeof(time_t) == 4 || trans_width == 8) {
191 if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions)
194 if (fread(transitions, 4, num_transitions, f) != num_transitions ||
195 fread(type_idxs, 1, num_transitions, f) != num_transitions)
199 /* Check for bogus indices in the data file, so we can hereafter
200 safely use type_idxs[T] as indices into `types' and never crash. */
201 for (i = 0; i < num_transitions; ++i)
202 if (type_idxs[i] >= num_types)
205 if (__BYTE_ORDER == __BIG_ENDIAN ? sizeof(time_t) == 8 && trans_width == 4
206 : sizeof(time_t) == 4 || trans_width == 4) {
207 /* Decode the transition times, stored as 4-byte integers in
208 network (big-endian) byte order. We work from the end of
209 the array so as not to clobber the next element to be
210 processed when sizeof (time_t) > 4. */
213 transitions[i] = decode((char *)transitions + i * 4);
214 } else if (__BYTE_ORDER != __BIG_ENDIAN && sizeof(time_t) == 8) {
215 /* Decode the transition times, stored as 8-byte integers in
216 network (big-endian) byte order. */
217 for (i = 0; i < num_transitions; ++i)
218 transitions[i] = decode64((char *)transitions + i * 8);
221 for (i = 0; i < num_types; ++i) {
225 if (fread(x, 1, sizeof(x), f) != sizeof(x))
228 if ((unsigned int)c > 1u)
232 if ((size_t) c > chars)
233 /* Bogus index in data file. */
236 types[i].offset = (long int)decode(x);
239 if (fread(zone_names, 1, chars, f) != chars)
242 zone_names[chars] = '\0';
244 for (i = 0; i < num_isstd; ++i) {
248 types[i].isstd = c != 0;
251 while (i < num_types)
252 types[i++].isstd = 0;
254 for (i = 0; i < num_isgmt; ++i) {
258 types[i].isgmt = c != 0;
261 while (i < num_types)
262 types[i++].isgmt = 0;
264 if (num_transitions == 0)
267 if (date < transitions[0] || date >= transitions[num_transitions - 1])
270 /* Find the first transition after TIMER, and
271 then pick the type of the transition before it. */
273 hi = num_transitions - 1;
275 /* Assume that DST is changing twice a year and guess initial
277 Half of a gregorian year has on average 365.2425 * 86400 / 2
278 = 15778476 seconds. */
279 i = (transitions[num_transitions - 1] - date) / 15778476;
280 if (i < num_transitions) {
281 i = num_transitions - 1 - i;
282 if (date < transitions[i]) {
283 if (i < 10 || date >= transitions[i - 10]) {
285 while (date < transitions[i - 1])
291 if (i + 10 >= num_transitions || date < transitions[i + 10]) {
293 while (date >= transitions[i])
302 while (lo + 1 < hi) {
304 if (date < transitions[i])
313 *switch_cur = transitions[i-1];
315 *zone_cur = strdup(&zone_names[types[type_idxs[i - 1]].idx]);
317 *dst_cur = types[type_idxs[i-1]].isdst;
320 *switch_next = transitions[i];
322 *delta_next = (types[type_idxs[i]].offset - types[type_idxs[i-1]].offset) / 60;
324 *zone_next = strdup(&zone_names[types[type_idxs[i]].idx]);
326 *dst_next = types[type_idxs[i]].isdst;