* time/tzfile.c (__tzfile_read): Handle the case where there are
[kopensolaris-gnu/glibc.git] / time / tzfile.c
1 /* Copyright (C) 1991, 92, 93, 95, 96, 97, 98 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 = 0;
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 = NULL;
52 static unsigned char *type_idxs = NULL;
53 static size_t num_types;
54 static struct ttinfo *types = NULL;
55 static char *zone_names = NULL;
56 static long int rule_stdoff;
57 static long int rule_dstoff;
58 static size_t num_leaps;
59 static struct leap *leaps = NULL;
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)
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
96   __use_tzfile = 0;
97
98   if (transitions != NULL)
99     free ((void *) transitions);
100   transitions = NULL;
101   if (type_idxs != NULL)
102     free ((void *) type_idxs);
103   type_idxs = NULL;
104   if (types != NULL)
105     free ((void *) types);
106   types = NULL;
107   if (zone_names != NULL)
108     free ((void *) zone_names);
109   zone_names = NULL;
110   if (leaps != NULL)
111     free ((void *) leaps);
112   leaps = NULL;
113
114   if (file == NULL)
115     /* No user specification; use the site-wide default.  */
116     file = TZDEFAULT;
117   else if (*file == '\0')
118     /* User specified the empty string; use UTC with no leap seconds.  */
119     return;
120   else
121     {
122       /* We must not allow to read an arbitrary file in a setuid
123          program.  So we fail for any file which is not in the
124          directory hierachy starting at TZDIR
125          and which is not the system wide default TZDEFAULT.  */
126       if (__libc_enable_secure
127           && ((*file == '/'
128                && memcmp (file, TZDEFAULT, sizeof TZDEFAULT)
129                && memcmp (file, default_tzdir, sizeof (default_tzdir) - 1))
130               || strstr (file, "../") != NULL))
131         /* This test is certainly a bit too restrictive but it should
132            catch all critical cases.  */
133         return;
134     }
135
136   if (*file != '/')
137     {
138       const char *tzdir;
139       unsigned int len, tzdir_len;
140       char *new, *tmp;
141
142       tzdir = __secure_getenv ("TZDIR");
143       if (tzdir == NULL || *tzdir == '\0')
144         {
145           tzdir = default_tzdir;
146           tzdir_len = sizeof (default_tzdir) - 1;
147         }
148       else
149         tzdir_len = strlen (tzdir);
150       len = strlen (file) + 1;
151       new = (char *) __alloca (tzdir_len + 1 + len);
152       tmp = __mempcpy (new, tzdir, tzdir_len);
153       *tmp++ = '/';
154       __mempcpy (tmp, file, len);
155       file = new;
156     }
157
158   f = fopen (file, "r");
159   if (f == NULL)
160     return;
161
162   if (fread_unlocked ((void *) &tzhead, sizeof (tzhead), 1, f) != 1)
163     goto lose;
164
165   num_transitions = (size_t) decode (tzhead.tzh_timecnt);
166   num_types = (size_t) decode (tzhead.tzh_typecnt);
167   chars = (size_t) decode (tzhead.tzh_charcnt);
168   num_leaps = (size_t) decode (tzhead.tzh_leapcnt);
169   num_isstd = (size_t) decode (tzhead.tzh_ttisstdcnt);
170   num_isgmt = (size_t) decode (tzhead.tzh_ttisgmtcnt);
171
172   if (num_transitions > 0)
173     {
174       transitions = (time_t *) malloc (num_transitions * sizeof (time_t));
175       if (transitions == NULL)
176         goto lose;
177       type_idxs = (unsigned char *) malloc (num_transitions);
178       if (type_idxs == NULL)
179         goto lose;
180     }
181   if (num_types > 0)
182     {
183       types = (struct ttinfo *) malloc (num_types * sizeof (struct ttinfo));
184       if (types == NULL)
185         goto lose;
186     }
187   if (chars > 0)
188     {
189       zone_names = (char *) malloc (chars);
190       if (zone_names == NULL)
191         goto lose;
192     }
193   if (num_leaps > 0)
194     {
195       leaps = (struct leap *) malloc (num_leaps * sizeof (struct leap));
196       if (leaps == NULL)
197         goto lose;
198     }
199
200   if (sizeof (time_t) < 4)
201       abort ();
202
203   if (fread_unlocked (transitions, 4, num_transitions, f) != num_transitions
204       || fread_unlocked (type_idxs, 1, num_transitions, f) != num_transitions)
205     goto lose;
206
207   /* Check for bogus indices in the data file, so we can hereafter
208      safely use type_idxs[T] as indices into `types' and never crash.  */
209   for (i = 0; i < num_transitions; ++i)
210     if (type_idxs[i] >= num_types)
211       goto lose;
212
213   if (BYTE_ORDER != BIG_ENDIAN || sizeof (time_t) != 4)
214     {
215       /* Decode the transition times, stored as 4-byte integers in
216          network (big-endian) byte order.  We work from the end of
217          the array so as not to clobber the next element to be
218          processed when sizeof (time_t) > 4.  */
219       i = num_transitions;
220       while (i-- > 0)
221         transitions[i] = decode ((char *) transitions + i * 4);
222     }
223
224   for (i = 0; i < num_types; ++i)
225     {
226       unsigned char x[4];
227       if (fread_unlocked (x, 1, 4, f) != 4
228           || fread_unlocked (&types[i].isdst, 1, 1, f) != 1
229           || fread_unlocked (&types[i].idx, 1, 1, f) != 1)
230         goto lose;
231       if (types[i].isdst > 1)
232         goto lose;
233       if (types[i].idx >= chars) /* Bogus index in data file.  */
234         goto lose;
235       types[i].offset = (long int) decode (x);
236     }
237
238   if (fread_unlocked (zone_names, 1, chars, f) != chars)
239     goto lose;
240
241   for (i = 0; i < num_leaps; ++i)
242     {
243       unsigned char x[4];
244       if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x))
245         goto lose;
246       leaps[i].transition = (time_t) decode (x);
247       if (fread_unlocked (x, 1, sizeof (x), f) != sizeof (x))
248         goto lose;
249       leaps[i].change = (long int) decode (x);
250     }
251
252   for (i = 0; i < num_isstd; ++i)
253     {
254       int c = getc_unlocked (f);
255       if (c == EOF)
256         goto lose;
257       types[i].isstd = c != 0;
258     }
259   while (i < num_types)
260     types[i++].isstd = 0;
261
262   for (i = 0; i < num_isgmt; ++i)
263     {
264       int c = getc_unlocked (f);
265       if (c == EOF)
266         goto lose;
267       types[i].isgmt = c != 0;
268     }
269   while (i < num_types)
270     types[i++].isgmt = 0;
271
272   fclose (f);
273
274   /* First "register" all timezone names.  */
275   for (i = 0; i < num_types; ++i)
276     (void) __tzstring (&zone_names[types[i].idx]);
277
278   /* Find the standard and daylight time offsets used by the rule file.
279      We choose the offsets in the types of each flavor that are
280      transitioned to earliest in time.  */
281   __tzname[0] = NULL;
282   __tzname[1] = NULL;
283   for (i = num_transitions; i > 0; )
284     {
285       int type = type_idxs[--i];
286       int dst = types[type].isdst;
287       int idx = types[type].idx;
288
289       if (__tzname[dst] == NULL)
290         {
291           __tzname[dst] = __tzstring (&zone_names[idx]);
292
293           if (__tzname[1 - dst] != NULL)
294             break;
295         }
296     }
297   if (__tzname[0] == NULL)
298     {
299       /* This should only happen if there are no transition rules.
300          In this case there should be only one single type.  */
301       assert (num_types == 1);
302       __tzname[0] = __tzstring (zone_names);
303     }
304   if (__tzname[1] == NULL)
305     __tzname[1] = __tzname[0];
306
307   compute_tzname_max (chars);
308
309   if (num_transitions == 0)
310     /* Use the first rule (which should also be the only one).  */
311     rule_stdoff = rule_dstoff = types[0].offset;
312   else
313     {
314       int stdoff_set = 0, dstoff_set = 0;
315       rule_stdoff = rule_dstoff = 0;
316       for (i = 0; i < num_transitions; ++i)
317         {
318           if (!stdoff_set && !types[type_idxs[i]].isdst)
319             {
320               stdoff_set = 1;
321               rule_stdoff = types[type_idxs[i]].offset;
322             }
323           if (!dstoff_set && types[type_idxs[i]].isdst)
324             {
325               dstoff_set = 1;
326               rule_dstoff = types[type_idxs[i]].offset;
327             }
328           if (stdoff_set && dstoff_set)
329             break;
330         }
331       if (!dstoff_set)
332         rule_dstoff = rule_stdoff;
333     }
334
335   __daylight = rule_stdoff != rule_dstoff;
336   __timezone = -rule_stdoff;
337
338   __use_tzfile = 1;
339   return;
340
341  lose:
342   fclose (f);
343 }
344 \f
345 /* The user specified a hand-made timezone, but not its DST rules.
346    We will use the names and offsets from the user, and the rules
347    from the TZDEFRULES file.  */
348
349 void
350 __tzfile_default (const char *std, const char *dst,
351                   long int stdoff, long int dstoff)
352 {
353   size_t stdlen, dstlen, i;
354   int isdst;
355
356   __tzfile_read (TZDEFRULES);
357   if (!__use_tzfile)
358     return;
359
360   if (num_types < 2)
361     {
362       __use_tzfile = 0;
363       return;
364     }
365
366   /* Ignore the zone names read from the file.  */
367   free (zone_names);
368
369   /* Use the names the user specified.  */
370   stdlen = strlen (std) + 1;
371   dstlen = strlen (dst) + 1;
372   zone_names = malloc (stdlen + dstlen);
373   if (zone_names == NULL)
374     {
375       __use_tzfile = 0;
376       return;
377     }
378   __mempcpy (__mempcpy (zone_names, std, stdlen), dst, dstlen);
379
380   /* Now there are only two zones, regardless of what the file contained.  */
381   num_types = 2;
382
383   /* Now correct the transition times for the user-specified standard and
384      daylight offsets from GMT.  */
385   isdst = 0;
386   for (i = 0; i < num_transitions; ++i)
387     {
388       struct ttinfo *trans_type = &types[type_idxs[i]];
389
390       /* We will use only types 0 (standard) and 1 (daylight).
391          Fix up this transition to point to whichever matches
392          the flavor of its original type.  */
393       type_idxs[i] = trans_type->isdst;
394
395       if (trans_type->isgmt)
396         /* The transition time is in GMT.  No correction to apply.  */ ;
397       else if (isdst && !trans_type->isstd)
398         /* The type says this transition is in "local wall clock time", and
399            wall clock time as of the previous transition was DST.  Correct
400            for the difference between the rule's DST offset and the user's
401            DST offset.  */
402         transitions[i] += dstoff - rule_dstoff;
403       else
404         /* This transition is in "local wall clock time", and wall clock
405            time as of this iteration is non-DST.  Correct for the
406            difference between the rule's standard offset and the user's
407            standard offset.  */
408         transitions[i] += stdoff - rule_stdoff;
409
410       /* The DST state of "local wall clock time" for the next iteration is
411          as specified by this transition.  */
412       isdst = trans_type->isdst;
413     }
414
415   /* Reset types 0 and 1 to describe the user's settings.  */
416   types[0].idx = 0;
417   types[0].offset = stdoff;
418   types[0].isdst = 0;
419   types[1].idx = stdlen;
420   types[1].offset = dstoff;
421   types[1].isdst = 1;
422
423   /* Reset the zone names to point to the user's names.  */
424   __tzname[0] = (char *) std;
425   __tzname[1] = (char *) dst;
426
427   /* Set the timezone.  */
428   __timezone = -types[0].offset;
429
430   compute_tzname_max (stdlen + dstlen);
431 }
432 \f
433 static struct ttinfo *
434 internal_function
435 find_transition (time_t timer)
436 {
437   size_t i;
438
439   if (num_transitions == 0 || timer < transitions[0])
440     {
441       /* TIMER is before any transition (or there are no transitions).
442          Choose the first non-DST type
443          (or the first if they're all DST types).  */
444       i = 0;
445       while (i < num_types && types[i].isdst)
446         ++i;
447       if (i == num_types)
448         i = 0;
449     }
450   else
451     {
452       /* Find the first transition after TIMER, and
453          then pick the type of the transition before it.  */
454       for (i = 1; i < num_transitions; ++i)
455         if (timer < transitions[i])
456           break;
457       i = type_idxs[i - 1];
458     }
459
460   return &types[i];
461 }
462 \f
463 int
464 __tzfile_compute (time_t timer, int use_localtime,
465                   long int *leap_correct, int *leap_hit,
466                   struct tm *tp)
467 {
468   register size_t i;
469
470   if (use_localtime)
471     {
472       struct ttinfo *info = find_transition (timer);
473       __daylight = rule_stdoff != rule_dstoff;
474       __timezone = -rule_stdoff;
475       __tzname[0] = NULL;
476       __tzname[1] = NULL;
477       for (i = num_transitions; i > 0; )
478         {
479           int type = type_idxs[--i];
480           int dst = types[type].isdst;
481           int idx = types[type].idx;
482
483           if (__tzname[dst] == NULL)
484             {
485               __tzname[dst] = __tzstring (&zone_names[idx]);
486
487               if (__tzname[1 - dst] != NULL)
488                 break;
489             }
490         }
491       if (__tzname[0] == NULL)
492         {
493           /* This should only happen if there are no transition rules.
494              In this case there should be only one single type.  */
495           assert (num_types == 1);
496           __tzname[0] = __tzstring (zone_names);
497         }
498       if (__tzname[1] == NULL)
499         /* There is no daylight saving time.  */
500         __tzname[1] = __tzname[0];
501       tp->tm_isdst = info->isdst;
502       tp->tm_zone = &zone_names[info->idx];
503       tp->tm_gmtoff = info->offset;
504     }
505
506   *leap_correct = 0L;
507   *leap_hit = 0;
508
509   /* Find the last leap second correction transition time before TIMER.  */
510   i = num_leaps;
511   do
512     if (i-- == 0)
513       return 1;
514   while (timer < leaps[i].transition);
515
516   /* Apply its correction.  */
517   *leap_correct = leaps[i].change;
518
519   if (timer == leaps[i].transition && /* Exactly at the transition time.  */
520       ((i == 0 && leaps[i].change > 0) ||
521        leaps[i].change > leaps[i - 1].change))
522     {
523       *leap_hit = 1;
524       while (i > 0
525              && leaps[i].transition == leaps[i - 1].transition + 1
526              && leaps[i].change == leaps[i - 1].change + 1)
527         {
528           ++*leap_hit;
529           --i;
530         }
531     }
532
533   return 1;
534 }
535 \f
536 static void
537 internal_function
538 compute_tzname_max (size_t chars)
539 {
540   const char *p;
541
542   p = zone_names;
543   do
544     {
545       const char *start = p;
546       while (*p != '\0')
547         ++p;
548       if ((size_t) (p - start) > __tzname_cur_max)
549         __tzname_cur_max = p - start;
550     }
551   while (++p < &zone_names[chars]);
552 }