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