summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qiodevice.cpp53
-rw-r--r--src/corelib/io/qlockfile.cpp12
-rw-r--r--src/corelib/io/qlockfile_p.h1
-rw-r--r--src/corelib/io/qlockfile_unix.cpp48
-rw-r--r--src/corelib/io/qlockfile_win.cpp45
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp24
6 files changed, 154 insertions, 29 deletions
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index e73a200fb4..b908ae3145 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 d1804f2cb6..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
@@ -189,12 +199,50 @@ bool QLockFilePrivate::isApparentlyStale() const
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 4e0d8134ec..8cbe0a9dfd 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.
@@ -140,6 +141,9 @@ bool QLockFilePrivate::isApparentlyStale() const
::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.
}
}
#else // !Q_OS_WINRT
@@ -151,6 +155,47 @@ bool QLockFilePrivate::isApparentlyStale() const
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/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 7b8f608050..d170e7c0c0 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)
@@ -501,7 +509,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