summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-12-30 17:39:21 +0100
committerLars Knoll <lars.knoll@qt.io>2018-01-02 09:58:44 +0100
commit0f315adf9199efcfafa44371464ab6d1fc866774 (patch)
tree35b67591255624c670aff0579e45b2973f56fd81 /src/corelib/io
parent2b0eb3fac319a17dd92903106d501f0f06df871f (diff)
parent52b85212a2ec8ec5bf187f6cd00b669a45bcf0bd (diff)
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts: .qmake.conf sc/corelib/io/qfsfileengine_p.h src/corelib/io/qstorageinfo_unix.cpp src/platformsupport/eglconvenience/qeglpbuffer_p.h src/platformsupport/input/libinput/qlibinputkeyboard.cpp src/platformsupport/input/libinput/qlibinputpointer.cpp src/plugins/platforms/cocoa/qcocoamenu.mm src/plugins/platforms/ios/qiosscreen.h src/plugins/platforms/ios/qioswindow.h src/plugins/platforms/ios/quiview.mm src/printsupport/dialogs/qpagesetupdialog_unix_p.h src/printsupport/dialogs/qprintpreviewdialog.cpp src/printsupport/widgets/qcupsjobwidget_p.h src/widgets/widgets/qmenu.cpp tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp Change-Id: Iecb4883122efe97ef0ed850271e6c51bab568e9c
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qfile.cpp3
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp78
-rwxr-xr-x[-rw-r--r--]src/corelib/io/qfilesystemengine_win.cpp64
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h4
-rw-r--r--src/corelib/io/qfsfileengine_p.h3
-rw-r--r--src/corelib/io/qloggingregistry.cpp4
-rw-r--r--src/corelib/io/qloggingregistry_p.h2
-rw-r--r--src/corelib/io/qprocess.cpp6
-rw-r--r--src/corelib/io/qresource.cpp4
-rw-r--r--src/corelib/io/qsettings.cpp2
-rw-r--r--src/corelib/io/qstandardpaths.cpp29
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp18
-rw-r--r--src/corelib/io/qtemporaryfile.cpp22
-rw-r--r--src/corelib/io/qtemporaryfile_p.h8
-rw-r--r--src/corelib/io/qurl.cpp110
15 files changed, 297 insertions, 60 deletions
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index bac995ff25..e4888e9523 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -503,7 +503,8 @@ bool
QFile::remove()
{
Q_D(QFile);
- if (d->fileName.isEmpty()) {
+ if (d->fileName.isEmpty() &&
+ !static_cast<QFSFileEngine *>(d->engine())->isUnnamedFile()) {
qWarning("QFile::remove: Empty or null file name");
return false;
}
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index d77cdc123c..b974af80dc 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -55,6 +55,13 @@
#include <stdio.h>
#include <errno.h>
+#if QT_HAS_INCLUDE(<paths.h>)
+# include <paths.h>
+#endif
+#ifndef _PATH_TMP // from <paths.h>
+# define _PATH_TMP "/tmp"
+#endif
+
#if defined(Q_OS_MAC)
# include <QtCore/private/qcore_mac_p.h>
# include <CoreFoundation/CFBundle.h>
@@ -102,8 +109,22 @@ static int statx(int dirfd, const char *pathname, int flag, unsigned mask, struc
# endif
#endif
+#ifndef STATX_BASIC_STATS
+struct statx { mode_t stx_mode; };
+#endif
+
QT_BEGIN_NAMESPACE
+enum {
+#ifdef Q_OS_ANDROID
+ // On Android, the link(2) system call has been observed to always fail
+ // with EACCES, regardless of whether there are permission problems or not.
+ SupportsHardlinking = false
+#else
+ SupportsHardlinking = true
+#endif
+};
+
#define emptyFileEntryWarning() emptyFileEntryWarning_(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC)
static void emptyFileEntryWarning_(const char *file, int line, const char *function)
{
@@ -202,6 +223,8 @@ static inline typename QtPrivate::QEnableIf<(&T::st_atimespec, &T::st_mtimespec,
modification->tv_usec = p->st_mtimespec.tv_nsec / 1000;
}
+# ifndef st_atimensec
+// if "st_atimensec" is defined, this would expand to invalid C++
template <typename T>
static inline typename QtPrivate::QEnableIf<(&T::st_atimensec, &T::st_mtimensec, true)>::Type get(const T *p, struct timeval *access, struct timeval *modification)
{
@@ -211,6 +234,7 @@ static inline typename QtPrivate::QEnableIf<(&T::st_atimensec, &T::st_mtimensec,
modification->tv_sec = p->st_mtime;
modification->tv_usec = p->st_mtimensec / 1000;
}
+# endif
#endif
qint64 timespecToMSecs(const timespec &spec)
@@ -268,6 +292,7 @@ mtime(const T &statBuffer, int)
{ return timespecToMSecs(statBuffer.st_mtimespec); }
#endif
+#ifndef st_mtimensec
// Xtimensec
template <typename T>
Q_DECL_UNUSED static typename std::enable_if<(&T::st_atimensec, true), qint64>::type
@@ -288,8 +313,9 @@ template <typename T>
Q_DECL_UNUSED static typename std::enable_if<(&T::st_mtimensec, true), qint64>::type
mtime(const T &statBuffer, int)
{ return statBuffer.st_mtime * Q_INT64_C(1000) + statBuffer.st_mtimensec / 1000000; }
-}
-}
+#endif
+} // namespace GetFileTimes
+} // unnamed namespace
#ifdef STATX_BASIC_STATS
static int qt_real_statx(int fd, const char *pathname, int flags, struct statx *statxBuffer)
@@ -385,7 +411,6 @@ inline void QFileSystemMetaData::fillFromStatxBuf(const struct statx &statxBuffe
groupId_ = statxBuffer.stx_gid;
}
#else
-struct statx { mode_t stx_mode; };
static int qt_statx(const char *, struct statx *)
{ return -ENOSYS; }
@@ -918,7 +943,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
data.entryFlags &= ~what;
const QByteArray nativeFilePath = entry.nativeFilePath();
- bool entryExists = true; // innocent until proven otherwise
+ int entryErrno = 0; // innocent until proven otherwise
// first, we may try lstat(2). Possible outcomes:
// - success and is a symlink: filesystem entry exists, but we need stat(2)
@@ -968,7 +993,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
}
} else {
// it doesn't exist
- entryExists = false;
+ entryErrno = errno;
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
}
@@ -976,8 +1001,8 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
}
// second, we try a regular stat(2)
- if (statResult != 0 && (what & QFileSystemMetaData::PosixStatFlags)) {
- if (entryExists && statResult == -1) {
+ if (statResult == -1 && (what & QFileSystemMetaData::PosixStatFlags)) {
+ if (entryErrno == 0 && statResult == -1) {
data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
statResult = qt_statx(nativeFilePath, &statxBuffer);
if (statResult == -ENOSYS) {
@@ -991,7 +1016,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
}
if (statResult != 0) {
- entryExists = false;
+ entryErrno = errno;
data.birthTime_ = 0;
data.metadataChangeTime_ = 0;
data.modificationTime_ = 0;
@@ -1010,13 +1035,13 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
if (what & (QFileSystemMetaData::UserPermissions | QFileSystemMetaData::ExistsAttribute)) {
// calculate user permissions
auto checkAccess = [&](QFileSystemMetaData::MetaDataFlag flag, int mode) {
- if (!entryExists || (what & flag) == 0)
+ if (entryErrno != 0 || (what & flag) == 0)
return;
if (QT_ACCESS(nativeFilePath, mode) == 0) {
// access ok (and file exists)
data.entryFlags |= flag | QFileSystemMetaData::ExistsAttribute;
} else if (errno != EACCES && errno != EROFS) {
- entryExists = false;
+ entryErrno = errno;
}
};
@@ -1025,9 +1050,10 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
checkAccess(QFileSystemMetaData::UserExecutePermission, X_OK);
// if we still haven't found out if the file exists, try F_OK
- if (entryExists && (data.entryFlags & QFileSystemMetaData::ExistsAttribute) == 0) {
- entryExists = QT_ACCESS(nativeFilePath, F_OK) == 0;
- if (entryExists)
+ if (entryErrno == 0 && (data.entryFlags & QFileSystemMetaData::ExistsAttribute) == 0) {
+ if (QT_ACCESS(nativeFilePath, F_OK) == -1)
+ entryErrno = errno;
+ else
data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
}
@@ -1037,13 +1063,13 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
#if defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::AliasType) {
- if (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
+ if (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
data.entryFlags |= QFileSystemMetaData::AliasType;
data.knownFlagsMask |= QFileSystemMetaData::AliasType;
}
if (what & QFileSystemMetaData::BundleType) {
- if (entryExists && isPackage(data, entry))
+ if (entryErrno == 0 && isPackage(data, entry))
data.entryFlags |= QFileSystemMetaData::BundleType;
data.knownFlagsMask |= QFileSystemMetaData::BundleType;
@@ -1055,19 +1081,19 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
QString fileName = entry.fileName();
if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
#if defined(Q_OS_DARWIN)
- || (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey))
+ || (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey))
#endif
)
data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
}
- if (!entryExists) {
+ if (entryErrno != 0) {
what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink
data.clearFlags(what);
return false;
}
- return data.hasFlags(what);
+ return true;
}
// static
@@ -1278,7 +1304,7 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
}
#endif
- if (::link(srcPath, tgtPath) == 0) {
+ if (SupportsHardlinking && ::link(srcPath, tgtPath) == 0) {
if (::unlink(srcPath) == 0)
return true;
@@ -1292,6 +1318,11 @@ bool QFileSystemEngine::renameFile(const QFileSystemEntry &source, const QFileSy
error = QSystemError(savedErrno, QSystemError::StandardLibraryError);
return false;
+ } else if (!SupportsHardlinking) {
+ // man 2 link on Linux has:
+ // EPERM The filesystem containing oldpath and newpath does not
+ // support the creation of hard links.
+ errno = EPERM;
}
switch (errno) {
@@ -1483,14 +1514,13 @@ QString QFileSystemEngine::tempPath()
#else
QString temp = QFile::decodeName(qgetenv("TMPDIR"));
if (temp.isEmpty()) {
+ if (false) {
#if defined(Q_OS_DARWIN) && !defined(QT_BOOTSTRAPPED)
- if (NSString *nsPath = NSTemporaryDirectory()) {
+ } else if (NSString *nsPath = NSTemporaryDirectory()) {
temp = QString::fromCFString((CFStringRef)nsPath);
- } else {
-#else
- {
#endif
- temp = QLatin1String("/tmp");
+ } else {
+ temp = QLatin1String(_PATH_TMP);
}
}
return QDir::cleanPath(temp);
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 944ca232ee..fadc058110 100644..100755
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -160,6 +160,7 @@ static TRUSTEE_W currentUserTrusteeW;
static TRUSTEE_W worldTrusteeW;
static PSID currentUserSID = 0;
static PSID worldSID = 0;
+static HANDLE currentUserImpersonatedToken = nullptr;
QT_BEGIN_NAMESPACE
@@ -180,6 +181,11 @@ GlobalSid::~GlobalSid()
::FreeSid(worldSID);
worldSID = 0;
}
+
+ if (currentUserImpersonatedToken) {
+ ::CloseHandle(currentUserImpersonatedToken);
+ currentUserImpersonatedToken = nullptr;
+ }
}
GlobalSid::GlobalSid()
@@ -210,6 +216,12 @@ GlobalSid::GlobalSid()
::CloseHandle(token);
}
+ token = nullptr;
+ if (::OpenProcessToken(hnd, TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &token)) {
+ ::DuplicateToken(token, SecurityImpersonation, &currentUserImpersonatedToken);
+ ::CloseHandle(token);
+ }
+
{
// Create TRUSTEE for Everyone (World)
SID_IDENTIFIER_AUTHORITY worldAuth = { SECURITY_WORLD_SID_AUTHORITY };
@@ -724,15 +736,49 @@ bool QFileSystemEngine::fillPermissions(const QFileSystemEntry &entry, QFileSyst
ACCESS_MASK access_mask;
TRUSTEE_W trustee;
if (what & QFileSystemMetaData::UserPermissions) { // user
- data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
- if (GetEffectiveRightsFromAcl(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
- access_mask = (ACCESS_MASK)-1;
- if(access_mask & ReadMask)
- data.entryFlags |= QFileSystemMetaData::UserReadPermission;
- if(access_mask & WriteMask)
- data.entryFlags|= QFileSystemMetaData::UserWritePermission;
- if(access_mask & ExecMask)
- data.entryFlags|= QFileSystemMetaData::UserExecutePermission;
+ // Using AccessCheck because GetEffectiveRightsFromAcl doesn't account for elevation
+ if (currentUserImpersonatedToken) {
+ GENERIC_MAPPING mapping = {FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS};
+ PRIVILEGE_SET privileges;
+ DWORD grantedAccess;
+ BOOL result;
+
+ data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
+ DWORD genericAccessRights = GENERIC_READ;
+ ::MapGenericMask(&genericAccessRights, &mapping);
+
+ DWORD privilegesLength = sizeof(privileges);
+ if (::AccessCheck(pSD, currentUserImpersonatedToken, genericAccessRights,
+ &mapping, &privileges, &privilegesLength, &grantedAccess, &result) && result) {
+ data.entryFlags |= QFileSystemMetaData::UserReadPermission;
+ }
+
+ privilegesLength = sizeof(privileges);
+ genericAccessRights = GENERIC_WRITE;
+ ::MapGenericMask(&genericAccessRights, &mapping);
+ if (::AccessCheck(pSD, currentUserImpersonatedToken, genericAccessRights,
+ &mapping, &privileges, &privilegesLength, &grantedAccess, &result) && result) {
+ data.entryFlags |= QFileSystemMetaData::UserWritePermission;
+ }
+
+ privilegesLength = sizeof(privileges);
+ genericAccessRights = GENERIC_EXECUTE;
+ ::MapGenericMask(&genericAccessRights, &mapping);
+ if (::AccessCheck(pSD, currentUserImpersonatedToken, genericAccessRights,
+ &mapping, &privileges, &privilegesLength, &grantedAccess, &result) && result) {
+ data.entryFlags |= QFileSystemMetaData::UserExecutePermission;
+ }
+ } else { // fallback to GetEffectiveRightsFromAcl
+ data.knownFlagsMask |= QFileSystemMetaData::UserPermissions;
+ if (GetEffectiveRightsFromAclW(pDacl, &currentUserTrusteeW, &access_mask) != ERROR_SUCCESS)
+ access_mask = ACCESS_MASK(-1);
+ if (access_mask & ReadMask)
+ data.entryFlags |= QFileSystemMetaData::UserReadPermission;
+ if (access_mask & WriteMask)
+ data.entryFlags|= QFileSystemMetaData::UserWritePermission;
+ if (access_mask & ExecMask)
+ data.entryFlags|= QFileSystemMetaData::UserExecutePermission;
+ }
}
if (what & QFileSystemMetaData::OwnerPermissions) { // owner
data.knownFlagsMask |= QFileSystemMetaData::OwnerPermissions;
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index 55e44d52c7..4d2a5acb9b 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -64,6 +64,10 @@
# endif
#endif
+#ifdef Q_OS_UNIX
+struct statx;
+#endif
+
QT_BEGIN_NAMESPACE
class QFileSystemEngine;
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index bf90995fdd..16ba161b75 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -112,6 +112,9 @@ public:
qint64 write(const char *data, qint64 len) override;
bool cloneTo(QAbstractFileEngine *target) override;
+ virtual bool isUnnamedFile() const
+ { return false; }
+
bool extension(Extension extension, const ExtensionOption *option = 0, ExtensionReturn *output = 0) override;
bool supportsExtension(Extension extension) const override;
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index 1bf61017f6..b5f8e30b80 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -255,7 +255,7 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line)
QLoggingRegistry::QLoggingRegistry()
: categoryFilter(defaultCategoryFilter)
{
- initalizeRules(); // Init on first use
+ initializeRules(); // Init on first use
}
static bool qtLoggingDebug()
@@ -284,7 +284,7 @@ static QVector<QLoggingRule> loadRulesFromFile(const QString &filePath)
Initializes the rules database by loading
$QT_LOGGING_CONF, $QT_LOGGING_RULES, and .config/QtProject/qtlogging.ini.
*/
-void QLoggingRegistry::initalizeRules()
+void QLoggingRegistry::initializeRules()
{
QVector<QLoggingRule> er, qr, cr;
// get rules from environment
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index a3857d3588..12a1f166b3 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -113,7 +113,7 @@ class Q_AUTOTEST_EXPORT QLoggingRegistry
public:
QLoggingRegistry();
- void initalizeRules();
+ void initializeRules();
void registerCategory(QLoggingCategory *category, QtMsgType enableForLevel);
void unregisterCategory(QLoggingCategory *category);
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 41f4b2aa83..2ee680a7c6 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -99,6 +99,10 @@ QT_END_NAMESPACE
#include <private/qcore_unix_p.h>
#endif
+#if QT_HAS_INCLUDE(<paths.h>)
+#include <paths.h>
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -2637,6 +2641,8 @@ QString QProcess::nullDevice()
{
#ifdef Q_OS_WIN
return QStringLiteral("\\\\.\\NUL");
+#elif defined(_PATH_DEVNULL)
+ return QStringLiteral(_PATH_DEVNULL);
#else
return QStringLiteral("/dev/null");
#endif
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index 9a63374e6f..35a0de4fb7 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -86,8 +86,8 @@ public:
}
const QChar *m_data;
- qssize_t m_len;
- qssize_t m_pos = 0;
+ qsizetype m_len;
+ qsizetype m_pos = 0;
QChar m_splitChar = QLatin1Char('/');
};
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index d0cbc82c56..bbc66120b5 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -1451,7 +1451,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
Files that we can't read (because of permissions or
because they don't exist) are treated as empty files.
*/
- if (file.isReadable() && fileInfo.size() != 0) {
+ if (file.isReadable() && file.size() != 0) {
bool ok = false;
#ifdef Q_OS_MAC
if (format == QSettings::NativeFormat) {
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index c3d45caf0e..b3a5bd797a 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -48,6 +48,14 @@
#include <qcoreapplication.h>
#endif
+#if QT_HAS_INCLUDE(<paths.h>)
+#include <paths.h>
+#endif
+
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
#ifndef QT_NO_STANDARDPATHS
QT_BEGIN_NAMESPACE
@@ -509,6 +517,27 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr
QStringList searchPaths = paths;
if (paths.isEmpty()) {
QByteArray pEnv = qgetenv("PATH");
+ if (Q_UNLIKELY(pEnv.isNull())) {
+ // Get a default path. POSIX.1 does not actually require this, but
+ // most Unix libc fall back to confstr(_CS_PATH) if the PATH
+ // environment variable isn't set. Let's try to do the same.
+#if defined(_PATH_DEFPATH)
+ // BSD API.
+ pEnv = _PATH_DEFPATH;
+#elif defined(_CS_PATH)
+ // POSIX API.
+ size_t n = confstr(_CS_PATH, nullptr, 0);
+ if (n) {
+ pEnv.resize(n);
+ // size()+1 is ok because QByteArray always has an extra NUL-terminator
+ confstr(_CS_PATH, pEnv.data(), pEnv.size() + 1);
+ }
+#else
+ // Windows SDK's execvpe() does not have a fallback, so we won't
+ // apply one either.
+#endif
+ }
+
// Remove trailing slashes, which occur on Windows.
const QStringList rawPaths = QString::fromLocal8Bit(pEnv.constData()).split(QDir::listSeparator(), QString::SkipEmptyParts);
searchPaths.reserve(rawPaths.size());
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 6d8b6ee1a0..7664b77d81 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -108,6 +108,13 @@
# endif // QT_LARGEFILE_SUPPORT
#endif // Q_OS_BSD4
+#if QT_HAS_INCLUDE(<paths.h>)
+# include <paths.h>
+#endif
+#ifndef _PATH_MOUNTED
+# define _PATH_MOUNTED "/etc/mnttab"
+#endif
+
QT_BEGIN_NAMESPACE
class QStorageIterator
@@ -274,11 +281,9 @@ inline QByteArray QStorageIterator::subvolume() const
}
#elif defined(Q_OS_SOLARIS)
-static const char pathMounted[] = "/etc/mnttab";
-
inline QStorageIterator::QStorageIterator()
{
- const int fd = qt_safe_open(pathMounted, O_RDONLY);
+ const int fd = qt_safe_open(_PATH_MOUNTED, O_RDONLY);
fp = ::fdopen(fd, "r");
}
@@ -319,11 +324,9 @@ inline QByteArray QStorageIterator::subvolume() const
}
#elif defined(Q_OS_ANDROID)
-static const QLatin1String pathMounted("/proc/mounts");
-
inline QStorageIterator::QStorageIterator()
{
- file.setFileName(pathMounted);
+ file.setFileName(_PATH_MOUNTED);
file.open(QIODevice::ReadOnly | QIODevice::Text);
}
@@ -380,7 +383,6 @@ inline QByteArray QStorageIterator::subvolume() const
}
#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
-static const char pathMounted[] = "/etc/mtab";
static const int bufferSize = 1024; // 2 paths (mount point+device) and metainfo;
// should be enough
@@ -397,7 +399,7 @@ inline QStorageIterator::QStorageIterator() :
usingMountinfo = true;
} else {
usingMountinfo = false;
- fp = ::setmntent(pathMounted, "r");
+ fp = ::setmntent(_PATH_MOUNTED, "r");
}
}
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index b8d3e859cf..35699d52df 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -393,7 +393,9 @@ bool QTemporaryFileEngine::remove()
// we must explicitly call QFSFileEngine::close() before we remove it.
d->unmapAll();
QFSFileEngine::close();
- if (isUnnamedFile() || QFSFileEngine::remove()) {
+ if (isUnnamedFile())
+ return true;
+ if (!filePathIsTemplate && QFSFileEngine::remove()) {
d->fileEntry.clear();
// If a QTemporaryFile is constructed using a template file path, the path
// is generated in QTemporaryFileEngine::open() and then filePathIsTemplate
@@ -511,7 +513,10 @@ bool QTemporaryFileEngine::materializeUnnamedFile(const QString &newName, QTempo
bool QTemporaryFileEngine::isUnnamedFile() const
{
#ifdef LINUX_UNNAMED_TMPFILE
- Q_ASSERT(unnamedFile == d_func()->fileEntry.isEmpty());
+ if (unnamedFile) {
+ Q_ASSERT(d_func()->fileEntry.isEmpty());
+ Q_ASSERT(filePathIsTemplate);
+ }
return unnamedFile;
#else
return false;
@@ -749,10 +754,21 @@ bool QTemporaryFile::autoRemove() const
}
/*!
- Sets the QTemporaryFile into auto-remove mode if \a b is true.
+ Sets the QTemporaryFile into auto-remove mode if \a b is \c true.
Auto-remove is on by default.
+ If you set this property to \c false, ensure the application provides a way
+ to remove the file once it is no longer needed, including passing the
+ responsibility on to another process. Always use the fileName() function to
+ obtain the name and never try to guess the name that QTemporaryFile has
+ generated.
+
+ On some systems, if fileName() is not called before closing the file, the
+ temporary file may be removed regardless of the state of this property.
+ This behavior should not be relied upon, so application code should either
+ call fileName() or leave the auto removal functionality enabled.
+
\sa autoRemove(), remove()
*/
void QTemporaryFile::setAutoRemove(bool b)
diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h
index 46a0d7aba3..fb8887af53 100644
--- a/src/corelib/io/qtemporaryfile_p.h
+++ b/src/corelib/io/qtemporaryfile_p.h
@@ -58,7 +58,7 @@
#include "private/qfile_p.h"
#include "qtemporaryfile.h"
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) && QT_CONFIG(linkat)
# include <fcntl.h>
# ifdef O_TMPFILE
// some early libc support had the wrong values for O_TMPFILE
@@ -74,8 +74,8 @@ QT_BEGIN_NAMESPACE
struct QTemporaryFileName
{
QFileSystemEntry::NativePath path;
- qssize_t pos;
- qssize_t length;
+ qsizetype pos;
+ qsizetype length;
QTemporaryFileName(const QString &templateName);
QFileSystemEntry::NativePath generateNext();
@@ -140,7 +140,7 @@ public:
enum MaterializationMode { Overwrite, DontOverwrite, NameIsTemplate };
bool materializeUnnamedFile(const QString &newName, MaterializationMode mode);
- bool isUnnamedFile() const;
+ bool isUnnamedFile() const override final;
const QString &templateName;
quint32 fileMode;
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index cf7ed130ba..4587b9fcd6 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -90,11 +90,6 @@
fromPercentEncoding() and toPercentEncoding() which deal with
percent encoding and decoding of QString objects.
- Calling isRelative() will tell whether or not the URL is
- relative. A relative URL can be resolved by passing it as argument
- to resolved(), which returns an absolute URL. isParentOf() is used
- for determining whether one URL is a parent of another.
-
fromLocalFile() constructs a QUrl by parsing a local
file path. toLocalFile() converts a URL to a local file path.
@@ -116,6 +111,37 @@
from freedesktop.org, provided that the locale encodes file names using
UTF-8 (required by IDN).
+ \section2 Relative URLs vs Relative Paths
+
+ Calling isRelative() will return whether or not the URL is relative.
+ A relative URL has no \l {scheme}. For example:
+
+ \code
+ qDebug() << QUrl("main.qml").isRelative(); // true: no scheme
+ qDebug() << QUrl("qml/main.qml").isRelative(); // true: no scheme
+ qDebug() << QUrl("file:main.qml").isRelative(); // false: has "file" scheme
+ qDebug() << QUrl("file:qml/main.qml").isRelative(); // false: has "file" scheme
+ \endcode
+
+ Notice that a URL can be absolute while containing a relative path, and
+ vice versa:
+
+ \code
+ // Absolute URL, relative path
+ QUrl url("file:file.txt");
+ qDebug() << url.isRelative(); // false: has "file" scheme
+ qDebug() << QDir::isAbsolutePath(url.path()); // false: relative path
+
+ // Relative URL, absolute path
+ url = QUrl("/home/user/file.txt");
+ qDebug() << url.isRelative(); // true: has no scheme
+ qDebug() << QDir::isAbsolutePath(url.path()); // true: absolute path
+ \endcode
+
+ A relative URL can be resolved by passing it as an argument to resolved(),
+ which returns an absolute URL. isParentOf() is used for determining whether
+ one URL is a parent of another.
+
\section2 Error checking
QUrl is capable of detecting many errors in URLs while parsing it or when
@@ -2539,6 +2565,12 @@ void QUrl::setPath(const QString &path, ParsingMode mode)
/*!
Returns the path of the URL.
+ \code
+ qDebug() << QUrl("file:file.txt").path(); // "file.txt"
+ qDebug() << QUrl("/home/user/file.txt").path(); // "/home/user/file.txt"
+ qDebug() << QUrl("http://www.example.com/test/123").path(); // "/test/123"
+ \endcode
+
The \a options argument controls how to format the path component. All
values produce an unambiguous result. With QUrl::FullyDecoded, all
percent-encoded sequences are decoded; otherwise, the returned value may
@@ -2549,6 +2581,31 @@ void QUrl::setPath(const QString &path, ParsingMode mode)
sequences are present. It is recommended to use that value when the result
will be used in a non-URL context, such as sending to an FTP server.
+ An example of data loss is when you have non-Unicode percent-encoded sequences
+ and use FullyDecoded (the default):
+
+ \code
+ qDebug() << QUrl("/foo%FFbar").path();
+ \endcode
+
+ In this example, there will be some level of data loss because the \c %FF cannot
+ be converted.
+
+ Data loss can also occur when the path contains sub-delimiters (such as \c +):
+
+ \code
+ qDebug() << QUrl("/foo+bar%2B").path(); // "/foo+bar+"
+ \endcode
+
+ Other decoding examples:
+
+ \code
+ const QUrl url("/tmp/Mambo %235%3F.mp3");
+ qDebug() << url.path(QUrl::FullyDecoded); // "/tmp/Mambo #5?.mp3"
+ qDebug() << url.path(QUrl::PrettyDecoded); // "/tmp/Mambo #5?.mp3"
+ qDebug() << url.path(QUrl::FullyEncoded); // "/tmp/Mambo%20%235%3F.mp3"
+ \endcode
+
\sa setPath()
*/
QString QUrl::path(ComponentFormattingOptions options) const
@@ -3257,6 +3314,8 @@ QUrl QUrl::resolved(const QUrl &relative) const
equivalent to calling scheme().isEmpty().
Relative references are defined in RFC 3986 section 4.2.
+
+ \sa {Relative URLs vs Relative Paths}
*/
bool QUrl::isRelative() const
{
@@ -3796,6 +3855,41 @@ bool QUrl::isDetached() const
An empty \a localFile leads to an empty URL (since Qt 5.4).
+ \code
+ qDebug() << QUrl::fromLocalFile("file.txt"); // QUrl("file:file.txt")
+ qDebug() << QUrl::fromLocalFile("/home/user/file.txt"); // QUrl("file:///home/user/file.txt")
+ qDebug() << QUrl::fromLocalFile("file:file.txt"); // doesn't make sense; expects path, not url with scheme
+ \endcode
+
+ In the first line in snippet above, a file URL is constructed from a
+ local, relative path. A file URL with a relative path only makes sense
+ if there is a base URL to resolve it against. For example:
+
+ \code
+ QUrl url = QUrl::fromLocalFile("file.txt");
+ QUrl baseUrl = QUrl("file:/home/user/");
+ // wrong: prints QUrl("file:file.txt"), as url already has a scheme
+ qDebug() << baseUrl.resolved(url);
+ \endcode
+
+ To resolve such a URL, it's necessary to remove the scheme beforehand:
+
+ \code
+ // correct: prints QUrl("file:///home/user/file.txt")
+ url.setScheme(QString());
+ qDebug() << baseUrl.resolved(url);
+ \endcode
+
+ For this reason, it is better to use a relative URL (that is, no scheme)
+ for relative file paths:
+
+ \code
+ QUrl url = QUrl("file.txt");
+ QUrl baseUrl = QUrl("file:/home/user/");
+ // prints QUrl("file:///home/user/file.txt")
+ qDebug() << baseUrl.resolved(url);
+ \endcode
+
\sa toLocalFile(), isLocalFile(), QDir::toNativeSeparators()
*/
QUrl QUrl::fromLocalFile(const QString &localFile)
@@ -3840,6 +3934,12 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
returned value in the form found on SMB networks (for example,
"//servername/path/to/file.txt").
+ \code
+ qDebug() << QUrl("file:file.txt").toLocalFile(); // "file:file.txt"
+ qDebug() << QUrl("file:/home/user/file.txt").toLocalFile(); // "file:///home/user/file.txt"
+ qDebug() << QUrl("file.txt").toLocalFile(); // ""; wasn't a local file as it had no scheme
+ \endcode
+
Note: if the path component of this URL contains a non-UTF-8 binary
sequence (such as %80), the behaviour of this function is undefined.