summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri14
-rw-r--r--src/corelib/io/qabstractfileengine.cpp47
-rw-r--r--src/corelib/io/qabstractfileengine_p.h9
-rw-r--r--src/corelib/io/qbuffer.cpp4
-rw-r--r--src/corelib/io/qbuffer.h26
-rw-r--r--src/corelib/io/qdatastream.cpp1417
-rw-r--r--src/corelib/io/qdatastream.h464
-rw-r--r--src/corelib/io/qdatastream_p.h73
-rw-r--r--src/corelib/io/qdebug.cpp138
-rw-r--r--src/corelib/io/qdebug.h3
-rw-r--r--src/corelib/io/qdir.cpp1
-rw-r--r--src/corelib/io/qfile.cpp135
-rw-r--r--src/corelib/io/qfile.h15
-rw-r--r--src/corelib/io/qfiledevice.cpp70
-rw-r--r--src/corelib/io/qfiledevice.h31
-rw-r--r--src/corelib/io/qfiledevice_p.h2
-rw-r--r--src/corelib/io/qfileinfo.cpp341
-rw-r--r--src/corelib/io/qfileinfo.h11
-rw-r--r--src/corelib/io/qfileinfo_p.h48
-rw-r--r--src/corelib/io/qfileselector.h2
-rw-r--r--src/corelib/io/qfilesystemengine.cpp228
-rw-r--r--src/corelib/io/qfilesystemengine_p.h10
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp948
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp317
-rw-r--r--src/corelib/io/qfilesystementry.cpp5
-rw-r--r--src/corelib/io/qfilesystementry_p.h5
-rw-r--r--src/corelib/io/qfilesystemiterator_unix.cpp17
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h64
-rw-r--r--src/corelib/io/qfilesystemwatcher.h4
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents.mm2
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify_p.h4
-rw-r--r--src/corelib/io/qfilesystemwatcher_polling_p.h4
-rw-r--r--src/corelib/io/qfsfileengine.cpp97
-rw-r--r--src/corelib/io/qfsfileengine_iterator_p.h8
-rw-r--r--src/corelib/io/qfsfileengine_p.h82
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp163
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp65
-rw-r--r--src/corelib/io/qiodevice.cpp141
-rw-r--r--src/corelib/io/qiodevice.h7
-rw-r--r--src/corelib/io/qiodevice_p.h7
-rw-r--r--src/corelib/io/qlockfile.cpp98
-rw-r--r--src/corelib/io/qlockfile_p.h24
-rw-r--r--src/corelib/io/qlockfile_unix.cpp169
-rw-r--r--src/corelib/io/qlockfile_win.cpp64
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice_p.h58
-rw-r--r--src/corelib/io/qprocess.cpp114
-rw-r--r--src/corelib/io/qprocess.h27
-rw-r--r--src/corelib/io/qprocess_p.h8
-rw-r--r--src/corelib/io/qprocess_unix.cpp131
-rw-r--r--src/corelib/io/qprocess_win.cpp139
-rw-r--r--src/corelib/io/qresource.cpp56
-rw-r--r--src/corelib/io/qresource_iterator_p.h6
-rw-r--r--src/corelib/io/qresource_p.h60
-rw-r--r--src/corelib/io/qsavefile.cpp45
-rw-r--r--src/corelib/io/qsavefile.h10
-rw-r--r--src/corelib/io/qsettings.cpp82
-rw-r--r--src/corelib/io/qsettings.h16
-rw-r--r--src/corelib/io/qsettings_mac.cpp2
-rw-r--r--src/corelib/io/qsettings_p.h21
-rw-r--r--src/corelib/io/qstandardpaths.cpp35
-rw-r--r--src/corelib/io/qstandardpaths_mac.mm29
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp12
-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/qstorageinfo_mac.cpp6
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp255
-rw-r--r--src/corelib/io/qstorageinfo_win.cpp4
-rw-r--r--src/corelib/io/qtemporarydir.cpp87
-rw-r--r--src/corelib/io/qtemporarydir.h2
-rw-r--r--src/corelib/io/qtemporaryfile.cpp522
-rw-r--r--src/corelib/io/qtemporaryfile.h8
-rw-r--r--src/corelib/io/qtemporaryfile_p.h52
-rw-r--r--src/corelib/io/qtextstream.cpp3193
-rw-r--r--src/corelib/io/qtextstream.h287
-rw-r--r--src/corelib/io/qtextstream_p.h200
-rw-r--r--src/corelib/io/qtldurl.cpp42
-rw-r--r--src/corelib/io/qurl.h2
-rw-r--r--src/corelib/io/qurlidna.cpp5
-rw-r--r--src/corelib/io/qwindowspipereader.cpp15
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp10
-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
84 files changed, 3483 insertions, 8013 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index b2c531a8ad..d138ab2f00 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -3,8 +3,6 @@
HEADERS += \
io/qabstractfileengine_p.h \
io/qbuffer.h \
- io/qdatastream.h \
- io/qdatastream_p.h \
io/qdataurl_p.h \
io/qdebug.h \
io/qdebug_p.h \
@@ -22,8 +20,6 @@ HEADERS += \
io/qlockfile.h \
io/qlockfile_p.h \
io/qnoncontiguousbytedevice_p.h \
- io/qtextstream.h \
- io/qtextstream_p.h \
io/qtemporarydir.h \
io/qtemporaryfile.h \
io/qtemporaryfile_p.h \
@@ -57,7 +53,6 @@ HEADERS += \
SOURCES += \
io/qabstractfileengine.cpp \
io/qbuffer.cpp \
- io/qdatastream.cpp \
io/qdataurl.cpp \
io/qtldurl.cpp \
io/qdebug.cpp \
@@ -71,7 +66,6 @@ SOURCES += \
io/qlockfile.cpp \
io/qnoncontiguousbytedevice.cpp \
io/qstorageinfo.cpp \
- io/qtextstream.cpp \
io/qtemporarydir.cpp \
io/qtemporaryfile.cpp \
io/qresource.cpp \
@@ -121,18 +115,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..f2a895bbb8 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -328,7 +328,8 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
These are used by the fileTime() function.
- \value CreationTime When the file was created.
+ \value BirthTime When the file was born (created).
+ \value MetadataChangeTime When the file's metadata was last changed.
\value ModificationTime When the file was most recently modified.
\value AccessTime When the file was most recently accessed (e.g.
read or written to).
@@ -737,13 +738,31 @@ 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
- recently modified. If \a time is \c AccessTime, return when the
- file was most recently accessed (e.g. read or written).
- If the time cannot be determined return QDateTime() (an invalid
- date time).
+ If \a time is \c BirthTime, return when the file was born (created). If \a
+ time is \c MetadataChangeTime, return when the file's metadata was last
+ changed. If \a time is \c ModificationTime, return when the file was most
+ recently modified. If \a time is \c AccessTime, return when the file was
+ most recently accessed (e.g. read or written). If the time cannot be
+ determined return QDateTime() (an invalid date time).
This virtual function must be reimplemented by all subclasses.
@@ -843,6 +862,20 @@ bool QAbstractFileEngine::unmap(uchar *address)
}
/*!
+ \since 5.10
+
+ Duplicates the contents of this file (starting from the current position)
+ to the file specified by the engine \a target.
+
+ Returns \c true on success; otherwise, \c false is returned.
+ */
+bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
+{
+ Q_UNUSED(target);
+ 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..00c415b521 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -113,9 +113,10 @@ public:
OwnerGroup
};
enum FileTime {
- CreationTime,
- ModificationTime,
- AccessTime
+ AccessTime,
+ BirthTime,
+ MetadataChangeTime,
+ ModificationTime
};
virtual ~QAbstractFileEngine();
@@ -145,9 +146,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 cloneTo(QAbstractFileEngine *target);
bool atEnd() const;
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index 86dd737809..e0b9c41323 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -60,8 +60,8 @@ public:
QByteArray *buf;
QByteArray defaultBuf;
- virtual qint64 peek(char *data, qint64 maxSize) Q_DECL_OVERRIDE;
- virtual QByteArray peek(qint64 maxSize) Q_DECL_OVERRIDE;
+ virtual qint64 peek(char *data, qint64 maxSize) override;
+ virtual QByteArray peek(qint64 maxSize) override;
#ifndef QT_NO_QOBJECT
// private slots
diff --git a/src/corelib/io/qbuffer.h b/src/corelib/io/qbuffer.h
index fd05dff311..39e1e7b39d 100644
--- a/src/corelib/io/qbuffer.h
+++ b/src/corelib/io/qbuffer.h
@@ -57,8 +57,8 @@ class Q_CORE_EXPORT QBuffer : public QIODevice
public:
#ifndef QT_NO_QOBJECT
- explicit QBuffer(QObject *parent = Q_NULLPTR);
- QBuffer(QByteArray *buf, QObject *parent = Q_NULLPTR);
+ explicit QBuffer(QObject *parent = nullptr);
+ QBuffer(QByteArray *buf, QObject *parent = nullptr);
#else
QBuffer();
explicit QBuffer(QByteArray *buf);
@@ -73,22 +73,22 @@ public:
inline void setData(const char *data, int len);
const QByteArray &data() const;
- bool open(OpenMode openMode) Q_DECL_OVERRIDE;
+ bool open(OpenMode openMode) override;
- void close() Q_DECL_OVERRIDE;
- qint64 size() const Q_DECL_OVERRIDE;
- qint64 pos() const Q_DECL_OVERRIDE;
- bool seek(qint64 off) Q_DECL_OVERRIDE;
- bool atEnd() const Q_DECL_OVERRIDE;
- bool canReadLine() const Q_DECL_OVERRIDE;
+ void close() override;
+ qint64 size() const override;
+ qint64 pos() const override;
+ bool seek(qint64 off) override;
+ bool atEnd() const override;
+ bool canReadLine() const override;
protected:
#ifndef QT_NO_QOBJECT
- void connectNotify(const QMetaMethod &) Q_DECL_OVERRIDE;
- void disconnectNotify(const QMetaMethod &) Q_DECL_OVERRIDE;
+ void connectNotify(const QMetaMethod &) override;
+ void disconnectNotify(const QMetaMethod &) override;
#endif
- qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
- qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE;
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
private:
Q_DECLARE_PRIVATE(QBuffer)
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
deleted file mode 100644
index 9a42fb4a37..0000000000
--- a/src/corelib/io/qdatastream.cpp
+++ /dev/null
@@ -1,1417 +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 "qdatastream.h"
-#include "qdatastream_p.h"
-
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
-#include "qbuffer.h"
-#include "qfloat16.h"
-#include "qstring.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "qendian.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \class QDataStream
- \inmodule QtCore
- \reentrant
- \brief The QDataStream class provides serialization of binary data
- to a QIODevice.
-
- \ingroup io
-
-
- A data stream is a binary stream of encoded information which is
- 100% independent of the host computer's operating system, CPU or
- byte order. For example, a data stream that is written by a PC
- under Windows can be read by a Sun SPARC running Solaris.
-
- You can also use a data stream to read/write \l{raw}{raw
- unencoded binary data}. If you want a "parsing" input stream, see
- QTextStream.
-
- The QDataStream class implements the serialization of C++'s basic
- data types, like \c char, \c short, \c int, \c{char *}, etc.
- Serialization of more complex data is accomplished by breaking up
- the data into primitive units.
-
- A data stream cooperates closely with a QIODevice. A QIODevice
- represents an input/output medium one can read data from and write
- data to. The QFile class is an example of an I/O device.
-
- Example (write binary data to a stream):
-
- \snippet code/src_corelib_io_qdatastream.cpp 0
-
- Example (read binary data from a stream):
-
- \snippet code/src_corelib_io_qdatastream.cpp 1
-
- Each item written to the stream is written in a predefined binary
- format that varies depending on the item's type. Supported Qt
- types include QBrush, QColor, QDateTime, QFont, QPixmap, QString,
- QVariant and many others. For the complete list of all Qt types
- supporting data streaming see \l{Serializing Qt Data Types}.
-
- For integers it is best to always cast to a Qt integer type for
- writing, and to read back into the same Qt integer type. This
- ensures that you get integers of the size you want and insulates
- you from compiler and platform differences.
-
- To take one example, a \c{char *} string is written as a 32-bit
- integer equal to the length of the string including the '\\0' byte,
- followed by all the characters of the string including the
- '\\0' byte. When reading a \c{char *} string, 4 bytes are read to
- create the 32-bit length value, then that many characters for the
- \c {char *} string including the '\\0' terminator are read.
-
- The initial I/O device is usually set in the constructor, but can be
- changed with setDevice(). If you've reached the end of the data
- (or if there is no I/O device set) atEnd() will return true.
-
- \section1 Versioning
-
- QDataStream's binary format has evolved since Qt 1.0, and is
- likely to continue evolving to reflect changes done in Qt. When
- inputting or outputting complex types, it's very important to
- make sure that the same version of the stream (version()) is used
- for reading and writing. If you need both forward and backward
- compatibility, you can hardcode the version number in the
- application:
-
- \snippet code/src_corelib_io_qdatastream.cpp 2
-
- If you are producing a new binary data format, such as a file
- format for documents created by your application, you could use a
- QDataStream to write the data in a portable format. Typically, you
- would write a brief header containing a magic string and a version
- number to give yourself room for future expansion. For example:
-
- \snippet code/src_corelib_io_qdatastream.cpp 3
-
- Then read it in with:
-
- \snippet code/src_corelib_io_qdatastream.cpp 4
-
- You can select which byte order to use when serializing data. The
- default setting is big endian (MSB first). Changing it to little
- endian breaks the portability (unless the reader also changes to
- little endian). We recommend keeping this setting unless you have
- special requirements.
-
- \target raw
- \section1 Reading and Writing Raw Binary Data
-
- You may wish to read/write your own raw binary data to/from the
- data stream directly. Data may be read from the stream into a
- preallocated \c{char *} using readRawData(). Similarly data can be
- written to the stream using writeRawData(). Note that any
- encoding/decoding of the data must be done by you.
-
- A similar pair of functions is readBytes() and writeBytes(). These
- differ from their \e raw counterparts as follows: readBytes()
- reads a quint32 which is taken to be the length of the data to be
- read, then that number of bytes is read into the preallocated
- \c{char *}; writeBytes() writes a quint32 containing the length of the
- data, followed by the data. Note that any encoding/decoding of
- the data (apart from the length quint32) must be done by you.
-
- \section1 Reading and Writing Qt Collection Classes
-
- The Qt container classes can also be serialized to a QDataStream.
- These include QList, QLinkedList, QVector, QSet, QHash, and QMap.
- The stream operators are declared as non-members of the classes.
-
- \target Serializing Qt Classes
- \section1 Reading and Writing Other Qt Classes
-
- In addition to the overloaded stream operators documented here,
- any Qt classes that you might want to serialize to a QDataStream
- will have appropriate stream operators declared as non-member of
- the class:
-
- \code
- QDataStream &operator<<(QDataStream &, const QXxx &);
- QDataStream &operator>>(QDataStream &, QXxx &);
- \endcode
-
- For example, here are the stream operators declared as non-members
- of the QImage class:
-
- \code
- QDataStream & operator<< (QDataStream& stream, const QImage& image);
- QDataStream & operator>> (QDataStream& stream, QImage& image);
- \endcode
-
- To see if your favorite Qt class has similar stream operators
- defined, check the \b {Related Non-Members} section of the
- class's documentation page.
-
- \section1 Using Read Transactions
-
- When a data stream operates on an asynchronous device, the chunks of data
- can arrive at arbitrary points in time. The QDataStream class implements
- a transaction mechanism that provides the ability to read the data
- atomically with a series of stream operators. As an example, you can
- handle incomplete reads from a socket by using a transaction in a slot
- connected to the readyRead() signal:
-
- \snippet code/src_corelib_io_qdatastream.cpp 6
-
- If no full packet is received, this code restores the stream to the
- initial position, after which you need to wait for more data to arrive.
-
- \sa QTextStream, QVariant
-*/
-
-/*!
- \enum QDataStream::ByteOrder
-
- The byte order used for reading/writing the data.
-
- \value BigEndian Most significant byte first (the default)
- \value LittleEndian Least significant byte first
-*/
-
-/*!
- \enum QDataStream::FloatingPointPrecision
-
- The precision of floating point numbers used for reading/writing the data. This will only have
- an effect if the version of the data stream is Qt_4_6 or higher.
-
- \warning The floating point precision must be set to the same value on the object that writes
- and the object that reads the data stream.
-
- \value SinglePrecision All floating point numbers in the data stream have 32-bit precision.
- \value DoublePrecision All floating point numbers in the data stream have 64-bit precision.
-
- \sa setFloatingPointPrecision(), floatingPointPrecision()
-*/
-
-/*!
- \enum QDataStream::Status
-
- This enum describes the current status of the data stream.
-
- \value Ok The data stream is operating normally.
- \value ReadPastEnd The data stream has read past the end of the
- data in the underlying device.
- \value ReadCorruptData The data stream has read corrupt data.
- \value WriteFailed The data stream cannot write to the underlying device.
-*/
-
-/*****************************************************************************
- QDataStream member functions
- *****************************************************************************/
-
-#define Q_VOID
-
-#undef CHECK_STREAM_PRECOND
-#ifndef QT_NO_DEBUG
-#define CHECK_STREAM_PRECOND(retVal) \
- if (!dev) { \
- qWarning("QDataStream: No device"); \
- return retVal; \
- }
-#else
-#define CHECK_STREAM_PRECOND(retVal) \
- if (!dev) { \
- return retVal; \
- }
-#endif
-
-#define CHECK_STREAM_WRITE_PRECOND(retVal) \
- CHECK_STREAM_PRECOND(retVal) \
- if (q_status != Ok) \
- return retVal;
-
-#define CHECK_STREAM_TRANSACTION_PRECOND(retVal) \
- if (!d || d->transactionDepth == 0) { \
- qWarning("QDataStream: No transaction in progress"); \
- return retVal; \
- }
-
-/*!
- Constructs a data stream that has no I/O device.
-
- \sa setDevice()
-*/
-
-QDataStream::QDataStream()
-{
- dev = 0;
- owndev = false;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
-}
-
-/*!
- Constructs a data stream that uses the I/O device \a d.
-
- \sa setDevice(), device()
-*/
-
-QDataStream::QDataStream(QIODevice *d)
-{
- dev = d; // set device
- owndev = false;
- byteorder = BigEndian; // default byte order
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
-}
-
-/*!
- \fn QDataStream::QDataStream(QByteArray *a, QIODevice::OpenMode mode)
-
- Constructs a data stream that operates on a byte array, \a a. The
- \a mode describes how the device is to be used.
-
- Alternatively, you can use QDataStream(const QByteArray &) if you
- just want to read from a byte array.
-
- Since QByteArray is not a QIODevice subclass, internally a QBuffer
- is created to wrap the byte array.
-*/
-
-QDataStream::QDataStream(QByteArray *a, QIODevice::OpenMode flags)
-{
- QBuffer *buf = new QBuffer(a);
-#ifndef QT_NO_QOBJECT
- buf->blockSignals(true);
-#endif
- buf->open(flags);
- dev = buf;
- owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
-}
-
-/*!
- Constructs a read-only data stream that operates on byte array \a a.
- Use QDataStream(QByteArray*, int) if you want to write to a byte
- array.
-
- Since QByteArray is not a QIODevice subclass, internally a QBuffer
- is created to wrap the byte array.
-*/
-QDataStream::QDataStream(const QByteArray &a)
-{
- QBuffer *buf = new QBuffer;
-#ifndef QT_NO_QOBJECT
- buf->blockSignals(true);
-#endif
- buf->setData(a);
- buf->open(QIODevice::ReadOnly);
- dev = buf;
- owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
-}
-
-/*!
- Destroys the data stream.
-
- The destructor will not affect the current I/O device, unless it is
- an internal I/O device (e.g. a QBuffer) processing a QByteArray
- passed in the \e constructor, in which case the internal I/O device
- is destroyed.
-*/
-
-QDataStream::~QDataStream()
-{
- if (owndev)
- delete dev;
-}
-
-
-/*!
- \fn QIODevice *QDataStream::device() const
-
- Returns the I/O device currently set, or 0 if no
- device is currently set.
-
- \sa setDevice()
-*/
-
-/*!
- void QDataStream::setDevice(QIODevice *d)
-
- Sets the I/O device to \a d, which can be 0
- to unset to current I/O device.
-
- \sa device()
-*/
-
-void QDataStream::setDevice(QIODevice *d)
-{
- if (owndev) {
- delete dev;
- owndev = false;
- }
- dev = d;
-}
-
-/*!
- \obsolete
- Unsets the I/O device.
- Use setDevice(0) instead.
-*/
-
-void QDataStream::unsetDevice()
-{
- setDevice(0);
-}
-
-
-/*!
- \fn bool QDataStream::atEnd() const
-
- Returns \c true if the I/O device has reached the end position (end of
- the stream or file) or if there is no I/O device set; otherwise
- returns \c false.
-
- \sa QIODevice::atEnd()
-*/
-
-bool QDataStream::atEnd() const
-{
- return dev ? dev->atEnd() : true;
-}
-
-/*!
- Returns the floating point precision of the data stream.
-
- \since 4.6
-
- \sa FloatingPointPrecision, setFloatingPointPrecision()
-*/
-QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
-{
- return d == 0 ? QDataStream::DoublePrecision : d->floatingPointPrecision;
-}
-
-/*!
- Sets the floating point precision of the data stream to \a precision. If the floating point precision is
- DoublePrecision and the version of the data stream is Qt_4_6 or higher, all floating point
- numbers will be written and read with 64-bit precision. If the floating point precision is
- SinglePrecision and the version is Qt_4_6 or higher, all floating point numbers will be written
- and read with 32-bit precision.
-
- For versions prior to Qt_4_6, the precision of floating point numbers in the data stream depends
- on the stream operator called.
-
- The default is DoublePrecision.
-
- Note that this property does not affect the serialization or deserialization of \c qfloat16
- instances.
-
- \warning This property must be set to the same value on the object that writes and the object
- that reads the data stream.
-
- \since 4.6
-*/
-void QDataStream::setFloatingPointPrecision(QDataStream::FloatingPointPrecision precision)
-{
- if (d == 0)
- d.reset(new QDataStreamPrivate());
- d->floatingPointPrecision = precision;
-}
-
-/*!
- Returns the status of the data stream.
-
- \sa Status, setStatus(), resetStatus()
-*/
-
-QDataStream::Status QDataStream::status() const
-{
- return q_status;
-}
-
-/*!
- Resets the status of the data stream.
-
- \sa Status, status(), setStatus()
-*/
-void QDataStream::resetStatus()
-{
- q_status = Ok;
-}
-
-/*!
- Sets the status of the data stream to the \a status given.
-
- Subsequent calls to setStatus() are ignored until resetStatus()
- is called.
-
- \sa Status, status(), resetStatus()
-*/
-void QDataStream::setStatus(Status status)
-{
- if (q_status == Ok)
- q_status = status;
-}
-
-/*!
- \fn int QDataStream::byteOrder() const
-
- Returns the current byte order setting -- either BigEndian or
- LittleEndian.
-
- \sa setByteOrder()
-*/
-
-/*!
- Sets the serialization byte order to \a bo.
-
- The \a bo parameter can be QDataStream::BigEndian or
- QDataStream::LittleEndian.
-
- The default setting is big endian. We recommend leaving this
- setting unless you have special requirements.
-
- \sa byteOrder()
-*/
-
-void QDataStream::setByteOrder(ByteOrder bo)
-{
- byteorder = bo;
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- noswap = (byteorder == BigEndian);
- else
- noswap = (byteorder == LittleEndian);
-}
-
-
-/*!
- \enum QDataStream::Version
-
- This enum provides symbolic synonyms for the data serialization
- format version numbers.
-
- \value Qt_1_0 Version 1 (Qt 1.x)
- \value Qt_2_0 Version 2 (Qt 2.0)
- \value Qt_2_1 Version 3 (Qt 2.1, 2.2, 2.3)
- \value Qt_3_0 Version 4 (Qt 3.0)
- \value Qt_3_1 Version 5 (Qt 3.1, 3.2)
- \value Qt_3_3 Version 6 (Qt 3.3)
- \value Qt_4_0 Version 7 (Qt 4.0, Qt 4.1)
- \value Qt_4_1 Version 7 (Qt 4.0, Qt 4.1)
- \value Qt_4_2 Version 8 (Qt 4.2)
- \value Qt_4_3 Version 9 (Qt 4.3)
- \value Qt_4_4 Version 10 (Qt 4.4)
- \value Qt_4_5 Version 11 (Qt 4.5)
- \value Qt_4_6 Version 12 (Qt 4.6, Qt 4.7, Qt 4.8)
- \value Qt_4_7 Same as Qt_4_6.
- \value Qt_4_8 Same as Qt_4_6.
- \value Qt_4_9 Same as Qt_4_6.
- \value Qt_5_0 Version 13 (Qt 5.0)
- \value Qt_5_1 Version 14 (Qt 5.1)
- \value Qt_5_2 Version 15 (Qt 5.2)
- \value Qt_5_3 Same as Qt_5_2
- \value Qt_5_4 Version 16 (Qt 5.4)
- \value Qt_5_5 Same as Qt_5_4
- \value Qt_5_6 Version 17 (Qt 5.6)
- \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
- \omitvalue Qt_DefaultCompiledVersion
-
- \sa setVersion(), version()
-*/
-
-/*!
- \fn int QDataStream::version() const
-
- Returns the version number of the data serialization format.
-
- \sa setVersion(), Version
-*/
-
-/*!
- \fn void QDataStream::setVersion(int v)
-
- Sets the version number of the data serialization format to \a v,
- a value of the \l Version enum.
-
- You don't \e have to set a version if you are using the current
- version of Qt, but for your own custom binary formats we
- recommend that you do; see \l{Versioning} in the Detailed
- Description.
-
- To accommodate new functionality, the datastream serialization
- format of some Qt classes has changed in some versions of Qt. If
- you want to read data that was created by an earlier version of
- Qt, or write data that can be read by a program that was compiled
- with an earlier version of Qt, use this function to modify the
- serialization format used by QDataStream.
-
- The \l Version enum provides symbolic constants for the different
- versions of Qt. For example:
-
- \snippet code/src_corelib_io_qdatastream.cpp 5
-
- \sa version(), Version
-*/
-
-/*!
- \since 5.7
-
- Starts a new read transaction on the stream.
-
- Defines a restorable point within the sequence of read operations. For
- sequential devices, read data will be duplicated internally to allow
- recovery in case of incomplete reads. For random-access devices,
- this function saves the current position of the stream. Call
- commitTransaction(), rollbackTransaction(), or abortTransaction() to
- finish the current transaction.
-
- Once a transaction is started, subsequent calls to this function will make
- the transaction recursive. Inner transactions act as agents of the
- outermost transaction (i.e., report the status of read operations to the
- outermost transaction, which can restore the position of the stream).
-
- \note Restoring to the point of the nested startTransaction() call is not
- supported.
-
- When an error occurs during a transaction (including an inner transaction
- failing), reading from the data stream is suspended (all subsequent read
- operations return empty/zero values) and subsequent inner transactions are
- forced to fail. Starting a new outermost transaction recovers from this
- state. This behavior makes it unnecessary to error-check every read
- operation separately.
-
- \sa commitTransaction(), rollbackTransaction(), abortTransaction()
-*/
-
-void QDataStream::startTransaction()
-{
- CHECK_STREAM_PRECOND(Q_VOID)
-
- if (d == 0)
- d.reset(new QDataStreamPrivate());
-
- if (++d->transactionDepth == 1) {
- dev->startTransaction();
- resetStatus();
- }
-}
-
-/*!
- \since 5.7
-
- Completes a read transaction. Returns \c true if no read errors have
- occurred during the transaction; otherwise returns \c false.
-
- If called on an inner transaction, committing will be postponed until
- the outermost commitTransaction(), rollbackTransaction(), or
- abortTransaction() call occurs.
-
- Otherwise, if the stream status indicates reading past the end of the
- data, this function restores the stream data to the point of the
- startTransaction() call. When this situation occurs, you need to wait for
- more data to arrive, after which you start a new transaction. If the data
- stream has read corrupt data or any of the inner transactions was aborted,
- this function aborts the transaction.
-
- \sa startTransaction(), rollbackTransaction(), abortTransaction()
-*/
-
-bool QDataStream::commitTransaction()
-{
- CHECK_STREAM_TRANSACTION_PRECOND(false)
- if (--d->transactionDepth == 0) {
- CHECK_STREAM_PRECOND(false)
-
- if (q_status == ReadPastEnd) {
- dev->rollbackTransaction();
- return false;
- }
- dev->commitTransaction();
- }
- return q_status == Ok;
-}
-
-/*!
- \since 5.7
-
- Reverts a read transaction.
-
- This function is commonly used to rollback the transaction when an
- incomplete read was detected prior to committing the transaction.
-
- If called on an inner transaction, reverting is delegated to the outermost
- transaction, and subsequently started inner transactions are forced to
- fail.
-
- For the outermost transaction, restores the stream data to the point of
- the startTransaction() call. If the data stream has read corrupt data or
- any of the inner transactions was aborted, this function aborts the
- transaction.
-
- If the preceding stream operations were successful, sets the status of the
- data stream to \value ReadPastEnd.
-
- \sa startTransaction(), commitTransaction(), abortTransaction()
-*/
-
-void QDataStream::rollbackTransaction()
-{
- setStatus(ReadPastEnd);
-
- CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
- return;
-
- CHECK_STREAM_PRECOND(Q_VOID)
- if (q_status == ReadPastEnd)
- dev->rollbackTransaction();
- else
- dev->commitTransaction();
-}
-
-/*!
- \since 5.7
-
- Aborts a read transaction.
-
- This function is commonly used to discard the transaction after
- higher-level protocol errors or loss of stream synchronization.
-
- If called on an inner transaction, aborting is delegated to the outermost
- transaction, and subsequently started inner transactions are forced to
- fail.
-
- For the outermost transaction, discards the restoration point and any
- internally duplicated data of the stream. Will not affect the current
- read position of the stream.
-
- Sets the status of the data stream to \value ReadCorruptData.
-
- \sa startTransaction(), commitTransaction(), rollbackTransaction()
-*/
-
-void QDataStream::abortTransaction()
-{
- q_status = ReadCorruptData;
-
- CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
- return;
-
- CHECK_STREAM_PRECOND(Q_VOID)
- dev->commitTransaction();
-}
-
-/*****************************************************************************
- QDataStream read functions
- *****************************************************************************/
-
-/*!
- \internal
-*/
-
-int QDataStream::readBlock(char *data, int len)
-{
- // Disable reads on failure in transacted stream
- if (q_status != Ok && dev->isTransactionStarted())
- return -1;
-
- const int readResult = dev->read(data, len);
- if (readResult != len)
- setStatus(ReadPastEnd);
- return readResult;
-}
-
-/*!
- \fn QDataStream &QDataStream::operator>>(std::nullptr &ptr)
- \since 5.9
- \overload
-
- Simulates reading a \c{std::nullptr_t} from the stream into \a ptr and
- returns a reference to the stream. This function does not actually read
- anything from the stream, as \c{std::nullptr_t} values are stored as 0
- bytes.
-*/
-
-/*!
- \fn QDataStream &QDataStream::operator>>(quint8 &i)
- \overload
-
- Reads an unsigned byte from the stream into \a i, and returns a
- reference to the stream.
-*/
-
-/*!
- Reads a signed byte from the stream into \a i, and returns a
- reference to the stream.
-*/
-
-QDataStream &QDataStream::operator>>(qint8 &i)
-{
- i = 0;
- CHECK_STREAM_PRECOND(*this)
- char c;
- if (readBlock(&c, 1) == 1)
- i = qint8(c);
- return *this;
-}
-
-
-/*!
- \fn QDataStream &QDataStream::operator>>(quint16 &i)
- \overload
-
- Reads an unsigned 16-bit integer from the stream into \a i, and
- returns a reference to the stream.
-*/
-
-/*!
- \overload
-
- Reads a signed 16-bit integer from the stream into \a i, and
- returns a reference to the stream.
-*/
-
-QDataStream &QDataStream::operator>>(qint16 &i)
-{
- i = 0;
- CHECK_STREAM_PRECOND(*this)
- if (readBlock(reinterpret_cast<char *>(&i), 2) != 2) {
- i = 0;
- } else {
- if (!noswap) {
- i = qbswap(i);
- }
- }
- return *this;
-}
-
-
-/*!
- \fn QDataStream &QDataStream::operator>>(quint32 &i)
- \overload
-
- Reads an unsigned 32-bit integer from the stream into \a i, and
- returns a reference to the stream.
-*/
-
-/*!
- \overload
-
- Reads a signed 32-bit integer from the stream into \a i, and
- returns a reference to the stream.
-*/
-
-QDataStream &QDataStream::operator>>(qint32 &i)
-{
- i = 0;
- CHECK_STREAM_PRECOND(*this)
- if (readBlock(reinterpret_cast<char *>(&i), 4) != 4) {
- i = 0;
- } else {
- if (!noswap) {
- i = qbswap(i);
- }
- }
- return *this;
-}
-
-/*!
- \fn QDataStream &QDataStream::operator>>(quint64 &i)
- \overload
-
- Reads an unsigned 64-bit integer from the stream, into \a i, and
- returns a reference to the stream.
-*/
-
-/*!
- \overload
-
- Reads a signed 64-bit integer from the stream into \a i, and
- returns a reference to the stream.
-*/
-
-QDataStream &QDataStream::operator>>(qint64 &i)
-{
- i = qint64(0);
- CHECK_STREAM_PRECOND(*this)
- if (version() < 6) {
- quint32 i1, i2;
- *this >> i2 >> i1;
- i = ((quint64)i1 << 32) + i2;
- } else {
- if (readBlock(reinterpret_cast<char *>(&i), 8) != 8) {
- i = qint64(0);
- } else {
- if (!noswap) {
- i = qbswap(i);
- }
- }
- }
- return *this;
-}
-
-/*!
- Reads a boolean value from the stream into \a i. Returns a
- reference to the stream.
-*/
-QDataStream &QDataStream::operator>>(bool &i)
-{
- qint8 v;
- *this >> v;
- i = !!v;
- return *this;
-}
-
-/*!
- \overload
-
- Reads a floating point number from the stream into \a f,
- using the standard IEEE 754 format. Returns a reference to the
- stream.
-
- \sa setFloatingPointPrecision()
-*/
-
-QDataStream &QDataStream::operator>>(float &f)
-{
- if (version() >= QDataStream::Qt_4_6
- && floatingPointPrecision() == QDataStream::DoublePrecision) {
- double d;
- *this >> d;
- f = d;
- return *this;
- }
-
- f = 0.0f;
- CHECK_STREAM_PRECOND(*this)
- if (readBlock(reinterpret_cast<char *>(&f), 4) != 4) {
- f = 0.0f;
- } else {
- if (!noswap) {
- union {
- float val1;
- quint32 val2;
- } x;
- x.val2 = qbswap(*reinterpret_cast<quint32 *>(&f));
- f = x.val1;
- }
- }
- return *this;
-}
-
-/*!
- \overload
-
- Reads a floating point number from the stream into \a f,
- using the standard IEEE 754 format. Returns a reference to the
- stream.
-
- \sa setFloatingPointPrecision()
-*/
-
-QDataStream &QDataStream::operator>>(double &f)
-{
- if (version() >= QDataStream::Qt_4_6
- && floatingPointPrecision() == QDataStream::SinglePrecision) {
- float d;
- *this >> d;
- f = d;
- return *this;
- }
-
- f = 0.0;
- CHECK_STREAM_PRECOND(*this)
- if (readBlock(reinterpret_cast<char *>(&f), 8) != 8) {
- f = 0.0;
- } else {
- if (!noswap) {
- union {
- double val1;
- quint64 val2;
- } x;
- x.val2 = qbswap(*reinterpret_cast<quint64 *>(&f));
- f = x.val1;
- }
- }
- return *this;
-}
-
-
-/*!
- \overload
- \since 5.9
-
- Reads a floating point number from the stream into \a f,
- using the standard IEEE 754 format. Returns a reference to the
- stream.
-*/
-QDataStream &QDataStream::operator>>(qfloat16 &f)
-{
- return *this >> reinterpret_cast<qint16&>(f);
-}
-
-
-/*!
- \overload
-
- Reads the '\\0'-terminated string \a s from the stream and returns
- a reference to the stream.
-
- The string is deserialized using \c{readBytes()}.
-
- Space for the string is allocated using \c{new []} -- the caller must
- destroy it with \c{delete []}.
-
- \sa readBytes(), readRawData()
-*/
-
-QDataStream &QDataStream::operator>>(char *&s)
-{
- uint len = 0;
- return readBytes(s, len);
-}
-
-
-/*!
- Reads the buffer \a s from the stream and returns a reference to
- the stream.
-
- The buffer \a s is allocated using \c{new []}. Destroy it with the
- \c{delete []} operator.
-
- The \a l parameter is set to the length of the buffer. If the
- string read is empty, \a l is set to 0 and \a s is set to
- a null pointer.
-
- The serialization format is a quint32 length specifier first,
- then \a l bytes of data.
-
- \sa readRawData(), writeBytes()
-*/
-
-QDataStream &QDataStream::readBytes(char *&s, uint &l)
-{
- s = 0;
- l = 0;
- CHECK_STREAM_PRECOND(*this)
-
- quint32 len;
- *this >> len;
- if (len == 0)
- return *this;
-
- const quint32 Step = 1024 * 1024;
- quint32 allocated = 0;
- char *prevBuf = 0;
- char *curBuf = 0;
-
- do {
- int blockSize = qMin(Step, len - allocated);
- prevBuf = curBuf;
- curBuf = new char[allocated + blockSize + 1];
- if (prevBuf) {
- memcpy(curBuf, prevBuf, allocated);
- delete [] prevBuf;
- }
- if (readBlock(curBuf + allocated, blockSize) != blockSize) {
- delete [] curBuf;
- return *this;
- }
- allocated += blockSize;
- } while (allocated < len);
-
- s = curBuf;
- s[len] = '\0';
- l = (uint)len;
- return *this;
-}
-
-/*!
- Reads at most \a len bytes from the stream into \a s and returns the number of
- bytes read. If an error occurs, this function returns -1.
-
- The buffer \a s must be preallocated. The data is \e not encoded.
-
- \sa readBytes(), QIODevice::read(), writeRawData()
-*/
-
-int QDataStream::readRawData(char *s, int len)
-{
- CHECK_STREAM_PRECOND(-1)
- return readBlock(s, len);
-}
-
-
-/*****************************************************************************
- QDataStream write functions
- *****************************************************************************/
-
-/*!
- \fn QDataStream &QDataStream::operator<<(std::nullptr ptr)
- \since 5.9
- \overload
-
- Simulates writing a \c{std::nullptr_t}, \a ptr, to the stream and returns a
- reference to the stream. This function does not actually write anything to
- the stream, as \c{std::nullptr_t} values are stored as 0 bytes.
-*/
-
-/*!
- \fn QDataStream &QDataStream::operator<<(quint8 i)
- \overload
-
- Writes an unsigned byte, \a i, to the stream and returns a
- reference to the stream.
-*/
-
-/*!
- Writes a signed byte, \a i, to the stream and returns a reference
- to the stream.
-*/
-
-QDataStream &QDataStream::operator<<(qint8 i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (!dev->putChar(i))
- q_status = WriteFailed;
- return *this;
-}
-
-
-/*!
- \fn QDataStream &QDataStream::operator<<(quint16 i)
- \overload
-
- Writes an unsigned 16-bit integer, \a i, to the stream and returns
- a reference to the stream.
-*/
-
-/*!
- \overload
-
- Writes a signed 16-bit integer, \a i, to the stream and returns a
- reference to the stream.
-*/
-
-QDataStream &QDataStream::operator<<(qint16 i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (!noswap) {
- i = qbswap(i);
- }
- if (dev->write((char *)&i, sizeof(qint16)) != sizeof(qint16))
- q_status = WriteFailed;
- return *this;
-}
-
-/*!
- \overload
-
- Writes a signed 32-bit integer, \a i, to the stream and returns a
- reference to the stream.
-*/
-
-QDataStream &QDataStream::operator<<(qint32 i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (!noswap) {
- i = qbswap(i);
- }
- if (dev->write((char *)&i, sizeof(qint32)) != sizeof(qint32))
- q_status = WriteFailed;
- return *this;
-}
-
-/*!
- \fn QDataStream &QDataStream::operator<<(quint64 i)
- \overload
-
- Writes an unsigned 64-bit integer, \a i, to the stream and returns a
- reference to the stream.
-*/
-
-/*!
- \overload
-
- Writes a signed 64-bit integer, \a i, to the stream and returns a
- reference to the stream.
-*/
-
-QDataStream &QDataStream::operator<<(qint64 i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (version() < 6) {
- quint32 i1 = i & 0xffffffff;
- quint32 i2 = i >> 32;
- *this << i2 << i1;
- } else {
- if (!noswap) {
- i = qbswap(i);
- }
- if (dev->write((char *)&i, sizeof(qint64)) != sizeof(qint64))
- q_status = WriteFailed;
- }
- return *this;
-}
-
-/*!
- \fn QDataStream &QDataStream::operator<<(quint32 i)
- \overload
-
- Writes an unsigned integer, \a i, to the stream as a 32-bit
- unsigned integer (quint32). Returns a reference to the stream.
-*/
-
-/*!
- Writes a boolean value, \a i, to the stream. Returns a reference
- to the stream.
-*/
-
-QDataStream &QDataStream::operator<<(bool i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (!dev->putChar(qint8(i)))
- q_status = WriteFailed;
- return *this;
-}
-
-/*!
- \overload
-
- Writes a floating point number, \a f, to the stream using
- the standard IEEE 754 format. Returns a reference to the stream.
-
- \sa setFloatingPointPrecision()
-*/
-
-QDataStream &QDataStream::operator<<(float f)
-{
- if (version() >= QDataStream::Qt_4_6
- && floatingPointPrecision() == QDataStream::DoublePrecision) {
- *this << double(f);
- return *this;
- }
-
- CHECK_STREAM_WRITE_PRECOND(*this)
- float g = f; // fixes float-on-stack problem
- if (!noswap) {
- union {
- float val1;
- quint32 val2;
- } x;
- x.val1 = g;
- x.val2 = qbswap(x.val2);
-
- if (dev->write((char *)&x.val2, sizeof(float)) != sizeof(float))
- q_status = WriteFailed;
- return *this;
- }
-
- if (dev->write((char *)&g, sizeof(float)) != sizeof(float))
- q_status = WriteFailed;
- return *this;
-}
-
-
-/*!
- \overload
-
- Writes a floating point number, \a f, to the stream using
- the standard IEEE 754 format. Returns a reference to the stream.
-
- \sa setFloatingPointPrecision()
-*/
-
-QDataStream &QDataStream::operator<<(double f)
-{
- if (version() >= QDataStream::Qt_4_6
- && floatingPointPrecision() == QDataStream::SinglePrecision) {
- *this << float(f);
- return *this;
- }
-
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (noswap) {
- if (dev->write((char *)&f, sizeof(double)) != sizeof(double))
- q_status = WriteFailed;
- } else {
- union {
- double val1;
- quint64 val2;
- } x;
- x.val1 = f;
- x.val2 = qbswap(x.val2);
- if (dev->write((char *)&x.val2, sizeof(double)) != sizeof(double))
- q_status = WriteFailed;
- }
- return *this;
-}
-
-
-/*!
- \fn QDataStream &QDataStream::operator<<(qfloat16 f)
- \overload
- \since 5.9
-
- Writes a floating point number, \a f, to the stream using
- the standard IEEE 754 format. Returns a reference to the stream.
-*/
-QDataStream &QDataStream::operator<<(qfloat16 f)
-{
- return *this << reinterpret_cast<qint16&>(f);
-}
-
-/*!
- \overload
-
- Writes the '\\0'-terminated string \a s to the stream and returns a
- reference to the stream.
-
- The string is serialized using \c{writeBytes()}.
-
- \sa writeBytes(), writeRawData()
-*/
-
-QDataStream &QDataStream::operator<<(const char *s)
-{
- if (!s) {
- *this << (quint32)0;
- return *this;
- }
- uint len = qstrlen(s) + 1; // also write null terminator
- *this << (quint32)len; // write length specifier
- writeRawData(s, len);
- return *this;
-}
-
-/*!
- Writes the length specifier \a len and the buffer \a s to the
- stream and returns a reference to the stream.
-
- The \a len is serialized as a quint32, followed by \a len bytes
- from \a s. Note that the data is \e not encoded.
-
- \sa writeRawData(), readBytes()
-*/
-
-QDataStream &QDataStream::writeBytes(const char *s, uint len)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- *this << (quint32)len; // write length specifier
- if (len)
- writeRawData(s, len);
- return *this;
-}
-
-
-/*!
- Writes \a len bytes from \a s to the stream. Returns the
- number of bytes actually written, or -1 on error.
- The data is \e not encoded.
-
- \sa writeBytes(), QIODevice::write(), readRawData()
-*/
-
-int QDataStream::writeRawData(const char *s, int len)
-{
- CHECK_STREAM_WRITE_PRECOND(-1)
- int ret = dev->write(s, len);
- if (ret != len)
- q_status = WriteFailed;
- return ret;
-}
-
-/*!
- \since 4.1
-
- Skips \a len bytes from the device. Returns the number of bytes
- actually skipped, or -1 on error.
-
- This is equivalent to calling readRawData() on a buffer of length
- \a len and ignoring the buffer.
-
- \sa QIODevice::seek()
-*/
-int QDataStream::skipRawData(int len)
-{
- CHECK_STREAM_PRECOND(-1)
-
- if (dev->isSequential()) {
- char buf[4096];
- int sumRead = 0;
-
- while (len > 0) {
- int blockSize = qMin(len, (int)sizeof(buf));
- int n = readBlock(buf, blockSize);
- if (n == -1)
- return -1;
- if (n == 0)
- return sumRead;
-
- sumRead += n;
- len -= blockSize;
- }
- return sumRead;
- } else {
- qint64 pos = dev->pos();
- qint64 size = dev->size();
- if (pos + len > size)
- len = size - pos;
- if (!dev->seek(pos + len))
- return -1;
- return len;
- }
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DATASTREAM
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
deleted file mode 100644
index 575607e147..0000000000
--- a/src/corelib/io/qdatastream.h
+++ /dev/null
@@ -1,464 +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 QDATASTREAM_H
-#define QDATASTREAM_H
-
-#include <QtCore/qscopedpointer.h>
-#include <QtCore/qiodevice.h>
-#include <QtCore/qpair.h>
-
-#ifdef Status
-#error qdatastream.h must be included before any header file that defines Status
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class qfloat16;
-class QByteArray;
-class QIODevice;
-
-template <typename T> class QList;
-template <typename T> class QLinkedList;
-template <typename T> class QVector;
-template <typename T> class QSet;
-template <class Key, class T> class QHash;
-template <class Key, class T> class QMap;
-
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
-class QDataStreamPrivate;
-namespace QtPrivate {
-class StreamStateSaver;
-}
-class Q_CORE_EXPORT QDataStream
-{
-public:
- enum Version {
- Qt_1_0 = 1,
- Qt_2_0 = 2,
- Qt_2_1 = 3,
- Qt_3_0 = 4,
- Qt_3_1 = 5,
- Qt_3_3 = 6,
- Qt_4_0 = 7,
- Qt_4_1 = Qt_4_0,
- Qt_4_2 = 8,
- Qt_4_3 = 9,
- Qt_4_4 = 10,
- Qt_4_5 = 11,
- Qt_4_6 = 12,
- Qt_4_7 = Qt_4_6,
- Qt_4_8 = Qt_4_7,
- Qt_4_9 = Qt_4_8,
- Qt_5_0 = 13,
- Qt_5_1 = 14,
- Qt_5_2 = 15,
- Qt_5_3 = Qt_5_2,
- Qt_5_4 = 16,
- Qt_5_5 = Qt_5_4,
- Qt_5_6 = 17,
- Qt_5_7 = Qt_5_6,
- Qt_5_8 = Qt_5_7,
- Qt_5_9 = Qt_5_8,
-#if QT_VERSION >= 0x050a00
-#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
-#endif
- Qt_DefaultCompiledVersion = Qt_5_9
- };
-
- enum ByteOrder {
- BigEndian = QSysInfo::BigEndian,
- LittleEndian = QSysInfo::LittleEndian
- };
-
- enum Status {
- Ok,
- ReadPastEnd,
- ReadCorruptData,
- WriteFailed
- };
-
- enum FloatingPointPrecision {
- SinglePrecision,
- DoublePrecision
- };
-
- QDataStream();
- explicit QDataStream(QIODevice *);
- QDataStream(QByteArray *, QIODevice::OpenMode flags);
- QDataStream(const QByteArray &);
- ~QDataStream();
-
- QIODevice *device() const;
- void setDevice(QIODevice *);
- void unsetDevice();
-
- bool atEnd() const;
-
- Status status() const;
- void setStatus(Status status);
- void resetStatus();
-
- FloatingPointPrecision floatingPointPrecision() const;
- void setFloatingPointPrecision(FloatingPointPrecision precision);
-
- ByteOrder byteOrder() const;
- void setByteOrder(ByteOrder);
-
- int version() const;
- void setVersion(int);
-
- QDataStream &operator>>(qint8 &i);
- QDataStream &operator>>(quint8 &i);
- QDataStream &operator>>(qint16 &i);
- QDataStream &operator>>(quint16 &i);
- QDataStream &operator>>(qint32 &i);
- QDataStream &operator>>(quint32 &i);
- QDataStream &operator>>(qint64 &i);
- QDataStream &operator>>(quint64 &i);
- QDataStream &operator>>(std::nullptr_t &ptr) { ptr = nullptr; return *this; }
-
- QDataStream &operator>>(bool &i);
- QDataStream &operator>>(qfloat16 &f);
- QDataStream &operator>>(float &f);
- QDataStream &operator>>(double &f);
- QDataStream &operator>>(char *&str);
-
- QDataStream &operator<<(qint8 i);
- QDataStream &operator<<(quint8 i);
- QDataStream &operator<<(qint16 i);
- QDataStream &operator<<(quint16 i);
- QDataStream &operator<<(qint32 i);
- QDataStream &operator<<(quint32 i);
- QDataStream &operator<<(qint64 i);
- QDataStream &operator<<(quint64 i);
- QDataStream &operator<<(std::nullptr_t) { return *this; }
- QDataStream &operator<<(bool i);
- QDataStream &operator<<(qfloat16 f);
- QDataStream &operator<<(float f);
- QDataStream &operator<<(double f);
- QDataStream &operator<<(const char *str);
-
- QDataStream &readBytes(char *&, uint &len);
- int readRawData(char *, int len);
-
- QDataStream &writeBytes(const char *, uint len);
- int writeRawData(const char *, int len);
-
- int skipRawData(int len);
-
- void startTransaction();
- bool commitTransaction();
- void rollbackTransaction();
- void abortTransaction();
-
-private:
- Q_DISABLE_COPY(QDataStream)
-
- QScopedPointer<QDataStreamPrivate> d;
-
- QIODevice *dev;
- bool owndev;
- bool noswap;
- ByteOrder byteorder;
- int ver;
- Status q_status;
-
- int readBlock(char *data, int len);
- friend class QtPrivate::StreamStateSaver;
-};
-
-namespace QtPrivate {
-
-class StreamStateSaver
-{
-public:
- inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status())
- {
- if (!stream->dev || !stream->dev->isTransactionStarted())
- stream->resetStatus();
- }
- inline ~StreamStateSaver()
- {
- if (oldStatus != QDataStream::Ok) {
- stream->resetStatus();
- stream->setStatus(oldStatus);
- }
- }
-
-private:
- QDataStream *stream;
- QDataStream::Status oldStatus;
-};
-
-template <typename Container>
-QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
-{
- StreamStateSaver stateSaver(&s);
-
- c.clear();
- quint32 n;
- s >> n;
- c.reserve(n);
- for (quint32 i = 0; i < n; ++i) {
- typename Container::value_type t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- c.clear();
- break;
- }
- c.append(t);
- }
-
- return s;
-}
-
-template <typename Container>
-QDataStream &readListBasedContainer(QDataStream &s, Container &c)
-{
- StreamStateSaver stateSaver(&s);
-
- c.clear();
- quint32 n;
- s >> n;
- for (quint32 i = 0; i < n; ++i) {
- typename Container::value_type t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- c.clear();
- break;
- }
- c << t;
- }
-
- return s;
-}
-
-template <typename Container>
-QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
-{
- StreamStateSaver stateSaver(&s);
-
- c.clear();
- quint32 n;
- s >> n;
- for (quint32 i = 0; i < n; ++i) {
- typename Container::key_type k;
- typename Container::mapped_type t;
- s >> k >> t;
- if (s.status() != QDataStream::Ok) {
- c.clear();
- break;
- }
- c.insertMulti(k, t);
- }
-
- return s;
-}
-
-template <typename Container>
-QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
-{
- s << quint32(c.size());
- for (const typename Container::value_type &t : c)
- s << t;
-
- return s;
-}
-
-template <typename Container>
-QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
-{
- s << quint32(c.size());
- // Deserialization should occur in the reverse order.
- // Otherwise, value() will return the least recently inserted
- // value instead of the most recently inserted one.
- auto it = c.constEnd();
- auto begin = c.constBegin();
- while (it != begin) {
- --it;
- s << it.key() << it.value();
- }
-
- return s;
-}
-
-} // QtPrivate namespace
-
-/*****************************************************************************
- QDataStream inline functions
- *****************************************************************************/
-
-inline QIODevice *QDataStream::device() const
-{ return dev; }
-
-inline QDataStream::ByteOrder QDataStream::byteOrder() const
-{ return byteorder; }
-
-inline int QDataStream::version() const
-{ return ver; }
-
-inline void QDataStream::setVersion(int v)
-{ ver = v; }
-
-inline QDataStream &QDataStream::operator>>(quint8 &i)
-{ return *this >> reinterpret_cast<qint8&>(i); }
-
-inline QDataStream &QDataStream::operator>>(quint16 &i)
-{ return *this >> reinterpret_cast<qint16&>(i); }
-
-inline QDataStream &QDataStream::operator>>(quint32 &i)
-{ return *this >> reinterpret_cast<qint32&>(i); }
-
-inline QDataStream &QDataStream::operator>>(quint64 &i)
-{ return *this >> reinterpret_cast<qint64&>(i); }
-
-inline QDataStream &QDataStream::operator<<(quint8 i)
-{ return *this << qint8(i); }
-
-inline QDataStream &QDataStream::operator<<(quint16 i)
-{ return *this << qint16(i); }
-
-inline QDataStream &QDataStream::operator<<(quint32 i)
-{ return *this << qint32(i); }
-
-inline QDataStream &QDataStream::operator<<(quint64 i)
-{ return *this << qint64(i); }
-
-template <typename Enum>
-inline QDataStream &operator<<(QDataStream &s, QFlags<Enum> e)
-{ return s << e.i; }
-
-template <typename Enum>
-inline QDataStream &operator>>(QDataStream &s, QFlags<Enum> &e)
-{ return s >> e.i; }
-
-template <typename T>
-inline QDataStream &operator>>(QDataStream &s, QList<T> &l)
-{
- return QtPrivate::readArrayBasedContainer(s, l);
-}
-
-template <typename T>
-inline QDataStream &operator<<(QDataStream &s, const QList<T> &l)
-{
- return QtPrivate::writeSequentialContainer(s, l);
-}
-
-template <typename T>
-inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l)
-{
- return QtPrivate::readListBasedContainer(s, l);
-}
-
-template <typename T>
-inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l)
-{
- return QtPrivate::writeSequentialContainer(s, l);
-}
-
-template<typename T>
-inline QDataStream &operator>>(QDataStream &s, QVector<T> &v)
-{
- return QtPrivate::readArrayBasedContainer(s, v);
-}
-
-template<typename T>
-inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v)
-{
- return QtPrivate::writeSequentialContainer(s, v);
-}
-
-template <typename T>
-inline QDataStream &operator>>(QDataStream &s, QSet<T> &set)
-{
- return QtPrivate::readListBasedContainer(s, set);
-}
-
-template <typename T>
-inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set)
-{
- return QtPrivate::writeSequentialContainer(s, set);
-}
-
-template <class Key, class T>
-inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
-{
- return QtPrivate::readAssociativeContainer(s, hash);
-}
-
-template <class Key, class T>
-inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
-{
- return QtPrivate::writeAssociativeContainer(s, hash);
-}
-
-template <class Key, class T>
-inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
-{
- return QtPrivate::readAssociativeContainer(s, map);
-}
-
-template <class Key, class T>
-inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
-{
- return QtPrivate::writeAssociativeContainer(s, map);
-}
-
-#ifndef QT_NO_DATASTREAM
-template <class T1, class T2>
-inline QDataStream& operator>>(QDataStream& s, QPair<T1, T2>& p)
-{
- s >> p.first >> p.second;
- return s;
-}
-
-template <class T1, class T2>
-inline QDataStream& operator<<(QDataStream& s, const QPair<T1, T2>& p)
-{
- s << p.first << p.second;
- return s;
-}
-#endif
-
-#endif // QT_NO_DATASTREAM
-
-QT_END_NAMESPACE
-
-#endif // QDATASTREAM_H
diff --git a/src/corelib/io/qdatastream_p.h b/src/corelib/io/qdatastream_p.h
deleted file mode 100644
index 3ca0ae840e..0000000000
--- a/src/corelib/io/qdatastream_p.h
+++ /dev/null
@@ -1,73 +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 QDATASTREAM_P_H
-#define QDATASTREAM_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 <qdatastream.h>
-
-QT_BEGIN_NAMESPACE
-
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
-class QDataStreamPrivate
-{
-public:
- QDataStreamPrivate() : floatingPointPrecision(QDataStream::DoublePrecision),
- transactionDepth(0) { }
-
- QDataStream::FloatingPointPrecision floatingPointPrecision;
- int transactionDepth;
-};
-#endif
-
-QT_END_NAMESPACE
-
-#endif // QDATASTREAM_P_H
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index be33ec2d23..0d9a6c8749 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -121,15 +121,15 @@ using QtMiscUtils::fromHex;
*/
/*!
- \fn QDebug::QDebug(QtMsgType type)
+ \fn QDebug::QDebug(QtMsgType t)
- Constructs a debug stream that writes to the handler for the message type specified by \a type.
+ Constructs a debug stream that writes to the handler for the message type \a t.
*/
/*!
- \fn QDebug::QDebug(const QDebug &other)
+ \fn QDebug::QDebug(const QDebug &o)
- Constructs a copy of the \a other debug stream.
+ Constructs a copy of the other debug stream \a o.
*/
/*!
@@ -501,79 +501,79 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug &QDebug::operator<<(signed short i)
+ \fn QDebug &QDebug::operator<<(signed short t)
- Writes the signed short integer, \a i, to the stream and returns a reference
+ Writes the signed short integer, \a t, to the stream and returns a reference
to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(unsigned short i)
+ \fn QDebug &QDebug::operator<<(unsigned short t)
- Writes then unsigned short integer, \a i, to the stream and returns a
+ Writes then unsigned short integer, \a t, to the stream and returns a
reference to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(signed int i)
+ \fn QDebug &QDebug::operator<<(signed int t)
- Writes the signed integer, \a i, to the stream and returns a reference
+ Writes the signed integer, \a t, to the stream and returns a reference
to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(unsigned int i)
+ \fn QDebug &QDebug::operator<<(unsigned int t)
- Writes then unsigned integer, \a i, to the stream and returns a reference to
+ Writes then unsigned integer, \a t, to the stream and returns a reference to
the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(signed long l)
+ \fn QDebug &QDebug::operator<<(signed long t)
- Writes the signed long integer, \a l, to the stream and returns a reference
+ Writes the signed long integer, \a t, to the stream and returns a reference
to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(unsigned long l)
+ \fn QDebug &QDebug::operator<<(unsigned long t)
- Writes then unsigned long integer, \a l, to the stream and returns a reference
+ Writes then unsigned long integer, \a t, to the stream and returns a reference
to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(qint64 i)
+ \fn QDebug &QDebug::operator<<(qint64 t)
- Writes the signed 64-bit integer, \a i, to the stream and returns a reference
+ Writes the signed 64-bit integer, \a t, to the stream and returns a reference
to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(quint64 i)
+ \fn QDebug &QDebug::operator<<(quint64 t)
- Writes then unsigned 64-bit integer, \a i, to the stream and returns a
+ Writes then unsigned 64-bit integer, \a t, to the stream and returns a
reference to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(float f)
+ \fn QDebug &QDebug::operator<<(float t)
- Writes the 32-bit floating point number, \a f, to the stream and returns a
+ Writes the 32-bit floating point number, \a t, to the stream and returns a
reference to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(double f)
+ \fn QDebug &QDebug::operator<<(double t)
- Writes the 64-bit floating point number, \a f, to the stream and returns a
+ Writes the 64-bit floating point number, \a t, to the stream and returns a
reference to the stream.
*/
/*!
- \fn QDebug &QDebug::operator<<(const char *s)
+ \fn QDebug &QDebug::operator<<(const char *t)
- Writes the '\\0'-terminated string, \a s, to the stream and returns a
+ Writes the '\\0'-terminated string, \a t, to the stream and returns a
reference to the stream. The string is never quoted nor transformed to the
output, but note that some QDebug backends might not be 8-bit clean.
*/
@@ -595,9 +595,9 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug &QDebug::operator<<(const QString &s)
+ \fn QDebug &QDebug::operator<<(const QString &t)
- Writes the string, \a s, to the stream and returns a reference to the
+ Writes the string, \a t, 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).
@@ -634,9 +634,9 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug &QDebug::operator<<(const QStringRef &s)
+ \fn QDebug &QDebug::operator<<(const QStringRef &t)
- Writes the string, \a s, to the stream and returns a reference to the
+ Writes the string, \a t, 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).
@@ -648,9 +648,10 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug &QDebug::operator<<(QLatin1String s)
+ \since 5.10
+ \fn QDebug &QDebug::operator<<(QStringView s)
- Writes the string, \a s, to the stream and returns a reference to the
+ 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).
@@ -662,9 +663,23 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug &QDebug::operator<<(const QByteArray &b)
+ \fn QDebug &QDebug::operator<<(QLatin1String t)
- Writes the byte array, \a b, to the stream and returns a reference to the
+ Writes the string, \a t, 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<<(const QByteArray &t)
+
+ Writes the byte array, \a t, to the stream and returns a reference to the
stream. Normally, QDebug prints the array inside quotes and transforms
control or non-US-ASCII characters to their C escape sequences (\\xAB). This
way, the output is always 7-bit clean and the string can be copied from the
@@ -701,9 +716,9 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug &QDebug::operator<<(const void *p)
+ \fn QDebug &QDebug::operator<<(const void *t)
- Writes a pointer, \a p, to the stream and returns a reference to the stream.
+ Writes a pointer, \a t, to the stream and returns a reference to the stream.
*/
/*!
@@ -717,99 +732,99 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn QDebug operator<<(QDebug stream, const QList<T> &list)
+ \fn template <class T> QDebug operator<<(QDebug debug, const QList<T> &list)
\relates QDebug
- Writes the contents of \a list to \a stream. \c T needs to
+ Writes the contents of \a list to \a debug. \c T needs to
support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const std::list<T, Alloc> &list)
+ \fn template <typename T, typename Alloc> QDebug operator<<(QDebug debug, const std::list<T, Alloc> &vec)
\relates QDebug
\since 5.7
- Writes the contents of \a list to \a stream. \c T needs to
+ Writes the contents of list \a vec to \a debug. \c T needs to
support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const QVector<T> &vector)
+ \fn template <typename T> QDebug operator<<(QDebug debug, const QVector<T> &vec)
\relates QDebug
- Writes the contents of \a vector to \a stream. \c T needs to
+ Writes the contents of vector \a vec to \a debug. \c T needs to
support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const std::vector<T, Alloc> &vector)
+ \fn template <typename T, typename Alloc> QDebug operator<<(QDebug debug, const std::vector<T, Alloc> &vec)
\relates QDebug
\since 5.7
- Writes the contents of \a vector to \a stream. \c T needs to
+ Writes the contents of vector \a vec to \a debug. \c T needs to
support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const QSet<T> &set)
+ \fn template <typename T> QDebug operator<<(QDebug debug, const QSet<T> &set)
\relates QDebug
- Writes the contents of \a set to \a stream. \c T needs to
+ Writes the contents of \a set to \a debug. \c T needs to
support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const QMap<Key, T> &map)
+ \fn template <class Key, class T> QDebug operator<<(QDebug debug, const QMap<Key, T> &map)
\relates QDebug
- Writes the contents of \a map to \a stream. Both \c Key and
+ Writes the contents of \a map to \a debug. Both \c Key and
\c T need to support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const std::map<Key, T, Compare, Alloc> &map)
+ \fn template <typename Key, typename T, typename Compare, typename Alloc> QDebug operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map)
\relates QDebug
\since 5.7
- Writes the contents of \a map to \a stream. Both \c Key and
+ Writes the contents of \a map to \a debug. Both \c Key and
\c T need to support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const std::multimap<Key, T, Compare, Alloc> &map)
+ \fn template <typename Key, typename T, typename Compare, typename Alloc> QDebug operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map)
\relates QDebug
\since 5.7
- Writes the contents of \a map to \a stream. Both \c Key and
+ Writes the contents of \a map to \a debug. Both \c Key and
\c T need to support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const QHash<Key, T> &hash)
+ \fn template <class Key, class T> QDebug operator<<(QDebug debug, const QHash<Key, T> &hash)
\relates QDebug
- Writes the contents of \a hash to \a stream. Both \c Key and
+ Writes the contents of \a hash to \a debug. Both \c Key and
\c T need to support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const QPair<T1, T2> &pair)
+ \fn template <class T1, class T2> QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair)
\relates QDebug
- Writes the contents of \a pair to \a stream. Both \c T1 and
+ Writes the contents of \a pair to \a debug. Both \c T1 and
\c T2 need to support streaming into QDebug.
*/
/*!
- \fn QDebug operator<<(QDebug stream, const QFlags<T> &flag)
+ \fn template<typename T> QDebug operator<<(QDebug debug, const QFlags<T> &flags)
\relates QDebug
\since 4.7
- Writes \a flag to \a stream.
+ Writes \a flags to \a debug.
*/
/*!
- \fn QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr)
+ \fn template<typename T> QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr)
\relates QSharedPointer
\since 5.7
@@ -820,6 +835,11 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \fn QDebug &QDebug::operator<<(std::nullptr_t)
+ \internal
+ */
+
+/*!
\class QDebugStateSaver
\inmodule QtCore
\brief Convenience class for custom QDebug operators
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/qdir.cpp b/src/corelib/io/qdir.cpp
index 6d144cb65d..520f98b18f 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -2087,6 +2087,7 @@ bool QDir::match(const QString &filter, const QString &fileName)
#endif // QT_NO_REGEXP
/*!
+ \internal
Returns \a path with redundant directory separators removed,
and "."s and ".."s resolved (as far as possible).
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index 64d34aec59..33b0b2eb66 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -42,12 +43,14 @@
#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"
#include "private/qfile_p.h"
#include "private/qfilesystemengine_p.h"
#include "private/qsystemerror_p.h"
+#include "private/qtemporaryfile_p.h"
#if defined(QT_BUILD_CORE_LIB)
# include "qcoreapplication.h"
#endif
@@ -420,7 +423,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);
}
/*!
@@ -500,7 +503,8 @@ bool
QFile::remove()
{
Q_D(QFile);
- if (d->fileName.isEmpty()) {
+ if (d->fileName.isEmpty() &&
+ !static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) {
qWarning("QFile::remove: Empty or null file name");
return false;
}
@@ -553,7 +557,9 @@ bool
QFile::rename(const QString &newName)
{
Q_D(QFile);
- if (d->fileName.isEmpty()) {
+
+ // if this is a QTemporaryFile, the virtual fileName() call here may do something
+ if (fileName().isEmpty()) {
qWarning("QFile::rename: Empty or null file name");
return false;
}
@@ -565,57 +571,64 @@ QFile::rename(const QString &newName)
d->setError(QFile::RenameError, tr("Source file does not exist."));
return false;
}
+
// If the file exists and it is a case-changing rename ("foo" -> "Foo"),
// compare Ids to make sure it really is a different file.
// Note: this does not take file engines into account.
+ bool changingCase = false;
QByteArray targetId = QFileSystemEngine::id(QFileSystemEntry(newName));
if (!targetId.isNull()) {
QByteArray fileId = d->fileEngine ?
d->fileEngine->id() :
QFileSystemEngine::id(QFileSystemEntry(d->fileName));
- if (fileId != targetId || d->fileName.compare(newName, Qt::CaseInsensitive)) {
- // ### Race condition. If a file is moved in after this, it /will/ be
- // overwritten. On Unix, the proper solution is to use hardlinks:
- // return ::link(old, new) && ::remove(old);
+ changingCase = (fileId == targetId && d->fileName.compare(newName, Qt::CaseInsensitive) == 0);
+ if (!changingCase) {
d->setError(QFile::RenameError, tr("Destination file exists"));
return false;
}
-#ifndef QT_NO_TEMPORARYFILE
- // This #ifndef disables the workaround it encloses. Therefore, this configuration is not recommended.
+
#ifdef Q_OS_LINUX
// rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive
// FS, such as FAT32. Move the file away and rename in 2 steps to work around.
- QTemporaryFile tempFile(d->fileName + QLatin1String(".XXXXXX"));
- tempFile.setAutoRemove(false);
- if (!tempFile.open(QIODevice::ReadWrite)) {
- d->setError(QFile::RenameError, tempFile.errorString());
- return false;
- }
- tempFile.close();
- if (!d->engine()->rename(tempFile.fileName())) {
- d->setError(QFile::RenameError, tr("Error while renaming."));
- return false;
- }
- if (tempFile.rename(newName)) {
- d->fileEngine->setFileName(newName);
- d->fileName = newName;
- return true;
- }
- d->setError(QFile::RenameError, tempFile.errorString());
- // We need to restore the original file.
- if (!tempFile.rename(d->fileName)) {
- d->setError(QFile::RenameError, errorString() + QLatin1Char('\n')
+ QTemporaryFileName tfn(d->fileName);
+ QFileSystemEntry src(d->fileName);
+ QSystemError error;
+ for (int attempt = 0; attempt < 16; ++attempt) {
+ QFileSystemEntry tmp(tfn.generateNext(), QFileSystemEntry::FromNativePath());
+
+ // rename to temporary name
+ if (!QFileSystemEngine::renameFile(src, tmp, error))
+ continue;
+
+ // rename to final name
+ if (QFileSystemEngine::renameFile(tmp, QFileSystemEntry(newName), error)) {
+ d->fileEngine->setFileName(newName);
+ d->fileName = newName;
+ return true;
+ }
+
+ // We need to restore the original file.
+ QSystemError error2;
+ if (QFileSystemEngine::renameFile(tmp, src, error2))
+ break; // report the original error, below
+
+ // report both errors
+ d->setError(QFile::RenameError,
+ tr("Error while renaming: %1").arg(error.toString())
+ + QLatin1Char('\n')
+ tr("Unable to restore from %1: %2").
- arg(QDir::toNativeSeparators(tempFile.fileName()), tempFile.errorString()));
+ arg(QDir::toNativeSeparators(tmp.filePath()), error2.toString()));
+ return false;
}
+ d->setError(QFile::RenameError,
+ tr("Error while renaming: %1").arg(error.toString()));
return false;
#endif // Q_OS_LINUX
-#endif // QT_NO_TEMPORARYFILE
}
unsetError();
close();
if(error() == QFile::NoError) {
- if (d->engine()->rename(newName)) {
+ if (changingCase ? d->engine()->renameOverwrite(newName) : d->engine()->rename(newName)) {
unsetError();
// engine was able to handle the new name so we just reset it
d->fileEngine->setFileName(newName);
@@ -707,7 +720,7 @@ bool
QFile::link(const QString &linkName)
{
Q_D(QFile);
- if (d->fileName.isEmpty()) {
+ if (fileName().isEmpty()) {
qWarning("QFile::link: Empty or null file name");
return false;
}
@@ -753,7 +766,7 @@ bool
QFile::copy(const QString &newName)
{
Q_D(QFile);
- if (d->fileName.isEmpty()) {
+ if (fileName().isEmpty()) {
qWarning("QFile::copy: Empty or null file name");
return false;
}
@@ -794,25 +807,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 (!d->engine()->cloneTo(out.d_func()->engine())) {
+ 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;
@@ -878,9 +893,9 @@ bool QFile::open(OpenMode mode)
qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
return false;
}
- if (mode & Append)
+ // Either Append or NewOnly implies WriteOnly
+ if (mode & (Append | NewOnly))
mode |= WriteOnly;
-
unsetError();
if ((mode & (ReadOnly | WriteOnly)) == 0) {
qWarning("QIODevice::open: File access not specified");
@@ -950,14 +965,17 @@ bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
return false;
}
- if (mode & Append)
+ // Either Append or NewOnly implies WriteOnly
+ if (mode & (Append | NewOnly))
mode |= WriteOnly;
unsetError();
if ((mode & (ReadOnly | WriteOnly)) == 0) {
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);
@@ -1006,14 +1024,17 @@ bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
return false;
}
- if (mode & Append)
+ // Either Append or NewOnly implies WriteOnly
+ if (mode & (Append | NewOnly))
mode |= WriteOnly;
unsetError();
if ((mode & (ReadOnly | WriteOnly)) == 0) {
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/qfile.h b/src/corelib/io/qfile.h
index a2a1b25248..e6f3d942fe 100644
--- a/src/corelib/io/qfile.h
+++ b/src/corelib/io/qfile.h
@@ -70,7 +70,7 @@ public:
#endif
~QFile();
- QString fileName() const Q_DECL_OVERRIDE;
+ QString fileName() const override;
void setFileName(const QString &name);
#if defined(Q_OS_DARWIN)
@@ -81,6 +81,7 @@ public:
}
static QString decodeName(const QByteArray &localFileName)
{
+ // note: duplicated in qglobal.cpp (qEnvironmentVariable)
return QString::fromUtf8(localFileName).normalized(QString::NormalizationForm_C);
}
#else
@@ -123,25 +124,25 @@ public:
bool copy(const QString &newName);
static bool copy(const QString &fileName, const QString &newName);
- bool open(OpenMode flags) Q_DECL_OVERRIDE;
+ bool open(OpenMode flags) override;
bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
- qint64 size() const Q_DECL_OVERRIDE;
+ qint64 size() const override;
- bool resize(qint64 sz) Q_DECL_OVERRIDE;
+ bool resize(qint64 sz) override;
static bool resize(const QString &filename, qint64 sz);
- Permissions permissions() const Q_DECL_OVERRIDE;
+ Permissions permissions() const override;
static Permissions permissions(const QString &filename);
- bool setPermissions(Permissions permissionSpec) Q_DECL_OVERRIDE;
+ bool setPermissions(Permissions permissionSpec) override;
static bool setPermissions(const QString &filename, Permissions permissionSpec);
protected:
#ifdef QT_NO_QOBJECT
QFile(QFilePrivate &dd);
#else
- QFile(QFilePrivate &dd, QObject *parent = Q_NULLPTR);
+ QFile(QFilePrivate &dd, QObject *parent = nullptr);
#endif
private:
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index f50949e6c1..2f99775c65 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -740,6 +740,76 @@ bool QFileDevice::unmap(uchar *address)
return false;
}
+/*!
+ \enum QFileDevice::FileTime
+ \since 5.10
+
+ This enum is used by the fileTime() and setFileTime() functions.
+
+ \value FileAccessTime When the file was most recently accessed
+ (e.g. read or written to).
+ \value FileBirthTime When the file was created (may not be not
+ supported on UNIX).
+ \value FileMetadataChangeTime When the file's metadata was last changed.
+ \value FileModificationTime When the file was most recently modified.
+
+ \sa setFileTime(), fileTime(), QFileInfo::fileTime()
+*/
+
+static inline QAbstractFileEngine::FileTime FileDeviceTimeToAbstractFileEngineTime(QFileDevice::FileTime time)
+{
+ Q_STATIC_ASSERT(int(QFileDevice::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
+ Q_STATIC_ASSERT(int(QFileDevice::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
+ Q_STATIC_ASSERT(int(QFileDevice::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
+ Q_STATIC_ASSERT(int(QFileDevice::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
+ return QAbstractFileEngine::FileTime(time);
+}
+
+/*!
+ \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..af41bec2f6 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,13 @@ public:
CopyError = 14
};
+ enum FileTime {
+ FileAccessTime,
+ FileBirthTime,
+ FileMetadataChangeTime,
+ FileModificationTime
+ };
+
enum Permission {
ReadOwner = 0x4000, WriteOwner = 0x2000, ExeOwner = 0x1000,
ReadUser = 0x0400, WriteUser = 0x0200, ExeUser = 0x0100,
@@ -92,19 +100,19 @@ public:
FileError error() const;
void unsetError();
- virtual void close() Q_DECL_OVERRIDE;
+ virtual void close() override;
- bool isSequential() const Q_DECL_OVERRIDE;
+ bool isSequential() const override;
int handle() const;
virtual QString fileName() const;
- qint64 pos() const Q_DECL_OVERRIDE;
- bool seek(qint64 offset) Q_DECL_OVERRIDE;
- bool atEnd() const Q_DECL_OVERRIDE;
+ qint64 pos() const override;
+ bool seek(qint64 offset) override;
+ bool atEnd() const override;
bool flush();
- qint64 size() const Q_DECL_OVERRIDE;
+ qint64 size() const override;
virtual bool resize(qint64 sz);
virtual Permissions permissions() const;
@@ -119,18 +127,21 @@ 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
QFileDevice(QFileDevicePrivate &dd);
#else
explicit QFileDevice(QObject *parent);
- QFileDevice(QFileDevicePrivate &dd, QObject *parent = Q_NULLPTR);
+ QFileDevice(QFileDevicePrivate &dd, QObject *parent = nullptr);
#endif
- qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
- qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE;
- qint64 readLineData(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
+ qint64 readLineData(char *data, qint64 maxlen) override;
private:
Q_DISABLE_COPY(QFileDevice)
diff --git a/src/corelib/io/qfiledevice_p.h b/src/corelib/io/qfiledevice_p.h
index 60c51afb7e..47053d01b7 100644
--- a/src/corelib/io/qfiledevice_p.h
+++ b/src/corelib/io/qfiledevice_p.h
@@ -69,7 +69,7 @@ protected:
inline bool ensureFlushed() const;
- bool putCharHelper(char c) Q_DECL_OVERRIDE;
+ bool putCharHelper(char c) override;
void setError(QFileDevice::FileError err);
void setError(QFileDevice::FileError err, const QString &errorString);
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 907574b6dd..26078a6c71 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,25 @@ 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)
- cf = CachedCTime;
- else if (request == QAbstractFileEngine::ModificationTime)
- cf = CachedMTime;
- else
+
+ uint cf = 0;
+ switch (request) {
+ case QAbstractFileEngine::AccessTime:
cf = CachedATime;
+ break;
+ case QAbstractFileEngine::BirthTime:
+ cf = CachedBTime;
+ break;
+ case QAbstractFileEngine::MetadataChangeTime:
+ cf = CachedMCTime;
+ break;
+ case QAbstractFileEngine::ModificationTime:
+ cf = CachedMTime;
+ break;
+ }
+
if (!getCachedFlag(cf)) {
fileTimes[request] = fileEngine->fileTime(request);
setCachedFlag(cf);
@@ -262,8 +271,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
@@ -582,9 +591,6 @@ QString QFileInfo::absolutePath() const
if (d->isDefaultConstructed) {
return QLatin1String("");
- } else if (d->fileEntry.isEmpty()) {
- qWarning("QFileInfo::absolutePath: Constructed with empty filename");
- return QLatin1String("");
}
return d->getFileName(QAbstractFileEngine::AbsolutePathName);
}
@@ -904,14 +910,10 @@ QDir QFileInfo::absoluteDir() const
bool QFileInfo::isReadable() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserReadPermission);
- return (d->metaData.permissions() & QFile::ReadUser) != 0;
- }
- return d->getFileFlags(QAbstractFileEngine::ReadUserPerm);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::UserReadPermission,
+ [d]() { return (d->metaData.permissions() & QFile::ReadUser) != 0; },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::ReadUserPerm); });
}
/*!
@@ -925,14 +927,10 @@ bool QFileInfo::isReadable() const
bool QFileInfo::isWritable() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserWritePermission))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserWritePermission);
- return (d->metaData.permissions() & QFile::WriteUser) != 0;
- }
- return d->getFileFlags(QAbstractFileEngine::WriteUserPerm);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::UserWritePermission,
+ [d]() { return (d->metaData.permissions() & QFile::WriteUser) != 0; },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::WriteUserPerm); });
}
/*!
@@ -943,14 +941,10 @@ bool QFileInfo::isWritable() const
bool QFileInfo::isExecutable() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserExecutePermission))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserExecutePermission);
- return (d->metaData.permissions() & QFile::ExeUser) != 0;
- }
- return d->getFileFlags(QAbstractFileEngine::ExeUserPerm);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::UserExecutePermission,
+ [d]() { return (d->metaData.permissions() & QFile::ExeUser) != 0; },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::ExeUserPerm); });
}
/*!
@@ -962,14 +956,10 @@ bool QFileInfo::isExecutable() const
bool QFileInfo::isHidden() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::HiddenAttribute))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::HiddenAttribute);
- return d->metaData.isHidden();
- }
- return d->getFileFlags(QAbstractFileEngine::HiddenFlag);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::HiddenAttribute,
+ [d]() { return d->metaData.isHidden(); },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::HiddenFlag); });
}
/*!
@@ -1005,14 +995,10 @@ bool QFileInfo::isNativePath() const
bool QFileInfo::isFile() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::FileType))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::FileType);
- return d->metaData.isFile();
- }
- return d->getFileFlags(QAbstractFileEngine::FileType);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::FileType,
+ [d]() { return d->metaData.isFile(); },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::FileType); });
}
/*!
@@ -1024,14 +1010,10 @@ bool QFileInfo::isFile() const
bool QFileInfo::isDir() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::DirectoryType))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::DirectoryType);
- return d->metaData.isDirectory();
- }
- return d->getFileFlags(QAbstractFileEngine::DirectoryType);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::DirectoryType,
+ [d]() { return d->metaData.isDirectory(); },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::DirectoryType); });
}
@@ -1045,14 +1027,10 @@ bool QFileInfo::isDir() const
bool QFileInfo::isBundle() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::BundleType))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::BundleType);
- return d->metaData.isBundle();
- }
- return d->getFileFlags(QAbstractFileEngine::BundleType);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::BundleType,
+ [d]() { return d->metaData.isBundle(); },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::BundleType); });
}
/*!
@@ -1079,14 +1057,10 @@ bool QFileInfo::isBundle() const
bool QFileInfo::isSymLink() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::LegacyLinkType))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::LegacyLinkType);
- return d->metaData.isLegacyLink();
- }
- return d->getFileFlags(QAbstractFileEngine::LinkType);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::LegacyLinkType,
+ [d]() { return d->metaData.isLegacyLink(); },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); });
}
/*!
@@ -1098,7 +1072,7 @@ bool QFileInfo::isRoot() const
{
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
- return true;
+ return false;
if (d->fileEngine == 0) {
if (d->fileEntry.isRoot()) {
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
@@ -1174,14 +1148,10 @@ QString QFileInfo::owner() const
uint QFileInfo::ownerId() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return 0;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::UserId))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::UserId);
- return d->metaData.userId();
- }
- return d->fileEngine->ownerId(QAbstractFileEngine::OwnerUser);
+ return d->checkAttribute(uint(-2),
+ QFileSystemMetaData::UserId,
+ [d]() { return d->metaData.userId(); },
+ [d]() { return d->fileEngine->ownerId(QAbstractFileEngine::OwnerUser); });
}
/*!
@@ -1213,14 +1183,10 @@ QString QFileInfo::group() const
uint QFileInfo::groupId() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return 0;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::GroupId))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::GroupId);
- return d->metaData.groupId();
- }
- return d->fileEngine->ownerId(QAbstractFileEngine::OwnerGroup);
+ return d->checkAttribute(uint(-2),
+ QFileSystemMetaData::GroupId,
+ [d]() { return d->metaData.groupId(); },
+ [d]() { return d->fileEngine->ownerId(QAbstractFileEngine::OwnerGroup); });
}
/*!
@@ -1242,16 +1208,15 @@ uint QFileInfo::groupId() const
bool QFileInfo::permission(QFile::Permissions permissions) const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return false;
- if (d->fileEngine == 0) {
- // the QFileSystemMetaData::MetaDataFlag and QFile::Permissions overlap, so just static cast.
- QFileSystemMetaData::MetaDataFlag permissionFlags = static_cast<QFileSystemMetaData::MetaDataFlag>((int)permissions);
- if (!d->cache_enabled || !d->metaData.hasFlags(permissionFlags))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, permissionFlags);
- return (d->metaData.permissions() & permissions) == permissions;
- }
- return d->getFileFlags(QAbstractFileEngine::FileFlags((int)permissions)) == (uint)permissions;
+ // the QFileSystemMetaData::MetaDataFlag and QFile::Permissions overlap, so just cast.
+ auto fseFlags = QFileSystemMetaData::MetaDataFlag(int(permissions));
+ auto feFlags = QAbstractFileEngine::FileFlags(int(permissions));
+ return d->checkAttribute<bool>(
+ fseFlags,
+ [=]() { return (d->metaData.permissions() & permissions) == permissions; },
+ [=]() {
+ return d->getFileFlags(feFlags) == uint(permissions);
+ });
}
/*!
@@ -1264,14 +1229,12 @@ bool QFileInfo::permission(QFile::Permissions permissions) const
QFile::Permissions QFileInfo::permissions() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return 0;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::Permissions))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::Permissions);
- return d->metaData.permissions();
- }
- return QFile::Permissions(d->getFileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask);
+ return d->checkAttribute<QFile::Permissions>(
+ QFileSystemMetaData::Permissions,
+ [d]() { return d->metaData.permissions(); },
+ [d]() {
+ return QFile::Permissions(d->getFileFlags(QAbstractFileEngine::PermsMask) & QAbstractFileEngine::PermsMask);
+ });
}
@@ -1284,64 +1247,77 @@ QFile::Permissions QFileInfo::permissions() const
qint64 QFileInfo::size() const
{
Q_D(const QFileInfo);
- if (d->isDefaultConstructed)
- return 0;
- if (d->fileEngine == 0) {
- if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::SizeAttribute))
- QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::SizeAttribute);
- return d->metaData.size();
- }
- if (!d->getCachedFlag(QFileInfoPrivate::CachedSize)) {
- d->setCachedFlag(QFileInfoPrivate::CachedSize);
- d->fileSize = d->fileEngine->size();
- }
- return d->fileSize;
+ return d->checkAttribute<qint64>(
+ QFileSystemMetaData::SizeAttribute,
+ [d]() { return d->metaData.size(); },
+ [d]() {
+ if (!d->getCachedFlag(QFileInfoPrivate::CachedSize)) {
+ d->setCachedFlag(QFileInfoPrivate::CachedSize);
+ d->fileSize = d->fileEngine->size();
+ }
+ return d->fileSize;
+ });
}
+#if QT_DEPRECATED_SINCE(5, 10)
/*!
- Returns the date and local time when the file was created.
+ \deprecated
- On most Unix systems, this function returns the time of the last
- status change. A status change occurs when the file is created,
- but it also occurs whenever the user writes or sets inode
- information (for example, changing the file permissions).
+ Returns the date and time when the file was created, the time its metadata
+ was last changed or the time of last modification, whichever one of the
+ three is available (in that order).
- If neither creation time nor "last status change" time are not
- available, returns the same as lastModified().
+ This function is deprecated. Instead, use the birthTime() function to get
+ the time the file was created, metadataChangeTime() to get the time its
+ metadata was last changed, or lastModified() to get the time it was last modified.
- \sa lastModified(), lastRead()
+ \sa birthTime(), metadataChangeTime(), lastModified(), lastRead()
*/
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();
+ QDateTime d = fileTime(QFile::FileBirthTime);
+ if (d.isValid())
+ return d;
+ return fileTime(QFile::FileMetadataChangeTime);
+}
+#endif
+
+/*!
+ \since 5.10
+ Returns the date and time when the file was created / born.
+
+ If the file birth time is not available, this function returns an invalid
+ QDateTime.
+
+ \sa lastModified(), lastRead(), metadataChangeTime()
+*/
+QDateTime QFileInfo::birthTime() const
+{
+ return fileTime(QFile::FileBirthTime);
+}
+
+/*!
+ \since 5.10
+ Returns the date and time when the file metadata was changed. A metadata
+ change occurs when the file is created, but it also occurs whenever the
+ user writes or sets inode information (for example, changing the file
+ permissions).
+
+ \sa lastModified(), lastRead()
+*/
+QDateTime QFileInfo::metadataChangeTime() const
+{
+ return fileTime(QFile::FileMetadataChangeTime);
}
/*!
Returns the date and local time when the file was last modified.
- \sa created(), lastRead()
+ \sa birthTime(), lastRead(), metadataChangeTime(), 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);
}
/*!
@@ -1350,20 +1326,50 @@ QDateTime QFileInfo::lastModified() const
On platforms where this information is not available, returns the
same as lastModified().
- \sa created(), lastModified()
+ \sa birthTime(), lastModified(), metadataChangeTime(), 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, an invalid date time is returned.
+
+ \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::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
+ Q_STATIC_ASSERT(int(QFile::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
+ Q_STATIC_ASSERT(int(QFile::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
+
Q_D(const QFileInfo);
- 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();
+ auto fetime = QAbstractFileEngine::FileTime(time);
+ QFileSystemMetaData::MetaDataFlags flag;
+ switch (time) {
+ case QFile::FileAccessTime:
+ flag = QFileSystemMetaData::AccessTime;
+ break;
+ case QFile::FileBirthTime:
+ flag = QFileSystemMetaData::BirthTime;
+ break;
+ case QFile::FileMetadataChangeTime:
+ flag = QFileSystemMetaData::MetadataChangeTime;
+ break;
+ case QFile::FileModificationTime:
+ flag = QFileSystemMetaData::ModificationTime;
+ break;
}
- return d->getFileTime(QAbstractFileEngine::AccessTime).toLocalTime();
+
+ return d->checkAttribute<QDateTime>(
+ flag,
+ [=]() { return d->metaData.fileTime(fetime).toLocalTime(); },
+ [=]() { return d->getFileTime(fetime).toLocalTime(); });
}
/*!
@@ -1410,4 +1416,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..f295a86015 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -129,9 +129,16 @@ public:
qint64 size() const;
+ // ### Qt6: inline these functions
+#if QT_DEPRECATED_SINCE(5, 10)
+ QT_DEPRECATED_X("Use either birthTime() or metadataChangeTime()")
QDateTime created() const;
+#endif
+ QDateTime birthTime() const;
+ QDateTime metadataChangeTime() const;
QDateTime lastModified() const;
QDateTime lastRead() const;
+ QDateTime fileTime(QFile::FileTime time) const;
bool caching() const;
void setCaching(bool on);
@@ -151,6 +158,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..e4b28f4519 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>
@@ -67,9 +66,18 @@ QT_BEGIN_NAMESPACE
class QFileInfoPrivate : public QSharedData
{
public:
- enum { CachedFileFlags=0x01, CachedLinkTypeFlag=0x02, CachedBundleTypeFlag=0x04,
- CachedMTime=0x10, CachedCTime=0x20, CachedATime=0x40,
- CachedSize =0x08, CachedPerms=0x80 };
+ enum {
+ // note: cachedFlags is only 30-bits wide
+ CachedFileFlags = 0x01,
+ CachedLinkTypeFlag = 0x02,
+ CachedBundleTypeFlag = 0x04,
+ CachedSize = 0x08,
+ CachedATime = 0x10,
+ CachedBTime = 0x20,
+ CachedMCTime = 0x40,
+ CachedMTime = 0x80,
+ CachedPerms = 0x100
+ };
inline QFileInfoPrivate()
: QSharedData(), fileEngine(0),
@@ -95,7 +103,7 @@ public:
fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
- isDefaultConstructed(false),
+ isDefaultConstructed(file.isEmpty()),
#else
isDefaultConstructed(!fileEngine),
#endif
@@ -158,24 +166,40 @@ 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
{ if (cache_enabled) cachedFlags |= c; }
+ template <typename Ret, typename FSLambda, typename EngineLambda>
+ Ret checkAttribute(Ret defaultValue, QFileSystemMetaData::MetaDataFlags fsFlags, const FSLambda &fsLambda,
+ const EngineLambda &engineLambda) const
+ {
+ if (isDefaultConstructed)
+ return defaultValue;
+ if (fileEngine)
+ return engineLambda();
+ if (!cache_enabled || !metaData.hasFlags(fsFlags)) {
+ QFileSystemEngine::fillMetaData(fileEntry, metaData, fsFlags);
+ // ignore errors, fillMetaData will have cleared the flags
+ }
+ return fsLambda();
+ }
+
+ template <typename Ret, typename FSLambda, typename EngineLambda>
+ Ret checkAttribute(QFileSystemMetaData::MetaDataFlags fsFlags, const FSLambda &fsLambda,
+ const EngineLambda &engineLambda) const
+ {
+ return checkAttribute(Ret(), fsFlags, fsLambda, engineLambda);
+ }
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfileselector.h b/src/corelib/io/qfileselector.h
index fafb7f7609..c9c2f564f6 100644
--- a/src/corelib/io/qfileselector.h
+++ b/src/corelib/io/qfileselector.h
@@ -50,7 +50,7 @@ class Q_CORE_EXPORT QFileSelector : public QObject
{
Q_OBJECT
public:
- explicit QFileSelector(QObject *parent = Q_NULLPTR);
+ explicit QFileSelector(QObject *parent = nullptr);
~QFileSelector();
QString select(const QString &filePath) const;
diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp
index ccbcdb1037..7abdf90bf5 100644
--- a/src/corelib/io/qfilesystemengine.cpp
+++ b/src/corelib/io/qfilesystemengine.cpp
@@ -86,8 +86,6 @@ QString QFileSystemEngine::slowCanonicalized(const QString &path)
fi.setFile(prefix);
if (fi.isSymLink()) {
QString target = fi.symLinkTarget();
- if(QFileInfo(target).isRelative())
- target = fi.absolutePath() + slash + target;
if (separatorPos != -1) {
if (fi.isDir() && !target.endsWith(slash))
target.append(slash);
@@ -204,228 +202,6 @@ QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
return engine;
}
-//these unix functions are in this file, because they are shared by symbian port
-//for open C file handles.
-#ifdef Q_OS_UNIX
-//static
-bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data)
-{
- data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
- data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
-
- QT_STATBUF statBuffer;
- if (QT_FSTAT(fd, &statBuffer) == 0) {
- data.fillFromStatBuf(statBuffer);
- return true;
- }
-
- return false;
-}
-
-#if defined(_DEXTRA_FIRST)
-static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32)
-{
- statBuf64->st_mode = statBuf32.st_mode;
- statBuf64->st_size = statBuf32.st_size;
-#if _POSIX_VERSION >= 200809L
- statBuf64->st_ctim = statBuf32.st_ctim;
- statBuf64->st_mtim = statBuf32.st_mtim;
- statBuf64->st_atim = statBuf32.st_atim;
-#else
- statBuf64->st_ctime = statBuf32.st_ctime;
- statBuf64->st_mtime = statBuf32.st_mtime;
- statBuf64->st_atime = statBuf32.st_atime;
-#endif
- statBuf64->st_uid = statBuf32.st_uid;
- statBuf64->st_gid = statBuf32.st_gid;
-}
-#endif
-
-#if _POSIX_VERSION >= 200809L
-static qint64 timespecToMSecs(const timespec &spec)
-{
- return (qint64(spec.tv_sec) * 1000) + (spec.tv_nsec / 1000000);
-}
-#endif
-
-void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
-{
- // Permissions
- if (statBuffer.st_mode & S_IRUSR)
- entryFlags |= QFileSystemMetaData::OwnerReadPermission;
- if (statBuffer.st_mode & S_IWUSR)
- entryFlags |= QFileSystemMetaData::OwnerWritePermission;
- if (statBuffer.st_mode & S_IXUSR)
- entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
-
- if (statBuffer.st_mode & S_IRGRP)
- entryFlags |= QFileSystemMetaData::GroupReadPermission;
- if (statBuffer.st_mode & S_IWGRP)
- entryFlags |= QFileSystemMetaData::GroupWritePermission;
- if (statBuffer.st_mode & S_IXGRP)
- entryFlags |= QFileSystemMetaData::GroupExecutePermission;
-
- if (statBuffer.st_mode & S_IROTH)
- entryFlags |= QFileSystemMetaData::OtherReadPermission;
- if (statBuffer.st_mode & S_IWOTH)
- entryFlags |= QFileSystemMetaData::OtherWritePermission;
- if (statBuffer.st_mode & S_IXOTH)
- entryFlags |= QFileSystemMetaData::OtherExecutePermission;
-
- // Type
- if ((statBuffer.st_mode & S_IFMT) == S_IFREG)
- entryFlags |= QFileSystemMetaData::FileType;
- else if ((statBuffer.st_mode & S_IFMT) == S_IFDIR)
- entryFlags |= QFileSystemMetaData::DirectoryType;
- else if ((statBuffer.st_mode & S_IFMT) != S_IFBLK)
- entryFlags |= QFileSystemMetaData::SequentialType;
-
- // Attributes
- entryFlags |= QFileSystemMetaData::ExistsAttribute;
- size_ = statBuffer.st_size;
-#if defined(Q_OS_DARWIN)
- if (statBuffer.st_flags & UF_HIDDEN) {
- entryFlags |= QFileSystemMetaData::HiddenAttribute;
- knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
- }
-#endif
-
- // Times
-#if _POSIX_VERSION >= 200809L
- modificationTime_ = timespecToMSecs(statBuffer.st_mtim);
- creationTime_ = timespecToMSecs(statBuffer.st_ctim);
- if (!creationTime_)
- creationTime_ = modificationTime_;
- accessTime_ = timespecToMSecs(statBuffer.st_atim);
-#else
- creationTime_ = qint64(statBuffer.st_ctime ? statBuffer.st_ctime : statBuffer.st_mtime) * 1000;
- modificationTime_ = qint64(statBuffer.st_mtime) * 1000;
- accessTime_ = qint64(statBuffer.st_atime) * 1000;
-#endif
- userId_ = statBuffer.st_uid;
- groupId_ = statBuffer.st_gid;
-}
-
-void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
-{
-#if defined(_DEXTRA_FIRST)
- knownFlagsMask = 0;
- entryFlags = 0;
- for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry);
- extra = _DEXTRA_NEXT(extra)) {
- if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) {
-
- const struct dirent_extra_stat * const extra_stat =
- reinterpret_cast<struct dirent_extra_stat *>(extra);
-
- // Remember whether this was a link or not, this saves an lstat() call later.
- if (extra->d_type == _DTYPE_LSTAT) {
- knownFlagsMask |= QFileSystemMetaData::LinkType;
- if (S_ISLNK(extra_stat->d_stat.st_mode))
- entryFlags |= QFileSystemMetaData::LinkType;
- }
-
- // For symlinks, the extra type _DTYPE_LSTAT doesn't work for filling out the meta data,
- // as we need the stat() information there, not the lstat() information.
- // In this case, don't use the extra information.
- // Unfortunately, readdir() never seems to return extra info of type _DTYPE_STAT, so for
- // symlinks, we always incur the cost of an extra stat() call later.
- if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT)
- continue;
-
-#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
- // Even with large file support, d_stat is always of type struct stat, not struct stat64,
- // so it needs to be converted
- struct stat64 statBuf;
- fillStat64fromStat32(&statBuf, extra_stat->d_stat);
- fillFromStatBuf(statBuf);
-#else
- fillFromStatBuf(extra_stat->d_stat);
-#endif
- knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
- if (!S_ISLNK(extra_stat->d_stat.st_mode)) {
- knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
- entryFlags |= QFileSystemMetaData::ExistsAttribute;
- }
- }
- }
-#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4)
- // BSD4 includes OS X and iOS
-
- // ### This will clear all entry flags and knownFlagsMask
- switch (entry.d_type)
- {
- case DT_DIR:
- knownFlagsMask = QFileSystemMetaData::LinkType
- | QFileSystemMetaData::FileType
- | QFileSystemMetaData::DirectoryType
- | QFileSystemMetaData::SequentialType
- | QFileSystemMetaData::ExistsAttribute;
-
- entryFlags = QFileSystemMetaData::DirectoryType
- | QFileSystemMetaData::ExistsAttribute;
-
- break;
-
- case DT_BLK:
- knownFlagsMask = QFileSystemMetaData::LinkType
- | QFileSystemMetaData::FileType
- | QFileSystemMetaData::DirectoryType
- | QFileSystemMetaData::BundleType
- | QFileSystemMetaData::AliasType
- | QFileSystemMetaData::SequentialType
- | QFileSystemMetaData::ExistsAttribute;
-
- entryFlags = QFileSystemMetaData::ExistsAttribute;
-
- break;
-
- case DT_CHR:
- case DT_FIFO:
- case DT_SOCK:
- // ### System attribute
- knownFlagsMask = QFileSystemMetaData::LinkType
- | QFileSystemMetaData::FileType
- | QFileSystemMetaData::DirectoryType
- | QFileSystemMetaData::BundleType
- | QFileSystemMetaData::AliasType
- | QFileSystemMetaData::SequentialType
- | QFileSystemMetaData::ExistsAttribute;
-
- entryFlags = QFileSystemMetaData::SequentialType
- | QFileSystemMetaData::ExistsAttribute;
-
- break;
-
- case DT_LNK:
- knownFlagsMask = QFileSystemMetaData::LinkType;
- entryFlags = QFileSystemMetaData::LinkType;
- break;
-
- case DT_REG:
- knownFlagsMask = QFileSystemMetaData::LinkType
- | QFileSystemMetaData::FileType
- | QFileSystemMetaData::DirectoryType
- | QFileSystemMetaData::BundleType
- | QFileSystemMetaData::SequentialType
- | QFileSystemMetaData::ExistsAttribute;
-
- entryFlags = QFileSystemMetaData::FileType
- | QFileSystemMetaData::ExistsAttribute;
-
- break;
-
- case DT_UNKNOWN:
- default:
- clear();
- }
-#else
- Q_UNUSED(entry)
-#endif
-}
-
-#endif
-
//static
QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileSystemMetaData &metaData)
{
@@ -435,6 +211,8 @@ QString QFileSystemEngine::resolveUserName(const QFileSystemEntry &entry, QFileS
#else //(Q_OS_UNIX)
if (!metaData.hasFlags(QFileSystemMetaData::UserId))
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::UserId);
+ if (!metaData.exists())
+ return QString();
return resolveUserName(metaData.userId());
#endif
}
@@ -448,6 +226,8 @@ QString QFileSystemEngine::resolveGroupName(const QFileSystemEntry &entry, QFile
#else //(Q_OS_UNIX)
if (!metaData.hasFlags(QFileSystemMetaData::GroupId))
QFileSystemEngine::fillMetaData(entry, metaData, QFileSystemMetaData::GroupId);
+ if (!metaData.exists())
+ return QString();
return resolveGroupName(metaData.groupId());
#endif
}
diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h
index e3e52f6eaa..09ec2d6a10 100644
--- a/src/corelib/io/qfilesystemengine_p.h
+++ b/src/corelib/io/qfilesystemengine_p.h
@@ -91,8 +91,11 @@ public:
static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what);
#if defined(Q_OS_UNIX)
+ static bool cloneFile(int srcfd, int dstfd, const QFileSystemMetaData &knownData);
static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags
static QByteArray id(int fd);
+ static bool setFileTime(int fd, const QDateTime &newDate,
+ QAbstractFileEngine::FileTime whatTime, QSystemError &error);
static bool setPermissions(int fd, QFile::Permissions permissions, QSystemError &error,
QFileSystemMetaData *data = nullptr);
#endif
@@ -106,6 +109,8 @@ public:
static bool fillPermissions(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what);
static QByteArray id(HANDLE fHandle);
+ static bool setFileTime(HANDLE fHandle, const QDateTime &newDate,
+ QAbstractFileEngine::FileTime whatTime, QSystemError &error);
static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own);
static QString nativeAbsoluteFilePath(const QString &path);
#endif
@@ -121,11 +126,16 @@ public:
static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
+ static bool renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool removeFile(const QFileSystemEntry &entry, QSystemError &error);
static bool setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error,
QFileSystemMetaData *data = 0);
+ // unused, therefore not implemented
+ static bool setFileTime(const QFileSystemEntry &entry, const QDateTime &newDate,
+ QAbstractFileEngine::FileTime whatTime, QSystemError &error);
+
static bool setCurrentPath(const QFileSystemEntry &entry);
static QFileSystemEntry currentPath();
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 7fed54f733..b974af80dc 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 <pwd.h>
@@ -53,6 +55,12 @@
#include <stdio.h>
#include <errno.h>
+#if QT_HAS_INCLUDE(<paths.h>)
+# include <paths.h>
+#endif
+#ifndef _PATH_TMP // from <paths.h>
+# define _PATH_TMP "/tmp"
+#endif
#if defined(Q_OS_MAC)
# include <QtCore/private/qcore_mac_p.h>
@@ -68,14 +76,62 @@
#endif
#if defined(Q_OS_DARWIN)
+# if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(101200, 100000, 100000, 30000)
+# include <sys/clonefile.h>
+# endif
+# include <copyfile.h>
// We cannot include <Foundation/Foundation.h> (it's an Objective-C header), but
// we need these declarations:
Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
extern "C" NSString *NSTemporaryDirectory();
#endif
+#if defined(Q_OS_LINUX)
+# include <sys/ioctl.h>
+# include <sys/syscall.h>
+# include <sys/sendfile.h>
+# include <linux/fs.h>
+
+// in case linux/fs.h is too old and doesn't define it:
+#ifndef FICLONE
+# define FICLONE _IOW(0x94, 9, int)
+#endif
+
+# if !QT_CONFIG(renameat2) && defined(SYS_renameat2)
+static int renameat2(int oldfd, const char *oldpath, int newfd, const char *newpath, unsigned flags)
+{ return syscall(SYS_renameat2, oldfd, oldpath, newfd, newpath, flags); }
+# endif
+
+# if !QT_CONFIG(statx) && defined(SYS_statx) && QT_HAS_INCLUDE(<linux/stat.h>)
+# include <linux/stat.h>
+static int statx(int dirfd, const char *pathname, int flag, unsigned mask, struct statx *statxbuf)
+{ return syscall(SYS_statx, dirfd, pathname, flag, mask, statxbuf); }
+# endif
+#endif
+
+#ifndef STATX_BASIC_STATS
+struct statx { mode_t stx_mode; };
+#endif
+
QT_BEGIN_NAMESPACE
+enum {
+#ifdef Q_OS_ANDROID
+ // On Android, the link(2) system call has been observed to always fail
+ // with EACCES, regardless of whether there are permission problems or not.
+ SupportsHardlinking = false
+#else
+ SupportsHardlinking = true
+#endif
+};
+
+#define emptyFileEntryWarning() emptyFileEntryWarning_(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC)
+static void emptyFileEntryWarning_(const char *file, int line, const char *function)
+{
+ QMessageLogger(file, line, function).warning("Empty filename passed to function");
+ errno = EINVAL;
+}
+
#if defined(Q_OS_DARWIN)
static inline bool hasResourcePropertyFlag(const QFileSystemMetaData &data,
const QFileSystemEntry &entry,
@@ -144,33 +200,457 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
}
#endif
+namespace {
+namespace GetFileTimes {
+#if !QT_CONFIG(futimens) && (QT_CONFIG(futimes))
+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;
+}
+
+# ifndef st_atimensec
+// if "st_atimensec" is defined, this would expand to invalid C++
+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
+#endif
+
+qint64 timespecToMSecs(const timespec &spec)
+{
+ return (qint64(spec.tv_sec) * 1000) + (spec.tv_nsec / 1000000);
+}
+
+// fallback set
+Q_DECL_UNUSED qint64 atime(const QT_STATBUF &statBuffer, ulong) { return qint64(statBuffer.st_atime) * 1000; }
+Q_DECL_UNUSED qint64 birthtime(const QT_STATBUF &, ulong) { return Q_INT64_C(0); }
+Q_DECL_UNUSED qint64 ctime(const QT_STATBUF &statBuffer, ulong) { return qint64(statBuffer.st_ctime) * 1000; }
+Q_DECL_UNUSED qint64 mtime(const QT_STATBUF &statBuffer, ulong) { return qint64(statBuffer.st_mtime) * 1000; }
+
+// Xtim, POSIX.1-2008
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_atim, true), qint64>::type
+atime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_atim); }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_birthtim, true), qint64>::type
+birthtime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_birthtim); }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_ctim, true), qint64>::type
+ctime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_ctim); }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_mtim, true), qint64>::type
+mtime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_mtim); }
+
+#ifndef st_mtimespec
+// Xtimespec
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_atimespec, true), qint64>::type
+atime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_atimespec); }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_birthtimespec, true), qint64>::type
+birthtime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_birthtimespec); }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_ctimespec, true), qint64>::type
+ctime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_ctimespec); }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_mtimespec, true), qint64>::type
+mtime(const T &statBuffer, int)
+{ return timespecToMSecs(statBuffer.st_mtimespec); }
+#endif
+
+#ifndef st_mtimensec
+// Xtimensec
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_atimensec, true), qint64>::type
+atime(const T &statBuffer, int)
+{ return statBuffer.st_atime * Q_INT64_C(1000) + statBuffer.st_atimensec / 1000000; }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_birthtimensec, true), qint64>::type
+birthtime(const T &statBuffer, int)
+{ return statBuffer.st_birthtime * Q_INT64_C(1000) + statBuffer.st_birthtimensec / 1000000; }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_ctimensec, true), qint64>::type
+ctime(const T &statBuffer, int)
+{ return statBuffer.st_ctime * Q_INT64_C(1000) + statBuffer.st_ctimensec / 1000000; }
+
+template <typename T>
+Q_DECL_UNUSED static typename std::enable_if<(&T::st_mtimensec, true), qint64>::type
+mtime(const T &statBuffer, int)
+{ return statBuffer.st_mtime * Q_INT64_C(1000) + statBuffer.st_mtimensec / 1000000; }
+#endif
+} // namespace GetFileTimes
+} // unnamed namespace
+
+#ifdef STATX_BASIC_STATS
+static int qt_real_statx(int fd, const char *pathname, int flags, struct statx *statxBuffer)
+{
+#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
+ static QBasicAtomicInteger<qint8> statxTested = Q_BASIC_ATOMIC_INITIALIZER(0);
+#else
+ static QBasicAtomicInt statxTested = Q_BASIC_ATOMIC_INITIALIZER(0);
+#endif
+
+ if (statxTested.load() == -1)
+ return -ENOSYS;
+
+ unsigned mask = STATX_BASIC_STATS | STATX_BTIME;
+ int ret = statx(fd, pathname, flags, mask, statxBuffer);
+ if (ret == -1 && errno == ENOSYS) {
+ statxTested.store(-1);
+ return -ENOSYS;
+ }
+ statxTested.store(1);
+ return ret == -1 ? -errno : 0;
+}
+
+static int qt_statx(const char *pathname, struct statx *statxBuffer)
+{
+ return qt_real_statx(AT_FDCWD, pathname, 0, statxBuffer);
+}
+
+static int qt_lstatx(const char *pathname, struct statx *statxBuffer)
+{
+ return qt_real_statx(AT_FDCWD, pathname, AT_SYMLINK_NOFOLLOW, statxBuffer);
+}
+
+static int qt_fstatx(int fd, struct statx *statxBuffer)
+{
+ return qt_real_statx(fd, "", AT_EMPTY_PATH, statxBuffer);
+}
+
+inline void QFileSystemMetaData::fillFromStatxBuf(const struct statx &statxBuffer)
+{
+ // Permissions
+ if (statxBuffer.stx_mode & S_IRUSR)
+ entryFlags |= QFileSystemMetaData::OwnerReadPermission;
+ if (statxBuffer.stx_mode & S_IWUSR)
+ entryFlags |= QFileSystemMetaData::OwnerWritePermission;
+ if (statxBuffer.stx_mode & S_IXUSR)
+ entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
+
+ if (statxBuffer.stx_mode & S_IRGRP)
+ entryFlags |= QFileSystemMetaData::GroupReadPermission;
+ if (statxBuffer.stx_mode & S_IWGRP)
+ entryFlags |= QFileSystemMetaData::GroupWritePermission;
+ if (statxBuffer.stx_mode & S_IXGRP)
+ entryFlags |= QFileSystemMetaData::GroupExecutePermission;
+
+ if (statxBuffer.stx_mode & S_IROTH)
+ entryFlags |= QFileSystemMetaData::OtherReadPermission;
+ if (statxBuffer.stx_mode & S_IWOTH)
+ entryFlags |= QFileSystemMetaData::OtherWritePermission;
+ if (statxBuffer.stx_mode & S_IXOTH)
+ entryFlags |= QFileSystemMetaData::OtherExecutePermission;
+
+ // Type
+ if (S_ISLNK(statxBuffer.stx_mode))
+ entryFlags |= QFileSystemMetaData::LinkType;
+ if ((statxBuffer.stx_mode & S_IFMT) == S_IFREG)
+ entryFlags |= QFileSystemMetaData::FileType;
+ else if ((statxBuffer.stx_mode & S_IFMT) == S_IFDIR)
+ entryFlags |= QFileSystemMetaData::DirectoryType;
+ else if ((statxBuffer.stx_mode & S_IFMT) != S_IFBLK)
+ entryFlags |= QFileSystemMetaData::SequentialType;
+
+ // Attributes
+ entryFlags |= QFileSystemMetaData::ExistsAttribute; // inode exists
+ if (statxBuffer.stx_nlink == 0)
+ entryFlags |= QFileSystemMetaData::WasDeletedAttribute;
+ size_ = qint64(statxBuffer.stx_size);
+
+ // Times
+ auto toMSecs = [](struct statx_timestamp ts)
+ {
+ return qint64(ts.tv_sec) * 1000 + (ts.tv_nsec / 1000000);
+ };
+ accessTime_ = toMSecs(statxBuffer.stx_atime);
+ metadataChangeTime_ = toMSecs(statxBuffer.stx_ctime);
+ modificationTime_ = toMSecs(statxBuffer.stx_mtime);
+ if (statxBuffer.stx_mask & STATX_BTIME)
+ birthTime_ = toMSecs(statxBuffer.stx_btime);
+ else
+ birthTime_ = 0;
+
+ userId_ = statxBuffer.stx_uid;
+ groupId_ = statxBuffer.stx_gid;
+}
+#else
+static int qt_statx(const char *, struct statx *)
+{ return -ENOSYS; }
+
+static int qt_lstatx(const char *, struct statx *)
+{ return -ENOSYS; }
+
+static int qt_fstatx(int, struct statx *)
+{ return -ENOSYS; }
+
+inline void QFileSystemMetaData::fillFromStatxBuf(const struct statx &)
+{ }
+#endif
+
//static
-QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
+bool QFileSystemEngine::fillMetaData(int fd, 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;
+ data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
+
+ union {
+ struct statx statxBuffer;
+ QT_STATBUF statBuffer;
+ };
+
+ int ret = qt_fstatx(fd, &statxBuffer);
+ if (ret != -ENOSYS) {
+ if (ret == 0) {
+ data.fillFromStatxBuf(statxBuffer);
+ return true;
}
- if (len < size) {
- break;
+ return false;
+ }
+
+ if (QT_FSTAT(fd, &statBuffer) == 0) {
+ data.fillFromStatBuf(statBuffer);
+ return true;
+ }
+
+ return false;
+}
+
+#if defined(_DEXTRA_FIRST)
+static void fillStat64fromStat32(struct stat64 *statBuf64, const struct stat &statBuf32)
+{
+ statBuf64->st_mode = statBuf32.st_mode;
+ statBuf64->st_size = statBuf32.st_size;
+#if _POSIX_VERSION >= 200809L
+ statBuf64->st_ctim = statBuf32.st_ctim;
+ statBuf64->st_mtim = statBuf32.st_mtim;
+ statBuf64->st_atim = statBuf32.st_atim;
+#else
+ statBuf64->st_ctime = statBuf32.st_ctime;
+ statBuf64->st_mtime = statBuf32.st_mtime;
+ statBuf64->st_atime = statBuf32.st_atime;
+#endif
+ statBuf64->st_uid = statBuf32.st_uid;
+ statBuf64->st_gid = statBuf32.st_gid;
+}
+#endif
+
+void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
+{
+ // Permissions
+ if (statBuffer.st_mode & S_IRUSR)
+ entryFlags |= QFileSystemMetaData::OwnerReadPermission;
+ if (statBuffer.st_mode & S_IWUSR)
+ entryFlags |= QFileSystemMetaData::OwnerWritePermission;
+ if (statBuffer.st_mode & S_IXUSR)
+ entryFlags |= QFileSystemMetaData::OwnerExecutePermission;
+
+ if (statBuffer.st_mode & S_IRGRP)
+ entryFlags |= QFileSystemMetaData::GroupReadPermission;
+ if (statBuffer.st_mode & S_IWGRP)
+ entryFlags |= QFileSystemMetaData::GroupWritePermission;
+ if (statBuffer.st_mode & S_IXGRP)
+ entryFlags |= QFileSystemMetaData::GroupExecutePermission;
+
+ if (statBuffer.st_mode & S_IROTH)
+ entryFlags |= QFileSystemMetaData::OtherReadPermission;
+ if (statBuffer.st_mode & S_IWOTH)
+ entryFlags |= QFileSystemMetaData::OtherWritePermission;
+ if (statBuffer.st_mode & S_IXOTH)
+ entryFlags |= QFileSystemMetaData::OtherExecutePermission;
+
+ // Type
+ if ((statBuffer.st_mode & S_IFMT) == S_IFREG)
+ entryFlags |= QFileSystemMetaData::FileType;
+ else if ((statBuffer.st_mode & S_IFMT) == S_IFDIR)
+ entryFlags |= QFileSystemMetaData::DirectoryType;
+ else if ((statBuffer.st_mode & S_IFMT) != S_IFBLK)
+ entryFlags |= QFileSystemMetaData::SequentialType;
+
+ // Attributes
+ entryFlags |= QFileSystemMetaData::ExistsAttribute; // inode exists
+ if (statBuffer.st_nlink == 0)
+ entryFlags |= QFileSystemMetaData::WasDeletedAttribute;
+ size_ = statBuffer.st_size;
+#ifdef UF_HIDDEN
+ if (statBuffer.st_flags & UF_HIDDEN) {
+ entryFlags |= QFileSystemMetaData::HiddenAttribute;
+ knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
+ }
+#endif
+
+ // Times
+ accessTime_ = GetFileTimes::atime(statBuffer, 0);
+ birthTime_ = GetFileTimes::birthtime(statBuffer, 0);
+ metadataChangeTime_ = GetFileTimes::ctime(statBuffer, 0);
+ modificationTime_ = GetFileTimes::mtime(statBuffer, 0);
+
+ userId_ = statBuffer.st_uid;
+ groupId_ = statBuffer.st_gid;
+}
+
+void QFileSystemMetaData::fillFromDirEnt(const QT_DIRENT &entry)
+{
+#if defined(_DEXTRA_FIRST)
+ knownFlagsMask = 0;
+ entryFlags = 0;
+ for (dirent_extra *extra = _DEXTRA_FIRST(&entry); _DEXTRA_VALID(extra, &entry);
+ extra = _DEXTRA_NEXT(extra)) {
+ if (extra->d_type == _DTYPE_STAT || extra->d_type == _DTYPE_LSTAT) {
+
+ const struct dirent_extra_stat * const extra_stat =
+ reinterpret_cast<struct dirent_extra_stat *>(extra);
+
+ // Remember whether this was a link or not, this saves an lstat() call later.
+ if (extra->d_type == _DTYPE_LSTAT) {
+ knownFlagsMask |= QFileSystemMetaData::LinkType;
+ if (S_ISLNK(extra_stat->d_stat.st_mode))
+ entryFlags |= QFileSystemMetaData::LinkType;
+ }
+
+ // For symlinks, the extra type _DTYPE_LSTAT doesn't work for filling out the meta data,
+ // as we need the stat() information there, not the lstat() information.
+ // In this case, don't use the extra information.
+ // Unfortunately, readdir() never seems to return extra info of type _DTYPE_STAT, so for
+ // symlinks, we always incur the cost of an extra stat() call later.
+ if (S_ISLNK(extra_stat->d_stat.st_mode) && extra->d_type == _DTYPE_LSTAT)
+ continue;
+
+#if defined(QT_USE_XOPEN_LFS_EXTENSIONS) && defined(QT_LARGEFILE_SUPPORT)
+ // Even with large file support, d_stat is always of type struct stat, not struct stat64,
+ // so it needs to be converted
+ struct stat64 statBuf;
+ fillStat64fromStat32(&statBuf, extra_stat->d_stat);
+ fillFromStatBuf(statBuf);
+#else
+ fillFromStatBuf(extra_stat->d_stat);
+#endif
+ knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
+ if (!S_ISLNK(extra_stat->d_stat.st_mode)) {
+ knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
+ entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ }
}
- size *= 2;
+ }
+#elif defined(_DIRENT_HAVE_D_TYPE) || defined(Q_OS_BSD4)
+ // BSD4 includes OS X and iOS
+
+ // ### This will clear all entry flags and knownFlagsMask
+ switch (entry.d_type)
+ {
+ case DT_DIR:
+ knownFlagsMask = QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ entryFlags = QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ break;
+
+ case DT_BLK:
+ knownFlagsMask = QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::BundleType
+ | QFileSystemMetaData::AliasType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ entryFlags = QFileSystemMetaData::ExistsAttribute;
+
+ break;
+
+ case DT_CHR:
+ case DT_FIFO:
+ case DT_SOCK:
+ // ### System attribute
+ knownFlagsMask = QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::BundleType
+ | QFileSystemMetaData::AliasType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ entryFlags = QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ break;
+
+ case DT_LNK:
+ knownFlagsMask = QFileSystemMetaData::LinkType;
+ entryFlags = QFileSystemMetaData::LinkType;
+ break;
+
+ case DT_REG:
+ knownFlagsMask = QFileSystemMetaData::LinkType
+ | QFileSystemMetaData::FileType
+ | QFileSystemMetaData::DirectoryType
+ | QFileSystemMetaData::BundleType
+ | QFileSystemMetaData::SequentialType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ entryFlags = QFileSystemMetaData::FileType
+ | QFileSystemMetaData::ExistsAttribute;
+
+ break;
+
+ case DT_UNKNOWN:
+ default:
+ clear();
}
#else
- char s[PATH_MAX+1];
- int len = readlink(link.nativeFilePath().constData(), s, PATH_MAX);
+ Q_UNUSED(entry)
#endif
- if (len > 0) {
+}
+
+//static
+QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link, QFileSystemMetaData &data)
+{
+ if (Q_UNLIKELY(link.isEmpty()))
+ return emptyFileEntryWarning(), link;
+
+ QByteArray s = qt_readlink(link.nativeFilePath().constData());
+ if (s.length() > 0) {
QString ret;
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
@@ -181,19 +661,10 @@ 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 linkPath = link.path();
- if (linkPath.startsWith(QLatin1Char('/')))
- ret.prepend(linkPath + QLatin1Char('/'));
- else
- ret.prepend(QDir::currentPath() + QLatin1Char('/') + linkPath + QLatin1Char('/'));
- }
+ if (!ret.startsWith(QLatin1Char('/')))
+ ret.prepend(absoluteName(link).path() + QLatin1Char('/'));
ret = QDir::cleanPath(ret);
if (ret.size() > 1 && ret.endsWith(QLatin1Char('/')))
ret.chop(1);
@@ -235,7 +706,9 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
//static
QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry, QFileSystemMetaData &data)
{
- if (entry.isEmpty() || entry.isRoot())
+ if (Q_UNLIKELY(entry.isEmpty()))
+ return emptyFileEntryWarning(), entry;
+ if (entry.isRoot())
return entry;
#if !defined(Q_OS_MAC) && !defined(Q_OS_QNX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_HAIKU) && _POSIX_VERSION < 200809L
@@ -302,6 +775,8 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
//static
QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
{
+ if (Q_UNLIKELY(entry.isEmpty()))
+ return emptyFileEntryWarning(), entry;
if (entry.isAbsolute() && entry.isClean())
return entry;
@@ -335,6 +810,9 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
//static
QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
{
+ if (Q_UNLIKELY(entry.isEmpty()))
+ return emptyFileEntryWarning(), QByteArray();
+
QT_STATBUF statResult;
if (QT_STAT(entry.nativeFilePath().constData(), &statResult)) {
if (errno != ENOENT)
@@ -442,56 +920,105 @@ QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry)
bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what)
{
+ if (Q_UNLIKELY(entry.isEmpty()))
+ return emptyFileEntryWarning(), false;
+
#if defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::BundleType) {
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
what |= QFileSystemMetaData::DirectoryType;
}
+#endif
+#ifdef UF_HIDDEN
if (what & QFileSystemMetaData::HiddenAttribute) {
// OS X >= 10.5: st_flags & UF_HIDDEN
what |= QFileSystemMetaData::PosixStatFlags;
}
#endif // defined(Q_OS_DARWIN)
+ // if we're asking for any of the stat(2) flags, then we're getting them all
if (what & QFileSystemMetaData::PosixStatFlags)
what |= QFileSystemMetaData::PosixStatFlags;
- if (what & QFileSystemMetaData::ExistsAttribute) {
- // FIXME: Would other queries being performed provide this bit?
- what |= QFileSystemMetaData::PosixStatFlags;
- }
-
data.entryFlags &= ~what;
const QByteArray nativeFilePath = entry.nativeFilePath();
- bool entryExists = true; // innocent until proven otherwise
-
- QT_STATBUF statBuffer;
- bool statBufferValid = false;
+ int entryErrno = 0; // innocent until proven otherwise
+
+ // first, we may try lstat(2). Possible outcomes:
+ // - success and is a symlink: filesystem entry exists, but we need stat(2)
+ // -> statResult = -1;
+ // - success and is not a symlink: filesystem entry exists and we're done
+ // -> statResult = 0
+ // - failure: really non-existent filesystem entry
+ // -> entryExists = false; statResult = 0;
+ // both stat(2) and lstat(2) may generate a number of different errno
+ // conditions, but of those, the only ones that could happen and the
+ // entry still exist are EACCES, EFAULT, ENOMEM and EOVERFLOW. If we get
+ // EACCES or ENOMEM, then we have no choice on how to proceed, so we may
+ // as well conclude it doesn't exist; EFAULT can't happen and EOVERFLOW
+ // shouldn't happen because we build in _LARGEFIE64.
+ union {
+ QT_STATBUF statBuffer;
+ struct statx statxBuffer;
+ };
+ int statResult = -1;
if (what & QFileSystemMetaData::LinkType) {
- if (QT_LSTAT(nativeFilePath, &statBuffer) == 0) {
- if (S_ISLNK(statBuffer.st_mode)) {
+ mode_t mode = 0;
+ statResult = qt_lstatx(nativeFilePath, &statxBuffer);
+ if (statResult == -ENOSYS) {
+ // use lstst(2)
+ statResult = QT_LSTAT(nativeFilePath, &statBuffer);
+ if (statResult == 0)
+ mode = statBuffer.st_mode;
+ } else if (statResult == 0) {
+ statResult = 1; // record it was statx(2) that succeeded
+ mode = statxBuffer.stx_mode;
+ }
+
+ if (statResult >= 0) {
+ if (S_ISLNK(mode)) {
+ // it's a symlink, we don't know if the file "exists"
data.entryFlags |= QFileSystemMetaData::LinkType;
+ statResult = -1; // force stat(2) below
} else {
- statBufferValid = true;
- data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ // it's a reagular file and it exists
+ if (statResult)
+ data.fillFromStatxBuf(statxBuffer);
+ else
+ data.fillFromStatBuf(statBuffer);
+ data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags
+ | QFileSystemMetaData::ExistsAttribute;
+ data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
}
} else {
- entryExists = false;
+ // it doesn't exist
+ entryErrno = errno;
+ data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
}
data.knownFlagsMask |= QFileSystemMetaData::LinkType;
}
- if (statBufferValid || (what & QFileSystemMetaData::PosixStatFlags)) {
- if (entryExists && !statBufferValid)
- statBufferValid = (QT_STAT(nativeFilePath, &statBuffer) == 0);
+ // second, we try a regular stat(2)
+ if (statResult == -1 && (what & QFileSystemMetaData::PosixStatFlags)) {
+ if (entryErrno == 0 && statResult == -1) {
+ data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ statResult = qt_statx(nativeFilePath, &statxBuffer);
+ if (statResult == -ENOSYS) {
+ // use stat(2)
+ statResult = QT_STAT(nativeFilePath, &statBuffer);
+ if (statResult == 0)
+ data.fillFromStatBuf(statBuffer);
+ } else if (statResult == 0) {
+ data.fillFromStatxBuf(statxBuffer);
+ }
+ }
- if (statBufferValid)
- data.fillFromStatBuf(statBuffer);
- else {
- entryExists = false;
- data.creationTime_ = 0;
+ if (statResult != 0) {
+ entryErrno = errno;
+ data.birthTime_ = 0;
+ data.metadataChangeTime_ = 0;
data.modificationTime_ = 0;
data.accessTime_ = 0;
data.size_ = 0;
@@ -504,60 +1031,135 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
| QFileSystemMetaData::ExistsAttribute;
}
+ // third, we try access(2)
+ if (what & (QFileSystemMetaData::UserPermissions | QFileSystemMetaData::ExistsAttribute)) {
+ // calculate user permissions
+ auto checkAccess = [&](QFileSystemMetaData::MetaDataFlag flag, int mode) {
+ if (entryErrno != 0 || (what & flag) == 0)
+ return;
+ if (QT_ACCESS(nativeFilePath, mode) == 0) {
+ // access ok (and file exists)
+ data.entryFlags |= flag | QFileSystemMetaData::ExistsAttribute;
+ } else if (errno != EACCES && errno != EROFS) {
+ entryErrno = errno;
+ }
+ };
+
+ checkAccess(QFileSystemMetaData::UserReadPermission, R_OK);
+ checkAccess(QFileSystemMetaData::UserWritePermission, W_OK);
+ checkAccess(QFileSystemMetaData::UserExecutePermission, X_OK);
+
+ // if we still haven't found out if the file exists, try F_OK
+ if (entryErrno == 0 && (data.entryFlags & QFileSystemMetaData::ExistsAttribute) == 0) {
+ if (QT_ACCESS(nativeFilePath, F_OK) == -1)
+ entryErrno = errno;
+ else
+ data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ }
+
+ data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions) |
+ QFileSystemMetaData::ExistsAttribute;
+ }
+
#if defined(Q_OS_DARWIN)
- if (what & QFileSystemMetaData::AliasType)
- {
- if (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
+ if (what & QFileSystemMetaData::AliasType) {
+ if (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
data.entryFlags |= QFileSystemMetaData::AliasType;
data.knownFlagsMask |= QFileSystemMetaData::AliasType;
}
-#endif
- if (what & QFileSystemMetaData::UserPermissions) {
- // calculate user permissions
+ if (what & QFileSystemMetaData::BundleType) {
+ if (entryErrno == 0 && isPackage(data, entry))
+ data.entryFlags |= QFileSystemMetaData::BundleType;
- if (entryExists) {
- if (what & QFileSystemMetaData::UserReadPermission) {
- if (QT_ACCESS(nativeFilePath, R_OK) == 0)
- data.entryFlags |= QFileSystemMetaData::UserReadPermission;
- }
- if (what & QFileSystemMetaData::UserWritePermission) {
- if (QT_ACCESS(nativeFilePath, W_OK) == 0)
- data.entryFlags |= QFileSystemMetaData::UserWritePermission;
- }
- if (what & QFileSystemMetaData::UserExecutePermission) {
- if (QT_ACCESS(nativeFilePath, X_OK) == 0)
- data.entryFlags |= QFileSystemMetaData::UserExecutePermission;
- }
- }
- data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions);
+ data.knownFlagsMask |= QFileSystemMetaData::BundleType;
}
+#endif
if (what & QFileSystemMetaData::HiddenAttribute
&& !data.isHidden()) {
QString fileName = entry.fileName();
if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
#if defined(Q_OS_DARWIN)
- || (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey))
+ || (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey))
#endif
)
data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
}
-#if defined(Q_OS_DARWIN)
- if (what & QFileSystemMetaData::BundleType) {
- if (entryExists && isPackage(data, entry))
- data.entryFlags |= QFileSystemMetaData::BundleType;
+ if (entryErrno != 0) {
+ what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink
+ data.clearFlags(what);
+ return false;
+ }
+ return true;
+}
- data.knownFlagsMask |= QFileSystemMetaData::BundleType;
+// static
+bool QFileSystemEngine::cloneFile(int srcfd, int dstfd, const QFileSystemMetaData &knownData)
+{
+ QT_STATBUF statBuffer;
+ if (knownData.hasFlags(QFileSystemMetaData::PosixStatFlags) &&
+ knownData.isFile()) {
+ statBuffer.st_size = knownData.size();
+ statBuffer.st_mode = S_IFREG;
+ } else if (knownData.hasFlags(QFileSystemMetaData::PosixStatFlags) &&
+ knownData.isDirectory()) {
+ return false; // fcopyfile(3) returns success on directories
+ } else if (QT_FSTAT(srcfd, &statBuffer) == -1) {
+ return false;
+ } else if (!S_ISREG((statBuffer.st_mode))) {
+ // not a regular file, let QFile do the copy
+ return false;
}
-#endif
- if (!entryExists) {
- data.clearFlags(what);
+
+#if defined(Q_OS_LINUX)
+ if (statBuffer.st_size == 0) {
+ // empty file? we're done.
+ return true;
+ }
+
+ // first, try FICLONE (only works on regular files and only on certain fs)
+ if (::ioctl(dstfd, FICLONE, srcfd) == 0)
+ return true;
+
+ // Second, try sendfile (it can send to some special types too).
+ // sendfile(2) is limited in the kernel to 2G - 4k
+ auto sendfileSize = [](QT_OFF_T size) { return size_t(qMin<qint64>(0x7ffff000, size)); };
+
+ ssize_t n = ::sendfile(dstfd, srcfd, NULL, sendfileSize(statBuffer.st_size));
+ if (n == -1) {
+ // if we got an error here, give up and try at an upper layer
return false;
}
- return data.hasFlags(what);
+
+ statBuffer.st_size -= n;
+ while (statBuffer.st_size) {
+ n = ::sendfile(dstfd, srcfd, NULL, sendfileSize(statBuffer.st_size));
+ if (n == 0) {
+ // uh oh, this is probably a real error (like ENOSPC), but we have
+ // no way to notify QFile of partial success, so just erase any work
+ // done (hopefully we won't get any errors, because there's nothing
+ // we can do about them)
+ n = ftruncate(dstfd, 0);
+ n = lseek(srcfd, 0, SEEK_SET);
+ n = lseek(dstfd, 0, SEEK_SET);
+ return false;
+ }
+ if (n == 0)
+ return true;
+ statBuffer.st_size -= n;
+ }
+
+ return true;
+#elif defined(Q_OS_DARWIN)
+ // try fcopyfile
+ return fcopyfile(srcfd, dstfd, nullptr, COPYFILE_DATA | COPYFILE_STAT) == 0;
+#else
+ Q_UNUSED(dstfd);
+ return false;
+#endif
}
// Note: if \a shouldMkdirFirst is false, we assume the caller did try to mkdir
@@ -598,6 +1200,8 @@ static bool createDirectoryWithParents(const QByteArray &nativeName, bool should
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
{
QString dirName = entry.filePath();
+ if (Q_UNLIKELY(dirName.isEmpty()))
+ return emptyFileEntryWarning(), false;
// Darwin doesn't support trailing /'s, so remove for everyone
while (dirName.size() > 1 && dirName.endsWith(QLatin1Char('/')))
@@ -616,6 +1220,9 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
//static
bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents)
{
+ if (Q_UNLIKELY(entry.isEmpty()))
+ return emptyFileEntryWarning(), false;
+
if (removeEmptyParents) {
QString dirName = QDir::cleanPath(entry.filePath());
for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
@@ -639,6 +1246,8 @@ bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool remo
//static
bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
+ if (Q_UNLIKELY(source.isEmpty() || target.isEmpty()))
+ return emptyFileEntryWarning(), false;
if (::symlink(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
return true;
error = QSystemError(errno, QSystemError::StandardLibraryError);
@@ -648,8 +1257,18 @@ 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)
+ if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, 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;
}
@@ -657,6 +1276,83 @@ bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSyst
//static
bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
+ QFileSystemEntry::NativePath srcPath = source.nativeFilePath();
+ QFileSystemEntry::NativePath tgtPath = target.nativeFilePath();
+ if (Q_UNLIKELY(srcPath.isEmpty() || tgtPath.isEmpty()))
+ return emptyFileEntryWarning(), false;
+
+#if defined(RENAME_NOREPLACE) && (QT_CONFIG(renameat2) || defined(SYS_renameat2))
+ if (renameat2(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_NOREPLACE) == 0)
+ return true;
+
+ // If we're using syscall(), check for ENOSYS;
+ // if renameat2 came from libc, we don't accept ENOSYS.
+ // We can also get EINVAL for some non-local filesystems.
+ if ((QT_CONFIG(renameat2) || errno != ENOSYS) && errno != EINVAL) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+#endif
+#if defined(Q_OS_DARWIN) && defined(RENAME_EXCL)
+ if (__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *)) {
+ if (renameatx_np(AT_FDCWD, srcPath, AT_FDCWD, tgtPath, RENAME_EXCL) == 0)
+ return true;
+ if (errno != ENOTSUP) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+ }
+#endif
+
+ if (SupportsHardlinking && ::link(srcPath, tgtPath) == 0) {
+ if (::unlink(srcPath) == 0)
+ return true;
+
+ // if we managed to link but can't unlink the source, it's likely
+ // it's in a directory we don't have write access to; fail the
+ // renaming instead
+ int savedErrno = errno;
+
+ // this could fail too, but there's nothing we can do about it now
+ ::unlink(tgtPath);
+
+ error = QSystemError(savedErrno, QSystemError::StandardLibraryError);
+ return false;
+ } else if (!SupportsHardlinking) {
+ // man 2 link on Linux has:
+ // EPERM The filesystem containing oldpath and newpath does not
+ // support the creation of hard links.
+ errno = EPERM;
+ }
+
+ switch (errno) {
+ case EACCES:
+ case EEXIST:
+ case ENAMETOOLONG:
+ case ENOENT:
+ case ENOTDIR:
+ case EROFS:
+ case EXDEV:
+ // accept the error from link(2) (especially EEXIST) and don't retry
+ break;
+
+ default:
+ // fall back to rename()
+ // ### Race condition. If a file is moved in after this, it /will/ be
+ // overwritten.
+ if (::rename(srcPath, tgtPath) == 0)
+ return true;
+ }
+
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+}
+
+//static
+bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ if (Q_UNLIKELY(source.isEmpty() || target.isEmpty()))
+ return emptyFileEntryWarning(), false;
if (::rename(source.nativeFilePath().constData(), target.nativeFilePath().constData()) == 0)
return true;
error = QSystemError(errno, QSystemError::StandardLibraryError);
@@ -666,6 +1362,8 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
//static
bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
{
+ if (Q_UNLIKELY(entry.isEmpty()))
+ return emptyFileEntryWarning(), false;
if (unlink(entry.nativeFilePath().constData()) == 0)
return true;
error = QSystemError(errno, QSystemError::StandardLibraryError);
@@ -700,8 +1398,10 @@ static mode_t toMode_t(QFile::Permissions permissions)
//static
bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error, QFileSystemMetaData *data)
{
- mode_t mode = toMode_t(permissions);
+ if (Q_UNLIKELY(entry.isEmpty()))
+ return emptyFileEntryWarning(), false;
+ mode_t mode = toMode_t(permissions);
bool success = ::chmod(entry.nativeFilePath().constData(), mode) == 0;
if (success && data) {
data->entryFlags &= ~QFileSystemMetaData::Permissions;
@@ -729,6 +1429,71 @@ bool QFileSystemEngine::setPermissions(int fd, QFile::Permissions permissions, Q
return success;
}
+//static
+bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QAbstractFileEngine::FileTime time, QSystemError &error)
+{
+ if (!newDate.isValid() || time == QAbstractFileEngine::BirthTime ||
+ time == QAbstractFileEngine::MetadataChangeTime) {
+ error = QSystemError(EINVAL, QSystemError::StandardLibraryError);
+ 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(fd, ts) == -1) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ return true;
+#elif QT_CONFIG(futimes)
+ struct timeval tv[2];
+ QT_STATBUF st;
+
+ if (QT_FSTAT(fd, &st) == -1) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ 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 (futimes(fd, tv) == -1) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ return true;
+#else
+ Q_UNUSED(fd);
+ error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
+ return false;
+#endif
+}
+
QString QFileSystemEngine::homePath()
{
QString home = QFile::decodeName(qgetenv("HOME"));
@@ -749,14 +1514,13 @@ QString QFileSystemEngine::tempPath()
#else
QString temp = QFile::decodeName(qgetenv("TMPDIR"));
if (temp.isEmpty()) {
+ if (false) {
#if defined(Q_OS_DARWIN) && !defined(QT_BOOTSTRAPPED)
- if (NSString *nsPath = NSTemporaryDirectory()) {
+ } else if (NSString *nsPath = NSTemporaryDirectory()) {
temp = QString::fromCFString((CFStringRef)nsPath);
- } else {
-#else
- {
#endif
- temp = QLatin1String("/tmp");
+ } else {
+ temp = QLatin1String(_PATH_TMP);
}
}
return QDir::cleanPath(temp);
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index c9a56a81cc..fadc058110 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,49 +147,31 @@ 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;
static HANDLE currentUserImpersonatedToken = nullptr;
-/*
- 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;
@@ -206,39 +188,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
@@ -253,7 +209,7 @@ 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);
}
@@ -266,54 +222,62 @@ static void resolveLibs()
::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");
}
}
+
+Q_GLOBAL_STATIC(GlobalSid, initGlobalSid)
+
+QT_END_NAMESPACE
+
+} // anonymous namespace
#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;
+QT_BEGIN_NAMESPACE
+Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
-static bool resolveUNCLibs()
+static inline bool toFileTime(const QDateTime &date, FILETIME *fileTime)
{
- 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
+ SYSTEMTIME sTime;
+ if (date.timeSpec() == Qt::LocalTime) {
+ SYSTEMTIME lTime;
+ const QDate d = date.date();
+ const QTime t = date.time();
+
+ lTime.wYear = d.year();
+ lTime.wMonth = d.month();
+ lTime.wDay = d.day();
+ lTime.wHour = t.hour();
+ lTime.wMinute = t.minute();
+ lTime.wSecond = t.second();
+ lTime.wMilliseconds = t.msec();
+ lTime.wDayOfWeek = d.dayOfWeek() % 7;
+
+ if (!::TzSpecificLocalTimeToSystemTime(0, &lTime, &sTime))
+ return false;
+ } else {
+ QDateTime utcDate = date.toUTC();
+ const QDate d = utcDate.date();
+ const QTime t = utcDate.time();
+
+ sTime.wYear = d.year();
+ sTime.wMonth = d.month();
+ sTime.wDay = d.day();
+ sTime.wHour = t.hour();
+ sTime.wMinute = t.minute();
+ sTime.wSecond = t.second();
+ sTime.wMilliseconds = t.msec();
+ sTime.wDayOfWeek = d.dayOfWeek() % 7;
}
- return ptrNetShareEnum && ptrNetApiBufferFree;
+
+ return ::SystemTimeToFileTime(&sTime, fileTime);
}
static QString readSymLink(const QFileSystemEntry &link)
@@ -351,7 +315,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;
@@ -448,32 +412,35 @@ 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)
{
data.size_ = 0;
data.fileAttribute_ = 0;
- data.creationTime_ = FILETIME();
+ data.birthTime_ = FILETIME();
+ data.changeTime_ = FILETIME();
data.lastAccessTime_ = FILETIME();
data.lastWriteTime_ = FILETIME();
}
@@ -662,36 +629,72 @@ QByteArray QFileSystemEngine::id(HANDLE fHandle)
}
//static
+bool QFileSystemEngine::setFileTime(HANDLE fHandle, const QDateTime &newDate,
+ QAbstractFileEngine::FileTime time, QSystemError &error)
+{
+ 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::BirthTime:
+ pCreationTime = &fTime;
+ break;
+
+ default:
+ error = QSystemError(ERROR_INVALID_PARAMETER, QSystemError::NativeError);
+ return false;
+ }
+
+ if (!toFileTime(newDate, &fTime))
+ return false;
+
+ if (!::SetFileTime(fHandle, pCreationTime, pLastAccess, pLastWrite)) {
+ error = QSystemError(::GetLastError(), QSystemError::NativeError);
+ return false;
+ }
+ return true;
+}
+
QString QFileSystemEngine::owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own)
{
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 {
@@ -716,9 +719,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();
@@ -726,9 +729,9 @@ 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;
@@ -767,7 +770,7 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
}
} else { // fallback to GetEffectiveRightsFromAcl
data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
- if (ptrGetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
+ if (GetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
access_mask = ACCESS_MASK(-1);
if (access_mask & ReadMask)
data.entryFlags |= QFileSystemMetaData::UserReadPermission;
@@ -779,8 +782,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;
@@ -791,8 +794,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;
@@ -803,7 +806,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;
@@ -956,8 +959,10 @@ bool QFileSystemEngine::fillMetaData(HANDLE fHandle, QFileSystemMetaData &data,
FILE_BASIC_INFO fileBasicInfo;
if (GetFileInformationByHandleEx(fHandle, FileBasicInfo, &fileBasicInfo, sizeof(fileBasicInfo))) {
data.fillFromFileAttribute(fileBasicInfo.FileAttributes);
- data.creationTime_.dwHighDateTime = fileBasicInfo.CreationTime.HighPart;
- data.creationTime_.dwLowDateTime = fileBasicInfo.CreationTime.LowPart;
+ data.birthTime_.dwHighDateTime = fileBasicInfo.CreationTime.HighPart;
+ data.birthTime_.dwLowDateTime = fileBasicInfo.CreationTime.LowPart;
+ data.changeTime_.dwHighDateTime = fileBasicInfo.ChangeTime.HighPart;
+ data.changeTime_.dwLowDateTime = fileBasicInfo.ChangeTime.LowPart;
data.lastAccessTime_.dwHighDateTime = fileBasicInfo.LastAccessTime.HighPart;
data.lastAccessTime_.dwLowDateTime = fileBasicInfo.LastAccessTime.LowPart;
data.lastWriteTime_.dwHighDateTime = fileBasicInfo.LastWriteTime.HighPart;
@@ -1214,19 +1219,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;
@@ -1372,6 +1377,17 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
}
//static
+bool QFileSystemEngine::renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
+{
+ bool ret = ::MoveFileEx(reinterpret_cast<const wchar_t *>(source.nativeFilePath().utf16()),
+ reinterpret_cast<const wchar_t *>(target.nativeFilePath().utf16()),
+ MOVEFILE_REPLACE_EXISTING) != 0;
+ if (!ret)
+ error = QSystemError(::GetLastError(), QSystemError::NativeError);
+ return ret;
+}
+
+//static
bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &error)
{
bool ret = ::DeleteFile((wchar_t*)entry.nativeFilePath().utf16()) != 0;
@@ -1403,6 +1419,9 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
{
+ if (time->dwHighDateTime == 0 && time->dwLowDateTime == 0)
+ return QDateTime();
+
SYSTEMTIME sTime;
FileTimeToSystemTime(time, &sTime);
return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
@@ -1410,9 +1429,13 @@ static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
Qt::UTC);
}
-QDateTime QFileSystemMetaData::creationTime() const
+QDateTime QFileSystemMetaData::birthTime() const
+{
+ return fileTimeToQDateTime(&birthTime_);
+}
+QDateTime QFileSystemMetaData::metadataChangeTime() const
{
- return fileTimeToQDateTime(&creationTime_);
+ return fileTimeToQDateTime(&changeTime_);
}
QDateTime QFileSystemMetaData::modificationTime() const
{
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
index cbff17d0f1..3ff90bd0a3 100644
--- a/src/corelib/io/qfilesystementry.cpp
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -331,11 +331,6 @@ bool QFileSystemEntry::isRoot() const
return isRootPath(m_filePath);
}
-bool QFileSystemEntry::isEmpty() const
-{
- return m_filePath.isEmpty() && m_nativeFilePath.isEmpty();
-}
-
// private methods
void QFileSystemEntry::findLastSeparator() const
diff --git a/src/corelib/io/qfilesystementry_p.h b/src/corelib/io/qfilesystementry_p.h
index 700696d09e..251eca553a 100644
--- a/src/corelib/io/qfilesystementry_p.h
+++ b/src/corelib/io/qfilesystementry_p.h
@@ -98,7 +98,10 @@ public:
#endif
bool isRoot() const;
- bool isEmpty() const;
+ bool isEmpty() const
+ {
+ return m_filePath.isEmpty() && m_nativeFilePath.isEmpty();
+ }
void clear()
{
*this = QFileSystemEntry();
diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp
index 0d1438f137..a9acf542d4 100644
--- a/src/corelib/io/qfilesystemiterator_unix.cpp
+++ b/src/corelib/io/qfilesystemiterator_unix.cpp
@@ -77,12 +77,19 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
if (!dir)
return false;
- dirEntry = QT_READDIR(dir);
+ for (;;) {
+ dirEntry = QT_READDIR(dir);
- if (dirEntry) {
- fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name), QFileSystemEntry::FromNativePath());
- metaData.fillFromDirEnt(*dirEntry);
- return true;
+ if (dirEntry) {
+ // process entries with correct UTF-8 names only
+ if (QFile::encodeName(QFile::decodeName(dirEntry->d_name)) == dirEntry->d_name) {
+ fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name), QFileSystemEntry::FromNativePath());
+ metaData.fillFromDirEnt(*dirEntry);
+ return true;
+ }
+ } else {
+ break;
+ }
}
lastError = errno;
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index b09223d656..4d2a5acb9b 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -64,6 +64,10 @@
# endif
#endif
+#ifdef Q_OS_UNIX
+struct statx;
+#endif
+
QT_BEGIN_NAMESPACE
class QFileSystemEngine;
@@ -120,16 +124,22 @@ 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
+ // Times - if we know one of them, we know them all
+ AccessTime = 0x02000000,
+ BirthTime = 0x02000000,
+ MetadataChangeTime = 0x02000000,
ModificationTime = 0x02000000,
- AccessTime = 0x04000000,
- Times = CreationTime | ModificationTime | AccessTime,
+ Times = AccessTime | BirthTime | MetadataChangeTime | ModificationTime,
// Owner IDs
UserId = 0x10000000,
@@ -144,6 +154,7 @@ public:
| QFileSystemMetaData::DirectoryType
| QFileSystemMetaData::SequentialType
| QFileSystemMetaData::SizeAttribute
+ | QFileSystemMetaData::WasDeletedAttribute
| QFileSystemMetaData::Times
| QFileSystemMetaData::OwnerIds,
@@ -191,6 +202,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
@@ -201,9 +213,10 @@ public:
QFile::Permissions permissions() const { return QFile::Permissions(Permissions & entryFlags); }
- QDateTime creationTime() const;
- QDateTime modificationTime() const;
QDateTime accessTime() const;
+ QDateTime birthTime() const;
+ QDateTime metadataChangeTime() const;
+ QDateTime modificationTime() const;
QDateTime fileTime(QAbstractFileEngine::FileTime time) const;
uint userId() const;
@@ -211,6 +224,7 @@ public:
uint ownerId(QAbstractFileEngine::FileOwner owner) const;
#ifdef Q_OS_UNIX
+ void fillFromStatxBuf(const struct statx &statBuffer);
void fillFromStatBuf(const QT_STATBUF &statBuffer);
void fillFromDirEnt(const QT_DIRENT &statBuffer);
#endif
@@ -233,14 +247,16 @@ private:
// Platform-specific data goes here:
#if defined(Q_OS_WIN)
DWORD fileAttribute_;
- FILETIME creationTime_;
+ FILETIME birthTime_;
+ FILETIME changeTime_;
FILETIME lastAccessTime_;
FILETIME lastWriteTime_;
#else
// msec precision
- qint64 creationTime_;
- qint64 modificationTime_;
qint64 accessTime_;
+ qint64 birthTime_;
+ qint64 metadataChangeTime_;
+ qint64 modificationTime_;
uint userId_;
uint groupId_;
@@ -268,8 +284,11 @@ inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime tim
case QAbstractFileEngine::AccessTime:
return accessTime();
- case QAbstractFileEngine::CreationTime:
- return creationTime();
+ case QAbstractFileEngine::BirthTime:
+ return birthTime();
+
+ case QAbstractFileEngine::MetadataChangeTime:
+ return metadataChangeTime();
}
return QDateTime();
@@ -277,9 +296,14 @@ inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime tim
#endif
#if defined(Q_OS_UNIX)
-inline QDateTime QFileSystemMetaData::creationTime() const { return QDateTime::fromMSecsSinceEpoch(creationTime_); }
-inline QDateTime QFileSystemMetaData::modificationTime() const { return QDateTime::fromMSecsSinceEpoch(modificationTime_); }
-inline QDateTime QFileSystemMetaData::accessTime() const { return QDateTime::fromMSecsSinceEpoch(accessTime_); }
+inline QDateTime QFileSystemMetaData::birthTime() const
+{ return birthTime_ ? QDateTime::fromMSecsSinceEpoch(birthTime_) : QDateTime(); }
+inline QDateTime QFileSystemMetaData::metadataChangeTime() const
+{ return metadataChangeTime_ ? QDateTime::fromMSecsSinceEpoch(metadataChangeTime_) : QDateTime(); }
+inline QDateTime QFileSystemMetaData::modificationTime() const
+{ return modificationTime_ ? QDateTime::fromMSecsSinceEpoch(modificationTime_) : QDateTime(); }
+inline QDateTime QFileSystemMetaData::accessTime() const
+{ return accessTime_ ? QDateTime::fromMSecsSinceEpoch(accessTime_) : QDateTime(); }
inline uint QFileSystemMetaData::userId() const { return userId_; }
inline uint QFileSystemMetaData::groupId() const { return groupId_; }
@@ -318,9 +342,9 @@ inline void QFileSystemMetaData::fillFromFileAttribute(DWORD fileAttribute,bool
inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, bool setLinkType, bool isDriveRoot)
{
fillFromFileAttribute(findData.dwFileAttributes, isDriveRoot);
- creationTime_ = findData.ftCreationTime;
+ birthTime_ = findData.ftCreationTime;
lastAccessTime_ = findData.ftLastAccessTime;
- lastWriteTime_ = findData.ftLastWriteTime;
+ changeTime_ = lastWriteTime_ = findData.ftLastWriteTime;
if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
size_ = 0;
} else {
@@ -343,9 +367,9 @@ inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, boo
inline void QFileSystemMetaData::fillFromFindInfo(BY_HANDLE_FILE_INFORMATION &fileInfo)
{
fillFromFileAttribute(fileInfo.dwFileAttributes);
- creationTime_ = fileInfo.ftCreationTime;
+ birthTime_ = fileInfo.ftCreationTime;
lastAccessTime_ = fileInfo.ftLastAccessTime;
- lastWriteTime_ = fileInfo.ftLastWriteTime;
+ changeTime_ = lastWriteTime_ = fileInfo.ftLastWriteTime;
if (fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY) {
size_ = 0;
} else {
diff --git a/src/corelib/io/qfilesystemwatcher.h b/src/corelib/io/qfilesystemwatcher.h
index 09d4e8e65e..057a20672c 100644
--- a/src/corelib/io/qfilesystemwatcher.h
+++ b/src/corelib/io/qfilesystemwatcher.h
@@ -55,8 +55,8 @@ class Q_CORE_EXPORT QFileSystemWatcher : public QObject
Q_DECLARE_PRIVATE(QFileSystemWatcher)
public:
- QFileSystemWatcher(QObject *parent = Q_NULLPTR);
- QFileSystemWatcher(const QStringList &paths, QObject *parent = Q_NULLPTR);
+ QFileSystemWatcher(QObject *parent = nullptr);
+ QFileSystemWatcher(const QStringList &paths, QObject *parent = nullptr);
~QFileSystemWatcher();
bool addPath(const QString &file);
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.mm b/src/corelib/io/qfilesystemwatcher_fsevents.mm
index b4517cbac7..792ea387ac 100644
--- a/src/corelib/io/qfilesystemwatcher_fsevents.mm
+++ b/src/corelib/io/qfilesystemwatcher_fsevents.mm
@@ -336,7 +336,7 @@ QStringList QFseventsFileSystemWatcherEngine::addPaths(const QStringList &paths,
QMutexLocker locker(&lock);
- bool wasRunning = stream != Q_NULLPTR;
+ bool wasRunning = stream != nullptr;
bool needsRestart = false;
WatchingState oldState = watchingState;
diff --git a/src/corelib/io/qfilesystemwatcher_inotify_p.h b/src/corelib/io/qfilesystemwatcher_inotify_p.h
index 777d62dc8a..0c873466c8 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify_p.h
+++ b/src/corelib/io/qfilesystemwatcher_inotify_p.h
@@ -70,8 +70,8 @@ public:
static QInotifyFileSystemWatcherEngine *create(QObject *parent);
- QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories) Q_DECL_OVERRIDE;
- QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories) Q_DECL_OVERRIDE;
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
private Q_SLOTS:
void readFromInotify();
diff --git a/src/corelib/io/qfilesystemwatcher_polling_p.h b/src/corelib/io/qfilesystemwatcher_polling_p.h
index 6dff08ac05..4c46633fdf 100644
--- a/src/corelib/io/qfilesystemwatcher_polling_p.h
+++ b/src/corelib/io/qfilesystemwatcher_polling_p.h
@@ -110,8 +110,8 @@ class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine
public:
QPollingFileSystemWatcherEngine(QObject *parent);
- QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories) Q_DECL_OVERRIDE;
- QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories) Q_DECL_OVERRIDE;
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
private Q_SLOTS:
void timeout();
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 88e8baedca..387990ed79 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -165,6 +165,35 @@ QFSFileEngine::QFSFileEngine(QFSFileEnginePrivate &dd)
}
/*!
+ \internal
+*/
+bool QFSFileEngine::processOpenModeFlags(QIODevice::OpenMode *mode)
+{
+ QIODevice::OpenMode &openMode = *mode;
+ if ((openMode & QFile::NewOnly) && (openMode & QFile::ExistingOnly)) {
+ qWarning("NewOnly and ExistingOnly are mutually exclusive");
+ setError(QFile::OpenError, QLatin1String("NewOnly and ExistingOnly are mutually exclusive"));
+ return false;
+ }
+
+ if ((openMode & QFile::ExistingOnly) && !(openMode & (QFile::ReadOnly | QFile::WriteOnly))) {
+ qWarning("ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite");
+ setError(QFile::OpenError, QLatin1String("ExistingOnly must be specified alongside ReadOnly, WriteOnly, or ReadWrite"));
+ return false;
+ }
+
+ // Either Append or NewOnly implies WriteOnly
+ if (openMode & (QFile::Append | QFile::NewOnly))
+ openMode |= QFile::WriteOnly;
+
+ // WriteOnly implies Truncate when ReadOnly, Append, and NewOnly are not set.
+ if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append | QFile::NewOnly)))
+ openMode |= QFile::Truncate;
+
+ return true;
+}
+
+/*!
Destructs the QFSFileEngine.
*/
QFSFileEngine::~QFSFileEngine()
@@ -195,6 +224,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");
@@ -202,13 +234,8 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode)
return false;
}
- // Append implies WriteOnly.
- if (openMode & QFile::Append)
- openMode |= QFile::WriteOnly;
-
- // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
- if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
- openMode |= QFile::Truncate;
+ if (!processOpenModeFlags(&openMode))
+ return false;
d->openMode = openMode;
d->lastFlushFailed = false;
@@ -230,15 +257,13 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh)
bool QFSFileEngine::open(QIODevice::OpenMode openMode, FILE *fh, QFile::FileHandleFlags handleFlags)
{
- Q_D(QFSFileEngine);
+ Q_ASSERT_X(openMode & QIODevice::Unbuffered, "QFSFileEngine::open",
+ "QFSFileEngine no longer supports buffered mode; upper layer must buffer");
- // Append implies WriteOnly.
- if (openMode & QFile::Append)
- openMode |= QFile::WriteOnly;
+ Q_D(QFSFileEngine);
- // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
- if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
- openMode |= QFile::Truncate;
+ if (!processOpenModeFlags(&openMode))
+ return false;
d->openMode = openMode;
d->lastFlushFailed = false;
@@ -255,6 +280,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;
@@ -293,13 +321,8 @@ bool QFSFileEngine::open(QIODevice::OpenMode openMode, int fd, QFile::FileHandle
{
Q_D(QFSFileEngine);
- // Append implies WriteOnly.
- if (openMode & QFile::Append)
- openMode |= QFile::WriteOnly;
-
- // WriteOnly implies Truncate if neither ReadOnly nor Append are sent.
- if ((openMode & QFile::WriteOnly) && !(openMode & (QFile::ReadOnly | QFile::Append)))
- openMode |= QFile::Truncate;
+ if (!processOpenModeFlags(&openMode))
+ return false;
d->openMode = openMode;
d->lastFlushFailed = false;
@@ -516,6 +539,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 +741,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 +903,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)
@@ -886,11 +929,11 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
For Unix, the list contains just the root path "/".
*/
-/*! \fn QString QFSFileEngine::fileName(FileName file) const
+/*! \fn QString QFSFileEngine::fileName(QAbstractFileEngine::FileName file) const
\reimp
*/
-/*! \fn QDateTime QFSFileEngine::fileTime(FileTime time) const
+/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QAbstractFileEngine::FileTime time)
\reimp
*/
@@ -916,7 +959,7 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
-/*! \fn uint QFSFileEngine::ownerId(FileOwner own) const
+/*! \fn uint QFSFileEngine::ownerId(QAbstractFileEngine::FileOwner own) const
In Unix, if stat() is successful, the \c uid is returned if
\a own is the owner. Otherwise the \c gid is returned. If stat()
is unsuccessful, -2 is reuturned.
@@ -924,7 +967,7 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
For Windows, -2 is always returned.
*/
-/*! \fn QString QFSFileEngine::owner(FileOwner own) const
+/*! \fn QString QFSFileEngine::owner(QAbstractFileEngine::FileOwner own) const
\reimp
*/
diff --git a/src/corelib/io/qfsfileengine_iterator_p.h b/src/corelib/io/qfsfileengine_iterator_p.h
index 7f094ba9d7..bde00bf578 100644
--- a/src/corelib/io/qfsfileengine_iterator_p.h
+++ b/src/corelib/io/qfsfileengine_iterator_p.h
@@ -68,11 +68,11 @@ public:
QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
~QFSFileEngineIterator();
- QString next() Q_DECL_OVERRIDE;
- bool hasNext() const Q_DECL_OVERRIDE;
+ QString next() override;
+ bool hasNext() const override;
- QString currentFileName() const Q_DECL_OVERRIDE;
- QFileInfo currentFileInfo() const Q_DECL_OVERRIDE;
+ QString currentFileName() const override;
+ QFileInfo currentFileInfo() const override;
private:
void advance() const;
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index ab9ad3aa6b..6b091a8eef 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -71,47 +71,52 @@ public:
explicit QFSFileEngine(const QString &file);
~QFSFileEngine();
- bool open(QIODevice::OpenMode openMode) Q_DECL_OVERRIDE;
+ bool open(QIODevice::OpenMode openMode) override;
bool open(QIODevice::OpenMode flags, FILE *fh);
- bool close() Q_DECL_OVERRIDE;
- bool flush() Q_DECL_OVERRIDE;
- bool syncToDisk() Q_DECL_OVERRIDE;
- qint64 size() const Q_DECL_OVERRIDE;
- qint64 pos() const Q_DECL_OVERRIDE;
- bool seek(qint64) Q_DECL_OVERRIDE;
- bool isSequential() const Q_DECL_OVERRIDE;
- bool remove() Q_DECL_OVERRIDE;
- bool copy(const QString &newName) Q_DECL_OVERRIDE;
- bool rename(const QString &newName) Q_DECL_OVERRIDE;
- bool renameOverwrite(const QString &newName) Q_DECL_OVERRIDE;
- bool link(const QString &newName) Q_DECL_OVERRIDE;
- bool mkdir(const QString &dirName, bool createParentDirectories) const Q_DECL_OVERRIDE;
- bool rmdir(const QString &dirName, bool recurseParentDirectories) const Q_DECL_OVERRIDE;
- bool setSize(qint64 size) Q_DECL_OVERRIDE;
- bool caseSensitive() const Q_DECL_OVERRIDE;
- bool isRelativePath() const Q_DECL_OVERRIDE;
- QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE;
- FileFlags fileFlags(FileFlags type) const Q_DECL_OVERRIDE;
- bool setPermissions(uint perms) Q_DECL_OVERRIDE;
+ bool close() override;
+ bool flush() override;
+ bool syncToDisk() override;
+ qint64 size() const override;
+ qint64 pos() const override;
+ bool seek(qint64) override;
+ bool isSequential() const override;
+ bool remove() override;
+ bool copy(const QString &newName) override;
+ bool rename(const QString &newName) override;
+ bool renameOverwrite(const QString &newName) override;
+ bool link(const QString &newName) override;
+ bool mkdir(const QString &dirName, bool createParentDirectories) const override;
+ bool rmdir(const QString &dirName, bool recurseParentDirectories) const override;
+ bool setSize(qint64 size) override;
+ bool caseSensitive() const override;
+ bool isRelativePath() const override;
+ QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const override;
+ FileFlags fileFlags(FileFlags type) const override;
+ bool setPermissions(uint perms) override;
QByteArray id() const override;
- QString fileName(FileName file) const Q_DECL_OVERRIDE;
- uint ownerId(FileOwner) const Q_DECL_OVERRIDE;
- QString owner(FileOwner) const 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;
+ QString fileName(FileName file) const override;
+ uint ownerId(FileOwner) const override;
+ QString owner(FileOwner) const override;
+ bool setFileTime(const QDateTime &newDate, FileTime time) override;
+ QDateTime fileTime(FileTime time) const override;
+ void setFileName(const QString &file) override;
+ int handle() const override;
#ifndef QT_NO_FILESYSTEMITERATOR
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE;
- Iterator *endEntryList() Q_DECL_OVERRIDE;
+ Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
+ Iterator *endEntryList() override;
#endif
- 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;
+ qint64 read(char *data, qint64 maxlen) override;
+ qint64 readLine(char *data, qint64 maxlen) override;
+ qint64 write(const char *data, qint64 len) override;
+ bool cloneTo(QAbstractFileEngine *target) override;
- bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) Q_DECL_OVERRIDE;
- bool supportsExtension(Extension extension) const Q_DECL_OVERRIDE;
+ virtual bool isUnnamedFile() const
+ { return false; }
+
+ bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) override;
+ bool supportsExtension(Extension extension) const override;
//FS only!!
bool open(QIODevice::OpenMode flags, int fd);
@@ -126,6 +131,9 @@ public:
protected:
QFSFileEngine(QFSFileEnginePrivate &dd);
+
+private:
+ inline bool processOpenModeFlags(QIODevice::OpenMode *mode);
};
class Q_AUTOTEST_EXPORT QFSFileEnginePrivate : public QAbstractFileEnginePrivate
@@ -214,6 +222,12 @@ public:
int sysOpen(const QString &, int flags);
#endif
+ static bool openModeCanCreate(QIODevice::OpenMode openMode)
+ {
+ // WriteOnly can create, but only when ExistingOnly isn't specified.
+ // ReadOnly by itself never creates.
+ return (openMode & QFile::WriteOnly) && !(openMode & QFile::ExistingOnly);
+ }
protected:
QFSFileEnginePrivate();
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index c613368a91..7dd4f6556d 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)
@@ -114,11 +74,13 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
oflags |= QT_OPEN_LARGEFILE;
#endif
- if ((mode & QFile::ReadWrite) == QFile::ReadWrite) {
- oflags = QT_OPEN_RDWR | QT_OPEN_CREAT;
- } else if (mode & QFile::WriteOnly) {
- oflags = QT_OPEN_WRONLY | QT_OPEN_CREAT;
- }
+ if ((mode & QFile::ReadWrite) == QFile::ReadWrite)
+ oflags = QT_OPEN_RDWR;
+ else if (mode & QFile::WriteOnly)
+ oflags = QT_OPEN_WRONLY;
+
+ if (QFSFileEnginePrivate::openModeCanCreate(mode))
+ oflags |= QT_OPEN_CREAT;
if (mode & QFile::Append) {
oflags |= QT_OPEN_APPEND;
@@ -127,18 +89,10 @@ static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
oflags |= QT_OPEN_TRUNC;
}
- return oflags;
-}
+ if (mode & QFile::NewOnly)
+ oflags |= QT_OPEN_EXCL;
-/*!
- \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;
+ return oflags;
}
static inline QString msgOpenDirectory()
@@ -158,6 +112,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 +155,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;
@@ -416,8 +329,14 @@ bool QFSFileEngine::copy(const QString &newName)
bool QFSFileEngine::renameOverwrite(const QString &newName)
{
- // On Unix, rename() overwrites.
- return rename(newName);
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
+
+ if (!ret)
+ setError(QFile::RenameError, error.toString());
+
+ return ret;
}
bool QFSFileEngine::rename(const QString &newName)
@@ -549,11 +468,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 +507,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 +612,23 @@ 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 (d->doStat(QFileSystemMetaData::Times))
- return d->metaData.fileTime(time);
+ QSystemError error;
+ if (!QFileSystemEngine::setFileTime(d->nativeHandle(), newDate, time, error)) {
+ setError(QFile::PermissionsError, error.toString());
+ return false;
+ }
- return QDateTime();
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
+ return true;
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
@@ -715,7 +647,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 +737,20 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
#endif
}
+/*!
+ \reimp
+*/
+bool QFSFileEngine::cloneTo(QAbstractFileEngine *target)
+{
+ Q_D(QFSFileEngine);
+ if ((target->fileFlags(LocalDiskFlag) & LocalDiskFlag) == 0)
+ return false;
+
+ int srcfd = d->nativeHandle();
+ int dstfd = target->handle();
+ return QFileSystemEngine::cloneFile(srcfd, dstfd, d->metaData);
+}
+
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..8199f6a846 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -117,9 +117,12 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
if (openMode & QIODevice::WriteOnly)
accessRights |= GENERIC_WRITE;
-
// WriteOnly can create files, ReadOnly cannot.
- DWORD creationDisp = (openMode & QIODevice::WriteOnly) ? OPEN_ALWAYS : OPEN_EXISTING;
+ DWORD creationDisp = (openMode & QIODevice::NewOnly)
+ ? CREATE_NEW
+ : openModeCanCreate(openMode)
+ ? OPEN_ALWAYS
+ : OPEN_EXISTING;
// Create the file handle.
#ifndef Q_OS_WINRT
SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
@@ -474,11 +477,10 @@ bool QFSFileEngine::rename(const QString &newName)
bool QFSFileEngine::renameOverwrite(const QString &newName)
{
Q_D(QFSFileEngine);
- bool ret = ::MoveFileEx((wchar_t*)d->fileEntry.nativeFilePath().utf16(),
- (wchar_t*)QFileSystemEntry(newName).nativeFilePath().utf16(),
- MOVEFILE_REPLACE_EXISTING) != 0;
+ QSystemError error;
+ bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
if (!ret)
- setError(QFile::RenameError, QSystemError(::GetLastError(), QSystemError::NativeError).toString());
+ setError(QFile::RenameError, error.toString());
return ret;
}
@@ -694,6 +696,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 +858,41 @@ 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() || time == QAbstractFileEngine::MetadataChangeTime) {
+ setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
+ return false;
+ }
+
+ HANDLE handle = d->fileHandle;
+ 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));
+ }
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
+ return false;
+ }
+
+ QSystemError error;
+ if (!QFileSystemEngine::setFileTime(handle, newDate, time, error)) {
+ setError(QFile::PermissionsError, error.toString());
+ return false;
+ }
+
+ d->metaData.clearFlags(QFileSystemMetaData::Times);
+ return true;
}
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
@@ -1002,4 +1032,15 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
return true;
}
+/*!
+ \reimp
+*/
+bool QFSFileEngine::cloneTo(QAbstractFileEngine *target)
+{
+ // There's some Windows Server 2016 API, but we won't
+ // bother with it.
+ Q_UNUSED(target);
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 80122eac5e..95a5fb27cf 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -324,6 +324,23 @@ QIODevicePrivate::~QIODevicePrivate()
terminators are translated to the local encoding, for
example '\\r\\n' for Win32.
\value Unbuffered Any buffer in the device is bypassed.
+ \value NewOnly Fail if the file to be opened already exists. Create and
+ open the file only if it does not exist. There is a
+ guarantee from the operating system that you are the only
+ one creating and opening the file. Note that this mode
+ implies WriteOnly, and combining it with ReadWrite is
+ allowed. This flag currently only affects QFile. Other
+ classes might use this flag in the future, but until then
+ using this flag with any classes other than QFile may
+ result in undefined behavior.
+ \value ExistingOnly Fail if the file to be opened does not exist. This flag
+ must be specified alongside ReadOnly, WriteOnly, or
+ ReadWrite. Note that using this flag with ReadOnly alone
+ is redundant, as ReadOnly already fails when the file does
+ not exist. This flag currently only affects QFile. Other
+ classes might use this flag in the future, but until then
+ using this flag with any classes other than QFile may
+ result in undefined behavior.
Certain flags, such as \c Unbuffered and \c Truncate, are
meaningless when used with some subclasses. Some of these
@@ -775,6 +792,7 @@ bool QIODevice::open(OpenMode mode)
d->writeBuffers.clear();
d->setReadChannelCount(isReadable() ? 1 : 0);
d->setWriteChannelCount(isWritable() ? 1 : 0);
+ d->errorString.clear();
#if defined QIODEVICE_DEBUG
printf("%p QIODevice::open(0x%x)\n", this, quint32(mode));
#endif
@@ -801,7 +819,6 @@ void QIODevice::close()
emit aboutToClose();
#endif
d->openMode = NotOpen;
- d->errorString.clear();
d->pos = 0;
d->transactionStarted = false;
d->transactionPos = 0;
@@ -1879,6 +1896,128 @@ QByteArray QIODevice::peek(qint64 maxSize)
}
/*!
+ \since 5.10
+
+ Skips up to \a maxSize bytes from the device. Returns the number of bytes
+ actually skipped, or -1 on error.
+
+ This function does not wait and only discards the data that is already
+ available for reading.
+
+ If the device is opened in text mode, end-of-line terminators are
+ translated to '\n' symbols and count as a single byte identically to the
+ read() and peek() behavior.
+
+ This function works for all devices, including sequential ones that cannot
+ seek(). It is optimized to skip unwanted data after a peek() call.
+
+ For random-access devices, skip() can be used to seek forward from the
+ current position. Negative \a maxSize values are not allowed.
+
+ \sa peek(), seek(), read()
+*/
+qint64 QIODevice::skip(qint64 maxSize)
+{
+ Q_D(QIODevice);
+ CHECK_MAXLEN(skip, qint64(-1));
+ CHECK_READABLE(skip, qint64(-1));
+
+ const bool sequential = d->isSequential();
+
+#if defined QIODEVICE_DEBUG
+ printf("%p QIODevice::skip(%lld), d->pos = %lld, d->buffer.size() = %lld\n",
+ this, maxSize, d->pos, d->buffer.size());
+#endif
+
+ if ((sequential && d->transactionStarted) || (d->openMode & QIODevice::Text) != 0)
+ return d->skipByReading(maxSize);
+
+ // First, skip over any data in the internal buffer.
+ qint64 skippedSoFar = 0;
+ if (!d->buffer.isEmpty()) {
+ skippedSoFar = d->buffer.skip(maxSize);
+#if defined QIODEVICE_DEBUG
+ printf("%p \tskipping %lld bytes in buffer\n", this, skippedSoFar);
+#endif
+ if (!sequential)
+ d->pos += skippedSoFar;
+ if (d->buffer.isEmpty())
+ readData(nullptr, 0);
+ if (skippedSoFar == maxSize)
+ return skippedSoFar;
+
+ maxSize -= skippedSoFar;
+ }
+
+ // Try to seek on random-access device. At this point,
+ // the internal read buffer is empty.
+ if (!sequential) {
+ const qint64 bytesToSkip = qMin(size() - d->pos, maxSize);
+
+ // If the size is unknown or file position is at the end,
+ // fall back to reading below.
+ if (bytesToSkip > 0) {
+ if (!seek(d->pos + bytesToSkip))
+ return skippedSoFar ? skippedSoFar : Q_INT64_C(-1);
+ if (bytesToSkip == maxSize)
+ return skippedSoFar + bytesToSkip;
+
+ skippedSoFar += bytesToSkip;
+ maxSize -= bytesToSkip;
+ }
+ }
+
+ const qint64 skipResult = d->skip(maxSize);
+ if (skippedSoFar == 0)
+ return skipResult;
+
+ if (skipResult == -1)
+ return skippedSoFar;
+
+ return skippedSoFar + skipResult;
+}
+
+/*!
+ \internal
+*/
+qint64 QIODevicePrivate::skipByReading(qint64 maxSize)
+{
+ qint64 readSoFar = 0;
+ do {
+ char dummy[4096];
+ const qint64 readBytes = qMin<qint64>(maxSize, sizeof(dummy));
+ const qint64 readResult = read(dummy, readBytes);
+
+ // Do not try again, if we got less data.
+ if (readResult != readBytes) {
+ if (readSoFar == 0)
+ return readResult;
+
+ if (readResult == -1)
+ return readSoFar;
+
+ return readSoFar + readResult;
+ }
+
+ readSoFar += readResult;
+ maxSize -= readResult;
+ } while (maxSize > 0);
+
+ return readSoFar;
+}
+
+/*!
+ \internal
+*/
+qint64 QIODevicePrivate::skip(qint64 maxSize)
+{
+ // Base implementation discards the data by reading into the dummy buffer.
+ // It's slow, but this works for all types of devices. Subclasses can
+ // reimplement this function to improve on that.
+ return skipByReading(maxSize);
+}
+
+/*!
Blocks until new data is available for reading and the readyRead()
signal has been emitted, or until \a msecs milliseconds have
passed. If msecs is -1, this function will not time out.
diff --git a/src/corelib/io/qiodevice.h b/src/corelib/io/qiodevice.h
index 162480d22f..2e4debe339 100644
--- a/src/corelib/io/qiodevice.h
+++ b/src/corelib/io/qiodevice.h
@@ -76,7 +76,9 @@ public:
Append = 0x0004,
Truncate = 0x0008,
Text = 0x0010,
- Unbuffered = 0x0020
+ Unbuffered = 0x0020,
+ NewOnly = 0x0040,
+ ExistingOnly = 0x0080
};
Q_DECLARE_FLAGS(OpenMode, OpenModeFlag)
@@ -136,6 +138,7 @@ public:
qint64 peek(char *data, qint64 maxlen);
QByteArray peek(qint64 maxlen);
+ qint64 skip(qint64 maxSize);
virtual bool waitForReadyRead(int msecs);
virtual bool waitForBytesWritten(int msecs);
@@ -160,7 +163,7 @@ protected:
#ifdef QT_NO_QOBJECT
QIODevice(QIODevicePrivate &dd);
#else
- QIODevice(QIODevicePrivate &dd, QObject *parent = Q_NULLPTR);
+ QIODevice(QIODevicePrivate &dd, QObject *parent = nullptr);
#endif
virtual qint64 readData(char *data, qint64 maxlen) = 0;
virtual qint64 readLineData(char *data, qint64 maxlen);
diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h
index 71a326dd53..15a53a67dc 100644
--- a/src/corelib/io/qiodevice_p.h
+++ b/src/corelib/io/qiodevice_p.h
@@ -88,14 +88,14 @@ public:
class QRingBufferRef {
QRingBuffer *m_buf;
- inline QRingBufferRef() : m_buf(Q_NULLPTR) { }
+ inline QRingBufferRef() : m_buf(nullptr) { }
friend class QIODevicePrivate;
public:
// wrap functions from QRingBuffer
inline void setChunkSize(int size) { Q_ASSERT(m_buf); m_buf->setChunkSize(size); }
inline int chunkSize() const { Q_ASSERT(m_buf); return m_buf->chunkSize(); }
inline qint64 nextDataBlockSize() const { return (m_buf ? m_buf->nextDataBlockSize() : Q_INT64_C(0)); }
- inline const char *readPointer() const { return (m_buf ? m_buf->readPointer() : Q_NULLPTR); }
+ inline const char *readPointer() const { return (m_buf ? m_buf->readPointer() : nullptr); }
inline const char *readPointerAtPosition(qint64 pos, qint64 &length) const { Q_ASSERT(m_buf); return m_buf->readPointerAtPosition(pos, length); }
inline void free(qint64 bytes) { Q_ASSERT(m_buf); m_buf->free(bytes); }
inline char *reserve(qint64 bytes) { Q_ASSERT(m_buf); return m_buf->reserve(bytes); }
@@ -174,6 +174,9 @@ public:
qint64 read(char *data, qint64 maxSize, bool peeking = false);
virtual qint64 peek(char *data, qint64 maxSize);
virtual QByteArray peek(qint64 maxSize);
+ qint64 skipByReading(qint64 maxSize);
+ // ### Qt6: consider replacing with a protected virtual QIODevice::skipData().
+ virtual qint64 skip(qint64 maxSize);
#ifdef QT_NO_QOBJECT
QIODevice *q_ptr;
diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp
index 48317d07e0..aa84ce6bc1 100644
--- a/src/corelib/io/qlockfile.cpp
+++ b/src/corelib/io/qlockfile.cpp
@@ -2,6 +2,7 @@
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -42,12 +43,36 @@
#include "qlockfile_p.h"
#include <QtCore/qthread.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qfileinfo.h>
QT_BEGIN_NAMESPACE
+namespace {
+struct LockFileInfo
+{
+ qint64 pid;
+ QString appname;
+ QString hostname;
+ QByteArray hostid;
+ QByteArray bootid;
+};
+}
+
+static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info);
+
+static QString machineName()
+{
+#ifdef Q_OS_WIN
+ // we don't use QSysInfo because it tries to do name resolution
+ return qEnvironmentVariable("COMPUTERNAME");
+#else
+ return QSysInfo::machineHostName();
+#endif
+}
+
/*!
\class QLockFile
\inmodule QtCore
@@ -291,13 +316,32 @@ bool QLockFile::tryLock(int timeout)
bool QLockFile::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
{
Q_D(const QLockFile);
- return d->getLockInfo(pid, hostname, appname);
+ LockFileInfo info;
+ if (!getLockInfo_helper(d->fileName, &info))
+ return false;
+ if (pid)
+ *pid = info.pid;
+ if (hostname)
+ *hostname = info.hostname;
+ if (appname)
+ *appname = info.appname;
+ return true;
+}
+
+QByteArray QLockFilePrivate::lockFileContents() const
+{
+ // Use operator% from the fast builder to avoid multiple memory allocations.
+ return QByteArray::number(QCoreApplication::applicationPid()) % '\n'
+ % processNameByPid(QCoreApplication::applicationPid()).toUtf8() % '\n'
+ % machineName().toUtf8() % '\n'
+ % QSysInfo::machineUniqueId() % '\n'
+ % QSysInfo::bootUniqueId() % '\n';
}
-bool QLockFilePrivate::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
+static bool getLockInfo_helper(const QString &fileName, LockFileInfo *info)
{
QFile reader(fileName);
- if (!reader.open(QIODevice::ReadOnly))
+ if (!reader.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
QByteArray pidLine = reader.readLine();
@@ -309,14 +353,46 @@ bool QLockFilePrivate::getLockInfo(qint64 *pid, QString *hostname, QString *appn
QByteArray hostNameLine = reader.readLine();
hostNameLine.chop(1);
- qint64 thePid = pidLine.toLongLong();
- if (pid)
- *pid = thePid;
- if (appname)
- *appname = QString::fromUtf8(appNameLine);
- if (hostname)
- *hostname = QString::fromUtf8(hostNameLine);
- return thePid > 0;
+ // prior to Qt 5.10, only the lines above were recorded
+ QByteArray hostId = reader.readLine();
+ hostId.chop(1);
+ QByteArray bootId = reader.readLine();
+ bootId.chop(1);
+
+ bool ok;
+ info->appname = QString::fromUtf8(appNameLine);
+ info->hostname = QString::fromUtf8(hostNameLine);
+ info->hostid = hostId;
+ info->bootid = bootId;
+ info->pid = pidLine.toLongLong(&ok);
+ return ok && info->pid > 0;
+}
+
+bool QLockFilePrivate::isApparentlyStale() const
+{
+ LockFileInfo info;
+ if (getLockInfo_helper(fileName, &info)) {
+ bool sameHost = info.hostname.isEmpty() || info.hostname == machineName();
+ if (!info.hostid.isEmpty()) {
+ // Override with the host ID, if we know it.
+ QByteArray ourHostId = QSysInfo::machineUniqueId();
+ if (!ourHostId.isEmpty())
+ sameHost = (ourHostId == info.hostid);
+ }
+
+ if (sameHost) {
+ if (!info.bootid.isEmpty()) {
+ // If we've rebooted, then the lock is definitely stale.
+ if (info.bootid != QSysInfo::bootUniqueId())
+ return true;
+ }
+ if (!isProcessRunning(info.pid, info.appname))
+ return true;
+ }
+ }
+
+ const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTimeUtc());
+ return staleLockTime > 0 && qAbs(age) > staleLockTime;
}
/*!
diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h
index 86a606ec00..5b69347206 100644
--- a/src/corelib/io/qlockfile_p.h
+++ b/src/corelib/io/qlockfile_p.h
@@ -55,7 +55,10 @@
#include <QtCore/qlockfile.h>
#include <QtCore/qfile.h>
+#include <qplatformdefs.h>
+
#ifdef Q_OS_WIN
+#include <io.h>
#include <qt_windows.h>
#endif
@@ -78,16 +81,14 @@ public:
}
QLockFile::LockError tryLock_sys();
bool removeStaleLock();
- bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const;
+ QByteArray lockFileContents() const;
// Returns \c true if the lock belongs to dead PID, or is old.
// The attempt to delete it will tell us if it was really stale or not, though.
bool isApparentlyStale() const;
+
// used in dbusmenu
Q_CORE_EXPORT static QString processNameByPid(qint64 pid);
-
-#ifdef Q_OS_UNIX
- static int checkFcntlWorksAfterFlock(const QString &fn);
-#endif
+ static bool isProcessRunning(qint64 pid, const QString &appname);
QString fileName;
#ifdef Q_OS_WIN
@@ -98,6 +99,19 @@ public:
int staleLockTime; // "int milliseconds" is big enough for 24 days
QLockFile::LockError lockError;
bool isLocked;
+
+ static int getLockFileHandle(QLockFile *f)
+ {
+ int fd;
+#ifdef Q_OS_WIN
+ // Use of this function on Windows WILL leak a file descriptor.
+ fd = _open_osfhandle(intptr_t(f->d_func()->fileHandle), 0);
+#else
+ fd = f->d_func()->fileHandle;
+#endif
+ QT_LSEEK(fd, 0, SEEK_SET);
+ return fd;
+ }
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index ccc607afd5..418b7d22ba 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2017 Intel Corporation.
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -42,7 +42,6 @@
#include "private/qlockfile_p.h"
#include "QtCore/qtemporaryfile.h"
-#include "QtCore/qcoreapplication.h"
#include "QtCore/qfileinfo.h"
#include "QtCore/qdebug.h"
#include "QtCore/qdatetime.h"
@@ -94,93 +93,61 @@ static qint64 qt_write_loop(int fd, const char *data, qint64 len)
return pos;
}
-int QLockFilePrivate::checkFcntlWorksAfterFlock(const QString &fn)
-{
-#ifndef QT_NO_TEMPORARYFILE
- QTemporaryFile file(fn);
- if (!file.open())
- return 0;
- const int fd = file.d_func()->engine()->handle();
-#if defined(LOCK_EX) && defined(LOCK_NB)
- if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs
- return 0;
-#endif
- struct flock flockData;
- flockData.l_type = F_WRLCK;
- flockData.l_whence = SEEK_SET;
- flockData.l_start = 0;
- flockData.l_len = 0; // 0 = entire file
- flockData.l_pid = getpid();
- if (fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems
- return 0;
- return 1;
-#else
- Q_UNUSED(fn);
- return 0;
-#endif
-}
-
-// Cache the result of checkFcntlWorksAfterFlock for each directory a lock
-// file is created in because in some filesystems, like NFS, both locks
-// are the same. This does not take into account a filesystem changing.
-// QCache is set to hold a maximum of 10 entries, this is to avoid unbounded
-// growth, this is caching directories of files and it is assumed a low number
-// will be sufficient.
-typedef QCache<QString, bool> CacheType;
-Q_GLOBAL_STATIC_WITH_ARGS(CacheType, fcntlOK, (10));
-static QBasicMutex fcntlLock;
+/*
+ * Details about file locking on Unix.
+ *
+ * There are three types of advisory locks on Unix systems:
+ * 1) POSIX process-wide locks using fcntl(F_SETLK)
+ * 2) BSD flock(2) system call
+ * 3) Linux-specific file descriptor locks using fcntl(F_OFD_SETLK)
+ * There's also a mandatory locking feature by POSIX, which is deprecated on
+ * Linux and users are advised not to use it.
+ *
+ * The first problem is that the POSIX API is braindead. POSIX.1-2008 says:
+ *
+ * All locks associated with a file for a given process shall be removed when
+ * a file descriptor for that file is closed by that process or the process
+ * holding that file descriptor terminates.
+ *
+ * The Linux manpage is clearer:
+ *
+ * * If a process closes _any_ file descriptor referring to a file, then all
+ * of the process's locks on that file are released, regardless of the file
+ * descriptor(s) on which the locks were obtained. This is bad: [...]
+ *
+ * * The threads in a process share locks. In other words, a multithreaded
+ * program can't use record locking to ensure that threads don't
+ * simultaneously access the same region of a file.
+ *
+ * So in order to use POSIX locks, we'd need a global mutex that stays locked
+ * while the QLockFile is locked. For that reason, Qt does not use POSIX
+ * advisory locks anymore.
+ *
+ * The next problem is that POSIX leaves undefined the relationship between
+ * locks with fcntl(), flock() and lockf(). In some systems (like the BSDs),
+ * all three use the same record set, while on others (like Linux) the locks
+ * are independent, except if locking over NFS mounts, in which case they're
+ * actually the same. Therefore, it's a very bad idea to mix them in the same
+ * process.
+ *
+ * We therefore use only flock(2).
+ */
-/*!
- \internal
- Checks that the OS isn't using POSIX locks to emulate flock().
- \macos is one of those.
-*/
-static bool fcntlWorksAfterFlock(const QString &fn)
-{
- QMutexLocker lock(&fcntlLock);
- if (fcntlOK.isDestroyed())
- return QLockFilePrivate::checkFcntlWorksAfterFlock(fn);
- bool *worksPtr = fcntlOK->object(fn);
- if (worksPtr)
- return *worksPtr;
-
- const bool val = QLockFilePrivate::checkFcntlWorksAfterFlock(fn);
- worksPtr = new bool(val);
- fcntlOK->insert(fn, worksPtr);
-
- return val;
-}
-
-static bool setNativeLocks(const QString &fileName, int fd)
+static bool setNativeLocks(int fd)
{
#if defined(LOCK_EX) && defined(LOCK_NB)
if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs
return false;
+#else
+ Q_UNUSED(fd);
#endif
- struct flock flockData;
- flockData.l_type = F_WRLCK;
- flockData.l_whence = SEEK_SET;
- flockData.l_start = 0;
- flockData.l_len = 0; // 0 = entire file
- flockData.l_pid = getpid();
- if (fcntlWorksAfterFlock(QDir::cleanPath(QFileInfo(fileName).absolutePath()) + QString('/'))
- && fcntl(fd, F_SETLK, &flockData) == -1) { // for networked filesystems
- return false;
- }
return true;
}
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
- // Assemble data, to write in a single call to write
- // (otherwise we'd have to check every write call)
- // Use operator% from the fast builder to avoid multiple memory allocations.
- QByteArray fileData = QByteArray::number(QCoreApplication::applicationPid()) % '\n'
- % QCoreApplication::applicationName().toUtf8() % '\n'
- % QSysInfo::machineHostName().toUtf8() % '\n';
-
const QByteArray lockFileName = QFile::encodeName(fileName);
- const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY | O_CREAT | O_EXCL, 0666);
+ const int fd = qt_safe_open(lockFileName.constData(), O_RDWR | O_CREAT | O_EXCL, 0666);
if (fd < 0) {
switch (errno) {
case EEXIST:
@@ -193,13 +160,14 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
}
}
// Ensure nobody else can delete the file while we have it
- if (!setNativeLocks(fileName, fd)) {
+ if (!setNativeLocks(fd)) {
const int errnoSaved = errno;
qWarning() << "setNativeLocks failed:" << qt_error_string(errnoSaved);
}
+ QByteArray fileData = lockFileContents();
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
@@ -224,31 +192,26 @@ bool QLockFilePrivate::removeStaleLock()
const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY, 0666);
if (fd < 0) // gone already?
return false;
- bool success = setNativeLocks(fileName, fd) && (::unlink(lockFileName) == 0);
+ bool success = setNativeLocks(fd) && (::unlink(lockFileName) == 0);
close(fd);
return success;
}
-bool QLockFilePrivate::isApparentlyStale() const
+bool QLockFilePrivate::isProcessRunning(qint64 pid, const QString &appname)
{
- qint64 pid;
- QString hostname, appname;
- if (getLockInfo(&pid, &hostname, &appname)) {
- if (hostname.isEmpty() || hostname == QSysInfo::machineHostName()) {
- if (::kill(pid, 0) == -1 && errno == ESRCH)
- return true; // PID doesn't exist anymore
- const QString processName = processNameByPid(pid);
- if (!processName.isEmpty()) {
- QFileInfo fi(appname);
- if (fi.isSymLink())
- fi.setFile(fi.symLinkTarget());
- if (processName != fi.fileName())
- return true; // PID got reused by a different application.
- }
- }
+ if (::kill(pid, 0) == -1 && errno == ESRCH)
+ return false; // PID doesn't exist anymore
+
+ const QString processName = processNameByPid(pid);
+ if (!processName.isEmpty()) {
+ QFileInfo fi(appname);
+ if (fi.isSymLink())
+ fi.setFile(fi.symLinkTarget());
+ if (processName != fi.fileName())
+ return false; // PID got reused by a different application.
}
- const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
- return staleLockTime > 0 && qAbs(age) > staleLockTime;
+
+ return true;
}
QString QLockFilePrivate::processNameByPid(qint64 pid)
@@ -258,17 +221,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/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index 4b43181686..6b8028460c 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -2,6 +2,7 @@
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -42,7 +43,6 @@
#include "private/qfilesystementry_p.h"
#include <qt_windows.h>
-#include "QtCore/qcoreapplication.h"
#include "QtCore/qfileinfo.h"
#include "QtCore/qdatetime.h"
#include "QtCore/qdebug.h"
@@ -50,11 +50,6 @@
QT_BEGIN_NAMESPACE
-static inline QByteArray localHostName()
-{
- return qgetenv("COMPUTERNAME");
-}
-
static inline bool fileExists(const wchar_t *fileName)
{
WIN32_FILE_ATTRIBUTE_DATA data;
@@ -73,7 +68,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
#ifndef Q_OS_WINRT
SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
HANDLE fh = CreateFile((const wchar_t*)fileEntry.nativeFilePath().utf16(),
- GENERIC_WRITE,
+ GENERIC_READ | GENERIC_WRITE,
dwShareMode,
&securityAtts,
CREATE_NEW, // error if already exists
@@ -81,7 +76,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
NULL);
#else // !Q_OS_WINRT
HANDLE fh = CreateFile2((const wchar_t*)fileEntry.nativeFilePath().utf16(),
- GENERIC_WRITE,
+ GENERIC_READ | GENERIC_WRITE,
dwShareMode,
CREATE_NEW, // error if already exists
NULL);
@@ -107,15 +102,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
// We hold the lock, continue.
fileHandle = fh;
- // Assemble data, to write in a single call to write
- // (otherwise we'd have to check every write call)
- QByteArray fileData;
- fileData += QByteArray::number(QCoreApplication::applicationPid());
- fileData += '\n';
- fileData += QCoreApplication::applicationName().toUtf8();
- fileData += '\n';
- fileData += localHostName();
- fileData += '\n';
+ QByteArray fileData = lockFileContents();
DWORD bytesWritten = 0;
QLockFile::LockError error = QLockFile::NoError;
if (!WriteFile(fh, fileData.constData(), fileData.size(), &bytesWritten, NULL) || !FlushFileBuffers(fh))
@@ -129,38 +116,33 @@ bool QLockFilePrivate::removeStaleLock()
return QFile::remove(fileName);
}
-bool QLockFilePrivate::isApparentlyStale() const
+bool QLockFilePrivate::isProcessRunning(qint64 pid, const QString &appname)
{
- qint64 pid;
- QString hostname, appname;
-
// On WinRT there seems to be no way of obtaining information about other
// processes due to sandboxing
#ifndef Q_OS_WINRT
- if (getLockInfo(&pid, &hostname, &appname)) {
- if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) {
- HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
- if (!procHandle)
- return true;
- // We got a handle but check if process is still alive
- DWORD exitCode = 0;
- if (!::GetExitCodeProcess(procHandle, &exitCode))
- exitCode = 0;
- ::CloseHandle(procHandle);
- if (exitCode != STILL_ACTIVE)
- return true;
- const QString processName = processNameByPid(pid);
- if (!processName.isEmpty() && processName != appname)
- return true; // PID got reused by a different application.
- }
- }
+ HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+ if (!procHandle)
+ return false;
+
+ // We got a handle but check if process is still alive
+ DWORD exitCode = 0;
+ if (!::GetExitCodeProcess(procHandle, &exitCode))
+ exitCode = 0;
+ ::CloseHandle(procHandle);
+ if (exitCode != STILL_ACTIVE)
+ return false;
+
+ const QString processName = processNameByPid(pid);
+ if (!processName.isEmpty() && processName != appname)
+ return false; // PID got reused by a different application.
+
#else // !Q_OS_WINRT
Q_UNUSED(pid);
- Q_UNUSED(hostname);
Q_UNUSED(appname);
#endif // Q_OS_WINRT
- const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
- return staleLockTime > 0 && qAbs(age) > staleLockTime;
+
+ return true;
}
QString QLockFilePrivate::processNameByPid(qint64 pid)
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
index bb0b533831..ebed1120db 100644
--- a/src/corelib/io/qnoncontiguousbytedevice_p.h
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
@@ -105,12 +105,12 @@ class QNonContiguousByteDeviceByteArrayImpl : public QNonContiguousByteDevice
public:
QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba);
~QNonContiguousByteDeviceByteArrayImpl();
- const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE;
- bool advanceReadPointer(qint64 amount) Q_DECL_OVERRIDE;
- bool atEnd() const Q_DECL_OVERRIDE;
- bool reset() Q_DECL_OVERRIDE;
- qint64 size() const Q_DECL_OVERRIDE;
- qint64 pos() const Q_DECL_OVERRIDE;
+ const char* readPointer(qint64 maximumLength, qint64 &len) override;
+ bool advanceReadPointer(qint64 amount) override;
+ bool atEnd() const override;
+ bool reset() override;
+ qint64 size() const override;
+ qint64 pos() const override;
protected:
QByteArray* byteArray;
qint64 currentPosition;
@@ -121,12 +121,12 @@ class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice
public:
QNonContiguousByteDeviceRingBufferImpl(QSharedPointer<QRingBuffer> rb);
~QNonContiguousByteDeviceRingBufferImpl();
- const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE;
- bool advanceReadPointer(qint64 amount) Q_DECL_OVERRIDE;
- bool atEnd() const Q_DECL_OVERRIDE;
- bool reset() Q_DECL_OVERRIDE;
- qint64 size() const Q_DECL_OVERRIDE;
- qint64 pos() const Q_DECL_OVERRIDE;
+ const char* readPointer(qint64 maximumLength, qint64 &len) override;
+ bool advanceReadPointer(qint64 amount) override;
+ bool atEnd() const override;
+ bool reset() override;
+ qint64 size() const override;
+ qint64 pos() const override;
protected:
QSharedPointer<QRingBuffer> ringBuffer;
qint64 currentPosition;
@@ -139,12 +139,12 @@ class QNonContiguousByteDeviceIoDeviceImpl : public QNonContiguousByteDevice
public:
QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d);
~QNonContiguousByteDeviceIoDeviceImpl();
- const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE;
- bool advanceReadPointer(qint64 amount) Q_DECL_OVERRIDE;
- bool atEnd() const Q_DECL_OVERRIDE;
- bool reset() Q_DECL_OVERRIDE;
- qint64 size() const Q_DECL_OVERRIDE;
- qint64 pos() const Q_DECL_OVERRIDE;
+ const char* readPointer(qint64 maximumLength, qint64 &len) override;
+ bool advanceReadPointer(qint64 amount) override;
+ bool atEnd() const override;
+ bool reset() override;
+ qint64 size() const override;
+ qint64 pos() const override;
protected:
QIODevice* device;
QByteArray* currentReadBuffer;
@@ -162,11 +162,11 @@ class QNonContiguousByteDeviceBufferImpl : public QNonContiguousByteDevice
public:
QNonContiguousByteDeviceBufferImpl(QBuffer *b);
~QNonContiguousByteDeviceBufferImpl();
- const char* readPointer(qint64 maximumLength, qint64 &len) Q_DECL_OVERRIDE;
- bool advanceReadPointer(qint64 amount) Q_DECL_OVERRIDE;
- bool atEnd() const Q_DECL_OVERRIDE;
- bool reset() Q_DECL_OVERRIDE;
- qint64 size() const Q_DECL_OVERRIDE;
+ const char* readPointer(qint64 maximumLength, qint64 &len) override;
+ bool advanceReadPointer(qint64 amount) override;
+ bool atEnd() const override;
+ bool reset() override;
+ qint64 size() const override;
protected:
QBuffer* buffer;
QByteArray byteArray;
@@ -179,13 +179,13 @@ class QByteDeviceWrappingIoDevice : public QIODevice
public:
QByteDeviceWrappingIoDevice (QNonContiguousByteDevice *bd);
~QByteDeviceWrappingIoDevice ();
- virtual bool isSequential () const Q_DECL_OVERRIDE;
- virtual bool atEnd () const Q_DECL_OVERRIDE;
- virtual bool reset () Q_DECL_OVERRIDE;
- virtual qint64 size () const Q_DECL_OVERRIDE;
+ virtual bool isSequential () const override;
+ virtual bool atEnd () const override;
+ virtual bool reset () override;
+ virtual qint64 size () const override;
protected:
- virtual qint64 readData ( char * data, qint64 maxSize ) Q_DECL_OVERRIDE;
- virtual qint64 writeData ( const char * data, qint64 maxSize ) Q_DECL_OVERRIDE;
+ virtual qint64 readData ( char * data, qint64 maxSize ) override;
+ virtual qint64 writeData ( const char * data, qint64 maxSize ) override;
QNonContiguousByteDevice *byteDevice;
};
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 88a54f275f..2ee680a7c6 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -99,6 +99,10 @@ QT_END_NAMESPACE
#include <private/qcore_unix_p.h>
#endif
+#if QT_HAS_INCLUDE(<paths.h>)
+#include <paths.h>
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -450,11 +454,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
@@ -1058,10 +1057,7 @@ bool QProcessPrivate::tryReadFromChannel(Channel *channel)
readBuffer.chop(available - readBytes);
bool didRead = false;
- if (readBytes == 0) {
- if (channel->notifier)
- channel->notifier->setEnabled(false);
- } else if (currentReadChannel == channelIdx) {
+ if (currentReadChannel == channelIdx) {
didRead = true;
if (!emittedReadyRead) {
emittedReadyRead = true;
@@ -1098,10 +1094,9 @@ bool QProcessPrivate::_q_canReadStandardError()
*/
bool QProcessPrivate::_q_canWrite()
{
- if (stdinChannel.notifier)
- stdinChannel.notifier->setEnabled(false);
-
if (writeBuffer.isEmpty()) {
+ if (stdinChannel.notifier)
+ stdinChannel.notifier->setEnabled(false);
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::canWrite(), not writing anything (empty write buffer).");
#endif
@@ -1110,10 +1105,10 @@ bool QProcessPrivate::_q_canWrite()
const bool writeSucceeded = writeToStdin();
- if (stdinChannel.notifier && !writeBuffer.isEmpty())
- stdinChannel.notifier->setEnabled(true);
if (writeBuffer.isEmpty() && stdinChannel.closed)
closeWriteChannel();
+ else if (stdinChannel.notifier)
+ stdinChannel.notifier->setEnabled(!writeBuffer.isEmpty());
return writeSucceeded;
}
@@ -2114,6 +2109,64 @@ 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. Note that the child process may exit and the PID
+ may become invalid without notice. Furthermore, after the child process
+ exits, the same PID may be recycled and used by a completely different
+ process. User code should be careful when using this variable, especially
+ if one intends to forcibly terminate the process by operating system means.
+
+ 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.
@@ -2447,6 +2500,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
@@ -2454,16 +2509,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.
@@ -2474,10 +2523,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);
}
/*!
@@ -2486,11 +2536,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.
@@ -2508,9 +2561,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
@@ -2587,6 +2641,8 @@ QString QProcess::nullDevice()
{
#ifdef Q_OS_WIN
return QStringLiteral("\\\\.\\NUL");
+#elif defined(_PATH_DEVNULL)
+ return QStringLiteral(_PATH_DEVNULL);
#else
return QStringLiteral("/dev/null");
#endif
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 19157bdd02..474fc87de8 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -155,7 +155,7 @@ public:
};
Q_ENUM(ExitStatus)
- explicit QProcess(QObject *parent = Q_NULLPTR);
+ explicit QProcess(QObject *parent = nullptr);
virtual ~QProcess();
void start(const QString &program, const QStringList &arguments, OpenMode mode = ReadWrite);
@@ -163,7 +163,8 @@ public:
void start(const QString &command, OpenMode mode = ReadWrite);
#endif
void start(OpenMode mode = ReadWrite);
- bool open(OpenMode mode = ReadWrite) Q_DECL_OVERRIDE;
+ bool startDetached(qint64 *pid = nullptr);
+ bool open(OpenMode mode = ReadWrite) override;
QString program() const;
void setProgram(const QString &program);
@@ -226,8 +227,8 @@ public:
qint64 processId() const;
bool waitForStarted(int msecs = 30000);
- bool waitForReadyRead(int msecs = 30000) Q_DECL_OVERRIDE;
- bool waitForBytesWritten(int msecs = 30000) Q_DECL_OVERRIDE;
+ bool waitForReadyRead(int msecs = 30000) override;
+ bool waitForBytesWritten(int msecs = 30000) override;
bool waitForFinished(int msecs = 30000);
QByteArray readAllStandardOutput();
@@ -237,12 +238,12 @@ public:
QProcess::ExitStatus exitStatus() const;
// QIODevice
- qint64 bytesAvailable() const Q_DECL_OVERRIDE; // ### Qt6: remove trivial override
- qint64 bytesToWrite() const Q_DECL_OVERRIDE;
- bool isSequential() const Q_DECL_OVERRIDE;
- bool canReadLine() const Q_DECL_OVERRIDE; // ### Qt6: remove trivial override
- void close() Q_DECL_OVERRIDE;
- bool atEnd() const Q_DECL_OVERRIDE; // ### Qt6: remove trivial override
+ qint64 bytesAvailable() const override; // ### Qt6: remove trivial override
+ qint64 bytesToWrite() const override;
+ bool isSequential() const override;
+ bool canReadLine() const override; // ### Qt6: remove trivial override
+ void close() override;
+ bool atEnd() const override; // ### Qt6: remove trivial override
static int execute(const QString &program, const QStringList &arguments);
static int execute(const QString &command);
@@ -252,7 +253,7 @@ public:
#if defined(Q_QDOC)
= QString()
#endif
- , qint64 *pid = Q_NULLPTR);
+ , qint64 *pid = nullptr);
#if !defined(Q_QDOC)
static bool startDetached(const QString &program, const QStringList &arguments); // ### Qt6: merge overloads
#endif
@@ -285,8 +286,8 @@ protected:
virtual void setupChildProcess();
// QIODevice
- qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
- qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE;
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
private:
Q_DECLARE_PRIVATE(QProcess)
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index c5abf7b762..aa7ecbe91d 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -350,9 +350,9 @@ 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);
+ bool processStarted(QString *errorMessage = nullptr);
void terminateProcess();
void killProcess();
void findExitCode();
@@ -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 318c633017..68b7a8bf9b 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");
}
@@ -915,7 +885,7 @@ bool QProcessPrivate::waitForDeadChild()
// read the process information from our fd
forkfd_info info;
int ret;
- EINTR_LOOP(ret, forkfd_wait(forkfd, &info, Q_NULLPTR));
+ EINTR_LOOP(ret, forkfd_wait(forkfd, &info, nullptr));
exitCode = info.status;
crashed = info.code != CLD_EXITED;
@@ -933,7 +903,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);
@@ -949,6 +919,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;
@@ -965,6 +946,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());
@@ -975,23 +968,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));
@@ -1021,6 +1019,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 fa9efcb1ce..3a62a67e3b 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -48,6 +48,7 @@
#include <qdir.h>
#include <qelapsedtimer.h>
#include <qfileinfo.h>
+#include <qrandom.h>
#include <qregexp.h>
#include <qwineventnotifier.h>
#include <private/qsystemlibrary_p.h>
@@ -99,10 +100,9 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
wchar_t pipeName[256];
unsigned int attempts = 1000;
forever {
- // ### The user must make sure to call qsrand() to make the pipe names less predictable.
- // ### Replace the call to qrand() with a secure version, once we have it in Qt.
_snwprintf(pipeName, sizeof(pipeName) / sizeof(pipeName[0]),
- L"\\\\.\\pipe\\qt-%lX-%X", long(QCoreApplication::applicationPid()), qrand());
+ L"\\\\.\\pipe\\qt-%lX-%X", long(QCoreApplication::applicationPid()),
+ QRandomGenerator::global()->generate());
DWORD dwOpenMode = FILE_FLAG_OVERLAPPED;
DWORD dwOutputBufferSize = 0;
@@ -115,9 +115,7 @@ static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
dwOpenMode |= PIPE_ACCESS_INBOUND;
dwInputBufferSize = dwPipeBufferSize;
}
- DWORD dwPipeFlags = PIPE_TYPE_BYTE | PIPE_WAIT;
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
- dwPipeFlags |= PIPE_REJECT_REMOTE_CLIENTS;
+ DWORD dwPipeFlags = PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS;
hServer = CreateNamedPipe(pipeName,
dwOpenMode,
dwPipeFlags,
@@ -358,7 +356,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 +386,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 +456,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 +502,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 +532,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 +547,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 +834,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 +845,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 +869,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 +922,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..35a0de4fb7 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;
+ qsizetype m_len;
+ qsizetype 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,
@@ -913,8 +911,8 @@ public:
inline QDynamicBufferResourceRoot(const QString &_root) : root(_root), buffer(0) { }
inline ~QDynamicBufferResourceRoot() { }
inline const uchar *mappingBuffer() const { return buffer; }
- virtual QString mappingRoot() const Q_DECL_OVERRIDE { return root; }
- virtual ResourceRootType type() const Q_DECL_OVERRIDE { return Resource_Buffer; }
+ virtual QString mappingRoot() const override { return root; }
+ virtual ResourceRootType type() const override { return Resource_Buffer; }
// size == -1 means "unknown"
bool registerSelf(const uchar *b, int size)
@@ -996,7 +994,7 @@ public:
}
}
QString mappingFile() const { return fileName; }
- virtual ResourceRootType type() const Q_DECL_OVERRIDE { return Resource_File; }
+ virtual ResourceRootType type() const override { return Resource_File; }
bool registerSelf(const QString &f) {
bool fromMM = false;
diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h
index 6a4e215864..207a88b0ba 100644
--- a/src/corelib/io/qresource_iterator_p.h
+++ b/src/corelib/io/qresource_iterator_p.h
@@ -63,10 +63,10 @@ public:
QResourceFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
~QResourceFileEngineIterator();
- QString next() Q_DECL_OVERRIDE;
- bool hasNext() const Q_DECL_OVERRIDE;
+ QString next() override;
+ bool hasNext() const override;
- QString currentFileName() const Q_DECL_OVERRIDE;
+ QString currentFileName() const override;
private:
mutable QStringList entries;
diff --git a/src/corelib/io/qresource_p.h b/src/corelib/io/qresource_p.h
index e08ba64d2b..dcfe46704c 100644
--- a/src/corelib/io/qresource_p.h
+++ b/src/corelib/io/qresource_p.h
@@ -64,52 +64,52 @@ public:
explicit QResourceFileEngine(const QString &path);
~QResourceFileEngine();
- virtual void setFileName(const QString &file) Q_DECL_OVERRIDE;
+ virtual void setFileName(const QString &file) override;
- virtual bool open(QIODevice::OpenMode flags) Q_DECL_OVERRIDE ;
- virtual bool close() Q_DECL_OVERRIDE;
- virtual bool flush() Q_DECL_OVERRIDE;
- virtual qint64 size() const Q_DECL_OVERRIDE;
- virtual qint64 pos() const Q_DECL_OVERRIDE;
+ virtual bool open(QIODevice::OpenMode flags) override ;
+ virtual bool close() override;
+ virtual bool flush() override;
+ virtual qint64 size() const override;
+ virtual qint64 pos() const override;
virtual bool atEnd() const;
- virtual bool seek(qint64) Q_DECL_OVERRIDE;
- virtual qint64 read(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
- virtual qint64 write(const char *data, qint64 len) Q_DECL_OVERRIDE;
+ virtual bool seek(qint64) override;
+ virtual qint64 read(char *data, qint64 maxlen) override;
+ virtual qint64 write(const char *data, qint64 len) override;
- virtual bool remove() Q_DECL_OVERRIDE;
- virtual bool copy(const QString &newName) Q_DECL_OVERRIDE;
- virtual bool rename(const QString &newName) Q_DECL_OVERRIDE;
- virtual bool link(const QString &newName) Q_DECL_OVERRIDE;
+ virtual bool remove() override;
+ virtual bool copy(const QString &newName) override;
+ virtual bool rename(const QString &newName) override;
+ virtual bool link(const QString &newName) override;
- virtual bool isSequential() const Q_DECL_OVERRIDE;
+ virtual bool isSequential() const override;
- virtual bool isRelativePath() const Q_DECL_OVERRIDE;
+ virtual bool isRelativePath() const override;
- virtual bool mkdir(const QString &dirName, bool createParentDirectories) const Q_DECL_OVERRIDE;
- virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const Q_DECL_OVERRIDE;
+ virtual bool mkdir(const QString &dirName, bool createParentDirectories) const override;
+ virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const override;
- virtual bool setSize(qint64 size) Q_DECL_OVERRIDE;
+ virtual bool setSize(qint64 size) override;
- virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const Q_DECL_OVERRIDE;
+ virtual QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const override;
- virtual bool caseSensitive() const Q_DECL_OVERRIDE;
+ virtual bool caseSensitive() const override;
- virtual FileFlags fileFlags(FileFlags type) const Q_DECL_OVERRIDE;
+ virtual FileFlags fileFlags(FileFlags type) const override;
- virtual bool setPermissions(uint perms) Q_DECL_OVERRIDE;
+ virtual bool setPermissions(uint perms) override;
- virtual QString fileName(QAbstractFileEngine::FileName file) const Q_DECL_OVERRIDE;
+ virtual QString fileName(QAbstractFileEngine::FileName file) const override;
- virtual uint ownerId(FileOwner) const Q_DECL_OVERRIDE;
- virtual QString owner(FileOwner) const Q_DECL_OVERRIDE;
+ virtual uint ownerId(FileOwner) const override;
+ virtual QString owner(FileOwner) const override;
- virtual QDateTime fileTime(FileTime time) const Q_DECL_OVERRIDE;
+ virtual QDateTime fileTime(FileTime time) const override;
- virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) Q_DECL_OVERRIDE;
- virtual Iterator *endEntryList() Q_DECL_OVERRIDE;
+ virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
+ virtual Iterator *endEntryList() override;
- bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) Q_DECL_OVERRIDE;
- bool supportsExtension(Extension extension) const Q_DECL_OVERRIDE;
+ bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) override;
+ bool supportsExtension(Extension extension) const override;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index 3f45ca5f91..56934a9a0f 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -184,7 +184,8 @@ void QSaveFile::setFileName(const QString &name)
Important: the \a mode must include QIODevice::WriteOnly.
It may also have additional flags, such as QIODevice::Text and QIODevice::Unbuffered.
- QIODevice::ReadWrite and QIODevice::Append are not supported at the moment.
+ QIODevice::ReadWrite, QIODevice::Append, QIODevice::NewOnly and
+ QIODevice::ExistingOnly are not supported at the moment.
\sa QIODevice::OpenMode, setFileName()
*/
@@ -201,7 +202,8 @@ bool QSaveFile::open(OpenMode mode)
return false;
}
// In the future we could implement ReadWrite by copying from the existing file to the temp file...
- if ((mode & ReadOnly) || (mode & Append)) {
+ // The implications of NewOnly and ExistingOnly when used with QSaveFile need to be considered carefully...
+ if (mode & (ReadOnly | Append | NewOnly | ExistingOnly)) {
qWarning("QSaveFile::open: Unsupported open mode 0x%x", int(mode));
return false;
}
@@ -231,7 +233,38 @@ bool QSaveFile::open(OpenMode mode)
d->finalFileName = existingFile.filePath();
}
- d->fileEngine = new QTemporaryFileEngine;
+ auto openDirectly = [&]() {
+ d->fileEngine = QAbstractFileEngine::create(d->finalFileName);
+ if (d->fileEngine->open(mode | QIODevice::Unbuffered)) {
+ d->useTemporaryFile = false;
+ QFileDevice::open(mode);
+ return true;
+ }
+ return false;
+ };
+
+#ifdef Q_OS_WIN
+ // check if it is an Alternate Data Stream
+ if (d->finalFileName == d->fileName && d->fileName.indexOf(QLatin1Char(':'), 2) > 1) {
+ // yes, we can't rename onto it...
+ if (d->directWriteFallback) {
+ if (openDirectly())
+ return true;
+ d->setError(d->fileEngine->error(), d->fileEngine->errorString());
+ delete d->fileEngine;
+ d->fileEngine = 0;
+ } else {
+ QString msg =
+ QSaveFile::tr("QSaveFile cannot open '%1' without direct write fallback "
+ "enabled: path contains an Alternate Data Stream specifier")
+ .arg(QDir::toNativeSeparators(d->fileName));
+ d->setError(QFileDevice::OpenError, msg);
+ }
+ return false;
+ }
+#endif
+
+ d->fileEngine = new QTemporaryFileEngine(&d->finalFileName);
// if the target file exists, we'll copy its permissions below,
// but until then, let's ensure the temporary file is not accessible
// to a third party
@@ -243,12 +276,8 @@ bool QSaveFile::open(OpenMode mode)
#ifdef Q_OS_UNIX
if (d->directWriteFallback && err == QFileDevice::OpenError && errno == EACCES) {
delete d->fileEngine;
- d->fileEngine = QAbstractFileEngine::create(d->finalFileName);
- if (d->fileEngine->open(mode | QIODevice::Unbuffered)) {
- d->useTemporaryFile = false;
- QFileDevice::open(mode);
+ if (openDirectly())
return true;
- }
err = d->fileEngine->error();
}
#endif
diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h
index 09d6e29272..200068d30d 100644
--- a/src/corelib/io/qsavefile.h
+++ b/src/corelib/io/qsavefile.h
@@ -67,15 +67,15 @@ public:
explicit QSaveFile(const QString &name);
#ifndef QT_NO_QOBJECT
- explicit QSaveFile(QObject *parent = Q_NULLPTR);
+ explicit QSaveFile(QObject *parent = nullptr);
explicit QSaveFile(const QString &name, QObject *parent);
#endif
~QSaveFile();
- QString fileName() const Q_DECL_OVERRIDE;
+ QString fileName() const override;
void setFileName(const QString &name);
- bool open(OpenMode flags) Q_DECL_OVERRIDE;
+ bool open(OpenMode flags) override;
bool commit();
void cancelWriting();
@@ -84,10 +84,10 @@ public:
bool directWriteFallback() const;
protected:
- qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE;
+ qint64 writeData(const char *data, qint64 len) override;
private:
- void close() Q_DECL_OVERRIDE;
+ void close() override;
#if !QT_CONFIG(translation)
static QString tr(const char *string) { return QString::fromLatin1(string); }
#endif
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 9b930e7e14..4b1b9888d8 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -1405,6 +1405,11 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
return;
}
+ if (!readOnly && !confFile->isWritable()) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
#ifndef QT_BOOTSTRAPPED
/*
Use a lockfile in order to protect us against other QSettings instances
@@ -1414,17 +1419,11 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
Concurrent read and write are not a problem because the writing operation is atomic.
*/
QLockFile lockFile(confFile->name + QLatin1String(".lock"));
-#endif
- if (!readOnly) {
- if (!confFile->isWritable()
-#ifndef QT_BOOTSTRAPPED
- || !lockFile.lock()
-#endif
- ) {
- setStatus(QSettings::AccessError);
- return;
- }
+ if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
+ setStatus(QSettings::AccessError);
+ return;
}
+#endif
/*
We hold the lock. Let's reread the file if it has changed
@@ -1452,7 +1451,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
Files that we can't read (because of permissions or
because they don't exist) are treated as empty files.
*/
- if (file.isReadable() && fileInfo.size() != 0) {
+ if (file.isReadable() && file.size() != 0) {
bool ok = false;
#ifdef Q_OS_MAC
if (format == QSettings::NativeFormat) {
@@ -1496,6 +1495,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
QSaveFile sf(confFile->name);
+ sf.setDirectWriteFallback(!atomicSyncOnly);
#else
QFile sf(confFile->name);
#endif
@@ -1802,6 +1802,8 @@ struct QSettingsIniSection
inline QSettingsIniSection() : position(-1) {}
};
+Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE);
+
typedef QMap<QString, QSettingsIniSection> IniMap;
/*
@@ -2199,10 +2201,16 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
QSettings can safely be used from different processes (which can
be different instances of your application running at the same
time or different applications altogether) to read and write to
- the same system locations. It uses advisory file locking and a
- smart merging algorithm to ensure data integrity. Note that sync()
- imports changes made by other processes (in addition to writing
- the changes from this QSettings).
+ the same system locations, provided certain conditions are met. For
+ QSettings::IniFormat, it uses advisory file locking and a smart merging
+ algorithm to ensure data integrity. The condition for that to work is that
+ the writeable configuration file must be a regular file and must reside in
+ a directory that the current user can create new, temporary files in. If
+ that is not the case, then one must use setAtomicSyncRequired() to turn the
+ safety off.
+
+ Note that sync() imports changes made by other processes (in addition to
+ writing the changes from this QSettings).
\section1 Platform-Specific Notes
@@ -2888,6 +2896,50 @@ QSettings::Status QSettings::status() const
}
/*!
+ \since 5.10
+
+ Returns \c true if QSettings is only allowed to perform atomic saving and
+ reloading (synchronization) of the settings. Returns \c false if it is
+ allowed to save the settings contents directly to the configuration file.
+
+ The default is \c true.
+
+ \sa setAtomicSyncRequired(), QSaveFile
+*/
+bool QSettings::isAtomicSyncRequired() const
+{
+ Q_D(const QSettings);
+ return d->atomicSyncOnly;
+}
+
+/*!
+ \since 5.10
+
+ Configures whether QSettings is required to perform atomic saving and
+ reloading (synchronization) of the settings. If the \a enable argument is
+ \c true (the default), sync() will only perform synchronization operations
+ that are atomic. If this is not possible, sync() will fail and status()
+ will be an error condition.
+
+ Setting this property to \c false will allow QSettings to write directly to
+ the configuration file and ignore any errors trying to lock it against
+ other processes trying to write at the same time. Because of the potential
+ for corruption, this option should be used with care, but is required in
+ certain conditions, like a QSettings::IniFormat configuration file that
+ exists in an otherwise non-writeable directory or NTFS Alternate Data
+ Streams.
+
+ See \l QSaveFile for more information on the feature.
+
+ \sa isAtomicSyncRequired(), QSaveFile
+*/
+void QSettings::setAtomicSyncRequired(bool enable)
+{
+ Q_D(QSettings);
+ d->atomicSyncOnly = enable;
+}
+
+/*!
Appends \a prefix to the current group.
The current group is automatically prepended to all keys
diff --git a/src/corelib/io/qsettings.h b/src/corelib/io/qsettings.h
index edd59026ed..d78edd23a2 100644
--- a/src/corelib/io/qsettings.h
+++ b/src/corelib/io/qsettings.h
@@ -88,7 +88,7 @@ public:
NativeFormat,
IniFormat,
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
Registry32Format,
Registry64Format,
#endif
@@ -125,13 +125,13 @@ public:
#ifndef QT_NO_QOBJECT
explicit QSettings(const QString &organization,
- const QString &application = QString(), QObject *parent = Q_NULLPTR);
+ const QString &application = QString(), QObject *parent = nullptr);
QSettings(Scope scope, const QString &organization,
- const QString &application = QString(), QObject *parent = Q_NULLPTR);
+ const QString &application = QString(), QObject *parent = nullptr);
QSettings(Format format, Scope scope, const QString &organization,
- const QString &application = QString(), QObject *parent = Q_NULLPTR);
- QSettings(const QString &fileName, Format format, QObject *parent = Q_NULLPTR);
- explicit QSettings(QObject *parent = Q_NULLPTR);
+ const QString &application = QString(), QObject *parent = nullptr);
+ QSettings(const QString &fileName, Format format, QObject *parent = nullptr);
+ explicit QSettings(QObject *parent = nullptr);
#else
explicit QSettings(const QString &organization,
const QString &application = QString());
@@ -146,6 +146,8 @@ public:
void clear();
void sync();
Status status() const;
+ bool isAtomicSyncRequired() const;
+ void setAtomicSyncRequired(bool enable);
void beginGroup(const QString &prefix);
void endGroup();
@@ -197,7 +199,7 @@ public:
protected:
#ifndef QT_NO_QOBJECT
- bool event(QEvent *event) Q_DECL_OVERRIDE;
+ bool event(QEvent *event) override;
#endif
private:
diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp
index 2a08ee2e64..aa14d8435a 100644
--- a/src/corelib/io/qsettings_mac.cpp
+++ b/src/corelib/io/qsettings_mac.cpp
@@ -616,7 +616,7 @@ bool QConfFileSettingsPrivate::readPlistFile(const QByteArray &data, ParsedSetti
{
QCFType<CFDataRef> cfData = data.toRawCFData();
QCFType<CFPropertyListRef> propertyList =
- CFPropertyListCreateWithData(kCFAllocatorDefault, cfData, kCFPropertyListImmutable, Q_NULLPTR, Q_NULLPTR);
+ CFPropertyListCreateWithData(kCFAllocatorDefault, cfData, kCFPropertyListImmutable, nullptr, nullptr);
if (!propertyList)
return true;
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index 639605d8c4..d18c96a06c 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;
@@ -247,6 +249,7 @@ protected:
QString groupPrefix;
bool fallbacks;
bool pendingChanges;
+ bool atomicSyncOnly = true;
mutable QSettings::Status status;
};
@@ -258,17 +261,17 @@ public:
QConfFileSettingsPrivate(const QString &fileName, QSettings::Format format);
~QConfFileSettingsPrivate();
- void remove(const QString &key) Q_DECL_OVERRIDE;
- void set(const QString &key, const QVariant &value) Q_DECL_OVERRIDE;
- bool get(const QString &key, QVariant *value) const Q_DECL_OVERRIDE;
+ void remove(const QString &key) override;
+ void set(const QString &key, const QVariant &value) override;
+ bool get(const QString &key, QVariant *value) const override;
- QStringList children(const QString &prefix, ChildSpec spec) const Q_DECL_OVERRIDE;
+ QStringList children(const QString &prefix, ChildSpec spec) const override;
- void clear() Q_DECL_OVERRIDE;
- void sync() Q_DECL_OVERRIDE;
- void flush() Q_DECL_OVERRIDE;
- bool isWritable() const Q_DECL_OVERRIDE;
- QString fileName() const Q_DECL_OVERRIDE;
+ void clear() override;
+ void sync() override;
+ void flush() override;
+ bool isWritable() const override;
+ QString fileName() const override;
bool readIniFile(const QByteArray &data, UnparsedSettingsMap *unparsedIniSections);
static bool readIniSection(const QSettingsKey &section, const QByteArray &data,
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index f2368c3b23..b3a5bd797a 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -48,6 +48,14 @@
#include <qcoreapplication.h>
#endif
+#if QT_HAS_INCLUDE(<paths.h>)
+#include <paths.h>
+#endif
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
#ifndef QT_NO_STANDARDPATHS
QT_BEGIN_NAMESPACE
@@ -183,7 +191,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 +215,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>"
@@ -509,6 +517,27 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr
QStringList searchPaths = paths;
if (paths.isEmpty()) {
QByteArray pEnv = qgetenv("PATH");
+ if (Q_UNLIKELY(pEnv.isNull())) {
+ // Get a default path. POSIX.1 does not actually require this, but
+ // most Unix libc fall back to confstr(_CS_PATH) if the PATH
+ // environment variable isn't set. Let's try to do the same.
+#if defined(_PATH_DEFPATH)
+ // BSD API.
+ pEnv = _PATH_DEFPATH;
+#elif defined(_CS_PATH)
+ // POSIX API.
+ size_t n = confstr(_CS_PATH, nullptr, 0);
+ if (n) {
+ pEnv.resize(n);
+ // size()+1 is ok because QByteArray always has an extra NUL-terminator
+ confstr(_CS_PATH, pEnv.data(), pEnv.size() + 1);
+ }
+#else
+ // Windows SDK's execvpe() does not have a fallback, so we won't
+ // apply one either.
+#endif
+ }
+
// Remove trailing slashes, which occur on Windows.
const QStringList rawPaths = QString::fromLocal8Bit(pEnv.constData()).split(QDir::listSeparator(), QString::SkipEmptyParts);
searchPaths.reserve(rawPaths.size());
diff --git a/src/corelib/io/qstandardpaths_mac.mm b/src/corelib/io/qstandardpaths_mac.mm
index ab73edb008..11b5cc8c37 100644
--- a/src/corelib/io/qstandardpaths_mac.mm
+++ b/src/corelib/io/qstandardpaths_mac.mm
@@ -203,28 +203,17 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
if (type == AppDataLocation || type == AppLocalDataLocation) {
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle) {
- CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle);
- CFStringRef cfBundlePath = CFURLCopyFileSystemPath(bundleUrl, kCFURLPOSIXPathStyle);
- QString bundlePath = QString::fromCFString(cfBundlePath);
- CFRelease(cfBundlePath);
- CFRelease(bundleUrl);
-
- CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(mainBundle);
- CFStringRef cfResourcesPath = CFURLCopyFileSystemPath(resourcesUrl,
- kCFURLPOSIXPathStyle);
- QString resourcesPath = QString::fromCFString(cfResourcesPath);
- CFRelease(cfResourcesPath);
- CFRelease(resourcesUrl);
-
- // Handle bundled vs unbundled executables. CFBundleGetMainBundle() returns
- // a valid bundle in both cases. CFBundleCopyResourcesDirectoryURL() returns
- // an absolute path for unbundled executables.
- if (resourcesPath.startsWith(QLatin1Char('/')))
- dirs.append(resourcesPath);
- else
- dirs.append(bundlePath + resourcesPath);
+ if (QCFType<CFURLRef> resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle)) {
+ if (QCFType<CFURLRef> absoluteResouresURL = CFURLCopyAbsoluteURL(resourcesURL)) {
+ if (QCFType<CFStringRef> path = CFURLCopyFileSystemPath(absoluteResouresURL,
+ kCFURLPOSIXPathStyle)) {
+ dirs.append(QString::fromCFString(path));
+ }
+ }
+ }
}
}
+
const QString localDir = writableLocation(type);
if (!localDir.isEmpty())
dirs.prepend(localDir);
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index f0ff46fe7f..e49edd9a40 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -42,6 +42,7 @@
#include <qfile.h>
#include <qhash.h>
#include <qtextstream.h>
+#include <qregularexpression.h>
#include <private/qfilesystemengine_p.h>
#include <errno.h>
#include <stdlib.h>
@@ -169,7 +170,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
break;
}
-#ifndef QT_BOOTSTRAPPED
+#if QT_CONFIG(regularexpression)
// http://www.freedesktop.org/wiki/Software/xdg-user-dirs
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
if (xdgConfigHome.isEmpty())
@@ -179,11 +180,12 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QHash<QString, QString> lines;
QTextStream stream(&file);
// Only look for lines like: XDG_DESKTOP_DIR="$HOME/Desktop"
- QRegExp exp(QLatin1String("^XDG_(.*)_DIR=(.*)$"));
+ QRegularExpression exp(QLatin1String("^XDG_(.*)_DIR=(.*)$"));
while (!stream.atEnd()) {
const QString &line = stream.readLine();
- if (exp.indexIn(line) != -1) {
- const QStringList lst = exp.capturedTexts();
+ QRegularExpressionMatch match = exp.match(line);
+ if (match.hasMatch()) {
+ const QStringList lst = match.capturedTexts();
const QString key = lst.at(1);
QString value = lst.at(2);
if (value.length() > 2
@@ -230,7 +232,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
}
}
}
-#endif
+#endif // QT_CONFIG(regularexpression)
QString path;
switch (type) {
diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp
index a06b204da7..eeb02419c3 100644
--- a/src/corelib/io/qstandardpaths_win.cpp
+++ b/src/corelib/io/qstandardpaths_win.cpp
@@ -227,7 +227,15 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
QString applicationDirPath = qApp ? QCoreApplication::applicationDirPath()
: QFileInfo(qAppFileName()).path();
dirs.append(applicationDirPath);
- dirs.append(applicationDirPath + QLatin1String("/data"));
+ const QString dataDir = 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/qstorageinfo_mac.cpp b/src/corelib/io/qstorageinfo_mac.cpp
index 0f271f2bc6..8b06543d71 100644
--- a/src/corelib/io/qstorageinfo_mac.cpp
+++ b/src/corelib/io/qstorageinfo_mac.cpp
@@ -112,7 +112,7 @@ void QStorageInfoPrivate::retrieveUrlProperties(bool initRootPath)
QCFType<CFArrayRef> keys = CFArrayCreate(kCFAllocatorDefault,
initRootPath ? rootPathKeys : propertyKeys,
size,
- Q_NULLPTR);
+ nullptr);
if (!keys)
return;
@@ -178,9 +178,9 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
QList<QStorageInfo> volumes;
QCFType<CFURLEnumeratorRef> enumerator;
- enumerator = CFURLEnumeratorCreateForMountedVolumes(Q_NULLPTR,
+ enumerator = CFURLEnumeratorCreateForMountedVolumes(nullptr,
kCFURLEnumeratorSkipInvisibles,
- Q_NULLPTR);
+ nullptr);
CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
do {
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 1fc32e0f2d..7664b77d81 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -45,6 +45,7 @@
#include <QtCore/qtextstream.h>
#include <QtCore/private/qcore_unix_p.h>
+#include <QtCore/private/qlocale_tools_p.h>
#include <errno.h>
#include <sys/stat.h>
@@ -107,6 +108,13 @@
# endif // QT_LARGEFILE_SUPPORT
#endif // Q_OS_BSD4
+#if QT_HAS_INCLUDE(<paths.h>)
+# include <paths.h>
+#endif
+#ifndef _PATH_MOUNTED
+# define _PATH_MOUNTED "/etc/mnttab"
+#endif
+
QT_BEGIN_NAMESPACE
class QStorageIterator
@@ -121,6 +129,7 @@ public:
inline QByteArray fileSystemType() const;
inline QByteArray device() const;
inline QByteArray options() const;
+ inline QByteArray subvolume() const;
private:
#if defined(Q_OS_BSD4)
QT_STATFSBUF *stat_buf;
@@ -136,9 +145,36 @@ private:
QByteArray m_device;
QByteArray m_options;
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
+ struct mountinfoent : public mntent {
+ // Details from proc(5) section from /proc/<pid>/mountinfo:
+ //(1) mount ID: a unique ID for the mount (may be reused after umount(2)).
+ int mount_id;
+ //(2) parent ID: the ID of the parent mount (or of self for the top of the mount tree).
+// int parent_id;
+ //(3) major:minor: the value of st_dev for files on this filesystem (see stat(2)).
+// dev_t rdev;
+ //(4) root: the pathname of the directory in the filesystem which forms the root of this mount.
+ char *subvolume;
+ //(5) mount point: the pathname of the mount point relative to the process's root directory.
+// char *mnt_dir; // in mntent
+ //(6) mount options: per-mount options.
+// char *mnt_opts; // in mntent
+ //(7) optional fields: zero or more fields of the form "tag[:value]"; see below.
+// int flags;
+ //(8) separator: the end of the optional fields is marked by a single hyphen.
+
+ //(9) filesystem type: the filesystem type in the form "type[.subtype]".
+// char *mnt_type; // in mntent
+ //(10) mount source: filesystem-specific information or "none".
+// char *mnt_fsname; // in mntent
+ //(11) super options: per-superblock options.
+ char *superopts;
+ };
+
FILE *fp;
- mntent mnt;
QByteArray buffer;
+ mountinfoent mnt;
+ bool usingMountinfo;
#elif defined(Q_OS_HAIKU)
BVolumeRoster m_volumeRoster;
@@ -239,13 +275,15 @@ inline QByteArray QStorageIterator::options() const
return QByteArray();
}
+inline QByteArray QStorageIterator::subvolume() const
+{
+ return QByteArray();
+}
#elif defined(Q_OS_SOLARIS)
-static const char pathMounted[] = "/etc/mnttab";
-
inline QStorageIterator::QStorageIterator()
{
- const int fd = qt_safe_open(pathMounted, O_RDONLY);
+ const int fd = qt_safe_open(_PATH_MOUNTED, O_RDONLY);
fp = ::fdopen(fd, "r");
}
@@ -257,7 +295,7 @@ inline QStorageIterator::~QStorageIterator()
inline bool QStorageIterator::isValid() const
{
- return fp != Q_NULLPTR;
+ return fp != nullptr;
}
inline bool QStorageIterator::next()
@@ -280,13 +318,15 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(mnt.mnt_mntopts);
}
+inline QByteArray QStorageIterator::subvolume() const
+{
+ return QByteArray();
+}
#elif defined(Q_OS_ANDROID)
-static const QLatin1String pathMounted("/proc/mounts");
-
inline QStorageIterator::QStorageIterator()
{
- file.setFileName(pathMounted);
+ file.setFileName(_PATH_MOUNTED);
file.open(QIODevice::ReadOnly | QIODevice::Text);
}
@@ -337,32 +377,170 @@ inline QByteArray QStorageIterator::options() const
return m_options;
}
+inline QByteArray QStorageIterator::subvolume() const
+{
+ return QByteArray();
+}
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
-static const char pathMounted[] = "/etc/mtab";
static const int bufferSize = 1024; // 2 paths (mount point+device) and metainfo;
// should be enough
inline QStorageIterator::QStorageIterator() :
buffer(QByteArray(bufferSize, 0))
{
- fp = ::setmntent(pathMounted, "r");
+ fp = nullptr;
+
+#ifdef Q_OS_LINUX
+ // first, try to open /proc/self/mountinfo, which has more details
+ fp = ::fopen("/proc/self/mountinfo", "re");
+#endif
+ if (fp) {
+ usingMountinfo = true;
+ } else {
+ usingMountinfo = false;
+ fp = ::setmntent(_PATH_MOUNTED, "r");
+ }
}
inline QStorageIterator::~QStorageIterator()
{
- if (fp)
- ::endmntent(fp);
+ if (fp) {
+ if (usingMountinfo)
+ ::fclose(fp);
+ else
+ ::endmntent(fp);
+ }
}
inline bool QStorageIterator::isValid() const
{
- return fp != Q_NULLPTR;
+ return fp != nullptr;
}
inline bool QStorageIterator::next()
{
- return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != Q_NULLPTR;
+ mnt.subvolume = nullptr;
+ mnt.superopts = nullptr;
+ if (!usingMountinfo)
+ return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != nullptr;
+
+ // Helper function to parse paths that the kernel inserts escape sequences
+ // for. The unescaped string is left at \a src and is properly
+ // NUL-terminated. Returns a pointer to the delimiter that terminated the
+ // path, or nullptr if it failed.
+ auto parseMangledPath = [](char *src) {
+ // The kernel escapes with octal the following characters:
+ // space ' ', tab '\t', backslask '\\', and newline '\n'
+ char *dst = src;
+ while (*src) {
+ switch (*src) {
+ case ' ':
+ // Unescaped space: end of the field.
+ *dst = '\0';
+ return src;
+
+ default:
+ *dst++ = *src++;
+ break;
+
+ case '\\':
+ // It always uses exactly three octal characters.
+ ++src;
+ char c = (*src++ - '0') << 6;
+ c |= (*src++ - '0') << 3;
+ c |= (*src++ - '0');
+ *dst++ = c;
+ break;
+ }
+ }
+
+ // Found a NUL before the end of the field.
+ src = nullptr;
+ return src;
+ };
+
+ char *ptr = buffer.data();
+ if (fgets(ptr, buffer.size(), fp) == nullptr)
+ return false;
+
+ size_t len = strlen(buffer.data());
+ if (len == 0)
+ return false;
+ if (ptr[len - 1] == '\n')
+ ptr[len - 1] = '\0';
+
+ // parse the line
+ bool ok;
+ mnt.mnt_freq = 0;
+ mnt.mnt_passno = 0;
+
+ mnt.mount_id = qstrtoll(ptr, const_cast<const char **>(&ptr), 10, &ok);
+ if (!ptr || !ok)
+ return false;
+
+ int parent_id = qstrtoll(ptr, const_cast<const char **>(&ptr), 10, &ok);
+ Q_UNUSED(parent_id);
+ if (!ptr || !ok)
+ return false;
+
+ int rdevmajor = qstrtoll(ptr, const_cast<const char **>(&ptr), 10, &ok);
+ if (!ptr || !ok)
+ return false;
+ if (*ptr != ':')
+ return false;
+ int rdevminor = qstrtoll(ptr + 1, const_cast<const char **>(&ptr), 10, &ok);
+ if (!ptr || !ok)
+ return false;
+ Q_UNUSED(rdevmajor);
+ Q_UNUSED(rdevminor);
+
+ if (*ptr != ' ')
+ return false;
+
+ mnt.subvolume = ++ptr;
+ ptr = parseMangledPath(ptr);
+ if (!ptr)
+ return false;
+
+ // unset a subvolume of "/" -- it's not a *sub* volume
+ if (mnt.subvolume + 1 == ptr)
+ *mnt.subvolume = '\0';
+
+ mnt.mnt_dir = ++ptr;
+ ptr = parseMangledPath(ptr);
+ if (!ptr)
+ return false;
+
+ mnt.mnt_opts = ++ptr;
+ ptr = strchr(ptr, ' ');
+ if (!ptr)
+ return false;
+
+ // we don't parse the flags, so just find the separator
+ if (char *const dashed = strstr(ptr, " - ")) {
+ *ptr = '\0';
+ ptr = dashed + strlen(" - ") - 1;
+ } else {
+ return false;
+ }
+
+ mnt.mnt_type = ++ptr;
+ ptr = strchr(ptr, ' ');
+ if (!ptr)
+ return false;
+ *ptr = '\0';
+
+ mnt.mnt_fsname = ++ptr;
+ ptr = parseMangledPath(ptr);
+ if (!ptr)
+ return false;
+
+ mnt.superopts = ++ptr;
+ ptr += strcspn(ptr, " \n");
+ *ptr = '\0';
+
+ return true;
}
inline QString QStorageIterator::rootPath() const
@@ -382,9 +560,28 @@ inline QByteArray QStorageIterator::device() const
inline QByteArray QStorageIterator::options() const
{
+ // Merge the two options, starting with the superblock options and letting
+ // the per-mount options override.
+ const char *superopts = mnt.superopts;
+
+ // Both mnt_opts and superopts start with "ro" or "rw", so we can skip the
+ // superblock's field (see show_mountinfo() in fs/proc_namespace.c).
+ if (superopts && superopts[0] == 'r') {
+ if (superopts[2] == '\0') // no other superopts besides "ro" / "rw"?
+ superopts = nullptr;
+ else if (superopts[2] == ',')
+ superopts += 3;
+ }
+
+ if (superopts)
+ return QByteArray(superopts) + ',' + mnt.mnt_opts;
return QByteArray(mnt.mnt_opts);
}
+inline QByteArray QStorageIterator::subvolume() const
+{
+ return QByteArray(mnt.subvolume);
+}
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
{
@@ -447,6 +644,10 @@ inline QByteArray QStorageIterator::options() const
return QByteArray();
}
+inline QByteArray QStorageIterator::subvolume() const
+{
+ return QByteArray();
+}
#else
inline QStorageIterator::QStorageIterator()
@@ -487,31 +688,11 @@ inline QByteArray QStorageIterator::options() const
return QByteArray();
}
-#endif
-
-static QByteArray extractSubvolume(const QStorageIterator &it)
+inline QByteArray QStorageIterator::subvolume() const
{
-#ifdef Q_OS_LINUX
- if (it.fileSystemType() == "btrfs") {
- const QByteArrayList opts = it.options().split(',');
- QByteArray id;
- for (const QByteArray &opt : opts) {
- static const char subvol[] = "subvol=";
- static const char subvolid[] = "subvolid=";
- if (opt.startsWith(subvol))
- return std::move(opt).mid(strlen(subvol));
- if (opt.startsWith(subvolid))
- id = std::move(opt).mid(strlen(subvolid));
- }
-
- // if we didn't find the subvolume name, return the subvolume ID
- return id;
- }
-#else
- Q_UNUSED(it);
-#endif
return QByteArray();
}
+#endif
void QStorageInfoPrivate::initRootPath()
{
@@ -539,7 +720,7 @@ void QStorageInfoPrivate::initRootPath()
rootPath = mountDir;
device = it.device();
fileSystemType = fsName;
- subvolume = extractSubvolume(it);
+ subvolume = it.subvolume();
}
}
}
diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp
index 3830c5480c..8a3db90f87 100644
--- a/src/corelib/io/qstorageinfo_win.cpp
+++ b/src/corelib/io/qstorageinfo_win.cpp
@@ -147,8 +147,8 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
const bool result = ::GetVolumeInformation(reinterpret_cast<const wchar_t *>(path.utf16()),
nameBuffer,
defaultBufferSize,
- Q_NULLPTR,
- Q_NULLPTR,
+ nullptr,
+ nullptr,
&fileSystemFlags,
fileSystemTypeBuffer,
defaultBufferSize);
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
index ffaee9c683..ed52472ab3 100644
--- a/src/corelib/io/qtemporarydir.cpp
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -42,24 +42,17 @@
#ifndef QT_NO_TEMPORARYFILE
+#include "qdebug.h"
#include "qdiriterator.h"
+#include "qpair.h"
#include "qplatformdefs.h"
-#include <QDebug>
-#include <QPair>
+#include "qrandom.h"
+#include "private/qtemporaryfile_p.h"
#if defined(QT_BUILD_CORE_LIB)
#include "qcoreapplication.h"
#endif
-#if !defined(Q_OS_QNX) && !defined(Q_OS_WIN) && !defined(Q_OS_ANDROID) && !defined(Q_OS_INTEGRITY)
-# define USE_SYSTEM_MKDTEMP
-#endif
-
-#include <stdlib.h> // mkdtemp
-#ifndef USE_SYSTEM_MKDTEMP
-#include <private/qfilesystemengine_p.h>
-#endif
-
#if !defined(Q_OS_WIN)
#include <errno.h>
#endif
@@ -102,38 +95,12 @@ static QString defaultTemplateName()
return QDir::tempPath() + QLatin1Char('/') + baseName + QLatin1String("-XXXXXX");
}
-#ifndef USE_SYSTEM_MKDTEMP
-static int nextRand(int &v)
-{
- int r = v % 62;
- v /= 62;
- if (v < 62)
- v = qrand();
- return r;
-}
-
-QPair<QString, bool> q_mkdtemp(QString templateName)
+void QTemporaryDirPrivate::create(const QString &templateName)
{
- Q_ASSERT(templateName.endsWith(QLatin1String("XXXXXX")));
-
- static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
- const int length = templateName.size();
-
- QChar *XXXXXX = templateName.data() + length - 6;
-
+ QTemporaryFileName tfn(templateName);
for (int i = 0; i < 256; ++i) {
- int v = qrand();
-
- /* Fill in the random bits. */
- XXXXXX[0] = QLatin1Char(letters[nextRand(v)]);
- XXXXXX[1] = QLatin1Char(letters[nextRand(v)]);
- XXXXXX[2] = QLatin1Char(letters[nextRand(v)]);
- XXXXXX[3] = QLatin1Char(letters[nextRand(v)]);
- XXXXXX[4] = QLatin1Char(letters[nextRand(v)]);
- XXXXXX[5] = QLatin1Char(letters[v % 62]);
-
- QFileSystemEntry fileSystemEntry(templateName);
+ tfn.generateNext();
+ QFileSystemEntry fileSystemEntry(tfn.path, QFileSystemEntry::FromNativePath());
if (QFileSystemEngine::createDirectory(fileSystemEntry, false)) {
QSystemError error;
QFileSystemEngine::setPermissions(fileSystemEntry,
@@ -145,7 +112,9 @@ QPair<QString, bool> q_mkdtemp(QString templateName)
qWarning() << "Unable to remove unused directory" << templateName;
continue;
}
- return qMakePair(templateName, true);
+ success = true;
+ pathOrError = fileSystemEntry.filePath();
+ return;
}
# ifdef Q_OS_WIN
const int exists = ERROR_ALREADY_EXISTS;
@@ -155,36 +124,10 @@ QPair<QString, bool> q_mkdtemp(QString templateName)
int code = errno;
# endif
if (code != exists)
- return qMakePair(qt_error_string(code), false);
+ break;
}
- return qMakePair(qt_error_string(), false);
-}
-
-#else // !USE_SYSTEM_MKDTEMP
-
-QPair<QString, bool> q_mkdtemp(char *templateName)
-{
- bool ok = (mkdtemp(templateName) != 0);
- return qMakePair(ok ? QFile::decodeName(templateName) : qt_error_string(), ok);
-}
-
-#endif // USE_SYSTEM_MKDTEMP
-
-void QTemporaryDirPrivate::create(const QString &templateName)
-{
-#ifndef USE_SYSTEM_MKDTEMP
- QString buffer = templateName;
- if (!buffer.endsWith(QLatin1String("XXXXXX")))
- buffer += QLatin1String("XXXXXX");
- const QPair<QString, bool> result = q_mkdtemp(buffer);
-#else // !USE_SYSTEM_MKDTEMP
- QByteArray buffer = QFile::encodeName(templateName);
- if (!buffer.endsWith("XXXXXX"))
- buffer += "XXXXXX";
- QPair<QString, bool> result = q_mkdtemp(buffer.data()); // modifies buffer
-#endif // USE_SYSTEM_MKDTEMP
- pathOrError = result.first;
- success = result.second;
+ pathOrError = qt_error_string();
+ success = false;
}
//************* QTemporaryDir
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
index 3f6b70a2eb..5864ce5cfc 100644
--- a/src/corelib/io/qtemporarydir.h
+++ b/src/corelib/io/qtemporarydir.h
@@ -41,7 +41,7 @@
#define QTEMPORARYDIR_H
#include <QtCore/qdir.h>
-#include <QtCore/QScopedPointer>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 8a99873fee..73249d7df8 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -39,9 +40,8 @@
#include "qtemporaryfile.h"
-#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"
@@ -53,6 +53,8 @@
#if defined(QT_BUILD_CORE_LIB)
#include "qcoreapplication.h"
+#else
+#define tr(X) QString::fromLatin1(X)
#endif
QT_BEGIN_NAMESPACE
@@ -73,82 +75,145 @@ typedef char Latin1Char;
typedef int NativeFileHandle;
#endif
-/*
- * Copyright (c) 1987, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+QTemporaryFileName::QTemporaryFileName(const QString &templateName)
+{
+ // Ensure there is a placeholder mask
+ QString qfilename = templateName;
+ uint phPos = qfilename.length();
+ uint phLength = 0;
+
+ while (phPos != 0) {
+ --phPos;
+
+ if (qfilename[phPos] == QLatin1Char('X')) {
+ ++phLength;
+ continue;
+ }
+
+ if (phLength >= 6
+ || qfilename[phPos] == QLatin1Char('/')) {
+ ++phPos;
+ break;
+ }
+
+ // start over
+ phLength = 0;
+ }
+
+ if (phLength < 6)
+ qfilename.append(QLatin1String(".XXXXXX"));
+
+ // "Nativify" :-)
+ QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName(
+ QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()))
+ .nativeFilePath();
+
+ // Find mask in native path
+ phPos = filename.length();
+ phLength = 0;
+ while (phPos != 0) {
+ --phPos;
+
+ if (filename[phPos] == Latin1Char('X')) {
+ ++phLength;
+ continue;
+ }
+
+ if (phLength >= 6) {
+ ++phPos;
+ break;
+ }
+
+ // start over
+ phLength = 0;
+ }
+
+ Q_ASSERT(phLength >= 6);
+ path = filename;
+ pos = phPos;
+ length = phLength;
+}
/*!
\internal
- Generates a unique file path and returns a native handle to the open file.
- \a path is used as a template when generating unique paths, \a pos
- identifies the position of the first character that will be replaced in the
- template and \a length the number of characters that may be substituted.
- \a mode specifies the file mode bits (not used on Windows).
-
- Returns an open handle to the newly created file if successful, an invalid
- handle otherwise. In both cases, the string in \a path will be changed and
- contain the generated path name.
+ Generates a unique file path from the template \a templ and returns it.
+ The path in \c templ.path is modified.
*/
-static bool createFileFromTemplate(NativeFileHandle &file,
- QFileSystemEntry::NativePath &path, size_t pos, size_t length, quint32 mode,
- QSystemError &error)
+QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
{
Q_ASSERT(length != 0);
- Q_ASSERT(pos < size_t(path.length()));
- Q_ASSERT(length <= size_t(path.length()) - pos);
+ Q_ASSERT(pos < path.length());
+ Q_ASSERT(length <= path.length() - pos);
Char *const placeholderStart = (Char *)path.data() + pos;
Char *const placeholderEnd = placeholderStart + length;
- // Initialize placeholder with random chars + PID.
+ // Replace placeholder with random chars.
{
+ // Since our dictionary is 26+26 characters, it would seem we only need
+ // a random number from 0 to 63 to select a character. However, due to
+ // the limited range, that would mean 12 (64-52) characters have double
+ // the probability of the others: 1 in 32 instead of 1 in 64.
+ //
+ // To overcome this limitation, we use more bits per character. With 10
+ // bits, there are 16 characters with probability 19/1024 and the rest
+ // at 20/1024 (i.e, less than .1% difference). This allows us to do 3
+ // characters per 32-bit random number, which is also half the typical
+ // placeholder length.
+ enum { BitsPerCharacter = 10 };
+
Char *rIter = placeholderEnd;
+ while (rIter != placeholderStart) {
+ quint32 rnd = QRandomGenerator::global()->generate();
+ auto applyOne = [&]() {
+ quint32 v = rnd & ((1 << BitsPerCharacter) - 1);
+ rnd >>= BitsPerCharacter;
+ char ch = char((26 + 26) * v / (1 << BitsPerCharacter));
+ if (ch < 26)
+ *--rIter = Latin1Char(ch + 'A');
+ else
+ *--rIter = Latin1Char(ch - 26 + 'a');
+ };
+
+ applyOne();
+ if (rIter == placeholderStart)
+ break;
-#if defined(QT_BUILD_CORE_LIB)
- quint64 pid = quint64(QCoreApplication::applicationPid());
- do {
- *--rIter = Latin1Char((pid % 10) + '0');
- pid /= 10;
- } while (rIter != placeholderStart && pid != 0);
-#endif
+ applyOne();
+ if (rIter == placeholderStart)
+ break;
- while (rIter != placeholderStart) {
- char ch = char((qrand() & 0xffff) % (26 + 26));
- if (ch < 26)
- *--rIter = Latin1Char(ch + 'A');
- else
- *--rIter = Latin1Char(ch - 26 + 'a');
+ applyOne();
}
}
- for (;;) {
+ return path;
+}
+
+#ifndef QT_NO_TEMPORARYFILE
+
+/*!
+ \internal
+
+ Generates a unique file path from the template \a templ and creates a new
+ file based based on those parameters: the \c templ.length characters in \c
+ templ.path starting at \c templ.pos will be replacd by a random sequence of
+ characters. \a mode specifies the file mode bits (not used on Windows).
+
+ Returns true on success and sets the file handle on \a file. On error,
+ returns false, sets an invalid handle on \a handle and sets the error
+ condition in \a error. In both cases, the string in \a templ will be
+ changed and contain the generated path name.
+*/
+static bool createFileFromTemplate(NativeFileHandle &file, QTemporaryFileName &templ,
+ quint32 mode, QSystemError &error)
+{
+ const int maxAttempts = 16;
+ for (int attempt = 0; attempt < maxAttempts; ++attempt) {
// Atomically create file and obtain handle
+ const QFileSystemEntry::NativePath &path = templ.generateNext();
+
#if defined(Q_OS_WIN)
Q_UNUSED(mode);
@@ -183,7 +248,7 @@ static bool createFileFromTemplate(NativeFileHandle &file,
}
#else // POSIX
file = QT_OPEN(path.constData(),
- QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE,
+ QT_OPEN_CREAT | QT_OPEN_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE,
static_cast<mode_t>(mode));
if (file != -1)
@@ -195,45 +260,58 @@ static bool createFileFromTemplate(NativeFileHandle &file,
return false;
}
#endif
-
- /* tricky little algorwwithm for backward compatibility */
- for (Char *iter = placeholderStart;;) {
- // Character progression: [0-9] => 'a' ... 'z' => 'A' .. 'Z'
- // String progression: "ZZaiC" => "aabiC"
- switch (char(*iter)) {
- case 'Z':
- // Rollover, advance next character
- *iter = Latin1Char('a');
- if (++iter == placeholderEnd) {
- // Out of alternatives. Return file exists error, previously set.
- error = QSystemError(err, QSystemError::NativeError);
- return false;
- }
-
- continue;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- *iter = Latin1Char('a');
- break;
-
- case 'z':
- // increment 'z' to 'A'
- *iter = Latin1Char('A');
- break;
-
- default:
- ++*iter;
- break;
- }
- break;
- }
}
- Q_ASSERT(false);
return false;
}
+enum class CreateUnnamedFileStatus {
+ Success = 0,
+ NotSupported,
+ OtherError
+};
+
+static CreateUnnamedFileStatus
+createUnnamedFile(NativeFileHandle &file, QTemporaryFileName &tfn, quint32 mode, QSystemError *error)
+{
+#ifdef LINUX_UNNAMED_TMPFILE
+ // first, check if we have /proc, otherwise can't make the file exist later
+ // (no error message set, as caller will try regular temporary file)
+ if (!qt_haveLinuxProcfs())
+ return CreateUnnamedFileStatus::NotSupported;
+
+ const char *p = ".";
+ int lastSlash = tfn.path.lastIndexOf('/');
+ if (lastSlash != -1) {
+ tfn.path[lastSlash] = '\0';
+ p = tfn.path.data();
+ }
+
+ file = QT_OPEN(p, O_TMPFILE | QT_OPEN_RDWR | QT_OPEN_LARGEFILE,
+ static_cast<mode_t>(mode));
+ if (file != -1)
+ return CreateUnnamedFileStatus::Success;
+
+ if (errno == EOPNOTSUPP || errno == EISDIR) {
+ // fs or kernel doesn't support O_TMPFILE, so
+ // put the slash back so we may try a regular file
+ if (lastSlash != -1)
+ tfn.path[lastSlash] = '/';
+ return CreateUnnamedFileStatus::NotSupported;
+ }
+
+ // real error
+ *error = QSystemError(errno, QSystemError::NativeError);
+ return CreateUnnamedFileStatus::OtherError;
+#else
+ Q_UNUSED(file);
+ Q_UNUSED(tfn);
+ Q_UNUSED(mode);
+ Q_UNUSED(error);
+ return CreateUnnamedFileStatus::NotSupported;
+#endif
+}
+
//************* QTemporaryFileEngine
QTemporaryFileEngine::~QTemporaryFileEngine()
{
@@ -264,13 +342,6 @@ void QTemporaryFileEngine::setFileName(const QString &file)
QFSFileEngine::setFileName(file);
}
-void QTemporaryFileEngine::setFileTemplate(const QString &fileTemplate)
-{
- Q_D(QFSFileEngine);
- if (filePathIsTemplate)
- d->fileEntry = QFileSystemEntry(fileTemplate);
-}
-
bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
{
Q_D(QFSFileEngine);
@@ -281,59 +352,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
if (!filePathIsTemplate)
return QFSFileEngine::open(openMode);
- QString qfilename = d->fileEntry.filePath();
-
- // Ensure there is a placeholder mask
- uint phPos = qfilename.length();
- uint phLength = 0;
-
- while (phPos != 0) {
- --phPos;
-
- if (qfilename[phPos] == QLatin1Char('X')) {
- ++phLength;
- continue;
- }
-
- if (phLength >= 6
- || qfilename[phPos] == QLatin1Char('/')) {
- ++phPos;
- break;
- }
-
- // start over
- phLength = 0;
- }
-
- if (phLength < 6)
- qfilename.append(QLatin1String(".XXXXXX"));
-
- // "Nativify" :-)
- QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName(
- QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()))
- .nativeFilePath();
-
- // Find mask in native path
- phPos = filename.length();
- phLength = 0;
- while (phPos != 0) {
- --phPos;
-
- if (filename[phPos] == Latin1Char('X')) {
- ++phLength;
- continue;
- }
-
- if (phLength >= 6) {
- ++phPos;
- break;
- }
-
- // start over
- phLength = 0;
- }
-
- Q_ASSERT(phLength >= 6);
+ QTemporaryFileName tfn(templateName);
QSystemError error;
#if defined(Q_OS_WIN)
@@ -342,19 +361,24 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode)
NativeFileHandle &file = d->fd;
#endif
- if (!createFileFromTemplate(file, filename, phPos, phLength, fileMode, error)) {
+ CreateUnnamedFileStatus st = createUnnamedFile(file, tfn, fileMode, &error);
+ if (st == CreateUnnamedFileStatus::Success) {
+ unnamedFile = true;
+ d->fileEntry.clear();
+ } else if (st == CreateUnnamedFileStatus::NotSupported &&
+ createFileFromTemplate(file, tfn, fileMode, error)) {
+ filePathIsTemplate = false;
+ unnamedFile = false;
+ d->fileEntry = QFileSystemEntry(tfn.path, QFileSystemEntry::FromNativePath());
+ } else {
setError(QFile::OpenError, error.toString());
return false;
}
- d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath());
-
#if !defined(Q_OS_WIN) || defined(Q_OS_WINRT)
d->closeFileHandle = true;
#endif
- filePathIsTemplate = false;
-
d->openMode = openMode;
d->lastFlushFailed = false;
d->tried_stat = 0;
@@ -369,7 +393,9 @@ bool QTemporaryFileEngine::remove()
// we must explicitly call QFSFileEngine::close() before we remove it.
d->unmapAll();
QFSFileEngine::close();
- if (QFSFileEngine::remove()) {
+ if (isUnnamedFile())
+ return true;
+ if (!filePathIsTemplate && QFSFileEngine::remove()) {
d->fileEntry.clear();
// If a QTemporaryFile is constructed using a template file path, the path
// is generated in QTemporaryFileEngine::open() and then filePathIsTemplate
@@ -384,12 +410,22 @@ bool QTemporaryFileEngine::remove()
bool QTemporaryFileEngine::rename(const QString &newName)
{
+ if (isUnnamedFile()) {
+ bool ok = materializeUnnamedFile(newName, DontOverwrite);
+ QFSFileEngine::close();
+ return ok;
+ }
QFSFileEngine::close();
return QFSFileEngine::rename(newName);
}
bool QTemporaryFileEngine::renameOverwrite(const QString &newName)
{
+ if (isUnnamedFile()) {
+ bool ok = materializeUnnamedFile(newName, Overwrite);
+ QFSFileEngine::close();
+ return ok;
+ }
QFSFileEngine::close();
return QFSFileEngine::renameOverwrite(newName);
}
@@ -402,6 +438,91 @@ bool QTemporaryFileEngine::close()
return true;
}
+QString QTemporaryFileEngine::fileName(QAbstractFileEngine::FileName file) const
+{
+ if (isUnnamedFile()) {
+ if (file == LinkName) {
+ // we know our file isn't (won't be) a symlink
+ return QString();
+ }
+
+ // for all other cases, materialize the file
+ const_cast<QTemporaryFileEngine *>(this)->materializeUnnamedFile(templateName, NameIsTemplate);
+ }
+ return QFSFileEngine::fileName(file);
+}
+
+bool QTemporaryFileEngine::materializeUnnamedFile(const QString &newName, QTemporaryFileEngine::MaterializationMode mode)
+{
+ Q_ASSERT(isUnnamedFile());
+
+#ifdef LINUX_UNNAMED_TMPFILE
+ Q_D(QFSFileEngine);
+ const QByteArray src = "/proc/self/fd/" + QByteArray::number(d->fd);
+ auto materializeAt = [=](const QFileSystemEntry &dst) {
+ return ::linkat(AT_FDCWD, src, AT_FDCWD, dst.nativeFilePath(), AT_SYMLINK_FOLLOW) == 0;
+ };
+#else
+ auto materializeAt = [](const QFileSystemEntry &) { return false; };
+#endif
+
+ auto success = [this](const QFileSystemEntry &entry) {
+ filePathIsTemplate = false;
+ unnamedFile = false;
+ d_func()->fileEntry = entry;
+ return true;
+ };
+
+ auto materializeAsTemplate = [=](const QString &newName) {
+ QTemporaryFileName tfn(newName);
+ static const int maxAttempts = 16;
+ for (int attempt = 0; attempt < maxAttempts; ++attempt) {
+ tfn.generateNext();
+ QFileSystemEntry entry(tfn.path, QFileSystemEntry::FromNativePath());
+ if (materializeAt(entry))
+ return success(entry);
+ }
+ return false;
+ };
+
+ if (mode == NameIsTemplate) {
+ if (materializeAsTemplate(newName))
+ return true;
+ } else {
+ // Use linkat to materialize the file
+ QFileSystemEntry dst(newName);
+ if (materializeAt(dst))
+ return success(dst);
+
+ if (errno == EEXIST && mode == Overwrite) {
+ // retry by first creating a temporary file in the right dir
+ if (!materializeAsTemplate(templateName))
+ return false;
+
+ // then rename the materialized file to target (same as renameOverwrite)
+ QFSFileEngine::close();
+ return QFSFileEngine::renameOverwrite(newName);
+ }
+ }
+
+ // failed
+ setError(QFile::RenameError, QSystemError(errno, QSystemError::NativeError).toString());
+ return false;
+}
+
+bool QTemporaryFileEngine::isUnnamedFile() const
+{
+#ifdef LINUX_UNNAMED_TMPFILE
+ if (unnamedFile) {
+ Q_ASSERT(d_func()->fileEntry.isEmpty());
+ Q_ASSERT(filePathIsTemplate);
+ }
+ return unnamedFile;
+#else
+ return false;
+#endif
+}
+
//************* QTemporaryFilePrivate
QTemporaryFilePrivate::QTemporaryFilePrivate()
@@ -420,7 +541,7 @@ QTemporaryFilePrivate::~QTemporaryFilePrivate()
QAbstractFileEngine *QTemporaryFilePrivate::engine() const
{
if (!fileEngine) {
- fileEngine = new QTemporaryFileEngine;
+ fileEngine = new QTemporaryFileEngine(&templateName);
resetFileEngine();
}
return fileEngine;
@@ -438,6 +559,17 @@ void QTemporaryFilePrivate::resetFileEngine() const
tef->initialize(fileName, 0600, false);
}
+void QTemporaryFilePrivate::materializeUnnamedFile()
+{
+#ifdef LINUX_UNNAMED_TMPFILE
+ if (!fileName.isEmpty() || !fileEngine)
+ return;
+
+ auto *tef = static_cast<QTemporaryFileEngine *>(fileEngine);
+ fileName = tef->fileName(QAbstractFileEngine::DefaultName);
+#endif
+}
+
QString QTemporaryFilePrivate::defaultTemplateName()
{
QString baseName;
@@ -622,10 +754,21 @@ bool QTemporaryFile::autoRemove() const
}
/*!
- Sets the QTemporaryFile into auto-remove mode if \a b is true.
+ Sets the QTemporaryFile into auto-remove mode if \a b is \c true.
Auto-remove is on by default.
+ If you set this property to \c false, ensure the application provides a way
+ to remove the file once it is no longer needed, including passing the
+ responsibility on to another process. Always use the fileName() function to
+ obtain the name and never try to guess the name that QTemporaryFile has
+ generated.
+
+ On some systems, if fileName() is not called before closing the file, the
+ temporary file may be removed regardless of the state of this property.
+ This behavior should not be relied upon, so application code should either
+ call fileName() or leave the auto removal functionality enabled.
+
\sa autoRemove(), remove()
*/
void QTemporaryFile::setAutoRemove(bool b)
@@ -646,6 +789,10 @@ void QTemporaryFile::setAutoRemove(bool b)
QString QTemporaryFile::fileName() const
{
Q_D(const QTemporaryFile);
+ auto tef = static_cast<QTemporaryFileEngine *>(d->fileEngine);
+ if (tef && tef->isReallyOpen())
+ const_cast<QTemporaryFilePrivate *>(d)->materializeUnnamedFile();
+
if(d->fileName.isEmpty())
return QString();
return d->engine()->fileName(QAbstractFileEngine::DefaultName);
@@ -679,8 +826,36 @@ void QTemporaryFile::setFileTemplate(const QString &name)
{
Q_D(QTemporaryFile);
d->templateName = name;
- if (d->fileEngine)
- static_cast<QTemporaryFileEngine*>(d->fileEngine)->setFileTemplate(name);
+}
+
+/*!
+ \internal
+
+ This is just a simplified version of QFile::rename() because we know a few
+ extra details about what kind of file we have. The documentation is hidden
+ from the user because QFile::rename() should be enough.
+*/
+bool QTemporaryFile::rename(const QString &newName)
+{
+ Q_D(QTemporaryFile);
+ auto tef = static_cast<QTemporaryFileEngine *>(d->fileEngine);
+ if (!tef || !tef->isReallyOpen() || !tef->filePathWasTemplate)
+ return QFile::rename(newName);
+
+ unsetError();
+ close();
+ if (error() == QFile::NoError) {
+ if (tef->rename(newName)) {
+ unsetError();
+ // engine was able to handle the new name so we just reset it
+ tef->setFileName(newName);
+ d->fileName = newName;
+ return true;
+ }
+
+ d->setError(QFile::RenameError, tef->errorString());
+ }
+ return false;
}
/*!
@@ -771,11 +946,10 @@ QTemporaryFile *QTemporaryFile::createNativeFile(QFile &file)
bool QTemporaryFile::open(OpenMode flags)
{
Q_D(QTemporaryFile);
- if (!d->fileName.isEmpty()) {
- if (static_cast<QTemporaryFileEngine*>(d->engine())->isReallyOpen()) {
- setOpenMode(flags);
- return true;
- }
+ auto tef = static_cast<QTemporaryFileEngine *>(d->fileEngine);
+ if (tef && tef->isReallyOpen()) {
+ setOpenMode(flags);
+ return true;
}
// reset the engine state so it creates a new, unique file name from the template;
@@ -786,16 +960,20 @@ bool QTemporaryFile::open(OpenMode flags)
d->resetFileEngine();
if (QFile::open(flags)) {
- d->fileName = d->fileEngine->fileName(QAbstractFileEngine::DefaultName);
+ tef = static_cast<QTemporaryFileEngine *>(d->fileEngine);
+ if (tef->isUnnamedFile())
+ d->fileName.clear();
+ else
+ d->fileName = tef->fileName(QAbstractFileEngine::DefaultName);
return true;
}
return false;
}
-QT_END_NAMESPACE
-
#endif // QT_NO_TEMPORARYFILE
+QT_END_NAMESPACE
+
#ifndef QT_NO_QOBJECT
#include "moc_qtemporaryfile.cpp"
#endif
diff --git a/src/corelib/io/qtemporaryfile.h b/src/corelib/io/qtemporaryfile.h
index 3dc2e75f50..90a6a613e6 100644
--- a/src/corelib/io/qtemporaryfile.h
+++ b/src/corelib/io/qtemporaryfile.h
@@ -77,9 +77,13 @@ public:
// ### Hides open(flags)
bool open() { return open(QIODevice::ReadWrite); }
- QString fileName() const Q_DECL_OVERRIDE;
+ QString fileName() const override;
QString fileTemplate() const;
void setFileTemplate(const QString &name);
+
+ // Hides QFile::rename
+ bool rename(const QString &newName);
+
#if QT_DEPRECATED_SINCE(5,1)
QT_DEPRECATED inline static QTemporaryFile *createLocalFile(const QString &fileName)
{ return createNativeFile(fileName); }
@@ -91,7 +95,7 @@ public:
static QTemporaryFile *createNativeFile(QFile &file);
protected:
- bool open(OpenMode flags) Q_DECL_OVERRIDE;
+ bool open(OpenMode flags) override;
private:
friend class QFile;
diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h
index 7f365f0e8a..fb8887af53 100644
--- a/src/corelib/io/qtemporaryfile_p.h
+++ b/src/corelib/io/qtemporaryfile_p.h
@@ -53,25 +53,48 @@
#include <QtCore/qglobal.h>
-#ifndef QT_NO_TEMPORARYFILE
-
#include "private/qfsfileengine_p.h"
#include "private/qfilesystemengine_p.h"
#include "private/qfile_p.h"
+#include "qtemporaryfile.h"
+
+#if defined(Q_OS_LINUX) && QT_CONFIG(linkat)
+# include <fcntl.h>
+# ifdef O_TMPFILE
+// some early libc support had the wrong values for O_TMPFILE
+// (see https://bugzilla.gnome.org/show_bug.cgi?id=769453#c18)
+# if (O_TMPFILE & O_DIRECTORY) == O_DIRECTORY
+# define LINUX_UNNAMED_TMPFILE
+# endif
+# endif
+#endif
QT_BEGIN_NAMESPACE
+struct QTemporaryFileName
+{
+ QFileSystemEntry::NativePath path;
+ qsizetype pos;
+ qsizetype length;
+
+ QTemporaryFileName(const QString &templateName);
+ QFileSystemEntry::NativePath generateNext();
+};
+
+#ifndef QT_NO_TEMPORARYFILE
+
class QTemporaryFilePrivate : public QFilePrivate
{
Q_DECLARE_PUBLIC(QTemporaryFile)
-protected:
+public:
QTemporaryFilePrivate();
explicit QTemporaryFilePrivate(const QString &templateNameIn);
~QTemporaryFilePrivate();
QAbstractFileEngine *engine() const override;
void resetFileEngine() const;
+ void materializeUnnamedFile();
bool autoRemove = true;
QString templateName = defaultTemplateName();
@@ -85,37 +108,50 @@ class QTemporaryFileEngine : public QFSFileEngine
{
Q_DECLARE_PRIVATE(QFSFileEngine)
public:
+ QTemporaryFileEngine(const QString *templateName)
+ : templateName(*templateName)
+ {}
+
void initialize(const QString &file, quint32 mode, bool nameIsTemplate = true)
{
Q_D(QFSFileEngine);
Q_ASSERT(!isReallyOpen());
fileMode = mode;
filePathIsTemplate = filePathWasTemplate = nameIsTemplate;
- d->fileEntry = QFileSystemEntry(file);
- if (!filePathIsTemplate)
+ if (filePathIsTemplate) {
+ d->fileEntry.clear();
+ } else {
+ d->fileEntry = QFileSystemEntry(file);
QFSFileEngine::setFileName(file);
+ }
}
~QTemporaryFileEngine();
bool isReallyOpen() const;
void setFileName(const QString &file) override;
- void setFileTemplate(const QString &fileTemplate);
bool open(QIODevice::OpenMode flags) override;
bool remove() override;
bool rename(const QString &newName) override;
bool renameOverwrite(const QString &newName) override;
bool close() override;
+ QString fileName(FileName file) const override;
+ enum MaterializationMode { Overwrite, DontOverwrite, NameIsTemplate };
+ bool materializeUnnamedFile(const QString &newName, MaterializationMode mode);
+ bool isUnnamedFile() const override final;
+
+ const QString &templateName;
quint32 fileMode;
bool filePathIsTemplate;
bool filePathWasTemplate;
+ bool unnamedFile = false;
};
-QT_END_NAMESPACE
-
#endif // QT_NO_TEMPORARYFILE
+QT_END_NAMESPACE
+
#endif /* QTEMPORARYFILE_P_H */
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
deleted file mode 100644
index 5144ac0ec9..0000000000
--- a/src/corelib/io/qtextstream.cpp
+++ /dev/null
@@ -1,3193 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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$
-**
-****************************************************************************/
-
-//#define QTEXTSTREAM_DEBUG
-static const int QTEXTSTREAM_BUFFERSIZE = 16384;
-
-/*!
- \class QTextStream
- \inmodule QtCore
-
- \brief The QTextStream class provides a convenient interface for
- reading and writing text.
-
- \ingroup io
- \ingroup string-processing
- \reentrant
-
- QTextStream can operate on a QIODevice, a QByteArray or a
- QString. Using QTextStream's streaming operators, you can
- conveniently read and write words, lines and numbers. For
- generating text, QTextStream supports formatting options for field
- padding and alignment, and formatting of numbers. Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 0
-
- It's also common to use QTextStream to read console input and write
- console output. QTextStream is locale aware, and will automatically decode
- standard input using the correct codec. Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 1
-
- Besides using QTextStream's constructors, you can also set the
- device or string QTextStream operates on by calling setDevice() or
- setString(). You can seek to a position by calling seek(), and
- atEnd() will return true when there is no data left to be read. If
- you call flush(), QTextStream will empty all data from its write
- buffer into the device and call flush() on the device.
-
- Internally, QTextStream uses a Unicode based buffer, and
- QTextCodec is used by QTextStream to automatically support
- different character sets. By default, QTextCodec::codecForLocale()
- is used for reading and writing, but you can also set the codec by
- calling setCodec(). Automatic Unicode detection is also
- supported. When this feature is enabled (the default behavior),
- QTextStream will detect the UTF-16 or the UTF-32 BOM (Byte Order Mark) and
- switch to the appropriate UTF codec when reading. QTextStream
- does not write a BOM by default, but you can enable this by calling
- setGenerateByteOrderMark(true). When QTextStream operates on a QString
- directly, the codec is disabled.
-
- There are three general ways to use QTextStream when reading text
- files:
-
- \list
-
- \li Chunk by chunk, by calling readLine() or readAll().
-
- \li Word by word. QTextStream supports streaming into \l {QString}s,
- \l {QByteArray}s and char* buffers. Words are delimited by space, and
- leading white space is automatically skipped.
-
- \li Character by character, by streaming into QChar or char types.
- This method is often used for convenient input handling when
- parsing files, independent of character encoding and end-of-line
- semantics. To skip white space, call skipWhiteSpace().
-
- \endlist
-
- Since the text stream uses a buffer, you should not read from
- the stream using the implementation of a superclass. For instance,
- if you have a QFile and read from it directly using
- QFile::readLine() instead of using the stream, the text stream's
- internal position will be out of sync with the file's position.
-
- By default, when reading numbers from a stream of text,
- QTextStream will automatically detect the number's base
- representation. For example, if the number starts with "0x", it is
- assumed to be in hexadecimal form. If it starts with the digits
- 1-9, it is assumed to be in decimal form, and so on. You can set
- the integer base, thereby disabling the automatic detection, by
- calling setIntegerBase(). Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 2
-
- QTextStream supports many formatting options for generating text.
- You can set the field width and pad character by calling
- setFieldWidth() and setPadChar(). Use setFieldAlignment() to set
- the alignment within each field. For real numbers, call
- setRealNumberNotation() and setRealNumberPrecision() to set the
- notation (SmartNotation, ScientificNotation, FixedNotation) and precision in
- digits of the generated number. Some extra number formatting
- options are also available through setNumberFlags().
-
- \target QTextStream manipulators
-
- Like \c <iostream> in the standard C++ library, QTextStream also
- defines several global manipulator functions:
-
- \table
- \header \li Manipulator \li Description
- \row \li \c bin \li Same as setIntegerBase(2).
- \row \li \c oct \li Same as setIntegerBase(8).
- \row \li \c dec \li Same as setIntegerBase(10).
- \row \li \c hex \li Same as setIntegerBase(16).
- \row \li \c showbase \li Same as setNumberFlags(numberFlags() | ShowBase).
- \row \li \c forcesign \li Same as setNumberFlags(numberFlags() | ForceSign).
- \row \li \c forcepoint \li Same as setNumberFlags(numberFlags() | ForcePoint).
- \row \li \c noshowbase \li Same as setNumberFlags(numberFlags() & ~ShowBase).
- \row \li \c noforcesign \li Same as setNumberFlags(numberFlags() & ~ForceSign).
- \row \li \c noforcepoint \li Same as setNumberFlags(numberFlags() & ~ForcePoint).
- \row \li \c uppercasebase \li Same as setNumberFlags(numberFlags() | UppercaseBase).
- \row \li \c uppercasedigits \li Same as setNumberFlags(numberFlags() | UppercaseDigits).
- \row \li \c lowercasebase \li Same as setNumberFlags(numberFlags() & ~UppercaseBase).
- \row \li \c lowercasedigits \li Same as setNumberFlags(numberFlags() & ~UppercaseDigits).
- \row \li \c fixed \li Same as setRealNumberNotation(FixedNotation).
- \row \li \c scientific \li Same as setRealNumberNotation(ScientificNotation).
- \row \li \c left \li Same as setFieldAlignment(AlignLeft).
- \row \li \c right \li Same as setFieldAlignment(AlignRight).
- \row \li \c center \li Same as setFieldAlignment(AlignCenter).
- \row \li \c endl \li Same as operator<<('\\n') and flush().
- \row \li \c flush \li Same as flush().
- \row \li \c reset \li Same as reset().
- \row \li \c ws \li Same as skipWhiteSpace().
- \row \li \c bom \li Same as setGenerateByteOrderMark(true).
- \endtable
-
- In addition, Qt provides three global manipulators that take a
- parameter: qSetFieldWidth(), qSetPadChar(), and
- qSetRealNumberPrecision().
-
- \sa QDataStream, QIODevice, QFile, QBuffer, QTcpSocket, {Text Codecs Example}
-*/
-
-/*! \enum QTextStream::RealNumberNotation
-
- This enum specifies which notations to use for expressing \c
- float and \c double as strings.
-
- \value ScientificNotation Scientific notation (\c{printf()}'s \c %e flag).
- \value FixedNotation Fixed-point notation (\c{printf()}'s \c %f flag).
- \value SmartNotation Scientific or fixed-point notation, depending on which makes most sense (\c{printf()}'s \c %g flag).
-
- \sa setRealNumberNotation()
-*/
-
-/*! \enum QTextStream::FieldAlignment
-
- This enum specifies how to align text in fields when the field is
- wider than the text that occupies it.
-
- \value AlignLeft Pad on the right side of fields.
- \value AlignRight Pad on the left side of fields.
- \value AlignCenter Pad on both sides of field.
- \value AlignAccountingStyle Same as AlignRight, except that the
- sign of a number is flush left.
-
- \sa setFieldAlignment()
-*/
-
-/*! \enum QTextStream::NumberFlag
-
- This enum specifies various flags that can be set to affect the
- output of integers, \c{float}s, and \c{double}s.
-
- \value ShowBase Show the base as a prefix if the base
- is 16 ("0x"), 8 ("0"), or 2 ("0b").
- \value ForcePoint Always put the decimal separator in numbers, even if
- there are no decimals.
- \value ForceSign Always put the sign in numbers, even for positive numbers.
- \value UppercaseBase Use uppercase versions of base prefixes ("0X", "0B").
- \value UppercaseDigits Use uppercase letters for expressing
- digits 10 to 35 instead of lowercase.
-
- \sa setNumberFlags()
-*/
-
-/*! \enum QTextStream::Status
-
- This enum describes the current status of the text stream.
-
- \value Ok The text stream is operating normally.
- \value ReadPastEnd The text stream has read past the end of the
- data in the underlying device.
- \value ReadCorruptData The text stream has read corrupt data.
- \value WriteFailed The text stream cannot write to the underlying device.
-
- \sa status()
-*/
-
-#include "qtextstream.h"
-#include "private/qtextstream_p.h"
-#include "qbuffer.h"
-#include "qfile.h"
-#include "qnumeric.h"
-#include "qvarlengtharray.h"
-
-#include <locale.h>
-#include "private/qlocale_p.h"
-
-#include <stdlib.h>
-#include <limits.h>
-#include <new>
-
-#if defined QTEXTSTREAM_DEBUG
-#include <ctype.h>
-#include "private/qtools_p.h"
-
-QT_BEGIN_NAMESPACE
-
-// Returns a human readable representation of the first \a len
-// characters in \a data.
-static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
-{
- if (!data) return "(null)";
- QByteArray out;
- for (int i = 0; i < len; ++i) {
- char c = data[i];
- if (isprint(int(uchar(c)))) {
- out += c;
- } else switch (c) {
- case '\n': out += "\\n"; break;
- case '\r': out += "\\r"; break;
- case '\t': out += "\\t"; break;
- default: {
- const char buf[] = {
- '\\',
- 'x',
- QtMiscUtils::toHexLower(uchar(c) / 16),
- QtMiscUtils::toHexLower(uchar(c) % 16),
- 0
- };
- out += buf;
- }
- }
- }
-
- if (len < maxSize)
- out += "...";
-
- return out;
-}
-QT_END_NAMESPACE
-
-#endif
-
-// A precondition macro
-#define Q_VOID
-#define CHECK_VALID_STREAM(x) do { \
- if (!d->string && !d->device) { \
- qWarning("QTextStream: No device"); \
- return x; \
- } } while (0)
-
-// Base implementations of operator>> for ints and reals
-#define IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(type) do { \
- Q_D(QTextStream); \
- CHECK_VALID_STREAM(*this); \
- qulonglong tmp; \
- switch (d->getNumber(&tmp)) { \
- case QTextStreamPrivate::npsOk: \
- i = (type)tmp; \
- break; \
- case QTextStreamPrivate::npsMissingDigit: \
- case QTextStreamPrivate::npsInvalidPrefix: \
- i = (type)0; \
- setStatus(atEnd() ? QTextStream::ReadPastEnd : QTextStream::ReadCorruptData); \
- break; \
- } \
- return *this; } while (0)
-
-#define IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR(type) do { \
- Q_D(QTextStream); \
- CHECK_VALID_STREAM(*this); \
- double tmp; \
- if (d->getReal(&tmp)) { \
- f = (type)tmp; \
- } else { \
- f = (type)0; \
- setStatus(atEnd() ? QTextStream::ReadPastEnd : QTextStream::ReadCorruptData); \
- } \
- return *this; } while (0)
-
-QT_BEGIN_NAMESPACE
-
-//-------------------------------------------------------------------
-
-/*!
- \internal
-*/
-QTextStreamPrivate::QTextStreamPrivate(QTextStream *q_ptr)
- :
-#ifndef QT_NO_TEXTCODEC
- readConverterSavedState(0),
-#endif
- readConverterSavedStateOffset(0),
- locale(QLocale::c())
-{
- this->q_ptr = q_ptr;
- reset();
-}
-
-/*!
- \internal
-*/
-QTextStreamPrivate::~QTextStreamPrivate()
-{
- if (deleteDevice) {
-#ifndef QT_NO_QOBJECT
- device->blockSignals(true);
-#endif
- delete device;
- }
-#ifndef QT_NO_TEXTCODEC
- delete readConverterSavedState;
-#endif
-}
-
-#ifndef QT_NO_TEXTCODEC
-static void resetCodecConverterStateHelper(QTextCodec::ConverterState *state)
-{
- state->~ConverterState();
- new (state) QTextCodec::ConverterState;
-}
-
-static void copyConverterStateHelper(QTextCodec::ConverterState *dest,
- const QTextCodec::ConverterState *src)
-{
- // ### QTextCodec::ConverterState's copy constructors and assignments are
- // private. This function copies the structure manually.
- Q_ASSERT(!src->d);
- dest->flags = src->flags;
- dest->invalidChars = src->invalidChars;
- dest->state_data[0] = src->state_data[0];
- dest->state_data[1] = src->state_data[1];
- dest->state_data[2] = src->state_data[2];
-}
-#endif
-
-void QTextStreamPrivate::Params::reset()
-{
- realNumberPrecision = 6;
- integerBase = 0;
- fieldWidth = 0;
- padChar = QLatin1Char(' ');
- fieldAlignment = QTextStream::AlignRight;
- realNumberNotation = QTextStream::SmartNotation;
- numberFlags = 0;
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::reset()
-{
- params.reset();
-
- device = 0;
- deleteDevice = false;
- string = 0;
- stringOffset = 0;
- stringOpenMode = QIODevice::NotOpen;
-
- readBufferOffset = 0;
- readBufferStartDevicePos = 0;
- lastTokenSize = 0;
-
-#ifndef QT_NO_TEXTCODEC
- codec = QTextCodec::codecForLocale();
- resetCodecConverterStateHelper(&readConverterState);
- resetCodecConverterStateHelper(&writeConverterState);
- delete readConverterSavedState;
- readConverterSavedState = 0;
- writeConverterState.flags |= QTextCodec::IgnoreHeader;
- autoDetectUnicode = true;
-#endif
-}
-
-/*!
- \internal
-*/
-bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
-{
- // no buffer next to the QString itself; this function should only
- // be called internally, for devices.
- Q_ASSERT(!string);
- Q_ASSERT(device);
-
- // handle text translation and bypass the Text flag in the device.
- bool textModeEnabled = device->isTextModeEnabled();
- if (textModeEnabled)
- device->setTextModeEnabled(false);
-
- // read raw data into a temporary buffer
- char buf[QTEXTSTREAM_BUFFERSIZE];
- qint64 bytesRead = 0;
-#if defined(Q_OS_WIN)
- // On Windows, there is no non-blocking stdin - so we fall back to reading
- // lines instead. If there is no QOBJECT, we read lines for all sequential
- // devices; otherwise, we read lines only for stdin.
- QFile *file = 0;
- Q_UNUSED(file);
- if (device->isSequential()
-#if !defined(QT_NO_QOBJECT)
- && (file = qobject_cast<QFile *>(device)) && file->handle() == 0
-#endif
- ) {
- if (maxBytes != -1)
- bytesRead = device->readLine(buf, qMin<qint64>(sizeof(buf), maxBytes));
- else
- bytesRead = device->readLine(buf, sizeof(buf));
- } else
-#endif
- {
- if (maxBytes != -1)
- bytesRead = device->read(buf, qMin<qint64>(sizeof(buf), maxBytes));
- else
- bytesRead = device->read(buf, sizeof(buf));
- }
-
- // reset the Text flag.
- if (textModeEnabled)
- device->setTextModeEnabled(true);
-
- if (bytesRead <= 0)
- return false;
-
-#ifndef QT_NO_TEXTCODEC
- // codec auto detection, explicitly defaults to locale encoding if the
- // codec has been set to 0.
- if (!codec || autoDetectUnicode) {
- autoDetectUnicode = false;
-
- codec = QTextCodec::codecForUtfText(QByteArray::fromRawData(buf, bytesRead), codec);
- if (!codec) {
- codec = QTextCodec::codecForLocale();
- writeConverterState.flags |= QTextCodec::IgnoreHeader;
- }
- }
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::fillReadBuffer(), using %s codec",
- codec ? codec->name().constData() : "no");
-#endif
-#endif
-
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::fillReadBuffer(), device->read(\"%s\", %d) == %d",
- qt_prettyDebug(buf, qMin(32,int(bytesRead)) , int(bytesRead)).constData(), int(sizeof(buf)), int(bytesRead));
-#endif
-
- int oldReadBufferSize = readBuffer.size();
-#ifndef QT_NO_TEXTCODEC
- // convert to unicode
- readBuffer += Q_LIKELY(codec) ? codec->toUnicode(buf, bytesRead, &readConverterState)
- : QString::fromLatin1(buf, bytesRead);
-#else
- readBuffer += QString::fromLatin1(buf, bytesRead);
-#endif
-
- // remove all '\r\n' in the string.
- if (readBuffer.size() > oldReadBufferSize && textModeEnabled) {
- QChar CR = QLatin1Char('\r');
- QChar *writePtr = readBuffer.data() + oldReadBufferSize;
- QChar *readPtr = readBuffer.data() + oldReadBufferSize;
- QChar *endPtr = readBuffer.data() + readBuffer.size();
-
- int n = oldReadBufferSize;
- if (readPtr < endPtr) {
- // Cut-off to avoid unnecessary self-copying.
- while (*readPtr++ != CR) {
- ++n;
- if (++writePtr == endPtr)
- break;
- }
- }
- while (readPtr < endPtr) {
- QChar ch = *readPtr++;
- if (ch != CR) {
- *writePtr++ = ch;
- } else {
- if (n < readBufferOffset)
- --readBufferOffset;
- --bytesRead;
- }
- ++n;
- }
- readBuffer.resize(writePtr - readBuffer.data());
- }
-
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::fillReadBuffer() read %d bytes from device. readBuffer = [%s]", int(bytesRead),
- qt_prettyDebug(readBuffer.toLatin1(), readBuffer.size(), readBuffer.size()).data());
-#endif
- return true;
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::resetReadBuffer()
-{
- readBuffer.clear();
- readBufferOffset = 0;
- readBufferStartDevicePos = (device ? device->pos() : 0);
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::flushWriteBuffer()
-{
- // no buffer next to the QString itself; this function should only
- // be called internally, for devices.
- if (string || !device)
- return;
-
- // Stream went bye-bye already. Appending further data may succeed again,
- // but would create a corrupted stream anyway.
- if (status != QTextStream::Ok)
- return;
-
- if (writeBuffer.isEmpty())
- return;
-
-#if defined (Q_OS_WIN)
- // handle text translation and bypass the Text flag in the device.
- bool textModeEnabled = device->isTextModeEnabled();
- if (textModeEnabled) {
- device->setTextModeEnabled(false);
- writeBuffer.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
- }
-#endif
-
-#ifndef QT_NO_TEXTCODEC
- if (!codec)
- codec = QTextCodec::codecForLocale();
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::flushWriteBuffer(), using %s codec (%s generating BOM)",
- codec ? codec->name().constData() : "no",
- !codec || (writeConverterState.flags & QTextCodec::IgnoreHeader) ? "not" : "");
-#endif
-
- // convert from unicode to raw data
- // codec might be null if we're already inside global destructors (QTestCodec::codecForLocale returned null)
- QByteArray data = Q_LIKELY(codec) ? codec->fromUnicode(writeBuffer.data(), writeBuffer.size(), &writeConverterState)
- : writeBuffer.toLatin1();
-#else
- QByteArray data = writeBuffer.toLatin1();
-#endif
- writeBuffer.clear();
-
- // write raw data to the device
- qint64 bytesWritten = device->write(data);
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::flushWriteBuffer(), device->write(\"%s\") == %d",
- qt_prettyDebug(data.constData(), qMin(data.size(),32), data.size()).constData(), int(bytesWritten));
-#endif
-
-#if defined (Q_OS_WIN)
- // reset the text flag
- if (textModeEnabled)
- device->setTextModeEnabled(true);
-#endif
-
- if (bytesWritten <= 0) {
- status = QTextStream::WriteFailed;
- return;
- }
-
- // flush the file
-#ifndef QT_NO_QOBJECT
- QFileDevice *file = qobject_cast<QFileDevice *>(device);
- bool flushed = !file || file->flush();
-#else
- bool flushed = true;
-#endif
-
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::flushWriteBuffer() wrote %d bytes",
- int(bytesWritten));
-#endif
- if (!flushed || bytesWritten != qint64(data.size()))
- status = QTextStream::WriteFailed;
-}
-
-QString QTextStreamPrivate::read(int maxlen)
-{
- QString ret;
- if (string) {
- lastTokenSize = qMin(maxlen, string->size() - stringOffset);
- ret = string->mid(stringOffset, lastTokenSize);
- } else {
- while (readBuffer.size() - readBufferOffset < maxlen && fillReadBuffer()) ;
- lastTokenSize = qMin(maxlen, readBuffer.size() - readBufferOffset);
- ret = readBuffer.mid(readBufferOffset, lastTokenSize);
- }
- consumeLastToken();
-
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::read() maxlen = %d, token length = %d", maxlen, ret.length());
-#endif
- return ret;
-}
-
-/*!
- \internal
-
- Scans no more than \a maxlen QChars in the current buffer for the
- first \a delimiter. Stores a pointer to the start offset of the
- token in \a ptr, and the length in QChars in \a length.
-*/
-bool QTextStreamPrivate::scan(const QChar **ptr, int *length, int maxlen, TokenDelimiter delimiter)
-{
- int totalSize = 0;
- int delimSize = 0;
- bool consumeDelimiter = false;
- bool foundToken = false;
- int startOffset = device ? readBufferOffset : stringOffset;
- QChar lastChar;
-
- bool canStillReadFromDevice = true;
- do {
- int endOffset;
- const QChar *chPtr;
- if (device) {
- chPtr = readBuffer.constData();
- endOffset = readBuffer.size();
- } else {
- chPtr = string->constData();
- endOffset = string->size();
- }
- chPtr += startOffset;
-
- for (; !foundToken && startOffset < endOffset && (!maxlen || totalSize < maxlen); ++startOffset) {
- const QChar ch = *chPtr++;
- ++totalSize;
-
- switch (delimiter) {
- case Space:
- if (ch.isSpace()) {
- foundToken = true;
- delimSize = 1;
- }
- break;
- case NotSpace:
- if (!ch.isSpace()) {
- foundToken = true;
- delimSize = 1;
- }
- break;
- case EndOfLine:
- if (ch == QLatin1Char('\n')) {
- foundToken = true;
- delimSize = (lastChar == QLatin1Char('\r')) ? 2 : 1;
- consumeDelimiter = true;
- }
- lastChar = ch;
- break;
- }
- }
- } while (!foundToken
- && (!maxlen || totalSize < maxlen)
- && (device && (canStillReadFromDevice = fillReadBuffer())));
-
- if (totalSize == 0) {
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::scan() reached the end of input.");
-#endif
- return false;
- }
-
- // if we find a '\r' at the end of the data when reading lines,
- // don't make it part of the line.
- if (delimiter == EndOfLine && totalSize > 0 && !foundToken) {
- if (((string && stringOffset + totalSize == string->size()) || (device && device->atEnd()))
- && lastChar == QLatin1Char('\r')) {
- consumeDelimiter = true;
- ++delimSize;
- }
- }
-
- // set the read offset and length of the token
- if (length)
- *length = totalSize - delimSize;
- if (ptr)
- *ptr = readPtr();
-
- // update last token size. the callee will call consumeLastToken() when
- // done.
- lastTokenSize = totalSize;
- if (!consumeDelimiter)
- lastTokenSize -= delimSize;
-
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::scan(%p, %p, %d, %x) token length = %d, delimiter = %d",
- ptr, length, maxlen, (int)delimiter, totalSize - delimSize, delimSize);
-#endif
- return true;
-}
-
-/*!
- \internal
-*/
-inline const QChar *QTextStreamPrivate::readPtr() const
-{
- Q_ASSERT(readBufferOffset <= readBuffer.size());
- if (string)
- return string->constData() + stringOffset;
- return readBuffer.constData() + readBufferOffset;
-}
-
-/*!
- \internal
-*/
-inline void QTextStreamPrivate::consumeLastToken()
-{
- if (lastTokenSize)
- consume(lastTokenSize);
- lastTokenSize = 0;
-}
-
-/*!
- \internal
-*/
-inline void QTextStreamPrivate::consume(int size)
-{
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStreamPrivate::consume(%d)", size);
-#endif
- if (string) {
- stringOffset += size;
- if (stringOffset > string->size())
- stringOffset = string->size();
- } else {
- readBufferOffset += size;
- if (readBufferOffset >= readBuffer.size()) {
- readBufferOffset = 0;
- readBuffer.clear();
- saveConverterState(device->pos());
- } else if (readBufferOffset > QTEXTSTREAM_BUFFERSIZE) {
- readBuffer = readBuffer.remove(0,readBufferOffset);
- readConverterSavedStateOffset += readBufferOffset;
- readBufferOffset = 0;
- }
- }
-}
-
-/*!
- \internal
-*/
-inline void QTextStreamPrivate::saveConverterState(qint64 newPos)
-{
-#ifndef QT_NO_TEXTCODEC
- if (readConverterState.d) {
- // converter cannot be copied, so don't save anything
- // don't update readBufferStartDevicePos either
- return;
- }
-
- if (!readConverterSavedState)
- readConverterSavedState = new QTextCodec::ConverterState;
- copyConverterStateHelper(readConverterSavedState, &readConverterState);
-#endif
-
- readBufferStartDevicePos = newPos;
- readConverterSavedStateOffset = 0;
-}
-
-/*!
- \internal
-*/
-inline void QTextStreamPrivate::restoreToSavedConverterState()
-{
-#ifndef QT_NO_TEXTCODEC
- if (readConverterSavedState) {
- // we have a saved state
- // that means the converter can be copied
- copyConverterStateHelper(&readConverterState, readConverterSavedState);
- } else {
- // the only state we could save was the initial
- // so reset to that
- resetCodecConverterStateHelper(&readConverterState);
- }
-#endif
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::write(const QChar *data, int len)
-{
- if (string) {
- // ### What about seek()??
- string->append(data, len);
- } else {
- writeBuffer.append(data, len);
- if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
- flushWriteBuffer();
- }
-}
-
-/*!
- \internal
-*/
-inline void QTextStreamPrivate::write(QChar ch)
-{
- if (string) {
- // ### What about seek()??
- string->append(ch);
- } else {
- writeBuffer += ch;
- if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
- flushWriteBuffer();
- }
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::write(QLatin1String data)
-{
- if (string) {
- // ### What about seek()??
- string->append(data);
- } else {
- writeBuffer += data;
- if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
- flushWriteBuffer();
- }
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::writePadding(int len)
-{
- if (string) {
- // ### What about seek()??
- string->resize(string->size() + len, params.padChar);
- } else {
- writeBuffer.resize(writeBuffer.size() + len, params.padChar);
- if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE)
- flushWriteBuffer();
- }
-}
-
-/*!
- \internal
-*/
-inline bool QTextStreamPrivate::getChar(QChar *ch)
-{
- if ((string && stringOffset == string->size())
- || (device && readBuffer.isEmpty() && !fillReadBuffer())) {
- if (ch)
- *ch = 0;
- return false;
- }
- if (ch)
- *ch = *readPtr();
- consume(1);
- return true;
-}
-
-/*!
- \internal
-*/
-inline void QTextStreamPrivate::ungetChar(QChar ch)
-{
- if (string) {
- if (stringOffset == 0)
- string->prepend(ch);
- else
- (*string)[--stringOffset] = ch;
- return;
- }
-
- if (readBufferOffset == 0) {
- readBuffer.prepend(ch);
- return;
- }
-
- readBuffer[--readBufferOffset] = ch;
-}
-
-/*!
- \internal
-*/
-inline void QTextStreamPrivate::putChar(QChar ch)
-{
- if (params.fieldWidth > 0)
- putString(&ch, 1);
- else
- write(ch);
-}
-
-
-/*!
- \internal
-*/
-QTextStreamPrivate::PaddingResult QTextStreamPrivate::padding(int len) const
-{
- Q_ASSERT(params.fieldWidth > len); // calling padding() when no padding is needed is an error
-
- int left = 0, right = 0;
-
- const int padSize = params.fieldWidth - len;
-
- switch (params.fieldAlignment) {
- case QTextStream::AlignLeft:
- right = padSize;
- break;
- case QTextStream::AlignRight:
- case QTextStream::AlignAccountingStyle:
- left = padSize;
- break;
- case QTextStream::AlignCenter:
- left = padSize/2;
- right = padSize - padSize/2;
- break;
- }
- const PaddingResult result = { left, right };
- return result;
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::putString(const QChar *data, int len, bool number)
-{
- if (Q_UNLIKELY(params.fieldWidth > len)) {
-
- // handle padding:
-
- const PaddingResult pad = padding(len);
-
- if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) {
- const QChar sign = len > 0 ? data[0] : QChar();
- if (sign == locale.negativeSign() || sign == locale.positiveSign()) {
- // write the sign before the padding, then skip it later
- write(&sign, 1);
- ++data;
- --len;
- }
- }
-
- writePadding(pad.left);
- write(data, len);
- writePadding(pad.right);
- } else {
- write(data, len);
- }
-}
-
-/*!
- \internal
-*/
-void QTextStreamPrivate::putString(QLatin1String data, bool number)
-{
- if (Q_UNLIKELY(params.fieldWidth > data.size())) {
-
- // handle padding
-
- const PaddingResult pad = padding(data.size());
-
- if (params.fieldAlignment == QTextStream::AlignAccountingStyle && number) {
- const QChar sign = data.size() > 0 ? QLatin1Char(*data.data()) : QChar();
- if (sign == locale.negativeSign() || sign == locale.positiveSign()) {
- // write the sign before the padding, then skip it later
- write(&sign, 1);
- data = QLatin1String(data.data() + 1, data.size() - 1);
- }
- }
-
- writePadding(pad.left);
- write(data);
- writePadding(pad.right);
- } else {
- write(data);
- }
-}
-
-/*!
- Constructs a QTextStream. Before you can use it for reading or
- writing, you must assign a device or a string.
-
- \sa setDevice(), setString()
-*/
-QTextStream::QTextStream()
- : d_ptr(new QTextStreamPrivate(this))
-{
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStream::QTextStream()");
-#endif
- Q_D(QTextStream);
- d->status = Ok;
-}
-
-/*!
- Constructs a QTextStream that operates on \a device.
-*/
-QTextStream::QTextStream(QIODevice *device)
- : d_ptr(new QTextStreamPrivate(this))
-{
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStream::QTextStream(QIODevice *device == *%p)",
- device);
-#endif
- Q_D(QTextStream);
- d->device = device;
-#ifndef QT_NO_QOBJECT
- d->deviceClosedNotifier.setupDevice(this, d->device);
-#endif
- d->status = Ok;
-}
-
-/*!
- Constructs a QTextStream that operates on \a string, using \a
- openMode to define the open mode.
-*/
-QTextStream::QTextStream(QString *string, QIODevice::OpenMode openMode)
- : d_ptr(new QTextStreamPrivate(this))
-{
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStream::QTextStream(QString *string == *%p, openMode = %d)",
- string, int(openMode));
-#endif
- Q_D(QTextStream);
- d->string = string;
- d->stringOpenMode = openMode;
- d->status = Ok;
-}
-
-/*!
- Constructs a QTextStream that operates on \a array, using \a
- openMode to define the open mode. Internally, the array is wrapped
- by a QBuffer.
-*/
-QTextStream::QTextStream(QByteArray *array, QIODevice::OpenMode openMode)
- : d_ptr(new QTextStreamPrivate(this))
-{
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStream::QTextStream(QByteArray *array == *%p, openMode = %d)",
- array, int(openMode));
-#endif
- Q_D(QTextStream);
- d->device = new QBuffer(array);
- d->device->open(openMode);
- d->deleteDevice = true;
-#ifndef QT_NO_QOBJECT
- d->deviceClosedNotifier.setupDevice(this, d->device);
-#endif
- d->status = Ok;
-}
-
-/*!
- Constructs a QTextStream that operates on \a array, using \a
- openMode to define the open mode. The array is accessed as
- read-only, regardless of the values in \a openMode.
-
- This constructor is convenient for working on constant
- strings. Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 3
-*/
-QTextStream::QTextStream(const QByteArray &array, QIODevice::OpenMode openMode)
- : d_ptr(new QTextStreamPrivate(this))
-{
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStream::QTextStream(const QByteArray &array == *(%p), openMode = %d)",
- &array, int(openMode));
-#endif
- QBuffer *buffer = new QBuffer;
- buffer->setData(array);
- buffer->open(openMode);
-
- Q_D(QTextStream);
- d->device = buffer;
- d->deleteDevice = true;
-#ifndef QT_NO_QOBJECT
- d->deviceClosedNotifier.setupDevice(this, d->device);
-#endif
- d->status = Ok;
-}
-
-/*!
- Constructs a QTextStream that operates on \a fileHandle, using \a
- openMode to define the open mode. Internally, a QFile is created
- to handle the FILE pointer.
-
- This constructor is useful for working directly with the common
- FILE based input and output streams: stdin, stdout and stderr. Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 4
-*/
-
-QTextStream::QTextStream(FILE *fileHandle, QIODevice::OpenMode openMode)
- : d_ptr(new QTextStreamPrivate(this))
-{
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStream::QTextStream(FILE *fileHandle = %p, openMode = %d)",
- fileHandle, int(openMode));
-#endif
- QFile *file = new QFile;
- file->open(fileHandle, openMode);
-
- Q_D(QTextStream);
- d->device = file;
- d->deleteDevice = true;
-#ifndef QT_NO_QOBJECT
- d->deviceClosedNotifier.setupDevice(this, d->device);
-#endif
- d->status = Ok;
-}
-
-/*!
- Destroys the QTextStream.
-
- If the stream operates on a device, flush() will be called
- implicitly. Otherwise, the device is unaffected.
-*/
-QTextStream::~QTextStream()
-{
- Q_D(QTextStream);
-#if defined (QTEXTSTREAM_DEBUG)
- qDebug("QTextStream::~QTextStream()");
-#endif
- if (!d->writeBuffer.isEmpty())
- d->flushWriteBuffer();
-}
-
-/*!
- Resets QTextStream's formatting options, bringing it back to its
- original constructed state. The device, string and any buffered
- data is left untouched.
-*/
-void QTextStream::reset()
-{
- Q_D(QTextStream);
-
- d->params.reset();
-}
-
-/*!
- Flushes any buffered data waiting to be written to the device.
-
- If QTextStream operates on a string, this function does nothing.
-*/
-void QTextStream::flush()
-{
- Q_D(QTextStream);
- d->flushWriteBuffer();
-}
-
-/*!
- Seeks to the position \a pos in the device. Returns \c true on
- success; otherwise returns \c false.
-*/
-bool QTextStream::seek(qint64 pos)
-{
- Q_D(QTextStream);
- d->lastTokenSize = 0;
-
- if (d->device) {
- // Empty the write buffer
- d->flushWriteBuffer();
- if (!d->device->seek(pos))
- return false;
- d->resetReadBuffer();
-
-#ifndef QT_NO_TEXTCODEC
- // Reset the codec converter states.
- resetCodecConverterStateHelper(&d->readConverterState);
- resetCodecConverterStateHelper(&d->writeConverterState);
- delete d->readConverterSavedState;
- d->readConverterSavedState = 0;
- d->writeConverterState.flags |= QTextCodec::IgnoreHeader;
-#endif
- return true;
- }
-
- // string
- if (d->string && pos <= d->string->size()) {
- d->stringOffset = int(pos);
- return true;
- }
- return false;
-}
-
-/*!
- \since 4.2
-
- Returns the device position corresponding to the current position of the
- stream, or -1 if an error occurs (e.g., if there is no device or string,
- or if there's a device error).
-
- Because QTextStream is buffered, this function may have to
- seek the device to reconstruct a valid device position. This
- operation can be expensive, so you may want to avoid calling this
- function in a tight loop.
-
- \sa seek()
-*/
-qint64 QTextStream::pos() const
-{
- Q_D(const QTextStream);
- if (d->device) {
- // Cutoff
- if (d->readBuffer.isEmpty())
- return d->device->pos();
- if (d->device->isSequential())
- return 0;
-
- // Seek the device
- if (!d->device->seek(d->readBufferStartDevicePos))
- return qint64(-1);
-
- // Reset the read buffer
- QTextStreamPrivate *thatd = const_cast<QTextStreamPrivate *>(d);
- thatd->readBuffer.clear();
-
-#ifndef QT_NO_TEXTCODEC
- thatd->restoreToSavedConverterState();
- if (d->readBufferStartDevicePos == 0)
- thatd->autoDetectUnicode = true;
-#endif
-
- // Rewind the device to get to the current position Ensure that
- // readBufferOffset is unaffected by fillReadBuffer()
- int oldReadBufferOffset = d->readBufferOffset + d->readConverterSavedStateOffset;
- while (d->readBuffer.size() < oldReadBufferOffset) {
- if (!thatd->fillReadBuffer(1))
- return qint64(-1);
- }
- thatd->readBufferOffset = oldReadBufferOffset;
- thatd->readConverterSavedStateOffset = 0;
-
- // Return the device position.
- return d->device->pos();
- }
-
- if (d->string)
- return d->stringOffset;
-
- qWarning("QTextStream::pos: no device");
- return qint64(-1);
-}
-
-/*!
- Reads and discards whitespace from the stream until either a
- non-space character is detected, or until atEnd() returns
- true. This function is useful when reading a stream character by
- character.
-
- Whitespace characters are all characters for which
- QChar::isSpace() returns \c true.
-
- \sa operator>>()
-*/
-void QTextStream::skipWhiteSpace()
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(Q_VOID);
- d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
- d->consumeLastToken();
-}
-
-/*!
- Sets the current device to \a device. If a device has already been
- assigned, QTextStream will call flush() before the old device is
- replaced.
-
- \note This function resets locale to the default locale ('C')
- and codec to the default codec, QTextCodec::codecForLocale().
-
- \sa device(), setString()
-*/
-void QTextStream::setDevice(QIODevice *device)
-{
- Q_D(QTextStream);
- flush();
- if (d->deleteDevice) {
-#ifndef QT_NO_QOBJECT
- d->deviceClosedNotifier.disconnect();
-#endif
- delete d->device;
- d->deleteDevice = false;
- }
-
- d->reset();
- d->status = Ok;
- d->device = device;
- d->resetReadBuffer();
-#ifndef QT_NO_QOBJECT
- d->deviceClosedNotifier.setupDevice(this, d->device);
-#endif
-}
-
-/*!
- Returns the current device associated with the QTextStream,
- or 0 if no device has been assigned.
-
- \sa setDevice(), string()
-*/
-QIODevice *QTextStream::device() const
-{
- Q_D(const QTextStream);
- return d->device;
-}
-
-/*!
- Sets the current string to \a string, using the given \a
- openMode. If a device has already been assigned, QTextStream will
- call flush() before replacing it.
-
- \sa string(), setDevice()
-*/
-void QTextStream::setString(QString *string, QIODevice::OpenMode openMode)
-{
- Q_D(QTextStream);
- flush();
- if (d->deleteDevice) {
-#ifndef QT_NO_QOBJECT
- d->deviceClosedNotifier.disconnect();
- d->device->blockSignals(true);
-#endif
- delete d->device;
- d->deleteDevice = false;
- }
-
- d->reset();
- d->status = Ok;
- d->string = string;
- d->stringOpenMode = openMode;
-}
-
-/*!
- Returns the current string assigned to the QTextStream, or 0 if no
- string has been assigned.
-
- \sa setString(), device()
-*/
-QString *QTextStream::string() const
-{
- Q_D(const QTextStream);
- return d->string;
-}
-
-/*!
- Sets the field alignment to \a mode. When used together with
- setFieldWidth(), this function allows you to generate formatted
- output with text aligned to the left, to the right or center
- aligned.
-
- \sa fieldAlignment(), setFieldWidth()
-*/
-void QTextStream::setFieldAlignment(FieldAlignment mode)
-{
- Q_D(QTextStream);
- d->params.fieldAlignment = mode;
-}
-
-/*!
- Returns the current field alignment.
-
- \sa setFieldAlignment(), fieldWidth()
-*/
-QTextStream::FieldAlignment QTextStream::fieldAlignment() const
-{
- Q_D(const QTextStream);
- return d->params.fieldAlignment;
-}
-
-/*!
- Sets the pad character to \a ch. The default value is the ASCII
- space character (' '), or QChar(0x20). This character is used to
- fill in the space in fields when generating text.
-
- Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 5
-
- The string \c s contains:
-
- \snippet code/src_corelib_io_qtextstream.cpp 6
-
- \sa padChar(), setFieldWidth()
-*/
-void QTextStream::setPadChar(QChar ch)
-{
- Q_D(QTextStream);
- d->params.padChar = ch;
-}
-
-/*!
- Returns the current pad character.
-
- \sa setPadChar(), setFieldWidth()
-*/
-QChar QTextStream::padChar() const
-{
- Q_D(const QTextStream);
- return d->params.padChar;
-}
-
-/*!
- Sets the current field width to \a width. If \a width is 0 (the
- default), the field width is equal to the length of the generated
- text.
-
- \note The field width applies to every element appended to this
- stream after this function has been called (e.g., it also pads
- endl). This behavior is different from similar classes in the STL,
- where the field width only applies to the next element.
-
- \sa fieldWidth(), setPadChar()
-*/
-void QTextStream::setFieldWidth(int width)
-{
- Q_D(QTextStream);
- d->params.fieldWidth = width;
-}
-
-/*!
- Returns the current field width.
-
- \sa setFieldWidth()
-*/
-int QTextStream::fieldWidth() const
-{
- Q_D(const QTextStream);
- return d->params.fieldWidth;
-}
-
-/*!
- Sets the current number flags to \a flags. \a flags is a set of
- flags from the NumberFlag enum, and describes options for
- formatting generated code (e.g., whether or not to always write
- the base or sign of a number).
-
- \sa numberFlags(), setIntegerBase(), setRealNumberNotation()
-*/
-void QTextStream::setNumberFlags(NumberFlags flags)
-{
- Q_D(QTextStream);
- d->params.numberFlags = flags;
-}
-
-/*!
- Returns the current number flags.
-
- \sa setNumberFlags(), integerBase(), realNumberNotation()
-*/
-QTextStream::NumberFlags QTextStream::numberFlags() const
-{
- Q_D(const QTextStream);
- return d->params.numberFlags;
-}
-
-/*!
- Sets the base of integers to \a base, both for reading and for
- generating numbers. \a base can be either 2 (binary), 8 (octal),
- 10 (decimal) or 16 (hexadecimal). If \a base is 0, QTextStream
- will attempt to detect the base by inspecting the data on the
- stream. When generating numbers, QTextStream assumes base is 10
- unless the base has been set explicitly.
-
- \sa integerBase(), QString::number(), setNumberFlags()
-*/
-void QTextStream::setIntegerBase(int base)
-{
- Q_D(QTextStream);
- d->params.integerBase = base;
-}
-
-/*!
- Returns the current base of integers. 0 means that the base is
- detected when reading, or 10 (decimal) when generating numbers.
-
- \sa setIntegerBase(), QString::number(), numberFlags()
-*/
-int QTextStream::integerBase() const
-{
- Q_D(const QTextStream);
- return d->params.integerBase;
-}
-
-/*!
- Sets the real number notation to \a notation (SmartNotation,
- FixedNotation, ScientificNotation). When reading and generating
- numbers, QTextStream uses this value to detect the formatting of
- real numbers.
-
- \sa realNumberNotation(), setRealNumberPrecision(), setNumberFlags(), setIntegerBase()
-*/
-void QTextStream::setRealNumberNotation(RealNumberNotation notation)
-{
- Q_D(QTextStream);
- d->params.realNumberNotation = notation;
-}
-
-/*!
- Returns the current real number notation.
-
- \sa setRealNumberNotation(), realNumberPrecision(), numberFlags(), integerBase()
-*/
-QTextStream::RealNumberNotation QTextStream::realNumberNotation() const
-{
- Q_D(const QTextStream);
- return d->params.realNumberNotation;
-}
-
-/*!
- Sets the precision of real numbers to \a precision. This value
- describes the number of fraction digits QTextStream should
- write when generating real numbers.
-
- The precision cannot be a negative value. The default value is 6.
-
- \sa realNumberPrecision(), setRealNumberNotation()
-*/
-void QTextStream::setRealNumberPrecision(int precision)
-{
- Q_D(QTextStream);
- if (precision < 0) {
- qWarning("QTextStream::setRealNumberPrecision: Invalid precision (%d)", precision);
- d->params.realNumberPrecision = 6;
- return;
- }
- d->params.realNumberPrecision = precision;
-}
-
-/*!
- Returns the current real number precision, or the number of fraction
- digits QTextStream will write when generating real numbers.
-
- \sa setRealNumberNotation(), realNumberNotation(), numberFlags(), integerBase()
-*/
-int QTextStream::realNumberPrecision() const
-{
- Q_D(const QTextStream);
- return d->params.realNumberPrecision;
-}
-
-/*!
- Returns the status of the text stream.
-
- \sa QTextStream::Status, setStatus(), resetStatus()
-*/
-
-QTextStream::Status QTextStream::status() const
-{
- Q_D(const QTextStream);
- return d->status;
-}
-
-/*!
- \since 4.1
-
- Resets the status of the text stream.
-
- \sa QTextStream::Status, status(), setStatus()
-*/
-void QTextStream::resetStatus()
-{
- Q_D(QTextStream);
- d->status = Ok;
-}
-
-/*!
- \since 4.1
-
- Sets the status of the text stream to the \a status given.
-
- Subsequent calls to setStatus() are ignored until resetStatus()
- is called.
-
- \sa Status, status(), resetStatus()
-*/
-void QTextStream::setStatus(Status status)
-{
- Q_D(QTextStream);
- if (d->status == Ok)
- d->status = status;
-}
-
-/*!
- Returns \c true if there is no more data to be read from the
- QTextStream; otherwise returns \c false. This is similar to, but not
- the same as calling QIODevice::atEnd(), as QTextStream also takes
- into account its internal Unicode buffer.
-*/
-bool QTextStream::atEnd() const
-{
- Q_D(const QTextStream);
- CHECK_VALID_STREAM(true);
-
- if (d->string)
- return d->string->size() == d->stringOffset;
- return d->readBuffer.isEmpty() && d->device->atEnd();
-}
-
-/*!
- Reads the entire content of the stream, and returns it as a
- QString. Avoid this function when working on large files, as it
- will consume a significant amount of memory.
-
- Calling \l {QTextStream::readLine()}{readLine()} is better if you do not know how much data is
- available.
-
- \sa readLine()
-*/
-QString QTextStream::readAll()
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(QString());
-
- return d->read(INT_MAX);
-}
-
-/*!
- Reads one line of text from the stream, and returns it as a
- QString. The maximum allowed line length is set to \a maxlen. If
- the stream contains lines longer than this, then the lines will be
- split after \a maxlen characters and returned in parts.
-
- If \a maxlen is 0, the lines can be of any length.
-
- The returned line has no trailing end-of-line characters ("\\n"
- or "\\r\\n"), so calling QString::trimmed() can be unnecessary.
-
- If the stream has read to the end of the file, \l {QTextStream::readLine()}{readLine()}
- will return a null QString. For strings, or for devices that support it,
- you can explicitly test for the end of the stream using atEnd().
-
- \sa readAll(), QIODevice::readLine()
-*/
-QString QTextStream::readLine(qint64 maxlen)
-{
- QString line;
-
- readLineInto(&line, maxlen);
- return line;
-}
-
-/*!
- \since 5.5
-
- Reads one line of text from the stream into \a line.
- If \a line is 0, the read line is not stored.
-
- The maximum allowed line length is set to \a maxlen. If
- the stream contains lines longer than this, then the lines will be
- split after \a maxlen characters and returned in parts.
-
- If \a maxlen is 0, the lines can be of any length.
-
- The resulting line has no trailing end-of-line characters ("\\n"
- or "\\r\\n"), so calling QString::trimmed() can be unnecessary.
-
- If \a line has sufficient capacity for the data that is about to be
- read, this function may not need to allocate new memory. Because of
- this, it can be faster than readLine().
-
- Returns \c false if the stream has read to the end of the file or
- an error has occurred; otherwise returns \c true. The contents in
- \a line before the call are discarded in any case.
-
- \sa readAll(), QIODevice::readLine()
-*/
-bool QTextStream::readLineInto(QString *line, qint64 maxlen)
-{
- Q_D(QTextStream);
- // keep in sync with CHECK_VALID_STREAM
- if (!d->string && !d->device) {
- qWarning("QTextStream: No device");
- if (line && !line->isNull())
- line->resize(0);
- return false;
- }
-
- const QChar *readPtr;
- int length;
- if (!d->scan(&readPtr, &length, int(maxlen), QTextStreamPrivate::EndOfLine)) {
- if (line && !line->isNull())
- line->resize(0);
- return false;
- }
-
- if (Q_LIKELY(line))
- line->setUnicode(readPtr, length);
- d->consumeLastToken();
- return true;
-}
-
-/*!
- \since 4.1
-
- Reads at most \a maxlen characters from the stream, and returns the data
- read as a QString.
-
- \sa readAll(), readLine(), QIODevice::read()
-*/
-QString QTextStream::read(qint64 maxlen)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(QString());
-
- if (maxlen <= 0)
- return QString::fromLatin1(""); // empty, not null
-
- return d->read(int(maxlen));
-}
-
-/*!
- \internal
-*/
-QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong *ret)
-{
- scan(0, 0, 0, NotSpace);
- consumeLastToken();
-
- // detect int encoding
- int base = params.integerBase;
- if (base == 0) {
- QChar ch;
- if (!getChar(&ch))
- return npsInvalidPrefix;
- if (ch == QLatin1Char('0')) {
- QChar ch2;
- if (!getChar(&ch2)) {
- // Result is the number 0
- *ret = 0;
- return npsOk;
- }
- ch2 = ch2.toLower();
-
- if (ch2 == QLatin1Char('x')) {
- base = 16;
- } else if (ch2 == QLatin1Char('b')) {
- base = 2;
- } else if (ch2.isDigit() && ch2.digitValue() >= 0 && ch2.digitValue() <= 7) {
- base = 8;
- } else {
- base = 10;
- }
- ungetChar(ch2);
- } else if (ch == locale.negativeSign() || ch == locale.positiveSign() || ch.isDigit()) {
- base = 10;
- } else {
- ungetChar(ch);
- return npsInvalidPrefix;
- }
- ungetChar(ch);
- // State of the stream is now the same as on entry
- // (cursor is at prefix),
- // and local variable 'base' has been set appropriately.
- }
-
- qulonglong val=0;
- switch (base) {
- case 2: {
- QChar pf1, pf2, dig;
- // Parse prefix '0b'
- if (!getChar(&pf1) || pf1 != QLatin1Char('0'))
- return npsInvalidPrefix;
- if (!getChar(&pf2) || pf2.toLower() != QLatin1Char('b'))
- return npsInvalidPrefix;
- // Parse digits
- int ndigits = 0;
- while (getChar(&dig)) {
- int n = dig.toLower().unicode();
- if (n == '0' || n == '1') {
- val <<= 1;
- val += n - '0';
- } else {
- ungetChar(dig);
- break;
- }
- ndigits++;
- }
- if (ndigits == 0) {
- // Unwind the prefix and abort
- ungetChar(pf2);
- ungetChar(pf1);
- return npsMissingDigit;
- }
- break;
- }
- case 8: {
- QChar pf, dig;
- // Parse prefix '0'
- if (!getChar(&pf) || pf != QLatin1Char('0'))
- return npsInvalidPrefix;
- // Parse digits
- int ndigits = 0;
- while (getChar(&dig)) {
- int n = dig.toLower().unicode();
- if (n >= '0' && n <= '7') {
- val *= 8;
- val += n - '0';
- } else {
- ungetChar(dig);
- break;
- }
- ndigits++;
- }
- if (ndigits == 0) {
- // Unwind the prefix and abort
- ungetChar(pf);
- return npsMissingDigit;
- }
- break;
- }
- case 10: {
- // Parse sign (or first digit)
- QChar sign;
- int ndigits = 0;
- if (!getChar(&sign))
- return npsMissingDigit;
- if (sign != locale.negativeSign() && sign != locale.positiveSign()) {
- if (!sign.isDigit()) {
- ungetChar(sign);
- return npsMissingDigit;
- }
- val += sign.digitValue();
- ndigits++;
- }
- // Parse digits
- QChar ch;
- while (getChar(&ch)) {
- if (ch.isDigit()) {
- val *= 10;
- val += ch.digitValue();
- } else if (locale != QLocale::c() && ch == locale.groupSeparator()) {
- continue;
- } else {
- ungetChar(ch);
- break;
- }
- ndigits++;
- }
- if (ndigits == 0)
- return npsMissingDigit;
- if (sign == locale.negativeSign()) {
- qlonglong ival = qlonglong(val);
- if (ival > 0)
- ival = -ival;
- val = qulonglong(ival);
- }
- break;
- }
- case 16: {
- QChar pf1, pf2, dig;
- // Parse prefix ' 0x'
- if (!getChar(&pf1) || pf1 != QLatin1Char('0'))
- return npsInvalidPrefix;
- if (!getChar(&pf2) || pf2.toLower() != QLatin1Char('x'))
- return npsInvalidPrefix;
- // Parse digits
- int ndigits = 0;
- while (getChar(&dig)) {
- int n = dig.toLower().unicode();
- if (n >= '0' && n <= '9') {
- val <<= 4;
- val += n - '0';
- } else if (n >= 'a' && n <= 'f') {
- val <<= 4;
- val += 10 + (n - 'a');
- } else {
- ungetChar(dig);
- break;
- }
- ndigits++;
- }
- if (ndigits == 0) {
- return npsMissingDigit;
- }
- break;
- }
- default:
- // Unsupported integerBase
- return npsInvalidPrefix;
- }
-
- if (ret)
- *ret = val;
- return npsOk;
-}
-
-/*!
- \internal
- (hihi)
-*/
-bool QTextStreamPrivate::getReal(double *f)
-{
- // We use a table-driven FSM to parse floating point numbers
- // strtod() cannot be used directly since we may be reading from a
- // QIODevice.
- enum ParserState {
- Init = 0,
- Sign = 1,
- Mantissa = 2,
- Dot = 3,
- Abscissa = 4,
- ExpMark = 5,
- ExpSign = 6,
- Exponent = 7,
- Nan1 = 8,
- Nan2 = 9,
- Inf1 = 10,
- Inf2 = 11,
- NanInf = 12,
- Done = 13
- };
- enum InputToken {
- None = 0,
- InputSign = 1,
- InputDigit = 2,
- InputDot = 3,
- InputExp = 4,
- InputI = 5,
- InputN = 6,
- InputF = 7,
- InputA = 8,
- InputT = 9
- };
-
- static const uchar table[13][10] = {
- // None InputSign InputDigit InputDot InputExp InputI InputN InputF InputA InputT
- { 0, Sign, Mantissa, Dot, 0, Inf1, Nan1, 0, 0, 0 }, // 0 Init
- { 0, 0, Mantissa, Dot, 0, Inf1, Nan1, 0, 0, 0 }, // 1 Sign
- { Done, Done, Mantissa, Dot, ExpMark, 0, 0, 0, 0, 0 }, // 2 Mantissa
- { 0, 0, Abscissa, 0, 0, 0, 0, 0, 0, 0 }, // 3 Dot
- { Done, Done, Abscissa, Done, ExpMark, 0, 0, 0, 0, 0 }, // 4 Abscissa
- { 0, ExpSign, Exponent, 0, 0, 0, 0, 0, 0, 0 }, // 5 ExpMark
- { 0, 0, Exponent, 0, 0, 0, 0, 0, 0, 0 }, // 6 ExpSign
- { Done, Done, Exponent, Done, Done, 0, 0, 0, 0, 0 }, // 7 Exponent
- { 0, 0, 0, 0, 0, 0, 0, 0, Nan2, 0 }, // 8 Nan1
- { 0, 0, 0, 0, 0, 0, NanInf, 0, 0, 0 }, // 9 Nan2
- { 0, 0, 0, 0, 0, 0, Inf2, 0, 0, 0 }, // 10 Inf1
- { 0, 0, 0, 0, 0, 0, 0, NanInf, 0, 0 }, // 11 Inf2
- { Done, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 11 NanInf
- };
-
- ParserState state = Init;
- InputToken input = None;
-
- scan(0, 0, 0, NotSpace);
- consumeLastToken();
-
- const int BufferSize = 128;
- char buf[BufferSize];
- int i = 0;
-
- QChar c;
- while (getChar(&c)) {
- switch (c.unicode()) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- input = InputDigit;
- break;
- case 'i': case 'I':
- input = InputI;
- break;
- case 'n': case 'N':
- input = InputN;
- break;
- case 'f': case 'F':
- input = InputF;
- break;
- case 'a': case 'A':
- input = InputA;
- break;
- case 't': case 'T':
- input = InputT;
- break;
- default: {
- QChar lc = c.toLower();
- if (lc == locale.decimalPoint().toLower())
- input = InputDot;
- else if (lc == locale.exponential().toLower())
- input = InputExp;
- else if (lc == locale.negativeSign().toLower()
- || lc == locale.positiveSign().toLower())
- input = InputSign;
- else if (locale != QLocale::c() // backward-compatibility
- && lc == locale.groupSeparator().toLower())
- input = InputDigit; // well, it isn't a digit, but no one cares.
- else
- input = None;
- }
- break;
- }
-
- state = ParserState(table[state][input]);
-
- if (state == Init || state == Done || i > (BufferSize - 5)) {
- ungetChar(c);
- if (i > (BufferSize - 5)) { // ignore rest of digits
- while (getChar(&c)) {
- if (!c.isDigit()) {
- ungetChar(c);
- break;
- }
- }
- }
- break;
- }
-
- buf[i++] = c.toLatin1();
- }
-
- if (i == 0)
- return false;
- if (!f)
- return true;
- buf[i] = '\0';
-
- // backward-compatibility. Old implementation supported +nan/-nan
- // for some reason. QLocale only checks for lower-case
- // nan/+inf/-inf, so here we also check for uppercase and mixed
- // case versions.
- if (!qstricmp(buf, "nan") || !qstricmp(buf, "+nan") || !qstricmp(buf, "-nan")) {
- *f = qSNaN();
- return true;
- } else if (!qstricmp(buf, "+inf") || !qstricmp(buf, "inf")) {
- *f = qInf();
- return true;
- } else if (!qstricmp(buf, "-inf")) {
- *f = -qInf();
- return true;
- }
- bool ok;
- *f = locale.toDouble(QString::fromLatin1(buf), &ok);
- return ok;
-}
-
-/*!
- Reads a character from the stream and stores it in \a c. Returns a
- reference to the QTextStream, so several operators can be
- nested. Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 7
-
- Whitespace is \e not skipped.
-*/
-
-QTextStream &QTextStream::operator>>(QChar &c)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
- if (!d->getChar(&c))
- setStatus(ReadPastEnd);
- return *this;
-}
-
-/*!
- \overload
-
- Reads a character from the stream and stores it in \a c. The
- character from the stream is converted to ISO-5589-1 before it is
- stored.
-
- \sa QChar::toLatin1()
-*/
-QTextStream &QTextStream::operator>>(char &c)
-{
- QChar ch;
- *this >> ch;
- c = ch.toLatin1();
- return *this;
-}
-
-/*!
- Reads an integer from the stream and stores it in \a i, then
- returns a reference to the QTextStream. The number is cast to
- the correct type before it is stored. If no number was detected on
- the stream, \a i is set to 0.
-
- By default, QTextStream will attempt to detect the base of the
- number using the following rules:
-
- \table
- \header \li Prefix \li Base
- \row \li "0b" or "0B" \li 2 (binary)
- \row \li "0" followed by "0-7" \li 8 (octal)
- \row \li "0" otherwise \li 10 (decimal)
- \row \li "0x" or "0X" \li 16 (hexadecimal)
- \row \li "1" to "9" \li 10 (decimal)
- \endtable
-
- By calling setIntegerBase(), you can specify the integer base
- explicitly. This will disable the auto-detection, and speed up
- QTextStream slightly.
-
- Leading whitespace is skipped.
-*/
-QTextStream &QTextStream::operator>>(signed short &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(signed short);
-}
-
-/*!
- \overload
-
- Stores the integer in the unsigned short \a i.
-*/
-QTextStream &QTextStream::operator>>(unsigned short &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(unsigned short);
-}
-
-/*!
- \overload
-
- Stores the integer in the signed int \a i.
-*/
-QTextStream &QTextStream::operator>>(signed int &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(signed int);
-}
-
-/*!
- \overload
-
- Stores the integer in the unsigned int \a i.
-*/
-QTextStream &QTextStream::operator>>(unsigned int &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(unsigned int);
-}
-
-/*!
- \overload
-
- Stores the integer in the signed long \a i.
-*/
-QTextStream &QTextStream::operator>>(signed long &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(signed long);
-}
-
-/*!
- \overload
-
- Stores the integer in the unsigned long \a i.
-*/
-QTextStream &QTextStream::operator>>(unsigned long &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(unsigned long);
-}
-
-/*!
- \overload
-
- Stores the integer in the qlonglong \a i.
-*/
-QTextStream &QTextStream::operator>>(qlonglong &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(qlonglong);
-}
-
-/*!
- \overload
-
- Stores the integer in the qulonglong \a i.
-*/
-QTextStream &QTextStream::operator>>(qulonglong &i)
-{
- IMPLEMENT_STREAM_RIGHT_INT_OPERATOR(qulonglong);
-}
-
-/*!
- Reads a real number from the stream and stores it in \a f, then
- returns a reference to the QTextStream. The number is cast to
- the correct type. If no real number is detect on the stream, \a f
- is set to 0.0.
-
- As a special exception, QTextStream allows the strings "nan" and "inf" to
- represent NAN and INF floats or doubles.
-
- Leading whitespace is skipped.
-*/
-QTextStream &QTextStream::operator>>(float &f)
-{
- IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR(float);
-}
-
-/*!
- \overload
-
- Stores the real number in the double \a f.
-*/
-QTextStream &QTextStream::operator>>(double &f)
-{
- IMPLEMENT_STREAM_RIGHT_REAL_OPERATOR(double);
-}
-
-/*!
- Reads a word from the stream and stores it in \a str, then returns
- a reference to the stream. Words are separated by whitespace
- (i.e., all characters for which QChar::isSpace() returns \c true).
-
- Leading whitespace is skipped.
-*/
-QTextStream &QTextStream::operator>>(QString &str)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
-
- str.clear();
- d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
- d->consumeLastToken();
-
- const QChar *ptr;
- int length;
- if (!d->scan(&ptr, &length, 0, QTextStreamPrivate::Space)) {
- setStatus(ReadPastEnd);
- return *this;
- }
-
- str = QString(ptr, length);
- d->consumeLastToken();
- return *this;
-}
-
-/*!
- \overload
-
- Converts the word to ISO-8859-1, then stores it in \a array.
-
- \sa QString::toLatin1()
-*/
-QTextStream &QTextStream::operator>>(QByteArray &array)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
-
- array.clear();
- d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
- d->consumeLastToken();
-
- const QChar *ptr;
- int length;
- if (!d->scan(&ptr, &length, 0, QTextStreamPrivate::Space)) {
- setStatus(ReadPastEnd);
- return *this;
- }
-
- for (int i = 0; i < length; ++i)
- array += ptr[i].toLatin1();
-
- d->consumeLastToken();
- return *this;
-}
-
-/*!
- \overload
-
- Stores the word in \a c, terminated by a '\\0' character. If no word is
- available, only the '\\0' character is stored.
-
- Warning: Although convenient, this operator is dangerous and must
- be used with care. QTextStream assumes that \a c points to a
- buffer with enough space to hold the word. If the buffer is too
- small, your application may crash.
-
- If possible, use the QByteArray operator instead.
-*/
-QTextStream &QTextStream::operator>>(char *c)
-{
- Q_D(QTextStream);
- *c = 0;
- CHECK_VALID_STREAM(*this);
- d->scan(0, 0, 0, QTextStreamPrivate::NotSpace);
- d->consumeLastToken();
-
- const QChar *ptr;
- int length;
- if (!d->scan(&ptr, &length, 0, QTextStreamPrivate::Space)) {
- setStatus(ReadPastEnd);
- return *this;
- }
-
- for (int i = 0; i < length; ++i)
- *c++ = ptr[i].toLatin1();
- *c = '\0';
- d->consumeLastToken();
- return *this;
-}
-
-/*!
- \internal
- */
-void QTextStreamPrivate::putNumber(qulonglong number, bool negative)
-{
- QString result;
-
- unsigned flags = 0;
- const QTextStream::NumberFlags numberFlags = params.numberFlags;
- if (numberFlags & QTextStream::ShowBase)
- flags |= QLocaleData::ShowBase;
- if (numberFlags & QTextStream::ForceSign)
- flags |= QLocaleData::AlwaysShowSign;
- if (numberFlags & QTextStream::UppercaseBase)
- flags |= QLocaleData::UppercaseBase;
- if (numberFlags & QTextStream::UppercaseDigits)
- flags |= QLocaleData::CapitalEorX;
-
- // add thousands group separators. For backward compatibility we
- // don't add a group separator for C locale.
- if (locale != QLocale::c() && !locale.numberOptions().testFlag(QLocale::OmitGroupSeparator))
- flags |= QLocaleData::ThousandsGroup;
-
- const QLocaleData *dd = locale.d->m_data;
- int base = params.integerBase ? params.integerBase : 10;
- if (negative && base == 10) {
- result = dd->longLongToString(-static_cast<qlonglong>(number), -1,
- base, -1, flags);
- } else if (negative) {
- // Workaround for backward compatibility for writing negative
- // numbers in octal and hex:
- // QTextStream(result) << showbase << hex << -1 << oct << -1
- // should output: -0x1 -0b1
- result = dd->unsLongLongToString(number, -1, base, -1, flags);
- result.prepend(locale.negativeSign());
- } else {
- result = dd->unsLongLongToString(number, -1, base, -1, flags);
- // workaround for backward compatibility - in octal form with
- // ShowBase flag set zero should be written as '00'
- if (number == 0 && base == 8 && params.numberFlags & QTextStream::ShowBase
- && result == QLatin1String("0")) {
- result.prepend(QLatin1Char('0'));
- }
- }
- putString(result, true);
-}
-
-/*!
- Writes the character \a c to the stream, then returns a reference
- to the QTextStream.
-
- \sa setFieldWidth()
-*/
-QTextStream &QTextStream::operator<<(QChar c)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putChar(c);
- return *this;
-}
-
-/*!
- \overload
-
- Converts \a c from ASCII to a QChar, then writes it to the stream.
-*/
-QTextStream &QTextStream::operator<<(char c)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putChar(QChar::fromLatin1(c));
- return *this;
-}
-
-/*!
- Writes the integer number \a i to the stream, then returns a
- reference to the QTextStream. By default, the number is stored in
- decimal form, but you can also set the base by calling
- setIntegerBase().
-
- \sa setFieldWidth(), setNumberFlags()
-*/
-QTextStream &QTextStream::operator<<(signed short i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber((qulonglong)qAbs(qlonglong(i)), i < 0);
- return *this;
-}
-
-/*!
- \overload
-
- Writes the unsigned short \a i to the stream.
-*/
-QTextStream &QTextStream::operator<<(unsigned short i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber((qulonglong)i, false);
- return *this;
-}
-
-/*!
- \overload
-
- Writes the signed int \a i to the stream.
-*/
-QTextStream &QTextStream::operator<<(signed int i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber((qulonglong)qAbs(qlonglong(i)), i < 0);
- return *this;
-}
-
-/*!
- \overload
-
- Writes the unsigned int \a i to the stream.
-*/
-QTextStream &QTextStream::operator<<(unsigned int i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber((qulonglong)i, false);
- return *this;
-}
-
-/*!
- \overload
-
- Writes the signed long \a i to the stream.
-*/
-QTextStream &QTextStream::operator<<(signed long i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber((qulonglong)qAbs(qlonglong(i)), i < 0);
- return *this;
-}
-
-/*!
- \overload
-
- Writes the unsigned long \a i to the stream.
-*/
-QTextStream &QTextStream::operator<<(unsigned long i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber((qulonglong)i, false);
- return *this;
-}
-
-/*!
- \overload
-
- Writes the qlonglong \a i to the stream.
-*/
-QTextStream &QTextStream::operator<<(qlonglong i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber((qulonglong)qAbs(i), i < 0);
- return *this;
-}
-
-/*!
- \overload
-
- Writes the qulonglong \a i to the stream.
-*/
-QTextStream &QTextStream::operator<<(qulonglong i)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putNumber(i, false);
- return *this;
-}
-
-/*!
- Writes the real number \a f to the stream, then returns a
- reference to the QTextStream. By default, QTextStream stores it
- using SmartNotation, with up to 6 digits of precision. You can
- change the textual representation QTextStream will use for real
- numbers by calling setRealNumberNotation(),
- setRealNumberPrecision() and setNumberFlags().
-
- \sa setFieldWidth(), setRealNumberNotation(),
- setRealNumberPrecision(), setNumberFlags()
-*/
-QTextStream &QTextStream::operator<<(float f)
-{
- return *this << double(f);
-}
-
-/*!
- \overload
-
- Writes the double \a f to the stream.
-*/
-QTextStream &QTextStream::operator<<(double f)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
-
- QLocaleData::DoubleForm form = QLocaleData::DFDecimal;
- switch (realNumberNotation()) {
- case FixedNotation:
- form = QLocaleData::DFDecimal;
- break;
- case ScientificNotation:
- form = QLocaleData::DFExponent;
- break;
- case SmartNotation:
- form = QLocaleData::DFSignificantDigits;
- break;
- }
-
- uint flags = 0;
- const QLocale::NumberOptions numberOptions = locale().numberOptions();
- if (numberFlags() & ShowBase)
- flags |= QLocaleData::ShowBase;
- if (numberFlags() & ForceSign)
- flags |= QLocaleData::AlwaysShowSign;
- if (numberFlags() & UppercaseBase)
- flags |= QLocaleData::UppercaseBase;
- if (numberFlags() & UppercaseDigits)
- flags |= QLocaleData::CapitalEorX;
- if (numberFlags() & ForcePoint) {
- flags |= QLocaleData::ForcePoint;
-
- // Only for backwards compatibility
- flags |= QLocaleData::AddTrailingZeroes | QLocaleData::ShowBase;
- }
- if (locale() != QLocale::c() && !(numberOptions & QLocale::OmitGroupSeparator))
- flags |= QLocaleData::ThousandsGroup;
- if (!(numberOptions & QLocale::OmitLeadingZeroInExponent))
- flags |= QLocaleData::ZeroPadExponent;
- if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
- flags |= QLocaleData::AddTrailingZeroes;
-
- const QLocaleData *dd = d->locale.d->m_data;
- QString num = dd->doubleToString(f, d->params.realNumberPrecision, form, -1, flags);
- d->putString(num, true);
- return *this;
-}
-
-/*!
- Writes the string \a string to the stream, and returns a reference
- to the QTextStream. The string is first encoded using the assigned
- codec (the default codec is QTextCodec::codecForLocale()) before
- it is written to the stream.
-
- \sa setFieldWidth(), setCodec()
-*/
-QTextStream &QTextStream::operator<<(const QString &string)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putString(string);
- return *this;
-}
-
-/*!
- \overload
-
- Writes \a string to the stream, and returns a reference to the
- QTextStream.
-*/
-QTextStream &QTextStream::operator<<(QLatin1String string)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putString(string);
- return *this;
-}
-
-/*!
- \since 5.6
- \overload
-
- Writes \a string to the stream, and returns a reference to the
- QTextStream.
-*/
-QTextStream &QTextStream::operator<<(const QStringRef &string)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putString(string.data(), string.size());
- return *this;
-}
-
-/*!
- \overload
-
- Writes \a array to the stream. The contents of \a array are
- converted with QString::fromUtf8().
-*/
-QTextStream &QTextStream::operator<<(const QByteArray &array)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- d->putString(QString::fromUtf8(array.constData(), array.length()));
- return *this;
-}
-
-/*!
- \overload
-
- Writes the constant string pointed to by \a string to the stream. \a
- string is assumed to be in ISO-8859-1 encoding. This operator
- is convenient when working with constant string data. Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 8
-
- Warning: QTextStream assumes that \a string points to a string of
- text, terminated by a '\\0' character. If there is no terminating
- '\\0' character, your application may crash.
-*/
-QTextStream &QTextStream::operator<<(const char *string)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- // ### Qt6: consider changing to UTF-8
- d->putString(QLatin1String(string));
- return *this;
-}
-
-/*!
- \overload
-
- Writes \a ptr to the stream as a hexadecimal number with a base.
-*/
-
-QTextStream &QTextStream::operator<<(const void *ptr)
-{
- Q_D(QTextStream);
- CHECK_VALID_STREAM(*this);
- const int oldBase = d->params.integerBase;
- const NumberFlags oldFlags = d->params.numberFlags;
- d->params.integerBase = 16;
- d->params.numberFlags |= ShowBase;
- d->putNumber(reinterpret_cast<quintptr>(ptr), false);
- d->params.integerBase = oldBase;
- d->params.numberFlags = oldFlags;
- return *this;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setIntegerBase(2) on \a stream and returns \a
- stream.
-
- \sa oct(), dec(), hex(), {QTextStream manipulators}
-*/
-QTextStream &bin(QTextStream &stream)
-{
- stream.setIntegerBase(2);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setIntegerBase(8) on \a stream and returns \a
- stream.
-
- \sa bin(), dec(), hex(), {QTextStream manipulators}
-*/
-QTextStream &oct(QTextStream &stream)
-{
- stream.setIntegerBase(8);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setIntegerBase(10) on \a stream and returns \a
- stream.
-
- \sa bin(), oct(), hex(), {QTextStream manipulators}
-*/
-QTextStream &dec(QTextStream &stream)
-{
- stream.setIntegerBase(10);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setIntegerBase(16) on \a stream and returns \a
- stream.
-
- \note The hex modifier can only be used for writing to streams.
- \sa bin(), oct(), dec(), {QTextStream manipulators}
-*/
-QTextStream &hex(QTextStream &stream)
-{
- stream.setIntegerBase(16);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() |
- QTextStream::ShowBase) on \a stream and returns \a stream.
-
- \sa noshowbase(), forcesign(), forcepoint(), {QTextStream manipulators}
-*/
-QTextStream &showbase(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() | QTextStream::ShowBase);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() |
- QTextStream::ForceSign) on \a stream and returns \a stream.
-
- \sa noforcesign(), forcepoint(), showbase(), {QTextStream manipulators}
-*/
-QTextStream &forcesign(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() | QTextStream::ForceSign);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() |
- QTextStream::ForcePoint) on \a stream and returns \a stream.
-
- \sa noforcepoint(), forcesign(), showbase(), {QTextStream manipulators}
-*/
-QTextStream &forcepoint(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() | QTextStream::ForcePoint);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() &
- ~QTextStream::ShowBase) on \a stream and returns \a stream.
-
- \sa showbase(), noforcesign(), noforcepoint(), {QTextStream manipulators}
-*/
-QTextStream &noshowbase(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() &= ~QTextStream::ShowBase);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() &
- ~QTextStream::ForceSign) on \a stream and returns \a stream.
-
- \sa forcesign(), noforcepoint(), noshowbase(), {QTextStream manipulators}
-*/
-QTextStream &noforcesign(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() &= ~QTextStream::ForceSign);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() &
- ~QTextStream::ForcePoint) on \a stream and returns \a stream.
-
- \sa forcepoint(), noforcesign(), noshowbase(), {QTextStream manipulators}
-*/
-QTextStream &noforcepoint(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() &= ~QTextStream::ForcePoint);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() |
- QTextStream::UppercaseBase) on \a stream and returns \a stream.
-
- \sa lowercasebase(), uppercasedigits(), {QTextStream manipulators}
-*/
-QTextStream &uppercasebase(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() | QTextStream::UppercaseBase);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() |
- QTextStream::UppercaseDigits) on \a stream and returns \a stream.
-
- \sa lowercasedigits(), uppercasebase(), {QTextStream manipulators}
-*/
-QTextStream &uppercasedigits(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() | QTextStream::UppercaseDigits);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() &
- ~QTextStream::UppercaseBase) on \a stream and returns \a stream.
-
- \sa uppercasebase(), lowercasedigits(), {QTextStream manipulators}
-*/
-QTextStream &lowercasebase(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() & ~QTextStream::UppercaseBase);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setNumberFlags(QTextStream::numberFlags() &
- ~QTextStream::UppercaseDigits) on \a stream and returns \a stream.
-
- \sa uppercasedigits(), lowercasebase(), {QTextStream manipulators}
-*/
-QTextStream &lowercasedigits(QTextStream &stream)
-{
- stream.setNumberFlags(stream.numberFlags() & ~QTextStream::UppercaseDigits);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setRealNumberNotation(QTextStream::FixedNotation)
- on \a stream and returns \a stream.
-
- \sa scientific(), {QTextStream manipulators}
-*/
-QTextStream &fixed(QTextStream &stream)
-{
- stream.setRealNumberNotation(QTextStream::FixedNotation);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setRealNumberNotation(QTextStream::ScientificNotation)
- on \a stream and returns \a stream.
-
- \sa fixed(), {QTextStream manipulators}
-*/
-QTextStream &scientific(QTextStream &stream)
-{
- stream.setRealNumberNotation(QTextStream::ScientificNotation);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setFieldAlignment(QTextStream::AlignLeft)
- on \a stream and returns \a stream.
-
- \sa {QTextStream::}{right()}, {QTextStream::}{center()}, {QTextStream manipulators}
-*/
-QTextStream &left(QTextStream &stream)
-{
- stream.setFieldAlignment(QTextStream::AlignLeft);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setFieldAlignment(QTextStream::AlignRight)
- on \a stream and returns \a stream.
-
- \sa {QTextStream::}{left()}, {QTextStream::}{center()}, {QTextStream manipulators}
-*/
-QTextStream &right(QTextStream &stream)
-{
- stream.setFieldAlignment(QTextStream::AlignRight);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::setFieldAlignment(QTextStream::AlignCenter)
- on \a stream and returns \a stream.
-
- \sa {QTextStream::}{left()}, {QTextStream::}{right()}, {QTextStream manipulators}
-*/
-QTextStream &center(QTextStream &stream)
-{
- stream.setFieldAlignment(QTextStream::AlignCenter);
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Writes '\\n' to the \a stream and flushes the stream.
-
- Equivalent to
-
- \snippet code/src_corelib_io_qtextstream.cpp 9
-
- Note: On Windows, all '\\n' characters are written as '\\r\\n' if
- QTextStream's device or string is opened using the QIODevice::Text flag.
-
- \sa flush(), reset(), {QTextStream manipulators}
-*/
-QTextStream &endl(QTextStream &stream)
-{
- return stream << QLatin1Char('\n') << flush;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::flush() on \a stream and returns \a stream.
-
- \sa endl(), reset(), {QTextStream manipulators}
-*/
-QTextStream &flush(QTextStream &stream)
-{
- stream.flush();
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls QTextStream::reset() on \a stream and returns \a stream.
-
- \sa flush(), {QTextStream manipulators}
-*/
-QTextStream &reset(QTextStream &stream)
-{
- stream.reset();
- return stream;
-}
-
-/*!
- \relates QTextStream
-
- Calls \l {QTextStream::}{skipWhiteSpace()} on \a stream and returns \a stream.
-
- \sa {QTextStream manipulators}
-*/
-QTextStream &ws(QTextStream &stream)
-{
- stream.skipWhiteSpace();
- return stream;
-}
-
-/*!
- \fn QTextStreamManipulator qSetFieldWidth(int width)
- \relates QTextStream
-
- Equivalent to QTextStream::setFieldWidth(\a width).
-*/
-
-/*!
- \fn QTextStreamManipulator qSetPadChar(QChar ch)
- \relates QTextStream
-
- Equivalent to QTextStream::setPadChar(\a ch).
-*/
-
-/*!
- \fn QTextStreamManipulator qSetRealNumberPrecision(int precision)
- \relates QTextStream
-
- Equivalent to QTextStream::setRealNumberPrecision(\a precision).
-*/
-
-#ifndef QT_NO_TEXTCODEC
-/*!
- \relates QTextStream
-
- Toggles insertion of the Byte Order Mark on \a stream when QTextStream is
- used with a UTF codec.
-
- \sa QTextStream::setGenerateByteOrderMark(), {QTextStream manipulators}
-*/
-QTextStream &bom(QTextStream &stream)
-{
- stream.setGenerateByteOrderMark(true);
- return stream;
-}
-
-/*!
- Sets the codec for this stream to \a codec. The codec is used for
- decoding any data that is read from the assigned device, and for
- encoding any data that is written. By default,
- QTextCodec::codecForLocale() is used, and automatic unicode
- detection is enabled.
-
- If QTextStream operates on a string, this function does nothing.
-
- \warning If you call this function while the text stream is reading
- from an open sequential socket, the internal buffer may still contain
- text decoded using the old codec.
-
- \sa codec(), setAutoDetectUnicode(), setLocale()
-*/
-void QTextStream::setCodec(QTextCodec *codec)
-{
- Q_D(QTextStream);
- qint64 seekPos = -1;
- if (!d->readBuffer.isEmpty()) {
- if (!d->device->isSequential()) {
- seekPos = pos();
- }
- }
- d->codec = codec;
- if (seekPos >=0 && !d->readBuffer.isEmpty())
- seek(seekPos);
-}
-
-/*!
- Sets the codec for this stream to the QTextCodec for the encoding
- specified by \a codecName. Common values for \c codecName include
- "ISO 8859-1", "UTF-8", and "UTF-16". If the encoding isn't
- recognized, nothing happens.
-
- Example:
-
- \snippet code/src_corelib_io_qtextstream.cpp 10
-
- \sa QTextCodec::codecForName(), setLocale()
-*/
-void QTextStream::setCodec(const char *codecName)
-{
- QTextCodec *codec = QTextCodec::codecForName(codecName);
- if (codec)
- setCodec(codec);
-}
-
-/*!
- Returns the codec that is current assigned to the stream.
-
- \sa setCodec(), setAutoDetectUnicode(), locale()
-*/
-QTextCodec *QTextStream::codec() const
-{
- Q_D(const QTextStream);
- return d->codec;
-}
-
-/*!
- If \a enabled is true, QTextStream will attempt to detect Unicode
- encoding by peeking into the stream data to see if it can find the
- UTF-16 or UTF-32 BOM (Byte Order Mark). If this mark is found, QTextStream
- will replace the current codec with the UTF codec.
-
- This function can be used together with setCodec(). It is common
- to set the codec to UTF-8, and then enable UTF-16 detection.
-
- \sa autoDetectUnicode(), setCodec()
-*/
-void QTextStream::setAutoDetectUnicode(bool enabled)
-{
- Q_D(QTextStream);
- d->autoDetectUnicode = enabled;
-}
-
-/*!
- Returns \c true if automatic Unicode detection is enabled, otherwise
- returns \c false. Automatic Unicode detection is enabled by default.
-
- \sa setAutoDetectUnicode(), setCodec()
-*/
-bool QTextStream::autoDetectUnicode() const
-{
- Q_D(const QTextStream);
- return d->autoDetectUnicode;
-}
-
-/*!
- If \a generate is true and a UTF codec is used, QTextStream will insert
- the BOM (Byte Order Mark) before any data has been written to the
- device. If \a generate is false, no BOM will be inserted. This function
- must be called before any data is written. Otherwise, it does nothing.
-
- \sa generateByteOrderMark(), bom()
-*/
-void QTextStream::setGenerateByteOrderMark(bool generate)
-{
- Q_D(QTextStream);
- if (d->writeBuffer.isEmpty()) {
- d->writeConverterState.flags.setFlag(QTextCodec::IgnoreHeader, !generate);
- }
-}
-
-/*!
- Returns \c true if QTextStream is set to generate the UTF BOM (Byte Order
- Mark) when using a UTF codec; otherwise returns \c false. UTF BOM generation is
- set to false by default.
-
- \sa setGenerateByteOrderMark()
-*/
-bool QTextStream::generateByteOrderMark() const
-{
- Q_D(const QTextStream);
- return (d->writeConverterState.flags & QTextCodec::IgnoreHeader) == 0;
-}
-
-#endif
-
-/*!
- \since 4.5
-
- Sets the locale for this stream to \a locale. The specified locale is
- used for conversions between numbers and their string representations.
-
- The default locale is C and it is a special case - the thousands
- group separator is not used for backward compatibility reasons.
-
- \sa locale()
-*/
-void QTextStream::setLocale(const QLocale &locale)
-{
- Q_D(QTextStream);
- d->locale = locale;
-}
-
-/*!
- \since 4.5
-
- Returns the locale for this stream. The default locale is C.
-
- \sa setLocale()
-*/
-QLocale QTextStream::locale() const
-{
- Q_D(const QTextStream);
- return d->locale;
-}
-
-QT_END_NAMESPACE
-
-#ifndef QT_NO_QOBJECT
-#include "moc_qtextstream_p.cpp"
-#endif
diff --git a/src/corelib/io/qtextstream.h b/src/corelib/io/qtextstream.h
deleted file mode 100644
index e72b7942fd..0000000000
--- a/src/corelib/io/qtextstream.h
+++ /dev/null
@@ -1,287 +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 QTEXTSTREAM_H
-#define QTEXTSTREAM_H
-
-#include <QtCore/qiodevice.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qchar.h>
-#include <QtCore/qlocale.h>
-#include <QtCore/qscopedpointer.h>
-
-#include <stdio.h>
-
-#ifdef Status
-#error qtextstream.h must be included before any header file that defines Status
-#endif
-
-QT_BEGIN_NAMESPACE
-
-
-class QTextCodec;
-class QTextDecoder;
-
-class QTextStreamPrivate;
-class Q_CORE_EXPORT QTextStream // text stream class
-{
- Q_DECLARE_PRIVATE(QTextStream)
-
-public:
- enum RealNumberNotation {
- SmartNotation,
- FixedNotation,
- ScientificNotation
- };
- enum FieldAlignment {
- AlignLeft,
- AlignRight,
- AlignCenter,
- AlignAccountingStyle
- };
- enum Status {
- Ok,
- ReadPastEnd,
- ReadCorruptData,
- WriteFailed
- };
- enum NumberFlag {
- ShowBase = 0x1,
- ForcePoint = 0x2,
- ForceSign = 0x4,
- UppercaseBase = 0x8,
- UppercaseDigits = 0x10
- };
- Q_DECLARE_FLAGS(NumberFlags, NumberFlag)
-
- QTextStream();
- explicit QTextStream(QIODevice *device);
- explicit QTextStream(FILE *fileHandle, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
- explicit QTextStream(QString *string, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
- explicit QTextStream(QByteArray *array, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
- explicit QTextStream(const QByteArray &array, QIODevice::OpenMode openMode = QIODevice::ReadOnly);
- virtual ~QTextStream();
-
-#ifndef QT_NO_TEXTCODEC
- void setCodec(QTextCodec *codec);
- void setCodec(const char *codecName);
- QTextCodec *codec() const;
- void setAutoDetectUnicode(bool enabled);
- bool autoDetectUnicode() const;
- void setGenerateByteOrderMark(bool generate);
- bool generateByteOrderMark() const;
-#endif
-
- void setLocale(const QLocale &locale);
- QLocale locale() const;
-
- void setDevice(QIODevice *device);
- QIODevice *device() const;
-
- void setString(QString *string, QIODevice::OpenMode openMode = QIODevice::ReadWrite);
- QString *string() const;
-
- Status status() const;
- void setStatus(Status status);
- void resetStatus();
-
- bool atEnd() const;
- void reset();
- void flush();
- bool seek(qint64 pos);
- qint64 pos() const;
-
- void skipWhiteSpace();
-
- QString readLine(qint64 maxlen = 0);
- bool readLineInto(QString *line, qint64 maxlen = 0);
- QString readAll();
- QString read(qint64 maxlen);
-
- void setFieldAlignment(FieldAlignment alignment);
- FieldAlignment fieldAlignment() const;
-
- void setPadChar(QChar ch);
- QChar padChar() const;
-
- void setFieldWidth(int width);
- int fieldWidth() const;
-
- void setNumberFlags(NumberFlags flags);
- NumberFlags numberFlags() const;
-
- void setIntegerBase(int base);
- int integerBase() const;
-
- void setRealNumberNotation(RealNumberNotation notation);
- RealNumberNotation realNumberNotation() const;
-
- void setRealNumberPrecision(int precision);
- int realNumberPrecision() const;
-
- QTextStream &operator>>(QChar &ch);
- QTextStream &operator>>(char &ch);
- QTextStream &operator>>(signed short &i);
- QTextStream &operator>>(unsigned short &i);
- QTextStream &operator>>(signed int &i);
- QTextStream &operator>>(unsigned int &i);
- QTextStream &operator>>(signed long &i);
- QTextStream &operator>>(unsigned long &i);
- QTextStream &operator>>(qlonglong &i);
- QTextStream &operator>>(qulonglong &i);
- QTextStream &operator>>(float &f);
- QTextStream &operator>>(double &f);
- QTextStream &operator>>(QString &s);
- QTextStream &operator>>(QByteArray &array);
- QTextStream &operator>>(char *c);
-
- QTextStream &operator<<(QChar ch);
- QTextStream &operator<<(char ch);
- QTextStream &operator<<(signed short i);
- QTextStream &operator<<(unsigned short i);
- QTextStream &operator<<(signed int i);
- QTextStream &operator<<(unsigned int i);
- QTextStream &operator<<(signed long i);
- QTextStream &operator<<(unsigned long i);
- QTextStream &operator<<(qlonglong i);
- QTextStream &operator<<(qulonglong i);
- QTextStream &operator<<(float f);
- QTextStream &operator<<(double f);
- QTextStream &operator<<(const QString &s);
- QTextStream &operator<<(QLatin1String s);
- QTextStream &operator<<(const QStringRef &s);
- QTextStream &operator<<(const QByteArray &array);
- QTextStream &operator<<(const char *c);
- QTextStream &operator<<(const void *ptr);
-
-private:
- Q_DISABLE_COPY(QTextStream)
- friend class QDebugStateSaverPrivate;
- friend class QDebug;
-
- QScopedPointer<QTextStreamPrivate> d_ptr;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QTextStream::NumberFlags)
-
-/*****************************************************************************
- QTextStream manipulators
- *****************************************************************************/
-
-typedef QTextStream & (*QTextStreamFunction)(QTextStream &);// manipulator function
-typedef void (QTextStream::*QTSMFI)(int); // manipulator w/int argument
-typedef void (QTextStream::*QTSMFC)(QChar); // manipulator w/QChar argument
-
-
-class Q_CORE_EXPORT QTextStreamManipulator
-{
-public:
- Q_DECL_CONSTEXPR QTextStreamManipulator(QTSMFI m, int a) Q_DECL_NOTHROW : mf(m), mc(Q_NULLPTR), arg(a), ch() {}
- Q_DECL_CONSTEXPR QTextStreamManipulator(QTSMFC m, QChar c) Q_DECL_NOTHROW : mf(Q_NULLPTR), mc(m), arg(-1), ch(c) {}
- void exec(QTextStream &s) { if (mf) { (s.*mf)(arg); } else { (s.*mc)(ch); } }
-
-private:
- QTSMFI mf; // QTextStream member function
- QTSMFC mc; // QTextStream member function
- int arg; // member function argument
- QChar ch;
-};
-
-inline QTextStream &operator>>(QTextStream &s, QTextStreamFunction f)
-{ return (*f)(s); }
-
-inline QTextStream &operator<<(QTextStream &s, QTextStreamFunction f)
-{ return (*f)(s); }
-
-inline QTextStream &operator<<(QTextStream &s, QTextStreamManipulator m)
-{ m.exec(s); return s; }
-
-Q_CORE_EXPORT QTextStream &bin(QTextStream &s);
-Q_CORE_EXPORT QTextStream &oct(QTextStream &s);
-Q_CORE_EXPORT QTextStream &dec(QTextStream &s);
-Q_CORE_EXPORT QTextStream &hex(QTextStream &s);
-
-Q_CORE_EXPORT QTextStream &showbase(QTextStream &s);
-Q_CORE_EXPORT QTextStream &forcesign(QTextStream &s);
-Q_CORE_EXPORT QTextStream &forcepoint(QTextStream &s);
-Q_CORE_EXPORT QTextStream &noshowbase(QTextStream &s);
-Q_CORE_EXPORT QTextStream &noforcesign(QTextStream &s);
-Q_CORE_EXPORT QTextStream &noforcepoint(QTextStream &s);
-
-Q_CORE_EXPORT QTextStream &uppercasebase(QTextStream &s);
-Q_CORE_EXPORT QTextStream &uppercasedigits(QTextStream &s);
-Q_CORE_EXPORT QTextStream &lowercasebase(QTextStream &s);
-Q_CORE_EXPORT QTextStream &lowercasedigits(QTextStream &s);
-
-Q_CORE_EXPORT QTextStream &fixed(QTextStream &s);
-Q_CORE_EXPORT QTextStream &scientific(QTextStream &s);
-
-Q_CORE_EXPORT QTextStream &left(QTextStream &s);
-Q_CORE_EXPORT QTextStream &right(QTextStream &s);
-Q_CORE_EXPORT QTextStream &center(QTextStream &s);
-
-Q_CORE_EXPORT QTextStream &endl(QTextStream &s);
-Q_CORE_EXPORT QTextStream &flush(QTextStream &s);
-Q_CORE_EXPORT QTextStream &reset(QTextStream &s);
-
-Q_CORE_EXPORT QTextStream &bom(QTextStream &s);
-
-Q_CORE_EXPORT QTextStream &ws(QTextStream &s);
-
-inline QTextStreamManipulator qSetFieldWidth(int width)
-{
- QTSMFI func = &QTextStream::setFieldWidth;
- return QTextStreamManipulator(func,width);
-}
-
-inline QTextStreamManipulator qSetPadChar(QChar ch)
-{
- QTSMFC func = &QTextStream::setPadChar;
- return QTextStreamManipulator(func, ch);
-}
-
-inline QTextStreamManipulator qSetRealNumberPrecision(int precision)
-{
- QTSMFI func = &QTextStream::setRealNumberPrecision;
- return QTextStreamManipulator(func, precision);
-}
-
-QT_END_NAMESPACE
-
-#endif // QTEXTSTREAM_H
diff --git a/src/corelib/io/qtextstream_p.h b/src/corelib/io/qtextstream_p.h
deleted file mode 100644
index a642beddc4..0000000000
--- a/src/corelib/io/qtextstream_p.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Copyright (C) 2016 Intel Corporation.
-** 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 QTEXTSTREAM_P_H
-#define QTEXTSTREAM_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 "qtextstream.h"
-#ifndef QT_NO_TEXTCODEC
-#include "qtextcodec.h"
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#ifndef QT_NO_QOBJECT
-class QDeviceClosedNotifier : public QObject
-{
- Q_OBJECT
-public:
- inline QDeviceClosedNotifier()
- { }
-
- inline void setupDevice(QTextStream *stream, QIODevice *device)
- {
- disconnect();
- if (device)
- connect(device, SIGNAL(aboutToClose()), this, SLOT(flushStream()));
- this->stream = stream;
- }
-
-public Q_SLOTS:
- inline void flushStream() { stream->flush(); }
-
-private:
- QTextStream *stream;
-};
-#endif
-
-class QTextStreamPrivate
-{
- Q_DECLARE_PUBLIC(QTextStream)
-public:
- // streaming parameters
- class Params
- {
- public:
- void reset();
-
- int realNumberPrecision;
- int integerBase;
- int fieldWidth;
- QChar padChar;
- QTextStream::FieldAlignment fieldAlignment;
- QTextStream::RealNumberNotation realNumberNotation;
- QTextStream::NumberFlags numberFlags;
- };
-
- QTextStreamPrivate(QTextStream *q_ptr);
- ~QTextStreamPrivate();
- void reset();
-
- // device
- QIODevice *device;
-#ifndef QT_NO_QOBJECT
- QDeviceClosedNotifier deviceClosedNotifier;
-#endif
-
- // string
- QString *string;
- int stringOffset;
- QIODevice::OpenMode stringOpenMode;
-
-#ifndef QT_NO_TEXTCODEC
- // codec
- QTextCodec *codec;
- QTextCodec::ConverterState readConverterState;
- QTextCodec::ConverterState writeConverterState;
- QTextCodec::ConverterState *readConverterSavedState;
-#endif
-
- QString writeBuffer;
- QString readBuffer;
- int readBufferOffset;
- int readConverterSavedStateOffset; //the offset between readBufferStartDevicePos and that start of the buffer
- qint64 readBufferStartDevicePos;
-
- Params params;
-
- // status
- QTextStream::Status status;
- QLocale locale;
- QTextStream *q_ptr;
-
- int lastTokenSize;
- bool deleteDevice;
-#ifndef QT_NO_TEXTCODEC
- bool autoDetectUnicode;
-#endif
-
- // i/o
- enum TokenDelimiter {
- Space,
- NotSpace,
- EndOfLine
- };
-
- QString read(int maxlen);
- bool scan(const QChar **ptr, int *tokenLength,
- int maxlen, TokenDelimiter delimiter);
- inline const QChar *readPtr() const;
- inline void consumeLastToken();
- inline void consume(int nchars);
- void saveConverterState(qint64 newPos);
- void restoreToSavedConverterState();
-
- // Return value type for getNumber()
- enum NumberParsingStatus {
- npsOk,
- npsMissingDigit,
- npsInvalidPrefix
- };
-
- inline bool getChar(QChar *ch);
- inline void ungetChar(QChar ch);
- NumberParsingStatus getNumber(qulonglong *l);
- bool getReal(double *f);
-
- inline void write(const QString &data) { write(data.begin(), data.length()); }
- inline void write(QChar ch);
- void write(const QChar *data, int len);
- void write(QLatin1String data);
- void writePadding(int len);
- inline void putString(const QString &ch, bool number = false) { putString(ch.constData(), ch.length(), number); }
- void putString(const QChar *data, int len, bool number = false);
- void putString(QLatin1String data, bool number = false);
- inline void putChar(QChar ch);
- void putNumber(qulonglong number, bool negative);
-
- struct PaddingResult {
- int left, right;
- };
- PaddingResult padding(int len) const;
-
- // buffers
- bool fillReadBuffer(qint64 maxBytes = -1);
- void resetReadBuffer();
- void flushWriteBuffer();
-};
-
-QT_END_NAMESPACE
-
-#endif // QTEXTSTREAM_P_H
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/qurl.h b/src/corelib/io/qurl.h
index 0bb8707ff9..5062ef7905 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -184,7 +184,7 @@ public:
#endif
#ifdef Q_COMPILER_RVALUE_REFS
QUrl(QUrl &&other) Q_DECL_NOTHROW : d(other.d)
- { other.d = Q_NULLPTR; }
+ { other.d = nullptr; }
inline QUrl &operator=(QUrl &&other) Q_DECL_NOTHROW
{ qSwap(d, other.d); return *this; }
#endif
diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp
index 226bc8ba28..2f8bd91f6e 100644
--- a/src/corelib/io/qurlidna.cpp
+++ b/src/corelib/io/qurlidna.cpp
@@ -60,11 +60,6 @@ struct NameprepCaseFoldingEntry {
ushort mapping[4];
};
-#if defined(Q_CC_MSVC) && _MSC_VER < 1600
-inline bool operator<(const NameprepCaseFoldingEntry &one, const NameprepCaseFoldingEntry &other)
-{ return one.uc < other.uc; }
-#endif
-
inline bool operator<(uint one, const NameprepCaseFoldingEntry &other)
{ return one < other.uc; }
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index b93fed5ba8..3055fb392e 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) {
@@ -184,7 +175,7 @@ void QWindowsPipeReader::notified(DWORD errorCode, DWORD numberOfBytesRead)
case ERROR_OPERATION_ABORTED:
if (stopped)
break;
- // fall through
+ Q_FALLTHROUGH();
default:
emit winError(errorCode, QLatin1String("QWindowsPipeReader::notified"));
pipeBroken = true;
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index 846891102f..92e8b6db52 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();
@@ -147,7 +145,7 @@ void QWindowsPipeWriter::notified(DWORD errorCode, DWORD numberOfBytesWritten)
case ERROR_OPERATION_ABORTED:
if (stopped)
break;
- // fall through
+ Q_FALLTHROUGH();
default:
qErrnoWarning(errorCode, "QWindowsPipeWriter: asynchronous write failed.");
break;
@@ -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