gtimezone: Split out fallback timezone identification for unix

When the TZ environment variable is not set, we get the local timezone
identifier by reading specific files.

We are going to need these identifiers earlier, so split this logic into
its own function, in preparation for the next commit.

Based on idea proposed by Sebastian Keller <skeller@gnome.org>.
This commit is contained in:
António Fernandes 2020-09-23 18:13:47 +01:00 committed by Philip Withnall
parent 8cbe2da75e
commit 7124b91e21

View File

@ -438,46 +438,17 @@ zone_for_constant_offset (GTimeZone *gtz, const gchar *name)
} }
#ifdef G_OS_UNIX #ifdef G_OS_UNIX
static GBytes* static gchar *
zone_info_unix (const gchar *identifier, zone_identifier_unix (void)
gchar **out_identifier)
{ {
gchar *filename;
GMappedFile *file = NULL;
GBytes *zoneinfo = NULL;
gchar *resolved_identifier = NULL; gchar *resolved_identifier = NULL;
const gchar *tzdir;
tzdir = g_getenv ("TZDIR");
if (tzdir == NULL)
tzdir = "/usr/share/zoneinfo";
/* identifier can be a relative or absolute path name;
if relative, it is interpreted starting from /usr/share/zoneinfo
while the POSIX standard says it should start with :,
glibc allows both syntaxes, so we should too */
if (identifier != NULL)
{
resolved_identifier = g_strdup (identifier);
if (*identifier == ':')
identifier ++;
if (g_path_is_absolute (identifier))
filename = g_strdup (identifier);
else
filename = g_build_filename (tzdir, identifier, NULL);
}
else
{
gsize prefix_len = 0; gsize prefix_len = 0;
gchar *canonical_path = NULL; gchar *canonical_path = NULL;
GError *read_link_err = NULL; GError *read_link_err = NULL;
const gchar *tzdir;
filename = g_strdup ("/etc/localtime");
/* Resolve the actual timezone pointed to by /etc/localtime. */ /* Resolve the actual timezone pointed to by /etc/localtime. */
resolved_identifier = g_file_read_link (filename, &read_link_err); resolved_identifier = g_file_read_link ("/etc/localtime", &read_link_err);
if (resolved_identifier == NULL) if (resolved_identifier == NULL)
{ {
gboolean not_a_symlink = g_error_matches (read_link_err, gboolean not_a_symlink = g_error_matches (read_link_err,
@ -512,6 +483,10 @@ zone_info_unix (const gchar *identifier,
resolved_identifier = g_steal_pointer (&canonical_path); resolved_identifier = g_steal_pointer (&canonical_path);
} }
tzdir = g_getenv ("TZDIR");
if (tzdir == NULL)
tzdir = "/usr/share/zoneinfo";
/* Strip the prefix and slashes if possible. */ /* Strip the prefix and slashes if possible. */
if (g_str_has_prefix (resolved_identifier, tzdir)) if (g_str_has_prefix (resolved_identifier, tzdir))
{ {
@ -524,7 +499,51 @@ zone_info_unix (const gchar *identifier,
memmove (resolved_identifier, resolved_identifier + prefix_len, memmove (resolved_identifier, resolved_identifier + prefix_len,
strlen (resolved_identifier) - prefix_len + 1 /* nul terminator */); strlen (resolved_identifier) - prefix_len + 1 /* nul terminator */);
g_assert (resolved_identifier != NULL);
out:
g_free (canonical_path); g_free (canonical_path);
return resolved_identifier;
}
static GBytes*
zone_info_unix (const gchar *identifier,
gchar **out_identifier)
{
gchar *filename = NULL;
GMappedFile *file = NULL;
GBytes *zoneinfo = NULL;
gchar *resolved_identifier = NULL;
const gchar *tzdir;
tzdir = g_getenv ("TZDIR");
if (tzdir == NULL)
tzdir = "/usr/share/zoneinfo";
/* identifier can be a relative or absolute path name;
if relative, it is interpreted starting from /usr/share/zoneinfo
while the POSIX standard says it should start with :,
glibc allows both syntaxes, so we should too */
if (identifier != NULL)
{
resolved_identifier = g_strdup (identifier);
if (*identifier == ':')
identifier ++;
if (g_path_is_absolute (identifier))
filename = g_strdup (identifier);
else
filename = g_build_filename (tzdir, identifier, NULL);
}
else
{
resolved_identifier = zone_identifier_unix ();
if (resolved_identifier == NULL)
goto out;
filename = g_strdup ("/etc/localtime");
} }
file = g_mapped_file_new (filename, FALSE, NULL); file = g_mapped_file_new (filename, FALSE, NULL);