chiark / gitweb /
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,117 @@
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 + */
36 +static GBytes *
37 +zone_info_android (const gchar *identifier)
38 +{
39 +  struct tzdata_header
40 +  {
41 +    char     version[12];
42 +    uint32_t index_offset;
43 +    uint32_t data_offset;
44 +    uint32_t zonetab_offset;
45 +  } __attribute__((packed)) header;
46 +
47 +  struct tzdata_index_entry
48 +  {
49 +    char     name[40];
50 +    uint32_t offset;
51 +    uint32_t length;
52 +    uint32_t unused;
53 +  } __attribute__((packed)) entry;
54 +
55 +  char sys_timezone[PROP_VALUE_MAX];
56 +  int tzdata_fd;
57 +
58 +  if (identifier == NULL)
59 +    {
60 +      if (__system_property_get ("persist.sys.timezone", sys_timezone) < 1)
61 +        {
62 +          g_warning ("__system_property_get(\"persist.sys.timezone\") failed");
63 +          return NULL;
64 +        }
65 +      identifier = sys_timezone;
66 +    }
67 +
68 +  tzdata_fd = TEMP_FAILURE_RETRY (open ("/system/usr/share/zoneinfo/tzdata", O_RDONLY));
69 +  if (tzdata_fd < 0)
70 +  {
71 +    g_warning ("Failed opening tzdata");
72 +    return NULL;
73 +  }
74 +
75 +  if (TEMP_FAILURE_RETRY (read (tzdata_fd, &header, sizeof(header)) < (ssize_t) sizeof (header)))
76 +  {
77 +    g_warning ("Failed reading tzdata header");
78 +    goto error;
79 +  }
80 +
81 +  header.index_offset = htonl (header.index_offset);
82 +  header.data_offset = htonl (header.data_offset);
83 +
84 +  uint32_t current_offset = header.index_offset;
85 +  while (current_offset < header.data_offset)
86 +    {
87 +      if (TEMP_FAILURE_RETRY (read (tzdata_fd, &entry, sizeof(entry)) < (ssize_t) sizeof (entry)))
88 +      {
89 +        g_warning ("Failed reading tzdata index entry");
90 +        goto error;
91 +      }
92 +
93 +      if (strcmp (entry.name, identifier) == 0)
94 +        {
95 +          entry.offset = htonl (entry.offset);
96 +          entry.length = htonl (entry.length);
97 +          if (entry.length == 0)
98 +            {
99 +              g_warning ("Invalid tzdata entry with length zero");
100 +              goto error;
101 +            }
102 +
103 +          if (TEMP_FAILURE_RETRY (lseek (tzdata_fd, header.data_offset + entry.offset, SEEK_SET) == -1))
104 +            {
105 +              g_warning ("Failed seeking to tzdata entry");
106 +              goto error;
107 +            }
108 +
109 +          /* Use a reasonable but arbitrary max length of an entry. */
110 +          if (entry.length > 65536)
111 +            {
112 +              g_warning ("Too large tzdata entry length");
113 +              goto error;
114 +            }
115 +
116 +          guint8* data = g_malloc (entry.length);
117 +          if (TEMP_FAILURE_RETRY (read (tzdata_fd, data, entry.length) < entry.length))
118 +            {
119 +              g_warning ("Failed reading tzdata entry");
120 +              g_free (data);
121 +              goto error;
122 +            }
123 +
124 +          close (tzdata_fd);
125 +          return g_bytes_new_take (data, entry.length);
126 +        }
127 +    }
128 +
129 +error:
130 +  close (tzdata_fd);
131 +
132 +  return NULL;
133 +}
134 +
135 +#elif defined(G_OS_UNIX)
136 +
137  static GBytes*
138  zone_info_unix (const gchar *identifier)
139  {
140 @@ -436,6 +541,10 @@
141    return zoneinfo;
142  }
143  
144 +#endif
145 +
146 +#ifdef G_OS_UNIX
147 +
148  static void
149  init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo)
150  {
151 @@ -1387,7 +1496,11 @@
152    if (tz->t_info == NULL)
153      {
154  #ifdef G_OS_UNIX
155 +# ifdef __ANDROID__
156 +      GBytes *zoneinfo = zone_info_android (identifier);
157 +# else
158        GBytes *zoneinfo = zone_info_unix (identifier);
159 +# endif
160        if (!zoneinfo)
161          zone_for_constant_offset (tz, "UTC");
162        else