summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorRyan Chu <ryan.chu@qt.io>2019-07-11 13:23:59 +0200
committerRyan Chu <ryan.chu@qt.io>2019-08-16 23:25:33 +0200
commit7a4e5e7433afe7150cdf40025d4525277809c412 (patch)
tree47161c2c289bee5c636ab36868e265287d3a1d5a /tests
parent7ac6cefd8affc1f3bf963035c4ce4184a6023c5a (diff)
Make Qt aware of symlinks and shortcuts on Windows
Qt has traditionally considered Windows shortcut files equivalent to symlinks on Unix file systems. Because of NTFS symlinks, the interpretation of shotcut files as symlinks is confusing. In this change, QFileInfo treats shortcut (.lnk) files as regular files but can follow the pointed object. In addition, QFileInfo introduces a more comprehensive file type. So that applications can make well-informed decisions about how to treat a file system entry. Based on the implementation of QFileInfo::type(), two inline helper functions are introduced to QFileInfo. 1. isSymbolicLink, returns true if it points to a symbolic link. 2. isShortcut, returns true if it points to a shortcut. [ChangeLog][QtCore][QFileInfo] Introduce QFileInfo::type() to replace the isSymLink method. Task-number: QTBUG-75869 Change-Id: Icc0dd52f9ad0ea50b0265d77ee0d0a3d25054e39 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp166
1 files changed, 162 insertions, 4 deletions
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index 60e320c44d..6fcfe87c83 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -236,6 +236,8 @@ private slots:
void isSymLink_data();
void isSymLink();
+ void link_data();
+ void link();
void isHidden_data();
void isHidden();
@@ -277,6 +279,9 @@ private slots:
void invalidState();
void nonExistingFile();
+ void type_data();
+ void type();
+
private:
const QString m_currentDir;
QString m_sourceFile;
@@ -1337,6 +1342,88 @@ void tst_QFileInfo::isSymLink()
#endif
}
+Q_DECLARE_METATYPE(QFileInfo::FileType)
+
+void tst_QFileInfo::link_data()
+{
+ QFile::remove("link");
+ QFile::remove("link.lnk");
+ QFile::remove("brokenlink");
+ QFile::remove("brokenlink.lnk");
+ QFile::remove("dummyfile");
+ QFile::remove("relative/link");
+
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QFileInfo::FileType>("linkType");
+ QTest::addColumn<QString>("linkTarget");
+
+ QFile file1(m_sourceFile);
+ QFile file2("dummyfile");
+ file2.open(QIODevice::WriteOnly);
+
+ QTest::newRow("existent file") << m_sourceFile << QFileInfo::Unknown << "";
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ // windows shortcuts
+ QVERIFY(file1.link("link.lnk"));
+ QTest::newRow("link.lnk")
+ << "link.lnk" << QFileInfo::Shortcut << QFileInfo(m_sourceFile).absoluteFilePath();
+
+ QVERIFY(file2.link("brokenlink.lnk"));
+ QTest::newRow("broken link.lnk")
+ << "brokenlink.lnk" << QFileInfo::Shortcut << QFileInfo("dummyfile").absoluteFilePath();
+#endif
+
+#ifndef Q_NO_SYMLINKS
+#if defined(Q_OS_WIN)
+#if !defined(Q_OS_WINRT)
+ QString errorMessage;
+ DWORD creationResult = createSymbolicLink("link", m_sourceFile, &errorMessage);
+ if (creationResult == ERROR_PRIVILEGE_NOT_HELD) {
+ QWARN(msgInsufficientPrivileges(errorMessage));
+ } else {
+ QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
+ QTest::newRow("link")
+ << "link" << QFileInfo::SymbolicLink << QFileInfo(m_sourceFile).absoluteFilePath();
+ }
+
+ creationResult = createSymbolicLink("brokenlink", "dummyfile", &errorMessage);
+ if (creationResult == ERROR_PRIVILEGE_NOT_HELD) {
+ QWARN(msgInsufficientPrivileges(errorMessage));
+ } else {
+ QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
+ QTest::newRow("broken link")
+ << "brokenlink" << QFileInfo::SymbolicLink << QFileInfo("dummyfile").absoluteFilePath();
+ }
+#endif // !Q_OS_WINRT
+#else // Unix:
+ QVERIFY(file1.link("link"));
+ QTest::newRow("link")
+ << "link" << QFileInfo::SymbolicLink << QFileInfo(m_sourceFile).absoluteFilePath();
+
+ QVERIFY(file2.link("brokenlink"));
+ QTest::newRow("broken link")
+ << "brokenlink" << QFileInfo::SymbolicLink << QFileInfo("dummyfile").absoluteFilePath();
+
+ QDir::current().mkdir("relative");
+ QFile::link("../dummyfile", "relative/link");
+ QTest::newRow("relative link")
+ << "relative/link" << QFileInfo::SymbolicLink << QFileInfo("dummyfile").absoluteFilePath();
+#endif
+#endif // !Q_NO_SYMLINKS
+ file2.remove();
+}
+
+void tst_QFileInfo::link()
+{
+ QFETCH(QString, path);
+ QFETCH(QFileInfo::FileType, linkType);
+ QFETCH(QString, linkTarget);
+
+ QFileInfo fi(path);
+ QCOMPARE(fi.type() & QFileInfo::LinkTypeMask, linkType);
+ QCOMPARE(fi.symLinkTarget(), linkTarget);
+}
+
void tst_QFileInfo::isHidden_data()
{
QTest::addColumn<QString>("path");
@@ -1638,7 +1725,7 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks()
QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
QFileInfo fi(path);
- const bool actualIsSymLink = fi.isSymLink();
+ const bool actualIsSymLink = fi.isSymbolicLink();
const QString actualSymLinkTarget = isSymLink ? fi.symLinkTarget() : QString();
const QString actualCanonicalFilePath = isSymLink ? fi.canonicalFilePath() : QString();
// Ensure that junctions, mountpoints are removed. If this fails, do not remove
@@ -1667,14 +1754,16 @@ void tst_QFileInfo::brokenShortcut()
file.close();
QFileInfo info(linkName);
- QVERIFY(info.isSymLink());
+ QVERIFY(!info.isSymbolicLink());
+ QVERIFY(info.isShortcut());
QVERIFY(!info.exists());
QFile::remove(linkName);
QDir current; // QTBUG-21863
QVERIFY(current.mkdir(linkName));
QFileInfo dirInfo(linkName);
- QVERIFY(!dirInfo.isSymLink());
+ QVERIFY(!dirInfo.isSymbolicLink());
+ QVERIFY(!dirInfo.isShortcut());
QVERIFY(dirInfo.isDir());
current.rmdir(linkName);
}
@@ -2032,7 +2121,8 @@ static void stateCheck(const QFileInfo &info, const QString &dirname, const QStr
QVERIFY(!info.isHidden());
QVERIFY(!info.isFile());
QVERIFY(!info.isDir());
- QVERIFY(!info.isSymLink());
+ QVERIFY(!info.isSymbolicLink());
+ QVERIFY(!info.isShortcut());
QVERIFY(!info.isBundle());
QVERIFY(!info.isRoot());
QCOMPARE(info.isNativePath(), !filename.isEmpty());
@@ -2089,5 +2179,73 @@ void tst_QFileInfo::nonExistingFile()
stateCheck(info, dirname, filename);
}
+Q_DECLARE_METATYPE(QFileInfo::FileTypes)
+
+void tst_QFileInfo::type_data()
+{
+ QFile::remove("link.lnk");
+ QFile::remove("symlink.lnk");
+ QFile::remove("link");
+ QFile::remove("symlink");
+ QFile::remove("directory.lnk");
+ QFile::remove("directory");
+
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<QFileInfo::FileTypes>("type");
+
+ QFile regularFile(m_sourceFile);
+ QTest::newRow("regular")
+ << regularFile.fileName() << QFileInfo::FileTypes(QFileInfo::Regular);
+ QTest::newRow("directory")
+ << QDir::currentPath() << QFileInfo::FileTypes(QFileInfo::Directory);
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ // windows shortcuts
+ QVERIFY(regularFile.link("link.lnk"));
+ QTest::newRow("shortcut")
+ << "link.lnk" << QFileInfo::FileTypes(QFileInfo::Shortcut | QFileInfo::Regular);
+ QVERIFY(regularFile.link("link"));
+ QTest::newRow("invalid-shortcut")
+ << "link" << QFileInfo::FileTypes(QFileInfo::Regular);
+ QVERIFY(QFile::link(QDir::currentPath(), "directory.lnk"));
+ QTest::newRow("directory-shortcut")
+ << "directory.lnk" << QFileInfo::FileTypes(QFileInfo::Shortcut | QFileInfo::Directory);
+#endif
+
+#ifndef Q_NO_SYMLINKS
+#if defined(Q_OS_WIN)
+#if !defined(Q_OS_WINRT)
+ QString errorMessage;
+ const DWORD creationResult = createSymbolicLink("symlink", m_sourceFile, &errorMessage);
+ if (creationResult == ERROR_PRIVILEGE_NOT_HELD) {
+ QWARN(msgInsufficientPrivileges(errorMessage));
+ } else {
+ QVERIFY2(creationResult == ERROR_SUCCESS, qPrintable(errorMessage));
+ QTest::newRow("NTFS-symlink")
+ << "symlink" << QFileInfo::FileTypes(QFileInfo::SymbolicLink | QFileInfo::Regular);
+ }
+#endif // !Q_OS_WINRT
+#else // Unix:
+ QVERIFY(regularFile.link("symlink.lnk"));
+ QTest::newRow("symlink.lnk")
+ << "symlink.lnk" << QFileInfo::FileTypes(QFileInfo::SymbolicLink | QFileInfo::Regular);
+ QVERIFY(regularFile.link("symlink"));
+ QTest::newRow("symlink")
+ << "symlink" << QFileInfo::FileTypes(QFileInfo::SymbolicLink | QFileInfo::Regular);
+ QVERIFY(QFile::link(QDir::currentPath(), "directory"));
+ QTest::newRow("directory-symlink")
+ << "directory" << QFileInfo::FileTypes(QFileInfo::SymbolicLink | QFileInfo::Directory);
+#endif
+#endif // !Q_NO_SYMLINKS
+}
+
+void tst_QFileInfo::type()
+{
+ QFETCH(QString, path);
+ QFETCH(QFileInfo::FileTypes, type);
+
+ QFileInfo info(path);
+ QCOMPARE(info.type(), type);
+}
+
QTEST_MAIN(tst_QFileInfo)
#include "tst_qfileinfo.moc"