blob: cf0fd6b96fcae56a93464902b79d52142c10b4c9 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/*
2** This file is in the public domain, so clarified as of
3** 1996-06-05 by Arthur David Olson.
4*/
5
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08006/*
7** Leap second handling from Bradley White.
8** POSIX-style TZ environment variable handling from Guy Harris.
9*/
10
11/*LINTLIBRARY*/
12
Elliott Hughes9fb22a32015-10-07 17:13:40 -070013#define LOCALTIME_IMPLEMENTATION
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080014#include "private.h"
Elliott Hughes9fb22a32015-10-07 17:13:40 -070015
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080016#include "tzfile.h"
17#include "fcntl.h"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080018
Elliott Hughes9fb22a32015-10-07 17:13:40 -070019#if THREAD_SAFE
20# include <pthread.h>
21static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER;
22static int lock(void) { return pthread_mutex_lock(&locallock); }
23static void unlock(void) { pthread_mutex_unlock(&locallock); }
24#else
25static int lock(void) { return 0; }
26static void unlock(void) { }
27#endif
28
29/* NETBSD_INSPIRED_EXTERN functions are exported to callers if
30 NETBSD_INSPIRED is defined, and are private otherwise. */
31#if NETBSD_INSPIRED
32# define NETBSD_INSPIRED_EXTERN
33#else
34# define NETBSD_INSPIRED_EXTERN static
35#endif
36
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080037#ifndef TZ_ABBR_MAX_LEN
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070038#define TZ_ABBR_MAX_LEN 16
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080039#endif /* !defined TZ_ABBR_MAX_LEN */
40
41#ifndef TZ_ABBR_CHAR_SET
42#define TZ_ABBR_CHAR_SET \
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070043 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080044#endif /* !defined TZ_ABBR_CHAR_SET */
45
46#ifndef TZ_ABBR_ERR_CHAR
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070047#define TZ_ABBR_ERR_CHAR '_'
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080048#endif /* !defined TZ_ABBR_ERR_CHAR */
49
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080050/*
51** SunOS 4.1.1 headers lack O_BINARY.
52*/
53
54#ifdef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070055#define OPEN_MODE (O_RDONLY | O_BINARY)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080056#endif /* defined O_BINARY */
57#ifndef O_BINARY
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070058#define OPEN_MODE O_RDONLY
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080059#endif /* !defined O_BINARY */
60
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080061#ifndef WILDABBR
62/*
63** Someone might make incorrect use of a time zone abbreviation:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070064** 1. They might reference tzname[0] before calling tzset (explicitly
65** or implicitly).
66** 2. They might reference tzname[1] before calling tzset (explicitly
67** or implicitly).
68** 3. They might reference tzname[1] after setting to a time zone
69** in which Daylight Saving Time is never observed.
70** 4. They might reference tzname[0] after setting to a time zone
71** in which Standard Time is never observed.
72** 5. They might reference tm.TM_ZONE after calling offtime.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080073** What's best to do in the above cases is open to debate;
74** for now, we just set things up so that in any of the five cases
75** WILDABBR is used. Another possibility: initialize tzname[0] to the
76** string "tzname[0] used before set", and similarly for the other cases.
77** And another: initialize tzname[0] to "ERA", with an explanation in the
78** manual page of what this "time zone abbreviation" means (doing this so
79** that tzname[0] has the "normal" length of three characters).
80*/
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070081#define WILDABBR " "
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080082#endif /* !defined WILDABBR */
83
Elliott Hughes906eb992014-06-18 19:46:25 -070084static const char wildabbr[] = WILDABBR;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080085
Calin Juravled8928922014-02-28 12:18:53 +000086static const char gmt[] = "GMT";
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080087
88/*
89** The DST rules to use if TZ has no rules and we can't load TZDEFRULES.
90** We default to US rules as of 1999-08-17.
91** POSIX 1003.1 section 8.1.1 says that the default DST rules are
92** implementation dependent; for historical reasons, US rules are a
93** common default.
94*/
95#ifndef TZDEFRULESTRING
96#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
97#endif /* !defined TZDEFDST */
98
Calin Juravled8928922014-02-28 12:18:53 +000099struct ttinfo { /* time type information */
Elliott Hughese0d0b152013-09-27 00:04:30 -0700100 int_fast32_t tt_gmtoff; /* UT offset in seconds */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700101 bool tt_isdst; /* used to set tm_isdst */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700102 int tt_abbrind; /* abbreviation list index */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700103 bool tt_ttisstd; /* transition is std time */
104 bool tt_ttisgmt; /* transition is UT */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800105};
106
Calin Juravled8928922014-02-28 12:18:53 +0000107struct lsinfo { /* leap second information */
Elliott Hughesce4783c2013-07-12 17:31:11 -0700108 time_t ls_trans; /* transition time */
109 int_fast64_t ls_corr; /* correction to apply */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800110};
111
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700112#define SMALLEST(a, b) (((a) < (b)) ? (a) : (b))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700113#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800114
115#ifdef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700116#define MY_TZNAME_MAX TZNAME_MAX
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800117#endif /* defined TZNAME_MAX */
118#ifndef TZNAME_MAX
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700119#define MY_TZNAME_MAX 255
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800120#endif /* !defined TZNAME_MAX */
121
122struct state {
Calin Juravled8928922014-02-28 12:18:53 +0000123 int leapcnt;
124 int timecnt;
125 int typecnt;
126 int charcnt;
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700127 bool goback;
128 bool goahead;
Calin Juravled8928922014-02-28 12:18:53 +0000129 time_t ats[TZ_MAX_TIMES];
130 unsigned char types[TZ_MAX_TIMES];
131 struct ttinfo ttis[TZ_MAX_TYPES];
132 char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
133 (2 * (MY_TZNAME_MAX + 1)))];
134 struct lsinfo lsis[TZ_MAX_LEAPS];
135 int defaulttype; /* for early times or if no transitions */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800136};
137
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700138enum r_type {
139 JULIAN_DAY, /* Jn = Julian day */
140 DAY_OF_YEAR, /* n = day of year */
141 MONTH_NTH_DAY_OF_WEEK /* Mm.n.d = month, week, day of week */
142};
143
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800144struct rule {
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700145 enum r_type r_type; /* type of rule */
Calin Juravled8928922014-02-28 12:18:53 +0000146 int r_day; /* day number of rule */
147 int r_week; /* week number of rule */
148 int r_mon; /* month number of rule */
149 int_fast32_t r_time; /* transition time of rule */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800150};
151
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700152static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t,
153 struct tm *);
154static bool increment_overflow(int *, int);
155static bool increment_overflow_time(time_t *, int_fast32_t);
156static bool normalize_overflow32(int_fast32_t *, int *, int);
157static struct tm *timesub(time_t const *, int_fast32_t, struct state const *,
158 struct tm *);
159static bool typesequiv(struct state const *, int, int);
160static bool tzparse(char const *, struct state *, bool);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800161
162#ifdef ALL_STATE
Calin Juravled8928922014-02-28 12:18:53 +0000163static struct state * lclptr;
164static struct state * gmtptr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800165#endif /* defined ALL_STATE */
166
167#ifndef ALL_STATE
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700168static struct state lclmem;
169static struct state gmtmem;
170#define lclptr (&lclmem)
171#define gmtptr (&gmtmem)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800172#endif /* State Farm */
173
174#ifndef TZ_STRLEN_MAX
175#define TZ_STRLEN_MAX 255
176#endif /* !defined TZ_STRLEN_MAX */
177
Calin Juravled8928922014-02-28 12:18:53 +0000178static char lcl_TZname[TZ_STRLEN_MAX + 1];
179static int lcl_is_set;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800180
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800181/*
182** Section 4.12.3 of X3.159-1989 requires that
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700183** Except for the strftime function, these functions [asctime,
184** ctime, gmtime, localtime] return values in one of two static
185** objects: a broken-down time structure and an array of char.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800186** Thanks to Paul Eggert for noting this.
187*/
188
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700189static struct tm tm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800190
Elliott Hughes0a610d02016-07-29 14:04:17 -0700191#if !HAVE_POSIX_DECLS
192char * tzname[2] = {
193 (char *) wildabbr,
194 (char *) wildabbr
195};
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800196#ifdef USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700197long timezone;
198int daylight;
Elliott Hughes0a610d02016-07-29 14:04:17 -0700199# endif
200#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800201
202#ifdef ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700203long altzone;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800204#endif /* defined ALTZONE */
205
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700206/* Initialize *S to a value based on GMTOFF, ISDST, and ABBRIND. */
207static void
208init_ttinfo(struct ttinfo *s, int_fast32_t gmtoff, bool isdst, int abbrind)
209{
210 s->tt_gmtoff = gmtoff;
211 s->tt_isdst = isdst;
212 s->tt_abbrind = abbrind;
213 s->tt_ttisstd = false;
214 s->tt_ttisgmt = false;
215}
216
Elliott Hughesce4783c2013-07-12 17:31:11 -0700217static int_fast32_t
218detzcode(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800219{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700220 register int_fast32_t result;
221 register int i;
222 int_fast32_t one = 1;
223 int_fast32_t halfmaxval = one << (32 - 2);
224 int_fast32_t maxval = halfmaxval - 1 + halfmaxval;
225 int_fast32_t minval = -1 - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800226
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700227 result = codep[0] & 0x7f;
228 for (i = 1; i < 4; ++i)
229 result = (result << 8) | (codep[i] & 0xff);
230
231 if (codep[0] & 0x80) {
232 /* Do two's-complement negation even on non-two's-complement machines.
233 If the result would be minval - 1, return minval. */
234 result -= !TWOS_COMPLEMENT(int_fast32_t) && result != 0;
235 result += minval;
236 }
237 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800238}
239
Calin Juravle627d37c2014-02-28 11:46:03 +0000240static int_fast64_t
Elliott Hughesce4783c2013-07-12 17:31:11 -0700241detzcode64(const char *const codep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800242{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700243 register uint_fast64_t result;
244 register int i;
245 int_fast64_t one = 1;
246 int_fast64_t halfmaxval = one << (64 - 2);
247 int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
248 int_fast64_t minval = -TWOS_COMPLEMENT(int_fast64_t) - maxval;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800249
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700250 result = codep[0] & 0x7f;
251 for (i = 1; i < 8; ++i)
252 result = (result << 8) | (codep[i] & 0xff);
253
254 if (codep[0] & 0x80) {
255 /* Do two's-complement negation even on non-two's-complement machines.
256 If the result would be minval - 1, return minval. */
257 result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
258 result += minval;
259 }
260 return result;
261}
262
263static void
264update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp)
265{
266 tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
267#ifdef USG_COMPAT
268 if (!ttisp->tt_isdst)
269 timezone = - ttisp->tt_gmtoff;
270#endif
271#ifdef ALTZONE
272 if (ttisp->tt_isdst)
273 altzone = - ttisp->tt_gmtoff;
274#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800275}
276
277static void
Elliott Hughesce4783c2013-07-12 17:31:11 -0700278settzname(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800279{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700280 register struct state * const sp = lclptr;
281 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800282
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700283 tzname[0] = tzname[1] = (char *) wildabbr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800284#ifdef USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700285 daylight = 0;
286 timezone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800287#endif /* defined USG_COMPAT */
288#ifdef ALTZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700289 altzone = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800290#endif /* defined ALTZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700291 if (sp == NULL) {
292 tzname[0] = tzname[1] = (char *) gmt;
293 return;
294 }
295 /*
296 ** And to get the latest zone names into tzname. . .
297 */
298 for (i = 0; i < sp->typecnt; ++i) {
299 register const struct ttinfo * const ttisp = &sp->ttis[i];
300 update_tzname_etc(sp, ttisp);
301 }
302 for (i = 0; i < sp->timecnt; ++i) {
303 register const struct ttinfo * const ttisp =
304 &sp->ttis[
305 sp->types[i]];
306 update_tzname_etc(sp, ttisp);
Elliott Hughesce4783c2013-07-12 17:31:11 -0700307#ifdef USG_COMPAT
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700308 if (ttisp->tt_isdst)
309 daylight = 1;
Elliott Hughesce4783c2013-07-12 17:31:11 -0700310#endif /* defined USG_COMPAT */
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700311 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800312}
313
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700314static void
315scrub_abbrs(struct state *sp)
316{
317 int i;
318 /*
319 ** First, replace bogus characters.
320 */
321 for (i = 0; i < sp->charcnt; ++i)
322 if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
323 sp->chars[i] = TZ_ABBR_ERR_CHAR;
324 /*
325 ** Second, truncate long abbreviations.
326 */
327 for (i = 0; i < sp->typecnt; ++i) {
328 register const struct ttinfo * const ttisp = &sp->ttis[i];
329 register char * cp = &sp->chars[ttisp->tt_abbrind];
330
331 if (strlen(cp) > TZ_ABBR_MAX_LEN &&
332 strcmp(cp, GRANDPARENTED) != 0)
333 *(cp + TZ_ABBR_MAX_LEN) = '\0';
334 }
335}
336
337static bool
338differ_by_repeat(const time_t t1, const time_t t0)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800339{
Calin Juravled8928922014-02-28 12:18:53 +0000340 if (TYPE_BIT(time_t) - TYPE_SIGNED(time_t) < SECSPERREPEAT_BITS)
341 return 0;
Christopher Ferris384ffe32015-11-02 12:56:37 -0800342#if defined(__LP64__) // 32-bit Android/glibc has a signed 32-bit time_t; 64-bit doesn't.
Calin Juravled8928922014-02-28 12:18:53 +0000343 return t1 - t0 == SECSPERREPEAT;
Elliott Hughes51aeff72013-10-08 18:30:44 -0700344#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800345}
346
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700347/* Input buffer for data read from a compiled tz file. */
348union input_buffer {
349 /* The first part of the buffer, interpreted as a header. */
350 struct tzhead tzhead;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800351
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700352 /* The entire buffer. */
353 char buf[2 * sizeof(struct tzhead) + 2 * sizeof (struct state)
354 + 4 * TZ_MAX_TIMES];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800355};
356
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700357/* Local storage needed for 'tzloadbody'. */
358union local_storage {
359 /* The file name to be opened. */
360 char fullname[FILENAME_MAX + 1];
361
362 /* The results of analyzing the file's contents after it is opened. */
363 struct {
364 /* The input buffer. */
365 union input_buffer u;
366
367 /* A temporary state used for parsing a TZ string in the file. */
368 struct state st;
369 } u;
370};
371
372static int __bionic_open_tzdata(const char*);
373
374/* Load tz data from the file named NAME into *SP. Read extended
375 format if DOEXTEND. Use *LSP for temporary storage. Return 0 on
376 success, an errno value on failure. */
377static int
378tzloadbody(char const *name, struct state *sp, bool doextend,
379 union local_storage *lsp)
380{
381 register int i;
382 register int fid;
383 register int stored;
384 register ssize_t nread;
385#if !defined(__ANDROID__)
386 register bool doaccess;
387 register char *fullname = lsp->fullname;
388#endif
389 register union input_buffer *up = &lsp->u.u;
390 register int tzheadsize = sizeof (struct tzhead);
391
392 sp->goback = sp->goahead = false;
393
394 if (! name) {
395 name = TZDEFAULT;
396 if (! name)
397 return EINVAL;
398 }
399
400#if defined(__ANDROID__)
401 fid = __bionic_open_tzdata(name);
402#else
403 if (name[0] == ':')
404 ++name;
405 doaccess = name[0] == '/';
406 if (!doaccess) {
407 char const *p = TZDIR;
408 if (! p)
409 return EINVAL;
410 if (sizeof lsp->fullname - 1 <= strlen(p) + strlen(name))
411 return ENAMETOOLONG;
412 strcpy(fullname, p);
413 strcat(fullname, "/");
414 strcat(fullname, name);
415 /* Set doaccess if '.' (as in "../") shows up in name. */
416 if (strchr(name, '.'))
417 doaccess = true;
418 name = fullname;
419 }
420 if (doaccess && access(name, R_OK) != 0)
421 return errno;
422 fid = open(name, OPEN_MODE);
423#endif
424 if (fid < 0)
425 return errno;
426
427 nread = read(fid, up->buf, sizeof up->buf);
428 if (nread < tzheadsize) {
429 int err = nread < 0 ? errno : EINVAL;
430 close(fid);
431 return err;
432 }
433 if (close(fid) < 0)
434 return errno;
435 for (stored = 4; stored <= 8; stored *= 2) {
436 int_fast32_t ttisstdcnt = detzcode(up->tzhead.tzh_ttisstdcnt);
437 int_fast32_t ttisgmtcnt = detzcode(up->tzhead.tzh_ttisgmtcnt);
438 int_fast32_t leapcnt = detzcode(up->tzhead.tzh_leapcnt);
439 int_fast32_t timecnt = detzcode(up->tzhead.tzh_timecnt);
440 int_fast32_t typecnt = detzcode(up->tzhead.tzh_typecnt);
441 int_fast32_t charcnt = detzcode(up->tzhead.tzh_charcnt);
442 char const *p = up->buf + tzheadsize;
443 if (! (0 <= leapcnt && leapcnt < TZ_MAX_LEAPS
444 && 0 < typecnt && typecnt < TZ_MAX_TYPES
445 && 0 <= timecnt && timecnt < TZ_MAX_TIMES
446 && 0 <= charcnt && charcnt < TZ_MAX_CHARS
447 && (ttisstdcnt == typecnt || ttisstdcnt == 0)
448 && (ttisgmtcnt == typecnt || ttisgmtcnt == 0)))
449 return EINVAL;
450 if (nread
451 < (tzheadsize /* struct tzhead */
452 + timecnt * stored /* ats */
453 + timecnt /* types */
454 + typecnt * 6 /* ttinfos */
455 + charcnt /* chars */
456 + leapcnt * (stored + 4) /* lsinfos */
457 + ttisstdcnt /* ttisstds */
458 + ttisgmtcnt)) /* ttisgmts */
459 return EINVAL;
460 sp->leapcnt = leapcnt;
461 sp->timecnt = timecnt;
462 sp->typecnt = typecnt;
463 sp->charcnt = charcnt;
464
465 /* Read transitions, discarding those out of time_t range.
466 But pretend the last transition before time_t_min
467 occurred at time_t_min. */
468 timecnt = 0;
469 for (i = 0; i < sp->timecnt; ++i) {
470 int_fast64_t at
471 = stored == 4 ? detzcode(p) : detzcode64(p);
472 sp->types[i] = at <= time_t_max;
473 if (sp->types[i]) {
474 time_t attime
475 = ((TYPE_SIGNED(time_t) ? at < time_t_min : at < 0)
476 ? time_t_min : at);
477 if (timecnt && attime <= sp->ats[timecnt - 1]) {
478 if (attime < sp->ats[timecnt - 1])
479 return EINVAL;
480 sp->types[i - 1] = 0;
481 timecnt--;
482 }
483 sp->ats[timecnt++] = attime;
484 }
485 p += stored;
486 }
487
488 timecnt = 0;
489 for (i = 0; i < sp->timecnt; ++i) {
490 unsigned char typ = *p++;
491 if (sp->typecnt <= typ)
492 return EINVAL;
493 if (sp->types[i])
494 sp->types[timecnt++] = typ;
495 }
496 sp->timecnt = timecnt;
497 for (i = 0; i < sp->typecnt; ++i) {
498 register struct ttinfo * ttisp;
499 unsigned char isdst, abbrind;
500
501 ttisp = &sp->ttis[i];
502 ttisp->tt_gmtoff = detzcode(p);
503 p += 4;
504 isdst = *p++;
505 if (! (isdst < 2))
506 return EINVAL;
507 ttisp->tt_isdst = isdst;
508 abbrind = *p++;
509 if (! (abbrind < sp->charcnt))
510 return EINVAL;
511 ttisp->tt_abbrind = abbrind;
512 }
513 for (i = 0; i < sp->charcnt; ++i)
514 sp->chars[i] = *p++;
515 sp->chars[i] = '\0'; /* ensure '\0' at end */
516
517 /* Read leap seconds, discarding those out of time_t range. */
518 leapcnt = 0;
519 for (i = 0; i < sp->leapcnt; ++i) {
520 int_fast64_t tr = stored == 4 ? detzcode(p) : detzcode64(p);
521 int_fast32_t corr = detzcode(p + stored);
522 p += stored + 4;
523 if (tr <= time_t_max) {
524 time_t trans
525 = ((TYPE_SIGNED(time_t) ? tr < time_t_min : tr < 0)
526 ? time_t_min : tr);
527 if (leapcnt && trans <= sp->lsis[leapcnt - 1].ls_trans) {
528 if (trans < sp->lsis[leapcnt - 1].ls_trans)
529 return EINVAL;
530 leapcnt--;
531 }
532 sp->lsis[leapcnt].ls_trans = trans;
533 sp->lsis[leapcnt].ls_corr = corr;
534 leapcnt++;
535 }
536 }
537 sp->leapcnt = leapcnt;
538
539 for (i = 0; i < sp->typecnt; ++i) {
540 register struct ttinfo * ttisp;
541
542 ttisp = &sp->ttis[i];
543 if (ttisstdcnt == 0)
544 ttisp->tt_ttisstd = false;
545 else {
546 if (*p != true && *p != false)
547 return EINVAL;
548 ttisp->tt_ttisstd = *p++;
549 }
550 }
551 for (i = 0; i < sp->typecnt; ++i) {
552 register struct ttinfo * ttisp;
553
554 ttisp = &sp->ttis[i];
555 if (ttisgmtcnt == 0)
556 ttisp->tt_ttisgmt = false;
557 else {
558 if (*p != true && *p != false)
559 return EINVAL;
560 ttisp->tt_ttisgmt = *p++;
561 }
562 }
563 /*
564 ** If this is an old file, we're done.
565 */
566 if (up->tzhead.tzh_version[0] == '\0')
567 break;
568 nread -= p - up->buf;
569 memmove(up->buf, p, nread);
570 }
571 if (doextend && nread > 2 &&
572 up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
573 sp->typecnt + 2 <= TZ_MAX_TYPES) {
574 struct state *ts = &lsp->u.st;
575
576 up->buf[nread - 1] = '\0';
577 if (tzparse(&up->buf[1], ts, false)
578 && ts->typecnt == 2) {
579
580 /* Attempt to reuse existing abbreviations.
581 Without this, America/Anchorage would stop
582 working after 2037 when TZ_MAX_CHARS is 50, as
583 sp->charcnt equals 42 (for LMT CAT CAWT CAPT AHST
584 AHDT YST AKDT AKST) and ts->charcnt equals 10
585 (for AKST AKDT). Reusing means sp->charcnt can
586 stay 42 in this example. */
587 int gotabbr = 0;
588 int charcnt = sp->charcnt;
589 for (i = 0; i < 2; i++) {
590 char *tsabbr = ts->chars + ts->ttis[i].tt_abbrind;
591 int j;
592 for (j = 0; j < charcnt; j++)
593 if (strcmp(sp->chars + j, tsabbr) == 0) {
594 ts->ttis[i].tt_abbrind = j;
595 gotabbr++;
596 break;
597 }
598 if (! (j < charcnt)) {
599 int tsabbrlen = strlen(tsabbr);
600 if (j + tsabbrlen < TZ_MAX_CHARS) {
601 strcpy(sp->chars + j, tsabbr);
602 charcnt = j + tsabbrlen + 1;
603 ts->ttis[i].tt_abbrind = j;
604 gotabbr++;
605 }
606 }
607 }
608 if (gotabbr == 2) {
609 sp->charcnt = charcnt;
610 for (i = 0; i < ts->timecnt; i++)
611 if (sp->ats[sp->timecnt - 1] < ts->ats[i])
612 break;
613 while (i < ts->timecnt
614 && sp->timecnt < TZ_MAX_TIMES) {
615 sp->ats[sp->timecnt] = ts->ats[i];
616 sp->types[sp->timecnt] = (sp->typecnt
617 + ts->types[i]);
618 sp->timecnt++;
619 i++;
620 }
621 sp->ttis[sp->typecnt++] = ts->ttis[0];
622 sp->ttis[sp->typecnt++] = ts->ttis[1];
623 }
624 }
625 }
626 if (sp->timecnt > 1) {
627 for (i = 1; i < sp->timecnt; ++i)
628 if (typesequiv(sp, sp->types[i], sp->types[0]) &&
629 differ_by_repeat(sp->ats[i], sp->ats[0])) {
630 sp->goback = true;
631 break;
632 }
633 for (i = sp->timecnt - 2; i >= 0; --i)
634 if (typesequiv(sp, sp->types[sp->timecnt - 1],
635 sp->types[i]) &&
636 differ_by_repeat(sp->ats[sp->timecnt - 1],
637 sp->ats[i])) {
638 sp->goahead = true;
639 break;
640 }
641 }
642 /*
643 ** If type 0 is is unused in transitions,
644 ** it's the type to use for early times.
645 */
646 for (i = 0; i < sp->timecnt; ++i)
647 if (sp->types[i] == 0)
648 break;
649 i = i < sp->timecnt ? -1 : 0;
650 /*
651 ** Absent the above,
652 ** if there are transition times
653 ** and the first transition is to a daylight time
654 ** find the standard type less than and closest to
655 ** the type of the first transition.
656 */
657 if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
658 i = sp->types[0];
659 while (--i >= 0)
660 if (!sp->ttis[i].tt_isdst)
661 break;
662 }
663 /*
664 ** If no result yet, find the first standard type.
665 ** If there is none, punt to type zero.
666 */
667 if (i < 0) {
668 i = 0;
669 while (sp->ttis[i].tt_isdst)
670 if (++i >= sp->typecnt) {
671 i = 0;
672 break;
673 }
674 }
675 sp->defaulttype = i;
676 return 0;
677}
678
679/* Load tz data from the file named NAME into *SP. Read extended
680 format if DOEXTEND. Return 0 on success, an errno value on failure. */
681static int
682tzload(char const *name, struct state *sp, bool doextend)
683{
684#ifdef ALL_STATE
685 union local_storage *lsp = malloc(sizeof *lsp);
686 if (!lsp)
687 return errno;
688 else {
689 int err = tzloadbody(name, sp, doextend, lsp);
690 free(lsp);
691 return err;
692 }
693#else
694 union local_storage ls;
695 return tzloadbody(name, sp, doextend, &ls);
696#endif
697}
698
699static bool
700typesequiv(const struct state *sp, int a, int b)
701{
702 register bool result;
703
704 if (sp == NULL ||
705 a < 0 || a >= sp->typecnt ||
706 b < 0 || b >= sp->typecnt)
707 result = false;
708 else {
709 register const struct ttinfo * ap = &sp->ttis[a];
710 register const struct ttinfo * bp = &sp->ttis[b];
711 result = ap->tt_gmtoff == bp->tt_gmtoff &&
712 ap->tt_isdst == bp->tt_isdst &&
713 ap->tt_ttisstd == bp->tt_ttisstd &&
714 ap->tt_ttisgmt == bp->tt_ttisgmt &&
715 strcmp(&sp->chars[ap->tt_abbrind],
716 &sp->chars[bp->tt_abbrind]) == 0;
717 }
718 return result;
719}
720
721static const int mon_lengths[2][MONSPERYEAR] = {
722 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
723 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
724};
725
726static const int year_lengths[2] = {
727 DAYSPERNYEAR, DAYSPERLYEAR
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800728};
729
730/*
731** Given a pointer into a time zone string, scan until a character that is not
732** a valid character in a zone name is found. Return a pointer to that
733** character.
734*/
735
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700736static const char * ATTRIBUTE_PURE
737getzname(register const char *strp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800738{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700739 register char c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800740
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700741 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
742 c != '+')
743 ++strp;
744 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800745}
746
747/*
748** Given a pointer into an extended time zone string, scan until the ending
749** delimiter of the zone name is located. Return a pointer to the delimiter.
750**
751** As with getzname above, the legal character set is actually quite
752** restricted, with other characters producing undefined results.
753** We don't do any checking here; checking is done later in common-case code.
754*/
755
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700756static const char * ATTRIBUTE_PURE
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800757getqzname(register const char *strp, const int delim)
758{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700759 register int c;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800760
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700761 while ((c = *strp) != '\0' && c != delim)
762 ++strp;
763 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800764}
765
766/*
767** Given a pointer into a time zone string, extract a number from that string.
768** Check that the number is within a specified range; if it is not, return
769** NULL.
770** Otherwise, return a pointer to the first character not part of the number.
771*/
772
773static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700774getnum(register const char *strp, int *const nump, const int min, const int max)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800775{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700776 register char c;
777 register int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800778
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700779 if (strp == NULL || !is_digit(c = *strp))
780 return NULL;
781 num = 0;
782 do {
783 num = num * 10 + (c - '0');
784 if (num > max)
785 return NULL; /* illegal value */
786 c = *++strp;
787 } while (is_digit(c));
788 if (num < min)
789 return NULL; /* illegal value */
790 *nump = num;
791 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800792}
793
794/*
795** Given a pointer into a time zone string, extract a number of seconds,
796** in hh[:mm[:ss]] form, from the string.
797** If any error occurs, return NULL.
798** Otherwise, return a pointer to the first character not part of the number
799** of seconds.
800*/
801
802static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700803getsecs(register const char *strp, int_fast32_t *const secsp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800804{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700805 int num;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800806
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700807 /*
808 ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
809 ** "M10.4.6/26", which does not conform to Posix,
810 ** but which specifies the equivalent of
811 ** "02:00 on the first Sunday on or after 23 Oct".
812 */
813 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
814 if (strp == NULL)
815 return NULL;
816 *secsp = num * (int_fast32_t) SECSPERHOUR;
817 if (*strp == ':') {
818 ++strp;
819 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
820 if (strp == NULL)
821 return NULL;
822 *secsp += num * SECSPERMIN;
823 if (*strp == ':') {
824 ++strp;
825 /* 'SECSPERMIN' allows for leap seconds. */
826 strp = getnum(strp, &num, 0, SECSPERMIN);
827 if (strp == NULL)
828 return NULL;
829 *secsp += num;
830 }
831 }
832 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800833}
834
835/*
836** Given a pointer into a time zone string, extract an offset, in
837** [+-]hh[:mm[:ss]] form, from the string.
838** If any error occurs, return NULL.
839** Otherwise, return a pointer to the first character not part of the time.
840*/
841
842static const char *
Elliott Hughesce4783c2013-07-12 17:31:11 -0700843getoffset(register const char *strp, int_fast32_t *const offsetp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800844{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700845 register bool neg = false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800846
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700847 if (*strp == '-') {
848 neg = true;
849 ++strp;
850 } else if (*strp == '+')
851 ++strp;
852 strp = getsecs(strp, offsetp);
853 if (strp == NULL)
854 return NULL; /* illegal time */
855 if (neg)
856 *offsetp = -*offsetp;
857 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800858}
859
860/*
861** Given a pointer into a time zone string, extract a rule in the form
862** date[/time]. See POSIX section 8 for the format of "date" and "time".
863** If a valid rule is not found, return NULL.
864** Otherwise, return a pointer to the first character not part of the rule.
865*/
866
867static const char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700868getrule(const char *strp, register struct rule *const rulep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800869{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700870 if (*strp == 'J') {
871 /*
872 ** Julian day.
873 */
874 rulep->r_type = JULIAN_DAY;
875 ++strp;
876 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
877 } else if (*strp == 'M') {
878 /*
879 ** Month, week, day.
880 */
881 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
882 ++strp;
883 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
884 if (strp == NULL)
885 return NULL;
886 if (*strp++ != '.')
887 return NULL;
888 strp = getnum(strp, &rulep->r_week, 1, 5);
889 if (strp == NULL)
890 return NULL;
891 if (*strp++ != '.')
892 return NULL;
893 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
894 } else if (is_digit(*strp)) {
895 /*
896 ** Day of year.
897 */
898 rulep->r_type = DAY_OF_YEAR;
899 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
900 } else return NULL; /* invalid format */
901 if (strp == NULL)
902 return NULL;
903 if (*strp == '/') {
904 /*
905 ** Time specified.
906 */
907 ++strp;
908 strp = getoffset(strp, &rulep->r_time);
909 } else rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
910 return strp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800911}
912
913/*
Calin Juravle627d37c2014-02-28 11:46:03 +0000914** Given a year, a rule, and the offset from UT at the time that rule takes
915** effect, calculate the year-relative time that rule takes effect.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800916*/
917
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700918static int_fast32_t ATTRIBUTE_PURE
Calin Juravle627d37c2014-02-28 11:46:03 +0000919transtime(const int year, register const struct rule *const rulep,
Calin Juravled8928922014-02-28 12:18:53 +0000920 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800921{
Elliott Hughes9fb22a32015-10-07 17:13:40 -0700922 register bool leapyear;
Calin Juravled8928922014-02-28 12:18:53 +0000923 register int_fast32_t value;
924 register int i;
925 int d, m1, yy0, yy1, yy2, dow;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800926
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700927 INITIALIZE(value);
928 leapyear = isleap(year);
929 switch (rulep->r_type) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800930
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700931 case JULIAN_DAY:
932 /*
933 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
934 ** years.
935 ** In non-leap years, or if the day number is 59 or less, just
936 ** add SECSPERDAY times the day number-1 to the time of
937 ** January 1, midnight, to get the day.
938 */
Calin Juravled8928922014-02-28 12:18:53 +0000939 value = (rulep->r_day - 1) * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700940 if (leapyear && rulep->r_day >= 60)
941 value += SECSPERDAY;
942 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800943
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700944 case DAY_OF_YEAR:
945 /*
946 ** n - day of year.
947 ** Just add SECSPERDAY times the day number to the time of
948 ** January 1, midnight, to get the day.
949 */
Calin Juravled8928922014-02-28 12:18:53 +0000950 value = rulep->r_day * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700951 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800952
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700953 case MONTH_NTH_DAY_OF_WEEK:
954 /*
955 ** Mm.n.d - nth "dth day" of month m.
956 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800957
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700958 /*
959 ** Use Zeller's Congruence to get day-of-week of first day of
960 ** month.
961 */
962 m1 = (rulep->r_mon + 9) % 12 + 1;
963 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
964 yy1 = yy0 / 100;
965 yy2 = yy0 % 100;
966 dow = ((26 * m1 - 2) / 10 +
967 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
968 if (dow < 0)
969 dow += DAYSPERWEEK;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800970
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700971 /*
972 ** "dow" is the day-of-week of the first day of the month. Get
973 ** the day-of-month (zero-origin) of the first "dow" day of the
974 ** month.
975 */
976 d = rulep->r_day - dow;
977 if (d < 0)
978 d += DAYSPERWEEK;
979 for (i = 1; i < rulep->r_week; ++i) {
980 if (d + DAYSPERWEEK >=
981 mon_lengths[leapyear][rulep->r_mon - 1])
982 break;
983 d += DAYSPERWEEK;
984 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800985
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700986 /*
987 ** "d" is the day-of-month (zero-origin) of the day we want.
988 */
Calin Juravled8928922014-02-28 12:18:53 +0000989 value = d * SECSPERDAY;
990 for (i = 0; i < rulep->r_mon - 1; ++i)
991 value += mon_lengths[leapyear][i] * SECSPERDAY;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700992 break;
993 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800994
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700995 /*
Calin Juravled8928922014-02-28 12:18:53 +0000996 ** "value" is the year-relative time of 00:00:00 UT on the day in
997 ** question. To get the year-relative time of the specified local
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700998 ** time on that day, add the transition time and the current offset
Elliott Hughese0d0b152013-09-27 00:04:30 -0700999 ** from UT.
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001000 */
1001 return value + rulep->r_time + offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001002}
1003
1004/*
1005** Given a POSIX section 8-style TZ string, fill in the rule tables as
1006** appropriate.
1007*/
1008
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001009static bool
1010tzparse(const char *name, struct state *sp, bool lastditch)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001011{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001012 const char * stdname;
1013 const char * dstname;
1014 size_t stdlen;
1015 size_t dstlen;
1016 size_t charcnt;
1017 int_fast32_t stdoffset;
1018 int_fast32_t dstoffset;
1019 register char * cp;
1020 register bool load_ok;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001021
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001022 stdname = name;
1023 if (lastditch) {
1024 stdlen = sizeof gmt - 1;
1025 name += stdlen;
1026 stdoffset = 0;
1027 } else {
1028 if (*name == '<') {
1029 name++;
1030 stdname = name;
1031 name = getqzname(name, '>');
1032 if (*name != '>')
1033 return false;
1034 stdlen = name - stdname;
1035 name++;
1036 } else {
1037 name = getzname(name);
1038 stdlen = name - stdname;
1039 }
1040 if (!stdlen)
1041 return false;
1042 name = getoffset(name, &stdoffset);
1043 if (name == NULL)
1044 return false;
1045 }
1046 charcnt = stdlen + 1;
1047 if (sizeof sp->chars < charcnt)
1048 return false;
1049 load_ok = tzload(TZDEFRULES, sp, false) == 0;
1050 if (!load_ok)
1051 sp->leapcnt = 0; /* so, we're off a little */
1052 if (*name != '\0') {
1053 if (*name == '<') {
1054 dstname = ++name;
1055 name = getqzname(name, '>');
1056 if (*name != '>')
1057 return false;
1058 dstlen = name - dstname;
1059 name++;
1060 } else {
1061 dstname = name;
1062 name = getzname(name);
1063 dstlen = name - dstname; /* length of DST zone name */
1064 }
1065 if (!dstlen)
1066 return false;
1067 charcnt += dstlen + 1;
1068 if (sizeof sp->chars < charcnt)
1069 return false;
1070 if (*name != '\0' && *name != ',' && *name != ';') {
1071 name = getoffset(name, &dstoffset);
1072 if (name == NULL)
1073 return false;
1074 } else dstoffset = stdoffset - SECSPERHOUR;
1075 if (*name == '\0' && !load_ok)
1076 name = TZDEFRULESTRING;
1077 if (*name == ',' || *name == ';') {
1078 struct rule start;
1079 struct rule end;
1080 register int year;
1081 register int yearlim;
1082 register int timecnt;
1083 time_t janfirst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001084
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001085 ++name;
1086 if ((name = getrule(name, &start)) == NULL)
1087 return false;
1088 if (*name++ != ',')
1089 return false;
1090 if ((name = getrule(name, &end)) == NULL)
1091 return false;
1092 if (*name != '\0')
1093 return false;
1094 sp->typecnt = 2; /* standard time and DST */
1095 /*
1096 ** Two transitions per year, from EPOCH_YEAR forward.
1097 */
1098 init_ttinfo(&sp->ttis[0], -dstoffset, true, stdlen + 1);
1099 init_ttinfo(&sp->ttis[1], -stdoffset, false, 0);
1100 sp->defaulttype = 0;
1101 timecnt = 0;
1102 janfirst = 0;
1103 yearlim = EPOCH_YEAR + YEARSPERREPEAT;
1104 for (year = EPOCH_YEAR; year < yearlim; year++) {
1105 int_fast32_t
1106 starttime = transtime(year, &start, stdoffset),
1107 endtime = transtime(year, &end, dstoffset);
1108 int_fast32_t
1109 yearsecs = (year_lengths[isleap(year)]
1110 * SECSPERDAY);
1111 bool reversed = endtime < starttime;
1112 if (reversed) {
1113 int_fast32_t swap = starttime;
1114 starttime = endtime;
1115 endtime = swap;
1116 }
1117 if (reversed
1118 || (starttime < endtime
1119 && (endtime - starttime
1120 < (yearsecs
1121 + (stdoffset - dstoffset))))) {
1122 if (TZ_MAX_TIMES - 2 < timecnt)
1123 break;
1124 yearlim = year + YEARSPERREPEAT + 1;
1125 sp->ats[timecnt] = janfirst;
1126 if (increment_overflow_time
1127 (&sp->ats[timecnt], starttime))
1128 break;
1129 sp->types[timecnt++] = reversed;
1130 sp->ats[timecnt] = janfirst;
1131 if (increment_overflow_time
1132 (&sp->ats[timecnt], endtime))
1133 break;
1134 sp->types[timecnt++] = !reversed;
1135 }
1136 if (increment_overflow_time(&janfirst, yearsecs))
1137 break;
1138 }
1139 sp->timecnt = timecnt;
1140 if (!timecnt)
1141 sp->typecnt = 1; /* Perpetual DST. */
1142 } else {
1143 register int_fast32_t theirstdoffset;
1144 register int_fast32_t theirdstoffset;
1145 register int_fast32_t theiroffset;
1146 register bool isdst;
1147 register int i;
1148 register int j;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001149
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001150 if (*name != '\0')
1151 return false;
1152 /*
1153 ** Initial values of theirstdoffset and theirdstoffset.
1154 */
1155 theirstdoffset = 0;
1156 for (i = 0; i < sp->timecnt; ++i) {
1157 j = sp->types[i];
1158 if (!sp->ttis[j].tt_isdst) {
1159 theirstdoffset =
1160 -sp->ttis[j].tt_gmtoff;
1161 break;
1162 }
1163 }
1164 theirdstoffset = 0;
1165 for (i = 0; i < sp->timecnt; ++i) {
1166 j = sp->types[i];
1167 if (sp->ttis[j].tt_isdst) {
1168 theirdstoffset =
1169 -sp->ttis[j].tt_gmtoff;
1170 break;
1171 }
1172 }
1173 /*
1174 ** Initially we're assumed to be in standard time.
1175 */
1176 isdst = false;
1177 theiroffset = theirstdoffset;
1178 /*
1179 ** Now juggle transition times and types
1180 ** tracking offsets as you do.
1181 */
1182 for (i = 0; i < sp->timecnt; ++i) {
1183 j = sp->types[i];
1184 sp->types[i] = sp->ttis[j].tt_isdst;
1185 if (sp->ttis[j].tt_ttisgmt) {
1186 /* No adjustment to transition time */
1187 } else {
1188 /*
1189 ** If summer time is in effect, and the
1190 ** transition time was not specified as
1191 ** standard time, add the summer time
1192 ** offset to the transition time;
1193 ** otherwise, add the standard time
1194 ** offset to the transition time.
1195 */
1196 /*
1197 ** Transitions from DST to DDST
1198 ** will effectively disappear since
1199 ** POSIX provides for only one DST
1200 ** offset.
1201 */
1202 if (isdst && !sp->ttis[j].tt_ttisstd) {
1203 sp->ats[i] += dstoffset -
1204 theirdstoffset;
1205 } else {
1206 sp->ats[i] += stdoffset -
1207 theirstdoffset;
1208 }
1209 }
1210 theiroffset = -sp->ttis[j].tt_gmtoff;
1211 if (sp->ttis[j].tt_isdst)
1212 theirdstoffset = theiroffset;
1213 else theirstdoffset = theiroffset;
1214 }
1215 /*
1216 ** Finally, fill in ttis.
1217 */
1218 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1219 init_ttinfo(&sp->ttis[1], -dstoffset, true, stdlen + 1);
1220 sp->typecnt = 2;
1221 sp->defaulttype = 0;
1222 }
1223 } else {
1224 dstlen = 0;
1225 sp->typecnt = 1; /* only standard time */
1226 sp->timecnt = 0;
1227 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
1228 sp->defaulttype = 0;
1229 }
1230 sp->charcnt = charcnt;
1231 cp = sp->chars;
1232 memcpy(cp, stdname, stdlen);
1233 cp += stdlen;
1234 *cp++ = '\0';
1235 if (dstlen != 0) {
1236 memcpy(cp, dstname, dstlen);
1237 *(cp + dstlen) = '\0';
1238 }
1239 return true;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001240}
1241
1242static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001243gmtload(struct state *const sp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001244{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001245 if (tzload(gmt, sp, true) != 0)
1246 tzparse(gmt, sp, true);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001247}
1248
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001249/* Initialize *SP to a value appropriate for the TZ setting NAME.
1250 Return 0 on success, an errno value on failure. */
1251static int
1252zoneinit(struct state *sp, char const *name)
1253{
1254 if (name && ! name[0]) {
1255 /*
1256 ** User wants it fast rather than right.
1257 */
1258 sp->leapcnt = 0; /* so, we're off a little */
1259 sp->timecnt = 0;
1260 sp->typecnt = 0;
1261 sp->charcnt = 0;
1262 sp->goback = sp->goahead = false;
1263 init_ttinfo(&sp->ttis[0], 0, false, 0);
1264 strcpy(sp->chars, gmt);
1265 sp->defaulttype = 0;
1266 return 0;
1267 } else {
1268 int err = tzload(name, sp, true);
1269 if (err != 0 && name && name[0] != ':' && tzparse(name, sp, false))
1270 err = 0;
1271 if (err == 0)
1272 scrub_abbrs(sp);
1273 return err;
1274 }
1275}
1276
1277static void
1278tzsetlcl(char const *name)
1279{
1280 struct state *sp = lclptr;
1281 int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
1282 if (lcl < 0
1283 ? lcl_is_set < 0
1284 : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0)
1285 return;
1286#ifdef ALL_STATE
1287 if (! sp)
1288 lclptr = sp = malloc(sizeof *lclptr);
1289#endif /* defined ALL_STATE */
1290 if (sp) {
1291 if (zoneinit(sp, name) != 0)
1292 zoneinit(sp, "");
1293 if (0 < lcl)
1294 strcpy(lcl_TZname, name);
1295 }
1296 settzname();
1297 lcl_is_set = lcl;
1298}
1299
1300#ifdef STD_INSPIRED
Elliott Hughesce4783c2013-07-12 17:31:11 -07001301void
1302tzsetwall(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001303{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001304 if (lock() != 0)
1305 return;
1306 tzsetlcl(NULL);
1307 unlock();
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001308}
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001309#endif
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001310
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001311#if defined(__ANDROID__)
Mark Salyzynd0578942015-10-02 13:15:07 -07001312#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
1313#include <sys/_system_properties.h> // For __system_property_serial.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001314#endif
Elliott Hughesce4783c2013-07-12 17:31:11 -07001315
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001316static void
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001317tzset_unlocked(void)
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001318{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001319#if defined(__ANDROID__)
Elliott Hughesd1c28a32015-11-13 08:38:48 -08001320 // The TZ environment variable is meant to override the system-wide setting.
Elliott Hughes3e3f4a52016-07-20 17:23:54 -07001321 const char* name = getenv("TZ");
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001322
Elliott Hughesd1c28a32015-11-13 08:38:48 -08001323 // If that's not set, look at the "persist.sys.timezone" system property.
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001324 if (name == NULL) {
Elliott Hughes3e3f4a52016-07-20 17:23:54 -07001325 static const prop_info* pi;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001326
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001327 if (!pi) {
1328 pi = __system_property_find("persist.sys.timezone");
Elliott Hughesce4783c2013-07-12 17:31:11 -07001329 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001330 if (pi) {
1331 static char buf[PROP_VALUE_MAX];
1332 static uint32_t s = -1;
1333 static bool ok = false;
1334 uint32_t serial = __system_property_serial(pi);
1335 if (serial != s) {
1336 ok = __system_property_read(pi, 0, buf) > 0;
1337 s = serial;
1338 }
1339 if (ok) {
Elliott Hughes3e3f4a52016-07-20 17:23:54 -07001340 // POSIX and Java disagree about the sign in a timezone string. For POSIX, "GMT+3" means
1341 // "3 hours west/behind", but for Java it means "3 hours east/ahead". Since (a) Java is
1342 // the one that matches human expectations and (b) this system property is used directly
1343 // by Java, we flip the sign here to translate from Java to POSIX. http://b/25463955.
1344 if (buf[3] == '-') {
1345 buf[3] = '+';
1346 } else if (buf[3] == '+') {
1347 buf[3] = '-';
1348 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001349 name = buf;
1350 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001351 }
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001352 }
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001353
Elliott Hughes3e3f4a52016-07-20 17:23:54 -07001354 // If the system property is also not available (because you're running AOSP on a WiFi-only
Elliott Hughesd1c28a32015-11-13 08:38:48 -08001355 // device, say), fall back to GMT.
1356 if (name == NULL) name = gmt;
1357
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001358 tzsetlcl(name);
1359#else
1360 tzsetlcl(getenv("TZ"));
1361#endif
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001362}
1363
1364void
Elliott Hughesce4783c2013-07-12 17:31:11 -07001365tzset(void)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001366{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001367 if (lock() != 0)
1368 return;
1369 tzset_unlocked();
1370 unlock();
1371}
1372
1373static void
1374gmtcheck(void)
1375{
1376 static bool gmt_is_set;
1377 if (lock() != 0)
1378 return;
1379 if (! gmt_is_set) {
1380#ifdef ALL_STATE
1381 gmtptr = malloc(sizeof *gmtptr);
1382#endif
1383 if (gmtptr)
1384 gmtload(gmtptr);
1385 gmt_is_set = true;
1386 }
1387 unlock();
1388}
1389
1390#if NETBSD_INSPIRED
1391
1392timezone_t
1393tzalloc(char const *name)
1394{
1395 timezone_t sp = malloc(sizeof *sp);
1396 if (sp) {
1397 int err = zoneinit(sp, name);
1398 if (err != 0) {
1399 free(sp);
1400 errno = err;
1401 return NULL;
1402 }
1403 }
1404 return sp;
1405}
1406
1407void
1408tzfree(timezone_t sp)
1409{
1410 free(sp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001411}
1412
1413/*
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001414** NetBSD 6.1.4 has ctime_rz, but omit it because POSIX says ctime and
1415** ctime_r are obsolescent and have potential security problems that
1416** ctime_rz would share. Callers can instead use localtime_rz + strftime.
1417**
1418** NetBSD 6.1.4 has tzgetname, but omit it because it doesn't work
1419** in zones with three or more time zone abbreviations.
1420** Callers can instead use localtime_rz + strftime.
1421*/
1422
1423#endif
1424
1425/*
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001426** The easy way to behave "as if no library function calls" localtime
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001427** is to not call it, so we drop its guts into "localsub", which can be
1428** freely called. (And no, the PANS doesn't require the above behavior,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001429** but it *is* desirable.)
1430**
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001431** If successful and SETNAME is nonzero,
1432** set the applicable parts of tzname, timezone and altzone;
1433** however, it's OK to omit this step if the time zone is POSIX-compatible,
1434** since in that case tzset should have already done this step correctly.
1435** SETNAME's type is intfast32_t for compatibility with gmtsub,
1436** but it is actually a boolean and its value should be 0 or 1.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001437*/
1438
1439/*ARGSUSED*/
1440static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001441localsub(struct state const *sp, time_t const *timep, int_fast32_t setname,
1442 struct tm *const tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001443{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001444 register const struct ttinfo * ttisp;
1445 register int i;
1446 register struct tm * result;
1447 const time_t t = *timep;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001448
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001449 if (sp == NULL) {
1450 /* Don't bother to set tzname etc.; tzset has already done it. */
1451 return gmtsub(gmtptr, timep, 0, tmp);
1452 }
1453 if ((sp->goback && t < sp->ats[0]) ||
1454 (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
1455 time_t newt = t;
1456 register time_t seconds;
1457 register time_t years;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001458
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001459 if (t < sp->ats[0])
1460 seconds = sp->ats[0] - t;
1461 else seconds = t - sp->ats[sp->timecnt - 1];
1462 --seconds;
1463 years = (seconds / SECSPERREPEAT + 1) * YEARSPERREPEAT;
1464 seconds = years * AVGSECSPERYEAR;
1465 if (t < sp->ats[0])
1466 newt += seconds;
1467 else newt -= seconds;
1468 if (newt < sp->ats[0] ||
1469 newt > sp->ats[sp->timecnt - 1])
1470 return NULL; /* "cannot happen" */
1471 result = localsub(sp, &newt, setname, tmp);
1472 if (result) {
1473 register int_fast64_t newy;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001474
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001475 newy = result->tm_year;
1476 if (t < sp->ats[0])
1477 newy -= years;
1478 else newy += years;
1479 if (! (INT_MIN <= newy && newy <= INT_MAX))
1480 return NULL;
1481 result->tm_year = newy;
1482 }
1483 return result;
1484 }
1485 if (sp->timecnt == 0 || t < sp->ats[0]) {
1486 i = sp->defaulttype;
1487 } else {
1488 register int lo = 1;
1489 register int hi = sp->timecnt;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001490
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001491 while (lo < hi) {
1492 register int mid = (lo + hi) >> 1;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001493
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001494 if (t < sp->ats[mid])
1495 hi = mid;
1496 else lo = mid + 1;
1497 }
1498 i = (int) sp->types[lo - 1];
1499 }
1500 ttisp = &sp->ttis[i];
1501 /*
1502 ** To get (wrong) behavior that's compatible with System V Release 2.0
1503 ** you'd replace the statement below with
1504 ** t += ttisp->tt_gmtoff;
1505 ** timesub(&t, 0L, sp, tmp);
1506 */
1507 result = timesub(&t, ttisp->tt_gmtoff, sp, tmp);
1508 if (result) {
1509 result->tm_isdst = ttisp->tt_isdst;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001510#ifdef TM_ZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001511 result->TM_ZONE = (char *) &sp->chars[ttisp->tt_abbrind];
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001512#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001513 if (setname)
1514 update_tzname_etc(sp, ttisp);
1515 }
1516 return result;
1517}
1518
1519#if NETBSD_INSPIRED
1520
1521struct tm *
1522localtime_rz(struct state *sp, time_t const *timep, struct tm *tmp)
1523{
1524 return localsub(sp, timep, 0, tmp);
1525}
1526
1527#endif
1528
1529static struct tm *
1530localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
1531{
1532 int err = lock();
1533 if (err) {
1534 errno = err;
1535 return NULL;
1536 }
1537 if (setname || !lcl_is_set)
1538 tzset_unlocked();
1539 tmp = localsub(lclptr, timep, setname, tmp);
1540 unlock();
1541 return tmp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001542}
1543
1544struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001545localtime(const time_t *timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001546{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001547 return localtime_tzset(timep, &tm, true);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001548}
1549
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001550struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001551localtime_r(const time_t *timep, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001552{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001553 return localtime_tzset(timep, tmp, false);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001554}
1555
1556/*
1557** gmtsub is to gmtime as localsub is to localtime.
1558*/
1559
1560static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001561gmtsub(struct state const *sp, time_t const *timep, int_fast32_t offset,
1562 struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001563{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001564 register struct tm * result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001565
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001566 result = timesub(timep, offset, gmtptr, tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001567#ifdef TM_ZONE
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001568 /*
1569 ** Could get fancy here and deliver something such as
1570 ** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
1571 ** but this is no time for a treasure hunt.
1572 */
1573 tmp->TM_ZONE = ((char *)
1574 (offset ? wildabbr : gmtptr ? gmtptr->chars : gmt));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001575#endif /* defined TM_ZONE */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001576 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001577}
1578
1579/*
1580* Re-entrant version of gmtime.
1581*/
1582
1583struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001584gmtime_r(const time_t *timep, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001585{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001586 gmtcheck();
1587 return gmtsub(gmtptr, timep, 0, tmp);
1588}
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001589
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001590struct tm *
1591gmtime(const time_t *timep)
1592{
1593 return gmtime_r(timep, &tm);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001594}
1595
Elliott Hughes906eb992014-06-18 19:46:25 -07001596#ifdef STD_INSPIRED
1597
1598struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001599offtime(const time_t *timep, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07001600{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001601 gmtcheck();
1602 return gmtsub(gmtptr, timep, offset, &tm);
Elliott Hughes906eb992014-06-18 19:46:25 -07001603}
1604
1605#endif /* defined STD_INSPIRED */
1606
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001607/*
1608** Return the number of leap years through the end of the given year
1609** where, to make the math easy, the answer for year zero is defined as zero.
1610*/
1611
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001612static int ATTRIBUTE_PURE
Elliott Hughesce4783c2013-07-12 17:31:11 -07001613leaps_thru_end_of(register const int y)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001614{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001615 return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
1616 -(leaps_thru_end_of(-(y + 1)) + 1);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001617}
1618
1619static struct tm *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001620timesub(const time_t *timep, int_fast32_t offset,
1621 const struct state *sp, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001622{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001623 register const struct lsinfo * lp;
1624 register time_t tdays;
1625 register int idays; /* unsigned would be so 2003 */
1626 register int_fast64_t rem;
1627 int y;
1628 register const int * ip;
1629 register int_fast64_t corr;
1630 register bool hit;
1631 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001632
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001633 corr = 0;
1634 hit = false;
1635 i = (sp == NULL) ? 0 : sp->leapcnt;
1636 while (--i >= 0) {
1637 lp = &sp->lsis[i];
1638 if (*timep >= lp->ls_trans) {
1639 if (*timep == lp->ls_trans) {
1640 hit = ((i == 0 && lp->ls_corr > 0) ||
1641 lp->ls_corr > sp->lsis[i - 1].ls_corr);
1642 if (hit)
1643 while (i > 0 &&
1644 sp->lsis[i].ls_trans ==
1645 sp->lsis[i - 1].ls_trans + 1 &&
1646 sp->lsis[i].ls_corr ==
1647 sp->lsis[i - 1].ls_corr + 1) {
1648 ++hit;
1649 --i;
1650 }
1651 }
1652 corr = lp->ls_corr;
1653 break;
1654 }
1655 }
1656 y = EPOCH_YEAR;
1657 tdays = *timep / SECSPERDAY;
1658 rem = *timep % SECSPERDAY;
1659 while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
1660 int newy;
1661 register time_t tdelta;
1662 register int idelta;
1663 register int leapdays;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001664
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001665 tdelta = tdays / DAYSPERLYEAR;
1666 if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
1667 && tdelta <= INT_MAX))
1668 goto out_of_range;
1669 idelta = tdelta;
1670 if (idelta == 0)
1671 idelta = (tdays < 0) ? -1 : 1;
1672 newy = y;
1673 if (increment_overflow(&newy, idelta))
1674 goto out_of_range;
1675 leapdays = leaps_thru_end_of(newy - 1) -
1676 leaps_thru_end_of(y - 1);
1677 tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
1678 tdays -= leapdays;
1679 y = newy;
1680 }
1681 /*
1682 ** Given the range, we can now fearlessly cast...
1683 */
1684 idays = tdays;
1685 rem += offset - corr;
1686 while (rem < 0) {
1687 rem += SECSPERDAY;
1688 --idays;
1689 }
1690 while (rem >= SECSPERDAY) {
1691 rem -= SECSPERDAY;
1692 ++idays;
1693 }
1694 while (idays < 0) {
1695 if (increment_overflow(&y, -1))
1696 goto out_of_range;
1697 idays += year_lengths[isleap(y)];
1698 }
1699 while (idays >= year_lengths[isleap(y)]) {
1700 idays -= year_lengths[isleap(y)];
1701 if (increment_overflow(&y, 1))
1702 goto out_of_range;
1703 }
1704 tmp->tm_year = y;
1705 if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
1706 goto out_of_range;
1707 tmp->tm_yday = idays;
1708 /*
1709 ** The "extra" mods below avoid overflow problems.
1710 */
1711 tmp->tm_wday = EPOCH_WDAY +
1712 ((y - EPOCH_YEAR) % DAYSPERWEEK) *
1713 (DAYSPERNYEAR % DAYSPERWEEK) +
1714 leaps_thru_end_of(y - 1) -
1715 leaps_thru_end_of(EPOCH_YEAR - 1) +
1716 idays;
1717 tmp->tm_wday %= DAYSPERWEEK;
1718 if (tmp->tm_wday < 0)
1719 tmp->tm_wday += DAYSPERWEEK;
1720 tmp->tm_hour = (int) (rem / SECSPERHOUR);
1721 rem %= SECSPERHOUR;
1722 tmp->tm_min = (int) (rem / SECSPERMIN);
1723 /*
1724 ** A positive leap second requires a special
1725 ** representation. This uses "... ??:59:60" et seq.
1726 */
1727 tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
1728 ip = mon_lengths[isleap(y)];
1729 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
1730 idays -= ip[tmp->tm_mon];
1731 tmp->tm_mday = (int) (idays + 1);
1732 tmp->tm_isdst = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001733#ifdef TM_GMTOFF
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001734 tmp->TM_GMTOFF = offset;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001735#endif /* defined TM_GMTOFF */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001736 return tmp;
1737
1738 out_of_range:
1739 errno = EOVERFLOW;
1740 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001741}
1742
1743char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001744ctime(const time_t *timep)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001745{
1746/*
1747** Section 4.12.3.2 of X3.159-1989 requires that
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001748** The ctime function converts the calendar time pointed to by timer
1749** to local time in the form of a string. It is equivalent to
1750** asctime(localtime(timer))
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001751*/
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001752 struct tm *tmp = localtime(timep);
1753 return tmp ? asctime(tmp) : NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001754}
1755
1756char *
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001757ctime_r(const time_t *timep, char *buf)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001758{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001759 struct tm mytm;
1760 struct tm *tmp = localtime_r(timep, &mytm);
1761 return tmp ? asctime_r(tmp, buf) : NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001762}
1763
1764/*
1765** Adapted from code provided by Robert Elz, who writes:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001766** The "best" way to do mktime I think is based on an idea of Bob
1767** Kridle's (so its said...) from a long time ago.
1768** It does a binary search of the time_t space. Since time_t's are
1769** just 32 bits, its a max of 32 iterations (even at 64 bits it
1770** would still be very reasonable).
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001771*/
1772
1773#ifndef WRONG
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001774#define WRONG (-1)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001775#endif /* !defined WRONG */
1776
1777/*
Elliott Hughesce4783c2013-07-12 17:31:11 -07001778** Normalize logic courtesy Paul Eggert.
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001779*/
1780
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001781static bool
1782increment_overflow(int *ip, int j)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001783{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001784 register int const i = *ip;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001785
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001786 /*
1787 ** If i >= 0 there can only be overflow if i + j > INT_MAX
1788 ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
1789 ** If i < 0 there can only be overflow if i + j < INT_MIN
1790 ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
1791 */
1792 if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
1793 return true;
1794 *ip += j;
1795 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001796}
1797
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001798static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001799increment_overflow32(int_fast32_t *const lp, int const m)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001800{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001801 register int_fast32_t const l = *lp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001802
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001803 if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
1804 return true;
1805 *lp += m;
1806 return false;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001807}
1808
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001809static bool
Calin Juravle627d37c2014-02-28 11:46:03 +00001810increment_overflow_time(time_t *tp, int_fast32_t j)
1811{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001812 /*
1813 ** This is like
1814 ** 'if (! (time_t_min <= *tp + j && *tp + j <= time_t_max)) ...',
1815 ** except that it does the right thing even if *tp + j would overflow.
1816 */
1817 if (! (j < 0
1818 ? (TYPE_SIGNED(time_t) ? time_t_min - j <= *tp : -1 - j < *tp)
1819 : *tp <= time_t_max - j))
1820 return true;
1821 *tp += j;
1822 return false;
Calin Juravle627d37c2014-02-28 11:46:03 +00001823}
1824
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001825static bool
Elliott Hughesce4783c2013-07-12 17:31:11 -07001826normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001827{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001828 register int tensdelta;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001829
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001830 tensdelta = (*unitsptr >= 0) ?
1831 (*unitsptr / base) :
1832 (-1 - (-1 - *unitsptr) / base);
1833 *unitsptr -= tensdelta * base;
1834 return increment_overflow(tensptr, tensdelta);
1835}
1836
1837static bool
1838normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base)
1839{
1840 register int tensdelta;
1841
1842 tensdelta = (*unitsptr >= 0) ?
1843 (*unitsptr / base) :
1844 (-1 - (-1 - *unitsptr) / base);
1845 *unitsptr -= tensdelta * base;
1846 return increment_overflow32(tensptr, tensdelta);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001847}
1848
1849static int
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001850tmcomp(register const struct tm *const atmp,
1851 register const struct tm *const btmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001852{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001853 register int result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001854
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001855 if (atmp->tm_year != btmp->tm_year)
1856 return atmp->tm_year < btmp->tm_year ? -1 : 1;
1857 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1858 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1859 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1860 (result = (atmp->tm_min - btmp->tm_min)) == 0)
1861 result = atmp->tm_sec - btmp->tm_sec;
1862 return result;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001863}
1864
1865static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001866time2sub(struct tm *const tmp,
1867 struct tm *(*funcp)(struct state const *, time_t const *,
1868 int_fast32_t, struct tm *),
1869 struct state const *sp,
1870 const int_fast32_t offset,
1871 bool *okayp,
1872 bool do_norm_secs)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001873{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001874 register int dir;
1875 register int i, j;
1876 register int saved_seconds;
1877 register int_fast32_t li;
1878 register time_t lo;
1879 register time_t hi;
1880 int_fast32_t y;
1881 time_t newt;
1882 time_t t;
1883 struct tm yourtm, mytm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001884
Elliott Hughes9fb22a32015-10-07 17:13:40 -07001885 *okayp = false;
1886 yourtm = *tmp;
1887 if (do_norm_secs) {
1888 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
1889 SECSPERMIN))
1890 return WRONG;
1891 }
1892 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
1893 return WRONG;
1894 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
1895 return WRONG;
1896 y = yourtm.tm_year;
1897 if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
1898 return WRONG;
1899 /*
1900 ** Turn y into an actual year number for now.
1901 ** It is converted back to an offset from TM_YEAR_BASE later.
1902 */
1903 if (increment_overflow32(&y, TM_YEAR_BASE))
1904 return WRONG;
1905 while (yourtm.tm_mday <= 0) {
1906 if (increment_overflow32(&y, -1))
1907 return WRONG;
1908 li = y + (1 < yourtm.tm_mon);
1909 yourtm.tm_mday += year_lengths[isleap(li)];
1910 }
1911 while (yourtm.tm_mday > DAYSPERLYEAR) {
1912 li = y + (1 < yourtm.tm_mon);
1913 yourtm.tm_mday -= year_lengths[isleap(li)];
1914 if (increment_overflow32(&y, 1))
1915 return WRONG;
1916 }
1917 for ( ; ; ) {
1918 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1919 if (yourtm.tm_mday <= i)
1920 break;
1921 yourtm.tm_mday -= i;
1922 if (++yourtm.tm_mon >= MONSPERYEAR) {
1923 yourtm.tm_mon = 0;
1924 if (increment_overflow32(&y, 1))
1925 return WRONG;
1926 }
1927 }
1928 if (increment_overflow32(&y, -TM_YEAR_BASE))
1929 return WRONG;
1930 if (! (INT_MIN <= y && y <= INT_MAX))
1931 return WRONG;
1932 yourtm.tm_year = y;
1933 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
1934 saved_seconds = 0;
1935 else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
1936 /*
1937 ** We can't set tm_sec to 0, because that might push the
1938 ** time below the minimum representable time.
1939 ** Set tm_sec to 59 instead.
1940 ** This assumes that the minimum representable time is
1941 ** not in the same minute that a leap second was deleted from,
1942 ** which is a safer assumption than using 58 would be.
1943 */
1944 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
1945 return WRONG;
1946 saved_seconds = yourtm.tm_sec;
1947 yourtm.tm_sec = SECSPERMIN - 1;
1948 } else {
1949 saved_seconds = yourtm.tm_sec;
1950 yourtm.tm_sec = 0;
1951 }
1952 /*
1953 ** Do a binary search (this works whatever time_t's type is).
1954 */
1955 lo = time_t_min;
1956 hi = time_t_max;
1957 for ( ; ; ) {
1958 t = lo / 2 + hi / 2;
1959 if (t < lo)
1960 t = lo;
1961 else if (t > hi)
1962 t = hi;
1963 if (! funcp(sp, &t, offset, &mytm)) {
1964 /*
1965 ** Assume that t is too extreme to be represented in
1966 ** a struct tm; arrange things so that it is less
1967 ** extreme on the next pass.
1968 */
1969 dir = (t > 0) ? 1 : -1;
1970 } else dir = tmcomp(&mytm, &yourtm);
1971 if (dir != 0) {
1972 if (t == lo) {
1973 if (t == time_t_max)
1974 return WRONG;
1975 ++t;
1976 ++lo;
1977 } else if (t == hi) {
1978 if (t == time_t_min)
1979 return WRONG;
1980 --t;
1981 --hi;
1982 }
1983 if (lo > hi)
1984 return WRONG;
1985 if (dir > 0)
1986 hi = t;
1987 else lo = t;
1988 continue;
1989 }
1990#if defined TM_GMTOFF && ! UNINIT_TRAP
1991 if (mytm.TM_GMTOFF != yourtm.TM_GMTOFF
1992 && (yourtm.TM_GMTOFF < 0
1993 ? (-SECSPERDAY <= yourtm.TM_GMTOFF
1994 && (mytm.TM_GMTOFF <=
1995 (SMALLEST (INT_FAST32_MAX, LONG_MAX)
1996 + yourtm.TM_GMTOFF)))
1997 : (yourtm.TM_GMTOFF <= SECSPERDAY
1998 && ((BIGGEST (INT_FAST32_MIN, LONG_MIN)
1999 + yourtm.TM_GMTOFF)
2000 <= mytm.TM_GMTOFF)))) {
2001 /* MYTM matches YOURTM except with the wrong UTC offset.
2002 YOURTM.TM_GMTOFF is plausible, so try it instead.
2003 It's OK if YOURTM.TM_GMTOFF contains uninitialized data,
2004 since the guess gets checked. */
2005 time_t altt = t;
2006 int_fast32_t diff = mytm.TM_GMTOFF - yourtm.TM_GMTOFF;
2007 if (!increment_overflow_time(&altt, diff)) {
2008 struct tm alttm;
2009 if (funcp(sp, &altt, offset, &alttm)
2010 && alttm.tm_isdst == mytm.tm_isdst
2011 && alttm.TM_GMTOFF == yourtm.TM_GMTOFF
2012 && tmcomp(&alttm, &yourtm) == 0) {
2013 t = altt;
2014 mytm = alttm;
2015 }
2016 }
2017 }
2018#endif
2019 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
2020 break;
2021 /*
2022 ** Right time, wrong type.
2023 ** Hunt for right time, right type.
2024 ** It's okay to guess wrong since the guess
2025 ** gets checked.
2026 */
2027 if (sp == NULL)
2028 return WRONG;
2029 for (i = sp->typecnt - 1; i >= 0; --i) {
2030 if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
2031 continue;
2032 for (j = sp->typecnt - 1; j >= 0; --j) {
2033 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
2034 continue;
2035 newt = t + sp->ttis[j].tt_gmtoff -
2036 sp->ttis[i].tt_gmtoff;
2037 if (! funcp(sp, &newt, offset, &mytm))
2038 continue;
2039 if (tmcomp(&mytm, &yourtm) != 0)
2040 continue;
2041 if (mytm.tm_isdst != yourtm.tm_isdst)
2042 continue;
2043 /*
2044 ** We have a match.
2045 */
2046 t = newt;
2047 goto label;
2048 }
2049 }
2050 return WRONG;
2051 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002052label:
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002053 newt = t + saved_seconds;
2054 if ((newt < t) != (saved_seconds < 0))
2055 return WRONG;
2056 t = newt;
2057 if (funcp(sp, &t, offset, tmp))
2058 *okayp = true;
2059 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002060}
2061
2062static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002063time2(struct tm * const tmp,
2064 struct tm *(*funcp)(struct state const *, time_t const *,
2065 int_fast32_t, struct tm *),
2066 struct state const *sp,
Elliott Hughesce4783c2013-07-12 17:31:11 -07002067 const int_fast32_t offset,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002068 bool *okayp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002069{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002070 time_t t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002071
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002072 /*
2073 ** First try without normalization of seconds
2074 ** (in case tm_sec contains a value associated with a leap second).
2075 ** If that fails, try with normalization of seconds.
2076 */
2077 t = time2sub(tmp, funcp, sp, offset, okayp, false);
2078 return *okayp ? t : time2sub(tmp, funcp, sp, offset, okayp, true);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002079}
2080
2081static time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002082time1(struct tm *const tmp,
2083 struct tm *(*funcp) (struct state const *, time_t const *,
2084 int_fast32_t, struct tm *),
2085 struct state const *sp,
2086 const int_fast32_t offset)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002087{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002088 register time_t t;
2089 register int samei, otheri;
2090 register int sameind, otherind;
2091 register int i;
2092 register int nseen;
2093 char seen[TZ_MAX_TYPES];
2094 unsigned char types[TZ_MAX_TYPES];
2095 bool okay;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002096
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002097 if (tmp == NULL) {
2098 errno = EINVAL;
2099 return WRONG;
2100 }
2101 if (tmp->tm_isdst > 1)
2102 tmp->tm_isdst = 1;
2103 t = time2(tmp, funcp, sp, offset, &okay);
2104 if (okay)
2105 return t;
2106 if (tmp->tm_isdst < 0)
Elliott Hughes906eb992014-06-18 19:46:25 -07002107#ifdef PCTS
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002108 /*
2109 ** POSIX Conformance Test Suite code courtesy Grant Sullivan.
2110 */
2111 tmp->tm_isdst = 0; /* reset to std and try again */
Elliott Hughes906eb992014-06-18 19:46:25 -07002112#else
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002113 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002114#endif /* !defined PCTS */
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002115 /*
2116 ** We're supposed to assume that somebody took a time of one type
2117 ** and did some math on it that yielded a "struct tm" that's bad.
2118 ** We try to divine the type they started from and adjust to the
2119 ** type they need.
2120 */
2121 if (sp == NULL)
2122 return WRONG;
2123 for (i = 0; i < sp->typecnt; ++i)
2124 seen[i] = false;
2125 nseen = 0;
2126 for (i = sp->timecnt - 1; i >= 0; --i)
2127 if (!seen[sp->types[i]]) {
2128 seen[sp->types[i]] = true;
2129 types[nseen++] = sp->types[i];
2130 }
2131 for (sameind = 0; sameind < nseen; ++sameind) {
2132 samei = types[sameind];
2133 if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
2134 continue;
2135 for (otherind = 0; otherind < nseen; ++otherind) {
2136 otheri = types[otherind];
2137 if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
2138 continue;
2139 tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
2140 sp->ttis[samei].tt_gmtoff;
2141 tmp->tm_isdst = !tmp->tm_isdst;
2142 t = time2(tmp, funcp, sp, offset, &okay);
2143 if (okay)
2144 return t;
2145 tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
2146 sp->ttis[samei].tt_gmtoff;
2147 tmp->tm_isdst = !tmp->tm_isdst;
2148 }
2149 }
2150 return WRONG;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002151}
2152
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002153static time_t
2154mktime_tzname(struct state *sp, struct tm *tmp, bool setname)
2155{
2156 if (sp)
2157 return time1(tmp, localsub, sp, setname);
2158 else {
2159 gmtcheck();
2160 return time1(tmp, gmtsub, gmtptr, 0);
2161 }
2162}
2163
2164#if NETBSD_INSPIRED
2165
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002166time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002167mktime_z(struct state *sp, struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002168{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002169 return mktime_tzname(sp, tmp, false);
2170}
2171
2172#endif
2173
2174time_t
2175mktime(struct tm *tmp)
2176{
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002177#if __ANDROID__
2178 int saved_errno = errno;
2179#endif
2180
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002181 time_t t;
2182 int err = lock();
2183 if (err) {
2184 errno = err;
2185 return -1;
2186 }
2187 tzset_unlocked();
2188 t = mktime_tzname(lclptr, tmp, true);
2189 unlock();
Elliott Hughesf8ebaa42016-08-12 16:28:36 -07002190
2191#if __ANDROID__
2192 errno = (t == -1) ? EOVERFLOW : saved_errno;
2193#endif
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002194 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002195}
2196
2197#ifdef STD_INSPIRED
2198
2199time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002200timelocal(struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002201{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002202 if (tmp != NULL)
2203 tmp->tm_isdst = -1; /* in case it wasn't initialized */
2204 return mktime(tmp);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002205}
2206
2207time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002208timegm(struct tm *tmp)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002209{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002210 return timeoff(tmp, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002211}
2212
Elliott Hughes906eb992014-06-18 19:46:25 -07002213time_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002214timeoff(struct tm *tmp, long offset)
Elliott Hughes906eb992014-06-18 19:46:25 -07002215{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002216 if (tmp)
2217 tmp->tm_isdst = 0;
2218 gmtcheck();
2219 return time1(tmp, gmtsub, gmtptr, offset);
Elliott Hughes906eb992014-06-18 19:46:25 -07002220}
2221
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002222#endif /* defined STD_INSPIRED */
2223
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002224/*
2225** XXX--is the below the right way to conditionalize??
2226*/
2227
2228#ifdef STD_INSPIRED
2229
2230/*
2231** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
2232** shall correspond to "Wed Dec 31 23:59:59 UTC 1986", which
2233** is not the case if we are accounting for leap seconds.
2234** So, we provide the following conversion routines for use
2235** when exchanging timestamps with POSIX conforming systems.
2236*/
2237
Elliott Hughesce4783c2013-07-12 17:31:11 -07002238static int_fast64_t
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002239leapcorr(struct state const *sp, time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002240{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002241 register struct lsinfo const * lp;
2242 register int i;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002243
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002244 i = sp->leapcnt;
2245 while (--i >= 0) {
2246 lp = &sp->lsis[i];
2247 if (t >= lp->ls_trans)
2248 return lp->ls_corr;
2249 }
2250 return 0;
2251}
2252
2253NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
2254time2posix_z(struct state *sp, time_t t)
2255{
2256 return t - leapcorr(sp, t);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002257}
2258
2259time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002260time2posix(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002261{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002262 int err = lock();
2263 if (err) {
2264 errno = err;
2265 return -1;
2266 }
2267 if (!lcl_is_set)
2268 tzset_unlocked();
2269 if (lclptr)
2270 t = time2posix_z(lclptr, t);
2271 unlock();
2272 return t;
2273}
2274
2275NETBSD_INSPIRED_EXTERN time_t ATTRIBUTE_PURE
2276posix2time_z(struct state *sp, time_t t)
2277{
2278 time_t x;
2279 time_t y;
2280 /*
2281 ** For a positive leap second hit, the result
2282 ** is not unique. For a negative leap second
2283 ** hit, the corresponding time doesn't exist,
2284 ** so we return an adjacent second.
2285 */
2286 x = t + leapcorr(sp, t);
2287 y = x - leapcorr(sp, x);
2288 if (y < t) {
2289 do {
2290 x++;
2291 y = x - leapcorr(sp, x);
2292 } while (y < t);
2293 x -= y != t;
2294 } else if (y > t) {
2295 do {
2296 --x;
2297 y = x - leapcorr(sp, x);
2298 } while (y > t);
2299 x += y != t;
2300 }
2301 return x;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002302}
2303
2304time_t
Elliott Hughesce4783c2013-07-12 17:31:11 -07002305posix2time(time_t t)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002306{
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002307 int err = lock();
2308 if (err) {
2309 errno = err;
2310 return -1;
2311 }
2312 if (!lcl_is_set)
2313 tzset_unlocked();
2314 if (lclptr)
2315 t = posix2time_z(lclptr, t);
2316 unlock();
2317 return t;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08002318}
2319
2320#endif /* defined STD_INSPIRED */
Elliott Hughesd23af232012-10-17 16:30:47 -07002321
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002322#ifdef time_tz
2323
2324/* Convert from the underlying system's time_t to the ersatz time_tz,
2325 which is called 'time_t' in this file. */
2326
2327time_t
2328time(time_t *p)
2329{
2330 time_t r = sys_time(0);
2331 if (p)
2332 *p = r;
2333 return r;
2334}
2335
2336#endif
2337
Elliott Hughesce4783c2013-07-12 17:31:11 -07002338// BEGIN android-added
2339
Elliott Hughes1c295722012-10-19 18:13:15 -07002340#include <assert.h>
Elliott Hughesd23af232012-10-17 16:30:47 -07002341#include <stdint.h>
Elliott Hughes8b954042012-10-18 13:42:59 -07002342#include <arpa/inet.h> // For ntohl(3).
Elliott Hughesd23af232012-10-17 16:30:47 -07002343
Elliott Hughescf178bf2013-09-18 19:25:28 -07002344static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002345 const char* olson_id) {
Elliott Hughescf178bf2013-09-18 19:25:28 -07002346 const char* path_prefix = getenv(path_prefix_variable);
2347 if (path_prefix == NULL) {
2348 fprintf(stderr, "%s: %s not set!\n", __FUNCTION__, path_prefix_variable);
2349 return -1;
2350 }
Elliott Hughes329103d2014-04-25 16:55:04 -07002351 size_t path_length = strlen(path_prefix) + 1 + strlen(path_suffix) + 1;
2352 char* path = malloc(path_length);
2353 if (path == NULL) {
2354 fprintf(stderr, "%s: couldn't allocate %zu-byte path\n", __FUNCTION__, path_length);
2355 return -1;
2356 }
2357 snprintf(path, path_length, "%s/%s", path_prefix, path_suffix);
Elliott Hughes1c295722012-10-19 18:13:15 -07002358 int fd = TEMP_FAILURE_RETRY(open(path, OPEN_MODE));
Elliott Hughesd23af232012-10-17 16:30:47 -07002359 if (fd == -1) {
Elliott Hughes329103d2014-04-25 16:55:04 -07002360 free(path);
Elliott Hughes1c295722012-10-19 18:13:15 -07002361 return -2; // Distinguish failure to find any data from failure to find a specific id.
Elliott Hughesd23af232012-10-17 16:30:47 -07002362 }
2363
2364 // byte[12] tzdata_version -- "tzdata2012f\0"
Elliott Hughesd23af232012-10-17 16:30:47 -07002365 // int index_offset
2366 // int data_offset
2367 // int zonetab_offset
2368 struct bionic_tzdata_header {
2369 char tzdata_version[12];
Elliott Hughesd23af232012-10-17 16:30:47 -07002370 int32_t index_offset;
2371 int32_t data_offset;
2372 int32_t zonetab_offset;
2373 } header;
Elliott Hughese7aaad82013-04-25 14:02:59 -07002374 memset(&header, 0, sizeof(header));
2375 ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header)));
2376 if (bytes_read != sizeof(header)) {
2377 fprintf(stderr, "%s: could not read header of \"%s\": %s\n",
2378 __FUNCTION__, path, (bytes_read == -1) ? strerror(errno) : "short read");
Elliott Hughes329103d2014-04-25 16:55:04 -07002379 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002380 close(fd);
2381 return -1;
2382 }
2383
2384 if (strncmp(header.tzdata_version, "tzdata", 6) != 0 || header.tzdata_version[11] != 0) {
Elliott Hughese7aaad82013-04-25 14:02:59 -07002385 fprintf(stderr, "%s: bad magic in \"%s\": \"%.6s\"\n",
2386 __FUNCTION__, path, header.tzdata_version);
Elliott Hughes329103d2014-04-25 16:55:04 -07002387 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002388 close(fd);
2389 return -1;
2390 }
Elliott Hughesd23af232012-10-17 16:30:47 -07002391
2392#if 0
Elliott Hughes23935352012-10-22 14:47:58 -07002393 fprintf(stderr, "version: %s\n", header.tzdata_version);
Elliott Hughesd23af232012-10-17 16:30:47 -07002394 fprintf(stderr, "index_offset = %d\n", ntohl(header.index_offset));
2395 fprintf(stderr, "data_offset = %d\n", ntohl(header.data_offset));
2396 fprintf(stderr, "zonetab_offset = %d\n", ntohl(header.zonetab_offset));
2397#endif
2398
2399 if (TEMP_FAILURE_RETRY(lseek(fd, ntohl(header.index_offset), SEEK_SET)) == -1) {
Elliott Hughese7aaad82013-04-25 14:02:59 -07002400 fprintf(stderr, "%s: couldn't seek to index in \"%s\": %s\n",
2401 __FUNCTION__, path, strerror(errno));
Elliott Hughes329103d2014-04-25 16:55:04 -07002402 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002403 close(fd);
2404 return -1;
2405 }
2406
2407 off_t specific_zone_offset = -1;
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002408 ssize_t index_size = ntohl(header.data_offset) - ntohl(header.index_offset);
2409 char* index = malloc(index_size);
Elliott Hughes329103d2014-04-25 16:55:04 -07002410 if (index == NULL) {
2411 fprintf(stderr, "%s: couldn't allocate %zd-byte index for \"%s\"\n",
2412 __FUNCTION__, index_size, path);
2413 free(path);
2414 close(fd);
2415 return -1;
2416 }
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002417 if (TEMP_FAILURE_RETRY(read(fd, index, index_size)) != index_size) {
2418 fprintf(stderr, "%s: could not read index of \"%s\": %s\n",
2419 __FUNCTION__, path, (bytes_read == -1) ? strerror(errno) : "short read");
Elliott Hughes329103d2014-04-25 16:55:04 -07002420 free(path);
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002421 free(index);
2422 close(fd);
2423 return -1;
2424 }
Elliott Hughesd23af232012-10-17 16:30:47 -07002425
Elliott Hughes1c295722012-10-19 18:13:15 -07002426 static const size_t NAME_LENGTH = 40;
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002427 struct index_entry_t {
2428 char buf[NAME_LENGTH];
2429 int32_t start;
2430 int32_t length;
Elliott Hughes13bab432014-08-06 15:23:11 -07002431 int32_t unused; // Was raw GMT offset; always 0 since tzdata2014f (L).
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002432 };
Elliott Hughese0175ca2013-03-14 14:38:08 -07002433
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002434 size_t id_count = (ntohl(header.data_offset) - ntohl(header.index_offset)) / sizeof(struct index_entry_t);
2435 struct index_entry_t* entry = (struct index_entry_t*) index;
Elliott Hughese0175ca2013-03-14 14:38:08 -07002436 for (size_t i = 0; i < id_count; ++i) {
Elliott Hughes1c295722012-10-19 18:13:15 -07002437 char this_id[NAME_LENGTH + 1];
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002438 memcpy(this_id, entry->buf, NAME_LENGTH);
Elliott Hughes1c295722012-10-19 18:13:15 -07002439 this_id[NAME_LENGTH] = '\0';
Elliott Hughesd23af232012-10-17 16:30:47 -07002440
2441 if (strcmp(this_id, olson_id) == 0) {
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002442 specific_zone_offset = ntohl(entry->start) + ntohl(header.data_offset);
Elliott Hughesd23af232012-10-17 16:30:47 -07002443 break;
2444 }
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002445
2446 ++entry;
Elliott Hughesd23af232012-10-17 16:30:47 -07002447 }
Elliott Hughesfd3a9fb2014-02-27 18:18:25 -08002448 free(index);
Elliott Hughesd23af232012-10-17 16:30:47 -07002449
2450 if (specific_zone_offset == -1) {
Elliott Hughes329103d2014-04-25 16:55:04 -07002451 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002452 close(fd);
2453 return -1;
2454 }
2455
2456 if (TEMP_FAILURE_RETRY(lseek(fd, specific_zone_offset, SEEK_SET)) == -1) {
Elliott Hughese7aaad82013-04-25 14:02:59 -07002457 fprintf(stderr, "%s: could not seek to %ld in \"%s\": %s\n",
2458 __FUNCTION__, specific_zone_offset, path, strerror(errno));
Elliott Hughes329103d2014-04-25 16:55:04 -07002459 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002460 close(fd);
2461 return -1;
2462 }
2463
Elliott Hughese7aaad82013-04-25 14:02:59 -07002464 // TODO: check that there's TZ_MAGIC at this offset, so we can fall back to the other file if not.
2465
Elliott Hughes329103d2014-04-25 16:55:04 -07002466 free(path);
Elliott Hughesd23af232012-10-17 16:30:47 -07002467 return fd;
2468}
Elliott Hughes1c295722012-10-19 18:13:15 -07002469
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002470static int __bionic_open_tzdata(const char* olson_id) {
2471 int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata", olson_id);
Neil Fuller1f95ffe2015-03-02 17:43:42 +00002472 if (fd < 0) {
Elliott Hughes9fb22a32015-10-07 17:13:40 -07002473 fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id);
Neil Fuller1f95ffe2015-03-02 17:43:42 +00002474 if (fd == -2) {
2475 // The first thing that 'recovery' does is try to format the current time. It doesn't have
2476 // any tzdata available, so we must not abort here --- doing so breaks the recovery image!
2477 fprintf(stderr, "%s: couldn't find any tzdata when looking for %s!\n", __FUNCTION__, olson_id);
2478 }
Elliott Hughes1c295722012-10-19 18:13:15 -07002479 }
2480 return fd;
2481}
Elliott Hughesce4783c2013-07-12 17:31:11 -07002482
Elliott Hughesce4783c2013-07-12 17:31:11 -07002483// END android-added