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