yhkylin-backup-tools/backup-daemon/parsebackuplist.cpp

606 lines
17 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "parsebackuplist.h"
#include <QFile>
#include <QTextStream>
#include <QXmlStreamReader>
#include <QDebug>
#include <algorithm>
/*
<?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>
<Position>0</Position>
<UserId>1000</UserId>
<PrefixDestPath>/</PrefixDestPath>
</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 USERID "UserId"
#define OS "OS"
#define ARCH "Arch"
#define ARCHDETECT "ArchDetect"
#define PREFIXDESTPATH "PrefixDestPath"
#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 ParseBackupList::BackupPoint::operator <
* @param other
* @return
*/
bool ParseBackupList::BackupPoint::operator < (const BackupPoint &other)
{
return other.m_time > this->m_time;
}
/**
* @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 获取xml文件中备份点uuid和backupname的映射
* @param uuid_namexml文件中备份点uuid和backupname的映射
* @return
*/
void ParseBackupList::getXmlUuidNameMap(QMap<QString, QString> &uuid_name)
{
BackupPoint backupPoint;
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 eleUuid = node.firstChildElement(UUID);
if (eleUuid.isNull() || eleUuid.text().isEmpty())
continue;
QDomElement eleBackupName = node.firstChildElement(COMMENT);
if (eleBackupName.isNull() || eleBackupName.text().isEmpty())
continue;
uuid_name.insert(eleUuid.text(), eleBackupName.text());
}
return ;
}
/**
* @brief 获取自定义备份路径列表
* @param customizePaths
*/
void ParseBackupList::getCustomizePaths(QStringList &customizePaths)
{
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 elePrefixPath = node.firstChildElement(PREFIXDESTPATH);
if (!elePrefixPath.isNull()) {
QString prefixPath = elePrefixPath.text() + BACKUP_SNAPSHOTS_PATH;
prefixPath.replace("//", "/");
if (!customizePaths.contains(prefixPath))
customizePaths << prefixPath;
}
}
}
/**
* @brief 获取最后一次系统备份,排除自动备份点、自定义备份点
* @return
* @note 经过测试发现出厂备份点也不能作为基准点进行增量,因为出厂备份的安全标记和其它不同,咨询安全同事说解决不了。所以也排除出厂备份。
*/
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 eleUuid = node.firstChildElement(UUID);
if (eleUuid.isNull() || eleUuid.text() == AUTO_BACKUP_UUID || eleUuid.text() == FACTORY_BACKUP_UUID)
continue;
QDomElement eleState = node.firstChildElement(STATE);
if (eleState.isNull() || eleState.text() != QString(STATUE_BACKUP_FINESHED))
continue;
QDomElement elePosition = node.firstChildElement(POSITION);
if (!elePosition.isNull() && elePosition.text().toInt() == BackupPosition::CUSTOMIZE)
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();
if (backupPoint.m_uuid == FACTORY_BACKUP_UUID)
backupPoint.m_backupName = QObject::tr("factory backup");
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() && !elePosition.text().isEmpty())
backupPoint.m_iPosition = elePosition.text().toInt();
QDomElement eleUserId = node.firstChildElement(USERID);
if (!eleUserId.isNull())
backupPoint.m_userId = eleUserId.text();
QDomElement eleOS = node.firstChildElement(OS);
if (!eleOS.isNull())
backupPoint.m_os = eleOS.text();
QDomElement eleArch = node.firstChildElement(ARCH);
if (!eleArch.isNull())
backupPoint.m_arch = eleArch.text();
QDomElement eleArchDetect = node.firstChildElement(ARCHDETECT);
if (!eleArchDetect.isNull())
backupPoint.m_archdetect = eleArchDetect.text();
QDomElement elePrefixPath = node.firstChildElement(PREFIXDESTPATH);
if (!elePrefixPath.isNull()) {
backupPoint.m_path = elePrefixPath.text();
} else {
backupPoint.m_path = m_xmlPath;
backupPoint.m_path.replace(BACKUP_XML_PATH, "");
}
}
/**
* @brief backupPoint --> ElementNode
* @param backupPoint, BackupPoint
* @param node, QDomElement
*/
void ParseBackupList::backupPointToElementNode(const BackupPoint& backupPoint, QDomDocument& doc, QDomNode& node)
{
node.appendChild(createTextElement(doc, COMMENT, backupPoint.m_backupName));
node.appendChild(createTextElement(doc, TIME, backupPoint.m_time));
node.appendChild(createTextElement(doc, UUID, backupPoint.m_uuid));
node.appendChild(createTextElement(doc, SIZE, backupPoint.m_size));
node.appendChild(createTextElement(doc, STATE, backupPoint.m_state));
node.appendChild(createTextElement(doc, TYPE, QString::number(backupPoint.m_type)));
node.appendChild(createTextElement(doc, POSITION, QString::number(backupPoint.m_iPosition)));
if (!backupPoint.m_userId.isEmpty()) {
node.appendChild(createTextElement(doc, USERID, backupPoint.m_userId));
}
if (!backupPoint.m_os.isEmpty()) {
node.appendChild(createTextElement(doc, OS, backupPoint.m_os));
}
if (!backupPoint.m_arch.isEmpty()) {
node.appendChild(createTextElement(doc, ARCH, backupPoint.m_arch));
}
if (!backupPoint.m_archdetect.isEmpty()) {
node.appendChild(createTextElement(doc, ARCHDETECT, backupPoint.m_archdetect));
}
if (!backupPoint.m_path.isEmpty()) {
node.appendChild(createTextElement(doc, PREFIXDESTPATH, backupPoint.m_path));
}
}
/**
* @brief createTextElement
* @param tagName
* @param text
* @return <tagName>text</tagName>
*/
QDomElement ParseBackupList::createTextElement(QDomDocument& doc, const QString& tagName, const QString& text)
{
QDomElement node = doc.createElement(tagName);
QDomText textNode = doc.createTextNode(text);
node.appendChild(textNode);
return node;
}
/**
* @brief 新增备份节点
* @param backupPoint, 备份点信息
* @return SUCCESS成功 XML_PARSE_ERR失败
*/
ParseBackupList::ParseResult ParseBackupList::addItem(const BackupPoint& backupPoint)
{
QDomDocument doc;
if (!Doc_setContent(doc))
return XML_PARSE_ERR;
QDomElement backupPointNode = doc.createElement(BACKUPPOINT);
backupPointToElementNode(backupPoint, doc, backupPointNode);
QDomElement root = doc.documentElement();
root.appendChild(backupPointNode);
QFile xmlFile(m_xmlPath);
if (!xmlFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
return FAIL;
QTextStream out(&xmlFile);
doc.save(out, QDomNode::NodeType::CDATASectionNode);
xmlFile.close();
return SUCCESS;
}
/**
* @brief 更新备份点信息
* @param backupPoint新的备份点信息
* @return SUCCESS成功 XML_PARSE_ERR失败
*/
ParseBackupList::ParseResult ParseBackupList::updateItem(const BackupPoint & backupPoint)
{
QDomDocument doc;
if (!Doc_setContent(doc))
return XML_PARSE_ERR;
QDomElement root = doc.documentElement();
QDomNodeList list = root.childNodes();
int i = 0;
for (; i < list.count(); i++) {
QDomNode node = list.at(i);
if (!node.isElement())
continue;
QDomElement eleUuid = node.firstChildElement(UUID);
if (eleUuid.isNull() || backupPoint.m_uuid != eleUuid.text())
continue;
break ;
}
// 找到了旧节点
if (i < list.count()) {
// 移除旧节点,更新后的节点放到最后
root.removeChild(list.at(i));
}
QDomElement newNode = doc.createElement(BACKUPPOINT);
backupPointToElementNode(backupPoint, doc, newNode);
root.appendChild(newNode);
QFile xmlFile(m_xmlPath);
if (!xmlFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
return FAIL;
}
QTextStream out(&xmlFile);
doc.save(out, QDomNode::NodeType::EntityReferenceNode);
xmlFile.close();
return SUCCESS;
}
/**
* @brief 删除备份点记录
* @param uuid
* @return SUCCESS成功 XML_PARSE_ERR失败
*/
ParseBackupList::ParseResult ParseBackupList::deleteItem(const QString& uuid)
{
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 eleUuid = node.firstChildElement(UUID);
if (eleUuid.isNull() || uuid != eleUuid.text())
continue;
root.removeChild(node);
break ;
}
QFile xmlFile(m_xmlPath);
if (!xmlFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
return FAIL;
}
QTextStream out(&xmlFile);
doc.save(out, QDomNode::NodeType::EntityReferenceNode);
xmlFile.close();
return SUCCESS;
}
/**
* @brief 获取备份列表
* @return
*/
QList<ParseBackupList::BackupPoint> ParseBackupList::getBackupPointList()
{
QList<ParseBackupList::BackupPoint> backupPointList;
QDomDocument doc;
if (!Doc_setContent(doc))
return backupPointList;
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())
continue;
BackupPoint backupPoint;
elementNodeToBackupPoint(node.toElement(), backupPoint);
backupPointList << backupPoint;
}
// std::sort(backupPointList.begin(), backupPointList.end());
return backupPointList;
}