summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfilesystemengine_unix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qfilesystemengine_unix.cpp')
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp78
1 files changed, 54 insertions, 24 deletions
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);