From 272456a31d0867f575e36a2462507816964bf39a Mon Sep 17 00:00:00 2001 From: zhaominyong Date: Tue, 17 Aug 2021 10:07:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backup-daemon/backup-daemon.pro | 6 +- backup-daemon/main.cpp | 4 + backup-daemon/mybackupmanager.cpp | 2 + backup-daemon/parsebackuplist.cpp | 330 ++++++++++++++++++++++++++++ backup-daemon/parsebackuplist.h | 85 +++++++ backup-daemon/systembackupproxy.cpp | 106 ++++++++- backup-daemon/systembackupproxy.h | 27 ++- backup-daemon/workerfactory.cpp | 4 +- backup-daemon/workerfactory.h | 2 +- common/mydefine.h | 15 +- common/mydusizetool.cpp | 113 ++++++++++ common/mydusizetool.h | 34 +++ common/utils.cpp | 104 +++++++-- common/utils.h | 15 +- yhkylin-backup-tool.pro.user | 292 ++++++++++++++++++++++++ 15 files changed, 1102 insertions(+), 37 deletions(-) create mode 100644 backup-daemon/parsebackuplist.cpp create mode 100644 backup-daemon/parsebackuplist.h create mode 100644 common/mydusizetool.cpp create mode 100644 common/mydusizetool.h create mode 100644 yhkylin-backup-tool.pro.user diff --git a/backup-daemon/backup-daemon.pro b/backup-daemon/backup-daemon.pro index 4ed5865..6e77156 100644 --- a/backup-daemon/backup-daemon.pro +++ b/backup-daemon/backup-daemon.pro @@ -1,6 +1,6 @@ QT += core QT -= gui -QT += dbus +QT += dbus xml CONFIG += c++11 console CONFIG -= app_bundle @@ -20,6 +20,7 @@ DEFINES += QT_DEPRECATED_WARNINGS HEADERS += \ ../common/mydefine.h \ + ../common/mydusizetool.h \ ../common/mylittleparse.h \ ../common/reflect.h \ ../common/singleton.h \ @@ -29,11 +30,13 @@ HEADERS += \ mybackupmanager.h \ mymountproxy.h \ myprocess/mountbackupprocess.h \ + parsebackuplist.h \ systembackupproxy.h \ workerfactory.h SOURCES += \ ../common/mydefine.cpp \ + ../common/mydusizetool.cpp \ ../common/mylittleparse.cpp \ ../common/reflect.cpp \ ../common/utils.cpp \ @@ -42,6 +45,7 @@ SOURCES += \ mybackupmanager.cpp \ mymountproxy.cpp \ myprocess/mountbackupprocess.cpp \ + parsebackuplist.cpp \ systembackupproxy.cpp \ workerfactory.cpp diff --git a/backup-daemon/main.cpp b/backup-daemon/main.cpp index fc9c4c2..a04a5b6 100644 --- a/backup-daemon/main.cpp +++ b/backup-daemon/main.cpp @@ -5,6 +5,7 @@ #include "backupmanager_adaptor.h" // test begin +#include #include "../common/reflect.h" #include "mymountproxy.h" // test end @@ -27,9 +28,12 @@ int main(int argc, char *argv[]) //MyMountProxy * proxy = (MyMountProxy*)Reflect::createObject("MyMountProxy"); //proxy->mountBackupPartition(); + qDebug() << QString("测试 begin"); BackupWrapper backupWrapper; MyBackupManager manager; manager.checkEnv(backupWrapper); + + qDebug() << QString("测试 end"); // test end MyBackupManager* backup_deamon = new MyBackupManager; diff --git a/backup-daemon/mybackupmanager.cpp b/backup-daemon/mybackupmanager.cpp index 5b48f9c..1e4d0de 100644 --- a/backup-daemon/mybackupmanager.cpp +++ b/backup-daemon/mybackupmanager.cpp @@ -63,6 +63,8 @@ int MyBackupManager::checkEnv(const BackupWrapper& backupWrapper) connect(&workerThread, &QThread::started, worker, &Worker::checkEnv); connect(&workerThread, &QThread::finished, worker, &Worker::deleteLater); + workerThread.start(); + return int(BackupResult::BACKUP_RESULT_INIT); } diff --git a/backup-daemon/parsebackuplist.cpp b/backup-daemon/parsebackuplist.cpp new file mode 100644 index 0000000..282e007 --- /dev/null +++ b/backup-daemon/parsebackuplist.cpp @@ -0,0 +1,330 @@ +#include "parsebackuplist.h" +#include +#include +#include +#include + +/* + + + + 21-07-21 14:14:01 + + {beecb746-561f-4fa1-99ba-19fb849a1ba7} + 24.26KB + backup finished + 2 + + +*/ + +#define BACKUPLIST "backupList" +#define BACKUPPOINT "BackupPoint" +#define COMMENT "Comment" +#define TIME "Time" +#define UUID "Uuid" +#define SIZE "Size" +#define STATE "State" +#define TYPE "Type" +#define POSITION "Position" +#define STATUE_BACKUP_FINESHED "backup finished" + +ParseBackupList::ParseBackupList(const QString& xmlPath) + : m_xmlPath(xmlPath) +{ + QFile xmlFile(m_xmlPath); + if (!xmlFile.exists() || 0 == xmlFile.size()) { + InitXml(); + } +} + +/** + * @brief 初始化xml文件 + * @return + */ +bool ParseBackupList::InitXml() +{ + QFile xmlFile(m_xmlPath); + if (!xmlFile.open(QIODevice::ReadWrite | QIODevice::Truncate)) + return false; + + QDomDocument doc; + + QDomProcessingInstruction ins = doc.createProcessingInstruction("xml", "version=\'1.0\'"); + doc.appendChild(ins); + + QDomElement root = doc.createElement(BACKUPLIST); + doc.appendChild(root); + + QTextStream out(&xmlFile); + doc.save(out, QDomNode::NodeType::CDATASectionNode); + + xmlFile.close(); + return true; +} + +/** + * @brief 校验xml格式是否正确 + * @return + */ +bool ParseBackupList::isXmlCorrect() +{ + QFile xmlFile(m_xmlPath); + if (!xmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "Open file " << m_xmlPath << " failure"; + return false; + } + QXmlStreamReader reader(&xmlFile); + while (!reader.atEnd()) { + if (reader.isStartElement()) { + } + reader.readNext(); + } + if (reader.hasError()) { + qDebug() << "xml parse error!"; + xmlFile.close(); + return false; + } + xmlFile.close(); + return true; +} + +/** + * @brief 读取xml文件 + * @param doc + * @return + */ +bool ParseBackupList::Doc_setContent(QDomDocument& doc) +{ + QFile xmlFile(m_xmlPath); + if (!xmlFile.open(QIODevice::ReadOnly)) { + qDebug() << " open backuplist.xml failed!"; + return false; + } + QString errStr; + int errLine; + int errCol; + + if (!doc.setContent(&xmlFile, false, &errStr, &errLine, &errCol)) { + qDebug() << QString("parse backuplist.xml error at line %1, column %2:%3").arg(errLine).arg(errCol).arg(errStr); + xmlFile.close(); + return false; + } + xmlFile.close(); + return true; +} + +/** + * @brief 出厂备份修改backuplist.xml,仅保留出厂备份信息 + * @param factoryBackupUuid,出厂备份的uuid + * @return ParseResult枚举类型 + * @author zhaominyong + * @since 2021/06/27 + */ +ParseBackupList::ParseResult ParseBackupList::updateForFactoryRestore(const QString& factoryBackupUuid) +{ + QDomDocument doc; + if (!Doc_setContent(doc)) + return XML_PARSE_ERR; + + QDomElement root = doc.documentElement(); + QDomNodeList list = root.childNodes(); + + for (int i = 0; i < list.count(); i++) { + QDomNode node = list.at(i); + if (!node.isElement()) + continue ; + QDomElement element = node.toElement(); + QDomNodeList nodes = element.elementsByTagName(UUID); + if (0 < nodes.count()) { + QDomElement uuidElement = nodes.at(0).toElement(); + QString tag = uuidElement.tagName(); + QString text = uuidElement.text(); + if (uuidElement.text() != factoryBackupUuid) { + root.removeChild(node); + --i; + } + } + } + + QFile xmlFile(m_xmlPath); + if (!xmlFile.open(QIODevice::WriteOnly)) { + qDebug() << "update state failed"; + return FAIL; + } + QTextStream out(&xmlFile); + doc.save(out, QDomNode::NodeType::EntityReferenceNode); + out.flush(); + xmlFile.close(); + return SUCCESS; +} + +/** + * @brief 根据comment查找uuid + * @param comment + * @return uuid + */ +QString ParseBackupList::findUuidByComment(const QString& comment) +{ + QDomDocument doc; + if (!Doc_setContent(doc)) + return ""; + + QDomElement root = doc.documentElement(); + QDomNodeList list = root.childNodes(); + + for (int i = 0; i < list.count(); i++) { + QDomNode node = list.at(i); + if (!node.isElement()) + continue; + + QDomElement eleComment = node.firstChildElement(COMMENT); + if (eleComment.isNull()) + continue; + + if (comment != eleComment.text()) + continue; + + QDomElement eleUuid = node.firstChildElement(UUID); + if (eleUuid.isNull()) + return ""; + + return eleUuid.text(); + } + + return ""; +} + +/** + * @brief 根据Uuid查找备份点信息 + * @param Uuid + * @return 备份点信息 + */ +ParseBackupList::BackupPoint ParseBackupList::findBackupPointByUuid(const QString& Uuid) +{ + BackupPoint backupPoint; + QDomDocument doc; + if (!Doc_setContent(doc)) + return backupPoint; + + QDomElement root = doc.documentElement(); + QDomNodeList list = root.childNodes(); + + for (int i = 0; i < list.count(); i++) { + QDomNode node = list.at(i); + if (!node.isElement()) + continue; + + QDomElement eleUuid = node.firstChildElement(UUID); + if (eleUuid.isNull() || Uuid != eleUuid.text()) + continue; + + elementNodeToBackupPoint(node.toElement(), backupPoint); + return backupPoint; + } + + return backupPoint; +} + +/** + * @brief 获取最后一次系统备份 + * @return + */ +ParseBackupList::BackupPoint ParseBackupList::getLastSysBackupPoint() +{ + BackupPoint backupPoint; + QDomDocument doc; + if (!Doc_setContent(doc)) + return backupPoint; + + QDomElement root = doc.documentElement(); + QDomNodeList list = root.childNodes(); + + for (int i = 0; i < list.count(); i++) { + QDomNode node = list.at(i); + if (!node.isElement()) + continue; + + QDomElement eleType = node.firstChildElement(TYPE); + if (eleType.isNull() || (BackupType::BACKUP_SYSTEM != eleType.text().toInt() && BackupType::INC_BACKUP_SYSTEM != eleType.text().toInt())) + continue; + + QDomElement eleState = node.firstChildElement(STATE); + QString type = eleState.text(); + if (eleState.isNull() || eleState.text() != QString(STATUE_BACKUP_FINESHED)) + continue; + + elementNodeToBackupPoint(node.toElement(), backupPoint); + } + + return backupPoint; +} + +/** + * @brief elementNode --> BackupPoint + * @param node, QDomElement + * @param backupPoint, BackupPoint + */ +void ParseBackupList::elementNodeToBackupPoint(const QDomElement& node, BackupPoint& backupPoint) +{ + QDomElement eleUuid = node.firstChildElement(UUID); + if (!eleUuid.isNull()) + backupPoint.m_uuid = eleUuid.text(); + + QDomElement eleComment = node.firstChildElement(COMMENT); + if (!eleComment.isNull()) + backupPoint.m_backupName = eleComment.text(); + + QDomElement eleTime = node.firstChildElement(TIME); + if (!eleTime.isNull()) + backupPoint.m_time = eleTime.text(); + + QDomElement eleSize = node.firstChildElement(SIZE); + if (!eleSize.isNull()) + backupPoint.m_size = eleSize.text(); + + QDomElement eleState = node.firstChildElement(STATE); + if (!eleState.isNull()) + backupPoint.m_state = eleState.text(); + + QDomElement eleType = node.firstChildElement(TYPE); + if (!eleType.isNull()) + backupPoint.m_type = eleType.text().toInt(); + + QDomElement elePosition = node.firstChildElement(POSITION); + if (!elePosition.isNull()) + backupPoint.m_iPosition = elePosition.text().toInt(); +} + +/** + * @brief backupPoint --> ElementNode + * @param backupPoint, BackupPoint + * @param node, QDomElement + */ +void ParseBackupList::backupPointToElementNode(const BackupPoint& backupPoint, QDomElement& node) +{ + node.appendChild(createTextElement(COMMENT, backupPoint.m_backupName)); + node.appendChild(createTextElement(TIME, backupPoint.m_time)); + node.appendChild(createTextElement(UUID, backupPoint.m_uuid)); + node.appendChild(createTextElement(SIZE, backupPoint.m_size)); + node.appendChild(createTextElement(STATE, backupPoint.m_state)); + node.appendChild(createTextElement(TYPE, QString::number(backupPoint.m_type))); + node.appendChild(createTextElement(POSITION, QString::number(backupPoint.m_iPosition))); +} + +/** + * @brief createTextElement + * @param tagName + * @param text + * @return text + */ +QDomElement ParseBackupList::createTextElement(const QString& tagName, const QString& text) +{ + QDomElement node; + node.setTagName(tagName); + QDomText textNode; + textNode.setData(text); + node.appendChild(textNode); + + return node; +} diff --git a/backup-daemon/parsebackuplist.h b/backup-daemon/parsebackuplist.h new file mode 100644 index 0000000..24350aa --- /dev/null +++ b/backup-daemon/parsebackuplist.h @@ -0,0 +1,85 @@ +#ifndef PARSEBACKUPLIST_H +#define PARSEBACKUPLIST_H + +#include +#include +#include +#include "../common/mydefine.h" + +class ParseBackupList { +public: + enum ParseResult { + // xml解析错误 + XML_PARSE_ERR, + // 失败 + FAIL, + // 成功 + SUCCESS, + }; + + struct BackupPoint { + // 备份或还原指定的UUID + QString m_uuid; + // 备份名称,用来替换m_comment + QString m_backupName; + // 备份时间 + QString m_time; + // 本地备份还是U盘备份: 0-本地备份;1-移动设备备份 + int m_iPosition = -1; + // 操作类型,如:系统备份, 系统还原 + int m_type = -1; + // 备份大小 + QString m_size; + // 备份状态,如是否完成 + QString m_state; + + bool isNull() { return m_uuid.isEmpty(); } + }; + + ParseBackupList(const QString& xmlPath); + + /** + * @brief 出厂备份修改backuplist.xml,仅保留出厂备份信息 + * @param factoryBackupUuid,出厂备份的uuid + * @return ParseResult枚举类型 + * @author zhaominyong + * @since 2021/06/27 + */ + ParseResult updateForFactoryRestore(const QString &factoryBackupUuid); + + /** + * @brief 根据comment查找uuid + * @param comment + * @return uuid + */ + QString findUuidByComment(const QString& comment); + + /** + * @brief 根据Uuid查找备份点信息 + * @param Uuid + * @return 备份点信息 + */ + BackupPoint findBackupPointByUuid(const QString& Uuid); + + /** + * @brief 获取最后一次系统备份 + * @return + */ + BackupPoint getLastSysBackupPoint(); + + inline QString getXmlPath() { return m_xmlPath; } + +private: + bool InitXml(); + bool isXmlCorrect(); + bool Doc_setContent(QDomDocument& doc); + + void elementNodeToBackupPoint(const QDomElement& eleNode, BackupPoint& backupPoint); + void backupPointToElementNode(const BackupPoint& backupPoint, QDomElement& eleNode); + QDomElement createTextElement(const QString& tagName, const QString& text); + +private: + QString m_xmlPath; +}; + +#endif // PARSEBACKUPLIST_H diff --git a/backup-daemon/systembackupproxy.cpp b/backup-daemon/systembackupproxy.cpp index 76cb40b..f0876ed 100644 --- a/backup-daemon/systembackupproxy.cpp +++ b/backup-daemon/systembackupproxy.cpp @@ -1,20 +1,40 @@ #include "systembackupproxy.h" +#include #include #include "../common/utils.h" +#include "../common/mydusizetool.h" +#include "mymountproxy.h" +#include "parsebackuplist.h" IMPLEMENT_DYNCREATE(SystemBackupProxy) -SystemBackupProxy::SystemBackupProxy(QObject * parent) : - Worker(parent) +SystemBackupProxy::SystemBackupProxy() {} SystemBackupProxy::~SystemBackupProxy() {} +/** + * @brief 环境检测 + */ void SystemBackupProxy::checkEnvEx() { qDebug() << "SystemBackupProxy::checkEnv invoke begin"; - emit checkResult((int)BackupResult::BACKUP_START_SUCCESS); + + // 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载 + MyMountProxy mountProxy; + if ( MyMountProxy::MountResult::MOUNTED != mountProxy.mountBackupPartition() ) { + emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL)); + return ; + } + + // 2、检测备份是否增量备份 + bool bInc = checkIsIncBackup(); + m_backupWrapper.m_bIncrement = bInc; + + // 3、检测空间是否满足备份 + checkFreeCapacity(bInc); + qDebug() << "SystemBackupProxy::checkEnv invoke end"; } @@ -24,3 +44,83 @@ void SystemBackupProxy::doWorkEx() void SystemBackupProxy::cancelEx() {} +/** + * @brief 校验是否增量备份 + * @return true,增量备份; false,全量备份 + */ +bool SystemBackupProxy::checkIsIncBackup() +{ + QString backupPath; + if (m_backupWrapper.m_uuid.isEmpty()) { + QString xmlPath(Utils::getSysRootPath() + BACKUP_XML_PATH); + xmlPath.replace("//", "/"); + ParseBackupList parser(xmlPath); + ParseBackupList::BackupPoint point = parser.getLastSysBackupPoint(); + if (point.m_uuid.isEmpty()) + return false; + backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + point.m_uuid + "/data"; + } else { + backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data"; + } + + backupPath.replace("//", "/"); + return Utils::isDirExist(backupPath); +} + +/** + * @brief 校验剩余空间是否满足备份 + * @param bInc,是否增量备份 + * @note 增量备份和全量备份计算空间方法不同 + */ +void SystemBackupProxy::checkFreeCapacity(bool bInc) +{ + // 1、计算待备份数据的大小 + MyDuSizeTool du; + qint64 itotalSize = du.Do(m_backupWrapper.m_backupPaths, m_backupWrapper.m_backupExcludePaths, true); + if (-1 == itotalSize) { + qCritical() << "du system backup failed"; + emit checkResult(int(BackupResult::DU_ERR)); + return ; + } + + // 2、计算备份分区剩余空间大小 + QString backupPath(Utils::getSysRootPath() + BACKUP_PATH); + backupPath.replace("//", "/"); + QStorageInfo backupDisk(backupPath); + qint64 freeSize = backupDisk.bytesFree(); +} + +/** + * @brief 根据场景获取rsync命令参数 + * @param scene,场景 + * @return rsync的参数信息 + */ +QStringList SystemBackupProxy::getRsyncArgs(SystemBackupScene scene) +{ + QStringList args; + + switch (scene) { + case SystemBackupScene::SYSTEM_BACKUP : + args << "-avAXW"; + args << "--progress"; + break ; + case SystemBackupScene::INC_SYSTEM_BACKUP : + args << "-avAXr"; + args << "--progress"; + args << "--link-dest"; + break ; + case SystemBackupScene::TRY_SYSTEM_BACKUP : + args << "-avAXWn"; + args << "--stats"; + break ; + case SystemBackupScene::TRY_INC_SYSTEM_BACKUP : + args << "-avAXrn"; + args << "--stats"; + args << "--link-dest"; + break ; + default: + } + + return args; +} + diff --git a/backup-daemon/systembackupproxy.h b/backup-daemon/systembackupproxy.h index 86b698b..23d67d0 100644 --- a/backup-daemon/systembackupproxy.h +++ b/backup-daemon/systembackupproxy.h @@ -8,7 +8,15 @@ class SystemBackupProxy : public Worker Q_OBJECT DECLARE_DYNCREATE(SystemBackupProxy) public: - SystemBackupProxy(QObject * parent = nullptr); + // 系统备份的几种场景 + enum SystemBackupScene { + SYSTEM_BACKUP, // 系统备份 + INC_SYSTEM_BACKUP, // 增量系统备份 + TRY_SYSTEM_BACKUP, // 测试系统备份,可用于计算备份传输数据大小 + TRY_INC_SYSTEM_BACKUP, // 测试增量系统备份,可用于计算备份传输数据大小 + }; + + explicit SystemBackupProxy(); virtual ~SystemBackupProxy(); public: @@ -20,6 +28,23 @@ public: // 任务取消 virtual void cancelEx(); + +private: + // 校验是否增量备份 + bool checkIsIncBackup(); + + // 校验剩余空间是否满足备份 + void checkFreeCapacity(bool bInc); + + /** + * @brief 根据场景获取rsync命令参数 + * @param scene,场景 + * @return 组装好的rsync的参数信息 + */ + QString getRsyncArgs(SystemBackupScene scene); + + // 是否增量备份 + bool m_bIncrement = false; }; #endif // SYSTEMBACKUPPROXY_H diff --git a/backup-daemon/workerfactory.cpp b/backup-daemon/workerfactory.cpp index 173281f..adddd60 100644 --- a/backup-daemon/workerfactory.cpp +++ b/backup-daemon/workerfactory.cpp @@ -1,8 +1,8 @@ #include "workerfactory.h" #include -Worker::Worker(QObject* parent) : - QObject(parent) +Worker::Worker() : + QObject(nullptr) {} Worker::~Worker() diff --git a/backup-daemon/workerfactory.h b/backup-daemon/workerfactory.h index 741007e..48468b7 100644 --- a/backup-daemon/workerfactory.h +++ b/backup-daemon/workerfactory.h @@ -12,7 +12,7 @@ class Worker : public QObject { Q_OBJECT public: - Worker(QObject* parent = nullptr); + explicit Worker(); virtual ~Worker(); signals: diff --git a/common/mydefine.h b/common/mydefine.h index 2b050ca..32cef9c 100644 --- a/common/mydefine.h +++ b/common/mydefine.h @@ -8,19 +8,16 @@ #define DEFAULT_APP_PATH "/usr/bin" -#define LOCK_FILE "/tmp/lock/kylin-backup.lock" - -#define BACKUP_XML_PATH "/backup/snapshots/backuplist.xml" - -#define BOOTINFO_PATH "/etc/.bootinfo" - #define BACKUP_PATH "/backup" - #define BACKUP_SNAPSHOTS_PATH "/backup/snapshots" - +#define BACKUP_XML_PATH "/backup/snapshots/backuplist.xml" #define EXCLUDE_FILE_PATH "/backup/snapshots/.exclude" +#define BOOTINFO_PATH "/etc/.bootinfo" #define FSTAB_PATH "/etc/fstab" +#define LOCK_FILE "/tmp/lock/kylin-backup.lock" +#define LOCK_FILE_PATH "/tmp/lock" +#define PROC_LOG "/var/log/backup.log" #define BACKUP_CLI_NAME "kybackup" @@ -83,6 +80,8 @@ struct BackupWrapper { int m_frontUid = -1; // 备份用户所属组id int m_gid = -1; + // 是否增量备份 + bool m_bIncrement = false; static void registerMetaType(); }; diff --git a/common/mydusizetool.cpp b/common/mydusizetool.cpp new file mode 100644 index 0000000..629cdc1 --- /dev/null +++ b/common/mydusizetool.cpp @@ -0,0 +1,113 @@ +#include "mydusizetool.h" +#include +#include "utils.h" + +MyDuSizeTool::MyDuSizeTool(QObject* parent) +{ + m_p = new QProcess(this); + connect(m_p, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus))); + connect(m_p, &QProcess::readyReadStandardError, this, [&]() { + QByteArray err = m_p->readAllStandardError(); + qCritical("du process error: %s", err.data()); + }); +} + +MyDuSizeTool::~MyDuSizeTool() +{ + delete m_p; +} + +/** + * @brief MyDuSizeTool::Do + * @param paths, du计算路径列表 + * @param excludePaths,du排查路径列表 + * @param block,bool, 是否阻塞方式计算 + * @return + */ +qint64 MyDuSizeTool::Do(QStringList paths, QStringList excludePaths, bool block) +{ + return _Do(paths, excludePaths, true, block); +} + +/** + * @brief MyDuSizeTool::_Do + * @param paths, du计算路径列表 + * @param excludePaths,du排查路径列表 + * @param needExclude,bool,是否需要排除 + * @param block,bool, 是否阻塞方式计算 + * @return + */ +qint64 MyDuSizeTool::_Do(QStringList paths, QStringList excludePaths, bool needExclude, bool block) +{ + Init(paths, excludePaths); + + if (paths.isEmpty()) { + qCritical("du paths is empty!"); + return -1; + } + if (needExclude && excludePaths.isEmpty()) { + qCritical("du excludepaths is empty!"); + return -1; + } + + QString cmd = "du"; + for (QString& x : paths) { + cmd.append(QString(" \"%1\"").arg(x)); + } + if (needExclude) { + for (QString& item : excludePaths) { + QString arg = QString(" --exclude=\"%1\"").arg(x); + cmd.append(arg); + } + } + + cmd.append(" -sb | tail -1 | awk -F \" \" '{print $1}'"); + + qDebug("cmd is %s", cmd.toStdString().c_str()); + + QStringList Args; + Args << "-c" << cmd; + m_p->start("bash", Args); + + if (!m_p->waitForStarted()) + return -1; + + if (block) { + if (!m_p->waitForFinished(-1)) { + return -1; + } + + return m_size; + } + + return 0; +} + +/** + * @brief MyDuSizeTool::Do + * @param paths, du计算路径列表 + * @param excludePaths,du排查路径列表 + * @param block,bool, 是否阻塞方式计算 + * @return + */ +qint64 MyDuSizeTool::Do(QStringList paths, bool block) +{ + return _Do(paths, {}, false, block); +} + +void MyDuSizeTool::Init(QStringList paths, QStringList excludePaths) +{ + m_paths = paths; + m_excludePaths = excludePaths; +} + +void MyDuSizeTool::finished(int, QProcess::ExitStatus) +{ + QString result = m_p->readAll(); + if (result.isEmpty()) + m_size = 0; + else + m_size = result.toLongLong(); + emit duFinished(m_size); +} + diff --git a/common/mydusizetool.h b/common/mydusizetool.h new file mode 100644 index 0000000..3bcc3f4 --- /dev/null +++ b/common/mydusizetool.h @@ -0,0 +1,34 @@ +#ifndef MYDUSIZETOOL_H +#define MYDUSIZETOOL_H + +#include +#include + +class MyDuSizeTool : public QObject { + Q_OBJECT +public: + MyDuSizeTool(QObject* parent = nullptr); + ~MyDuSizeTool(); + + qint64 Do(QStringList paths, QStringList excludePaths, bool block = true); + qint64 Do(QStringList paths, bool block = true); + qint64 size() { return m_size; } + +private: + void Init(QStringList paths, QStringList excludePaths); + qint64 _Do(QStringList paths, QStringList excludePaths, bool needExclude, bool block = true); + +signals: + void duFinished(qint64 size); +private slots: + void finished(int, QProcess::ExitStatus); + +private: + QStringList m_paths; + QStringList m_excludePaths; + qint64 m_size = 0; + + QProcess* m_p; +}; + +#endif // !MYDUSIZETOOL_H diff --git a/common/utils.cpp b/common/utils.cpp index 0c3d114..7e4e0e2 100644 --- a/common/utils.cpp +++ b/common/utils.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -66,13 +67,13 @@ void Utils::customMessageHandler(QtMsgType type, const QMessageLogContext& conte // 设置输出信息格式 QString strDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd"); - QString strMessage = strMsg + QString("DateTime:%1 Message:%2 File:%3(%4)") - .arg(strDateTime).arg(localMsg.constData()).arg(context.file).arg(context.line); + QString strMessage = strMsg + QString("DateTime:%1 ThreadId:%2 Message:%3 File:%4(%5)") + .arg(strDateTime).arg(QString::number(quintptr(QThread::currentThreadId()))).arg(localMsg.constData()).arg(context.file).arg(context.line); std::cout << strMessage.toUtf8().data() << std::endl; // 输出信息至文件中(读写、追加形式) - QString fileName = m_sysRootPath + "/var/log/backup.log"; + QString fileName = m_sysRootPath + PROC_LOG; fileName.replace("//", "/"); QFile file(fileName); file.open(QIODevice::ReadWrite | QIODevice::Append); @@ -91,10 +92,10 @@ void Utils::customMessageHandler(QtMsgType type, const QMessageLogContext& conte */ int Utils::lockProgram(int frontUid) { - QDir dir("/tmp/lock"); + QDir dir(LOCK_FILE_PATH); if (!dir.exists()) { - dir.mkdir("/tmp/lock"); - chmod("/tmp/lock", S_IRWXU | S_IRWXG | S_IRWXO); + dir.mkdir(LOCK_FILE_PATH); + chmod(LOCK_FILE_PATH, S_IRWXU | S_IRWXG | S_IRWXO); } int lock_file_fd = ::open(LOCK_FILE, O_CREAT | O_RDWR, 0666); @@ -169,7 +170,7 @@ bool Utils::checkBootInfoExists() /** * @brief 获取备份分区的UUID - * @return + * @return 备份分区的UUID */ QString Utils::getBackupPartitionUuid() { @@ -252,7 +253,7 @@ void Utils::excludeFstabBindPath(QStringList &excludes) } /** - * @brief 生成rsync --exclude路径规则文件 + * @brief 生成rsync --exclude-from排除路径规则文件 * @return */ bool Utils::generateExcludePathsFile() @@ -270,25 +271,25 @@ bool Utils::generateExcludePathsFile() QTextStream in(&excludePathFile); in << "/backup" << endl; //分区 in << "/boot/efi" << endl; + in << "/cdrom" << endl; + in << "/dev" << endl; // efi原始目录在/boot/efi,备份到目标目录为/efi下,再还原时已经单独处理了,批量还原时应该屏蔽此目录 in << "/efi" << endl; - in << "/dev/*" << endl; - in << "/ghost" << endl; //ghost镜像文件 - in << "/mnt/*" << endl; - in << "/proc/*" << endl; - in << "/run/*" << endl; - in << "/sys/*" << endl; //添加*,表示如果/sys目录不存在,则会拷贝/sys,但不会拷贝/sys下的内容 - in << "/media/*" << endl; - in << "/tmp/*" << endl; - in << "/lost+found/*" << endl; - in << "/var/lib/udisks2/*" << endl; - in << "/cdrom/*" << endl; - in << "/swap_file" << endl; // 安全模块会将文件/usr/share/kysec-utils/data/readonly_list中的文件列表限制只读,无法修改、备份(包含扩展属性时)、删除等 // 现在里面仅有/etc/uid_list,先暂时排除掉;等后续安全模块有其它保护方案后再进一步修改 in << "/etc/uid_list" << endl; + in << "/ghost" << endl; //ghost镜像文件 + in << "/lost+found" << endl; + in << "/media" << endl; + in << "/mnt" << endl; + in << "/proc" << endl; + in << "/run" << endl; + in << "/swap_file" << endl; + in << "/sys" << endl; //添加*(/sys/*),表示如果/sys目录不存在,则会拷贝/sys,但不会拷贝/sys下的内容 + in << "/tmp" << endl; // 安卓兼容的这个里面很多文件都是设置了特殊扩展文件属性,lsetxattr无法设置成功,听取安卓兼容模块同事的意见不用管这个文件夹,其实是从home下挂载的 in << "/var/lib/kmre" << endl; + in << "/var/lib/udisks2" << endl; in << "/var/log" << endl; // 系统安装后有的会将/data/home /data/root挂载到的/home /root上,实际文件是存放在/data/home /data/root下面 @@ -302,3 +303,66 @@ bool Utils::generateExcludePathsFile() excludePathFile.close(); return true; } + +/** + * @brief 判断目录是否存在 + * @param 目录路径 + * @return true,存在;false,不存在 + */ +bool Utils::isDirExist(const QString& fullDirName) +{ + QDir dir(fullDirName); + if (dir.exists()) + return true; + return false; +} + +/** + * @brief 获取系统备份还原排除路径列表, rsync --exclude-from排除路径规则文件中读取 + * @return 系统备份还原排除路径列表 + */ +QStringList Utils::getFromExcludePathsFile() +{ + QString excludeFile = Utils::m_sysRootPath + EXCLUDE_FILE_PATH; + excludeFile.replace("//", "/"); + QFile excludePathFile(excludeFile); + if (!excludePathFile.open(QIODevice::ReadOnly)) { + QStringList list; + list << "/backup"; + list << "/boot/efi"; + list << "/cdrom"; + list << "/dev"; + list << "/efi"; + list << "/etc/uid_list"; + list << "/ghost"; + list << "/lost+found"; + list << "/media"; + list << "/mnt"; + list << "/proc"; + list << "/run"; + list << "/swap_file"; + list << "/sys"; + list << "/tmp"; + list << "/var/lib/kmre"; + list << "/var/lib/udisks2"; + list << "/var/log"; + + // 系统安装后有的会将/data/home /data/root挂载到的/home /root上,实际文件是存放在/data/home /data/root下面 + QStringList excludes; + Utils::excludeFstabBindPath(excludes); + for (const QString& item : excludes) { + list << item; + } + + return list; + } + + QTextStream out(&excludePathFile); + QString strAll = out.readAll(); + excludePathFile.close(); + + QStringList list = strAll.split("\n"); + list.removeAll(QString("")); + + return list; +} diff --git a/common/utils.h b/common/utils.h index 1582f6d..9243605 100644 --- a/common/utils.h +++ b/common/utils.h @@ -87,11 +87,24 @@ public: static void excludeFstabBindPath(QStringList &excludes); /** - * @brief 生成rsync --exclude路径规则文件 + * @brief 生成rsync --exclude-from排除路径规则文件 * @return */ static bool generateExcludePathsFile(); + /** + * @brief 获取系统备份还原排除路径列表 + * @return 系统备份还原排除路径列表 + */ + static QStringList getFromExcludePathsFile(); + + /** + * @brief 判断目录是否存在 + * @param 目录路径 + * @return true,存在;false,不存在 + */ + static bool isDirExist(const QString& fullDirName); + private: // 系统根目录,默认"/" static QString m_sysRootPath; diff --git a/yhkylin-backup-tool.pro.user b/yhkylin-backup-tool.pro.user new file mode 100644 index 0000000..d30b5e5 --- /dev/null +++ b/yhkylin-backup-tool.pro.user @@ -0,0 +1,292 @@ + + + + + + EnvironmentId + {d6d3c1b3-be59-4e12-87de-c60657210d67} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + + ProjectExplorer.Project.Target.0 + + 桌面 + 桌面 + {5440484b-1916-43f8-99de-3fbc4fe13c66} + 0 + 0 + 0 + + /home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug + + + true + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + 1 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:/home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/backup-daemon/backup-daemon.pro + /home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/backup-daemon/backup-daemon.pro + + false + + false + true + true + false + false + true + + /home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug/backup-daemon + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:/home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/kybackup/kybackup.pro + /home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/kybackup/kybackup.pro + + false + + false + true + true + false + false + true + + /home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug/kybackup + + 2 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + +