diff --git a/autotests/jobtest.cpp b/autotests/jobtest.cpp --- a/autotests/jobtest.cpp +++ b/autotests/jobtest.cpp @@ -2042,32 +2042,39 @@ f.seek(9999999); f.write("0"); f.close(); - QCOMPARE(f.size(), 10000000); //~10MB + QCOMPARE(f.size(), 10000000); //~10MB to make sure copy is not too fast, or the tests won't pass if (overwrite) { createTestFile(destFile); } + const QString destToCheck = (!overwrite) ? destFile : destFile + QStringLiteral(".part"); KIO::JobFlag m_overwriteFlag = overwrite ? KIO::Overwrite : KIO::DefaultFlags; KIO::FileCopyJob *copyJob = KIO::file_copy(QUrl::fromLocalFile(f.fileName()), QUrl::fromLocalFile(destFile), -1, KIO::HideProgressInfo | m_overwriteFlag); copyJob->setUiDelegate(nullptr); QSignalSpy spyProcessedSize(copyJob, &KIO::Job::processedSize); - connect(copyJob, &KIO::Job::processedSize, this, [destFile, suspend, overwrite](KJob *job, qulonglong processedSize) { + QSignalSpy spyFinished(copyJob, &KIO::Job::finished); + connect(copyJob, &KIO::Job::processedSize, this, [destFile, suspend, destToCheck](KJob *job, qulonglong processedSize) { if (processedSize > 0) { - const QString destToCheck = (!overwrite) ? destFile : destFile + QStringLiteral(".part"); QVERIFY2(QFile::exists(destToCheck), qPrintable(destToCheck)); if (suspend) { job->suspend(); } - job->kill(); - QVERIFY(!QFile::exists(destToCheck)); + QVERIFY(job->kill()); } }); + QVERIFY(!copyJob->exec()); QCOMPARE(spyProcessedSize.count(), 1); - // Give time to the kioslave to finish copy() and warn about chown/chmod failing (because FileCopyJob::doKill removed the file) - // Less confusing if the warnings show here. - QTest::qWait(500); - QVERIFY(!QFile::exists(destFile)); + QCOMPARE(spyFinished.count(), 1); + QCOMPARE(copyJob->error(), KIO::ERR_USER_CANCELED); + + if (overwrite) { + // the destination file actual deletion happens after finished() is emitted + // we need to give some time to the ioslave to finish the file cleaning + QTRY_VERIFY(!QFile::exists(destToCheck)); + } else { + QVERIFY(QFile::exists(destToCheck)); + } } diff --git a/src/core/filecopyjob.cpp b/src/core/filecopyjob.cpp --- a/src/core/filecopyjob.cpp +++ b/src/core/filecopyjob.cpp @@ -578,6 +578,12 @@ bool FileCopyJob::doKill() { +#ifdef Q_OS_WIN +//TODO Use SetConsoleCtrlHandler on Windows or similar behaviour. +// https://stackoverflow.com/questions/2007516/is-there-a-posix-sigterm-alternative-on-windows-a-gentle-kill-for-console-ap +// https://danielkaes.wordpress.com/2009/06/04/how-to-catch-kill-events-with-python/ +// https://phabricator.kde.org/D25117#566107 + Q_D(FileCopyJob); // If we are interrupted in the middle of file copying, @@ -592,7 +598,7 @@ QFile::remove(d->m_dest.toLocalFile()); } } - +#endif return Job::doKill(); } diff --git a/src/ioslaves/file/file_unix.cpp b/src/ioslaves/file/file_unix.cpp --- a/src/ioslaves/file/file_unix.cpp +++ b/src/ioslaves/file/file_unix.cpp @@ -311,7 +311,7 @@ bool use_sendfile = buff_src.st_size < 0x7FFFFFFF; #endif bool existing_dest_delete_attempted = false; - while (1) { + while (!wasKilled()) { #ifdef USE_SENDFILE if (use_sendfile) { off_t sf = processed_size; @@ -398,6 +398,15 @@ src_file.close(); dest_file.close(); + if (wasKilled()) { + qCDebug(KIO_FILE) << "Clean dest file after ioslave was killed:" << dest; + if (!QFile::remove(dest)) { // don't keep partly copied file + execWithElevatedPrivilege(DEL, {_dest}, errno); + } + error(KIO::ERR_USER_CANCELED, dest); + return; + } + if (dest_file.error() != QFile::NoError) { qCWarning(KIO_FILE) << "Error when closing file descriptor[2]:" << dest_file.errorString(); error(KIO::ERR_CANNOT_WRITE, dest);