summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri8
-rw-r--r--src/corelib/io/qabstractfileengine.cpp31
-rw-r--r--src/corelib/io/qabstractfileengine_p.h2
-rw-r--r--src/corelib/io/qdatastream.cpp1
-rw-r--r--src/corelib/io/qdatastream.h5
-rw-r--r--src/corelib/io/qdebug.cpp15
-rw-r--r--src/corelib/io/qdebug.h3
-rw-r--r--src/corelib/io/qfile.cpp47
-rw-r--r--src/corelib/io/qfiledevice.cpp76
-rw-r--r--src/corelib/io/qfiledevice.h10
-rw-r--r--src/corelib/io/qfileinfo.cpp104
-rw-r--r--src/corelib/io/qfileinfo.h6
-rw-r--r--src/corelib/io/qfileinfo_p.h10
-rw-r--r--src/corelib/io/qfilesystemengine.cpp4
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp51
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp221
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h11
-rw-r--r--src/corelib/io/qfsfileengine.cpp37
-rw-r--r--src/corelib/io/qfsfileengine_p.h2
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp237
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp109
-rw-r--r--src/corelib/io/qlockfile_unix.cpp12
-rw-r--r--src/corelib/io/qprocess.cpp90
-rw-r--r--src/corelib/io/qprocess.h1
-rw-r--r--src/corelib/io/qprocess_p.h6
-rw-r--r--src/corelib/io/qprocess_unix.cpp129
-rw-r--r--src/corelib/io/qprocess_win.cpp127
-rw-r--r--src/corelib/io/qresource.cpp50
-rw-r--r--src/corelib/io/qsettings.cpp2
-rw-r--r--src/corelib/io/qsettings_p.h2
-rw-r--r--src/corelib/io/qstandardpaths.cpp6
-rw-r--r--src/corelib/io/qstandardpaths_win.cpp10
-rw-r--r--src/corelib/io/qstorageinfo.cpp35
-rw-r--r--src/corelib/io/qstorageinfo.h7
-rw-r--r--src/corelib/io/qtemporaryfile.cpp7
-rw-r--r--src/corelib/io/qtemporaryfile_p.h2
-rw-r--r--src/corelib/io/qtextstream.cpp3
-rw-r--r--src/corelib/io/qtldurl.cpp42
-rw-r--r--src/corelib/io/qwindowspipereader.cpp13
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp8
-rw-r--r--src/corelib/io/qwindowspipewriter_p.h1
-rw-r--r--src/corelib/io/qwinoverlappedionotifier.cpp428
-rw-r--r--src/corelib/io/qwinoverlappedionotifier_p.h90
43 files changed, 979 insertions, 1082 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index d24c290508..4614fe2a6b 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -121,18 +121,16 @@ win32 {
!winrt {
HEADERS += \
io/qwindowspipereader_p.h \
- io/qwindowspipewriter_p.h \
- io/qwinoverlappedionotifier_p.h
+ io/qwindowspipewriter_p.h
SOURCES += \
io/qsettings_win.cpp \
io/qstandardpaths_win.cpp \
io/qstorageinfo_win.cpp \
io/qwindowspipereader.cpp \
- io/qwindowspipewriter.cpp \
- io/qwinoverlappedionotifier.cpp
+ io/qwindowspipewriter.cpp
- LIBS += -lmpr
+ LIBS += -lmpr -lnetapi32 -luserenv
} else {
SOURCES += \
io/qstandardpaths_winrt.cpp \
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index 89727673d3..7a603544f3 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -737,6 +737,24 @@ QString QAbstractFileEngine::owner(FileOwner owner) const
return QString();
}
+
+/*!
+ \since 5.10
+
+ Sets the file \a time to \a newDate, returning true if successful;
+ otherwise returns false.
+
+ This virtual function must be reimplemented by all subclasses.
+
+ \sa fileTime()
+*/
+bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+{
+ Q_UNUSED(newDate);
+ Q_UNUSED(time);
+ return false;
+}
+
/*!
If \a time is \c CreationTime, return when the file was created.
If \a time is \c ModificationTime, return when the file was most
@@ -843,6 +861,19 @@ bool QAbstractFileEngine::unmap(uchar *address)
}
/*!
+ \since 5.10
+
+ Copies the contents from the file specified by \a sourceHandle to this file
+ by cloning it.
+ Returns \c true on success; otherwise, \c false is returned.
+ */
+bool QAbstractFileEngine::clone(int sourceHandle)
+{
+ Q_UNUSED(sourceHandle);
+ return false;
+}
+
+/*!
\since 4.3
\class QAbstractFileEngineIterator
\inmodule QtCore
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
index 58fa776e49..47b3a624fe 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -145,9 +145,11 @@ public:
virtual QString fileName(FileName file=DefaultName) const;
virtual uint ownerId(FileOwner) const;
virtual QString owner(FileOwner) const;
+ virtual bool setFileTime(const QDateTime &newDate, FileTime time);
virtual QDateTime fileTime(FileTime time) const;
virtual void setFileName(const QString &file);
virtual int handle() const;
+ virtual bool clone(int sourceHandle);
bool atEnd() const;
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
index 9a42fb4a37..9044ad74b1 100644
--- a/src/corelib/io/qdatastream.cpp
+++ b/src/corelib/io/qdatastream.cpp
@@ -562,6 +562,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_5_7 Same as Qt_5_6
\value Qt_5_8 Same as Qt_5_6
\value Qt_5_9 Same as Qt_5_6
+ \value Qt_5_10 Same as Qt_5_6
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index 575607e147..0a429d091a 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -96,10 +96,11 @@ public:
Qt_5_7 = Qt_5_6,
Qt_5_8 = Qt_5_7,
Qt_5_9 = Qt_5_8,
-#if QT_VERSION >= 0x050a00
+ Qt_5_10 = Qt_5_9,
+#if QT_VERSION >= 0x050b00
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
- Qt_DefaultCompiledVersion = Qt_5_9
+ Qt_DefaultCompiledVersion = Qt_5_10
};
enum ByteOrder {
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index be33ec2d23..341400fd93 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -648,6 +648,21 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \since 5.10
+ \fn QDebug &QDebug::operator<<(QStringView s)
+
+ Writes the string view, \a s, to the stream and returns a reference to the
+ stream. Normally, QDebug prints the string inside quotes and transforms
+ non-printable characters to their Unicode values (\\u1234).
+
+ To print non-printable characters without transformation, enable the
+ noquote() functionality. Note that some QDebug backends might not be 8-bit
+ clean.
+
+ See the QString overload for examples.
+*/
+
+/*!
\fn QDebug &QDebug::operator<<(QLatin1String s)
Writes the string, \a s, to the stream and returns a reference to the
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 186722b69b..ee8ef679a9 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -151,8 +151,11 @@ public:
inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); }
+#if QT_STRINGVIEW_LEVEL < 2
inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
inline QDebug &operator<<(const QStringRef & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
+#endif
+ inline QDebug &operator<<(QStringView s) { putString(s.data(), size_t(s.size())); return maybeSpace(); }
inline QDebug &operator<<(QLatin1String t) { putByteArray(t.latin1(), t.size(), ContainsLatin1); return maybeSpace(); }
inline QDebug &operator<<(const QByteArray & t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); }
inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index f7e711a7cf..2cfb718932 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -42,6 +42,7 @@
#include "qfile.h"
#include "qfsfileengine_p.h"
#include "qtemporaryfile.h"
+#include "qtemporaryfile_p.h"
#include "qlist.h"
#include "qfileinfo.h"
#include "private/qiodevice_p.h"
@@ -420,7 +421,7 @@ QFile::exists() const
Q_D(const QFile);
// 0x1000000 = QAbstractFileEngine::Refresh, forcing an update
return (d->engine()->fileFlags(QAbstractFileEngine::FlagsMask
- | QAbstractFileEngine::FileFlag(0x1000000)) & QAbstractFileEngine::ExistsFlag);
+ | QAbstractFileEngine::Refresh) & QAbstractFileEngine::ExistsFlag);
}
/*!
@@ -794,25 +795,27 @@ QFile::copy(const QString &newName)
close();
d->setError(QFile::CopyError, tr("Cannot open for output"));
} else {
- char block[4096];
- qint64 totalRead = 0;
- while(!atEnd()) {
- qint64 in = read(block, sizeof(block));
- if (in <= 0)
- break;
- totalRead += in;
- if(in != out.write(block, in)) {
- close();
- d->setError(QFile::CopyError, tr("Failure to write block"));
- error = true;
- break;
+ if (!out.d_func()->engine()->clone(d->engine()->handle())) {
+ char block[4096];
+ qint64 totalRead = 0;
+ while (!atEnd()) {
+ qint64 in = read(block, sizeof(block));
+ if (in <= 0)
+ break;
+ totalRead += in;
+ if (in != out.write(block, in)) {
+ close();
+ d->setError(QFile::CopyError, tr("Failure to write block"));
+ error = true;
+ break;
+ }
}
- }
- if (totalRead != size()) {
- // Unable to read from the source. The error string is
- // already set from read().
- error = true;
+ if (totalRead != size()) {
+ // Unable to read from the source. The error string is
+ // already set from read().
+ error = true;
+ }
}
if (!error && !out.rename(newName)) {
error = true;
@@ -957,7 +960,9 @@ bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
qWarning("QFile::open: File access not specified");
return false;
}
- if (d->openExternalFile(mode, fh, handleFlags)) {
+
+ // QIODevice provides the buffering, so request unbuffered file engines
+ if (d->openExternalFile(mode | Unbuffered, fh, handleFlags)) {
QIODevice::open(mode);
if (!(mode & Append) && !isSequential()) {
qint64 pos = (qint64)QT_FTELL(fh);
@@ -1013,7 +1018,9 @@ bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
qWarning("QFile::open: File access not specified");
return false;
}
- if (d->openExternalFile(mode, fd, handleFlags)) {
+
+ // QIODevice provides the buffering, so request unbuffered file engines
+ if (d->openExternalFile(mode | Unbuffered, fd, handleFlags)) {
QIODevice::open(mode);
if (!(mode & Append) && !isSequential()) {
qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR);
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index 715dc7293a..b642add7f6 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -738,6 +738,82 @@ bool QFileDevice::unmap(uchar *address)
return false;
}
+/*!
+ \enum QFileDevice::FileTime
+ \since 5.10
+
+ This enum is used by the fileTime() and setFileTime() functions.
+
+ \value FileCreationTime When the file was created (not supported on UNIX).
+ \value FileModificationTime When the file was most recently modified.
+ \value FileAccessTime When the file was most recently accessed (e.g.
+ read or written to).
+
+ \sa setFileTime(), fileTime()
+*/
+
+static inline QAbstractFileEngine::FileTime FileDeviceTimeToAbstractFileEngineTime(QFileDevice::FileTime time)
+{
+ switch (time) {
+ case QFileDevice::FileAccessTime:
+ return QAbstractFileEngine::AccessTime;
+
+ case QFileDevice::FileCreationTime:
+ return QAbstractFileEngine::CreationTime;
+
+ case QFileDevice::FileModificationTime:
+ return QAbstractFileEngine::ModificationTime;
+ }
+
+ Q_UNREACHABLE();
+ return QAbstractFileEngine::AccessTime;
+}
+
+/*!
+ \since 5.10
+ Returns the file time specified by \a time.
+ If the time cannot be determined return QDateTime() (an invalid
+ date time).
+
+ \sa setFileTime(), FileTime, QDateTime::isValid()
+*/
+QDateTime QFileDevice::fileTime(QFileDevice::FileTime time) const
+{
+ Q_D(const QFileDevice);
+
+ if (d->engine())
+ return d->engine()->fileTime(FileDeviceTimeToAbstractFileEngineTime(time));
+
+ return QDateTime();
+}
+
+/*!
+ \since 5.10
+ Sets the file time specified by \a fileTime to \a newDate, returning true
+ if successful; otherwise returns false.
+
+ \note The file must be open to use this function.
+
+ \sa fileTime(), FileTime
+*/
+bool QFileDevice::setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime)
+{
+ Q_D(QFileDevice);
+
+ if (!d->engine()) {
+ d->setError(QFileDevice::UnspecifiedError, tr("No file engine available"));
+ return false;
+ }
+
+ if (!d->fileEngine->setFileTime(newDate, FileDeviceTimeToAbstractFileEngineTime(fileTime))) {
+ d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+ return false;
+ }
+
+ unsetError();
+ return true;
+}
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfiledevice.h b/src/corelib/io/qfiledevice.h
index 4cfda1b044..3519a049a9 100644
--- a/src/corelib/io/qfiledevice.h
+++ b/src/corelib/io/qfiledevice.h
@@ -45,6 +45,7 @@
QT_BEGIN_NAMESPACE
+class QDateTime;
class QFileDevicePrivate;
class Q_CORE_EXPORT QFileDevice : public QIODevice
@@ -73,6 +74,12 @@ public:
CopyError = 14
};
+ enum FileTime {
+ FileCreationTime,
+ FileModificationTime,
+ FileAccessTime
+ };
+
enum Permission {
ReadOwner = 0x4000, WriteOwner = 0x2000, ExeOwner = 0x1000,
ReadUser = 0x0400, WriteUser = 0x0200, ExeUser = 0x0100,
@@ -119,6 +126,9 @@ public:
uchar *map(qint64 offset, qint64 size, MemoryMapFlags flags = NoOptions);
bool unmap(uchar *address);
+ QDateTime fileTime(QFileDevice::FileTime time) const;
+ bool setFileTime(const QDateTime &newDate, QFileDevice::FileTime fileTime);
+
protected:
QFileDevice();
#ifdef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 12fd7d3048..77349d511d 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -42,6 +42,7 @@
#include "qglobal.h"
#include "qdir.h"
#include "qfileinfo_p.h"
+#include "qdebug.h"
QT_BEGIN_NAMESPACE
@@ -185,17 +186,22 @@ uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) cons
QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) const
{
Q_ASSERT(fileEngine); // should never be called when using the native FS
- if (fileTimes.size() != 3)
- fileTimes.resize(3);
if (!cache_enabled)
clearFlags();
- uint cf;
- if (request == QAbstractFileEngine::CreationTime)
+
+ uint cf = 0;
+ switch (request) {
+ case QAbstractFileEngine::AccessTime:
+ cf = CachedATime;
+ break;
+ case QAbstractFileEngine::CreationTime:
cf = CachedCTime;
- else if (request == QAbstractFileEngine::ModificationTime)
+ break;
+ case QAbstractFileEngine::ModificationTime:
cf = CachedMTime;
- else
- cf = CachedATime;
+ break;
+ }
+
if (!getCachedFlag(cf)) {
fileTimes[request] = fileEngine->fileTime(request);
setCachedFlag(cf);
@@ -262,8 +268,8 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
info objects, just append one to the file name given to the constructors
or setFile().
- The file's dates are returned by created(), lastModified() and
- lastRead(). Information about the file's access permissions is
+ The file's dates are returned by created(), lastModified(), lastRead() and
+ fileTime(). Information about the file's access permissions is
obtained with isReadable(), isWritable() and isExecutable(). The
file's ownership is available from owner(), ownerId(), group() and
groupId(). You can examine a file's permissions and ownership in a
@@ -1309,35 +1315,17 @@ qint64 QFileInfo::size() const
*/
QDateTime QFileInfo::created() const
{
- Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return QDateTime();
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::CreationTime))
- if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::CreationTime))
- return QDateTime();
- return d->metaData.creationTime().toLocalTime();
- }
- return d->getFileTime(QAbstractFileEngine::CreationTime).toLocalTime();
+ return fileTime(QFile::FileCreationTime);
}
/*!
Returns the date and local time when the file was last modified.
- \sa created(), lastRead()
+ \sa created(), lastRead(), fileTime()
*/
QDateTime QFileInfo::lastModified() const
{
- Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return QDateTime();
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ModificationTime))
- if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ModificationTime))
- return QDateTime();
- return d->metaData.modificationTime().toLocalTime();
- }
- return d->getFileTime(QAbstractFileEngine::ModificationTime).toLocalTime();
+ return fileTime(QFile::FileModificationTime);
}
/*!
@@ -1346,20 +1334,51 @@ QDateTime QFileInfo::lastModified() const
On platforms where this information is not available, returns the
same as lastModified().
- \sa created(), lastModified()
+ \sa created(), lastModified(), fileTime()
*/
QDateTime QFileInfo::lastRead() const
{
+ return fileTime(QFile::FileAccessTime);
+}
+
+/*!
+ \since 5.10
+ Returns the file time specified by \a time.
+ If the time cannot be determined return QDateTime() (an invalid
+ date time).
+
+ \sa QFile::FileTime, QDateTime::isValid()
+*/
+QDateTime QFileInfo::fileTime(QFile::FileTime time) const
+{
+ Q_STATIC_ASSERT(int(QFile::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
+ Q_STATIC_ASSERT(int(QFile::FileCreationTime) == int(QAbstractFileEngine::CreationTime));
+ Q_STATIC_ASSERT(int(QFile::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
+
Q_D(const QFileInfo);
+ auto fetime = QAbstractFileEngine::FileTime(time);
if (d->isDefaultConstructed)
return QDateTime();
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::AccessTime))
- if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::AccessTime))
- return QDateTime();
- return d->metaData.accessTime().toLocalTime();
+ if (d->fileEngine)
+ return d->getFileTime(fetime).toLocalTime();
+
+ QFileSystemMetaData::MetaDataFlags flag;
+ switch (time) {
+ case QFile::FileAccessTime:
+ flag = QFileSystemMetaData::AccessTime;
+ break;
+ case QFile::FileCreationTime:
+ flag = QFileSystemMetaData::CreationTime;
+ break;
+ case QFile::FileModificationTime:
+ flag = QFileSystemMetaData::ModificationTime;
+ break;
}
- return d->getFileTime(QAbstractFileEngine::AccessTime).toLocalTime();
+
+ if (!d->cache_enabled || !d->metaData.hasFlags(flag))
+ if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, flag))
+ return QDateTime();
+ return d->metaData.fileTime(fetime).toLocalTime();
}
/*!
@@ -1406,4 +1425,15 @@ void QFileInfo::setCaching(bool enable)
Synonym for QList<QFileInfo>.
*/
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QFileInfo &fi)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg.noquote();
+ dbg << "QFileInfo(" << QDir::toNativeSeparators(fi.filePath()) << ')';
+ return dbg;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index a160e8463e..845fdefac7 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -129,9 +129,11 @@ public:
qint64 size() const;
+ // ### Qt6: inline these functions
QDateTime created() const;
QDateTime lastModified() const;
QDateTime lastRead() const;
+ QDateTime fileTime(QFile::FileTime time) const;
bool caching() const;
void setCaching(bool on);
@@ -151,6 +153,10 @@ Q_DECLARE_SHARED(QFileInfo)
typedef QList<QFileInfo> QFileInfoList;
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QFileInfo &);
+#endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QFileInfo)
diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h
index 806df179e8..d45cf6be33 100644
--- a/src/corelib/io/qfileinfo_p.h
+++ b/src/corelib/io/qfileinfo_p.h
@@ -56,7 +56,6 @@
#include "qatomic.h"
#include "qshareddata.h"
#include "qfilesystemengine_p.h"
-#include "qvector.h"
#include <QtCore/private/qabstractfileengine_p.h>
#include <QtCore/private/qfilesystementry_p.h>
@@ -158,19 +157,14 @@ public:
QScopedPointer<QAbstractFileEngine> const fileEngine;
mutable QString fileNames[QAbstractFileEngine::NFileNames];
- mutable QString fileOwners[2];
+ mutable QString fileOwners[2]; // QAbstractFileEngine::FileOwner: OwnerUser and OwnerGroup
+ mutable QDateTime fileTimes[4]; // QAbstractFileEngine::FileTime: BirthTime, MetadataChangeTime, ModificationTime, AccessTime
mutable uint cachedFlags : 30;
bool const isDefaultConstructed : 1; // QFileInfo is a default constructed instance
bool cache_enabled : 1;
mutable uint fileFlags;
mutable qint64 fileSize;
- // ### Qt6: FIXME: This vector is essentially a plain array
- // mutable QDateTime fileTimes[3], but the array is slower
- // to initialize than the QVector as QDateTime has a pimpl.
- // In Qt 6, QDateTime should inline its data members,
- // and this here can be an array again.
- mutable QVector<QDateTime> fileTimes;
inline bool getCachedFlag(uint c) const
{ return cache_enabled ? (cachedFlags & c) : 0; }
inline void setCachedFlag(uint c) const
diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp
index ccbcdb1037..f3205ae6e2 100644
--- a/src/corelib/io/qfilesystemengine.cpp
+++ b/src/corelib/io/qfilesystemengine.cpp
@@ -281,7 +281,9 @@ void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
entryFlags |= QFileSystemMetaData::SequentialType;
// Attributes
- entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ entryFlags |= QFileSystemMetaData::ExistsAttribute; // inode exists
+ if (statBuffer.st_nlink == 0)
+ entryFlags |= QFileSystemMetaData::WasDeletedAttribute;
size_ = statBuffer.st_size;
#if defined(Q_OS_DARWIN)
if (statBuffer.st_flags & UF_HIDDEN) {
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 6640e2b7e7..b0c23e3f82 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -43,6 +43,8 @@
#include "qfilesystemengine_p.h"
#include "qfile.h"
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/private/qcore_unix_p.h>
#include <QtCore/qvarlengtharray.h>
#include <stdlib.h> // for realpath()
@@ -67,6 +69,9 @@
#endif
#if defined(Q_OS_DARWIN)
+# if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000)
+# include <sys/clonefile.h>
+# endif
// We cannot include <Foundation/Foundation.h> (it's an Objective-C header), but
// we need these declarations:
Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
@@ -146,30 +151,8 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
//static
QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
{
-#if defined(__GLIBC__) && !defined(PATH_MAX)
-#define PATH_CHUNK_SIZE 256
- char *s = 0;
- int len = -1;
- int size = PATH_CHUNK_SIZE;
-
- while (1) {
- s = (char *) ::realloc(s, size);
- Q_CHECK_PTR(s);
- len = ::readlink(link.nativeFilePath().constData(), s, size);
- if (len < 0) {
- ::free(s);
- break;
- }
- if (len < size) {
- break;
- }
- size *= 2;
- }
-#else
- char s[PATH_MAX+1];
- int len = readlink(link.nativeFilePath().constData(), s, PATH_MAX);
-#endif
- if (len > 0) {
+ QByteArray s = qt_readlink(link.nativeFilePath().constData());
+ if (s.length() > 0) {
QString ret;
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
@@ -180,11 +163,7 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
if (!ret.isEmpty() && !ret.endsWith(QLatin1Char('/')))
ret += QLatin1Char('/');
}
- s[len] = '\0';
- ret += QFile::decodeName(QByteArray(s));
-#if defined(__GLIBC__) && !defined(PATH_MAX)
- ::free(s);
-#endif
+ ret += QFile::decodeName(s);
if (!ret.startsWith(QLatin1Char('/'))) {
const QString linkFilePath = link.filePath();
@@ -649,8 +628,22 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
//static
bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
+#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000)
+ const auto current = QOperatingSystemVersion::current();
+ if (current >= QOperatingSystemVersion::MacOSSierra ||
+ current >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 10) ||
+ current >= QOperatingSystemVersion(QOperatingSystemVersion::TvOS, 10) ||
+ current >= QOperatingSystemVersion(QOperatingSystemVersion::WatchOS, 3)) {
+ if (::clonefile(source.nativeFilePath().constData(),
+ target.nativeFilePath().constData(), 0) == 0)
+ return true;
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+#else
Q_UNUSED(source);
Q_UNUSED(target);
+#endif
error = QSystemError(ENOSYS, QSystemError::StandardLibraryError); //Function not implemented
return false;
}
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 0542d9e16c..5a9864edb2 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -48,7 +48,6 @@
#include "qfile.h"
#include "qdir.h"
-#include "private/qmutexpool_p.h"
#include "qvarlengtharray.h"
#include "qdatetime.h"
#include "qt_windows.h"
@@ -60,6 +59,7 @@
#include <objbase.h>
#ifndef Q_OS_WINRT
# include <shlobj.h>
+# include <lm.h>
# include <accctrl.h>
#endif
#include <initguid.h>
@@ -147,48 +147,30 @@ typedef struct _REPARSE_DATA_BUFFER {
# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif
-QT_BEGIN_NAMESPACE
-
-Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
-
-#if defined(Q_OS_WINRT)
-// As none of the functions we try to resolve do exist on WinRT we
-// avoid library loading on WinRT in general to shorten everything
-// up a little bit.
+#if defined(Q_OS_WINRT) || defined(QT_BOOTSTRAPPED)
# define QT_FEATURE_fslibs -1
#else
-# define QT_FEATURE_fslibs QT_FEATURE_library
+# define QT_FEATURE_fslibs 1
#endif // Q_OS_WINRT
#if QT_CONFIG(fslibs)
-QT_BEGIN_INCLUDE_NAMESPACE
-typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*);
-static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0;
-typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE);
-static PtrLookupAccountSidW ptrLookupAccountSidW = 0;
-typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID);
-static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0;
-typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK);
-static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0;
-typedef BOOL (WINAPI *PtrGetUserProfileDirectoryW)(HANDLE, LPWSTR, LPDWORD);
-static PtrGetUserProfileDirectoryW ptrGetUserProfileDirectoryW = 0;
-QT_END_INCLUDE_NAMESPACE
-
+#include <aclapi.h>
+#include <userenv.h>
static TRUSTEE_W currentUserTrusteeW;
static TRUSTEE_W worldTrusteeW;
static PSID currentUserSID = 0;
static PSID worldSID = 0;
-/*
- Deletes the allocated SIDs during global static cleanup
-*/
-class SidCleanup
+QT_BEGIN_NAMESPACE
+
+namespace {
+struct GlobalSid
{
-public:
- ~SidCleanup();
+ GlobalSid();
+ ~GlobalSid();
};
-SidCleanup::~SidCleanup()
+GlobalSid::~GlobalSid()
{
free(currentUserSID);
currentUserSID = 0;
@@ -200,39 +182,13 @@ SidCleanup::~SidCleanup()
}
}
-Q_GLOBAL_STATIC(SidCleanup, initSidCleanup)
-
-static void resolveLibs()
+GlobalSid::GlobalSid()
{
- static bool triedResolve = false;
- if (!triedResolve) {
- // need to resolve the security info functions
-
- // protect initialization
-#ifndef QT_NO_THREAD
- QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
- // check triedResolve again, since another thread may have already
- // done the initialization
- if (triedResolve) {
- // another thread did initialize the security function pointers,
- // so we shouldn't do it again.
- return;
- }
-#endif
-
- triedResolve = true;
- HINSTANCE advapiHnd = QSystemLibrary::load(L"advapi32");
- if (advapiHnd) {
- ptrGetNamedSecurityInfoW = (PtrGetNamedSecurityInfoW)GetProcAddress(advapiHnd, "GetNamedSecurityInfoW");
- ptrLookupAccountSidW = (PtrLookupAccountSidW)GetProcAddress(advapiHnd, "LookupAccountSidW");
- ptrBuildTrusteeWithSidW = (PtrBuildTrusteeWithSidW)GetProcAddress(advapiHnd, "BuildTrusteeWithSidW");
- ptrGetEffectiveRightsFromAclW = (PtrGetEffectiveRightsFromAclW)GetProcAddress(advapiHnd, "GetEffectiveRightsFromAclW");
- }
- if (ptrBuildTrusteeWithSidW) {
+ {
+ {
// Create TRUSTEE for current user
HANDLE hnd = ::GetCurrentProcess();
HANDLE token = 0;
- initSidCleanup();
if (::OpenProcessToken(hnd, TOKEN_QUERY, &token)) {
DWORD retsize = 0;
// GetTokenInformation requires a buffer big enough for the TOKEN_USER struct and
@@ -247,62 +203,33 @@ static void resolveLibs()
DWORD sidLen = ::GetLengthSid(tokenSid);
currentUserSID = reinterpret_cast<PSID>(malloc(sidLen));
if (::CopySid(sidLen, currentUserSID, tokenSid))
- ptrBuildTrusteeWithSidW(&currentUserTrusteeW, currentUserSID);
+ BuildTrusteeWithSid(&currentUserTrusteeW, currentUserSID);
}
free(tokenBuffer);
}
::CloseHandle(token);
}
- typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*);
- PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = (PtrAllocateAndInitializeSid)GetProcAddress(advapiHnd, "AllocateAndInitializeSid");
- if (ptrAllocateAndInitializeSid) {
+ {
// Create TRUSTEE for Everyone (World)
SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY };
- if (ptrAllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSID))
- ptrBuildTrusteeWithSidW(&worldTrusteeW, worldSID);
+ if (AllocateAndInitializeSid(&worldAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &worldSID))
+ BuildTrusteeWithSid(&worldTrusteeW, worldSID);
}
}
- HINSTANCE userenvHnd = QSystemLibrary::load(L"userenv");
- if (userenvHnd)
- ptrGetUserProfileDirectoryW = (PtrGetUserProfileDirectoryW)GetProcAddress(userenvHnd, "GetUserProfileDirectoryW");
}
}
-#endif // QT_CONFIG(fslibs)
-typedef DWORD (WINAPI *PtrNetShareEnum)(LPWSTR, DWORD, LPBYTE*, DWORD, LPDWORD, LPDWORD, LPDWORD);
-static PtrNetShareEnum ptrNetShareEnum = 0;
-typedef DWORD (WINAPI *PtrNetApiBufferFree)(LPVOID);
-static PtrNetApiBufferFree ptrNetApiBufferFree = 0;
-typedef struct _SHARE_INFO_1 {
- LPWSTR shi1_netname;
- DWORD shi1_type;
- LPWSTR shi1_remark;
-} SHARE_INFO_1;
+Q_GLOBAL_STATIC(GlobalSid, initGlobalSid)
+QT_END_NAMESPACE
-static bool resolveUNCLibs()
-{
- static bool triedResolve = false;
- if (!triedResolve) {
-#ifndef QT_NO_THREAD
- QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
- if (triedResolve) {
- return ptrNetShareEnum && ptrNetApiBufferFree;
- }
-#endif
- triedResolve = true;
-#if !defined(Q_OS_WINRT)
- HINSTANCE hLib = QSystemLibrary::load(L"Netapi32");
- if (hLib) {
- ptrNetShareEnum = (PtrNetShareEnum)GetProcAddress(hLib, "NetShareEnum");
- if (ptrNetShareEnum)
- ptrNetApiBufferFree = (PtrNetApiBufferFree)GetProcAddress(hLib, "NetApiBufferFree");
- }
-#endif // !Q_OS_WINRT
- }
- return ptrNetShareEnum && ptrNetApiBufferFree;
-}
+} // anonymous namespace
+#endif // QT_CONFIG(fslibs)
+
+QT_BEGIN_NAMESPACE
+
+Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
static QString readSymLink(const QFileSystemEntry &link)
{
@@ -339,7 +266,7 @@ static QString readSymLink(const QFileSystemEntry &link)
CloseHandle(handle);
#if QT_CONFIG(fslibs)
- resolveLibs();
+ initGlobalSid();
QRegExp matchVolName(QLatin1String("^Volume\\{([a-z]|[0-9]|-)+\\}\\\\"), Qt::CaseInsensitive);
if (matchVolName.indexIn(result) == 0) {
DWORD len;
@@ -436,25 +363,27 @@ static inline bool getFindData(QString path, WIN32_FIND_DATA &findData)
bool QFileSystemEngine::uncListSharesOnServer(const QString &server, QStringList *list)
{
- if (resolveUNCLibs()) {
- SHARE_INFO_1 *BufPtr, *p;
- DWORD res;
- DWORD er = 0, tr = 0, resume = 0, i;
- do {
- res = ptrNetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume);
- if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) {
- p = BufPtr;
- for (i = 1; i <= er; ++i) {
- if (list && p->shi1_type == 0)
- list->append(QString::fromWCharArray(p->shi1_netname));
- p++;
- }
+ DWORD res = ERROR_NOT_SUPPORTED;
+#ifndef Q_OS_WINRT
+ SHARE_INFO_1 *BufPtr, *p;
+ DWORD er = 0, tr = 0, resume = 0, i;
+ do {
+ res = NetShareEnum((wchar_t*)server.utf16(), 1, (LPBYTE *)&BufPtr, DWORD(-1), &er, &tr, &resume);
+ if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA) {
+ p = BufPtr;
+ for (i = 1; i <= er; ++i) {
+ if (list && p->shi1_type == 0)
+ list->append(QString::fromWCharArray(p->shi1_netname));
+ p++;
}
- ptrNetApiBufferFree(BufPtr);
- } while (res == ERROR_MORE_DATA);
- return res == ERROR_SUCCESS;
- }
- return false;
+ }
+ NetApiBufferFree(BufPtr);
+ } while (res == ERROR_MORE_DATA);
+#else
+ Q_UNUSED(server);
+ Q_UNUSED(list);
+#endif
+ return res == ERROR_SUCCESS;
}
void QFileSystemEngine::clearWinStatData(QFileSystemMetaData &data)
@@ -647,31 +576,31 @@ QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEng
QString name;
#if QT_CONFIG(fslibs)
extern int qt_ntfs_permission_lookup;
- if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) {
- resolveLibs();
- if (ptrGetNamedSecurityInfoW && ptrLookupAccountSidW) {
+ if (qt_ntfs_permission_lookup > 0) {
+ initGlobalSid();
+ {
PSID pOwner = 0;
PSECURITY_DESCRIPTOR pSD;
- if (ptrGetNamedSecurityInfoW((wchar_t*)entry.nativeFilePath().utf16(), SE_FILE_OBJECT,
- own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION,
- own == QAbstractFileEngine::OwnerUser ? &pOwner : 0, own == QAbstractFileEngine::OwnerGroup ? &pOwner : 0,
- 0, 0, &pSD) == ERROR_SUCCESS) {
+ if (GetNamedSecurityInfo(reinterpret_cast<const wchar_t*>(entry.nativeFilePath().utf16()), SE_FILE_OBJECT,
+ own == QAbstractFileEngine::OwnerGroup ? GROUP_SECURITY_INFORMATION : OWNER_SECURITY_INFORMATION,
+ own == QAbstractFileEngine::OwnerUser ? &pOwner : 0, own == QAbstractFileEngine::OwnerGroup ? &pOwner : 0,
+ 0, 0, &pSD) == ERROR_SUCCESS) {
DWORD lowner = 64;
DWORD ldomain = 64;
QVarLengthArray<wchar_t, 64> owner(lowner);
QVarLengthArray<wchar_t, 64> domain(ldomain);
SID_NAME_USE use = SidTypeUnknown;
// First call, to determine size of the strings (with '\0').
- if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner,
- (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) {
+ if (!LookupAccountSid(NULL, pOwner, (LPWSTR)owner.data(), &lowner,
+ domain.data(), &ldomain, &use)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
if (lowner > (DWORD)owner.size())
owner.resize(lowner);
if (ldomain > (DWORD)domain.size())
domain.resize(ldomain);
// Second call, try on resized buf-s
- if (!ptrLookupAccountSidW(NULL, pOwner, (LPWSTR)owner.data(), &lowner,
- (LPWSTR)domain.data(), &ldomain, (SID_NAME_USE*)&use)) {
+ if (!LookupAccountSid(NULL, pOwner, owner.data(), &lowner,
+ domain.data(), &ldomain, &use)) {
lowner = 0;
}
} else {
@@ -696,9 +625,9 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
QFileSystemMetaData::MetaDataFlags what)
{
#if QT_CONFIG(fslibs)
- if((qt_ntfs_permission_lookup > 0) && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) {
- resolveLibs();
- if(ptrGetNamedSecurityInfoW && ptrBuildTrusteeWithSidW && ptrGetEffectiveRightsFromAclW) {
+ if (qt_ntfs_permission_lookup > 0) {
+ initGlobalSid();
+ {
enum { ReadMask = 0x00000001, WriteMask = 0x00000002, ExecMask = 0x00000020 };
QString fname = entry.nativeFilePath();
@@ -706,15 +635,15 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
PSID pGroup = 0;
PACL pDacl;
PSECURITY_DESCRIPTOR pSD;
- DWORD res = ptrGetNamedSecurityInfoW((wchar_t*)fname.utf16(), SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
- &pOwner, &pGroup, &pDacl, 0, &pSD);
+ DWORD res = GetNamedSecurityInfo(reinterpret_cast<const wchar_t*>(fname.utf16()), SE_FILE_OBJECT,
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
+ &pOwner, &pGroup, &pDacl, 0, &pSD);
if(res == ERROR_SUCCESS) {
ACCESS_MASK access_mask;
TRUSTEE_W trustee;
if (what & QFileSystemMetaData::UserPermissions) { // user
data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
- if(ptrGetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
+ if (GetEffectiveRightsFromAcl(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
access_mask = (ACCESS_MASK)-1;
if(access_mask & ReadMask)
data.entryFlags |= QFileSystemMetaData::UserReadPermission;
@@ -725,8 +654,8 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
}
if (what & QFileSystemMetaData::OwnerPermissions) { // owner
data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions;
- ptrBuildTrusteeWithSidW(&trustee, pOwner);
- if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
+ BuildTrusteeWithSid(&trustee, pOwner);
+ if (GetEffectiveRightsFromAcl(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
access_mask = (ACCESS_MASK)-1;
if(access_mask & ReadMask)
data.entryFlags |= QFileSystemMetaData::OwnerReadPermission;
@@ -737,8 +666,8 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
}
if (what & QFileSystemMetaData::GroupPermissions) { // group
data.knownFlagsMask |= QFileSystemMetaData::GroupPermissions;
- ptrBuildTrusteeWithSidW(&trustee, pGroup);
- if(ptrGetEffectiveRightsFromAclW(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
+ BuildTrusteeWithSid(&trustee, pGroup);
+ if (GetEffectiveRightsFromAcl(pDacl, &trustee, &access_mask) != ERROR_SUCCESS)
access_mask = (ACCESS_MASK)-1;
if(access_mask & ReadMask)
data.entryFlags |= QFileSystemMetaData::GroupReadPermission;
@@ -749,7 +678,7 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
}
if (what & QFileSystemMetaData::OtherPermissions) { // other (world)
data.knownFlagsMask |= QFileSystemMetaData::OtherPermissions;
- if(ptrGetEffectiveRightsFromAclW(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS)
+ if (GetEffectiveRightsFromAcl(pDacl, &worldTrusteeW, &access_mask) != ERROR_SUCCESS)
access_mask = (ACCESS_MASK)-1; // ###
if(access_mask & ReadMask)
data.entryFlags |= QFileSystemMetaData::OtherReadPermission;
@@ -1160,19 +1089,19 @@ QString QFileSystemEngine::homePath()
{
QString ret;
#if QT_CONFIG(fslibs)
- resolveLibs();
- if (ptrGetUserProfileDirectoryW) {
+ initGlobalSid();
+ {
HANDLE hnd = ::GetCurrentProcess();
HANDLE token = 0;
BOOL ok = ::OpenProcessToken(hnd, TOKEN_QUERY, &token);
if (ok) {
DWORD dwBufferSize = 0;
// First call, to determine size of the strings (with '\0').
- ok = ptrGetUserProfileDirectoryW(token, NULL, &dwBufferSize);
+ ok = GetUserProfileDirectory(token, NULL, &dwBufferSize);
if (!ok && dwBufferSize != 0) { // We got the required buffer size
wchar_t *userDirectory = new wchar_t[dwBufferSize];
// Second call, now we can fill the allocated buffer.
- ok = ptrGetUserProfileDirectoryW(token, userDirectory, &dwBufferSize);
+ ok = GetUserProfileDirectory(token, userDirectory, &dwBufferSize);
if (ok)
ret = QString::fromWCharArray(userDirectory);
delete [] userDirectory;
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index b09223d656..2f25721bee 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -120,9 +120,14 @@ public:
// Attributes
HiddenAttribute = 0x00100000,
SizeAttribute = 0x00200000, // Note: overlaps with QAbstractFileEngine::LocalDiskFlag
- ExistsAttribute = 0x00400000,
+ ExistsAttribute = 0x00400000, // For historical reasons, indicates existence of data, not the file
+#if defined(Q_OS_WIN)
+ WasDeletedAttribute = 0x0,
+#else
+ WasDeletedAttribute = 0x40000000, // Indicates the file was deleted
+#endif
- Attributes = HiddenAttribute | SizeAttribute | ExistsAttribute,
+ Attributes = HiddenAttribute | SizeAttribute | ExistsAttribute | WasDeletedAttribute,
// Times
CreationTime = 0x01000000, // Note: overlaps with QAbstractFileEngine::Refresh
@@ -144,6 +149,7 @@ public:
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::SequentialType
| QFileSystemMetaData::SizeAttribute
+ | QFileSystemMetaData::WasDeletedAttribute
| QFileSystemMetaData::Times
| QFileSystemMetaData::OwnerIds,
@@ -191,6 +197,7 @@ public:
bool isLegacyLink() const { return (entryFlags & LegacyLinkType); }
bool isSequential() const { return (entryFlags & SequentialType); }
bool isHidden() const { return (entryFlags & HiddenAttribute); }
+ bool wasDeleted() const { return (entryFlags & WasDeletedAttribute); }
#if defined(Q_OS_WIN)
bool isLnkFile() const { return (entryFlags & WinLnkType); }
#else
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 88e8baedca..037deb8942 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -195,6 +195,9 @@ void QFSFileEngine::setFileName(const QString &file)
*/
bool QFSFileEngine::open(QIODevice::OpenMode openMode)
{
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
+
Q_D(QFSFileEngine);
if (d->fileEntry.isEmpty()) {
qWarning("QFSFileEngine::open: No file name specified");
@@ -230,6 +233,9 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh)
bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHandleFlags handleFlags)
{
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
+
Q_D(QFSFileEngine);
// Append implies WriteOnly.
@@ -255,6 +261,9 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHand
*/
bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
{
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
+
Q_Q(QFSFileEngine);
this->fh = fh;
fd = -1;
@@ -516,6 +525,25 @@ bool QFSFileEngine::seek(qint64 pos)
}
/*!
+ \reimp
+*/
+QDateTime QFSFileEngine::fileTime(FileTime time) const
+{
+ Q_D(const QFSFileEngine);
+
+ if (time == AccessTime) {
+ // always refresh for the access time
+ d->metaData.clearFlags(QFileSystemMetaData::AccessTime);
+ }
+
+ if (d->doStat(QFileSystemMetaData::Times))
+ return d->metaData.fileTime(time);
+
+ return QDateTime();
+}
+
+
+/*!
\internal
*/
bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
@@ -699,6 +727,7 @@ qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
qint64 QFSFileEngine::write(const char *data, qint64 len)
{
Q_D(QFSFileEngine);
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
// On Windows' stdlib implementation, the results of calling fread and
// fwrite are undefined if not called either in sequence, or if preceded
@@ -860,9 +889,9 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
/*! \fn bool QFSFileEngine::copy(const QString &copyName)
- For windows, copy the file to file \a copyName.
+ For Windows or Apple platforms, copy the file to file \a copyName.
- Not implemented for Unix.
+ Not implemented for other Unix platforms.
*/
/*! \fn QString QFSFileEngine::currentPath(const QString &fileName)
@@ -890,6 +919,10 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
+/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+ \reimp
+*/
+
/*! \fn QDateTime QFSFileEngine::fileTime(FileTime time) const
\reimp
*/
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index ab9ad3aa6b..f352fcd475 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -97,6 +97,7 @@ public:
QString fileName(FileName file) const Q_DECL_OVERRIDE;
uint ownerId(FileOwner) const Q_DECL_OVERRIDE;
QString owner(FileOwner) const Q_DECL_OVERRIDE;
+ bool setFileTime(const QDateTime &newDate, FileTime time) Q_DECL_OVERRIDE;
QDateTime fileTime(FileTime time) const Q_DECL_OVERRIDE;
void setFileName(const QString &file) Q_DECL_OVERRIDE;
int handle() const Q_DECL_OVERRIDE;
@@ -109,6 +110,7 @@ public:
qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
qint64 readLine(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE;
+ bool clone(int sourceHandle) override;
bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) Q_DECL_OVERRIDE;
bool supportsExtension(Extension extension) const Q_DECL_OVERRIDE;
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index c613368a91..ab762d2b4d 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -65,46 +65,6 @@ QT_BEGIN_NAMESPACE
/*!
\internal
- Returns the stdlib open string corresponding to a QIODevice::OpenMode.
-*/
-static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry,
- QFileSystemMetaData &metaData)
-{
- QByteArray mode;
- if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) {
- mode = "rb";
- if (flags & QIODevice::WriteOnly) {
- metaData.clearFlags(QFileSystemMetaData::FileType);
- if (!fileEntry.isEmpty()
- && QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::FileType)
- && metaData.isFile()) {
- mode += '+';
- } else {
- mode = "wb+";
- }
- }
- } else if (flags & QIODevice::WriteOnly) {
- mode = "wb";
- if (flags & QIODevice::ReadOnly)
- mode += '+';
- }
- if (flags & QIODevice::Append) {
- mode = "ab";
- if (flags & QIODevice::ReadOnly)
- mode += '+';
- }
-
-#if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0207
- // must be glibc >= 2.7
- mode += 'e';
-#endif
-
- return mode;
-}
-
-/*!
- \internal
-
Returns the stdio open flags corresponding to a QIODevice::OpenMode.
*/
static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
@@ -130,17 +90,6 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
return oflags;
}
-/*!
- \internal
-
- Sets the file descriptor to close on exec. That is, the file
- descriptor is not inherited by child processes.
-*/
-static inline bool setCloseOnExec(int fd)
-{
- return fd != -1 && fcntl(fd, F_SETFD, FD_CLOEXEC) != -1;
-}
-
static inline QString msgOpenDirectory()
{
const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory");
@@ -151,6 +100,44 @@ static inline QString msgOpenDirectory()
#endif
}
+#if !QT_CONFIG(futimens) && (QT_CONFIG(futimes) || QT_CONFIG(futimesat))
+namespace {
+namespace GetFileTimes {
+
+template <typename T>
+static inline typename QtPrivate::QEnableIf<(&T::st_atim, &T::st_mtim, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification)
+{
+ access->tv_sec = p->st_atim.tv_sec;
+ access->tv_usec = p->st_atim.tv_nsec / 1000;
+
+ modification->tv_sec = p->st_mtim.tv_sec;
+ modification->tv_usec = p->st_mtim.tv_nsec / 1000;
+}
+
+template <typename T>
+static inline typename QtPrivate::QEnableIf<(&T::st_atimespec, &T::st_mtimespec, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification)
+{
+ access->tv_sec = p->st_atimespec.tv_sec;
+ access->tv_usec = p->st_atimespec.tv_nsec / 1000;
+
+ modification->tv_sec = p->st_mtimespec.tv_sec;
+ modification->tv_usec = p->st_mtimespec.tv_nsec / 1000;
+}
+
+template <typename T>
+static inline typename QtPrivate::QEnableIf<(&T::st_atimensec, &T::st_mtimensec, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification)
+{
+ access->tv_sec = p->st_atime;
+ access->tv_usec = p->st_atimensec / 1000;
+
+ modification->tv_sec = p->st_mtime;
+ modification->tv_usec = p->st_mtimensec / 1000;
+}
+
+}
+}
+#endif
+
/*!
\internal
*/
@@ -158,6 +145,8 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
{
Q_Q(QFSFileEngine);
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
if (openMode & QIODevice::Unbuffered) {
int flags = openModeToOpenFlags(openMode);
@@ -199,49 +188,6 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
}
fh = 0;
- } else {
- QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData);
-
- // Try to open the file in buffered mode.
- do {
- fh = QT_FOPEN(fileEntry.nativeFilePath().constData(), fopenMode.constData());
- } while (!fh && errno == EINTR);
-
- // On failure, return and report the error.
- if (!fh) {
- q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(int(errno)));
- return false;
- }
-
- if (!(openMode & QIODevice::WriteOnly)) {
- // we don't need this check if we tried to open for writing because then
- // we had received EISDIR anyway.
- if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData)
- && metaData.isDirectory()) {
- q->setError(QFile::OpenError, msgOpenDirectory());
- fclose(fh);
- return false;
- }
- }
-
- setCloseOnExec(fileno(fh)); // ignore failure
-
- // Seek to the end when in Append mode.
- if (openMode & QIODevice::Append) {
- int ret;
- do {
- ret = QT_FSEEK(fh, 0, SEEK_END);
- } while (ret == -1 && errno == EINTR);
-
- if (ret == -1) {
- q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(int(errno)));
- return false;
- }
- }
-
- fd = -1;
}
closeFileHandle = true;
@@ -549,11 +495,14 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
| QFileSystemMetaData::LinkType
| QFileSystemMetaData::FileType
| QFileSystemMetaData::DirectoryType
- | QFileSystemMetaData::BundleType;
+ | QFileSystemMetaData::BundleType
+ | QFileSystemMetaData::WasDeletedAttribute;
if (type & FlagsMask)
queryFlags |= QFileSystemMetaData::HiddenAttribute
| QFileSystemMetaData::ExistsAttribute;
+ else if (type & ExistsFlag)
+ queryFlags |= QFileSystemMetaData::WasDeletedAttribute;
queryFlags |= QFileSystemMetaData::LinkType;
@@ -585,7 +534,8 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const
}
if (type & FlagsMask) {
- if (exists)
+ // the inode existing does not mean the file exists
+ if (!d->metaData.wasDeleted())
ret |= ExistsFlag;
if (d->fileEntry.isRoot())
ret |= RootFlag;
@@ -689,14 +639,81 @@ bool QFSFileEngine::setSize(qint64 size)
return ret;
}
-QDateTime QFSFileEngine::fileTime(FileTime time) const
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
{
- Q_D(const QFSFileEngine);
+ Q_D(QFSFileEngine);
+
+ if (d->openMode == QIODevice::NotOpen) {
+ setError(QFile::PermissionsError, qt_error_string(EACCES));
+ return false;
+ }
+
+ if (!newDate.isValid() || time == QAbstractFileEngine::CreationTime) {
+ setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
+ return false;
+ }
+
+#if QT_CONFIG(futimens)
+ struct timespec ts[2];
+
+ ts[0].tv_sec = ts[1].tv_sec = 0;
+ ts[0].tv_nsec = ts[1].tv_nsec = UTIME_OMIT;
+
+ const qint64 msecs = newDate.toMSecsSinceEpoch();
+
+ if (time == QAbstractFileEngine::AccessTime) {
+ ts[0].tv_sec = msecs / 1000;
+ ts[0].tv_nsec = (msecs % 1000) * 1000000;
+ } else if (time == QAbstractFileEngine::ModificationTime) {
+ ts[1].tv_sec = msecs / 1000;
+ ts[1].tv_nsec = (msecs % 1000) * 1000000;
+ }
+
+ if (futimens(d->nativeHandle(), ts) == -1) {
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
- if (d->doStat(QFileSystemMetaData::Times))
- return d->metaData.fileTime(time);
+ return true;
+#elif QT_CONFIG(futimes) || QT_CONFIG(futimesat)
+ struct timeval tv[2];
+ QT_STATBUF st;
+
+ if (QT_FSTAT(d->nativeHandle(), &st) == -1) {
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ GetFileTimes::get(&st, &tv[0], &tv[1]);
+
+ const qint64 msecs = newDate.toMSecsSinceEpoch();
+
+ if (time == QAbstractFileEngine::AccessTime) {
+ tv[0].tv_sec = msecs / 1000;
+ tv[0].tv_usec = (msecs % 1000) * 1000;
+ } else if (time == QAbstractFileEngine::ModificationTime) {
+ tv[1].tv_sec = msecs / 1000;
+ tv[1].tv_usec = (msecs % 1000) * 1000;
+ }
+
+#if QT_CONFIG(futimes)
+ if (futimes(d->nativeHandle(), tv) == -1) {
+#else
+ if (futimesat(d->nativeHandle(), NULL, tv) == -1) {
+#endif
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
- return QDateTime();
+ return true;
+#else
+ setError(QFile::UnspecifiedError, qt_error_string(ENOSYS));
+ return false;
+#endif
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
@@ -715,7 +732,6 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
#endif
Q_Q(QFSFileEngine);
- Q_UNUSED(flags);
if (openMode == QIODevice::NotOpen) {
q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
return 0;
@@ -806,6 +822,23 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
#endif
}
+/*!
+ \reimp
+*/
+bool QFSFileEngine::clone(int sourceHandle)
+{
+#if defined(Q_OS_LINUX)
+ Q_D(QFSFileEngine);
+# if !defined FICLONE
+# define FICLONE _IOW (0x94, 9, int)
+# endif
+ return ::ioctl(d->fd, FICLONE, sourceHandle) == 0;
+#else
+ Q_UNUSED(sourceHandle);
+ return false;
+#endif
+}
+
QT_END_NAMESPACE
#endif // QT_NO_FSFILEENGINE
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index c99a25f30d..0decd26179 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -80,6 +80,39 @@ static inline bool isUncPath(const QString &path)
&& path.size() > 2 && path.at(2) != QLatin1Char('.'));
}
+static inline void QDateTimeToSystemTime(const QDateTime &date, SYSTEMTIME *systemTime)
+{
+ const QDate d = date.date();
+ const QTime t = date.time();
+
+ systemTime->wYear = d.year();
+ systemTime->wMonth = d.month();
+ systemTime->wDay = d.day();
+ systemTime->wHour = t.hour();
+ systemTime->wMinute = t.minute();
+ systemTime->wSecond = t.second();
+ systemTime->wMilliseconds = t.msec();
+ systemTime->wDayOfWeek = d.dayOfWeek() % 7;
+}
+
+static inline bool QDateTimeToFileTime(const QDateTime &date, FILETIME *fileTime)
+{
+ SYSTEMTIME sTime;
+
+#if defined(Q_OS_WINCE)
+ QDateTimeToSystemTime(date, &sTime);
+#else
+ SYSTEMTIME lTime;
+
+ QDateTimeToSystemTime(date, &lTime);
+
+ if (!::TzSpecificLocalTimeToSystemTime(0, &lTime, &sTime))
+ return false;
+#endif
+
+ return ::SystemTimeToFileTime(&sTime, fileTime);
+}
+
/*!
\internal
*/
@@ -694,6 +727,8 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil
}
if (type & FlagsMask) {
if (d->metaData.exists()) {
+ // if we succeeded in querying, then the file exists: a file on
+ // Windows cannot be deleted if we have an open handle to it
ret |= ExistsFlag;
if (d->fileEntry.isRoot())
ret |= RootFlag;
@@ -854,15 +889,68 @@ bool QFSFileEngine::setSize(qint64 size)
return false;
}
-
-QDateTime QFSFileEngine::fileTime(FileTime time) const
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
{
- Q_D(const QFSFileEngine);
+ Q_D(QFSFileEngine);
- if (d->doStat(QFileSystemMetaData::Times))
- return d->metaData.fileTime(time);
+ if (d->openMode == QFile::NotOpen) {
+ setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return false;
+ }
- return QDateTime();
+ if (!newDate.isValid()) {
+ setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
+ return false;
+ }
+
+ HANDLE handle = d->fileHandle;
+
+#ifndef Q_OS_WINCE
+ if (handle == INVALID_HANDLE_VALUE) {
+ if (d->fh)
+ handle = reinterpret_cast<HANDLE>(::_get_osfhandle(QT_FILENO(d->fh)));
+ else if (d->fd != -1)
+ handle = reinterpret_cast<HANDLE>(::_get_osfhandle(d->fd));
+ }
+#endif
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return false;
+ }
+
+ FILETIME fTime;
+ FILETIME *pLastWrite = NULL;
+ FILETIME *pLastAccess = NULL;
+ FILETIME *pCreationTime = NULL;
+
+ switch (time) {
+ case QAbstractFileEngine::ModificationTime:
+ pLastWrite = &fTime;
+ break;
+
+ case QAbstractFileEngine::AccessTime:
+ pLastAccess = &fTime;
+ break;
+
+ case QAbstractFileEngine::CreationTime:
+ pCreationTime = &fTime;
+ break;
+ }
+
+ if (!QDateTimeToFileTime(newDate, &fTime)) {
+ setError(QFile::UnspecifiedError, qt_error_string());
+ return false;
+ }
+
+ if (!::SetFileTime(handle, pCreationTime, pLastAccess, pLastWrite)) {
+ setError(QFile::PermissionsError, qt_error_string());
+ return false;
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
+
+ return true;
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
@@ -1002,4 +1090,13 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
return true;
}
+/*!
+ \reimp
+*/
+bool QFSFileEngine::clone(int sourceHandle)
+{
+ Q_UNUSED(sourceHandle);
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index ccc607afd5..1ee8ce889c 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -199,7 +199,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
}
if (qt_write_loop(fd, fileData.constData(), fileData.size()) < fileData.size()) {
- close(fd);
+ qt_safe_close(fd);
if (!QFile::remove(fileName))
qWarning("QLockFile: Could not remove our own lock file %s.", qPrintable(fileName));
return QLockFile::UnknownError; // partition full
@@ -258,17 +258,17 @@ QString QLockFilePrivate::processNameByPid(qint64 pid)
proc_name(pid, name, sizeof(name) / sizeof(char));
return QFile::decodeName(name);
#elif defined(Q_OS_LINUX)
- if (!QFile::exists(QStringLiteral("/proc/version")))
+ if (!qt_haveLinuxProcfs())
return QString();
+
char exePath[64];
- char buf[PATH_MAX + 1];
sprintf(exePath, "/proc/%lld/exe", pid);
- size_t len = (size_t)readlink(exePath, buf, sizeof(buf));
- if (len >= sizeof(buf)) {
+
+ QByteArray buf = qt_readlink(exePath);
+ if (buf.isEmpty()) {
// The pid is gone. Return some invalid process name to fail the test.
return QStringLiteral("/ERROR/");
}
- buf[len] = 0;
return QFileInfo(QFile::decodeName(buf)).fileName();
#elif defined(Q_OS_HAIKU)
thread_info info;
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 2226b4435b..bb16b0c427 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -450,11 +450,6 @@ void QProcessPrivate::Channel::clear()
process = 0;
}
-/*! \fn bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
-
-\internal
- */
-
/*!
\class QProcess
\inmodule QtCore
@@ -2112,6 +2107,60 @@ void QProcess::start(OpenMode mode)
}
/*!
+ \since 5.10
+
+ Starts the program set by setProgram() with arguments set by setArguments()
+ in a new process, and detaches from it. Returns \c true on success;
+ otherwise returns \c false. If the calling process exits, the
+ detached process will continue to run unaffected.
+
+ \b{Unix:} The started process will run in its own session and act
+ like a daemon.
+
+ The process will be started in the directory set by setWorkingDirectory().
+ If workingDirectory() is empty, the working directory is inherited
+ from the calling process.
+
+ \note On QNX, this may cause all application threads to
+ temporarily freeze.
+
+ If the function is successful then *\a pid is set to the process
+ identifier of the started process.
+
+ Only the following property setters are supported by startDetached():
+ \list
+ \li setArguments()
+ \li setCreateProcessArgumentsModifier()
+ \li setNativeArguments()
+ \li setProcessEnvironment()
+ \li setProgram()
+ \li setStandardErrorFile()
+ \li setStandardInputFile()
+ \li setStandardOutputFile()
+ \li setWorkingDirectory()
+ \endlist
+ All other properties of the QProcess object are ignored.
+
+ \sa start()
+ \sa startDetached(const QString &program, const QStringList &arguments,
+ const QString &workingDirectory, qint64 *pid)
+ \sa startDetached(const QString &command)
+*/
+bool QProcess::startDetached(qint64 *pid)
+{
+ Q_D(QProcess);
+ if (d->processState != NotRunning) {
+ qWarning("QProcess::startDetached: Process is already running");
+ return false;
+ }
+ if (d->program.isEmpty()) {
+ d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
+ return false;
+ }
+ return d->startDetached(pid);
+}
+
+/*!
Starts the program set by setProgram() with arguments set by setArguments().
The OpenMode is set to \a mode.
@@ -2445,6 +2494,8 @@ int QProcess::execute(const QString &command)
}
/*!
+ \overload startDetached()
+
Starts the program \a program with the arguments \a arguments in a
new process, and detaches from it. Returns \c true on success;
otherwise returns \c false. If the calling process exits, the
@@ -2452,16 +2503,10 @@ int QProcess::execute(const QString &command)
Argument handling is identical to the respective start() overload.
- \b{Unix:} The started process will run in its own session and act
- like a daemon.
-
The process will be started in the directory \a workingDirectory.
If \a workingDirectory is empty, the working directory is inherited
from the calling process.
- \note On QNX, this may cause all application threads to
- temporarily freeze.
-
If the function is successful then *\a pid is set to the process
identifier of the started process.
@@ -2472,10 +2517,11 @@ bool QProcess::startDetached(const QString &program,
const QString &workingDirectory,
qint64 *pid)
{
- return QProcessPrivate::startDetached(program,
- arguments,
- workingDirectory,
- pid);
+ QProcess process;
+ process.setProgram(program);
+ process.setArguments(arguments);
+ process.setWorkingDirectory(workingDirectory);
+ return process.startDetached(pid);
}
/*!
@@ -2484,11 +2530,14 @@ bool QProcess::startDetached(const QString &program,
bool QProcess::startDetached(const QString &program,
const QStringList &arguments)
{
- return QProcessPrivate::startDetached(program, arguments);
+ QProcess process;
+ process.setProgram(program);
+ process.setArguments(arguments);
+ return process.startDetached();
}
/*!
- \overload
+ \overload startDetached()
Starts the command \a command in a new process, and detaches from it.
Returns \c true on success; otherwise returns \c false.
@@ -2506,9 +2555,10 @@ bool QProcess::startDetached(const QString &command)
if (args.isEmpty())
return false;
- const QString prog = args.takeFirst();
-
- return QProcessPrivate::startDetached(prog, args);
+ QProcess process;
+ process.setProgram(args.takeFirst());
+ process.setArguments(args);
+ return process.startDetached();
}
QT_BEGIN_INCLUDE_NAMESPACE
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 19157bdd02..c8aef2f0b1 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -163,6 +163,7 @@ public:
void start(const QString &command, OpenMode mode = ReadWrite);
#endif
void start(OpenMode mode = ReadWrite);
+ bool startDetached(qint64 *pid = nullptr);
bool open(OpenMode mode = ReadWrite) Q_DECL_OVERRIDE;
QString program() const;
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index c5abf7b762..deb29dca0a 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -350,7 +350,7 @@ public:
void start(QIODevice::OpenMode mode);
void startProcess();
#if defined(Q_OS_UNIX)
- void execChild(const char *workingDirectory, char **path, char **argv, char **envp);
+ void execChild(const char *workingDirectory, char **argv, char **envp);
#endif
bool processStarted(QString *errorMessage = Q_NULLPTR);
void terminateProcess();
@@ -360,13 +360,13 @@ public:
bool waitForDeadChild();
#endif
#ifdef Q_OS_WIN
+ bool callCreateProcess(QProcess::CreateProcessArguments *cpargs);
bool drainOutputPipes();
void flushPipeWriter();
qint64 pipeWriterBytesToWrite() const;
#endif
- static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(),
- qint64 *pid = 0);
+ bool startDetached(qint64 *pPid);
int exitCode;
QProcess::ExitStatus exitStatus;
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 6b7f187fee..cf9d38097a 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -87,6 +87,7 @@ QT_END_NAMESPACE
#include "qprocess.h"
#include "qprocess_p.h"
+#include "qstandardpaths.h"
#include "private/qcore_unix_p.h"
#ifdef Q_OS_MAC
@@ -420,8 +421,16 @@ void QProcessPrivate::startProcess()
#endif
// Add the program name to the argument list.
- char *dupProgramName = ::strdup(encodedProgramName.constData());
- argv[0] = dupProgramName;
+ argv[0] = nullptr;
+ if (!program.contains(QLatin1Char('/'))) {
+ const QString &exeFilePath = QStandardPaths::findExecutable(program);
+ if (!exeFilePath.isEmpty()) {
+ const QByteArray &tmp = QFile::encodeName(exeFilePath);
+ argv[0] = ::strdup(tmp.constData());
+ }
+ }
+ if (!argv[0])
+ argv[0] = ::strdup(encodedProgramName.constData());
// Add every argument to the list
for (int i = 0; i < arguments.count(); ++i)
@@ -443,29 +452,6 @@ void QProcessPrivate::startProcess()
workingDirPtr = encodedWorkingDirectory.constData();
}
- // If the program does not specify a path, generate a list of possible
- // locations for the binary using the PATH environment variable.
- char **path = 0;
- int pathc = 0;
- if (!program.contains(QLatin1Char('/'))) {
- const QString pathEnv = QString::fromLocal8Bit(qgetenv("PATH"));
- if (!pathEnv.isEmpty()) {
- QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
- if (!pathEntries.isEmpty()) {
- pathc = pathEntries.size();
- path = new char *[pathc + 1];
- path[pathc] = 0;
-
- for (int k = 0; k < pathEntries.size(); ++k) {
- QByteArray tmp = QFile::encodeName(pathEntries.at(k));
- if (!tmp.endsWith('/')) tmp += '/';
- tmp += encodedProgramName;
- path[k] = ::strdup(tmp.constData());
- }
- }
- }
- }
-
// Start the process manager, and fork off the child process.
pid_t childPid;
forkfd = ::forkfd(FFD_CLOEXEC, &childPid);
@@ -473,16 +459,12 @@ void QProcessPrivate::startProcess()
if (forkfd != FFD_CHILD_PROCESS) {
// Parent process.
// Clean up duplicated memory.
- free(dupProgramName);
- for (int i = 1; i <= arguments.count(); ++i)
+ for (int i = 0; i <= arguments.count(); ++i)
free(argv[i]);
for (int i = 0; i < envc; ++i)
free(envp[i]);
- for (int i = 0; i < pathc; ++i)
- free(path[i]);
delete [] argv;
delete [] envp;
- delete [] path;
}
// On QNX, if spawnChild failed, childPid will be -1 but forkfd is still 0.
@@ -503,7 +485,7 @@ void QProcessPrivate::startProcess()
// Start the child.
if (forkfd == FFD_CHILD_PROCESS) {
- execChild(workingDirPtr, path, argv, envp);
+ execChild(workingDirPtr, argv, envp);
::_exit(-1);
}
@@ -550,7 +532,7 @@ struct ChildError
char function[8];
};
-void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp)
+void QProcessPrivate::execChild(const char *workingDir, char **argv, char **envp)
{
::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
@@ -574,7 +556,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
}
}
- // make sure this fd is closed if execvp() succeeds
+ // make sure this fd is closed if execv() succeeds
qt_safe_close(childStartedPipe[0]);
// enter the working directory
@@ -589,25 +571,13 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
// execute the process
if (!envp) {
- qt_safe_execvp(argv[0], argv);
+ qt_safe_execv(argv[0], argv);
strcpy(error.function, "execvp");
} else {
- if (path) {
- char **arg = path;
- while (*arg) {
- argv[0] = *arg;
#if defined (QPROCESS_DEBUG)
- fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);
+ fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
#endif
- qt_safe_execve(argv[0], argv, envp);
- ++arg;
- }
- } else {
-#if defined (QPROCESS_DEBUG)
- fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
-#endif
- qt_safe_execve(argv[0], argv, envp);
- }
+ qt_safe_execve(argv[0], argv, envp);
strcpy(error.function, "execve");
}
@@ -921,7 +891,7 @@ bool QProcessPrivate::waitForDeadChild()
return true;
}
-bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
+bool QProcessPrivate::startDetached(qint64 *pid)
{
QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory);
@@ -937,6 +907,17 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
return false;
}
+ if ((stdinChannel.type == Channel::Redirect && !openChannel(stdinChannel))
+ || (stdoutChannel.type == Channel::Redirect && !openChannel(stdoutChannel))
+ || (stderrChannel.type == Channel::Redirect && !openChannel(stderrChannel))) {
+ closeChannel(&stdinChannel);
+ closeChannel(&stdoutChannel);
+ closeChannel(&stderrChannel);
+ qt_safe_close(startedPipe[0]);
+ qt_safe_close(startedPipe[1]);
+ return false;
+ }
+
pid_t childPid = fork();
if (childPid == 0) {
struct sigaction noaction;
@@ -953,6 +934,18 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
if (doubleForkPid == 0) {
qt_safe_close(pidPipe[1]);
+ // copy the stdin socket if asked to (without closing on exec)
+ if (inputChannelMode != QProcess::ForwardedInputChannel)
+ qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
+
+ // copy the stdout and stderr if asked to
+ if (processChannelMode != QProcess::ForwardedChannels) {
+ if (processChannelMode != QProcess::ForwardedOutputChannel)
+ qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0);
+ if (processChannelMode != QProcess::ForwardedErrorChannel)
+ qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0);
+ }
+
if (!encodedWorkingDirectory.isEmpty()) {
if (QT_CHDIR(encodedWorkingDirectory.constData()) == -1)
qWarning("QProcessPrivate::startDetached: failed to chdir to %s", encodedWorkingDirectory.constData());
@@ -963,23 +956,28 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
argv[arguments.size() + 1] = 0;
+ // Duplicate the environment.
+ int envc = 0;
+ char **envp = nullptr;
+ if (environment.d.constData()) {
+ QProcessEnvironmentPrivate::MutexLocker locker(environment.d);
+ envp = _q_dupEnvironment(environment.d.constData()->vars, &envc);
+ }
+
+ QByteArray tmp;
if (!program.contains(QLatin1Char('/'))) {
- const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
- if (!path.isEmpty()) {
- QStringList pathEntries = path.split(QLatin1Char(':'));
- for (int k = 0; k < pathEntries.size(); ++k) {
- QByteArray tmp = QFile::encodeName(pathEntries.at(k));
- if (!tmp.endsWith('/')) tmp += '/';
- tmp += QFile::encodeName(program);
- argv[0] = tmp.data();
- qt_safe_execv(argv[0], argv);
- }
- }
- } else {
- QByteArray tmp = QFile::encodeName(program);
- argv[0] = tmp.data();
- qt_safe_execv(argv[0], argv);
+ const QString &exeFilePath = QStandardPaths::findExecutable(program);
+ if (!exeFilePath.isEmpty())
+ tmp = QFile::encodeName(exeFilePath);
}
+ if (tmp.isEmpty())
+ tmp = QFile::encodeName(program);
+ argv[0] = tmp.data();
+
+ if (envp)
+ qt_safe_execve(argv[0], argv, envp);
+ else
+ qt_safe_execv(argv[0], argv);
struct sigaction noaction;
memset(&noaction, 0, sizeof(noaction));
@@ -1009,6 +1007,9 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
::_exit(1);
}
+ closeChannel(&stdinChannel);
+ closeChannel(&stdoutChannel);
+ closeChannel(&stderrChannel);
qt_safe_close(startedPipe[1]);
qt_safe_close(pidPipe[1]);
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 05c9d6594c..2bbc4eddd0 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -358,7 +358,8 @@ void QProcessPrivate::closeChannel(Channel *channel)
destroyPipe(channel->pipe);
}
-static QString qt_create_commandline(const QString &program, const QStringList &arguments)
+static QString qt_create_commandline(const QString &program, const QStringList &arguments,
+ const QString &nativeArguments)
{
QString args;
if (!program.isEmpty()) {
@@ -387,6 +388,13 @@ static QString qt_create_commandline(const QString &program, const QStringList &
}
args += QLatin1Char(' ') + tmp;
}
+
+ if (!nativeArguments.isEmpty()) {
+ if (!args.isEmpty())
+ args += QLatin1Char(' ');
+ args += nativeArguments;
+ }
+
return args;
}
@@ -450,6 +458,30 @@ static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &e
return envlist;
}
+bool QProcessPrivate::callCreateProcess(QProcess::CreateProcessArguments *cpargs)
+{
+ if (modifyCreateProcessArgs)
+ modifyCreateProcessArgs(cpargs);
+ bool success = CreateProcess(cpargs->applicationName, cpargs->arguments,
+ cpargs->processAttributes, cpargs->threadAttributes,
+ cpargs->inheritHandles, cpargs->flags, cpargs->environment,
+ cpargs->currentDirectory, cpargs->startupInfo,
+ cpargs->processInformation);
+ if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
+ CloseHandle(stdinChannel.pipe[0]);
+ stdinChannel.pipe[0] = INVALID_Q_PIPE;
+ }
+ if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) {
+ CloseHandle(stdoutChannel.pipe[1]);
+ stdoutChannel.pipe[1] = INVALID_Q_PIPE;
+ }
+ if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
+ CloseHandle(stderrChannel.pipe[1]);
+ stderrChannel.pipe[1] = INVALID_Q_PIPE;
+ }
+ return success;
+}
+
void QProcessPrivate::startProcess()
{
Q_Q(QProcess);
@@ -472,15 +504,10 @@ void QProcessPrivate::startProcess()
!openChannel(stderrChannel))
return;
- QString args = qt_create_commandline(program, arguments);
+ const QString args = qt_create_commandline(program, arguments, nativeArguments);
QByteArray envlist;
if (environment.d.constData())
envlist = qt_create_environment(environment.d.constData()->vars);
- if (!nativeArguments.isEmpty()) {
- if (!args.isEmpty())
- args += QLatin1Char(' ');
- args += nativeArguments;
- }
#if defined QPROCESS_DEBUG
qDebug("Creating process");
@@ -507,18 +534,14 @@ void QProcessPrivate::startProcess()
const QString nativeWorkingDirectory = QDir::toNativeSeparators(workingDirectory);
QProcess::CreateProcessArguments cpargs = {
- 0, (wchar_t*)args.utf16(),
- 0, 0, TRUE, dwCreationFlags,
- environment.isEmpty() ? 0 : envlist.data(),
- nativeWorkingDirectory.isEmpty() ? Q_NULLPTR : (wchar_t*)nativeWorkingDirectory.utf16(),
+ nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
+ nullptr, nullptr, true, dwCreationFlags,
+ environment.isEmpty() ? nullptr : envlist.data(),
+ nativeWorkingDirectory.isEmpty()
+ ? nullptr : reinterpret_cast<const wchar_t *>(nativeWorkingDirectory.utf16()),
&startupInfo, pid
};
- if (modifyCreateProcessArgs)
- modifyCreateProcessArgs(&cpargs);
- success = CreateProcess(cpargs.applicationName, cpargs.arguments, cpargs.processAttributes,
- cpargs.threadAttributes, cpargs.inheritHandles, cpargs.flags,
- cpargs.environment, cpargs.currentDirectory, cpargs.startupInfo,
- cpargs.processInformation);
+ success = callCreateProcess(&cpargs);
QString errorString;
if (!success) {
@@ -526,19 +549,6 @@ void QProcessPrivate::startProcess()
errorString = QProcess::tr("Process failed to start: %1").arg(qt_error_string());
}
- if (stdinChannel.pipe[0] != INVALID_Q_PIPE) {
- CloseHandle(stdinChannel.pipe[0]);
- stdinChannel.pipe[0] = INVALID_Q_PIPE;
- }
- if (stdoutChannel.pipe[1] != INVALID_Q_PIPE) {
- CloseHandle(stdoutChannel.pipe[1]);
- stdoutChannel.pipe[1] = INVALID_Q_PIPE;
- }
- if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
- CloseHandle(stderrChannel.pipe[1]);
- stderrChannel.pipe[1] = INVALID_Q_PIPE;
- }
-
if (!success) {
cleanup();
setErrorAndEmit(QProcess::FailedToStart, errorString);
@@ -826,6 +836,7 @@ bool QProcessPrivate::writeToStdin()
// Use ShellExecuteEx() to trigger an UAC prompt when CreateProcess()fails
// with ERROR_ELEVATION_REQUIRED.
static bool startDetachedUacPrompt(const QString &programIn, const QStringList &arguments,
+ const QString &nativeArguments,
const QString &workingDir, qint64 *pid)
{
typedef BOOL (WINAPI *ShellExecuteExType)(SHELLEXECUTEINFOW *);
@@ -836,7 +847,8 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList &
if (!shellExecuteEx)
return false;
- const QString args = qt_create_commandline(QString(), arguments); // needs arguments only
+ const QString args = qt_create_commandline(QString(), // needs arguments only
+ arguments, nativeArguments);
SHELLEXECUTEINFOW shellExecuteExInfo;
memset(&shellExecuteExInfo, 0, sizeof(SHELLEXECUTEINFOW));
shellExecuteExInfo.cbSize = sizeof(SHELLEXECUTEINFOW);
@@ -859,25 +871,52 @@ static bool startDetachedUacPrompt(const QString &programIn, const QStringList &
return true;
}
-bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDir, qint64 *pid)
+bool QProcessPrivate::startDetached(qint64 *pid)
{
static const DWORD errorElevationRequired = 740;
- QString args = qt_create_commandline(program, arguments);
+ if ((stdinChannel.type == Channel::Redirect && !openChannel(stdinChannel))
+ || (stdoutChannel.type == Channel::Redirect && !openChannel(stdoutChannel))
+ || (stderrChannel.type == Channel::Redirect && !openChannel(stderrChannel))) {
+ closeChannel(&stdinChannel);
+ closeChannel(&stdoutChannel);
+ closeChannel(&stderrChannel);
+ return false;
+ }
+
+ QString args = qt_create_commandline(program, arguments, nativeArguments);
bool success = false;
PROCESS_INFORMATION pinfo;
+ void *envPtr = nullptr;
+ QByteArray envlist;
+ if (environment.d.constData()) {
+ envlist = qt_create_environment(environment.d.constData()->vars);
+ envPtr = envlist.data();
+ }
+
DWORD dwCreationFlags = (GetConsoleWindow() ? 0 : CREATE_NO_WINDOW);
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
STARTUPINFOW startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
(ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0,
+ STARTF_USESTDHANDLES,
+ 0, 0, 0,
+ stdinChannel.pipe[0], stdoutChannel.pipe[1], stderrChannel.pipe[1]
};
- success = CreateProcess(0, (wchar_t*)args.utf16(),
- 0, 0, FALSE, dwCreationFlags, 0,
- workingDir.isEmpty() ? 0 : (wchar_t*)workingDir.utf16(),
- &startupInfo, &pinfo);
+
+ const bool inheritHandles = stdinChannel.type == Channel::Redirect
+ || stdoutChannel.type == Channel::Redirect
+ || stderrChannel.type == Channel::Redirect;
+ QProcess::CreateProcessArguments cpargs = {
+ nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())),
+ nullptr, nullptr, inheritHandles, dwCreationFlags, envPtr,
+ workingDirectory.isEmpty()
+ ? nullptr : reinterpret_cast<const wchar_t *>(workingDirectory.utf16()),
+ &startupInfo, &pinfo
+ };
+ success = callCreateProcess(&cpargs);
if (success) {
CloseHandle(pinfo.hThread);
@@ -885,9 +924,19 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
if (pid)
*pid = pinfo.dwProcessId;
} else if (GetLastError() == errorElevationRequired) {
- success = startDetachedUacPrompt(program, arguments, workingDir, pid);
+ if (envPtr)
+ qWarning("QProcess: custom environment will be ignored for detached elevated process.");
+ if (!stdinChannel.file.isEmpty() || !stdoutChannel.file.isEmpty()
+ || !stderrChannel.file.isEmpty()) {
+ qWarning("QProcess: file redirection is unsupported for detached elevated processes.");
+ }
+ success = startDetachedUacPrompt(program, arguments, nativeArguments,
+ workingDirectory, pid);
}
+ closeChannel(&stdinChannel);
+ closeChannel(&stdoutChannel);
+ closeChannel(&stderrChannel);
return success;
}
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index 4e7120a3b8..c1187e5145 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -67,10 +67,9 @@ QT_BEGIN_NAMESPACE
class QStringSplitter
{
public:
- QStringSplitter(const QString &s)
- : m_string(s), m_data(m_string.constData()), m_len(s.length()), m_pos(0)
+ explicit QStringSplitter(QStringView sv)
+ : m_data(sv.data()), m_len(sv.size())
{
- m_splitChar = QLatin1Char('/');
}
inline bool hasNext() {
@@ -79,18 +78,17 @@ public:
return m_pos < m_len;
}
- inline QStringRef next() {
+ inline QStringView next() {
int start = m_pos;
while (m_pos < m_len && m_data[m_pos] != m_splitChar)
++m_pos;
- return QStringRef(&m_string, start, m_pos - start);
+ return QStringView(m_data + start, m_pos - start);
}
- QString m_string;
const QChar *m_data;
- QChar m_splitChar;
- int m_len;
- int m_pos;
+ qssize_t m_len;
+ qssize_t m_pos = 0;
+ QChar m_splitChar = QLatin1Char('/');
};
@@ -679,7 +677,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
QStringSplitter splitter(path);
while (child_count && splitter.hasNext()) {
- QStringRef segment = splitter.next();
+ QStringView segment = splitter.next();
#ifdef DEBUG_RESOURCE_MATCH
qDebug() << " CHILDREN" << segment;
@@ -836,24 +834,24 @@ QStringList QResourceRoot::children(int node) const
bool QResourceRoot::mappingRootSubdir(const QString &path, QString *match) const
{
const QString root = mappingRoot();
- if(!root.isEmpty()) {
- const QVector<QStringRef> root_segments = root.splitRef(QLatin1Char('/'), QString::SkipEmptyParts),
- path_segments = path.splitRef(QLatin1Char('/'), QString::SkipEmptyParts);
- if(path_segments.size() <= root_segments.size()) {
- int matched = 0;
- for(int i = 0; i < path_segments.size(); ++i) {
- if(root_segments[i] != path_segments[i])
- break;
- ++matched;
- }
- if(matched == path_segments.size()) {
- if(match && root_segments.size() > matched)
- *match = root_segments.at(matched).toString();
- return true;
- }
+ if (root.isEmpty())
+ return false;
+
+ QStringSplitter rootIt(root);
+ QStringSplitter pathIt(path);
+ while (rootIt.hasNext()) {
+ if (pathIt.hasNext()) {
+ if (rootIt.next() != pathIt.next()) // mismatch
+ return false;
+ } else {
+ // end of path, but not of root:
+ if (match)
+ *match = rootIt.next().toString();
+ return true;
}
}
- return false;
+ // end of root
+ return !pathIt.hasNext();
}
Q_CORE_EXPORT bool qRegisterResourceData(int version, const unsigned char *tree,
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index d5460238ec..850e729987 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -1802,6 +1802,8 @@ struct QSettingsIniSection
inline QSettingsIniSection() : position(-1) {}
};
+Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE);
+
typedef QMap<QString, QSettingsIniSection> IniMap;
/*
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index 639605d8c4..d8e91e48ce 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -109,6 +109,8 @@ private:
};
#endif
+Q_DECLARE_TYPEINFO(QSettingsKey, Q_MOVABLE_TYPE);
+
typedef QMap<QSettingsKey, QByteArray> UnparsedSettingsMap;
typedef QMap<QSettingsKey, QVariant> ParsedSettingsMap;
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index f2368c3b23..c3d45caf0e 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -183,7 +183,7 @@ QT_BEGIN_NAMESPACE
\li "C:/Users/<USER>"
\row \li DataLocation
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
- \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data", "<APPDIR>/data/<APPNAME>"
\row \li CacheLocation
\li "~/Library/Caches/<APPNAME>", "/Library/Caches/<APPNAME>"
\li "C:/Users/<USER>/AppData/Local/<APPNAME>/cache"
@@ -207,10 +207,10 @@ QT_BEGIN_NAMESPACE
\li "C:/Users/<USER>/AppData/Local/cache"
\row \li AppDataLocation
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
- \li "C:/Users/<USER>/AppData/Roaming/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
+ \li "C:/Users/<USER>/AppData/Roaming/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data", "<APPDIR>/data/<APPNAME>"
\row \li AppLocalDataLocation
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
- \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data", "<APPDIR>/data/<APPNAME>"
\row \li AppConfigLocation
\li "~/Library/Preferences/<APPNAME>"
\li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>"
diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp
index a64bde6fb4..41fd31df8b 100644
--- a/src/corelib/io/qstandardpaths_win.cpp
+++ b/src/corelib/io/qstandardpaths_win.cpp
@@ -218,7 +218,15 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
}
#ifndef QT_BOOTSTRAPPED
dirs.append(QCoreApplication::applicationDirPath());
- dirs.append(QCoreApplication::applicationDirPath() + QLatin1String("/data"));
+ const QString dataDir = QCoreApplication::applicationDirPath() + QLatin1String("/data");
+ dirs.append(dataDir);
+
+ if (!isGenericConfigLocation(type)) {
+ QString appDataDir = dataDir;
+ appendOrganizationAndApp(appDataDir);
+ if (appDataDir != dataDir)
+ dirs.append(appDataDir);
+ }
#endif // !QT_BOOTSTRAPPED
} // isConfigLocation()
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 27f0552a31..e2c1f0232f 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -40,6 +40,8 @@
#include "qstorageinfo.h"
#include "qstorageinfo_p.h"
+#include "qdebug.h"
+
QT_BEGIN_NAMESPACE
/*!
@@ -431,4 +433,37 @@ QStorageInfo QStorageInfo::root()
volume than the \a second; otherwise returns false.
*/
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QStorageInfo &s)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug.noquote();
+ debug << "QStorageInfo(";
+ if (s.isValid()) {
+ const QStorageInfoPrivate *d = s.d.constData();
+ debug << '"' << d->rootPath << '"';
+ if (!d->fileSystemType.isEmpty())
+ debug << ", type=" << d->fileSystemType;
+ if (!d->name.isEmpty())
+ debug << ", name=\"" << d->name << '"';
+ if (!d->device.isEmpty())
+ debug << ", device=\"" << d->device << '"';
+ if (!d->subvolume.isEmpty())
+ debug << ", subvolume=\"" << d->subvolume << '"';
+ if (d->readOnly)
+ debug << " [read only]";
+ debug << (d->ready ? " [ready]" : " [not ready]");
+ if (d->bytesTotal > 0) {
+ debug << ", bytesTotal=" << d->bytesTotal << ", bytesFree=" << d->bytesFree
+ << ", bytesAvailable=" << d->bytesAvailable;
+ }
+ } else {
+ debug << "invalid";
+ }
+ debug<< ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
index e2d9747ceb..4ab7a353ef 100644
--- a/src/corelib/io/qstorageinfo.h
+++ b/src/corelib/io/qstorageinfo.h
@@ -49,6 +49,8 @@
QT_BEGIN_NAMESPACE
+class QDebug;
+
class QStorageInfoPrivate;
class Q_CORE_EXPORT QStorageInfo
{
@@ -94,6 +96,7 @@ public:
private:
friend class QStorageInfoPrivate;
friend bool operator==(const QStorageInfo &first, const QStorageInfo &second);
+ friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QStorageInfo &);
QExplicitlySharedDataPointer<QStorageInfoPrivate> d;
};
@@ -114,6 +117,10 @@ inline bool QStorageInfo::isRoot() const
Q_DECLARE_SHARED(QStorageInfo)
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QStorageInfo &);
+#endif
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QStorageInfo)
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 8a99873fee..efab2a30ff 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -42,6 +42,7 @@
#ifndef QT_NO_TEMPORARYFILE
#include "qplatformdefs.h"
+#include "qrandom.h"
#include "private/qtemporaryfile_p.h"
#include "private/qfile_p.h"
#include "private/qsystemerror_p.h"
@@ -131,15 +132,17 @@ static bool createFileFromTemplate(NativeFileHandle &file,
Char *rIter = placeholderEnd;
#if defined(QT_BUILD_CORE_LIB)
+ // don't consume more than half of the template with the PID
+ Char *pidStart = placeholderEnd - (placeholderEnd - placeholderStart) / 2;
quint64 pid = quint64(QCoreApplication::applicationPid());
do {
*--rIter = Latin1Char((pid % 10) + '0');
pid /= 10;
- } while (rIter != placeholderStart && pid != 0);
+ } while (rIter != pidStart && pid != 0);
#endif
while (rIter != placeholderStart) {
- char ch = char((qrand() & 0xffff) % (26 + 26));
+ char ch = char(QRandomGenerator::bounded(26 + 26));
if (ch < 26)
*--rIter = Latin1Char(ch + 'A');
else
diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h
index 7f365f0e8a..bf40e1627a 100644
--- a/src/corelib/io/qtemporaryfile_p.h
+++ b/src/corelib/io/qtemporaryfile_p.h
@@ -65,7 +65,7 @@ class QTemporaryFilePrivate : public QFilePrivate
{
Q_DECLARE_PUBLIC(QTemporaryFile)
-protected:
+public:
QTemporaryFilePrivate();
explicit QTemporaryFilePrivate(const QString &templateNameIn);
~QTemporaryFilePrivate();
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 5144ac0ec9..ee3cb4efcb 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -954,8 +954,7 @@ QTextStreamPrivate::PaddingResult QTextStreamPrivate::padding(int len) const
right = padSize - padSize/2;
break;
}
- const PaddingResult result = { left, right };
- return result;
+ return { left, right };
}
/*!
diff --git a/src/corelib/io/qtldurl.cpp b/src/corelib/io/qtldurl.cpp
index 96543bbbfd..a934d19fa2 100644
--- a/src/corelib/io/qtldurl.cpp
+++ b/src/corelib/io/qtldurl.cpp
@@ -50,9 +50,21 @@
QT_BEGIN_NAMESPACE
-static bool containsTLDEntry(const QStringRef &entry)
+enum TLDMatchType {
+ ExactMatch,
+ SuffixMatch,
+ ExceptionMatch,
+};
+
+static bool containsTLDEntry(QStringView entry, TLDMatchType match)
{
- int index = qt_hash(entry) % tldCount;
+ const QStringView matchSymbols[] = {
+ QStringViewLiteral(""),
+ QStringViewLiteral("*"),
+ QStringViewLiteral("!"),
+ };
+ const auto symbol = matchSymbols[match];
+ int index = qt_hash(entry, qt_hash(symbol)) % tldCount;
// select the right chunk from the big table
short chunk = 0;
@@ -65,19 +77,14 @@ static bool containsTLDEntry(const QStringRef &entry)
// check all the entries from the given index
while (chunkIndex < tldIndices[index+1] - offset) {
- QString currentEntry = QString::fromUtf8(tldData[chunk] + chunkIndex);
- if (currentEntry == entry)
+ const auto utf8 = tldData[chunk] + chunkIndex;
+ if ((symbol.isEmpty() || QLatin1Char(*utf8) == symbol) && entry == QString::fromUtf8(utf8 + symbol.size()))
return true;
- chunkIndex += qstrlen(tldData[chunk] + chunkIndex) + 1; // +1 for the ending \0
+ chunkIndex += qstrlen(utf8) + 1; // +1 for the ending \0
}
return false;
}
-static inline bool containsTLDEntry(const QString &entry)
-{
- return containsTLDEntry(QStringRef(&entry));
-}
-
/*!
\internal
@@ -111,19 +118,16 @@ Q_CORE_EXPORT bool qIsEffectiveTLD(const QStringRef &domain)
{
// for domain 'foo.bar.com':
// 1. return if TLD table contains 'foo.bar.com'
- if (containsTLDEntry(domain))
+ // 2. else if table contains '*.bar.com',
+ // 3. test that table does not contain '!foo.bar.com'
+
+ if (containsTLDEntry(domain, ExactMatch)) // 1
return true;
const int dot = domain.indexOf(QLatin1Char('.'));
if (dot >= 0) {
- int count = domain.size() - dot;
- QString wildCardDomain = QLatin1Char('*') + domain.right(count);
- // 2. if table contains '*.bar.com',
- // test if table contains '!foo.bar.com'
- if (containsTLDEntry(wildCardDomain)) {
- QString exceptionDomain = QLatin1Char('!') + domain;
- return (! containsTLDEntry(exceptionDomain));
- }
+ if (containsTLDEntry(domain.mid(dot), SuffixMatch)) // 2
+ return !containsTLDEntry(domain, ExceptionMatch); // 3
}
return false;
}
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index b93fed5ba8..ef5ff2d827 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -132,17 +132,8 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
actualReadBufferSize--;
readSoFar = 1;
} else {
- qint64 bytesToRead = qMin(actualReadBufferSize, maxlen);
- readSoFar = 0;
- while (readSoFar < bytesToRead) {
- const char *ptr = readBuffer.readPointer();
- qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
- readBuffer.nextDataBlockSize());
- memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
- readSoFar += bytesToReadFromThisBlock;
- readBuffer.free(bytesToReadFromThisBlock);
- actualReadBufferSize -= bytesToReadFromThisBlock;
- }
+ readSoFar = readBuffer.read(data, qMin(actualReadBufferSize, maxlen));
+ actualReadBufferSize -= readSoFar;
}
if (!pipeBroken) {
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index 846891102f..75cb8a7ede 100644
--- a/src/corelib/io/qwindowspipewriter.cpp
+++ b/src/corelib/io/qwindowspipewriter.cpp
@@ -57,7 +57,6 @@ QWindowsPipeWriter::QWindowsPipeWriter(HANDLE pipeWriteEnd, QObject *parent)
: QObject(parent),
handle(pipeWriteEnd),
overlapped(nullptr),
- numberOfBytesToWrite(0),
pendingBytesWrittenValue(0),
stopped(true),
writeSequenceStarted(false),
@@ -98,7 +97,7 @@ bool QWindowsPipeWriter::waitForWrite(int msecs)
qint64 QWindowsPipeWriter::bytesToWrite() const
{
- return numberOfBytesToWrite + pendingBytesWrittenValue;
+ return buffer.size() + pendingBytesWrittenValue;
}
void QWindowsPipeWriter::emitPendingBytesWrittenValue()
@@ -137,7 +136,6 @@ void QWindowsPipeWriter::notified(DWORD errorCode, DWORD numberOfBytesWritten)
{
notifiedCalled = true;
writeSequenceStarted = false;
- numberOfBytesToWrite = 0;
Q_ASSERT(errorCode != ERROR_SUCCESS || numberOfBytesWritten == DWORD(buffer.size()));
buffer.clear();
@@ -193,13 +191,11 @@ bool QWindowsPipeWriter::write(const QByteArray &ba)
overlapped = new Overlapped(this);
overlapped->clear();
buffer = ba;
- numberOfBytesToWrite = buffer.size();
stopped = false;
writeSequenceStarted = true;
- if (!WriteFileEx(handle, buffer.constData(), numberOfBytesToWrite,
+ if (!WriteFileEx(handle, buffer.constData(), buffer.size(),
overlapped, &writeFileCompleted)) {
writeSequenceStarted = false;
- numberOfBytesToWrite = 0;
buffer.clear();
const DWORD errorCode = GetLastError();
diff --git a/src/corelib/io/qwindowspipewriter_p.h b/src/corelib/io/qwindowspipewriter_p.h
index c8252e2a4b..d6671c3f27 100644
--- a/src/corelib/io/qwindowspipewriter_p.h
+++ b/src/corelib/io/qwindowspipewriter_p.h
@@ -145,7 +145,6 @@ private:
HANDLE handle;
Overlapped *overlapped;
QByteArray buffer;
- qint64 numberOfBytesToWrite;
qint64 pendingBytesWrittenValue;
bool stopped;
bool writeSequenceStarted;
diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp
deleted file mode 100644
index d7745ae1b6..0000000000
--- a/src/corelib/io/qwinoverlappedionotifier.cpp
+++ /dev/null
@@ -1,428 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qwinoverlappedionotifier_p.h"
-#include <qdebug.h>
-#include <qatomic.h>
-#include <qelapsedtimer.h>
-#include <qmutex.h>
-#include <qpointer.h>
-#include <qqueue.h>
-#include <qset.h>
-#include <qthread.h>
-#include <qt_windows.h>
-#include <private/qobject_p.h>
-#include <private/qiodevice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QWinOverlappedIoNotifier
- \inmodule QtCore
- \brief The QWinOverlappedIoNotifier class provides support for overlapped I/O notifications on Windows.
- \since 5.0
- \internal
-
- The QWinOverlappedIoNotifier class makes it possible to use efficient
- overlapped (asynchronous) I/O notifications on Windows by using an
- I/O completion port.
-
- Once you have obtained a file handle, you can use setHandle() to get
- notifications for I/O operations. Whenever an I/O operation completes,
- the notified() signal is emitted which will pass the number of transferred
- bytes, the operation's error code and a pointer to the operation's
- OVERLAPPED object to the receiver.
-
- Every handle that supports overlapped I/O can be used by
- QWinOverlappedIoNotifier. That includes file handles, TCP sockets
- and named pipes.
-
- Note that you must not use ReadFileEx() and WriteFileEx() together
- with QWinOverlappedIoNotifier. They are not supported as they use a
- different I/O notification mechanism.
-
- The hEvent member in the OVERLAPPED structure passed to ReadFile()
- or WriteFile() is ignored and can be used for other purposes.
-
- \warning This class is only available on Windows.
-
- Due to peculiarities of the Windows I/O completion port API, users of
- QWinOverlappedIoNotifier must pay attention to the following restrictions:
- \list
- \li File handles with a QWinOverlappedIoNotifer are assigned to an I/O
- completion port until the handle is closed. It is impossible to
- disassociate the file handle from the I/O completion port.
- \li There can be only one QWinOverlappedIoNotifer per file handle. Creating
- another QWinOverlappedIoNotifier for that file, even with a duplicated
- handle, will fail.
- \li Certain Windows API functions are unavailable for file handles that are
- assigned to an I/O completion port. This includes the functions
- \c{ReadFileEx} and \c{WriteFileEx}.
- \endlist
- See also the remarks in the MSDN documentation for the
- \c{CreateIoCompletionPort} function.
-*/
-
-struct IOResult
-{
- IOResult(DWORD n = 0, DWORD e = 0, OVERLAPPED *p = 0)
- : numberOfBytes(n), errorCode(e), overlapped(p)
- {}
-
- DWORD numberOfBytes;
- DWORD errorCode;
- OVERLAPPED *overlapped;
-};
-
-
-class QWinIoCompletionPort;
-
-class QWinOverlappedIoNotifierPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QWinOverlappedIoNotifier)
-public:
- QWinOverlappedIoNotifierPrivate()
- : hHandle(INVALID_HANDLE_VALUE)
- {
- }
-
- OVERLAPPED *waitForAnyNotified(int msecs);
- void notify(DWORD numberOfBytes, DWORD errorCode, OVERLAPPED *overlapped);
- void _q_notified();
- OVERLAPPED *dispatchNextIoResult();
-
- static QWinIoCompletionPort *iocp;
- static HANDLE iocpInstanceLock;
- static unsigned int iocpInstanceRefCount;
- HANDLE hHandle;
- HANDLE hSemaphore;
- HANDLE hResultsMutex;
- QAtomicInt waiting;
- QQueue<IOResult> results;
-};
-
-QWinIoCompletionPort *QWinOverlappedIoNotifierPrivate::iocp = 0;
-HANDLE QWinOverlappedIoNotifierPrivate::iocpInstanceLock = CreateMutex(NULL, FALSE, NULL);
-unsigned int QWinOverlappedIoNotifierPrivate::iocpInstanceRefCount = 0;
-
-
-class QWinIoCompletionPort : protected QThread
-{
-public:
- QWinIoCompletionPort()
- : finishThreadKey(reinterpret_cast<ULONG_PTR>(this)),
- drainQueueKey(reinterpret_cast<ULONG_PTR>(this + 1)),
- hPort(INVALID_HANDLE_VALUE)
- {
- setObjectName(QLatin1String("I/O completion port thread"));
- HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
- if (!hIOCP) {
- qErrnoWarning("CreateIoCompletionPort failed.");
- return;
- }
- hPort = hIOCP;
- hQueueDrainedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!hQueueDrainedEvent) {
- qErrnoWarning("CreateEvent failed.");
- return;
- }
- }
-
- ~QWinIoCompletionPort()
- {
- PostQueuedCompletionStatus(hPort, 0, finishThreadKey, NULL);
- QThread::wait();
- CloseHandle(hPort);
- CloseHandle(hQueueDrainedEvent);
- }
-
- void registerNotifier(QWinOverlappedIoNotifierPrivate *notifier)
- {
- const HANDLE hHandle = notifier->hHandle;
- HANDLE hIOCP = CreateIoCompletionPort(hHandle, hPort,
- reinterpret_cast<ULONG_PTR>(notifier), 0);
- if (!hIOCP) {
- qErrnoWarning("Can't associate file handle %x with I/O completion port.", hHandle);
- return;
- }
- mutex.lock();
- notifiers += notifier;
- mutex.unlock();
- if (!QThread::isRunning())
- QThread::start();
- }
-
- void unregisterNotifier(QWinOverlappedIoNotifierPrivate *notifier)
- {
- mutex.lock();
- notifiers.remove(notifier);
- mutex.unlock();
- }
-
- void drainQueue()
- {
- QMutexLocker locker(&drainQueueMutex);
- ResetEvent(hQueueDrainedEvent);
- PostQueuedCompletionStatus(hPort, 0, drainQueueKey, NULL);
- WaitForSingleObject(hQueueDrainedEvent, INFINITE);
- }
-
- using QThread::isRunning;
-
-protected:
- void run()
- {
- DWORD dwBytesRead;
- ULONG_PTR pulCompletionKey;
- OVERLAPPED *overlapped;
- DWORD msecs = INFINITE;
-
- forever {
- BOOL success = GetQueuedCompletionStatus(hPort,
- &dwBytesRead,
- &pulCompletionKey,
- &overlapped,
- msecs);
-
- DWORD errorCode = success ? ERROR_SUCCESS : GetLastError();
- if (!success && !overlapped) {
- if (!msecs) {
- // Time out in drain mode. The completion status queue is empty.
- msecs = INFINITE;
- SetEvent(hQueueDrainedEvent);
- continue;
- }
- qErrnoWarning(errorCode, "GetQueuedCompletionStatus failed.");
- return;
- }
-
- if (pulCompletionKey == finishThreadKey)
- return;
- if (pulCompletionKey == drainQueueKey) {
- // Enter drain mode.
- Q_ASSERT(msecs == INFINITE);
- msecs = 0;
- continue;
- }
-
- QWinOverlappedIoNotifierPrivate *notifier
- = reinterpret_cast<QWinOverlappedIoNotifierPrivate *>(pulCompletionKey);
- mutex.lock();
- if (notifiers.contains(notifier))
- notifier->notify(dwBytesRead, errorCode, overlapped);
- mutex.unlock();
- }
- }
-
-private:
- const ULONG_PTR finishThreadKey;
- const ULONG_PTR drainQueueKey;
- HANDLE hPort;
- QSet<QWinOverlappedIoNotifierPrivate *> notifiers;
- QMutex mutex;
- QMutex drainQueueMutex;
- HANDLE hQueueDrainedEvent;
-};
-
-
-QWinOverlappedIoNotifier::QWinOverlappedIoNotifier(QObject *parent)
- : QObject(*new QWinOverlappedIoNotifierPrivate, parent)
-{
- Q_D(QWinOverlappedIoNotifier);
- WaitForSingleObject(d->iocpInstanceLock, INFINITE);
- if (!d->iocp)
- d->iocp = new QWinIoCompletionPort;
- d->iocpInstanceRefCount++;
- ReleaseMutex(d->iocpInstanceLock);
-
- d->hSemaphore = CreateSemaphore(NULL, 0, 255, NULL);
- d->hResultsMutex = CreateMutex(NULL, FALSE, NULL);
- connect(this, SIGNAL(_q_notify()), this, SLOT(_q_notified()), Qt::QueuedConnection);
-}
-
-QWinOverlappedIoNotifier::~QWinOverlappedIoNotifier()
-{
- Q_D(QWinOverlappedIoNotifier);
- setEnabled(false);
- CloseHandle(d->hResultsMutex);
- CloseHandle(d->hSemaphore);
-
- WaitForSingleObject(d->iocpInstanceLock, INFINITE);
- if (!--d->iocpInstanceRefCount) {
- delete d->iocp;
- d->iocp = 0;
- }
- ReleaseMutex(d->iocpInstanceLock);
-}
-
-void QWinOverlappedIoNotifier::setHandle(Qt::HANDLE h)
-{
- Q_D(QWinOverlappedIoNotifier);
- d->hHandle = h;
-}
-
-Qt::HANDLE QWinOverlappedIoNotifier::handle() const
-{
- Q_D(const QWinOverlappedIoNotifier);
- return d->hHandle;
-}
-
-void QWinOverlappedIoNotifier::setEnabled(bool enabled)
-{
- Q_D(QWinOverlappedIoNotifier);
- if (enabled)
- d->iocp->registerNotifier(d);
- else
- d->iocp->unregisterNotifier(d);
-}
-
-OVERLAPPED *QWinOverlappedIoNotifierPrivate::waitForAnyNotified(int msecs)
-{
- if (!iocp->isRunning()) {
- qWarning("Called QWinOverlappedIoNotifier::waitForAnyNotified on inactive notifier.");
- return 0;
- }
-
- if (msecs == 0)
- iocp->drainQueue();
-
- const DWORD wfso = WaitForSingleObject(hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs));
- switch (wfso) {
- case WAIT_OBJECT_0:
- return dispatchNextIoResult();
- case WAIT_TIMEOUT:
- return 0;
- default:
- qErrnoWarning("QWinOverlappedIoNotifier::waitForAnyNotified: WaitForSingleObject failed.");
- return 0;
- }
-}
-
-class QScopedAtomicIntIncrementor
-{
-public:
- QScopedAtomicIntIncrementor(QAtomicInt &i)
- : m_int(i)
- {
- ++m_int;
- }
-
- ~QScopedAtomicIntIncrementor()
- {
- --m_int;
- }
-
-private:
- QAtomicInt &m_int;
-};
-
-/*!
- * Wait synchronously for any notified signal.
- *
- * The function returns a pointer to the OVERLAPPED object corresponding to the completed I/O
- * operation. In case no I/O operation was completed during the \a msec timeout, this function
- * returns a null pointer.
- */
-OVERLAPPED *QWinOverlappedIoNotifier::waitForAnyNotified(int msecs)
-{
- Q_D(QWinOverlappedIoNotifier);
- QScopedAtomicIntIncrementor saii(d->waiting);
- OVERLAPPED *result = d->waitForAnyNotified(msecs);
- return result;
-}
-
-/*!
- * Wait synchronously for the notified signal.
- *
- * The function returns true if the notified signal was emitted for
- * the I/O operation that corresponds to the OVERLAPPED object.
- */
-bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped)
-{
- Q_D(QWinOverlappedIoNotifier);
- QScopedAtomicIntIncrementor saii(d->waiting);
- int t = msecs;
- QElapsedTimer stopWatch;
- stopWatch.start();
- forever {
- OVERLAPPED *triggeredOverlapped = waitForAnyNotified(t);
- if (!triggeredOverlapped)
- return false;
- if (triggeredOverlapped == overlapped)
- return true;
- t = qt_subtract_from_timeout(msecs, stopWatch.elapsed());
- if (t == 0)
- return false;
- }
-}
-
-/*!
- * Note: This function runs in the I/O completion port thread.
- */
-void QWinOverlappedIoNotifierPrivate::notify(DWORD numberOfBytes, DWORD errorCode,
- OVERLAPPED *overlapped)
-{
- Q_Q(QWinOverlappedIoNotifier);
- WaitForSingleObject(hResultsMutex, INFINITE);
- results.enqueue(IOResult(numberOfBytes, errorCode, overlapped));
- ReleaseMutex(hResultsMutex);
- ReleaseSemaphore(hSemaphore, 1, NULL);
- if (!waiting)
- emit q->_q_notify();
-}
-
-void QWinOverlappedIoNotifierPrivate::_q_notified()
-{
- if (WaitForSingleObject(hSemaphore, 0) == WAIT_OBJECT_0)
- dispatchNextIoResult();
-}
-
-OVERLAPPED *QWinOverlappedIoNotifierPrivate::dispatchNextIoResult()
-{
- Q_Q(QWinOverlappedIoNotifier);
- WaitForSingleObject(hResultsMutex, INFINITE);
- IOResult ioresult = results.dequeue();
- ReleaseMutex(hResultsMutex);
- emit q->notified(ioresult.numberOfBytes, ioresult.errorCode, ioresult.overlapped);
- return ioresult.overlapped;
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qwinoverlappedionotifier_p.cpp"
diff --git a/src/corelib/io/qwinoverlappedionotifier_p.h b/src/corelib/io/qwinoverlappedionotifier_p.h
deleted file mode 100644
index 276a1d861e..0000000000
--- a/src/corelib/io/qwinoverlappedionotifier_p.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWINOVERLAPPEDIONOTIFIER_P_H
-#define QWINOVERLAPPEDIONOTIFIER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/private/qglobal_p.h>
-#include <qobject.h>
-
-typedef struct _OVERLAPPED OVERLAPPED;
-
-QT_BEGIN_NAMESPACE
-
-class QWinOverlappedIoNotifierPrivate;
-
-class Q_CORE_EXPORT QWinOverlappedIoNotifier : public QObject
-{
- Q_OBJECT
- Q_DISABLE_COPY(QWinOverlappedIoNotifier)
- Q_DECLARE_PRIVATE(QWinOverlappedIoNotifier)
- Q_PRIVATE_SLOT(d_func(), void _q_notified())
- friend class QWinIoCompletionPort;
-public:
- QWinOverlappedIoNotifier(QObject *parent = 0);
- ~QWinOverlappedIoNotifier();
-
- void setHandle(Qt::HANDLE h);
- Qt::HANDLE handle() const;
-
- void setEnabled(bool enabled);
- OVERLAPPED *waitForAnyNotified(int msecs);
- bool waitForNotified(int msecs, OVERLAPPED *overlapped);
-
-Q_SIGNALS:
- void notified(quint32 numberOfBytes, quint32 errorCode, OVERLAPPED *overlapped);
-#if !defined(Q_QDOC)
- void _q_notify();
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif // QWINOVERLAPPEDIONOTIFIER_P_H