summary refs log tree commit diff
path: root/gnu/packages/patches/qtbase-use-TZDIR.patch
blob: 98bf7493e9f1c9fbf9ec4a8a7743111287030109 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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

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).
 static QTzTimeZoneHash loadTzTimeZones()
 {
-    QString path = QStringLiteral("/usr/share/zoneinfo/zone.tab");
-    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();
 
     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"));
         if (!tzif.open(QIODevice::ReadOnly))
             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;
         }
     }
 
@@ -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