Update.
[platform/upstream/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991, 92, 93, 95, 96, 97 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 <stdlib.h>
20 #include <stdio.h>
21 #include <time.h>
22 #include <string.h>
23 #include <limits.h>
24 #include <unistd.h>
25
26 #define NOID
27 #include <tzfile.h>
28
29 int __use_tzfile = 0;
30
31 struct ttinfo
32   {
33     long int offset;            /* Seconds east of GMT.  */
34     unsigned char isdst;        /* Used to set tm_isdst.  */
35     unsigned char idx;          /* Index into `zone_names'.  */
36     unsigned char isstd;        /* Transition times are in standard time.  */
37     unsigned char isgmt;        /* Transition times are in GMT.  */
38   };
39
40 struct leap
41   {
42     time_t transition;          /* Time the transition takes effect.  */
43     long int change;            /* Seconds of correction to apply.  */
44   };
45
46 extern const char * __tzstring (const char *); /* Defined in tzset.c.  */
47
48 static struct ttinfo *find_transition (time_t timer);
49 static void compute_tzname_max (size_t);
50
51 static size_t num_transitions;
52 static time_t *transitions = NULL;
53 static unsigned char *type_idxs = NULL;
54 static size_t num_types;
55 static struct ttinfo *types = NULL;
56 static char *zone_names = NULL;
57 static size_t num_leaps;
58 static struct leap *leaps = NULL;
59
60 #include <endian.h>
61
62 /* Decode the four bytes at PTR as a signed integer in network byte order.  */
63 static inline int
64 decode (const void *ptr)
65 {
66   if ((BYTE_ORDER == BIG_ENDIAN) && sizeof (int) == 4)
67     return *(const int *) ptr;
68   else
69     {
70       const unsigned char *p = ptr;
71       int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
72
73       result = (result << 8) | *p++;
74       result = (result << 8) | *p++;
75       result = (result << 8) | *p++;
76       result = (result << 8) | *p++;
77
78       return result;
79     }
80 }
81
82 void
83 __tzfile_read (const char *file)
84 {
85   static const char default_tzdir[] = TZDIR;
86   size_t num_isstd, num_isgmt;
87   register FILE *f;
88   struct tzhead tzhead;
89   size_t chars;
90   register size_t i;
91   struct ttinfo *info;
92
93   __use_tzfile = 0;
94
95   if (transitions != NULL)
96     free ((void *) transitions);
97   transitions = NULL;
98   if (type_idxs != NULL)
99     free ((void *) type_idxs);
100   type_idxs = NULL;
101   if (types != NULL)
102     free ((void *) types);
103   types = NULL;
104   if (zone_names != NULL)
105     free ((void *) zone_names);
106   zone_names = NULL;
107   if (leaps != NULL)
108     free ((void *) leaps);
109   leaps = NULL;
110
111   if (file == NULL)
112     /* No user specification; use the site-wide default.  */
113     file = TZDEFAULT;
114   else if (*file == '\0')
115     /* User specified the empty string; use UTC explicitly.  */
116     file = "Universal";
117   else
118     {
119       /* We must not allow to read an arbitrary file in a setuid
120          program.  So we fail for any file which is not in the
121          directory hierachy starting at TZDIR
122          and which is not the system wide default TZDEFAULT.  */
123       if (__libc_enable_secure
124           && ((*file == '/'
125                && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
126                && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
127               || strstr (file, "../") != NULL))
128         /* This test is certainly a bit too restrictive but it should
129            catch all critical cases.  */
130         return;
131     }
132
133   if (*file != '/')
134     {
135       const char *tzdir;
136       unsigned int len, tzdir_len;
137       char *new;
138
139       tzdir = __secure_getenv ("TZDIR");
140       if (tzdir == NULL || *tzdir == '\0')
141         {
142           tzdir = default_tzdir;
143           tzdir_len = sizeof (default_tzdir) - 1;
144         }
145       else
146         tzdir_len = strlen (tzdir);
147       len = strlen (file) + 1;
148       new = (char *) __alloca (tzdir_len + 1 + len);
149       memcpy (new, tzdir, tzdir_len);
150       new[tzdir_len] = '/';
151       memcpy (&new[tzdir_len + 1], file, len);
152       file = new;
153     }
154
155   f = fopen (file, "r");
156   if (f == NULL)
157     return;
158
159   if (fread ((void *) &tzhead, sizeof (tzhead), 1, f) != 1)
160     goto lose;
161
162   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
163   num_types = (size_t) decode (tzhead.tzh_typecnt);
164   chars = (size_t) decode (tzhead.tzh_charcnt);
165   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
166   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
167   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
168
169   if (num_transitions > 0)
170     {
171       transitions = (time_t *) malloc (num_transitions * sizeof(time_t));
172       if (transitions == NULL)
173         goto lose;
174       type_idxs = (unsigned char *) malloc (num_transitions);
175       if (type_idxs == NULL)
176         goto lose;
177     }
178   if (num_types > 0)
179     {
180       types = (struct ttinfo *) malloc (num_types * sizeof (struct ttinfo));
181       if (types == NULL)
182         goto lose;
183     }
184   if (chars > 0)
185     {
186       zone_names = (char *) malloc (chars);
187       if (zone_names == NULL)
188         goto lose;
189     }
190   if (num_leaps > 0)
191     {
192       leaps = (struct leap *) malloc (num_leaps * sizeof (struct leap));
193       if (leaps == NULL)
194         goto lose;
195     }
196
197   if (sizeof (time_t) < 4)
198       abort ();
199
200   if (fread(transitions, 4, num_transitions, f) != num_transitions ||
201       fread(type_idxs, 1, num_transitions, f) != num_transitions)
202     goto lose;
203
204   /* Check for bogus indices in the data file, so we can hereafter
205      safely use type_idxs[T] as indices into `types' and never crash.  */
206   for (i = 0; i < num_transitions; ++i)
207     if (type_idxs[i] >= num_types)
208       goto lose;
209
210   if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
211     {
212       /* Decode the transition times, stored as 4-byte integers in
213          network (big-endian) byte order.  We work from the end of
214          the array so as not to clobber the next element to be
215          processed when sizeof (time_t) > 4.  */
216       i = num_transitions;
217       while (i-- > 0)
218         transitions[i] = decode ((char *) transitions + i*4);
219     }
220
221   for (i = 0; i < num_types; ++i)
222     {
223       unsigned char x[4];
224       if (fread (x, 1, 4, f) != 4 ||
225           fread (&types[i].isdst, 1, 1, f) != 1 ||
226           fread (&types[i].idx, 1, 1, f) != 1)
227         goto lose;
228       if (types[i].idx >= chars) /* Bogus index in data file.  */
229         goto lose;
230       types[i].offset = (long int) decode (x);
231     }
232
233   if (fread (zone_names, 1, chars, f) != chars)
234     goto lose;
235
236   for (i = 0; i < num_leaps; ++i)
237     {
238       unsigned char x[4];
239       if (fread (x, 1, sizeof (x), f) != sizeof (x))
240         goto lose;
241       leaps[i].transition = (time_t) decode (x);
242       if (fread (x, 1, sizeof (x), f) != sizeof (x))
243         goto lose;
244       leaps[i].change = (long int) decode (x);
245     }
246
247   for (i = 0; i < num_isstd; ++i)
248     {
249       int c = getc (f);
250       if (c == EOF)
251         goto lose;
252       types[i].isstd = c != 0;
253     }
254   while (i < num_types)
255     types[i++].isstd = 0;
256
257   for (i = 0; i < num_isgmt; ++i)
258     {
259       int c = getc (f);
260       if (c == EOF)
261         goto lose;
262       types[i].isgmt = c != 0;
263     }
264   while (i < num_types)
265     types[i++].isgmt = 0;
266
267   fclose (f);
268
269   info = find_transition (0);
270   for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
271        ++i)
272     __tzname[types[i].isdst] = __tzstring (&zone_names[types[i].idx]);
273   if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
274     __tzname[info->isdst] = __tzstring (&zone_names[info->idx]);
275
276   compute_tzname_max (chars);
277
278   __use_tzfile = 1;
279   return;
280
281  lose:;
282   fclose(f);
283 }
284 \f
285 /* The user specified a hand-made timezone, but not its DST rules.
286    We will use the names and offsets from the user, and the rules
287    from the TZDEFRULES file.  */
288
289 void
290 __tzfile_default (const char *std, const char *dst,
291                   long int stdoff, long int dstoff)
292 {
293   size_t stdlen, dstlen, i;
294   long int rule_offset, rule_stdoff, rule_dstoff;
295   int isdst;
296
297   __tzfile_read (TZDEFRULES);
298   if (!__use_tzfile)
299     return;
300
301   if (num_types < 2)
302     {
303       __use_tzfile = 0;
304       return;
305     }
306
307   /* Ignore the zone names read from the file.  */
308   free (zone_names);
309
310   /* Use the names the user specified.  */
311   stdlen = strlen (std) + 1;
312   dstlen = strlen (dst) + 1;
313   zone_names = malloc (stdlen + dstlen);
314   if (zone_names == NULL)
315     {
316       __use_tzfile = 0;
317       return;
318     }
319   memcpy (zone_names, std, stdlen);
320   memcpy (&zone_names[stdlen], dst, dstlen);
321
322   /* Find the standard and daylight time offsets used by the rule file.
323      We choose the offsets in the types of each flavor that are
324      transitioned to earliest in time.  */
325   rule_stdoff = rule_dstoff = 0;
326   for (i = 0; i < num_transitions; ++i)
327     {
328       if (!rule_stdoff && !types[type_idxs[i]].isdst)
329         rule_stdoff = types[type_idxs[i]].offset;
330       if (!rule_dstoff && types[type_idxs[i]].isdst)
331         rule_dstoff = types[type_idxs[i]].offset;
332       if (rule_stdoff && rule_dstoff)
333         break;
334     }
335
336   /* Now correct the transition times for the user-specified standard and
337      daylight offsets from GMT.  */
338   isdst = 0;
339   rule_offset = rule_offset;
340   for (i = 0; i < num_transitions; ++i)
341     {
342       struct ttinfo *trans_type = &types[type_idxs[i]];
343
344       /* We will use only types 0 (standard) and 1 (daylight).
345          Fix up this transition to point to whichever matches
346          the flavor of its original type.  */
347       type_idxs[i] = trans_type->isdst;
348
349       if (trans_type->isgmt)
350         /* The transition time is in GMT.  No correction to apply.  */ ;
351       else if (isdst && !trans_type->isstd)
352         /* The type says this transition is in "local wall clock time", and
353            wall clock time as of the previous transition was DST.  Correct
354            for the difference between the rule's DST offset and the user's
355            DST offset.  */
356         transitions[i] += dstoff - rule_dstoff;
357       else
358         /* This transition is in "local wall clock time", and wall clock
359            time as of this iteration is non-DST.  Correct for the
360            difference between the rule's standard offset and the user's
361            standard offset.  */
362         transitions[i] += stdoff - rule_stdoff;
363
364       /* The DST state of "local wall clock time" for the next iteration is
365          as specified by this transition.  */
366       isdst = trans_type->isdst;
367     }
368
369   /* Reset types 0 and 1 to describe the user's settings.  */
370   types[0].idx = 0;
371   types[0].offset = stdoff;
372   types[0].isdst = 0;
373   types[1].idx = stdlen;
374   types[1].offset = dstoff;
375   types[1].isdst = 1;
376
377   /* Reset the zone names to point to the user's names.  */
378   __tzname[0] = (char *) std;
379   __tzname[1] = (char *) dst;
380
381   compute_tzname_max (stdlen + dstlen);
382 }
383 \f
384 static struct ttinfo *
385 find_transition (time_t timer)
386 {
387   size_t i;
388
389   if (num_transitions == 0 || timer < transitions[0])
390     {
391       /* TIMER is before any transition (or there are no transitions).
392          Choose the first non-DST type
393          (or the first if they're all DST types).  */
394       i = 0;
395       while (i < num_types && types[i].isdst)
396         ++i;
397       if (i == num_types)
398         i = 0;
399     }
400   else
401     {
402       /* Find the first transition after TIMER, and
403          then pick the type of the transition before it.  */
404       for (i = 1; i < num_transitions; ++i)
405         if (timer < transitions[i])
406           break;
407       i = type_idxs[i - 1];
408     }
409
410   return &types[i];
411 }
412 \f
413 int
414 __tzfile_compute (time_t timer, long int *leap_correct, int *leap_hit)
415 {
416   struct ttinfo *info;
417   register size_t i;
418
419   info = find_transition (timer);
420   __daylight = info->isdst;
421   __timezone = info->offset;
422   for (i = 0; i < num_types && i < sizeof (__tzname) / sizeof (__tzname[0]);
423        ++i)
424     __tzname[types[i].isdst] = &zone_names[types[i].idx];
425   if (info->isdst < sizeof (__tzname) / sizeof (__tzname[0]))
426     __tzname[info->isdst] = &zone_names[info->idx];
427
428   *leap_correct = 0L;
429   *leap_hit = 0;
430
431   /* Find the last leap second correction transition time before TIMER.  */
432   i = num_leaps;
433   do
434     if (i-- == 0)
435       return 1;
436   while (timer < leaps[i].transition);
437
438   /* Apply its correction.  */
439   *leap_correct = leaps[i].change;
440
441   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
442       ((i == 0 && leaps[i].change > 0) ||
443        leaps[i].change > leaps[i - 1].change))
444     {
445       *leap_hit = 1;
446       while (i > 0 &&
447              leaps[i].transition == leaps[i - 1].transition + 1 &&
448              leaps[i].change == leaps[i - 1].change + 1)
449         {
450           ++*leap_hit;
451           --i;
452         }
453     }
454
455   return 1;
456 }
457 \f
458 void
459 compute_tzname_max (size_t chars)
460 {
461   extern size_t __tzname_cur_max; /* Defined in tzset.c. */
462
463   const char *p;
464
465   p = zone_names;
466   do
467     {
468       const char *start = p;
469       while (*p != '\0')
470         ++p;
471       if ((size_t) (p - start) > __tzname_cur_max)
472         __tzname_cur_max = p - start;
473     } while (++p < &zone_names[chars]);
474 }