Updated to fedora-glibc-20070117T0857
[kopensolaris-gnu/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) == 4 || trans_width == 4))
283       || (BYTE_ORDER == BIG_ENDIAN && sizeof (time_t) == 8
284           && trans_width == 4))
285     {
286       /* Decode the transition times, stored as 4-byte integers in
287          network (big-endian) byte order.  We work from the end of
288          the array so as not to clobber the next element to be
289          processed when sizeof (time_t) > 4.  */
290       i = num_transitions;
291       while (i-- > 0)
292         transitions[i] = decode ((char *) transitions + i * 4);
293     }
294   else if (BYTE_ORDER != BIG_ENDIAN && sizeof (time_t) == 8)
295     {
296       /* Decode the transition times, stored as 8-byte integers in
297          network (big-endian) byte order.  */
298       for (i = 0; i < num_transitions; ++i)
299         transitions[i] = decode64 ((char *) transitions + i * 8);
300     }
301
302   for (i = 0; i < num_types; ++i)
303     {
304       unsigned char x[4];
305       int c;
306       if (__builtin_expect (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x),
307                             0))
308         goto lose;
309       c = getc_unlocked (f);
310       if (__builtin_expect ((unsigned int) c > 1u, 0))
311         goto lose;
312       types[i].isdst = c;
313       c = getc_unlocked (f);
314       if (__builtin_expect ((size_t) c > chars, 0))
315         /* Bogus index in data file.  */
316         goto lose;
317       types[i].idx = c;
318       types[i].offset = (long int) decode (x);
319     }
320
321   if (__builtin_expect (fread_unlocked (zone_names, 1, chars, f) != chars, 0))
322     goto lose;
323
324   for (i = 0; i < num_leaps; ++i)
325     {
326       unsigned char x[8];
327       if (__builtin_expect (fread_unlocked (x, 1, trans_width, f)
328                             != trans_width, 0))
329         goto lose;
330       if (sizeof (time_t) == 4 || trans_width == 4)
331         leaps[i].transition = (time_t) decode (x);
332       else
333         leaps[i].transition = (time_t) decode64 (x);
334
335       if (__builtin_expect (fread_unlocked (x, 1, 4, f) != 4, 0))
336         goto lose;
337       leaps[i].change = (long int) decode (x);
338     }
339
340   for (i = 0; i < num_isstd; ++i)
341     {
342       int c = getc_unlocked (f);
343       if (__builtin_expect (c == EOF, 0))
344         goto lose;
345       types[i].isstd = c != 0;
346     }
347   while (i < num_types)
348     types[i++].isstd = 0;
349
350   for (i = 0; i < num_isgmt; ++i)
351     {
352       int c = getc_unlocked (f);
353       if (__builtin_expect (c == EOF, 0))
354         goto lose;
355       types[i].isgmt = c != 0;
356     }
357   while (i < num_types)
358     types[i++].isgmt = 0;
359
360   /* XXX When a version 2 file is available it can contain a POSIX TZ-style
361      formatted string which specifies how times past the last one specified
362      are supposed to be handled.  We might want to handle this at some
363      point.  But it might be overhead since most/all? files have an
364      open-ended last entry.  */
365
366   fclose (f);
367
368   /* First "register" all timezone names.  */
369   for (i = 0; i < num_types; ++i)
370     (void) __tzstring (&zone_names[types[i].idx]);
371
372   /* Find the standard and daylight time offsets used by the rule file.
373      We choose the offsets in the types of each flavor that are
374      transitioned to earliest in time.  */
375   __tzname[0] = NULL;
376   __tzname[1] = NULL;
377   for (i = num_transitions; i > 0; )
378     {
379       int type = type_idxs[--i];
380       int dst = types[type].isdst;
381
382       if (__tzname[dst] == NULL)
383         {
384           int idx = types[type].idx;
385
386           __tzname[dst] = __tzstring (&zone_names[idx]);
387
388           if (__tzname[1 - dst] != NULL)
389             break;
390         }
391     }
392   if (__tzname[0] == NULL)
393     {
394       /* This should only happen if there are no transition rules.
395          In this case there should be only one single type.  */
396       assert (num_types == 1);
397       __tzname[0] = __tzstring (zone_names);
398     }
399   if (__tzname[1] == NULL)
400     __tzname[1] = __tzname[0];
401
402   compute_tzname_max (chars);
403
404   if (num_transitions == 0)
405     /* Use the first rule (which should also be the only one).  */
406     rule_stdoff = rule_dstoff = types[0].offset;
407   else
408     {
409       int stdoff_set = 0, dstoff_set = 0;
410       rule_stdoff = rule_dstoff = 0;
411       i = num_transitions - 1;
412       do
413         {
414           if (!stdoff_set && !types[type_idxs[i]].isdst)
415             {
416               stdoff_set = 1;
417               rule_stdoff = types[type_idxs[i]].offset;
418             }
419           else if (!dstoff_set && types[type_idxs[i]].isdst)
420             {
421               dstoff_set = 1;
422               rule_dstoff = types[type_idxs[i]].offset;
423             }
424           if (stdoff_set && dstoff_set)
425             break;
426         }
427       while (i-- > 0);
428
429       if (!dstoff_set)
430         rule_dstoff = rule_stdoff;
431     }
432
433   __daylight = rule_stdoff != rule_dstoff;
434   __timezone = -rule_stdoff;
435
436   __use_tzfile = 1;
437   return;
438
439  lose:
440   fclose (f);
441  ret_free_transitions:
442   free ((void *) transitions);
443   transitions = NULL;
444 }
445 \f
446 /* The user specified a hand-made timezone, but not its DST rules.
447    We will use the names and offsets from the user, and the rules
448    from the TZDEFRULES file.  */
449
450 void
451 __tzfile_default (const char *std, const char *dst,
452                   long int stdoff, long int dstoff)
453 {
454   size_t stdlen = strlen (std) + 1;
455   size_t dstlen = strlen (dst) + 1;
456   size_t i;
457   int isdst;
458   char *cp;
459
460   __tzfile_read (TZDEFRULES, stdlen + dstlen, &cp);
461   if (!__use_tzfile)
462     return;
463
464   if (num_types < 2)
465     {
466       __use_tzfile = 0;
467       return;
468     }
469
470   /* Ignore the zone names read from the file and use the given ones
471      instead.  */
472   __mempcpy (__mempcpy (cp, std, stdlen), dst, dstlen);
473   zone_names = cp;
474
475   /* Now there are only two zones, regardless of what the file contained.  */
476   num_types = 2;
477
478   /* Now correct the transition times for the user-specified standard and
479      daylight offsets from GMT.  */
480   isdst = 0;
481   for (i = 0; i < num_transitions; ++i)
482     {
483       struct ttinfo *trans_type = &types[type_idxs[i]];
484
485       /* We will use only types 0 (standard) and 1 (daylight).
486          Fix up this transition to point to whichever matches
487          the flavor of its original type.  */
488       type_idxs[i] = trans_type->isdst;
489
490       if (trans_type->isgmt)
491         /* The transition time is in GMT.  No correction to apply.  */ ;
492       else if (isdst && !trans_type->isstd)
493         /* The type says this transition is in "local wall clock time", and
494            wall clock time as of the previous transition was DST.  Correct
495            for the difference between the rule's DST offset and the user's
496            DST offset.  */
497         transitions[i] += dstoff - rule_dstoff;
498       else
499         /* This transition is in "local wall clock time", and wall clock
500            time as of this iteration is non-DST.  Correct for the
501            difference between the rule's standard offset and the user's
502            standard offset.  */
503         transitions[i] += stdoff - rule_stdoff;
504
505       /* The DST state of "local wall clock time" for the next iteration is
506          as specified by this transition.  */
507       isdst = trans_type->isdst;
508     }
509
510   /* Now that we adjusted the transitions to the requested offsets,
511      reset the rule_stdoff and rule_dstoff values appropriately.  They
512      are used elsewhere.  */
513   rule_stdoff = stdoff;
514   rule_dstoff = dstoff;
515
516   /* Reset types 0 and 1 to describe the user's settings.  */
517   types[0].idx = 0;
518   types[0].offset = stdoff;
519   types[0].isdst = 0;
520   types[1].idx = stdlen;
521   types[1].offset = dstoff;
522   types[1].isdst = 1;
523
524   /* Reset the zone names to point to the user's names.  */
525   __tzname[0] = (char *) std;
526   __tzname[1] = (char *) dst;
527
528   /* Set the timezone.  */
529   __timezone = -types[0].offset;
530
531   compute_tzname_max (stdlen + dstlen);
532 }
533 \f
534 static struct ttinfo *
535 internal_function
536 find_transition (time_t timer)
537 {
538   size_t i;
539
540   if (num_transitions == 0 || timer < transitions[0])
541     {
542       /* TIMER is before any transition (or there are no transitions).
543          Choose the first non-DST type
544          (or the first if they're all DST types).  */
545       i = 0;
546       while (i < num_types && types[i].isdst)
547         ++i;
548       if (i == num_types)
549         i = 0;
550     }
551   else
552     {
553       /* Find the first transition after TIMER, and
554          then pick the type of the transition before it.  */
555       for (i = 1; i < num_transitions; ++i)
556         if (timer < transitions[i])
557           break;
558       i = type_idxs[i - 1];
559     }
560
561   return &types[i];
562 }
563 \f
564 void
565 __tzfile_compute (time_t timer, int use_localtime,
566                   long int *leap_correct, int *leap_hit,
567                   struct tm *tp)
568 {
569   register size_t i;
570
571   if (use_localtime)
572     {
573       struct ttinfo *info = find_transition (timer);
574       __daylight = rule_stdoff != rule_dstoff;
575       __timezone = -rule_stdoff;
576       __tzname[0] = NULL;
577       __tzname[1] = NULL;
578       for (i = num_transitions; i > 0; )
579         {
580           int type = type_idxs[--i];
581           int dst = types[type].isdst;
582           int idx = types[type].idx;
583
584           if (__tzname[dst] == NULL)
585             {
586               __tzname[dst] = __tzstring (&zone_names[idx]);
587
588               if (__tzname[1 - dst] != NULL)
589                 break;
590             }
591         }
592       if (__tzname[0] == NULL)
593         {
594           /* This should only happen if there are no transition rules.
595              In this case there should be only one single type.  */
596           assert (num_types == 1);
597           __tzname[0] = __tzstring (zone_names);
598         }
599       if (__tzname[1] == NULL)
600         /* There is no daylight saving time.  */
601         __tzname[1] = __tzname[0];
602       tp->tm_isdst = info->isdst;
603       tp->tm_zone = __tzstring (&zone_names[info->idx]);
604       tp->tm_gmtoff = info->offset;
605     }
606
607   *leap_correct = 0L;
608   *leap_hit = 0;
609
610   /* Find the last leap second correction transition time before TIMER.  */
611   i = num_leaps;
612   do
613     if (i-- == 0)
614       return;
615   while (timer < leaps[i].transition);
616
617   /* Apply its correction.  */
618   *leap_correct = leaps[i].change;
619
620   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
621       ((i == 0 && leaps[i].change > 0) ||
622        leaps[i].change > leaps[i - 1].change))
623     {
624       *leap_hit = 1;
625       while (i > 0
626              && leaps[i].transition == leaps[i - 1].transition + 1
627              && leaps[i].change == leaps[i - 1].change + 1)
628         {
629           ++*leap_hit;
630           --i;
631         }
632     }
633 }
634 \f
635 static void
636 internal_function
637 compute_tzname_max (size_t chars)
638 {
639   const char *p;
640
641   p = zone_names;
642   do
643     {
644       const char *start = p;
645       while (*p != '\0')
646         ++p;
647       if ((size_t) (p - start) > __tzname_cur_max)
648         __tzname_cur_max = p - start;
649     }
650   while (++p < &zone_names[chars]);
651 }