Rather than invalidating the cache by comparing `TZ` to the cached
timezone identifier, key entirely off the value of `TZ` (and a cached
copy of it).
This fixes the timezone cache being constantly invalidated if `TZ` is
`NULL` (which will always differ from the identifier of the default
local timezone which is constructed from `g_time_zone_new (NULL)`.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2204
GTK ci rightly complains about this when ti builds
GLib as a subproject with -Werror=maybe-uninitialized.
subkey_dynamic_w will be freed without being initialized
when the first goto is taken.
`getenv()` doesn't work well on Windows, f.ex., it can't fetch env
vars set with `SetEnvironmentVariable()`. This also means that it
doesn't work at all when targeting UWP since that's the only way to
set env vars in that case.
Since tzcode95f (1995), TZif files have had a trailing
TZ string, used for timestamps after the last transition.
This string is specified in Internet RFC 8536 section 3.3.
init_zone_from_iana_info has ignored this string, causing it
to mishandle timestamps past the year 2038. With zic's new -b
slim flag, init_zone_from_iana_info would even mishandle current
timestamps. Fix this by parsing the trailing TZ string and adding
its transitions.
Closes#2129
Time zone transition times can range from -167:59:59 through
+167:59:59, according to Internet RFC 8536 section 3.3.1;
this is an extension to POSIX. It is needed for proper
support of TZif version 3 files.
This was mostly machine generated with the following command:
```
codespell \
--builtin clear,rare,usage \
--skip './po/*' --skip './.git/*' --skip './NEWS*' \
--write-changes .
```
using the latest git version of `codespell` as per [these
instructions](https://github.com/codespell-project/codespell#user-content-updating).
Then I manually checked each change using `git add -p`, made a few
manual fixups and dropped a load of incorrect changes.
There are still some outdated or loaded terms used in GLib, mostly to do
with git branch terminology. They will need to be changed later as part
of a wider migration of git terminology.
If I’ve missed anything, please file an issue!
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Move the separate function inline using g_once_init_{enter,leave}(),
rather than g_once().
This marginally improves performance, taking 0.39s to create 10000000
UTC timezones, rather than 0.43s previously. (Who cares?)
Follow-up to !1105.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
The timezone(3) man page on Fedora 31 describes the start/end
field in the POSIX TZ format as follows:
[quote]
The start field specifies when daylight saving time goes
into effect and the end field specifies when the change is
made back to standard time. These fields may have the fol‐
lowing formats:
Jn This specifies the Julian day with n between 1 and
365. Leap days are not counted. In this format,
February 29 can't be represented; February 28 is day
59, and March 1 is always day 60.
n This specifies the zero-based Julian day with n
between 0 and 365. February 29 is counted in leap
years.
Mm.w.d This specifies day d (0 <= d <= 6) of week w (1 <= w
<= 5) of month m (1 <= m <= 12). Week 1 is the
first week in which day d occurs and week 5 is the
last week in which day d occurs. Day 0 is a Sunday.
[/quote]
The GTimeZone code does not correctly parse the 'n' syntax,
treating it as having the range 1-365, the same as the 'Jn'
syntax. This is semantically broken as it makes it impossible
to represent the 366th day, which is the purpose of the 'n'
syntax.
There is a code comment saying this was done because the Linux
semantics are different from zOS and BSD. This is not correct,
as GLibC does indeed use the same 0-365 range as other operating
systems. It is believed that the original author was mislead by
a bug in old versions of the Linux libc timezone(3) man pages
which was fixed in
commit 5a554f8e525faa98354c1b95bfe4aca7125a3657
Author: Peter Schiffer <pschiffe@redhat.com>
Date: Sat Mar 24 16:08:10 2012 +1300
tzset.3: Correct description for Julian 'n' date format
The Julian 'n' date format counts atrting from 0, not 1.
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
Fixes: #1999
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
The callers of parse_tz_boundary inverted the value passed
for the ignore_leap parameter. Fortunately the method impl
also had an inverted test cancelling out the first bug.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Previously, these GTimeZone objects were being cached in the `time_zones` cache, but dropped from it when their final ref was dropped (which was frequently). That meant additional reads of `/etc/localtime` next time they were created, which was noticeable on profiles. Keep a permanent ref to the UTC and local timezones.
On Windows, we may be using the US DST boundaries by using the default
"Pacific Standard Time" for rules_from_windows_time_zone() in
rules_from_identifier(). This has the unfortunate side-effect of
hardcoding the out_identifier to "Pacific Standard Time", which is
likely not what we want.
Instead, upon retrieving the items successfully using
rules_from_windows_time_zone ("Pacific Standard Time", ...), we just
set the out_identifier to whatever identifier that was passed into
rules_from_identifier().
The existing method of using RegQueryValueExW() to query the Std/Dlt
strings can only retrive the localized versions of those strings, so
that means they will vary by the language version of Windows. Instead,
use RegQueryValueExW() only as a fallback when RegLoadMUIStringW() fails,
as RegLoadMUIStringW() can query for the Std and Dlt strings in
whatever language we need by setting the locale stuff programatically on
the fly.
We are going to use RegLoadMUIStringW() in the next commit, since there
is no real RegLoadMUIStringA() function (it exists as a stub only).
This is done so that we are consistent along the way
Also fix rule_from_windows_time_zone_info() as we can't just do a strncpy()
of tzi->StandardName and tzi->DaylightName directly, as they are wchar_t/
gunichar2 strings, where we must convert to UTF-8 first.
https://bugzilla.gnome.org/show_bug.cgi?id=719344
glib/gtimezone.c: In function ‘g_time_zone_unref’:
glib/gtimezone.c:241:29: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Werror=sign-compare]
for (idx = 0; idx < tz->t_info->len; idx++)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gtimezone.h:27,
from glib/gtimezone.c:24:
glib/gtimezone.c: In function ‘init_zone_from_iana_info’:
glib/gtimezone.c:578:34: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Werror=sign-compare]
g_assert (trans.info_index < gtz->t_info->len);
^
glib/gmacros.h:455:25: note: in definition of macro ‘G_LIKELY’
#define G_LIKELY(expr) (expr)
^~~~
glib/gtimezone.c:578:7: note: in expansion of macro ‘g_assert’
g_assert (trans.info_index < gtz->t_info->len);
^~~~~~~~
glib/gtimezone.c: In function ‘find_relative_date’:
glib/gtimezone.c:859:22: error: comparison of integer expressions of different signedness: ‘GDateWeekday’ {aka ‘enum <anonymous>’} and ‘gint’ {aka ‘int’} [-Werror=sign-compare]
if (first_wday > wday)
^
glib/gtimezone.c: In function ‘init_zone_from_rules’:
glib/gtimezone.c:938:19: error: comparison of integer expressions of different signedness: ‘guint’ {aka ‘unsigned int’} and ‘int’ [-Werror=sign-compare]
for (ri = 0; ri < rules_num - 1; ri++)
^
glib/gtimezone.c:958:19: error: comparison of integer expressions of different signedness: ‘guint’ {aka ‘unsigned int’} and ‘int’ [-Werror=sign-compare]
for (ri = 0; ri < rules_num - 1; ri++)
^
glib/gtimezone.c: In function ‘g_time_zone_adjust_time’:
glib/gtimezone.c:1792:17: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Werror=sign-compare]
for (i = 0; i <= intervals; i++)
^~
glib/gtimezone.c:1825:39: error: comparison of integer expressions of different signedness: ‘gboolean’ {aka ‘int’} and ‘GTimeType’ {aka ‘enum <anonymous>’} [-Werror=sign-compare]
else if (interval_isdst (tz, i) != type)
^~
glib/gtimezone.c:1832:22: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Werror=sign-compare]
else if (i < intervals &&
^
glib/gtimezone.c: In function ‘g_time_zone_find_interval’:
glib/gtimezone.c:1881:17: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Werror=sign-compare]
for (i = 0; i <= intervals; i++)
^~
glib/gtimezone.c:1900:35: error: comparison of integer expressions of different signedness: ‘gboolean’ {aka ‘int’} and ‘GTimeType’ {aka ‘enum <anonymous>’} [-Werror=sign-compare]
else if (interval_isdst (tz, i) != type)
^~
glib/gtimezone.c:1905:18: error: comparison of integer expressions of different signedness: ‘gint’ {aka ‘int’} and ‘guint’ {aka ‘unsigned int’} [-Werror=sign-compare]
else if (i < intervals && time_ >= interval_local_start (tz, i + 1))
^
On non-systemd Gentoo systems the chosen timezone is expressed in
/etc/timezone and /etc/localtime may be a copy of the timezone
file instead of symlink. Add this path to the fallback test to
not regress dates into UTC.
• A leak of filename on an error path
• A leak of resolved_identifier if no out_identifier return location
was provided
The latter was spotted by Peter Bloomfield
(8945227743 (note_111254)).
Thanks!
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Reviewed-by: nobody
The timezone setup utility of FreeBSD, tzsetup, which is run during the
installation, creates /etc/localtime by copying the chosen timezone file
from /usr/share/zoneinfo. Although it can correctly deal with the case
where /etc/localtime is a symlink, it is not the default and there is no
user interface to change the default copying behaviour.
Fortunately, tzsetup has been modified to write the name of the chosen
timezone to /var/db/zoneinfo in 2009, so we can know the name of the
current timezone by reading it. DragonflyBSD also seems to do the same
thing in its tzsetup.
https://svnweb.freebsd.org/changeset/base/198267https://bugzilla.gnome.org/show_bug.cgi?id=795165
The return value of g_file_read_link ("/etc/localtime") can
be a relative path in the form of "../usr/share/zoneinfo".
This breaks the prefix check that is performed, and makes
the timezone identifier be "../usr/share/zoneinfo/America/Sao_Paulo",
for example, which breaks other parts of the system.
Fix that by canonicalizing the symlink path if we detect
is it a relative path.
(Tweaked by Philip Withnall <withnall@endlessm.com> to remove a
conditional which was unnecessary.)
https://bugzilla.gnome.org/show_bug.cgi?id=111848
This is a non-trivial accessor which gets the identifier string used to
create the GTimeZone — unless the string passed to g_time_zone_new() was
invalid, in which case the identifier will be `UTC`.
Implementing this required reworking how timezone information was loaded
so that the tz->name is always set at the same time as tz->t_info, so
they are in sync. Previously, the tz->name was unconditionally set to
whatever was passed to g_time_zone_new(), and then not updated if the
tz->t_info was eventually set to the default UTC information.
This includes tests for the new g_time_zone_get_identifier() API, and
for the g_date_time_get_timezone() API added in the previous commit.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795165
All glib/*.{c,h} files have been processed, as well as gtester-report.
12 of those files are not licensed under LGPL:
gbsearcharray.h
gconstructor.h
glibintl.h
gmirroringtable.h
gscripttable.h
gtranslit-data.h
gunibreak.h
gunichartables.h
gunicomp.h
gunidecomp.h
valgrind.h
win_iconv.c
Some of them are generated files, some are licensed under a BSD-style
license and win_iconv.c is in the public domain.
Sub-directories inside glib/:
deprecated/: processed in a previous commit
glib-mirroring-tab/: already LGPLv2.1+
gnulib/: not modified, the code is copied from gnulib
libcharset/: a copy
pcre/: a copy
tests/: processed in a previous commit
https://bugzilla.gnome.org/show_bug.cgi?id=776504
If we have an input parameter (or return value) we need to use (nullable).
However, if it is an (inout) or (out) parameter, (optional) is sufficient.
It looks like (nullable) could be used for everything according to the
Annotation documentation, but (optional) is more specific.
The condition removed erroneously excluded UTC-based and DST-less
timezones and so left the GArray with no contents, so GTimeZone functions
returned whatever random garbage was in memory.
We need to re-get the size of tzi.DaylightName before we call
RegQueryValue() because the buffer might not have enough room to hold the
value for tzi.DaylightName that would be acquired by RegQueryValueExA(),
even though the size of tzi.DaylightName and tzi.StandardName is the same.
This is a pitfall of RegQueryValue()[1] as not doing this can result in an
ERROR_MORE_DATA (234) failure, causing the acquisition of tzi.DaylightName
to fail.
This will fix the gdatetime/equal test, amongst some other tests in
gdatetime, at least on certain non-English version of Windows.
[1]: http://social.msdn.microsoft.com/Forums/vstudio/en-US/84f90854-e90c-4b63-8fc1-655a0b4645fd/regqueryvalueex-returns-errormoredatahttps://bugzilla.gnome.org/show_bug.cgi?id=719344