diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index fa6cd33ec4..5e2b5eb4ad 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -1118,8 +1118,8 @@ bool QFileInfo::isSymLink() const opens the \l{symLinkTarget()}{link's target}. In contrast to isSymLink(), false will be returned for shortcuts - (\c *.lnk files) on Windows and aliases on \macos. - Use QFileInfo::isShortcut() on Windows instead. + (\c *.lnk files) on Windows and aliases on \macos. Use QFileInfo::isShortcut() + and QFileInfo::isAlias() instead. \note If the symlink points to a non existing file, exists() returns false. @@ -1162,6 +1162,29 @@ bool QFileInfo::isShortcut() const [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); }); } +/*! + Returns \c true if this object points to an alias; + otherwise returns \c false. + + \since 6.4 + + Aliases only exist on \macos. They are treated as regular files, so + opening an alias will open the file itself. In order to open the file + or directory an alias references use symLinkTarget(). + + \note Even if an alias points to a non existing file, + isAlias() returns true. + + \sa isFile(), isDir(), isSymLink(), symLinkTarget() +*/ +bool QFileInfo::isAlias() const +{ + Q_D(const QFileInfo); + return d->checkAttribute( + QFileSystemMetaData::LegacyLinkType, + [d]() { return d->metaData.isAlias(); }, + [d]() { return d->getFileFlags(QAbstractFileEngine::LinkType); }); +} /*! \since 5.15 diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h index f2260db410..ac6211fcf9 100644 --- a/src/corelib/io/qfileinfo.h +++ b/src/corelib/io/qfileinfo.h @@ -156,6 +156,7 @@ public: bool isSymLink() const; bool isSymbolicLink() const; bool isShortcut() const; + bool isAlias() const; bool isJunction() const; bool isRoot() const; bool isBundle() const; diff --git a/tests/auto/corelib/io/qfileinfo/CMakeLists.txt b/tests/auto/corelib/io/qfileinfo/CMakeLists.txt index da955ff6a6..8b015d518c 100644 --- a/tests/auto/corelib/io/qfileinfo/CMakeLists.txt +++ b/tests/auto/corelib/io/qfileinfo/CMakeLists.txt @@ -45,3 +45,7 @@ qt_internal_extend_target(tst_qfileinfo CONDITION WIN32 advapi32 netapi32 ) + +if (APPLE) + target_compile_options(tst_qfileinfo PRIVATE -x objective-c++) +endif() diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index 45645e2ac6..a46fac04a4 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -62,6 +62,10 @@ #include #include "../../../../shared/filesystem.h" +#if defined(Q_OS_MACOS) +#include +#endif + #if defined(Q_OS_VXWORKS) #define Q_NO_SYMLINKS #endif @@ -218,6 +222,9 @@ private slots: void isShortcut_data(); void isShortcut(); + void isAlias_data(); + void isAlias(); + void link_data(); void link(); @@ -1345,6 +1352,57 @@ void tst_QFileInfo::isShortcut() QCOMPARE(fi.isShortcut(), isShortcut); } +void tst_QFileInfo::isAlias_data() +{ + QFile::remove("symlink"); + QFile::remove("file-alias"); + QFile::remove("directory-alias"); + + QTest::addColumn("path"); + QTest::addColumn("isAlias"); + + QFile regularFile(m_sourceFile); + QTest::newRow("regular-file") << regularFile.fileName() << false; + QTest::newRow("directory") << QDir::currentPath() << false; + +#if defined(Q_OS_MACOS) + auto createAlias = [](const QString &target, const QString &alias) { + NSURL *targetUrl = [NSURL fileURLWithPath:target.toNSString()]; + NSURL *aliasUrl = [NSURL fileURLWithPath:alias.toNSString()]; + NSData *bookmarkData = [targetUrl bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile + includingResourceValuesForKeys:nil relativeToURL:nil error:nullptr]; + Q_ASSERT(bookmarkData); + + bool success = [NSURL writeBookmarkData:bookmarkData toURL:aliasUrl + options:NSURLBookmarkCreationSuitableForBookmarkFile error:nullptr]; + Q_ASSERT(success); + }; + + regularFile.link("symlink"); + QTest::newRow("symlink") << "symlink" << false; + + createAlias(regularFile.fileName(), QDir::current().filePath("file-alias")); + QTest::newRow("file-alias") << "file-alias" << true; + + createAlias(QDir::currentPath(), QDir::current().filePath("directory-alias")); + QTest::newRow("directory-alias") << "directory-alias" << true; + + regularFile.copy("non-existing-file"); + createAlias("non-existing-file", QDir::current().filePath("non-existing-file-alias")); + QDir::current().remove("non-existing-file"); + QTest::newRow("non-existing-file-alias") << "non-existing-file-alias" << true; +#endif +} + +void tst_QFileInfo::isAlias() +{ + QFETCH(QString, path); + QFETCH(bool, isAlias); + + QFileInfo fi(path); + QCOMPARE(fi.isAlias(), isAlias); +} + void tst_QFileInfo::isSymbolicLink_data() { QTest::addColumn("path");