diff options
Diffstat (limited to 'src/corelib/io/qfilesystemengine_unix.cpp')
-rw-r--r-- | src/corelib/io/qfilesystemengine_unix.cpp | 78 |
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); |