diff options
author | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-06-03 10:23:56 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2015-06-03 10:23:56 +0200 |
commit | e2f66f921594b7be4af4a058c959557489e86879 (patch) | |
tree | cc44931708b57bd5a761906797c7dee0360d1d6b /src/corelib/io | |
parent | 933bf178aab88ab5df8a68cbf02611d6d8744b1b (diff) | |
parent | 754efa57d89c62d1796e01b407e9222e67450f52 (diff) |
Merge remote-tracking branch 'origin/5.5' into dev
Conflicts:
src/corelib/global/qnamespace.qdoc
src/corelib/io/qwindowspipereader.cpp
src/corelib/io/qwindowspipereader_p.h
src/corelib/statemachine/qstatemachine.cpp
src/corelib/statemachine/qstatemachine_p.h
src/plugins/platforms/xcb/qxcbconnection.h
tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
tests/auto/tools/qmake/tst_qmake.cpp
tests/manual/touch/main.cpp
Change-Id: I917d694890e79ee3da7d65134b5b085e23e0dd62
Diffstat (limited to 'src/corelib/io')
-rw-r--r-- | src/corelib/io/io.pri | 2 | ||||
-rw-r--r-- | src/corelib/io/qfileselector.cpp | 12 | ||||
-rw-r--r-- | src/corelib/io/qfilesystementry.cpp | 16 | ||||
-rw-r--r-- | src/corelib/io/qfilesystemwatcher.cpp | 4 | ||||
-rw-r--r-- | src/corelib/io/qiodevice.cpp | 53 | ||||
-rw-r--r-- | src/corelib/io/qlockfile.cpp | 12 | ||||
-rw-r--r-- | src/corelib/io/qlockfile_p.h | 1 | ||||
-rw-r--r-- | src/corelib/io/qlockfile_unix.cpp | 58 | ||||
-rw-r--r-- | src/corelib/io/qlockfile_win.cpp | 73 | ||||
-rw-r--r-- | src/corelib/io/qnoncontiguousbytedevice.cpp | 18 | ||||
-rw-r--r-- | src/corelib/io/qnoncontiguousbytedevice_p.h | 4 | ||||
-rw-r--r-- | src/corelib/io/qsettings.cpp | 6 | ||||
-rw-r--r-- | src/corelib/io/qstandardpaths.cpp | 30 | ||||
-rw-r--r-- | src/corelib/io/qstandardpaths_ios.mm | 29 | ||||
-rw-r--r-- | src/corelib/io/qstorageinfo_unix.cpp | 24 | ||||
-rw-r--r-- | src/corelib/io/qtextstream.cpp | 12 | ||||
-rw-r--r-- | src/corelib/io/qurl.h | 4 | ||||
-rw-r--r-- | src/corelib/io/qwindowspipereader.cpp | 102 | ||||
-rw-r--r-- | src/corelib/io/qwindowspipereader_p.h | 4 |
19 files changed, 321 insertions, 143 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 4c189bfe57..207de2a85b 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -187,7 +187,7 @@ win32 { } !nacl { - freebsd-*|mac|darwin-*|openbsd-*:{ + freebsd-*|mac|darwin-*|openbsd-*|netbsd-*:{ SOURCES += io/qfilesystemwatcher_kqueue.cpp HEADERS += io/qfilesystemwatcher_kqueue_p.h } diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index 4ca07ba41d..cddd70f908 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -225,9 +225,13 @@ QString QFileSelector::select(const QString &filePath) const return d->select(filePath); } -static QString qrcScheme() +static bool isLocalScheme(const QString &file) { - return QStringLiteral("qrc"); + bool local = file == QStringLiteral("qrc"); +#ifdef Q_OS_ANDROID + local |= file == QStringLiteral("assets"); +#endif + return local; } /*! @@ -240,10 +244,10 @@ static QString qrcScheme() QUrl QFileSelector::select(const QUrl &filePath) const { Q_D(const QFileSelector); - if (filePath.scheme() != qrcScheme() && !filePath.isLocalFile()) + if (!isLocalScheme(filePath.scheme()) && !filePath.isLocalFile()) return filePath; QUrl ret(filePath); - if (filePath.scheme() == qrcScheme()) { + if (isLocalScheme(filePath.scheme())) { QString equivalentPath = QLatin1Char(':') + filePath.path(); QString selectedPath = d->select(equivalentPath); ret.setPath(selectedPath.remove(0, 1)); diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp index faaf7a00af..79f16a0839 100644 --- a/src/corelib/io/qfilesystementry.cpp +++ b/src/corelib/io/qfilesystementry.cpp @@ -255,15 +255,15 @@ QString QFileSystemEntry::completeSuffix() const bool QFileSystemEntry::isRelative() const { resolveFilePath(); - return (m_filePath.isEmpty() || (!m_filePath.isEmpty() && (m_filePath[0].unicode() != '/') - && (!(m_filePath.length() >= 2 && m_filePath[1].unicode() == ':')))); + return (m_filePath.isEmpty() || (!m_filePath.isEmpty() && (m_filePath.at(0).unicode() != '/') + && (!(m_filePath.length() >= 2 && m_filePath.at(1).unicode() == ':')))); } bool QFileSystemEntry::isAbsolute() const { resolveFilePath(); return (!m_filePath.isEmpty() && ((m_filePath.length() >= 3 - && (m_filePath[0].isLetter() && m_filePath[1].unicode() == ':' && m_filePath[2].unicode() == '/')) + && (m_filePath.at(0).isLetter() && m_filePath.at(1).unicode() == ':' && m_filePath.at(2).unicode() == '/')) || (m_filePath.length() >= 2 && (m_filePath.at(0) == QLatin1Char('/') && m_filePath.at(1) == QLatin1Char('/'))) )); } @@ -276,7 +276,7 @@ bool QFileSystemEntry::isRelative() const bool QFileSystemEntry::isAbsolute() const { resolveFilePath(); - return (!m_filePath.isEmpty() && (m_filePath[0].unicode() == '/')); + return (!m_filePath.isEmpty() && (m_filePath.at(0).unicode() == '/')); } #endif @@ -337,10 +337,10 @@ void QFileSystemEntry::findFileNameSeparators() const int i = m_filePath.size() - 1; for (; i >= stop; --i) { - if (m_filePath[i].unicode() == '.') { + if (m_filePath.at(i).unicode() == '.') { firstDotInFileName = lastDotInFileName = i; break; - } else if (m_filePath[i].unicode() == '/') { + } else if (m_filePath.at(i).unicode() == '/') { lastSeparator = i; break; } @@ -348,9 +348,9 @@ void QFileSystemEntry::findFileNameSeparators() const if (lastSeparator != i) { for (--i; i >= stop; --i) { - if (m_filePath[i].unicode() == '.') + if (m_filePath.at(i).unicode() == '.') firstDotInFileName = i; - else if (m_filePath[i].unicode() == '/') { + else if (m_filePath.at(i).unicode() == '/') { lastSeparator = i; break; } diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 0bd46400d3..3a8f7bd0a9 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -52,7 +52,7 @@ # include "qfilesystemwatcher_win_p.h" #elif defined(USE_INOTIFY) # include "qfilesystemwatcher_inotify_p.h" -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_IOS) +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_IOS) # include "qfilesystemwatcher_kqueue_p.h" #elif defined(Q_OS_OSX) # include "qfilesystemwatcher_fsevents_p.h" @@ -68,7 +68,7 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject // there is a chance that inotify may fail on Linux pre-2.6.13 (August // 2005), so we can't just new inotify directly. return QInotifyFileSystemWatcherEngine::create(parent); -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_IOS) +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_IOS) return QKqueueFileSystemWatcherEngine::create(parent); #elif defined(Q_OS_OSX) return QFseventsFileSystemWatcherEngine::create(parent); diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index d68f33287d..07a2ff8f6b 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -38,9 +38,9 @@ #include "qiodevice_p.h" #include "qfile.h" #include "qstringlist.h" +#include "qdir.h" #include <algorithm> -#include <limits.h> #ifdef QIODEVICE_DEBUG # include <ctype.h> @@ -80,10 +80,29 @@ void debugBinaryString(const char *data, qint64 maxlen) #define Q_VOID +static void checkWarnMessage(const QIODevice *device, const char *function, const char *what) +{ + QDebug d = qWarning(); + d.noquote(); + d.nospace(); + d << "QIODevice::" << function; +#ifndef QT_NO_QOBJECT + d << " (" << device->metaObject()->className(); + if (!device->objectName().isEmpty()) + d << ", \"" << device->objectName() << '"'; + if (const QFile *f = qobject_cast<const QFile *>(device)) + d << ", \"" << QDir::toNativeSeparators(f->fileName()) << '"'; + d << ')'; +#else + Q_UNUSED(device) +#endif // !QT_NO_QOBJECT + d << ": " << what; +} + #define CHECK_MAXLEN(function, returnType) \ do { \ if (maxSize < 0) { \ - qWarning("QIODevice::"#function": Called with maxSize < 0"); \ + checkWarnMessage(this, #function, "Called with maxSize < 0"); \ return returnType; \ } \ } while (0) @@ -92,10 +111,10 @@ void debugBinaryString(const char *data, qint64 maxlen) do { \ if ((d->openMode & WriteOnly) == 0) { \ if (d->openMode == NotOpen) { \ - qWarning("QIODevice::"#function": device not open"); \ + checkWarnMessage(this, #function, "device not open"); \ return returnType; \ } \ - qWarning("QIODevice::"#function": ReadOnly device"); \ + checkWarnMessage(this, #function, "ReadOnly device"); \ return returnType; \ } \ } while (0) @@ -104,10 +123,10 @@ void debugBinaryString(const char *data, qint64 maxlen) do { \ if ((d->openMode & ReadOnly) == 0) { \ if (d->openMode == NotOpen) { \ - qWarning("QIODevice::"#function": device not open"); \ + checkWarnMessage(this, #function, "device not open"); \ return returnType; \ } \ - qWarning("QIODevice::"#function": WriteOnly device"); \ + checkWarnMessage(this, #function, "WriteOnly device"); \ return returnType; \ } \ } while (0) @@ -462,7 +481,7 @@ void QIODevice::setTextModeEnabled(bool enabled) { Q_D(QIODevice); if (!isOpen()) { - qWarning("QIODevice::setTextModeEnabled: The device is not open"); + checkWarnMessage(this, "setTextModeEnabled", "The device is not open"); return; } if (enabled) @@ -621,11 +640,11 @@ bool QIODevice::seek(qint64 pos) { Q_D(QIODevice); if (d->isSequential()) { - qWarning("QIODevice::seek: Cannot call seek on a sequential device"); + checkWarnMessage(this, "seek", "Cannot call seek on a sequential device"); return false; } if (d->openMode == NotOpen) { - qWarning("QIODevice::seek: The device is not open"); + checkWarnMessage(this, "seek", "The device is not open"); return false; } if (pos < 0) { @@ -922,9 +941,9 @@ QByteArray QIODevice::read(qint64 maxSize) Q_UNUSED(d); #endif - if (maxSize != qint64(int(maxSize))) { - qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit"); - maxSize = INT_MAX; + if (quint64(maxSize) >= QByteArray::MaxSize) { + checkWarnMessage(this, "read", "maxSize argument exceeds QByteArray size limit"); + maxSize = QByteArray::MaxSize - 1; } qint64 readBytes = 0; @@ -976,7 +995,7 @@ QByteArray QIODevice::readAll() // flush internal read buffer if (!(d->openMode & Text) && !d->buffer.isEmpty()) { - if (d->buffer.size() >= INT_MAX) + if (quint64(d->buffer.size()) >= QByteArray::MaxSize) return QByteArray(); result = d->buffer.readAll(); readBytes = result.size(); @@ -1055,7 +1074,7 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize) { Q_D(QIODevice); if (maxSize < 2) { - qWarning("QIODevice::readLine: Called with maxSize < 2"); + checkWarnMessage(this, "readLine", "Called with maxSize < 2"); return qint64(-1); } @@ -1159,9 +1178,9 @@ QByteArray QIODevice::readLine(qint64 maxSize) Q_UNUSED(d); #endif - if (maxSize > INT_MAX) { + if (quint64(maxSize) >= QByteArray::MaxSize) { qWarning("QIODevice::read: maxSize argument exceeds QByteArray size limit"); - maxSize = INT_MAX; + maxSize = QByteArray::MaxSize - 1; } result.resize(int(maxSize)); @@ -1169,7 +1188,7 @@ QByteArray QIODevice::readLine(qint64 maxSize) if (!result.size()) { // If resize fails or maxSize == 0, read incrementally if (maxSize == 0) - maxSize = INT_MAX; + maxSize = QByteArray::MaxSize - 1; // The first iteration needs to leave an extra byte for the terminating null result.resize(1); diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp index 4f5aeff395..2bd996d213 100644 --- a/src/corelib/io/qlockfile.cpp +++ b/src/corelib/io/qlockfile.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org> +** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -66,9 +67,12 @@ QT_BEGIN_NAMESPACE If the process holding the lock crashes, the lock file stays on disk and can prevent any other process from accessing the shared resource, ever. For this reason, QLockFile - tries to detect such a "stale" lock file, based on the process ID written into the file, - and (in case that process ID got reused meanwhile), on the last modification time of - the lock file (30s by default, for the use case of a short-lived operation). + tries to detect such a "stale" lock file, based on the process ID written into the file. + To cover the situation that the process ID got reused meanwhile, the current process name is + compared to the name of the process that corresponds to the process ID from the lock file. + If the process names differ, the lock file is considered stale. + Additionally, the last modification time of the lock file (30s by default, for the use case of a + short-lived operation) is taken into account. If the lock file is found to be stale, it will be deleted. For the use case of protecting a resource over a long time, you should therefore call @@ -122,7 +126,7 @@ QLockFile::~QLockFile() The value of \a staleLockTime is used by lock() and tryLock() in order to determine when an existing lock file is considered stale, i.e. left over by a crashed process. This is useful for the case where the PID got reused - meanwhile, so the only way to detect a stale lock file is by the fact that + meanwhile, so one way to detect a stale lock file is by the fact that it has been around for a long time. \sa staleLockTime() diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h index 0cfaa42849..168062f467 100644 --- a/src/corelib/io/qlockfile_p.h +++ b/src/corelib/io/qlockfile_p.h @@ -75,6 +75,7 @@ public: // Returns \c true if the lock belongs to dead PID, or is old. // The attempt to delete it will tell us if it was really stale or not, though. bool isApparentlyStale() const; + static QString processNameByPid(qint64 pid); #ifdef Q_OS_UNIX static int checkFcntlWorksAfterFlock(); diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index b817a24c74..d6ea2f1f2d 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org> +** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -48,6 +49,15 @@ #include <signal.h> // kill #include <unistd.h> // gethostname +#if defined(Q_OS_OSX) +# include <libproc.h> +#elif defined(Q_OS_LINUX) +# include <unistd.h> +# include <cstdio> +#elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS) +# include <sys/user.h> +#endif + QT_BEGIN_NAMESPACE static QByteArray localHostName() // from QHostInfo::localHostName(), modified to return a QByteArray @@ -185,16 +195,54 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; - if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { - if (::kill(pid, 0) == -1 && errno == ESRCH) - return true; // PID doesn't exist anymore + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { + if (::kill(pid, 0) == -1 && errno == ESRCH) + return true; // PID doesn't exist anymore + const QString processName = processNameByPid(pid); + if (!processName.isEmpty()) { + QFileInfo fi(appname); + if (fi.isSymLink()) + fi.setFile(fi.symLinkTarget()); + if (processName != fi.fileName()) + return true; // PID got reused by a different application. + } + } } const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); return staleLockTime > 0 && age > staleLockTime; } +QString QLockFilePrivate::processNameByPid(qint64 pid) +{ +#if defined(Q_OS_OSX) + char name[1024]; + proc_name(pid, name, sizeof(name) / sizeof(char)); + return QString::fromUtf8(name); +#elif defined(Q_OS_LINUX) + if (!QFile::exists(QStringLiteral("/proc/version"))) + return QString(); + char exePath[64]; + char buf[PATH_MAX]; + memset(buf, 0, sizeof(buf)); + sprintf(exePath, "/proc/%lld/exe", pid); + if (readlink(exePath, buf, sizeof(buf)) < 0) { + // The pid is gone. Return some invalid process name to fail the test. + return QStringLiteral("/ERROR/"); + } + return QFileInfo(QString::fromUtf8(buf)).fileName(); +#elif defined(Q_OS_BSD4) && !defined(Q_OS_IOS) + kinfo_proc *proc = kinfo_getproc(pid); + if (!proc) + return QString(); + QString name = QString::fromUtf8(proc->ki_comm); + free(proc); + return name; +#else + return QString(); +#endif +} + void QLockFile::unlock() { Q_D(QLockFile); diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index 9fe86e1ad8..5bd1ba04c9 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org> +** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -126,27 +127,75 @@ bool QLockFilePrivate::isApparentlyStale() const { qint64 pid; QString hostname, appname; - if (!getLockInfo(&pid, &hostname, &appname)) - return false; // On WinRT there seems to be no way of obtaining information about other // processes due to sandboxing #ifndef Q_OS_WINRT - if (hostname == QString::fromLocal8Bit(localHostName())) { - HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); - if (!procHandle) - return true; - // We got a handle but check if process is still alive - DWORD dwR = ::WaitForSingleObject(procHandle, 0); - ::CloseHandle(procHandle); - if (dwR == WAIT_TIMEOUT) - return true; + if (getLockInfo(&pid, &hostname, &appname)) { + if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) { + HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!procHandle) + return true; + // We got a handle but check if process is still alive + DWORD dwR = ::WaitForSingleObject(procHandle, 0); + ::CloseHandle(procHandle); + if (dwR == WAIT_TIMEOUT) + return true; + const QString processName = processNameByPid(pid); + if (!processName.isEmpty() && processName != appname) + return true; // PID got reused by a different application. + } } -#endif // !Q_OS_WINRT +#else // !Q_OS_WINRT + Q_UNUSED(pid); + Q_UNUSED(hostname); + Q_UNUSED(appname); +#endif // Q_OS_WINRT const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); return staleLockTime > 0 && age > staleLockTime; } +QString QLockFilePrivate::processNameByPid(qint64 pid) +{ +#if !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE) + typedef DWORD (WINAPI *GetModuleFileNameExFunc)(HANDLE, HMODULE, LPTSTR, DWORD); + + HMODULE hPsapi = LoadLibraryA("psapi"); + if (!hPsapi) + return QString(); + + GetModuleFileNameExFunc qGetModuleFileNameEx + = (GetModuleFileNameExFunc)GetProcAddress(hPsapi, "GetModuleFileNameExW"); + if (!qGetModuleFileNameEx) { + FreeLibrary(hPsapi); + return QString(); + } + + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, DWORD(pid)); + if (!hProcess) { + FreeLibrary(hPsapi); + return QString(); + } + wchar_t buf[MAX_PATH]; + const DWORD length = qGetModuleFileNameEx(hProcess, NULL, buf, sizeof(buf) / sizeof(wchar_t)); + CloseHandle(hProcess); + FreeLibrary(hPsapi); + if (!length) + return QString(); + QString name = QString::fromWCharArray(buf, length); + int i = name.lastIndexOf(QLatin1Char('\\')); + if (i >= 0) + name.remove(0, i + 1); + i = name.lastIndexOf(QLatin1Char('.')); + if (i >= 0) + name.truncate(i); + return name; +#else + Q_UNUSED(pid); + return QString(); +#endif +} + void QLockFile::unlock() { Q_D(QLockFile); diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp index c17b42ef81..af1bb56fe9 100644 --- a/src/corelib/io/qnoncontiguousbytedevice.cpp +++ b/src/corelib/io/qnoncontiguousbytedevice.cpp @@ -216,6 +216,11 @@ qint64 QNonContiguousByteDeviceByteArrayImpl::size() return byteArray->size(); } +qint64 QNonContiguousByteDeviceByteArrayImpl::pos() +{ + return currentPosition; +} + QNonContiguousByteDeviceRingBufferImpl::QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb) : QNonContiguousByteDevice(), currentPosition(0) { @@ -253,6 +258,11 @@ bool QNonContiguousByteDeviceRingBufferImpl::atEnd() return currentPosition >= size(); } +qint64 QNonContiguousByteDeviceRingBufferImpl::pos() +{ + return currentPosition; +} + bool QNonContiguousByteDeviceRingBufferImpl::reset() { currentPosition = 0; @@ -381,6 +391,14 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::size() return device->size() - initialPosition; } +qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() +{ + if (device->isSequential()) + return -1; + + return device->pos(); +} + QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0) { byteDevice = bd; diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h index 8b5bf3080a..38089dedd7 100644 --- a/src/corelib/io/qnoncontiguousbytedevice_p.h +++ b/src/corelib/io/qnoncontiguousbytedevice_p.h @@ -61,6 +61,7 @@ public: virtual const char* readPointer(qint64 maximumLength, qint64 &len) = 0; virtual bool advanceReadPointer(qint64 amount) = 0; virtual bool atEnd() = 0; + virtual qint64 pos() { return -1; } virtual bool reset() = 0; virtual qint64 size() = 0; @@ -103,6 +104,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QByteArray* byteArray; qint64 currentPosition; @@ -118,6 +120,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QSharedPointer<QRingBuffer> ringBuffer; qint64 currentPosition; @@ -135,6 +138,7 @@ public: bool atEnd() Q_DECL_OVERRIDE; bool reset() Q_DECL_OVERRIDE; qint64 size() Q_DECL_OVERRIDE; + qint64 pos() Q_DECL_OVERRIDE; protected: QIODevice* device; QByteArray* currentReadBuffer; diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index cb6de29532..251b10ea89 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -104,6 +104,10 @@ using namespace ABI::Windows::Storage; #define Q_XDG_PLATFORM #endif +#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(Q_OS_IOS)) +#define QSETTINGS_USE_QSTANDARDPATHS +#endif + // ************************************************************************ // QConfFile @@ -1044,7 +1048,7 @@ static void initDefaultPaths(QMutexLocker *locker) windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator()); #else -#if defined(QT_NO_STANDARDPATHS) || !defined(Q_XDG_PLATFORM) +#ifndef QSETTINGS_USE_QSTANDARDPATHS // Non XDG platforms (OS X, iOS, Blackberry, Android...) have used this code path erroneously // for some time now. Moving away from that would require migrating existing settings. QString userPath; diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp index beb5d29d54..04848a38e5 100644 --- a/src/corelib/io/qstandardpaths.cpp +++ b/src/corelib/io/qstandardpaths.cpp @@ -274,45 +274,67 @@ QT_BEGIN_NAMESPACE \endtable \table - \header \li Path type \li Android + \header \li Path type \li Android \li iOS \row \li DesktopLocation \li "<APPROOT>/files" + \li "<APPROOT>/<APPDIR>" (not writable) \row \li DocumentsLocation \li "<USER>/Documents", "<USER>/<APPNAME>/Documents" + \li "<APPROOT>/Documents" \row \li FontsLocation \li "/system/fonts" (not writable) + \li "<APPROOT>/Documents/.fonts" \row \li ApplicationsLocation \li not supported (directory not readable) + \li not supported \row \li MusicLocation \li "<USER>/Music", "<USER>/<APPNAME>/Music" + \li "<APPROOT>/Documents/Music" \row \li MoviesLocation \li "<USER>/Movies", "<USER>/<APPNAME>/Movies" + \li "<APPROOT>/Documents/Movies" \row \li PicturesLocation \li "<USER>/Pictures", "<USER>/<APPNAME>/Pictures" + \li "<APPROOT>/Documents/Pictures", "assets-library://" \row \li TempLocation \li "<APPROOT>/cache" + \li "<APPROOT>/tmp" \row \li HomeLocation \li "<APPROOT>/files" + \li "<APPROOT>/<APPDIR>" (not writable) \row \li DataLocation \li "<APPROOT>/files", "<USER>/<APPNAME>/files" + \li "<APPROOT>/Library/Application Support" \row \li CacheLocation \li "<APPROOT>/cache", "<USER>/<APPNAME>/cache" + \li "<APPROOT>/Library/Caches" \row \li GenericDataLocation \li "<USER>" + \li "<APPROOT>/Documents" \row \li RuntimeLocation \li "<APPROOT>/cache" + \li not supported \row \li ConfigLocation \li "<APPROOT>/files/settings" + \li "<APPROOT>/Documents" \row \li GenericConfigLocation \li "<APPROOT>/files/settings" (there is no shared settings) + \li "<APPROOT>/Documents" \row \li DownloadLocation \li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads" + \li "<APPROOT>/Documents/Download" \row \li GenericCacheLocation \li "<APPROOT>/cache" (there is no shared cache) + \li "<APPROOT>/Library/Caches" \row \li AppDataLocation \li "<APPROOT>/files", "<USER>/<APPNAME>/files" + \li "<APPROOT>/Library/Application Support" \row \li AppConfigLocation \li "<APPROOT>/files/settings" + \li "<APPROOT>/Documents" + \row \li AppLocalDataLocation + \li "<APPROOT>/files", "<USER>/<APPNAME>/files" + \li "<APPROOT>/Library/Application Support" \endtable In the table above, \c <APPNAME> is usually the organization name, the @@ -327,6 +349,12 @@ QT_BEGIN_NAMESPACE \note On Android, applications with open files on the external storage (<USER> locations), will be killed if the external storage is unmounted. + \note On iOS, if you do pass \c {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()} + as argument to \l{QFileDialog::setDirectory()}, + a native image picker dialog will be used for accessing the user's photo album. + The filename returned can be loaded using QFile and related APIs. + This feature was added in Qt 5.5. + \sa writableLocation(), standardLocations(), displayName(), locate(), locateAll() */ diff --git a/src/corelib/io/qstandardpaths_ios.mm b/src/corelib/io/qstandardpaths_ios.mm index 27d28526c2..eb85e2fd23 100644 --- a/src/corelib/io/qstandardpaths_ios.mm +++ b/src/corelib/io/qstandardpaths_ios.mm @@ -55,30 +55,31 @@ QString QStandardPaths::writableLocation(StandardLocation type) QString location; switch (type) { - case DesktopLocation: - location = pathForDirectory(NSDesktopDirectory); - break; case DocumentsLocation: location = pathForDirectory(NSDocumentDirectory); break; case FontsLocation: - location = bundlePath() + QLatin1String("/.fonts"); + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/.fonts"); break; case ApplicationsLocation: - location = pathForDirectory(NSApplicationDirectory); + // NSApplicationDirectory points to a non-existing write-protected path. break; case MusicLocation: - location = pathForDirectory(NSMusicDirectory); + // NSMusicDirectory points to a non-existing write-protected path. Use sensible fallback. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Music"); break; case MoviesLocation: - location = pathForDirectory(NSMoviesDirectory); + // NSMoviesDirectory points to a non-existing write-protected path. Use sensible fallback. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Movies"); break; case PicturesLocation: - location = pathForDirectory(NSPicturesDirectory); + // NSPicturesDirectory points to a non-existing write-protected path. Use sensible fallback. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Pictures"); break; case TempLocation: location = QString::fromNSString(NSTemporaryDirectory()); break; + case DesktopLocation: case HomeLocation: location = bundlePath(); break; @@ -99,20 +100,12 @@ QString QStandardPaths::writableLocation(StandardLocation type) location = pathForDirectory(NSDocumentDirectory); break; case DownloadLocation: - location = pathForDirectory(NSDownloadsDirectory); - break; - default: + // NSDownloadsDirectory points to a non-existing write-protected path. + location = pathForDirectory(NSDocumentDirectory) + QLatin1String("/Download"); break; - } - - switch (type) { case RuntimeLocation: break; default: - // All other types must return something, so use the document directory - // as a reasonable fall-back (which will always exist). - if (location.isEmpty()) - location = pathForDirectory(NSDocumentDirectory); break; } diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 7823787711..f82d0ff0a1 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -67,8 +67,20 @@ #endif #if defined(Q_OS_BSD4) -# define QT_STATFSBUF struct statvfs -# define QT_STATFS ::statvfs +# if defined(Q_OS_NETBSD) + define QT_STATFSBUF struct statvfs + define QT_STATFS ::statvfs +# else +# define QT_STATFSBUF struct statfs +# define QT_STATFS ::statfs +# endif + +# if !defined(ST_RDONLY) +# define ST_RDONLY MNT_RDONLY +# endif +# if !defined(_STATFS_F_FLAGS) +# define _STATFS_F_FLAGS 1 +# endif #elif defined(Q_OS_ANDROID) # define QT_STATFS ::statfs # define QT_STATFSBUF struct statfs @@ -122,11 +134,7 @@ public: inline QByteArray device() const; private: #if defined(Q_OS_BSD4) -# if defined(Q_OS_NETBSD) - struct statvfs *stat_buf; -# else - struct statfs *stat_buf; -# endif + QT_STATFSBUF *stat_buf; int entryCount; int currentIndex; #elif defined(Q_OS_SOLARIS) @@ -502,7 +510,7 @@ void QStorageInfoPrivate::retrieveVolumeInfo() bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize; bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize; bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize; -#if defined(Q_OS_ANDROID) +#if defined(Q_OS_ANDROID) || defined (Q_OS_BSD4) #if defined(_STATFS_F_FLAGS) readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0; #endif diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 5fe4cfef9d..47b96d708f 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -464,7 +464,7 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes) } #if defined (QTEXTSTREAM_DEBUG) qDebug("QTextStreamPrivate::fillReadBuffer(), using %s codec", - codec->name().constData()); + codec ? codec->name().constData() : "no"); #endif #endif @@ -476,9 +476,10 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes) int oldReadBufferSize = readBuffer.size(); #ifndef QT_NO_TEXTCODEC // convert to unicode - readBuffer += codec->toUnicode(buf, bytesRead, &readConverterState); + readBuffer += Q_LIKELY(codec) ? codec->toUnicode(buf, bytesRead, &readConverterState) + : QString::fromLatin1(buf, bytesRead); #else - readBuffer += QString::fromLatin1(QByteArray(buf, bytesRead).constData()); + readBuffer += QString::fromLatin1(buf, bytesRead); #endif // reset the Text flag. @@ -564,7 +565,8 @@ void QTextStreamPrivate::flushWriteBuffer() codec = QTextCodec::codecForLocale(); #if defined (QTEXTSTREAM_DEBUG) qDebug("QTextStreamPrivate::flushWriteBuffer(), using %s codec (%s generating BOM)", - codec->name().constData(), writeConverterState.flags & QTextCodec::IgnoreHeader ? "not" : ""); + codec ? codec->name().constData() : "no", + !codec || (writeConverterState.flags & QTextCodec::IgnoreHeader) ? "not" : ""); #endif // convert from unicode to raw data @@ -572,7 +574,7 @@ void QTextStreamPrivate::flushWriteBuffer() QByteArray data = Q_LIKELY(codec) ? codec->fromUnicode(writeBuffer.data(), writeBuffer.size(), &writeConverterState) : writeBuffer.toLatin1(); #else - QByteArray data = writeBuffer.toLocal8Bit(); + QByteArray data = writeBuffer.toLatin1(); #endif writeBuffer.clear(); diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index 945b7df930..e6c570d1db 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -186,7 +186,7 @@ public: QString url(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toDisplayString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; - QUrl adjusted(FormattingOptions options) const; + QUrl adjusted(FormattingOptions options) const Q_REQUIRED_RESULT; QByteArray toEncoded(FormattingOptions options = FullyEncoded) const; static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode); @@ -243,7 +243,7 @@ public: QString fragment(ComponentFormattingOptions options = PrettyDecoded) const; void setFragment(const QString &fragment, ParsingMode mode = TolerantMode); - QUrl resolved(const QUrl &relative) const; + QUrl resolved(const QUrl &relative) const Q_REQUIRED_RESULT; bool isRelative() const; bool isParentOf(const QUrl &url) const; diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 1502e5dada..2cc5741250 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -36,7 +36,6 @@ #include <qdebug.h> #include <qelapsedtimer.h> #include <qeventloop.h> -#include <qtimer.h> QT_BEGIN_NAMESPACE @@ -45,13 +44,11 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent) handle(INVALID_HANDLE_VALUE), readBufferMaxSize(0), actualReadBufferSize(0), - emitReadyReadTimer(new QTimer(this)), + stopped(true), readSequenceStarted(false), pipeBroken(false), readyReadEmitted(false) { - emitReadyReadTimer->setSingleShot(true); - connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead())); dataReadNotifier = new QWinOverlappedIoNotifier(this); connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified); } @@ -73,12 +70,7 @@ static bool qt_cancelIo(HANDLE handle, OVERLAPPED *overlapped) QWindowsPipeReader::~QWindowsPipeReader() { - if (readSequenceStarted) { - if (qt_cancelIo(handle, &overlapped)) - dataReadNotifier->waitForNotified(-1, &overlapped); - else - qErrnoWarning("QWindowsPipeReader: qt_cancelIo on handle %x failed.", handle); - } + stop(); } /*! @@ -89,9 +81,9 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) readBuffer.clear(); actualReadBufferSize = 0; handle = hPipeReadEnd; - ZeroMemory(&overlapped, sizeof(overlapped)); pipeBroken = false; readyReadEmitted = false; + stopped = false; if (hPipeReadEnd != INVALID_HANDLE_VALUE) { dataReadNotifier->setHandle(hPipeReadEnd); dataReadNotifier->setEnabled(true); @@ -100,13 +92,24 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) /*! Stops the asynchronous read sequence. - This function assumes that the file already has been closed. - It does not cancel any I/O operation. + If the read sequence is running then the I/O operation is canceled. */ void QWindowsPipeReader::stop() { - dataReadNotifier->setEnabled(false); + stopped = true; + if (readSequenceStarted) { + if (qt_cancelIo(handle, &overlapped)) { + dataReadNotifier->waitForNotified(-1, &overlapped); + } else { + const DWORD dwError = GetLastError(); + if (dwError != ERROR_NOT_FOUND) { + qErrnoWarning(dwError, "QWindowsPipeReader: qt_cancelIo on handle %x failed.", + handle); + } + } + } readSequenceStarted = false; + dataReadNotifier->setEnabled(false); handle = INVALID_HANDLE_VALUE; } @@ -119,7 +122,7 @@ qint64 QWindowsPipeReader::bytesAvailable() const } /*! - Stops the asynchronous read sequence. + Copies at most \c{maxlen} bytes from the internal read buffer to \c{data}. */ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) { @@ -147,9 +150,7 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen) } if (!pipeBroken) { - if (!actualReadBufferSize) - emitReadyReadTimer->stop(); - if (!readSequenceStarted) + if (!readSequenceStarted && !stopped) startAsyncRead(); if (readSoFar == 0) return -2; // signal EWOULDBLOCK @@ -172,13 +173,41 @@ void QWindowsPipeReader::notified(quint32 numberOfBytesRead, quint32 errorCode, { if (&overlapped != notifiedOverlapped) return; - if (!completeAsyncRead(numberOfBytesRead, errorCode)) { + + switch (errorCode) { + case ERROR_SUCCESS: + break; + case ERROR_MORE_DATA: + // This is not an error. We're connected to a message mode + // pipe and the message didn't fit into the pipe's system + // buffer. We will read the remaining data in the next call. + break; + case ERROR_BROKEN_PIPE: + case ERROR_PIPE_NOT_CONNECTED: pipeBroken = true; + break; + default: + emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); + pipeBroken = true; + break; + } + + readSequenceStarted = false; + + // After the reader was stopped, the only reason why this function can be called is the + // completion of a cancellation. No signals should be emitted, and no new read sequence should + // be started in this case. + if (stopped) + return; + + if (pipeBroken) { emit pipeClosed(); return; } + + actualReadBufferSize += numberOfBytesRead; + readBuffer.truncate(actualReadBufferSize); startAsyncRead(); - emitReadyReadTimer->stop(); readyReadEmitted = true; emit readyRead(); } @@ -206,6 +235,7 @@ void QWindowsPipeReader::startAsyncRead() char *ptr = readBuffer.reserve(bytesToRead); readSequenceStarted = true; + ZeroMemory(&overlapped, sizeof(overlapped)); if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { // We get notified by the QWinOverlappedIoNotifier - even in the synchronous case. return; @@ -241,38 +271,6 @@ void QWindowsPipeReader::startAsyncRead() /*! \internal - Sets the correct size of the read buffer after a read operation. - Returns \c false, if an error occurred or the connection dropped. - */ -bool QWindowsPipeReader::completeAsyncRead(DWORD bytesRead, DWORD errorCode) -{ - readSequenceStarted = false; - - switch (errorCode) { - case ERROR_SUCCESS: - break; - case ERROR_MORE_DATA: - // This is not an error. We're connected to a message mode - // pipe and the message didn't fit into the pipe's system - // buffer. We will read the remaining data in the next call. - break; - case ERROR_BROKEN_PIPE: - case ERROR_PIPE_NOT_CONNECTED: - return false; - default: - emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); - return false; - } - - actualReadBufferSize += bytesRead; - readBuffer.truncate(actualReadBufferSize); - if (!emitReadyReadTimer->isActive()) - emitReadyReadTimer->start(); - return true; -} - -/*! - \internal Returns the number of available bytes in the pipe. Sets QWindowsPipeReader::pipeBroken to true if the connection is broken. */ diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index 53872e2552..c8a66d9511 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -47,7 +47,6 @@ #include <qbytearray.h> #include <qobject.h> -#include <qtimer.h> #include <private/qringbuffer_p.h> #include <qt_windows.h> @@ -89,7 +88,6 @@ private Q_SLOTS: void notified(quint32 numberOfBytesRead, quint32 errorCode, OVERLAPPED *notifiedOverlapped); private: - bool completeAsyncRead(DWORD bytesRead, DWORD errorCode); DWORD checkPipeState(); private: @@ -99,7 +97,7 @@ private: qint64 readBufferMaxSize; QRingBuffer readBuffer; qint64 actualReadBufferSize; - QTimer *emitReadyReadTimer; + bool stopped; bool readSequenceStarted; bool pipeBroken; bool readyReadEmitted; |