2 Add support for use of the system timezone database, rather
3 than embedding a copy. Discussed upstream but was not desired.
6 r3: fix a crash if /usr/share/zoneinfo doesn't exist (Raphael Geissert)
7 r2: add filesystem trawl to set up name alias index
10 --- php-5.2.5/ext/date/lib/timelib.m4.systzdata
11 +++ php-5.2.5/ext/date/lib/timelib.m4
12 @@ -78,3 +78,17 @@ stdlib.h
14 dnl Check for strtoll, atoll
15 AC_CHECK_FUNCS(strtoll atoll strftime)
17 +PHP_ARG_WITH(system-tzdata, for use of system timezone data,
18 +[ --with-system-tzdata[=DIR] to specify use of system timezone data],
21 +if test "$PHP_SYSTEM_TZDATA" != "no"; then
22 + AC_DEFINE(HAVE_SYSTEM_TZDATA, 1, [Define if system timezone data is used])
24 + if test "$PHP_SYSTEM_TZDATA" != "yes"; then
25 + AC_DEFINE_UNQUOTED(HAVE_SYSTEM_TZDATA_PREFIX, "$PHP_SYSTEM_TZDATA",
26 + [Define for location of system timezone data])
30 --- php-5.2.5/ext/date/lib/parse_tz.c.systzdata
31 +++ php-5.2.5/ext/date/lib/parse_tz.c
36 +#ifdef HAVE_SYSTEM_TZDATA
37 +#include <sys/mman.h>
38 +#include <sys/stat.h>
43 +#include "php_scandir.h"
54 +#ifndef HAVE_SYSTEM_TZDATA
55 #include "timezonedb.h"
58 #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
59 # if defined(__LITTLE_ENDIAN__)
60 @@ -206,6 +219,195 @@ void timelib_dump_tzinfo(timelib_tzinfo
64 +#ifdef HAVE_SYSTEM_TZDATA
66 +#ifdef HAVE_SYSTEM_TZDATA_PREFIX
67 +#define ZONEINFO_PREFIX HAVE_SYSTEM_TZDATA_PREFIX
69 +#define ZONEINFO_PREFIX "/usr/share/zoneinfo"
72 +static const timelib_tzdb *timezonedb_system = NULL;
74 +/* Filter out some non-tzdata files and the posix/right databases, if
76 +static int index_filter(const struct dirent *ent)
78 + return strcmp(ent->d_name, ".") != 0
79 + && strcmp(ent->d_name, "..") != 0
80 + && strcmp(ent->d_name, "posix") != 0
81 + && strcmp(ent->d_name, "posixrules") != 0
82 + && strcmp(ent->d_name, "right") != 0
83 + && strstr(ent->d_name, ".tab") == NULL;
86 +/* Create the zone identifier index by trawling the filesystem. */
87 +static void create_zone_index(timelib_tzdb *db)
89 + size_t dirstack_size, dirstack_top;
90 + size_t index_size, index_next;
91 + timelib_tzdb_index_entry *db_index;
94 + /* LIFO stack to hold directory entries to scan; each slot is a
95 + * directory name relative to the zoneinfo prefix. */
97 + dirstack = malloc(dirstack_size * sizeof *dirstack);
99 + dirstack[0] = strdup("");
103 + db_index = malloc(index_size * sizeof *db_index);
107 + struct dirent **ents;
108 + char name[PATH_MAX], *top;
111 + /* Pop the top stack entry, and iterate through its contents. */
112 + top = dirstack[--dirstack_top];
113 + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s", top);
115 + count = php_scandir(name, &ents, index_filter, php_alphasort);
117 + while (count > 0) {
119 + const char *leaf = ents[count - 1]->d_name;
121 + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s/%s",
124 + if (strlen(name) && stat(name, &st) == 0) {
125 + /* Name, relative to the zoneinfo prefix. */
126 + const char *root = top;
128 + if (root[0] == '/') root++;
130 + snprintf(name, sizeof name, "%s%s%s", root,
131 + *root ? "/": "", leaf);
133 + if (S_ISDIR(st.st_mode)) {
134 + if (dirstack_top == dirstack_size) {
135 + dirstack_size *= 2;
136 + dirstack = realloc(dirstack,
137 + dirstack_size * sizeof *dirstack);
139 + dirstack[dirstack_top++] = strdup(name);
142 + if (index_next == index_size) {
144 + db_index = realloc(db_index,
145 + index_size * sizeof *db_index);
148 + db_index[index_next].id = strdup(name);
149 + db_index[index_next++].pos = 0;
153 + free(ents[--count]);
156 + if (count != -1) free(ents);
158 + } while (dirstack_top);
160 + db->index = db_index;
161 + db->index_size = index_next;
166 +/* Return the mmap()ed tzfile if found, else NULL. On success, the
167 + * length of the mapped data is placed in *length. */
168 +static char *map_tzfile(const char *timezone, size_t *length)
170 + char fname[PATH_MAX];
175 + if (strstr(timezone, "..") != NULL) {
179 + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone);
181 + fd = open(fname, O_RDONLY);
184 + } else if (fstat(fd, &st) != 0 || st.st_size < 21) {
189 + *length = st.st_size;
190 + p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
193 + return p != MAP_FAILED ? p : NULL;
196 +const timelib_tzdb *timelib_builtin_db(void)
198 + if (timezonedb_system == NULL) {
199 + timelib_tzdb *tmp = malloc(sizeof *tmp);
201 + tmp->version = "0.system";
203 + create_zone_index(tmp);
204 + timezonedb_system = tmp;
207 + return timezonedb_system;
210 +const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count)
212 + *count = timezonedb_system->index_size;
213 + return timezonedb_system->index;
216 +int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb)
218 + char fname[PATH_MAX];
220 + if (strstr(timezone, "..") != NULL) {
224 + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone);
226 + return access(fname, R_OK) == 0 ? 1 : 0;
229 +timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb)
232 + timelib_tzinfo *tmp;
235 + orig = map_tzfile(timezone, &len);
236 + if (orig == NULL) {
240 + tmp = timelib_tzinfo_ctor(timezone);
243 + read_header(&tzf, tmp);
244 + read_transistions(&tzf, tmp);
245 + read_types(&tzf, tmp);
251 +#else /* !HAVE_SYSTEM_TZDATA */
253 static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb)
255 int left = 0, right = tzdb->index_size - 1;
256 @@ -279,6 +481,7 @@ timelib_tzinfo *timelib_parse_tzfile(cha
262 static ttinfo* fetch_timezone_offset(timelib_tzinfo *tz, timelib_sll ts, timelib_sll *transition_time)