File indexing completed on 2024-04-28 09:45:20

0001 //**************************************************************************
0002 //   Copyright 2006 - 2023 Martin Koller, kollix@aon.at
0003 //
0004 //   This program is free software; you can redistribute it and/or modify
0005 //   it under the terms of the GNU General Public License as published by
0006 //   the Free Software Foundation, version 2 of the License
0007 //
0008 //**************************************************************************
0009 
0010 #ifndef _ARCHIVER_H_
0011 #define _ARCHIVER_H_
0012 
0013 // the class which does the archiving
0014 
0015 #include <QObject>
0016 #include <QPointer>
0017 #include <QSet>
0018 #include <QElapsedTimer>
0019 #include <QTime>
0020 #include <QDateTime>
0021 #include <QStringList>
0022 #include <QList>
0023 #include <QRegExp>
0024 
0025 #include <QUrl>
0026 #include <kio/global.h>
0027 #include <kio/copyjob.h>
0028 #include <kio/udsentry.h>
0029 #include <KCompressionDevice>
0030 
0031 class QDir;
0032 class QFileInfo;
0033 class QFile;
0034 
0035 
0036 class Archiver : public QObject
0037 {
0038   Q_OBJECT
0039 
0040   public:
0041     explicit Archiver(QWidget *parent);
0042 
0043     static Archiver *instance;
0044 
0045     // always call after you have already set maxSliceMBs, as the sliceCapacity
0046     // might be limited with it
0047     void setTarget(const QUrl &target);
0048     const QUrl &getTarget() const { return targetURL; }
0049 
0050     enum { UNLIMITED = 0 };
0051     void setMaxSliceMBs(int mbs);
0052     int getMaxSliceMBs() const { return maxSliceMBs; }
0053 
0054     void setFilePrefix(const QString &prefix);
0055     const QString &getFilePrefix() const { return filePrefix; }
0056 
0057     void setMediaNeedsChange(bool b) { mediaNeedsChange = b; }
0058     bool getMediaNeedsChange() const { return mediaNeedsChange; }
0059 
0060     void setCompressFiles(bool b);
0061     bool getCompressFiles() const { return !ext.isEmpty(); }
0062 
0063     // number of backups to keep before older ones will be deleted (UNLIMITED or 1..n)
0064     void setKeptBackups(int num);
0065     int getKeptBackups() const { return numKeptBackups; }
0066 
0067     // define a filename filter in wildcard format each separated with a space
0068     // e.g. "*.png *.ogg"
0069     void setFilter(const QString &filter);
0070     QString getFilter() const;
0071 
0072     // define a list of path wildcards to filter complete dirs, separated by newline
0073     void setDirFilter(const QString &filter);
0074     QString getDirFilter() const;
0075 
0076     // interval for a full backup instead differential backup; when 1 given == full backup
0077     void setFullBackupInterval(int days);
0078     int getFullBackupInterval() const { return fullBackupInterval; }
0079 
0080     const QDateTime &getLastFullBackup() const { return lastFullBackup; }
0081     const QDateTime &getLastBackup() const { return lastBackup; }
0082 
0083     // when manually saving a profile, we need to restart the backup (incremental) cycle
0084     void resetBackupCycle();
0085 
0086     // print every single file/dir in non-interactive mode
0087     void setVerbose(bool b) { verbose = b; }
0088 
0089     // loads the profile into the Archiver and returns includes/excludes lists
0090     // return true if loaded, false on file open error
0091     bool loadProfile(const QString &fileName, QStringList &includes, QStringList &excludes, QString &error);
0092     void setLoadedProfile(const QString &fileName) { loadedProfile = fileName; }
0093 
0094     bool saveProfile(const QString &fileName, const QStringList &includes, const QStringList &excludes, QString &error);
0095 
0096     // return true if the backup completed successfully, else false
0097     bool createArchive(const QStringList &includes, const QStringList &excludes);
0098 
0099     KIO::filesize_t getTotalBytes() const { return totalBytes; }
0100     int getTotalFiles() const { return totalFiles; }
0101 
0102     bool isInProgress() const { return runs; }
0103 
0104     static bool getDiskFree(const QString &path, KIO::filesize_t &capacityBytes, KIO::filesize_t &freeBytes);
0105 
0106     // TODO: put probably in some global settings object
0107     static QString sliceScript;
0108 
0109   public Q_SLOTS:
0110     void cancel();  // cancel a running creation
0111     void setForceFullBackup(bool force = true);
0112 
0113   Q_SIGNALS:
0114     void inProgress(bool runs);
0115     void logging(const QString &);
0116     void warning(const QString &);
0117     void targetCapacity(KIO::filesize_t bytes);
0118     void sliceProgress(int percent);
0119     void fileProgress(int percent);
0120     void newSlice(int);
0121     void totalFilesChanged(int);
0122     void totalBytesChanged(KIO::filesize_t);
0123     void elapsedChanged(const QTime &);
0124     void backupTypeChanged(bool incremental);
0125 
0126   private Q_SLOTS:
0127     void slotResult(KJob *);
0128     void slotListResult(KIO::Job *, const KIO::UDSEntryList &);
0129     void receivedOutput();
0130     void loggingSlot(const QString &message); // for non-interactive output
0131     void warningSlot(const QString &message); // for non-interactive output
0132     void updateElapsed();
0133 
0134   private:
0135     void calculateCapacity();  // also emits signals
0136     void addDirFiles(QDir &dir);
0137     void addFile(const QFileInfo &info);
0138 
0139     enum AddFileStatus { Error, Added, Skipped };
0140     AddFileStatus addLocalFile(const QFileInfo &info, struct archive_entry *entry);
0141 
0142     bool compressFile(const QString &origName, QFile &comprFile);
0143 
0144     void finishSlice();
0145     bool getNextSlice();
0146 
0147     void runScript(const QString &mode);
0148     void setIncrementalBackup(bool inc);
0149 
0150     // returns true if the next backup will be an incremental one, false for a full backup
0151     bool isIncrementalBackup() const { return !forceFullBackup && incrementalBackup; }
0152 
0153     // return true if given fileName matches any of the defined filters
0154     bool fileIsFiltered(const QString &fileName) const;
0155 
0156     void emitArchiveError();
0157 
0158     static bool UDSlessThan(const KIO::UDSEntry &left, const KIO::UDSEntry &right);
0159 
0160   private:
0161     QSet<QString> excludeFiles;
0162     QSet<QString> excludeDirs;
0163 
0164     QString archiveName;
0165     QString filePrefix;  // default = "backup"
0166     QStringList sliceList;
0167     QString loadedProfile;
0168 
0169     struct archive *archive = nullptr;
0170     KIO::filesize_t totalBytes = 0;
0171     int totalFiles = 0;
0172     int filteredFiles = 0;  // filter or time filter (incremental backup)
0173     QElapsedTimer elapsed;
0174 
0175     QList<QRegExp> filters;
0176     QList<QRegExp> dirFilters;
0177 
0178     QUrl targetURL;
0179     QString baseName;
0180     int sliceNum = 0;
0181     int maxSliceMBs = Archiver::UNLIMITED;
0182     bool mediaNeedsChange = false;
0183 
0184     int numKeptBackups = Archiver::UNLIMITED;
0185     KIO::UDSEntryList targetDirList;
0186 
0187     QDateTime lastFullBackup;
0188     QDateTime lastBackup;
0189     int fullBackupInterval = 1;
0190     bool incrementalBackup = false;
0191     bool forceFullBackup = false;
0192 
0193     KIO::filesize_t sliceBytes = 0;
0194     KIO::filesize_t sliceCapacity = 0;
0195 
0196     QString ext;
0197     KCompressionDevice::CompressionType compressionType = KCompressionDevice::None;
0198 
0199     bool interactive;
0200     bool cancelled = false;
0201     bool runs = false;
0202     bool skippedFiles = false;  // did we skip files during backup ?
0203     bool verbose = false;
0204 
0205     QPointer<KIO::CopyJob> job;
0206     int jobResult = 0;
0207 };
0208 
0209 #endif