diff --git a/src/core/copyjob.h b/src/core/copyjob.h --- a/src/core/copyjob.h +++ b/src/core/copyjob.h @@ -130,6 +130,11 @@ void setWriteIntoExistingDirectories(bool overwriteAllDirs); /** + * Reimplemented to do a proper cleanup of partially copied files. + */ + bool doKill() Q_DECL_OVERRIDE; + + /** * Reimplemented for internal reasons */ bool doSuspend() Q_DECL_OVERRIDE; @@ -286,7 +291,7 @@ * * @param src the file or directory to copy * @param dest the destination - * @param flags copy() supports HideProgressInfo and Overwrite. + * @param flags copy() supports HideProgressInfo, Overwrite and NoCancelCleanup. * Note: Overwrite has the meaning of both "write into existing directories" and * "overwrite existing files". However if "dest" exists, then src is copied * into a subdir of dest, just like "cp" does. Use copyAs if you don't want that. @@ -307,7 +312,7 @@ * * @param src the file or directory to copy * @param dest the destination - * @param flags copyAs() supports HideProgressInfo and Overwrite. + * @param flags copyAs() supports HideProgressInfo, Overwrite and NoCancelCleanup. * Note: Overwrite has the meaning of both "write into existing directories" and * "overwrite existing files". * @@ -320,7 +325,7 @@ * * @param src the list of files and/or directories * @param dest the destination - * @param flags copy() supports HideProgressInfo and Overwrite. + * @param flags copy() supports HideProgressInfo, Overwrite and NoCancelCleanup. * Note: Overwrite has the meaning of both "write into existing directories" and * "overwrite existing files". However if "dest" exists, then src is copied * into a subdir of dest, just like "cp" does. @@ -333,7 +338,7 @@ * * @param src the file or directory to copy * @param dest the destination - * @param flags move() supports HideProgressInfo and Overwrite. + * @param flags move() supports HideProgressInfo, Overwrite and NoCancelCleanup. * Note: Overwrite has the meaning of both "write into existing directories" and * "overwrite existing files". However if "dest" exists, then src is copied * into a subdir of dest, just like "cp" does. @@ -349,7 +354,7 @@ * * @param src the file or directory to copy * @param dest the destination - * @param flags moveAs() supports HideProgressInfo and Overwrite. + * @param flags moveAs() supports HideProgressInfo, Overwrite and NoCancelCleanup. * Note: Overwrite has the meaning of both "write into existing directories" and * "overwrite existing files". * @return the job handling the operation @@ -361,7 +366,7 @@ * * @param src the list of files or directories to copy * @param dest the destination - * @param flags move() supports HideProgressInfo and Overwrite. + * @param flags move() supports HideProgressInfo, Overwrite and NoCancelCleanup. * Note: Overwrite has the meaning of both "write into existing directories" and * "overwrite existing files". However if "dest" exists, then src is copied * into a subdir of dest, just like "cp" does. diff --git a/src/core/copyjob.cpp b/src/core/copyjob.cpp --- a/src/core/copyjob.cpp +++ b/src/core/copyjob.cpp @@ -135,6 +135,7 @@ , m_totalSize(0) , m_processedSize(0) , m_fileProcessedSize(0) + , m_bFileCopyingIsInProcess(false) , m_processedFiles(0) , m_processedDirs(0) , m_srcList(src) @@ -149,6 +150,7 @@ , m_bAutoSkipDirs(false) , m_bOverwriteAllFiles(false) , m_bOverwriteAllDirs(false) + , m_bDoCancelCleanup(false) , m_conflictError(0) , m_reportTimer(nullptr) { @@ -180,6 +182,7 @@ KIO::filesize_t m_totalSize; KIO::filesize_t m_processedSize; KIO::filesize_t m_fileProcessedSize; + bool m_bFileCopyingIsInProcess; int m_processedFiles; int m_processedDirs; QList files; @@ -203,6 +206,7 @@ bool m_bAutoSkipDirs; bool m_bOverwriteAllFiles; bool m_bOverwriteAllDirs; + bool m_bDoCancelCleanup; int m_conflictError; QTimer *m_reportTimer; @@ -290,6 +294,9 @@ } job->d_func()->m_operationType = copyType; } + if (!(flags & KIO::NoCancelCleanup)) { + job->d_func()->m_bDoCancelCleanup = true; + } return job; } }; @@ -544,6 +551,24 @@ } } +bool CopyJob::doKill() +{ + const bool res = Job::doKill(); + + Q_D(CopyJob); + + // If we are interrupted in the middle of file copying, + // we may end up with corrupted file at the destination. + // It is better to clean up this file. + if (d->m_bDoCancelCleanup && + d->state == STATE_COPYING_FILES && + d->m_bFileCopyingIsInProcess) { + KIO::del(d->m_currentDestURL); + } + + return res; +} + bool CopyJob::doSuspend() { Q_D(CopyJob); @@ -1272,6 +1297,9 @@ void CopyJobPrivate::slotResultCopyingFiles(KJob *job) { Q_Q(CopyJob); + + m_bFileCopyingIsInProcess = false; + // The file we were trying to copy: QList::Iterator it = files.begin(); if (job->error()) { @@ -1797,6 +1825,7 @@ { Q_Q(CopyJob); qCDebug(KIO_COPYJOB_DEBUG) << data_size; + m_bFileCopyingIsInProcess = true; m_fileProcessedSize = data_size; q->setProcessedAmount(KJob::Bytes, m_processedSize + m_fileProcessedSize); diff --git a/src/core/job_base.h b/src/core/job_base.h --- a/src/core/job_base.h +++ b/src/core/job_base.h @@ -278,7 +278,8 @@ */ enum JobFlag { /** - * Show the progress info GUI, no Resume and no Overwrite + * Show the progress info GUI, no Resume, no Overwrite, and do incomplete + * files cleanup if canceled. */ DefaultFlags = 0, @@ -311,6 +312,15 @@ * @since 5.43 */ NoPrivilegeExecution = 8, + + /** + * By default (since 5.44), if the job is canceled, it will clean up incompletely copied + * files, if they exist. This flag turns off such a behavior. + * Used by KIO::copy(), KIO::copyAs(), KIO::move(), KIO::moveAs() + * + * @since 5.44 + */ + NoCancelCleanup = 16, }; Q_DECLARE_FLAGS(JobFlags, JobFlag) Q_DECLARE_OPERATORS_FOR_FLAGS(JobFlags)