blob: 018acadd52a24a9855ed2b18f7efb01d764c9e06 [file] [log] [blame]
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001/* Convert timestamp from time_t to struct tm. */
2
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003/*
4** This file is in the public domain, so clarified as of
5** 1996-06-05 by Arthur David Olson.
6*/
7
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08008/*
9** Leap second handling from Bradley White.
10** POSIX-style TZ environment variable handling from Guy Harris.
11*/
12
13/*LINTLIBRARY*/
14
Elliott Hughes9fb22a32015-10-07 17:13:40 -070015#define LOCALTIME_IMPLEMENTATION
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080016#include "private.h"
Elliott Hughes9fb22a32015-10-07 17:13:40 -070017
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080018#include "tzfile.h"
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000019#include <fcntl.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080020
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000021#if defined THREAD_SAFE && THREAD_SAFE
Elliott Hughes9fb22a32015-10-07 17:13:40 -070022# include <pthread.h>
23static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
24static int lock(void) { return pthread_mutex_lock(&locallock); }
25static void unlock(void) { pthread_mutex_unlock(&locallock); }
26#else
27static int lock(void) { return 0; }
28static void unlock(void) { }
29#endif
30
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080031#ifndef TZ_ABBR_CHAR_SET
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010032# define TZ_ABBR_CHAR_SET \
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070033 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080034#endif /* !defined TZ_ABBR_CHAR_SET */
35
36#ifndef TZ_ABBR_ERR_CHAR
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010037# define TZ_ABBR_ERR_CHAR '_'
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080038#endif /* !defined TZ_ABBR_ERR_CHAR */
39
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080040/*
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010041+** Support non-POSIX platforms that distinguish between text and binary files.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080042*/
43
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080044#ifndef O_BINARY
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010045# define O_BINARY 0
46#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080047
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080048#ifndef WILDABBR
49/*
50** Someone might make incorrect use of a time zone abbreviation:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070051** 1. They might reference tzname[0] before calling tzset (explicitly
52** or implicitly).
53** 2. They might reference tzname[1] before calling tzset (explicitly
54** or implicitly).
55** 3. They might reference tzname[1] after setting to a time zone
56** in which Daylight Saving Time is never observed.
57** 4. They might reference tzname[0] after setting to a time zone
58** in which Standard Time is never observed.
59** 5. They might reference tm.TM_ZONE after calling offtime.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080060** What's best to do in the above cases is open to debate;
61** for now, we just set things up so that in any of the five cases
62** WILDABBR is used. Another possibility: initialize tzname[0] to the
63** string "tzname[0] used before set", and similarly for the other cases.
64** And another: initialize tzname[0] to "ERA", with an explanation in the
65** manual page of what this "time zone abbreviation" means (doing this so
66** that tzname[0] has the "normal" length of three characters).
67*/
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010068# define WILDABBR " "
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080069#endif /* !defined WILDABBR */
70
Elliott Hughes906eb992014-06-18 19:46:25 -070071static const char wildabbr[] = WILDABBR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010073static char const etc_utc[] = "Etc/UTC";
74static char const *utc = etc_utc + sizeof "Etc/" - 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080075
76/*
77** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000078** Default to US rules as of 2017-05-07.
79** POSIX does not specify the default DST rules;
80** for historical reasons, US rules are a common default.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080081*/
82#ifndef TZDEFRULESTRING
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +010083# define TZDEFRULESTRING ",M3.2.0,M11.1.0"
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000084#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080085
Calin Juravled8928922014-02-28 12:18:53 +000086struct ttinfo { /* time type information */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000087 int_fast32_t tt_utoff; /* UT offset in seconds */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070088 bool tt_isdst; /* used to set tm_isdst */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000089 int tt_desigidx; /* abbreviation list index */
Elliott Hughes9fb22a32015-10-07 17:13:40 -070090 bool tt_ttisstd; /* transition is std time */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000091 bool tt_ttisut; /* transition is UT */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080092};
93
Calin Juravled8928922014-02-28 12:18:53 +000094struct lsinfo { /* leap second information */
Elliott Hughesce4783c2013-07-12 17:31:11 -070095 time_t ls_trans; /* transition time */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000096 int_fast32_t ls_corr; /* correction to apply */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080097};
98
Almaz Mingaleev5411aff2022-02-11 12:27:12 +000099/* This abbreviation means local time is unspecified. */
100static char const UNSPEC[] = "-00";
101
102/* How many extra bytes are needed at the end of struct state's chars array.
103 This needs to be at least 1 for null termination in case the input
104 data isn't properly terminated, and it also needs to be big enough
105 for ttunspecified to work without crashing. */
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100106enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 };
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000107
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100108/* Limit to time zone abbreviation length in POSIX-style TZ strings.
109 This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */
110#ifndef TZNAME_MAXIMUM
111# define TZNAME_MAXIMUM 255
112#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800113
114struct state {
Calin Juravled8928922014-02-28 12:18:53 +0000115 int leapcnt;
116 int timecnt;
117 int typecnt;
118 int charcnt;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700119 bool goback;
120 bool goahead;
Calin Juravled8928922014-02-28 12:18:53 +0000121 time_t ats[TZ_MAX_TIMES];
122 unsigned char types[TZ_MAX_TIMES];
123 struct ttinfo ttis[TZ_MAX_TYPES];
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100124 char chars[max(max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof "UTC"),
125 2 * (TZNAME_MAXIMUM + 1))];
Calin Juravled8928922014-02-28 12:18:53 +0000126 struct lsinfo lsis[TZ_MAX_LEAPS];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000127 /* The time type to use for early times or if no transitions.
128 It is always zero for recent tzdb releases.
129 It might be nonzero for data from tzdb 2018e or earlier. */
130 int defaulttype;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800131};
132
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700133enum r_type {
134 JULIAN_DAY, /* Jn = Julian day */
135 DAY_OF_YEAR, /* n = day of year */
136 MONTH_NTH_DAY_OF_WEEK /* Mm.n.d = month, week, day of week */
137};
138
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800139struct rule {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700140 enum r_type r_type; /* type of rule */
Calin Juravled8928922014-02-28 12:18:53 +0000141 int r_day; /* day number of rule */
142 int r_week; /* week number of rule */
143 int r_mon; /* month number of rule */
144 int_fast32_t r_time; /* transition time of rule */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800145};
146
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700147static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
148 struct tm *);
149static bool increment_overflow(int *, int);
150static bool increment_overflow_time(time_t *, int_fast32_t);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000151static int_fast32_t leapcorr(struct state const *, time_t);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700152static bool normalize_overflow32(int_fast32_t *, int *, int);
153static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
154 struct tm *);
155static bool typesequiv(struct state const *, int, int);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000156static bool tzparse(char const *, struct state *, struct state *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157
158#ifdef ALL_STATE
Calin Juravled8928922014-02-28 12:18:53 +0000159static struct state * lclptr;
160static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800161#endif /* defined ALL_STATE */
162
163#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700164static struct state lclmem;
165static struct state gmtmem;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100166static struct state *const lclptr = &lclmem;
167static struct state *const gmtptr = &gmtmem;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800168#endif /* State Farm */
169
170#ifndef TZ_STRLEN_MAX
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100171# define TZ_STRLEN_MAX 255
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172#endif /* !defined TZ_STRLEN_MAX */
173
Calin Juravled8928922014-02-28 12:18:53 +0000174static char lcl_TZname[TZ_STRLEN_MAX + 1];
175static int lcl_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800176
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800177/*
178** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700179** Except for the strftime function, these functions [asctime,
180** ctime, gmtime, localtime] return values in one of two static
181** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800182** Thanks to Paul Eggert for noting this.
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100183**
184** This requirement was removed in C99, so support it only if requested,
185** as support is more likely to lead to bugs in badly written programs.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800186*/
187
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100188#if SUPPORT_C89
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700189static struct tm tm;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100190#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800191
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000192#if 2 <= HAVE_TZNAME + TZ_TIME_T
Elliott Hughes0a610d02016-07-29 14:04:17 -0700193char * tzname[2] = {
194 (char *) wildabbr,
195 (char *) wildabbr
196};
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000197#endif
198#if 2 <= USG_COMPAT + TZ_TIME_T
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700199long timezone;
200int daylight;
Elliott Hughes0a610d02016-07-29 14:04:17 -0700201#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800202
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000203#if 2 <= ALTZONE + TZ_TIME_T
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700204long altzone;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000205#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800206
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000207/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700208static void
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000209init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx)
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700210{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000211 s->tt_utoff = utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700212 s->tt_isdst = isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000213 s->tt_desigidx = desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700214 s->tt_ttisstd = false;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000215 s->tt_ttisut = false;
216}
217
218/* Return true if SP's time type I does not specify local time. */
219static bool
220ttunspecified(struct state const *sp, int i)
221{
222 char const *abbr = &sp->chars[sp->ttis[i].tt_desigidx];
223 /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA. */
224 return memcmp(abbr, UNSPEC, sizeof UNSPEC) == 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700225}
226
Elliott Hughesce4783c2013-07-12 17:31:11 -0700227static int_fast32_t
228detzcode(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800229{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700230 register int_fast32_t result;
231 register int i;
232 int_fast32_t one = 1;
233 int_fast32_t halfmaxval = one << (32 - 2);
234 int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
235 int_fast32_t minval = -1 - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800236
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700237 result = codep[0] & 0x7f;
238 for (i = 1; i < 4; ++i)
239 result = (result << 8) | (codep[i] & 0xff);
240
241 if (codep[0] & 0x80) {
242 /* Do two's-complement negation even on non-two's-complement machines.
243 If the result would be minval - 1, return minval. */
244 result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
245 result += minval;
246 }
247 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248}
249
Calin Juravle627d37c2014-02-28 11:46:03 +0000250static int_fast64_t
Elliott Hughesce4783c2013-07-12 17:31:11 -0700251detzcode64(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800252{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000253 register int_fast64_t result;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700254 register int i;
255 int_fast64_t one = 1;
256 int_fast64_t halfmaxval = one << (64 - 2);
257 int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
258 int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800259
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700260 result = codep[0] & 0x7f;
261 for (i = 1; i < 8; ++i)
262 result = (result << 8) | (codep[i] & 0xff);
263
264 if (codep[0] & 0x80) {
265 /* Do two's-complement negation even on non-two's-complement machines.
266 If the result would be minval - 1, return minval. */
267 result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
268 result += minval;
269 }
270 return result;
271}
272
273static void
274update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
275{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000276#if HAVE_TZNAME
277 tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx];
278#endif
279#if USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700280 if (!ttisp->tt_isdst)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000281 timezone = - ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700282#endif
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000283#if ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700284 if (ttisp->tt_isdst)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000285 altzone = - ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700286#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287}
288
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000289/* If STDDST_MASK indicates that SP's TYPE provides useful info,
290 update tzname, timezone, and/or altzone and return STDDST_MASK,
291 diminished by the provided info if it is a specified local time.
292 Otherwise, return STDDST_MASK. See settzname for STDDST_MASK. */
293static int
294may_update_tzname_etc(int stddst_mask, struct state *sp, int type)
295{
296 struct ttinfo *ttisp = &sp->ttis[type];
297 int this_bit = 1 << ttisp->tt_isdst;
298 if (stddst_mask & this_bit) {
299 update_tzname_etc(sp, ttisp);
300 if (!ttunspecified(sp, type))
301 return stddst_mask & ~this_bit;
302 }
303 return stddst_mask;
304}
305
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800306static void
Elliott Hughesce4783c2013-07-12 17:31:11 -0700307settzname(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800308{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700309 register struct state * const sp = lclptr;
310 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800311
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000312 /* If STDDST_MASK & 1 we need info about a standard time.
313 If STDDST_MASK & 2 we need info about a daylight saving time.
314 When STDDST_MASK becomes zero we can stop looking. */
315 int stddst_mask = 0;
316
317#if HAVE_TZNAME
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100318 tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000319 stddst_mask = 3;
320#endif
321#if USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700322 timezone = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000323 stddst_mask = 3;
324#endif
325#if ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700326 altzone = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000327 stddst_mask |= 2;
328#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700329 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000330 ** And to get the latest time zone abbreviations into tzname. . .
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700331 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000332 if (sp) {
333 for (i = sp->timecnt - 1; stddst_mask && 0 <= i; i--)
334 stddst_mask = may_update_tzname_etc(stddst_mask, sp, sp->types[i]);
335 for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--)
336 stddst_mask = may_update_tzname_etc(stddst_mask, sp, i);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700337 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000338#if USG_COMPAT
339 daylight = stddst_mask >> 1 ^ 1;
340#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800341}
342
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100343/* Replace bogus characters in time zone abbreviations.
344 Return 0 on success, an errno value if a time zone abbreviation is
345 too long. */
346static int
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700347scrub_abbrs(struct state *sp)
348{
349 int i;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100350
351 /* Reject overlong abbreviations. */
352 for (i = 0; i < sp->charcnt - (TZNAME_MAXIMUM + 1); ) {
353 int len = strlen(&sp->chars[i]);
354 if (TZNAME_MAXIMUM < len)
355 return EOVERFLOW;
356 i += len + 1;
357 }
358
359 /* Replace bogus characters. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700360 for (i = 0; i < sp->charcnt; ++i)
361 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
362 sp->chars[i] = TZ_ABBR_ERR_CHAR;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700363
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100364 return 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700365}
366
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700367/* Input buffer for data read from a compiled tz file. */
368union input_buffer {
369 /* The first part of the buffer, interpreted as a header. */
370 struct tzhead tzhead;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800371
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700372 /* The entire buffer. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000373 char buf[2 * sizeof(struct tzhead) + 2 * sizeof(struct state)
374 + 4 * TZ_MAX_TIMES];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800375};
376
Elliott Hughes31fc69f2023-06-20 15:36:11 -0700377#if defined(__BIONIC__)
378// Android: there is no directory with one file per timezone on Android,
379// but we do have a system property instead.
380#include <sys/system_properties.h>
381#else
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000382/* TZDIR with a trailing '/' rather than a trailing '\0'. */
383static char const tzdirslash[sizeof TZDIR] = TZDIR "/";
384#endif
385
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700386/* Local storage needed for 'tzloadbody'. */
387union local_storage {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700388 /* The results of analyzing the file's contents after it is opened. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000389 struct file_analysis {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700390 /* The input buffer. */
391 union input_buffer u;
392
393 /* A temporary state used for parsing a TZ string in the file. */
394 struct state st;
395 } u;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000396
397 // Android-removed: There is no directory with file-per-time zone on Android.
398 #ifndef __BIONIC__
399 /* The file name to be opened. */
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100400 char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000401 #endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700402};
403
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700404/* Load tz data from the file named NAME into *SP. Read extended
405 format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
406 success, an errno value on failure. */
407static int
408tzloadbody(char const *name, struct state *sp, bool doextend,
409 union local_storage *lsp)
410{
411 register int i;
412 register int fid;
413 register int stored;
414 register ssize_t nread;
Elliott Hughesa9209d72016-09-16 18:16:47 -0700415#if !defined(__BIONIC__)
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700416 register bool doaccess;
417 register char *fullname = lsp->fullname;
418#endif
419 register union input_buffer *up = &lsp->u.u;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000420 register int tzheadsize = sizeof(struct tzhead);
Elliott Hughes31fc69f2023-06-20 15:36:11 -0700421 char system_tz_name[PROP_VALUE_MAX];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700422
423 sp->goback = sp->goahead = false;
424
425 if (! name) {
Elliott Hughes31fc69f2023-06-20 15:36:11 -0700426#if defined(__BIONIC__)
427 extern void __bionic_get_system_tz(char* , size_t);
428 __bionic_get_system_tz(system_tz_name, sizeof(system_tz_name));
429 name = system_tz_name;
430#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700431 name = TZDEFAULT;
432 if (! name)
433 return EINVAL;
Elliott Hughes31fc69f2023-06-20 15:36:11 -0700434#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700435 }
436
Elliott Hughesa9209d72016-09-16 18:16:47 -0700437#if defined(__BIONIC__)
Elliott Hughes0e8616a2017-04-11 14:44:51 -0700438 extern int __bionic_open_tzdata(const char*, int32_t*);
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700439 int32_t entry_length;
440 fid = __bionic_open_tzdata(name, &entry_length);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700441#else
442 if (name[0] == ':')
443 ++name;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000444#ifdef SUPPRESS_TZDIR
445 /* Do not prepend TZDIR. This is intended for specialized
446 applications only, due to its security implications. */
447 doaccess = true;
448#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700449 doaccess = name[0] == '/';
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000450#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700451 if (!doaccess) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000452 char const *dot;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100453 if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700454 return ENAMETOOLONG;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000455
456 /* Create a string "TZDIR/NAME". Using sprintf here
457 would pull in stdio (and would fail if the
458 resulting string length exceeded INT_MAX!). */
459 memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash);
460 strcpy(lsp->fullname + sizeof tzdirslash, name);
461
462 /* Set doaccess if NAME contains a ".." file name
463 component, as such a name could read a file outside
464 the TZDIR virtual subtree. */
465 for (dot = name; (dot = strchr(dot, '.')); dot++)
466 if ((dot == name || dot[-1] == '/') && dot[1] == '.'
467 && (dot[2] == '/' || !dot[2])) {
468 doaccess = true;
469 break;
470 }
471
472 name = lsp->fullname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700473 }
474 if (doaccess && access(name, R_OK) != 0)
475 return errno;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100476 fid = open(name, O_RDONLY | O_BINARY);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700477#endif
478 if (fid < 0)
479 return errno;
480
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700481#if defined(__BIONIC__)
Elliott Hughes4edd6512016-10-03 16:46:33 -0700482 nread = TEMP_FAILURE_RETRY(read(fid, up->buf, entry_length));
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700483#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700484 nread = read(fid, up->buf, sizeof up->buf);
Elliott Hughes81c46fc2016-10-03 12:29:30 -0700485#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700486 if (nread < tzheadsize) {
487 int err = nread < 0 ? errno : EINVAL;
488 close(fid);
489 return err;
490 }
491 if (close(fid) < 0)
492 return errno;
493 for (stored = 4; stored <= 8; stored *= 2) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000494 char version = up->tzhead.tzh_version[0];
495 bool skip_datablock = stored == 4 && version;
496 int_fast32_t datablock_size;
497 int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
498 int_fast32_t ttisutcnt = detzcode(up->tzhead.tzh_ttisutcnt);
499 int_fast64_t prevtr = -1;
500 int_fast32_t prevcorr;
501 int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
502 int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
503 int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
504 int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
505 char const *p = up->buf + tzheadsize;
506 /* Although tzfile(5) currently requires typecnt to be nonzero,
507 support future formats that may allow zero typecnt
508 in files that have a TZ string and no transitions. */
509 if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
510 && 0 <= typecnt && typecnt < TZ_MAX_TYPES
511 && 0 <= timecnt && timecnt < TZ_MAX_TIMES
512 && 0 <= charcnt && charcnt < TZ_MAX_CHARS
513 && 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES
514 && 0 <= ttisutcnt && ttisutcnt < TZ_MAX_TYPES))
515 return EINVAL;
516 datablock_size
517 = (timecnt * stored /* ats */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700518 + timecnt /* types */
519 + typecnt * 6 /* ttinfos */
520 + charcnt /* chars */
521 + leapcnt * (stored + 4) /* lsinfos */
522 + ttisstdcnt /* ttisstds */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000523 + ttisutcnt); /* ttisuts */
524 if (nread < tzheadsize + datablock_size)
525 return EINVAL;
526 if (skip_datablock)
527 p += datablock_size;
528 else {
529 if (! ((ttisstdcnt == typecnt || ttisstdcnt == 0)
530 && (ttisutcnt == typecnt || ttisutcnt == 0)))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700531 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000532
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700533 sp->leapcnt = leapcnt;
534 sp->timecnt = timecnt;
535 sp->typecnt = typecnt;
536 sp->charcnt = charcnt;
537
538 /* Read transitions, discarding those out of time_t range.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000539 But pretend the last transition before TIME_T_MIN
540 occurred at TIME_T_MIN. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700541 timecnt = 0;
542 for (i = 0; i < sp->timecnt; ++i) {
543 int_fast64_t at
544 = stored == 4 ? detzcode(p) : detzcode64(p);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000545 sp->types[i] = at <= TIME_T_MAX;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700546 if (sp->types[i]) {
547 time_t attime
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000548 = ((TYPE_SIGNED(time_t) ? at < TIME_T_MIN : at < 0)
549 ? TIME_T_MIN : at);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700550 if (timecnt && attime <= sp->ats[timecnt - 1]) {
551 if (attime < sp->ats[timecnt - 1])
552 return EINVAL;
553 sp->types[i - 1] = 0;
554 timecnt--;
555 }
556 sp->ats[timecnt++] = attime;
557 }
558 p += stored;
559 }
560
561 timecnt = 0;
562 for (i = 0; i < sp->timecnt; ++i) {
563 unsigned char typ = *p++;
564 if (sp->typecnt <= typ)
565 return EINVAL;
566 if (sp->types[i])
567 sp->types[timecnt++] = typ;
568 }
569 sp->timecnt = timecnt;
570 for (i = 0; i < sp->typecnt; ++i) {
571 register struct ttinfo * ttisp;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000572 unsigned char isdst, desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700573
574 ttisp = &sp->ttis[i];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000575 ttisp->tt_utoff = detzcode(p);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700576 p += 4;
577 isdst = *p++;
578 if (! (isdst < 2))
579 return EINVAL;
580 ttisp->tt_isdst = isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000581 desigidx = *p++;
582 if (! (desigidx < sp->charcnt))
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700583 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000584 ttisp->tt_desigidx = desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700585 }
586 for (i = 0; i < sp->charcnt; ++i)
587 sp->chars[i] = *p++;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000588 /* Ensure '\0'-terminated, and make it safe to call
589 ttunspecified later. */
590 memset(&sp->chars[i], 0, CHARS_EXTRA);
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700591
592 /* Read leap seconds, discarding those out of time_t range. */
593 leapcnt = 0;
594 for (i = 0; i < sp->leapcnt; ++i) {
595 int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
596 int_fast32_t corr = detzcode(p + stored);
597 p += stored + 4;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000598
599 /* Leap seconds cannot occur before the Epoch,
600 or out of order. */
601 if (tr <= prevtr)
602 return EINVAL;
603
604 /* To avoid other botches in this code, each leap second's
605 correction must differ from the previous one's by 1
606 second or less, except that the first correction can be
607 any value; these requirements are more generous than
608 RFC 8536, to allow future RFC extensions. */
609 if (! (i == 0
610 || (prevcorr < corr
611 ? corr == prevcorr + 1
612 : (corr == prevcorr
613 || corr == prevcorr - 1))))
614 return EINVAL;
615 prevtr = tr;
616 prevcorr = corr;
617
618 if (tr <= TIME_T_MAX) {
619 sp->lsis[leapcnt].ls_trans = tr;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700620 sp->lsis[leapcnt].ls_corr = corr;
621 leapcnt++;
622 }
623 }
624 sp->leapcnt = leapcnt;
625
626 for (i = 0; i < sp->typecnt; ++i) {
627 register struct ttinfo * ttisp;
628
629 ttisp = &sp->ttis[i];
630 if (ttisstdcnt == 0)
631 ttisp->tt_ttisstd = false;
632 else {
633 if (*p != true && *p != false)
634 return EINVAL;
635 ttisp->tt_ttisstd = *p++;
636 }
637 }
638 for (i = 0; i < sp->typecnt; ++i) {
639 register struct ttinfo * ttisp;
640
641 ttisp = &sp->ttis[i];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000642 if (ttisutcnt == 0)
643 ttisp->tt_ttisut = false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700644 else {
645 if (*p != true && *p != false)
646 return EINVAL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000647 ttisp->tt_ttisut = *p++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700648 }
649 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000650 }
651
652 nread -= p - up->buf;
653 memmove(up->buf, p, nread);
654
655 /* If this is an old file, we're done. */
656 if (!version)
657 break;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700658 }
659 if (doextend && nread > 2 &&
660 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
661 sp->typecnt + 2 <= TZ_MAX_TYPES) {
662 struct state *ts = &lsp->u.st;
663
664 up->buf[nread - 1] = '\0';
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000665 if (tzparse(&up->buf[1], ts, sp)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700666
667 /* Attempt to reuse existing abbreviations.
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000668 Without this, America/Anchorage would be right on
669 the edge after 2037 when TZ_MAX_CHARS is 50, as
670 sp->charcnt equals 40 (for LMT AST AWT APT AHST
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700671 AHDT YST AKDT AKST) and ts->charcnt equals 10
672 (for AKST AKDT). Reusing means sp->charcnt can
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000673 stay 40 in this example. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700674 int gotabbr = 0;
675 int charcnt = sp->charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000676 for (i = 0; i < ts->typecnt; i++) {
677 char *tsabbr = ts->chars + ts->ttis[i].tt_desigidx;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700678 int j;
679 for (j = 0; j < charcnt; j++)
680 if (strcmp(sp->chars + j, tsabbr) == 0) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000681 ts->ttis[i].tt_desigidx = j;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700682 gotabbr++;
683 break;
684 }
685 if (! (j < charcnt)) {
686 int tsabbrlen = strlen(tsabbr);
687 if (j + tsabbrlen < TZ_MAX_CHARS) {
688 strcpy(sp->chars + j, tsabbr);
689 charcnt = j + tsabbrlen + 1;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000690 ts->ttis[i].tt_desigidx = j;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700691 gotabbr++;
692 }
693 }
694 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000695 if (gotabbr == ts->typecnt) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700696 sp->charcnt = charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000697
698 /* Ignore any trailing, no-op transitions generated
699 by zic as they don't help here and can run afoul
700 of bugs in zic 2016j or earlier. */
701 while (1 < sp->timecnt
702 && (sp->types[sp->timecnt - 1]
703 == sp->types[sp->timecnt - 2]))
704 sp->timecnt--;
705
706 for (i = 0;
707 i < ts->timecnt && sp->timecnt < TZ_MAX_TIMES;
708 i++) {
709 time_t t = ts->ats[i];
710 if (increment_overflow_time(&t, leapcorr(sp, t))
711 || (0 < sp->timecnt
712 && t <= sp->ats[sp->timecnt - 1]))
713 continue;
714 sp->ats[sp->timecnt] = t;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700715 sp->types[sp->timecnt] = (sp->typecnt
716 + ts->types[i]);
717 sp->timecnt++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700718 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000719 for (i = 0; i < ts->typecnt; i++)
720 sp->ttis[sp->typecnt++] = ts->ttis[i];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700721 }
722 }
723 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000724 if (sp->typecnt == 0)
725 return EINVAL;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700726 if (sp->timecnt > 1) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000727 if (sp->ats[0] <= TIME_T_MAX - SECSPERREPEAT) {
728 time_t repeatat = sp->ats[0] + SECSPERREPEAT;
729 int repeattype = sp->types[0];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700730 for (i = 1; i < sp->timecnt; ++i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000731 if (sp->ats[i] == repeatat
732 && typesequiv(sp, sp->types[i], repeattype)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700733 sp->goback = true;
734 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000735 }
736 }
737 if (TIME_T_MIN + SECSPERREPEAT <= sp->ats[sp->timecnt - 1]) {
738 time_t repeatat = sp->ats[sp->timecnt - 1] - SECSPERREPEAT;
739 int repeattype = sp->types[sp->timecnt - 1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700740 for (i = sp->timecnt - 2; i >= 0; --i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000741 if (sp->ats[i] == repeatat
742 && typesequiv(sp, sp->types[i], repeattype)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700743 sp->goahead = true;
744 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000745 }
746 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700747 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000748
749 /* Infer sp->defaulttype from the data. Although this default
750 type is always zero for data from recent tzdb releases,
751 things are trickier for data from tzdb 2018e or earlier.
752
753 The first set of heuristics work around bugs in 32-bit data
754 generated by tzdb 2013c or earlier. The workaround is for
755 zones like Australia/Macquarie where timestamps before the
756 first transition have a time type that is not the earliest
757 standard-time type. See:
758 https://mm.icann.org/pipermail/tz/2013-May/019368.html */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700759 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000760 ** If type 0 does not specify local time, or is unused in transitions,
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700761 ** it's the type to use for early times.
762 */
763 for (i = 0; i < sp->timecnt; ++i)
764 if (sp->types[i] == 0)
765 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000766 i = i < sp->timecnt && ! ttunspecified(sp, 0) ? -1 : 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700767 /*
768 ** Absent the above,
769 ** if there are transition times
770 ** and the first transition is to a daylight time
771 ** find the standard type less than and closest to
772 ** the type of the first transition.
773 */
774 if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
775 i = sp->types[0];
776 while (--i >= 0)
777 if (!sp->ttis[i].tt_isdst)
778 break;
779 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000780 /* The next heuristics are for data generated by tzdb 2018e or
781 earlier, for zones like EST5EDT where the first transition
782 is to DST. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700783 /*
784 ** If no result yet, find the first standard type.
785 ** If there is none, punt to type zero.
786 */
787 if (i < 0) {
788 i = 0;
789 while (sp->ttis[i].tt_isdst)
790 if (++i >= sp->typecnt) {
791 i = 0;
792 break;
793 }
794 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000795 /* A simple 'sp->defaulttype = 0;' would suffice here if we
796 didn't have to worry about 2018e-or-earlier data. Even
797 simpler would be to remove the defaulttype member and just
798 use 0 in its place. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700799 sp->defaulttype = i;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000800
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700801 return 0;
802}
803
804/* Load tz data from the file named NAME into *SP. Read extended
805 format if DOEXTEND. Return 0 on success, an errno value on failure. */
806static int
807tzload(char const *name, struct state *sp, bool doextend)
808{
809#ifdef ALL_STATE
810 union local_storage *lsp = malloc(sizeof *lsp);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000811 if (!lsp) {
812 return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
813 } else {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700814 int err = tzloadbody(name, sp, doextend, lsp);
815 free(lsp);
816 return err;
817 }
818#else
819 union local_storage ls;
820 return tzloadbody(name, sp, doextend, &ls);
821#endif
822}
823
824static bool
825typesequiv(const struct state *sp, int a, int b)
826{
827 register bool result;
828
829 if (sp == NULL ||
830 a < 0 || a >= sp->typecnt ||
831 b < 0 || b >= sp->typecnt)
832 result = false;
833 else {
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100834 /* Compare the relevant members of *AP and *BP.
835 Ignore tt_ttisstd and tt_ttisut, as they are
836 irrelevant now and counting them could cause
837 sp->goahead to mistakenly remain false. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700838 register const struct ttinfo * ap = &sp->ttis[a];
839 register const struct ttinfo * bp = &sp->ttis[b];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000840 result = (ap->tt_utoff == bp->tt_utoff
841 && ap->tt_isdst == bp->tt_isdst
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000842 && (strcmp(&sp->chars[ap->tt_desigidx],
843 &sp->chars[bp->tt_desigidx])
844 == 0));
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700845 }
846 return result;
847}
848
849static const int mon_lengths[2][MONSPERYEAR] = {
850 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
851 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
852};
853
854static const int year_lengths[2] = {
855 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800856};
857
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000858/* Is C an ASCII digit? */
859static bool
860is_digit(char c)
861{
862 return '0' <= c && c <= '9';
863}
864
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800865/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000866** Given a pointer into a timezone string, scan until a character that is not
867** a valid character in a time zone abbreviation is found.
868** Return a pointer to that character.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800869*/
870
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100871ATTRIBUTE_REPRODUCIBLE static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700872getzname(register const char *strp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800873{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700874 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800875
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700876 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
877 c != '+')
878 ++strp;
879 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800880}
881
882/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000883** Given a pointer into an extended timezone string, scan until the ending
884** delimiter of the time zone abbreviation is located.
885** Return a pointer to the delimiter.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800886**
887** As with getzname above, the legal character set is actually quite
888** restricted, with other characters producing undefined results.
889** We don't do any checking here; checking is done later in common-case code.
890*/
891
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +0100892ATTRIBUTE_REPRODUCIBLE static const char *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800893getqzname(register const char *strp, const int delim)
894{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700895 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800896
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700897 while ((c = *strp) != '\0' && c != delim)
898 ++strp;
899 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800900}
901
902/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000903** Given a pointer into a timezone string, extract a number from that string.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800904** Check that the number is within a specified range; if it is not, return
905** NULL.
906** Otherwise, return a pointer to the first character not part of the number.
907*/
908
909static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700910getnum(register const char *strp, int *const nump, const int min, const int max)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800911{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700912 register char c;
913 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800914
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700915 if (strp == NULL || !is_digit(c = *strp))
916 return NULL;
917 num = 0;
918 do {
919 num = num * 10 + (c - '0');
920 if (num > max)
921 return NULL; /* illegal value */
922 c = *++strp;
923 } while (is_digit(c));
924 if (num < min)
925 return NULL; /* illegal value */
926 *nump = num;
927 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800928}
929
930/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000931** Given a pointer into a timezone string, extract a number of seconds,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800932** in hh[:mm[:ss]] form, from the string.
933** If any error occurs, return NULL.
934** Otherwise, return a pointer to the first character not part of the number
935** of seconds.
936*/
937
938static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700939getsecs(register const char *strp, int_fast32_t *const secsp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800940{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700941 int num;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000942 int_fast32_t secsperhour = SECSPERHOUR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800943
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700944 /*
945 ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
946 ** "M10.4.6/26", which does not conform to Posix,
947 ** but which specifies the equivalent of
948 ** "02:00 on the first Sunday on or after 23 Oct".
949 */
950 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
951 if (strp == NULL)
952 return NULL;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000953 *secsp = num * secsperhour;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700954 if (*strp == ':') {
955 ++strp;
956 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
957 if (strp == NULL)
958 return NULL;
959 *secsp += num * SECSPERMIN;
960 if (*strp == ':') {
961 ++strp;
962 /* 'SECSPERMIN' allows for leap seconds. */
963 strp = getnum(strp, &num, 0, SECSPERMIN);
964 if (strp == NULL)
965 return NULL;
966 *secsp += num;
967 }
968 }
969 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800970}
971
972/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000973** Given a pointer into a timezone string, extract an offset, in
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800974** [+-]hh[:mm[:ss]] form, from the string.
975** If any error occurs, return NULL.
976** Otherwise, return a pointer to the first character not part of the time.
977*/
978
979static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700980getoffset(register const char *strp, int_fast32_t *const offsetp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800981{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700982 register bool neg = false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800983
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700984 if (*strp == '-') {
985 neg = true;
986 ++strp;
987 } else if (*strp == '+')
988 ++strp;
989 strp = getsecs(strp, offsetp);
990 if (strp == NULL)
991 return NULL; /* illegal time */
992 if (neg)
993 *offsetp = -*offsetp;
994 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800995}
996
997/*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +0000998** Given a pointer into a timezone string, extract a rule in the form
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800999** date[/time]. See POSIX section 8 for the format of "date" and "time".
1000** If a valid rule is not found, return NULL.
1001** Otherwise, return a pointer to the first character not part of the rule.
1002*/
1003
1004static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001005getrule(const char *strp, register struct rule *const rulep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001006{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001007 if (*strp == 'J') {
1008 /*
1009 ** Julian day.
1010 */
1011 rulep->r_type = JULIAN_DAY;
1012 ++strp;
1013 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
1014 } else if (*strp == 'M') {
1015 /*
1016 ** Month, week, day.
1017 */
1018 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
1019 ++strp;
1020 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
1021 if (strp == NULL)
1022 return NULL;
1023 if (*strp++ != '.')
1024 return NULL;
1025 strp = getnum(strp, &rulep->r_week, 1, 5);
1026 if (strp == NULL)
1027 return NULL;
1028 if (*strp++ != '.')
1029 return NULL;
1030 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
1031 } else if (is_digit(*strp)) {
1032 /*
1033 ** Day of year.
1034 */
1035 rulep->r_type = DAY_OF_YEAR;
1036 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
1037 } else return NULL; /* invalid format */
1038 if (strp == NULL)
1039 return NULL;
1040 if (*strp == '/') {
1041 /*
1042 ** Time specified.
1043 */
1044 ++strp;
1045 strp = getoffset(strp, &rulep->r_time);
1046 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
1047 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001048}
1049
1050/*
Calin Juravle627d37c2014-02-28 11:46:03 +00001051** Given a year, a rule, and the offset from UT at the time that rule takes
1052** effect, calculate the year-relative time that rule takes effect.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001053*/
1054
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001055static int_fast32_t
Calin Juravle627d37c2014-02-28 11:46:03 +00001056transtime(const int year, register const struct rule *const rulep,
Calin Juravled8928922014-02-28 12:18:53 +00001057 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001058{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001059 register bool leapyear;
Calin Juravled8928922014-02-28 12:18:53 +00001060 register int_fast32_t value;
1061 register int i;
1062 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001063
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001064 leapyear = isleap(year);
1065 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001066
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001067 case JULIAN_DAY:
1068 /*
1069 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
1070 ** years.
1071 ** In non-leap years, or if the day number is 59 or less, just
1072 ** add SECSPERDAY times the day number-1 to the time of
1073 ** January 1, midnight, to get the day.
1074 */
Calin Juravled8928922014-02-28 12:18:53 +00001075 value = (rulep->r_day - 1) * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001076 if (leapyear && rulep->r_day >= 60)
1077 value += SECSPERDAY;
1078 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001079
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001080 case DAY_OF_YEAR:
1081 /*
1082 ** n - day of year.
1083 ** Just add SECSPERDAY times the day number to the time of
1084 ** January 1, midnight, to get the day.
1085 */
Calin Juravled8928922014-02-28 12:18:53 +00001086 value = rulep->r_day * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001087 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001088
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001089 case MONTH_NTH_DAY_OF_WEEK:
1090 /*
1091 ** Mm.n.d - nth "dth day" of month m.
1092 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001093
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001094 /*
1095 ** Use Zeller's Congruence to get day-of-week of first day of
1096 ** month.
1097 */
1098 m1 = (rulep->r_mon + 9) % 12 + 1;
1099 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
1100 yy1 = yy0 / 100;
1101 yy2 = yy0 % 100;
1102 dow = ((26 * m1 - 2) / 10 +
1103 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
1104 if (dow < 0)
1105 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001106
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001107 /*
1108 ** "dow" is the day-of-week of the first day of the month. Get
1109 ** the day-of-month (zero-origin) of the first "dow" day of the
1110 ** month.
1111 */
1112 d = rulep->r_day - dow;
1113 if (d < 0)
1114 d += DAYSPERWEEK;
1115 for (i = 1; i < rulep->r_week; ++i) {
1116 if (d + DAYSPERWEEK >=
1117 mon_lengths[leapyear][rulep->r_mon - 1])
1118 break;
1119 d += DAYSPERWEEK;
1120 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001121
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001122 /*
1123 ** "d" is the day-of-month (zero-origin) of the day we want.
1124 */
Calin Juravled8928922014-02-28 12:18:53 +00001125 value = d * SECSPERDAY;
1126 for (i = 0; i < rulep->r_mon - 1; ++i)
1127 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001128 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001129
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001130 default: unreachable();
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001131 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001132
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001133 /*
Calin Juravled8928922014-02-28 12:18:53 +00001134 ** "value" is the year-relative time of 00:00:00 UT on the day in
1135 ** question. To get the year-relative time of the specified local
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001136 ** time on that day, add the transition time and the current offset
Elliott Hughese0d0b152013-09-27 00:04:30 -07001137 ** from UT.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001138 */
1139 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001140}
1141
1142/*
1143** Given a POSIX section 8-style TZ string, fill in the rule tables as
1144** appropriate.
1145*/
1146
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001147static bool
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001148tzparse(const char *name, struct state *sp, struct state *basep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001149{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001150 const char * stdname;
1151 const char * dstname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001152 int_fast32_t stdoffset;
1153 int_fast32_t dstoffset;
1154 register char * cp;
1155 register bool load_ok;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001156 ptrdiff_t stdlen, dstlen, charcnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001157 time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001158
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001159 stdname = name;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001160 if (*name == '<') {
1161 name++;
1162 stdname = name;
1163 name = getqzname(name, '>');
1164 if (*name != '>')
1165 return false;
1166 stdlen = name - stdname;
1167 name++;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001168 } else {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001169 name = getzname(name);
1170 stdlen = name - stdname;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001171 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001172 if (! (0 < stdlen && stdlen <= TZNAME_MAXIMUM))
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001173 return false;
1174 name = getoffset(name, &stdoffset);
1175 if (name == NULL)
1176 return false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001177 charcnt = stdlen + 1;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001178 if (basep) {
1179 if (0 < basep->timecnt)
1180 atlo = basep->ats[basep->timecnt - 1];
1181 load_ok = false;
1182 sp->leapcnt = basep->leapcnt;
1183 memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis);
1184 } else {
1185 load_ok = tzload(TZDEFRULES, sp, false) == 0;
1186 if (!load_ok)
1187 sp->leapcnt = 0; /* So, we're off a little. */
1188 }
1189 if (0 < sp->leapcnt)
1190 leaplo = sp->lsis[sp->leapcnt - 1].ls_trans;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001191 if (*name != '\0') {
1192 if (*name == '<') {
1193 dstname = ++name;
1194 name = getqzname(name, '>');
1195 if (*name != '>')
1196 return false;
1197 dstlen = name - dstname;
1198 name++;
1199 } else {
1200 dstname = name;
1201 name = getzname(name);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001202 dstlen = name - dstname; /* length of DST abbr. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001203 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001204 if (! (0 < dstlen && dstlen <= TZNAME_MAXIMUM))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001205 return false;
1206 charcnt += dstlen + 1;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001207 if (*name != '\0' && *name != ',' && *name != ';') {
1208 name = getoffset(name, &dstoffset);
1209 if (name == NULL)
1210 return false;
1211 } else dstoffset = stdoffset - SECSPERHOUR;
1212 if (*name == '\0' && !load_ok)
1213 name = TZDEFRULESTRING;
1214 if (*name == ',' || *name == ';') {
1215 struct rule start;
1216 struct rule end;
1217 register int year;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001218 register int timecnt;
1219 time_t janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001220 int_fast32_t janoffset = 0;
1221 int yearbeg, yearlim;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001222
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001223 ++name;
1224 if ((name = getrule(name, &start)) == NULL)
1225 return false;
1226 if (*name++ != ',')
1227 return false;
1228 if ((name = getrule(name, &end)) == NULL)
1229 return false;
1230 if (*name != '\0')
1231 return false;
1232 sp->typecnt = 2; /* standard time and DST */
1233 /*
1234 ** Two transitions per year, from EPOCH_YEAR forward.
1235 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001236 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1237 init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001238 sp->defaulttype = 0;
1239 timecnt = 0;
1240 janfirst = 0;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001241 yearbeg = EPOCH_YEAR;
1242
1243 do {
1244 int_fast32_t yearsecs
1245 = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
1246 yearbeg--;
1247 if (increment_overflow_time(&janfirst, -yearsecs)) {
1248 janoffset = -yearsecs;
1249 break;
1250 }
1251 } while (atlo < janfirst
1252 && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
1253
1254 while (true) {
1255 int_fast32_t yearsecs
1256 = year_lengths[isleap(yearbeg)] * SECSPERDAY;
1257 int yearbeg1 = yearbeg;
1258 time_t janfirst1 = janfirst;
1259 if (increment_overflow_time(&janfirst1, yearsecs)
1260 || increment_overflow(&yearbeg1, 1)
1261 || atlo <= janfirst1)
1262 break;
1263 yearbeg = yearbeg1;
1264 janfirst = janfirst1;
1265 }
1266
1267 yearlim = yearbeg;
1268 if (increment_overflow(&yearlim, YEARSPERREPEAT + 1))
1269 yearlim = INT_MAX;
1270 for (year = yearbeg; year < yearlim; year++) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001271 int_fast32_t
1272 starttime = transtime(year, &start, stdoffset),
1273 endtime = transtime(year, &end, dstoffset);
1274 int_fast32_t
1275 yearsecs = (year_lengths[isleap(year)]
1276 * SECSPERDAY);
1277 bool reversed = endtime < starttime;
1278 if (reversed) {
1279 int_fast32_t swap = starttime;
1280 starttime = endtime;
1281 endtime = swap;
1282 }
1283 if (reversed
1284 || (starttime < endtime
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001285 && endtime - starttime < yearsecs)) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001286 if (TZ_MAX_TIMES - 2 < timecnt)
1287 break;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001288 sp->ats[timecnt] = janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001289 if (! increment_overflow_time
1290 (&sp->ats[timecnt],
1291 janoffset + starttime)
1292 && atlo <= sp->ats[timecnt])
1293 sp->types[timecnt++] = !reversed;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001294 sp->ats[timecnt] = janfirst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001295 if (! increment_overflow_time
1296 (&sp->ats[timecnt],
1297 janoffset + endtime)
1298 && atlo <= sp->ats[timecnt]) {
1299 sp->types[timecnt++] = reversed;
1300 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001301 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001302 if (endtime < leaplo) {
1303 yearlim = year;
1304 if (increment_overflow(&yearlim,
1305 YEARSPERREPEAT + 1))
1306 yearlim = INT_MAX;
1307 }
1308 if (increment_overflow_time
1309 (&janfirst, janoffset + yearsecs))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001310 break;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001311 janoffset = 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001312 }
1313 sp->timecnt = timecnt;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001314 if (! timecnt) {
1315 sp->ttis[0] = sp->ttis[1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001316 sp->typecnt = 1; /* Perpetual DST. */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001317 } else if (YEARSPERREPEAT < year - yearbeg)
1318 sp->goback = sp->goahead = true;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001319 } else {
1320 register int_fast32_t theirstdoffset;
1321 register int_fast32_t theirdstoffset;
1322 register int_fast32_t theiroffset;
1323 register bool isdst;
1324 register int i;
1325 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001326
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001327 if (*name != '\0')
1328 return false;
1329 /*
1330 ** Initial values of theirstdoffset and theirdstoffset.
1331 */
1332 theirstdoffset = 0;
1333 for (i = 0; i < sp->timecnt; ++i) {
1334 j = sp->types[i];
1335 if (!sp->ttis[j].tt_isdst) {
1336 theirstdoffset =
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001337 - sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001338 break;
1339 }
1340 }
1341 theirdstoffset = 0;
1342 for (i = 0; i < sp->timecnt; ++i) {
1343 j = sp->types[i];
1344 if (sp->ttis[j].tt_isdst) {
1345 theirdstoffset =
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001346 - sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001347 break;
1348 }
1349 }
1350 /*
1351 ** Initially we're assumed to be in standard time.
1352 */
1353 isdst = false;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001354 /*
1355 ** Now juggle transition times and types
1356 ** tracking offsets as you do.
1357 */
1358 for (i = 0; i < sp->timecnt; ++i) {
1359 j = sp->types[i];
1360 sp->types[i] = sp->ttis[j].tt_isdst;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001361 if (sp->ttis[j].tt_ttisut) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001362 /* No adjustment to transition time */
1363 } else {
1364 /*
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001365 ** If daylight saving time is in
1366 ** effect, and the transition time was
1367 ** not specified as standard time, add
1368 ** the daylight saving time offset to
1369 ** the transition time; otherwise, add
1370 ** the standard time offset to the
1371 ** transition time.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001372 */
1373 /*
1374 ** Transitions from DST to DDST
1375 ** will effectively disappear since
1376 ** POSIX provides for only one DST
1377 ** offset.
1378 */
1379 if (isdst && !sp->ttis[j].tt_ttisstd) {
1380 sp->ats[i] += dstoffset -
1381 theirdstoffset;
1382 } else {
1383 sp->ats[i] += stdoffset -
1384 theirstdoffset;
1385 }
1386 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001387 theiroffset = -sp->ttis[j].tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001388 if (sp->ttis[j].tt_isdst)
1389 theirdstoffset = theiroffset;
1390 else theirstdoffset = theiroffset;
1391 }
1392 /*
1393 ** Finally, fill in ttis.
1394 */
1395 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1396 init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1397 sp->typecnt = 2;
1398 sp->defaulttype = 0;
1399 }
1400 } else {
1401 dstlen = 0;
1402 sp->typecnt = 1; /* only standard time */
1403 sp->timecnt = 0;
1404 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1405 sp->defaulttype = 0;
1406 }
1407 sp->charcnt = charcnt;
1408 cp = sp->chars;
1409 memcpy(cp, stdname, stdlen);
1410 cp += stdlen;
1411 *cp++ = '\0';
1412 if (dstlen != 0) {
1413 memcpy(cp, dstname, dstlen);
1414 *(cp + dstlen) = '\0';
1415 }
1416 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001417}
1418
1419static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001420gmtload(struct state *const sp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001421{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001422 if (tzload(etc_utc, sp, true) != 0)
1423 tzparse("UTC0", sp, NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001424}
1425
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001426/* Initialize *SP to a value appropriate for the TZ setting NAME.
1427 Return 0 on success, an errno value on failure. */
1428static int
1429zoneinit(struct state *sp, char const *name)
1430{
1431 if (name && ! name[0]) {
1432 /*
1433 ** User wants it fast rather than right.
1434 */
1435 sp->leapcnt = 0; /* so, we're off a little */
1436 sp->timecnt = 0;
1437 sp->typecnt = 0;
1438 sp->charcnt = 0;
1439 sp->goback = sp->goahead = false;
1440 init_ttinfo(&sp->ttis[0], 0, false, 0);
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001441 strcpy(sp->chars, utc);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001442 sp->defaulttype = 0;
1443 return 0;
1444 } else {
1445 int err = tzload(name, sp, true);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001446 if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001447 err = 0;
1448 if (err == 0)
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001449 err = scrub_abbrs(sp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001450 return err;
1451 }
1452}
1453
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001454void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001455tzsetlcl(char const *name)
1456{
1457 struct state *sp = lclptr;
1458 int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
1459 if (lcl < 0
1460 ? lcl_is_set < 0
1461 : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
1462 return;
1463#ifdef ALL_STATE
1464 if (! sp)
1465 lclptr = sp = malloc(sizeof *lclptr);
1466#endif /* defined ALL_STATE */
1467 if (sp) {
1468 if (zoneinit(sp, name) != 0)
1469 zoneinit(sp, "");
1470 if (0 < lcl)
1471 strcpy(lcl_TZname, name);
1472 }
1473 settzname();
1474 lcl_is_set = lcl;
1475}
1476
Elliott Hughesa9209d72016-09-16 18:16:47 -07001477#if defined(__BIONIC__)
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001478extern void tzset_unlocked(void);
1479#else
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001480static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001481tzset_unlocked(void)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001482{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001483 tzsetlcl(getenv("TZ"));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001484}
Elliott Hughes0e8616a2017-04-11 14:44:51 -07001485#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001486
1487void
Elliott Hughesce4783c2013-07-12 17:31:11 -07001488tzset(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001489{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001490 if (lock() != 0)
1491 return;
1492 tzset_unlocked();
1493 unlock();
1494}
1495
1496static void
1497gmtcheck(void)
1498{
1499 static bool gmt_is_set;
1500 if (lock() != 0)
1501 return;
1502 if (! gmt_is_set) {
1503#ifdef ALL_STATE
1504 gmtptr = malloc(sizeof *gmtptr);
1505#endif
1506 if (gmtptr)
1507 gmtload(gmtptr);
1508 gmt_is_set = true;
1509 }
1510 unlock();
1511}
1512
1513#if NETBSD_INSPIRED
1514
1515timezone_t
1516tzalloc(char const *name)
1517{
1518 timezone_t sp = malloc(sizeof *sp);
1519 if (sp) {
1520 int err = zoneinit(sp, name);
1521 if (err != 0) {
1522 free(sp);
1523 errno = err;
1524 return NULL;
1525 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001526 } else if (!HAVE_MALLOC_ERRNO)
1527 errno = ENOMEM;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001528 return sp;
1529}
1530
1531void
1532tzfree(timezone_t sp)
1533{
1534 free(sp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001535}
1536
1537/*
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001538** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
1539** ctime_r are obsolescent and have potential security problems that
1540** ctime_rz would share. Callers can instead use localtime_rz + strftime.
1541**
1542** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
1543** in zones with three or more time zone abbreviations.
1544** Callers can instead use localtime_rz + strftime.
1545*/
1546
1547#endif
1548
1549/*
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001550** The easy way to behave "as if no library function calls" localtime
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001551** is to not call it, so we drop its guts into "localsub", which can be
1552** freely called. (And no, the PANS doesn't require the above behavior,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001553** but it *is* desirable.)
1554**
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001555** If successful and SETNAME is nonzero,
1556** set the applicable parts of tzname, timezone and altzone;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001557** however, it's OK to omit this step if the timezone is POSIX-compatible,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001558** since in that case tzset should have already done this step correctly.
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001559** SETNAME's type is int_fast32_t for compatibility with gmtsub,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001560** but it is actually a boolean and its value should be 0 or 1.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001561*/
1562
1563/*ARGSUSED*/
1564static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001565localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
1566 struct tm *const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001567{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001568 register const struct ttinfo * ttisp;
1569 register int i;
1570 register struct tm * result;
1571 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001572
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001573 if (sp == NULL) {
1574 /* Don't bother to set tzname etc.; tzset has already done it. */
1575 return gmtsub(gmtptr, timep, 0, tmp);
1576 }
1577 if ((sp->goback && t < sp->ats[0]) ||
1578 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001579 time_t newt;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001580 register time_t seconds;
1581 register time_t years;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001582
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001583 if (t < sp->ats[0])
1584 seconds = sp->ats[0] - t;
1585 else seconds = t - sp->ats[sp->timecnt - 1];
1586 --seconds;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001587
1588 /* Beware integer overflow, as SECONDS might
1589 be close to the maximum time_t. */
1590 years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001591 seconds = years * AVGSECSPERYEAR;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001592 years += YEARSPERREPEAT;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001593 if (t < sp->ats[0])
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001594 newt = t + seconds + SECSPERREPEAT;
1595 else
1596 newt = t - seconds - SECSPERREPEAT;
1597
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001598 if (newt < sp->ats[0] ||
1599 newt > sp->ats[sp->timecnt - 1])
1600 return NULL; /* "cannot happen" */
1601 result = localsub(sp, &newt, setname, tmp);
1602 if (result) {
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001603#if defined ckd_add && defined ckd_sub
1604 if (t < sp->ats[0]
1605 ? ckd_sub(&result->tm_year,
1606 result->tm_year, years)
1607 : ckd_add(&result->tm_year,
1608 result->tm_year, years))
1609 return NULL;
1610#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001611 register int_fast64_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001612
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001613 newy = result->tm_year;
1614 if (t < sp->ats[0])
1615 newy -= years;
1616 else newy += years;
1617 if (! (INT_MIN <= newy && newy <= INT_MAX))
1618 return NULL;
1619 result->tm_year = newy;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001620#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001621 }
1622 return result;
1623 }
1624 if (sp->timecnt == 0 || t < sp->ats[0]) {
1625 i = sp->defaulttype;
1626 } else {
1627 register int lo = 1;
1628 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001629
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001630 while (lo < hi) {
1631 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001632
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001633 if (t < sp->ats[mid])
1634 hi = mid;
1635 else lo = mid + 1;
1636 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001637 i = sp->types[lo - 1];
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001638 }
1639 ttisp = &sp->ttis[i];
1640 /*
1641 ** To get (wrong) behavior that's compatible with System V Release 2.0
1642 ** you'd replace the statement below with
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001643 ** t += ttisp->tt_utoff;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001644 ** timesub(&t, 0L, sp, tmp);
1645 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001646 result = timesub(&t, ttisp->tt_utoff, sp, tmp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001647 if (result) {
1648 result->tm_isdst = ttisp->tt_isdst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001649#ifdef TM_ZONE
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001650 result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001651#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001652 if (setname)
1653 update_tzname_etc(sp, ttisp);
1654 }
1655 return result;
1656}
1657
1658#if NETBSD_INSPIRED
1659
1660struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001661localtime_rz(struct state *restrict sp, time_t const *restrict timep,
1662 struct tm *restrict tmp)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001663{
1664 return localsub(sp, timep, 0, tmp);
1665}
1666
1667#endif
1668
1669static struct tm *
Elliott Hughesea877162017-01-11 14:34:16 -08001670localtime_tzset(time_t const *timep, struct tm *tmp)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001671{
1672 int err = lock();
1673 if (err) {
1674 errno = err;
1675 return NULL;
1676 }
Elliott Hughesea877162017-01-11 14:34:16 -08001677
1678 // http://b/31339449: POSIX says localtime(3) acts as if it called tzset(3), but upstream
1679 // and glibc both think it's okay for localtime_r(3) to not do so (presumably because of
1680 // the "not required to set tzname" clause). It's unclear that POSIX actually intended this,
1681 // the BSDs disagree with glibc, and it's confusing to developers to have localtime_r(3)
1682 // behave differently than other time zone-sensitive functions in <time.h>.
1683 tzset_unlocked();
1684
1685 tmp = localsub(lclptr, timep, true, tmp);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001686 unlock();
1687 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001688}
1689
1690struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001691localtime(const time_t *timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001692{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001693#if !SUPPORT_C89
1694 static struct tm tm;
1695#endif
Elliott Hughesea877162017-01-11 14:34:16 -08001696 return localtime_tzset(timep, &tm);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001697}
1698
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001699struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001700localtime_r(const time_t *restrict timep, struct tm *restrict tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001701{
Elliott Hughesea877162017-01-11 14:34:16 -08001702 return localtime_tzset(timep, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001703}
1704
1705/*
1706** gmtsub is to gmtime as localsub is to localtime.
1707*/
1708
1709static struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001710gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep,
1711 int_fast32_t offset, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001712{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001713 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001714
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001715 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001716#ifdef TM_ZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001717 /*
1718 ** Could get fancy here and deliver something such as
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001719 ** "+xx" or "-xx" if offset is non-zero,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001720 ** but this is no time for a treasure hunt.
1721 */
1722 tmp->TM_ZONE = ((char *)
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001723 (offset ? wildabbr : gmtptr ? gmtptr->chars : utc));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001724#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001725 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001726}
1727
1728/*
1729* Re-entrant version of gmtime.
1730*/
1731
1732struct tm *
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001733gmtime_r(time_t const *restrict timep, struct tm *restrict tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001734{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001735 gmtcheck();
1736 return gmtsub(gmtptr, timep, 0, tmp);
1737}
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001738
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001739struct tm *
1740gmtime(const time_t *timep)
1741{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001742#if !SUPPORT_C89
1743 static struct tm tm;
1744#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001745 return gmtime_r(timep, &tm);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001746}
1747
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001748#if STD_INSPIRED
Elliott Hughes906eb992014-06-18 19:46:25 -07001749
1750struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001751offtime(const time_t *timep, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07001752{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001753 gmtcheck();
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001754
1755#if !SUPPORT_C89
1756 static struct tm tm;
1757#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001758 return gmtsub(gmtptr, timep, offset, &tm);
Elliott Hughes906eb992014-06-18 19:46:25 -07001759}
1760
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001761#endif
Elliott Hughes906eb992014-06-18 19:46:25 -07001762
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001763/*
1764** Return the number of leap years through the end of the given year
1765** where, to make the math easy, the answer for year zero is defined as zero.
1766*/
1767
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001768static time_t
1769leaps_thru_end_of_nonneg(time_t y)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001770{
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001771 return y / 4 - y / 100 + y / 400;
1772}
1773
1774static time_t
1775leaps_thru_end_of(time_t y)
1776{
1777 return (y < 0
1778 ? -1 - leaps_thru_end_of_nonneg(-1 - y)
1779 : leaps_thru_end_of_nonneg(y));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001780}
1781
1782static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001783timesub(const time_t *timep, int_fast32_t offset,
1784 const struct state *sp, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001785{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001786 register const struct lsinfo * lp;
1787 register time_t tdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001788 register const int * ip;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001789 register int_fast32_t corr;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001790 register int i;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001791 int_fast32_t idays, rem, dayoff, dayrem;
1792 time_t y;
1793
1794 /* If less than SECSPERMIN, the number of seconds since the
1795 most recent positive leap second; otherwise, do not add 1
1796 to localtime tm_sec because of leap seconds. */
1797 time_t secs_since_posleap = SECSPERMIN;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001798
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001799 corr = 0;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001800 i = (sp == NULL) ? 0 : sp->leapcnt;
1801 while (--i >= 0) {
1802 lp = &sp->lsis[i];
1803 if (*timep >= lp->ls_trans) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001804 corr = lp->ls_corr;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001805 if ((i == 0 ? 0 : lp[-1].ls_corr) < corr)
1806 secs_since_posleap = *timep - lp->ls_trans;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001807 break;
1808 }
1809 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001810
1811 /* Calculate the year, avoiding integer overflow even if
1812 time_t is unsigned. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001813 tdays = *timep / SECSPERDAY;
1814 rem = *timep % SECSPERDAY;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001815 rem += offset % SECSPERDAY - corr % SECSPERDAY + 3 * SECSPERDAY;
1816 dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3;
1817 rem %= SECSPERDAY;
1818 /* y = (EPOCH_YEAR
1819 + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
1820 sans overflow. But calculate against 1570 (EPOCH_YEAR -
1821 YEARSPERREPEAT) instead of against 1970 so that things work
1822 for localtime values before 1970 when time_t is unsigned. */
1823 dayrem = tdays % DAYSPERREPEAT;
1824 dayrem += dayoff % DAYSPERREPEAT;
1825 y = (EPOCH_YEAR - YEARSPERREPEAT
1826 + ((1 + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT
1827 - ((dayrem % DAYSPERREPEAT) < 0)
1828 + tdays / DAYSPERREPEAT)
1829 * YEARSPERREPEAT));
1830 /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */
1831 idays = tdays % DAYSPERREPEAT;
1832 idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
1833 idays %= DAYSPERREPEAT;
1834 /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */
1835 while (year_lengths[isleap(y)] <= idays) {
1836 int tdelta = idays / DAYSPERLYEAR;
1837 int_fast32_t ydelta = tdelta + !tdelta;
1838 time_t newy = y + ydelta;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001839 register int leapdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001840 leapdays = leaps_thru_end_of(newy - 1) -
1841 leaps_thru_end_of(y - 1);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001842 idays -= ydelta * DAYSPERNYEAR;
1843 idays -= leapdays;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001844 y = newy;
1845 }
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001846
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001847#ifdef ckd_add
1848 if (ckd_add(&tmp->tm_year, y, -TM_YEAR_BASE)) {
1849 errno = EOVERFLOW;
1850 return NULL;
1851 }
1852#else
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001853 if (!TYPE_SIGNED(time_t) && y < TM_YEAR_BASE) {
1854 int signed_y = y;
1855 tmp->tm_year = signed_y - TM_YEAR_BASE;
1856 } else if ((!TYPE_SIGNED(time_t) || INT_MIN + TM_YEAR_BASE <= y)
1857 && y - TM_YEAR_BASE <= INT_MAX)
1858 tmp->tm_year = y - TM_YEAR_BASE;
1859 else {
1860 errno = EOVERFLOW;
1861 return NULL;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001862 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001863#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001864 tmp->tm_yday = idays;
1865 /*
1866 ** The "extra" mods below avoid overflow problems.
1867 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001868 tmp->tm_wday = (TM_WDAY_BASE
1869 + ((tmp->tm_year % DAYSPERWEEK)
1870 * (DAYSPERNYEAR % DAYSPERWEEK))
1871 + leaps_thru_end_of(y - 1)
1872 - leaps_thru_end_of(TM_YEAR_BASE - 1)
1873 + idays);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001874 tmp->tm_wday %= DAYSPERWEEK;
1875 if (tmp->tm_wday < 0)
1876 tmp->tm_wday += DAYSPERWEEK;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001877 tmp->tm_hour = rem / SECSPERHOUR;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001878 rem %= SECSPERHOUR;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001879 tmp->tm_min = rem / SECSPERMIN;
1880 tmp->tm_sec = rem % SECSPERMIN;
1881
1882 /* Use "... ??:??:60" at the end of the localtime minute containing
1883 the second just before the positive leap second. */
1884 tmp->tm_sec += secs_since_posleap <= tmp->tm_sec;
1885
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001886 ip = mon_lengths[isleap(y)];
1887 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1888 idays -= ip[tmp->tm_mon];
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001889 tmp->tm_mday = idays + 1;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001890 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001891#ifdef TM_GMTOFF
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001892 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001893#endif /* defined TM_GMTOFF */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001894 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001895}
1896
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001897/*
1898** Adapted from code provided by Robert Elz, who writes:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001899** The "best" way to do mktime I think is based on an idea of Bob
1900** Kridle's (so its said...) from a long time ago.
1901** It does a binary search of the time_t space. Since time_t's are
1902** just 32 bits, its a max of 32 iterations (even at 64 bits it
1903** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001904*/
1905
1906#ifndef WRONG
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001907# define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001908#endif /* !defined WRONG */
1909
1910/*
Elliott Hughesce4783c2013-07-12 17:31:11 -07001911** Normalize logic courtesy Paul Eggert.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001912*/
1913
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001914static bool
1915increment_overflow(int *ip, int j)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001916{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001917#ifdef ckd_add
1918 return ckd_add(ip, *ip, j);
1919#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001920 register int const i = *ip;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001921
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001922 /*
1923 ** If i >= 0 there can only be overflow if i + j > INT_MAX
1924 ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1925 ** If i < 0 there can only be overflow if i + j < INT_MIN
1926 ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1927 */
1928 if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
1929 return true;
1930 *ip += j;
1931 return false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001932#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001933}
1934
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001935static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001936increment_overflow32(int_fast32_t *const lp, int const m)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001937{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001938#ifdef ckd_add
1939 return ckd_add(lp, *lp, m);
1940#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001941 register int_fast32_t const l = *lp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001942
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001943 if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
1944 return true;
1945 *lp += m;
1946 return false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001947#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001948}
1949
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001950static bool
Calin Juravle627d37c2014-02-28 11:46:03 +00001951increment_overflow_time(time_t *tp, int_fast32_t j)
1952{
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001953#ifdef ckd_add
1954 return ckd_add(tp, *tp, j);
1955#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001956 /*
1957 ** This is like
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001958 ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001959 ** except that it does the right thing even if *tp + j would overflow.
1960 */
1961 if (! (j < 0
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00001962 ? (TYPE_SIGNED(time_t) ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
1963 : *tp <= TIME_T_MAX - j))
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001964 return true;
1965 *tp += j;
1966 return false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01001967#endif
Calin Juravle627d37c2014-02-28 11:46:03 +00001968}
1969
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001970static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001971normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001972{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001973 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001974
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001975 tensdelta = (*unitsptr >= 0) ?
1976 (*unitsptr / base) :
1977 (-1 - (-1 - *unitsptr) / base);
1978 *unitsptr -= tensdelta * base;
1979 return increment_overflow(tensptr, tensdelta);
1980}
1981
1982static bool
1983normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
1984{
1985 register int tensdelta;
1986
1987 tensdelta = (*unitsptr >= 0) ?
1988 (*unitsptr / base) :
1989 (-1 - (-1 - *unitsptr) / base);
1990 *unitsptr -= tensdelta * base;
1991 return increment_overflow32(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001992}
1993
1994static int
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001995tmcomp(register const struct tm *const atmp,
1996 register const struct tm *const btmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001997{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001998 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001999
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002000 if (atmp->tm_year != btmp->tm_year)
2001 return atmp->tm_year < btmp->tm_year ? -1 : 1;
2002 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
2003 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
2004 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
2005 (result = (atmp->tm_min - btmp->tm_min)) == 0)
2006 result = atmp->tm_sec - btmp->tm_sec;
2007 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002008}
2009
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002010/* Copy to *DEST from *SRC. Copy only the members needed for mktime,
2011 as other members might not be initialized. */
2012static void
2013mktmcpy(struct tm *dest, struct tm const *src)
2014{
2015 dest->tm_sec = src->tm_sec;
2016 dest->tm_min = src->tm_min;
2017 dest->tm_hour = src->tm_hour;
2018 dest->tm_mday = src->tm_mday;
2019 dest->tm_mon = src->tm_mon;
2020 dest->tm_year = src->tm_year;
2021 dest->tm_isdst = src->tm_isdst;
2022#if defined TM_GMTOFF && ! UNINIT_TRAP
2023 dest->TM_GMTOFF = src->TM_GMTOFF;
2024#endif
2025}
2026
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002027static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002028time2sub(struct tm *const tmp,
2029 struct tm *(*funcp)(struct state const *, time_t const *,
2030 int_fast32_t, struct tm *),
2031 struct state const *sp,
2032 const int_fast32_t offset,
2033 bool *okayp,
2034 bool do_norm_secs)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002035{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002036 register int dir;
2037 register int i, j;
2038 register int saved_seconds;
2039 register int_fast32_t li;
2040 register time_t lo;
2041 register time_t hi;
2042 int_fast32_t y;
2043 time_t newt;
2044 time_t t;
2045 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002046
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002047 *okayp = false;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002048 mktmcpy(&yourtm, tmp);
2049
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002050 if (do_norm_secs) {
2051 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
2052 SECSPERMIN))
2053 return WRONG;
2054 }
2055 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
2056 return WRONG;
2057 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
2058 return WRONG;
2059 y = yourtm.tm_year;
2060 if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
2061 return WRONG;
2062 /*
2063 ** Turn y into an actual year number for now.
2064 ** It is converted back to an offset from TM_YEAR_BASE later.
2065 */
2066 if (increment_overflow32(&y, TM_YEAR_BASE))
2067 return WRONG;
2068 while (yourtm.tm_mday <= 0) {
2069 if (increment_overflow32(&y, -1))
2070 return WRONG;
2071 li = y + (1 < yourtm.tm_mon);
2072 yourtm.tm_mday += year_lengths[isleap(li)];
2073 }
2074 while (yourtm.tm_mday > DAYSPERLYEAR) {
2075 li = y + (1 < yourtm.tm_mon);
2076 yourtm.tm_mday -= year_lengths[isleap(li)];
2077 if (increment_overflow32(&y, 1))
2078 return WRONG;
2079 }
2080 for ( ; ; ) {
2081 i = mon_lengths[isleap(y)][yourtm.tm_mon];
2082 if (yourtm.tm_mday <= i)
2083 break;
2084 yourtm.tm_mday -= i;
2085 if (++yourtm.tm_mon >= MONSPERYEAR) {
2086 yourtm.tm_mon = 0;
2087 if (increment_overflow32(&y, 1))
2088 return WRONG;
2089 }
2090 }
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002091#ifdef ckd_add
2092 if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE))
2093 return WRONG;
2094#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002095 if (increment_overflow32(&y, -TM_YEAR_BASE))
2096 return WRONG;
2097 if (! (INT_MIN <= y && y <= INT_MAX))
2098 return WRONG;
2099 yourtm.tm_year = y;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002100#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002101 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
2102 saved_seconds = 0;
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002103 else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002104 /*
2105 ** We can't set tm_sec to 0, because that might push the
2106 ** time below the minimum representable time.
2107 ** Set tm_sec to 59 instead.
2108 ** This assumes that the minimum representable time is
2109 ** not in the same minute that a leap second was deleted from,
2110 ** which is a safer assumption than using 58 would be.
2111 */
2112 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
2113 return WRONG;
2114 saved_seconds = yourtm.tm_sec;
2115 yourtm.tm_sec = SECSPERMIN - 1;
2116 } else {
2117 saved_seconds = yourtm.tm_sec;
2118 yourtm.tm_sec = 0;
2119 }
2120 /*
2121 ** Do a binary search (this works whatever time_t's type is).
2122 */
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002123 lo = TIME_T_MIN;
2124 hi = TIME_T_MAX;
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002125 for ( ; ; ) {
2126 t = lo / 2 + hi / 2;
2127 if (t < lo)
2128 t = lo;
2129 else if (t > hi)
2130 t = hi;
2131 if (! funcp(sp, &t, offset, &mytm)) {
2132 /*
2133 ** Assume that t is too extreme to be represented in
2134 ** a struct tm; arrange things so that it is less
2135 ** extreme on the next pass.
2136 */
2137 dir = (t > 0) ? 1 : -1;
2138 } else dir = tmcomp(&mytm, &yourtm);
2139 if (dir != 0) {
2140 if (t == lo) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002141 if (t == TIME_T_MAX)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002142 return WRONG;
2143 ++t;
2144 ++lo;
2145 } else if (t == hi) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002146 if (t == TIME_T_MIN)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002147 return WRONG;
2148 --t;
2149 --hi;
2150 }
2151 if (lo > hi)
2152 return WRONG;
2153 if (dir > 0)
2154 hi = t;
2155 else lo = t;
2156 continue;
2157 }
2158#if defined TM_GMTOFF && ! UNINIT_TRAP
2159 if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
2160 && (yourtm.TM_GMTOFF < 0
2161 ? (-SECSPERDAY <= yourtm.TM_GMTOFF
2162 && (mytm.TM_GMTOFF <=
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002163 (min(INT_FAST32_MAX, LONG_MAX)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002164 + yourtm.TM_GMTOFF)))
2165 : (yourtm.TM_GMTOFF <= SECSPERDAY
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002166 && ((max(INT_FAST32_MIN, LONG_MIN)
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002167 + yourtm.TM_GMTOFF)
2168 <= mytm.TM_GMTOFF)))) {
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002169 /* MYTM matches YOURTM except with the wrong UT offset.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002170 YOURTM.TM_GMTOFF is plausible, so try it instead.
2171 It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
2172 since the guess gets checked. */
2173 time_t altt = t;
2174 int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
2175 if (!increment_overflow_time(&altt, diff)) {
2176 struct tm alttm;
2177 if (funcp(sp, &altt, offset, &alttm)
2178 && alttm.tm_isdst == mytm.tm_isdst
2179 && alttm.TM_GMTOFF == yourtm.TM_GMTOFF
2180 && tmcomp(&alttm, &yourtm) == 0) {
2181 t = altt;
2182 mytm = alttm;
2183 }
2184 }
2185 }
2186#endif
2187 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2188 break;
2189 /*
2190 ** Right time, wrong type.
2191 ** Hunt for right time, right type.
2192 ** It's okay to guess wrong since the guess
2193 ** gets checked.
2194 */
2195 if (sp == NULL)
2196 return WRONG;
2197 for (i = sp->typecnt - 1; i >= 0; --i) {
2198 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2199 continue;
2200 for (j = sp->typecnt - 1; j >= 0; --j) {
2201 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2202 continue;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002203 if (ttunspecified(sp, j))
2204 continue;
2205 newt = (t + sp->ttis[j].tt_utoff
2206 - sp->ttis[i].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002207 if (! funcp(sp, &newt, offset, &mytm))
2208 continue;
2209 if (tmcomp(&mytm, &yourtm) != 0)
2210 continue;
2211 if (mytm.tm_isdst != yourtm.tm_isdst)
2212 continue;
2213 /*
2214 ** We have a match.
2215 */
2216 t = newt;
2217 goto label;
2218 }
2219 }
2220 return WRONG;
2221 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002222label:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002223 newt = t + saved_seconds;
2224 if ((newt < t) != (saved_seconds < 0))
2225 return WRONG;
2226 t = newt;
2227 if (funcp(sp, &t, offset, tmp))
2228 *okayp = true;
2229 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002230}
2231
2232static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002233time2(struct tm * const tmp,
2234 struct tm *(*funcp)(struct state const *, time_t const *,
2235 int_fast32_t, struct tm *),
2236 struct state const *sp,
Elliott Hughesce4783c2013-07-12 17:31:11 -07002237 const int_fast32_t offset,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002238 bool *okayp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002239{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002240 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002241
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002242 /*
2243 ** First try without normalization of seconds
2244 ** (in case tm_sec contains a value associated with a leap second).
2245 ** If that fails, try with normalization of seconds.
2246 */
2247 t = time2sub(tmp, funcp, sp, offset, okayp, false);
2248 return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002249}
2250
2251static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002252time1(struct tm *const tmp,
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002253 struct tm *(*funcp)(struct state const *, time_t const *,
2254 int_fast32_t, struct tm *),
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002255 struct state const *sp,
2256 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002257{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002258 register time_t t;
2259 register int samei, otheri;
2260 register int sameind, otherind;
2261 register int i;
2262 register int nseen;
2263 char seen[TZ_MAX_TYPES];
2264 unsigned char types[TZ_MAX_TYPES];
2265 bool okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002266
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002267 if (tmp == NULL) {
2268 errno = EINVAL;
2269 return WRONG;
2270 }
2271 if (tmp->tm_isdst > 1)
2272 tmp->tm_isdst = 1;
2273 t = time2(tmp, funcp, sp, offset, &okay);
2274 if (okay)
2275 return t;
2276 if (tmp->tm_isdst < 0)
Elliott Hughes906eb992014-06-18 19:46:25 -07002277#ifdef PCTS
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002278 /*
2279 ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
2280 */
2281 tmp->tm_isdst = 0; /* reset to std and try again */
Elliott Hughes906eb992014-06-18 19:46:25 -07002282#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002283 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002284#endif /* !defined PCTS */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002285 /*
2286 ** We're supposed to assume that somebody took a time of one type
2287 ** and did some math on it that yielded a "struct tm" that's bad.
2288 ** We try to divine the type they started from and adjust to the
2289 ** type they need.
2290 */
2291 if (sp == NULL)
2292 return WRONG;
2293 for (i = 0; i < sp->typecnt; ++i)
2294 seen[i] = false;
2295 nseen = 0;
2296 for (i = sp->timecnt - 1; i >= 0; --i)
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002297 if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002298 seen[sp->types[i]] = true;
2299 types[nseen++] = sp->types[i];
2300 }
2301 for (sameind = 0; sameind < nseen; ++sameind) {
2302 samei = types[sameind];
2303 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2304 continue;
2305 for (otherind = 0; otherind < nseen; ++otherind) {
2306 otheri = types[otherind];
2307 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2308 continue;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002309 tmp->tm_sec += (sp->ttis[otheri].tt_utoff
2310 - sp->ttis[samei].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002311 tmp->tm_isdst = !tmp->tm_isdst;
2312 t = time2(tmp, funcp, sp, offset, &okay);
2313 if (okay)
2314 return t;
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002315 tmp->tm_sec -= (sp->ttis[otheri].tt_utoff
2316 - sp->ttis[samei].tt_utoff);
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002317 tmp->tm_isdst = !tmp->tm_isdst;
2318 }
2319 }
2320 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002321}
2322
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002323static time_t
2324mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
2325{
2326 if (sp)
2327 return time1(tmp, localsub, sp, setname);
2328 else {
2329 gmtcheck();
2330 return time1(tmp, gmtsub, gmtptr, 0);
2331 }
2332}
2333
2334#if NETBSD_INSPIRED
2335
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002336time_t
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002337mktime_z(struct state *restrict sp, struct tm *restrict tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002338{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002339 return mktime_tzname(sp, tmp, false);
2340}
2341
2342#endif
2343
2344time_t
2345mktime(struct tm *tmp)
2346{
Elliott Hughesa9209d72016-09-16 18:16:47 -07002347#if defined(__BIONIC__)
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002348 int saved_errno = errno;
2349#endif
2350
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002351 time_t t;
2352 int err = lock();
2353 if (err) {
2354 errno = err;
2355 return -1;
2356 }
2357 tzset_unlocked();
2358 t = mktime_tzname(lclptr, tmp, true);
2359 unlock();
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002360
Elliott Hughesa9209d72016-09-16 18:16:47 -07002361#if defined(__BIONIC__)
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002362 errno = (t == -1) ? EOVERFLOW : saved_errno;
2363#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002364 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002365}
2366
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002367#if STD_INSPIRED
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002368time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002369timelocal(struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002370{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002371 if (tmp != NULL)
2372 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2373 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002374}
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002375#else
2376static
2377#endif
Elliott Hughes906eb992014-06-18 19:46:25 -07002378time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002379timeoff(struct tm *tmp, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07002380{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002381 if (tmp)
2382 tmp->tm_isdst = 0;
2383 gmtcheck();
2384 return time1(tmp, gmtsub, gmtptr, offset);
Elliott Hughes906eb992014-06-18 19:46:25 -07002385}
2386
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002387time_t
2388timegm(struct tm *tmp)
2389{
2390 time_t t;
2391 struct tm tmcpy;
2392 mktmcpy(&tmcpy, tmp);
2393 tmcpy.tm_wday = -1;
2394 t = timeoff(&tmcpy, 0);
2395 if (0 <= tmcpy.tm_wday)
2396 *tmp = tmcpy;
2397 return t;
2398}
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002399
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002400static int_fast32_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002401leapcorr(struct state const *sp, time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002402{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002403 register struct lsinfo const * lp;
2404 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002405
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002406 i = sp->leapcnt;
2407 while (--i >= 0) {
2408 lp = &sp->lsis[i];
2409 if (t >= lp->ls_trans)
2410 return lp->ls_corr;
2411 }
2412 return 0;
2413}
2414
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002415/*
2416** XXX--is the below the right way to conditionalize??
2417*/
2418
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002419#if STD_INSPIRED
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002420
2421/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
2422 NETBSD_INSPIRED is defined, and are private otherwise. */
2423# if NETBSD_INSPIRED
2424# define NETBSD_INSPIRED_EXTERN
2425# else
2426# define NETBSD_INSPIRED_EXTERN static
2427# endif
2428
2429/*
2430** IEEE Std 1003.1 (POSIX) says that 536457599
2431** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2432** is not the case if we are accounting for leap seconds.
2433** So, we provide the following conversion routines for use
2434** when exchanging timestamps with POSIX conforming systems.
2435*/
2436
2437NETBSD_INSPIRED_EXTERN time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002438time2posix_z(struct state *sp, time_t t)
2439{
2440 return t - leapcorr(sp, t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002441}
2442
2443time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002444time2posix(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002445{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002446 int err = lock();
2447 if (err) {
2448 errno = err;
2449 return -1;
2450 }
2451 if (!lcl_is_set)
2452 tzset_unlocked();
2453 if (lclptr)
2454 t = time2posix_z(lclptr, t);
2455 unlock();
2456 return t;
2457}
2458
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002459NETBSD_INSPIRED_EXTERN time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002460posix2time_z(struct state *sp, time_t t)
2461{
2462 time_t x;
2463 time_t y;
2464 /*
2465 ** For a positive leap second hit, the result
2466 ** is not unique. For a negative leap second
2467 ** hit, the corresponding time doesn't exist,
2468 ** so we return an adjacent second.
2469 */
2470 x = t + leapcorr(sp, t);
2471 y = x - leapcorr(sp, x);
2472 if (y < t) {
2473 do {
2474 x++;
2475 y = x - leapcorr(sp, x);
2476 } while (y < t);
2477 x -= y != t;
2478 } else if (y > t) {
2479 do {
2480 --x;
2481 y = x - leapcorr(sp, x);
2482 } while (y > t);
2483 x += y != t;
2484 }
2485 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002486}
2487
2488time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002489posix2time(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002490{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002491 int err = lock();
2492 if (err) {
2493 errno = err;
2494 return -1;
2495 }
2496 if (!lcl_is_set)
2497 tzset_unlocked();
2498 if (lclptr)
2499 t = posix2time_z(lclptr, t);
2500 unlock();
2501 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002502}
2503
Almaz Mingaleevd86a3ab2023-04-27 11:24:48 +01002504#endif /* STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002505
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002506#if TZ_TIME_T
2507
2508# if !USG_COMPAT
2509# define daylight 0
2510# define timezone 0
2511# endif
2512# if !ALTZONE
2513# define altzone 0
2514# endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002515
2516/* Convert from the underlying system's time_t to the ersatz time_tz,
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002517 which is called 'time_t' in this file. Typically, this merely
2518 converts the time's integer width. On some platforms, the system
2519 time is local time not UT, or uses some epoch other than the POSIX
2520 epoch.
2521
2522 Although this code appears to define a function named 'time' that
2523 returns time_t, the macros in private.h cause this code to actually
2524 define a function named 'tz_time' that returns tz_time_t. The call
2525 to sys_time invokes the underlying system's 'time' function. */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002526
2527time_t
2528time(time_t *p)
2529{
2530 time_t r = sys_time(0);
Almaz Mingaleev5411aff2022-02-11 12:27:12 +00002531 if (r != (time_t) -1) {
2532 int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0;
2533 if (increment_overflow32(&offset, -EPOCH_OFFSET)
2534 || increment_overflow_time(&r, offset)) {
2535 errno = EOVERFLOW;
2536 r = -1;
2537 }
2538 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002539 if (p)
2540 *p = r;
2541 return r;
2542}
2543
2544#endif