glib: Update gtimezone.c patch after review
[termux-packages] / packages / glib / glib-gtimezone.c.patch
1 Patch submitted at https://bugzilla.gnome.org/show_bug.cgi?id=771304
2
3 diff -u -r ../glib-2.54.2/glib/gtimezone.c ./glib/gtimezone.c
4 --- ../glib-2.54.2/glib/gtimezone.c 2017-07-14 01:03:39.000000000 +0200
5 +++ ./glib/gtimezone.c 2017-12-09 02:03:46.797229494 +0100
6 @@ -43,6 +43,14 @@
7 #include <windows.h>
8 #endif
9
10 +#ifdef __ANDROID__
11 +#include <arpa/inet.h>
12 +#include <errno.h>
13 +#include <fcntl.h>
14 +#include <sys/system_properties.h>
15 +#include <unistd.h>
16 +#endif
17 +
18 /**
19 * SECTION:timezone
20 * @title: GTimeZone
21 @@ -392,7 +399,116 @@
22 gtz->transitions = NULL;
23 }
24
25 -#ifdef G_OS_UNIX
26 +#ifdef __ANDROID__
27 +/* Android uses a 'persist.sys.timezone' system property for the
28 + current timezone instead of a /etc/localtime file:
29 + https://android.googlesource.com/platform/ndk/+/android-2.2_r1/docs/system/libc/OVERVIEW.TXT#67
30 +
31 + There are no files under /usr/share/zoneinfo - instead a single
32 + /system/usr/share/zoneinfo/tzdata file is used which contains all
33 + files compiled together with the following tool:
34 + https://android.googlesource.com/platform/system/timezone/+/master/zone_compactor/main/java/ZoneCompactor.java */
35 +static GBytes*
36 +zone_info_android (const gchar *identifier)
37 +{
38 + struct tzdata_header
39 + {
40 + char version[12];
41 + uint32_t index_offset;
42 + uint32_t data_offset;
43 + uint32_t zonetab_offset;
44 + } __attribute__((packed)) header;
45 +
46 + struct tzdata_index_entry
47 + {
48 + char name[40];
49 + uint32_t offset;
50 + uint32_t length;
51 + uint32_t unused;
52 + } __attribute__((packed)) entry;
53 +
54 + char sys_timezone[PROP_VALUE_MAX];
55 + int tzdata_fd;
56 +
57 + if (identifier == NULL)
58 + {
59 + if (__system_property_get ("persist.sys.timezone", sys_timezone) < 1)
60 + {
61 + g_warning ("__system_property_get(\"persist.sys.timezone\") failed");
62 + return NULL;
63 + }
64 + identifier = sys_timezone;
65 + }
66 +
67 + tzdata_fd = TEMP_FAILURE_RETRY(open ("/system/usr/share/zoneinfo/tzdata", O_RDONLY));
68 + if (tzdata_fd < 0)
69 + {
70 + g_warning ("Failed opening tzdata");
71 + return NULL;
72 + }
73 +
74 + if (TEMP_FAILURE_RETRY(read (tzdata_fd, &header, sizeof(header)) < (ssize_t) sizeof (header)))
75 + {
76 + g_warning ("Failed reading tzdata header");
77 + goto error;
78 + }
79 +
80 + header.index_offset = htonl (header.index_offset);
81 + header.data_offset = htonl (header.data_offset);
82 +
83 + uint32_t current_offset = header.index_offset;
84 + while (current_offset < header.data_offset)
85 + {
86 + if (TEMP_FAILURE_RETRY(read (tzdata_fd, &entry, sizeof(entry)) < (ssize_t) sizeof (entry)))
87 + {
88 + g_warning ("Failed reading tzdata index entry");
89 + goto error;
90 + }
91 +
92 + if (strcmp (entry.name, identifier) == 0)
93 + {
94 + entry.offset = htonl (entry.offset);
95 + entry.length = htonl (entry.length);
96 + if (entry.length == 0)
97 + {
98 + g_warning ("Invalid tzdata entry with length zero");
99 + goto error;
100 + }
101 +
102 + if (TEMP_FAILURE_RETRY(lseek (tzdata_fd, header.data_offset + entry.offset, SEEK_SET) == -1))
103 + {
104 + g_warning ("Failed seeking to tzdata entry");
105 + goto error;
106 + }
107 +
108 + /* Use a reasonable but arbitrary max length of an entry. */
109 + if (entry.length > 65536)
110 + {
111 + g_warning ("Too large tzdata entry length");
112 + goto error;
113 + }
114 +
115 + guint8* data = g_malloc (entry.length);
116 + if (TEMP_FAILURE_RETRY(read (tzdata_fd, data, entry.length) < entry.length))
117 + {
118 + g_warning ("Failed reading tzdata entry");
119 + g_free (data);
120 + goto error;
121 + }
122 +
123 + close (tzdata_fd);
124 + return g_bytes_new_take (data, entry.length);
125 + }
126 + }
127 +
128 +error:
129 + close (tzdata_fd);
130 +
131 + return NULL;
132 +}
133 +
134 +#elif defined(G_OS_UNIX)
135 +
136 static GBytes*
137 zone_info_unix (const gchar *identifier)
138 {
139 @@ -436,6 +541,10 @@
140 return zoneinfo;
141 }
142
143 +#endif
144 +
145 +#ifdef G_OS_UNIX
146 +
147 static void
148 init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo)
149 {
150 @@ -1387,7 +1496,11 @@
151 if (tz->t_info == NULL)
152 {
153 #ifdef G_OS_UNIX
154 +# ifdef __ANDROID__
155 + GBytes *zoneinfo = zone_info_android (identifier);
156 +# else
157 GBytes *zoneinfo = zone_info_unix (identifier);
158 +# endif
159 if (!zoneinfo)
160 zone_for_constant_offset (tz, "UTC");
161 else