File indexing completed on 2024-12-08 13:32:53

0001 // SPDX-FileCopyrightText: 2020 Simon Persson <simon.persson@mykolab.com>
0002 //
0003 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 
0005 #include "restorejob.h"
0006 
0007 #include <QDir>
0008 #include <KLocalizedString>
0009 #include <utility>
0010 
0011 #include <unistd.h>
0012 #include <sys/resource.h>
0013 #ifdef Q_OS_LINUX
0014 #include <sys/syscall.h>
0015 #endif
0016 
0017 RestoreJob::RestoreJob(QString pRepositoryPath, QString pSourcePath, QString pRestorationPath,
0018                        int pTotalDirCount, qint64 pTotalFileSize, const QHash<QString, qint64> &pFileSizes)
0019  : mRepositoryPath(std::move(pRepositoryPath)), mSourcePath(std::move(pSourcePath)), mRestorationPath(std::move(pRestorationPath)),
0020    mTotalDirCount(pTotalDirCount), mTotalFileSize(pTotalFileSize), mFileSizes(pFileSizes)
0021 {
0022     setCapabilities(Killable);
0023     mRestoreProcess.setOutputChannelMode(KProcess::SeparateChannels);
0024     int lOffset = mSourcePath.endsWith(QDir::separator()) ? -2: -1;
0025     mSourceFileName = mSourcePath.section(QDir::separator(), lOffset, lOffset);
0026 }
0027 
0028 void RestoreJob::start() {
0029     setTotalAmount(Bytes, mTotalFileSize);
0030     setProcessedAmount(Bytes, 0);
0031     setTotalAmount(Files, static_cast<quint64>(mFileSizes.count()));
0032     setProcessedAmount(Files, 0);
0033     setTotalAmount(Directories, static_cast<quint64>(mTotalDirCount));
0034     setProcessedAmount(Directories, 0);
0035     setPercent(0);
0036     mRestoreProcess << QStringLiteral("bup");
0037     mRestoreProcess << QStringLiteral("-d") << mRepositoryPath;
0038     mRestoreProcess << QStringLiteral("restore") << QStringLiteral("-vv");
0039     mRestoreProcess << QStringLiteral("-C") << mRestorationPath;
0040     mRestoreProcess << mSourcePath;
0041     connect(&mRestoreProcess, SIGNAL(started()), SLOT(slotRestoringStarted()));
0042     connect(&mRestoreProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(slotRestoringDone(int,QProcess::ExitStatus)));
0043     mRestoreProcess.start();
0044     mTimerId = startTimer(100);
0045 }
0046 
0047 void RestoreJob::slotRestoringStarted() {
0048     makeNice(mRestoreProcess.processId());
0049 }
0050 
0051 void RestoreJob::timerEvent(QTimerEvent *pTimerEvent) {
0052     Q_UNUSED(pTimerEvent)
0053     quint64 lProcessedDirectories = processedAmount(Directories);
0054     quint64 lProcessedFiles = processedAmount(Files);
0055     quint64 lProcessedBytes = processedAmount(Bytes);
0056     bool lDirWasUpdated = false;
0057     bool lFileWasUpdated = false;
0058     QString lLastFileName;
0059 
0060     while(mRestoreProcess.canReadLine()) {
0061         QString lFileName = QString::fromLocal8Bit(mRestoreProcess.readLine()).trimmed();
0062         if(lFileName.size() == 0) {
0063             break;
0064         }
0065         if(lFileName.endsWith(QLatin1Char('/'))) { // it's a directory
0066             lProcessedDirectories++;
0067             lDirWasUpdated = true;
0068         } else {
0069             if(mSourcePath.endsWith(QDir::separator())) {
0070                 lFileName.prepend(QDir::separator());
0071                 lFileName.prepend(mSourceFileName);
0072             }
0073             lProcessedBytes += mFileSizes.value(lFileName);
0074             lProcessedFiles++;
0075             lLastFileName = lFileName;
0076             lFileWasUpdated = true;
0077         }
0078     }
0079     if(lDirWasUpdated) {
0080         setProcessedAmount(Directories, lProcessedDirectories);
0081     }
0082     if(lFileWasUpdated) {
0083         emit description(this, xi18nc("progress report, current operation", "Restoring"),
0084                          qMakePair(xi18nc("progress report, label", "File"), lLastFileName));
0085         setProcessedAmount(Files, lProcessedFiles);
0086         setProcessedAmount(Bytes, lProcessedBytes); // this will also call emitPercent()
0087     }
0088 }
0089 
0090 void RestoreJob::slotRestoringDone(int pExitCode, QProcess::ExitStatus pExitStatus) {
0091     killTimer(mTimerId);
0092     if(pExitStatus != QProcess::NormalExit || pExitCode != 0) {
0093         setError(1);
0094         setErrorText(QString::fromUtf8(mRestoreProcess.readAllStandardError()));
0095     }
0096     emitResult();
0097 }
0098 
0099 void RestoreJob::makeNice(int pPid) {
0100 #ifdef Q_OS_LINUX
0101     // See linux documentation Documentation/block/ioprio.txt for details of the syscall
0102     syscall(SYS_ioprio_set, 1, pPid, 3 << 13 | 7);
0103 #endif
0104     setpriority(PRIO_PROCESS, static_cast<uint>(pPid), 19);
0105 }
0106