diff options
author | Liang Qi <liang.qi@qt.io> | 2019-06-14 11:56:56 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-06-14 13:45:18 +0200 |
commit | b1a216649ec064412160638dd00195cd47c567aa (patch) | |
tree | a4134415a3849cfb857942e698514be9da18924f /src/corelib/time/qtimezoneprivate_tz.cpp | |
parent | 2e20ae3c1b57169497f6f3904623be4f5e617e12 (diff) | |
parent | 1632786f00875d23c7d111cbb29dedaa35c1c8c2 (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Conflicts:
qmake/generators/makefile.cpp
qmake/generators/unix/unixmake2.cpp
src/corelib/thread/qthread_unix.cpp
tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp
Change-Id: I1df0d4ba20685de7f9300bf07458c13376493408
Diffstat (limited to 'src/corelib/time/qtimezoneprivate_tz.cpp')
-rw-r--r-- | src/corelib/time/qtimezoneprivate_tz.cpp | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp index 2c845b1bce..1c74305e3d 100644 --- a/src/corelib/time/qtimezoneprivate_tz.cpp +++ b/src/corelib/time/qtimezoneprivate_tz.cpp @@ -50,6 +50,12 @@ #include <qdebug.h> #include <algorithm> +#include <errno.h> +#include <limits.h> +#if !defined(Q_OS_INTEGRITY) +#include <sys/param.h> // to use MAXSYMLINKS constant +#endif +#include <unistd.h> // to use _SC_SYMLOOP_MAX constant QT_BEGIN_NAMESPACE @@ -1057,6 +1063,27 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs return last > m_tranTimes.cbegin() ? dataForTzTransition(*--last) : invalidData(); } +static long getSymloopMax() +{ +#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 +# if defined(MAXSYMLINKS) + return MAXSYMLINKS; +# else + return 8; +# endif +#endif +} + // TODO Could cache the value and monitor the required files for any changes QByteArray QTzTimeZonePrivate::systemTimeZoneId() const { @@ -1074,12 +1101,18 @@ QByteArray QTzTimeZonePrivate::systemTimeZoneId() const // On most distros /etc/localtime is a symlink to a real file so extract name from the path if (ianaId.isEmpty()) { - const QString path = QFile::symLinkTarget(QStringLiteral("/etc/localtime")); - if (!path.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 - int index = path.indexOf(QLatin1String("/zoneinfo/")); - if (index != -1) - ianaId = path.mid(index + 10).toUtf8(); + ianaId = path.mid(index + zoneinfo.size()).toUtf8(); } } |