chiark / gitweb /
libuv: Update from 1.20.0 to 1.20.1
[termux-packages] / packages / glib / glib-gtimezone.c.patch
1 diff -u -r ../glib-2.54.2/glib/gtimezone.c ./glib/gtimezone.c
2 --- ../glib-2.54.2/glib/gtimezone.c     2017-07-14 01:03:39.000000000 +0200
3 +++ ./glib/gtimezone.c  2018-01-07 23:20:34.447775267 +0100
4 @@ -43,6 +43,10 @@
5  #include <windows.h>
6  #endif
7  
8 +#ifdef __ANDROID__
9 +#include <sys/system_properties.h>
10 +#endif
11 +
12  /**
13   * SECTION:timezone
14   * @title: GTimeZone
15 @@ -392,7 +396,131 @@
16    gtz->transitions = NULL;
17  }
18  
19 -#ifdef G_OS_UNIX
20 +#ifdef __ANDROID__
21 +/* Android uses a 'persist.sys.timezone' system property for the
22 + * current timezone instead of a /etc/localtime file:
23 + * https://android.googlesource.com/platform/ndk/+/android-2.2_r1/docs/system/libc/OVERVIEW.TXT#67
24 + *
25 + * There are no files under /usr/share/zoneinfo - instead a single
26 + * /system/usr/share/zoneinfo/tzdata file is used which contains all
27 + * files compiled together with the following tool:
28 + * https://android.googlesource.com/platform/system/timezone/+/master/zone_compactor/main/java/ZoneCompactor.java
29 + */
30 +static GBytes *
31 +zone_info_android (const gchar *identifier)
32 +{
33 +  char sys_timezone[PROP_VALUE_MAX];
34 +  GMappedFile *file;
35 +  gchar *tzdata;
36 +  gsize tzdata_length;
37 +  const gsize index_entry_size = 52;
38 +  gint32 header_index_offset, header_data_offset;
39 +  gint32 entry_count, current_index;
40 +  char* entry_name;
41 +  gint32 entry_offset, entry_length;
42 +  guint32 entry_name_start, entry_name_end;
43 +  guint32 zoneinfo_start, zoneinfo_end;
44 +  GBytes *zoneinfo;
45 +  GError *error = NULL;
46 +
47 +  if (identifier == NULL)
48 +    {
49 +      if (__system_property_get ("persist.sys.timezone", sys_timezone) < 1)
50 +        {
51 +          g_warning ("__system_property_get(\"persist.sys.timezone\") failed");
52 +          return NULL;
53 +        }
54 +      identifier = sys_timezone;
55 +    }
56 +
57 +  file = g_mapped_file_new ("/system/usr/share/zoneinfo/tzdata", FALSE, &error);
58 +  if (file == NULL)
59 +    {
60 +      g_warning ("Failed mapping tzdata file: %s", error->message);
61 +      g_error_free (error);
62 +      return NULL;
63 +    }
64 +
65 +  tzdata = g_mapped_file_get_contents (file);
66 +  tzdata_length = g_mapped_file_get_length (file);
67 +  if (tzdata == NULL || tzdata_length < 24)
68 +  {
69 +    g_warning ("Too small tzdata file");
70 +    goto error;
71 +  }
72 +
73 +  header_index_offset = gint32_from_be (*((gint32_be*) (tzdata + 12)));
74 +  header_data_offset = gint32_from_be (*((gint32_be*) (tzdata + 16)));
75 +
76 +  if (header_index_offset < 0 || header_data_offset < 0 || header_data_offset < index_entry_size)
77 +    {
78 +      g_warning ("Invalid tzdata content");
79 +      goto error;
80 +    }
81 +
82 +  entry_count = (header_data_offset - header_index_offset) / index_entry_size;
83 +  if (entry_count < 1)
84 +    {
85 +      g_warning ("No index entry found");
86 +      goto error;
87 +    }
88 +
89 +  current_index = 0;
90 +  while (current_index < entry_count)
91 +    {
92 +      if (!g_uint_checked_mul(&entry_name_start, current_index, index_entry_size) ||
93 +          !g_uint_checked_add(&entry_name_start, entry_name_start, header_index_offset) ||
94 +          !g_uint_checked_add(&entry_name_end, entry_name_start, 40))
95 +        {
96 +          g_warning ("Overflow when computing entry name offset");
97 +          goto error;
98 +        }
99 +
100 +      entry_name = tzdata + entry_name_start;
101 +
102 +      /* The name should be null terminated within the 40 chars. */
103 +      if (memchr (entry_name, 0, 40) == NULL)
104 +        {
105 +          g_warning ("Invalid index entry");
106 +          goto error;
107 +        }
108 +
109 +      if (strcmp (entry_name, identifier) == 0)
110 +        {
111 +          entry_offset = gint32_from_be (*(gint32_be*) (entry_name + 40));
112 +          entry_length = gint32_from_be (*(gint32_be*) (entry_name + 44));
113 +          if (entry_length == 0 || entry_length > 65536)
114 +            {
115 +              /* Use a reasonable but arbitrary max length of an entry. */
116 +              g_warning ("Invalid zoneinfo entry length");
117 +              goto error;
118 +            }
119 +
120 +          if (!g_uint_checked_add(&zoneinfo_start, header_data_offset, entry_offset) ||
121 +              !g_uint_checked_add(&zoneinfo_end, zoneinfo_start, entry_length) ||
122 +              zoneinfo_end > tzdata_length)
123 +            {
124 +              g_warning ("Too large zoneinfo entry length");
125 +              goto error;
126 +            }
127 +
128 +          zoneinfo = g_bytes_new_with_free_func (tzdata + zoneinfo_start,
129 +                                                 entry_length,
130 +                                                 (GDestroyNotify)g_mapped_file_unref,
131 +                                                 g_mapped_file_ref (file));
132 +          g_mapped_file_unref (file);
133 +          return zoneinfo;
134 +        }
135 +      current_index++;
136 +    }
137 +
138 +error:
139 +  g_mapped_file_unref (file);
140 +  return NULL;
141 +}
142 +
143 +#elif defined(G_OS_UNIX)
144 +
145  static GBytes*
146  zone_info_unix (const gchar *identifier)
147  {
148 @@ -436,6 +564,10 @@
149    return zoneinfo;
150  }
151  
152 +#endif
153 +
154 +#ifdef G_OS_UNIX
155 +
156  static void
157  init_zone_from_iana_info (GTimeZone *gtz, GBytes *zoneinfo)
158  {
159 @@ -1387,7 +1519,11 @@
160    if (tz->t_info == NULL)
161      {
162  #ifdef G_OS_UNIX
163 +# ifdef __ANDROID__
164 +      GBytes *zoneinfo = zone_info_android (identifier);
165 +# else
166        GBytes *zoneinfo = zone_info_unix (identifier);
167 +# endif
168        if (!zoneinfo)
169          zone_for_constant_offset (tz, "UTC");
170        else