summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri34
-rw-r--r--src/corelib/io/qdatastream.cpp36
-rw-r--r--src/corelib/io/qdatastream.h8
-rw-r--r--src/corelib/io/qdebug.cpp96
-rw-r--r--src/corelib/io/qdebug.h99
-rw-r--r--src/corelib/io/qdir.cpp6
-rw-r--r--src/corelib/io/qfiledevice.cpp11
-rw-r--r--src/corelib/io/qfiledevice.h4
-rw-r--r--src/corelib/io/qfileselector.cpp9
-rw-r--r--src/corelib/io/qfsfileengine.cpp16
-rw-r--r--src/corelib/io/qfsfileengine_p.h1
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp8
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp28
-rw-r--r--src/corelib/io/qiodevice.cpp6
-rw-r--r--src/corelib/io/qiodevice_p.h16
-rw-r--r--src/corelib/io/qlockfile_unix.cpp5
-rw-r--r--src/corelib/io/qlockfile_win.cpp37
-rw-r--r--src/corelib/io/qloggingcategory.cpp88
-rw-r--r--src/corelib/io/qloggingcategory.h32
-rw-r--r--src/corelib/io/qloggingregistry.cpp52
-rw-r--r--src/corelib/io/qloggingregistry_p.h6
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice.cpp39
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice_p.h6
-rw-r--r--src/corelib/io/qsavefile.cpp24
-rw-r--r--src/corelib/io/qsavefile_p.h1
-rw-r--r--src/corelib/io/qsettings.cpp304
-rw-r--r--src/corelib/io/qsettings_p.h4
-rw-r--r--src/corelib/io/qsettings_winrt.cpp695
-rw-r--r--src/corelib/io/qstandardpaths.cpp35
-rw-r--r--src/corelib/io/qstandardpaths.h4
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp5
-rw-r--r--src/corelib/io/qstandardpaths_blackberry.cpp5
-rw-r--r--src/corelib/io/qstandardpaths_ios.mm3
-rw-r--r--src/corelib/io/qstandardpaths_mac.cpp16
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp8
-rw-r--r--src/corelib/io/qstandardpaths_win.cpp34
-rw-r--r--src/corelib/io/qstandardpaths_winrt.cpp7
-rw-r--r--src/corelib/io/qstorageinfo.cpp398
-rw-r--r--src/corelib/io/qstorageinfo.h122
-rw-r--r--src/corelib/io/qstorageinfo_mac.cpp213
-rw-r--r--src/corelib/io/qstorageinfo_p.h103
-rw-r--r--src/corelib/io/qstorageinfo_stub.cpp (renamed from src/corelib/io/qloggingcategory_p.h)43
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp456
-rw-r--r--src/corelib/io/qstorageinfo_win.cpp193
-rw-r--r--src/corelib/io/qtemporaryfile.cpp3
-rw-r--r--src/corelib/io/qtextstream.cpp4
-rw-r--r--src/corelib/io/qtldurl.cpp6
-rw-r--r--src/corelib/io/qurl.cpp64
-rw-r--r--src/corelib/io/qurl.h9
-rw-r--r--src/corelib/io/qwinoverlappedionotifier.cpp60
-rw-r--r--src/corelib/io/qwinoverlappedionotifier_p.h1
51 files changed, 2937 insertions, 526 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index f651860e08..bdc362ef22 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -32,6 +32,8 @@ HEADERS += \
io/qresource_iterator_p.h \
io/qsavefile.h \
io/qstandardpaths.h \
+ io/qstorageinfo.h \
+ io/qstorageinfo_p.h \
io/qurl.h \
io/qurl_p.h \
io/qurlquery.h \
@@ -51,7 +53,6 @@ HEADERS += \
io/qfileselector.h \
io/qfileselector_p.h \
io/qloggingcategory.h \
- io/qloggingcategory_p.h \
io/qloggingregistry_p.h
SOURCES += \
@@ -71,6 +72,7 @@ SOURCES += \
io/qlockfile.cpp \
io/qnoncontiguousbytedevice.cpp \
io/qprocess.cpp \
+ io/qstorageinfo.cpp \
io/qtextstream.cpp \
io/qtemporarydir.cpp \
io/qtemporaryfile.cpp \
@@ -109,7 +111,8 @@ win32 {
SOURCES += io/qstandardpaths_win.cpp
wince* {
- SOURCES += io/qprocess_wince.cpp
+ SOURCES += io/qprocess_wince.cpp \
+ io/qstorageinfo_stub.cpp
} else {
HEADERS += \
io/qwinoverlappedionotifier_p.h \
@@ -117,10 +120,15 @@ win32 {
SOURCES += \
io/qprocess_win.cpp \
io/qwinoverlappedionotifier.cpp \
- io/qwindowspipereader.cpp
+ io/qwindowspipereader.cpp \
+ io/qstorageinfo_win.cpp
+ LIBS += -lmpr
}
} else {
- SOURCES += io/qstandardpaths_winrt.cpp
+ SOURCES += \
+ io/qstandardpaths_winrt.cpp \
+ io/qsettings_winrt.cpp \
+ io/qstorageinfo_stub.cpp
}
} else:unix|integrity {
SOURCES += \
@@ -140,18 +148,28 @@ win32 {
HEADERS += io/qfilesystemwatcher_fsevents_p.h
}
macx {
- SOURCES += io/qstandardpaths_mac.cpp
+ SOURCES += \
+ io/qstorageinfo_mac.cpp \
+ io/qstandardpaths_mac.cpp
+ LIBS += -framework DiskArbitration -framework IOKit
} else:ios {
OBJECTIVE_SOURCES += io/qstandardpaths_ios.mm
+ SOURCES += io/qstorageinfo_mac.cpp
} else {
SOURCES += io/qstandardpaths_unix.cpp
}
} else:blackberry {
- SOURCES += io/qstandardpaths_blackberry.cpp
+ SOURCES += \
+ io/qstandardpaths_blackberry.cpp \
+ io/qstorageinfo_unix.cpp
} else:android:!android-no-sdk {
- SOURCES += io/qstandardpaths_android.cpp
+ SOURCES += \
+ io/qstandardpaths_android.cpp \
+ io/qstorageinfo_unix.cpp
} else {
- SOURCES += io/qstandardpaths_unix.cpp
+ SOURCES += \
+ io/qstandardpaths_unix.cpp \
+ io/qstorageinfo_unix.cpp
}
linux|if(qnx:contains(QT_CONFIG, inotify)) {
diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp
index a6fbffee7e..127244e994 100644
--- a/src/corelib/io/qdatastream.cpp
+++ b/src/corelib/io/qdatastream.cpp
@@ -250,10 +250,6 @@ QT_BEGIN_NAMESPACE
if (q_status != Ok) \
return retVal;
-enum {
- DefaultStreamVersion = QDataStream::Qt_5_3
-};
-
/*!
Constructs a data stream that has no I/O device.
@@ -265,7 +261,7 @@ QDataStream::QDataStream()
dev = 0;
owndev = false;
byteorder = BigEndian;
- ver = DefaultStreamVersion;
+ ver = Qt_DefaultCompiledVersion;
noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
q_status = Ok;
}
@@ -287,7 +283,7 @@ QDataStream::QDataStream(QIODevice *d)
dev = d; // set device
owndev = false;
byteorder = BigEndian; // default byte order
- ver = DefaultStreamVersion;
+ ver = Qt_DefaultCompiledVersion;
noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
q_status = Ok;
}
@@ -315,7 +311,7 @@ QDataStream::QDataStream(QByteArray *a, QIODevice::OpenMode flags)
dev = buf;
owndev = true;
byteorder = BigEndian;
- ver = DefaultStreamVersion;
+ ver = Qt_DefaultCompiledVersion;
noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
q_status = Ok;
}
@@ -339,7 +335,7 @@ QDataStream::QDataStream(const QByteArray &a)
dev = buf;
owndev = true;
byteorder = BigEndian;
- ver = DefaultStreamVersion;
+ ver = Qt_DefaultCompiledVersion;
noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
q_status = Ok;
}
@@ -542,6 +538,8 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_5_1 Version 14 (Qt 5.1)
\value Qt_5_2 Version 15 (Qt 5.2)
\value Qt_5_3 Same as Qt_5_2
+ \value Qt_5_4 Version 16 (Qt 5.4)
+ \omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
*/
@@ -557,7 +555,8 @@ void QDataStream::setByteOrder(ByteOrder bo)
/*!
\fn void QDataStream::setVersion(int v)
- Sets the version number of the data serialization format to \a v.
+ Sets the version number of the data serialization format to \a v,
+ a value of the \l Version enum.
You don't \e have to set a version if you are using the current
version of Qt, but for your own custom binary formats we
@@ -571,25 +570,6 @@ void QDataStream::setByteOrder(ByteOrder bo)
with an earlier version of Qt, use this function to modify the
serialization format used by QDataStream.
- \table
- \header \li Qt Version \li QDataStream Version
- \row \li Qt 5.2 \li 15
- \row \li Qt 5.1 \li 14
- \row \li Qt 5.0 \li 13
- \row \li Qt 4.6 \li 12
- \row \li Qt 4.5 \li 11
- \row \li Qt 4.4 \li 10
- \row \li Qt 4.3 \li 9
- \row \li Qt 4.2 \li 8
- \row \li Qt 4.0, 4.1 \li 7
- \row \li Qt 3.3 \li 6
- \row \li Qt 3.1, 3.2 \li 5
- \row \li Qt 3.0 \li 4
- \row \li Qt 2.1, 2.2, 2.3 \li 3
- \row \li Qt 2.0 \li 2
- \row \li Qt 1.x \li 1
- \endtable
-
The \l Version enum provides symbolic constants for the different
versions of Qt. For example:
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index 28f1d51a12..808fbe73f6 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -88,10 +88,12 @@ public:
Qt_5_0 = 13,
Qt_5_1 = 14,
Qt_5_2 = 15,
- Qt_5_3 = Qt_5_2
-#if QT_VERSION >= 0x050400
-#error Add the datastream version for this Qt version
+ Qt_5_3 = Qt_5_2,
+ Qt_5_4 = 16,
+#if QT_VERSION >= 0x050500
+#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
+ Qt_DefaultCompiledVersion = Qt_5_4
};
enum ByteOrder {
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 3370cce6d5..b0411f9dd9 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -79,6 +79,18 @@ QT_BEGIN_NAMESPACE
used to write debugging information to files and other devices. The constructor
that accepts a QString is used to write to a string for display or serialization.
+ \section1 Formatting Options
+
+ QDebug formats output so that it's easily readable. It automatically adds spaces
+ between arguments, and adds quotes around QString, QByteArray, QChar arguments.
+
+ You can tweak these options through the space(), nospace() and quote(), noquote()
+ methods. Furthermore, \l{QTextStream manipulators} can be piped into a QDebug
+ stream.
+
+ QDebugStateSaver limits changes to the formatting to the current scope.
+ resetFormat() resets the options to the default ones.
+
\section1 Writing Custom Types to a Stream
Many standard types can be written to QDebug objects, and Qt provides support for
@@ -128,6 +140,20 @@ QT_BEGIN_NAMESPACE
Flushes any pending data to be written and destroys the debug stream.
*/
+// Has been defined in the header / inlined before Qt 5.4
+QDebug::~QDebug()
+{
+ if (!--stream->ref) {
+ if (stream->space && stream->buffer.endsWith(QLatin1Char(' ')))
+ stream->buffer.chop(1);
+ if (stream->message_output) {
+ qt_message_output(stream->type,
+ stream->context,
+ stream->buffer);
+ }
+ delete stream;
+ }
+}
/*!
\fn QDebug::swap(QDebug &other)
@@ -138,6 +164,21 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ Resets the stream formatting options, bringing it back to its original constructed state.
+
+ \sa space(), quote()
+ \since 5.4
+*/
+QDebug &QDebug::resetFormat()
+{
+ stream->ts.reset();
+ stream->space = true;
+ if (stream->context.version > 1)
+ stream->flags = 0;
+ return *this;
+}
+
+/*!
\fn QDebug &QDebug::space()
Writes a space character to the debug stream and returns a reference to
@@ -188,6 +229,41 @@ QT_BEGIN_NAMESPACE
\sa QDebugStateSaver
*/
+
+/*!
+ \fn QDebug &QDebug::quote()
+ \since 5.4
+
+ Enables automatic insertion of quotation characters around QChar, QString and QByteArray
+ contents and returns a reference to the stream.
+
+ Quoting is enabled by default.
+
+ \sa noquote(), maybeQuote()
+*/
+
+/*!
+ \fn QDebug &QDebug::noquote()
+ \since 5.4
+
+ Disables automatic insertion of quotation characters around QChar, QString and QByteArray
+ contents and returns a reference to the stream.
+
+ \sa quote(), maybeQuote()
+*/
+
+/*!
+ \fn QDebug &QDebug::maybeQuote(char c)
+ \since 5.4
+
+ Writes a character \a c to the debug stream, depending on the
+ current setting for automatic insertion of quotes, and returns a reference to the stream.
+
+ The default character is a double quote \c{"}.
+
+ \sa quote(), noquote()
+*/
+
/*!
\fn QDebug &QDebug::operator<<(QChar t)
@@ -334,7 +410,9 @@ QT_BEGIN_NAMESPACE
\brief Convenience class for custom QDebug operators
- Saves the settings used by QDebug, and restores them upon destruction.
+ Saves the settings used by QDebug, and restores them upon destruction,
+ then calls maybeSpace(), to separate arguments with a space if
+ autoInsertSpaces() was true at the time of constructing the QDebugStateSaver.
The automatic insertion of spaces between writes is one of the settings
that QDebugStateSaver stores for the duration of the current block.
@@ -352,19 +430,33 @@ public:
QDebugStateSaverPrivate(QDebug &dbg)
: m_dbg(dbg),
m_spaces(dbg.autoInsertSpaces()),
+ m_flags(0),
m_streamParams(dbg.stream->ts.d_ptr->params)
{
+ if (m_dbg.stream->context.version > 1)
+ m_flags = m_dbg.stream->flags;
}
void restoreState()
{
+ const bool currentSpaces = m_dbg.autoInsertSpaces();
+ if (currentSpaces && !m_spaces)
+ if (m_dbg.stream->buffer.endsWith(QLatin1Char(' ')))
+ m_dbg.stream->buffer.chop(1);
+
m_dbg.setAutoInsertSpaces(m_spaces);
m_dbg.stream->ts.d_ptr->params = m_streamParams;
+ if (m_dbg.stream->context.version > 1)
+ m_dbg.stream->flags = m_flags;
+
+ if (!currentSpaces && m_spaces)
+ m_dbg.stream->ts << ' ';
}
QDebug &m_dbg;
// QDebug state
const bool m_spaces;
+ int m_flags;
// QTextStream state
const QTextStreamPrivate::Params m_streamParams;
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index bdaaa05768..6b81d9431f 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -61,9 +61,9 @@ class Q_CORE_EXPORT QDebug
friend class QMessageLogger;
friend class QDebugStateSaverPrivate;
struct Stream {
- Stream(QIODevice *device) : ts(device), ref(1), type(QtDebugMsg), space(true), message_output(false) {}
- Stream(QString *string) : ts(string, QIODevice::WriteOnly), ref(1), type(QtDebugMsg), space(true), message_output(false) {}
- Stream(QtMsgType t) : ts(&buffer, QIODevice::WriteOnly), ref(1), type(t), space(true), message_output(true) {}
+ Stream(QIODevice *device) : ts(device), ref(1), type(QtDebugMsg), space(true), message_output(false), flags(0) {}
+ Stream(QString *string) : ts(string, QIODevice::WriteOnly), ref(1), type(QtDebugMsg), space(true), message_output(false), flags(0) {}
+ Stream(QtMsgType t) : ts(&buffer, QIODevice::WriteOnly), ref(1), type(t), space(true), message_output(true), flags(0) {}
QTextStream ts;
QString buffer;
int ref;
@@ -71,6 +71,18 @@ class Q_CORE_EXPORT QDebug
bool space;
bool message_output;
QMessageLogContext context;
+
+ enum FormatFlag {
+ NoQuotes = 0x1
+ };
+
+ // ### Qt 6: unify with space, introduce own version member
+ bool testFlag(FormatFlag flag) const { return (context.version > 1) ? (flags & flag) : false; }
+ void setFlag(FormatFlag flag) { if (context.version > 1) { flags |= flag; } }
+ void unsetFlag(FormatFlag flag) { if (context.version > 1) { flags &= ~flag; } }
+
+ // added in 5.4
+ int flags;
} *stream;
public:
inline QDebug(QIODevice *device) : stream(new Stream(device)) {}
@@ -78,22 +90,11 @@ public:
inline QDebug(QtMsgType t) : stream(new Stream(t)) {}
inline QDebug(const QDebug &o):stream(o.stream) { ++stream->ref; }
inline QDebug &operator=(const QDebug &other);
- inline ~QDebug() {
- if (!--stream->ref) {
- if (stream->space && stream->buffer.endsWith(QLatin1Char(' ')))
- stream->buffer.chop(1);
- if (stream->message_output) {
- QT_TRY {
- qt_message_output(stream->type,
- stream->context,
- stream->buffer);
- } QT_CATCH(std::bad_alloc&) { /* We're out of memory - give up. */ }
- }
- delete stream;
- }
- }
+ ~QDebug();
inline void swap(QDebug &other) { qSwap(stream, other.stream); }
+ QDebug &resetFormat();
+
inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }
inline QDebug &nospace() { stream->space = false; return *this; }
inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }
@@ -101,7 +102,11 @@ public:
bool autoInsertSpaces() const { return stream->space; }
void setAutoInsertSpaces(bool b) { stream->space = b; }
- inline QDebug &operator<<(QChar t) { stream->ts << '\'' << t << '\''; return maybeSpace(); }
+ inline QDebug &quote() { stream->unsetFlag(Stream::NoQuotes); return *this; }
+ inline QDebug &noquote() { stream->setFlag(Stream::NoQuotes); return *this; }
+ inline QDebug &maybeQuote(char c = '"') { if (!(stream->testFlag(Stream::NoQuotes))) stream->ts << c; return *this; }
+
+ inline QDebug &operator<<(QChar t) { maybeQuote('\''); stream->ts << t; maybeQuote('\''); return maybeSpace(); }
inline QDebug &operator<<(bool t) { stream->ts << (t ? "true" : "false"); return maybeSpace(); }
inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(signed short t) { stream->ts << t; return maybeSpace(); }
@@ -115,10 +120,10 @@ public:
inline QDebug &operator<<(float t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); }
- inline QDebug &operator<<(const QString & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); }
+ inline QDebug &operator<<(const QString & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
inline QDebug &operator<<(const QStringRef & t) { return operator<<(t.toString()); }
- inline QDebug &operator<<(QLatin1String t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); }
- inline QDebug &operator<<(const QByteArray & t) { stream->ts << '\"' << t << '\"'; return maybeSpace(); }
+ inline QDebug &operator<<(QLatin1String t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
+ inline QDebug &operator<<(const QByteArray & t) { maybeQuote(); stream->ts << t; maybeQuote(); return maybeSpace(); }
inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(QTextStreamFunction f) {
stream->ts << f;
@@ -150,6 +155,9 @@ public:
inline QNoDebug &space() { return *this; }
inline QNoDebug &nospace() { return *this; }
inline QNoDebug &maybeSpace() { return *this; }
+ inline QNoDebug &quote() { return *this; }
+ inline QNoDebug &noquote() { return *this; }
+ inline QNoDebug &maybeQuote(const char = '"') { return *this; }
template<typename T>
inline QNoDebug &operator<<(const T &) { return *this; }
@@ -164,13 +172,8 @@ inline QDebug &QDebug::operator=(const QDebug &other)
return *this;
}
-#if defined(FORCE_UREF)
-template <class T>
-inline QDebug &operator<<(QDebug debug, const QList<T> &list)
-#else
template <class T>
inline QDebug operator<<(QDebug debug, const QList<T> &list)
-#endif
{
const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << '(';
@@ -184,13 +187,8 @@ inline QDebug operator<<(QDebug debug, const QList<T> &list)
return debug.maybeSpace();
}
-#if defined(FORCE_UREF)
-template <typename T>
-inline QDebug &operator<<(QDebug debug, const QVector<T> &vec)
-#else
template <typename T>
inline QDebug operator<<(QDebug debug, const QVector<T> &vec)
-#endif
{
const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QVector";
@@ -198,13 +196,8 @@ inline QDebug operator<<(QDebug debug, const QVector<T> &vec)
return operator<<(debug, vec.toList());
}
-#if defined(FORCE_UREF)
-template <class aKey, class aT>
-inline QDebug &operator<<(QDebug debug, const QMap<aKey, aT> &map)
-#else
template <class aKey, class aT>
inline QDebug operator<<(QDebug debug, const QMap<aKey, aT> &map)
-#endif
{
const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QMap(";
@@ -217,13 +210,8 @@ inline QDebug operator<<(QDebug debug, const QMap<aKey, aT> &map)
return debug.maybeSpace();
}
-#if defined(FORCE_UREF)
-template <class aKey, class aT>
-inline QDebug &operator<<(QDebug debug, const QHash<aKey, aT> &hash)
-#else
template <class aKey, class aT>
inline QDebug operator<<(QDebug debug, const QHash<aKey, aT> &hash)
-#endif
{
const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QHash(";
@@ -235,13 +223,8 @@ inline QDebug operator<<(QDebug debug, const QHash<aKey, aT> &hash)
return debug.maybeSpace();
}
-#if defined(FORCE_UREF)
-template <class T1, class T2>
-inline QDebug &operator<<(QDebug debug, const QPair<T1, T2> &pair)
-#else
template <class T1, class T2>
inline QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair)
-#endif
{
const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QPair(" << pair.first << ',' << pair.second << ')';
@@ -258,13 +241,8 @@ inline QDebug operator<<(QDebug debug, const QSet<T> &set)
return operator<<(debug, set.toList());
}
-#if defined(FORCE_UREF)
-template <class T>
-inline QDebug &operator<<(QDebug debug, const QContiguousCache<T> &cache)
-#else
template <class T>
inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache)
-#endif
{
const bool oldSetting = debug.autoInsertSpaces();
debug.nospace() << "QContiguousCache(";
@@ -278,29 +256,24 @@ inline QDebug operator<<(QDebug debug, const QContiguousCache<T> &cache)
return debug.maybeSpace();
}
-#if defined(FORCE_UREF)
-template <class T>
-inline QDebug &operator<<(QDebug debug, const QFlags<T> &flags)
-#else
template <class T>
inline QDebug operator<<(QDebug debug, const QFlags<T> &flags)
-#endif
{
- const bool oldSetting = debug.autoInsertSpaces();
- debug.nospace() << "QFlags(";
+ QDebugStateSaver saver(debug);
+ debug.resetFormat();
+ debug.nospace() << "QFlags(" << hex << showbase;
bool needSeparator = false;
for (uint i = 0; i < sizeof(T) * 8; ++i) {
if (flags.testFlag(T(1 << i))) {
if (needSeparator)
- debug.nospace() << '|';
+ debug << '|';
else
needSeparator = true;
- debug.nospace() << "0x" << QByteArray::number(typename QFlags<T>::Int(1) << i, 16).constData();
+ debug << (typename QFlags<T>::Int(1) << i);
}
}
debug << ')';
- debug.setAutoInsertSpaces(oldSetting);
- return debug.maybeSpace();
+ return debug;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index ec7d89fa87..be15e33fff 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -760,9 +760,13 @@ QString QDir::relativeFilePath(const QString &fileName) const
#endif
QString result;
+#if defined(Q_OS_WIN)
QStringList dirElts = dir.split(QLatin1Char('/'), QString::SkipEmptyParts);
QStringList fileElts = file.split(QLatin1Char('/'), QString::SkipEmptyParts);
-
+#else
+ QVector<QStringRef> dirElts = dir.splitRef(QLatin1Char('/'), QString::SkipEmptyParts);
+ QVector<QStringRef> fileElts = file.splitRef(QLatin1Char('/'), QString::SkipEmptyParts);
+#endif
int i = 0;
while (i < dirElts.size() && i < fileElts.size() &&
#if defined(Q_OS_WIN)
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index f9a79cdca0..bb81877857 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -680,6 +680,13 @@ bool QFileDevice::setPermissions(Permissions permissions)
function.
\value NoOptions No options.
+ \value MapPrivateOption The mapped memory will be private, so any
+ modifications will not be visible to other processes and will not
+ be written to disk. Any such modifications will be lost when the
+ memory is unmapped. It is unspecified whether modifications made
+ to the file made after the mapping is created will be visible through
+ the mapped memory. This flag is not supported on Windows CE.
+ This enum value was introduced in Qt 5.4.
*/
/*!
@@ -689,6 +696,10 @@ bool QFileDevice::setPermissions(Permissions permissions)
or a new file is opened with this object, any maps that have not been
unmapped will automatically be unmapped.
+ The mapping will have the same open mode as the file (read and/or write),
+ except when using MapPrivateOption, in which case it is always possible
+ to write to the mapped memory.
+
Any mapping options can be passed through \a flags.
Returns a pointer to the memory or 0 if there is an error.
diff --git a/src/corelib/io/qfiledevice.h b/src/corelib/io/qfiledevice.h
index fc2779086a..4b13ffe589 100644
--- a/src/corelib/io/qfiledevice.h
+++ b/src/corelib/io/qfiledevice.h
@@ -112,8 +112,10 @@ public:
virtual Permissions permissions() const;
virtual bool setPermissions(Permissions permissionSpec);
+ // ### Qt 6: rename to MemoryMapFlag & make it a QFlags
enum MemoryMapFlags {
- NoOptions = 0
+ NoOptions = 0,
+ MapPrivateOption = 0x0001
};
uchar *map(qint64 offset, qint64 size, MemoryMapFlags flags = NoOptions);
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index 0fa1f02f5c..639310876a 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -51,10 +51,6 @@
#include <QtCore/QLocale>
#include <QtCore/QDebug>
-#ifdef Q_OS_UNIX
-#include <sys/utsname.h>
-#endif
-
QT_BEGIN_NAMESPACE
//Environment variable to allow tooling full control of file selectors
@@ -360,6 +356,7 @@ void QFileSelectorPrivate::updateSelectors()
QStringList QFileSelectorPrivate::platformSelectors()
{
+ // similar, but not identical to QSysInfo::osType
QStringList ret;
#if defined(Q_OS_WIN)
ret << QStringLiteral("windows");
@@ -390,9 +387,7 @@ QStringList QFileSelectorPrivate::platformSelectors()
ret << QStringLiteral("osx");
# endif
# else
- struct utsname u;
- if (uname(&u) != -1)
- ret << QString::fromLatin1(u.sysname).toLower();
+ ret << QSysInfo::kernelType();
# endif
#endif
return ret;
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 1ae182a4c1..de39f0b619 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -179,9 +179,7 @@ QFSFileEngine::~QFSFileEngine()
} while (ret == -1 && errno == EINTR);
}
}
- QList<uchar*> keys = d->maps.keys();
- for (int i = 0; i < keys.count(); ++i)
- unmap(keys.at(i));
+ d->unmapAll();
}
/*!
@@ -463,6 +461,18 @@ qint64 QFSFileEngine::size() const
return d->nativeSize();
}
+/*!
+ \internal
+*/
+void QFSFileEnginePrivate::unmapAll()
+{
+ if (!maps.isEmpty()) {
+ const QList<uchar*> keys = maps.keys(); // Make a copy since unmap() modifies the map.
+ for (int i = 0; i < keys.count(); ++i)
+ unmap(keys.at(i));
+ }
+}
+
#ifndef Q_OS_WIN
/*!
\internal
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index 21f38fea1d..b0610b1459 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -175,6 +175,7 @@ public:
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
+ void unmapAll();
mutable QFileSystemMetaData metaData;
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index 064a1a511f..f9c6c8ab98 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -713,6 +713,12 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
if (openMode & QIODevice::ReadOnly) access |= PROT_READ;
if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE;
+ int sharemode = MAP_SHARED;
+ if (flags & QFileDevice::MapPrivateOption) {
+ sharemode = MAP_PRIVATE;
+ access |= PROT_WRITE;
+ }
+
#if defined(Q_OS_INTEGRITY)
int pageSize = sysconf(_SC_PAGESIZE);
#else
@@ -730,7 +736,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
realOffset &= ~(QT_OFF_T(pageSize - 1));
void *mapAddress = QT_MMAP((void*)0, realSize,
- access, MAP_SHARED, nativeHandle(), realOffset);
+ access, sharemode, nativeHandle(), realOffset);
if (MAP_FAILED != mapAddress) {
uchar *address = extra + static_cast<uchar*>(mapAddress);
maps[address] = QPair<int,size_t>(extra, realSize);
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index fb4107b95d..cebca1a56f 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -369,15 +369,15 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
if (fileHandle == INVALID_HANDLE_VALUE)
return -1;
- DWORD bytesToRead = DWORD(maxlen); // <- lossy
+ qint64 bytesToRead = maxlen;
// Reading on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
// the chunks are too large, so we limit the block size to 32MB.
- static const DWORD maxBlockSize = 32 * 1024 * 1024;
+ static const qint64 maxBlockSize = 32 * 1024 * 1024;
qint64 totalRead = 0;
do {
- DWORD blockSize = qMin<DWORD>(bytesToRead, maxBlockSize);
+ DWORD blockSize = DWORD(qMin(bytesToRead, maxBlockSize));
DWORD bytesRead;
if (!ReadFile(fileHandle, data + totalRead, blockSize, &bytesRead, NULL)) {
if (totalRead == 0) {
@@ -392,7 +392,7 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 maxlen)
totalRead += bytesRead;
bytesToRead -= bytesRead;
} while (totalRead < maxlen);
- return qint64(totalRead);
+ return totalRead;
}
/*
@@ -965,6 +965,21 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
return 0;
}
+ // check/setup args to map
+ DWORD access = 0;
+ if (flags & QFileDevice::MapPrivateOption) {
+#ifdef FILE_MAP_COPY
+ access = FILE_MAP_COPY;
+#else
+ q->setError(QFile::UnspecifiedError, "MapPrivateOption unsupported");
+ return 0;
+#endif
+ } else if (openMode & QIODevice::WriteOnly) {
+ access = FILE_MAP_WRITE;
+ } else if (openMode & QIODevice::ReadOnly) {
+ access = FILE_MAP_READ;
+ }
+
if (mapHandle == NULL) {
// get handle to the file
HANDLE handle = fileHandle;
@@ -1011,11 +1026,6 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size,
}
}
- // setup args to map
- DWORD access = 0;
- if (openMode & QIODevice::ReadOnly) access = FILE_MAP_READ;
- if (openMode & QIODevice::WriteOnly) access = FILE_MAP_WRITE;
-
DWORD offsetHi = offset >> 32;
DWORD offsetLo = offset & Q_UINT64_C(0xffffffff);
SYSTEM_INFO sysinfo;
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 7b0557a497..06f7fb17cd 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -832,7 +832,7 @@ qint64 QIODevice::read(char *data, qint64 maxSize)
// In buffered mode, we try to fill up the QIODevice buffer before
// we do anything else.
// buffer is empty at this point, try to fill it
- int bytesToBuffer = QIODEVICE_BUFFERSIZE;
+ const int bytesToBuffer = QIODEVICE_BUFFERSIZE;
char *writePointer = d->buffer.reserve(bytesToBuffer);
// Make sure the device is positioned correctly.
@@ -1013,6 +1013,8 @@ QByteArray QIODevice::readAll()
// flush internal read buffer
if (!(d->openMode & Text) && !d->buffer.isEmpty()) {
+ if (d->buffer.size() >= INT_MAX)
+ return QByteArray();
result = d->buffer.readAll();
readBytes = result.size();
d->pos += readBytes;
@@ -1031,6 +1033,8 @@ QByteArray QIODevice::readAll()
} else {
// Read it all in one go.
// If resize fails, don't read anything.
+ if (readBytes + theSize - d->pos > INT_MAX)
+ return QByteArray();
result.resize(int(readBytes + theSize - d->pos));
readBytes += read(result.data() + readBytes, result.size() - readBytes);
}
diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h
index faf64e2cf1..132ab1cad2 100644
--- a/src/corelib/io/qiodevice_p.h
+++ b/src/corelib/io/qiodevice_p.h
@@ -84,13 +84,13 @@ public:
first = buf;
capacity = 0;
}
- int size() const {
+ qint64 size() const {
return len;
}
bool isEmpty() const {
return len == 0;
}
- void skip(int n) {
+ void skip(qint64 n) {
if (n >= len) {
clear();
} else {
@@ -106,14 +106,14 @@ public:
first++;
return ch;
}
- int read(char* target, int size) {
+ int read(char* target, qint64 size) {
int r = qMin(size, len);
memcpy(target, first, r);
len -= r;
first += r;
return r;
}
- int peek(char* target, int size) {
+ int peek(char* target, qint64 size) {
int r = qMin(size, len);
memcpy(target, first, r);
return r;
@@ -124,7 +124,7 @@ public:
len += size;
return writePtr;
}
- void chop(int size) {
+ void chop(qint64 size) {
if (size >= len) {
clear();
} else {
@@ -136,7 +136,7 @@ public:
clear();
return retVal;
}
- int readLine(char* target, int size) {
+ int readLine(char* target, qint64 size) {
int r = qMin(size, len);
char* eol = static_cast<char*>(memchr(first, '\n', r));
if (eol)
@@ -158,7 +158,7 @@ public:
len++;
*first = c;
}
- void ungetBlock(const char* block, int size) {
+ void ungetBlock(const char* block, qint64 size) {
if ((first - buf) < size) {
// underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer
makeSpace(len + size, freeSpaceAtStart);
@@ -191,7 +191,7 @@ private:
private:
// length of the unread data
- int len;
+ qint64 len;
// start of the unread data
char* first;
// the allocated buffer
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index d1ef9c1770..cd4cf3a50d 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -206,7 +206,10 @@ void QLockFile::unlock()
return;
close(d->fileHandle);
d->fileHandle = -1;
- QFile::remove(d->fileName);
+ if (!QFile::remove(d->fileName)) {
+ qWarning() << "Could not remove our own lock file" << d->fileName << "maybe permissions changed meanwhile?";
+ // This is bad because other users of this lock file will now have to wait for the stale-lock-timeout...
+ }
d->lockError = QLockFile::NoError;
d->isLocked = false;
}
diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp
index 28f6b02a64..5f82270706 100644
--- a/src/corelib/io/qlockfile_win.cpp
+++ b/src/corelib/io/qlockfile_win.cpp
@@ -47,9 +47,15 @@
#include "QtCore/qfileinfo.h"
#include "QtCore/qdatetime.h"
#include "QtCore/qdebug.h"
+#include "QtCore/qthread.h"
QT_BEGIN_NAMESPACE
+static inline QByteArray localHostName()
+{
+ return qgetenv("COMPUTERNAME");
+}
+
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
const QFileSystemEntry fileEntry(fileName);
@@ -98,7 +104,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys()
fileData += '\n';
fileData += qAppName().toUtf8();
fileData += '\n';
- //fileData += localHostname(); // gethostname requires winsock init, see QHostInfo...
+ fileData += localHostName();
fileData += '\n';
DWORD bytesWritten = 0;
QLockFile::LockError error = QLockFile::NoError;
@@ -123,14 +129,16 @@ bool QLockFilePrivate::isApparentlyStale() const
// On WinRT there seems to be no way of obtaining information about other
// processes due to sandboxing
#ifndef Q_OS_WINRT
- HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
- if (!procHandle)
- return true;
- // We got a handle but check if process is still alive
- DWORD dwR = ::WaitForSingleObject(procHandle, 0);
- ::CloseHandle(procHandle);
- if (dwR == WAIT_TIMEOUT)
- return true;
+ if (hostname == QString::fromLocal8Bit(localHostName())) {
+ HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+ if (!procHandle)
+ return true;
+ // We got a handle but check if process is still alive
+ DWORD dwR = ::WaitForSingleObject(procHandle, 0);
+ ::CloseHandle(procHandle);
+ if (dwR == WAIT_TIMEOUT)
+ return true;
+ }
#endif // !Q_OS_WINRT
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
return staleLockTime > 0 && age > staleLockTime;
@@ -142,7 +150,16 @@ void QLockFile::unlock()
if (!d->isLocked)
return;
CloseHandle(d->fileHandle);
- QFile::remove(d->fileName);
+ int attempts = 0;
+ static const int maxAttempts = 500; // 500ms
+ while (!QFile::remove(d->fileName) && ++attempts < maxAttempts) {
+ // Someone is reading the lock file right now (on Windows this prevents deleting it).
+ QThread::msleep(1);
+ }
+ if (attempts == maxAttempts) {
+ qWarning() << "Could not remove our own lock file" << d->fileName << ". Either other users of the lock file are reading it constantly for 500 ms, or we (no longer) have permissions to delete the file";
+ // This is bad because other users of this lock file will now have to wait for the stale-lock-timeout...
+ }
d->lockError = QLockFile::NoError;
d->isLocked = false;
}
diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp
index 07245ddea2..a368e92932 100644
--- a/src/corelib/io/qloggingcategory.cpp
+++ b/src/corelib/io/qloggingcategory.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -40,7 +40,6 @@
****************************************************************************/
#include "qloggingcategory.h"
-#include "qloggingcategory_p.h"
#include "qloggingregistry_p.h"
QT_BEGIN_NAMESPACE
@@ -82,7 +81,7 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
\section1 Creating category objects
- The Q_LOGGING_CATEGORY() and the Q_DECLARE_LOGGING_CATEGORY() macros
+ The Q_DECLARE_LOGGING_CATEGORY() and Q_LOGGING_CATEGORY() macros
conveniently declare and create QLoggingCategory objects:
\snippet qloggingcategory/main.cpp 1
@@ -101,13 +100,21 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
\section1 Default category configuration
- In the default configuration \l isWarningEnabled() , \l isDebugEnabled() and
- \l isCriticalEnabled() will return \c true.
+ Both the QLoggingCategory constructor and the Q_LOGGING_CATEGORY() macro
+ accept an optional QtMsgType argument, which disables all message types with
+ a lower severity. That is, a category declared with
+
+ \snippet qloggingcategory/main.cpp 5
+
+ will log messages of type \c QtWarningMsg, \c QtCriticalMsg, \c QtFatalMsg, but will
+ ignore messages of type \c QtDebugMsg.
+
+ If no argument is passed, all messages will be logged.
\section1 Configuring Categories
- Categories can be centrally configured by either setting logging rules,
- or by installing a custom filter.
+ The default configuration of categories can be overridden either by setting logging
+ rules, or by installing a custom filter.
\section2 Logging Rules
@@ -131,7 +138,13 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
are automatically loaded from the \c [Rules] section of a logging
configuration file. Such configuration files are looked up in the QtProject
configuration directory, or explicitly set in a \c QT_LOGGING_CONF
- environment variable.
+ environment variable:
+
+ \code
+ [Rules]
+ *.debug=false
+ driver.usb.debug=true
+ \endcode
Rules set by \l setFilterRules() take precedence over rules specified
in the QtProject configuration directory, and can, in turn, be
@@ -177,7 +190,7 @@ static void setBoolLane(QBasicAtomicInt *atomic, bool enable, int shift)
/*!
Constructs a QLoggingCategory object with the provided \a category name.
- The object becomes the local identifier for the category.
+ All message types for this category are enabled by default.
If \a category is \c{0}, the category name is changed to \c "default".
*/
@@ -185,23 +198,35 @@ QLoggingCategory::QLoggingCategory(const char *category)
: d(0),
name(0)
{
- Q_UNUSED(d);
- Q_UNUSED(placeholder);
- enabled.store(0x01010101); // enabledDebug = enabledWarning = enabledCritical = true;
+ init(category, QtDebugMsg);
+}
- const bool isDefaultCategory
- = (category == 0) || (strcmp(category, qtDefaultCategoryName) == 0);
+/*!
+ Constructs a QLoggingCategory object with the provided \a category name,
+ and enables all messages with types more severe or equal than \a enableForLevel.
- // normalize "default" category name, so that we can just do
- // pointer comparison in QLoggingRegistry::updateCategory
- if (isDefaultCategory) {
- name = qtDefaultCategoryName;
- } else {
+ If \a category is \c{0}, the category name is changed to \c "default".
+
+ \since 5.4
+*/
+QLoggingCategory::QLoggingCategory(const char *category, QtMsgType enableForLevel)
+ : d(0),
+ name(0)
+{
+ init(category, enableForLevel);
+}
+
+void QLoggingCategory::init(const char *category, QtMsgType severityLevel)
+{
+ enabled.store(0x01010101); // enabledDebug = enabledWarning = enabledCritical = true;
+
+ if (category)
name = category;
- }
+ else
+ name = qtDefaultCategoryName;
if (QLoggingRegistry *reg = QLoggingRegistry::instance())
- reg->registerCategory(this);
+ reg->registerCategory(this, severityLevel);
}
/*!
@@ -501,6 +526,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
*/
/*!
\macro Q_DECLARE_LOGGING_CATEGORY(name)
+ \sa Q_LOGGING_CATEGORY()
\relates QLoggingCategory
\since 5.2
@@ -512,11 +538,12 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*!
\macro Q_LOGGING_CATEGORY(name, string)
+ \sa Q_DECLARE_LOGGING_CATEGORY()
\relates QLoggingCategory
\since 5.2
Defines a logging category \a name, and makes it configurable under the
- \a string identifier.
+ \a string identifier. By default, all message types are enabled.
Only one translation unit in a library or executable can define a category
with a specific name.
@@ -524,4 +551,21 @@ void QLoggingCategory::setFilterRules(const QString &rules)
This macro must be used outside of a class or method.
*/
+/*!
+ \macro Q_LOGGING_CATEGORY(name, string, msgType)
+ \sa Q_DECLARE_LOGGING_CATEGORY()
+ \relates QLoggingCategory
+ \since 5.4
+
+ Defines a logging category \a name, and makes it configurable under the
+ \a string identifier. By default, messages of QtMsgType \a msgType
+ and more severe are enabled, types with a lower severity are disabled.
+
+ Only one translation unit in a library or executable can define a category
+ with a specific name.
+
+ This macro must be used outside of a class or method. It is only defined
+ if variadic macros are supported.
+*/
+
QT_END_NAMESPACE
diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h
index 573af2105c..cca2031108 100644
--- a/src/corelib/io/qloggingcategory.h
+++ b/src/corelib/io/qloggingcategory.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -51,7 +51,9 @@ class Q_CORE_EXPORT QLoggingCategory
{
Q_DISABLE_COPY(QLoggingCategory)
public:
+ // ### Qt 6: Merge constructors
explicit QLoggingCategory(const char *category);
+ QLoggingCategory(const char *category, QtMsgType severityLevel);
~QLoggingCategory();
bool isEnabled(QtMsgType type) const;
@@ -80,7 +82,9 @@ public:
static void setFilterRules(const QString &rules);
private:
- void *d; // reserved for future use
+ void init(const char *category, QtMsgType severityLevel);
+
+ Q_DECL_UNUSED_MEMBER void *d; // reserved for future use
const char *name;
#ifdef Q_BIG_ENDIAN
@@ -100,22 +104,20 @@ private:
AtomicBools bools;
QBasicAtomicInt enabled;
};
- bool placeholder[4]; // reserve for future use
+ Q_DECL_UNUSED_MEMBER bool placeholder[4]; // reserved for future use
};
#define Q_DECLARE_LOGGING_CATEGORY(name) \
extern const QLoggingCategory &name();
-// relies on QLoggingCategory(QString) being thread safe!
-#define Q_LOGGING_CATEGORY(name, string) \
+#if defined(Q_COMPILER_VARIADIC_MACROS) || defined(Q_MOC_RUN)
+
+#define Q_LOGGING_CATEGORY(name, ...) \
const QLoggingCategory &name() \
{ \
- static const QLoggingCategory category(string); \
+ static const QLoggingCategory category(__VA_ARGS__); \
return category; \
}
-
-#ifdef Q_COMPILER_VARIADIC_MACROS
-
#define qCDebug(category, ...) \
for (bool qt_category_enabled = category().isDebugEnabled(); qt_category_enabled; qt_category_enabled = false) \
QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).debug(__VA_ARGS__)
@@ -126,14 +128,22 @@ private:
for (bool qt_category_enabled = category().isCriticalEnabled(); qt_category_enabled; qt_category_enabled = false) \
QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO, category().categoryName()).critical(__VA_ARGS__)
-#else
+#else // defined(Q_COMPILER_VARIADIC_MACROS) || defined(Q_MOC_RUN)
+
+// Optional msgType argument not supported
+#define Q_LOGGING_CATEGORY(name, string) \
+ const QLoggingCategory &name() \
+ { \
+ static const QLoggingCategory category(string); \
+ return category; \
+ }
// check for enabled category inside QMessageLogger.
#define qCDebug qDebug
#define qCWarning qWarning
#define qCCritical qCritical
-#endif // Q_COMPILER_VARIADIC_MACROS
+#endif // Q_COMPILER_VARIADIC_MACROS || defined(Q_MOC_RUN)
#if defined(QT_NO_DEBUG_OUTPUT)
# undef qCDebug
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index 575150f148..3ce0a571b4 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -40,7 +40,6 @@
****************************************************************************/
#include "qloggingregistry_p.h"
-#include "qloggingcategory_p.h"
#include <QtCore/qfile.h>
#include <QtCore/qstandardpaths.h>
@@ -131,15 +130,15 @@ void QLoggingRule::parse(const QStringRef &pattern)
// strip trailing ".messagetype"
if (pattern.endsWith(QLatin1String(".debug"))) {
p = QStringRef(pattern.string(), pattern.position(),
- pattern.length() - strlen(".debug"));
+ pattern.length() - 6); // strlen(".debug")
messageType = QtDebugMsg;
} else if (pattern.endsWith(QLatin1String(".warning"))) {
p = QStringRef(pattern.string(), pattern.position(),
- pattern.length() - strlen(".warning"));
+ pattern.length() - 8); // strlen(".warning")
messageType = QtWarningMsg;
} else if (pattern.endsWith(QLatin1String(".critical"))) {
p = QStringRef(pattern.string(), pattern.position(),
- pattern.length() - strlen(".critical"));
+ pattern.length() - 9); // strlen(".critical")
messageType = QtCriticalMsg;
} else {
p = pattern;
@@ -261,12 +260,12 @@ void QLoggingRegistry::init()
if (!rulesFilePath.isEmpty()) {
QFile file(QFile::decodeName(rulesFilePath));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream stream(&file);
- QLoggingSettingsParser parser;
- parser.setContent(stream);
if (qtLoggingDebug())
debugMsg("Loading \"%s\" ...",
QDir::toNativeSeparators(file.fileName()).toUtf8().constData());
+ QTextStream stream(&file);
+ QLoggingSettingsParser parser;
+ parser.setContent(stream);
envRules = parser.rules();
}
}
@@ -285,12 +284,12 @@ void QLoggingRegistry::init()
if (!envPath.isEmpty()) {
QFile file(envPath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream stream(&file);
- QLoggingSettingsParser parser;
- parser.setContent(stream);
if (qtLoggingDebug())
debugMsg("Loading \"%s\" ...",
QDir::toNativeSeparators(envPath).toUtf8().constData());
+ QTextStream stream(&file);
+ QLoggingSettingsParser parser;
+ parser.setContent(stream);
configRules = parser.rules();
}
}
@@ -307,12 +306,12 @@ void QLoggingRegistry::init()
This method might be called concurrently for the same category object.
*/
-void QLoggingRegistry::registerCategory(QLoggingCategory *cat)
+void QLoggingRegistry::registerCategory(QLoggingCategory *cat, QtMsgType enableForLevel)
{
QMutexLocker locker(&registryMutex);
if (!categories.contains(cat)) {
- categories.append(cat);
+ categories.insert(cat, enableForLevel);
(*categoryFilter)(cat);
}
}
@@ -324,8 +323,7 @@ void QLoggingRegistry::registerCategory(QLoggingCategory *cat)
void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
{
QMutexLocker locker(&registryMutex);
-
- categories.removeOne(cat);
+ categories.remove(cat);
}
/*!
@@ -341,7 +339,7 @@ void QLoggingRegistry::setApiRules(const QString &content)
QMutexLocker locker(&registryMutex);
if (qtLoggingDebug())
- debugMsg("Loading logging rules set by Qt API ...");
+ debugMsg("Loading logging rules set by QLoggingCategory::setFilterRules ...");
apiRules = parser.rules();
@@ -361,7 +359,7 @@ void QLoggingRegistry::updateRules()
rules = configRules + apiRules + envRules;
- foreach (QLoggingCategory *cat, categories)
+ foreach (QLoggingCategory *cat, categories.keys())
(*categoryFilter)(cat);
}
@@ -380,7 +378,7 @@ QLoggingRegistry::installFilter(QLoggingCategory::CategoryFilter filter)
QLoggingCategory::CategoryFilter old = categoryFilter;
categoryFilter = filter;
- foreach (QLoggingCategory *cat, categories)
+ foreach (QLoggingCategory *cat, categories.keys())
(*categoryFilter)(cat);
return old;
@@ -397,18 +395,22 @@ QLoggingRegistry *QLoggingRegistry::instance()
*/
void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
{
- // QLoggingCategory() normalizes "default" strings
- // to qtDefaultCategoryName
- bool debug = true;
+ QLoggingRegistry *reg = QLoggingRegistry::instance();
+ Q_ASSERT(reg->categories.contains(cat));
+ QtMsgType enableForLevel = reg->categories.value(cat);
+
+ bool debug = (enableForLevel == QtDebugMsg) ? true : false;
+ bool warning = (enableForLevel <= QtWarningMsg) ? true : false;
+ bool critical = (enableForLevel <= QtCriticalMsg) ? true : false;
+
+ // hard-wired implementation of
+ // qt.*.debug=false
+ // qt.debug=false
char c;
if (!memcmp(cat->categoryName(), "qt", 2) && (!(c = cat->categoryName()[2]) || c == '.'))
debug = false;
- bool warning = true;
- bool critical = true;
-
QString categoryName = QLatin1String(cat->categoryName());
- QLoggingRegistry *reg = QLoggingRegistry::instance();
foreach (const QLoggingRule &item, reg->rules) {
int filterpass = item.pass(categoryName, QtDebugMsg);
if (filterpass != 0)
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index 48804cfc2b..ce2503b32c 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -113,7 +113,7 @@ public:
void init();
- void registerCategory(QLoggingCategory *category);
+ void registerCategory(QLoggingCategory *category, QtMsgType enableForLevel);
void unregisterCategory(QLoggingCategory *category);
void setApiRules(const QString &content);
@@ -134,7 +134,7 @@ private:
QVector<QLoggingRule> envRules;
QVector<QLoggingRule> apiRules;
QVector<QLoggingRule> rules;
- QList<QLoggingCategory*> categories;
+ QHash<QLoggingCategory*,QtMsgType> categories;
QLoggingCategory::CategoryFilter categoryFilter;
friend class ::tst_QLoggingRegistry;
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
index b1e4dd7584..4c5fb38c67 100644
--- a/src/corelib/io/qnoncontiguousbytedevice.cpp
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
@@ -506,6 +506,25 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QIODevice *dev
}
/*!
+ Create a QNonContiguousByteDevice out of a QIODevice, return it in a QSharedPointer.
+ For QFile, QBuffer and all other QIODevice, sequential or not.
+
+ \internal
+*/
+QSharedPointer<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(QIODevice *device)
+{
+ // shortcut if it is a QBuffer
+ if (QBuffer *buffer = qobject_cast<QBuffer*>(device))
+ return QSharedPointer<QNonContiguousByteDeviceBufferImpl>::create(buffer);
+
+ // ### FIXME special case if device is a QFile that supports map()
+ // then we can actually deal with the file without using read/peek
+
+ // generic QIODevice
+ return QSharedPointer<QNonContiguousByteDeviceIoDeviceImpl>::create(device); // FIXME
+}
+
+/*!
\fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QSharedPointer<QRingBuffer> ringBuffer)
Create a QNonContiguousByteDevice out of a QRingBuffer.
@@ -518,6 +537,16 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QSharedPointer
}
/*!
+ Create a QNonContiguousByteDevice out of a QRingBuffer, return it in a QSharedPointer.
+
+ \internal
+*/
+QSharedPointer<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(QSharedPointer<QRingBuffer> ringBuffer)
+{
+ return QSharedPointer<QNonContiguousByteDeviceRingBufferImpl>::create(qMove(ringBuffer));
+}
+
+/*!
\fn static QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *byteArray)
Create a QNonContiguousByteDevice out of a QByteArray.
@@ -530,6 +559,16 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *by
}
/*!
+ Create a QNonContiguousByteDevice out of a QByteArray.
+
+ \internal
+*/
+QSharedPointer<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(QByteArray *byteArray)
+{
+ return QSharedPointer<QNonContiguousByteDeviceByteArrayImpl>::create(byteArray);
+}
+
+/*!
\fn static QIODevice* QNonContiguousByteDeviceFactory::wrap(QNonContiguousByteDevice* byteDevice)
Wrap the \a byteDevice (possibly again) into a QIODevice.
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
index 4606ac2686..1e746db80f 100644
--- a/src/corelib/io/qnoncontiguousbytedevice_p.h
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
@@ -90,8 +90,14 @@ class Q_CORE_EXPORT QNonContiguousByteDeviceFactory
{
public:
static QNonContiguousByteDevice* create(QIODevice *device);
+ static QSharedPointer<QNonContiguousByteDevice> createShared(QIODevice *device);
+
static QNonContiguousByteDevice* create(QByteArray *byteArray);
+ static QSharedPointer<QNonContiguousByteDevice> createShared(QByteArray *byteArray);
+
static QNonContiguousByteDevice* create(QSharedPointer<QRingBuffer> ringBuffer);
+ static QSharedPointer<QNonContiguousByteDevice> createShared(QSharedPointer<QRingBuffer> ringBuffer);
+
static QIODevice* wrap(QNonContiguousByteDevice* byteDevice);
};
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index 2b901c7ccd..8be4125ef5 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -205,14 +205,32 @@ bool QSaveFile::open(OpenMode mode)
d->writeError = QFileDevice::WriteError;
return false;
}
- d->fileEngine = new QTemporaryFileEngine(d->fileName);
+
+ if (existingFile.isDir()) {
+ d->setError(QFileDevice::WriteError, QSaveFile::tr("Filename refers to a directory"));
+ d->writeError = QFileDevice::WriteError;
+ return false;
+ }
+
+ // Resolve symlinks. Don't use QFileInfo::canonicalFilePath so it still give the expected
+ // target even if the file does not exist
+ d->finalFileName = d->fileName;
+ if (existingFile.isSymLink()) {
+ int maxDepth = 128;
+ while (--maxDepth && existingFile.isSymLink())
+ existingFile.setFile(existingFile.symLinkTarget());
+ if (maxDepth > 0)
+ d->finalFileName = existingFile.filePath();
+ }
+
+ d->fileEngine = new QTemporaryFileEngine(d->finalFileName);
// Same as in QFile: QIODevice provides the buffering, so there's no need to request it from the file engine.
if (!d->fileEngine->open(mode | QIODevice::Unbuffered)) {
QFileDevice::FileError err = d->fileEngine->error();
#ifdef Q_OS_UNIX
if (d->directWriteFallback && err == QFileDevice::OpenError && errno == EACCES) {
delete d->fileEngine;
- d->fileEngine = QAbstractFileEngine::create(d->fileName);
+ d->fileEngine = QAbstractFileEngine::create(d->finalFileName);
if (d->fileEngine->open(mode | QIODevice::Unbuffered)) {
d->useTemporaryFile = false;
QFileDevice::open(mode);
@@ -285,7 +303,7 @@ bool QSaveFile::commit()
// atomically replace old file with new file
// Can't use QFile::rename for that, must use the file engine directly
Q_ASSERT(d->fileEngine);
- if (!d->fileEngine->renameOverwrite(d->fileName)) {
+ if (!d->fileEngine->renameOverwrite(d->finalFileName)) {
d->setError(d->fileEngine->error(), d->fileEngine->errorString());
d->fileEngine->remove();
delete d->fileEngine;
diff --git a/src/corelib/io/qsavefile_p.h b/src/corelib/io/qsavefile_p.h
index b9efd1ee7c..2134c4c9bc 100644
--- a/src/corelib/io/qsavefile_p.h
+++ b/src/corelib/io/qsavefile_p.h
@@ -70,6 +70,7 @@ protected:
~QSaveFilePrivate();
QString fileName;
+ QString finalFileName; // fileName with symbolic links resolved
QFileDevice::FileError writeError;
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 1748170324..7a2e1909b2 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -53,6 +53,8 @@
#include "qmutex.h"
#include "qlibraryinfo.h"
#include "qtemporaryfile.h"
+#include "qstandardpaths.h"
+#include <qdatastream.h>
#ifndef QT_NO_TEXTCODEC
# include "qtextcodec.h"
@@ -68,6 +70,11 @@
#include "qcoreapplication.h"
#endif
+#ifndef QT_BOOTSTRAPPED
+#include "qsavefile.h"
+#include "qlockfile.h"
+#endif
+
#ifdef Q_OS_VXWORKS
# include <ioLib.h>
#endif
@@ -101,12 +108,6 @@ using namespace ABI::Windows::Storage;
#define CSIDL_APPDATA 0x001a // <username>\Application Data
#endif
-#ifdef Q_AUTOTEST_EXPORT
-# define Q_AUTOTEST_EXPORT_HELPER Q_AUTOTEST_EXPORT
-#else
-# define Q_AUTOTEST_EXPORT_HELPER static
-#endif
-
// ************************************************************************
// QConfFile
@@ -141,101 +142,6 @@ static QBasicMutex settingsGlobalMutex;
static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
-#ifndef Q_OS_WIN
-inline bool qt_isEvilFsTypeName(const char *name)
-{
- return (qstrncmp(name, "nfs", 3) == 0
- || qstrncmp(name, "autofs", 6) == 0
- || qstrncmp(name, "cachefs", 7) == 0);
-}
-
-#if defined(Q_OS_BSD4) && !defined(Q_OS_NETBSD)
-QT_BEGIN_INCLUDE_NAMESPACE
-# include <sys/param.h>
-# include <sys/mount.h>
-QT_END_INCLUDE_NAMESPACE
-
-Q_AUTOTEST_EXPORT_HELPER bool qIsLikelyToBeNfs(int handle)
-{
- struct statfs buf;
- if (fstatfs(handle, &buf) != 0)
- return false;
- return qt_isEvilFsTypeName(buf.f_fstypename);
-}
-
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
-QT_BEGIN_INCLUDE_NAMESPACE
-# include <sys/vfs.h>
-# ifdef QT_LINUXBASE
- // LSB 3.2 has fstatfs in sys/statfs.h, sys/vfs.h is just an empty dummy header
-# include <sys/statfs.h>
-# endif
-QT_END_INCLUDE_NAMESPACE
-# ifndef NFS_SUPER_MAGIC
-# define NFS_SUPER_MAGIC 0x00006969
-# endif
-# ifndef AUTOFS_SUPER_MAGIC
-# define AUTOFS_SUPER_MAGIC 0x00000187
-# endif
-# ifndef AUTOFSNG_SUPER_MAGIC
-# define AUTOFSNG_SUPER_MAGIC 0x7d92b1a0
-# endif
-
-Q_AUTOTEST_EXPORT_HELPER bool qIsLikelyToBeNfs(int handle)
-{
- struct statfs buf;
- if (fstatfs(handle, &buf) != 0)
- return false;
- return buf.f_type == NFS_SUPER_MAGIC
- || buf.f_type == AUTOFS_SUPER_MAGIC
- || buf.f_type == AUTOFSNG_SUPER_MAGIC;
-}
-
-#elif defined(Q_OS_SOLARIS) || defined(Q_OS_IRIX) || defined(Q_OS_AIX) || defined(Q_OS_HPUX) \
- || defined(Q_OS_OSF) || defined(Q_OS_QNX) || defined(Q_OS_SCO) \
- || defined(Q_OS_UNIXWARE) || defined(Q_OS_RELIANT) || defined(Q_OS_NETBSD)
-QT_BEGIN_INCLUDE_NAMESPACE
-# include <sys/statvfs.h>
-QT_END_INCLUDE_NAMESPACE
-
-Q_AUTOTEST_EXPORT_HELPER bool qIsLikelyToBeNfs(int handle)
-{
- struct statvfs buf;
- if (fstatvfs(handle, &buf) != 0)
- return false;
-#if defined(Q_OS_NETBSD)
- return qt_isEvilFsTypeName(buf.f_fstypename);
-#else
- return qt_isEvilFsTypeName(buf.f_basetype);
-#endif
-}
-#else
-Q_AUTOTEST_EXPORT_HELPER inline bool qIsLikelyToBeNfs(int /* handle */)
-{
- return true;
-}
-#endif
-
-static bool unixLock(int handle, int lockType)
-{
- /*
- NFS hangs on the fcntl() call below when statd or lockd isn't
- running. There's no way to detect this. Our work-around for
- now is to disable locking when we detect NFS (or AutoFS or
- CacheFS, which are probably wrapping NFS).
- */
- if (qIsLikelyToBeNfs(handle))
- return false;
-
- struct flock fl;
- fl.l_whence = SEEK_SET;
- fl.l_start = 0;
- fl.l_len = 0;
- fl.l_type = lockType;
- return fcntl(handle, F_SETLKW, &fl) == 0;
-}
-#endif
-
QConfFile::QConfFile(const QString &fileName, bool _userPerms)
: name(fileName), size(0), ref(1), userPerms(_userPerms)
{
@@ -376,9 +282,9 @@ after_loop:
return result;
}
-// see also qsettings_win.cpp and qsettings_mac.cpp
+// see also qsettings_win.cpp, qsettings_winrt.cpp and qsettings_mac.cpp
-#if defined(Q_OS_WINRT) || (!defined(Q_OS_WIN) && !defined(Q_OS_MAC))
+#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
{
@@ -386,7 +292,7 @@ QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::
}
#endif
-#if defined(Q_OS_WINRT) || !defined(Q_OS_WIN)
+#if !defined(Q_OS_WIN)
QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
{
return new QConfFileSettingsPrivate(fileName, format);
@@ -1140,6 +1046,8 @@ static void initDefaultPaths(QMutexLocker *locker)
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
windowsConfigPath(CSIDL_COMMON_APPDATA) + QDir::separator());
#else
+
+#ifdef QT_NO_STANDARDPATHS
QString userPath;
char *env = getenv("XDG_CONFIG_HOME");
if (env == 0) {
@@ -1153,6 +1061,9 @@ static void initDefaultPaths(QMutexLocker *locker)
userPath += QLatin1Char('/');
userPath += QFile::decodeName(env);
}
+#else
+ QString userPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
+#endif
userPath += QLatin1Char('/');
pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), userPath);
@@ -1457,105 +1368,30 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
return;
}
+#ifndef QT_BOOTSTRAPPED
/*
- Open the configuration file and try to use it using a named
- semaphore on Windows and an advisory lock on Unix-based
- systems. This protect us against other QSettings instances
- trying to access the same file from other threads or
- processes.
-
- As it stands now, the locking mechanism doesn't work for
- .plist files.
- */
- QFile file(confFile->name);
- bool createFile = !file.exists();
- if (!readOnly && confFile->isWritable())
- file.open(QFile::ReadWrite);
- if (!file.isOpen())
- file.open(QFile::ReadOnly);
-
- if (!createFile && !file.isOpen())
- setStatus(QSettings::AccessError);
-
-#ifdef Q_OS_WIN
- HANDLE readSemaphore = 0;
- HANDLE writeSemaphore = 0;
- static const int FileLockSemMax = 50;
- int numReadLocks = readOnly ? 1 : FileLockSemMax;
-
- if (file.isOpen()) {
- // Acquire the write lock if we will be writing
- if (!readOnly) {
- QString writeSemName = QLatin1String("QSettingsWriteSem ");
- writeSemName.append(file.fileName());
-
-#ifndef Q_OS_WINRT
- writeSemaphore = CreateSemaphore(0, 1, 1, reinterpret_cast<const wchar_t *>(writeSemName.utf16()));
-#else
- writeSemaphore = CreateSemaphoreEx(0, 1, 1, reinterpret_cast<const wchar_t *>(writeSemName.utf16()), 0, SEMAPHORE_ALL_ACCESS);
-#endif
-
- if (writeSemaphore) {
-#ifndef Q_OS_WINRT
- WaitForSingleObject(writeSemaphore, INFINITE);
-#else
- WaitForSingleObjectEx(writeSemaphore, INFINITE, FALSE);
-#endif
- } else {
- setStatus(QSettings::AccessError);
- return;
- }
- }
-
- // Acquire all the read locks if we will be writing, to make sure nobody
- // reads while we're writing. If we are only reading, acquire a single
- // read lock.
- QString readSemName(QLatin1String("QSettingsReadSem "));
- readSemName.append(file.fileName());
-
-#ifndef Q_OS_WINRT
- readSemaphore = CreateSemaphore(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(readSemName.utf16()));
-#else
- readSemaphore = CreateSemaphoreEx(0, FileLockSemMax, FileLockSemMax, reinterpret_cast<const wchar_t *>(readSemName.utf16()), 0, SEMAPHORE_ALL_ACCESS);
-#endif
+ Use a lockfile in order to protect us against other QSettings instances
+ trying to write the same settings at the same time.
- if (readSemaphore) {
- for (int i = 0; i < numReadLocks; ++i)
-#ifndef Q_OS_WINRT
- WaitForSingleObject(readSemaphore, INFINITE);
-#else
- WaitForSingleObjectEx(readSemaphore, INFINITE, FALSE);
-#endif
- } else {
+ We only need to lock if we are actually writing as only concurrent writes are a problem.
+ Concurrent read and write are not a problem because the writing operation is atomic.
+ */
+ QLockFile lockFile(confFile->name + QLatin1String(".lock"));
+ if (!readOnly) {
+ if (!confFile->isWritable() || !lockFile.lock() ) {
setStatus(QSettings::AccessError);
- if (writeSemaphore != 0) {
- ReleaseSemaphore(writeSemaphore, 1, 0);
- CloseHandle(writeSemaphore);
- }
return;
}
}
-#else
- if (file.isOpen())
- unixLock(file.handle(), readOnly ? F_RDLCK : F_WRLCK);
#endif
- // If we have created the file, apply the file perms
- if (file.isOpen()) {
- if (createFile) {
- QFile::Permissions perms = file.permissions() | QFile::ReadOwner | QFile::WriteOwner;
- if (!confFile->userPerms)
- perms |= QFile::ReadGroup | QFile::ReadOther;
- file.setPermissions(perms);
- }
- }
-
/*
We hold the lock. Let's reread the file if it has changed
since last time we read it.
*/
QFileInfo fileInfo(confFile->name);
bool mustReadFile = true;
+ bool createFile = !fileInfo.exists();
if (!readOnly)
mustReadFile = (confFile->size != fileInfo.size()
@@ -1565,6 +1401,12 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
confFile->unparsedIniSections.clear();
confFile->originalKeys.clear();
+ QFile file(confFile->name);
+ if (!createFile && !file.open(QFile::ReadOnly)) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
/*
Files that we can't read (because of permissions or
because they don't exist) are treated as empty files.
@@ -1615,42 +1457,40 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
ensureAllSectionsParsed(confFile);
ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
- if (file.isWritable()) {
#ifdef Q_OS_MAC
- if (format == QSettings::NativeFormat) {
- ok = writePlistFile(confFile->name, mergedKeys);
- } else
+ if (format == QSettings::NativeFormat) {
+ ok = writePlistFile(confFile->name, mergedKeys);
+ } else
#endif
- {
- file.seek(0);
- file.resize(0);
+ {
+#ifndef QT_BOOTSTRAPPED
+ QSaveFile sf(confFile->name);
+#else
+ QFile sf(confFile->name);
+#endif
+ if (!sf.open(QIODevice::WriteOnly)) {
+ setStatus(QSettings::AccessError);
+ ok = false;
+ } else if (format <= QSettings::IniFormat) {
+ ok = writeIniFile(sf, mergedKeys);
+ } else {
+ if (writeFunc) {
+ QSettings::SettingsMap tempOriginalKeys;
- if (format <= QSettings::IniFormat) {
- ok = writeIniFile(file, mergedKeys);
- if (!ok) {
- // try to restore old data; might work if the disk was full and the new data
- // was larger than the old data
- file.seek(0);
- file.resize(0);
- writeIniFile(file, confFile->originalKeys);
+ ParsedSettingsMap::const_iterator i = mergedKeys.constBegin();
+ while (i != mergedKeys.constEnd()) {
+ tempOriginalKeys.insert(i.key(), i.value());
+ ++i;
}
+ ok = writeFunc(sf, tempOriginalKeys);
} else {
- if (writeFunc) {
- QSettings::SettingsMap tempOriginalKeys;
-
- ParsedSettingsMap::const_iterator i = mergedKeys.constBegin();
- while (i != mergedKeys.constEnd()) {
- tempOriginalKeys.insert(i.key(), i.value());
- ++i;
- }
- ok = writeFunc(file, tempOriginalKeys);
- } else {
- ok = false;
- }
+ ok = false;
}
}
- } else {
- ok = false;
+#ifndef QT_BOOTSTRAPPED
+ if (ok)
+ ok = sf.commit();
+#endif
}
if (ok) {
@@ -1662,24 +1502,18 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo)
QFileInfo fileInfo(confFile->name);
confFile->size = fileInfo.size();
confFile->timeStamp = fileInfo.lastModified();
+
+ // If we have created the file, apply the file perms
+ if (createFile) {
+ QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
+ if (!confFile->userPerms)
+ perms |= QFile::ReadGroup | QFile::ReadOther;
+ QFile(confFile->name).setPermissions(perms);
+ }
} else {
setStatus(QSettings::AccessError);
}
}
-
- /*
- Release the file lock.
- */
-#ifdef Q_OS_WIN
- if (readSemaphore != 0) {
- ReleaseSemaphore(readSemaphore, numReadLocks, 0);
- CloseHandle(readSemaphore);
- }
- if (writeSemaphore != 0) {
- ReleaseSemaphore(writeSemaphore, 1, 0);
- CloseHandle(writeSemaphore);
- }
-#endif
}
enum { Space = 0x1, Special = 0x2 };
@@ -2505,12 +2339,6 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
10.8 (Mountain Lion), only root can. However, 10.9 (Mavericks) changes
that rule again but only for the native format (plist files).
- \li On Unix and Mac OS X systems, the advisory file locking is disabled
- if NFS (or AutoFS or CacheFS) is detected to work around a bug in the
- NFS fcntl() implementation, which hangs forever if statd or lockd aren't
- running. Also, the locking isn't performed when accessing \c .plist
- files.
-
\li On the BlackBerry platform, applications run in a sandbox. They are not
allowed to read or write outside of this sandbox. This involves the
following limitations:
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index a28b583162..5ed203bd46 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -70,6 +70,10 @@ QT_BEGIN_NAMESPACE
#define QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
#endif
+#if defined(Q_OS_WINRT)
+#define QT_QTSETTINGS_FORGET_ORIGINAL_KEY_ORDER
+#endif
+
// used in testing framework
#define QSETTINGS_P_H_VERSION 3
diff --git a/src/corelib/io/qsettings_winrt.cpp b/src/corelib/io/qsettings_winrt.cpp
new file mode 100644
index 0000000000..ad02f050e5
--- /dev/null
+++ b/src/corelib/io/qsettings_winrt.cpp
@@ -0,0 +1,695 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsettings.h"
+
+#ifndef QT_NO_SETTINGS
+
+#include "qsettings_p.h"
+#include "qvector.h"
+#include "qmap.h"
+#include "qdebug.h"
+#include "qfunctions_winrt.h"
+
+#include <wrl.h>
+#include <wrl/event.h>
+#include <Windows.ApplicationModel.h>
+#include <windows.storage.h>
+
+using namespace ABI::Windows::ApplicationModel;
+using namespace ABI::Windows::Storage;
+using namespace ABI::Windows::Foundation;
+using namespace ABI::Windows::Foundation::Collections;
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers;
+
+typedef ITypedEventHandler<ApplicationData*, IInspectable*> DataHandler;
+typedef Collections::IKeyValuePair<HSTRING, ApplicationDataContainer*> ContainerItem;
+typedef Collections::IIterable<ContainerItem*> ContainerIterable;
+typedef Collections::IIterator<ContainerItem*> ContainerIterator;
+
+typedef Collections::IKeyValuePair<HSTRING, IInspectable*> ValueItem;
+typedef Collections::IIterable<ValueItem*> ValueIterable;
+typedef Collections::IIterator<ValueItem*> ValueIterator;
+
+QT_BEGIN_NAMESPACE
+
+static IApplicationDataContainer *subContainer(IApplicationDataContainer *parent, const QString &name)
+{
+ ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer;
+ HRESULT hr = parent->get_Containers(&childrenContainer);
+ if (FAILED(hr))
+ return 0;
+
+ ComPtr< ContainerIterable > iterable;
+ ComPtr< ContainerIterator > iterator;
+
+ hr = childrenContainer.As(&iterable);
+ if (FAILED(hr))
+ return 0;
+
+ hr = iterable->First(&iterator);
+ if (FAILED(hr))
+ return 0;
+ boolean current;
+ hr = iterator->get_HasCurrent(&current);
+ if (FAILED(hr))
+ return 0;
+
+ while (SUCCEEDED(S_OK) && current) {
+ ComPtr<ContainerItem> item;
+ hr = iterator->get_Current(&item);
+ if (FAILED(hr))
+ return 0;
+
+ HString key;
+ hr = item->get_Key(key.GetAddressOf());
+ if (FAILED(hr))
+ continue;
+ QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr));
+ if (name == subName) {
+ IApplicationDataContainer *container;
+ hr = item->get_Value(&container);
+ return SUCCEEDED(hr) ? container : 0;
+ }
+ hr = iterator->MoveNext(&current);
+ }
+
+ return 0;
+}
+
+static QStringList subContainerNames(IApplicationDataContainer *container, bool recursive = false)
+{
+ QStringList result;
+ ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer;
+ HRESULT hr = container->get_Containers(&childrenContainer);
+ if (FAILED(hr))
+ return result;
+
+ ComPtr< ContainerIterable > iterable;
+ ComPtr< ContainerIterator > iterator;
+
+ hr = childrenContainer.As(&iterable);
+ if (FAILED(hr))
+ return result;
+
+ hr = iterable->First(&iterator);
+ if (FAILED(hr))
+ return result;
+ boolean current;
+ hr = iterator->get_HasCurrent(&current);
+ if (FAILED(hr))
+ return result;
+
+ while (SUCCEEDED(hr) && current) {
+ ComPtr<ContainerItem> item;
+ hr = iterator->get_Current(&item);
+ if (FAILED(hr))
+ return result;
+
+ HString key;
+ hr = item->get_Key(key.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr));
+ result.append(subName);
+ if (recursive) {
+ ComPtr<IApplicationDataContainer> sub = subContainer(container, subName);
+ QStringList subSubNames = subContainerNames(sub.Get(), recursive);
+ for (int i = 0; i < subSubNames.size(); ++i)
+ subSubNames[i] = subName + QLatin1Char('/') + subSubNames[i];
+ result.append(subSubNames);
+ }
+ hr = iterator->MoveNext(&current);
+ }
+ }
+ return result;
+}
+
+static QStringList keyNames(IApplicationDataContainer *container) {
+ HRESULT hr;
+ QStringList result;
+ ComPtr<IPropertySet> values;
+ hr = container->get_Values(&values);
+ if (FAILED(hr))
+ return result;
+
+ ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
+
+ hr = values.As(&settingsMap);
+ if (FAILED(hr))
+ return result;
+
+ ComPtr<IMapView<HSTRING, IInspectable*>> mapView;
+ hr = settingsMap->GetView(&mapView);
+ if (FAILED(hr))
+ return result;
+
+ ComPtr< ValueIterable > iterable;
+ ComPtr< ValueIterator > iterator;
+
+ hr = mapView.As(&iterable);
+ if (FAILED(hr))
+ return result;
+
+ boolean current = false;
+ hr = iterable->First(&iterator);
+ if (FAILED(hr))
+ return result;
+ hr = iterator->get_HasCurrent(&current);
+ if (FAILED(hr))
+ return result;
+
+ while (SUCCEEDED(hr) && current){
+ ComPtr<ValueItem> item;
+ hr = iterator->get_Current(&item);
+ if (FAILED(hr))
+ return result;
+
+ HString key;
+ hr = item->get_Key(key.GetAddressOf());
+ if (SUCCEEDED(hr)) {
+ result += QString::fromWCharArray(key.GetRawBuffer(nullptr));
+ hr = iterator->MoveNext(&current);
+ }
+ }
+ return result;
+}
+
+static IApplicationDataContainer *createSubContainer(IApplicationDataContainer *parent, const QString &name)
+{
+ HStringReference childGroupNativeName((const wchar_t*)name.utf16(), name.size());
+
+ IApplicationDataContainer *result = subContainer(parent, name);
+ if (!result)
+ parent->CreateContainer(childGroupNativeName.Get(), ApplicationDataCreateDisposition_Always, &result);
+ return result;
+}
+
+#define PROP_CASE_TO_VARIANT(TYPE, VARTYPE, QTYPE) \
+ case PropertyType_##TYPE: { \
+ VARTYPE v; \
+ value->Get##TYPE(&v); \
+ result.setValue( QTYPE(v) ); \
+ break; \
+ }
+
+static QVariant propertyValueToQVariant(IPropertyValue *value)
+{
+ QVariant result;
+ PropertyType type;
+ value->get_Type(&type);
+ switch (type) {
+ PROP_CASE_TO_VARIANT(Boolean, boolean, bool)
+ PROP_CASE_TO_VARIANT(UInt8, UINT8, quint8)
+ PROP_CASE_TO_VARIANT(Int16, INT16, qint16)
+ PROP_CASE_TO_VARIANT(UInt16, UINT16, quint16)
+ PROP_CASE_TO_VARIANT(Int32, INT32, qint32)
+ PROP_CASE_TO_VARIANT(UInt32, UINT32, quint32)
+ PROP_CASE_TO_VARIANT(Int64, INT64, qint64)
+ PROP_CASE_TO_VARIANT(UInt64, UINT64, quint64)
+ PROP_CASE_TO_VARIANT(Single, FLOAT, float)
+ PROP_CASE_TO_VARIANT(Double, DOUBLE, double)
+ case PropertyType_StringArray: {
+ UINT32 size;
+ HSTRING *content;
+ value->GetStringArray(&size, &content);
+ QStringList list;
+ // The last item is assumed to be added by us
+ for (UINT32 i = 0; i < size - 1; ++i) {
+ QString s = QString::fromWCharArray(WindowsGetStringRawBuffer(content[i], nullptr));
+ list.append(s);
+ }
+ result = QSettingsPrivate::stringListToVariantList(list);
+ break;
+ }
+ case PropertyType_String: {
+ HString v;
+ value->GetString(v.GetAddressOf());
+ result = QSettingsPrivate::stringToVariant(QString::fromWCharArray(v.GetRawBuffer(nullptr)));
+ break;
+ }
+ default: {
+ UINT32 size;
+ BYTE *arr;
+ value->GetUInt8Array(&size, &arr);
+ QByteArray data = QByteArray::fromRawData((const char*)arr, size);
+ QString s;
+ if (size) {
+ // We assume this is our qt stored data like on other platforms
+ // as well. QList and others are converted to byte arrays
+ s = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
+ result = QSettingsPrivate::stringToVariant(s);
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+class QWinRTSettingsPrivate : public QSettingsPrivate
+{
+public:
+ QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application);
+ QWinRTSettingsPrivate(QString rKey);
+ ~QWinRTSettingsPrivate();
+
+ void remove(const QString &uKey);
+ void set(const QString &uKey, const QVariant &value);
+ bool get(const QString &uKey, QVariant *value) const;
+ QStringList children(const QString &uKey, ChildSpec spec) const;
+ void clear();
+ void sync();
+ void flush();
+ bool isWritable() const;
+ QString fileName() const;
+
+private:
+ void init(QSettings::Scope scope);
+ IApplicationDataContainer *getContainer(IApplicationDataContainer *parent, const QString &group, bool create = false) const;
+ void clearContainerMaps();
+
+ HRESULT onDataChanged(IApplicationData*, IInspectable*);
+
+ ComPtr<IApplicationData> applicationData;
+ QVector<ComPtr<IApplicationDataContainer>> readContainers;
+ ComPtr<IApplicationDataContainer> writeContainer;
+ EventRegistrationToken dataChangedToken;
+};
+
+QWinRTSettingsPrivate::QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application)
+ : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
+ , writeContainer(0)
+{
+ init(scope);
+}
+
+QWinRTSettingsPrivate::QWinRTSettingsPrivate(QString rPath)
+ : QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, rPath, QString())
+ , writeContainer(0)
+{
+ init(QSettings::UserScope);
+}
+
+QWinRTSettingsPrivate::~QWinRTSettingsPrivate()
+{
+ clearContainerMaps();
+}
+
+void QWinRTSettingsPrivate::remove(const QString &uKey)
+{
+ int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
+ QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
+ QString groupKey = uKey.mid(lastIndex + 1);
+
+ ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, false);
+ if (!container)
+ return;
+
+ HRESULT hr;
+ ComPtr<IPropertySet> values;
+ hr = container->get_Values(&values);
+ if (FAILED(hr))
+ return;
+
+ ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
+
+ hr = values.As(&settingsMap);
+ if (FAILED(hr))
+ return;
+
+ HStringReference ref((const wchar_t*)groupKey.utf16(), groupKey.size());
+ hr = settingsMap->Remove(ref.Get());
+
+ // groupKey can be a container as well
+ hr = container->DeleteContainer(ref.Get());
+ init(scope);
+}
+
+void QWinRTSettingsPrivate::set(const QString &uKey, const QVariant &value)
+{
+ int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
+ QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
+ QString groupKey = uKey.mid(lastIndex + 1);
+
+ ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, true);
+
+ ComPtr<IPropertySet> values;
+ HRESULT hr = container->get_Values(&values);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Could not access Windows container values");
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
+ hr = values.As(&settingsMap);
+ if (FAILED(hr)) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ ComPtr<IPropertyValueStatics> valueStatics;
+ hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &valueStatics);
+ if (FAILED(hr)) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ ComPtr<IInspectable> val;
+
+ switch (value.type()) {
+ case QVariant::List:
+ case QVariant::StringList: {
+ QStringList l = variantListToStringList(value.toList());
+ QStringList::const_iterator it = l.constBegin();
+ bool containsNull = false;
+ for (; it != l.constEnd(); ++it) {
+ if ((*it).length() == 0 || it->indexOf(QChar::Null) != -1) {
+ // We can only store as binary
+ containsNull = true;
+ break;
+ }
+ }
+
+ if (containsNull) {
+ // Store binary
+ const QString s = variantToString(value);
+ hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val);
+ } else {
+ // Store as native string list
+ int size = l.size();
+ HSTRING *nativeHandleList = new HSTRING[size+1];
+ for (int i = 0; i < size; ++i)
+ hr = WindowsCreateString((const wchar_t*)l[i].utf16(), l[i].size(), &nativeHandleList[i]);
+ // Add end marker
+ hr = WindowsCreateString((const wchar_t*)L"\0\0@", 3, &nativeHandleList[size]);
+ hr = valueStatics->CreateStringArray(size + 1 , nativeHandleList, &val);
+ for (int i = 0; i < size; ++i)
+ hr = WindowsDeleteString(nativeHandleList[i]);
+ delete [] nativeHandleList;
+ }
+ break;
+ }
+ case QVariant::Bool:
+ hr = valueStatics->CreateBoolean(boolean(value.toBool()), &val);
+ break;
+ case QVariant::Int:
+ hr = valueStatics->CreateInt32(INT32(value.toInt()), &val);
+ break;
+ case QVariant::UInt:
+ hr = valueStatics->CreateUInt32(UINT32(value.toUInt()), &val);
+ break;
+ case QVariant::LongLong:
+ hr = valueStatics->CreateInt64(INT64(value.toLongLong()), &val);
+ break;
+ case QVariant::ULongLong:
+ hr = valueStatics->CreateUInt64(UINT64(value.toULongLong()), &val);
+ break;
+ default: {
+ const QString s = variantToString(value);
+ if (s.indexOf(QChar::Null) != -1) {
+ hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val);
+ } else {
+ HStringReference ref((const wchar_t*)s.utf16(), s.size());
+ hr = valueStatics->CreateString(ref.Get(), &val);
+ }
+
+ break;
+ }
+ }
+
+ RETURN_VOID_IF_FAILED("QSettings: Could not save QVariant value into IInspectable");
+
+ HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size());
+ boolean rep;
+
+ hr = settingsMap->Insert(key.Get(), val.Get(), &rep);
+ RETURN_VOID_IF_FAILED("QSettings: Could not store value");
+}
+
+bool QWinRTSettingsPrivate::get(const QString &uKey, QVariant *value) const
+{
+ int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
+ QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
+ QString groupKey = uKey.mid(lastIndex + 1);
+
+ HRESULT hr;
+
+ for (int i = 0; i < readContainers.size(); ++i) {
+ ComPtr<IApplicationDataContainer> container = const_cast<QWinRTSettingsPrivate*>(this)->getContainer(readContainers.at(i).Get(), groupName);
+
+ if (!container)
+ continue;
+
+ ComPtr<IPropertySet> values;
+ hr = container->get_Values(&values);
+ if (FAILED(hr))
+ continue;
+
+ ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
+ hr = values.As(&settingsMap);
+ if (FAILED(hr))
+ continue;
+
+ HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size());
+ boolean exists;
+
+ hr = settingsMap.Get()->HasKey(key.Get(), &exists);
+ if (FAILED(hr))
+ continue;
+
+ if (!exists) {
+ if (!fallbacks)
+ break;
+ else
+ continue;
+ }
+
+ if (value) {
+ ComPtr<IInspectable> val;
+ hr = settingsMap->Lookup(key.Get(), &val);
+ if (FAILED(hr))
+ return false;
+
+ ComPtr<IPropertyValue> pVal;
+ hr = val.As(&pVal);
+ if (FAILED(hr))
+ return false;
+
+ *value = propertyValueToQVariant(pVal.Get());
+ }
+ return true;
+ }
+ setStatus(QSettings::AccessError);
+ return false;
+}
+
+QStringList QWinRTSettingsPrivate::children(const QString &uKey, ChildSpec spec) const
+{
+ QStringList result;
+ for (int i = 0; i < readContainers.size(); ++i) {
+ ComPtr<IApplicationDataContainer> container = getContainer(readContainers.at(i).Get(), uKey, false);
+ if (!container.Get())
+ continue;
+
+ // Get Keys in this container
+ if (spec == AllKeys || spec == ChildKeys)
+ result += keyNames(container.Get());
+
+ // Get Subcontainer(s)
+ if (spec == AllKeys || spec == ChildGroups) {
+ const QStringList subContainerList = subContainerNames(container.Get(), spec == AllKeys);
+
+ if (spec == AllKeys) {
+ foreach (const QString &item, subContainerList) {
+ const QString subChildren = uKey.isEmpty() ? item : (uKey + QLatin1Char('/') + item);
+ const QStringList subResult = children(subChildren, ChildKeys);
+ foreach (const QString &subItem, subResult)
+ result += item + QLatin1Char('/') + subItem;
+ }
+ }
+
+ if (spec == ChildGroups)
+ result += subContainerList;
+ }
+
+ }
+ result.removeDuplicates();
+ return result;
+}
+
+void QWinRTSettingsPrivate::clear()
+{
+ ComPtr<IApplicationDataContainer> container;
+ HRESULT hr;
+ if (scope == QSettings::UserScope)
+ hr = applicationData->get_LocalSettings(&container);
+ else
+ hr = applicationData->get_RoamingSettings(&container);
+
+ RETURN_VOID_IF_FAILED("Could not access settings container");
+
+ QString containerName = applicationName.isEmpty() ? organizationName : applicationName;
+ HStringReference containerNativeName((const wchar_t*)containerName.utf16(), containerName.size());
+
+ hr = container->DeleteContainer(containerNativeName.Get());
+ RETURN_VOID_IF_FAILED("Could not delete Container");
+
+ init(scope);
+}
+
+void QWinRTSettingsPrivate::sync()
+{
+ // No native sync available
+}
+
+void QWinRTSettingsPrivate::flush()
+{
+ // No native flush available
+}
+
+QString QWinRTSettingsPrivate::fileName() const
+{
+ Q_UNIMPLEMENTED();
+ return QString();
+}
+
+HRESULT QWinRTSettingsPrivate::onDataChanged(IApplicationData *, IInspectable *)
+{
+ // This only happens, if roaming data is changed by the OS.
+ // To ensure sanity we clean up the map and start from scratch
+ init(scope);
+ return S_OK;
+}
+
+void QWinRTSettingsPrivate::init(QSettings::Scope scope)
+{
+ clearContainerMaps();
+
+ ComPtr<IApplicationDataStatics> applicationDataStatics;
+ HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Could not access Storage Factory");
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ hr = applicationDataStatics->get_Current(&applicationData);
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "Could not access application data statics");
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
+ const QString organizationString = organizationName.isEmpty() ? QLatin1String("OrganizationDefaults") : organizationName;
+ ComPtr<IApplicationDataContainer> localContainer;
+ if (scope == QSettings::UserScope && SUCCEEDED(applicationData->get_LocalSettings(&localContainer))) {
+ if (!applicationName.isEmpty())
+ readContainers.append(createSubContainer(localContainer.Get(), applicationName));
+ readContainers.append(createSubContainer(localContainer.Get(), organizationString));
+ }
+
+ ComPtr<IApplicationDataContainer> roamingContainer;
+ if (SUCCEEDED(applicationData->get_RoamingSettings(&roamingContainer))) {
+ if (!applicationName.isEmpty())
+ readContainers.append(createSubContainer(roamingContainer.Get(), applicationName));
+ readContainers.append(createSubContainer(roamingContainer.Get(), organizationString));
+ }
+
+ ComPtr<IApplicationDataContainer> writeRootContainer = (scope == QSettings::UserScope) ? localContainer : roamingContainer;
+ if (!applicationName.isEmpty())
+ writeContainer = createSubContainer(writeRootContainer.Get(), applicationName);
+ else
+ writeContainer = createSubContainer(writeRootContainer.Get(), organizationString);
+
+ hr = applicationData->add_DataChanged(Callback<DataHandler>(this, &QWinRTSettingsPrivate::onDataChanged).Get(), &dataChangedToken);
+}
+
+IApplicationDataContainer *QWinRTSettingsPrivate::getContainer(IApplicationDataContainer *parent, const QString &group, bool create) const
+{
+ IApplicationDataContainer *current = parent;
+ if (group.isEmpty())
+ return current;
+ const QStringList groupPath = group.split(QLatin1Char('/'), QString::SkipEmptyParts);
+
+ foreach (const QString &subGroup, groupPath) {
+ ComPtr<IApplicationDataContainer> sub = subContainer(current, subGroup);
+ if (!sub && create)
+ sub = createSubContainer(current, subGroup);
+ if (!sub)
+ return 0; // Something seriously went wrong
+ current = sub.Detach();
+ }
+ return current;
+}
+
+void QWinRTSettingsPrivate::clearContainerMaps()
+{
+ readContainers.clear();
+ writeContainer.Reset();
+}
+
+bool QWinRTSettingsPrivate::isWritable() const
+{
+ return true;
+}
+
+QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
+ const QString &organization, const QString &application)
+{
+ if (format == QSettings::NativeFormat)
+ return new QWinRTSettingsPrivate(scope, organization, application);
+ else
+ return new QConfFileSettingsPrivate(format, scope, organization, application);
+}
+
+QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
+{
+ if (format == QSettings::NativeFormat)
+ return new QWinRTSettingsPrivate(fileName);
+ else
+ return new QConfFileSettingsPrivate(fileName, format);
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_SETTINGS
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index bd9fa68d93..8c47ad1391 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -117,10 +117,9 @@ QT_BEGIN_NAMESPACE
\value HomeLocation Returns the user's home directory (the same as QDir::homePath()). On Unix
systems, this is equal to the HOME environment variable. This value might be
generic or application-specific, but the returned path is never empty.
- \value DataLocation Returns a directory location where persistent
- application data can be stored. This is an application-specific directory. To obtain a
- path to store data to be shared with other applications, use
- QStandardPaths::GenericDataLocation. The returned path is never empty.
+ \value DataLocation Returns the same value as AppLocalDataLocation. This enumeration value
+ is deprecated. Using AppDataLocation is preferable since on Windows, the roaming path is
+ recommended.
\value CacheLocation Returns a directory location where user-specific
non-essential (cached) data should be written. This is an application-specific directory.
The returned path is never empty.
@@ -142,6 +141,15 @@ QT_BEGIN_NAMESPACE
\value GenericConfigLocation Returns a directory location where user-specific
configuration files shared between multiple applications should be written.
This is a generic value and the returned path is never empty.
+ \value AppDataLocation Returns a directory location where persistent
+ application data can be stored. This is an application-specific directory.
+ To obtain a path to store data to be shared with other applications, use
+ QStandardPaths::GenericDataLocation. The returned path is never empty.
+ On the Windows operating system, this returns the roaming path.
+ This enum value was added in Qt 5.4.
+ \value AppLocalDataLocation Returns the local settings path on the Windows operating
+ system. On all other platforms, it returns the same value as AppDataLocation.
+ This enum value was added in Qt 5.4.
The following table gives examples of paths on different operating systems.
The first path is the writable path (unless noted). Other, additional
@@ -200,6 +208,12 @@ QT_BEGIN_NAMESPACE
\row \li GenericCacheLocation
\li "~/Library/Caches", "/Library/Caches"
\li "C:/Users/<USER>/AppData/Local/cache"
+ \row \li AppDataLocation
+ \li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
+ \li "C:/Users/<USER>/AppData/Roaming/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
+ \row \li AppLocalDataLocation
+ \li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
\endtable
\table
@@ -255,6 +269,12 @@ QT_BEGIN_NAMESPACE
\row \li GenericCacheLocation
\li "<APPROOT>/data/Cache" (there is no shared cache)
\li "~/.cache"
+ \row \li AppDataLocation
+ \li "<APPROOT>/data", "<APPROOT>/app/native/assets"
+ \li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
+ \row \li AppLocalDataLocation
+ \li "<APPROOT>/data", "<APPROOT>/app/native/assets"
+ \li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
\endtable
\table
@@ -293,6 +313,8 @@ QT_BEGIN_NAMESPACE
\li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads"
\row \li GenericCacheLocation
\li "<APPROOT>/cache" (there is no shared cache)
+ \row \li AppDataLocation
+ \li "<APPROOT>/files", "<USER>/<APPNAME>/files"
\endtable
In the table above, \c <APPNAME> is usually the organization name, the
@@ -534,8 +556,6 @@ QString QStandardPaths::displayName(StandardLocation type)
return QCoreApplication::translate("QStandardPaths", "Temporary Directory");
case HomeLocation:
return QCoreApplication::translate("QStandardPaths", "Home");
- case DataLocation:
- return QCoreApplication::translate("QStandardPaths", "Application Data");
case CacheLocation:
return QCoreApplication::translate("QStandardPaths", "Cache");
case GenericDataLocation:
@@ -550,6 +570,9 @@ QString QStandardPaths::displayName(StandardLocation type)
return QCoreApplication::translate("QStandardPaths", "Shared Cache");
case DownloadLocation:
return QCoreApplication::translate("QStandardPaths", "Download");
+ case AppDataLocation:
+ case AppLocalDataLocation:
+ return QCoreApplication::translate("QStandardPaths", "Application Data");
}
// not reached
return QString();
diff --git a/src/corelib/io/qstandardpaths.h b/src/corelib/io/qstandardpaths.h
index 08d6d7b50c..b93adbf156 100644
--- a/src/corelib/io/qstandardpaths.h
+++ b/src/corelib/io/qstandardpaths.h
@@ -70,7 +70,9 @@ public:
ConfigLocation,
DownloadLocation,
GenericCacheLocation,
- GenericConfigLocation
+ GenericConfigLocation,
+ AppDataLocation,
+ AppLocalDataLocation = DataLocation
};
static QString writableLocation(StandardLocation type);
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index 60b285a3d6..9bd4b4b428 100644
--- a/src/corelib/io/qstandardpaths_android.cpp
+++ b/src/corelib/io/qstandardpaths_android.cpp
@@ -244,7 +244,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return getFilesDir() + testDir() + QLatin1String("/settings");
case QStandardPaths::GenericDataLocation:
return getExternalStorageDirectory() + testDir();
- case QStandardPaths::DataLocation:
+ case QStandardPaths::AppDataLocation:
+ case QStandardPaths::AppLocalDataLocation:
return getFilesDir() + testDir();
case QStandardPaths::GenericCacheLocation:
case QStandardPaths::RuntimeLocation:
@@ -301,7 +302,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
<< getExternalFilesDir("DIRECTORY_DOWNLOADS");
}
- if (type == DataLocation) {
+ if (type == AppDataLocation || type == AppLocalDataLocation) {
return QStringList() << writableLocation(type)
<< getExternalFilesDir();
}
diff --git a/src/corelib/io/qstandardpaths_blackberry.cpp b/src/corelib/io/qstandardpaths_blackberry.cpp
index ec2e61bd15..2e9d62cd05 100644
--- a/src/corelib/io/qstandardpaths_blackberry.cpp
+++ b/src/corelib/io/qstandardpaths_blackberry.cpp
@@ -63,7 +63,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
const QString sharedRoot = sharedDir.absolutePath();
switch (type) {
- case DataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
return QDir::homePath() + testModeInsert();
case DesktopLocation:
case HomeLocation:
@@ -108,7 +109,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
if (type == FontsLocation)
return QStringList(QLatin1String("/base/usr/fonts"));
- if (type == DataLocation)
+ if (type == AppDataLocation || type == AppLocalDataLocation)
dirs.append(QDir::homePath() + testModeInsert() + QLatin1String("native/assets"));
const QString localDir = writableLocation(type);
diff --git a/src/corelib/io/qstandardpaths_ios.mm b/src/corelib/io/qstandardpaths_ios.mm
index e2100045a6..cdca28b8b5 100644
--- a/src/corelib/io/qstandardpaths_ios.mm
+++ b/src/corelib/io/qstandardpaths_ios.mm
@@ -90,7 +90,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case HomeLocation:
location = bundlePath();
break;
- case DataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
case GenericDataLocation:
location = pathForDirectory(NSDocumentDirectory);
break;
diff --git a/src/corelib/io/qstandardpaths_mac.cpp b/src/corelib/io/qstandardpaths_mac.cpp
index aff9112fb7..a27920899c 100644
--- a/src/corelib/io/qstandardpaths_mac.cpp
+++ b/src/corelib/io/qstandardpaths_mac.cpp
@@ -83,7 +83,8 @@ OSType translateLocation(QStandardPaths::StandardLocation type)
return kTemporaryFolderType;
case QStandardPaths::GenericDataLocation:
case QStandardPaths::RuntimeLocation:
- case QStandardPaths::DataLocation:
+ case QStandardPaths::AppDataLocation:
+ case QStandardPaths::AppLocalDataLocation:
return kApplicationSupportFolderType;
case QStandardPaths::GenericCacheLocation:
case QStandardPaths::CacheLocation:
@@ -128,7 +129,7 @@ static QString macLocation(QStandardPaths::StandardLocation type, short domain)
QString path = getFullPath(ref);
- if (type == QStandardPaths::DataLocation || type == QStandardPaths::CacheLocation)
+ if (type == QStandardPaths::AppDataLocation || type == QStandardPaths::AppLocalDataLocation || type == QStandardPaths::CacheLocation)
appendOrganizationAndApp(path);
return path;
}
@@ -140,9 +141,10 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QString path;
switch (type) {
case GenericDataLocation:
- case DataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
path = qttestDir + QLatin1String("/Application Support");
- if (type == DataLocation)
+ if (type != GenericDataLocation)
appendOrganizationAndApp(path);
return path;
case GenericCacheLocation:
@@ -165,7 +167,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case TempLocation:
return QDir::tempPath();
case GenericDataLocation:
- case DataLocation:
+ case AppLocalDataLocation:
case GenericCacheLocation:
case CacheLocation:
case RuntimeLocation:
@@ -179,13 +181,13 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
{
QStringList dirs;
- if (type == GenericDataLocation || type == DataLocation || type == GenericCacheLocation || type == CacheLocation) {
+ if (type == GenericDataLocation || type == AppDataLocation || type == AppLocalDataLocation || type == GenericCacheLocation || type == CacheLocation) {
const QString path = macLocation(type, kOnAppropriateDisk);
if (!path.isEmpty())
dirs.append(path);
}
- if (type == DataLocation) {
+ if (type == AppDataLocation || type == AppLocalDataLocation) {
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle) {
CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle);
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index e2ed7c3766..cde1e4bc72 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -90,7 +90,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
appendOrganizationAndApp(xdgCacheHome);
return xdgCacheHome;
}
- case DataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
case GenericDataLocation:
{
QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
@@ -98,7 +99,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
xdgDataHome = QDir::homePath() + QLatin1String("/.qttest/share");
if (xdgDataHome.isEmpty())
xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
- if (type == QStandardPaths::DataLocation)
+ if (type == AppDataLocation || type == AppLocalDataLocation)
appendOrganizationAndApp(xdgDataHome);
return xdgDataHome;
}
@@ -305,7 +306,8 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
for (int i = 0; i < dirs.count(); ++i)
dirs[i].append(QLatin1String("/applications"));
break;
- case DataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
dirs = xdgDataDirs();
for (int i = 0; i < dirs.count(); ++i)
appendOrganizationAndApp(dirs[i]);
diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp
index 062ab49207..aaa390ac34 100644
--- a/src/corelib/io/qstandardpaths_win.cpp
+++ b/src/corelib/io/qstandardpaths_win.cpp
@@ -81,6 +81,18 @@ static QString convertCharArray(const wchar_t *path)
return QDir::fromNativeSeparators(QString::fromWCharArray(path));
}
+static inline int clsidForAppDataLocation(QStandardPaths::StandardLocation type)
+{
+#ifndef Q_OS_WINCE
+ return type == QStandardPaths::AppDataLocation ?
+ CSIDL_APPDATA : // "Roaming" path
+ CSIDL_LOCAL_APPDATA; // Local path
+#else
+ Q_UNUSED(type)
+ return CSIDL_APPDATA;
+#endif
+}
+
QString QStandardPaths::writableLocation(StandardLocation type)
{
QString result;
@@ -92,15 +104,12 @@ QString QStandardPaths::writableLocation(StandardLocation type)
wchar_t path[MAX_PATH];
switch (type) {
- case ConfigLocation: // same as DataLocation, on Windows (oversight, but too late to fix it)
- case GenericConfigLocation: // same as GenericDataLocation, on Windows
- case DataLocation:
+ case ConfigLocation: // same as AppLocalDataLocation, on Windows
+ case GenericConfigLocation: // same as GenericDataLocation on Windows
+ case AppDataLocation:
+ case AppLocalDataLocation:
case GenericDataLocation:
-#if defined Q_OS_WINCE
- if (SHGetSpecialFolderPath(0, path, CSIDL_APPDATA, FALSE))
-#else
- if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE))
-#endif
+ if (SHGetSpecialFolderPath(0, path, clsidForAppDataLocation(type), FALSE))
result = convertCharArray(path);
if (isTestModeEnabled())
result += QLatin1String("/qttest");
@@ -165,7 +174,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
// Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache
// location for everyone. Most applications seem to be using a
// cache directory located in their AppData directory
- return writableLocation(DataLocation) + QLatin1String("/cache");
+ return writableLocation(AppLocalDataLocation) + QLatin1String("/cache");
case GenericCacheLocation:
return writableLocation(GenericDataLocation) + QLatin1String("/cache");
@@ -192,11 +201,12 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
{
wchar_t path[MAX_PATH];
switch (type) {
- case ConfigLocation: // same as DataLocation, on Windows (oversight, but too late to fix it)
+ case ConfigLocation: // same as AppLocalDataLocation, on Windows (oversight, but too late to fix it)
case GenericConfigLocation: // same as GenericDataLocation, on Windows
- case DataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
case GenericDataLocation:
- if (SHGetSpecialFolderPath(0, path, CSIDL_COMMON_APPDATA, FALSE)) {
+ if (SHGetSpecialFolderPath(0, path, clsidForAppDataLocation(type), FALSE)) {
QString result = convertCharArray(path);
if (type != GenericDataLocation && type != GenericConfigLocation) {
#ifndef QT_BOOTSTRAPPED
diff --git a/src/corelib/io/qstandardpaths_winrt.cpp b/src/corelib/io/qstandardpaths_winrt.cpp
index feafdf2e7c..81b9d10baf 100644
--- a/src/corelib/io/qstandardpaths_winrt.cpp
+++ b/src/corelib/io/qstandardpaths_winrt.cpp
@@ -73,9 +73,10 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QString result;
switch (type) {
- case ConfigLocation: // same as DataLocation, on Windows
+ case ConfigLocation: // same as AppLocalDataLocation, on Windows
case GenericConfigLocation: // same as GenericDataLocation, on Windows
- case DataLocation:
+ case AppDataLocation:
+ case AppLocalDataLocation:
case GenericDataLocation: {
ComPtr<IApplicationDataStatics> applicationDataStatics;
if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
@@ -98,7 +99,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
break;
}
case CacheLocation:
- return writableLocation(DataLocation) + QLatin1String("/cache");
+ return writableLocation(AppLocalDataLocation) + QLatin1String("/cache");
case GenericCacheLocation:
return writableLocation(GenericDataLocation) + QLatin1String("/cache");
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
new file mode 100644
index 0000000000..388b71b39c
--- /dev/null
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -0,0 +1,398 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstorageinfo.h"
+#include "qstorageinfo_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QStorageInfo
+ \inmodule QtCore
+ \since 5.4
+ \brief Provides information about currently mounted storage and drives.
+
+ \ingroup io
+ \ingroup shared
+
+ Allows retrieving information about the volume's space, its mount point,
+ label, and filesystem name.
+
+ You can create an instance of QStorageInfo by passing the path to the
+ volume's mount point as a constructor parameter, or you can set it using
+ the setPath() method. The static mountedVolumes() method can be used to get the
+ list of all mounted filesystems.
+
+ QStorageInfo always caches the retrieved information, but you can call
+ refresh() to invalidate the cache.
+
+ The following example retrieves the most common information about the root
+ volume of the system, and prints information about it.
+
+ \snippet code/src_corelib_io_qstorageinfo.cpp 2
+*/
+
+/*!
+ Constructs an empty QStorageInfo object.
+
+ Objects created with the default constructor will be invalid and therefore
+ not ready for use.
+
+ \sa setPath(), isReady(), isValid()
+*/
+QStorageInfo::QStorageInfo()
+ : d(new QStorageInfoPrivate)
+{
+}
+
+/*!
+ Constructs a new QStorageInfo object that gives information about the volume
+ mounted at \a path.
+
+ If you pass a directory or file, the QStorageInfo object will refer to the
+ volume where this directory or file is located.
+ You can check if the created object is correct using the isValid() method.
+
+ The following example shows how to get the volume on which the application is
+ located. It is recommended to always check that the volume is ready and valid.
+
+ \snippet code/src_corelib_io_qstorageinfo.cpp 0
+
+ \sa setPath()
+*/
+QStorageInfo::QStorageInfo(const QString &path)
+ : d(new QStorageInfoPrivate)
+{
+ setPath(path);
+}
+
+/*!
+ Constructs a new QStorageInfo object that gives information about the volume
+ containing the \a dir folder.
+*/
+QStorageInfo::QStorageInfo(const QDir &dir)
+ : d(new QStorageInfoPrivate)
+{
+ setPath(dir.absolutePath());
+}
+
+/*!
+ Constructs a new QStorageInfo object that is a copy of the \a other QStorageInfo object.
+*/
+QStorageInfo::QStorageInfo(const QStorageInfo &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Destroys the QStorageInfo object and frees its resources.
+*/
+QStorageInfo::~QStorageInfo()
+{
+}
+
+/*!
+ Makes a copy of the QStorageInfo object \a other and assigns it to this QStorageInfo object.
+*/
+QStorageInfo &QStorageInfo::operator=(const QStorageInfo &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \fn QStorageInfo &QStorageInfo::operator=(QStorageInfo &&other)
+
+ Assigns \a other to this QStorageInfo instance.
+*/
+
+/*!
+ \fn void QStorageInfo::swap(QStorageInfo &other)
+
+ Swaps this volume info with \a other. This function is very fast and
+ never fails.
+*/
+
+/*!
+ Sets this QStorageInfo object to the filesystem mounted where \a path is located.
+
+ \a path can either be a root path of the filesystem, a directory, or a file
+ within that filesystem.
+
+ \sa rootPath()
+*/
+void QStorageInfo::setPath(const QString &path)
+{
+ if (d->rootPath == path)
+ return;
+ d.detach();
+ d->rootPath = path;
+ d->doStat();
+}
+
+/*!
+ Returns the mount point of the filesystem this QStorageInfo object
+ represents.
+
+ On Windows, it returns the volume letter in case the volume is not mounted to
+ a directory.
+
+ Note that the value returned by rootPath() is the real mount point of a
+ volume, and may not be equal to the value passed to the constructor or setPath()
+ method. For example, if you have only the root volume in the system, and
+ pass '/directory' to setPath(), then this method will return '/'.
+
+ \sa setPath(), device()
+*/
+QString QStorageInfo::rootPath() const
+{
+ return d->rootPath;
+}
+
+/*!
+ Returns the size (in bytes) available for the current user. It returns
+ the total size available if the user is the root user or a system administrator.
+
+ This size can be less than or equal to the free size returned by
+ bytesFree() function.
+
+ \sa bytesTotal(), bytesFree()
+*/
+qint64 QStorageInfo::bytesAvailable() const
+{
+ return d->bytesAvailable;
+}
+
+/*!
+ Returns the number of free bytes in a volume. Note that if there are
+ quotas on the filesystem, this value can be larger than the value
+ returned by bytesAvailable().
+
+ \sa bytesTotal(), bytesAvailable()
+*/
+qint64 QStorageInfo::bytesFree() const
+{
+ return d->bytesFree;
+}
+
+/*!
+ Returns the total volume size in bytes.
+
+ \sa bytesFree(), bytesAvailable()
+*/
+qint64 QStorageInfo::bytesTotal() const
+{
+ return d->bytesTotal;
+}
+
+/*!
+ Returns the type name of the filesystem.
+
+ This is a platform-dependent function, and filesystem names can vary
+ between different operating systems. For example, on Windows filesystems
+ they can be named \c NTFS, and on Linux they can be named \c ntfs-3g or \c fuseblk.
+
+ \sa name()
+*/
+QByteArray QStorageInfo::fileSystemType() const
+{
+ return d->fileSystemType;
+}
+
+/*!
+ Returns the device for this volume.
+
+ For example, on Unix filesystems (including OS X), this returns the
+ 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()
+*/
+QByteArray QStorageInfo::device() const
+{
+ return d->device;
+}
+
+/*!
+ 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
+ this method could be empty. An empty string is returned if the file system
+ does not support labels, or if no label is set.
+
+ On Linux, retrieving the volume's label requires \c udev to be present in the
+ system.
+
+ \sa fileSystemType()
+*/
+QString QStorageInfo::name() const
+{
+ return d->name;
+}
+
+/*!
+ Returns the volume's name, if available, or the root path if not.
+*/
+QString QStorageInfo::displayName() const
+{
+ if (!d->name.isEmpty())
+ return d->name;
+ return d->rootPath;
+}
+
+/*!
+ \fn bool QStorageInfo::isRoot() const
+
+ Returns true if this QStorageInfo represents the system root volume; false
+ otherwise.
+
+ On Unix filesystems, the root volume is a volume mounted on \c /. On Windows,
+ the root volume is the volume where the OS is installed.
+
+ \sa root()
+*/
+
+/*!
+ Returns true if the current filesystem is protected from writing; false
+ otherwise.
+*/
+bool QStorageInfo::isReadOnly() const
+{
+ return d->readOnly;
+}
+
+/*!
+ Returns true if the current filesystem is ready to work; false otherwise. For
+ example, false is returned if the CD volume is not inserted.
+
+ Note that fileSystemType(), name(), bytesTotal(), bytesFree(), and
+ bytesAvailable() will return invalid data until the volume is ready.
+
+ \sa isValid()
+*/
+bool QStorageInfo::isReady() const
+{
+ return d->ready;
+}
+
+/*!
+ Returns true if the QStorageInfo specified by rootPath exists and is mounted
+ correctly.
+
+ \sa isReady()
+*/
+bool QStorageInfo::isValid() const
+{
+ return d->valid;
+}
+
+/*!
+ Resets QStorageInfo's internal cache.
+
+ QStorageInfo caches information about storage to speed up performance.
+ QStorageInfo retrieves information during object construction and/or when calling
+ the setPath() method. You have to manually reset the cache by calling this
+ function to update storage information.
+*/
+void QStorageInfo::refresh()
+{
+ d.detach();
+ d->doStat();
+}
+
+/*!
+ Returns the list of QStorageInfo objects that corresponds to the list of currently
+ mounted filesystems.
+
+ On Windows, this returns the drives visible in the \gui{My Computer} folder. On Unix
+ operating systems, it returns the list of all mounted filesystems (except for
+ pseudo filesystems).
+
+ Returns all currently mounted filesystems by default.
+
+ The example shows how to retrieve all available filesystems, skipping read-only ones.
+
+ \snippet code/src_corelib_io_qstorageinfo.cpp 1
+
+ \sa root()
+*/
+QList<QStorageInfo> QStorageInfo::mountedVolumes()
+{
+ return QStorageInfoPrivate::mountedVolumes();
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QStorageInfo, getRoot, (QStorageInfoPrivate::root()))
+
+/*!
+ Returns a QStorageInfo object that represents the system root volume.
+
+ On Unix systems this call returns the root ('/') volume; in Windows the volume where
+ the operating system is installed.
+
+ \sa isRoot()
+*/
+QStorageInfo QStorageInfo::root()
+{
+ return *getRoot();
+}
+
+/*!
+ \fn inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
+
+ \relates QStorageInfo
+
+ Returns true if the \a first QStorageInfo object refers to the same drive or volume
+ as the \a second; otherwise it returns false.
+
+ Note that the result of comparing two invalid QStorageInfo objects is always
+ positive.
+*/
+
+/*!
+ \fn inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
+
+ \relates QStorageInfo
+
+ Returns true if the \a first QStorageInfo object refers to a different drive or
+ volume than the \a second; otherwise returns false.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
new file mode 100644
index 0000000000..0a4a620205
--- /dev/null
+++ b/src/corelib/io/qstorageinfo.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTORAGEINFO_H
+#define QSTORAGEINFO_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStorageInfoPrivate;
+class Q_CORE_EXPORT QStorageInfo
+{
+public:
+ QStorageInfo();
+ explicit QStorageInfo(const QString &path);
+ explicit QStorageInfo(const QDir &dir);
+ QStorageInfo(const QStorageInfo &other);
+ ~QStorageInfo();
+
+ QStorageInfo &operator=(const QStorageInfo &other);
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline QStorageInfo &operator=(QStorageInfo &&other)
+ { qSwap(d, other.d); return *this; }
+#endif
+
+ inline void swap(QStorageInfo &other)
+ { qSwap(d, other.d); }
+
+ void setPath(const QString &path);
+
+ QString rootPath() const;
+ QByteArray device() const;
+ QByteArray fileSystemType() const;
+ QString name() const;
+ QString displayName() const;
+
+ qint64 bytesTotal() const;
+ qint64 bytesFree() const;
+ qint64 bytesAvailable() const;
+
+ inline bool isRoot() const;
+ bool isReadOnly() const;
+ bool isReady() const;
+ bool isValid() const;
+
+ void refresh();
+
+ static QList<QStorageInfo> mountedVolumes();
+ static QStorageInfo root();
+
+private:
+ friend class QStorageInfoPrivate;
+ friend bool operator==(const QStorageInfo &first, const QStorageInfo &second);
+ QExplicitlySharedDataPointer<QStorageInfoPrivate> d;
+};
+
+inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
+{
+ if (first.d == second.d)
+ return true;
+ return first.device() == second.device();
+}
+
+inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
+{
+ return !(first == second);
+}
+
+inline bool QStorageInfo::isRoot() const
+{ return *this == QStorageInfo::root(); }
+
+Q_DECLARE_SHARED(QStorageInfo)
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QStorageInfo)
+
+#endif // QSTORAGEINFO_H
diff --git a/src/corelib/io/qstorageinfo_mac.cpp b/src/corelib/io/qstorageinfo_mac.cpp
new file mode 100644
index 0000000000..060e16b948
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_mac.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstorageinfo_p.h"
+
+#include <QtCore/qfileinfo.h>
+#include <QtCore/private/qcore_mac_p.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFURLEnumerator.h>
+
+#include <sys/mount.h>
+
+#define QT_STATFSBUF struct statfs
+#define QT_STATFS ::statfs
+
+QT_BEGIN_NAMESPACE
+
+void QStorageInfoPrivate::initRootPath()
+{
+ rootPath = QFileInfo(rootPath).canonicalFilePath();
+
+ if (rootPath.isEmpty())
+ return;
+
+ retrieveUrlProperties(true);
+}
+
+void QStorageInfoPrivate::doStat()
+{
+ initRootPath();
+
+ if (rootPath.isEmpty())
+ return;
+
+ retrieveLabel();
+ retrievePosixInfo();
+ retrieveUrlProperties();
+}
+
+void QStorageInfoPrivate::retrievePosixInfo()
+{
+ QT_STATFSBUF statfs_buf;
+ int result = QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf);
+ if (result == 0) {
+ device = QByteArray(statfs_buf.f_mntfromname);
+ readOnly = (statfs_buf.f_flags & MNT_RDONLY) != 0;
+ fileSystemType = QByteArray(statfs_buf.f_fstypename);
+ }
+}
+
+static inline qint64 CFDictionaryGetInt64(CFDictionaryRef dictionary, const void *key)
+{
+ CFNumberRef cfNumber = (CFNumberRef)CFDictionaryGetValue(dictionary, key);
+ if (!cfNumber)
+ return -1;
+ qint64 result;
+ bool ok = CFNumberGetValue(cfNumber, kCFNumberSInt64Type, &result);
+ if (!ok)
+ return -1;
+ return result;
+}
+
+void QStorageInfoPrivate::retrieveUrlProperties(bool initRootPath)
+{
+ static const void *rootPathKeys[] = { kCFURLVolumeURLKey };
+ static const void *propertyKeys[] = {
+ // kCFURLVolumeNameKey, // 10.7
+ // kCFURLVolumeLocalizedNameKey, // 10.7
+ kCFURLVolumeTotalCapacityKey,
+ kCFURLVolumeAvailableCapacityKey,
+ // kCFURLVolumeIsReadOnlyKey // 10.7
+ };
+ size_t size = (initRootPath ? sizeof(rootPathKeys) : sizeof(propertyKeys)) / sizeof(void*);
+ QCFType<CFArrayRef> keys = CFArrayCreate(kCFAllocatorDefault,
+ initRootPath ? rootPathKeys : propertyKeys,
+ size,
+ Q_NULLPTR);
+
+ if (!keys)
+ return;
+
+ const QCFString cfPath = rootPath;
+ if (initRootPath)
+ rootPath.clear();
+
+ QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+ cfPath,
+ kCFURLPOSIXPathStyle,
+ true);
+ if (!url)
+ return;
+
+ CFErrorRef error;
+ QCFType<CFDictionaryRef> map = CFURLCopyResourcePropertiesForKeys(url, keys, &error);
+
+ if (!map)
+ return;
+
+ if (initRootPath) {
+ const CFURLRef rootUrl = (CFURLRef)CFDictionaryGetValue(map, kCFURLVolumeURLKey);
+ if (!rootUrl)
+ return;
+
+ rootPath = QCFString(CFURLCopyFileSystemPath(rootUrl, kCFURLPOSIXPathStyle));
+ valid = true;
+ ready = true;
+
+ return;
+ }
+
+ bytesTotal = CFDictionaryGetInt64(map, kCFURLVolumeTotalCapacityKey);
+ bytesAvailable = CFDictionaryGetInt64(map, kCFURLVolumeAvailableCapacityKey);
+ bytesFree = bytesAvailable;
+}
+
+void QStorageInfoPrivate::retrieveLabel()
+{
+#if !defined(Q_OS_IOS)
+ // deprecated since 10.8
+ FSRef ref;
+ FSPathMakeRef(reinterpret_cast<const UInt8*>(QFile::encodeName(rootPath).constData()),
+ &ref,
+ Q_NULLPTR);
+
+ // deprecated since 10.8
+ FSCatalogInfo catalogInfo;
+ OSErr error;
+ error = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &catalogInfo, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR);
+ if (error != noErr)
+ return;
+
+ // deprecated (use CFURLCopyResourcePropertiesForKeys for 10.7 and higher)
+ HFSUniStr255 volumeName;
+ error = FSGetVolumeInfo(catalogInfo.volume,
+ 0,
+ Q_NULLPTR,
+ kFSVolInfoFSInfo,
+ Q_NULLPTR,
+ &volumeName,
+ Q_NULLPTR);
+ if (error == noErr)
+ name = QCFString(FSCreateStringFromHFSUniStr(Q_NULLPTR, &volumeName));
+#endif
+}
+
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ QList<QStorageInfo> volumes;
+
+ QCFType<CFURLEnumeratorRef> enumerator;
+ enumerator = CFURLEnumeratorCreateForMountedVolumes(Q_NULLPTR,
+ kCFURLEnumeratorSkipInvisibles,
+ Q_NULLPTR);
+
+ CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
+ do {
+ CFURLRef url;
+ CFErrorRef error;
+ result = CFURLEnumeratorGetNextURL(enumerator, &url, &error);
+ if (result == kCFURLEnumeratorSuccess) {
+ const QCFString urlString = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
+ volumes.append(QStorageInfo(urlString));
+ }
+ } while (result != kCFURLEnumeratorEnd);
+
+ return volumes;
+}
+
+QStorageInfo QStorageInfoPrivate::root()
+{
+ return QStorageInfo(QStringLiteral("/"));
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
new file mode 100644
index 0000000000..9c8e51f475
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTORAGEINFO_P_H
+#define QSTORAGEINFO_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstorageinfo.h"
+
+QT_BEGIN_NAMESPACE
+
+class QStorageInfoPrivate : public QSharedData
+{
+public:
+ inline QStorageInfoPrivate() : QSharedData(),
+ bytesTotal(0), bytesFree(0), bytesAvailable(0),
+ readOnly(false), ready(false), valid(false)
+ {}
+
+ void initRootPath();
+ void doStat();
+
+ static QList<QStorageInfo> mountedVolumes();
+ static QStorageInfo root();
+
+protected:
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT)
+ void retreiveVolumeInfo();
+ void retreiveDiskFreeSpace();
+#elif defined(Q_OS_MAC)
+ void retrievePosixInfo();
+ void retrieveUrlProperties(bool initRootPath = false);
+ void retrieveLabel();
+#elif defined(Q_OS_UNIX)
+ void retreiveVolumeInfo();
+#endif
+
+public:
+ QString rootPath;
+ QByteArray device;
+ QByteArray fileSystemType;
+ QString name;
+
+ qint64 bytesTotal;
+ qint64 bytesFree;
+ qint64 bytesAvailable;
+
+ bool readOnly;
+ bool ready;
+ bool valid;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSTORAGEINFO_P_H
diff --git a/src/corelib/io/qloggingcategory_p.h b/src/corelib/io/qstorageinfo_stub.cpp
index 7802f017fd..7e70cb1386 100644
--- a/src/corelib/io/qloggingcategory_p.h
+++ b/src/corelib/io/qstorageinfo_stub.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -39,28 +39,31 @@
**
****************************************************************************/
-#ifndef QLOGGINGCATEGORY_P_H
-#define QLOGGINGCATEGORY_P_H
+#include "qstorageinfo_p.h"
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of a number of Qt sources files. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
+QT_BEGIN_NAMESPACE
-#include <QtCore/qglobal.h>
+void QStorageInfoPrivate::initRootPath()
+{
+ Q_UNIMPLEMENTED();
+ rootPath = QString();
+}
-QT_BEGIN_NAMESPACE
+void QStorageInfoPrivate::doStat()
+{
+ Q_UNIMPLEMENTED();
+}
-// unique pointer to default category
-// (allows to compare for pointers instead of strings)
-extern const char qtDefaultCategoryName[];
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ Q_UNIMPLEMENTED();
+ return QList<QStorageInfo>();
+}
-QT_END_NAMESPACE
+QStorageInfo QStorageInfoPrivate::root()
+{
+ Q_UNIMPLEMENTED();
+ return QStorageInfo();
+}
-#endif // QLOGGINGCATEGORY_P_H
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
new file mode 100644
index 0000000000..b22358ed27
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -0,0 +1,456 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstorageinfo_p.h"
+
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qtextstream.h>
+
+#include <QtCore/private/qcore_unix_p.h>
+
+#include <errno.h>
+#include <sys/stat.h>
+
+#if defined(Q_OS_BSD4)
+# include <sys/mount.h>
+#elif defined(Q_OS_ANDROID)
+# include <sys/mount.h>
+# include <sys/vfs.h>
+# include <mntent.h>
+#elif defined(Q_OS_QNX)
+# include <sys/statvfs.h>
+#elif defined(Q_OS_LINUX)
+# include <mntent.h>
+# include <sys/statvfs.h>
+#elif defined(Q_OS_SOLARIS)
+# include <sys/mnttab.h>
+#endif
+
+#if defined(Q_OS_BSD4)
+# define QT_STATFSBUF struct statvfs
+# define QT_STATFS ::statvfs
+#elif defined(Q_OS_ANDROID)
+# define QT_STATFS ::statfs
+# define QT_STATFSBUF struct statfs
+# if !defined(ST_RDONLY)
+# define ST_RDONLY 1 // hack for missing define on Android
+# endif
+#else
+# if defined(QT_LARGEFILE_SUPPORT)
+# define QT_STATFSBUF struct statvfs64
+# define QT_STATFS ::statvfs64
+# else
+# define QT_STATFSBUF struct statvfs
+# define QT_STATFS ::statvfs
+# endif // QT_LARGEFILE_SUPPORT
+#endif // Q_OS_BSD4
+
+QT_BEGIN_NAMESPACE
+
+static bool isPseudoFs(const QString &mountDir, const QByteArray &type)
+{
+ if (mountDir.startsWith(QStringLiteral("/dev"))
+ || mountDir.startsWith(QStringLiteral("/proc"))
+ || mountDir.startsWith(QStringLiteral("/run"))
+ || mountDir.startsWith(QStringLiteral("/sys"))
+ || mountDir.startsWith(QStringLiteral("/var/run"))
+ || mountDir.startsWith(QStringLiteral("/var/lock"))) {
+ return true;
+ }
+#if defined(Q_OS_LINUX)
+ if (type == "rootfs")
+ return true;
+#else
+ Q_UNUSED(type);
+#endif
+
+ return false;
+}
+
+class QStorageIterator
+{
+public:
+ QStorageIterator();
+ ~QStorageIterator();
+
+ inline bool isValid() const;
+ inline bool next();
+ inline QString rootPath() const;
+ inline QByteArray fileSystemType() const;
+ inline QByteArray device() const;
+private:
+#if defined(Q_OS_BSD4)
+ statfs *stat_buf;
+ int entryCount;
+ int currentIndex;
+#elif defined(Q_OS_SOLARIS)
+ FILE *fp;
+ mnttab mnt;
+#elif defined(Q_OS_ANDROID)
+ QFile file;
+ QByteArray m_rootPath;
+ QByteArray m_fileSystemType;
+ QByteArray m_device;
+#elif defined(Q_OS_LINUX)
+ FILE *fp;
+ mntent mnt;
+ QByteArray buffer;
+#endif
+};
+
+#if defined(Q_OS_BSD4)
+
+inline QStorageIterator::QStorageIterator()
+ : entryCount(::getmntinfo(&stat_buf, 0)),
+ currentIndex(-1)
+{
+}
+
+inline QStorageIterator::~QStorageIterator()
+{
+}
+
+inline bool QStorageIterator::isValid() const
+{
+ return entryCount != -1;
+}
+
+inline bool QStorageIterator::next()
+{
+ return ++currentIndex < entryCount;
+}
+
+inline QString QStorageIterator::rootPath() const
+{
+ return QFile::decodeName(stat_buf[currentIndex].f_mntonname);
+}
+
+inline QByteArray QStorageIterator::fileSystemType() const
+{
+ return QByteArray(stat_buf[currentIndex].f_fstypename);
+}
+
+inline QByteArray QStorageIterator::device() const
+{
+ return QByteArray(stat_buf[currentIndex].f_mntfromname);
+}
+
+#elif defined(Q_OS_SOLARIS)
+
+static const char pathMounted[] = "/etc/mnttab";
+
+inline QStorageIterator::QStorageIterator()
+{
+ const int fd = qt_safe_open(pathMounted, O_RDONLY);
+ fp = ::fdopen(fd, "r");
+}
+
+inline QStorageIterator::~QStorageIterator()
+{
+ if (fp)
+ ::fclose(fp);
+}
+
+inline bool QStorageIterator::isValid() const
+{
+ return fp != Q_NULLPTR;
+}
+
+inline bool QStorageIterator::next()
+{
+ return ::getmntent(fp, &mnt) == Q_NULLPTR;
+}
+
+inline QString QStorageIterator::rootPath() const
+{
+ return QFile::decodeName(mnt->mnt_mountp);
+}
+
+inline QByteArray QStorageIterator::fileSystemType() const
+{
+ return QByteArray(mnt->mnt_fstype);
+}
+
+inline QByteArray QStorageIterator::device() const
+{
+ return QByteArray(mnt->mnt_mntopts);
+}
+
+#elif defined(Q_OS_ANDROID)
+
+static const char pathMounted[] = "/proc/mounts";
+
+inline QStorageIterator::QStorageIterator()
+{
+ file.setFileName(pathMounted);
+ file.open(QIODevice::ReadOnly | QIODevice::Text);
+}
+
+inline QStorageIterator::~QStorageIterator()
+{
+}
+
+inline bool QStorageIterator::isValid() const
+{
+ return file.isOpen();
+}
+
+inline bool QStorageIterator::next()
+{
+ QList<QByteArray> data;
+ do {
+ const QByteArray line = file.readLine();
+ data = line.split(' ');
+ } while (data.count() < 3 && !file.atEnd());
+
+ if (file.atEnd())
+ return false;
+ m_device = data.at(0);
+ m_rootPath = data.at(1);
+ m_fileSystemType = data.at(2);
+
+ return true;
+}
+
+inline QString QStorageIterator::rootPath() const
+{
+ return QFile::decodeName(m_rootPath);
+}
+
+inline QByteArray QStorageIterator::fileSystemType() const
+{
+ return m_fileSystemType;
+}
+
+inline QByteArray QStorageIterator::device() const
+{
+ return m_device;
+}
+
+#elif defined(Q_OS_LINUX)
+
+static const char pathMounted[] = "/etc/mtab";
+static const int bufferSize = 3*PATH_MAX; // 2 paths (mount point+device) and metainfo
+
+inline QStorageIterator::QStorageIterator() :
+ buffer(QByteArray(bufferSize, 0))
+{
+ fp = ::setmntent(pathMounted, "r");
+}
+
+inline QStorageIterator::~QStorageIterator()
+{
+ if (fp)
+ ::endmntent(fp);
+}
+
+inline bool QStorageIterator::isValid() const
+{
+ return fp != Q_NULLPTR;
+}
+
+inline bool QStorageIterator::next()
+{
+ return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != Q_NULLPTR;
+}
+
+inline QString QStorageIterator::rootPath() const
+{
+ return QFile::decodeName(mnt.mnt_dir);
+}
+
+inline QByteArray QStorageIterator::fileSystemType() const
+{
+ return QByteArray(mnt.mnt_type);
+}
+
+inline QByteArray QStorageIterator::device() const
+{
+ return QByteArray(mnt.mnt_fsname);
+}
+
+#else
+
+inline QStorageIterator::QStorageIterator()
+{
+}
+
+inline QStorageIterator::~QStorageIterator()
+{
+}
+
+inline bool QStorageIterator::isValid() const
+{
+ return false;
+}
+
+inline bool QStorageIterator::next()
+{
+ return false;
+}
+
+inline QString QStorageIterator::rootPath() const
+{
+ return QString();
+}
+
+inline QByteArray QStorageIterator::fileSystemType() const
+{
+ return QByteArray();
+}
+
+inline QByteArray QStorageIterator::device() const
+{
+ return QByteArray();
+}
+
+#endif
+
+void QStorageInfoPrivate::initRootPath()
+{
+ rootPath = QFileInfo(rootPath).canonicalFilePath();
+
+ if (rootPath.isEmpty())
+ return;
+
+ QStorageIterator it;
+ if (!it.isValid()) {
+ rootPath = QStringLiteral("/");
+ return;
+ }
+
+ int maxLength = 0;
+ const QString oldRootPath = rootPath;
+ rootPath.clear();
+
+ while (it.next()) {
+ const QString mountDir = it.rootPath();
+ const QByteArray fsName = it.fileSystemType();
+ if (isPseudoFs(mountDir, fsName))
+ continue;
+ // we try to find most suitable entry
+ if (oldRootPath.startsWith(mountDir) && maxLength < mountDir.length()) {
+ maxLength = mountDir.length();
+ rootPath = mountDir;
+ device = it.device();
+ fileSystemType = fsName;
+ }
+ }
+}
+
+static inline QString retrieveLabel(const QByteArray &device)
+{
+#ifdef Q_OS_LINUX
+ static const char pathDiskByLabel[] = "/dev/disk/by-label";
+
+ QDirIterator it(QLatin1String(pathDiskByLabel), QDir::NoDotAndDotDot);
+ while (it.hasNext()) {
+ it.next();
+ QFileInfo fileInfo(it.fileInfo());
+ if (fileInfo.isSymLink() && fileInfo.symLinkTarget().toLocal8Bit() == device)
+ return fileInfo.fileName();
+ }
+#else
+ Q_UNUSED(device);
+#endif
+
+ return QString();
+}
+
+void QStorageInfoPrivate::doStat()
+{
+ initRootPath();
+ if (rootPath.isEmpty())
+ return;
+
+ retreiveVolumeInfo();
+ name = retrieveLabel(device);
+}
+
+void QStorageInfoPrivate::retreiveVolumeInfo()
+{
+ QT_STATFSBUF statfs_buf;
+ int result;
+ EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf));
+ if (result == 0) {
+ valid = true;
+ ready = true;
+
+ bytesTotal = statfs_buf.f_blocks * statfs_buf.f_bsize;
+ bytesFree = statfs_buf.f_bfree * statfs_buf.f_bsize;
+ bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_bsize;
+#if defined(Q_OS_ANDROID)
+#if defined(_STATFS_F_FLAGS)
+ readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;
+#endif
+#else
+ readOnly = (statfs_buf.f_flag & ST_RDONLY) != 0;
+#endif
+ }
+}
+
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ QStorageIterator it;
+ if (!it.isValid())
+ return QList<QStorageInfo>() << root();
+
+ QList<QStorageInfo> volumes;
+
+ while (it.next()) {
+ const QString mountDir = it.rootPath();
+ const QByteArray fsName = it.fileSystemType();
+ if (isPseudoFs(mountDir, fsName))
+ continue;
+
+ volumes.append(QStorageInfo(mountDir));
+ }
+
+ return volumes;
+}
+
+QStorageInfo QStorageInfoPrivate::root()
+{
+ return QStorageInfo(QStringLiteral("/"));
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp
new file mode 100644
index 0000000000..aa970778e6
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_win.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstorageinfo_p.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include <Windows.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int defaultBufferSize = MAX_PATH + 1;
+
+void QStorageInfoPrivate::initRootPath()
+{
+ rootPath = QFileInfo(rootPath).canonicalFilePath();
+
+ if (rootPath.isEmpty())
+ return;
+
+ QString path = QDir::toNativeSeparators(rootPath);
+ rootPath.clear();
+
+ if (path.startsWith(QStringLiteral("\\\\?\\")))
+ path.remove(0, 4);
+ if (path.length() < 2 || path.at(1) != QLatin1Char(':'))
+ return;
+ path[0] = path[0].toUpper();
+ if (!(path.at(0).unicode() >= 'A' && path.at(0).unicode() <= 'Z'))
+ return;
+ if (!path.endsWith(QLatin1Char('\\')))
+ path.append(QLatin1Char('\\'));
+
+ // ### test if disk mounted to folder on other disk
+ wchar_t buffer[defaultBufferSize];
+ if (::GetVolumePathName(reinterpret_cast<const wchar_t *>(path.utf16()), buffer, defaultBufferSize))
+ rootPath = QDir::fromNativeSeparators(QString::fromWCharArray(buffer));
+}
+
+static inline QByteArray getDevice(const QString &rootPath)
+{
+ const QString path = QDir::toNativeSeparators(rootPath);
+ const UINT type = ::GetDriveType(reinterpret_cast<const wchar_t *>(path.utf16()));
+ if (type == DRIVE_REMOTE) {
+ QVarLengthArray<char, 256> buffer(256);
+ DWORD bufferLength = buffer.size();
+ DWORD result;
+ UNIVERSAL_NAME_INFO *remoteNameInfo;
+ do {
+ buffer.resize(bufferLength);
+ remoteNameInfo = reinterpret_cast<UNIVERSAL_NAME_INFO *>(buffer.data());
+ result = ::WNetGetUniversalName(reinterpret_cast<const wchar_t *>(path.utf16()),
+ UNIVERSAL_NAME_INFO_LEVEL,
+ remoteNameInfo,
+ &bufferLength);
+ } while (result == ERROR_MORE_DATA);
+ if (result == NO_ERROR)
+ return QString::fromWCharArray(remoteNameInfo->lpUniversalName).toUtf8();
+ return QByteArray();
+ }
+
+ wchar_t deviceBuffer[51];
+ if (::GetVolumeNameForVolumeMountPoint(reinterpret_cast<const wchar_t *>(path.utf16()),
+ deviceBuffer,
+ sizeof(deviceBuffer) / sizeof(wchar_t))) {
+ return QString::fromWCharArray(deviceBuffer).toLatin1();
+ }
+ return QByteArray();
+}
+
+void QStorageInfoPrivate::doStat()
+{
+ initRootPath();
+ if (rootPath.isEmpty())
+ return;
+
+ retreiveVolumeInfo();
+ device = getDevice(rootPath);
+ retreiveDiskFreeSpace();
+}
+
+void QStorageInfoPrivate::retreiveVolumeInfo()
+{
+ const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+
+ const QString path = QDir::toNativeSeparators(rootPath);
+ wchar_t nameBuffer[defaultBufferSize];
+ wchar_t fileSystemTypeBuffer[defaultBufferSize];
+ DWORD fileSystemFlags = 0;
+ const bool result = ::GetVolumeInformation(reinterpret_cast<const wchar_t *>(path.utf16()),
+ nameBuffer,
+ defaultBufferSize,
+ Q_NULLPTR,
+ Q_NULLPTR,
+ &fileSystemFlags,
+ fileSystemTypeBuffer,
+ defaultBufferSize);
+ if (!result) {
+ ready = false;
+ valid = ::GetLastError() == ERROR_NOT_READY;
+ } else {
+ ready = true;
+ valid = true;
+
+ fileSystemType = QString::fromWCharArray(fileSystemTypeBuffer).toLatin1();
+ name = QString::fromWCharArray(nameBuffer);
+
+ readOnly = (fileSystemFlags & FILE_READ_ONLY_VOLUME) != 0;
+ }
+
+ ::SetErrorMode(oldmode);
+}
+
+void QStorageInfoPrivate::retreiveDiskFreeSpace()
+{
+ const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+
+ const QString path = QDir::toNativeSeparators(rootPath);
+ ::GetDiskFreeSpaceEx(reinterpret_cast<const wchar_t *>(path.utf16()),
+ PULARGE_INTEGER(&bytesAvailable),
+ PULARGE_INTEGER(&bytesTotal),
+ PULARGE_INTEGER(&bytesFree));
+
+ ::SetErrorMode(oldmode);
+}
+
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ QList<QStorageInfo> volumes;
+
+ QString driveName = QStringLiteral("A:/");
+ const UINT oldmode = ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ quint32 driveBits = quint32(::GetLogicalDrives()) & 0x3ffffff;
+ ::SetErrorMode(oldmode);
+ while (driveBits) {
+ if (driveBits & 1) {
+ QStorageInfo drive(driveName);
+ if (!drive.rootPath().isEmpty()) // drive exists, but not mounted
+ volumes.append(drive);
+ }
+ driveName[0] = driveName[0].unicode() + 1;
+ driveBits = driveBits >> 1;
+ }
+
+ return volumes;
+}
+
+QStorageInfo QStorageInfoPrivate::root()
+{
+ return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index d88ffb7c84..54b59e802e 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -235,6 +235,8 @@ static bool createFileFromTemplate(NativeFileHandle &file,
//************* QTemporaryFileEngine
QTemporaryFileEngine::~QTemporaryFileEngine()
{
+ Q_D(QFSFileEngine);
+ d->unmapAll();
QFSFileEngine::close();
}
@@ -363,6 +365,7 @@ bool QTemporaryFileEngine::remove()
Q_D(QFSFileEngine);
// Since the QTemporaryFileEngine::close() does not really close the file,
// we must explicitly call QFSFileEngine::close() before we remove it.
+ d->unmapAll();
QFSFileEngine::close();
if (QFSFileEngine::remove()) {
d->fileEntry.clear();
diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp
index b67df6a4a6..974a7c2be4 100644
--- a/src/corelib/io/qtextstream.cpp
+++ b/src/corelib/io/qtextstream.cpp
@@ -2203,7 +2203,7 @@ void QTextStreamPrivate::putNumber(qulonglong number, bool negative)
// add thousands group separators. For backward compatibility we
// don't add a group separator for C locale.
- if (locale != QLocale::c())
+ if (locale != QLocale::c() && !locale.numberOptions().testFlag(QLocale::OmitGroupSeparator))
flags |= QLocaleData::ThousandsGroup;
const QLocaleData *dd = locale.d->m_data;
@@ -2414,6 +2414,8 @@ QTextStream &QTextStream::operator<<(double f)
flags |= QLocaleData::CapitalEorX;
if (numberFlags() & ForcePoint)
flags |= QLocaleData::Alternate;
+ if (locale() != QLocale::c() && !(locale().numberOptions() & QLocale::OmitGroupSeparator))
+ flags |= QLocaleData::ThousandsGroup;
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/qtldurl.cpp b/src/corelib/io/qtldurl.cpp
index dd4301e9f1..f8eddedf2f 100644
--- a/src/corelib/io/qtldurl.cpp
+++ b/src/corelib/io/qtldurl.cpp
@@ -43,7 +43,8 @@
#include "qurl.h"
#include "private/qurltlds_p.h"
#include "private/qtldurl_p.h"
-#include "QtCore/qstringlist.h"
+#include "QtCore/qstring.h"
+#include "QtCore/qvector.h"
#include "QtCore/qhash.h"
QT_BEGIN_NAMESPACE
@@ -80,7 +81,8 @@ static bool containsTLDEntry(const QString &entry)
Q_CORE_EXPORT QString qTopLevelDomain(const QString &domain)
{
- QStringList sections = domain.toLower().split(QLatin1Char('.'), QString::SkipEmptyParts);
+ const QString domainLower = domain.toLower();
+ QVector<QStringRef> sections = domainLower.splitRef(QLatin1Char('.'), QString::SkipEmptyParts);
if (sections.isEmpty())
return QString();
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index c109fc4d3a..5700b9ab24 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -364,6 +364,29 @@
*/
/*!
+ \enum QUrl::UserInputResolutionOption
+ \since 5.4
+
+ The user input resolution options define how fromUserInput() should
+ interpret strings that could either be a relative path or the short
+ form of a HTTP URL. For instance \c{file.pl} can be either a local file
+ or the URL \c{http://file.pl}.
+
+ \value DefaultResolution The default resolution mechanism is to check
+ whether a local file exists, in the working
+ directory given to fromUserInput, and only
+ return a local path in that case. Otherwise a URL
+ is assumed.
+ \value AssumeLocalFile This option makes fromUserInput() always return
+ a local path unless the input contains a scheme, such as
+ \c{http://file.pl}. This is useful for applications
+ such as text editors, which are able to create
+ the file if it doesn't exist.
+
+ \sa fromUserInput()
+*/
+
+/*!
\fn QUrl::QUrl(QUrl &&other)
Move-constructs a QUrl instance, making it point at the same
@@ -3714,11 +3737,15 @@ bool QUrl::isDetached() const
"//servername/path/to/file.txt". Note that only certain platforms can
actually open this file using QFile::open().
+ An empty \a localFile leads to an empty URL (since Qt 5.4).
+
\sa toLocalFile(), isLocalFile(), QDir::toNativeSeparators()
*/
QUrl QUrl::fromLocalFile(const QString &localFile)
{
QUrl url;
+ if (localFile.isEmpty())
+ return url;
url.setScheme(fileScheme());
QString deslashified = QDir::fromNativeSeparators(localFile);
@@ -4094,6 +4121,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Returns a valid URL from a user supplied \a userInput string if one can be
deducted. In the case that is not possible, an invalid QUrl() is returned.
+ This overload takes a \a workingDirectory path, in order to be able to
+ handle relative paths. This is especially useful when handling command
+ line arguments.
+ If \a workingDirectory is empty, no handling of relative paths will be done,
+ so this method will behave like its one argument overload.
+
+ By default, an input string that looks like a relative path will only be treated
+ as such if the file actually exists in the given working directory.
+
+ If the application can handle files that don't exist yet, it should pass the
+ flag AssumeLocalFile in \a options.
+
+ \since 5.4
+*/
+QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirectory,
+ UserInputResolutionOptions options)
+{
+ QString trimmedString = userInput.trimmed();
+
+ if (trimmedString.isEmpty())
+ return QUrl();
+
+ // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes)
+ QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
+ if (url.isRelative() && !QDir::isAbsolutePath(trimmedString)) {
+ QFileInfo fileInfo(QDir(workingDirectory), trimmedString);
+ if ((options & AssumeLocalFile) || fileInfo.exists())
+ return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+ }
+
+ return fromUserInput(trimmedString);
+}
+
+/*!
+ Returns a valid URL from a user supplied \a userInput string if one can be
+ deducted. In the case that is not possible, an invalid QUrl() is returned.
+
\since 4.6
Most applications that can browse the web, allow the user to input a URL
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index 602e91ce30..d621d7ef03 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -199,7 +199,16 @@ public:
QByteArray toEncoded(FormattingOptions options = FullyEncoded) const;
static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode);
+ enum UserInputResolutionOption {
+ DefaultResolution,
+ AssumeLocalFile
+ };
+ Q_DECLARE_FLAGS(UserInputResolutionOptions, UserInputResolutionOption)
+
static QUrl fromUserInput(const QString &userInput);
+ // ### Qt6 merge with fromUserInput(QString), by adding = QString()
+ static QUrl fromUserInput(const QString &userInput, const QString &workingDirectory,
+ UserInputResolutionOptions options = DefaultResolution);
bool isValid() const;
QString errorString() const;
diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp
index 33583afb78..06746c0597 100644
--- a/src/corelib/io/qwinoverlappedionotifier.cpp
+++ b/src/corelib/io/qwinoverlappedionotifier.cpp
@@ -41,6 +41,7 @@
#include "qwinoverlappedionotifier_p.h"
#include <qdebug.h>
+#include <qelapsedtimer.h>
#include <qmutex.h>
#include <qpointer.h>
#include <qqueue.h>
@@ -293,35 +294,58 @@ void QWinOverlappedIoNotifier::setEnabled(bool enabled)
}
/*!
- * Wait synchronously for the notified signal.
+ * Wait synchronously for any notified signal.
*
- * The function returns true if the notified signal was emitted for
- * the I/O operation that corresponds to the OVERLAPPED object.
+ * The function returns a pointer to the OVERLAPPED object corresponding to the completed I/O
+ * operation. In case no I/O operation was completed during the \a msec timeout, this function
+ * returns a null pointer.
*/
-bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped)
+OVERLAPPED *QWinOverlappedIoNotifier::waitForAnyNotified(int msecs)
{
Q_D(QWinOverlappedIoNotifier);
if (!d->iocp->isRunning()) {
- qWarning("Called QWinOverlappedIoNotifier::waitForNotified on inactive notifier.");
- return false;
+ qWarning("Called QWinOverlappedIoNotifier::waitForAnyNotified on inactive notifier.");
+ return 0;
}
+ if (msecs == 0)
+ d->iocp->drainQueue();
+
+ switch (WaitForSingleObject(d->hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs))) {
+ case WAIT_OBJECT_0:
+ ReleaseSemaphore(d->hSemaphore, 1, NULL);
+ return d->_q_notified();
+ case WAIT_TIMEOUT:
+ return 0;
+ default:
+ qErrnoWarning("QWinOverlappedIoNotifier::waitForAnyNotified: WaitForSingleObject failed.");
+ return 0;
+ }
+}
+
+/*!
+ * Wait synchronously for the notified signal.
+ *
+ * The function returns true if the notified signal was emitted for
+ * the I/O operation that corresponds to the OVERLAPPED object.
+ */
+bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped)
+{
+ int t = msecs;
+ QElapsedTimer stopWatch;
+ stopWatch.start();
forever {
- if (msecs == 0)
- d->iocp->drainQueue();
- DWORD result = WaitForSingleObject(d->hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs));
- if (result == WAIT_OBJECT_0) {
- ReleaseSemaphore(d->hSemaphore, 1, NULL);
- if (d->_q_notified() == overlapped)
- return true;
- continue;
- } else if (result == WAIT_TIMEOUT) {
+ OVERLAPPED *triggeredOverlapped = waitForAnyNotified(t);
+ if (!triggeredOverlapped)
return false;
+ if (triggeredOverlapped == overlapped)
+ return true;
+ if (msecs != -1) {
+ t = msecs - stopWatch.elapsed();
+ if (t < 0)
+ return false;
}
}
-
- qErrnoWarning("QWinOverlappedIoNotifier::waitForNotified: WaitForSingleObject failed.");
- return false;
}
/*!
diff --git a/src/corelib/io/qwinoverlappedionotifier_p.h b/src/corelib/io/qwinoverlappedionotifier_p.h
index f90fd2e615..25c0f3a081 100644
--- a/src/corelib/io/qwinoverlappedionotifier_p.h
+++ b/src/corelib/io/qwinoverlappedionotifier_p.h
@@ -76,6 +76,7 @@ public:
Qt::HANDLE handle() const;
void setEnabled(bool enabled);
+ OVERLAPPED *waitForAnyNotified(int msecs);
bool waitForNotified(int msecs, OVERLAPPED *overlapped);
Q_SIGNALS: