* time/tzfile.c (__tzfile_read): Extend to handle new file format
[platform/upstream/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991-1993,1995-2001,2003,2004,2006
2    Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdio_ext.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29
30 #define NOID
31 #include <timezone/tzfile.h>
32
33 int __use_tzfile;
34 static dev_t tzfile_dev;
35 static ino64_t tzfile_ino;
36 static time_t tzfile_mtime;
37
38 struct ttinfo
39   {
40     long int offset;            /* Seconds east of GMT.  */
41     unsigned char isdst;        /* Used to set tm_isdst.  */
42     unsigned char idx;          /* Index into `zone_names'.  */
43     unsigned char isstd;        /* Transition times are in standard time.  */
44     unsigned char isgmt;        /* Transition times are in GMT.  */
45   };
46
47 struct leap
48   {
49     time_t transition;          /* Time the transition takes effect.  */
50     long int change;            /* Seconds of correction to apply.  */
51   };
52
53 static struct ttinfo *find_transition (time_t timer) internal_function;
54 static void compute_tzname_max (size_t) internal_function;
55
56 static size_t num_transitions;
57 libc_freeres_ptr (static time_t *transitions);
58 static unsigned char *type_idxs;
59 static size_t num_types;
60 static struct ttinfo *types;
61 static char *zone_names;
62 static long int rule_stdoff;
63 static long int rule_dstoff;
64 static size_t num_leaps;
65 static struct leap *leaps;
66
67 #include <endian.h>
68 #include <byteswap.h>
69
70 /* Decode the four bytes at PTR as a signed integer in network byte order.  */
71 static inline int
72 __attribute ((always_inline))
73 decode (const void *ptr)
74 {
75   if (BYTE_ORDER == BIG_ENDIAN && sizeof (int) == 4)
76     return *(const int *) ptr;
77   if (sizeof (int) == 4)
78     return bswap_32 (*(const int *) ptr);
79
80   const unsigned char *p = ptr;
81   int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
82
83   result = (result << 8) | *p++;
84   result = (result << 8) | *p++;
85   result = (result << 8) | *p++;
86   result = (result << 8) | *p++;
87
88   return result;
89 }
90
91
92 static inline int64_t
93 __attribute ((always_inline))
94 decode64 (const void *ptr)
95 {
96   if ((BYTE_ORDER == BIG_ENDIAN))
97     return *(const int64_t *) ptr;
98
99   return bswap_64 (*(const int64_t *) ptr);
100 }
101
102
103 void
104 __tzfile_read (const char *file, size_t extra, char **extrap)
105 {
106   static const char default_tzdir[] = TZDIR;
107   size_t num_isstd, num_isgmt;
108   register FILE *f;
109   struct tzhead tzhead;
110   size_t chars;
111   register size_t i;
112   size_t total_size;
113   size_t types_idx;
114   size_t leaps_idx;
115   int was_using_tzfile = __use_tzfile;
116   int trans_width = 4;
117
118   if (sizeof (time_t) != 4 && sizeof (time_t) != 8)
119     abort ();
120
121   __use_tzfile = 0;
122
123   if (file == NULL)
124     /* No user specification; use the site-wide default.  */
125     file = TZDEFAULT;
126   else if (*file == '\0')
127     /* User specified the empty string; use UTC with no leap seconds.  */
128     goto ret_free_transitions;
129   else
130     {
131       /* We must not allow to read an arbitrary file in a setuid
132          program.  So we fail for any file which is not in the
133          directory hierachy starting at TZDIR
134          and which is not the system wide default TZDEFAULT.  */
135       if (__libc_enable_secure
136           && ((*file == '/'
137                && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
138                && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
139               || strstr (file, "../") != NULL))
140         /* This test is certainly a bit too restrictive but it should
141            catch all critical cases.  */
142         goto ret_free_transitions;
143     }
144
145   if (*file != '/')
146     {
147       const char *tzdir;
148       unsigned int len, tzdir_len;
149       char *new, *tmp;
150
151       tzdir = getenv ("TZDIR");
152       if (tzdir == NULL || *tzdir == '\0')
153         {
154           tzdir = default_tzdir;
155           tzdir_len = sizeof (default_tzdir) - 1;
156         }
157       else
158         tzdir_len = strlen (tzdir);
159       len = strlen (file) + 1;
160       new = (char *) __alloca (tzdir_len + 1 + len);
161       tmp = __mempcpy (new, tzdir, tzdir_len);
162       *tmp++ = '/';
163       memcpy (tmp, file, len);
164       file = new;
165     }
166
167   /* If we were already using tzfile, check whether the file changed.  */
168   struct stat64 st;
169   if (was_using_tzfile
170       && stat64 (file, &st) == 0
171       && tzfile_ino == st.st_ino && tzfile_dev == st.st_dev
172       && tzfile_mtime == st.st_mtime)
173     {
174       /* Nothing to do.  */
175       __use_tzfile = 1;
176       return;
177     }
178
179   /* Note the file is opened with cancellation in the I/O functions
180      disabled.  */
181   f = fopen (file, "rc");
182   if (f == NULL)
183     goto ret_free_transitions;
184
185   /* Get information about the file we are actually using.  */
186   if (fstat64 (fileno (f), &st) != 0)
187     {
188       fclose (f);
189       goto ret_free_transitions;
190     }
191
192   free ((void *) transitions);
193   transitions = NULL;
194
195   /* Remember the inode and device number and modification time.  */
196   tzfile_dev = st.st_dev;
197   tzfile_ino = st.st_ino;
198   tzfile_mtime = st.st_mtime;
199
200   /* No threads reading this stream.  */
201   __fsetlocking (f, FSETLOCKING_BYCALLER);
202
203  read_again:
204   if (__builtin_expect (fread_unlocked ((void *) &tzhead, sizeof (tzhead),
205                                         1, f) != 1, 0)
206       || memcmp (tzhead.tzh_magic, TZ_MAGIC, sizeof (tzhead.tzh_magic)) != 0)
207     goto lose;
208
209   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
210   num_types = (size_t) decode (tzhead.tzh_typecnt);
211   chars = (size_t) decode (tzhead.tzh_charcnt);
212   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
213   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
214   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
215
216   /* For platforms with 64-bit time_t we use the new format if available.  */
217   if (sizeof (time_t) == 8 && trans_width == 4
218       && tzhead.tzh_version[0] != '\0')
219     {
220       /* We use the 8-byte format.  */
221       trans_width = 8;
222
223       /* Position the stream before the second header.  */
224       size_t to_skip = (num_transitions * (4 + 1)
225                         + num_types * 6
226                         + chars
227                         + num_leaps * 8
228                         + num_isstd
229                         + num_isgmt);
230       if (fseek (f, to_skip, SEEK_CUR) != 0)
231         goto lose;
232
233       goto read_again;
234     }
235
236   total_size = num_transitions * (sizeof (time_t) + 1);
237   total_size = ((total_size + __alignof__ (struct ttinfo) - 1)
238                 & ~(__alignof__ (struct ttinfo) - 1));
239   types_idx = total_size;
240   total_size += num_types * sizeof (struct ttinfo) + chars;
241   total_size = ((total_size + __alignof__ (struct leap) - 1)
242                 & ~(__alignof__ (struct leap) - 1));
243   leaps_idx = total_size;
244   total_size += num_leaps * sizeof (struct leap);
245
246   /* Allocate enough memory including the extra block requested by the
247      caller.  */
248   transitions = (time_t *) malloc (total_size + extra);
249   if (transitions == NULL)
250     goto lose;
251
252   type_idxs = (unsigned char *) transitions + (num_transitions
253                                                * sizeof (time_t));
254   types = (struct ttinfo *) ((char *) transitions + types_idx);
255   zone_names = (char *) types + num_types * sizeof (struct ttinfo);
256   leaps = (struct leap *) ((char *) transitions + leaps_idx);
257   if (extra > 0)
258     *extrap = (char *) &leaps[num_leaps];
259
260   if (sizeof (time_t) == 4 || trans_width == 8)
261     {
262       if (__builtin_expect (fread_unlocked (transitions, trans_width + 1,
263                                             num_transitions, f)
264                             != num_transitions, 0))
265         goto lose;
266     }
267   else
268     {
269       if (__builtin_expect (fread_unlocked (transitions, 4, num_transitions, f)
270                             != num_transitions, 0)
271           || __builtin_expect (fread_unlocked (type_idxs, 1, num_transitions,
272                                                f) != num_transitions, 0))
273         goto lose;
274     }
275
276   /* Check for bogus indices in the data file, so we can hereafter
277      safely use type_idxs[T] as indices into `types' and never crash.  */
278   for (i = 0; i < num_transitions; ++i)
279     if (__builtin_expect (type_idxs[i] >= num_types, 0))
280       goto lose;
281
282   if (BYTE_ORDER != BIG_ENDIAN || (sizeof (time_t) == 8 && trans_width == 4))
283     {
284       /* Decode the transition times, stored as 4-byte integers in
285          network (big-endian) byte order.  We work from the end of
286          the array so as not to clobber the next element to be
287          processed when sizeof (time_t) > 4.  */
288       i = num_transitions;
289       while (i-- > 0)
290         transitions[i] = decode ((char *) transitions + i * 4);
291     }
292   else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8)
293     {
294       /* Decode the transition times, stored as 8-byte integers in
295          network (big-endian) byte order.  */
296       for (i = 0; i < num_transitions; ++i)
297         transitions[i] = decode64 ((char *) transitions + i * 8);
298     }
299
300   for (i = 0; i < num_types; ++i)
301     {
302       unsigned char x[4];
303       int c;
304       if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
305                             0))
306         goto lose;
307       c = getc_unlocked (f);
308       if (__builtin_expect ((unsigned int) c > 1u, 0))
309         goto lose;
310       types[i].isdst = c;
311       c = getc_unlocked (f);
312       if (__builtin_expect ((size_t) c > chars, 0))
313         /* Bogus index in data file.  */
314         goto lose;
315       types[i].idx = c;
316       types[i].offset = (long int) decode (x);
317     }
318
319   if (__builtin_expect (fread_unlocked (zone_names, 1, chars, f) != chars, 0))
320     goto lose;
321
322   for (i = 0; i < num_leaps; ++i)
323     {
324       unsigned char x[8];
325       if (__builtin_expect (fread_unlocked (x, 1, trans_width, f)
326                             != trans_width, 0))
327         goto lose;
328       if (sizeof (time_t) == 4 || trans_width == 4)
329         leaps[i].transition = (time_t) decode (x);
330       else
331         leaps[i].transition = (time_t) decode64 (x);
332
333       if (__builtin_expect (fread_unlocked (x, 1, 4, f) != 4, 0))
334         goto lose;
335       leaps[i].change = (long int) decode (x);
336     }
337
338   for (i = 0; i < num_isstd; ++i)
339     {
340       int c = getc_unlocked (f);
341       if (__builtin_expect (c == EOF, 0))
342         goto lose;
343       types[i].isstd = c != 0;
344     }
345   while (i < num_types)
346     types[i++].isstd = 0;
347
348   for (i = 0; i < num_isgmt; ++i)
349     {
350       int c = getc_unlocked (f);
351       if (__builtin_expect (c == EOF, 0))
352         goto lose;
353       types[i].isgmt = c != 0;
354     }
355   while (i < num_types)
356     types[i++].isgmt = 0;
357
358   /* XXX When a version 2 file is available it can contain a POSIX TZ-style
359      formatted string which specifies how times past the last one specified
360      are supposed to be handled.  We might want to handle this at some
361      point.  But it might be overhead since most/all? files have an
362      open-ended last entry.  */
363
364   fclose (f);
365
366   /* First "register" all timezone names.  */
367   for (i = 0; i < num_types; ++i)
368     (void) __tzstring (&zone_names[types[i].idx]);
369
370   /* Find the standard and daylight time offsets used by the rule file.
371      We choose the offsets in the types of each flavor that are
372      transitioned to earliest in time.  */
373   __tzname[0] = NULL;
374   __tzname[1] = NULL;
375   for (i = num_transitions; i > 0; )
376     {
377       int type = type_idxs[--i];
378       int dst = types[type].isdst;
379
380       if (__tzname[dst] == NULL)
381         {
382           int idx = types[type].idx;
383
384           __tzname[dst] = __tzstring (&zone_names[idx]);
385
386           if (__tzname[1 - dst] != NULL)
387             break;
388         }
389     }
390   if (__tzname[0] == NULL)
391     {
392       /* This should only happen if there are no transition rules.
393          In this case there should be only one single type.  */
394       assert (num_types == 1);
395       __tzname[0] = __tzstring (zone_names);
396     }
397   if (__tzname[1] == NULL)
398     __tzname[1] = __tzname[0];
399
400   compute_tzname_max (chars);
401
402   if (num_transitions == 0)
403     /* Use the first rule (which should also be the only one).  */
404     rule_stdoff = rule_dstoff = types[0].offset;
405   else
406     {
407       int stdoff_set = 0, dstoff_set = 0;
408       rule_stdoff = rule_dstoff = 0;
409       i = num_transitions - 1;
410       do
411         {
412           if (!stdoff_set && !types[type_idxs[i]].isdst)
413             {
414               stdoff_set = 1;
415               rule_stdoff = types[type_idxs[i]].offset;
416             }
417           else if (!dstoff_set && types[type_idxs[i]].isdst)
418             {
419               dstoff_set = 1;
420               rule_dstoff = types[type_idxs[i]].offset;
421             }
422           if (stdoff_set && dstoff_set)
423             break;
424         }
425       while (i-- > 0);
426
427       if (!dstoff_set)
428         rule_dstoff = rule_stdoff;
429     }
430
431   __daylight = rule_stdoff != rule_dstoff;
432   __timezone = -rule_stdoff;
433
434   __use_tzfile = 1;
435   return;
436
437  lose:
438   fclose (f);
439  ret_free_transitions:
440   free ((void *) transitions);
441   transitions = NULL;
442 }
443 \f
444 /* The user specified a hand-made timezone, but not its DST rules.
445    We will use the names and offsets from the user, and the rules
446    from the TZDEFRULES file.  */
447
448 void
449 __tzfile_default (const char *std, const char *dst,
450                   long int stdoff, long int dstoff)
451 {
452   size_t stdlen = strlen (std) + 1;
453   size_t dstlen = strlen (dst) + 1;
454   size_t i;
455   int isdst;
456   char *cp;
457
458   __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
459   if (!__use_tzfile)
460     return;
461
462   if (num_types < 2)
463     {
464       __use_tzfile = 0;
465       return;
466     }
467
468   /* Ignore the zone names read from the file and use the given ones
469      instead.  */
470   __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
471   zone_names = cp;
472
473   /* Now there are only two zones, regardless of what the file contained.  */
474   num_types = 2;
475
476   /* Now correct the transition times for the user-specified standard and
477      daylight offsets from GMT.  */
478   isdst = 0;
479   for (i = 0; i < num_transitions; ++i)
480     {
481       struct ttinfo *trans_type = &types[type_idxs[i]];
482
483       /* We will use only types 0 (standard) and 1 (daylight).
484          Fix up this transition to point to whichever matches
485          the flavor of its original type.  */
486       type_idxs[i] = trans_type->isdst;
487
488       if (trans_type->isgmt)
489         /* The transition time is in GMT.  No correction to apply.  */ ;
490       else if (isdst && !trans_type->isstd)
491         /* The type says this transition is in "local wall clock time", and
492            wall clock time as of the previous transition was DST.  Correct
493            for the difference between the rule's DST offset and the user's
494            DST offset.  */
495         transitions[i] += dstoff - rule_dstoff;
496       else
497         /* This transition is in "local wall clock time", and wall clock
498            time as of this iteration is non-DST.  Correct for the
499            difference between the rule's standard offset and the user's
500            standard offset.  */
501         transitions[i] += stdoff - rule_stdoff;
502
503       /* The DST state of "local wall clock time" for the next iteration is
504          as specified by this transition.  */
505       isdst = trans_type->isdst;
506     }
507
508   /* Now that we adjusted the transitions to the requested offsets,
509      reset the rule_stdoff and rule_dstoff values appropriately.  They
510      are used elsewhere.  */
511   rule_stdoff = stdoff;
512   rule_dstoff = dstoff;
513
514   /* Reset types 0 and 1 to describe the user's settings.  */
515   types[0].idx = 0;
516   types[0].offset = stdoff;
517   types[0].isdst = 0;
518   types[1].idx = stdlen;
519   types[1].offset = dstoff;
520   types[1].isdst = 1;
521
522   /* Reset the zone names to point to the user's names.  */
523   __tzname[0] = (char *) std;
524   __tzname[1] = (char *) dst;
525
526   /* Set the timezone.  */
527   __timezone = -types[0].offset;
528
529   compute_tzname_max (stdlen + dstlen);
530 }
531 \f
532 static struct ttinfo *
533 internal_function
534 find_transition (time_t timer)
535 {
536   size_t i;
537
538   if (num_transitions == 0 || timer < transitions[0])
539     {
540       /* TIMER is before any transition (or there are no transitions).
541          Choose the first non-DST type
542          (or the first if they're all DST types).  */
543       i = 0;
544       while (i < num_types && types[i].isdst)
545         ++i;
546       if (i == num_types)
547         i = 0;
548     }
549   else
550     {
551       /* Find the first transition after TIMER, and
552          then pick the type of the transition before it.  */
553       for (i = 1; i < num_transitions; ++i)
554         if (timer < transitions[i])
555           break;
556       i = type_idxs[i - 1];
557     }
558
559   return &types[i];
560 }
561 \f
562 void
563 __tzfile_compute (time_t timer, int use_localtime,
564                   long int *leap_correct, int *leap_hit,
565                   struct tm *tp)
566 {
567   register size_t i;
568
569   if (use_localtime)
570     {
571       struct ttinfo *info = find_transition (timer);
572       __daylight = rule_stdoff != rule_dstoff;
573       __timezone = -rule_stdoff;
574       __tzname[0] = NULL;
575       __tzname[1] = NULL;
576       for (i = num_transitions; i > 0; )
577         {
578           int type = type_idxs[--i];
579           int dst = types[type].isdst;
580           int idx = types[type].idx;
581
582           if (__tzname[dst] == NULL)
583             {
584               __tzname[dst] = __tzstring (&zone_names[idx]);
585
586               if (__tzname[1 - dst] != NULL)
587                 break;
588             }
589         }
590       if (__tzname[0] == NULL)
591         {
592           /* This should only happen if there are no transition rules.
593              In this case there should be only one single type.  */
594           assert (num_types == 1);
595           __tzname[0] = __tzstring (zone_names);
596         }
597       if (__tzname[1] == NULL)
598         /* There is no daylight saving time.  */
599         __tzname[1] = __tzname[0];
600       tp->tm_isdst = info->isdst;
601       tp->tm_zone = __tzstring (&zone_names[info->idx]);
602       tp->tm_gmtoff = info->offset;
603     }
604
605   *leap_correct = 0L;
606   *leap_hit = 0;
607
608   /* Find the last leap second correction transition time before TIMER.  */
609   i = num_leaps;
610   do
611     if (i-- == 0)
612       return;
613   while (timer < leaps[i].transition);
614
615   /* Apply its correction.  */
616   *leap_correct = leaps[i].change;
617
618   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
619       ((i == 0 && leaps[i].change > 0) ||
620        leaps[i].change > leaps[i - 1].change))
621     {
622       *leap_hit = 1;
623       while (i > 0
624              && leaps[i].transition == leaps[i - 1].transition + 1
625              && leaps[i].change == leaps[i - 1].change + 1)
626         {
627           ++*leap_hit;
628           --i;
629         }
630     }
631 }
632 \f
633 static void
634 internal_function
635 compute_tzname_max (size_t chars)
636 {
637   const char *p;
638
639   p = zone_names;
640   do
641     {
642       const char *start = p;
643       while (*p != '\0')
644         ++p;
645       if ((size_t) (p - start) > __tzname_cur_max)
646         __tzname_cur_max = p - start;
647     }
648   while (++p < &zone_names[chars]);
649 }