time-dst.c revision e2fd5e5ba281a22886fa3797dc6265cca670448b
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Timezone file reading code from glibc 2.16.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright (C) 1991-2012 Free Software Foundation, Inc.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2012 Kay Sievers
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * If tzh_version is '2' or greater, the above is followed by a second instance
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * of tzhead and a second instance of the data in which each coded transition
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * string for use in handling instants after the last transition time stored in
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * the file * (with nothing between the newlines if there is no POSIX
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering * representation for such instants).
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering char tzh_version[1]; /* '\0' or '2' as of 2005 */
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering char tzh_reserved[15]; /* reserved--must be zero */
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char tzh_leapcnt[4]; /* coded number of leap seconds */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char tzh_timecnt[4]; /* coded number of transition times */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char tzh_typecnt[4]; /* coded number of local time types */
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek char tzh_charcnt[4]; /* coded number of abbr. chars */
f5430a3ef308f3a102899fcaf7fbece757082f2aLennart Poettering long int offset; /* Seconds east of GMT. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned char isdst; /* Used to set tm_isdst. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned char idx; /* Index into `zone_names'. */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering unsigned char isstd; /* Transition times are in standard time. */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering unsigned char isgmt; /* Transition times are in GMT. */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering time_t transition; /* Time the transition takes effect. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering long int change; /* Seconds of correction to apply. */
8ac4e9e1e54397f6d1745c2a7a806132418c7da2Lennart Poetteringstatic inline int decode(const void *ptr) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic inline int64_t decode64(const void *ptr) {
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poetteringint time_get_dst(time_t date, const char *tzfile,
c0eb11cfd016381fe02875a4ef29c1ade00c94e7Lennart Poettering time_t *switch_cur, char **zone_cur, bool *dst_cur,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering time_t *switch_next, char **zone_next, bool *dst_next) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned char *type_idxs = 0;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek if (fstat(fileno(f), &st) < 0) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek if (fread((void *)&tzhead, sizeof(tzhead), 1, f) != 1 ||
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering memcmp(tzhead.tzh_magic, TZ_MAGIC, sizeof(tzhead.tzh_magic)) != 0)
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen num_transitions = (size_t)decode(tzhead.tzh_timecnt);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen num_types = (size_t)decode(tzhead.tzh_typecnt);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen num_leaps = (size_t)decode(tzhead.tzh_leapcnt);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen num_isstd = (size_t)decode(tzhead.tzh_ttisstdcnt);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen num_isgmt = (size_t)decode(tzhead.tzh_ttisgmtcnt);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering /* For platforms with 64-bit time_t we use the new format if available. */
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering if (sizeof(time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') {
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen /* We use the 8-byte format. */
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek /* Position the stream before the second header. */
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek to_skip = (num_transitions * (4 + 1)
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek + num_leaps * 8 + num_isstd + num_isgmt);
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (fseek(f, to_skip, SEEK_CUR) != 0)
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1)))
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek total_size = num_transitions * (sizeof(time_t) + 1);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek total_size = ((total_size + __alignof__(struct ttinfo) - 1) & ~(__alignof__(struct ttinfo) - 1));
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo))
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek total_size += num_types * sizeof(struct ttinfo);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (chars > SIZE_MAX - total_size)
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size)
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen total_size = ((total_size + __alignof__(struct leap) - 1) & ~(__alignof__(struct leap) - 1));
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct leap))
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen total_size += num_leaps * sizeof(struct leap);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (sizeof(time_t) == 8 && trans_width == 8) {
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering tzspec_len = (size_t) rem - (num_transitions * (8 + 1) + num_types * 6 + chars);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (num_leaps > SIZE_MAX / 12 || tzspec_len < num_leaps * 12)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt)
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen transitions = (time_t *)calloc(total_size + tzspec_len, 1);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering type_idxs = (unsigned char *)transitions + (num_transitions
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering types = (struct ttinfo *)((char *)transitions + types_idx);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering zone_names = (char *)types + num_types * sizeof(struct ttinfo);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if (sizeof(time_t) == 4 || trans_width == 8) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (fread(transitions, 4, num_transitions, f) != num_transitions ||
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fread(type_idxs, 1, num_transitions, f) != num_transitions)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Check for bogus indices in the data file, so we can hereafter
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering safely use type_idxs[T] as indices into `types' and never crash. */
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering for (i = 0; i < num_transitions; ++i)
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering if ((BYTE_ORDER != BIG_ENDIAN && (sizeof(time_t) == 4 || trans_width == 4)) ||
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt (BYTE_ORDER == BIG_ENDIAN && sizeof(time_t) == 8 && trans_width == 4)) {
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt /* Decode the transition times, stored as 4-byte integers in
i = num_transitions;
for (i = 0; i < num_transitions; ++i)
for (i = 0; i < num_types; ++i) {
goto lose;
c = getc(f);
goto lose;
c = getc(f);
goto lose;
goto lose;
for (i = 0; i < num_isstd; ++i) {
int c = getc(f);
if (c == EOF)
goto lose;
while (i < num_types)
for (i = 0; i < num_isgmt; ++i) {
int c = getc(f);
if (c == EOF)
goto lose;
while (i < num_types)
if (num_transitions == 0)
goto lose;
goto lose;
lo = 0;
if (i < num_transitions) {
goto found;
goto found;
hi = i;
lo = i;
i = hi;
if (switch_cur)
if (zone_cur)
if (dst_cur)
if (switch_next)
if (zone_next)
if (dst_next)
fclose(f);
lose:
fclose(f);
return err;