1 |
slords |
1.1 |
|
2 |
|
|
Add support for use of the system timezone database, rather |
3 |
|
|
than embedding a copy. Discussed upstream but was not desired. |
4 |
|
|
|
5 |
|
|
History: |
6 |
|
|
r7: improve check for valid timezone id to exclude directories |
7 |
|
|
r6: fix fd leak in r5, fix country code/BC flag use in |
8 |
|
|
timezone_identifiers_list() using system db, |
9 |
|
|
fix use of PECL timezonedb to override system db, |
10 |
|
|
r5: reverts addition of "System/Localtime" fake tzname. |
11 |
|
|
updated for 5.3.0, parses zone.tab to pick up mapping between |
12 |
|
|
timezone name, country code and long/lat coords |
13 |
|
|
r4: added "System/Localtime" tzname which uses /etc/localtime |
14 |
|
|
r3: fix a crash if /usr/share/zoneinfo doesn't exist (Raphael Geissert) |
15 |
|
|
r2: add filesystem trawl to set up name alias index |
16 |
|
|
r1: initial revision |
17 |
|
|
|
18 |
|
|
--- php-5.3.1/ext/date/lib/parse_tz.c.systzdata |
19 |
|
|
+++ php-5.3.1/ext/date/lib/parse_tz.c |
20 |
|
|
@@ -20,6 +20,16 @@ |
21 |
|
|
|
22 |
|
|
#include "timelib.h" |
23 |
|
|
|
24 |
|
|
+#ifdef HAVE_SYSTEM_TZDATA |
25 |
|
|
+#include <sys/mman.h> |
26 |
|
|
+#include <sys/stat.h> |
27 |
|
|
+#include <limits.h> |
28 |
|
|
+#include <fcntl.h> |
29 |
|
|
+#include <unistd.h> |
30 |
|
|
+ |
31 |
|
|
+#include "php_scandir.h" |
32 |
|
|
+#endif |
33 |
|
|
+ |
34 |
|
|
#include <stdio.h> |
35 |
|
|
|
36 |
|
|
#ifdef HAVE_LOCALE_H |
37 |
|
|
@@ -31,7 +41,12 @@ |
38 |
|
|
#else |
39 |
|
|
#include <strings.h> |
40 |
|
|
#endif |
41 |
|
|
+ |
42 |
|
|
+#ifndef HAVE_SYSTEM_TZDATA |
43 |
|
|
#include "timezonedb.h" |
44 |
|
|
+#endif |
45 |
|
|
+ |
46 |
|
|
+#include <ctype.h> |
47 |
|
|
|
48 |
|
|
#if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) |
49 |
|
|
# if defined(__LITTLE_ENDIAN__) |
50 |
|
|
@@ -51,9 +66,14 @@ |
51 |
|
|
|
52 |
|
|
static void read_preamble(const unsigned char **tzf, timelib_tzinfo *tz) |
53 |
|
|
{ |
54 |
|
|
- /* skip ID */ |
55 |
|
|
- *tzf += 4; |
56 |
|
|
- |
57 |
|
|
+ if (memcmp(tzf, "TZif", 4) == 0) { |
58 |
|
|
+ *tzf += 20; |
59 |
|
|
+ return; |
60 |
|
|
+ } |
61 |
|
|
+ |
62 |
|
|
+ /* skip ID */ |
63 |
|
|
+ *tzf += 4; |
64 |
|
|
+ |
65 |
|
|
/* read BC flag */ |
66 |
|
|
tz->bc = (**tzf == '\1'); |
67 |
|
|
*tzf += 1; |
68 |
|
|
@@ -253,7 +273,397 @@ void timelib_dump_tzinfo(timelib_tzinfo |
69 |
|
|
} |
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
-static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb) |
73 |
|
|
+#ifdef HAVE_SYSTEM_TZDATA |
74 |
|
|
+ |
75 |
|
|
+#ifdef HAVE_SYSTEM_TZDATA_PREFIX |
76 |
|
|
+#define ZONEINFO_PREFIX HAVE_SYSTEM_TZDATA_PREFIX |
77 |
|
|
+#else |
78 |
|
|
+#define ZONEINFO_PREFIX "/usr/share/zoneinfo" |
79 |
|
|
+#endif |
80 |
|
|
+ |
81 |
|
|
+/* System timezone database pointer. */ |
82 |
|
|
+static const timelib_tzdb *timezonedb_system = NULL; |
83 |
|
|
+ |
84 |
|
|
+/* Hash table entry for the cache of the zone.tab mapping table. */ |
85 |
|
|
+struct location_info { |
86 |
|
|
+ char code[2]; |
87 |
|
|
+ double latitude, longitude; |
88 |
|
|
+ char name[64]; |
89 |
|
|
+ char *comment; |
90 |
|
|
+ struct location_info *next; |
91 |
|
|
+}; |
92 |
|
|
+ |
93 |
|
|
+/* Cache of zone.tab. */ |
94 |
|
|
+static struct location_info **system_location_table; |
95 |
|
|
+ |
96 |
|
|
+/* Size of the zone.tab hash table; a random-ish prime big enough to |
97 |
|
|
+ * prevent too many collisions. */ |
98 |
|
|
+#define LOCINFO_HASH_SIZE (1021) |
99 |
|
|
+ |
100 |
|
|
+static uint32_t tz_hash(const char *str) |
101 |
|
|
+{ |
102 |
|
|
+ const unsigned char *p = (const unsigned char *)str; |
103 |
|
|
+ uint32_t hash = 5381; |
104 |
|
|
+ int c; |
105 |
|
|
+ |
106 |
|
|
+ while ((c = *p++) != '\0') { |
107 |
|
|
+ hash = (hash << 5) ^ hash ^ c; |
108 |
|
|
+ } |
109 |
|
|
+ |
110 |
|
|
+ return hash % LOCINFO_HASH_SIZE; |
111 |
|
|
+} |
112 |
|
|
+ |
113 |
|
|
+/* Parse an ISO-6709 date as used in zone.tab. Returns end of the |
114 |
|
|
+ * parsed string on success, or NULL on parse error. On success, |
115 |
|
|
+ * writes the parsed number to *result. */ |
116 |
|
|
+static char *parse_iso6709(char *p, double *result) |
117 |
|
|
+{ |
118 |
|
|
+ double v, sign; |
119 |
|
|
+ char *pend; |
120 |
|
|
+ size_t len; |
121 |
|
|
+ |
122 |
|
|
+ if (*p == '+') |
123 |
|
|
+ sign = 1.0; |
124 |
|
|
+ else if (*p == '-') |
125 |
|
|
+ sign = -1.0; |
126 |
|
|
+ else |
127 |
|
|
+ return NULL; |
128 |
|
|
+ |
129 |
|
|
+ p++; |
130 |
|
|
+ for (pend = p; *pend >= '0' && *pend <= '9'; pend++) |
131 |
|
|
+ ;; |
132 |
|
|
+ |
133 |
|
|
+ /* Annoying encoding used by zone.tab has no decimal point, so use |
134 |
|
|
+ * the length to determine the format: |
135 |
|
|
+ * |
136 |
|
|
+ * 4 = DDMM |
137 |
|
|
+ * 5 = DDDMM |
138 |
|
|
+ * 6 = DDMMSS |
139 |
|
|
+ * 7 = DDDMMSS |
140 |
|
|
+ */ |
141 |
|
|
+ len = pend - p; |
142 |
|
|
+ if (len < 4 || len > 7) { |
143 |
|
|
+ return NULL; |
144 |
|
|
+ } |
145 |
|
|
+ |
146 |
|
|
+ /* p => [D]DD */ |
147 |
|
|
+ v = (p[0] - '0') * 10.0 + (p[1] - '0'); |
148 |
|
|
+ p += 2; |
149 |
|
|
+ if (len == 5 || len == 7) |
150 |
|
|
+ v = v * 10.0 + (*p++ - '0'); |
151 |
|
|
+ /* p => MM[SS] */ |
152 |
|
|
+ v += (10.0 * (p[0] - '0') |
153 |
|
|
+ + p[1] - '0') / 60.0; |
154 |
|
|
+ p += 2; |
155 |
|
|
+ /* p => [SS] */ |
156 |
|
|
+ if (len > 5) { |
157 |
|
|
+ v += (10.0 * (p[0] - '0') |
158 |
|
|
+ + p[1] - '0') / 3600.0; |
159 |
|
|
+ p += 2; |
160 |
|
|
+ } |
161 |
|
|
+ |
162 |
|
|
+ /* Round to five decimal place, not because it's a good idea, |
163 |
|
|
+ * but, because the builtin data uses rounded data, so, match |
164 |
|
|
+ * that. */ |
165 |
|
|
+ *result = round(v * sign * 100000.0) / 100000.0; |
166 |
|
|
+ |
167 |
|
|
+ return p; |
168 |
|
|
+} |
169 |
|
|
+ |
170 |
|
|
+/* This function parses the zone.tab file to build up the mapping of |
171 |
|
|
+ * timezone to country code and geographic location, and returns a |
172 |
|
|
+ * hash table. The hash table is indexed by the function: |
173 |
|
|
+ * |
174 |
|
|
+ * tz_hash(timezone-name) |
175 |
|
|
+ */ |
176 |
|
|
+static struct location_info **create_location_table(void) |
177 |
|
|
+{ |
178 |
|
|
+ struct location_info **li, *i; |
179 |
|
|
+ char zone_tab[PATH_MAX]; |
180 |
|
|
+ char line[512]; |
181 |
|
|
+ FILE *fp; |
182 |
|
|
+ |
183 |
|
|
+ strncpy(zone_tab, ZONEINFO_PREFIX "/zone.tab", sizeof zone_tab); |
184 |
|
|
+ |
185 |
|
|
+ fp = fopen(zone_tab, "r"); |
186 |
|
|
+ if (!fp) { |
187 |
|
|
+ return NULL; |
188 |
|
|
+ } |
189 |
|
|
+ |
190 |
|
|
+ li = calloc(LOCINFO_HASH_SIZE, sizeof *li); |
191 |
|
|
+ |
192 |
|
|
+ while (fgets(line, sizeof line, fp)) { |
193 |
|
|
+ char *p = line, *code, *name, *comment; |
194 |
|
|
+ uint32_t hash; |
195 |
|
|
+ double latitude, longitude; |
196 |
|
|
+ |
197 |
|
|
+ while (isspace(*p)) |
198 |
|
|
+ p++; |
199 |
|
|
+ |
200 |
|
|
+ if (*p == '#' || *p == '\0' || *p == '\n') |
201 |
|
|
+ continue; |
202 |
|
|
+ |
203 |
|
|
+ if (!isalpha(p[0]) || !isalpha(p[1]) || p[2] != '\t') |
204 |
|
|
+ continue; |
205 |
|
|
+ |
206 |
|
|
+ /* code => AA */ |
207 |
|
|
+ code = p; |
208 |
|
|
+ p[2] = 0; |
209 |
|
|
+ p += 3; |
210 |
|
|
+ |
211 |
|
|
+ /* coords => [+-][D]DDMM[SS][+-][D]DDMM[SS] */ |
212 |
|
|
+ p = parse_iso6709(p, &latitude); |
213 |
|
|
+ if (!p) { |
214 |
|
|
+ continue; |
215 |
|
|
+ } |
216 |
|
|
+ p = parse_iso6709(p, &longitude); |
217 |
|
|
+ if (!p) { |
218 |
|
|
+ continue; |
219 |
|
|
+ } |
220 |
|
|
+ |
221 |
|
|
+ if (!p || *p != '\t') { |
222 |
|
|
+ continue; |
223 |
|
|
+ } |
224 |
|
|
+ |
225 |
|
|
+ /* name = string */ |
226 |
|
|
+ name = ++p; |
227 |
|
|
+ while (*p != '\t' && *p && *p != '\n') |
228 |
|
|
+ p++; |
229 |
|
|
+ |
230 |
|
|
+ *p++ = '\0'; |
231 |
|
|
+ |
232 |
|
|
+ /* comment = string */ |
233 |
|
|
+ comment = p; |
234 |
|
|
+ while (*p != '\t' && *p && *p != '\n') |
235 |
|
|
+ p++; |
236 |
|
|
+ |
237 |
|
|
+ if (*p == '\n' || *p == '\t') |
238 |
|
|
+ *p = '\0'; |
239 |
|
|
+ |
240 |
|
|
+ hash = tz_hash(name); |
241 |
|
|
+ i = malloc(sizeof *i); |
242 |
|
|
+ memcpy(i->code, code, 2); |
243 |
|
|
+ strncpy(i->name, name, sizeof i->name); |
244 |
|
|
+ i->comment = strdup(comment); |
245 |
|
|
+ i->longitude = longitude; |
246 |
|
|
+ i->latitude = latitude; |
247 |
|
|
+ i->next = li[hash]; |
248 |
|
|
+ li[hash] = i; |
249 |
|
|
+ /* printf("%s [%u, %f, %f]\n", name, hash, latitude, longitude); */ |
250 |
|
|
+ } |
251 |
|
|
+ |
252 |
|
|
+ fclose(fp); |
253 |
|
|
+ |
254 |
|
|
+ return li; |
255 |
|
|
+} |
256 |
|
|
+ |
257 |
|
|
+/* Return location info from hash table, using given timezone name. |
258 |
|
|
+ * Returns NULL if the name could not be found. */ |
259 |
|
|
+const struct location_info *find_zone_info(struct location_info **li, |
260 |
|
|
+ const char *name) |
261 |
|
|
+{ |
262 |
|
|
+ uint32_t hash = tz_hash(name); |
263 |
|
|
+ const struct location_info *l; |
264 |
|
|
+ |
265 |
|
|
+ if (!li) { |
266 |
|
|
+ return NULL; |
267 |
|
|
+ } |
268 |
|
|
+ |
269 |
|
|
+ for (l = li[hash]; l; l = l->next) { |
270 |
|
|
+ if (strcasecmp(l->name, name) == 0) |
271 |
|
|
+ return l; |
272 |
|
|
+ } |
273 |
|
|
+ |
274 |
|
|
+ return NULL; |
275 |
|
|
+} |
276 |
|
|
+ |
277 |
|
|
+/* Filter out some non-tzdata files and the posix/right databases, if |
278 |
|
|
+ * present. */ |
279 |
|
|
+static int index_filter(const struct dirent *ent) |
280 |
|
|
+{ |
281 |
|
|
+ return strcmp(ent->d_name, ".") != 0 |
282 |
|
|
+ && strcmp(ent->d_name, "..") != 0 |
283 |
|
|
+ && strcmp(ent->d_name, "posix") != 0 |
284 |
|
|
+ && strcmp(ent->d_name, "posixrules") != 0 |
285 |
|
|
+ && strcmp(ent->d_name, "right") != 0 |
286 |
|
|
+ && strstr(ent->d_name, ".tab") == NULL; |
287 |
|
|
+} |
288 |
|
|
+ |
289 |
|
|
+static int sysdbcmp(const void *first, const void *second) |
290 |
|
|
+{ |
291 |
|
|
+ const timelib_tzdb_index_entry *alpha = first, *beta = second; |
292 |
|
|
+ |
293 |
|
|
+ return strcmp(alpha->id, beta->id); |
294 |
|
|
+} |
295 |
|
|
+ |
296 |
|
|
+ |
297 |
|
|
+/* Create the zone identifier index by trawling the filesystem. */ |
298 |
|
|
+static void create_zone_index(timelib_tzdb *db) |
299 |
|
|
+{ |
300 |
|
|
+ size_t dirstack_size, dirstack_top; |
301 |
|
|
+ size_t index_size, index_next; |
302 |
|
|
+ timelib_tzdb_index_entry *db_index; |
303 |
|
|
+ char **dirstack; |
304 |
|
|
+ |
305 |
|
|
+ /* LIFO stack to hold directory entries to scan; each slot is a |
306 |
|
|
+ * directory name relative to the zoneinfo prefix. */ |
307 |
|
|
+ dirstack_size = 32; |
308 |
|
|
+ dirstack = malloc(dirstack_size * sizeof *dirstack); |
309 |
|
|
+ dirstack_top = 1; |
310 |
|
|
+ dirstack[0] = strdup(""); |
311 |
|
|
+ |
312 |
|
|
+ /* Index array. */ |
313 |
|
|
+ index_size = 64; |
314 |
|
|
+ db_index = malloc(index_size * sizeof *db_index); |
315 |
|
|
+ index_next = 0; |
316 |
|
|
+ |
317 |
|
|
+ do { |
318 |
|
|
+ struct dirent **ents; |
319 |
|
|
+ char name[PATH_MAX], *top; |
320 |
|
|
+ int count; |
321 |
|
|
+ |
322 |
|
|
+ /* Pop the top stack entry, and iterate through its contents. */ |
323 |
|
|
+ top = dirstack[--dirstack_top]; |
324 |
|
|
+ snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s", top); |
325 |
|
|
+ |
326 |
|
|
+ count = php_scandir(name, &ents, index_filter, php_alphasort); |
327 |
|
|
+ |
328 |
|
|
+ while (count > 0) { |
329 |
|
|
+ struct stat st; |
330 |
|
|
+ const char *leaf = ents[count - 1]->d_name; |
331 |
|
|
+ |
332 |
|
|
+ snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s/%s", |
333 |
|
|
+ top, leaf); |
334 |
|
|
+ |
335 |
|
|
+ if (strlen(name) && stat(name, &st) == 0) { |
336 |
|
|
+ /* Name, relative to the zoneinfo prefix. */ |
337 |
|
|
+ const char *root = top; |
338 |
|
|
+ |
339 |
|
|
+ if (root[0] == '/') root++; |
340 |
|
|
+ |
341 |
|
|
+ snprintf(name, sizeof name, "%s%s%s", root, |
342 |
|
|
+ *root ? "/": "", leaf); |
343 |
|
|
+ |
344 |
|
|
+ if (S_ISDIR(st.st_mode)) { |
345 |
|
|
+ if (dirstack_top == dirstack_size) { |
346 |
|
|
+ dirstack_size *= 2; |
347 |
|
|
+ dirstack = realloc(dirstack, |
348 |
|
|
+ dirstack_size * sizeof *dirstack); |
349 |
|
|
+ } |
350 |
|
|
+ dirstack[dirstack_top++] = strdup(name); |
351 |
|
|
+ } |
352 |
|
|
+ else { |
353 |
|
|
+ if (index_next == index_size) { |
354 |
|
|
+ index_size *= 2; |
355 |
|
|
+ db_index = realloc(db_index, |
356 |
|
|
+ index_size * sizeof *db_index); |
357 |
|
|
+ } |
358 |
|
|
+ |
359 |
|
|
+ db_index[index_next++].id = strdup(name); |
360 |
|
|
+ } |
361 |
|
|
+ } |
362 |
|
|
+ |
363 |
|
|
+ free(ents[--count]); |
364 |
|
|
+ } |
365 |
|
|
+ |
366 |
|
|
+ if (count != -1) free(ents); |
367 |
|
|
+ free(top); |
368 |
|
|
+ } while (dirstack_top); |
369 |
|
|
+ |
370 |
|
|
+ qsort(db_index, index_next, sizeof *db_index, sysdbcmp); |
371 |
|
|
+ |
372 |
|
|
+ db->index = db_index; |
373 |
|
|
+ db->index_size = index_next; |
374 |
|
|
+ |
375 |
|
|
+ free(dirstack); |
376 |
|
|
+} |
377 |
|
|
+ |
378 |
|
|
+#define FAKE_HEADER "1234\0??\1??" |
379 |
|
|
+#define FAKE_UTC_POS (7 - 4) |
380 |
|
|
+ |
381 |
|
|
+/* Create a fake data segment for database 'sysdb'. */ |
382 |
|
|
+static void fake_data_segment(timelib_tzdb *sysdb, |
383 |
|
|
+ struct location_info **info) |
384 |
|
|
+{ |
385 |
|
|
+ size_t n; |
386 |
|
|
+ char *data, *p; |
387 |
|
|
+ |
388 |
|
|
+ data = malloc(3 * sysdb->index_size + 7); |
389 |
|
|
+ |
390 |
|
|
+ p = mempcpy(data, FAKE_HEADER, sizeof(FAKE_HEADER) - 1); |
391 |
|
|
+ |
392 |
|
|
+ for (n = 0; n < sysdb->index_size; n++) { |
393 |
|
|
+ const struct location_info *li; |
394 |
|
|
+ timelib_tzdb_index_entry *ent; |
395 |
|
|
+ |
396 |
|
|
+ ent = (timelib_tzdb_index_entry *)&sysdb->index[n]; |
397 |
|
|
+ |
398 |
|
|
+ /* Lookup the timezone name in the hash table. */ |
399 |
|
|
+ if (strcmp(ent->id, "UTC") == 0) { |
400 |
|
|
+ ent->pos = FAKE_UTC_POS; |
401 |
|
|
+ continue; |
402 |
|
|
+ } |
403 |
|
|
+ |
404 |
|
|
+ li = find_zone_info(info, ent->id); |
405 |
|
|
+ if (li) { |
406 |
|
|
+ /* If found, append the BC byte and the |
407 |
|
|
+ * country code; set the position for this |
408 |
|
|
+ * section of timezone data. */ |
409 |
|
|
+ ent->pos = (p - data) - 4; |
410 |
|
|
+ *p++ = '\1'; |
411 |
|
|
+ *p++ = li->code[0]; |
412 |
|
|
+ *p++ = li->code[1]; |
413 |
|
|
+ } |
414 |
|
|
+ else { |
415 |
|
|
+ /* If not found, the timezone data can |
416 |
|
|
+ * point at the header. */ |
417 |
|
|
+ ent->pos = 0; |
418 |
|
|
+ } |
419 |
|
|
+ } |
420 |
|
|
+ |
421 |
|
|
+ sysdb->data = (unsigned char *)data; |
422 |
|
|
+} |
423 |
|
|
+ |
424 |
|
|
+/* Returns true if the passed-in stat structure describes a |
425 |
|
|
+ * probably-valid timezone file. */ |
426 |
|
|
+static int is_valid_tzfile(const struct stat *st) |
427 |
|
|
+{ |
428 |
|
|
+ return S_ISREG(st->st_mode) && st->st_size > 20; |
429 |
|
|
+} |
430 |
|
|
+ |
431 |
|
|
+/* Return the mmap()ed tzfile if found, else NULL. On success, the |
432 |
|
|
+ * length of the mapped data is placed in *length. */ |
433 |
|
|
+static char *map_tzfile(const char *timezone, size_t *length) |
434 |
|
|
+{ |
435 |
|
|
+ char fname[PATH_MAX]; |
436 |
|
|
+ struct stat st; |
437 |
|
|
+ char *p; |
438 |
|
|
+ int fd; |
439 |
|
|
+ |
440 |
|
|
+ if (timezone[0] == '\0' || strstr(timezone, "..") != NULL) { |
441 |
|
|
+ return NULL; |
442 |
|
|
+ } |
443 |
|
|
+ |
444 |
|
|
+ snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); |
445 |
|
|
+ |
446 |
|
|
+ fd = open(fname, O_RDONLY); |
447 |
|
|
+ if (fd == -1) { |
448 |
|
|
+ return NULL; |
449 |
|
|
+ } else if (fstat(fd, &st) != 0 || !is_valid_tzfile(&st)) { |
450 |
|
|
+ close(fd); |
451 |
|
|
+ return NULL; |
452 |
|
|
+ } |
453 |
|
|
+ |
454 |
|
|
+ *length = st.st_size; |
455 |
|
|
+ p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); |
456 |
|
|
+ close(fd); |
457 |
|
|
+ |
458 |
|
|
+ return p != MAP_FAILED ? p : NULL; |
459 |
|
|
+} |
460 |
|
|
+ |
461 |
|
|
+#endif |
462 |
|
|
+ |
463 |
|
|
+static int inmem_seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb) |
464 |
|
|
{ |
465 |
|
|
int left = 0, right = tzdb->index_size - 1; |
466 |
|
|
#ifdef HAVE_SETLOCALE |
467 |
|
|
@@ -292,36 +702,125 @@ static int seek_to_tz_position(const uns |
468 |
|
|
return 0; |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
+static int seek_to_tz_position(const unsigned char **tzf, char *timezone, |
472 |
|
|
+ char **map, size_t *maplen, |
473 |
|
|
+ const timelib_tzdb *tzdb) |
474 |
|
|
+{ |
475 |
|
|
+ if (tzdb == timezonedb_system) { |
476 |
|
|
+ char *orig; |
477 |
|
|
+ |
478 |
|
|
+ orig = map_tzfile(timezone, maplen); |
479 |
|
|
+ if (orig == NULL) { |
480 |
|
|
+ return 0; |
481 |
|
|
+ } |
482 |
|
|
+ |
483 |
|
|
+ (*tzf) = (unsigned char *)orig ; |
484 |
|
|
+ *map = orig; |
485 |
|
|
+ |
486 |
|
|
+ return 1; |
487 |
|
|
+ } |
488 |
|
|
+ else { |
489 |
|
|
+ return inmem_seek_to_tz_position(tzf, timezone, tzdb); |
490 |
|
|
+ } |
491 |
|
|
+} |
492 |
|
|
+ |
493 |
|
|
const timelib_tzdb *timelib_builtin_db(void) |
494 |
|
|
{ |
495 |
|
|
+#ifdef HAVE_SYSTEM_TZDATA |
496 |
|
|
+ if (timezonedb_system == NULL) { |
497 |
|
|
+ timelib_tzdb *tmp = malloc(sizeof *tmp); |
498 |
|
|
+ |
499 |
|
|
+ tmp->version = "0.system"; |
500 |
|
|
+ tmp->data = NULL; |
501 |
|
|
+ create_zone_index(tmp); |
502 |
|
|
+ system_location_table = create_location_table(); |
503 |
|
|
+ fake_data_segment(tmp, system_location_table); |
504 |
|
|
+ timezonedb_system = tmp; |
505 |
|
|
+ } |
506 |
|
|
+ |
507 |
|
|
+ |
508 |
|
|
+ return timezonedb_system; |
509 |
|
|
+#else |
510 |
|
|
return &timezonedb_builtin; |
511 |
|
|
+#endif |
512 |
|
|
} |
513 |
|
|
|
514 |
|
|
const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count) |
515 |
|
|
{ |
516 |
|
|
+#ifdef HAVE_SYSTEM_TZDATA |
517 |
|
|
+ *count = timezonedb_system->index_size; |
518 |
|
|
+ return timezonedb_system->index; |
519 |
|
|
+#else |
520 |
|
|
*count = sizeof(timezonedb_idx_builtin) / sizeof(*timezonedb_idx_builtin); |
521 |
|
|
return timezonedb_idx_builtin; |
522 |
|
|
+#endif |
523 |
|
|
} |
524 |
|
|
|
525 |
|
|
int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb) |
526 |
|
|
{ |
527 |
|
|
const unsigned char *tzf; |
528 |
|
|
- return (seek_to_tz_position(&tzf, timezone, tzdb)); |
529 |
|
|
+ |
530 |
|
|
+#ifdef HAVE_SYSTEM_TZDATA |
531 |
|
|
+ if (tzdb == timezonedb_system) { |
532 |
|
|
+ char fname[PATH_MAX]; |
533 |
|
|
+ struct stat st; |
534 |
|
|
+ |
535 |
|
|
+ if (timezone[0] == '\0' || strstr(timezone, "..") != NULL) { |
536 |
|
|
+ return 0; |
537 |
|
|
+ } |
538 |
|
|
+ |
539 |
|
|
+ snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); |
540 |
|
|
+ |
541 |
|
|
+ return stat(fname, &st) == 0 && is_valid_tzfile(&st); |
542 |
|
|
+ } |
543 |
|
|
+#endif |
544 |
|
|
+ |
545 |
|
|
+ return (inmem_seek_to_tz_position(&tzf, timezone, tzdb)); |
546 |
|
|
} |
547 |
|
|
|
548 |
|
|
timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb) |
549 |
|
|
{ |
550 |
|
|
const unsigned char *tzf; |
551 |
|
|
+ char *memmap = NULL; |
552 |
|
|
+ size_t maplen; |
553 |
|
|
timelib_tzinfo *tmp; |
554 |
|
|
|
555 |
|
|
- if (seek_to_tz_position(&tzf, timezone, tzdb)) { |
556 |
|
|
+ if (seek_to_tz_position(&tzf, timezone, &memmap, &maplen, tzdb)) { |
557 |
|
|
tmp = timelib_tzinfo_ctor(timezone); |
558 |
|
|
|
559 |
|
|
read_preamble(&tzf, tmp); |
560 |
|
|
read_header(&tzf, tmp); |
561 |
|
|
read_transistions(&tzf, tmp); |
562 |
|
|
read_types(&tzf, tmp); |
563 |
|
|
- read_location(&tzf, tmp); |
564 |
|
|
+ |
565 |
|
|
+#ifdef HAVE_SYSTEM_TZDATA |
566 |
|
|
+ if (memmap) { |
567 |
|
|
+ const struct location_info *li; |
568 |
|
|
+ |
569 |
|
|
+ /* TZif-style - grok the location info from the system database, |
570 |
|
|
+ * if possible. */ |
571 |
|
|
+ |
572 |
|
|
+ if ((li = find_zone_info(system_location_table, timezone)) != NULL) { |
573 |
|
|
+ tmp->location.comments = strdup(li->comment); |
574 |
|
|
+ strncpy(tmp->location.country_code, li->code, 2); |
575 |
|
|
+ tmp->location.longitude = li->longitude; |
576 |
|
|
+ tmp->location.latitude = li->latitude; |
577 |
|
|
+ tmp->bc = 1; |
578 |
|
|
+ } |
579 |
|
|
+ else { |
580 |
|
|
+ strcpy(tmp->location.country_code, "??"); |
581 |
|
|
+ tmp->bc = 0; |
582 |
|
|
+ tmp->location.comments = strdup(""); |
583 |
|
|
+ } |
584 |
|
|
+ |
585 |
|
|
+ /* Now done with the mmap segment - discard it. */ |
586 |
|
|
+ munmap(memmap, maplen); |
587 |
|
|
+#endif |
588 |
|
|
+ } |
589 |
|
|
+ else { |
590 |
|
|
+ /* PHP-style - use the embedded info. */ |
591 |
|
|
+ read_location(&tzf, tmp); |
592 |
|
|
+ } |
593 |
|
|
} else { |
594 |
|
|
tmp = NULL; |
595 |
|
|
} |
596 |
|
|
--- php-5.3.1/ext/date/lib/timelib.m4.systzdata |
597 |
|
|
+++ php-5.3.1/ext/date/lib/timelib.m4 |
598 |
|
|
@@ -78,3 +78,17 @@ stdlib.h |
599 |
|
|
|
600 |
|
|
dnl Check for strtoll, atoll |
601 |
|
|
AC_CHECK_FUNCS(strtoll atoll strftime) |
602 |
|
|
+ |
603 |
|
|
+PHP_ARG_WITH(system-tzdata, for use of system timezone data, |
604 |
|
|
+[ --with-system-tzdata[=DIR] to specify use of system timezone data], |
605 |
|
|
+no, no) |
606 |
|
|
+ |
607 |
|
|
+if test "$PHP_SYSTEM_TZDATA" != "no"; then |
608 |
|
|
+ AC_DEFINE(HAVE_SYSTEM_TZDATA, 1, [Define if system timezone data is used]) |
609 |
|
|
+ |
610 |
|
|
+ if test "$PHP_SYSTEM_TZDATA" != "yes"; then |
611 |
|
|
+ AC_DEFINE_UNQUOTED(HAVE_SYSTEM_TZDATA_PREFIX, "$PHP_SYSTEM_TZDATA", |
612 |
|
|
+ [Define for location of system timezone data]) |
613 |
|
|
+ fi |
614 |
|
|
+fi |
615 |
|
|
+ |