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