Modernize and unify filesystem code on Apple platforms.

Replace deprecated File Manager APIs with modern equivalents.

Change some Q_OS_MACX to Q_OS_DARWIN in file system related code.

All of these apply to iOS as well as OS X, and were ifdef'ed for OS X
only primarily due to legacy reasons - carryovers from Qt 4 or Carbon
APIs which have since been refactored into using CoreFoundation.

This also makes the code consistent with the documentation.

Change-Id: I414e9bdfffff731413ddf16171b1317027d87caf
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@theqtcompany.com>
This commit is contained in:
Jake Petroules 2015-07-13 20:16:44 -07:00
parent 827d0c0232
commit 46a372e1a1
6 changed files with 94 additions and 116 deletions

View File

@ -160,6 +160,7 @@ win32 {
} else:ios { } else:ios {
OBJECTIVE_SOURCES += io/qstandardpaths_ios.mm OBJECTIVE_SOURCES += io/qstandardpaths_ios.mm
SOURCES += io/qstorageinfo_mac.cpp SOURCES += io/qstorageinfo_mac.cpp
LIBS += -framework MobileCoreServices
} else { } else {
SOURCES += io/qstandardpaths_unix.cpp SOURCES += io/qstandardpaths_unix.cpp
} }

View File

@ -264,7 +264,7 @@ void QFileSystemMetaData::fillFromStatBuf(const QT_STATBUF &statBuffer)
// Attributes // Attributes
entryFlags |= QFileSystemMetaData::ExistsAttribute; entryFlags |= QFileSystemMetaData::ExistsAttribute;
size_ = statBuffer.st_size; size_ = statBuffer.st_size;
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
if (statBuffer.st_flags & UF_HIDDEN) { if (statBuffer.st_flags & UF_HIDDEN) {
entryFlags |= QFileSystemMetaData::HiddenAttribute; entryFlags |= QFileSystemMetaData::HiddenAttribute;
knownFlagsMask |= QFileSystemMetaData::HiddenAttribute; knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;

View File

@ -76,7 +76,7 @@ public:
static QString resolveGroupName(uint groupId); static QString resolveGroupName(uint groupId);
#endif #endif
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
static QString bundleName(const QFileSystemEntry &entry); static QString bundleName(const QFileSystemEntry &entry);
#else #else
static QString bundleName(const QFileSystemEntry &entry) { Q_UNUSED(entry) return QString(); } static QString bundleName(const QFileSystemEntry &entry) { Q_UNUSED(entry) return QString(); }

View File

@ -51,26 +51,38 @@
# include <CoreFoundation/CFBundle.h> # include <CoreFoundation/CFBundle.h>
#endif #endif
#ifdef Q_OS_OSX
#include <CoreServices/CoreServices.h>
#endif
#ifdef Q_OS_IOS
#include <MobileCoreServices/MobileCoreServices.h>
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
static inline bool _q_isMacHidden(const char *nativePath) static inline bool hasResourcePropertyFlag(const QFileSystemMetaData &data,
const QFileSystemEntry &entry,
CFStringRef key)
{ {
OSErr err; QCFString path = CFStringCreateWithFileSystemRepresentation(0,
entry.nativeFilePath().constData());
FSRef fsRef; if (!path)
err = FSPathMakeRefWithOptions(reinterpret_cast<const UInt8 *>(nativePath),
kFSPathMakeRefDoNotFollowLeafSymlink, &fsRef, 0);
if (err != noErr)
return false; return false;
FSCatalogInfo catInfo; QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle,
err = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL); data.hasFlags(QFileSystemMetaData::DirectoryType));
if (err != noErr) if (!url)
return false; return false;
FileInfo * const fileInfo = reinterpret_cast<FileInfo*>(&catInfo.finderInfo); CFBooleanRef value;
return (fileInfo->finderFlags & kIsInvisible); if (CFURLCopyResourcePropertyForKey(url, key, &value, NULL)) {
if (value == kCFBooleanTrue)
return true;
}
return false;
} }
static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &entry) static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &entry)
@ -97,6 +109,7 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
if (CFBundleGetPackageInfoInDirectory(url, &type, &creator)) if (CFBundleGetPackageInfoInDirectory(url, &type, &creator))
return true; return true;
#ifdef Q_OS_OSX
// Find if an application other than Finder claims to know how to handle the package // Find if an application other than Finder claims to know how to handle the package
QCFType<CFURLRef> application; QCFType<CFURLRef> application;
LSGetApplicationForURL(url, LSGetApplicationForURL(url,
@ -111,30 +124,11 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
if (applicationId != QLatin1String("com.apple.finder")) if (applicationId != QLatin1String("com.apple.finder"))
return true; return true;
} }
#endif
} }
// Third step: check if the directory has the package bit set // Third step: check if the directory has the package bit set
FSRef packageRef; return hasResourcePropertyFlag(data, entry, kCFURLIsPackageKey);
FSPathMakeRef((UInt8 *)entry.nativeFilePath().constData(), &packageRef, NULL);
FSCatalogInfo catalogInfo;
FSGetCatalogInfo(&packageRef,
kFSCatInfoFinderInfo,
&catalogInfo,
NULL,
NULL,
NULL);
FolderInfo *folderInfo = reinterpret_cast<FolderInfo *>(catalogInfo.finderInfo);
return folderInfo->finderFlags & kHasBundle;
}
#else
static inline bool _q_isMacHidden(const char *nativePath)
{
Q_UNUSED(nativePath);
// no-op
return false;
} }
#endif #endif
@ -194,22 +188,35 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
ret.chop(1); ret.chop(1);
return QFileSystemEntry(ret); return QFileSystemEntry(ret);
} }
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
{ {
FSRef fref; QCFString path = CFStringCreateWithFileSystemRepresentation(0,
if (FSPathMakeRef((const UInt8 *)QFile::encodeName(QDir::cleanPath(link.filePath())).data(), &fref, 0) == noErr) { QFile::encodeName(QDir::cleanPath(link.filePath())).data());
// TODO get the meta data info from the QFileSystemMetaData object if (!path)
Boolean isAlias, isFolder; return QFileSystemEntry();
if (FSResolveAliasFile(&fref, true, &isFolder, &isAlias) == noErr && isAlias) {
AliasHandle alias; QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle,
if (FSNewAlias(0, &fref, &alias) == noErr && alias) { data.hasFlags(QFileSystemMetaData::DirectoryType));
QCFString cfstr; if (!url)
if (FSCopyAliasInfo(alias, 0, 0, &cfstr, 0, 0) == noErr) return QFileSystemEntry();
QCFType<CFDataRef> bookmarkData = CFURLCreateBookmarkDataFromFile(0, url, NULL);
if (!bookmarkData)
return QFileSystemEntry();
QCFType<CFURLRef> resolvedUrl = CFURLCreateByResolvingBookmarkData(0,
bookmarkData,
(CFURLBookmarkResolutionOptions)(kCFBookmarkResolutionWithoutUIMask
| kCFBookmarkResolutionWithoutMountingMask), NULL, NULL, NULL, NULL);
if (!resolvedUrl)
return QFileSystemEntry();
QCFString cfstr(CFURLCopyFileSystemPath(resolvedUrl, kCFURLPOSIXPathStyle));
if (!cfstr)
return QFileSystemEntry();
return QFileSystemEntry(QCFString::toQString(cfstr)); return QFileSystemEntry(QCFString::toQString(cfstr));
} }
}
}
}
#endif #endif
return QFileSystemEntry(); return QFileSystemEntry();
} }
@ -226,10 +233,7 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath())); return QFileSystemEntry(slowCanonicalized(absoluteName(entry).filePath()));
#else #else
char *ret = 0; char *ret = 0;
# if defined(Q_OS_MACX) # if defined(Q_OS_DARWIN)
// When using -mmacosx-version-min=10.4, we get the legacy realpath implementation,
// which does not work properly with the realpath(X,0) form. See QTBUG-28282.
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) {
ret = (char*)malloc(PATH_MAX + 1); ret = (char*)malloc(PATH_MAX + 1);
if (ret && realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) { if (ret && realpath(entry.nativeFilePath().constData(), (char*)ret) == 0) {
const int savedErrno = errno; // errno is checked below, and free() might change it const int savedErrno = errno; // errno is checked below, and free() might change it
@ -237,20 +241,6 @@ QFileSystemEntry QFileSystemEngine::canonicalName(const QFileSystemEntry &entry,
errno = savedErrno; errno = savedErrno;
ret = 0; ret = 0;
} }
} else {
// on 10.5 we can use FSRef to resolve the file path.
QString path = QDir::cleanPath(entry.filePath());
FSRef fsref;
if (FSPathMakeRef((const UInt8 *)path.toUtf8().data(), &fsref, 0) == noErr) {
CFURLRef urlref = CFURLCreateFromFSRef(NULL, &fsref);
CFStringRef canonicalPath = CFURLCopyFileSystemPath(urlref, kCFURLPOSIXPathStyle);
QString ret = QCFString::toQString(canonicalPath);
CFRelease(canonicalPath);
CFRelease(urlref);
return QFileSystemEntry(ret);
}
}
# elif defined(Q_OS_ANDROID) # elif defined(Q_OS_ANDROID)
// On some Android versions, realpath() will return a path even if it does not exist // On some Android versions, realpath() will return a path even if it does not exist
// To work around this, we check existence in advance. // To work around this, we check existence in advance.
@ -406,7 +396,7 @@ QString QFileSystemEngine::resolveGroupName(uint groupId)
return QString(); return QString();
} }
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
//static //static
QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry) QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry)
{ {
@ -426,7 +416,7 @@ QString QFileSystemEngine::bundleName(const QFileSystemEntry &entry)
bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data, bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemMetaData &data,
QFileSystemMetaData::MetaDataFlags what) QFileSystemMetaData::MetaDataFlags what)
{ {
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::BundleType) { if (what & QFileSystemMetaData::BundleType) {
if (!data.hasFlags(QFileSystemMetaData::DirectoryType)) if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
what |= QFileSystemMetaData::DirectoryType; what |= QFileSystemMetaData::DirectoryType;
@ -435,7 +425,7 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
// OS X >= 10.5: st_flags & UF_HIDDEN // OS X >= 10.5: st_flags & UF_HIDDEN
what |= QFileSystemMetaData::PosixStatFlags; what |= QFileSystemMetaData::PosixStatFlags;
} }
#endif // defined(Q_OS_MACX) #endif // defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::PosixStatFlags) if (what & QFileSystemMetaData::PosixStatFlags)
what |= QFileSystemMetaData::PosixStatFlags; what |= QFileSystemMetaData::PosixStatFlags;
@ -496,19 +486,11 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
| QFileSystemMetaData::ExistsAttribute; | QFileSystemMetaData::ExistsAttribute;
} }
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::AliasType) if (what & QFileSystemMetaData::AliasType)
{ {
if (entryExists) { if (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsAliasFileKey))
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.entryFlags |= QFileSystemMetaData::AliasType;
}
}
}
data.knownFlagsMask |= QFileSystemMetaData::AliasType; data.knownFlagsMask |= QFileSystemMetaData::AliasType;
} }
#endif #endif
@ -537,12 +519,15 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
&& !data.isHidden()) { && !data.isHidden()) {
QString fileName = entry.fileName(); QString fileName = entry.fileName();
if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.')) if ((fileName.size() > 0 && fileName.at(0) == QLatin1Char('.'))
|| (entryExists && _q_isMacHidden(nativeFilePath))) #if defined(Q_OS_DARWIN)
|| (entryExists && hasResourcePropertyFlag(data, entry, kCFURLIsHiddenKey))
#endif
)
data.entryFlags |= QFileSystemMetaData::HiddenAttribute; data.entryFlags |= QFileSystemMetaData::HiddenAttribute;
data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute; data.knownFlagsMask |= QFileSystemMetaData::HiddenAttribute;
} }
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
if (what & QFileSystemMetaData::BundleType) { if (what & QFileSystemMetaData::BundleType) {
if (entryExists && isPackage(data, entry)) if (entryExists && isPackage(data, entry))
data.entryFlags |= QFileSystemMetaData::BundleType; data.entryFlags |= QFileSystemMetaData::BundleType;

View File

@ -93,7 +93,7 @@ public:
LinkType = 0x00010000, LinkType = 0x00010000,
FileType = 0x00020000, FileType = 0x00020000,
DirectoryType = 0x00040000, DirectoryType = 0x00040000,
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
BundleType = 0x00080000, BundleType = 0x00080000,
AliasType = 0x08000000, AliasType = 0x08000000,
#else #else
@ -243,7 +243,7 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(QFileSystemMetaData::MetaDataFlags)
#if defined(Q_OS_MACX) #if defined(Q_OS_DARWIN)
inline bool QFileSystemMetaData::isBundle() const { return (entryFlags & BundleType); } inline bool QFileSystemMetaData::isBundle() const { return (entryFlags & BundleType); }
inline bool QFileSystemMetaData::isAlias() const { return (entryFlags & AliasType); } inline bool QFileSystemMetaData::isAlias() const { return (entryFlags & AliasType); }
#else #else

View File

@ -147,32 +147,24 @@ void QStorageInfoPrivate::retrieveUrlProperties(bool initRootPath)
void QStorageInfoPrivate::retrieveLabel() void QStorageInfoPrivate::retrieveLabel()
{ {
#if !defined(Q_OS_IOS) QCFString path = CFStringCreateWithFileSystemRepresentation(0,
// deprecated since 10.8 QFile::encodeName(rootPath).constData());
FSRef ref; if (!path)
FSPathMakeRef(reinterpret_cast<const UInt8*>(QFile::encodeName(rootPath).constData()),
&ref,
Q_NULLPTR);
// deprecated since 10.8
FSCatalogInfo catalogInfo;
OSErr error;
error = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &catalogInfo, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR);
if (error != noErr)
return; return;
// deprecated (use CFURLCopyResourcePropertiesForKeys for 10.7 and higher) QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0, path, kCFURLPOSIXPathStyle, true);
HFSUniStr255 volumeName; if (!url)
error = FSGetVolumeInfo(catalogInfo.volume, return;
0,
Q_NULLPTR, QCFType<CFURLRef> volumeUrl;
kFSVolInfoFSInfo, if (!CFURLCopyResourcePropertyForKey(url, kCFURLVolumeURLKey, &volumeUrl, NULL))
Q_NULLPTR, return;
&volumeName,
Q_NULLPTR); QCFString volumeName;
if (error == noErr) if (!CFURLCopyResourcePropertyForKey(url, kCFURLNameKey, &volumeName, NULL))
name = QCFString(FSCreateStringFromHFSUniStr(Q_NULLPTR, &volumeName)); return;
#endif
name = volumeName;
} }
QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes() QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()