diff --git a/autotests/jobtest.cpp b/autotests/jobtest.cpp --- a/autotests/jobtest.cpp +++ b/autotests/jobtest.cpp @@ -78,6 +78,9 @@ // To avoid a runtime dependency on klauncher qputenv("KDE_FORK_SLAVES", "yes"); + // to make sure io is not too fast + qputenv("KIOSLAVE_FILE_ENABLE_TESTMODE", "1"); + s_referenceTimeStamp = QDateTime::currentDateTime().addSecs(-30); // 30 seconds ago // Start with a clean base dir @@ -2083,41 +2086,44 @@ const QString baseDir = homeTmpDir(); const QString srcTemplate = baseDir + QStringLiteral("testfile_XXXXXX"); - const QString destFile = baseDir + QStringLiteral("testfile_copy_") + QString::fromLatin1(QTest::currentDataTag()); + const QString destFile = baseDir + QStringLiteral("testfile_copy_slow_") + QString::fromLatin1(QTest::currentDataTag()); QTemporaryFile f(srcTemplate); if (!f.open()) { qFatal("Couldn't open %s", qPrintable(f.fileName())); } - f.seek(9999999); + f.seek(999999); f.write("0"); f.close(); - QCOMPARE(f.size(), 10000000); //~10MB + QCOMPARE(f.size(), 1000000); //~1MB if (overwrite) { createTestFile(destFile); } + const QString destToCheck = (overwrite) ? destFile + QStringLiteral(".part") : destFile; 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); + + // 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_VERIFY2(!QFile::exists(destToCheck), qPrintable(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.h b/src/ioslaves/file/file.h --- a/src/ioslaves/file/file.h +++ b/src/ioslaves/file/file.h @@ -121,6 +121,8 @@ mutable QHash mUsercache; mutable QHash mGroupcache; QFile *mFile; + + bool testMode = false; }; #endif diff --git a/src/ioslaves/file/file.cpp b/src/ioslaves/file/file.cpp --- a/src/ioslaves/file/file.cpp +++ b/src/ioslaves/file/file.cpp @@ -163,6 +163,7 @@ FileProtocol::FileProtocol(const QByteArray &pool, const QByteArray &app) : SlaveBase(QByteArrayLiteral("file"), pool, app), mFile(nullptr) { + testMode = !qEnvironmentVariableIsEmpty("KIOSLAVE_FILE_ENABLE_TESTMODE"); } FileProtocol::~FileProtocol() 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 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -311,7 +312,12 @@ bool use_sendfile = buff_src.st_size < 0x7FFFFFFF; #endif bool existing_dest_delete_attempted = false; - while (1) { + while (!wasKilled()) { + + if (testMode && dest_file.fileName().contains(QLatin1String("slow"))) { + QThread::usleep(500); + } + #ifdef USE_SENDFILE if (use_sendfile) { off_t sf = processed_size; @@ -398,6 +404,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);