File: tzfile.c

package info (click to toggle)
dietlibc 0.34~cvs20160606-10
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 11,336 kB
  • sloc: ansic: 71,631; asm: 13,006; cpp: 1,860; makefile: 799; sh: 292; perl: 62
file content (137 lines) | stat: -rw-r--r-- 3,553 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "dietfeatures.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <netinet/in.h>
#include <time.h>

#include <stdio.h>

/* This code appears to be subtly wrong depending on the date.
 * However, the documentation I found about the tzfile layout are not
 * sufficient to debug this. */

char* tzname[2]={"GMT","GMT"};

#ifdef WANT_TZFILE_PARSER
static unsigned char *tzfile;
static int tzlen=-1;

void __maplocaltime(void);
void __maplocaltime(void) {
  int fd;
  unsigned int len;
  if (tzlen>=0) return;
  tzlen=0;
  if ((fd=open("/etc/localtime",O_RDONLY))<0) return;
  len=lseek(fd,0,SEEK_END);
  if ((tzfile=mmap(0,len,PROT_READ,MAP_PRIVATE,fd,0))==MAP_FAILED) {
    close(fd);
    return;
  }
  close(fd);
  if (len<44 || ntohl(*(int*)tzfile) != 0x545a6966) {
    munmap(tzfile,len);
    tzfile=0;
    return;
  }
  tzlen=len;
}

static int32_t __myntohl(const unsigned char* c) {
  return (((uint32_t)c[0])<<24) +
         (((uint32_t)c[1])<<16) +
         (((uint32_t)c[2])<<8) +
         ((uint32_t)c[3]);
}

time_t __tzfile_map(time_t t, int *isdst, int forward);
time_t __tzfile_map(time_t t, int *isdst, int forward) {
  /* "TZif" plus 16 reserved bytes. */
  unsigned char *tmp;
  int i;
  int tzh_timecnt, tzh_typecnt;
  *isdst=0;
  if (!tzfile) return t;
  tzh_timecnt=ntohl(*(int*)(tzfile+32));
  tzh_typecnt=ntohl(*(int*)(tzfile+36));

#if 0
  int tzh_ttisgmtcnt=ntohl(*(int*)(tzfile+20));
  int tzh_ttisstdcnt=ntohl(*(int*)(tzfile+24));
  int tzh_leapcnt=ntohl(*(int*)(tzfile+28));
  int tzh_charcnt=ntohl(*(int*)(tzfile+40));
  tmp=tzfile+20+6*4;
  printf("ttisgmtcnt %d ttisstdcnt %d leapcnt %d timecnt %d typecnt %d charcnt %d\n",tzh_ttisgmtcnt,tzh_ttisstdcnt, tzh_leapcnt, tzh_timecnt, tzh_typecnt, tzh_charcnt);
  printf("transition times: ");
  for (i=0; i<tzh_timecnt; ++i) {
    printf("%s%lu",i?", ":"",ntohl(*(int*)tmp)); tmp+=4;
  }
  printf("\n");
  printf("indices: ");
  for (i=0; i<tzh_timecnt; ++i) {
    printf("%s%d",i?", ":"",*tmp); ++tmp;
  }
  printf("\n");
  printf("transition times: ");
  for (i=0; i<tzh_typecnt; ++i) {
    printf("%s(%lu,%d,%d)",i?", ":"",ntohl(*(int*)tmp),tmp[4],tmp[5]); tmp+=6;
  }
  printf("\n");
  for (i=0; i<tzh_charcnt; ++i) {
    printf("%s\"%s\"",i?", ":"",tmp);
    tmp+=strlen(tmp);
  }
  printf("\n");
#endif

  tmp=tzfile+20+6*4;
  daylight=(tzh_timecnt>0);
  if (forward) {
    for (i=0; i<tzh_timecnt; ++i) {
      if ((time_t)__myntohl(tmp+i*4) >= t) {
	unsigned char* tz=tmp;
  /*      printf("match at %d\n",i); */
	tmp+=tzh_timecnt*4;
	i=tmp[i-1];
  /*      printf("using index %d\n",i); */
	tmp+=tzh_timecnt;
	tz+=tzh_timecnt*5+tzh_typecnt*6;
	tmp+=i*6;
  /*      printf("(%lu,%d,%d)\n",ntohl(*(int*)tmp),tmp[4],tmp[5]); */
	*isdst=tmp[4];
	tzname[0]=(char*)(tz+tmp[5]);
	timezone=__myntohl(tmp);
	return t+timezone;
      }
    }
  } else {	/* reverse map, for mktime */
    time_t nexttz=0,lastval=0;
//    printf("tzh_timecnt: %d\n",tzh_timecnt);
    for (i=1; i<tzh_timecnt-1; ++i) {
      unsigned char* x, j;
      long k=0;
//      printf("ab %ld: ",__myntohl(tmp+i*4));
      x=tmp+tzh_timecnt*4;
      j=x[i-1];
      nexttz=__myntohl(x+tzh_timecnt+j*6);
//      printf("%ld - %ld (want %ld)\n",lastval,__myntohl(tmp+i*4)-nexttz,t);
      if (lastval <= t && (k=(__myntohl(tmp+i*4)-nexttz)) > t) {
//	printf("FOUND!1!!  Offset %d\n",nexttz);
	return t-nexttz;
      }
      lastval=k;
    }
  }
  return t;
}

void tzset(void) {
  int isdst;
  __maplocaltime();
  __tzfile_map(time(0),&isdst,1);
}

#else
void tzset(void) { }
#endif