2023-09-12 14:14:32 +00:00
|
|
|
From 1075606f8b2f9e153c82f8e50cbd69cea9c72e87 Mon Sep 17 00:00:00 2001
|
|
|
|
From: Edward Welbourne <edward.welbourne@qt.io>
|
|
|
|
Date: Mon, 11 Sep 2023 11:41:39 +0200
|
|
|
|
Subject: [PATCH] Support the TZDIR environment variable
|
2017-11-02 22:03:24 +00:00
|
|
|
|
2023-09-12 14:14:32 +00:00
|
|
|
On Linux / glibc, this overrides the default system location for the
|
|
|
|
zone info. So check for files there first. Break out a function to
|
|
|
|
manage the trying of (now three) zoneinfo directories when opening a
|
|
|
|
file by name relative to there.
|
|
|
|
|
|
|
|
Pick-to: 6.6 6.5
|
|
|
|
Task-number: QTBUG-116017
|
|
|
|
Change-Id: I1f97107aabd9015c0a5543639870f1d70654ca67
|
|
|
|
---
|
|
|
|
* Rebased on top of v6.5.2.
|
|
|
|
|
|
|
|
src/corelib/time/qtimezoneprivate_tz.cpp | 73 ++++++++++++++++--------
|
|
|
|
1 file changed, 49 insertions(+), 24 deletions(-)
|
|
|
|
|
|
|
|
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp
|
|
|
|
index 067191d816..a8b2fc894e 100644
|
|
|
|
--- a/src/corelib/time/qtimezoneprivate_tz.cpp
|
|
|
|
+++ b/src/corelib/time/qtimezoneprivate_tz.cpp
|
|
|
|
@@ -51,17 +51,41 @@ typedef QHash<QByteArray, QTzTimeZone> QTzTimeZoneHash;
|
|
|
|
|
|
|
|
static bool isTzFile(const QString &name);
|
|
|
|
|
|
|
|
+// Open a named file under the zone info directory:
|
|
|
|
+static bool openZoneInfo(QString name, QFile *file)
|
|
|
|
+{
|
|
|
|
+ // At least on Linux / glibc (see man 3 tzset), $TZDIR overrides the system
|
|
|
|
+ // default location for zone info:
|
|
|
|
+ const QString tzdir = qEnvironmentVariable("TZDIR");
|
|
|
|
+ if (!tzdir.isEmpty()) {
|
|
|
|
+ file->setFileName(QDir(tzdir).filePath(name));
|
|
|
|
+ if (file->open(QIODevice::ReadOnly))
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ // Try modern system path first:
|
|
|
|
+ constexpr auto zoneShare = "/usr/share/zoneinfo/"_L1;
|
|
|
|
+ if (tzdir != zoneShare && tzdir != zoneShare.chopped(1)) {
|
|
|
|
+ file->setFileName(zoneShare + name);
|
|
|
|
+ if (file->open(QIODevice::ReadOnly))
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ // Fall back to legacy system path:
|
|
|
|
+ constexpr auto zoneLib = "/usr/lib/zoneinfo/"_L1;
|
|
|
|
+ if (tzdir != zoneLib && tzdir != zoneLib.chopped(1)) {
|
|
|
|
+ file->setFileName(zoneShare + name);
|
|
|
|
+ if (file->open(QIODevice::ReadOnly))
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
// Parse zone.tab table for territory information, read directories to ensure we
|
|
|
|
// find all installed zones (many are omitted from zone.tab; even more from
|
|
|
|
// zone1970.tab).
|
2017-11-02 22:03:24 +00:00
|
|
|
static QTzTimeZoneHash loadTzTimeZones()
|
|
|
|
{
|
|
|
|
- QString path = QStringLiteral("/usr/share/zoneinfo/zone.tab");
|
2023-09-12 14:14:32 +00:00
|
|
|
- if (!QFile::exists(path))
|
|
|
|
- path = QStringLiteral("/usr/lib/zoneinfo/zone.tab");
|
|
|
|
-
|
|
|
|
- QFile tzif(path);
|
|
|
|
- if (!tzif.open(QIODevice::ReadOnly))
|
|
|
|
+ QFile tzif;
|
|
|
|
+ if (!openZoneInfo("zone.tab"_L1, &tzif))
|
|
|
|
return QTzTimeZoneHash();
|
2017-11-02 22:03:24 +00:00
|
|
|
|
2023-09-12 14:14:32 +00:00
|
|
|
QTzTimeZoneHash zonesHash;
|
|
|
|
@@ -91,6 +115,7 @@ static QTzTimeZoneHash loadTzTimeZones()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ const QString path = tzif.fileName();
|
|
|
|
const qsizetype cut = path.lastIndexOf(u'/');
|
|
|
|
Q_ASSERT(cut > 0);
|
|
|
|
const QDir zoneDir = QDir(path.first(cut));
|
|
|
|
@@ -761,20 +786,13 @@ QTzTimeZoneCacheEntry QTzTimeZoneCache::findEntry(const QByteArray &ianaId)
|
|
|
|
tzif.setFileName(QStringLiteral("/etc/localtime"));
|
2017-11-02 22:03:24 +00:00
|
|
|
if (!tzif.open(QIODevice::ReadOnly))
|
2023-09-12 14:14:32 +00:00
|
|
|
return ret;
|
|
|
|
- } else {
|
|
|
|
- // Open named tz, try modern path first, if fails try legacy path
|
|
|
|
- tzif.setFileName("/usr/share/zoneinfo/"_L1 + QString::fromLocal8Bit(ianaId));
|
|
|
|
- if (!tzif.open(QIODevice::ReadOnly)) {
|
|
|
|
- tzif.setFileName("/usr/lib/zoneinfo/"_L1 + QString::fromLocal8Bit(ianaId));
|
|
|
|
- if (!tzif.open(QIODevice::ReadOnly)) {
|
|
|
|
- // ianaId may be a POSIX rule, taken from $TZ or /etc/TZ
|
|
|
|
- auto check = validatePosixRule(ianaId);
|
|
|
|
- if (check.isValid) {
|
|
|
|
- ret.m_hasDst = check.hasDst;
|
|
|
|
- ret.m_posixRule = ianaId;
|
|
|
|
- }
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
+ } else if (!openZoneInfo(QString::fromLocal8Bit(ianaId), &tzif)) {
|
|
|
|
+ // ianaId may be a POSIX rule, taken from $TZ or /etc/TZ
|
|
|
|
+ auto check = validatePosixRule(ianaId);
|
|
|
|
+ if (check.isValid) {
|
|
|
|
+ ret.m_hasDst = check.hasDst;
|
|
|
|
+ ret.m_posixRule = ianaId;
|
|
|
|
+ return ret;
|
2017-11-02 22:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-12 14:14:32 +00:00
|
|
|
@@ -1317,7 +1335,8 @@ private:
|
|
|
|
{
|
|
|
|
// On most distros /etc/localtime is a symlink to a real file so extract
|
|
|
|
// name from the path
|
|
|
|
- const auto zoneinfo = "/zoneinfo/"_L1;
|
|
|
|
+ const QString tzdir = qEnvironmentVariable("TZDIR");
|
|
|
|
+ constexpr auto zoneinfo = "/zoneinfo/"_L1;
|
|
|
|
QString path = QStringLiteral("/etc/localtime");
|
|
|
|
long iteration = getSymloopMax();
|
|
|
|
// Symlink may point to another symlink etc. before being under zoneinfo/
|
|
|
|
@@ -1325,9 +1344,15 @@ private:
|
|
|
|
// symlink, like America/Montreal pointing to America/Toronto
|
|
|
|
do {
|
|
|
|
path = QFile::symLinkTarget(path);
|
|
|
|
- int index = path.indexOf(zoneinfo);
|
|
|
|
- if (index >= 0) // Found zoneinfo file; extract zone name from path:
|
|
|
|
- return QStringView{ path }.mid(index + zoneinfo.size()).toUtf8();
|
|
|
|
+ // If it's a zoneinfo file, extract the zone name from its path:
|
|
|
|
+ int index = tzdir.isEmpty() ? -1 : path.indexOf(tzdir);
|
|
|
|
+ if (index >= 0) {
|
|
|
|
+ const auto tail = QStringView{ path }.sliced(index + tzdir.size()).toUtf8();
|
|
|
|
+ return tail.startsWith(u'/') ? tail.sliced(1) : tail;
|
|
|
|
+ }
|
|
|
|
+ index = path.indexOf(zoneinfo);
|
|
|
|
+ if (index >= 0)
|
|
|
|
+ return QStringView{ path }.sliced(index + zoneinfo.size()).toUtf8();
|
|
|
|
} while (!path.isEmpty() && --iteration > 0);
|
|
|
|
|
|
|
|
return QByteArray();
|
|
|
|
|
|
|
|
base-commit: af457a9f0f7eb1a2a7d11f495da508faab91a442
|
|
|
|
--
|
|
|
|
2.41.0
|
|
|
|
|