diff --git a/autotests/jobtest.h b/autotests/jobtest.h --- a/autotests/jobtest.h +++ b/autotests/jobtest.h @@ -45,6 +45,7 @@ void storedPutIODeviceFastDevice(); void storedPutIODeviceSlowDevice(); void storedPutIODeviceSlowDeviceBigChunk(); + void fileSlaveCrash(); void copyFileToSamePartition(); void copyDirectoryToSamePartition(); void copyDirectoryToExistingDirectory(); diff --git a/autotests/jobtest.cpp b/autotests/jobtest.cpp --- a/autotests/jobtest.cpp +++ b/autotests/jobtest.cpp @@ -418,6 +418,57 @@ QVERIFY(!spyPercent.isEmpty()); } +void JobTest::fileSlaveCrash() +{ + const QString filePath = homeTmpDir() + "fileFromHome"; + const QUrl u = QUrl::fromLocalFile(filePath); + const QByteArray putDataContents(300000, 'K'); // Make sure the 300000 is bigger than MAX_READ_BUF_SIZE + + QBuffer putDataBuffer; + QVERIFY(putDataBuffer.open(QIODevice::ReadWrite)); + + QBuffer putDataBuffer2; + QVERIFY(putDataBuffer2.open(QIODevice::ReadWrite)); + + KIO::StoredTransferJob *job = KIO::storedPut(&putDataBuffer, u, 0600, KIO::Overwrite | KIO::HideProgressInfo); + job->setAsyncDataEnabled(true); + + bool job1Finished = false; + bool job2Finished = false; + int job2ErrorStatus = 0; + + connect(job, &KJob::finished, [&job1Finished] { + job1Finished = true; + }); + + QTimer::singleShot(200, this, [&putDataBuffer, &putDataBuffer2, putDataContents, &u, &job2Finished, &job2ErrorStatus]() { + putDataBuffer.write(putDataContents); + putDataBuffer.seek(0); + + KIO::StoredTransferJob *job2 = KIO::storedPut(&putDataBuffer2, u, 0600, KIO::HideProgressInfo); + job2->setAsyncDataEnabled(true); + + putDataBuffer2.write(putDataContents); + putDataBuffer2.seek(0); + + connect(job2, &KJob::finished, [&putDataBuffer2, &job2Finished, job2, &job2ErrorStatus] { + putDataBuffer2.readyRead(); + job2Finished = true; + job2ErrorStatus = job2->error(); + }); + }); + + // Simulate the transfer is done + QTimer::singleShot(400, this, [&putDataBuffer, &putDataBuffer2](){ + putDataBuffer.readChannelFinished(); + putDataBuffer2.readChannelFinished(); + }); + + QTRY_VERIFY(job1Finished); + QTRY_VERIFY(job2Finished); + QCOMPARE(job2ErrorStatus, KIO::ERR_FILE_ALREADY_EXIST); +} + //// void JobTest::copyLocalFile(const QString &src, const QString &dest) diff --git a/src/core/slavebase.cpp b/src/core/slavebase.cpp --- a/src/core/slavebase.cpp +++ b/src/core/slavebase.cpp @@ -1030,7 +1030,7 @@ if (isSubCommand(cmd)) { dispatch(cmd, data); } else { - qFatal("Fatal Error: Got cmd %d, while waiting for an answer!", cmd); + qFatal("Fatal Error: Got cmd %d, while waiting for an answer. Expected: %d, %d!", cmd, expected1, expected2); } } } diff --git a/src/core/storedtransferjob.cpp b/src/core/storedtransferjob.cpp --- a/src/core/storedtransferjob.cpp +++ b/src/core/storedtransferjob.cpp @@ -20,6 +20,8 @@ #include "storedtransferjob.h" #include "job_p.h" +#include "slave.h" + #include #include #include @@ -93,6 +95,11 @@ SLOT(slotStoredData(KIO::Job*,QByteArray))); connect(this, SIGNAL(dataReq(KIO::Job*,QByteArray&)), SLOT(slotStoredDataReq(KIO::Job*,QByteArray&))); + connect(this, &TransferJob::canResume, [&dd](KIO::Job*, KIO::filesize_t offset) { + if (offset != 0) { + dd.m_slave->sendResumeAnswer(false); + } + }); } StoredTransferJob::~StoredTransferJob() diff --git a/src/core/transferjob.cpp b/src/core/transferjob.cpp --- a/src/core/transferjob.cpp +++ b/src/core/transferjob.cpp @@ -324,8 +324,6 @@ q, SLOT(slotIODeviceClosedBeforeStart())); if (m_closedBeforeStart) { QMetaObject::invokeMethod(q, "slotIODeviceClosed", Qt::QueuedConnection); - } else if (m_outgoingDataSource->bytesAvailable() > 0) { - QMetaObject::invokeMethod(q, "slotDataReqFromDevice", Qt::QueuedConnection); } } else { q->connect(slave, SIGNAL(dataReq()),