time-dst.c revision bdd13f6be4b588568683a1ab54f421fc6a636dbb
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Timezone file reading code from glibc 2.16.
Copyright (C) 1991-2012 Free Software Foundation, Inc.
Copyright 2012 Kay Sievers
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <ctype.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <endian.h>
#include <byteswap.h>
#include <assert.h>
#include <limits.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include "time-dst.h"
#include "util.h"
/*
* If tzh_version is '2' or greater, the above is followed by a second instance
* of tzhead and a second instance of the data in which each coded transition
* time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style
* string for use in handling instants after the last transition time stored in
* the file * (with nothing between the newlines if there is no POSIX
* representation for such instants).
*/
#define TZ_MAGIC "TZif"
struct tzhead {
};
struct ttinfo {
long int offset; /* Seconds east of GMT. */
unsigned char isdst; /* Used to set tm_isdst. */
unsigned char idx; /* Index into `zone_names'. */
unsigned char isstd; /* Transition times are in standard time. */
unsigned char isgmt; /* Transition times are in GMT. */
};
struct leap {
long int change; /* Seconds of correction to apply. */
};
}
}
unsigned char *type_idxs = 0;
char *zone_names = NULL;
size_t i;
int trans_width = 4;
size_t num_transitions = 0;
_cleanup_fclose_ FILE *f;
if (f == NULL)
return -errno;
return -errno;
return -EINVAL;
/* For platforms with 64-bit time_t we use the new format if available. */
/* We use the 8-byte format. */
trans_width = 8;
/* Position the stream before the second header. */
+ num_types * 6
+ chars
return -EINVAL;
goto read_again;
}
return -EINVAL;
return -EINVAL;
return -EINVAL;
total_size += chars;
return -EINVAL;
return -EINVAL;
tzspec_len = 0;
return -EINVAL;
return -EINVAL;
if (tzspec_len < num_isstd)
return -EINVAL;
tzspec_len -= num_isstd;
return -EINVAL;
return -EINVAL;
}
if (transitions == NULL)
return -EINVAL;
* sizeof(time_t));
return -EINVAL;
} else {
return -EINVAL;
}
/* Check for bogus indices in the data file, so we can hereafter
safely use type_idxs[T] as indices into `types' and never crash. */
for (i = 0; i < num_transitions; ++i)
return -EINVAL;
/* 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)
/* Decode the transition times, stored as 8-byte integers in
network (big-endian) byte order. */
for (i = 0; i < num_transitions; ++i)
}
for (i = 0; i < num_types; ++i) {
unsigned char x[4];
int c;
if (fread(x, 1, sizeof(x), f) != sizeof(x))
return -EINVAL;
c = getc(f);
if ((unsigned int)c > 1u)
return -EINVAL;
c = getc(f);
/* Bogus index in data file. */
return -EINVAL;
}
return -EINVAL;
for (i = 0; i < num_isstd; ++i) {
int c = getc(f);
if (c == EOF)
return -EINVAL;
}
while (i < num_types)
for (i = 0; i < num_isgmt; ++i) {
int c = getc(f);
if (c == EOF)
return -EINVAL;
}
while (i < num_types)
if (num_transitions == 0)
return -EINVAL;
return -EINVAL;
/* Find the first transition after TIMER, and
then pick the type of the transition before it. */
lo = 0;
/* 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. */
if (i < num_transitions) {
i = num_transitions - 1 - i;
if (date < transitions[i]) {
/* Linear search. */
i--;
goto found;
}
hi = i - 10;
} else {
/* Linear search. */
while (date >= transitions[i])
i++;
goto found;
}
lo = i + 10;
}
}
/* Binary search. */
if (date < transitions[i])
hi = i;
else
lo = i;
}
i = hi;
if (switch_cur)
if (zone_cur)
if (dst_cur)
if (switch_next)
*switch_next = transitions[i];
if (delta_next)
if (zone_next)
if (dst_next)
return 0;
}