diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index ea594470eae..1ca5eea01e2 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -462,7 +462,9 @@ QFile::remove(const QString &fileName) //! [move-to-trash-common] The time for this function to run is independent of the size of the file being trashed. If this function is called on a directory, it may be - proportional to the number of files being trashed. + proportional to the number of files being trashed. If the current + fileName() points to a symbolic link, this function will move the link to + the trash, possibly breaking it, not the target of the link. This function uses the Windows and \macos APIs to perform the trashing on those two operating systems. Elsewhere (Unix systems), this function diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 0ca32a6b9f4..8a4072098cb 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -1531,7 +1531,7 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source, renamed = renameat(op.filesDirFd, op.tempTrashFileName, op.filesDirFd, QFile::encodeName(uniqueTrashedName)) == 0; if (renamed) - removeFile(source, error); // success, delete the original file + removeFile(sourcePath, error); // success, delete the original file } if (!renamed) { error = QSystemError(errno, QSystemError::StandardLibraryError); diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp index d69cc167d63..87736fdfc5a 100644 --- a/tests/auto/corelib/io/qfile/tst_qfile.cpp +++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp @@ -292,6 +292,9 @@ private slots: void moveToTrashDuplicateName(); void moveToTrashOpenFile_data(); void moveToTrashOpenFile(); + void moveToTrashSymlinkToFile(); + void moveToTrashSymlinkToDirectory_data(); + void moveToTrashSymlinkToDirectory(); void moveToTrashXdgSafety(); void stdfilesystem(); @@ -4236,6 +4239,79 @@ void tst_QFile::moveToTrashOpenFile() } } +void tst_QFile::moveToTrashSymlinkToFile() +{ +#if defined(Q_OS_ANDROID) || defined(Q_OS_WEBOS) || defined(Q_OS_VXWORKS) + QSKIP("This platform doesn't implement a trash bin"); +#endif + QTemporaryFile temp(QDir::homePath() + "/tst_qfile.moveToTrashSymlinkFile.XXXXXX"); + QVERIFY2(temp.open(), "Failed to create temporary file: " + temp.errorString().toLocal8Bit()); + + // Create the symlink + const QString linkName = temp.fileName() + ".lnk"; + QVERIFY2(temp.link(linkName), "Failed to create link: " + temp.errorString().toLocal8Bit()); + auto cleanLink = qScopeGuard([&]() { + QFile::remove(linkName); + }); + + // now trash it + QFile symlink(linkName); + QVERIFY(symlink.moveToTrash()); + QCOMPARE_NE(symlink.fileName(), linkName); + + // confirm that the target is still a symlink + QFileInfo fi(symlink.fileName()); + QVERIFY(fi.isSymLink()); + QVERIFY(fi.isFile()); // we used an absolute path, so it should not be broken! + symlink.remove(); + + // confirm that the symlink disappeared but the original file is still present + QVERIFY(QFile::exists(temp.fileName())); + QVERIFY(!QFile::exists(linkName)); + cleanLink.dismiss(); +} + +void tst_QFile::moveToTrashSymlinkToDirectory_data() +{ + QTest::addColumn("appendSlash"); + QTest::newRow("without-slash") << false; + QTest::newRow("with-slash") << true; +} + +void tst_QFile::moveToTrashSymlinkToDirectory() +{ +#if defined(Q_OS_ANDROID) || defined(Q_OS_WEBOS) || defined(Q_OS_VXWORKS) + QSKIP("This platform doesn't implement a trash bin"); +#endif + QFETCH(bool, appendSlash); + QTemporaryDir temp(QDir::homePath() + "/tst_qfile.moveToTrashSymlinkDir.XXXXXX"); + QVERIFY2(temp.isValid(), "Failed to create temporary dir: " + temp.errorString().toLocal8Bit()); + + // Create the symlink + const QString linkName = temp.path() + ".lnk"; + QVERIFY(QFile::link(temp.path(), linkName)); + auto cleanLink = qScopeGuard([&]() { + QFile::remove(linkName); + }); + + // now trash it + QFile symlink(appendSlash ? linkName + u'/' : linkName); + QVERIFY(symlink.moveToTrash()); + QCOMPARE_NE(symlink.fileName(), linkName); + QCOMPARE_NE(symlink.fileName(), linkName + u'/'); + + // confirm that the target is still a symlink + QFileInfo fi(symlink.fileName()); + QVERIFY(fi.isSymLink()); + QVERIFY(fi.isDir()); // we used an absolute path, so it should not be broken! + symlink.remove(); + + // confirm that the symlink disappeared but the original dir is still present + QVERIFY(QFile::exists(temp.path())); + QVERIFY(!QFile::exists(linkName)); + cleanLink.dismiss(); +} + void tst_QFile::moveToTrashXdgSafety() { #if defined(Q_OS_VXWORKS)