Commit | Line | Data |
---|---|---|
69fd9a5c FF |
1 | Patch submitted at https://bugzilla.gnome.org/show_bug.cgi?id=771304 |
2 | ||
8aef3a59 FF |
3 | diff -u -r ../glib-2.48.2/glib/gtimezone.c ./glib/gtimezone.c |
4 | --- ../glib-2.48.2/glib/gtimezone.c 2016-08-17 12:07:29.000000000 -0400 | |
5 | +++ ./glib/gtimezone.c 2016-09-12 16:52:41.864974630 -0400 | |
6 | @@ -43,6 +43,11 @@ | |
7 | #include <windows.h> | |
8 | #endif | |
9 | ||
10 | +#ifdef __ANDROID__ | |
11 | +#include <fcntl.h> | |
12 | +#include <sys/system_properties.h> | |
13 | +#endif | |
14 | + | |
15 | /** | |
16 | * SECTION:timezone | |
17 | * @title: GTimeZone | |
18 | @@ -396,6 +400,75 @@ | |
19 | static GBytes* | |
20 | zone_info_unix (const gchar *identifier) | |
21 | { | |
22 | +#ifdef __ANDROID__ | |
23 | + /* Android does not have /etc/localtime but uses a system property for the | |
24 | + the current timezone. There are no files under /usr/share/zoneinfo, | |
25 | + instead a single /system/usr/share/zoneinfo/tzdata which are all zoneinfo | |
26 | + files compiled together with the following tool: | |
27 | + https://android.googlesource.com/platform/external/icu/+/master/tools/ZoneCompactor.java */ | |
28 | + struct tzdata_header { | |
29 | + char version[12]; | |
30 | + uint32_t index_offset, data_offset, zonetab_offset; | |
31 | + } __attribute__((packed)) header; | |
32 | + | |
33 | + struct tzdata_index_entry { | |
34 | + char name[40]; | |
35 | + uint32_t offset, length, unused; | |
36 | + } __attribute__((packed)) entry; | |
37 | + | |
69fd9a5c | 38 | + char sys_timezone[PROP_VALUE_MAX]; |
8aef3a59 | 39 | + if (identifier == NULL) { |
8aef3a59 FF |
40 | + if (__system_property_get("persist.sys.timezone", sys_timezone) < 1) { |
41 | + g_warning("__system_property_get(\"persist.sys.timezone\") failed\n"); | |
42 | + return NULL; | |
43 | + } | |
44 | + identifier = sys_timezone; | |
45 | + } | |
46 | + if (identifier != NULL) { | |
47 | + int tzdata_fd = open("/system/usr/share/zoneinfo/tzdata", O_RDONLY); | |
48 | + if (tzdata_fd < 0) { | |
49 | + g_warning("Failed opening tzdata"); | |
50 | + return NULL; | |
51 | + } | |
52 | + if (read(tzdata_fd, &header, sizeof(header)) < (ssize_t) sizeof(header)) { | |
53 | + g_warning("Failed reading tzdata header"); | |
54 | + goto error; | |
55 | + } | |
56 | + header.index_offset = htonl(header.index_offset); | |
57 | + header.data_offset = htonl(header.data_offset); | |
58 | + | |
59 | + uint32_t current_offset = header.index_offset; | |
60 | + while (current_offset < header.data_offset) { | |
61 | + if (read(tzdata_fd, &entry, sizeof(entry)) < (ssize_t) sizeof(entry)) { | |
62 | + g_warning("Failed reading tzdata index entry"); | |
63 | + goto error; | |
64 | + } | |
65 | + if (strcmp(entry.name, identifier) == 0) { | |
66 | + entry.offset = htonl(entry.offset); | |
67 | + entry.length = htonl(entry.length); | |
68 | + if (entry.length == 0) { | |
69 | + g_warning("Invalid tzdata entry with length zero"); | |
70 | + goto error; | |
71 | + } | |
72 | + if (lseek(tzdata_fd, header.data_offset + entry.offset, SEEK_SET) == -1) { | |
73 | + g_warning("Failed seeking to tzdata entry"); | |
74 | + goto error; | |
75 | + } | |
76 | + guint8* data = g_malloc(entry.length); | |
77 | + if (read(tzdata_fd, data, entry.length) < entry.length) { | |
78 | + g_warning("Failed reading tzdata entry"); | |
79 | + g_free(data); | |
80 | + goto error; | |
81 | + } | |
82 | + close(tzdata_fd); | |
83 | + return g_bytes_new_take(data, entry.length); | |
84 | + } | |
85 | + } | |
86 | +error: | |
87 | + close(tzdata_fd); | |
88 | + } | |
89 | + return NULL; | |
90 | +#else | |
91 | gchar *filename; | |
92 | GMappedFile *file = NULL; | |
93 | GBytes *zoneinfo = NULL; | |
94 | @@ -434,6 +497,7 @@ | |
95 | } | |
96 | g_free (filename); | |
97 | return zoneinfo; | |
98 | +#endif | |
99 | } | |
100 | ||
101 | static void |