summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri5
-rw-r--r--src/corelib/io/qabstractfileengine.cpp2
-rw-r--r--src/corelib/io/qbuffer.cpp2
-rw-r--r--src/corelib/io/qdiriterator.cpp2
-rw-r--r--src/corelib/io/qfile.cpp64
-rw-r--r--src/corelib/io/qfile.h3
-rw-r--r--src/corelib/io/qfiledevice.cpp2
-rw-r--r--src/corelib/io/qfileinfo.cpp23
-rw-r--r--src/corelib/io/qfileinfo.h1
-rw-r--r--src/corelib/io/qfilesystemengine_mac.mm83
-rw-r--r--src/corelib/io/qfilesystemengine_p.h3
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp216
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp301
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h21
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp2
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp2
-rw-r--r--src/corelib/io/qfsfileengine.cpp116
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp77
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp74
-rw-r--r--src/corelib/io/qiodevice.cpp4
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice.cpp20
-rw-r--r--src/corelib/io/qprocess.cpp26
-rw-r--r--src/corelib/io/qprocess_unix.cpp37
-rw-r--r--src/corelib/io/qprocess_win.cpp15
-rw-r--r--src/corelib/io/qresource.cpp224
-rw-r--r--src/corelib/io/qresource.h5
-rw-r--r--src/corelib/io/qsavefile.cpp2
-rw-r--r--src/corelib/io/qsettings.cpp61
-rw-r--r--src/corelib/io/qsettings_p.h13
-rw-r--r--src/corelib/io/qsettings_wasm.cpp259
-rw-r--r--src/corelib/io/qurl.cpp9
-rw-r--r--src/corelib/io/qurl.h4
32 files changed, 1276 insertions, 402 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index fe81689932..a33ffe75f2 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -136,6 +136,7 @@ qtConfig(settings) {
} else: darwin:!nacl {
SOURCES += io/qsettings_mac.cpp
}
+ wasm : SOURCES += io/qsettings_wasm.cpp
}
win32 {
@@ -182,7 +183,9 @@ win32 {
SOURCES += io/qstorageinfo_mac.cpp
qtConfig(processenvironment): \
OBJECTIVE_SOURCES += io/qprocess_darwin.mm
- OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
+ OBJECTIVE_SOURCES += \
+ io/qstandardpaths_mac.mm \
+ io/qfilesystemengine_mac.mm
osx {
LIBS += -framework DiskArbitration -framework IOKit
} else {
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index 8a1679c5af..070139b608 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -658,7 +658,7 @@ QStringList QAbstractFileEngine::entryList(QDir::Filters filters, const QStringL
QAbstractFileEngine::FileFlags QAbstractFileEngine::fileFlags(FileFlags type) const
{
Q_UNUSED(type);
- return nullptr;
+ return {};
}
/*!
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index 8e980733de..595fcd2724 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -227,7 +227,7 @@ QBuffer::~QBuffer()
\snippet buffer/buffer.cpp 4
- If \a byteArray is 0, the buffer creates its own internal
+ If \a byteArray is \nullptr, the buffer creates its own internal
QByteArray to work on. This byte array is initially empty.
\sa buffer(), setData(), open()
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index ce436b06e3..1cf6b1be08 100644
--- a/src/corelib/io/qdiriterator.cpp
+++ b/src/corelib/io/qdiriterator.cpp
@@ -181,7 +181,7 @@ QDirIteratorPrivate::QDirIteratorPrivate(const QFileSystemEntry &entry, const QS
#elif QT_CONFIG(regularexpression)
nameRegExps.reserve(nameFilters.size());
for (const auto &filter : nameFilters) {
- QString re = QRegularExpression::anchoredPattern(QRegularExpression::wildcardToRegularExpression(filter));
+ QString re = QRegularExpression::wildcardToRegularExpression(filter);
nameRegExps.append(
QRegularExpression(re, (filters & QDir::CaseSensitive) ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption));
}
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index 95f03ef816..0cdc5bd6d3 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -251,7 +251,7 @@ QFile::QFile(QFilePrivate &dd)
Constructs a QFile object.
*/
QFile::QFile()
- : QFileDevice(*new QFilePrivate, 0)
+ : QFileDevice(*new QFilePrivate, nullptr)
{
}
/*!
@@ -265,7 +265,7 @@ QFile::QFile(QObject *parent)
Constructs a new file object to represent the file with the given \a name.
*/
QFile::QFile(const QString &name)
- : QFileDevice(*new QFilePrivate, 0)
+ : QFileDevice(*new QFilePrivate, nullptr)
{
Q_D(QFile);
d->fileName = name;
@@ -552,6 +552,66 @@ QFile::remove(const QString &fileName)
}
/*!
+ \since 5.15
+
+ Moves the file specified by fileName() to the trash. Returns \c true if successful,
+ and sets the fileName() to the path at which the file can be found within the trash;
+ otherwise returns \c false.
+
+ \note On systems where the system API doesn't report the location of the file in the
+ trash, fileName() will be set to the null string once the file has been moved. On
+ systems that don't have a trash can, this function always returns false.
+*/
+bool
+QFile::moveToTrash()
+{
+ Q_D(QFile);
+ if (d->fileName.isEmpty() &&
+ !static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) {
+ qWarning("QFile::remove: Empty or null file name");
+ return false;
+ }
+ unsetError();
+ close();
+ if (error() == QFile::NoError) {
+ QFileSystemEntry fileEntry(d->fileName);
+ QFileSystemEntry trashEntry;
+ QSystemError error;
+ if (QFileSystemEngine::moveFileToTrash(fileEntry, trashEntry, error)) {
+ setFileName(trashEntry.filePath());
+ unsetError();
+ return true;
+ }
+ d->setError(QFile::RenameError, error.toString());
+ }
+ return false;
+}
+
+/*!
+ \since 5.15
+ \overload
+
+ Moves the file specified by fileName() to the trash. Returns \c true if successful,
+ and sets \a pathInTrash (if provided) to the path at which the file can be found within
+ the trash; otherwise returns \c false.
+
+ \note On systems where the system API doesn't report the path of the file in the
+ trash, \a pathInTrash will be set to the null string once the file has been moved.
+ On systems that don't have a trash can, this function always returns false.
+*/
+bool
+QFile::moveToTrash(const QString &fileName, QString *pathInTrash)
+{
+ QFile file(fileName);
+ if (file.moveToTrash()) {
+ if (pathInTrash)
+ *pathInTrash = file.fileName();
+ return true;
+ }
+ return false;
+}
+
+/*!
Renames the file currently specified by fileName() to \a newName.
Returns \c true if successful; otherwise returns \c false.
diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h
index 2099b2852f..917fec4e1a 100644
--- a/src/corelib/io/qfile.h
+++ b/src/corelib/io/qfile.h
@@ -125,6 +125,9 @@ public:
bool remove();
static bool remove(const QString &fileName);
+ bool moveToTrash();
+ static bool moveToTrash(const QString &fileName, QString *pathInTrash = nullptr);
+
bool rename(const QString &newName);
static bool rename(const QString &oldName, const QString &newName);
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index ee619d99cc..b0aba3193c 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -202,7 +202,7 @@ QFileDevice::QFileDevice(QFileDevicePrivate &dd)
\internal
*/
QFileDevice::QFileDevice()
- : QIODevice(*new QFileDevicePrivate, 0)
+ : QIODevice(*new QFileDevicePrivate, nullptr)
{
}
/*!
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 89834de29f..64b1557231 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -134,7 +134,7 @@ uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) cons
// extra syscall. Bundle detecton on Mac can be slow, expecially on network
// paths, so we separate out that as well.
- QAbstractFileEngine::FileFlags req = nullptr;
+ QAbstractFileEngine::FileFlags req;
uint cachedFlags = 0;
if (request & (QAbstractFileEngine::FlagsMask | QAbstractFileEngine::TypesMask)) {
@@ -1145,6 +1145,27 @@ bool QFileInfo::isShortcut() const
[d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); });
}
+
+/*!
+ \since 5.15
+
+ Returns \c true if the object points to a junction;
+ otherwise returns \c false.
+
+ Junctions only exist on Windows' NTFS file system, and are typically
+ created by the \c{mklink} command. They can be thought of as symlinks for
+ directories, and can only be created for absolute paths on the local
+ volume.
+*/
+bool QFileInfo::isJunction() const
+{
+ Q_D(const QFileInfo);
+ return d->checkAttribute<bool>(
+ QFileSystemMetaData::LegacyLinkType,
+ [d]() { return d->metaData.isJunction(); },
+ [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); });
+}
+
/*!
Returns \c true if the object points to a directory or to a symbolic
link to a directory, and that directory is the root directory; otherwise
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index 3ac028085a..7c7ff56ae4 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -113,6 +113,7 @@ public:
bool isSymLink() const;
bool isSymbolicLink() const;
bool isShortcut() const;
+ bool isJunction() const;
bool isRoot() const;
bool isBundle() const;
diff --git a/src/corelib/io/qfilesystemengine_mac.mm b/src/corelib/io/qfilesystemengine_mac.mm
new file mode 100644
index 0000000000..258ae2e8e0
--- /dev/null
+++ b/src/corelib/io/qfilesystemengine_mac.mm
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qfilesystemengine_p.h"
+#include "qfile.h"
+#include "qurl.h"
+
+#include <QtCore/private/qcore_mac_p.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ This implementation does not enable the "put back" option in Finder
+ for the trashed object. The only way to get this is to use Finder automation,
+ which would query the user for permission to access Finder using a modal,
+ blocking dialog - which we definitely can't have in a console application.
+
+ Using Finder would also play the trash sound, which we don't want either in
+ such a core API; applications that want that can play the sound themselves.
+*/
+//static
+bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
+ QFileSystemEntry &newLocation, QSystemError &error)
+{
+#ifdef Q_OS_MACOS // desktop macOS has a trash can
+ QMacAutoReleasePool pool;
+
+ QFileInfo info(source.filePath());
+ NSString *filepath = info.filePath().toNSString();
+ NSURL *fileurl = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
+ NSURL *resultingUrl = nil;
+ NSError *nserror = nil;
+ NSFileManager *fm = [NSFileManager defaultManager];
+ if ([fm trashItemAtURL:fileurl resultingItemURL:&resultingUrl error:&nserror] != YES) {
+ error = QSystemError(nserror.code, QSystemError::NativeError);
+ return false;
+ }
+ newLocation = QFileSystemEntry(QUrl::fromNSURL(resultingUrl).path());
+ return true;
+#else // watch, tv, iOS don't have a trash can
+ return false;
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h
index ecfdc03743..555483a972 100644
--- a/src/corelib/io/qfilesystemengine_p.h
+++ b/src/corelib/io/qfilesystemengine_p.h
@@ -88,7 +88,7 @@ inline bool qIsFilenameBroken(const QFileSystemEntry &entry)
Q_RETURN_ON_INVALID_FILENAME("Broken filename passed to function", (result)); \
} while (false)
-class QFileSystemEngine
+class Q_AUTOTEST_EXPORT QFileSystemEngine
{
public:
static bool isCaseSensitive()
@@ -155,6 +155,7 @@ public:
static bool createLink(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
+ static bool moveFileToTrash(const QFileSystemEntry &source, QFileSystemEntry &newLocation, QSystemError &error);
static bool renameFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool renameOverwriteFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error);
static bool removeFile(const QFileSystemEntry &entry, QSystemError &error);
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 38cb6a423d..eaf4e2d9af 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -42,6 +42,8 @@
#include "qplatformdefs.h"
#include "qfilesystemengine_p.h"
#include "qfile.h"
+#include "qstorageinfo.h"
+#include "qtextstream.h"
#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/private/qcore_unix_p.h>
@@ -1076,14 +1078,14 @@ bool QFileSystemEngine::cloneFile(int srcfd, int dstfd, const QFileSystemMetaDat
// sendfile(2) is limited in the kernel to 2G - 4k
const size_t SendfileSize = 0x7ffff000;
- ssize_t n = ::sendfile(dstfd, srcfd, NULL, SendfileSize);
+ ssize_t n = ::sendfile(dstfd, srcfd, nullptr, SendfileSize);
if (n == -1) {
// if we got an error here, give up and try at an upper layer
return false;
}
while (n) {
- n = ::sendfile(dstfd, srcfd, NULL, SendfileSize);
+ n = ::sendfile(dstfd, srcfd, nullptr, SendfileSize);
if (n == -1) {
// uh oh, this is probably a real error (like ENOSPC), but we have
// no way to notify QFile of partial success, so just erase any work
@@ -1197,6 +1199,216 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
return false;
}
+#ifndef Q_OS_DARWIN
+/*
+ Implementing as per https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
+*/
+
+// bootstrapped tools don't need this, and we don't want QStorageInfo
+#ifndef QT_BOOTSTRAPPED
+static QString freeDesktopTrashLocation(const QString &sourcePath)
+{
+ auto makeTrashDir = [](const QDir &topDir, const QString &trashDir) -> QString {
+ auto ownerPerms = QFileDevice::ReadOwner
+ | QFileDevice::WriteOwner
+ | QFileDevice::ExeOwner;
+ QString targetDir = topDir.filePath(trashDir);
+ if (topDir.mkdir(trashDir))
+ QFile::setPermissions(targetDir, ownerPerms);
+ if (QFileInfo(targetDir).isDir())
+ return targetDir;
+ return QString();
+ };
+ auto isSticky = [](const QFileInfo &fileInfo) -> bool {
+ struct stat st;
+ if (stat(QFile::encodeName(fileInfo.absoluteFilePath()).constData(), &st) == 0)
+ return st.st_mode & S_ISVTX;
+
+ return false;
+ };
+
+ QString trash;
+ const QLatin1String dotTrash(".Trash");
+ const QStorageInfo sourceStorage(sourcePath);
+ const QStorageInfo homeStorage(QDir::home());
+ // We support trashing of files outside the users home partition
+ if (sourceStorage != homeStorage) {
+ QDir topDir(sourceStorage.rootPath());
+ /*
+ Method 1:
+ "An administrator can create an $topdir/.Trash directory. The permissions on this
+ directories should permit all users who can trash files at all to write in it;
+ and the “sticky bit” in the permissions must be set, if the file system supports
+ it.
+ When trashing a file from a non-home partition/device, an implementation
+ (if it supports trashing in top directories) MUST check for the presence
+ of $topdir/.Trash."
+ */
+ const QString userID = QString::number(::getuid());
+ if (topDir.cd(dotTrash)) {
+ const QFileInfo trashInfo(topDir.path());
+
+ // we MUST check that the sticky bit is set, and that it is not a symlink
+ if (trashInfo.isSymLink()) {
+ // we SHOULD report the failed check to the administrator
+ qCritical("Warning: '%s' is a symlink to '%s'",
+ trashInfo.absoluteFilePath().toLocal8Bit().constData(),
+ trashInfo.symLinkTarget().toLatin1().constData());
+ } else if (!isSticky(trashInfo)) {
+ // we SHOULD report the failed check to the administrator
+ qCritical("Warning: '%s' doesn't have sticky bit set!",
+ trashInfo.absoluteFilePath().toLocal8Bit().constData());
+ } else if (trashInfo.isDir()) {
+ /*
+ "If the directory exists and passes the checks, a subdirectory of the
+ $topdir/.Trash directory is to be used as the user's trash directory
+ for this partition/device. The name of this subdirectory is the numeric
+ identifier of the current user ($topdir/.Trash/$uid).
+ When trashing a file, if this directory does not exist for the current user,
+ the implementation MUST immediately create it, without any warnings or
+ delays for the user."
+ */
+ trash = makeTrashDir(topDir, userID);
+ }
+ }
+ /*
+ Method 2:
+ "If an $topdir/.Trash directory is absent, an $topdir/.Trash-$uid directory is to be
+ used as the user's trash directory for this device/partition. [...] When trashing a
+ file, if an $topdir/.Trash-$uid directory does not exist, the implementation MUST
+ immediately create it, without any warnings or delays for the user."
+ */
+ if (trash.isEmpty()) {
+ topDir = QDir(sourceStorage.rootPath());
+ const QString userTrashDir = dotTrash + QLatin1Char('-') + userID;
+ trash = makeTrashDir(topDir, userTrashDir);
+ }
+ }
+ /*
+ "If both (1) and (2) fail [...], the implementation MUST either trash the
+ file into the user's “home trash” or refuse to trash it."
+
+ We trash the file into the user's home trash.
+ */
+ if (trash.isEmpty()) {
+ QDir topDir = QDir::home();
+ trash = makeTrashDir(topDir, dotTrash);
+ if (!QFileInfo(trash).isDir()) {
+ qWarning("Unable to establish trash directory %s in %s",
+ dotTrash.latin1(), topDir.path().toLocal8Bit().constData());
+ }
+ }
+
+ return trash;
+}
+#endif // QT_BOOTSTRAPPED
+
+//static
+bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
+ QFileSystemEntry &newLocation, QSystemError &error)
+{
+#ifdef QT_BOOTSTRAPPED
+ Q_UNUSED(source);
+ Q_UNUSED(newLocation);
+ error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
+ return false;
+#else
+ const QFileInfo sourceInfo(source.filePath());
+ if (!sourceInfo.exists()) {
+ error = QSystemError(ENOENT, QSystemError::StandardLibraryError);
+ return false;
+ }
+ const QString sourcePath = sourceInfo.absoluteFilePath();
+
+ QDir trashDir(freeDesktopTrashLocation(sourcePath));
+ if (!trashDir.exists())
+ return false;
+ /*
+ "A trash directory contains two subdirectories, named info and files."
+ */
+ const QLatin1String filesDir("files");
+ const QLatin1String infoDir("info");
+ trashDir.mkdir(filesDir);
+ int savedErrno = errno;
+ trashDir.mkdir(infoDir);
+ if (!savedErrno)
+ savedErrno = errno;
+ if (!trashDir.exists(filesDir) || !trashDir.exists(infoDir)) {
+ error = QSystemError(savedErrno, QSystemError::StandardLibraryError);
+ return false;
+ }
+ /*
+ "The $trash/files directory contains the files and directories that were trashed.
+ The names of files in this directory are to be determined by the implementation;
+ the only limitation is that they must be unique within the directory. Even if a
+ file with the same name and location gets trashed many times, each subsequent
+ trashing must not overwrite a previous copy."
+ */
+ const QString trashedName = sourceInfo.isDir()
+ ? QDir(sourcePath).dirName()
+ : sourceInfo.fileName();
+ QString uniqueTrashedName = QLatin1Char('/') + trashedName;
+ QString infoFileName;
+ int counter = 0;
+ QFile infoFile;
+ auto makeUniqueTrashedName = [trashedName, &counter]() -> QString {
+ ++counter;
+ return QString(QLatin1String("/%1-%2"))
+ .arg(trashedName)
+ .arg(counter, 4, 10, QLatin1Char('0'));
+ };
+ do {
+ while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName))
+ uniqueTrashedName = makeUniqueTrashedName();
+ /*
+ "The $trash/info directory contains an "information file" for every file and directory
+ in $trash/files. This file MUST have exactly the same name as the file or directory in
+ $trash/files, plus the extension ".trashinfo"
+ [...]
+ When trashing a file or directory, the implementation MUST create the corresponding
+ file in $trash/info first. Moreover, it MUST try to do this in an atomic fashion,
+ so that if two processes try to trash files with the same filename this will result
+ in two different trash files. On Unix-like systems this is done by generating a
+ filename, and then opening with O_EXCL. If that succeeds the creation was atomic
+ (at least on the same machine), if it fails you need to pick another filename."
+ */
+ infoFileName = trashDir.filePath(infoDir)
+ + uniqueTrashedName + QLatin1String(".trashinfo");
+ infoFile.setFileName(infoFileName);
+ if (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text))
+ uniqueTrashedName = makeUniqueTrashedName();
+ } while (!infoFile.isOpen());
+
+ const QString targetPath = trashDir.filePath(filesDir) + uniqueTrashedName;
+ const QFileSystemEntry target(targetPath);
+
+ /*
+ We might fail to rename if source and target are on different file systems.
+ In that case, we don't try further, i.e. copying and removing the original
+ is usually not what the user would expect to happen.
+ */
+ if (!renameFile(source, target, error)) {
+ infoFile.close();
+ infoFile.remove();
+ return false;
+ }
+
+ QTextStream out(&infoFile);
+#if QT_CONFIG(textcodec)
+ out.setCodec("UTF-8");
+#endif
+ out << "[Trash Info]" << Qt::endl;
+ out << "Path=" << sourcePath << Qt::endl;
+ out << "DeletionDate="
+ << QDateTime::currentDateTime().toString(QLatin1String("yyyy-MM-ddThh:mm:ss")) << Qt::endl;
+ infoFile.close();
+
+ newLocation = QFileSystemEntry(targetPath);
+ return true;
+#endif // QT_BOOTSTRAPPED
+}
+#endif // Q_OS_DARWIN
+
//static
bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
{
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index ae29190848..36d43e9cb7 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -41,6 +41,7 @@
#include "qoperatingsystemversion.h"
#include "qplatformdefs.h"
#include "qsysinfo.h"
+#include "qscopeguard.h"
#include "private/qabstractfileengine_p.h"
#include "private/qfsfileengine_p.h"
#include <private/qsystemlibrary_p.h>
@@ -59,6 +60,8 @@
#include <objbase.h>
#ifndef Q_OS_WINRT
# include <shlobj.h>
+# include <shobjidl.h>
+# include <shellapi.h>
# include <lm.h>
# include <accctrl.h>
#endif
@@ -422,6 +425,104 @@ static inline bool getFindData(QString path, WIN32_FIND_DATA &findData)
return false;
}
+#if defined(__IFileOperation_INTERFACE_DEFINED__)
+class FileOperationProgressSink : public IFileOperationProgressSink
+{
+public:
+ FileOperationProgressSink()
+ : ref(1)
+ {}
+ virtual ~FileOperationProgressSink() {}
+
+ ULONG STDMETHODCALLTYPE AddRef()
+ {
+ return ++ref;
+ }
+ ULONG STDMETHODCALLTYPE Release()
+ {
+ if (--ref == 0) {
+ delete this;
+ return 0;
+ }
+ return ref;
+ }
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
+ {
+ if (!ppvObject)
+ return E_POINTER;
+
+ *ppvObject = nullptr;
+
+ if (iid == __uuidof(IUnknown)) {
+ *ppvObject = static_cast<IUnknown*>(this);
+ } else if (iid == __uuidof(IFileOperationProgressSink)) {
+ *ppvObject = static_cast<IFileOperationProgressSink*>(this);
+ }
+
+ if (*ppvObject) {
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ HRESULT STDMETHODCALLTYPE StartOperations()
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PreRenameItem(DWORD, IShellItem *, LPCWSTR)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PostRenameItem(DWORD, IShellItem *, LPCWSTR, HRESULT, IShellItem *)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PreMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PostMoveItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT,
+ IShellItem *)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PreCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR )
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PostCopyItem(DWORD, IShellItem *, IShellItem *, LPCWSTR, HRESULT,
+ IShellItem *)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD dwFlags, IShellItem *)
+ {
+ // stop the operation if the file will be deleted rather than trashed
+ return (dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE) ? S_OK : E_FAIL;
+ }
+ HRESULT STDMETHODCALLTYPE PostDeleteItem(DWORD /* dwFlags */, IShellItem * /* psiItem */,
+ HRESULT /* hrDelete */, IShellItem *psiNewlyCreated)
+ {
+ if (psiNewlyCreated) {
+ wchar_t *pszName = nullptr;
+ psiNewlyCreated->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
+ if (pszName) {
+ targetPath = QString::fromWCharArray(pszName);
+ CoTaskMemFree(pszName);
+ }
+ }
+ return S_OK;
+ }
+ HRESULT STDMETHODCALLTYPE PreNewItem(DWORD, IShellItem *, LPCWSTR)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PostNewItem(DWORD, IShellItem *, LPCWSTR, LPCWSTR, DWORD, HRESULT,
+ IShellItem *)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE UpdateProgress(UINT,UINT)
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE ResetTimer()
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE PauseTimer()
+ { return S_OK; }
+ HRESULT STDMETHODCALLTYPE ResumeTimer()
+ { return S_OK; }
+
+ QString targetPath;
+private:
+ ULONG ref;
+};
+#endif
+
bool QFileSystemEngine::uncListSharesOnServer(const QString &server, QStringList *list)
{
DWORD res = ERROR_NOT_SUPPORTED;
@@ -1123,67 +1224,62 @@ static bool isDirPath(const QString &dirPath, bool *existed)
return fileAttrib & FILE_ATTRIBUTE_DIRECTORY;
}
+// NOTE: if \a shouldMkdirFirst is false, we assume the caller did try to mkdir
+// before calling this function.
+static bool createDirectoryWithParents(const QString &nativeName, bool shouldMkdirFirst = true)
+{
+ const auto isUNCRoot = [](const QString &nativeName) {
+ return nativeName.startsWith(QLatin1String("\\\\")) && nativeName.count(QDir::separator()) <= 3;
+ };
+ const auto isDriveName = [](const QString &nativeName) {
+ return nativeName.size() == 2 && nativeName.at(1) == QLatin1Char(':');
+ };
+ const auto isDir = [](const QString &nativeName) {
+ bool exists = false;
+ return isDirPath(nativeName, &exists) && exists;
+ };
+ // Do not try to mkdir a UNC root path or a drive letter.
+ if (isUNCRoot(nativeName) || isDriveName(nativeName))
+ return false;
+
+ if (shouldMkdirFirst) {
+ if (mkDir(nativeName))
+ return true;
+ }
+
+ const int backSlash = nativeName.lastIndexOf(QDir::separator());
+ if (backSlash < 1)
+ return false;
+
+ const QString parentNativeName = nativeName.left(backSlash);
+ if (!createDirectoryWithParents(parentNativeName))
+ return false;
+
+ // try again
+ if (mkDir(nativeName))
+ return true;
+ return isDir(nativeName);
+}
+
//static
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents)
{
QString dirName = entry.filePath();
Q_CHECK_FILE_NAME(dirName, false);
- if (createParents) {
- dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
- // We spefically search for / so \ would break it..
- int oldslash = -1;
- if (dirName.startsWith(QLatin1String("\\\\"))) {
- // Don't try to create the root path of a UNC path;
- // CreateDirectory() will just return ERROR_INVALID_NAME.
- for (int i = 0; i < dirName.size(); ++i) {
- if (dirName.at(i) != QDir::separator()) {
- oldslash = i;
- break;
- }
- }
- if (oldslash != -1)
- oldslash = dirName.indexOf(QDir::separator(), oldslash);
- } else if (dirName.size() > 2
- && dirName.at(1) == QLatin1Char(':')) {
- // Don't try to call mkdir with just a drive letter
- oldslash = 2;
- }
- for (int slash=0; slash != -1; oldslash = slash) {
- slash = dirName.indexOf(QDir::separator(), oldslash+1);
- if (slash == -1) {
- if (oldslash == dirName.length())
- break;
- slash = dirName.length();
- }
- if (slash) {
- DWORD lastError;
- QString chunk = dirName.left(slash);
- if (!mkDir(chunk, &lastError)) {
- if (lastError == ERROR_ALREADY_EXISTS || lastError == ERROR_ACCESS_DENIED) {
- bool existed = false;
- if (isDirPath(chunk, &existed) && existed)
- continue;
-#ifdef Q_OS_WINRT
- static QThreadStorage<QString> dataLocation;
- if (!dataLocation.hasLocalData())
- dataLocation.setLocalData(QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DataLocation)));
- static QThreadStorage<QString> tempLocation;
- if (!tempLocation.hasLocalData())
- tempLocation.setLocalData(QDir::toNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::TempLocation)));
- // We try to create something outside the sandbox, which is forbidden
- // However we could still try to pass into the sandbox
- if (dataLocation.localData().startsWith(chunk) || tempLocation.localData().startsWith(chunk))
- continue;
-#endif
- }
- return false;
- }
- }
- }
+ dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName));
+
+ // try to mkdir this directory
+ DWORD lastError;
+ if (mkDir(dirName, &lastError))
return true;
- }
- return mkDir(entry.filePath());
+ // mkpath should return true, if the directory already exists, mkdir false.
+ if (!createParents)
+ return false;
+ if (lastError == ERROR_ALREADY_EXISTS)
+ return isDirPath(dirName, nullptr);
+
+ return createDirectoryWithParents(dirName, false);
}
//static
@@ -1436,6 +1532,103 @@ bool QFileSystemEngine::removeFile(const QFileSystemEntry &entry, QSystemError &
return ret;
}
+/*
+ If possible, we use the IFileOperation implementation, which allows us to determine
+ the location of the object in the trash.
+ If not (likely on mingw), we fall back to the old API, which won't allow us to know
+ that.
+*/
+//static
+bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
+ QFileSystemEntry &newLocation, QSystemError &error)
+{
+#ifndef Q_OS_WINRT
+ // we need the "display name" of the file, so can't use nativeFilePath
+ const QString sourcePath = QDir::toNativeSeparators(source.filePath());
+
+ /*
+ Windows 7 insists on showing confirmation dialogs and ignores the respective
+ flags set on IFileOperation. Fall back to SHFileOperation, even if it doesn't
+ give us the new location of the file.
+ */
+ if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7) {
+# if defined(__IFileOperation_INTERFACE_DEFINED__)
+ CoInitialize(NULL);
+ IFileOperation *pfo = nullptr;
+ IShellItem *deleteItem = nullptr;
+ FileOperationProgressSink *sink = nullptr;
+ HRESULT hres = E_FAIL;
+
+ auto coUninitialize = qScopeGuard([&](){
+ if (sink)
+ sink->Release();
+ if (deleteItem)
+ deleteItem->Release();
+ if (pfo)
+ pfo->Release();
+ CoUninitialize();
+ if (!SUCCEEDED(hres))
+ error = QSystemError(hres, QSystemError::NativeError);
+ });
+
+ hres = CoCreateInstance(CLSID_FileOperation, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
+ if (!pfo)
+ return false;
+ pfo->SetOperationFlags(FOF_ALLOWUNDO | FOFX_RECYCLEONDELETE | FOF_NOCONFIRMATION
+ | FOF_SILENT | FOF_NOERRORUI);
+ hres = SHCreateItemFromParsingName(reinterpret_cast<const wchar_t*>(sourcePath.utf16()),
+ nullptr, IID_PPV_ARGS(&deleteItem));
+ if (!deleteItem)
+ return false;
+ sink = new FileOperationProgressSink;
+ hres = pfo->DeleteItem(deleteItem, static_cast<IFileOperationProgressSink*>(sink));
+ if (!SUCCEEDED(hres))
+ return false;
+ hres = pfo->PerformOperations();
+ if (!SUCCEEDED(hres))
+ return false;
+ newLocation = QFileSystemEntry(sink->targetPath);
+
+# endif // no IFileOperation in SDK (mingw, likely) - fall back to SHFileOperation
+ } else {
+ // double null termination needed, so can't use QString::utf16
+ QVarLengthArray<wchar_t, MAX_PATH + 1> winFile(sourcePath.length() + 2);
+ sourcePath.toWCharArray(winFile.data());
+ winFile[sourcePath.length()] = wchar_t{};
+ winFile[sourcePath.length() + 1] = wchar_t{};
+
+ SHFILEOPSTRUCTW operation;
+ operation.hwnd = nullptr;
+ operation.wFunc = FO_DELETE;
+ operation.pFrom = winFile.constData();
+ operation.pTo = nullptr;
+ operation.fFlags = FOF_ALLOWUNDO | FOF_NO_UI;
+ operation.fAnyOperationsAborted = FALSE;
+ operation.hNameMappings = nullptr;
+ operation.lpszProgressTitle = nullptr;
+
+ int result = SHFileOperation(&operation);
+ if (result != 0) {
+ error = QSystemError(result, QSystemError::NativeError);
+ return false;
+ }
+ /*
+ This implementation doesn't let us know where the file ended up, even if
+ we would specify FOF_WANTMAPPINGHANDLE | FOF_RENAMEONCOLLISION, as
+ FOF_RENAMEONCOLLISION has no effect unless files are moved, copied, or renamed.
+ */
+ Q_UNUSED(newLocation);
+ }
+ return true;
+
+#else // Q_OS_WINRT
+ Q_UNUSED(source);
+ Q_UNUSED(newLocation);
+ Q_UNUSED(error);
+ return false;
+#endif
+}
+
//static
bool QFileSystemEngine::setPermissions(const QFileSystemEntry &entry, QFile::Permissions permissions, QSystemError &error,
QFileSystemMetaData *data)
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index 81f4b3ba13..3154658e5c 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -76,8 +76,7 @@ class Q_AUTOTEST_EXPORT QFileSystemMetaData
{
public:
QFileSystemMetaData()
- : knownFlagsMask(nullptr),
- size_(-1)
+ : size_(-1)
{
}
@@ -111,8 +110,10 @@ public:
AliasType = 0x0,
#endif
#if defined(Q_OS_WIN)
+ JunctionType = 0x04000000,
WinLnkType = 0x08000000, // Note: Uses the same position for AliasType on Mac
#else
+ JunctionType = 0x0,
WinLnkType = 0x0,
#endif
SequentialType = 0x00800000, // Note: overlaps with QAbstractFileEngine::RootFlag
@@ -184,7 +185,7 @@ public:
void clear()
{
- knownFlagsMask = nullptr;
+ knownFlagsMask = {};
}
void clearFlags(MetaDataFlags flags = AllMetaDataFlags)
@@ -205,8 +206,10 @@ public:
bool wasDeleted() const { return (entryFlags & WasDeletedAttribute); }
#if defined(Q_OS_WIN)
bool isLnkFile() const { return (entryFlags & WinLnkType); }
+ bool isJunction() const { return (entryFlags & JunctionType); }
#else
bool isLnkFile() const { return false; }
+ bool isJunction() const { return false; }
#endif
qint64 size() const { return size_; }
@@ -356,9 +359,15 @@ inline void QFileSystemMetaData::fillFromFindData(WIN32_FIND_DATA &findData, boo
if (setLinkType) {
knownFlagsMask |= LinkType;
entryFlags &= ~LinkType;
- if ((fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT)
- && (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
- entryFlags |= LinkType;
+ if (fileAttribute_ & FILE_ATTRIBUTE_REPARSE_POINT) {
+ if (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK) {
+ entryFlags |= LinkType;
+#if defined(IO_REPARSE_TAG_MOUNT_POINT)
+ } else if ((fileAttribute_ & FILE_ATTRIBUTE_DIRECTORY)
+ && (findData.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) {
+ entryFlags |= JunctionType;
+#endif
+ }
}
}
}
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index 54460aff77..86c8963cb6 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -88,7 +88,7 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject
}
QFileSystemWatcherPrivate::QFileSystemWatcherPrivate()
- : native(0), poller(0)
+ : native(nullptr), poller(nullptr)
{
}
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index ca1f6cc359..888af998a5 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -242,7 +242,7 @@ QInotifyFileSystemWatcherEngine *QInotifyFileSystemWatcherEngine::create(QObject
if (fd == -1) {
fd = inotify_init();
if (fd == -1)
- return 0;
+ return nullptr;
}
return new QInotifyFileSystemWatcherEngine(fd, parent);
}
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 0d73839f8d..3042eac2f0 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -911,14 +911,7 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
}
/*! \fn bool QFSFileEngine::caseSensitive() const
- Returns \c true for Windows, false for Unix.
-*/
-
-/*! \fn bool QFSFileEngine::copy(const QString &copyName)
-
- For Windows or Apple platforms, copy the file to file \a copyName.
-
- Not implemented for other Unix platforms.
+ Returns \c false for Windows, true for Unix.
*/
/*! \fn QString QFSFileEngine::currentPath(const QString &fileName)
@@ -950,11 +943,34 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
-/*! \fn QString QFSFileEngine::homePath()
+/*!
Returns the home path of the current user.
\sa rootPath()
*/
+QString QFSFileEngine::homePath()
+{
+ return QFileSystemEngine::homePath();
+}
+
+/*!
+ Returns the root path.
+
+ \sa homePath()
+*/
+QString QFSFileEngine::rootPath()
+{
+ return QFileSystemEngine::rootPath();
+}
+
+/*!
+ Returns the temporary path (i.e., a path in which it is safe
+ to store temporary files).
+*/
+QString QFSFileEngine::tempPath()
+{
+ return QFileSystemEngine::tempPath();
+}
/*! \fn bool QFSFileEngine::isRelativePath() const
\reimp
@@ -968,9 +984,6 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
true if successful; otherwise returns \c false.
*/
-/*! \fn bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
- \reimp
-*/
/*! \fn uint QFSFileEngine::ownerId(QAbstractFileEngine::FileOwner own) const
In Unix, if stat() is successful, the \c uid is returned if
@@ -984,35 +997,87 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
-/*! \fn bool QFSFileEngine::remove()
- \reimp
+/*!
+ For Windows or Apple platforms, copy the file to file \a copyName.
+
+ Not implemented for other Unix platforms.
*/
+bool QFSFileEngine::copy(const QString &copyName)
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error);
+ if (!ret)
+ setError(QFile::CopyError, error.toString());
+ return ret;
+}
-/*! \fn bool QFSFileEngine::rename(const QString &newName)
+/*!
\reimp
*/
+bool QFSFileEngine::remove()
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
+ d->metaData.clear();
+ if (!ret)
+ setError(QFile::RemoveError, error.toString());
+ return ret;
+}
-
-/*! \fn bool QFSFileEngine::renameOverwrite(const QString &newName)
+/*!
\reimp
*/
-
-/*! \fn bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
+bool QFSFileEngine::rename(const QString &newName)
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
+ if (!ret)
+ setError(QFile::RenameError, error.toString());
+ return ret;
+}
+/*!
\reimp
*/
+bool QFSFileEngine::renameOverwrite(const QString &newName)
+{
+ Q_D(QFSFileEngine);
+ QSystemError error;
+ bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
+ if (!ret)
+ setError(QFile::RenameError, error.toString());
+ return ret;
+}
-/*! \fn QString QFSFileEngine::rootPath()
- Returns the root path.
+/*!
+ \reimp
+*/
+bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
+{
+ return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
+}
- \sa homePath()
+/*!
+ \reimp
*/
+bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
+{
+ return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
+}
-/*! \fn bool QFSFileEngine::setCurrentPath(const QString &path)
+
+/*!
Sets the current path (e.g., for QDir), to \a path. Returns \c true if the
new path exists; otherwise this function does nothing, and returns \c false.
\sa currentPath()
*/
+bool QFSFileEngine::setCurrentPath(const QString &path)
+{
+ return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
+}
/*! \fn bool QFSFileEngine::setPermissions(uint perms)
\reimp
@@ -1022,11 +1087,6 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
-/*! \fn QString QFSFileEngine::tempPath()
- Returns the temporary path (i.e., a path in which it is safe
- to store temporary files).
-*/
-
/*! \fn QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const
\internal
*/
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index d4983c72af..4610e9306c 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -304,54 +304,6 @@ bool QFSFileEnginePrivate::nativeIsSequential() const
return isSequentialFdFh();
}
-bool QFSFileEngine::remove()
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
- d->metaData.clear();
- if (!ret) {
- setError(QFile::RemoveError, error.toString());
- }
- return ret;
-}
-
-bool QFSFileEngine::copy(const QString &newName)
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret) {
- setError(QFile::CopyError, error.toString());
- }
- return ret;
-}
-
-bool QFSFileEngine::renameOverwrite(const QString &newName)
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
-
- if (!ret)
- setError(QFile::RenameError, error.toString());
-
- return ret;
-}
-
-bool QFSFileEngine::rename(const QString &newName)
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
-
- if (!ret) {
- setError(QFile::RenameError, error.toString());
- }
-
- return ret;
-}
-
bool QFSFileEngine::link(const QString &newName)
{
Q_D(QFSFileEngine);
@@ -368,45 +320,16 @@ qint64 QFSFileEnginePrivate::nativeSize() const
return sizeFdFh();
}
-bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
-{
- return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
-}
-
-bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
-{
- return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
-}
-
bool QFSFileEngine::caseSensitive() const
{
return true;
}
-bool QFSFileEngine::setCurrentPath(const QString &path)
-{
- return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
-}
-
QString QFSFileEngine::currentPath(const QString &)
{
return QFileSystemEngine::currentPath().filePath();
}
-QString QFSFileEngine::homePath()
-{
- return QFileSystemEngine::homePath();
-}
-
-QString QFSFileEngine::rootPath()
-{
- return QFileSystemEngine::rootPath();
-}
-
-QString QFSFileEngine::tempPath()
-{
- return QFileSystemEngine::tempPath();
-}
QFileInfoList QFSFileEngine::drives()
{
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index 19cc3e6402..dd4882a2bc 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -443,66 +443,11 @@ bool QFSFileEnginePrivate::nativeIsSequential() const
#endif
}
-bool QFSFileEngine::remove()
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::removeFile(d->fileEntry, error);
- if (!ret)
- setError(QFile::RemoveError, error.toString());
- return ret;
-}
-
-bool QFSFileEngine::copy(const QString &copyName)
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::copyFile(d->fileEntry, QFileSystemEntry(copyName), error);
- if (!ret)
- setError(QFile::CopyError, error.toString());
- return ret;
-}
-
-bool QFSFileEngine::rename(const QString &newName)
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret)
- setError(QFile::RenameError, error.toString());
- return ret;
-}
-
-bool QFSFileEngine::renameOverwrite(const QString &newName)
-{
- Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret)
- setError(QFile::RenameError, error.toString());
- return ret;
-}
-
-bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) const
-{
- return QFileSystemEngine::createDirectory(QFileSystemEntry(name), createParentDirectories);
-}
-
-bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) const
-{
- return QFileSystemEngine::removeDirectory(QFileSystemEntry(name), recurseParentDirectories);
-}
-
bool QFSFileEngine::caseSensitive() const
{
return false;
}
-bool QFSFileEngine::setCurrentPath(const QString &path)
-{
- return QFileSystemEngine::setCurrentPath(QFileSystemEntry(path));
-}
-
QString QFSFileEngine::currentPath(const QString &fileName)
{
#if !defined(Q_OS_WINRT)
@@ -530,21 +475,6 @@ QString QFSFileEngine::currentPath(const QString &fileName)
#endif // Q_OS_WINRT
}
-QString QFSFileEngine::homePath()
-{
- return QFileSystemEngine::homePath();
-}
-
-QString QFSFileEngine::rootPath()
-{
- return QFileSystemEngine::rootPath();
-}
-
-QString QFSFileEngine::tempPath()
-{
- return QFileSystemEngine::tempPath();
-}
-
#if !defined(Q_OS_WINRT)
// cf QStorageInfo::isReady
static inline bool isDriveReady(const wchar_t *path)
@@ -661,14 +591,14 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil
if (type & Refresh)
d->metaData.clear();
- QAbstractFileEngine::FileFlags ret = 0;
+ QAbstractFileEngine::FileFlags ret;
if (type & FlagsMask)
ret |= LocalDiskFlag;
bool exists;
{
- QFileSystemMetaData::MetaDataFlags queryFlags = 0;
+ QFileSystemMetaData::MetaDataFlags queryFlags;
queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type))
& QFileSystemMetaData::Permissions;
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 076b2394ba..cc1d110252 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -461,7 +461,7 @@ QIODevice::QIODevice(QIODevicePrivate &dd)
*/
QIODevice::QIODevice()
- : QObject(*new QIODevicePrivate, 0)
+ : QObject(*new QIODevicePrivate, nullptr)
{
#if defined QIODEVICE_DEBUG
QFile *file = qobject_cast<QFile *>(this);
@@ -1829,7 +1829,7 @@ QByteArray QIODevicePrivate::peek(qint64 maxSize)
/*! \fn bool QIODevice::getChar(char *c)
Reads one character from the device and stores it in \a c. If \a c
- is 0, the character is discarded. Returns \c true on success;
+ is \nullptr, the character is discarded. Returns \c true on success;
otherwise returns \c false.
\sa read(), putChar(), ungetChar()
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
index d1806aa12b..df0197e8eb 100644
--- a/src/corelib/io/qnoncontiguousbytedevice.cpp
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
@@ -127,7 +127,7 @@ QT_BEGIN_NAMESPACE
\internal
*/
-QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)0)
+QNonContiguousByteDevice::QNonContiguousByteDevice() : QObject((QObject*)nullptr)
{
}
@@ -188,7 +188,7 @@ const char* QNonContiguousByteDeviceByteArrayImpl::readPointer(qint64 maximumLen
{
if (atEnd()) {
len = -1;
- return 0;
+ return nullptr;
}
if (maximumLength != -1)
@@ -241,7 +241,7 @@ const char* QNonContiguousByteDeviceRingBufferImpl::readPointer(qint64 maximumLe
{
if (atEnd()) {
len = -1;
- return 0;
+ return nullptr;
}
const char *returnValue = ringBuffer->readPointerAtPosition(currentPosition, len);
@@ -282,7 +282,7 @@ qint64 QNonContiguousByteDeviceRingBufferImpl::size() const
QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d)
: QNonContiguousByteDevice(),
- currentReadBuffer(0), currentReadBufferSize(16*1024),
+ currentReadBuffer(nullptr), currentReadBufferSize(16*1024),
currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0),
eof(false)
{
@@ -301,10 +301,10 @@ const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLeng
{
if (eof == true) {
len = -1;
- return 0;
+ return nullptr;
}
- if (currentReadBuffer == 0)
+ if (currentReadBuffer == nullptr)
currentReadBuffer = new QByteArray(currentReadBufferSize, '\0'); // lazy alloc
if (maximumLength == -1)
@@ -323,7 +323,7 @@ const char* QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLeng
// size was unknown before, emit a readProgress with the final size
if (size() == -1)
emit readProgress(totalAdvancements, totalAdvancements);
- return 0;
+ return nullptr;
}
currentReadBufferAmount = haveRead;
@@ -349,7 +349,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
if (currentReadBufferPosition > currentReadBufferAmount) {
qint64 i = currentReadBufferPosition - currentReadBufferAmount;
while (i > 0) {
- if (device->getChar(0) == false) {
+ if (device->getChar(nullptr) == false) {
emit readProgress(totalAdvancements - i, size());
return false; // ### FIXME handle eof
}
@@ -377,7 +377,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::reset()
totalAdvancements = 0; //reset the progress counter
if (currentReadBuffer) {
delete currentReadBuffer;
- currentReadBuffer = 0;
+ currentReadBuffer = nullptr;
}
currentReadBufferAmount = 0;
currentReadBufferPosition = 0;
@@ -405,7 +405,7 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() const
return device->pos();
}
-QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)0)
+QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)nullptr)
{
byteDevice = bd;
connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead()));
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 49e0847d44..aedcae2cdc 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -216,7 +216,7 @@ void QProcessEnvironmentPrivate::insert(const QProcessEnvironmentPrivate &other)
environment variables to be removed.
*/
QProcessEnvironment::QProcessEnvironment()
- : d(0)
+ : d(nullptr)
{
}
@@ -436,18 +436,18 @@ void QProcessPrivate::Channel::clear()
case PipeSource:
Q_ASSERT(process);
process->stdinChannel.type = Normal;
- process->stdinChannel.process = 0;
+ process->stdinChannel.process = nullptr;
break;
case PipeSink:
Q_ASSERT(process);
process->stdoutChannel.type = Normal;
- process->stdoutChannel.process = 0;
+ process->stdoutChannel.process = nullptr;
break;
}
type = Normal;
file.clear();
- process = 0;
+ process = nullptr;
}
/*!
@@ -869,8 +869,8 @@ QProcessPrivate::QProcessPrivate()
sequenceNumber = 0;
exitCode = 0;
exitStatus = QProcess::NormalExit;
- startupSocketNotifier = 0;
- deathNotifier = 0;
+ startupSocketNotifier = nullptr;
+ deathNotifier = nullptr;
childStartedPipe[0] = INVALID_Q_PIPE;
childStartedPipe[1] = INVALID_Q_PIPE;
forkfd = -1;
@@ -924,23 +924,23 @@ void QProcessPrivate::cleanup()
if (stdoutChannel.notifier) {
delete stdoutChannel.notifier;
- stdoutChannel.notifier = 0;
+ stdoutChannel.notifier = nullptr;
}
if (stderrChannel.notifier) {
delete stderrChannel.notifier;
- stderrChannel.notifier = 0;
+ stderrChannel.notifier = nullptr;
}
if (stdinChannel.notifier) {
delete stdinChannel.notifier;
- stdinChannel.notifier = 0;
+ stdinChannel.notifier = nullptr;
}
if (startupSocketNotifier) {
delete startupSocketNotifier;
- startupSocketNotifier = 0;
+ startupSocketNotifier = nullptr;
}
if (deathNotifier) {
delete deathNotifier;
- deathNotifier = 0;
+ deathNotifier = nullptr;
}
closeChannel(&stdoutChannel);
closeChannel(&stderrChannel);
@@ -1229,7 +1229,7 @@ void QProcessPrivate::closeWriteChannel()
#endif
if (stdinChannel.notifier) {
delete stdinChannel.notifier;
- stdinChannel.notifier = 0;
+ stdinChannel.notifier = nullptr;
}
#ifdef Q_OS_WIN
// ### Find a better fix, feeding the process little by little
@@ -2617,7 +2617,7 @@ QT_END_INCLUDE_NAMESPACE
QStringList QProcess::systemEnvironment()
{
QStringList tmp;
- char *entry = 0;
+ char *entry = nullptr;
int count = 0;
while ((entry = environ[count++]))
tmp << QString::fromLocal8Bit(entry);
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 0c80daa024..2186f23ab6 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -246,7 +246,7 @@ bool QProcessPrivate::openChannel(Channel &channel)
return false;
// create the socket notifiers
- if (threadData->hasEventDispatcher()) {
+ if (threadData.loadRelaxed()->hasEventDispatcher()) {
if (&channel == &stdinChannel) {
channel.notifier = new QSocketNotifier(channel.pipe[1],
QSocketNotifier::Write, q);
@@ -338,11 +338,11 @@ static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Map &environme
{
*envc = 0;
if (environment.isEmpty())
- return 0;
+ return nullptr;
char **envp = new char *[environment.count() + 2];
- envp[environment.count()] = 0;
- envp[environment.count() + 1] = 0;
+ envp[environment.count()] = nullptr;
+ envp[environment.count() + 1] = nullptr;
auto it = environment.constBegin();
const auto end = environment.constEnd();
@@ -377,7 +377,7 @@ void QProcessPrivate::startProcess()
return;
}
- if (threadData->hasEventDispatcher()) {
+ if (threadData.loadRelaxed()->hasEventDispatcher()) {
startupSocketNotifier = new QSocketNotifier(childStartedPipe[0],
QSocketNotifier::Read, q);
QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),
@@ -390,7 +390,7 @@ void QProcessPrivate::startProcess()
// Create argument list with right number of elements, and set the final
// one to 0.
char **argv = new char *[arguments.count() + 2];
- argv[arguments.count() + 1] = 0;
+ argv[arguments.count() + 1] = nullptr;
// Encode the program name.
QByteArray encodedProgramName = QFile::encodeName(program);
@@ -437,13 +437,13 @@ void QProcessPrivate::startProcess()
// Duplicate the environment.
int envc = 0;
- char **envp = 0;
+ char **envp = nullptr;
if (environment.d.constData()) {
envp = _q_dupEnvironment(environment.d.constData()->vars, &envc);
}
// Encode the working directory if it's non-empty, otherwise just pass 0.
- const char *workingDirPtr = 0;
+ const char *workingDirPtr = nullptr;
QByteArray encodedWorkingDirectory;
if (!workingDirectory.isEmpty()) {
encodedWorkingDirectory = QFile::encodeName(workingDirectory);
@@ -451,8 +451,13 @@ void QProcessPrivate::startProcess()
}
// Start the process manager, and fork off the child process.
+ // ### Qt6: revisit whether the change in behavior due to not using fork()
+ // is acceptable for derived classes.
+ int ffdflags = FFD_CLOEXEC;
+ if (typeid(*q) != typeid(QProcess))
+ ffdflags |= FFD_USE_FORK;
pid_t childPid;
- forkfd = ::forkfd(FFD_CLOEXEC, &childPid);
+ forkfd = ::forkfd(ffdflags , &childPid);
int lastForkErrno = errno;
if (forkfd != FFD_CHILD_PROCESS) {
// Parent process.
@@ -517,7 +522,7 @@ void QProcessPrivate::startProcess()
if (stderrChannel.pipe[0] != -1)
::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
- if (threadData->eventDispatcher.loadAcquire()) {
+ if (threadData.loadRelaxed()->eventDispatcher.loadAcquire()) {
deathNotifier = new QSocketNotifier(forkfd, QSocketNotifier::Read, q);
QObject::connect(deathNotifier, SIGNAL(activated(int)),
q, SLOT(_q_processDied()));
@@ -596,7 +601,7 @@ bool QProcessPrivate::processStarted(QString *errorMessage)
if (startupSocketNotifier) {
startupSocketNotifier->setEnabled(false);
startupSocketNotifier->deleteLater();
- startupSocketNotifier = 0;
+ startupSocketNotifier = nullptr;
}
qt_safe_close(childStartedPipe[0]);
childStartedPipe[0] = -1;
@@ -889,7 +894,7 @@ bool QProcessPrivate::waitForDeadChild()
crashed = info.code != CLD_EXITED;
delete deathNotifier;
- deathNotifier = 0;
+ deathNotifier = nullptr;
EINTR_LOOP(ret, forkfd_close(forkfd));
forkfd = -1; // Child is dead, don't try to kill it anymore
@@ -935,7 +940,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
struct sigaction noaction;
memset(&noaction, 0, sizeof(noaction));
noaction.sa_handler = SIG_IGN;
- ::sigaction(SIGPIPE, &noaction, 0);
+ ::sigaction(SIGPIPE, &noaction, nullptr);
::setsid();
@@ -964,7 +969,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
char **argv = new char *[arguments.size() + 2];
for (int i = 0; i < arguments.size(); ++i)
argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
- argv[arguments.size() + 1] = 0;
+ argv[arguments.size() + 1] = nullptr;
// Duplicate the environment.
int envc = 0;
@@ -991,7 +996,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
struct sigaction noaction;
memset(&noaction, 0, sizeof(noaction));
noaction.sa_handler = SIG_IGN;
- ::sigaction(SIGPIPE, &noaction, 0);
+ ::sigaction(SIGPIPE, &noaction, nullptr);
// '\1' means execv failed
char c = '\1';
@@ -1002,7 +1007,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
struct sigaction noaction;
memset(&noaction, 0, sizeof(noaction));
noaction.sa_handler = SIG_IGN;
- ::sigaction(SIGPIPE, &noaction, 0);
+ ::sigaction(SIGPIPE, &noaction, nullptr);
// '\2' means internal error
char c = '\2';
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 3ba86063e3..1527cf93ed 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -49,7 +49,6 @@
#include <qelapsedtimer.h>
#include <qfileinfo.h>
#include <qrandom.h>
-#include <qregexp.h>
#include <qwineventnotifier.h>
#include <private/qsystemlibrary_p.h>
#include <private/qthread_p.h>
@@ -398,7 +397,17 @@ static QString qt_create_commandline(const QString &program, const QStringList &
for (int i=0; i<arguments.size(); ++i) {
QString tmp = arguments.at(i);
// Quotes are escaped and their preceding backslashes are doubled.
- tmp.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\""));
+ int index = tmp.indexOf(QLatin1Char('"'));
+ while (index >= 0) {
+ // Escape quote
+ tmp.insert(index++, QLatin1Char('\\'));
+ // Double preceding backslashes (ignoring the one we just inserted)
+ for (int i = index - 2 ; i >= 0 && tmp.at(i) == QLatin1Char('\\') ; --i) {
+ tmp.insert(i, QLatin1Char('\\'));
+ index++;
+ }
+ index = tmp.indexOf(QLatin1Char('"'), index + 1);
+ }
if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) {
// The argument must not end with a \ since this would be interpreted
// as escaping the quote -- rather put the \ behind the quote: e.g.
@@ -590,7 +599,7 @@ void QProcessPrivate::startProcess()
if (!pid)
return;
- if (threadData->hasEventDispatcher()) {
+ if (threadData.loadRelaxed()->hasEventDispatcher()) {
processFinishedNotifier = new QWinEventNotifier(pid->hProcess, q);
QObject::connect(processFinishedNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_processDied()));
processFinishedNotifier->setEnabled(true);
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index a494daa29f..225ee0a769 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Copyright (C) 2019 Intel Corporation.
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2020 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -60,14 +60,14 @@
#include "private/qtools_p.h"
#include "private/qsystemerror_p.h"
+#ifndef QT_NO_COMPRESS
+# include <zconf.h>
+# include <zlib.h>
+#endif
#if QT_CONFIG(zstd)
# include <zstd.h>
#endif
-#ifdef Q_OS_UNIX
-# include "private/qcore_unix_p.h"
-#endif
-
#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP
# include <sys/mman.h>
@@ -296,6 +296,8 @@ public:
void ensureInitialized() const;
void ensureChildren() const;
+ qint64 uncompressedSize() const Q_DECL_PURE_FUNCTION;
+ qsizetype decompress(char *buffer, qsizetype bufferSize) const;
bool load(const QString &file);
void clear();
@@ -440,6 +442,78 @@ QResourcePrivate::ensureChildren() const
}
}
+qint64 QResourcePrivate::uncompressedSize() const
+{
+ switch (compressionAlgo) {
+ case QResource::NoCompression:
+ return size;
+
+ case QResource::ZlibCompression:
+#ifndef QT_NO_COMPRESS
+ if (size_t(size) >= sizeof(quint32))
+ return qFromBigEndian<quint32>(data);
+#else
+ Q_ASSERT(!"QResource: Qt built without support for Zlib compression");
+ Q_UNREACHABLE();
+#endif
+ break;
+
+ case QResource::ZstdCompression: {
+#if QT_CONFIG(zstd)
+ size_t n = ZSTD_getFrameContentSize(data, size);
+ return ZSTD_isError(n) ? -1 : qint64(n);
+#else
+ // This should not happen because we've refused to load such resource
+ Q_ASSERT(!"QResource: Qt built without support for Zstd compression");
+ Q_UNREACHABLE();
+#endif
+ }
+
+ }
+ return -1;
+}
+
+qsizetype QResourcePrivate::decompress(char *buffer, qsizetype bufferSize) const
+{
+ Q_ASSERT(data);
+
+ switch (compressionAlgo) {
+ case QResource::NoCompression:
+ Q_UNREACHABLE();
+ break;
+
+ case QResource::ZlibCompression: {
+#ifndef QT_NO_COMPRESS
+ uLong len = uLong(bufferSize);
+ int res = ::uncompress(reinterpret_cast<Bytef *>(buffer), &len,
+ data + sizeof(quint32), uLong(size - sizeof(quint32)));
+ if (res != Z_OK) {
+ qWarning("QResource: error decompressing zlib content (%d)", res);
+ return -1;
+ }
+ return len;
+#else
+ Q_UNREACHABLE();
+#endif
+ }
+
+ case QResource::ZstdCompression: {
+#if QT_CONFIG(zstd)
+ size_t usize = ZSTD_decompress(buffer, bufferSize, data, size);
+ if (ZSTD_isError(usize)) {
+ qWarning("QResource: error decompressing zstd content: %s", ZSTD_getErrorName(usize));
+ return -1;
+ }
+ return usize;
+#else
+ Q_UNREACHABLE();
+#endif
+ }
+ }
+
+ return -1;
+}
+
/*!
Constructs a QResource pointing to \a file. \a locale is used to
load a specific localization of a resource data.
@@ -600,9 +674,12 @@ QResource::Compression QResource::compressionAlgorithm() const
}
/*!
- Returns the size of the data backing the resource.
+ Returns the size of the stored data backing the resource.
- \sa data(), isFile()
+ If the resource is compressed, this function returns the size of the
+ compressed data. See uncompressedSize() for the uncompressed size.
+
+ \sa data(), uncompressedSize(), isFile()
*/
qint64 QResource::size() const
@@ -613,12 +690,29 @@ qint64 QResource::size() const
}
/*!
- Returns direct access to a read only segment of data that this resource
- represents. If the resource is compressed the data returned is compressed
- and the appropriate library functions must be used to access the data. If
- the resource is a directory \nullptr is returned.
+ \since 5.15
+
+ Returns the size of the data in this resource. If the data was not
+ compressed, this function returns the same as size(). If it was, then this
+ function extracts the size of the original uncompressed data from the
+ stored stream.
+
+ \sa size(), uncompressedData(), isFile()
+*/
+qint64 QResource::uncompressedSize() const
+{
+ Q_D(const QResource);
+ d->ensureInitialized();
+ return d->uncompressedSize();
+}
+
+/*!
+ Returns direct access to a segment of read-only data, that this resource
+ represents. If the resource is compressed, the data returned is also
+ compressed. The caller must then decompress the data or use
+ uncompressedData(). If the resource is a directory, \c nullptr is returned.
- \sa size(), compressionAlgorithm(), isFile()
+ \sa uncompressedData(), size(), isFile()
*/
const uchar *QResource::data() const
@@ -629,6 +723,42 @@ const uchar *QResource::data() const
}
/*!
+ \since 5.15
+
+ Returns the resource data, decompressing it first, if the data was stored
+ compressed. If the resource is a directory or an error occurs while
+ decompressing, a null QByteArray is returned.
+
+ \note If the data was compressed, this function will decompress every time
+ it is called. The result is not cached between calls.
+
+ \sa uncompressedData(), size(), isCompressed(), isFile()
+*/
+
+QByteArray QResource::uncompressedData() const
+{
+ Q_D(const QResource);
+ qint64 n = uncompressedSize();
+ if (n < 0)
+ return QByteArray();
+ if (n > std::numeric_limits<QByteArray::size_type>::max()) {
+ qWarning("QResource: compressed content does not fit into a QByteArray; use QFile instead");
+ return QByteArray();
+ }
+ if (d->compressionAlgo == NoCompression)
+ return QByteArray::fromRawData(reinterpret_cast<const char *>(d->data), n);
+
+ // decompress
+ QByteArray result(n, Qt::Uninitialized);
+ n = d->decompress(result.data(), n);
+ if (n < 0)
+ result.clear();
+ else
+ result.truncate(n);
+ return result;
+}
+
+/*!
\since 5.8
Returns the date and time when the file was last modified before
@@ -1451,13 +1581,7 @@ bool QResourceFileEngine::link(const QString &)
qint64 QResourceFileEngine::size() const
{
Q_D(const QResourceFileEngine);
- if (!d->resource.isValid())
- return 0;
- if (d->resource.compressionAlgorithm() != QResource::NoCompression) {
- d->uncompress();
- return d->uncompressed.size();
- }
- return d->resource.size();
+ return d->resource.isValid() ? d->resource.uncompressedSize() : 0;
}
qint64 QResourceFileEngine::pos() const
@@ -1494,7 +1618,7 @@ bool QResourceFileEngine::isSequential() const
QAbstractFileEngine::FileFlags QResourceFileEngine::fileFlags(QAbstractFileEngine::FileFlags type) const
{
Q_D(const QResourceFileEngine);
- QAbstractFileEngine::FileFlags ret = 0;
+ QAbstractFileEngine::FileFlags ret;
if(!d->resource.isValid())
return ret;
@@ -1586,7 +1710,7 @@ QAbstractFileEngine::Iterator *QResourceFileEngine::beginEntryList(QDir::Filters
*/
QAbstractFileEngine::Iterator *QResourceFileEngine::endEntryList()
{
- return 0;
+ return nullptr;
}
bool QResourceFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
@@ -1596,7 +1720,7 @@ bool QResourceFileEngine::extension(Extension extension, const ExtensionOption *
const MapExtensionOption *options = (const MapExtensionOption*)(option);
MapExtensionReturn *returnValue = static_cast<MapExtensionReturn*>(output);
returnValue->address = d->map(options->offset, options->size, options->flags);
- return (returnValue->address != 0);
+ return (returnValue->address != nullptr);
}
if (extension == UnMapExtension) {
const UnMapExtensionOption *options = (const UnMapExtensionOption*)option;
@@ -1615,22 +1739,21 @@ uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::Memory
Q_Q(QResourceFileEngine);
Q_UNUSED(flags);
- qint64 max = resource.size();
- if (resource.compressionAlgorithm() != QResource::NoCompression) {
- uncompress();
- max = uncompressed.size();
- }
-
+ qint64 max = resource.uncompressedSize();
qint64 end;
if (offset < 0 || size <= 0 || !resource.isValid() ||
add_overflow(offset, size, &end) || end > max) {
q->setError(QFile::UnspecifiedError, QString());
- return 0;
+ return nullptr;
}
const uchar *address = resource.data();
- if (resource.compressionAlgorithm() != QResource::NoCompression)
+ if (resource.compressionAlgorithm() != QResource::NoCompression) {
+ uncompress();
+ if (uncompressed.isNull())
+ return nullptr;
address = reinterpret_cast<const uchar *>(uncompressed.constData());
+ }
return const_cast<uchar *>(address) + offset;
}
@@ -1643,41 +1766,10 @@ bool QResourceFileEnginePrivate::unmap(uchar *ptr)
void QResourceFileEnginePrivate::uncompress() const
{
- if (uncompressed.isEmpty() && resource.size()) {
- quint64 size;
- switch (resource.compressionAlgorithm()) {
- case QResource::NoCompression:
- return; // nothing to do
-
- case QResource::ZlibCompression:
-#ifndef QT_NO_COMPRESS
- uncompressed = qUncompress(resource.data(), resource.size());
-#else
- Q_ASSERT(!"QResourceFileEngine::open: Qt built without support for Zlib compression");
-#endif
- break;
-
- case QResource::ZstdCompression:
-#if QT_CONFIG(zstd)
- size = ZSTD_getFrameContentSize(resource.data(), resource.size());
- if (!ZSTD_isError(size)) {
- if (size >= MaxAllocSize) {
- qWarning("QResourceFileEngine::open: content bigger than memory (size %lld)", size);
- } else {
- uncompressed = QByteArray(size, Qt::Uninitialized);
- size = ZSTD_decompress(const_cast<char *>(uncompressed.data()), size,
- resource.data(), resource.size());
- }
- }
- if (ZSTD_isError(size))
- qWarning("QResourceFileEngine::open: error decoding: %s", ZSTD_getErrorName(size));
-#else
- Q_UNUSED(size);
- Q_ASSERT(!"QResourceFileEngine::open: Qt built without support for Zstd compression");
-#endif
- break;
- }
- }
+ if (resource.compressionAlgorithm() == QResource::NoCompression
+ || !uncompressed.isEmpty() || resource.size() == 0)
+ return; // nothing to do
+ uncompressed = resource.uncompressedData();
}
#endif // !defined(QT_BOOTSTRAPPED)
diff --git a/src/corelib/io/qresource.h b/src/corelib/io/qresource.h
index 5ee8d5d266..52b0d74d29 100644
--- a/src/corelib/io/qresource.h
+++ b/src/corelib/io/qresource.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2019 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -75,6 +76,8 @@ public:
Compression compressionAlgorithm() const;
qint64 size() const;
const uchar *data() const;
+ qint64 uncompressedSize() const;
+ QByteArray uncompressedData() const;
QDateTime lastModified() const;
#if QT_DEPRECATED_SINCE(5, 13)
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index 0a884a7df9..067ccda3df 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -116,7 +116,7 @@ QSaveFile::QSaveFile(const QString &name)
Constructs a new file object to represent the file with the given \a name.
*/
QSaveFile::QSaveFile(const QString &name)
- : QFileDevice(*new QSaveFilePrivate, 0)
+ : QFileDevice(*new QSaveFilePrivate, nullptr)
{
Q_D(QSaveFile);
d->fileName = name;
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index fc7122d904..b191397e7e 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -76,10 +76,6 @@
# include <ioLib.h>
#endif
-#ifdef Q_OS_WASM
-#include <emscripten.h>
-#endif
-
#include <algorithm>
#include <stdlib.h>
@@ -210,7 +206,7 @@ QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms)
ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc();
- QConfFile *confFile = 0;
+ QConfFile *confFile = nullptr;
const auto locker = qt_scoped_lock(settingsGlobalMutex);
if (!(confFile = usedHash->value(absPath))) {
@@ -234,7 +230,7 @@ void QConfFile::clearCache()
// QSettingsPrivate
QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
- : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true),
+ : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(nullptr), fallbacks(true),
pendingChanges(false), status(QSettings::NoError)
{
}
@@ -242,7 +238,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
: format(format), scope(scope), organizationName(organization), applicationName(application),
- iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
+ iniCodec(nullptr), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
{
}
@@ -295,7 +291,7 @@ after_loop:
// see also qsettings_win.cpp, qsettings_winrt.cpp and qsettings_mac.cpp
-#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
+#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
{
@@ -400,12 +396,12 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
{
QString result;
- switch (v.type()) {
- case QVariant::Invalid:
+ switch (v.userType()) {
+ case QMetaType::UnknownType:
result = QLatin1String("@Invalid()");
break;
- case QVariant::ByteArray: {
+ case QMetaType::QByteArray: {
QByteArray a = v.toByteArray();
result = QLatin1String("@ByteArray(")
+ QLatin1String(a.constData(), a.size())
@@ -413,14 +409,14 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
break;
}
- case QVariant::String:
- case QVariant::LongLong:
- case QVariant::ULongLong:
- case QVariant::Int:
- case QVariant::UInt:
- case QVariant::Bool:
- case QVariant::Double:
- case QVariant::KeySequence: {
+ case QMetaType::QString:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::Bool:
+ case QMetaType::Double:
+ case QMetaType::QKeySequence: {
result = v.toString();
if (result.contains(QChar::Null))
result = QLatin1String("@String(") + result + QLatin1Char(')');
@@ -429,17 +425,17 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
break;
}
#ifndef QT_NO_GEOM_VARIANT
- case QVariant::Rect: {
+ case QMetaType::QRect: {
QRect r = qvariant_cast<QRect>(v);
result = QString::asprintf("@Rect(%d %d %d %d)", r.x(), r.y(), r.width(), r.height());
break;
}
- case QVariant::Size: {
+ case QMetaType::QSize: {
QSize s = qvariant_cast<QSize>(v);
result = QString::asprintf("@Size(%d %d)", s.width(), s.height());
break;
}
- case QVariant::Point: {
+ case QMetaType::QPoint: {
QPoint p = qvariant_cast<QPoint>(v);
result = QString::asprintf("@Point(%d %d)", p.x(), p.y());
break;
@@ -450,7 +446,7 @@ QString QSettingsPrivate::variantToString(const QVariant &v)
#ifndef QT_NO_DATASTREAM
QDataStream::Version version;
const char *typeSpec;
- if (v.type() == QVariant::DateTime) {
+ if (v.userType() == QMetaType::QDateTime) {
version = QDataStream::Qt_5_6;
typeSpec = "@DateTime(";
} else {
@@ -928,8 +924,8 @@ QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
void QConfFileSettingsPrivate::initFormat()
{
extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini");
- readFunc = 0;
- writeFunc = 0;
+ readFunc = nullptr;
+ writeFunc = nullptr;
#if defined(Q_OS_MAC)
caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity;
#else
@@ -1185,7 +1181,9 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
}
+#ifndef Q_OS_WASM // wasm needs to delay access until after file sync
initAccess();
+#endif
}
QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
@@ -1548,13 +1546,6 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
perms |= QFile::ReadGroup | QFile::ReadOther;
QFile(confFile->name).setPermissions(perms);
}
-#ifdef Q_OS_WASM
- EM_ASM(
- // Sync sandbox filesystem to persistent database filesystem. See QTBUG-70002
- FS.syncfs(false, function(err) {
- });
- );
-#endif
} else {
setStatus(QSettings::AccessError);
}
@@ -1897,8 +1888,8 @@ bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSetti
QVariant(QString("foo")).toList() returns an empty
list, not a list containing "foo".
*/
- if (value.type() == QVariant::StringList
- || (value.type() == QVariant::List && value.toList().size() != 1)) {
+ if (value.userType() == QMetaType::QStringList
+ || (value.userType() == QMetaType::QVariantList && value.toList().size() != 1)) {
iniEscapedStringList(variantListToStringList(value.toList()), block, iniCodec);
} else {
iniEscapedString(variantToString(value), block, iniCodec);
@@ -3347,7 +3338,7 @@ bool QSettings::contains(const QString &key) const
{
Q_D(const QSettings);
QString k = d->actualKey(key);
- return d->get(k, 0);
+ return d->get(k, nullptr);
}
/*!
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index d18c96a06c..c30f099a72 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -57,6 +57,10 @@
#include "QtCore/qiodevice.h"
#include "QtCore/qstack.h"
#include "QtCore/qstringlist.h"
+
+#include <QtCore/qvariant.h>
+#include "qsettings.h"
+
#ifndef QT_NO_QOBJECT
#include "private/qobject_p.h"
#endif
@@ -253,6 +257,10 @@ protected:
mutable QSettings::Status status;
};
+#ifdef Q_OS_WASM
+class QWasmSettingsPrivate;
+#endif
+
class QConfFileSettingsPrivate : public QSettingsPrivate
{
public:
@@ -281,7 +289,7 @@ public:
private:
void initFormat();
- void initAccess();
+ virtual void initAccess();
void syncConfFile(QConfFile *confFile);
bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
#ifdef Q_OS_MAC
@@ -297,6 +305,9 @@ private:
QString extension;
Qt::CaseSensitivity caseSensitivity;
int nextPosition;
+#ifdef Q_OS_WASM
+ friend class QWasmSettingsPrivate;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qsettings_wasm.cpp b/src/corelib/io/qsettings_wasm.cpp
new file mode 100644
index 0000000000..8d8f4b505c
--- /dev/null
+++ b/src/corelib/io/qsettings_wasm.cpp
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsettings.h"
+#ifndef QT_NO_SETTINGS
+
+#include "qsettings_p.h"
+#ifndef QT_NO_QOBJECT
+#include "qcoreapplication.h"
+#include <QFile>
+#endif // QT_NO_QOBJECT
+#include <QDebug>
+
+#include <QFileInfo>
+#include <QDir>
+#include <emscripten.h>
+
+QT_BEGIN_NAMESPACE
+
+static bool isReadReady = false;
+
+class QWasmSettingsPrivate : public QConfFileSettingsPrivate
+{
+public:
+ QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application);
+ ~QWasmSettingsPrivate();
+
+ bool get(const QString &key, QVariant *value) const override;
+ QStringList children(const QString &prefix, ChildSpec spec) const override;
+ void clear() override;
+ void sync() override;
+ void flush() override;
+ bool isWritable() const override;
+
+ void syncToLocal(const char *data, int size);
+ void loadLocal(const QByteArray &filename);
+ void setReady();
+ void initAccess() override;
+
+private:
+ QString databaseName;
+ QString id;
+};
+
+static void QWasmSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
+{
+ QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
+
+ QFile file(wasm->fileName());
+ QFileInfo fileInfo(wasm->fileName());
+ QDir dir(fileInfo.path());
+ if (!dir.exists())
+ dir.mkpath(fileInfo.path());
+
+ if (file.open(QFile::WriteOnly)) {
+ file.write(reinterpret_cast<char *>(dataPtr), size);
+ file.close();
+ wasm->setReady();
+ }
+}
+
+static void QWasmSettingsPrivate_onError(void *userData)
+{
+ QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
+ if (wasm)
+ wasm->setStatus(QSettings::AccessError);
+}
+
+static void QWasmSettingsPrivate_onStore(void *userData)
+{
+ QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
+ if (wasm)
+ wasm->setStatus(QSettings::NoError);
+}
+
+static void QWasmSettingsPrivate_onCheck(void *userData, int exists)
+{
+ QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
+ if (wasm) {
+ if (exists)
+ wasm->loadLocal(wasm->fileName().toLocal8Bit());
+ else
+ wasm->setReady();
+ }
+}
+
+QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format,
+ QSettings::Scope scope,
+ const QString &organization,
+ const QString &application)
+{
+ Q_UNUSED(format)
+ if (organization == QLatin1String("Qt"))
+ {
+ QString organizationDomain = QCoreApplication::organizationDomain();
+ QString applicationName = QCoreApplication::applicationName();
+
+ QSettingsPrivate *newSettings;
+ newSettings = new QWasmSettingsPrivate(scope, organizationDomain, applicationName);
+
+ newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(organization)));
+ if (!application.isEmpty())
+ newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(application)));
+
+ return newSettings;
+ }
+ return new QWasmSettingsPrivate(scope, organization, application);
+}
+
+QWasmSettingsPrivate::QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application)
+ : QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
+{
+ setStatus(QSettings::AccessError); // access error until sandbox gets loaded
+ databaseName = organization;
+ id = application;
+
+ emscripten_idb_async_exists("/home/web_user",
+ fileName().toLocal8Bit(),
+ reinterpret_cast<void*>(this),
+ QWasmSettingsPrivate_onCheck,
+ QWasmSettingsPrivate_onError);
+}
+
+QWasmSettingsPrivate::~QWasmSettingsPrivate()
+{
+}
+
+ void QWasmSettingsPrivate::initAccess()
+{
+ if (isReadReady)
+ QConfFileSettingsPrivate::initAccess();
+}
+
+bool QWasmSettingsPrivate::get(const QString &key, QVariant *value) const
+{
+ if (isReadReady)
+ return QConfFileSettingsPrivate::get(key, value);
+
+ return false;
+}
+
+QStringList QWasmSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
+{
+ return QConfFileSettingsPrivate::children(prefix, spec);
+}
+
+void QWasmSettingsPrivate::clear()
+{
+ QConfFileSettingsPrivate::clear();
+ emscripten_idb_async_delete("/home/web_user",
+ fileName().toLocal8Bit(),
+ reinterpret_cast<void*>(this),
+ QWasmSettingsPrivate_onStore,
+ QWasmSettingsPrivate_onError);
+}
+
+void QWasmSettingsPrivate::sync()
+{
+ QConfFileSettingsPrivate::sync();
+
+ QFile file(fileName());
+ if (file.open(QFile::ReadOnly)) {
+ QByteArray dataPointer = file.readAll();
+
+ emscripten_idb_async_store("/home/web_user",
+ fileName().toLocal8Bit(),
+ reinterpret_cast<void *>(dataPointer.data()),
+ dataPointer.length(),
+ reinterpret_cast<void*>(this),
+ QWasmSettingsPrivate_onStore,
+ QWasmSettingsPrivate_onError);
+ }
+}
+
+void QWasmSettingsPrivate::flush()
+{
+ sync();
+}
+
+bool QWasmSettingsPrivate::isWritable() const
+{
+ return isReadReady && QConfFileSettingsPrivate::isWritable();
+}
+
+void QWasmSettingsPrivate::syncToLocal(const char *data, int size)
+{
+ QFile file(fileName());
+
+ if (file.open(QFile::WriteOnly)) {
+ file.write(data, size + 1);
+ QByteArray data = file.readAll();
+
+ emscripten_idb_async_store("/home/web_user",
+ fileName().toLocal8Bit(),
+ reinterpret_cast<void *>(data.data()),
+ data.length(),
+ reinterpret_cast<void*>(this),
+ QWasmSettingsPrivate_onStore,
+ QWasmSettingsPrivate_onError);
+ setReady();
+ }
+}
+
+void QWasmSettingsPrivate::loadLocal(const QByteArray &filename)
+{
+ emscripten_idb_async_load("/home/web_user",
+ filename.data(),
+ reinterpret_cast<void*>(this),
+ QWasmSettingsPrivate_onLoad,
+ QWasmSettingsPrivate_onError);
+}
+
+void QWasmSettingsPrivate::setReady()
+{
+ isReadReady = true;
+ setStatus(QSettings::NoError);
+ QConfFileSettingsPrivate::initAccess();
+}
+
+QT_END_NAMESPACE
+#endif // QT_NO_SETTINGS
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 878e007fb0..def4a1095f 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -415,7 +415,7 @@
#include "qhash.h"
#include "qdir.h" // for QDir::fromNativeSeparators
#include "qdatastream.h"
-#if QT_CONFIG(topleveldomain)
+#if QT_CONFIG(topleveldomain) // ### Qt6: Remove section
#include "qtldurl_p.h"
#endif
#include "private/qipaddress_p.h"
@@ -823,7 +823,7 @@ recodeFromUser(const QString &input, const ushort *actions, int from, int to)
QString output;
const QChar *begin = input.constData() + from;
const QChar *end = input.constData() + to;
- if (qt_urlRecode(output, begin, end, nullptr, actions))
+ if (qt_urlRecode(output, begin, end, {}, actions))
return output;
return input.mid(from, to - from);
@@ -3149,10 +3149,13 @@ bool QUrl::hasFragment() const
return d->hasFragment();
}
+#if QT_DEPRECATED_SINCE(5, 15)
#if QT_CONFIG(topleveldomain)
/*!
\since 4.8
+ \deprecated
+
Returns the TLD (Top-Level Domain) of the URL, (e.g. .co.uk, .net).
Note that the return value is prefixed with a '.' unless the
URL does not contain a valid TLD, in which case the function returns
@@ -3185,7 +3188,7 @@ QString QUrl::topLevelDomain(ComponentFormattingOptions options) const
return tld;
}
#endif
-
+#endif // QT_DEPRECATED_SINCE(5, 15)
/*!
Returns the result of the merge of this URL with \a relative. This
URL is used as a base to convert \a relative to an absolute URL.
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index 94269e4369..eb7fb8087c 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -233,9 +233,11 @@ public:
void setHost(const QString &host, ParsingMode mode = DecodedMode);
QString host(ComponentFormattingOptions = FullyDecoded) const;
+#if QT_DEPRECATED_SINCE(5, 15)
#if QT_CONFIG(topleveldomain)
- QString topLevelDomain(ComponentFormattingOptions options = FullyDecoded) const;
+ QT_DEPRECATED QString topLevelDomain(ComponentFormattingOptions options = FullyDecoded) const;
#endif
+#endif // QT_DEPRECATED_SINCE(5, 15)
void setPort(int port);
int port(int defaultPort = -1) const;