From 4fd2aced96d9095254d89f9da9c911bd88f15245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 3 Sep 2010 20:17:35 +0200 Subject: 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 --- src/corelib/io/qfilesystemengine_p.h | 3 + src/corelib/io/qfilesystemengine_unix.cpp | 209 ++++++++++++++++++++- src/corelib/io/qfsfileengine.cpp | 33 +--- src/corelib/io/qfsfileengine_p.h | 14 +- src/corelib/io/qfsfileengine_unix.cpp | 300 +++++++++--------------------- 5 files changed, 324 insertions(+), 235 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h index f50701e..182ccd6 100644 --- a/src/corelib/io/qfilesystemengine_p.h +++ b/src/corelib/io/qfilesystemengine_p.h @@ -72,6 +72,9 @@ public: static bool fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, QFileSystemMetaData::MetaDataFlags what); +#if defined(Q_OS_UNIX) + static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags +#endif static bool createDirectory(const QFileSystemEntry &entry, bool createParents); static bool removeDirectory(const QFileSystemEntry &entry, bool removeEmptyParents); 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 // for realpath() #include +#if defined(Q_OS_SYMBIAN) +# include +# include +# include +# include +#endif + #if defined(Q_OS_MAC) # include #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(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(&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 path = CFStringCreateWithBytes(0, + (const UInt8*)nativeFilePath, nativeFilePathLength, + kCFStringEncodingUTF8, false); + QCFType 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 diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 5d7b354..1b0a28c 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -447,24 +447,13 @@ qint64 QFSFileEngine::size() const qint64 QFSFileEnginePrivate::sizeFdFh() const { Q_Q(const QFSFileEngine); - // ### Fix this function, it should not stat unless the file is closed. - QT_STATBUF st; - int ret = 0; const_cast(q)->flush(); - if (fh && fileEntry.isEmpty()) { - // Buffered stdlib mode. - // ### This should really be an ftell - ret = QT_FSTAT(QT_FILENO(fh), &st); - } else if (fd == -1) { - // Stateless stat. - ret = QT_STAT(fileEntry.nativeFilePath().constData(), &st); - } else { - // Unbuffered stdio mode. - ret = QT_FSTAT(fd, &st); - } - if (ret == -1) + + tried_stat = 0; + metaData.clearFlags(QFileSystemMetaData::SizeAttribute); + if (!doStat(QFileSystemMetaData::SizeAttribute)) return 0; - return st.st_size; + return metaData.size(); } #endif @@ -773,18 +762,14 @@ bool QFSFileEngine::isSequential() const /*! \internal */ +#ifdef Q_OS_UNIX bool QFSFileEnginePrivate::isSequentialFdFh() const { - if (!tried_stat) - doStat(); - if (could_stat) { -#ifdef Q_OS_UNIX - return (st.st_mode & S_IFMT) != S_IFREG; - // ### WINDOWS! -#endif - } + if (doStat(QFileSystemMetaData::SequentialType)) + return metaData.isSequential(); return true; } +#endif /*! \reimp diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 9eaf6fd..6e5f30e 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -56,7 +56,8 @@ #include "qplatformdefs.h" #include "QtCore/qfsfileengine.h" #include "private/qabstractfileengine_p.h" -#include "private/qfilesystementry_p.h" +#include +#include #include #ifndef QT_NO_FSFILEENGINE @@ -102,11 +103,17 @@ public: qint64 writeFdFh(const char *data, qint64 len); int nativeHandle() const; bool nativeIsSequential() const; +#ifndef Q_OS_WIN bool isSequentialFdFh() const; +#endif uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags); bool unmap(uchar *ptr); +#if defined(Q_OS_UNIX) + mutable QFileSystemMetaData metaData; +#endif + FILE *fh; #ifdef Q_WS_WIN HANDLE fileHandle; @@ -120,7 +127,6 @@ public: mutable DWORD fileAttrib; #else QHash > maps; - mutable QT_STATBUF st; #endif int fd; @@ -142,7 +148,11 @@ public: mutable uint is_link : 1; #endif +#if defined(Q_OS_WIN) bool doStat() const; +#else + bool doStat(QFileSystemMetaData::MetaDataFlags flags = QFileSystemMetaData::PosixStatFlags) const; +#endif bool isSymlink() const; #if defined(Q_OS_WIN32) diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 50b18fc..71a604a 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -69,7 +69,6 @@ QT_BEGIN_NAMESPACE - #if defined(Q_OS_SYMBIAN) /*! \internal @@ -124,16 +123,17 @@ void QFSFileEnginePrivate::setSymbianError(int symbianError, QFile::FileError de Returns the stdlib open string corresponding to a QIODevice::OpenMode. */ -static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QByteArray &fileName) +static inline QByteArray openModeToFopenMode(QIODevice::OpenMode flags, const QFileSystemEntry &fileEntry, + QFileSystemMetaData &metaData) { QByteArray mode; if ((flags & QIODevice::ReadOnly) && !(flags & QIODevice::Truncate)) { mode = "rb"; if (flags & QIODevice::WriteOnly) { - QT_STATBUF statBuf; - if (!fileName.isEmpty() - && QT_STAT(fileName, &statBuf) == 0 - && (statBuf.st_mode & S_IFMT) == S_IFREG) { + metaData.clearFlags(QFileSystemMetaData::FileType); + if (!fileEntry.isEmpty() + && QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::FileType) + && metaData.isFile()) { mode += '+'; } else { mode = "wb+"; @@ -222,13 +222,11 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) if (!(openMode & QIODevice::WriteOnly)) { // we don't need this check if we tried to open for writing because then // we had received EISDIR anyway. - QT_STATBUF statBuf; - if (QT_FSTAT(fd, &statBuf) != -1) { - if ((statBuf.st_mode & S_IFMT) == S_IFDIR) { - q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); - QT_CLOSE(fd); - return false; - } + if (QFileSystemEngine::fillMetaData(fd, metaData) + && metaData.isDirectory()) { + q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); + QT_CLOSE(fd); + return false; } } @@ -248,7 +246,7 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) fh = 0; } else { - QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry.nativeFilePath().constData()); + QByteArray fopenMode = openModeToFopenMode(openMode, fileEntry, metaData); // Try to open the file in buffered mode. do { @@ -265,13 +263,11 @@ bool QFSFileEnginePrivate::nativeOpen(QIODevice::OpenMode openMode) if (!(openMode & QIODevice::WriteOnly)) { // we don't need this check if we tried to open for writing because then // we had received EISDIR anyway. - QT_STATBUF statBuf; - if (QT_FSTAT(fileno(fh), &statBuf) != -1) { - if ((statBuf.st_mode & S_IFMT) == S_IFDIR) { - q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); - fclose(fh); - return false; - } + if (QFileSystemEngine::fillMetaData(QT_FILENO(fh), metaData) + && metaData.isDirectory()) { + q->setError(QFile::OpenError, QLatin1String("file to open is a directory")); + fclose(fh); + return false; } } @@ -626,123 +622,30 @@ QFileInfoList QFSFileEngine::drives() return ret; } -bool QFSFileEnginePrivate::doStat() const +bool QFSFileEnginePrivate::doStat(QFileSystemMetaData::MetaDataFlags flags) const { - if (!tried_stat) { - tried_stat = true; - could_stat = false; - - if (fh && fileEntry.isEmpty()) { - // ### actually covers two cases: d->fh and when the file is not open - could_stat = (QT_FSTAT(QT_FILENO(fh), &st) == 0); - } else if (fd == -1) { - // ### actually covers two cases: d->fh and when the file is not open -#if defined(Q_OS_SYMBIAN) - // Optimisation for Symbian where fileFlags() calls both doStat() and isSymlink(), but rarely on real links. - // When the filename is not a link, lstat will return the same info as stat, but this also removes - // any need for a further call to lstat to check if the file is a link. - need_lstat = false; - could_stat = (QT_LSTAT(fileEntry.nativeFilePath().constData(), &st) == 0); - is_link = could_stat ? S_ISLNK(st.st_mode) : false; - // if it turns out this was a link, we can call stat too. - if (is_link) -#endif - could_stat = (QT_STAT(fileEntry.nativeFilePath().constData(), &st) == 0); - } else { - could_stat = (QT_FSTAT(fd, &st) == 0); - } - } - return could_stat; -} + if (!tried_stat || !metaData.hasFlags(flags)) { + tried_stat = 1; -bool QFSFileEnginePrivate::isSymlink() const -{ - if (need_lstat) { - need_lstat = false; + int localFd = fd; + if (fh && fileEntry.isEmpty()) + localFd = QT_FILENO(fh); + if (localFd != -1) + QFileSystemEngine::fillMetaData(localFd, metaData); - QT_STATBUF st; // don't clobber our main one - is_link = (QT_LSTAT(fileEntry.nativeFilePath().constData(), &st) == 0) ? S_ISLNK(st.st_mode) : false; + if (metaData.missingFlags(flags) && !fileEntry.isEmpty()) + QFileSystemEngine::fillMetaData(fileEntry, metaData, metaData.missingFlags(flags)); } - return is_link; -} -#if defined(Q_OS_SYMBIAN) -static bool _q_isSymbianHidden(const QString &path, bool isDir) -{ - RFs rfs = qt_s60GetRFs(); - QFileInfo fi(path); - QString absPath = fi.absoluteFilePath(); - if (isDir && !absPath.endsWith(QLatin1Char('/'))) - absPath.append(QLatin1Char('/')); - QString native(QDir::toNativeSeparators(absPath)); - TPtrC ptr(qt_QString2TPtrC(native)); - TUint attributes; - TInt err = rfs.Att(ptr, attributes); - return (err == KErrNone && (attributes & KEntryAttHidden)); + return metaData.exists(); } -#endif -#if !defined(QWS) && defined(Q_OS_MAC) -static bool _q_isMacHidden(const QString &path) -{ - OSErr err = noErr; - - FSRef fsRef; - - err = FSPathMakeRefWithOptions(reinterpret_cast(QFile::encodeName(QDir::cleanPath(path)).constData()), - 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(&catInfo.finderInfo); - bool result = (fileInfo->finderFlags & kIsInvisible); - return result; -} -#endif - -QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFileEngine::FileFlags type) const +bool QFSFileEnginePrivate::isSymlink() const { - QAbstractFileEngine::FileFlags ret = 0; + if (!metaData.hasFlags(QFileSystemMetaData::LinkType)) + QFileSystemEngine::fillMetaData(fileEntry, metaData, QFileSystemMetaData::LinkType); - if (st.st_mode & S_IRUSR) - ret |= QAbstractFileEngine::ReadOwnerPerm; - if (st.st_mode & S_IWUSR) - ret |= QAbstractFileEngine::WriteOwnerPerm; - if (st.st_mode & S_IXUSR) - ret |= QAbstractFileEngine::ExeOwnerPerm; - if (st.st_mode & S_IRGRP) - ret |= QAbstractFileEngine::ReadGroupPerm; - if (st.st_mode & S_IWGRP) - ret |= QAbstractFileEngine::WriteGroupPerm; - if (st.st_mode & S_IXGRP) - ret |= QAbstractFileEngine::ExeGroupPerm; - if (st.st_mode & S_IROTH) - ret |= QAbstractFileEngine::ReadOtherPerm; - if (st.st_mode & S_IWOTH) - ret |= QAbstractFileEngine::WriteOtherPerm; - if (st.st_mode & S_IXOTH) - ret |= QAbstractFileEngine::ExeOtherPerm; - - // calculate user permissions - if (type & QAbstractFileEngine::ReadUserPerm) { - if (QT_ACCESS(fileEntry.nativeFilePath().constData(), R_OK) == 0) - ret |= QAbstractFileEngine::ReadUserPerm; - } - if (type & QAbstractFileEngine::WriteUserPerm) { - if (QT_ACCESS(fileEntry.nativeFilePath().constData(), W_OK) == 0) - ret |= QAbstractFileEngine::WriteUserPerm; - } - if (type & QAbstractFileEngine::ExeUserPerm) { - if (QT_ACCESS(fileEntry.nativeFilePath().constData(), X_OK) == 0) - ret |= QAbstractFileEngine::ExeUserPerm; - } - - return ret; + return metaData.isLink(); } /*! @@ -751,82 +654,71 @@ QAbstractFileEngine::FileFlags QFSFileEnginePrivate::getPermissions(QAbstractFil QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const { Q_D(const QFSFileEngine); - // Force a stat, so that we're guaranteed to get up-to-date results - if (type & Refresh) { - d->tried_stat = 0; - d->need_lstat = 1; - } + + if (type & Refresh) + d->metaData.clear(); QAbstractFileEngine::FileFlags ret = 0; + if (type & FlagsMask) ret |= LocalDiskFlag; - bool exists = d->doStat(); - if (!exists && !d->isSymlink()) + + bool exists; + { + QFileSystemMetaData::MetaDataFlags queryFlags = 0; + + queryFlags |= QFileSystemMetaData::MetaDataFlags(uint(type)) + & QFileSystemMetaData::Permissions; + + if (type & TypesMask) + queryFlags |= QFileSystemMetaData::AliasType + | QFileSystemMetaData::LinkType + | QFileSystemMetaData::FileType + | QFileSystemMetaData::DirectoryType + | QFileSystemMetaData::BundleType; + + if (type & FlagsMask) + queryFlags |= QFileSystemMetaData::HiddenAttribute + | QFileSystemMetaData::ExistsAttribute; + + queryFlags |= QFileSystemMetaData::LinkType; + + exists = d->doStat(queryFlags); + } + + if (!exists && !d->metaData.isLink()) return ret; if (exists && (type & PermsMask)) - ret |= d->getPermissions(type); + ret |= FileFlags(uint(d->metaData.permissions())); + if (type & TypesMask) { -#if !defined(QWS) && defined(Q_OS_MAC) - bool foundAlias = false; - { - FSRef fref; - if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(d->fileEntry.filePath())).data(), - &fref, NULL) == noErr) { - Boolean isAlias, isFolder; - if (FSIsAliasFile(&fref, &isAlias, &isFolder) == noErr && isAlias) { - foundAlias = true; - ret |= LinkType; - } - } - } - if (!foundAlias) -#endif - { - if ((type & LinkType) && d->isSymlink()) + if (d->metaData.isAlias()) { + ret |= LinkType; + } else { + if ((type & LinkType) && d->metaData.isLink()) ret |= LinkType; - if (exists && (d->st.st_mode & S_IFMT) == S_IFREG) - ret |= FileType; - else if (exists && (d->st.st_mode & S_IFMT) == S_IFDIR) - ret |= DirectoryType; -#if !defined(QWS) && defined(Q_OS_MAC) - if ((ret & DirectoryType) && (type & BundleType)) { - QCFType url = CFURLCreateWithFileSystemPath(0, QCFString(d->fileEntry.filePath()), - kCFURLPOSIXPathStyle, true); - UInt32 type, creator; - if (CFBundleGetPackageInfoInDirectory(url, &type, &creator)) - ret |= BundleType; + if (exists) { + if (d->metaData.isFile()) { + ret |= FileType; + } else if (d->metaData.isDirectory()) { + ret |= DirectoryType; + if ((type & BundleType) && d->metaData.isBundle()) + ret |= BundleType; + } } -#endif } } + if (type & FlagsMask) { if (exists) ret |= ExistsFlag; - if (d->fileEntry.isRoot()) { + if (d->fileEntry.isRoot()) ret |= RootFlag; - } else { -#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 (!d->isSymlink() && _q_isSymbianHidden(d->fileEntry.filePath(), ret & DirectoryType)) - ret |= HiddenFlag; -#else - QString baseName = fileName(BaseName); - if ((baseName.size() > 0 && baseName.at(0) == QLatin1Char('.')) -# if !defined(QWS) && defined(Q_OS_MAC) - || _q_isMacHidden(d->fileEntry.filePath()) -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - || d->st.st_flags & UF_HIDDEN -# endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -# endif - ) { - ret |= HiddenFlag; - } -#endif - } + else if (d->metaData.isHidden()) + ret |= HiddenFlag; } + return ret; } @@ -994,7 +886,8 @@ QString QFSFileEngine::fileName(FileName file) const #endif if (len > 0) { QString ret; - if (d->doStat() && S_ISDIR(d->st.st_mode) && s[0] != '/') { + if (d->doStat(QFileSystemMetaData::DirectoryType) + && d->metaData.isDirectory() && s[0] != '/') { QDir parent(d->fileEntry.filePath()); parent.cdUp(); ret = parent.path(); @@ -1057,12 +950,10 @@ uint QFSFileEngine::ownerId(FileOwner own) const { Q_D(const QFSFileEngine); static const uint nobodyID = (uint) -2; - if (d->doStat()) { - if (own == OwnerUser) - return d->st.st_uid; - else - return d->st.st_gid; - } + + if (d->doStat(QFileSystemMetaData::OwnerIds)) + return d->metaData.ownerId(own); + return nobodyID; } @@ -1170,16 +1061,11 @@ bool QFSFileEngine::setSize(qint64 size) QDateTime QFSFileEngine::fileTime(FileTime time) const { Q_D(const QFSFileEngine); - QDateTime ret; - if (d->doStat()) { - if (time == CreationTime) - ret.setTime_t(d->st.st_ctime ? d->st.st_ctime : d->st.st_mtime); - else if (time == ModificationTime) - ret.setTime_t(d->st.st_mtime); - else if (time == AccessTime) - ret.setTime_t(d->st.st_atime); - } - return ret; + + if (d->doStat(QFileSystemMetaData::Times)) + return d->metaData.fileTime(time); + + return QDateTime(); } uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags) @@ -1199,8 +1085,8 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla // If we know the mapping will extend beyond EOF, fail early to avoid // undefined behavior. Otherwise, let mmap have its say. - if (doStat() - && (QT_OFF_T(size) > st.st_size - QT_OFF_T(offset))) + if (doStat(QFileSystemMetaData::SizeAttribute) + && (QT_OFF_T(size) > metaData.size() - QT_OFF_T(offset))) qWarning("QFSFileEngine::map: Mapping a file beyond its size is not portable"); int access = 0; -- cgit v0.12