summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri4
-rw-r--r--src/corelib/io/qdatastream.cpp33
-rw-r--r--src/corelib/io/qdatastream.h293
-rw-r--r--src/corelib/io/qdebug.h12
-rw-r--r--src/corelib/io/qdir.cpp67
-rw-r--r--src/corelib/io/qdir.h2
-rw-r--r--src/corelib/io/qfileinfo.cpp18
-rw-r--r--src/corelib/io/qfileselector.cpp13
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp9
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp53
-rw-r--r--src/corelib/io/qfilesystementry.cpp2
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp7
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h2
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp53
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h10
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp286
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h15
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp4
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp27
-rw-r--r--src/corelib/io/qloggingregistry.cpp7
-rw-r--r--src/corelib/io/qprocess.cpp6
-rw-r--r--src/corelib/io/qprocess.h15
-rw-r--r--src/corelib/io/qprocess_darwin.mm58
-rw-r--r--src/corelib/io/qprocess_p.h6
-rw-r--r--src/corelib/io/qprocess_unix.cpp58
-rw-r--r--src/corelib/io/qprocess_win.cpp49
-rw-r--r--src/corelib/io/qsavefile.cpp20
-rw-r--r--src/corelib/io/qsavefile.h7
-rw-r--r--src/corelib/io/qsettings.cpp250
-rw-r--r--src/corelib/io/qsettings_mac.cpp13
-rw-r--r--src/corelib/io/qsettings_p.h18
-rw-r--r--src/corelib/io/qsettings_win.cpp31
-rw-r--r--src/corelib/io/qstorageinfo.cpp22
-rw-r--r--src/corelib/io/qstorageinfo.h3
-rw-r--r--src/corelib/io/qstorageinfo_p.h1
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp53
-rw-r--r--src/corelib/io/qtemporarydir.cpp27
-rw-r--r--src/corelib/io/qtemporarydir.h1
-rw-r--r--src/corelib/io/qtextstream.cpp15
-rw-r--r--src/corelib/io/qurl.cpp3
-rw-r--r--src/corelib/io/qurl.h4
41 files changed, 1056 insertions, 521 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index b5bfec8857..b0cac59f42 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -93,7 +93,7 @@ SOURCES += \
io/qloggingcategory.cpp \
io/qloggingregistry.cpp
-qtConfig(process) {
+qtConfig(processenvironment) {
SOURCES += \
io/qprocess.cpp
HEADERS += \
@@ -154,6 +154,8 @@ win32 {
}
mac {
SOURCES += io/qstorageinfo_mac.cpp
+ qtConfig(processenvironment): \
+ OBJECTIVE_SOURCES += io/qprocess_darwin.mm
OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
osx {
OBJECTIVE_SOURCES += io/qfilesystemwatcher_fsevents.mm
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
index b4eb98e062..2369fe4726 100644
--- a/src/corelib/io/qdatastream.cpp
+++ b/src/corelib/io/qdatastream.cpp
@@ -42,6 +42,7 @@
#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
#include "qbuffer.h"
+#include "qfloat16.h"
#include "qstring.h"
#include <stdio.h>
#include <ctype.h>
@@ -448,6 +449,9 @@ QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
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.
@@ -557,6 +561,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\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()
@@ -972,6 +977,20 @@ QDataStream &QDataStream::operator>>(double &f)
/*!
\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.
@@ -1259,6 +1278,19 @@ QDataStream &QDataStream::operator<<(double f)
/*!
+ \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
@@ -1281,7 +1313,6 @@ QDataStream &QDataStream::operator<<(const char *s)
return *this;
}
-
/*!
Writes the length specifier \a len and the buffer \a s to the
stream and returns a reference to the stream.
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index ac58677b77..db1bbfbd63 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -50,7 +50,7 @@
QT_BEGIN_NAMESPACE
-
+class qfloat16;
class QByteArray;
class QIODevice;
@@ -95,10 +95,11 @@ public:
Qt_5_6 = 17,
Qt_5_7 = Qt_5_6,
Qt_5_8 = Qt_5_7,
-#if QT_VERSION >= 0x050900
+ 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_8
+ Qt_DefaultCompiledVersion = Qt_5_9
};
enum ByteOrder {
@@ -153,6 +154,7 @@ public:
QDataStream &operator>>(quint64 &i);
QDataStream &operator>>(bool &i);
+ QDataStream &operator>>(qfloat16 &f);
QDataStream &operator>>(float &f);
QDataStream &operator>>(double &f);
QDataStream &operator>>(char *&str);
@@ -166,6 +168,7 @@ public:
QDataStream &operator<<(qint64 i);
QDataStream &operator<<(quint64 i);
QDataStream &operator<<(bool i);
+ QDataStream &operator<<(qfloat16 f);
QDataStream &operator<<(float f);
QDataStream &operator<<(double f);
QDataStream &operator<<(const char *str);
@@ -222,6 +225,98 @@ private:
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
/*****************************************************************************
@@ -264,210 +359,84 @@ inline QDataStream &QDataStream::operator<<(quint32 i)
inline QDataStream &QDataStream::operator<<(quint64 i)
{ return *this << qint64(i); }
-template <typename T>
-QDataStream& operator>>(QDataStream& s, QList<T>& l)
-{
- QtPrivate::StreamStateSaver stateSaver(&s);
+template <typename Enum>
+inline QDataStream &operator<<(QDataStream &s, QFlags<Enum> e)
+{ return s << e.i; }
- l.clear();
- quint32 c;
- s >> c;
- l.reserve(c);
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
+template <typename Enum>
+inline QDataStream &operator>>(QDataStream &s, QFlags<Enum> &e)
+{ return s >> e.i; }
- return s;
+template <typename T>
+inline QDataStream &operator>>(QDataStream &s, QList<T> &l)
+{
+ return QtPrivate::readArrayBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QList<T> &l)
{
- s << quint32(l.size());
- for (int i = 0; i < l.size(); ++i)
- s << l.at(i);
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template <typename T>
-QDataStream& operator>>(QDataStream& s, QLinkedList<T>& l)
+inline QDataStream &operator>>(QDataStream &s, QLinkedList<T> &l)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- l.clear();
- quint32 c;
- s >> c;
- for(quint32 i = 0; i < c; ++i)
- {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- l.clear();
- break;
- }
- l.append(t);
- }
-
- return s;
+ return QtPrivate::readListBasedContainer(s, l);
}
template <typename T>
-QDataStream& operator<<(QDataStream& s, const QLinkedList<T>& l)
+inline QDataStream &operator<<(QDataStream &s, const QLinkedList<T> &l)
{
- s << quint32(l.size());
- typename QLinkedList<T>::ConstIterator it = l.constBegin();
- for(; it != l.constEnd(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, l);
}
template<typename T>
-QDataStream& operator>>(QDataStream& s, QVector<T>& v)
+inline QDataStream &operator>>(QDataStream &s, QVector<T> &v)
{
- QtPrivate::StreamStateSaver stateSaver(&s);
-
- v.clear();
- quint32 c;
- s >> c;
- v.resize(c);
- for(quint32 i = 0; i < c; ++i) {
- T t;
- s >> t;
- if (s.status() != QDataStream::Ok) {
- v.clear();
- break;
- }
- v[i] = t;
- }
-
- return s;
+ return QtPrivate::readArrayBasedContainer(s, v);
}
template<typename T>
-QDataStream& operator<<(QDataStream& s, const QVector<T>& v)
+inline QDataStream &operator<<(QDataStream &s, const QVector<T> &v)
{
- s << quint32(v.size());
- for (typename QVector<T>::const_iterator it = v.begin(); it != v.end(); ++it)
- s << *it;
- return s;
+ return QtPrivate::writeSequentialContainer(s, v);
}
template <typename T>
-QDataStream &operator>>(QDataStream &in, QSet<T> &set)
+inline QDataStream &operator>>(QDataStream &s, QSet<T> &set)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- set.clear();
- quint32 c;
- in >> c;
- for (quint32 i = 0; i < c; ++i) {
- T t;
- in >> t;
- if (in.status() != QDataStream::Ok) {
- set.clear();
- break;
- }
- set << t;
- }
-
- return in;
+ return QtPrivate::readListBasedContainer(s, set);
}
template <typename T>
-QDataStream& operator<<(QDataStream &out, const QSet<T> &set)
+inline QDataStream &operator<<(QDataStream &s, const QSet<T> &set)
{
- out << quint32(set.size());
- typename QSet<T>::const_iterator i = set.constBegin();
- while (i != set.constEnd()) {
- out << *i;
- ++i;
- }
- return out;
+ return QtPrivate::writeSequentialContainer(s, set);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QHash<Key, T> &hash)
+inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- hash.clear();
- quint32 n;
- in >> n;
-
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- Key k;
- T t;
- in >> k >> t;
- hash.insertMulti(k, t);
- }
-
- if (in.status() != QDataStream::Ok)
- hash.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, hash);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QHash<Key, T>& hash)
+inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
{
- out << quint32(hash.size());
- typename QHash<Key, T>::ConstIterator it = hash.end();
- typename QHash<Key, T>::ConstIterator begin = hash.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, hash);
}
-#ifdef Q_QDOC
+
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<Key, T> &map)
-#else
-template <class aKey, class aT>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator>>(QDataStream &in, QMap<aKey, aT> &map)
-#endif
+inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
{
- QtPrivate::StreamStateSaver stateSaver(&in);
-
- map.clear();
- quint32 n;
- in >> n;
-
- map.detach();
- for (quint32 i = 0; i < n; ++i) {
- if (in.status() != QDataStream::Ok)
- break;
-
- aKey key;
- aT value;
- in >> key >> value;
- map.insertMulti(key, value);
- }
- if (in.status() != QDataStream::Ok)
- map.clear();
- return in;
+ return QtPrivate::readAssociativeContainer(s, map);
}
template <class Key, class T>
-Q_OUTOFLINE_TEMPLATE QDataStream &operator<<(QDataStream &out, const QMap<Key, T> &map)
+inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
{
- out << quint32(map.size());
- typename QMap<Key, T>::ConstIterator it = map.end();
- typename QMap<Key, T>::ConstIterator begin = map.begin();
- while (it != begin) {
- --it;
- out << it.key() << it.value();
- }
- return out;
+ return QtPrivate::writeAssociativeContainer(s, map);
}
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index abc2abeaec..61059dd694 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -365,7 +365,7 @@ Q_CORE_EXPORT QDebug qt_QMetaEnum_debugOperator(QDebug&, int value, const QMetaO
Q_CORE_EXPORT QDebug qt_QMetaEnum_flagDebugOperator(QDebug &dbg, quint64 value, const QMetaObject *meta, const char *name);
template<typename T>
-typename QtPrivate::QEnableIf<QtPrivate::IsQEnumHelper<T>::Value, QDebug>::Type
+typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, QDebug>::type
operator<<(QDebug dbg, T value)
{
const QMetaObject *obj = qt_getEnumMetaObject(value);
@@ -374,9 +374,9 @@ operator<<(QDebug dbg, T value)
}
template <class T>
-inline typename QtPrivate::QEnableIf<
+inline typename std::enable_if<
QtPrivate::IsQEnumHelper<T>::Value || QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
- QDebug>::Type
+ QDebug>::type
qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
{
const QMetaObject *obj = qt_getEnumMetaObject(T());
@@ -385,9 +385,9 @@ qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
}
template <class T>
-inline typename QtPrivate::QEnableIf<
+inline typename std::enable_if<
!QtPrivate::IsQEnumHelper<T>::Value && !QtPrivate::IsQEnumHelper<QFlags<T> >::Value,
- QDebug>::Type
+ QDebug>::type
qt_QMetaEnum_flagDebugOperator_helper(QDebug debug, const QFlags<T> &flags)
#else // !QT_NO_QOBJECT && !Q_QDOC
template <class T>
@@ -402,7 +402,7 @@ template<typename T>
inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
{
// We have to use an indirection otherwise specialisation of some other overload of the
- // operator<< the compiler would try to instantiate QFlags<T> for the QEnableIf
+ // operator<< the compiler would try to instantiate QFlags<T> for the std::enable_if
return qt_QMetaEnum_flagDebugOperator_helper(debug, flags);
}
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 437f774547..6d144cb65d 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -1843,6 +1843,26 @@ bool QDir::exists(const QString &name) const
}
/*!
+ Returns whether the directory is empty.
+
+ Equivalent to \c{count() == 0} with filters
+ \c{QDir::AllEntries | QDir::NoDotAndDotDot}, but faster as it just checks
+ whether the directory contains at least one entry.
+
+ \note Unless you set the \a filters flags to include \c{QDir::NoDotAndDotDot}
+ (as the default value does), no directory is empty.
+
+ \sa count(), entryList(), setFilter()
+ \since 5.9
+*/
+bool QDir::isEmpty(Filters filters) const
+{
+ const auto d = d_ptr.constData();
+ QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters);
+ return !it.hasNext();
+}
+
+/*!
Returns a list of the root directories on this system.
On Windows this returns a list of QFileInfo objects containing "C:/",
@@ -2085,11 +2105,11 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
return name;
int i = len - 1;
- QVarLengthArray<QChar> outVector(len);
+ QVarLengthArray<ushort> outVector(len);
int used = len;
- QChar *out = outVector.data();
- const QChar *p = name.unicode();
- const QChar *prefix = p;
+ ushort *out = outVector.data();
+ const ushort *p = name.utf16();
+ const ushort *prefix = p;
int up = 0;
const int prefixLength = rootLength(name, allowUncPaths);
@@ -2097,39 +2117,39 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
i -= prefixLength;
// replicate trailing slash (i > 0 checks for emptiness of input string p)
- if (i > 0 && p[i].unicode() == '/') {
- out[--used].unicode() = '/';
+ if (i > 0 && p[i] == '/') {
+ out[--used] = '/';
--i;
}
while (i >= 0) {
// remove trailing slashes
- if (p[i].unicode() == '/') {
+ if (p[i] == '/') {
--i;
continue;
}
// remove current directory
- if (p[i].unicode() == '.' && (i == 0 || p[i-1].unicode() == '/')) {
+ if (p[i] == '.' && (i == 0 || p[i-1] == '/')) {
--i;
continue;
}
// detect up dir
- if (i >= 1 && p[i].unicode() == '.' && p[i-1].unicode() == '.'
- && (i == 1 || (i >= 2 && p[i-2].unicode() == '/'))) {
+ if (i >= 1 && p[i] == '.' && p[i-1] == '.'
+ && (i == 1 || (i >= 2 && p[i-2] == '/'))) {
++up;
i -= 2;
continue;
}
// prepend a slash before copying when not empty
- if (!up && used != len && out[used].unicode() != '/')
- out[--used] = QLatin1Char('/');
+ if (!up && used != len && out[used] != '/')
+ out[--used] = '/';
// skip or copy
while (i >= 0) {
- if (p[i].unicode() == '/') { // do not copy slashes
+ if (p[i] == '/') { // do not copy slashes
--i;
break;
}
@@ -2151,17 +2171,17 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
// add remaining '..'
while (up) {
- if (used != len && out[used].unicode() != '/') // is not empty and there isn't already a '/'
- out[--used] = QLatin1Char('/');
- out[--used] = QLatin1Char('.');
- out[--used] = QLatin1Char('.');
+ if (used != len && out[used] != '/') // is not empty and there isn't already a '/'
+ out[--used] = '/';
+ out[--used] = '.';
+ out[--used] = '.';
--up;
}
bool isEmpty = used == len;
if (prefixLength) {
- if (!isEmpty && out[used].unicode() == '/') {
+ if (!isEmpty && out[used] == '/') {
// Eventhough there is a prefix the out string is a slash. This happens, if the input
// string only consists of a prefix followed by one or more slashes. Just skip the slash.
++used;
@@ -2172,18 +2192,19 @@ Q_AUTOTEST_EXPORT QString qt_normalizePathSegments(const QString &name, bool all
if (isEmpty) {
// After resolving the input path, the resulting string is empty (e.g. "foo/.."). Return
// a dot in that case.
- out[--used] = QLatin1Char('.');
- } else if (out[used].unicode() == '/') {
+ out[--used] = '.';
+ } else if (out[used] == '/') {
// After parsing the input string, out only contains a slash. That happens whenever all
// parts are resolved and there is a trailing slash ("./" or "foo/../" for example).
// Prepend a dot to have the correct return value.
- out[--used] = QLatin1Char('.');
+ out[--used] = '.';
}
}
// If path was not modified return the original value
- QString ret = (used == 0 ? name : QString(out + used, len - used));
- return ret;
+ if (used == 0)
+ return name;
+ return QString::fromUtf16(out + used, len - used);
}
static QString qt_cleanPath(const QString &path, bool *ok)
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index ef7ec2c701..950a26f327 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -144,6 +144,8 @@ public:
void setSorting(SortFlags sort);
uint count() const;
+ bool isEmpty(Filters filters = Filters(AllEntries | NoDotAndDotDot)) const;
+
QString operator[](int) const;
static QStringList nameFiltersFromString(const QString &nameFilter);
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 5acee25d02..12fd7d3048 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -1295,7 +1295,7 @@ qint64 QFileInfo::size() const
}
/*!
- Returns the date and time when the file was created.
+ Returns the date and local time when the file was created.
On most Unix systems, this function returns the time of the last
status change. A status change occurs when the file is created,
@@ -1316,13 +1316,13 @@ QDateTime QFileInfo::created() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::CreationTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::CreationTime))
return QDateTime();
- return d->metaData.creationTime();
+ return d->metaData.creationTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::CreationTime);
+ return d->getFileTime(QAbstractFileEngine::CreationTime).toLocalTime();
}
/*!
- Returns the date and time when the file was last modified.
+ Returns the date and local time when the file was last modified.
\sa created(), lastRead()
*/
@@ -1335,13 +1335,13 @@ QDateTime QFileInfo::lastModified() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::ModificationTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::ModificationTime))
return QDateTime();
- return d->metaData.modificationTime();
+ return d->metaData.modificationTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::ModificationTime);
+ return d->getFileTime(QAbstractFileEngine::ModificationTime).toLocalTime();
}
/*!
- Returns the date and time when the file was last read (accessed).
+ Returns the date and local time when the file was last read (accessed).
On platforms where this information is not available, returns the
same as lastModified().
@@ -1357,9 +1357,9 @@ QDateTime QFileInfo::lastRead() const
if (!d->cache_enabled || !d->metaData.hasFlags(QFileSystemMetaData::AccessTime))
if (!QFileSystemEngine::fillMetaData(d->fileEntry, d->metaData, QFileSystemMetaData::AccessTime))
return QDateTime();
- return d->metaData.accessTime();
+ return d->metaData.accessTime().toLocalTime();
}
- return d->getFileTime(QAbstractFileEngine::AccessTime);
+ return d->getFileTime(QAbstractFileEngine::AccessTime).toLocalTime();
}
/*!
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index 920281cef7..cb4f5c4b07 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -133,9 +133,9 @@ QFileSelectorPrivate::QFileSelectorPrivate()
With those files available, you would select a different file on the android platform,
but only if the locale was en_GB.
- QFileSelector will not attempt to select if the base file does not exist. For error handling in
- the case no valid selectors are present, it is recommended to have a default or error-handling
- file in the base file location even if you expect selectors to be present for all deployments.
+ For error handling in the case no valid selectors are present, it is recommended to have a default or
+ error-handling file in the base file location even if you expect selectors to be present for all
+ deployments.
In a future version, some may be marked as deploy-time static and be moved during the
deployment step as an optimization. As selectors come with a performance cost, it is
@@ -298,9 +298,6 @@ QString QFileSelectorPrivate::select(const QString &filePath) const
{
Q_Q(const QFileSelector);
QFileInfo fi(filePath);
- // If file doesn't exist, don't select
- if (!fi.exists())
- return filePath;
QString ret = selectionHelper(fi.path().isEmpty() ? QString() : fi.path() + QLatin1Char('/'),
fi.fileName(), q->allSelectors());
@@ -368,14 +365,10 @@ QStringList QFileSelectorPrivate::platformSelectors()
// similar, but not identical to QSysInfo::osType
QStringList ret;
#if defined(Q_OS_WIN)
- // can't fall back to QSysInfo because we need both "winphone" and "winrt" for the Windows Phone case
ret << QStringLiteral("windows");
ret << QSysInfo::kernelType(); // "winnt"
# if defined(Q_OS_WINRT)
ret << QStringLiteral("winrt");
-# if defined(Q_OS_WINPHONE)
- ret << QStringLiteral("winphone");
-# endif
# endif
#elif defined(Q_OS_UNIX)
ret << QStringLiteral("unix");
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 96829b3b03..3cb412e47c 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -122,13 +122,10 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
return true;
-#ifdef Q_OS_OSX
+#ifdef Q_OS_MACOS
// Find if an application other than Finder claims to know how to handle the package
- QCFType<CFURLRef> application;
- LSGetApplicationForURL(url,
- kLSRolesEditor|kLSRolesViewer,
- NULL,
- &application);
+ QCFType<CFURLRef> application = LSCopyDefaultApplicationURLForURL(url,
+ kLSRolesEditor | kLSRolesViewer, nullptr);
if (application) {
QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, application);
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 0d4ef94622..b1e218de9c 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qfilesystemengine_p.h"
-
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qsysinfo.h"
#include "private/qabstractfileengine_p.h"
@@ -81,11 +81,6 @@ using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::ApplicationModel;
-
-#if _MSC_VER < 1900
-#define Q_OS_WINRT_WIN81
-#endif
-
#endif // Q_OS_WINRT
#ifndef SPI_GETPLATFORMTYPE
@@ -157,7 +152,6 @@ QT_BEGIN_NAMESPACE
Q_CORE_EXPORT int qt_ntfs_permission_lookup = 0;
#if defined(Q_OS_WINRT)
-static QString qfsPrivateCurrentDir = QLatin1String("");
// 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.
@@ -504,7 +498,6 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
{
// can be //server or //server/share
QString absPath;
-#if !defined(Q_OS_WINRT_WIN81)
QVarLengthArray<wchar_t, MAX_PATH> buf(qMax(MAX_PATH, path.size() + 1));
wchar_t *fileName = 0;
DWORD retLen = GetFullPathName((wchar_t*)path.utf16(), buf.size(), buf.data(), &fileName);
@@ -524,12 +517,7 @@ QString QFileSystemEngine::nativeAbsoluteFilePath(const QString &path)
if (absPath.size() < rootPath.size() && rootPath.startsWith(absPath))
absPath = rootPath;
# endif // Q_OS_WINRT
-#else // !Q_OS_WINRT_WIN81
- if (QDir::isRelativePath(path))
- absPath = QDir::toNativeSeparators(QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + path));
- else
- absPath = QDir::toNativeSeparators(QDir::cleanPath(path));
-#endif // Q_OS_WINRT_WIN81
+
// This is really ugly, but GetFullPathName strips off whitespace at the end.
// If you for instance write ". " in the lineedit of QFileDialog,
// (which is an invalid filename) this function will strip the space off and viola,
@@ -551,14 +539,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
else
ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(entry.filePath()));
} else {
-#ifndef Q_OS_WINRT_WIN81
ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + entry.filePath());
-#else
- // Some WinRT APIs do not support absolute paths (due to sandboxing).
- // Thus the port uses the executable's directory as its root directory
- // and treats paths relative to that as absolute paths.
- ret = QDir::cleanPath(QDir::current().relativeFilePath(entry.filePath()));
-#endif
}
#ifndef Q_OS_WINRT
@@ -638,7 +619,7 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
FILE_SHARE_READ, OPEN_EXISTING, NULL);
#endif // Q_OS_WINRT
if (handle) {
- result = QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS8 ?
+ result = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows8 ?
fileIdWin8(handle) : fileId(handle);
CloseHandle(handle);
}
@@ -1219,9 +1200,6 @@ QString QFileSystemEngine::tempPath()
ret = QDir::fromNativeSeparators(ret);
}
#else // !Q_OS_WINRT
- // According to http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.applicationdata.temporaryfolder.aspx
- // the API is not available on winphone which should cause one of the functions
- // below to fail
ComPtr<IApplicationDataStatics> applicationDataStatics;
if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
return ret;
@@ -1253,20 +1231,14 @@ bool QFileSystemEngine::setCurrentPath(const QFileSystemEntry &entry)
if(!(meta.exists() && meta.isDirectory()))
return false;
-#if !defined(Q_OS_WINRT_WIN81)
//TODO: this should really be using nativeFilePath(), but that returns a path in long format \\?\c:\foo
//which causes many problems later on when it's returned through currentPath()
return ::SetCurrentDirectory(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(entry.filePath()).utf16())) != 0;
-#else
- qfsPrivateCurrentDir = entry.filePath();
- return true;
-#endif
}
QFileSystemEntry QFileSystemEngine::currentPath()
{
QString ret;
-#if !defined(Q_OS_WINRT_WIN81)
DWORD size = 0;
wchar_t currentName[PATH_MAX];
size = ::GetCurrentDirectory(PATH_MAX, currentName);
@@ -1282,13 +1254,6 @@ QFileSystemEntry QFileSystemEngine::currentPath()
}
if (ret.length() >= 2 && ret[1] == QLatin1Char(':'))
ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters.
-#else // !Q_OS_WINRT_WIN81
- //TODO - a race condition exists when using currentPath / setCurrentPath from multiple threads
- if (qfsPrivateCurrentDir.isEmpty())
- qfsPrivateCurrentDir = QDir::rootPath();
-
- ret = qfsPrivateCurrentDir;
-#endif // Q_OS_WINRT_WIN81
return QFileSystemEntry(ret, QFileSystemEntry::FromNativePath());
}
@@ -1369,15 +1334,11 @@ bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Per
static inline QDateTime fileTimeToQDateTime(const FILETIME *time)
{
- QDateTime ret;
-
- SYSTEMTIME sTime, lTime;
+ SYSTEMTIME sTime;
FileTimeToSystemTime(time, &sTime);
- SystemTimeToTzSpecificLocalTime(0, &sTime, &lTime);
- ret.setDate(QDate(lTime.wYear, lTime.wMonth, lTime.wDay));
- ret.setTime(QTime(lTime.wHour, lTime.wMinute, lTime.wSecond, lTime.wMilliseconds));
-
- return ret;
+ return QDateTime(QDate(sTime.wYear, sTime.wMonth, sTime.wDay),
+ QTime(sTime.wHour, sTime.wMinute, sTime.wSecond, sTime.wMilliseconds),
+ Qt::UTC);
}
QDateTime QFileSystemMetaData::creationTime() const
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
index 2e92f8fbba..de4c852068 100644
--- a/src/corelib/io/qfilesystementry.cpp
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -175,10 +175,8 @@ void QFileSystemEntry::resolveNativeFilePath() const
// WinRT/MSVC2015 allows a maximum of 256 characters for a filepath
// unless //?/ is prepended which extends the rule to have a maximum
// of 256 characters in the filename plus the preprending path
-#if _MSC_VER >= 1900
m_nativeFilePath.prepend("\\\\?\\");
#endif
-#endif
}
}
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
index 2ce7bd7a4b..2905a8e54e 100644
--- a/src/corelib/io/qfilesystemiterator_win.cpp
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -39,6 +39,7 @@
#include "qfilesystemiterator_p.h"
#include "qfilesystemengine_p.h"
+#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qvector.h"
@@ -68,10 +69,6 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi
nativePath.append(QLatin1Char('\\'));
nativePath.append(QLatin1Char('*'));
// In MSVC2015+ case we prepend //?/ for longer file-name support
-#if defined(Q_OS_WINRT) && _MSC_VER < 1900
- if (nativePath.startsWith(QLatin1Char('\\')))
- nativePath.remove(0, 1);
-#endif
if (!dirPath.endsWith(QLatin1Char('/')))
dirPath.append(QLatin1Char('/'));
if ((filters & (QDir::Dirs|QDir::Drives)) && (!(filters & (QDir::Files))))
@@ -93,7 +90,7 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
haveData = true;
int infoLevel = 0 ; // FindExInfoStandard;
DWORD dwAdditionalFlags = 0;
- if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows7) {
dwAdditionalFlags = 2; // FIND_FIRST_EX_LARGE_FETCH
infoLevel = 1 ; // FindExInfoBasic;
}
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index 091552f86e..b09223d656 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
class QFileSystemEngine;
-class QFileSystemMetaData
+class Q_AUTOTEST_EXPORT QFileSystemMetaData
{
public:
QFileSystemMetaData()
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index a1d90c76f4..612b3fa57c 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -64,6 +64,9 @@
# include "qfilesystemwatcher_fsevents_p.h"
#endif
+#include <algorithm>
+#include <iterator>
+
QT_BEGIN_NAMESPACE
QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject *parent)
@@ -102,6 +105,17 @@ void QFileSystemWatcherPrivate::init()
SIGNAL(directoryChanged(QString,bool)),
q,
SLOT(_q_directoryChanged(QString,bool)));
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemoval,
+ q, [this] (const QString &p) { _q_winDriveLockForRemoval(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed,
+ q, [this] (const QString &p) { _q_winDriveLockForRemovalFailed(p); });
+ QObject::connect(static_cast<QWindowsFileSystemWatcherEngine *>(native),
+ &QWindowsFileSystemWatcherEngine::driveRemoved,
+ q, [this] (const QString &p) { _q_winDriveRemoved(p); });
+#endif // !Q_OS_WINRT
}
}
@@ -146,7 +160,46 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re
emit q->directoryChanged(path, QFileSystemWatcher::QPrivateSignal());
}
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive for removal, release
+ // its paths under watch, temporarily storing them should the lock fail.
+ Q_Q(QFileSystemWatcher);
+ QStringList pathsToBeRemoved;
+ auto pred = [&path] (const QString &f) { return !f.startsWith(path, Qt::CaseInsensitive); };
+ std::remove_copy_if(files.cbegin(), files.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ std::remove_copy_if(directories.cbegin(), directories.cend(),
+ std::back_inserter(pathsToBeRemoved), pred);
+ if (!pathsToBeRemoved.isEmpty()) {
+ q->removePaths(pathsToBeRemoved);
+ temporarilyRemovedPaths.insert(path.at(0), pathsToBeRemoved);
+ }
+}
+
+void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &path)
+{
+ // Windows: Request to lock a (removable/USB) drive failed (blocked by other
+ // application), restore the watched paths.
+ Q_Q(QFileSystemWatcher);
+ if (!path.isEmpty()) {
+ const auto it = temporarilyRemovedPaths.find(path.at(0));
+ if (it != temporarilyRemovedPaths.end()) {
+ q->addPaths(it.value());
+ temporarilyRemovedPaths.erase(it);
+ }
+ }
+}
+void QFileSystemWatcherPrivate::_q_winDriveRemoved(const QString &path)
+{
+ // Windows: Drive finally removed, clear out paths stored in lock request.
+ if (!path.isEmpty())
+ temporarilyRemovedPaths.remove(path.at(0));
+}
+#endif // Q_OS_WIN && !Q_OS_WINRT
/*!
\class QFileSystemWatcher
diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h
index 6c64411f92..4220c1db28 100644
--- a/src/corelib/io/qfilesystemwatcher_p.h
+++ b/src/corelib/io/qfilesystemwatcher_p.h
@@ -58,6 +58,7 @@
#include <private/qobject_p.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qhash.h>
QT_BEGIN_NAMESPACE
@@ -106,6 +107,15 @@ public:
// private slots
void _q_fileChanged(const QString &path, bool removed);
void _q_directoryChanged(const QString &path, bool removed);
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ void _q_winDriveLockForRemoval(const QString &);
+ void _q_winDriveLockForRemovalFailed(const QString &);
+ void _q_winDriveRemoved(const QString &);
+
+private:
+ QHash<QChar, QStringList> temporarilyRemovedPaths;
+#endif // Q_OS_WIN && !Q_OS_WINRT
};
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index be56d8dd1d..c385a82fc5 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -52,6 +52,16 @@
#include <qt_windows.h>
+#ifndef Q_OS_WINRT
+# include <qabstractnativeeventfilter.h>
+# include <qcoreapplication.h>
+# include <qdir.h>
+# include <private/qeventdispatcher_win_p.h>
+# include <dbt.h>
+# include <algorithm>
+# include <vector>
+#endif // !Q_OS_WINRT
+
QT_BEGIN_NAMESPACE
// #define WINQFSW_DEBUG
@@ -61,11 +71,275 @@ QT_BEGIN_NAMESPACE
# define DEBUG if (false) qDebug
#endif
+#ifndef Q_OS_WINRT
+///////////
+// QWindowsRemovableDriveListener
+// Listen for the various WM_DEVICECHANGE message indicating drive addition/removal
+// requests and removals.
+///////////
+class QWindowsRemovableDriveListener : public QObject, public QAbstractNativeEventFilter
+{
+ Q_OBJECT
+public:
+ // Device UUids as declared in ioevent.h (GUID_IO_VOLUME_LOCK, ...)
+ enum VolumeUuid { UnknownUuid, UuidIoVolumeLock, UuidIoVolumeLockFailed,
+ UuidIoVolumeUnlock, UuidIoMediaRemoval };
+
+ struct RemovableDriveEntry {
+ HDEVNOTIFY devNotify;
+ wchar_t drive;
+ };
+
+ explicit QWindowsRemovableDriveListener(QObject *parent = nullptr);
+ ~QWindowsRemovableDriveListener();
+
+ // Call from QFileSystemWatcher::addPaths() to set up notifications on drives
+ void addPath(const QString &path);
+
+ bool nativeEventFilter(const QByteArray &, void *messageIn, long *) override;
+
+signals:
+ void driveAdded();
+ void driveRemoved(const QString &);
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+
+private:
+ static VolumeUuid volumeUuid(const UUID &needle);
+ void handleDbtCustomEvent(const MSG *msg);
+ void handleDbtDriveArrivalRemoval(const MSG *msg);
+
+ std::vector<RemovableDriveEntry> m_removableDrives;
+ quintptr m_lastMessageHash;
+};
+
+static inline QEventDispatcherWin32 *winEventDispatcher()
+{
+ return static_cast<QEventDispatcherWin32 *>(QCoreApplication::instance()->eventDispatcher());
+}
+
+QWindowsRemovableDriveListener::QWindowsRemovableDriveListener(QObject *parent)
+ : QObject(parent)
+ , m_lastMessageHash(0)
+{
+ winEventDispatcher()->installNativeEventFilter(this);
+}
+
+static void stopDeviceNotification(QWindowsRemovableDriveListener::RemovableDriveEntry &e)
+{
+ UnregisterDeviceNotification(e.devNotify);
+ e.devNotify = 0;
+}
+
+template <class Iterator> // Search sequence of RemovableDriveEntry for HDEVNOTIFY.
+static inline Iterator findByHDevNotify(Iterator i1, Iterator i2, HDEVNOTIFY hdevnotify)
+{
+ return std::find_if(i1, i2,
+ [hdevnotify] (const QWindowsRemovableDriveListener::RemovableDriveEntry &e) { return e.devNotify == hdevnotify; });
+}
+
+QWindowsRemovableDriveListener::~QWindowsRemovableDriveListener()
+{
+ std::for_each(m_removableDrives.begin(), m_removableDrives.end(), stopDeviceNotification);
+}
+
+static QString pathFromEntry(const QWindowsRemovableDriveListener::RemovableDriveEntry &re)
+{
+ QString path = QStringLiteral("A:/");
+ path[0] = QChar::fromLatin1(re.drive);
+ return path;
+}
+
+// Handle WM_DEVICECHANGE+DBT_CUSTOMEVENT, which is sent based on the registration
+// on the volume handle with QEventDispatcherWin32's message window in the class.
+// Capture the GUID_IO_VOLUME_LOCK indicating the drive is to be removed.
+QWindowsRemovableDriveListener::VolumeUuid QWindowsRemovableDriveListener::volumeUuid(const UUID &needle)
+{
+ static const struct VolumeUuidMapping // UUIDs from IoEvent.h (missing in MinGW)
+ {
+ VolumeUuid v;
+ UUID uuid;
+ } mapping[] = {
+ { UuidIoVolumeLock, // GUID_IO_VOLUME_LOCK
+ {0x50708874, 0xc9af, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeLockFailed, // GUID_IO_VOLUME_LOCK_FAILED
+ {0xae2eed10, 0x0ba8, 0x11d2, {0x8f, 0xfb, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoVolumeUnlock, // GUID_IO_VOLUME_UNLOCK
+ {0x9a8c3d68, 0xd0cb, 0x11d1, {0x8f, 0xef, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x32}} },
+ { UuidIoMediaRemoval, // GUID_IO_MEDIA_REMOVAL
+ {0xd07433c1, 0xa98e, 0x11d2, {0x91, 0x7a, 0x0, 0xa0, 0xc9, 0x06, 0x8f, 0xf3}} }
+ };
+
+ static const VolumeUuidMapping *end = mapping + sizeof(mapping) / sizeof(mapping[0]);
+ const VolumeUuidMapping *m =
+ std::find_if(mapping, end, [&needle] (const VolumeUuidMapping &m) { return IsEqualGUID(m.uuid, needle); });
+ return m != end ? m->v : UnknownUuid;
+}
+
+inline void QWindowsRemovableDriveListener::handleDbtCustomEvent(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ if (broadcastHeader->dbch_devicetype != DBT_DEVTYP_HANDLE)
+ return;
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ broadcastHandle->dbch_hdevnotify);
+ if (it == m_removableDrives.cend())
+ return;
+ switch (volumeUuid(broadcastHandle->dbch_eventguid)) {
+ case UuidIoVolumeLock: // Received for removable USB media
+ emit driveLockForRemoval(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeLockFailed:
+ emit driveLockForRemovalFailed(pathFromEntry(*it));
+ break;
+ case UuidIoVolumeUnlock:
+ break;
+ case UuidIoMediaRemoval: // Received for optical drives
+ break;
+ default:
+ break;
+ }
+}
+
+// Handle WM_DEVICECHANGE+DBT_DEVICEARRIVAL/DBT_DEVICEREMOVECOMPLETE which are
+// sent to all top level windows and cannot be registered for (that is, their
+// triggering depends on top level windows being present)
+inline void QWindowsRemovableDriveListener::handleDbtDriveArrivalRemoval(const MSG *msg)
+{
+ const DEV_BROADCAST_HDR *broadcastHeader = reinterpret_cast<const DEV_BROADCAST_HDR *>(msg->lParam);
+ switch (broadcastHeader->dbch_devicetype) {
+ case DBT_DEVTYP_HANDLE: // WM_DEVICECHANGE/DBT_DEVTYP_HANDLE is sent for our registered drives.
+ if (msg->wParam == DBT_DEVICEREMOVECOMPLETE) {
+ const DEV_BROADCAST_HANDLE *broadcastHandle = reinterpret_cast<const DEV_BROADCAST_HANDLE *>(broadcastHeader);
+ const auto it = findByHDevNotify(m_removableDrives.begin(), m_removableDrives.end(),
+ broadcastHandle->dbch_hdevnotify);
+ // Emit for removable USB drives we were registered for.
+ if (it != m_removableDrives.end()) {
+ emit driveRemoved(pathFromEntry(*it));
+ stopDeviceNotification(*it);
+ m_removableDrives.erase(it);
+ }
+ }
+ break;
+ case DBT_DEVTYP_VOLUME: {
+ const DEV_BROADCAST_VOLUME *broadcastVolume = reinterpret_cast<const DEV_BROADCAST_VOLUME *>(broadcastHeader);
+ // WM_DEVICECHANGE/DBT_DEVTYP_VOLUME messages are sent to all toplevel windows. Compare a hash value to ensure
+ // it is handled only once.
+ const quintptr newHash = reinterpret_cast<quintptr>(broadcastVolume) + msg->wParam
+ + quintptr(broadcastVolume->dbcv_flags) + quintptr(broadcastVolume->dbcv_unitmask);
+ if (newHash == m_lastMessageHash)
+ return;
+ m_lastMessageHash = newHash;
+ // Check for DBTF_MEDIA (inserted/Removed Optical drives). Ignore for now.
+ if (broadcastVolume->dbcv_flags & DBTF_MEDIA)
+ return;
+ // Continue with plugged in USB media where dbcv_flags=0.
+ switch (msg->wParam) {
+ case DBT_DEVICEARRIVAL:
+ emit driveAdded();
+ break;
+ case DBT_DEVICEREMOVECOMPLETE: // handled by DBT_DEVTYP_HANDLE above
+ break;
+ }
+ }
+ break;
+ }
+}
+
+bool QWindowsRemovableDriveListener::nativeEventFilter(const QByteArray &, void *messageIn, long *)
+{
+ const MSG *msg = reinterpret_cast<const MSG *>(messageIn);
+ if (msg->message == WM_DEVICECHANGE) {
+ switch (msg->wParam) {
+ case DBT_CUSTOMEVENT:
+ handleDbtCustomEvent(msg);
+ break;
+ case DBT_DEVICEARRIVAL:
+ case DBT_DEVICEREMOVECOMPLETE:
+ handleDbtDriveArrivalRemoval(msg);
+ break;
+ }
+ }
+ return false;
+}
+
+// Set up listening for WM_DEVICECHANGE+DBT_CUSTOMEVENT for a removable drive path,
+void QWindowsRemovableDriveListener::addPath(const QString &p)
+{
+ const wchar_t drive = p.size() >= 2 && p.at(0).isLetter() && p.at(1) == QLatin1Char(':')
+ ? wchar_t(p.at(0).toUpper().unicode()) : L'\0';
+ if (!drive)
+ return;
+ // Already listening?
+ if (std::any_of(m_removableDrives.cbegin(), m_removableDrives.cend(),
+ [drive](const RemovableDriveEntry &e) { return e.drive == drive; })) {
+ return;
+ }
+
+ wchar_t devicePath[8] = L"\\\\.\\A:\\";
+ devicePath[4] = drive;
+ RemovableDriveEntry re;
+ re.drive = drive;
+ if (GetDriveTypeW(devicePath + 4) != DRIVE_REMOVABLE)
+ return;
+ const HANDLE volumeHandle =
+ CreateFile(devicePath, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, 0,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, // Volume requires BACKUP_SEMANTICS
+ 0);
+ if (volumeHandle == INVALID_HANDLE_VALUE) {
+ qErrnoWarning("CreateFile %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ DEV_BROADCAST_HANDLE notify;
+ ZeroMemory(&notify, sizeof(notify));
+ notify.dbch_size = sizeof(notify);
+ notify.dbch_devicetype = DBT_DEVTYP_HANDLE;
+ notify.dbch_handle = volumeHandle;
+ re.devNotify = RegisterDeviceNotification(winEventDispatcher()->internalHwnd(),
+ &notify, DEVICE_NOTIFY_WINDOW_HANDLE);
+ // Empirically found: The notifications also work when the handle is immediately
+ // closed. Do it here to avoid having to close/reopen in lock message handling.
+ CloseHandle(volumeHandle);
+ if (!re.devNotify) {
+ qErrnoWarning("RegisterDeviceNotification %s failed.",
+ qPrintable(QString::fromWCharArray(devicePath)));
+ return;
+ }
+
+ m_removableDrives.push_back(re);
+}
+#endif // !Q_OS_WINRT
+
+///////////
+// QWindowsFileSystemWatcherEngine
+///////////
QWindowsFileSystemWatcherEngine::Handle::Handle()
: handle(INVALID_HANDLE_VALUE), flags(0u)
{
}
+QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent)
+ : QFileSystemWatcherEngine(parent)
+#ifndef Q_OS_WINRT
+ , m_driveListener(new QWindowsRemovableDriveListener(this))
+#endif
+{
+#ifndef Q_OS_WINRT
+ parent->setProperty("_q_driveListener",
+ QVariant::fromValue(static_cast<QObject *>(m_driveListener)));
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemoval,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemoval);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveLockForRemovalFailed,
+ this, &QWindowsFileSystemWatcherEngine::driveLockForRemovalFailed);
+ QObject::connect(m_driveListener, &QWindowsRemovableDriveListener::driveRemoved,
+ this, &QWindowsFileSystemWatcherEngine::driveRemoved);
+#endif // !Q_OS_WINRT
+}
+
QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
{
for (auto *thread : qAsConst(threads))
@@ -210,6 +484,13 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
}
}
}
+
+#ifndef Q_OS_WINRT
+ for (const QString &path : paths) {
+ if (!p.contains(path))
+ m_driveListener->addPath(path);
+ }
+#endif // !Q_OS_WINRT
return p;
}
@@ -439,4 +720,9 @@ void QWindowsFileSystemWatcherEngineThread::wakeup()
}
QT_END_NAMESPACE
+
+#ifndef Q_OS_WINRT
+# include "qfilesystemwatcher_win.moc"
+#endif
+
#endif // QT_NO_FILESYSTEMWATCHER
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index e8f5c49dec..51c7082483 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -66,6 +66,7 @@
QT_BEGIN_NAMESPACE
class QWindowsFileSystemWatcherEngineThread;
+class QWindowsRemovableDriveListener;
// Even though QWindowsFileSystemWatcherEngine is derived of QThread
// via QFileSystemWatcher, it does not start a thread.
@@ -75,9 +76,7 @@ class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine
{
Q_OBJECT
public:
- inline QWindowsFileSystemWatcherEngine(QObject *parent)
- : QFileSystemWatcherEngine(parent)
- { }
+ explicit QWindowsFileSystemWatcherEngine(QObject *parent);
~QWindowsFileSystemWatcherEngine();
QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
@@ -121,9 +120,17 @@ public:
|| lastModified != fileInfo.lastModified());
}
};
+
+signals:
+ void driveLockForRemoval(const QString &);
+ void driveLockForRemovalFailed(const QString &);
+ void driveRemoved(const QString &);
+
private:
QList<QWindowsFileSystemWatcherEngineThread *> threads;
-
+#ifndef Q_OS_WINRT
+ QWindowsRemovableDriveListener *m_driveListener;
+#endif
};
class QFileSystemWatcherPathKey : public QString
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index f8e31ed92b..e152b035e2 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -144,7 +144,7 @@ static inline bool setCloseOnExec(int fd)
static inline QString msgOpenDirectory()
{
const char message[] = QT_TRANSLATE_NOOP("QIODevice", "file to open is a directory");
-#ifndef QT_BOOTSTRAPPED
+#if QT_CONFIG(translation)
return QIODevice::tr(message);
#else
return QLatin1String(message);
@@ -629,7 +629,7 @@ QString QFSFileEngine::fileName(FileName file) const
bool QFSFileEngine::isRelativePath() const
{
Q_D(const QFSFileEngine);
- return d->fileEntry.filePath().length() ? d->fileEntry.filePath()[0] != QLatin1Char('/') : true;
+ return d->fileEntry.filePath().length() ? d->fileEntry.filePath().at(0) != QLatin1Char('/') : true;
}
uint QFSFileEngine::ownerId(FileOwner own) const
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index e427b62136..7d16e59195 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -108,6 +108,20 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode)
{
Q_Q(QFSFileEngine);
+ // Check if the file name is valid:
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
+ const QString fileName = fileEntry.fileName();
+ for (QString::const_iterator it = fileName.constBegin(), end = fileName.constEnd();
+ it != end; ++it) {
+ const QChar c = *it;
+ if (c == QLatin1Char('<') || c == QLatin1Char('>') || c == QLatin1Char(':') ||
+ c == QLatin1Char('\"') || c == QLatin1Char('/') || c == QLatin1Char('\\') ||
+ c == QLatin1Char('|') || c == QLatin1Char('?') || c == QLatin1Char('*')) {
+ q->setError(QFile::OpenError, QStringLiteral("Invalid file name"));
+ return false;
+ }
+ }
+
// All files are opened in share mode (both read and write).
DWORD shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
@@ -850,7 +864,6 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const
uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
QFile::MemoryMapFlags flags)
{
-#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
Q_UNUSED(flags);
if (openMode == QFile::NotOpen) {
@@ -960,18 +973,11 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
::CloseHandle(mapHandle);
mapHandle = NULL;
-#else // !Q_OS_WINPHONE
- Q_UNUSED(offset);
- Q_UNUSED(size);
- Q_UNUSED(flags);
- Q_UNIMPLEMENTED();
-#endif // Q_OS_WINPHONE
return 0;
}
bool QFSFileEnginePrivate::unmap(uchar *ptr)
{
-#ifndef Q_OS_WINPHONE
Q_Q(QFSFileEngine);
if (!maps.contains(ptr)) {
q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED));
@@ -990,11 +996,6 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr)
}
return true;
-#else // !Q_OS_WINPHONE
- Q_UNUSED(ptr);
- Q_UNIMPLEMENTED();
- return false;
-#endif // Q_OS_WINPHONE
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index 77a8c891b4..4f7bc95330 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -371,7 +371,12 @@ void QLoggingRegistry::setApiRules(const QString &content)
*/
void QLoggingRegistry::updateRules()
{
- rules = qtConfigRules + configRules + apiRules + envRules;
+ rules.clear();
+ rules.reserve(qtConfigRules.size() + configRules.size() + apiRules.size() + envRules.size()),
+ rules += qtConfigRules;
+ rules += configRules;
+ rules += apiRules;
+ rules += envRules;
for (auto it = categories.keyBegin(), end = categories.keyEnd(); it != end; ++it)
(*categoryFilter)(*it);
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index fd340ca607..c0ec35ff32 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -428,6 +428,8 @@ void QProcessEnvironment::insert(const QProcessEnvironment &e)
d->insert(*e.d);
}
+#if QT_CONFIG(process)
+
void QProcessPrivate::Channel::clear()
{
switch (type) {
@@ -1527,7 +1529,7 @@ void QProcess::setStandardOutputProcess(QProcess *destination)
dto->stdinChannel.pipeFrom(dfrom);
}
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
/*!
\since 4.7
@@ -2599,6 +2601,8 @@ QString QProcess::nullDevice()
\sa QProcess::pid()
*/
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#include "moc_qprocess.cpp"
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 67c163c012..19157bdd02 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -46,11 +46,13 @@
#include <functional>
-QT_REQUIRE_CONFIG(process);
+QT_REQUIRE_CONFIG(processenvironment);
QT_BEGIN_NAMESPACE
-#if !defined(Q_OS_WIN) || defined(Q_QDOC)
+class QProcessPrivate;
+
+#if !defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
typedef qint64 Q_PID;
#else
QT_END_NAMESPACE
@@ -60,7 +62,6 @@ typedef struct _STARTUPINFOW Q_STARTUPINFO;
QT_BEGIN_NAMESPACE
#endif
-class QProcessPrivate;
class QProcessEnvironmentPrivate;
class Q_CORE_EXPORT QProcessEnvironment
@@ -104,6 +105,8 @@ private:
Q_DECLARE_SHARED(QProcessEnvironment)
+#if QT_CONFIG(process)
+
class Q_CORE_EXPORT QProcess : public QIODevice
{
Q_OBJECT
@@ -186,7 +189,7 @@ public:
void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate);
void setStandardOutputProcess(QProcess *destination);
-#if defined(Q_OS_WIN)
+#if defined(Q_OS_WIN) || defined(Q_CLANG_QDOC)
QString nativeArguments() const;
void setNativeArguments(const QString &arguments);
struct CreateProcessArguments
@@ -205,7 +208,7 @@ public:
typedef std::function<void(CreateProcessArguments *)> CreateProcessArgumentModifier;
CreateProcessArgumentModifier createProcessArgumentsModifier() const;
void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier);
-#endif // Q_OS_WIN
+#endif // Q_OS_WIN || Q_CLANG_QDOC
QString workingDirectory() const;
void setWorkingDirectory(const QString &dir);
@@ -297,6 +300,8 @@ private:
friend class QProcessManager;
};
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#endif // QPROCESS_H
diff --git a/src/corelib/io/qprocess_darwin.mm b/src/corelib/io/qprocess_darwin.mm
new file mode 100644
index 0000000000..dd7a8275b9
--- /dev/null
+++ b/src/corelib/io/qprocess_darwin.mm
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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 <private/qprocess_p.h>
+
+#import <Foundation/Foundation.h>
+
+QT_BEGIN_NAMESPACE
+
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ __block QProcessEnvironment env;
+ [[[NSProcessInfo processInfo] environment]
+ enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *__unused stop) {
+ env.d->hash.insert(
+ QProcessEnvironmentPrivate::Key(QString::fromNSString(name).toLocal8Bit()),
+ QProcessEnvironmentPrivate::Value(QString::fromNSString(value).toLocal8Bit()));
+ }];
+ return env;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index 250eeb5de6..6e0630eb66 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -58,7 +58,7 @@
#include "QtCore/qshareddata.h"
#include "private/qiodevice_p.h"
-QT_REQUIRE_CONFIG(process);
+QT_REQUIRE_CONFIG(processenvironment);
#ifdef Q_OS_UNIX
#include <QtCore/private/qorderedmutexlocker_p.h>
@@ -234,6 +234,8 @@ template<> Q_INLINE_TEMPLATE void QSharedDataPointer<QProcessEnvironmentPrivate>
d = x;
}
+#if QT_CONFIG(process)
+
class QProcessPrivate : public QIODevicePrivate
{
public:
@@ -387,6 +389,8 @@ public:
void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());
};
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
#endif // QPROCESS_P_H
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 03e2c0c4ce..795229419c 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -41,7 +41,7 @@
//#define QPROCESS_DEBUG
#include "qdebug.h"
-#if defined QPROCESS_DEBUG
+#if QT_CONFIG(process) && defined(QPROCESS_DEBUG)
#include "private/qtools_p.h"
#include <ctype.h>
@@ -112,10 +112,36 @@ QT_END_NAMESPACE
#include <errno.h>
#include <stdlib.h>
#include <string.h>
+
+#if QT_CONFIG(process)
#include <forkfd.h>
+#endif
QT_BEGIN_NAMESPACE
+#if !defined(Q_OS_DARWIN)
+
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ QProcessEnvironment env;
+ const char *entry;
+ for (int count = 0; (entry = environ[count]); ++count) {
+ const char *equal = strchr(entry, '=');
+ if (!equal)
+ continue;
+
+ QByteArray name(entry, equal - entry);
+ QByteArray value(equal + 1);
+ env.d->hash.insert(QProcessEnvironmentPrivate::Key(name),
+ QProcessEnvironmentPrivate::Value(value));
+ }
+ return env;
+}
+
+#endif // !defined(Q_OS_DARWIN)
+
+#if QT_CONFIG(process)
+
// POSIX requires PIPE_BUF to be 512 or larger
// so we will use 512
static const int errorBufferMax = 512;
@@ -308,34 +334,6 @@ bool QProcessPrivate::openChannel(Channel &channel)
}
}
-QT_BEGIN_INCLUDE_NAMESPACE
-#if defined(Q_OS_MACX)
-# include <crt_externs.h>
-# define environ (*_NSGetEnviron())
-#else
- extern char **environ;
-#endif
-QT_END_INCLUDE_NAMESPACE
-
-QProcessEnvironment QProcessEnvironment::systemEnvironment()
-{
- QProcessEnvironment env;
-#if !defined(QT_PLATFORM_UIKIT)
- const char *entry;
- for (int count = 0; (entry = environ[count]); ++count) {
- const char *equal = strchr(entry, '=');
- if (!equal)
- continue;
-
- QByteArray name(entry, equal - entry);
- QByteArray value(equal + 1);
- env.d->hash.insert(QProcessEnvironmentPrivate::Key(name),
- QProcessEnvironmentPrivate::Value(value));
- }
-#endif
- return env;
-}
-
static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environment, int *envc)
{
*envc = 0;
@@ -1042,4 +1040,6 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
return success;
}
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 6dd431eb47..329d1842f0 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -38,6 +38,7 @@
**
****************************************************************************/
+//#define QPROCESS_DEBUG
#include "qprocess.h"
#include "qprocess_p.h"
#include "qwindowspipereader_p.h"
@@ -61,7 +62,29 @@
QT_BEGIN_NAMESPACE
-//#define QPROCESS_DEBUG
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
+{
+ QProcessEnvironment env;
+ // Calls to setenv() affect the low-level environment as well.
+ // This is not the case the other way round.
+ if (wchar_t *envStrings = GetEnvironmentStringsW()) {
+ for (const wchar_t *entry = envStrings; *entry; ) {
+ const int entryLen = int(wcslen(entry));
+ // + 1 to permit magic cmd variable names starting with =
+ if (const wchar_t *equal = wcschr(entry + 1, L'=')) {
+ int nameLen = equal - entry;
+ QString name = QString::fromWCharArray(entry, nameLen);
+ QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
+ env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), value);
+ }
+ entry += entryLen + 1;
+ }
+ FreeEnvironmentStringsW(envStrings);
+ }
+ return env;
+}
+
+#if QT_CONFIG(process)
static void qt_create_pipe(Q_PIPE *pipe, bool isInputPipe)
{
@@ -367,28 +390,6 @@ static QString qt_create_commandline(const QString &program, const QStringList &
return args;
}
-QProcessEnvironment QProcessEnvironment::systemEnvironment()
-{
- QProcessEnvironment env;
- // Calls to setenv() affect the low-level environment as well.
- // This is not the case the other way round.
- if (wchar_t *envStrings = GetEnvironmentStringsW()) {
- for (const wchar_t *entry = envStrings; *entry; ) {
- const int entryLen = int(wcslen(entry));
- // + 1 to permit magic cmd variable names starting with =
- if (const wchar_t *equal = wcschr(entry + 1, L'=')) {
- int nameLen = equal - entry;
- QString name = QString::fromWCharArray(entry, nameLen);
- QString value = QString::fromWCharArray(equal + 1, entryLen - nameLen - 1);
- env.d->hash.insert(QProcessEnvironmentPrivate::Key(name), value);
- }
- entry += entryLen + 1;
- }
- FreeEnvironmentStringsW(envStrings);
- }
- return env;
-}
-
static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Hash &environment)
{
QByteArray envlist;
@@ -890,4 +891,6 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
return success;
}
+#endif // QT_CONFIG(process)
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index 0254eb984f..d8166014db 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -104,13 +104,14 @@ QSaveFilePrivate::~QSaveFilePrivate()
\sa QTextStream, QDataStream, QFileInfo, QDir, QFile, QTemporaryFile
*/
-/*!
- Constructs a new file object with the given \a parent.
-*/
-QSaveFile::QSaveFile(QObject *parent)
- : QFileDevice(*new QSaveFilePrivate, parent)
+#ifdef QT_NO_QOBJECT
+QSaveFile::QSaveFile(const QString &name)
+ : QFileDevice(*new QSaveFilePrivate)
{
+ Q_D(QSaveFile);
+ d->fileName = name;
}
+#else
/*!
Constructs a new file object to represent the file with the given \a name.
*/
@@ -120,6 +121,14 @@ QSaveFile::QSaveFile(const QString &name)
Q_D(QSaveFile);
d->fileName = name;
}
+
+/*!
+ Constructs a new file object with the given \a parent.
+*/
+QSaveFile::QSaveFile(QObject *parent)
+ : QFileDevice(*new QSaveFilePrivate, parent)
+{
+}
/*!
Constructs a new file object with the given \a parent to represent the
file with the specified \a name.
@@ -130,6 +139,7 @@ QSaveFile::QSaveFile(const QString &name, QObject *parent)
Q_D(QSaveFile);
d->fileName = name;
}
+#endif
/*!
Destroys the file object, discarding the saved contents unless commit() was called.
diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h
index 10857c27d1..09d6e29272 100644
--- a/src/corelib/io/qsavefile.h
+++ b/src/corelib/io/qsavefile.h
@@ -58,14 +58,18 @@ class QSaveFilePrivate;
class Q_CORE_EXPORT QSaveFile : public QFileDevice
{
+#ifndef QT_NO_QOBJECT
Q_OBJECT
+#endif
Q_DECLARE_PRIVATE(QSaveFile)
public:
explicit QSaveFile(const QString &name);
+#ifndef QT_NO_QOBJECT
explicit QSaveFile(QObject *parent = Q_NULLPTR);
explicit QSaveFile(const QString &name, QObject *parent);
+#endif
~QSaveFile();
QString fileName() const Q_DECL_OVERRIDE;
@@ -84,6 +88,9 @@ protected:
private:
void close() Q_DECL_OVERRIDE;
+#if !QT_CONFIG(translation)
+ static QString tr(const char *string) { return QString::fromLatin1(string); }
+#endif
private:
Q_DISABLE_COPY(QSaveFile)
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index e12da68671..16dab38a60 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -128,7 +128,18 @@ Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
typedef QHash<QString, QConfFile *> ConfFileHash;
typedef QCache<QString, QConfFile> ConfFileCache;
-typedef QHash<int, QString> PathHash;
+namespace {
+ struct Path
+ {
+ // Note: Defining constructors explicitly because of buggy C++11
+ // implementation in MSVC (uniform initialization).
+ Path() {}
+ Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
+ QString path;
+ bool userDefined; //!< true - user defined, overridden by setPath
+ };
+}
+typedef QHash<int, Path> PathHash;
typedef QVector<QConfFileCustomFormat> CustomFormatVector;
Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
@@ -220,7 +231,7 @@ void QConfFile::clearCache()
// QSettingsPrivate
QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
- : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), spec(0), fallbacks(true),
+ : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true),
pendingChanges(false), status(QSettings::NoError)
{
}
@@ -228,7 +239,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
: format(format), scope(scope), organizationName(organization), applicationName(application),
- iniCodec(0), spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
+ iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
{
}
@@ -940,7 +951,7 @@ void QConfFileSettingsPrivate::initFormat()
void QConfFileSettingsPrivate::initAccess()
{
- if (confFiles[spec]) {
+ if (!confFiles.isEmpty()) {
if (format > QSettings::IniFormat) {
if (!readFunc)
setStatus(QSettings::AccessError);
@@ -1070,22 +1081,22 @@ static void initDefaultPaths(QMutexLocker *locker)
const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
# endif
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
- roamingAppDataFolder + QDir::separator());
+ Path(roamingAppDataFolder + QDir::separator(), false));
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
- programDataFolder + QDir::separator());
+ Path(programDataFolder + QDir::separator(), false));
#else
const QString userPath = make_user_path();
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
#ifndef Q_OS_MAC
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), userPath);
- pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), systemPath);
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
+ pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
#endif
#endif // Q_OS_WIN
}
}
-static QString getPath(QSettings::Format format, QSettings::Scope scope)
+static Path getPath(QSettings::Format format, QSettings::Scope scope)
{
Q_ASSERT((int)QSettings::NativeFormat == 0);
Q_ASSERT((int)QSettings::IniFormat == 1);
@@ -1095,14 +1106,23 @@ static QString getPath(QSettings::Format format, QSettings::Scope scope)
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- QString result = pathHash->value(pathHashKey(format, scope));
- if (!result.isEmpty())
+ Path result = pathHash->value(pathHashKey(format, scope));
+ if (!result.path.isEmpty())
return result;
// fall back on INI path
return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
}
+#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+// Note: Suitable only for autotests.
+void Q_AUTOTEST_EXPORT clearDefaultPaths()
+{
+ QMutexLocker locker(&settingsGlobalMutex);
+ pathHashFunc()->clear();
+}
+#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+
QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QSettings::Scope scope,
const QString &organization,
@@ -1110,7 +1130,6 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
: QSettingsPrivate(format, scope, organization, application),
nextPosition(0x40000000) // big positive number
{
- int i;
initFormat();
QString org = organization;
@@ -1123,22 +1142,43 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
QString orgFile = org + extension;
if (scope == QSettings::UserScope) {
- QString userPath = getPath(format, QSettings::UserScope);
+ Path userPath = getPath(format, QSettings::UserScope);
if (!application.isEmpty())
- confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true));
- confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
+ confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
}
- QString systemPath = getPath(format, QSettings::SystemScope);
- if (!application.isEmpty())
- confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false));
- confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false));
-
- for (i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i]) {
- spec = i;
- break;
+ Path systemPath = getPath(format, QSettings::SystemScope);
+#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
+ // check if the systemPath wasn't overridden by QSettings::setPath()
+ if (!systemPath.userDefined) {
+ // Note: We can't use QStandardPaths::locateAll() as we need all the
+ // possible files (not just the existing ones) and there is no way
+ // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
+ QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
+ // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
+ if (!dirs.isEmpty())
+ dirs.takeFirst();
+ QStringList paths;
+ if (!application.isEmpty()) {
+ paths.reserve(dirs.size() * 2);
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + appFile);
+ } else {
+ paths.reserve(dirs.size());
}
+ for (const auto &dir : qAsConst(dirs))
+ paths.append(dir + QLatin1Char('/') + orgFile);
+
+ // Note: No check for existence of files is done intentionaly.
+ for (const auto &path : qAsConst(paths))
+ confFiles.append(QConfFile::fromName(path, false));
+ } else
+#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
+ {
+ if (!application.isEmpty())
+ confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
+ confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
}
initAccess();
@@ -1151,7 +1191,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
{
initFormat();
- confFiles[0].reset(QConfFile::fromName(fileName, true));
+ confFiles.append(QConfFile::fromName(fileName, true));
initAccess();
}
@@ -1162,40 +1202,39 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (confFiles[i] && !confFiles[i]->ref.deref()) {
- if (confFiles[i]->size == 0) {
- delete confFiles[i].take();
+ for (auto conf_file : qAsConst(confFiles)) {
+ if (!conf_file->ref.deref()) {
+ if (conf_file->size == 0) {
+ delete conf_file;
} else {
if (usedHash)
- usedHash->remove(confFiles[i]->name);
+ usedHash->remove(conf_file->name);
if (unusedCache) {
QT_TRY {
// compute a better size?
- unusedCache->insert(confFiles[i]->name, confFiles[i].data(),
- 10 + (confFiles[i]->originalKeys.size() / 4));
- confFiles[i].take();
+ unusedCache->insert(conf_file->name, conf_file,
+ 10 + (conf_file->originalKeys.size() / 4));
} QT_CATCH(...) {
// out of memory. Do not cache the file.
- delete confFiles[i].take();
+ delete conf_file;
}
} else {
// unusedCache is gone - delete the entry to prevent a memory leak
- delete confFiles[i].take();
+ delete conf_file;
}
}
}
- // prevent the ScopedPointer to deref it again.
- confFiles[i].take();
}
}
void QConfFileSettingsPrivate::remove(const QString &key)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity);
QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
QMutexLocker locker(&confFile->mutex);
@@ -1219,10 +1258,12 @@ void QConfFileSettingsPrivate::remove(const QString &key)
void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QSettingsKey theKey(key, caseSensitivity, nextPosition++);
QMutexLocker locker(&confFile->mutex);
confFile->removedKeys.remove(theKey);
@@ -1235,29 +1276,27 @@ bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
ParsedSettingsMap::const_iterator j;
bool found = false;
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (!confFile->addedKeys.isEmpty()) {
- j = confFile->addedKeys.constFind(theKey);
- found = (j != confFile->addedKeys.constEnd());
- }
- if (!found) {
- ensureSectionParsed(confFile, theKey);
- j = confFile->originalKeys.constFind(theKey);
- found = (j != confFile->originalKeys.constEnd()
- && !confFile->removedKeys.contains(theKey));
- }
+ if (!confFile->addedKeys.isEmpty()) {
+ j = confFile->addedKeys.constFind(theKey);
+ found = (j != confFile->addedKeys.constEnd());
+ }
+ if (!found) {
+ ensureSectionParsed(confFile, theKey);
+ j = confFile->originalKeys.constFind(theKey);
+ found = (j != confFile->originalKeys.constEnd()
+ && !confFile->removedKeys.contains(theKey));
+ }
- if (found && value)
- *value = *j;
+ if (found && value)
+ *value = *j;
- if (found)
- return true;
- if (!fallbacks)
- break;
- }
+ if (found)
+ return true;
+ if (!fallbacks)
+ break;
}
return false;
}
@@ -1270,34 +1309,31 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
QSettingsKey thePrefix(prefix, caseSensitivity);
int startPos = prefix.size();
- for (int i = 0; i < NumConfFiles; ++i) {
- if (QConfFile *confFile = confFiles[i].data()) {
- QMutexLocker locker(&confFile->mutex);
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
- if (thePrefix.isEmpty()) {
- ensureAllSectionsParsed(confFile);
- } else {
- ensureSectionParsed(confFile, thePrefix);
- }
-
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->originalKeys)->lowerBound( thePrefix);
- while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
- if (!confFile->removedKeys.contains(j.key()))
- processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ if (thePrefix.isEmpty())
+ ensureAllSectionsParsed(confFile);
+ else
+ ensureSectionParsed(confFile, thePrefix);
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->addedKeys)->lowerBound(thePrefix);
- while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->originalKeys)->lowerBound( thePrefix);
+ while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ if (!confFile->removedKeys.contains(j.key()))
processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
- ++j;
- }
+ ++j;
+ }
- if (!fallbacks)
- break;
+ j = const_cast<const ParsedSettingsMap *>(
+ &confFile->addedKeys)->lowerBound(thePrefix);
+ while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
+ ++j;
}
+
+ if (!fallbacks)
+ break;
}
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()),
@@ -1307,10 +1343,12 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
void QConfFileSettingsPrivate::clear()
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return;
+ // Note: First config file is always the most specific.
+ QConfFile *confFile = confFiles.at(0);
+
QMutexLocker locker(&confFile->mutex);
ensureAllSectionsParsed(confFile);
confFile->addedKeys.clear();
@@ -1322,12 +1360,9 @@ void QConfFileSettingsPrivate::sync()
// people probably won't be checking the status a whole lot, so in case of
// error we just try to go on and make the best of it
- for (int i = 0; i < NumConfFiles; ++i) {
- QConfFile *confFile = confFiles[i].data();
- if (confFile) {
- QMutexLocker locker(&confFile->mutex);
- syncConfFile(i);
- }
+ for (auto confFile : qAsConst(confFiles)) {
+ QMutexLocker locker(&confFile->mutex);
+ syncConfFile(confFile);
}
}
@@ -1338,10 +1373,11 @@ void QConfFileSettingsPrivate::flush()
QString QConfFileSettingsPrivate::fileName() const
{
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return QString();
- return confFile->name;
+
+ // Note: First config file is always the most specific.
+ return confFiles.at(0)->name;
}
bool QConfFileSettingsPrivate::isWritable() const
@@ -1349,16 +1385,14 @@ bool QConfFileSettingsPrivate::isWritable() const
if (format > QSettings::IniFormat && !writeFunc)
return false;
- QConfFile *confFile = confFiles[spec].data();
- if (!confFile)
+ if (confFiles.isEmpty())
return false;
- return confFile->isWritable();
+ return confFiles.at(0)->isWritable();
}
-void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
+void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
{
- QConfFile *confFile = confFiles[confFileNo].data();
bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
/*
@@ -2188,9 +2222,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
\li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
- \li \c{/etc/xdg/MySoft/Star Runner.conf}
- \li \c{/etc/xdg/MySoft.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On \macos versions 10.2 and 10.3, these files are used by
default:
@@ -2225,9 +2260,10 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\list 1
\li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
\li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
- \li \c{/etc/xdg/MySoft/Star Runner.ini}
- \li \c{/etc/xdg/MySoft.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
+ \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
\endlist
+ \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
On Windows, the following files are used:
@@ -3380,7 +3416,7 @@ void QSettings::setPath(Format format, Scope scope, const QString &path)
PathHash *pathHash = pathHashFunc();
if (pathHash->isEmpty())
initDefaultPaths(&locker);
- pathHash->insert(pathHashKey(format, scope), path + QDir::separator());
+ pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
}
/*!
diff --git a/src/corelib/io/qsettings_mac.cpp b/src/corelib/io/qsettings_mac.cpp
index 0e3520441e..e4631bad12 100644
--- a/src/corelib/io/qsettings_mac.cpp
+++ b/src/corelib/io/qsettings_mac.cpp
@@ -424,20 +424,15 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString &
javaPackageName.prepend(QLatin1String("com."));
suiteId = javaPackageName;
- if (scope == QSettings::SystemScope)
- spec |= F_System;
-
- if (application.isEmpty()) {
- spec |= F_Organization;
- } else {
+ if (!application.isEmpty()) {
javaPackageName += QLatin1Char('.');
javaPackageName += application;
applicationId = javaPackageName;
}
numDomains = 0;
- for (int i = (spec & F_System) ? 1 : 0; i < 2; ++i) {
- for (int j = (spec & F_Organization) ? 1 : 0; j < 3; ++j) {
+ for (int i = (scope == QSettings::SystemScope) ? 1 : 0; i < 2; ++i) {
+ for (int j = (application.isEmpty()) ? 1 : 0; j < 3; ++j) {
SearchDomain &domain = domains[numDomains++];
domain.userName = (i == 0) ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser;
if (j == 0)
@@ -578,7 +573,7 @@ bool QMacSettingsPrivate::isWritable() const
QString QMacSettingsPrivate::fileName() const
{
QString result;
- if ((spec & F_System) == 0)
+ if (scope == QSettings::UserScope)
result = QDir::homePath();
result += QLatin1String("/Library/Preferences/");
result += QString::fromCFString(domains[0].applicationOrSuiteId);
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index e6d3413bab..639605d8c4 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -236,19 +236,6 @@ public:
QTextCodec *codec);
static QStringList splitArgs(const QString &s, int idx);
- /*
- The numeric values of these enums define their search order. For example,
- F_User | F_Organization is searched before F_System | F_Application,
- because their values are respectively 1 and 2.
- */
- enum {
- F_Application = 0x0,
- F_Organization = 0x1,
- F_User = 0x0,
- F_System = 0x2,
- NumConfFiles = 4
- };
-
QSettings::Format format;
QSettings::Scope scope;
QString organizationName;
@@ -258,7 +245,6 @@ public:
protected:
QStack<QSettingsGroup> groupStack;
QString groupPrefix;
- int spec;
bool fallbacks;
bool pendingChanges;
mutable QSettings::Status status;
@@ -293,7 +279,7 @@ public:
private:
void initFormat();
void initAccess();
- void syncConfFile(int confFileNo);
+ void syncConfFile(QConfFile *confFile);
bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
#ifdef Q_OS_MAC
bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
@@ -302,7 +288,7 @@ private:
void ensureAllSectionsParsed(QConfFile *confFile) const;
void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
- QScopedSharedPointer<QConfFile> confFiles[NumConfFiles];
+ QVector<QConfFile *> confFiles;
QSettings::ReadFunc readFunc;
QSettings::WriteFunc writeFunc;
QString extension;
diff --git a/src/corelib/io/qsettings_win.cpp b/src/corelib/io/qsettings_win.cpp
index 1c10548cbc..edcae16776 100644
--- a/src/corelib/io/qsettings_win.cpp
+++ b/src/corelib/io/qsettings_win.cpp
@@ -138,21 +138,6 @@ static void mergeKeySets(NameSet *dest, const QStringList &src)
** Wrappers for the insane windows registry API
*/
-static QString errorCodeToString(DWORD errorCode)
-{
- wchar_t *data = 0;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, 0, 0);
- QString result = QString::fromWCharArray(data);
-
- if (data != 0)
- LocalFree(data);
-
- if (result.endsWith(QLatin1Char('\n')))
- result.truncate(result.length() - 1);
-
- return result;
-}
-
// Open a key with the specified "perms".
// "access" is to explicitly use the 32- or 64-bit branch.
static HKEY openKey(HKEY parentHandle, REGSAM perms, const QString &rSubKey, REGSAM access = 0)
@@ -184,7 +169,7 @@ static HKEY createOrOpenKey(HKEY parentHandle, REGSAM perms, const QString &rSub
return resultHandle;
//qWarning("QSettings: Failed to create subkey \"%s\": %s",
- // rSubKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ // qPrintable(rSubKey), qPrintable(qt_error_string(int(res))));
return 0;
}
@@ -224,7 +209,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
&numKeys, &maxKeySize, 0, 0, 0);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegQueryInfoKey() failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegQueryInfoKey() failed: %s", qPrintable(qt_error_string(int(res))));
return result;
}
@@ -258,7 +243,7 @@ static QStringList childKeysOrGroups(HKEY parentHandle, QSettingsPrivate::ChildS
item = QString::fromWCharArray((const wchar_t *)buff.constData(), l);
if (res != ERROR_SUCCESS) {
- qWarning("QSettings: RegEnumValue failed: %s", errorCodeToString(res).toLatin1().data());
+ qWarning("QSettings: RegEnumValue failed: %s", qPrintable(qt_error_string(int(res))));
continue;
}
if (item.isEmpty())
@@ -313,7 +298,7 @@ static void deleteChildGroups(HKEY parentHandle, REGSAM access = 0)
LONG res = RegDeleteKey(parentHandle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
return;
}
}
@@ -613,7 +598,7 @@ QWinSettingsPrivate::~QWinSettingsPrivate()
DWORD res = RegDeleteKey(writeHandle(), reinterpret_cast<const wchar_t *>(emptyKey.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: Failed to delete key \"%s\": %s",
- regList.at(0).key().toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(regList.at(0).key()), qPrintable(qt_error_string(int(res))));
}
}
@@ -652,7 +637,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
LONG res = RegDeleteValue(handle, reinterpret_cast<const wchar_t *>(group.utf16()));
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteValue failed on subkey \"%s\": %s",
- group.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(group), qPrintable(qt_error_string(int(res))));
}
}
} else {
@@ -660,7 +645,7 @@ void QWinSettingsPrivate::remove(const QString &uKey)
if (res != ERROR_SUCCESS) {
qWarning("QSettings: RegDeleteKey failed on key \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
}
}
RegCloseKey(handle);
@@ -758,7 +743,7 @@ void QWinSettingsPrivate::set(const QString &uKey, const QVariant &value)
deleteWriteHandleOnExit = false;
} else {
qWarning("QSettings: failed to set subkey \"%s\": %s",
- rKey.toLatin1().data(), errorCodeToString(res).toLatin1().data());
+ qPrintable(rKey), qPrintable(qt_error_string(int(res))));
setStatus(QSettings::AccessError);
}
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 3773b72606..27f0552a31 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -260,7 +260,7 @@ QByteArray QStorageInfo::fileSystemType() const
devpath like \c /dev/sda0 for local storages. On Windows, it returns the UNC
path starting with \c \\\\?\\ for local storages (in other words, the volume GUID).
- \sa rootPath()
+ \sa rootPath(), subvolume()
*/
QByteArray QStorageInfo::device() const
{
@@ -268,6 +268,26 @@ QByteArray QStorageInfo::device() const
}
/*!
+ \since 5.9
+ Returns the subvolume name for this volume.
+
+ Some filesystem types allow multiple subvolumes inside one device, which
+ may be mounted in different paths. If the subvolume could be detected, it
+ is returned here. The format of the subvolume name is specific to each
+ filesystem type.
+
+ If this volume was not mounted from a subvolume of a larger filesystem or
+ if the subvolume could not be detected, this function returns an empty byte
+ array.
+
+ \sa device()
+*/
+QByteArray QStorageInfo::subvolume() const
+{
+ return d->subvolume;
+}
+
+/*!
Returns the human-readable name of a filesystem, usually called \c label.
Not all filesystems support this feature. In this case, the value returned by
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
index 8941c11a16..e2d9747ceb 100644
--- a/src/corelib/io/qstorageinfo.h
+++ b/src/corelib/io/qstorageinfo.h
@@ -71,6 +71,7 @@ public:
QString rootPath() const;
QByteArray device() const;
+ QByteArray subvolume() const;
QByteArray fileSystemType() const;
QString name() const;
QString displayName() const;
@@ -100,7 +101,7 @@ inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
{
if (first.d == second.d)
return true;
- return first.device() == second.device();
+ return first.device() == second.device() && first.rootPath() == second.rootPath();
}
inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
index a14fa8480a..ec5bb785e3 100644
--- a/src/corelib/io/qstorageinfo_p.h
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -85,6 +85,7 @@ protected:
public:
QString rootPath;
QByteArray device;
+ QByteArray subvolume;
QByteArray fileSystemType;
QString name;
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index ae5c42ffd1..b9c9883609 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -120,6 +120,7 @@ public:
inline QString rootPath() const;
inline QByteArray fileSystemType() const;
inline QByteArray device() const;
+ inline QByteArray options() const;
private:
#if defined(Q_OS_BSD4)
QT_STATFSBUF *stat_buf;
@@ -133,6 +134,7 @@ private:
QByteArray m_rootPath;
QByteArray m_fileSystemType;
QByteArray m_device;
+ QByteArray m_options;
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
FILE *fp;
mntent mnt;
@@ -228,6 +230,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(stat_buf[currentIndex].f_mntfromname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#elif defined(Q_OS_SOLARIS)
static const char pathMounted[] = "/etc/mnttab";
@@ -301,6 +308,7 @@ inline bool QStorageIterator::next()
m_device = data.at(0);
m_rootPath = data.at(1);
m_fileSystemType = data.at(2);
+ m_options = data.at(3);
return true;
}
@@ -320,6 +328,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return m_options;
+}
+
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
static const char pathMounted[] = "/etc/mtab";
@@ -363,6 +376,11 @@ inline QByteArray QStorageIterator::device() const
return QByteArray(mnt.mnt_fsname);
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray(mnt.mnt_opts);
+}
+
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
{
@@ -420,6 +438,11 @@ inline QByteArray QStorageIterator::device() const
return m_device;
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
#else
inline QStorageIterator::QStorageIterator()
@@ -455,7 +478,36 @@ inline QByteArray QStorageIterator::device() const
return QByteArray();
}
+inline QByteArray QStorageIterator::options() const
+{
+ return QByteArray();
+}
+
+#endif
+
+static QByteArray extractSubvolume(const QStorageIterator &it)
+{
+#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();
+}
void QStorageInfoPrivate::initRootPath()
{
@@ -483,6 +535,7 @@ void QStorageInfoPrivate::initRootPath()
rootPath = mountDir;
device = it.device();
fileSystemType = fsName;
+ subvolume = extractSubvolume(it);
}
}
}
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
index 6e50a8513e..b2bf9fce97 100644
--- a/src/corelib/io/qtemporarydir.cpp
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -305,6 +305,33 @@ QString QTemporaryDir::path() const
}
/*!
+ \since 5.9
+
+ Returns the path name of a file in the temporary directory.
+ Does \e not check if the file actually exists in the directory.
+ Redundant multiple separators or "." and ".." directories in
+ \a fileName are not removed (see QDir::cleanPath()). Absolute
+ paths are not allowed.
+*/
+QString QTemporaryDir::filePath(const QString &fileName) const
+{
+ if (QDir::isAbsolutePath(fileName)) {
+ qWarning("QTemporaryDir::filePath: Absolute paths are not allowed: %s", qUtf8Printable(fileName));
+ return QString();
+ }
+
+ if (!d_ptr->success)
+ return QString();
+
+ QString ret = d_ptr->pathOrError;
+ if (!fileName.isEmpty()) {
+ ret += QLatin1Char('/');
+ ret += fileName;
+ }
+ return ret;
+}
+
+/*!
Returns \c true if the QTemporaryDir is in auto remove
mode. Auto-remove mode will automatically delete the directory from
disk upon destruction. This makes it very easy to create your
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
index 2e70d34ae4..3f6b70a2eb 100644
--- a/src/corelib/io/qtemporarydir.h
+++ b/src/corelib/io/qtemporarydir.h
@@ -65,6 +65,7 @@ public:
bool remove();
QString path() const;
+ QString filePath(const QString &fileName) const;
private:
QScopedPointer<QTemporaryDirPrivate> d_ptr;
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index 4fdb1505ff..9b565bff9d 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -2547,6 +2547,7 @@ QTextStream &QTextStream::operator<<(double f)
}
uint flags = 0;
+ const QLocale::NumberOptions numberOptions = locale().numberOptions();
if (numberFlags() & ShowBase)
flags |= QLocaleData::ShowBase;
if (numberFlags() & ForceSign)
@@ -2555,12 +2556,18 @@ QTextStream &QTextStream::operator<<(double f)
flags |= QLocaleData::UppercaseBase;
if (numberFlags() & UppercaseDigits)
flags |= QLocaleData::CapitalEorX;
- if (numberFlags() & ForcePoint)
- flags |= QLocaleData::Alternate;
- if (locale() != QLocale::c() && !(locale().numberOptions() & QLocale::OmitGroupSeparator))
+ 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 (!(locale().numberOptions() & QLocale::OmitLeadingZeroInExponent))
+ 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);
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 3df7070557..b5772b5ce2 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -3182,8 +3182,7 @@ QUrl QUrl::resolved(const QUrl &relative) const
if (!relative.d) return *this;
QUrl t;
- // Compatibility hack (mostly for qtdeclarative) : treat "file:relative.txt" as relative even though QUrl::isRelative() says false
- if (!relative.d->scheme.isEmpty() && (!relative.isLocalFile() || QDir::isAbsolutePath(relative.d->path))) {
+ if (!relative.d->scheme.isEmpty()) {
t = relative;
t.detach();
} else {
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index a554a3b07e..c16825a033 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -69,8 +69,8 @@ public:
Q_DECL_CONSTEXPR inline QUrlTwoFlags(E1 f) : i(f) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(E2 f) : i(f) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlag f) : i(f) {}
- Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E1> f) : i(f.operator int()) {}
- Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E2> f) : i(f.operator int()) {}
+ Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E1> f) : i(f.operator typename QFlags<E1>::Int()) {}
+ Q_DECL_CONSTEXPR inline QUrlTwoFlags(QFlags<E2> f) : i(f.operator typename QFlags<E2>::Int()) {}
Q_DECL_CONSTEXPR inline QUrlTwoFlags(Zero = 0) : i(0) {}
inline QUrlTwoFlags &operator&=(int mask) { i &= mask; return *this; }