summaryrefslogtreecommitdiff
path: root/dev-qt/qtcore/files/qtcore-5.15.1-timezone-1.patch
blob: 1c8f1e89e7d5c1306a0dd5d16c10809344046489 (plain)
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
From c337f6fae51b987ce7dbed1fd9bea41e6073efbb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20K=2E=20H=C3=BCttel?= <dilfridge@gentoo.org>
Date: Sat, 10 Oct 2020 19:26:13 +0200
Subject: [PATCH 1/2] Revert "Cache system zone ID when fetched from the
 file-system"

This reverts commit c70ce3d042025c858faffe661f85d2482a2a0d8c.
---
 src/corelib/time/qtimezoneprivate_tz.cpp | 205 +++++++----------------
 1 file changed, 64 insertions(+), 141 deletions(-)

diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp
index c5c70b7364..01f9a6cce0 100644
--- a/src/corelib/time/qtimezoneprivate_tz.cpp
+++ b/src/corelib/time/qtimezoneprivate_tz.cpp
@@ -1,6 +1,5 @@
 /****************************************************************************
 **
-** Copyright (C) 2020 The Qt Company Ltd.
 ** Copyright (C) 2019 Crimson AS <info@crimson.no>
 ** Copyright (C) 2013 John Layt <jlayt@kde.org>
 ** Contact: https://www.qt.io/licensing/
@@ -43,19 +42,18 @@
 #include "qtimezoneprivate_p.h"
 #include "private/qlocale_tools_p.h"
 
-#include <QtCore/QDataStream>
-#include <QtCore/QDateTime>
 #include <QtCore/QFile>
-#include <QtCore/QHash>
 #include <QtCore/QMutex>
+#include <QtCore/QHash>
+#include <QtCore/QDataStream>
+#include <QtCore/QDateTime>
 
 #include <qdebug.h>
-#include <qplatformdefs.h>
 
 #include <algorithm>
 #include <errno.h>
 #include <limits.h>
-#ifndef Q_OS_INTEGRITY
+#if !defined(Q_OS_INTEGRITY)
 #include <sys/param.h> // to use MAXSYMLINKS constant
 #endif
 #include <unistd.h>    // to use _SC_SYMLOOP_MAX constant
@@ -1102,146 +1100,28 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs
     return last > tranCache().cbegin() ? dataForTzTransition(*--last) : invalidData();
 }
 
-bool QTzTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
-{
-    return tzZones->contains(ianaId);
-}
-
-QList<QByteArray> QTzTimeZonePrivate::availableTimeZoneIds() const
-{
-    QList<QByteArray> result = tzZones->keys();
-    std::sort(result.begin(), result.end());
-    return result;
-}
-
-QList<QByteArray> QTzTimeZonePrivate::availableTimeZoneIds(QLocale::Country country) const
+static long getSymloopMax()
 {
-    // TODO AnyCountry
-    QList<QByteArray> result;
-    for (auto it = tzZones->cbegin(), end = tzZones->cend(); it != end; ++it) {
-        if (it.value().country == country)
-            result << it.key();
-    }
-    std::sort(result.begin(), result.end());
-    return result;
-}
-
-// Getting the system zone's ID:
-
-namespace {
-class ZoneNameReader : public QObject
-{
-public:
-    QByteArray name()
-    {
-        /* Assumptions:
-           a) Systems don't change which of localtime and TZ they use without a
-              reboot.
-           b) When they change, they use atomic renames, hence a new device and
-              inode for the new file.
-           c) If we change which *name* is used for a zone, while referencing
-              the same final zoneinfo file, we don't care about the change of
-              name (e.g. if Europe/Oslo and Europe/Berlin are both symlinks to
-              the same CET file, continuing to use the old name, after
-              /etc/localtime changes which of the two it points to, is
-              harmless).
-
-           The alternative would be to use a file-system watcher, but they are a
-           scarce resource.
-         */
-        const StatIdent local = identify("/etc/localtime");
-        const StatIdent tz = identify("/etc/TZ");
-        if (!m_name.isEmpty() && m_last.isValid() && (m_last == local || m_last == tz))
-            return m_name;
-
-        m_name = etcLocalTime();
-        if (!m_name.isEmpty()) {
-            m_last = local;
-            return m_name;
-        }
-
-        m_name = etcTZ();
-        m_last = m_name.isEmpty() ? StatIdent() : tz;
-        return m_name;
-    }
-
-
-private:
-    QByteArray m_name;
-    struct StatIdent
-    {
-        static constexpr unsigned long bad = ~0ul;
-        unsigned long m_dev, m_ino;
-        StatIdent() : m_dev(bad), m_ino(bad) {}
-        StatIdent(const QT_STATBUF &data) : m_dev(data.st_dev), m_ino(data.st_ino) {}
-        bool isValid() { return m_dev != bad || m_ino != bad; }
-        bool operator==(const StatIdent &other)
-        { return other.m_dev == m_dev && other.m_ino == m_ino; }
-    };
-    StatIdent m_last;
-
-    static StatIdent identify(const char *path)
-    {
-        QT_STATBUF data;
-        return QT_STAT(path, &data) == -1 ? StatIdent() : StatIdent(data);
-    }
-
-    static QByteArray etcLocalTime()
-    {
-        // On most distros /etc/localtime is a symlink to a real file so extract
-        // name from the path
-        const QLatin1String zoneinfo("/zoneinfo/");
-        QString path = QStringLiteral("/etc/localtime");
-        long iteration = getSymloopMax();
-        // Symlink may point to another symlink etc. before being under zoneinfo/
-        // We stop on the first path under /zoneinfo/, even if it is itself a
-        // 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 path.midRef(index + zoneinfo.size()).toUtf8();
-        } while (!path.isEmpty() && --iteration > 0);
-
-        return QByteArray();
-    }
-
-    static QByteArray etcTZ()
-    {
-        // Some systems (e.g. uClibc) have a default value for $TZ in /etc/TZ:
-        const QString path = QStringLiteral("/etc/TZ");
-        QFile zone(path);
-        if (zone.open(QIODevice::ReadOnly))
-            return zone.readAll().trimmed();
-
-        return QByteArray();
-    }
-
-    // Any chain of symlinks longer than this is assumed to be a loop:
-    static long getSymloopMax()
-    {
-#ifdef SYMLOOP_MAX
-        // If defined, at runtime it can only be greater than this, so this is a safe bet:
-        return SYMLOOP_MAX;
+#if defined(SYMLOOP_MAX)
+    return SYMLOOP_MAX; // if defined, at runtime it can only be greater than this, so this is a safe bet
 #else
-        errno = 0;
-        long result = sysconf(_SC_SYMLOOP_MAX);
-        if (result >= 0)
-            return result;
-        // result is -1, meaning either error or no limit
-        Q_ASSERT(!errno); // ... but it can't be an error, POSIX mandates _SC_SYMLOOP_MAX
-
-        // therefore we can make up our own limit
-#  ifdef MAXSYMLINKS
-        return MAXSYMLINKS;
+    errno = 0;
+    long result = sysconf(_SC_SYMLOOP_MAX);
+    if (result >= 0)
+        return result;
+    // result is -1, meaning either error or no limit
+    Q_ASSERT(!errno); // ... but it can't be an error, POSIX mandates _SC_SYMLOOP_MAX
+
+    // therefore we can make up our own limit
+#  if defined(MAXSYMLINKS)
+    return MAXSYMLINKS;
 #  else
-        return 8;
+    return 8;
 #  endif
 #endif
-    }
-};
 }
 
+// TODO Could cache the value and monitor the required files for any changes
 QByteArray QTzTimeZonePrivate::systemTimeZoneId() const
 {
     // Check TZ env var first, if not populated try find it
@@ -1256,9 +1136,28 @@ QByteArray QTzTimeZonePrivate::systemTimeZoneId() const
     else if (ianaId.startsWith(':'))
         ianaId = ianaId.mid(1);
 
+    // On most distros /etc/localtime is a symlink to a real file so extract name from the path
+    if (ianaId.isEmpty()) {
+        const QLatin1String zoneinfo("/zoneinfo/");
+        QString path = QFile::symLinkTarget(QStringLiteral("/etc/localtime"));
+        int index = -1;
+        long iteration = getSymloopMax();
+        // Symlink may point to another symlink etc. before being under zoneinfo/
+        // We stop on the first path under /zoneinfo/, even if it is itself a
+        // symlink, like America/Montreal pointing to America/Toronto
+        while (iteration-- > 0 && !path.isEmpty() && (index = path.indexOf(zoneinfo)) < 0)
+            path = QFile::symLinkTarget(path);
+        if (index >= 0) {
+            // /etc/localtime is a symlink to the current TZ file, so extract from path
+            ianaId = path.midRef(index + zoneinfo.size()).toUtf8();
+        }
+    }
+
+    // Some systems (e.g. uClibc) have a default value for $TZ in /etc/TZ:
     if (ianaId.isEmpty()) {
-        thread_local static ZoneNameReader reader;
-        ianaId = reader.name();
+        QFile zone(QStringLiteral("/etc/TZ"));
+        if (zone.open(QIODevice::ReadOnly))
+            ianaId = zone.readAll().trimmed();
     }
 
     // Give up for now and return UTC
@@ -1268,4 +1167,28 @@ QByteArray QTzTimeZonePrivate::systemTimeZoneId() const
     return ianaId;
 }
 
+bool QTzTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
+{
+    return tzZones->contains(ianaId);
+}
+
+QList<QByteArray> QTzTimeZonePrivate::availableTimeZoneIds() const
+{
+    QList<QByteArray> result = tzZones->keys();
+    std::sort(result.begin(), result.end());
+    return result;
+}
+
+QList<QByteArray> QTzTimeZonePrivate::availableTimeZoneIds(QLocale::Country country) const
+{
+    // TODO AnyCountry
+    QList<QByteArray> result;
+    for (auto it = tzZones->cbegin(), end = tzZones->cend(); it != end; ++it) {
+        if (it.value().country == country)
+            result << it.key();
+    }
+    std::sort(result.begin(), result.end());
+    return result;
+}
+
 QT_END_NAMESPACE
-- 
2.28.0