time-dst.c revision e2fd5e5ba281a22886fa3797dc6265cca670448b
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/***
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Timezone file reading code from glibc 2.16.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright (C) 1991-2012 Free Software Foundation, Inc.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2012 Kay Sievers
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
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
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
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***/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <ctype.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <errno.h>
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen#include <stddef.h>
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen#include <stdio.h>
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include <stdlib.h>
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering#include <string.h>
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering#include <time.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <endian.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <byteswap.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <assert.h>
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering#include <limits.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <unistd.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <stdint.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <stdbool.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <sys/stat.h>
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
b93312f5960b276bae915906ccde36f545bae3e0Zbigniew Jędrzejewski-Szmek#include "time-dst.h"
b93312f5960b276bae915906ccde36f545bae3e0Zbigniew Jędrzejewski-Szmek
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*
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).
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering */
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering#define TZ_MAGIC "TZif"
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poetteringstruct tzhead {
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering char tzh_magic[4]; /* TZ_MAGIC */
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 */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering};
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstruct ttinfo {
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};
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poetteringstruct leap {
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering time_t transition; /* Time the transition takes effect. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering long int change; /* Seconds of correction to apply. */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering};
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
8ac4e9e1e54397f6d1745c2a7a806132418c7da2Lennart Poetteringstatic inline int decode(const void *ptr) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return be32toh(*(int *)ptr);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic inline int64_t decode64(const void *ptr) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return be64toh(*(int64_t *)ptr);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek
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 time_t *transitions = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t num_transitions = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned char *type_idxs = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t num_types = 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct ttinfo *types = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char *zone_names = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering struct stat st;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering size_t num_isstd, num_isgmt;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering FILE *f;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering struct tzhead tzhead;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering size_t chars;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering size_t i;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering size_t total_size;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering size_t types_idx;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering int trans_width = 4;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering size_t tzspec_len;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering size_t num_leaps;
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek size_t lo, hi;
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek int err = -EINVAL;
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek f = fopen(tzfile, "re");
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek if (f == NULL)
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek return -errno;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek if (fstat(fileno(f), &st) < 0) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek err = -errno;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek fclose(f);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek return err;
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek }
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmekread_again:
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 goto lose;
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen num_transitions = (size_t)decode(tzhead.tzh_timecnt);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen num_types = (size_t)decode(tzhead.tzh_typecnt);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen chars = (size_t)decode(tzhead.tzh_charcnt);
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);
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen
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') {
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering size_t to_skip;
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen /* We use the 8-byte format. */
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering trans_width = 8;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek
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_types * 6
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek + chars
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek + num_leaps * 8 + num_isstd + num_isgmt);
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (fseek(f, to_skip, SEEK_CUR) != 0)
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek goto lose;
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek goto read_again;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek }
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1)))
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek goto lose;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek
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 types_idx = total_size;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo))
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek goto lose;
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek total_size += num_types * sizeof(struct ttinfo);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek if (chars > SIZE_MAX - total_size)
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen goto lose;
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen total_size += chars;
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size)
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen goto lose;
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen
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 goto lose;
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen total_size += num_leaps * sizeof(struct leap);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen tzspec_len = 0;
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (sizeof(time_t) == 8 && trans_width == 8) {
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen off_t rem = st.st_size - ftello(f);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto lose;
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 goto lose;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering tzspec_len -= num_leaps * 12;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (tzspec_len < num_isstd)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering goto lose;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering tzspec_len -= num_isstd;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering goto lose;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering tzspec_len -= num_isgmt + 1;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (SIZE_MAX - total_size < tzspec_len)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering goto lose;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
7c1ff6ac3d9e3acae1d601d40728cf7ccc9a7730Tom Gundersen
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen transitions = (time_t *)calloc(total_size + tzspec_len, 1);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (transitions == NULL)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering goto lose;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering type_idxs = (unsigned char *)transitions + (num_transitions
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering * sizeof(time_t));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering types = (struct ttinfo *)((char *)transitions + types_idx);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering zone_names = (char *)types + num_types * sizeof(struct ttinfo);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if (sizeof(time_t) == 4 || trans_width == 8) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions)
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering goto lose;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering } else {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (fread(transitions, 4, num_transitions, f) != num_transitions ||
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fread(type_idxs, 1, num_transitions, f) != num_transitions)
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering goto lose;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering }
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering
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)
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering if (type_idxs[i] >= num_types)
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering goto lose;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
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
network (big-endian) byte order. We work from the end of
the array so as not to clobber the next element to be
processed when sizeof (time_t) > 4. */
i = num_transitions;
while (i-- > 0)
transitions[i] = decode((char *)transitions + i * 4);
} else if (BYTE_ORDER != BIG_ENDIAN && sizeof(time_t) == 8) {
/* Decode the transition times, stored as 8-byte integers in
network (big-endian) byte order. */
for (i = 0; i < num_transitions; ++i)
transitions[i] = decode64((char *)transitions + i * 8);
}
for (i = 0; i < num_types; ++i) {
unsigned char x[4];
int c;
if (fread(x, 1, sizeof(x), f) != sizeof(x))
goto lose;
c = getc(f);
if ((unsigned int)c > 1u)
goto lose;
types[i].isdst = c;
c = getc(f);
if ((size_t) c > chars)
/* Bogus index in data file. */
goto lose;
types[i].idx = c;
types[i].offset = (long int)decode(x);
}
if (fread(zone_names, 1, chars, f) != chars)
goto lose;
for (i = 0; i < num_isstd; ++i) {
int c = getc(f);
if (c == EOF)
goto lose;
types[i].isstd = c != 0;
}
while (i < num_types)
types[i++].isstd = 0;
for (i = 0; i < num_isgmt; ++i) {
int c = getc(f);
if (c == EOF)
goto lose;
types[i].isgmt = c != 0;
}
while (i < num_types)
types[i++].isgmt = 0;
if (num_transitions == 0)
goto lose;
if (date < transitions[0] || date >= transitions[num_transitions - 1])
goto lose;
/* Find the first transition after TIMER, and
then pick the type of the transition before it. */
lo = 0;
hi = num_transitions - 1;
/* Assume that DST is changing twice a year and guess initial
search spot from it.
Half of a gregorian year has on average 365.2425 * 86400 / 2
= 15778476 seconds. */
i = (transitions[num_transitions - 1] - date) / 15778476;
if (i < num_transitions) {
i = num_transitions - 1 - i;
if (date < transitions[i]) {
if (i < 10 || date >= transitions[i - 10]) {
/* Linear search. */
while (date < transitions[i - 1])
i--;
goto found;
}
hi = i - 10;
} else {
if (i + 10 >= num_transitions || date < transitions[i + 10]) {
/* Linear search. */
while (date >= transitions[i])
i++;
goto found;
}
lo = i + 10;
}
}
/* Binary search. */
while (lo + 1 < hi) {
i = (lo + hi) / 2;
if (date < transitions[i])
hi = i;
else
lo = i;
}
i = hi;
found:
if (switch_cur)
*switch_cur = transitions[i-1];
if (zone_cur)
*zone_cur = strdup(&zone_names[types[type_idxs[i - 1]].idx]);
if (dst_cur)
*dst_cur = types[type_idxs[i-1]].isdst;
if (switch_next)
*switch_next = transitions[i];
if (zone_next)
*zone_next = strdup(&zone_names[types[type_idxs[i]].idx]);
if (dst_next)
*dst_next = types[type_idxs[i]].isdst;
free(transitions);
fclose(f);
return 0;
lose:
free(transitions);
fclose(f);
return err;
}