summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfilesystemengine_unix.cpp
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-07-02 18:34:09 -0700
committerThiago Macieira <thiago.macieira@intel.com>2017-08-06 23:14:22 +0000
commit04f4d87bda7e108817e80a7b16ba6fa9323ed3c4 (patch)
treeaf7d6faec56ab34f05cdd74d75f6ae47be35ce6d /src/corelib/io/qfilesystemengine_unix.cpp
parent12339481ea016845ffb79e83d9b3dfb6849c7652 (diff)
QFileSystemEngine::fillMetaData: simplify and comment the code
Took me a long while to understand what it did. Now that I do, I can also answer the question left behind during the original implementation in Qt 4.8 (commit 4fd2aced96d9095254d89f9da9c911bd88f15245 in the old history): how to know if a file exists? Change-Id: I8d96dea9955d4c749b99fffd14cdae135499a0d3 Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io/qfilesystemengine_unix.cpp')
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp103
1 files changed, 65 insertions, 38 deletions
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index e64c7542dd..1774ef609b 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -698,43 +698,62 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
}
#endif // defined(Q_OS_DARWIN)
+ // if we're asking for any of the stat(2) flags, then we're getting them all
if (what & QFileSystemMetaData::PosixStatFlags)
what |= QFileSystemMetaData::PosixStatFlags;
- if (what & QFileSystemMetaData::ExistsAttribute) {
- // FIXME: Would other queries being performed provide this bit?
- what |= QFileSystemMetaData::PosixStatFlags;
- }
-
data.entryFlags &= ~what;
const QByteArray nativeFilePath = entry.nativeFilePath();
bool entryExists = true; // 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)
+ // -> statBufferValid = false
+ // - success and is not a symlink: filesystem entry exists and we're done
+ // -> statBufferValid = true
+ // - failure: really non-existent filesystem entry
+ // -> entryExists = false; statBufferValid = true
+ // both stat(2) and lstat(2) may generate a number of different errno
+ // conditions, but of those, the only ones that could happen and the
+ // entry still exist are EACCES, EFAULT, ENOMEM and EOVERFLOW. If we get
+ // EACCES or ENOMEM, then we have no choice on how to proceed, so we may
+ // as well conclude it doesn't exist; EFAULT can't happen and EOVERFLOW
+ // shouldn't happen because we build in _LARGEFIE64.
QT_STATBUF statBuffer;
bool statBufferValid = false;
if (what & QFileSystemMetaData::LinkType) {
if (QT_LSTAT(nativeFilePath, &statBuffer) == 0) {
if (S_ISLNK(statBuffer.st_mode)) {
+ // it's a symlink, we don't know if the file "exists"
data.entryFlags |= QFileSystemMetaData::LinkType;
} else {
+ // it's a reagular file and it exists
statBufferValid = true;
- data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ data.fillFromStatBuf(statBuffer);
+ data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags
+ | QFileSystemMetaData::ExistsAttribute;
+ data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
}
} else {
+ // it doesn't exist
entryExists = false;
+ data.knownFlagsMask |= QFileSystemMetaData::ExistsAttribute;
}
data.knownFlagsMask |= QFileSystemMetaData::LinkType;
}
+ // second, we try a regular stat(2)
if (statBufferValid || (what & QFileSystemMetaData::PosixStatFlags)) {
- if (entryExists && !statBufferValid)
+ if (entryExists && !statBufferValid) {
statBufferValid = (QT_STAT(nativeFilePath, &statBuffer) == 0);
+ data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ if (statBufferValid)
+ data.fillFromStatBuf(statBuffer);
+ }
- if (statBufferValid)
- data.fillFromStatBuf(statBuffer);
- else {
+ if (!statBufferValid) {
entryExists = false;
data.birthTime_ = 0;
data.metadataChangeTime_ = 0;
@@ -750,34 +769,49 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
| QFileSystemMetaData::ExistsAttribute;
}
+ // third, we try access(2)
+ if (what & (QFileSystemMetaData::UserPermissions | QFileSystemMetaData::ExistsAttribute)) {
+ // calculate user permissions
+ auto checkAccess = [&](QFileSystemMetaData::MetaDataFlag flag, int mode) {
+ if (!entryExists || (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;
+ }
+ };
+
+ checkAccess(QFileSystemMetaData::UserReadPermission, R_OK);
+ checkAccess(QFileSystemMetaData::UserWritePermission, W_OK);
+ 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)
+ data.entryFlags |= QFileSystemMetaData::ExistsAttribute;
+ }
+
+ data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions) |
+ QFileSystemMetaData::ExistsAttribute;
+ }
+
#if defined(Q_OS_DARWIN)
- if (what & QFileSystemMetaData::AliasType)
- {
+ if (what & QFileSystemMetaData::AliasType) {
if (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
data.entryFlags |= QFileSystemMetaData::AliasType;
data.knownFlagsMask |= QFileSystemMetaData::AliasType;
}
-#endif
- if (what & QFileSystemMetaData::UserPermissions) {
- // calculate user permissions
+ if (what & QFileSystemMetaData::BundleType) {
+ if (entryExists && isPackage(data, entry))
+ data.entryFlags |= QFileSystemMetaData::BundleType;
- if (entryExists) {
- if (what & QFileSystemMetaData::UserReadPermission) {
- if (QT_ACCESS(nativeFilePath, R_OK) == 0)
- data.entryFlags |= QFileSystemMetaData::UserReadPermission;
- }
- if (what & QFileSystemMetaData::UserWritePermission) {
- if (QT_ACCESS(nativeFilePath, W_OK) == 0)
- data.entryFlags |= QFileSystemMetaData::UserWritePermission;
- }
- if (what & QFileSystemMetaData::UserExecutePermission) {
- if (QT_ACCESS(nativeFilePath, X_OK) == 0)
- data.entryFlags |= QFileSystemMetaData::UserExecutePermission;
- }
- }
- data.knownFlagsMask |= (what & QFileSystemMetaData::UserPermissions);
+ data.knownFlagsMask |= QFileSystemMetaData::BundleType;
}
+#endif
if (what & QFileSystemMetaData::HiddenAttribute
&& !data.isHidden()) {
@@ -791,15 +825,8 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
}
-#if defined(Q_OS_DARWIN)
- if (what & QFileSystemMetaData::BundleType) {
- if (entryExists && isPackage(data, entry))
- data.entryFlags |= QFileSystemMetaData::BundleType;
-
- data.knownFlagsMask |= QFileSystemMetaData::BundleType;
- }
-#endif
if (!entryExists) {
+ what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink
data.clearFlags(what);
return false;
}