File indexing completed on 2024-11-24 04:31:15
0001 /* 0002 SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "movedatafilesjob.h" 0007 #include <KIO/FileCopyJob> 0008 #include <QFileInfo> 0009 #include <QUrl> 0010 #include <interfaces/torrentfileinterface.h> 0011 #include <kio/jobuidelegate.h> 0012 #include <kjobtrackerinterface.h> 0013 #include <klocalizedstring.h> 0014 #include <util/fileops.h> 0015 #include <util/functions.h> 0016 #include <util/log.h> 0017 0018 namespace bt 0019 { 0020 static ResourceManager move_data_files_slot(1); 0021 0022 MoveDataFilesJob::MoveDataFilesJob() 0023 : Job(true, nullptr) 0024 , Resource(&move_data_files_slot, "MoveDataFilesJob") 0025 , err(false) 0026 , active_job(nullptr) 0027 , running_recovery_jobs(0) 0028 , bytes_moved(0) 0029 , total_bytes(0) 0030 , bytes_moved_current_file(0) 0031 { 0032 } 0033 0034 MoveDataFilesJob::MoveDataFilesJob(const QMap<TorrentFileInterface *, QString> &fmap) 0035 : Job(true, nullptr) 0036 , Resource(&move_data_files_slot, "MoveDataFilesJob") 0037 , err(false) 0038 , active_job(nullptr) 0039 , running_recovery_jobs(0) 0040 , bytes_moved(0) 0041 , total_bytes(0) 0042 , bytes_moved_current_file(0) 0043 { 0044 file_map = fmap; 0045 QMap<TorrentFileInterface *, QString>::const_iterator i = file_map.constBegin(); 0046 while (i != file_map.constEnd()) { 0047 TorrentFileInterface *tf = i.key(); 0048 QString dest = i.value(); 0049 if (QFileInfo(dest).isDir()) { 0050 QString path = tf->getUserModifiedPath(); 0051 if (!dest.endsWith(bt::DirSeparator())) 0052 dest += bt::DirSeparator(); 0053 0054 int last = path.lastIndexOf(bt::DirSeparator()); 0055 QString dst = dest + path.mid(last + 1); 0056 if (QFileInfo(tf->getPathOnDisk()).canonicalPath() != QFileInfo(dst).canonicalPath()) 0057 addMove(tf->getPathOnDisk(), dst); 0058 } else if (QFileInfo(tf->getPathOnDisk()).canonicalPath() != QFileInfo(i.value()).canonicalPath()) { 0059 addMove(tf->getPathOnDisk(), i.value()); 0060 } 0061 ++i; 0062 } 0063 } 0064 0065 MoveDataFilesJob::~MoveDataFilesJob() 0066 { 0067 } 0068 0069 void MoveDataFilesJob::addMove(const QString &src, const QString &dst) 0070 { 0071 todo.insert(src, dst); 0072 } 0073 0074 void MoveDataFilesJob::onJobDone(KJob *j) 0075 { 0076 if (j->error() || err) { 0077 if (!err) 0078 setError(KIO::ERR_INTERNAL); 0079 0080 active_job = nullptr; 0081 if (j->error()) 0082 ((KIO::Job *)j)->uiDelegate()->showErrorMessage(); 0083 0084 // shit happened cancel all previous moves 0085 err = true; 0086 recover(j->error() != KIO::ERR_FILE_ALREADY_EXIST && j->error() != KIO::ERR_IDENTICAL_FILES); 0087 } else { 0088 bytes_moved += bytes_moved_current_file; 0089 bytes_moved_current_file = 0; 0090 success.insert(active_src, active_dst); 0091 active_src = active_dst = QString(); 0092 active_job = nullptr; 0093 startMoving(); 0094 } 0095 } 0096 0097 void MoveDataFilesJob::start() 0098 { 0099 registerWithTracker(); 0100 QMap<QString, QString>::iterator i = todo.begin(); 0101 while (i != todo.end()) { 0102 QFileInfo fi(i.key()); 0103 total_bytes += fi.size(); 0104 ++i; 0105 } 0106 setTotalAmount(KJob::Bytes, total_bytes); 0107 move_data_files_slot.add(this); 0108 if (!active_job) { 0109 description(this, 0110 i18n("Waiting for other move jobs to finish"), 0111 qMakePair(i18nc("The source of a file operation", "Source"), active_src), 0112 qMakePair(i18nc("The destination of a file operation", "Destination"), active_dst)); 0113 emitSpeed(0); 0114 } 0115 } 0116 0117 void MoveDataFilesJob::acquired() 0118 { 0119 startMoving(); 0120 } 0121 0122 void MoveDataFilesJob::kill(bool quietly) 0123 { 0124 Q_UNUSED(quietly); 0125 // don't do anything we cannot abort in the middle of this operation 0126 } 0127 0128 void MoveDataFilesJob::startMoving() 0129 { 0130 if (todo.isEmpty()) { 0131 emitResult(); 0132 return; 0133 } 0134 0135 QMap<QString, QString>::iterator i = todo.begin(); 0136 active_job = KIO::file_move(QUrl::fromLocalFile(i.key()), QUrl::fromLocalFile(i.value()), -1, KIO::HideProgressInfo); 0137 active_src = i.key(); 0138 active_dst = i.value(); 0139 Out(SYS_GEN | LOG_DEBUG) << "Moving " << active_src << " -> " << active_dst << endl; 0140 connect(active_job, &KIO::Job::result, this, &MoveDataFilesJob::onJobDone); 0141 connect(active_job, &KIO::Job::processedAmountChanged, this, &MoveDataFilesJob::onTransferred); 0142 connect(active_job, &KIO::Job::speed, this, &MoveDataFilesJob::onSpeed); 0143 todo.erase(i); 0144 0145 description(this, 0146 i18nc("@title job", "Moving"), 0147 qMakePair(i18nc("The source of a file operation", "Source"), active_src), 0148 qMakePair(i18nc("The destination of a file operation", "Destination"), active_dst)); 0149 addSubjob(active_job); 0150 } 0151 0152 void MoveDataFilesJob::recover(bool delete_active) 0153 { 0154 if (delete_active && bt::Exists(active_dst)) 0155 bt::Delete(active_dst, true); 0156 0157 if (success.isEmpty()) { 0158 emitResult(); 0159 return; 0160 } 0161 0162 running_recovery_jobs = 0; 0163 QMap<QString, QString>::iterator i = success.begin(); 0164 while (i != success.end()) { 0165 KIO::Job *j = KIO::file_move(QUrl::fromLocalFile(i.value()), QUrl::fromLocalFile(i.key()), -1, KIO::HideProgressInfo); 0166 connect(j, &KIO::Job::result, this, &MoveDataFilesJob::onRecoveryJobDone); 0167 running_recovery_jobs++; 0168 ++i; 0169 } 0170 success.clear(); 0171 } 0172 0173 void MoveDataFilesJob::onRecoveryJobDone(KJob *j) 0174 { 0175 Q_UNUSED(j); 0176 running_recovery_jobs--; 0177 if (running_recovery_jobs <= 0) 0178 emitResult(); 0179 } 0180 0181 void MoveDataFilesJob::onTransferred(KJob *job, KJob::Unit unit, qulonglong amount) 0182 { 0183 Q_UNUSED(job); 0184 if (unit == KJob::Bytes) { 0185 bytes_moved_current_file = amount; 0186 setProcessedAmount(unit, bytes_moved + bytes_moved_current_file); 0187 } 0188 } 0189 0190 void MoveDataFilesJob::onSpeed(KJob *job, unsigned long speed) 0191 { 0192 Q_UNUSED(job); 0193 emitSpeed(speed); 0194 } 0195 0196 }