summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qfilesystemengine_unix.cpp
diff options
context:
space:
mode:
authorJoão Abecasis <joao.abecasis@nokia.com>2010-09-03 18:17:35 (GMT)
committerJoão Abecasis <joao.abecasis@nokia.com>2010-09-03 18:39:50 (GMT)
commit4fd2aced96d9095254d89f9da9c911bd88f15245 (patch)
tree6a98f03fd019b401bf244fa053c6fca1f586303c /src/corelib/io/qfilesystemengine_unix.cpp
parent81b302d06c93b77127a2bd6ee527aeefadffbf64 (diff)
downloadQt-4fd2aced96d9095254d89f9da9c911bd88f15245.zip
Qt-4fd2aced96d9095254d89f9da9c911bd88f15245.tar.gz
Qt-4fd2aced96d9095254d89f9da9c911bd88f15245.tar.bz2
QFileSystemEngine::fillMetaData for Unix platforms
This shuffles a lot of code out of QFSFileEngine. fillMetaData, however is almost a reimplementation of the logic. Goals for this function are to maximize data gathered and minimize file system queries. Symbian had an optimization to lstat first and only stat again on links, having noticed a lot of lstat were being done that weren't really necessary. That optimization was also made in the new fillMetaData function and extended to all platforms, whenever the LinkType attribute is requested (QFSFileEngine will now typically request this in reply to a fileFlags request). We now try to cache all meta data we get from the file system, while still requesting "refreshes" as often as we did before. Client code going straight to QFileSystemEngine API can choose it's behaviour by clearing and querying specific flags in the QFileSystemMetaData instance. Reviewed-by: Prasanth Ullattil
Diffstat (limited to 'src/corelib/io/qfilesystemengine_unix.cpp')
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp209
1 files changed, 207 insertions, 2 deletions
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 3011aa0..6b3c157 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -47,12 +47,64 @@
#include <stdlib.h> // for realpath()
#include <errno.h>
+#if defined(Q_OS_SYMBIAN)
+# include <sys/syslimits.h>
+# include <f32file.h>
+# include <pathinfo.h>
+# include <QtCore/private/qcore_symbian_p.h>
+#endif
+
#if defined(Q_OS_MAC)
# include <QtCore/private/qcore_mac_p.h>
#endif
QT_BEGIN_NAMESPACE
+#if defined(Q_OS_SYMBIAN)
+static bool _q_isSymbianHidden(const QFileSystemEntry &entry, bool isDir)
+{
+ RFs rfs = qt_s60GetRFs();
+
+ QFileSystemEntry absoluteEntry = QFileSystemEngine::absoluteName(entry);
+ QString absolutePath = absoluteEntry.filePath();
+
+ if (isDir && !absolutePath.endsWith(QLatin1Char('/')))
+ absolutePath.append(QLatin1Char('/'));
+
+ TPtrC ptr(qt_QString2TPtrC(absolutePath));
+ TUint attributes;
+ TInt err = rfs.Att(ptr, attributes);
+ return (err == KErrNone && (attributes & KEntryAttHidden));
+}
+#endif
+
+#if !defined(QWS) && defined(Q_OS_MAC)
+static inline bool _q_isMacHidden(const char *nativePath)
+{
+ OSErr err;
+
+ FSRef fsRef;
+ err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(nativePath),
+ kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0);
+ if (err != noErr)
+ return false;
+
+ FSCatalogInfo catInfo;
+ err = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL);
+ if (err != noErr)
+ return false;
+
+ FileInfo * const fileInfo = reinterpret_cast<FileInfo*>(&catInfo.finderInfo);
+ return (fileInfo->finderFlags & kIsInvisible);
+}
+#else
+static inline bool _q_isMacHidden(const char *nativePath)
+{
+ // no-op
+ return false;
+}
+#endif
+
void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
{
// Permissions
@@ -207,9 +259,162 @@ QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry)
}
//static
-bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what)
+bool QFileSystemEngine::fillMetaData(int fd, QFileSystemMetaData &data)
{
- return false; // TODO implement;
+ data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags;
+
+ QT_STATBUF statBuffer;
+ if (QT_FSTAT(fd, &statBuffer) == 0) {
+ data.fillFromStatBuf(statBuffer);
+ return true;
+ }
+
+ return false;
+}
+
+//static
+bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
+ QFileSystemMetaData::MetaDataFlags what)
+{
+#if !defined(QWS) && defined(Q_OS_MAC)
+ if (what & QFileSystemMetaData::BundleType) {
+ if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
+ what |= QFileSystemMetaData::DirectoryType;
+ }
+#endif
+
+#if defined(Q_OS_SYMBIAN)
+ if (what & QFileSystemMetaData::HiddenAttribute) {
+ if (!data.hasFlags(QFileSystemMetaData::LinkType | QFileSystemMetaData::DirectoryType))
+ what |= QFileSystemMetaData::LinkType | QFileSystemMetaData::DirectoryType;
+ }
+#endif
+
+ 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 char * nativeFilePath;
+ int nativeFilePathLength;
+ {
+ const QByteArray &path = entry.nativeFilePath();
+ nativeFilePath = path.constData();
+ nativeFilePathLength = path.size();
+ }
+
+ bool entryExists = true; // innocent until proven otherwise
+
+ QT_STATBUF statBuffer;
+ bool statBufferValid = false;
+ if (what & QFileSystemMetaData::LinkType) {
+ if (QT_LSTAT(nativeFilePath, &statBuffer) == 0) {
+ if (S_ISLNK(statBuffer.st_mode)) {
+ data.entryFlags |= QFileSystemMetaData::LinkType;
+ } else {
+ statBufferValid = true;
+ data.entryFlags &= ~QFileSystemMetaData::PosixStatFlags;
+ }
+ } else {
+ entryExists = false;
+ }
+
+ data.knownFlagsMask |= QFileSystemMetaData::LinkType;
+ }
+
+ if (statBufferValid || (what & QFileSystemMetaData::PosixStatFlags)) {
+ if (entryExists && !statBufferValid)
+ statBufferValid = (QT_STAT(nativeFilePath, &statBuffer) == 0);
+
+ if (statBufferValid)
+ data.fillFromStatBuf(statBuffer);
+ else
+ entryExists = false;
+
+ // reset the mask
+ data.knownFlagsMask |= QFileSystemMetaData::PosixStatFlags
+ | QFileSystemMetaData::ExistsAttribute;
+ }
+
+#if !defined(QWS) && defined(Q_OS_MAC)
+ if (what & QFileSystemMetaData::AliasType)
+ {
+ if (entryExists) {
+ FSRef fref;
+ if (FSPathMakeRef((const UInt8 *)nativeFilePath, &fref, NULL) == noErr) {
+ Boolean isAlias, isFolder;
+ if (FSIsAliasFile(&fref, &isAlias, &isFolder) == noErr) {
+ if (isAlias)
+ data.entryFlags |= QFileSystemMetaData::AliasType;
+ }
+ }
+ }
+ data.knownFlagsMask |= QFileSystemMetaData::AliasType;
+ }
+#endif
+
+ if (what & QFileSystemMetaData::UserPermissions) {
+ // calculate user permissions
+
+ 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);
+ }
+
+ if (what & QFileSystemMetaData::HiddenAttribute
+ && !data.isHidden()) {
+#if defined(Q_OS_SYMBIAN)
+ // In Symbian, all symlinks have hidden attribute for some reason;
+ // lets make them visible for better compatibility with other platforms.
+ // If somebody actually wants a hidden link, then they are out of luck.
+ if (entryExists && !data.isLink() && _q_isSymbianHidden(entry, data.isDirectory()))
+ data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
+#else
+ QString fileName = entry.fileName();
+ if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
+ || (entryExists && _q_isMacHidden(nativeFilePath)))
+ data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
+#endif
+ data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
+ }
+
+#if !defined(QWS) && defined(Q_OS_MAC)
+ if (what & QFileSystemMetaData::BundleType) {
+ if (entryExists && data.isDirectory()) {
+ QCFType<CFStringRef> path = CFStringCreateWithBytes(0,
+ (const UInt8*)nativeFilePath, nativeFilePathLength,
+ kCFStringEncodingUTF8, false);
+ QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path,
+ kCFURLPOSIXPathStyle, true);
+
+ UInt32 type, creator;
+ if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
+ data.entryFlags |= QFileSystemMetaData::BundleType;
+ }
+
+ data.knownFlagsMask |= QFileSystemMetaData::BundleType;
+ }
+#endif
+
+ return data.hasFlags(what);
}
//static