This commit is contained in:
zhaominyong 2021-08-17 10:07:35 +08:00
parent 1d634ef885
commit 272456a31d
15 changed files with 1102 additions and 37 deletions

View File

@ -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

View File

@ -5,6 +5,7 @@
#include "backupmanager_adaptor.h"
// test begin
#include <QDebug>
#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;

View File

@ -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);
}

View File

@ -0,0 +1,330 @@
#include "parsebackuplist.h"
#include <QFile>
#include <QTextStream>
#include <QXmlStreamReader>
#include <QDebug>
/*
<?xml version='1.0'?>
<backupList>
<BackupPoint>
<Comment>21-07-21 14:14:01</Comment>
<Time>21-07-21 14:14:03</Time>
<Uuid>{beecb746-561f-4fa1-99ba-19fb849a1ba7}</Uuid>
<Size>24.26KB</Size>
<State>backup finished</State>
<Type>2</Type>
</BackupPoint>
</backupList>
*/
#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 factoryBackupUuiduuid
* @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 <tagName>text</tagName>
*/
QDomElement ParseBackupList::createTextElement(const QString& tagName, const QString& text)
{
QDomElement node;
node.setTagName(tagName);
QDomText textNode;
textNode.setData(text);
node.appendChild(textNode);
return node;
}

View File

@ -0,0 +1,85 @@
#ifndef PARSEBACKUPLIST_H
#define PARSEBACKUPLIST_H
#include <QString>
#include <QDomDocument>
#include <QDomElement>
#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 factoryBackupUuiduuid
* @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

View File

@ -1,20 +1,40 @@
#include "systembackupproxy.h"
#include <QStorageInfo>
#include <QDebug>
#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;
}

View File

@ -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

View File

@ -1,8 +1,8 @@
#include "workerfactory.h"
#include <QString>
Worker::Worker(QObject* parent) :
QObject(parent)
Worker::Worker() :
QObject(nullptr)
{}
Worker::~Worker()

View File

@ -12,7 +12,7 @@ class Worker : public QObject
{
Q_OBJECT
public:
Worker(QObject* parent = nullptr);
explicit Worker();
virtual ~Worker();
signals:

View File

@ -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();
};

113
common/mydusizetool.cpp Normal file
View File

@ -0,0 +1,113 @@
#include "mydusizetool.h"
#include <QDebug>
#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 excludePathsdu排查路径列表
* @param blockbool,
* @return
*/
qint64 MyDuSizeTool::Do(QStringList paths, QStringList excludePaths, bool block)
{
return _Do(paths, excludePaths, true, block);
}
/**
* @brief MyDuSizeTool::_Do
* @param paths, du计算路径列表
* @param excludePathsdu排查路径列表
* @param needExcludebool
* @param blockbool,
* @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 excludePathsdu排查路径列表
* @param blockbool,
* @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);
}

34
common/mydusizetool.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef MYDUSIZETOOL_H
#define MYDUSIZETOOL_H
#include <QObject>
#include <QProcess>
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

View File

@ -5,6 +5,7 @@
#include <QTextStream>
#include <QDir>
#include <QRegularExpression>
#include <QThread>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
@ -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;
}

View File

@ -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;

View File

@ -0,0 +1,292 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.0, 2021-08-16T15:03:50. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{d6d3c1b3-be59-4e12-87de-c60657210d67}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">桌面</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">桌面</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{5440484b-1916-43f8-99de-3fbc4fe13c66}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.BuildTargets"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
<value type="bool" key="Qt4ProjectManager.MakeStep.OverrideMakeflags">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
<value type="QString">cpu-cycles</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
<value type="int" key="Analyzer.Perf.Frequency">250</value>
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
<value type="QString">-e</value>
<value type="QString">cpu-cycles</value>
<value type="QString">--call-graph</value>
<value type="QString">dwarf,4096</value>
<value type="QString">-F</value>
<value type="QString">250</value>
</valuelist>
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/backup-daemon/backup-daemon.pro</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/backup-daemon/backup-daemon.pro</value>
<value type="QString" key="RunConfiguration.Arguments"></value>
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug/backup-daemon</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.1">
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
<value type="QString">cpu-cycles</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
<value type="int" key="Analyzer.Perf.Frequency">250</value>
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
<value type="QString">-e</value>
<value type="QString">cpu-cycles</value>
<value type="QString">--call-graph</value>
<value type="QString">dwarf,4096</value>
<value type="QString">-F</value>
<value type="QString">250</value>
</valuelist>
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:/home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/kybackup/kybackup.pro</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/zhaominyong/workspace/kylin-backup-tools-new/kylin-backup-tools-4.0.14/kybackup/kybackup.pro</value>
<value type="QString" key="RunConfiguration.Arguments"></value>
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/zhaominyong/workspace/kylin-backup-tools-new/build-yhkylin-backup-tool-unknown-Debug/kybackup</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>