QFileSystemEngine/Linux: fix when qt_lstatx() succeeds

When qt_lstatx() succeeds and the target is not a link, we'd erroneously
mark the file as non-existent during the pass to check qt_statx(). All
flags besides the file's modes were cleared.

This is unit-tested, but only happens on Linux kernels 4.12 or later. It
didn't happen to me because I already had this fix applied as part of a
later change relating to QSystemResult.

Task-number: QTBUG-64514
Change-Id: I938b024e38bf4aac9154fffd14f893506a1ef55b
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Thiago Macieira 2017-11-19 11:26:33 -08:00
parent 3c7a6a7a58
commit 4ee85ff7c5

View File

@ -918,7 +918,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
data.entryFlags &= ~what; data.entryFlags &= ~what;
const QByteArray nativeFilePath = entry.nativeFilePath(); 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: // first, we may try lstat(2). Possible outcomes:
// - success and is a symlink: filesystem entry exists, but we need stat(2) // - success and is a symlink: filesystem entry exists, but we need stat(2)
@ -968,7 +968,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
} }
} else { } else {
// it doesn't exist // it doesn't exist
entryExists = false; entryErrno = errno;
data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute; data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
} }
@ -976,8 +976,8 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
} }
// second, we try a regular stat(2) // second, we try a regular stat(2)
if (statResult != 0 && (what & QFileSystemMetaData::PosixStatFlags)) { if (statResult == -1 && (what & QFileSystemMetaData::PosixStatFlags)) {
if (entryExists && statResult == -1) { if (entryErrno == 0 && statResult == -1) {
data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags; data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
statResult = qt_statx(nativeFilePath, &statxBuffer); statResult = qt_statx(nativeFilePath, &statxBuffer);
if (statResult == -ENOSYS) { if (statResult == -ENOSYS) {
@ -991,7 +991,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
} }
if (statResult != 0) { if (statResult != 0) {
entryExists = false; entryErrno = errno;
data.birthTime_ = 0; data.birthTime_ = 0;
data.metadataChangeTime_ = 0; data.metadataChangeTime_ = 0;
data.modificationTime_ = 0; data.modificationTime_ = 0;
@ -1010,13 +1010,13 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
if (what & (QFileSystemMetaData::UserPermissions | QFileSystemMetaData::ExistsAttribute)) { if (what & (QFileSystemMetaData::UserPermissions | QFileSystemMetaData::ExistsAttribute)) {
// calculate user permissions // calculate user permissions
auto checkAccess = [&](QFileSystemMetaData::MetaDataFlag flag, int mode) { auto checkAccess = [&](QFileSystemMetaData::MetaDataFlag flag, int mode) {
if (!entryExists || (what & flag) == 0) if (entryErrno != 0 || (what & flag) == 0)
return; return;
if (QT_ACCESS(nativeFilePath, mode) == 0) { if (QT_ACCESS(nativeFilePath, mode) == 0) {
// access ok (and file exists) // access ok (and file exists)
data.entryFlags |= flag | QFileSystemMetaData::ExistsAttribute; data.entryFlags |= flag | QFileSystemMetaData::ExistsAttribute;
} else if (errno != EACCES && errno != EROFS) { } else if (errno != EACCES && errno != EROFS) {
entryExists = false; entryErrno = errno;
} }
}; };
@ -1025,9 +1025,10 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
checkAccess(QFileSystemMetaData::UserExecutePermission, X_OK); checkAccess(QFileSystemMetaData::UserExecutePermission, X_OK);
// if we still haven't found out if the file exists, try F_OK // if we still haven't found out if the file exists, try F_OK
if (entryExists && (data.entryFlags & QFileSystemMetaData::ExistsAttribute) == 0) { if (entryErrno == 0 && (data.entryFlags & QFileSystemMetaData::ExistsAttribute) == 0) {
entryExists = QT_ACCESS(nativeFilePath, F_OK) == 0; if (QT_ACCESS(nativeFilePath, F_OK) == -1)
if (entryExists) entryErrno = errno;
else
data.entryFlags |= QFileSystemMetaData::ExistsAttribute; data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
} }
@ -1037,13 +1038,13 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
#if defined(Q_OS_DARWIN) #if defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::AliasType) { if (what & QFileSystemMetaData::AliasType) {
if (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey)) if (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
data.entryFlags |= QFileSystemMetaData::AliasType; data.entryFlags |= QFileSystemMetaData::AliasType;
data.knownFlagsMask |= QFileSystemMetaData::AliasType; data.knownFlagsMask |= QFileSystemMetaData::AliasType;
} }
if (what & QFileSystemMetaData::BundleType) { if (what & QFileSystemMetaData::BundleType) {
if (entryExists && isPackage(data, entry)) if (entryErrno == 0 && isPackage(data, entry))
data.entryFlags |= QFileSystemMetaData::BundleType; data.entryFlags |= QFileSystemMetaData::BundleType;
data.knownFlagsMask |= QFileSystemMetaData::BundleType; data.knownFlagsMask |= QFileSystemMetaData::BundleType;
@ -1055,19 +1056,19 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
QString fileName = entry.fileName(); QString fileName = entry.fileName();
if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.')) if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
#if defined(Q_OS_DARWIN) #if defined(Q_OS_DARWIN)
|| (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey)) || (entryErrno == 0 && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey))
#endif #endif
) )
data.entryFlags |= QFileSystemMetaData::HiddenAttribute; data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute; data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
} }
if (!entryExists) { if (entryErrno != 0) {
what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink
data.clearFlags(what); data.clearFlags(what);
return false; return false;
} }
return data.hasFlags(what); return true;
} }
// static // static