Import Upstream version 4.1.0.1
|
@ -0,0 +1,7 @@
|
|||
# Kylin Backup Tools
|
||||
|
||||
1、对备份还原工具4.0.13版本进行了重构
|
||||
2、界面和流程对比4.0.13版本全都发送了变化
|
||||
3、适配UKui3.1界面风格
|
||||
4、新增了一些功能或对原功能进行了优化
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
QT += core
|
||||
QT -= gui
|
||||
QT += dbus xml
|
||||
|
||||
CONFIG += c++11 console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
CONFIG += link_pkgconfig
|
||||
|
||||
LIBS += -lblkid \
|
||||
-lkysec
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any Qt feature that has been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
QMAKE_CXXFLAGS += -Wno-implicit-fallthrough
|
||||
|
||||
HEADERS += \
|
||||
../common/mydefine.h \
|
||||
../common/mydusizetool.h \
|
||||
../common/mylittleparse.h \
|
||||
../common/reflect.h \
|
||||
../common/singleton.h \
|
||||
../common/spinlock_mutex.h \
|
||||
../common/utils.h \
|
||||
backupmanager_adaptor.h \
|
||||
customizedatabackupproxy.h \
|
||||
customizeghostImageproxy.h \
|
||||
customizesystembackupproxy.h \
|
||||
customizesystemrestoreproxy.h \
|
||||
databackupproxy.h \
|
||||
datarestoreproxy.h \
|
||||
deletebackupproxy.h \
|
||||
ghostimageproxy.h \
|
||||
mybackupmanager.h \
|
||||
mymountproxy.h \
|
||||
myprocess/calcbackupsize.h \
|
||||
myprocess/mksquashfsprocess.h \
|
||||
myprocess/mountbackupprocess.h \
|
||||
myprocess/rsyncpathtodirprocess.h \
|
||||
mythread.h \
|
||||
parsebackuplist.h \
|
||||
systembackupproxy.h \
|
||||
systemrestoreproxy.h \
|
||||
udiskdatabackupproxy.h \
|
||||
udiskdatarestoreproxy.h \
|
||||
udiskghostImageproxy.h \
|
||||
udisksystembackupproxy.h \
|
||||
udisksystemrestoreproxy.h \
|
||||
workerfactory.h
|
||||
|
||||
SOURCES += \
|
||||
../common/mydefine.cpp \
|
||||
../common/mydusizetool.cpp \
|
||||
../common/mylittleparse.cpp \
|
||||
../common/reflect.cpp \
|
||||
../common/utils.cpp \
|
||||
backupmanager_adaptor.cpp \
|
||||
customizedatabackupproxy.cpp \
|
||||
customizeghostImageproxy.cpp \
|
||||
customizesystembackupproxy.cpp \
|
||||
customizesystemrestoreproxy.cpp \
|
||||
databackupproxy.cpp \
|
||||
datarestoreproxy.cpp \
|
||||
deletebackupproxy.cpp \
|
||||
ghostimageproxy.cpp \
|
||||
main.cpp \
|
||||
mybackupmanager.cpp \
|
||||
mymountproxy.cpp \
|
||||
myprocess/calcbackupsize.cpp \
|
||||
myprocess/mksquashfsprocess.cpp \
|
||||
myprocess/mountbackupprocess.cpp \
|
||||
myprocess/rsyncpathtodirprocess.cpp \
|
||||
mythread.cpp \
|
||||
parsebackuplist.cpp \
|
||||
systembackupproxy.cpp \
|
||||
systemrestoreproxy.cpp \
|
||||
udiskdatabackupproxy.cpp \
|
||||
udiskdatarestoreproxy.cpp \
|
||||
udiskghostImageproxy.cpp \
|
||||
udisksystembackupproxy.cpp \
|
||||
udisksystemrestoreproxy.cpp \
|
||||
workerfactory.cpp
|
||||
|
||||
# Default rules for deployment.
|
||||
# qnx: target.path = /tmp/$${TARGET}/bin
|
||||
# else: unix:!android: target.path = /usr/bin
|
||||
# !isEmpty(target.path): INSTALLS += target
|
||||
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* This file was generated by qdbusxml2cpp version 0.8
|
||||
* Command line was: qdbusxml2cpp com.kylin.backup.manager.xml -i mybackupmanager.h -a ManagerAdaptor
|
||||
*
|
||||
* qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd.
|
||||
*
|
||||
* This is an auto-generated file.
|
||||
* Do not edit! All changes made to it will be lost.
|
||||
*/
|
||||
|
||||
#include "backupmanager_adaptor.h"
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
/*
|
||||
* Implementation of adaptor class ManagerAdaptor
|
||||
*/
|
||||
|
||||
ManagerAdaptor::ManagerAdaptor(QObject *parent)
|
||||
: QDBusAbstractAdaptor(parent)
|
||||
{
|
||||
// constructor
|
||||
setAutoRelaySignals(true);
|
||||
}
|
||||
|
||||
ManagerAdaptor::~ManagerAdaptor()
|
||||
{
|
||||
// destructor
|
||||
}
|
||||
|
||||
int ManagerAdaptor::Mount_backup_partition()
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.Mount_backup_partition
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "Mount_backup_partition", Q_RETURN_ARG(int, out0));
|
||||
return out0;
|
||||
}
|
||||
|
||||
bool ManagerAdaptor::umountBackupPartition()
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.umountBackupPartition
|
||||
bool out0;
|
||||
QMetaObject::invokeMethod(parent(), "umountBackupPartition", Q_RETURN_ARG(bool, out0));
|
||||
return out0;
|
||||
}
|
||||
|
||||
void ManagerAdaptor::autoBackUpForSystemUpdate_noreturn(const QString &autobackup_name, const QString &create_note, const QString &inc_note, const QString &frontUserName, int frontUid)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.autoBackUpForSystemUpdate_noreturn
|
||||
QMetaObject::invokeMethod(parent(), "autoBackUpForSystemUpdate_noreturn", Q_ARG(QString, autobackup_name), Q_ARG(QString, create_note), Q_ARG(QString, inc_note), Q_ARG(QString, frontUserName), Q_ARG(int, frontUid));
|
||||
}
|
||||
|
||||
int ManagerAdaptor::checkEnv(BackupWrapper backupWrapper)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.checkEnv
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "checkEnv", Q_RETURN_ARG(int, out0), Q_ARG(BackupWrapper, backupWrapper));
|
||||
return out0;
|
||||
}
|
||||
|
||||
int ManagerAdaptor::deleteBackupPoint(BackupWrapper backupWrapper)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.deleteBackupPoint
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "deleteBackupPoint", Q_RETURN_ARG(int, out0), Q_ARG(BackupWrapper, backupWrapper));
|
||||
return out0;
|
||||
}
|
||||
|
||||
QString ManagerAdaptor::getBackupCommentForSystemUpdate(QString &state)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.getBackupCommentForSystemUpdate
|
||||
//return static_cast<YourObjectType *>(parent())->getBackupCommentForSystemUpdate(state);
|
||||
QString out0;
|
||||
QMetaObject::invokeMethod(parent(), "getBackupCommentForSystemUpdate", Q_RETURN_ARG(QString, out0), Q_ARG(QString&, state));
|
||||
return out0;
|
||||
}
|
||||
|
||||
int ManagerAdaptor::getBackupState(bool &isActive)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.getBackupState
|
||||
//return static_cast<YourObjectType *>(parent())->getBackupState(isActive);
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "getBackupState", Q_RETURN_ARG(int, out0), Q_ARG(bool&, isActive));
|
||||
return out0;
|
||||
}
|
||||
|
||||
int ManagerAdaptor::ghostBackup(BackupWrapper backupWrapper)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.ghostBackup
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "ghostBackup", Q_RETURN_ARG(int, out0), Q_ARG(BackupWrapper, backupWrapper));
|
||||
return out0;
|
||||
}
|
||||
|
||||
int ManagerAdaptor::goBackup(BackupWrapper backupWrapper)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.goBackup
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "goBackup", Q_RETURN_ARG(int, out0), Q_ARG(BackupWrapper, backupWrapper));
|
||||
return out0;
|
||||
}
|
||||
|
||||
int ManagerAdaptor::goRestore(BackupWrapper backupWrapper)
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.goRestore
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "goRestore", Q_RETURN_ARG(int, out0), Q_ARG(BackupWrapper, backupWrapper));
|
||||
return out0;
|
||||
}
|
||||
|
||||
int ManagerAdaptor::cancel()
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.cancel
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "cancel", Q_RETURN_ARG(int, out0));
|
||||
return out0;
|
||||
}
|
||||
|
||||
int ManagerAdaptor::reboot()
|
||||
{
|
||||
// handle method call com.kylin.backup.manager.reboot
|
||||
int out0;
|
||||
QMetaObject::invokeMethod(parent(), "reboot", Q_RETURN_ARG(int, out0));
|
||||
return out0;
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* This file was generated by qdbusxml2cpp version 0.8
|
||||
* Command line was: qdbusxml2cpp com.kylin.backup.manager.xml -i mybackupmanager.h -a ManagerAdaptor
|
||||
*
|
||||
* qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd.
|
||||
*
|
||||
* This is an auto-generated file.
|
||||
* This file may have been hand-edited. Look for HAND-EDIT comments
|
||||
* before re-generating it.
|
||||
*/
|
||||
|
||||
#ifndef MANAGERADAPTOR_H
|
||||
#define MANAGERADAPTOR_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtDBus/QtDBus>
|
||||
#include "mybackupmanager.h"
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QByteArray;
|
||||
template<class T> class QList;
|
||||
template<class Key, class Value> class QMap;
|
||||
class QString;
|
||||
class QStringList;
|
||||
class QVariant;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
/*
|
||||
* Adaptor class for interface com.kylin.backup.manager
|
||||
*/
|
||||
class ManagerAdaptor: public QDBusAbstractAdaptor
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "com.kylin.backup.manager")
|
||||
Q_CLASSINFO("D-Bus Introspection", ""
|
||||
" <interface name=\"com.kylin.backup.manager\">\n"
|
||||
" <signal name=\"sendEnvCheckResult\">\n"
|
||||
" <arg direction=\"out\" type=\"i\" name=\"result\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"sendStartBackupResult\">\n"
|
||||
" <arg direction=\"out\" type=\"i\" name=\"result\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"sendBackupResult\">\n"
|
||||
" <arg direction=\"out\" type=\"b\" name=\"result\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"sendRate\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"sendRestoreResult\">\n"
|
||||
" <arg direction=\"out\" type=\"b\" name=\"result\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"sendDeleteResult\">\n"
|
||||
" <arg direction=\"out\" type=\"b\" name=\"result\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"sendGhostBackupResult\">\n"
|
||||
" <arg direction=\"out\" type=\"b\" name=\"result\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"backupFinished\">\n"
|
||||
" <arg direction=\"out\" type=\"b\" name=\"result\"/>\n"
|
||||
" </signal>\n"
|
||||
" <signal name=\"progress\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" </signal>\n"
|
||||
" <method name=\"Mount_backup_partition\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"umountBackupPartition\">\n"
|
||||
" <arg direction=\"out\" type=\"b\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"autoBackUpForSystemUpdate_noreturn\">\n"
|
||||
" <arg direction=\"in\" type=\"s\" name=\"autobackup_name\"/>\n"
|
||||
" <arg direction=\"in\" type=\"s\" name=\"create_note\"/>\n"
|
||||
" <arg direction=\"in\" type=\"s\" name=\"inc_note\"/>\n"
|
||||
" <arg direction=\"in\" type=\"s\" name=\"frontUserName\"/>\n"
|
||||
" <arg direction=\"in\" type=\"i\" name=\"frontUid\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"getBackupCommentForSystemUpdate\">\n"
|
||||
" <arg direction=\"out\" type=\"s\"/>\n"
|
||||
" <arg direction=\"out\" type=\"s\" name=\"state\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"getBackupState\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <arg direction=\"out\" type=\"b\" name=\"isActive\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"checkEnv\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <annotation value=\"BackupWrapper\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
|
||||
" <arg direction=\"in\" type=\"a(i)\" name=\"backupWrapper\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"goBackup\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <annotation value=\"BackupWrapper\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
|
||||
" <arg direction=\"in\" type=\"a(i)\" name=\"backupWrapper\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"goRestore\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <annotation value=\"BackupWrapper\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
|
||||
" <arg direction=\"in\" type=\"a(i)\" name=\"backupWrapper\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"deleteBackupPoint\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <annotation value=\"BackupWrapper\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
|
||||
" <arg direction=\"in\" type=\"a(i)\" name=\"backupWrapper\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"ghostBackup\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" <annotation value=\"BackupWrapper\" name=\"org.qtproject.QtDBus.QtTypeName.In0\"/>\n"
|
||||
" <arg direction=\"in\" type=\"a(i)\" name=\"backupWrapper\"/>\n"
|
||||
" </method>\n"
|
||||
" <method name=\"cancel\">\n"
|
||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
||||
" </method>\n"
|
||||
" </interface>\n"
|
||||
"")
|
||||
public:
|
||||
ManagerAdaptor(QObject *parent);
|
||||
virtual ~ManagerAdaptor();
|
||||
|
||||
public: // PROPERTIES
|
||||
public Q_SLOTS: // METHODS
|
||||
int Mount_backup_partition();
|
||||
bool umountBackupPartition();
|
||||
void autoBackUpForSystemUpdate_noreturn(const QString &autobackup_name, const QString &create_note, const QString &inc_note, const QString &frontUserName, int frontUid);
|
||||
int checkEnv(BackupWrapper backupWrapper);
|
||||
int deleteBackupPoint(BackupWrapper backupWrapper);
|
||||
QString getBackupCommentForSystemUpdate(QString &state);
|
||||
int getBackupState(bool &isActive);
|
||||
int ghostBackup(BackupWrapper backupWrapper);
|
||||
int goBackup(BackupWrapper backupWrapper);
|
||||
int goRestore(BackupWrapper backupWrapper);
|
||||
int cancel();
|
||||
int reboot();
|
||||
Q_SIGNALS: // SIGNALS
|
||||
void backupFinished(bool result);
|
||||
void progress(int in0, int in1);
|
||||
void sendBackupResult(bool result);
|
||||
void sendDeleteResult(bool result);
|
||||
void sendEnvCheckResult(int result);
|
||||
void sendGhostBackupResult(bool result);
|
||||
void sendRate(int in0, int in1);
|
||||
void sendRestoreResult(bool result);
|
||||
void sendStartBackupResult(int result);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node>
|
||||
<interface name="com.kylin.backup.manager">
|
||||
<signal name="sendEnvCheckResult">
|
||||
<arg name="result" type="i" direction="out"/>
|
||||
</signal>
|
||||
<signal name="sendStartBackupResult">
|
||||
<arg name="result" type="i" direction="out"/>
|
||||
</signal>
|
||||
<signal name="sendBackupResult">
|
||||
<arg name="result" type="b" direction="out"/>
|
||||
</signal>
|
||||
<signal name="sendRate">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg type="i" direction="out"/>
|
||||
</signal>
|
||||
<signal name="sendRestoreResult">
|
||||
<arg name="result" type="b" direction="out"/>
|
||||
</signal>
|
||||
<signal name="sendDeleteResult">
|
||||
<arg name="result" type="b" direction="out"/>
|
||||
</signal>
|
||||
<signal name="sendGhostBackupResult">
|
||||
<arg name="result" type="b" direction="out"/>
|
||||
</signal>
|
||||
<method name="Mount_backup_partition">
|
||||
<arg type="i" direction="out"/>
|
||||
</method>
|
||||
<method name="autoBackUpForSystemUpdate_noreturn">
|
||||
<arg name="autobackup_name" type="s" direction="in"/>
|
||||
<arg name="create_note" type="s" direction="in"/>
|
||||
<arg name="inc_note" type="s" direction="in"/>
|
||||
<arg name="frontUserName" type="s" direction="in"/>
|
||||
<arg name="frontUid" type="i" direction="in"/>
|
||||
</method>
|
||||
<method name="getBackupCommentForSystemUpdate">
|
||||
<arg type="s" direction="out"/>
|
||||
<arg name="state" type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="getBackupState">
|
||||
<arg type="i" direction="out"/>
|
||||
<arg name="isActive" type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="checkEnv">
|
||||
<arg type="i" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BackupWrapper"/>
|
||||
<arg name="backupWrapper" type="a(i)" direction="in"/>
|
||||
</method>
|
||||
<method name="goBackup">
|
||||
<arg type="i" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BackupWrapper"/>
|
||||
<arg name="backupWrapper" type="a(i)" direction="in"/>
|
||||
</method>
|
||||
<method name="goRestore">
|
||||
<arg type="i" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BackupWrapper"/>
|
||||
<arg name="backupWrapper" type="a(i)" direction="in"/>
|
||||
</method>
|
||||
<method name="deleteBackupPoint">
|
||||
<arg type="i" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BackupWrapper"/>
|
||||
<arg name="backupWrapper" type="a(i)" direction="in"/>
|
||||
</method>
|
||||
<method name="ghostBackup">
|
||||
<arg type="i" direction="out"/>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="BackupWrapper"/>
|
||||
<arg name="backupWrapper" type="a(i)" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
|
@ -0,0 +1,484 @@
|
|||
#include "customizedatabackupproxy.h"
|
||||
#include <QStorageInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <kysec/status.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(CustomizeDataBackupProxy)
|
||||
|
||||
CustomizeDataBackupProxy::CustomizeDataBackupProxy()
|
||||
{
|
||||
m_isOnlyCheck = true;
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_p = nullptr;
|
||||
m_size = 0;
|
||||
m_calc = new CalcBackupSize(this);
|
||||
|
||||
connect(this, &CustomizeDataBackupProxy::cancel, this, &CustomizeDataBackupProxy::cancelEx);
|
||||
}
|
||||
|
||||
CustomizeDataBackupProxy::~CustomizeDataBackupProxy()
|
||||
{
|
||||
delete m_p;
|
||||
m_p = nullptr;
|
||||
|
||||
delete m_calc;
|
||||
m_calc = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool CustomizeDataBackupProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "CustomizeDataBackupProxy::checkEnv invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
MyMountProxy mountProxy;
|
||||
MountResult result = mountProxy.mountBackupPartition();
|
||||
// 无备份分区
|
||||
if (MountResult::CANNOT_GET_BACKUPUUID == result) {
|
||||
qInfo() << "There is no backup partition!";
|
||||
|
||||
QString snapshotsPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH;
|
||||
snapshotsPath.replace("//", "/");
|
||||
Utils::mkpath(snapshotsPath);
|
||||
Utils::generateExcludePathsFile();
|
||||
} else if (MountResult::MOUNTED != result) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupWrapper.m_prefixDestPath)) {
|
||||
qCritical() << QString("dstDir %s is not exist!").arg(m_backupWrapper.m_prefixDestPath);
|
||||
Utils::mkpath(m_backupWrapper.m_prefixDestPath);
|
||||
}
|
||||
|
||||
// 因为有可能是选择的移动设备,故进行校验移动设备情况:空间大小、文件格式、挂载模式等
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo udisk(backupPath);
|
||||
QString udisk_type = udisk.fileSystemType();
|
||||
qDebug() << "udisk's filesystemtype is " << udisk_type;
|
||||
if (udisk_type == "vfat") {
|
||||
qCritical() << m_backupWrapper.m_prefixDestPath + " udisk's filesystemtype is vfat";
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT));
|
||||
return false;
|
||||
}
|
||||
if (udisk.isReadOnly()) {
|
||||
// 只读挂载的U盘
|
||||
qCritical() << QString("udisk(%s) is readonly filesystem").arg(m_backupWrapper.m_prefixDestPath);
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_IS_READONLY));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、判断备份是否增量备份
|
||||
isIncBackup();
|
||||
|
||||
// 3、检测空间是否满足备份
|
||||
calcSizeForBackup();
|
||||
|
||||
qDebug() << "CustomizeDataBackupProxy::checkEnv invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行备份逻辑
|
||||
*/
|
||||
void CustomizeDataBackupProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "CustomizeDataBackupProxy::doWorkEx invoke begin";
|
||||
|
||||
m_isOnlyCheck = false;
|
||||
// 环境检测
|
||||
checkEnvEx();
|
||||
|
||||
qDebug() << "CustomizeDataBackupProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消操作
|
||||
*/
|
||||
void CustomizeDataBackupProxy::cancelEx()
|
||||
{
|
||||
qDebug() << "CustomizeDataBackupProxy::cancelEx invoke begin";
|
||||
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_calc)
|
||||
m_calc->stop();
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
|
||||
qDebug() << "CustomizeDataBackupProxy::cancelEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void CustomizeDataBackupProxy::deleteFailedData()
|
||||
{
|
||||
if (m_curUuid.isEmpty())
|
||||
return;
|
||||
|
||||
// 1、删除备份目录
|
||||
QString destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid;
|
||||
destPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-rf";
|
||||
args << destPath;
|
||||
QProcess::execute("rm", args);
|
||||
|
||||
// 2、删除xml文件中的备份项
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.deleteItem(m_curUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否增量备份
|
||||
* @return true,增量备份; false,全量备份
|
||||
*/
|
||||
bool CustomizeDataBackupProxy::isIncBackup()
|
||||
{
|
||||
QString backupPath;
|
||||
ParseBackupList::BackupPoint point;
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
}
|
||||
|
||||
backupPath.replace("//", "/");
|
||||
if (Utils::isDirExist(backupPath)) {
|
||||
m_backupWrapper.m_bIncrement = true;
|
||||
m_backupWrapper.m_type = BackupType::INC_BACKUP_DATA;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验剩余空间是否满足备份
|
||||
*/
|
||||
bool CustomizeDataBackupProxy::checkFreeCapacity(qint64 itotalSize)
|
||||
{
|
||||
qDebug() << "CustomizeDataBackupProxy::checkFreeCapacity invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return false;
|
||||
|
||||
// 1、计算待备份数据的大小
|
||||
m_size = itotalSize;
|
||||
// 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留5M的空间
|
||||
itotalSize += 5 * MB;
|
||||
|
||||
// 2、计算备份分区剩余空间大小
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo backupDisk(backupPath);
|
||||
qint64 freeSize = backupDisk.bytesAvailable();
|
||||
|
||||
// 3、校验空间是否足够
|
||||
bool result = true;
|
||||
if (itotalSize > freeSize) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
result = false;
|
||||
return result;
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
}
|
||||
|
||||
if (m_isOnlyCheck)
|
||||
return result;
|
||||
|
||||
// 开始备份
|
||||
doBackup();
|
||||
|
||||
qDebug() << "CustomizeDataBackupProxy::checkFreeCapacity invoke end";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算备份所需空间大小
|
||||
* @return 计算备份所需空间大小,单位字节
|
||||
*/
|
||||
void CustomizeDataBackupProxy::calcSizeForBackup()
|
||||
{
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(CustomizeDataBackupScene::TRY_INC_DATA_BACKUP);
|
||||
destPath = m_backupWrapper.m_prefixDestPath;
|
||||
destPath += BACKUP_SNAPSHOTS_PATH;
|
||||
destPath += "/";
|
||||
destPath += m_backupWrapper.m_uuid;
|
||||
destPath += "/data/";
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(CustomizeDataBackupScene::TRY_DATA_BACKUP);
|
||||
destPath += CHECK_PATH;
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
Utils::mkpath(destPath);
|
||||
|
||||
connect(m_calc, &CalcBackupSize::finished, this, &CustomizeDataBackupProxy::checkFreeCapacity);
|
||||
m_calc->start(args, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return rsync的参数信息
|
||||
*/
|
||||
QStringList CustomizeDataBackupProxy::getRsyncArgs(CustomizeDataBackupScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
QString backupFile = "/tmp/.backup.user";
|
||||
Utils::writeFileByLines(backupFile, m_backupWrapper.m_backupPaths);
|
||||
|
||||
switch (scene) {
|
||||
case CustomizeDataBackupScene::DATA_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
case CustomizeDataBackupScene::INC_DATA_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
case CustomizeDataBackupScene::TRY_DATA_BACKUP :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
case CustomizeDataBackupScene::TRY_INC_DATA_BACKUP :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份
|
||||
*/
|
||||
void CustomizeDataBackupProxy::doBackup()
|
||||
{
|
||||
qDebug() << "CustomizeDataBackupProxy::doBackup invoke begin";
|
||||
|
||||
// 准备
|
||||
if (!doPrepare())
|
||||
return ;
|
||||
|
||||
// 启动数据备份
|
||||
backupData();
|
||||
|
||||
qDebug() << "CustomizeDataBackupProxy::doBackup invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份准备
|
||||
* @return true,准备成功;false,准备失败
|
||||
*/
|
||||
bool CustomizeDataBackupProxy::doPrepare()
|
||||
{
|
||||
qDebug() << "CustomizeDataBackupProxy::doPrepare invoke begin";
|
||||
|
||||
m_bSuccess = false;
|
||||
|
||||
// 1、设置当前备份的Uuid
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
// 新增备份点,不指定uuid的场景
|
||||
m_curUuid += Utils::createUuid();
|
||||
} else {
|
||||
// 指定uuid备份的场景
|
||||
m_curUuid = m_backupWrapper.m_uuid;
|
||||
}
|
||||
|
||||
// 2、准备备份目录及文件
|
||||
m_destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data";
|
||||
m_destPath.replace("//", "/");
|
||||
if (!Utils::mkpath(m_destPath)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE;
|
||||
m_userFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(m_userFile, m_backupWrapper.m_backupPaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(m_userFile) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
m_excludeUserFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(m_excludeUserFile, m_backupWrapper.m_backupExcludePaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(m_excludeUserFile) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、记录/backup/snapshots/backuplist.xml文件
|
||||
if (!recordBackupPoint()) {
|
||||
qCritical() << "add or update item to backuplist.xml failed !";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "CustomizeDataBackupProxy::doPrepare invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool CustomizeDataBackupProxy::recordBackupPoint()
|
||||
{
|
||||
m_backupPoint.m_backupName = m_backupWrapper.m_backupName;
|
||||
m_backupPoint.m_uuid = m_curUuid;
|
||||
m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition;
|
||||
m_backupPoint.m_type = m_backupWrapper.m_type;
|
||||
m_backupPoint.m_size = Utils::StringBySize(m_size);
|
||||
m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING;
|
||||
if (0 < m_backupWrapper.m_frontUid)
|
||||
m_backupPoint.m_userId = QString::number(m_backupWrapper.m_frontUid);
|
||||
m_backupPoint.m_os = SystemInfo::m_os;
|
||||
m_backupPoint.m_arch = SystemInfo::m_arch;
|
||||
m_backupPoint.m_archdetect = SystemInfo::m_archDetect;
|
||||
m_backupPoint.m_path = m_backupWrapper.m_prefixDestPath;
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份系统
|
||||
* @return true,备份成功;false,备份失败
|
||||
*/
|
||||
bool CustomizeDataBackupProxy::backupData()
|
||||
{
|
||||
qDebug() << "CustomizeDataBackupProxy::backupData invoke begin";
|
||||
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(CustomizeDataBackupScene::INC_DATA_BACKUP);
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(CustomizeDataBackupScene::DATA_BACKUP);
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
QString destPath = m_destPath + "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &CustomizeDataBackupProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING;
|
||||
m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath));
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.updateItem(m_backupPoint);
|
||||
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(m_backupPoint.m_time + ","
|
||||
+ m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
+ m_backupWrapper.m_note + "," + m_backupPoint.m_size
|
||||
+ "," + QString::number(m_backupWrapper.m_frontUid)
|
||||
+ "," + m_backupWrapper.m_backupName);
|
||||
Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
|
||||
emit this->workResult(result);
|
||||
});
|
||||
m_p->start(args, false);
|
||||
|
||||
do_kylin_security(m_destPath);
|
||||
|
||||
qDebug() << "CustomizeDataBackupProxy::backupData invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
void CustomizeDataBackupProxy::do_kylin_security(const QString& dstDir)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = kysec_getstatus();
|
||||
if (ret > 0) {
|
||||
QString seFilePath(dstDir + "/.exectl");
|
||||
QFile file(seFilePath);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef CUSTOMIZEDATABACKUPPROXY_H
|
||||
#define CUSTOMIZEDATABACKUPPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class CustomizeDataBackupProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(CustomizeDataBackupProxy)
|
||||
public:
|
||||
// 系统备份的几种场景
|
||||
enum CustomizeDataBackupScene {
|
||||
DATA_BACKUP, // 系统备份
|
||||
INC_DATA_BACKUP, // 增量系统备份
|
||||
TRY_DATA_BACKUP, // 测试系统备份,可用于计算备份传输数据大小
|
||||
TRY_INC_DATA_BACKUP, // 测试增量系统备份,可用于计算备份传输数据大小
|
||||
};
|
||||
|
||||
explicit CustomizeDataBackupProxy();
|
||||
virtual ~CustomizeDataBackupProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
public slots:
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private slots:
|
||||
// 校验剩余空间是否满足备份
|
||||
bool checkFreeCapacity(qint64 itotalSize);
|
||||
|
||||
// 备份
|
||||
void doBackup();
|
||||
|
||||
private:
|
||||
// 计算备份所需空间大小
|
||||
void calcSizeForBackup();
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool recordBackupPoint();
|
||||
|
||||
// 备份准备
|
||||
bool doPrepare();
|
||||
|
||||
// 备份系统
|
||||
bool backupData();
|
||||
|
||||
protected:
|
||||
// 判断是否增量备份
|
||||
bool isIncBackup();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(CustomizeDataBackupScene scene);
|
||||
|
||||
void do_kylin_security(const QString& dstDir);
|
||||
|
||||
// 失败则删除相应数据
|
||||
virtual void deleteFailedData();
|
||||
|
||||
// 计算备份空间大小的进程
|
||||
CalcBackupSize *m_calc;
|
||||
// 是否只是检测
|
||||
bool m_isOnlyCheck;
|
||||
// 是否完成
|
||||
bool m_isFinished;
|
||||
// 是否成功
|
||||
bool m_bSuccess;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前备份目标目录
|
||||
QString m_destPath;
|
||||
// 当前备份所需空间大小
|
||||
qint64 m_size;
|
||||
// 备份点用户备份路径文件
|
||||
QString m_userFile;
|
||||
// 备份点排除备份路径文件
|
||||
QString m_excludeUserFile;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
};
|
||||
|
||||
#endif // CUSTOMIZEDATABACKUPPROXY_H
|
|
@ -0,0 +1,240 @@
|
|||
#include "customizeghostImageproxy.h"
|
||||
#include <QStorageInfo>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <kysec/status.h>
|
||||
#include <unistd.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(CustomizeGhostImageProxy)
|
||||
|
||||
CustomizeGhostImageProxy::CustomizeGhostImageProxy()
|
||||
{
|
||||
m_p = nullptr;
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_isForce = false;
|
||||
|
||||
connect(this, &CustomizeGhostImageProxy::cancel, this, &CustomizeGhostImageProxy::cancelEx);
|
||||
}
|
||||
|
||||
CustomizeGhostImageProxy::~CustomizeGhostImageProxy()
|
||||
{
|
||||
// 不成功则删除中间文件
|
||||
if (!m_bSuccess) {
|
||||
deleteFailedData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
*/
|
||||
bool CustomizeGhostImageProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "CustomizeGhostImageProxy::checkEnvEx invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
MyMountProxy mountProxy;
|
||||
MountResult result = mountProxy.mountBackupPartition();
|
||||
// 无备份分区
|
||||
if (MountResult::CANNOT_GET_BACKUPUUID == result) {
|
||||
qInfo() << "There is no backup partition!";
|
||||
|
||||
QString snapshotsPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH;
|
||||
snapshotsPath.replace("//", "/");
|
||||
Utils::mkpath(snapshotsPath);
|
||||
Utils::generateExcludePathsFile();
|
||||
} else if (MountResult::MOUNTED != result) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、校验backuppoint.xml中相应的备份节点是否存在
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList xmlParse(xmlPath);
|
||||
m_backupPoint = xmlParse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (m_backupPoint.m_backupName.isEmpty()) {
|
||||
emit checkResult(int(BackupResult::GHOST_CANNOT_FIND_BACKUPPOINT));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、校验备份数据是否存在
|
||||
m_srcPath = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
m_srcPath.replace("//", "/");
|
||||
if (Utils::isDirEmpty(m_srcPath)) {
|
||||
emit checkResult(int(BackupResult::GHOST_SRC_DIRECTORY_IS_NOT_EXIST));
|
||||
return false;
|
||||
}
|
||||
m_imgDst = m_srcPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
|
||||
if (!Utils::filsExists(m_imgDst)) {
|
||||
emit checkResult(int(BackupResult::GHOST_SRC_DIRECTORY_IS_NOT_EXIST));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4、校验空间是否充足
|
||||
qint64 itotalSize = Utils::getDirOrFileSize(m_srcPath);
|
||||
m_destPath = m_backupWrapper.m_prefixDestPath + GHOST_PATH;
|
||||
m_destPath.replace("//", "/");
|
||||
Utils::mkpath(m_destPath);
|
||||
m_kyimg = m_destPath + "/" + m_backupWrapper.m_backupName;
|
||||
m_kyimg.replace("//", "/");
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
QStorageInfo storageInfo(m_destPath);
|
||||
qint64 sizeAvailable = storageInfo.bytesAvailable();
|
||||
if (sizeAvailable <= itotalSize) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
return false;
|
||||
}
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "CustomizeGhostImageProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务处理
|
||||
*/
|
||||
void CustomizeGhostImageProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "CustomizeGhostImageProxy::doWorkEx invoke begin";
|
||||
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
doGhostImage();
|
||||
|
||||
qDebug() << "CustomizeGhostImageProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务取消
|
||||
*/
|
||||
void CustomizeGhostImageProxy::cancelEx()
|
||||
{
|
||||
qDebug() << "CustomizeGhostImageProxy::cancelEx invoke begin";
|
||||
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
|
||||
qDebug() << "CustomizeGhostImageProxy::cancelEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void CustomizeGhostImageProxy::deleteFailedData()
|
||||
{
|
||||
// 1、删除临时镜像文件
|
||||
QFile kyimg(m_destPath + "/" + UDISK_MKSQUASHFS_IMG_NAME);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
|
||||
// 2、删除目标镜像文件
|
||||
if (!m_kyimg.isEmpty()) {
|
||||
QFile kyimgDest(m_kyimg);
|
||||
if (kyimgDest.exists())
|
||||
kyimgDest.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ghost镜像
|
||||
*/
|
||||
void CustomizeGhostImageProxy::doGhostImage()
|
||||
{
|
||||
qDebug() << "CustomizeGhostImageProxy::doGhostImage invoke begin";
|
||||
|
||||
// 同步到U盘
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &CustomizeGhostImageProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool resultRsync) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isForce = false;
|
||||
m_isFinished = true;
|
||||
if (resultRsync) {
|
||||
// 文件更名
|
||||
QString imgFileName = m_destPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
|
||||
if (Utils::filsExists(imgFileName)) {
|
||||
QStringList args;
|
||||
args << imgFileName;
|
||||
args << m_kyimg;
|
||||
QProcess::execute("mv", args);
|
||||
|
||||
chown(m_kyimg.toLocal8Bit().data(), m_backupWrapper.m_frontUid, m_backupWrapper.m_gid);
|
||||
m_bSuccess = true;
|
||||
resultRsync = true;
|
||||
} else {
|
||||
resultRsync = false;
|
||||
}
|
||||
}
|
||||
|
||||
emit this->workResult(resultRsync);
|
||||
});
|
||||
|
||||
QStringList arguments;
|
||||
arguments << "-av";
|
||||
arguments << "--info=progress2";
|
||||
arguments << m_imgDst;
|
||||
arguments << m_destPath + "/";
|
||||
|
||||
QTimer::singleShot(1*1000, this, &CustomizeGhostImageProxy::checkDestDirExists);
|
||||
m_p->start(arguments, false);
|
||||
|
||||
qDebug() << "CustomizeGhostImageProxy::doGhostImage invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验移动盘是否还在
|
||||
* @return: bool,存在返回true;不存在返回false
|
||||
* @author: zhaominyong
|
||||
* @since: 2021/05/24
|
||||
* @note:
|
||||
* add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据
|
||||
*/
|
||||
bool CustomizeGhostImageProxy::checkDestDirExists()
|
||||
{
|
||||
if (!m_isFinished)
|
||||
{
|
||||
// 拔掉U盘后,没有响应的场景(怀疑可能是某应用程序关闭引起,希望不是dbus服务关掉了)
|
||||
if (m_isForce) {
|
||||
emit this->workResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupWrapper.m_prefixDestPath)) {
|
||||
qCritical() << QString("dstDir %s is not exist!").arg(m_backupWrapper.m_prefixDestPath);
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
// 10s钟后如果还没有退出,则强制退出
|
||||
QTimer::singleShot(10*1000, this, &CustomizeGhostImageProxy::checkDestDirExists);
|
||||
m_isForce = true;
|
||||
} else {
|
||||
QTimer::singleShot(1*1000, this, &CustomizeGhostImageProxy::checkDestDirExists);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef CUSTOMIZEGHOSTIMAGEPROXY_H
|
||||
#define CUSTOMIZEGHOSTIMAGEPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class CustomizeGhostImageProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(CustomizeGhostImageProxy)
|
||||
public:
|
||||
explicit CustomizeGhostImageProxy();
|
||||
virtual ~CustomizeGhostImageProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private:
|
||||
void doGhostImage();
|
||||
bool checkDestDirExists();
|
||||
void deleteFailedData();
|
||||
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
|
||||
// 存放.kyimg文件的目录
|
||||
QString m_destPath;
|
||||
// .kyimg文件
|
||||
QString m_kyimg;
|
||||
// 源文件dst.img文件所在目录
|
||||
QString m_srcPath;
|
||||
// dst.img文件
|
||||
QString m_imgDst;
|
||||
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
|
||||
// 是否成功
|
||||
bool m_bSuccess;
|
||||
// 是否结束
|
||||
bool m_isFinished;
|
||||
// 强制结束标志(stop后没反应的情况,系统处于睡眠状态)
|
||||
bool m_isForce;
|
||||
};
|
||||
|
||||
#endif // CUSTOMIZEGHOSTIMAGEPROXY_H
|
|
@ -0,0 +1,400 @@
|
|||
#include "customizesystembackupproxy.h"
|
||||
|
||||
#include <QStorageInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <kysec/status.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(CustomizeSystemBackupProxy)
|
||||
|
||||
CustomizeSystemBackupProxy::CustomizeSystemBackupProxy()
|
||||
{
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_size = 0;
|
||||
m_calc = new CalcBackupSize(this);
|
||||
m_isOnlyCheck = true;
|
||||
m_mksquashfs = nullptr;
|
||||
|
||||
connect(this, &CustomizeSystemBackupProxy::cancel, this, &CustomizeSystemBackupProxy::cancelEx);
|
||||
}
|
||||
|
||||
CustomizeSystemBackupProxy::~CustomizeSystemBackupProxy()
|
||||
{
|
||||
delete m_calc;
|
||||
m_calc = nullptr;
|
||||
|
||||
delete m_mksquashfs;
|
||||
m_mksquashfs = nullptr;
|
||||
|
||||
// 如果备份失败,则删除备份数据
|
||||
if (!m_bSuccess) {
|
||||
deleteFailedData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return
|
||||
*/
|
||||
bool CustomizeSystemBackupProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "CustomizeSystemBackupProxy::checkEnv invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载。
|
||||
MyMountProxy mountProxy;
|
||||
MountResult result = mountProxy.mountBackupPartition();
|
||||
// 无备份分区
|
||||
if (MountResult::CANNOT_GET_BACKUPUUID == result) {
|
||||
qInfo() << "There is no backup partition!";
|
||||
|
||||
QString snapshotsPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH;
|
||||
snapshotsPath.replace("//", "/");
|
||||
Utils::mkpath(snapshotsPath);
|
||||
Utils::generateExcludePathsFile();
|
||||
} else if (MountResult::MOUNTED != result) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupWrapper.m_prefixDestPath)) {
|
||||
qCritical() << QString("dstDir %s is not exist!").arg(m_backupWrapper.m_prefixDestPath);
|
||||
Utils::mkpath(m_backupWrapper.m_prefixDestPath);
|
||||
}
|
||||
|
||||
// 因为有可能是选择的移动设备,故进行校验移动设备情况:空间大小、文件格式、挂载模式等
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo udisk(backupPath);
|
||||
QString udisk_type = udisk.fileSystemType();
|
||||
qDebug() << "udisk's filesystemtype is " << udisk_type;
|
||||
if (udisk_type == "vfat") {
|
||||
qCritical() << m_backupWrapper.m_prefixDestPath + " udisk's filesystemtype is vfat";
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT));
|
||||
return false;
|
||||
}
|
||||
if (udisk.isReadOnly()) {
|
||||
// 只读挂载的U盘
|
||||
qCritical() << QString("udisk(%s) is readonly filesystem").arg(m_backupWrapper.m_prefixDestPath);
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_IS_READONLY));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、计算备份大小
|
||||
calcSizeForBackup();
|
||||
|
||||
qDebug() << "CustomizeSystemBackupProxy::checkEnv invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行备份逻辑
|
||||
*/
|
||||
void CustomizeSystemBackupProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "CustomizeSystemBackupProxy::doWorkEx invoke begin";
|
||||
|
||||
m_isOnlyCheck = false;
|
||||
// 环境检测
|
||||
checkEnvEx();
|
||||
|
||||
qDebug() << "CustomizeSystemBackupProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
void CustomizeSystemBackupProxy::cancelEx()
|
||||
{
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_calc)
|
||||
m_calc->stop();
|
||||
if (m_mksquashfs)
|
||||
m_mksquashfs->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void CustomizeSystemBackupProxy::deleteFailedData()
|
||||
{
|
||||
if (m_curUuid.isEmpty())
|
||||
return;
|
||||
|
||||
// 1、删除备份目录
|
||||
QString destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid;
|
||||
destPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-rf";
|
||||
args << destPath;
|
||||
QProcess::execute("rm", args);
|
||||
|
||||
// 2、删除xml文件中的备份项
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.deleteItem(m_curUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验剩余空间是否满足备份
|
||||
*/
|
||||
void CustomizeSystemBackupProxy::checkFreeCapacity(qint64 itotalSize)
|
||||
{
|
||||
qDebug() << "CustomizeSystemBackupProxy::checkFreeCapacity invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
// 1、计算待备份数据的大小
|
||||
m_size = itotalSize;
|
||||
// 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留500M的空间
|
||||
itotalSize += 500 * MB;
|
||||
// 判断是否需要先压缩成img文件,压缩后一般小于原大小的70%
|
||||
itotalSize = itotalSize * 7 / 10;
|
||||
|
||||
// 2、计算备份分区剩余空间大小
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo backupDisk(backupPath);
|
||||
qint64 freeSize = backupDisk.bytesAvailable();
|
||||
|
||||
// 3、校验空间是否足够
|
||||
if (itotalSize > freeSize) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
return ;
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
}
|
||||
|
||||
if (m_isOnlyCheck)
|
||||
return ;
|
||||
|
||||
// 4、准备
|
||||
if (!doPrepare())
|
||||
return ;
|
||||
|
||||
// 5、开始制作img
|
||||
doMksqushfs();
|
||||
|
||||
qDebug() << "CustomizeSystemBackupProxy::checkFreeCapacity invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算备份所需空间大小
|
||||
* @return 计算备份所需空间大小,单位字节
|
||||
*/
|
||||
void CustomizeSystemBackupProxy::calcSizeForBackup()
|
||||
{
|
||||
// 拼接备份源路径和目标路径,测试所需备份空间大小;目标路径为一虚拟路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
destPath += CHECK_PATH;
|
||||
destPath.replace("//", "/");
|
||||
Utils::mkpath(destPath);
|
||||
|
||||
QStringList args = getRsyncArgs(CustomizeSystemBackupScene::TRY_SYSTEM_BACKUP);
|
||||
args << srcPath;
|
||||
args << destPath;
|
||||
|
||||
connect(m_calc, &CalcBackupSize::finished, this, &CustomizeSystemBackupProxy::checkFreeCapacity);
|
||||
m_calc->start(args, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return rsync的参数信息
|
||||
*/
|
||||
QStringList CustomizeSystemBackupProxy::getRsyncArgs(CustomizeSystemBackupScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
QStringList excludes;
|
||||
|
||||
switch (scene) {
|
||||
case CustomizeSystemBackupScene::TRY_SYSTEM_BACKUP :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
break ;
|
||||
case CustomizeSystemBackupScene::MKSQUASHFS :
|
||||
Utils::excludeFstabBindPath(excludes);
|
||||
// --exclude=排除路径设置
|
||||
for (QString item : m_backupWrapper.m_backupExcludePaths) {
|
||||
if (excludes.contains(item))
|
||||
continue;
|
||||
if (item.endsWith("/*")) {
|
||||
item.replace("/*", "");
|
||||
}
|
||||
|
||||
args << "-e" << item;
|
||||
}
|
||||
return args;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
// --exclude=排除路径设置
|
||||
for (const QString & item : m_backupWrapper.m_backupExcludePaths) {
|
||||
args << QString("--exclude=%1").arg(item);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief mksqushfs
|
||||
*/
|
||||
void CustomizeSystemBackupProxy::doMksqushfs()
|
||||
{
|
||||
qDebug() << "CustomizeSystemBackupProxy::doMksqushfs invoke begin";
|
||||
|
||||
m_mksquashfs = new MkSquashFSProcess(this);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::progress, this, &CustomizeSystemBackupProxy::progress);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::finished, this, [=](bool result) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING;
|
||||
m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath));
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (ParseBackupList::ParseResult::SUCCESS != parse.updateItem(m_backupPoint)) {
|
||||
qCritical() << "update backuplist.xml error in sendBackupResult";
|
||||
result = false;
|
||||
} else {
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(m_backupPoint.m_time + ","
|
||||
+ m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
+ m_backupWrapper.m_note + "," + m_backupPoint.m_size
|
||||
+ ",," + m_backupWrapper.m_backupName);
|
||||
|
||||
Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
}
|
||||
emit this->workResult(result);
|
||||
});
|
||||
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
QString dstImg = m_destPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
|
||||
QStringList args;
|
||||
args << srcPath << dstImg;
|
||||
args.append(getRsyncArgs(CustomizeSystemBackupScene::MKSQUASHFS));
|
||||
|
||||
if (m_mksquashfs->start(args)) {
|
||||
do_kylin_security(m_destPath);
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::MKSQUASHFS_DO_FAIL));
|
||||
}
|
||||
|
||||
qDebug() << "CustomizeSystemBackupProxy::doMksqushfs invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份准备
|
||||
* @return true,准备成功;false,准备失败
|
||||
*/
|
||||
bool CustomizeSystemBackupProxy::doPrepare()
|
||||
{
|
||||
qDebug() << "CustomizeSystemBackupProxy::doPrepare invoke begin";
|
||||
|
||||
m_bSuccess = false;
|
||||
|
||||
// 1、设置当前备份的Uuid
|
||||
m_curUuid += Utils::createUuid();
|
||||
|
||||
// 2、准备备份目录及文件
|
||||
m_destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data";
|
||||
m_destPath.replace("//", "/");
|
||||
if (!Utils::mkpath(m_destPath)) {
|
||||
qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ;
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE;
|
||||
userFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(userFile, m_backupWrapper.m_backupPaths)) {
|
||||
qCritical() << QString("create file %1 failed !").arg(userFile);
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
excludeUserFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(excludeUserFile, m_backupWrapper.m_backupExcludePaths)) {
|
||||
qCritical() << QString("create file %1 failed !").arg(excludeUserFile);
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、记录/backup/snapshots/backuplist.xml文件
|
||||
if (!recordBackupPoint()) {
|
||||
qCritical() << "add or update item to backuplist.xml failed !";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "CustomizeSystemBackupProxy::doPrepare invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool CustomizeSystemBackupProxy::recordBackupPoint()
|
||||
{
|
||||
m_backupPoint.m_backupName = m_backupWrapper.m_backupName;
|
||||
m_backupPoint.m_uuid = m_curUuid;
|
||||
m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition;
|
||||
m_backupPoint.m_type = m_backupWrapper.m_type;
|
||||
m_backupPoint.m_size = Utils::StringBySize(m_size);
|
||||
m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING;
|
||||
m_backupPoint.m_os = SystemInfo::m_os;
|
||||
m_backupPoint.m_arch = SystemInfo::m_arch;
|
||||
m_backupPoint.m_archdetect = SystemInfo::m_archDetect;
|
||||
m_backupPoint.m_path = m_backupWrapper.m_prefixDestPath;
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CustomizeSystemBackupProxy::do_kylin_security(const QString& dstDir)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = kysec_getstatus();
|
||||
if (ret > 0) {
|
||||
QString seFilePath(dstDir + "/.exectl");
|
||||
QFile file(seFilePath);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
#ifndef CUSTOMIZESYSTEMBACKUPPROXY_H
|
||||
#define CUSTOMIZESYSTEMBACKUPPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
#include "myprocess/mksquashfsprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class CustomizeSystemBackupProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(CustomizeSystemBackupProxy)
|
||||
|
||||
public:
|
||||
// 系统备份的几种场景
|
||||
enum CustomizeSystemBackupScene {
|
||||
TRY_SYSTEM_BACKUP, // 测试系统备份,可用于计算备份传输数据大小
|
||||
MKSQUASHFS, // 生成img文件
|
||||
};
|
||||
|
||||
explicit CustomizeSystemBackupProxy();
|
||||
virtual ~CustomizeSystemBackupProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
// 校验剩余空间是否满足备份
|
||||
void checkFreeCapacity(qint64 itotalSize);
|
||||
|
||||
// mksqushfs
|
||||
void doMksqushfs();
|
||||
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private:
|
||||
// 计算备份所需空间大小
|
||||
void calcSizeForBackup();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(CustomizeSystemBackupScene scene);
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool recordBackupPoint();
|
||||
|
||||
// 备份准备
|
||||
bool doPrepare();
|
||||
|
||||
bool backup(const QStringList &args);
|
||||
|
||||
void do_kylin_security(const QString& dstDir);
|
||||
|
||||
// 失败则删除相应数据
|
||||
void deleteFailedData();
|
||||
|
||||
// 计算备份空间大小的进程
|
||||
CalcBackupSize *m_calc;
|
||||
// 压缩进程
|
||||
MkSquashFSProcess *m_mksquashfs;
|
||||
|
||||
// 是否完成
|
||||
bool m_isFinished;
|
||||
// 是否备份成功
|
||||
bool m_bSuccess;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前备份目标目录
|
||||
QString m_destPath;
|
||||
// 当前备份所需空间大小
|
||||
qint64 m_size;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
// 是否只是检测
|
||||
bool m_isOnlyCheck;
|
||||
};
|
||||
|
||||
#endif // CUSTOMIZESYSTEMBACKUPPROXY_H
|
|
@ -0,0 +1,343 @@
|
|||
#include "customizesystemrestoreproxy.h"
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "../common/utils.h"
|
||||
#include "mymountproxy.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(CustomizeSystemRestoreProxy)
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
CustomizeSystemRestoreProxy::CustomizeSystemRestoreProxy()
|
||||
{
|
||||
m_bSuccess = false;
|
||||
m_p = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
CustomizeSystemRestoreProxy::~CustomizeSystemRestoreProxy()
|
||||
{
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool CustomizeSystemRestoreProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "CustomizeSystemRestoreProxy::checkEnvEx invoke begin";
|
||||
|
||||
// 1、检测xml中的还原点是否还存在
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (m_backupPoint.m_uuid.isEmpty()) {
|
||||
qCritical("xml中还原点不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、检测.user.txt是否存在
|
||||
m_userFile = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + PATHS_USER_FILE;
|
||||
m_userFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_userFile)) {
|
||||
qCritical(".user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、检测.exclude.user.txt是否存在
|
||||
m_excludeUserFile = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
m_excludeUserFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_excludeUserFile)) {
|
||||
qCritical(".exclude.user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4、检测还原点是否存在
|
||||
m_backupPath = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
m_backupPath.replace("//", "/");
|
||||
if (Utils::isDirEmpty(m_backupPath)) {
|
||||
qCritical("还原点{uuid}/data目录不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
m_imgFileName = m_backupPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
|
||||
if (!Utils::filsExists(m_imgFileName)) {
|
||||
qCritical("还原点{uuid}/data/dst.img文件不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_curUuid = m_backupWrapper.m_uuid;
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "CustomizeSystemRestoreProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行还原逻辑
|
||||
*/
|
||||
void CustomizeSystemRestoreProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "CustomizeSystemRestoreProxy::doWorkEx invoke begin";
|
||||
|
||||
// 1、校验
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
// 2、还原系统
|
||||
restoreSystem();
|
||||
|
||||
qDebug() << "CustomizeSystemRestoreProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份准备
|
||||
* @return true,准备成功;false,准备失败
|
||||
*/
|
||||
bool CustomizeSystemRestoreProxy::doPrepare()
|
||||
{
|
||||
qDebug() << "CustomizeSystemRestoreProxy::doPrepare invoke begin";
|
||||
|
||||
// 1、dst.img文件需要挂载到目录
|
||||
if (!mountImg())
|
||||
return false;
|
||||
|
||||
// 2、停止安全防护
|
||||
QProcess::execute("systemctl stop kysec-init.service");
|
||||
|
||||
// 3、以读写方式重新挂载boot分区,因为有的机器默认以只读挂载
|
||||
remountBoot();
|
||||
|
||||
// 4、是否有/boot/efi目录,有则认为有efi分区,需重新rw挂载
|
||||
QString efiPath = Utils::getSysRootPath() + "/boot/efi";
|
||||
efiPath.replace("//", "/");
|
||||
if (!Utils::isDirEmpty(efiPath)) {
|
||||
// 重新rw读写挂载
|
||||
remountEfi();
|
||||
}
|
||||
|
||||
qDebug() << "CustomizeSystemRestoreProxy::doPrepare invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将dst.img文件挂载到/backup/imgbackup目录
|
||||
* @return
|
||||
*/
|
||||
bool CustomizeSystemRestoreProxy::mountImg()
|
||||
{
|
||||
// 自定义路径系统备份,需要先将dst.img文件挂载到/backup/imgbackup目录
|
||||
// 1、检测目录/backup/imgbackup是否存在,不存在则创建此目录
|
||||
QString dstImgMountPath = Utils::getSysRootPath() + BACKUP_IMGBACKUP_PATH;
|
||||
dstImgMountPath.replace("//", "/");
|
||||
Utils::mkpath(dstImgMountPath);
|
||||
|
||||
// 2、先卸载/backup/imgbackup上的mount
|
||||
MountBackupProcess *processMount = new MountBackupProcess(this);
|
||||
processMount->umount(dstImgMountPath);
|
||||
|
||||
// 3、将img文件挂载到/backup/imgbackup上
|
||||
if (!processMount->mount(m_imgFileName, dstImgMountPath)) {
|
||||
emit checkResult(int(BackupResult::RESTOREDIR_PREPARE_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_srcPath = dstImgMountPath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新rw读写挂载efi分区
|
||||
*/
|
||||
void CustomizeSystemRestoreProxy::remountEfi()
|
||||
{
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot/efi";
|
||||
mountPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-o"
|
||||
<< "rw,remount"
|
||||
<< mountPath;
|
||||
QProcess::execute("mount", args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新rw读写挂载boot分区
|
||||
*/
|
||||
void CustomizeSystemRestoreProxy::remountBoot()
|
||||
{
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot";
|
||||
mountPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-o"
|
||||
<< "rw,remount"
|
||||
<< mountPath;
|
||||
QProcess::execute("mount", args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList CustomizeSystemRestoreProxy::getRsyncArgs(CustomizeSystemRestoreScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
|
||||
QStringList excludes;
|
||||
// 自定义备份的路径也需要跳过,不进行还原
|
||||
Utils::excludeCustomizePath(excludes);
|
||||
|
||||
switch (scene) {
|
||||
case CustomizeSystemRestoreScene::RESTORE_SYSTEM_WITH_DATA :
|
||||
args << "--exclude=/home";
|
||||
args << "--exclude=/root";
|
||||
if (Utils::isHuawei990()) {
|
||||
args << "--exclude=/data";
|
||||
} else {
|
||||
args << "--exclude=/data/usershare";
|
||||
}
|
||||
// 保留指纹数据,用户密码、角色、权限、生物识别等信息不需要改变
|
||||
args << "--exclude=/var/lib/biometric-auth";
|
||||
args << "--exclude=/data/sec_storage_data";
|
||||
args << "--exclude=/etc/passwd";
|
||||
args << "--exclude=/etc/shadow";
|
||||
args << "--exclude=/etc/group";
|
||||
args << "--exclude=/etc/gshadow";
|
||||
args << "--exclude=/etc/sudoers";
|
||||
args << "--exclude=/data/home";
|
||||
args << "--exclude=/data/root";
|
||||
|
||||
// 云桌面背景路径属于用户数据
|
||||
args << "--exclude=/var/lib/AccountsService";
|
||||
|
||||
// 域用户相关信息,还原后保持不退域
|
||||
args << "--exclude=/etc/sssd";
|
||||
args << "--exclude=/var/lib/sss";
|
||||
args << "--exclude=/usr/share/sssd";
|
||||
args << "--exclude=/etc/ipa";
|
||||
args << "--exclude=/etc/krb5.keytab";
|
||||
args << "--exclude=/etc/krb5.conf";
|
||||
args << "--exclude=/var/lib/ipa-client";
|
||||
args << "--exclude=/etc/nsswitch.conf";
|
||||
args << "--exclude=/etc/pam.d";
|
||||
args << "--exclude=/etc/hosts";
|
||||
args << "--exclude=/etc/hostname";
|
||||
args << "--exclude=/etc/hedron";
|
||||
args << "--exclude=/etc/kcm";
|
||||
args << "--exclude=/usr/hedron/hedronagent";
|
||||
args << "--exclude=/etc/.kyinfo";
|
||||
args << "--exclude=/etc/LICENSE";
|
||||
args << "--exclude=/etc/ssl/certs";
|
||||
args << "--exclude=/usr/share/ca-certificates";
|
||||
args << "--exclude=/etc/NetworkManager";
|
||||
|
||||
// 此处不要break,因为还需要排除SYSTEM_RESTORE中的项
|
||||
|
||||
case CustomizeSystemRestoreScene::SYSTEM_RESTORE :
|
||||
// 还原工具不还原自身
|
||||
args << "--exclude=/usr/bin/backup-daemon";
|
||||
args << "--exclude=/usr/bin/kybackup";
|
||||
args << "--exclude=/usr/bin/mount_fstab_efi";
|
||||
args << "--exclude=/usr/bin/backup-auto-efi";
|
||||
args << "--exclude=/usr/bin/backup-auto";
|
||||
args << "--exclude=/usr/bin/rsync";
|
||||
args << "--exclude=/usr/share/rsync";
|
||||
args << "--exclude=/usr/share/initramfs-tools/hooks/kybackup-hooks";
|
||||
args << "--exclude=/usr/share/initramfs-tools/scripts/local-bottom/kybackup";
|
||||
|
||||
for (const QString& item : excludes) {
|
||||
args << QString("--exclude=") + item;
|
||||
}
|
||||
|
||||
args << "--exclude-from" << m_excludeUserFile;
|
||||
args << "--files-from" << m_userFile;
|
||||
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 系统还原
|
||||
*/
|
||||
void CustomizeSystemRestoreProxy::restoreSystem()
|
||||
{
|
||||
qDebug() << "CustomizeSystemRestoreProxy::restoreSystem invoke begin";
|
||||
|
||||
// 还原前准备
|
||||
doPrepare();
|
||||
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
|
||||
QStringList args;
|
||||
// 保留用户数据还原
|
||||
if ( m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM_WITH_DATA) {
|
||||
args = getRsyncArgs(CustomizeSystemRestoreScene::RESTORE_SYSTEM_WITH_DATA);
|
||||
} else {
|
||||
args = getRsyncArgs(CustomizeSystemRestoreScene::SYSTEM_RESTORE);
|
||||
}
|
||||
|
||||
args << m_srcPath + "/";
|
||||
destPath += "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &CustomizeSystemRestoreProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
if (result) {
|
||||
QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,,," + m_backupPoint.m_backupName);
|
||||
|
||||
Utils::updateSyncFile();
|
||||
Utils::wait(2);
|
||||
QString fileIfSync = Utils::getSysRootPath() + FILE_IF_SYNC;
|
||||
fileIfSync.replace("//", "/");
|
||||
QFileInfo file(fileIfSync);
|
||||
QDateTime beginTime = file.fileTime(QFileDevice::FileModificationTime);
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(20);
|
||||
Utils::updateSyncFile();
|
||||
while (1) {
|
||||
Utils::wait(2);
|
||||
QFileInfo file1(fileIfSync);
|
||||
QDateTime UpdateTime = file1.fileTime(QFileDevice::FileModificationTime);
|
||||
if (UpdateTime > beginTime)
|
||||
break;
|
||||
}
|
||||
|
||||
emit this->workResult(result);
|
||||
Utils::wait(2);
|
||||
reboot(RB_AUTOBOOT);
|
||||
}
|
||||
emit this->workResult(result);
|
||||
});
|
||||
|
||||
m_p->start(args, false);
|
||||
|
||||
qDebug() << "CustomizeSystemRestoreProxy::restoreSystem invoke end";
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef CUSTOMIZESYSTEMRESTOREPROXY_H
|
||||
#define CUSTOMIZESYSTEMRESTOREPROXY_H
|
||||
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class CustomizeSystemRestoreProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(CustomizeSystemRestoreProxy)
|
||||
public:
|
||||
// 系统还原的几种场景
|
||||
enum CustomizeSystemRestoreScene {
|
||||
SYSTEM_RESTORE, // 系统还原
|
||||
RESTORE_SYSTEM_WITH_DATA, // 保留用户数据还原
|
||||
};
|
||||
|
||||
explicit CustomizeSystemRestoreProxy();
|
||||
virtual ~CustomizeSystemRestoreProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
private:
|
||||
// 将img文件挂载到/backup/imgbackup目录
|
||||
bool mountImg();
|
||||
// 以读写方式重新挂载efi分区
|
||||
void remountEfi();
|
||||
// 以读写方式重新挂载boot分区
|
||||
void remountBoot();
|
||||
// 还原前准备
|
||||
bool doPrepare();
|
||||
// 系统还原
|
||||
void restoreSystem();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(CustomizeSystemRestoreScene scene);
|
||||
|
||||
// .user.txt文件路径
|
||||
QString m_userFile;
|
||||
// .exclude.user.txt文件路径
|
||||
QString m_excludeUserFile;
|
||||
// 备份数据所在的data目录
|
||||
QString m_backupPath;
|
||||
// 压缩的img文件全名
|
||||
QString m_imgFileName;
|
||||
|
||||
// 是否还原成功
|
||||
bool m_bSuccess;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前还原源目录
|
||||
QString m_srcPath;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // CUSTOMIZESYSTEMRESTOREPROXY_H
|
||||
|
|
@ -0,0 +1 @@
|
|||
backup-auto与backup-auto-efi为同一个程序,用来替换backup-auto/backup-auto,后者使用Qt程序会导致/boot/内核超过16M.
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
|
||||
|
||||
<!DOCTYPE busconfig PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<busconfig>
|
||||
<!-- Only root can own the service -->
|
||||
<policy user="root">
|
||||
<allow own="com.kylin.backup"/>
|
||||
<allow send_interface="com.kylin.backup.manager" />
|
||||
</policy>
|
||||
|
||||
<!-- Allow anyone to invoke methods on the interfaces -->
|
||||
<policy context="default">
|
||||
<allow send_interface="com.kylin.backup.manager"/>
|
||||
<allow send_destination="com.kylin.backup"
|
||||
send_interface="org.freedesktop.DBus.Introspectable"/>
|
||||
<allow send_destination="com.kylin.backup"
|
||||
send_interface="org.freedesktop.DBus.Properties"/>
|
||||
</policy>
|
||||
</busconfig>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE policyconfig PUBLIC
|
||||
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
|
||||
<policyconfig>
|
||||
|
||||
<vendor>Backup Tools From KYLIN</vendor>
|
||||
<vendor_url>www.kylinos.cn</vendor_url>
|
||||
|
||||
<action id="com.kylin.backup.manager">
|
||||
<description>Determine Recovery Access</description>
|
||||
<message>更改启动模式操作需要管理权限,请输入管理员密码进行身份认证</message>
|
||||
<defaults>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin</allow_active>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
</policyconfig>
|
|
@ -0,0 +1,5 @@
|
|||
[D-BUS Service]
|
||||
Name=com.kylin.backup
|
||||
Exec=/usr/bin/backup-daemon
|
||||
User=root
|
||||
|
|
@ -0,0 +1 @@
|
|||
FRAMEBUFFER=y
|
|
@ -0,0 +1,91 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
PREREQS=""
|
||||
|
||||
prereqs() { echo "$PREREQS"; }
|
||||
|
||||
case "$1" in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# 上面的内容和initramfs脚本很像,可以不管。
|
||||
# hook脚本的功能是将一些文件放到initramfs文件里去。
|
||||
# 把该脚本放到 /usr/share/initramfs-tools/hooks/ 目录下,权限为 0755
|
||||
# 在更新initramfs时会自动执行该脚本,安装文件。
|
||||
|
||||
# 下面这一行是加载hook-functions里的一些功能,用到这个脚本来。
|
||||
# 这一行必须有
|
||||
# /usr/share/initramfs-tools/hook-functions定义了copy_exec
|
||||
. /usr/share/initramfs-tools/hook-functions
|
||||
|
||||
ExistCopyExec()
|
||||
{
|
||||
if [ -f $1 ]; then
|
||||
copy_exec $1 $2
|
||||
fi
|
||||
}
|
||||
|
||||
ExistCp()
|
||||
{
|
||||
if [ -f $1 ]; then
|
||||
cp $1 $2
|
||||
fi
|
||||
}
|
||||
|
||||
# 以添加rsync程序为例
|
||||
# 在系统中rsync在/usr/bin/ 目录下
|
||||
# 首先创建目录 /usr/bin/ ,一定要加上 $DESTDIR
|
||||
# 然后用copy_exec 将系统中的 rsync 拷贝到 initramfs 的预期位置中。
|
||||
# 对于动态可执行文件, copy_exec 会将其依赖库也拷贝到 initramfs 中。
|
||||
# 使用 copy_exec 时,不要用 $DESTDIR
|
||||
# 但是如果是拷贝普通文件,则用 cp ,并且还要使用 $DESTDIR ,例如
|
||||
# mkdir -p $DESTDIR/common/file
|
||||
# cp /common/file/path $DESTDIR/common/file/
|
||||
|
||||
mkdir -p $DESTDIR/usr/bin
|
||||
mkdir -p $DESTDIR/bin
|
||||
mkdir -p $DESTDIR/etc
|
||||
ExistCopyExec /etc/.bootinfo /etc
|
||||
ExistCopyExec /etc/fstab /etc/fstab-backup
|
||||
ExistCopyExec /usr/bin/rsync /usr/bin
|
||||
###backup-auto-efi需要调用bc来计算磁盘用量
|
||||
ExistCopyExec /usr/bin/bc /usr/bin
|
||||
###Qt program: ExistCopyExec /usr/bin/backup-auto /usr/bin
|
||||
ExistCopyExec /usr/bin/backup-auto-efi /usr/bin
|
||||
###Now backup-auto is identical to backup-auto-efi
|
||||
ExistCopyExec /usr/bin/backup-auto /usr/bin
|
||||
ExistCopyExec /usr/bin/mount_fstab_efi /usr/bin
|
||||
|
||||
ExistCopyExec /bin/bash /bin
|
||||
ExistCopyExec /bin/mkdir /bin
|
||||
ExistCopyExec /bin/ls /bin
|
||||
ExistCopyExec /bin/mount /bin
|
||||
ExistCopyExec /bin/sync /bin
|
||||
ExistCopyExec /sbin/reboot /bin
|
||||
#fix wrong timezone in initrd(#)
|
||||
#ExistCopyExec /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
|
||||
ExistCopyExec /usr/bin/kylin_activation_check /usr/bin
|
||||
ExistCopyExec /usr/bin/gpg /usr/bin
|
||||
|
||||
mkdir -p $DESTDIR//var/lib/dpkg/info
|
||||
ExistCp /var/lib/dpkg/info/libkylin-activation.md5sums $DESTDIR/var/lib/dpkg/info
|
||||
|
||||
mkdir -p $DESTDIR/etc/xdg/autostart
|
||||
ExistCp /etc/xdg/autostart/kylin-notification.desktop $DESTDIR/etc/xdg/autostart
|
||||
|
||||
mkdir -p $DESTDIR/etc/update-motd.d
|
||||
ExistCp /etc/update-motd.d/99-kylin-verify-info $DESTDIR/etc/update-motd.d/
|
||||
|
||||
ExistCopyExec /usr/bin/kylin-verify /usr/bin
|
||||
###打包很多库,包括gdk,内核会超过16M
|
||||
###ExistCopyExec /usr/bin/kylin-verify-gui /usr/bin
|
||||
ExistCopyExec /bin/bash /bin
|
||||
ExistCp /var/lib/dpkg/info/kylin-verify.md5sums $DESTDIR/var/lib/dpkg/info/
|
||||
ExistCp /var/lib/dpkg/info/bash.md5sums $DESTDIR/var/lib/dpkg/info/
|
||||
|
||||
#fix wrong timezone in initrd(#316)
|
||||
#ExistCp /usr/share/zoneinfo/Asia/Shanghai $DESTDIR/etc/localtime
|
|
@ -0,0 +1,528 @@
|
|||
#!/bin/bash
|
||||
|
||||
BACKUP_FLAG=backup
|
||||
RESTORE_FLAG=restore
|
||||
ROLLBACK_FLAG=rollback-backup
|
||||
# 把这个文件放在 /usr/share/initramfs-tools/scripts/local-bottom/ 目录下。
|
||||
# 权限为 0755,在自动更新initrd时,这个脚本就被放到initrd中了,例如,
|
||||
# update-initramfs -u
|
||||
# 更新后,这个脚本将在initrd 运行到 local-bottom 阶段时自动执行。
|
||||
# 此时根分区已经挂载到了${rootmnt}下,可以直接访问该分区的文件。
|
||||
|
||||
# PREREQ指定需要在什么脚本之后执行(同目录下的),也就是指定该脚本的依赖,以确定执行顺序。
|
||||
# 如果没有依赖,就可以是空字符串。
|
||||
PREREQ=""
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# 上述部分是initramfs脚本的固定格式,不用动它。
|
||||
# 除非有依赖,才需要改 PREREQ 的值。
|
||||
|
||||
#. /scripts/security-functions
|
||||
show_text_mesg()
|
||||
{
|
||||
echo "$1"
|
||||
}
|
||||
|
||||
plymouth_is_running()
|
||||
{
|
||||
if [ -e "/bin/plymouth" ] && /bin/plymouth --ping; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
show_message()
|
||||
{
|
||||
if plymouth_is_running; then
|
||||
/bin/plymouth message --text="$1"
|
||||
show_text_mesg "$1"
|
||||
else
|
||||
show_text_mesg "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
clear_message()
|
||||
{
|
||||
if plymouth_is_running; then
|
||||
plymouth message --text=""
|
||||
fi
|
||||
clear
|
||||
}
|
||||
|
||||
isEnglish()
|
||||
{
|
||||
LOCALFILE="${rootmnt}/etc/default/locale"
|
||||
if [ ! -e "$LOCALFILE" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
localcontent=`grep -E "^LANG" $LOCALFILE | grep -i "zh_CN.UTF"`
|
||||
|
||||
#echo "localcontent: $localcontent"
|
||||
|
||||
if [ -z $localcontent ]; then
|
||||
#echo "This is English"
|
||||
return 1
|
||||
else
|
||||
#echo "系统支持中文"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
isEnglish
|
||||
v_isEnglish=$?
|
||||
|
||||
myoutput()
|
||||
{
|
||||
#echo "v_isEnglish is "$v_isEnglish
|
||||
|
||||
#echo "first para: $1"
|
||||
#echo "second para: $2"
|
||||
|
||||
if [ $v_isEnglish -eq 1 ]; then
|
||||
echo $1
|
||||
#plymouth message --text=$1
|
||||
#echo "English"
|
||||
show_message "$1"
|
||||
else
|
||||
echo $2
|
||||
#plymouth message --text=$2
|
||||
#echo "中文"
|
||||
show_message "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
loop_wait()
|
||||
{
|
||||
#去掉原来的死循环,退出
|
||||
sleep 5
|
||||
reboot -f
|
||||
#while(true)
|
||||
#do
|
||||
# sleep 1
|
||||
#done
|
||||
}
|
||||
|
||||
get_is_990_9a0() {
|
||||
local ret=false
|
||||
# 匹配 kirin 990 5g, kirin990, kirin 9006c
|
||||
if egrep -qi 'kirin.?9[09]0' /proc/cpuinfo; then
|
||||
ret=true
|
||||
elif egrep -qi 'PANGU' /proc/cpuinfo; then
|
||||
ret=true
|
||||
|
||||
fi
|
||||
echo $ret
|
||||
}
|
||||
is_990_9a0=$(get_is_990_9a0)
|
||||
|
||||
factory_restore_warnning()
|
||||
{
|
||||
if [ x${is_990_9a0} == x"true" ]; then
|
||||
local is_sure=
|
||||
while :
|
||||
do
|
||||
if plymouth_is_running; then
|
||||
myoutput "You are doing factory restoration. Are you sure to continue? [y/n]" "正在准备进行出厂还原操作,是否继续?[y/n]"
|
||||
is_sure=$(/bin/plymouth watch-keystroke)
|
||||
echo is_sure=$is_sure
|
||||
case $is_sure in
|
||||
y|Y)
|
||||
break;;
|
||||
n|N)
|
||||
# 注意,reboot重启不了,可用reboot -f
|
||||
reboot -f;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
factory_restore_warnning_again()
|
||||
{
|
||||
if [ x${is_990_9a0} == x"true" ]; then
|
||||
local is_sure=
|
||||
while :
|
||||
do
|
||||
if plymouth_is_running; then
|
||||
myoutput "Please confirm again whether to restore the system to factory defaults. Are you sure to continue? [y/n]" "请再一次确认是否进行系统出厂还原,是否继续?[y/n]"
|
||||
is_sure=$(/bin/plymouth watch-keystroke)
|
||||
echo is_sure=$is_sure
|
||||
case $is_sure in
|
||||
y|Y)
|
||||
break;;
|
||||
n|N)
|
||||
# 注意,reboot重启不了,可用reboot -f
|
||||
reboot -f;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
restore_warnning()
|
||||
{
|
||||
local is_sure=
|
||||
while :
|
||||
do
|
||||
if plymouth_is_running; then
|
||||
if [ x"$FACTORY_RESTORE" = "xy" ]; then
|
||||
myoutput "This operation will delete all data and restore system to factory default state, data may be lost. Are you sure to continue? [y/n]" "本操作将会删除所有用户数据并恢复系统到出厂状态,有数据丢失风险,是否继续?[y/n]"
|
||||
else
|
||||
myoutput "This operation may delete some data, which may cause data loss. Are you sure to continue? [y/n]" "此操作可能会删除一些数据,造成丢失数据风险,是否继续?[y/n]"
|
||||
fi
|
||||
is_sure=$(/bin/plymouth watch-keystroke)
|
||||
echo is_sure=$is_sure
|
||||
case $is_sure in
|
||||
y|Y)
|
||||
break;;
|
||||
n|N)
|
||||
# 注意,reboot重启不了,可用reboot -f
|
||||
reboot -f;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
display_result()
|
||||
{
|
||||
#myoutput "返回值: $RET"
|
||||
#sleep 3
|
||||
RET=$1
|
||||
|
||||
if [ $RET -eq 1 ]; then
|
||||
myoutput "Can't find /etc/.bootinfo." "没有找到/etc/.bootinfo"
|
||||
loop_wait
|
||||
elif [ $RET -eq 2 ]; then
|
||||
myoutput "Can't open /etc/.bootinfo." "无法打开/etc/.bootinfo"
|
||||
loop_wait
|
||||
elif [ $RET -eq 3 ]; then
|
||||
myoutput "/etc/.bootinfo is not correct." "/etc/.bootinfo不正确"
|
||||
loop_wait
|
||||
elif [ $RET -eq 4 ]; then
|
||||
myoutput "The backup disk space is not enough, please delete unnecessary backups." "备份分区空间不足,请删除过期或者不需要的备份"
|
||||
loop_wait
|
||||
elif [ $RET -eq 5 ]; then
|
||||
myoutput "The backup disk must be /backup" "备份还原分区路径不是/backup"
|
||||
loop_wait
|
||||
elif [ $RET -eq 6 ]; then
|
||||
myoutput "There are not any good backups,and you can't restore the system." "没有有效的备份,不能还原系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 7 ]; then
|
||||
myoutput "The backup does not exist, and you can't restore it." "备份文件不存在,不能还原系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 8 ]; then
|
||||
myoutput "Can't start the restore process, please redo it." "不能启动还原进程,请重新还原系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 9 ]; then
|
||||
myoutput "Failed to restore the system, please redo it." "还原失败,请重新还原系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 10 ]; then
|
||||
myoutput "Can't start the mount process for backup." "不能启动备份还原分区安装进程,请重新启动系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 11 ]; then
|
||||
myoutput "Failed to wait for the process for backup." "备份还原分区安装进程等待结束时出错,请重新启动系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 12 ]; then
|
||||
myoutput "The backup disk does not exist or it is not mounted." "备份还原分区不存在或没有mount"
|
||||
loop_wait
|
||||
elif [ $RET -eq 13 ]; then
|
||||
myoutput "Can't start the backup process." "不能启动备份进程,请重新备份系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 14 ]; then
|
||||
myoutput "Failed to backup the system." "备份失败,请重新备份系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 15 ]; then
|
||||
myoutput "The usage of mount_fstab is not correct." "mount_fstab用法不正确,无法安装系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 16 ]; then
|
||||
myoutput "Failed to backup the system because /etc/fstab does not exist." "/etc/fstab不存在,无法备份系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 17 ]; then
|
||||
myoutput "Can't open /etc/fstab." "/etc/fstab打开失败,无法备份系统"
|
||||
loop_wait
|
||||
elif [ $RET -eq 18 ]; then
|
||||
myoutput "Wrong arguments." "调用backup-auto-efi 参数错误"
|
||||
loop_wait
|
||||
elif [ $RET -eq 19 ]; then
|
||||
myoutput "Wrong with caculate disk size." "计算磁盘大小出错"
|
||||
loop_wait
|
||||
elif [ $RET -eq 20 ]; then
|
||||
myoutput "Could not create /backup in initrd!" "无法在initrd中创建backup目录"
|
||||
loop_wait
|
||||
elif [ $RET -eq 21 ]; then
|
||||
myoutput "Could not mount backup partition in initrd!" "无法挂载备份还原分区"
|
||||
loop_wait
|
||||
elif [ $RET -eq 22 ]; then
|
||||
myoutput "Could not create log directory in /backup!" "无法创建日志目录"
|
||||
loop_wait
|
||||
elif [ $RET -eq 23 ]; then
|
||||
myoutput "Could not create log file!" "无法创建日志文件"
|
||||
loop_wait
|
||||
fi
|
||||
}
|
||||
|
||||
# 需要先指定BACKUP_FLAG,例如设置为 BACKUP_FLAG=backup,那么内核参数就可以选择下述两种方式的一种了
|
||||
# 1. backup 只要有backup,就表示需要备份
|
||||
# 2. backup=0 或者 backup=1 0表示不用备份,1表示需要备份。
|
||||
# 当然,还可以选择别的字符串做关键字,但一定要指定BACKUP_FLAG内容。
|
||||
#BACKUP_FLAG=
|
||||
NEED_BACKUP=
|
||||
NEED_RESTORE=
|
||||
NEED_ROLLBACK=
|
||||
NEED_RETAIN_USERDATA=
|
||||
# 针对 BACKUP_FLAG 为简单字符串(非键值对)的情况,可以这样获取内核参数。
|
||||
for x in $(cat /proc/cmdline); do
|
||||
case $x in
|
||||
backup)
|
||||
NEED_BACKUP=y
|
||||
;;
|
||||
restore)
|
||||
NEED_RESTORE=y
|
||||
;;
|
||||
restore-retain-userdata)
|
||||
NEED_RESTORE=y
|
||||
NEED_RETAIN_USERDATA=y
|
||||
;;
|
||||
rollback-backup)
|
||||
NEED_ROLLBACK=y
|
||||
;;
|
||||
factory-restore)
|
||||
NEED_RESTORE=y
|
||||
FACTORY_RESTORE=y
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
#for x in $(cat /proc/cmdline); do
|
||||
# if [ "$x" = "$BACKUP_FLAG" ]; then
|
||||
# NEED_BACKUP=y
|
||||
# fi
|
||||
#done
|
||||
#
|
||||
#for x in $(cat /proc/cmdline); do
|
||||
# if [ "$x" = "$RESTORE_FLAG" ]; then
|
||||
# NEED_RESTORE=y
|
||||
# fi
|
||||
#done
|
||||
#for x in $(cat /proc/cmdline); do
|
||||
# if [ "$x" = "$ROLLBACK_FLAG" ]; then
|
||||
# NEED_ROLLBACK=y
|
||||
# fi
|
||||
#done
|
||||
|
||||
#for x in $(cat /proc/cmdline); do
|
||||
# if [ "$x" = "$BACKUP_FLAG" ]; then
|
||||
# NEED_BACKUP=y
|
||||
# fi
|
||||
#done
|
||||
#
|
||||
#for x in $(cat /proc/cmdline); do
|
||||
# if [ "$x" = "$RESTORE_FLAG" ]; then
|
||||
# NEED_RESTORE=y
|
||||
# fi
|
||||
#done
|
||||
#for x in $(cat /proc/cmdline); do
|
||||
# if [ "$x" = "$ROLLBACK_FLAG" ]; then
|
||||
# NEED_ROLLBACK=y
|
||||
# fi
|
||||
#done
|
||||
|
||||
# 然后就可以根据 $NEED_BACKUP 来进行操作了。
|
||||
# 如果没有发现需要备份的标记,直接退出脚本,继续启动系统。
|
||||
|
||||
if [ "$NEED_BACKUP" = "y" ]; then
|
||||
mkdir /backup
|
||||
#useless: . /scripts/backup #就是本目录下的backup
|
||||
#useless: mount_fstab #定义在backup脚本中
|
||||
|
||||
#如果没有${rootmnt}/etc/fstab,则系统坏了,只能还原而不能备份.
|
||||
if [ ! -e ${rootmnt}/etc/fstab ]; then
|
||||
if [ ! -e /etc/fstab-backup ]; then
|
||||
#myoutput "The system has been destroyed and can not be backuped."
|
||||
myoutput "/etc/fstab does not exist." "/etc/fstab不存在,无法备份."
|
||||
loop_wait
|
||||
fi
|
||||
fi
|
||||
if [ ! -e ${rootmnt}/etc/.bootinfo ]; then
|
||||
if [ ! -e /etc/.bootinfo ]; then
|
||||
#myoutput "The system has been destroyed and you can restore it in the next version."
|
||||
myoutput "/etc/.bootinfo does not exist." "/etc/.bootinfo不存在,无法备份."
|
||||
loop_wait
|
||||
fi
|
||||
fi
|
||||
|
||||
mount_fstab_efi ${rootmnt} mount
|
||||
myoutput "Backuping the system, please wait for a moment." "正在备份系统"
|
||||
#myoutput "Backuping the system, please wait for a moment."
|
||||
backup-auto-efi --autobackup ${rootmnt} /backup
|
||||
|
||||
RET=$?
|
||||
display_result $RET
|
||||
|
||||
myoutput "The system has been backuped." "系统备份完成"
|
||||
#myoutput "The system has been backuped."
|
||||
#mount_fstab ${rootmnt} umount #because root
|
||||
sleep 3
|
||||
reboot -f
|
||||
fi
|
||||
|
||||
if [ "$NEED_RESTORE" = "y" ]; then
|
||||
factory_restore_warnning
|
||||
restore_warnning
|
||||
factory_restore_warnning_again
|
||||
#如果没有${rootmnt}/etc/fstab,则系统坏了,应该能还原,但需要在下一个版本中支持。
|
||||
if [ ! -e ${rootmnt}/etc/fstab ]; then
|
||||
if [ ! -e /etc/fstab-backup ]; then
|
||||
#myoutput "The system has been destroyed and you can restore it in the next version."
|
||||
myoutput "/etc/fstab does not exist." "/etc/fstab不存在,无法还原."
|
||||
loop_wait
|
||||
fi
|
||||
fi
|
||||
if [ ! -e ${rootmnt}/etc/.bootinfo ]; then
|
||||
if [ ! -e /etc/.bootinfo ]; then
|
||||
#myoutput "The system has been destroyed and you can restore it in the next version."
|
||||
myoutput "/etc/.bootinfo does not exist." "/etc/.bootinfo不存在,无法还原."
|
||||
loop_wait
|
||||
fi
|
||||
fi
|
||||
|
||||
mount_fstab_efi ${rootmnt} mount
|
||||
mkdir /backup
|
||||
myoutput "Restoring the system, please wait for a moment." "正在还原系统"
|
||||
#myoutput "Restoring the system, please wait for a moment."
|
||||
mount -o remount,rw ${rootmnt}
|
||||
if [ $? -ne 0 ];then
|
||||
myoutput "Could not mount filesystem with rw arguments." "错误:无法以读写方式挂载根文件系统."
|
||||
loop_wait
|
||||
|
||||
fi
|
||||
#. /scripts/backup
|
||||
if [ x"$NEED_RETAIN_USERDATA" = "xy" ]; then
|
||||
backup-auto-efi --restoreretainuserdata ${rootmnt} /backup
|
||||
elif [ x"$FACTORY_RESTORE" = "xy" ];then
|
||||
backup-auto-efi --factoryrestore ${rootmnt} /backup
|
||||
else
|
||||
backup-auto-efi --autorestore ${rootmnt} /backup
|
||||
fi
|
||||
|
||||
RET=$?
|
||||
display_result $RET
|
||||
|
||||
if [ ! -e ${rootmnt}/proc ]; then
|
||||
mkdir ${rootmnt}/proc
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/sys ]; then
|
||||
mkdir ${rootmnt}/sys
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/dev ]; then
|
||||
mkdir ${rootmnt}/dev
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/run ]; then
|
||||
mkdir ${rootmnt}/run
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/backup ]; then
|
||||
mkdir ${rootmnt}/backup
|
||||
fi
|
||||
|
||||
myoutput "The system has been restored." "系统还原完成"
|
||||
#myoutput "The system has been restored."
|
||||
#/scripts/mount_fstab ${rootmnt} umount #because root
|
||||
sleep 3
|
||||
reboot -f
|
||||
fi
|
||||
|
||||
|
||||
if [ "$NEED_ROLLBACK" = "y" ]; then
|
||||
factory_restore_warnning
|
||||
restore_warnning
|
||||
factory_restore_warnning_again
|
||||
#如果没有${rootmnt}/etc/fstab,则系统坏了,应该能还原,但需要在下一个版本中支持。
|
||||
if [ ! -e ${rootmnt}/etc/fstab ]; then
|
||||
if [ ! -e /etc/fstab-backup ]; then
|
||||
#myoutput "The system has been destroyed and you can restore it in the next version."
|
||||
myoutput "/etc/fstab does not exist." "/etc/fstab不存在,无法还原."
|
||||
loop_wait
|
||||
fi
|
||||
fi
|
||||
if [ ! -e ${rootmnt}/etc/.bootinfo ]; then
|
||||
if [ ! -e /etc/.bootinfo ]; then
|
||||
#myoutput "The system has been destroyed and you can restore it in the next version."
|
||||
myoutput "/etc/.bootinfo does not exist." "/etc/.bootinfo不存在,无法还原."
|
||||
loop_wait
|
||||
fi
|
||||
fi
|
||||
|
||||
mount_fstab_efi ${rootmnt} mount
|
||||
mkdir /backup
|
||||
myoutput "Restoring the system, please wait for a moment." "正在还原系统"
|
||||
#myoutput "Restoring the system, please wait for a moment."
|
||||
mount -o remount,rw ${rootmnt}
|
||||
if [ $? -ne 0 ];then
|
||||
myoutput "Could not mount filesystem with rw arguments." "错误:无法以读写方式挂载根文件系统."
|
||||
loop_wait
|
||||
|
||||
fi
|
||||
#. /scripts/backup
|
||||
backup-auto-efi --autorestore ${rootmnt} /backup {01234567-0123-0123-0123-0123456789ab}
|
||||
|
||||
RET=$?
|
||||
display_result $RET
|
||||
|
||||
if [ ! -e ${rootmnt}/proc ]; then
|
||||
mkdir ${rootmnt}/proc
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/sys ]; then
|
||||
mkdir ${rootmnt}/sys
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/dev ]; then
|
||||
mkdir ${rootmnt}/dev
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/run ]; then
|
||||
mkdir ${rootmnt}/run
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/backup ]; then
|
||||
mkdir ${rootmnt}/backup
|
||||
fi
|
||||
|
||||
myoutput "The system has been rollbacked." "系统回滚完成"
|
||||
reboot -f
|
||||
fi
|
||||
|
||||
# 否则
|
||||
# TODO 执行mount_fstab_efi ${rootmnt} mount备份操作
|
||||
|
||||
# 此时根分区已经挂载在 ${rootmnt} 处了,直接使用 ${rootmnt} 就可以了。
|
||||
# 例如查看lsb-release文件
|
||||
# cat ${rootmnt}/etc/lsb-release
|
||||
# 如果想要根据 UUID 或 LABEL 来确定分区,还可以执行blkid命令。例如,
|
||||
# /sbin/blkid -U <UUID> 该命令返回UUID对应的分区设备
|
||||
# /sbin/blkid -L <LABEL> 该命令返回LABEL对应的分区设备
|
||||
# 如果需要安装一些命令,需要写一个initramfs的hook脚本。
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,237 @@
|
|||
#!/bin/bash
|
||||
|
||||
BACKUP_FLAG=backup
|
||||
RESTORE_FLAG=restore
|
||||
|
||||
# 把这个文件放在 /usr/share/initramfs-tools/scripts/local-bottom/ 目录下。
|
||||
# 权限为 0755,在自动更新initrd时,这个脚本就被放到initrd中了,例如,
|
||||
# update-initramfs -u
|
||||
# 更新后,这个脚本将在initrd 运行到 local-bottom 阶段时自动执行。
|
||||
# 此时根分区已经挂载到了${rootmnt}下,可以直接访问该分区的文件。
|
||||
|
||||
|
||||
|
||||
# PREREQ指定需要在什么脚本之后执行(同目录下的),也就是指定该脚本的依赖,以确定执行顺序。
|
||||
# 如果没有依赖,就可以是空字符串。
|
||||
PREREQ=""
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# 上述部分是initramfs脚本的固定格式,不用动它。
|
||||
# 除非有依赖,才需要改 PREREQ 的值。
|
||||
|
||||
display_result()
|
||||
{
|
||||
#plymouth message --text="返回值: $RET"
|
||||
#sleep 3
|
||||
|
||||
if [ $RET -eq 200 ]; then
|
||||
plymouth message --text="没有找到备份还原配置文件/etc/.bootinfo"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 201 ]; then
|
||||
plymouth message --text="无法打开备份还原配置文件/etc/.bootinfo"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 202 ]; then
|
||||
plymouth message --text="备份还原配置文件内容不对/etc/.bootinfo"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 100 ]; then
|
||||
plymouth message --text="备份分区空间不足,请删除过期或者不需要的备份"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 101 ]; then
|
||||
plymouth message --text="备份还原分区路径不是/backup"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 300 ]; then
|
||||
plymouth message --text="没有有效的备份,不能还原系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 301 ]; then
|
||||
plymouth message --text="备份文件不存在,不能还原系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 302 ]; then
|
||||
plymouth message --text="不能启动还原进程,请重新还原系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 303 ]; then
|
||||
plymouth message --text="还原失败,请重新还原系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 401 ]; then
|
||||
plymouth message --text="不能启动备份还原分区安装进程,请重新启动系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 402 ]; then
|
||||
plymouth message --text="备份还原分区安装进程等待结束时出错,请重新启动系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 403 ]; then
|
||||
plymouth message --text="备份还原分区不存在或没有mount"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 501 ]; then
|
||||
plymouth message --text="不能启动备份进程,请重新备份系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 502 ]; then
|
||||
plymouth message --text="备份失败,请重新备份系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 700 ]; then
|
||||
plymouth message --text="mount_fstab用法不正确,无法安装系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 701 ]; then
|
||||
plymouth message --text="/etc/fstab不存在,无法备份系统"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 702 ]; then
|
||||
plymouth message --text="/etc/fstab打开失败,无法备份系统"
|
||||
sleep 3
|
||||
reboot
|
||||
fi
|
||||
}
|
||||
|
||||
# 需要先指定BACKUP_FLAG,例如设置为 BACKUP_FLAG=backup,那么内核参数就可以选择下述两种方式的一种了
|
||||
# 1. backup 只要有backup,就表示需要备份
|
||||
# 2. backup=0 或者 backup=1 0表示不用备份,1表示需要备份。
|
||||
# 当然,还可以选择别的字符串做关键字,但一定要指定BACKUP_FLAG内容。
|
||||
#BACKUP_FLAG=
|
||||
NEED_BACKUP=
|
||||
NEED_RESTORE=
|
||||
# 针对 BACKUP_FLAG 为简单字符串(非键值对)的情况,可以这样获取内核参数。
|
||||
for x in $(cat /proc/cmdline); do
|
||||
if [ "$x" = "$BACKUP_FLAG" ]; then
|
||||
NEED_BACKUP=y
|
||||
fi
|
||||
done
|
||||
|
||||
for x in $(cat /proc/cmdline); do
|
||||
if [ "$x" = "$RESTORE_FLAG" ]; then
|
||||
NEED_RESTORE=y
|
||||
fi
|
||||
done
|
||||
|
||||
# 然后就可以根据 $NEED_BACKUP 来进行操作了。
|
||||
|
||||
# 如果没有发现需要备份的标记,直接退出脚本,继续启动系统。
|
||||
|
||||
if [ "$NEED_BACKUP" = "y" ]; then
|
||||
mkdir /backup
|
||||
#useless: . /scripts/backup #就是本目录下的backup
|
||||
#useless: mount_fstab #定义在backup脚本中
|
||||
|
||||
#如果没有${rootmnt}/etc/fstab,则系统坏了,只能还原而不能备份.
|
||||
if [ ! -e ${rootmnt}/etc/fstab ]; then
|
||||
#plymouth message --text="The system has been destroyed and can not be backuped."
|
||||
plymouth message --text="/etc/fstab不存在,无法备份."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
if [ ! -e ${rootmnt}/etc/.bootinfo ]; then
|
||||
#plymouth message --text="The system has been destroyed and you can restore it in the next version."
|
||||
plymouth message --text="/etc/.bootinfo不存在,无法备份."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mount_fstab_efi ${rootmnt} mount
|
||||
plymouth message --text="正在备份系统"
|
||||
#plymouth message --text="Backuping the system, please wait for a moment."
|
||||
backup-auto-efi --autobackup ${rootmnt} /backup
|
||||
|
||||
RET=$?
|
||||
display_result $RET
|
||||
|
||||
plymouth message --text="系统备份完成"
|
||||
#plymouth message --text="The system has been backuped."
|
||||
#mount_fstab ${rootmnt} umount #because root
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$NEED_RESTORE" = "y" ]; then
|
||||
#如果没有${rootmnt}/etc/fstab,则系统坏了,应该能还原,但需要在下一个版本中支持。
|
||||
if [ ! -e ${rootmnt}/etc/fstab ]; then
|
||||
#plymouth message --text="The system has been destroyed and you can restore it in the next version."
|
||||
plymouth message --text="/etc/fstab不存在,无法还原."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
if [ ! -e ${rootmnt}/etc/.bootinfo ]; then
|
||||
#plymouth message --text="The system has been destroyed and you can restore it in the next version."
|
||||
plymouth message --text="/etc/.bootinfo不存在,无法还原."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mount_fstab_efi ${rootmnt} mount
|
||||
mkdir /backup
|
||||
plymouth message --text="正在还原系统"
|
||||
#plymouth message --text="Restoring the system, please wait for a moment."
|
||||
mount -o remount,rw ${rootmnt}
|
||||
#. /scripts/backup
|
||||
backup-auto-efi --autorestore ${rootmnt} /backup
|
||||
|
||||
RET=$?
|
||||
display_result $RET
|
||||
|
||||
if [ ! -e ${rootmnt}/proc ]; then
|
||||
mkdir ${rootmnt}/proc
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/sys ]; then
|
||||
mkdir ${rootmnt}/sys
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/dev ]; then
|
||||
mkdir ${rootmnt}/dev
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/run ]; then
|
||||
mkdir ${rootmnt}/run
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/backup ]; then
|
||||
mkdir ${rootmnt}/backup
|
||||
fi
|
||||
|
||||
plymouth message --text="系统还原完成"
|
||||
#plymouth message --text="The system has been restored."
|
||||
#/scripts/mount_fstab ${rootmnt} umount #because root
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 否则
|
||||
# TODO 执行备份操作
|
||||
|
||||
# 此时根分区已经挂载在 ${rootmnt} 处了,直接使用 ${rootmnt} 就可以了。
|
||||
# 例如查看lsb-release文件
|
||||
# cat ${rootmnt}/etc/lsb-release
|
||||
# 如果想要根据 UUID 或 LABEL 来确定分区,还可以执行blkid命令。例如,
|
||||
# /sbin/blkid -U <UUID> 该命令返回UUID对应的分区设备
|
||||
# /sbin/blkid -L <LABEL> 该命令返回LABEL对应的分区设备
|
||||
# 如果需要安装一些命令,需要写一个initramfs的hook脚本。
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,230 @@
|
|||
#!/bin/bash
|
||||
|
||||
BACKUP_FLAG=backup
|
||||
RESTORE_FLAG=restore
|
||||
|
||||
# 把这个文件放在 /usr/share/initramfs-tools/scripts/local-bottom/ 目录下。
|
||||
# 权限为 0755,在自动更新initrd时,这个脚本就被放到initrd中了,例如,
|
||||
# update-initramfs -u
|
||||
# 更新后,这个脚本将在initrd 运行到 local-bottom 阶段时自动执行。
|
||||
# 此时根分区已经挂载到了${rootmnt}下,可以直接访问该分区的文件。
|
||||
|
||||
|
||||
|
||||
# PREREQ指定需要在什么脚本之后执行(同目录下的),也就是指定该脚本的依赖,以确定执行顺序。
|
||||
# 如果没有依赖,就可以是空字符串。
|
||||
PREREQ=""
|
||||
|
||||
prereqs()
|
||||
{
|
||||
echo "$PREREQ"
|
||||
}
|
||||
|
||||
case $1 in
|
||||
prereqs)
|
||||
prereqs
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# 上述部分是initramfs脚本的固定格式,不用动它。
|
||||
# 除非有依赖,才需要改 PREREQ 的值。
|
||||
|
||||
display_result()
|
||||
{
|
||||
if [ $RET -eq 200 ]; then
|
||||
plymouth message --text="Can't find /etc/.bootinfo."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 201 ]; then
|
||||
plymouth message --text="Can't open /etc/.bootinfo."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 202 ]; then
|
||||
plymouth message --text="/etc/.bootinfo is not correct."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 100 ]; then
|
||||
plymouth message --text="The backup disk space is not enough, please delete unnecessary backups."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 101 ]; then
|
||||
plymouth message --text="The backup disk should be /backup"
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 300 ]; then
|
||||
plymouth message --text="There are not any good backups,and you can't restore the system."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 301 ]; then
|
||||
plymouth message --text="There is not the backup directory of your selection, and you can't restore it."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 302 ]; then
|
||||
plymouth message --text="The restore process can't be started."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 303 ]; then
|
||||
plymouth message --text="Failed to restore the system, please redo it."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 401 ]; then
|
||||
plymouth message --text="The mount process for backup disk can't be started."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 402 ]; then
|
||||
plymouth message --text="Failed to wait for the process for backup disk."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 403 ]; then
|
||||
plymouth message --text="The backup disk does not exist or it is not mounted."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 501 ]; then
|
||||
plymouth message --text="Can't start the backup process."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 502 ]; then
|
||||
plymouth message --text="Failed to backup the system."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 700 ]; then
|
||||
plymouth message --text="The usage of mount_fstab is not correct."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 701 ]; then
|
||||
plymouth message --text="Failed to backup the system because there is not /etc/fstab."
|
||||
sleep 3
|
||||
reboot
|
||||
elif [ $RET -eq 702 ]; then
|
||||
plymouth message --text="Can't to open /etc/fstab."
|
||||
sleep 3
|
||||
reboot
|
||||
fi
|
||||
}
|
||||
|
||||
# 需要先指定BACKUP_FLAG,例如设置为 BACKUP_FLAG=backup,那么内核参数就可以选择下述两种方式的一种了
|
||||
# 1. backup 只要有backup,就表示需要备份
|
||||
# 2. backup=0 或者 backup=1 0表示不用备份,1表示需要备份。
|
||||
# 当然,还可以选择别的字符串做关键字,但一定要指定BACKUP_FLAG内容。
|
||||
#BACKUP_FLAG=
|
||||
NEED_BACKUP=
|
||||
NEED_RESTORE=
|
||||
# 针对 BACKUP_FLAG 为简单字符串(非键值对)的情况,可以这样获取内核参数。
|
||||
for x in $(cat /proc/cmdline); do
|
||||
if [ "$x" = "$BACKUP_FLAG" ]; then
|
||||
NEED_BACKUP=y
|
||||
fi
|
||||
done
|
||||
|
||||
for x in $(cat /proc/cmdline); do
|
||||
if [ "$x" = "$RESTORE_FLAG" ]; then
|
||||
NEED_RESTORE=y
|
||||
fi
|
||||
done
|
||||
|
||||
# 然后就可以根据 $NEED_BACKUP 来进行操作了。
|
||||
|
||||
# 如果没有发现需要备份的标记,直接退出脚本,继续启动系统。
|
||||
|
||||
if [ "$NEED_BACKUP" = "y" ]; then
|
||||
mkdir /backup
|
||||
#useless: . /scripts/backup #就是本目录下的backup
|
||||
#useless: mount_fstab #定义在backup脚本中
|
||||
|
||||
#如果没有${rootmnt}/etc/fstab,则系统坏了,只能还原而不能备份.
|
||||
if [ ! -e ${rootmnt}/etc/fstab ]; then
|
||||
plymouth message --text="The system has been destroyed and can not be backuped."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
if [ ! -e ${rootmnt}/etc/.bootinfo ]; then
|
||||
plymouth message --text="The system has been destroyed and you can restore it in the next version."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mount_fstab_efi ${rootmnt} mount
|
||||
#plymouth message --text="正在备份系统"
|
||||
plymouth message --text="Backuping the system, please wait for a moment."
|
||||
backup-auto-efi --autobackup ${rootmnt} /backup
|
||||
|
||||
RET=$?
|
||||
display_result $RET
|
||||
|
||||
#plymouth message --text="系统备份完成"
|
||||
plymouth message --text="The system has been backuped."
|
||||
#mount_fstab ${rootmnt} umount #because root
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$NEED_RESTORE" = "y" ]; then
|
||||
#如果没有${rootmnt}/etc/fstab,则系统坏了,应该能还原,但需要在下一个版本中支持。
|
||||
if [ ! -e ${rootmnt}/etc/fstab ]; then
|
||||
plymouth message --text="The system has been destroyed and you can restore it in the next version."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
if [ ! -e ${rootmnt}/etc/.bootinfo ]; then
|
||||
plymouth message --text="The system has been destroyed and you can restore it in the next version."
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mount_fstab_efi ${rootmnt} mount
|
||||
mkdir /backup
|
||||
#plymouth message --text="正在还原系统"
|
||||
plymouth message --text="Restoring the system, please wait for a moment."
|
||||
mount -o remount,rw ${rootmnt}
|
||||
#. /scripts/backup
|
||||
backup-auto-efi --autorestore ${rootmnt} /backup
|
||||
|
||||
RET=$?
|
||||
display_result $RET
|
||||
|
||||
if [ ! -e ${rootmnt}/proc ]; then
|
||||
mkdir ${rootmnt}/proc
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/sys ]; then
|
||||
mkdir ${rootmnt}/sys
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/dev ]; then
|
||||
mkdir ${rootmnt}/dev
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/run ]; then
|
||||
mkdir ${rootmnt}/run
|
||||
fi
|
||||
|
||||
if [ ! -e ${rootmnt}/backup ]; then
|
||||
mkdir ${rootmnt}/backup
|
||||
fi
|
||||
|
||||
#plymouth message --text="系统还原完成"
|
||||
plymouth message --text="The system has been restored."
|
||||
#/scripts/mount_fstab ${rootmnt} umount #because root
|
||||
sleep 3
|
||||
reboot
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 否则
|
||||
# TODO 执行备份操作
|
||||
|
||||
# 此时根分区已经挂载在 ${rootmnt} 处了,直接使用 ${rootmnt} 就可以了。
|
||||
# 例如查看lsb-release文件
|
||||
# cat ${rootmnt}/etc/lsb-release
|
||||
# 如果想要根据 UUID 或 LABEL 来确定分区,还可以执行blkid命令。例如,
|
||||
# /sbin/blkid -U <UUID> 该命令返回UUID对应的分区设备
|
||||
# /sbin/blkid -L <LABEL> 该命令返回LABEL对应的分区设备
|
||||
# 如果需要安装一些命令,需要写一个initramfs的hook脚本。
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,124 @@
|
|||
#!/bin/bash
|
||||
|
||||
parse_device(){
|
||||
device=$1
|
||||
if echo $device | grep -E -q "^UUID="; then
|
||||
echo $device | sed 's:^UUID=:/dev/disk/by-uuid/:' | tr -d "\n"
|
||||
elif echo $device | grep -E -q "^LABEL="; then
|
||||
echo $device | sed 's:^LABEL=:/dev/disk/by-label/:' | tr -d "\n"
|
||||
else
|
||||
echo $device | tr -d "\n"
|
||||
fi
|
||||
}
|
||||
|
||||
findmnt_dev()
|
||||
{
|
||||
fstab_path=$1
|
||||
target_dir=$2
|
||||
cat "$fstab_path" | grep -Ev "^#" | awk '{print $1 " " $2 " " $3 " " $4 " " $5 " " $6}' |
|
||||
while read device mntdir fstype options dump passno ;
|
||||
do
|
||||
if [ "$mntdir" = "$target_dir" ] ; then
|
||||
parse_device "$device"
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
is_remote(){
|
||||
fstype=$1
|
||||
if [ nfs = "$fstype" ] || [ nfs4 = "$fstype" ] || [ smbfs = "$fstype" ] || [ cifs = "$fstype" ] || [ coda = "$fstype" ] || [ ncp = "$fstype" ]; then
|
||||
echo yes
|
||||
elif [ ncpfs = "$fstype" ] || [ ocfs2 = "$fstype" ] || [ gfs = "$fstype" ] || [ gfs2 = "$fstype" ] || [ ceph = "$fstype" ]; then
|
||||
echo yes
|
||||
else
|
||||
echo no
|
||||
fi
|
||||
}
|
||||
|
||||
parse_options(){
|
||||
options=$1
|
||||
optstr="showthrough bootwait nobootwait timeout ro"
|
||||
echo "$options" | awk -v optstr="$optstr" 'BEGIN{FS=","; split(optstr, opts, " ");} {
|
||||
result="";
|
||||
for( i=1; i<=NF; i++ ){
|
||||
flag=0;
|
||||
for( opt in opts ){
|
||||
if( $i == opts[opt] ){
|
||||
flag=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( flag == 1 )
|
||||
continue;
|
||||
|
||||
if( i==1 )
|
||||
result=$i;
|
||||
else
|
||||
result=result","$i;
|
||||
}
|
||||
|
||||
print result
|
||||
}'
|
||||
}
|
||||
|
||||
is_system_partition(){
|
||||
mntdir=$1
|
||||
sys_parts="/boot /home /var /usr /srv /opt /usr/local" # files under /tmp is temporary, need to remove
|
||||
|
||||
echo $sys_parts | grep -Eq "(^| )"$mntdir"( |$)" && echo "yes" || echo "no"
|
||||
}
|
||||
|
||||
|
||||
|
||||
mount_fstab(){
|
||||
fstab_path=${rootmnt}/etc/fstab
|
||||
if [ ! -e "$fstab_path" ]; then
|
||||
fstab_path=/etc/fstab-backup
|
||||
fi
|
||||
echo "mount $fstab_path begin"
|
||||
cat "$fstab_path" | grep -Ev "^#" | awk '{print $1 " " $2 " " $3 " " $4 " " $5 " " $6}' |
|
||||
while read device mntdir fstype options dump passno ;
|
||||
do
|
||||
device=$(parse_device $device)
|
||||
#mntopts=$(parse_options $options)
|
||||
mntopts=defaults,rw
|
||||
|
||||
#nodev filesystems
|
||||
( cat /proc/filesystems | grep "$fstype" | grep -q nodev ) && continue
|
||||
|
||||
#virtual or network filesystems
|
||||
([ none = "$mntdir" ] || [ yes = $(is_remote $fstype) ]) && continue
|
||||
|
||||
#swap or rootfs
|
||||
([ swap = "$fstype" ] || [ / = "$mntdir" ]) && continue
|
||||
#[ swap = "$fstype" ] || [ / = "$mntdir" ] || [ /home = "$mntdir" ] || [ /var/log = "$mntdir" ]&& continue
|
||||
|
||||
#not system partition
|
||||
#[ no = $(is_system_partition $mntdir) ] && continue
|
||||
|
||||
#去掉首字符'/'
|
||||
#mntdir_name=$(echo $mntdir | sed 's:^/::g')
|
||||
#target_mntdir="/$(echo $mntdir_name | sed 's:/:-:g').orig"
|
||||
target_mntdir=${rootmnt}${mntdir}
|
||||
mkdir -p "$target_mntdir"
|
||||
if [[ $options =~ bind ]] ; then
|
||||
# bind挂载的就不再挂了
|
||||
echo "mount -o $options ${rootmnt}${device} $target_mntdir"
|
||||
mount -o $options "${rootmnt}${device}" "$target_mntdir"
|
||||
else
|
||||
echo "mount -n -t $fstype -o $mntopts $device $target_mntdir"
|
||||
mount -n -t $fstype -o $mntopts $device "$target_mntdir"
|
||||
fi
|
||||
|
||||
#如果一个分区已经安装了,则下列会报错后不再继续
|
||||
#if [ $? -ne 0 ]; then
|
||||
# panic "Failed to mount %s on %s" "$device" "$target_mntdir"
|
||||
# break
|
||||
#fi
|
||||
|
||||
done || exit 1
|
||||
echo "mount $fstab_path end"
|
||||
}
|
||||
|
||||
mount_fstab
|
|
@ -0,0 +1,445 @@
|
|||
#include "databackupproxy.h"
|
||||
#include <QStorageInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <kysec/status.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(DataBackupProxy)
|
||||
|
||||
DataBackupProxy::DataBackupProxy()
|
||||
{
|
||||
m_isOnlyCheck = true;
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_p = nullptr;
|
||||
m_size = 0;
|
||||
m_calc = new CalcBackupSize(this);
|
||||
|
||||
connect(this, &DataBackupProxy::cancel, this, &DataBackupProxy::cancelEx);
|
||||
}
|
||||
|
||||
DataBackupProxy::~DataBackupProxy()
|
||||
{
|
||||
delete m_p;
|
||||
m_p = nullptr;
|
||||
|
||||
delete m_calc;
|
||||
m_calc = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool DataBackupProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "DataBackupProxy::checkEnv invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
MyMountProxy mountProxy;
|
||||
if ( MountResult::MOUNTED != mountProxy.mountBackupPartition() ) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、判断备份是否增量备份
|
||||
isIncBackup();
|
||||
|
||||
// 3、检测空间是否满足备份
|
||||
calcSizeForBackup();
|
||||
|
||||
qDebug() << "DataBackupProxy::checkEnv invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行备份逻辑
|
||||
*/
|
||||
void DataBackupProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "DataBackupProxy::doWorkEx invoke begin";
|
||||
|
||||
m_isOnlyCheck = false;
|
||||
// 环境检测
|
||||
checkEnvEx();
|
||||
|
||||
qDebug() << "DataBackupProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消操作
|
||||
*/
|
||||
void DataBackupProxy::cancelEx()
|
||||
{
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_calc)
|
||||
m_calc->stop();
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void DataBackupProxy::deleteFailedData()
|
||||
{
|
||||
if (m_curUuid.isEmpty())
|
||||
return;
|
||||
|
||||
// 1、删除备份目录
|
||||
QString destPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid;
|
||||
destPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-rf";
|
||||
args << destPath;
|
||||
QProcess::execute("rm", args);
|
||||
|
||||
// 2、删除xml文件中的备份项
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.deleteItem(m_curUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否增量备份
|
||||
* @return true,增量备份; false,全量备份
|
||||
*/
|
||||
bool DataBackupProxy::isIncBackup()
|
||||
{
|
||||
QString backupPath;
|
||||
ParseBackupList::BackupPoint point;
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
}
|
||||
|
||||
backupPath.replace("//", "/");
|
||||
if (Utils::isDirExist(backupPath)) {
|
||||
m_backupWrapper.m_bIncrement = true;
|
||||
m_backupWrapper.m_type = BackupType::INC_BACKUP_DATA;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验剩余空间是否满足备份
|
||||
*/
|
||||
bool DataBackupProxy::checkFreeCapacity(qint64 itotalSize)
|
||||
{
|
||||
qDebug() << "DataBackupProxy::checkFreeCapacity invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return false;
|
||||
|
||||
// 1、计算待备份数据的大小
|
||||
m_size = itotalSize;
|
||||
// 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留5M的空间
|
||||
itotalSize += 5 * MB;
|
||||
|
||||
// 2、计算备份分区剩余空间大小
|
||||
QString backupPath(Utils::getSysRootPath() + BACKUP_PATH);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo backupDisk(backupPath);
|
||||
qint64 freeSize = backupDisk.bytesAvailable();
|
||||
|
||||
// 3、校验空间是否足够
|
||||
bool result = true;
|
||||
if (itotalSize > freeSize) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
result = false;
|
||||
return result;
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
}
|
||||
|
||||
if (m_isOnlyCheck)
|
||||
return result;
|
||||
|
||||
// 开始备份
|
||||
doBackup();
|
||||
|
||||
qDebug() << "DataBackupProxy::checkFreeCapacity invoke end";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算备份所需空间大小
|
||||
* @return 计算备份所需空间大小,单位字节
|
||||
*/
|
||||
void DataBackupProxy::calcSizeForBackup()
|
||||
{
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::TRY_INC_DATA_BACKUP);
|
||||
destPath += BACKUP_SNAPSHOTS_PATH;
|
||||
destPath += "/";
|
||||
destPath += m_backupWrapper.m_uuid;
|
||||
destPath += "/data/";
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::TRY_DATA_BACKUP);
|
||||
destPath += CHECK_PATH;
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
Utils::mkpath(destPath);
|
||||
|
||||
connect(m_calc, &CalcBackupSize::finished, this, &DataBackupProxy::checkFreeCapacity);
|
||||
m_calc->start(args, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return rsync的参数信息
|
||||
*/
|
||||
QStringList DataBackupProxy::getRsyncArgs(DataBackupScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
QString backupFile = "/tmp/.backup.user";
|
||||
Utils::writeFileByLines(backupFile, m_backupWrapper.m_backupPaths);
|
||||
|
||||
switch (scene) {
|
||||
case DataBackupScene::DATA_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
case DataBackupScene::INC_DATA_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
case DataBackupScene::TRY_DATA_BACKUP :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
case DataBackupScene::TRY_INC_DATA_BACKUP :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
args << "--files-from" << backupFile;
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份
|
||||
*/
|
||||
void DataBackupProxy::doBackup()
|
||||
{
|
||||
qDebug() << "DataBackupProxy::doBackup invoke begin";
|
||||
|
||||
// 准备
|
||||
if (!doPrepare())
|
||||
return ;
|
||||
|
||||
// 启动数据备份
|
||||
backupData();
|
||||
|
||||
qDebug() << "DataBackupProxy::doBackup invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份准备
|
||||
* @return true,准备成功;false,准备失败
|
||||
*/
|
||||
bool DataBackupProxy::doPrepare()
|
||||
{
|
||||
qDebug() << "DataBackupProxy::doPrepare invoke begin";
|
||||
|
||||
m_bSuccess = false;
|
||||
|
||||
// 1、设置当前备份的Uuid
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
// 新增备份点,不指定uuid的场景
|
||||
m_curUuid += Utils::createUuid();
|
||||
} else {
|
||||
// 指定uuid备份的场景
|
||||
m_curUuid = m_backupWrapper.m_uuid;
|
||||
}
|
||||
|
||||
// 2、准备备份目录及文件
|
||||
m_destPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data";
|
||||
m_destPath.replace("//", "/");
|
||||
if (!Utils::mkpath(m_destPath)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_userFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE;
|
||||
m_userFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(m_userFile, m_backupWrapper.m_backupPaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(m_userFile) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_excludeUserFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
m_excludeUserFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(m_excludeUserFile, m_backupWrapper.m_backupExcludePaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(m_excludeUserFile) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、记录/backup/snapshots/backuplist.xml文件
|
||||
if (!recordBackupPoint()) {
|
||||
qCritical() << "add or update item to backuplist.xml failed !";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "DataBackupProxy::doPrepare invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool DataBackupProxy::recordBackupPoint()
|
||||
{
|
||||
m_backupPoint.m_backupName = m_backupWrapper.m_backupName;
|
||||
m_backupPoint.m_uuid = m_curUuid;
|
||||
m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition;
|
||||
m_backupPoint.m_type = m_backupWrapper.m_type;
|
||||
m_backupPoint.m_size = Utils::StringBySize(m_size);
|
||||
m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING;
|
||||
if (0 < m_backupWrapper.m_frontUid)
|
||||
m_backupPoint.m_userId = QString::number(m_backupWrapper.m_frontUid);
|
||||
m_backupPoint.m_os = SystemInfo::m_os;
|
||||
m_backupPoint.m_arch = SystemInfo::m_arch;
|
||||
m_backupPoint.m_archdetect = SystemInfo::m_archDetect;
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份系统
|
||||
* @return true,备份成功;false,备份失败
|
||||
*/
|
||||
bool DataBackupProxy::backupData()
|
||||
{
|
||||
qDebug() << "DataBackupProxy::backupData invoke begin";
|
||||
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::INC_DATA_BACKUP);
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::DATA_BACKUP);
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
QString destPath = m_destPath + "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &DataBackupProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING;
|
||||
m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath));
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.updateItem(m_backupPoint);
|
||||
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(m_backupPoint.m_time + ","
|
||||
+ m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
+ m_backupWrapper.m_note + "," + m_backupPoint.m_size
|
||||
+ "," + QString::number(m_backupWrapper.m_frontUid)
|
||||
+ "," + m_backupWrapper.m_backupName);
|
||||
Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
|
||||
emit this->workResult(result);
|
||||
});
|
||||
m_p->start(args, false);
|
||||
|
||||
do_kylin_security(m_destPath);
|
||||
|
||||
qDebug() << "DataBackupProxy::backupData invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataBackupProxy::do_kylin_security(const QString& dstDir)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = kysec_getstatus();
|
||||
if (ret > 0) {
|
||||
QString seFilePath(dstDir + "/.exectl");
|
||||
QFile file(seFilePath);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef DATABACKUPPROXY_H
|
||||
#define DATABACKUPPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class DataBackupProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(DataBackupProxy)
|
||||
public:
|
||||
// 系统备份的几种场景
|
||||
enum DataBackupScene {
|
||||
DATA_BACKUP, // 系统备份
|
||||
INC_DATA_BACKUP, // 增量系统备份
|
||||
TRY_DATA_BACKUP, // 测试系统备份,可用于计算备份传输数据大小
|
||||
TRY_INC_DATA_BACKUP, // 测试增量系统备份,可用于计算备份传输数据大小
|
||||
};
|
||||
|
||||
explicit DataBackupProxy();
|
||||
virtual ~DataBackupProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
public slots:
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private slots:
|
||||
// 校验剩余空间是否满足备份
|
||||
bool checkFreeCapacity(qint64 itotalSize);
|
||||
|
||||
// 备份
|
||||
void doBackup();
|
||||
|
||||
private:
|
||||
// 计算备份所需空间大小
|
||||
void calcSizeForBackup();
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool recordBackupPoint();
|
||||
|
||||
// 备份准备
|
||||
bool doPrepare();
|
||||
|
||||
// 备份系统
|
||||
bool backupData();
|
||||
|
||||
protected:
|
||||
// 判断是否增量备份
|
||||
virtual bool isIncBackup();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(DataBackupScene scene);
|
||||
|
||||
void do_kylin_security(const QString& dstDir);
|
||||
|
||||
// 失败则删除相应数据
|
||||
virtual void deleteFailedData();
|
||||
|
||||
// 计算备份空间大小的进程
|
||||
CalcBackupSize *m_calc;
|
||||
// 是否只是检测
|
||||
bool m_isOnlyCheck;
|
||||
// 是否完成
|
||||
bool m_isFinished;
|
||||
// 是否成功
|
||||
bool m_bSuccess;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前备份目标目录
|
||||
QString m_destPath;
|
||||
// 当前备份所需空间大小
|
||||
qint64 m_size;
|
||||
// 备份点用户备份路径文件
|
||||
QString m_userFile;
|
||||
// 备份点排除备份路径文件
|
||||
QString m_excludeUserFile;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
};
|
||||
|
||||
#endif // DATABACKUPPROXY_H
|
|
@ -0,0 +1,156 @@
|
|||
#include "datarestoreproxy.h"
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "../common/utils.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(DataRestoreProxy)
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
DataRestoreProxy::DataRestoreProxy()
|
||||
{
|
||||
m_bSuccess = false;
|
||||
m_p = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
DataRestoreProxy::~DataRestoreProxy()
|
||||
{
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool DataRestoreProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "DataRestoreProxy::checkEnvEx invoke begin";
|
||||
|
||||
if (m_backupWrapper.m_iPosition == BackupPosition::CUSTOMIZE)
|
||||
m_prePath = m_backupWrapper.m_prefixDestPath;
|
||||
else
|
||||
m_prePath = Utils::getSysRootPath();
|
||||
|
||||
// 1、检测.user.txt是否存在
|
||||
m_userFile = m_prePath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + PATHS_USER_FILE;
|
||||
m_userFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_userFile)) {
|
||||
qCritical(".user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、检测.exclude.user.txt是否存在
|
||||
m_excludeUserFile = m_prePath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
m_excludeUserFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_excludeUserFile)) {
|
||||
qCritical(".exclude.user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、检测还原点是否存在
|
||||
m_backupPath = m_prePath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
m_backupPath.replace("//", "/");
|
||||
if (Utils::isDirEmpty(m_backupPath)) {
|
||||
qCritical("还原点{uuid}/data目录不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4、检测xml中的还原点是否还存在
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (m_backupPoint.m_uuid.isEmpty()) {
|
||||
qCritical("xml中还原点不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "DataRestoreProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行还原逻辑
|
||||
*/
|
||||
void DataRestoreProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "DataRestoreProxy::doWorkEx invoke begin";
|
||||
|
||||
// 1、校验
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
// 2、还原数据
|
||||
restoreData();
|
||||
|
||||
qDebug() << "DataRestoreProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList DataRestoreProxy::getRsyncArgs(DataRestoreScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
|
||||
switch (scene) {
|
||||
case DataRestoreScene::DATA_RESTORE :
|
||||
args << "--files-from" << m_userFile;
|
||||
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 数据还原
|
||||
*/
|
||||
void DataRestoreProxy::restoreData()
|
||||
{
|
||||
QStringList args = getRsyncArgs(DataRestoreScene::DATA_RESTORE);
|
||||
|
||||
m_srcPath = m_backupPath;
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
destPath.replace("//", "/");
|
||||
args << m_srcPath + "/";
|
||||
args << destPath + "/";
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &DataRestoreProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
if (result) {
|
||||
QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
Utils::writeBackupLog(time + "," + m_backupWrapper.m_uuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid)+ "," + m_backupPoint.m_backupName);
|
||||
}
|
||||
emit this->workResult(result);
|
||||
});
|
||||
|
||||
m_p->start(args, false);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef DATARESTOREPROXY_H
|
||||
#define DATARESTOREPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class DataRestoreProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(DataRestoreProxy)
|
||||
public:
|
||||
// 数据还原的几种场景
|
||||
enum DataRestoreScene {
|
||||
DATA_RESTORE, // 数据还原
|
||||
};
|
||||
|
||||
explicit DataRestoreProxy();
|
||||
virtual ~DataRestoreProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
private:
|
||||
// 数据还原
|
||||
void restoreData();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(DataRestoreScene scene);
|
||||
|
||||
// .user.txt文件路径
|
||||
QString m_userFile;
|
||||
// .exclude.user.txt文件路径
|
||||
QString m_excludeUserFile;
|
||||
// 备份数据所在的data目录
|
||||
QString m_backupPath;
|
||||
// 备份点前缀路径
|
||||
QString m_prePath;
|
||||
|
||||
// 是否还原成功
|
||||
bool m_bSuccess;
|
||||
// 当前还原源目录
|
||||
QString m_srcPath;
|
||||
// 还原进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
|
||||
};
|
||||
|
||||
#endif // DATARESTOREPROXY_H
|
|
@ -0,0 +1,97 @@
|
|||
#include "deletebackupproxy.h"
|
||||
#include <QProcess>
|
||||
#include <QDateTime>
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
#include "../common/utils.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(DeleteBackupProxy)
|
||||
|
||||
DeleteBackupProxy::DeleteBackupProxy()
|
||||
{}
|
||||
|
||||
DeleteBackupProxy::~DeleteBackupProxy()
|
||||
{}
|
||||
|
||||
void DeleteBackupProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "DeleteBackupProxy::doWorkEx invoke begin";
|
||||
|
||||
// 1、删除/backup/snapshots/backuplist.xml对应项
|
||||
if (!deleteXmlBackupPoint())
|
||||
return;
|
||||
|
||||
// 2、删除/backup/snapshots/{uuid}对应目录
|
||||
deleteBackupPointDir();
|
||||
|
||||
// 3、同时删除唯一识别文件中对应的条目
|
||||
Utils::deleteBackupUniqueRecord(m_backupWrapper.m_backupName);
|
||||
|
||||
// 删除成功信号
|
||||
emit workResult(true);
|
||||
|
||||
qDebug() << "DeleteBackupProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 删除/backup/snapshots/backuplist.xml对应项
|
||||
*/
|
||||
bool DeleteBackupProxy::deleteXmlBackupPoint()
|
||||
{
|
||||
qDebug() << "DeleteBackupProxy::deleteXmlBackupPoint invoke begin";
|
||||
|
||||
QString xmlPath;
|
||||
if (m_backupWrapper.m_iPosition == BackupPosition::LOCAL || m_backupWrapper.m_iPosition == BackupPosition::CUSTOMIZE)
|
||||
xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
else
|
||||
xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
// 查询节点
|
||||
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
|
||||
// 删除节点
|
||||
if (!m_backupWrapper.m_uuid.contains(QRegularExpression("^\\{.*-.*-.*-.*-.*\\}$")) || parse.deleteItem(m_backupWrapper.m_uuid) != ParseBackupList::SUCCESS) {
|
||||
qCritical() << QString("failed to delete %1 from backuplist.xml!").arg(m_backupWrapper.m_uuid);
|
||||
emit workResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "DeleteBackupProxy::deleteXmlBackupPoint invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 删除/backup/snapshots/uuid对应目录
|
||||
*/
|
||||
void DeleteBackupProxy::deleteBackupPointDir()
|
||||
{
|
||||
qDebug() << "DeleteBackupProxy::deleteBackupPointDir invoke begin";
|
||||
|
||||
QString uuidPath;
|
||||
if (m_backupPoint.m_iPosition == BackupPosition::LOCAL)
|
||||
uuidPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid;
|
||||
else if (m_backupPoint.m_iPosition == BackupPosition::CUSTOMIZE)
|
||||
uuidPath = m_backupPoint.m_path + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid;
|
||||
else
|
||||
uuidPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid;
|
||||
|
||||
uuidPath.replace("//", "/");
|
||||
|
||||
QStringList args;
|
||||
args << "-rf";
|
||||
args << uuidPath;
|
||||
QProcess::execute("rm", args);
|
||||
|
||||
QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
if ( int(BackupType::BACKUP_DATA) == m_backupPoint.m_type
|
||||
|| int(BackupType::INC_BACKUP_DATA) == m_backupPoint.m_type) {
|
||||
Utils::writeBackupLog(time + "," + m_backupWrapper.m_uuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid)+ "," + m_backupPoint.m_backupName);
|
||||
} else {
|
||||
Utils::writeBackupLog(time + "," + m_backupWrapper.m_uuid + "," + QString::number(m_backupWrapper.m_type) + ",,,," + m_backupPoint.m_backupName);
|
||||
}
|
||||
|
||||
qDebug() << "DeleteBackupProxy::deleteBackupPointDir invoke end";
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef DELETEBACKUPPROXY_H
|
||||
#define DELETEBACKUPPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class DeleteBackupProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(DeleteBackupProxy)
|
||||
public:
|
||||
explicit DeleteBackupProxy();
|
||||
virtual ~DeleteBackupProxy();
|
||||
|
||||
public:
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
private:
|
||||
bool deleteXmlBackupPoint();
|
||||
|
||||
void deleteBackupPointDir();
|
||||
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
};
|
||||
|
||||
#endif // DELETEBACKUPPROXY_H
|
|
@ -0,0 +1,180 @@
|
|||
#include "ghostimageproxy.h"
|
||||
#include <QStorageInfo>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <kysec/status.h>
|
||||
#include <unistd.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(GhostImageProxy)
|
||||
|
||||
GhostImageProxy::GhostImageProxy()
|
||||
{
|
||||
m_mksquashfs = nullptr;
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
|
||||
connect(this, &GhostImageProxy::cancel, this, &GhostImageProxy::cancelEx);
|
||||
}
|
||||
|
||||
GhostImageProxy::~GhostImageProxy()
|
||||
{
|
||||
delete m_mksquashfs;
|
||||
m_mksquashfs = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
*/
|
||||
bool GhostImageProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "GhostImageProxy::checkEnvEx invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
MyMountProxy mountProxy;
|
||||
if ( MountResult::MOUNTED != mountProxy.mountBackupPartition() ) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、校验backuppoint.xml中相应的备份节点是否存在
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList xmlParse(xmlPath);
|
||||
ParseBackupList::BackupPoint backupPoint = xmlParse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (backupPoint.m_backupName.isEmpty()) {
|
||||
emit checkResult(int(BackupResult::GHOST_CANNOT_FIND_BACKUPPOINT));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、校验备份数据是否存在
|
||||
QString dataPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
dataPath.replace("//", "/");
|
||||
if (Utils::isDirEmpty(dataPath)) {
|
||||
emit checkResult(int(BackupResult::GHOST_SRC_DIRECTORY_IS_NOT_EXIST));
|
||||
return false;
|
||||
}
|
||||
qint64 itotalSize = Utils::getDirOrFileSize(dataPath);
|
||||
|
||||
// 4、校验空间大小是否充足
|
||||
m_destPath = Utils::getSysRootPath() + GHOST_PATH;
|
||||
m_destPath.replace("//", "/");
|
||||
Utils::mkpath(m_destPath);
|
||||
m_kyimg = Utils::getSysRootPath() + GHOST_PATH + "/" + m_backupWrapper.m_backupName;
|
||||
m_kyimg.replace("//", "/");
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
QStorageInfo storageInfo(m_destPath);
|
||||
qint64 sizeAvailable = storageInfo.bytesAvailable();
|
||||
if (sizeAvailable < itotalSize / 2) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
return false;
|
||||
}
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "GhostImageProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务处理
|
||||
*/
|
||||
void GhostImageProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "GhostImageProxy::doWorkEx invoke begin";
|
||||
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
doGhostImage();
|
||||
|
||||
qDebug() << "GhostImageProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务取消
|
||||
*/
|
||||
void GhostImageProxy::cancelEx()
|
||||
{
|
||||
qDebug() << "GhostImageProxy::cancelEx invoke begin";
|
||||
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_mksquashfs)
|
||||
m_mksquashfs->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
|
||||
qDebug() << "GhostImageProxy::cancelEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void GhostImageProxy::deleteFailedData()
|
||||
{
|
||||
// 1、删除镜像文件
|
||||
if (!m_kyimg.isEmpty()) {
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ghost镜像
|
||||
*/
|
||||
void GhostImageProxy::doGhostImage()
|
||||
{
|
||||
qDebug() << "GhostImageProxy::doGhostImage invoke begin";
|
||||
|
||||
QStringList args;
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
args << m_kyimg;
|
||||
|
||||
m_mksquashfs = new MkSquashFSProcess(this);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::progress, this, &GhostImageProxy::progress);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::finished, this, [&](bool result) {
|
||||
qDebug() << "GhostImageProxy::finished invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
chown(m_kyimg.toLocal8Bit().data(), m_backupWrapper.m_frontUid, m_backupWrapper.m_gid);
|
||||
// QFileInfo fileInfo(m_kyimg);
|
||||
// QString imgSize = Utils::StringBySize(fileInfo.size());
|
||||
// QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
// Utils::writeBackupLog(time + ","
|
||||
// + m_backupWrapper.m_uuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
// + m_backupWrapper.m_note + "," + imgSize
|
||||
// + ",," + m_backupWrapper.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
emit this->workResult(result);
|
||||
|
||||
qDebug() << "GhostImageProxy::finished invoke end";
|
||||
});
|
||||
m_bSuccess = false;
|
||||
m_mksquashfs->start(args);
|
||||
|
||||
qDebug() << "GhostImageProxy::doGhostImage invoke end";
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef GHOSTIMAGEPROXY_H
|
||||
#define GHOSTIMAGEPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/mksquashfsprocess.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class GhostImageProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(GhostImageProxy)
|
||||
public:
|
||||
explicit GhostImageProxy();
|
||||
virtual ~GhostImageProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private:
|
||||
void doGhostImage();
|
||||
|
||||
void deleteFailedData();
|
||||
|
||||
// 存放.kyimg文件的目录
|
||||
QString m_destPath;
|
||||
// .kyimg文件
|
||||
QString m_kyimg;
|
||||
|
||||
// 压缩进程
|
||||
MkSquashFSProcess *m_mksquashfs;
|
||||
|
||||
// 是否成功
|
||||
bool m_bSuccess;
|
||||
// 是否完成
|
||||
bool m_isFinished;
|
||||
};
|
||||
|
||||
#endif // GHOSTIMAGEPROXY_H
|
|
@ -0,0 +1,33 @@
|
|||
#include <QCoreApplication>
|
||||
#include <QTextCodec>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydefine.h"
|
||||
#include "backupmanager_adaptor.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 以防客户端传入的参数中的中文信息乱码
|
||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
QCoreApplication a(argc, argv);
|
||||
a.setApplicationName("backup-daemon");
|
||||
a.setApplicationVersion("4.0.14");
|
||||
|
||||
// 初始化日志
|
||||
QString qsAppPath = QCoreApplication::applicationDirPath();
|
||||
Utils::initSysRootPath(qsAppPath);
|
||||
qInstallMessageHandler(Utils::customMessageHandler);
|
||||
Utils::initSystemInfo();
|
||||
|
||||
MyBackupManager* backup_deamon = new MyBackupManager;
|
||||
new ManagerAdaptor(backup_deamon);
|
||||
QDBusConnection conn = QDBusConnection::systemBus();
|
||||
|
||||
if (!conn.registerService("com.kylin.backup")) {
|
||||
qDebug() << conn.lastError().message();
|
||||
}
|
||||
|
||||
conn.registerObject("/", backup_deamon);
|
||||
|
||||
return a.exec();
|
||||
}
|
|
@ -0,0 +1,590 @@
|
|||
/**
|
||||
* brief 程序比较小,将接口层和控制层合到一起;主要做一些任务分发,状态监控等一些简单工作;复杂的耗时的逻辑放到任务中moveToThread中去执行
|
||||
*/
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusUnixFileDescriptor>
|
||||
#include <QDBusConnection>
|
||||
#include <mutex>
|
||||
#include <sys/reboot.h>
|
||||
#include <kysec/status.h>
|
||||
#include "mybackupmanager.h"
|
||||
#include "../common/utils.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "workerfactory.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
MyBackupManager::MyBackupManager()
|
||||
{
|
||||
// 注册BackupWrapper类型,之后qdbus接口才能使用
|
||||
BackupWrapper::registerMetaType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
MyBackupManager::~MyBackupManager()
|
||||
{
|
||||
if (workerThread.isRunning()) {
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 挂载backup分区,兼容提供给自动更新模块的老接口
|
||||
* @return
|
||||
*/
|
||||
int MyBackupManager::Mount_backup_partition()
|
||||
{
|
||||
m_needUmount = false;
|
||||
MyMountProxy mymount;
|
||||
return int(mymount.mountBackupPartition());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 卸载backup分区
|
||||
* @return
|
||||
*/
|
||||
bool MyBackupManager::umountBackupPartition()
|
||||
{
|
||||
m_needUmount = true;
|
||||
return umountBackup();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 卸载backup分区
|
||||
* @return
|
||||
*/
|
||||
bool MyBackupManager::umountBackup()
|
||||
{
|
||||
// /backup分区卸载
|
||||
if (m_needUmount && m_isActive) {
|
||||
QTimer::singleShot(5*1000, this, &MyBackupManager::umountBackup);
|
||||
return true;
|
||||
} else if (m_needUmount) {
|
||||
MyMountProxy mymount;
|
||||
return mymount.umountBackupPartition();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @param backupWrapper,参数
|
||||
* @return 0,正确启动;非0,出现错误
|
||||
*/
|
||||
int MyBackupManager::checkEnv(const BackupWrapper& backupWrapper)
|
||||
{
|
||||
qDebug("MyBackupManager::checkEnv invoke begin");
|
||||
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
|
||||
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
|
||||
return int(BackupResult::LOCK_PROGRAM_FAIL);
|
||||
}
|
||||
|
||||
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
|
||||
if (nullptr == worker) {
|
||||
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
|
||||
return int(BackupResult::NO_FOUND_DEALCLASS);
|
||||
}
|
||||
|
||||
worker->setParam(backupWrapper);
|
||||
connect(worker, &Worker::checkResult, this, [&] (int result) {
|
||||
emit this->sendEnvCheckResult(result);
|
||||
this->finished();
|
||||
});
|
||||
worker->moveToThread(&workerThread);
|
||||
connect(&workerThread, &MyThread::started, worker, &Worker::checkEnv);
|
||||
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
qDebug("MyBackupManager::checkEnv invoke end");
|
||||
return int(BackupResult::BACKUP_RESULT_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份
|
||||
* @param backupWrapper
|
||||
* @return 0,正确启动备份;非0,出现错误
|
||||
*/
|
||||
int MyBackupManager::goBackup(const BackupWrapper& backupWrapper)
|
||||
{
|
||||
qDebug("MyBackupManager::goBackup invoke begin");
|
||||
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
|
||||
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
|
||||
return int(BackupResult::LOCK_PROGRAM_FAIL);
|
||||
}
|
||||
|
||||
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
|
||||
if (nullptr == worker) {
|
||||
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
|
||||
return int(BackupResult::NO_FOUND_DEALCLASS);
|
||||
}
|
||||
|
||||
worker->setParam(backupWrapper);
|
||||
connect(worker, &Worker::checkResult, this, [&](int result) {
|
||||
emit this->sendEnvCheckResult(result);
|
||||
|
||||
switch (result) {
|
||||
case int(BackupResult::CHECK_ENV_SUCCESS) :
|
||||
case int(BackupResult::MKSQUASHFS_START_SUCCESS) :
|
||||
case int(BackupResult::BACKUP_START_SUCCESS) :
|
||||
case int(BackupResult::START_CANCEL) :
|
||||
break;
|
||||
default:
|
||||
this->finished();
|
||||
break;
|
||||
}
|
||||
});
|
||||
connect(worker, &Worker::progress, this, [&](int rate) {
|
||||
emit this->progress(int(BackupState::WORKING), rate);
|
||||
});
|
||||
connect(worker, &Worker::workResult, this, [&] (bool result) {
|
||||
emit this->backupFinished(result);
|
||||
this->finished();
|
||||
});
|
||||
worker->moveToThread(&workerThread);
|
||||
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
|
||||
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
|
||||
connect(&workerThread, &MyThread::cancelWork, worker, &Worker::cancel);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
qDebug("MyBackupManager::goBackup invoke end");
|
||||
return int(BackupResult::BACKUP_RESULT_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 还原
|
||||
* @param backupWrapper
|
||||
* @return
|
||||
*/
|
||||
int MyBackupManager::goRestore(const BackupWrapper& backupWrapper)
|
||||
{
|
||||
qDebug("MyBackupManager::goRestore invoke begin");
|
||||
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
|
||||
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
|
||||
return int(BackupResult::LOCK_PROGRAM_FAIL);
|
||||
}
|
||||
|
||||
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
|
||||
if (nullptr == worker) {
|
||||
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
|
||||
return int(BackupResult::NO_FOUND_DEALCLASS);
|
||||
}
|
||||
|
||||
worker->setParam(backupWrapper);
|
||||
connect(worker, &Worker::checkResult, this, [&](int result) {
|
||||
emit this->sendEnvCheckResult(result);
|
||||
|
||||
switch (result) {
|
||||
case int(BackupResult::CHECK_ENV_SUCCESS) :
|
||||
case int(BackupResult::RESTORE_START_SUCCESS) :
|
||||
break;
|
||||
default:
|
||||
this->finished();
|
||||
break;
|
||||
}
|
||||
});
|
||||
connect(worker, &Worker::progress, this, [&](int rate) {
|
||||
emit this->progress(int(BackupState::WORKING), rate);
|
||||
});
|
||||
connect(worker, &Worker::workResult, this, [&] (bool result) {
|
||||
emit this->sendRestoreResult(result);
|
||||
this->finished();
|
||||
});
|
||||
worker->moveToThread(&workerThread);
|
||||
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
|
||||
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
qDebug("MyBackupManager::goRestore invoke end");
|
||||
return int(BackupResult::BACKUP_RESULT_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 删除备份
|
||||
* @param backupWrapper
|
||||
* @return
|
||||
*/
|
||||
int MyBackupManager::deleteBackupPoint(const BackupWrapper& backupWrapper)
|
||||
{
|
||||
qDebug("MyBackupManager::deleteBackupPoint invoke begin");
|
||||
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
|
||||
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
|
||||
return int(BackupResult::LOCK_PROGRAM_FAIL);
|
||||
}
|
||||
|
||||
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
|
||||
if (nullptr == worker) {
|
||||
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
|
||||
return int(BackupResult::NO_FOUND_DEALCLASS);
|
||||
}
|
||||
|
||||
worker->setParam(backupWrapper);
|
||||
connect(worker, &Worker::workResult, this, [&] (bool result) {
|
||||
emit this->sendDeleteResult(result);
|
||||
this->finished();
|
||||
});
|
||||
worker->moveToThread(&workerThread);
|
||||
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
|
||||
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
qDebug("MyBackupManager::deleteBackupPoint invoke end");
|
||||
return int(BackupResult::BACKUP_RESULT_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ghost镜像
|
||||
* @param backupWrapper
|
||||
* @return
|
||||
*/
|
||||
int MyBackupManager::ghostBackup(const BackupWrapper& backupWrapper)
|
||||
{
|
||||
qDebug("MyBackupManager::ghostBackup invoke begin");
|
||||
if (m_isActive || !lock(backupWrapper.m_frontUid)) {
|
||||
emit sendEnvCheckResult(int(BackupResult::LOCK_PROGRAM_FAIL));
|
||||
return int(BackupResult::LOCK_PROGRAM_FAIL);
|
||||
}
|
||||
|
||||
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
|
||||
if (nullptr == worker) {
|
||||
emit sendEnvCheckResult(int(BackupResult::NO_FOUND_DEALCLASS));
|
||||
return int(BackupResult::NO_FOUND_DEALCLASS);
|
||||
}
|
||||
|
||||
worker->setParam(backupWrapper);
|
||||
connect(worker, &Worker::checkResult, this, [&](int result) {
|
||||
emit this->sendEnvCheckResult(result);
|
||||
|
||||
switch (result) {
|
||||
case int(BackupResult::CHECK_ENV_SUCCESS) :
|
||||
case int(BackupResult::GHOST_START_SUCCESS) :
|
||||
case int(BackupResult::MKSQUASHFS_DO_SUCCESS) :
|
||||
case int(BackupResult::START_CANCEL) :
|
||||
break;
|
||||
default:
|
||||
this->finished();
|
||||
break;
|
||||
}
|
||||
});
|
||||
connect(worker, &Worker::progress, this, [&](int rate) {
|
||||
emit this->progress(int(BackupState::WORKING), rate);
|
||||
});
|
||||
connect(worker, &Worker::workResult, this, [&] (bool result) {
|
||||
emit this->sendGhostBackupResult(result);
|
||||
this->finished();
|
||||
});
|
||||
worker->moveToThread(&workerThread);
|
||||
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
|
||||
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
|
||||
connect(&workerThread, &MyThread::cancelWork, worker, &Worker::cancel);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
qDebug("MyBackupManager::ghostBackup invoke end");
|
||||
return int(BackupResult::BACKUP_RESULT_INIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 控制面板调用的备份接口,重构暂时先兼容以前的老接口
|
||||
* @param autobackup_name 备份名称
|
||||
* @param create_note 创建时备注
|
||||
* @param inc_note 增量备注
|
||||
* @param frontUserName 前端用户名
|
||||
* @param frontUid 前端用户id
|
||||
*/
|
||||
void MyBackupManager::autoBackUpForSystemUpdate_noreturn(const QString& autobackup_name, const QString& create_note, const QString& inc_note, const QString& frontUserName, int frontUid)
|
||||
{
|
||||
qDebug("MyBackupManager::autoBackUpForSystemUpdate_noreturn invoke begin");
|
||||
|
||||
if (m_isActive || !lock(frontUid)) {
|
||||
emit sendStartBackupResult(int(BackupResult::LOCK_PROGRAM_FAIL));
|
||||
return ;
|
||||
}
|
||||
|
||||
BackupWrapper backupWrapper;
|
||||
backupWrapper.m_uuid = AUTO_BACKUP_UUID;
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parseXml(xmlPath);
|
||||
ParseBackupList::BackupPoint backupPoint = parseXml.findBackupPointByUuid(backupWrapper.m_uuid);
|
||||
if (autobackup_name.isEmpty()) {
|
||||
if (backupPoint.m_backupName.isEmpty())
|
||||
backupWrapper.m_backupName = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
else
|
||||
backupWrapper.m_backupName = backupPoint.m_backupName;
|
||||
} else {
|
||||
backupWrapper.m_backupName = autobackup_name;
|
||||
}
|
||||
backupWrapper.m_backupPaths << "/";
|
||||
backupWrapper.m_backupExcludePaths = Utils::getFromExcludePathsFile();
|
||||
backupWrapper.m_backupExcludePaths << "/home";
|
||||
backupWrapper.m_backupExcludePaths << "/root";
|
||||
backupWrapper.m_backupExcludePaths << "/data/home";
|
||||
backupWrapper.m_backupExcludePaths << "/data/root";
|
||||
backupWrapper.m_type = BackupType::BACKUP_SYSTEM;
|
||||
backupWrapper.m_iPosition = BackupPosition::LOCAL;
|
||||
backupWrapper.m_frontUserName = frontUserName;
|
||||
backupWrapper.m_frontUid = frontUid;
|
||||
backupWrapper.m_note = create_note.isEmpty() ? inc_note : create_note;
|
||||
|
||||
Worker* worker = WorkerFactory::createWorker(backupWrapper.m_type, backupWrapper.m_iPosition);
|
||||
if (nullptr == worker) {
|
||||
emit sendStartBackupResult(int(BackupResult::NO_FOUND_DEALCLASS));
|
||||
return ;
|
||||
}
|
||||
|
||||
worker->setParam(backupWrapper);
|
||||
connect(worker, &Worker::checkResult, this, [&](int result) {
|
||||
switch (result) {
|
||||
case int(BackupResult::CHECK_ENV_SUCCESS) :
|
||||
case int(BackupResult::MKSQUASHFS_START_SUCCESS) :
|
||||
case int(BackupResult::BACKUP_START_SUCCESS) :
|
||||
break;
|
||||
default:
|
||||
emit this->sendStartBackupResult(result);
|
||||
this->finished();
|
||||
if (!Utils::isRunning("kybackup")) {
|
||||
this->umountBackupPartition();
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
connect(worker, &Worker::progress, this, [&](int rate) {
|
||||
emit this->sendRate(int(BackupState::WORKING), rate);
|
||||
});
|
||||
connect(worker, &Worker::workResult, this, [&] (bool result) {
|
||||
emit this->sendBackupResult(result);
|
||||
this->finished();
|
||||
if (!Utils::isRunning("kybackup")) {
|
||||
this->umountBackupPartition();
|
||||
}
|
||||
});
|
||||
worker->moveToThread(&workerThread);
|
||||
connect(&workerThread, &MyThread::started, worker, &Worker::doWork);
|
||||
connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater);
|
||||
|
||||
workerThread.start();
|
||||
|
||||
qDebug("MyBackupManager::autoBackUpForSystemUpdate_noreturn invoke end");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 控制面板调用的获取系统备份接口
|
||||
* @param state
|
||||
* @return
|
||||
*/
|
||||
QString MyBackupManager::getBackupCommentForSystemUpdate(QString& state)
|
||||
{
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parseXml(xmlPath);
|
||||
ParseBackupList::BackupPoint backupPoint = parseXml.findBackupPointByUuid(AUTO_BACKUP_UUID);
|
||||
state = backupPoint.m_state;
|
||||
return backupPoint.m_backupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取备份状态
|
||||
* @param isActive,是否活动状态
|
||||
* @return
|
||||
*/
|
||||
int MyBackupManager::getBackupState(bool& isActive)
|
||||
{
|
||||
isActive = m_isActive;
|
||||
return int(m_backupState);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消操作
|
||||
*/
|
||||
int MyBackupManager::cancel()
|
||||
{
|
||||
if (workerThread.isRunning())
|
||||
emit workerThread.cancelWork();
|
||||
else
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重启操作
|
||||
* @return
|
||||
*/
|
||||
int MyBackupManager::reboot()
|
||||
{
|
||||
return ::reboot(RB_AUTOBOOT);;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务结束
|
||||
*/
|
||||
void MyBackupManager::finished()
|
||||
{
|
||||
if (workerThread.isRunning()) {
|
||||
workerThread.quit();
|
||||
workerThread.wait();
|
||||
}
|
||||
|
||||
unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 锁定应用
|
||||
* @param frontUid,锁定应用的用户id
|
||||
* @return bool
|
||||
*/
|
||||
bool MyBackupManager::lock(int frontUid)
|
||||
{
|
||||
std::lock_guard<spinlock_mutex> lock(m_mutex);
|
||||
|
||||
int lock_file_fd = Utils::lockProgram(frontUid);
|
||||
if (lock_file_fd < 0) {
|
||||
Utils::rmLockFile();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 用于替换上面的文件锁的,对应需求8688
|
||||
// if (!inhibit())
|
||||
// return false;
|
||||
inhibit();
|
||||
|
||||
m_fdLockFile = lock_file_fd;
|
||||
m_backupState = BackupState::PREPARING;
|
||||
m_isActive = true;
|
||||
|
||||
setKysecStatus(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 阻止session关机用dbus新接口Inhibit来替换锁文件的方式
|
||||
* Inhibti函数有四个参数,按顺序分别为:
|
||||
what:需要阻止的是哪些过程,如关机、重启;可以输入的值有:”shutdown”(会同时阻止关机重启),”sleep”(会同时阻止睡眠休眠),需要同时阻止关机和睡眠可以输入 ”shutdown:sleep”
|
||||
who:是谁要阻止,调用该接口的程序名,如”ukui-sessions”
|
||||
why:阻止的原因,简单描述即可,如”package installing”
|
||||
mode:阻止的方式;可输入的值有”block”(无限期阻止,等到主动取消阻止才会取消),”delay”(超时阻止,超时一段时间后不管阻止锁,直接执行)
|
||||
建议使用”block”的方式阻止,加锁后记得解锁
|
||||
可以使用同服务下ListInhibitors方法获取当前的inhibit锁,测试验证是否成功注册
|
||||
* @return
|
||||
*/
|
||||
bool MyBackupManager::inhibit()
|
||||
{
|
||||
QDBusMessage message;
|
||||
message = QDBusMessage::createMethodCall("org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
QStringLiteral("Inhibit"));
|
||||
QString why("The backup and restore tool is busy, please wait.");
|
||||
// 区分中英文
|
||||
QString locale = QLocale::system().name();
|
||||
if (locale == "zh_CN") {
|
||||
why = QString("备份还原工具正在忙碌,请稍等");
|
||||
} else if (locale == "bo_CN") {
|
||||
why = QString("གྲབས་ཉར་སོར་ཆུད་ལག་ཆ་བྲེལ་བཞིན་ཡོད་།ཏོག་ཙམ་སྒུག་རོགས་།");
|
||||
}
|
||||
|
||||
// QVariantList({what, who, why, mode})
|
||||
QVariantList args;
|
||||
args << QString("shutdown:sleep");
|
||||
args << QString("backup-daemon");
|
||||
args << why;
|
||||
args << QString("block");
|
||||
message.setArguments(args);
|
||||
|
||||
QDBusPendingReply<QDBusUnixFileDescriptor> reply = QDBusConnection::systemBus().call(message);
|
||||
|
||||
if (!reply.isValid()) {
|
||||
qDebug() << "inhibit faile!";
|
||||
return false;
|
||||
}
|
||||
QDBusUnixFileDescriptor inhibitFileDescriptor = reply.value();
|
||||
inhibitFileDescriptor.swap(m_inhibitFileDescriptor);
|
||||
qDebug() << "inhibit success!";
|
||||
return true;
|
||||
}
|
||||
|
||||
void MyBackupManager::uninhibit()
|
||||
{
|
||||
if (!m_inhibitFileDescriptor.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "uninhibit success!";
|
||||
m_inhibitFileDescriptor = QDBusUnixFileDescriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解锁应用
|
||||
* @return bool
|
||||
*/
|
||||
bool MyBackupManager::unlock()
|
||||
{
|
||||
std::lock_guard<spinlock_mutex> lock(m_mutex);
|
||||
|
||||
setKysecStatus(true);
|
||||
|
||||
Utils::unLockProgram(m_fdLockFile);
|
||||
uninhibit();
|
||||
|
||||
m_fdLockFile = -1;
|
||||
m_backupState = BackupState::BACKUP_STATE_INIT;
|
||||
m_isActive = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置安全状态
|
||||
* @param status,true-开启;false-关闭
|
||||
* @note status=true时不一定会开启,取决于关闭时安全状态;
|
||||
* 使用此方法时注意:一定要先setKysecStatus(false);才能setKysecStatus(true);
|
||||
* 使用场景:备份/还原等业务时先关闭安全保护,业务完成后再重启安全保护
|
||||
*/
|
||||
void MyBackupManager::setKysecStatus(bool status)
|
||||
{
|
||||
if (status) {
|
||||
if (m_bOpenKysec)
|
||||
Utils::setKysecStatus(true);
|
||||
m_bOpenKysec = false;
|
||||
|
||||
if (m_bStartKysecDeamon)
|
||||
Utils::setKysecDaemon(true);
|
||||
m_bStartKysecDeamon = false;
|
||||
} else {
|
||||
if (KYSEC_STATUS_ENABLED == kysec_getstatus()) {
|
||||
// 安全保护已开启
|
||||
m_bOpenKysec = true;
|
||||
Utils::setKysecStatus(false);
|
||||
// 开启安全防护
|
||||
// QProcess::execute("systemctl start kysec-init.service");
|
||||
} else {
|
||||
m_bOpenKysec = false;
|
||||
}
|
||||
|
||||
if(Utils::isRunning("kysec-sync-daemon")){
|
||||
m_bStartKysecDeamon = true;
|
||||
Utils::setKysecDaemon(false);
|
||||
// 停止安全防护
|
||||
// QProcess::execute("systemctl stop kysec-init.service");
|
||||
} else {
|
||||
m_bStartKysecDeamon = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
#ifndef MYBACKUPMANAGER_H
|
||||
#define MYBACKUPMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QtDBus/QDBusVariant>
|
||||
#include <QHash>
|
||||
#include <QDBusUnixFileDescriptor>
|
||||
#include "mythread.h"
|
||||
#include "../common/mydefine.h"
|
||||
#include "../common/spinlock_mutex.h"
|
||||
|
||||
class MyBackupManager : public QObject {
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "com.kylin.backup.manager")
|
||||
|
||||
public:
|
||||
explicit MyBackupManager();
|
||||
virtual ~MyBackupManager();
|
||||
|
||||
signals:
|
||||
// 这3个信号供控制面板/自动更新等外围模块使用
|
||||
// 开始备份结果信号
|
||||
void sendStartBackupResult(int result);
|
||||
// 备份结果信号
|
||||
void sendBackupResult(bool result);
|
||||
// 进度信号
|
||||
void sendRate(int, int);
|
||||
|
||||
// 模块内使用的信号
|
||||
// 进度信号
|
||||
void progress(int, int);
|
||||
// 备份结果信号
|
||||
void backupFinished(bool result);
|
||||
// 环境检查结果信号
|
||||
void sendEnvCheckResult(int result);
|
||||
// 还原结果信号
|
||||
void sendRestoreResult(bool result);
|
||||
// 删除备份结果信号
|
||||
void sendDeleteResult(bool result);
|
||||
// ghost备份结果信号
|
||||
void sendGhostBackupResult(bool result);
|
||||
|
||||
public slots:
|
||||
// 备份分区挂载
|
||||
int Mount_backup_partition();
|
||||
// 卸载backup分区
|
||||
bool umountBackupPartition();
|
||||
// 环境检测
|
||||
int checkEnv(const BackupWrapper& backupWrapper);
|
||||
// 备份
|
||||
int goBackup(const BackupWrapper& backupWrapper);
|
||||
// 还原
|
||||
int goRestore(const BackupWrapper& backupWrapper);
|
||||
// 删除备份
|
||||
int deleteBackupPoint(const BackupWrapper& backupWrapper);
|
||||
// ghost镜像
|
||||
int ghostBackup(const BackupWrapper& backupWrapper);
|
||||
// 控制面板调用的备份接口,重构暂时先兼容以前的老接口
|
||||
void autoBackUpForSystemUpdate_noreturn(const QString& autobackup_name, const QString& create_note, const QString& inc_note, const QString& frontUserName, int frontUid);
|
||||
// 控制面板调用的获取系统备份接口
|
||||
QString getBackupCommentForSystemUpdate(QString& state);
|
||||
// 获取备份状态
|
||||
int getBackupState(bool& isActive);
|
||||
// 取消操作
|
||||
int cancel();
|
||||
// 重启操作
|
||||
int reboot();
|
||||
// 任务结束
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
// 卸载backup分区
|
||||
bool umountBackup();
|
||||
|
||||
private:
|
||||
// 锁定
|
||||
bool lock(int frontUid);
|
||||
bool inhibit();
|
||||
// 解锁
|
||||
bool unlock();
|
||||
void uninhibit();
|
||||
// 自旋锁
|
||||
spinlock_mutex m_mutex;
|
||||
|
||||
// 关闭、开启安全保护
|
||||
void setKysecStatus(bool status);
|
||||
|
||||
private:
|
||||
// 锁文件描述符
|
||||
int m_fdLockFile = -1;
|
||||
QDBusUnixFileDescriptor m_inhibitFileDescriptor;
|
||||
// 备份还原状态
|
||||
BackupState m_backupState = BackupState::BACKUP_STATE_INIT;
|
||||
// 是否活动的,兼容以前用的,和m_backupState的实际使用功能有重复
|
||||
bool m_isActive = false;
|
||||
bool m_needUmount = false;
|
||||
bool m_bOpenKysec = false;
|
||||
bool m_bStartKysecDeamon = false;
|
||||
// 工作者线程
|
||||
MyThread workerThread;
|
||||
};
|
||||
|
||||
#endif // MYBACKUPMANAGER_H
|
|
@ -0,0 +1,45 @@
|
|||
#include <QtDebug>
|
||||
#include <QDir>
|
||||
#include "mymountproxy.h"
|
||||
#include "../common/utils.h"
|
||||
|
||||
MyMountProxy::MyMountProxy(QObject* parent) : QObject(parent)
|
||||
{
|
||||
m_processMount = new MountBackupProcess(this);
|
||||
}
|
||||
|
||||
MountResult MyMountProxy::mountBackupPartition()
|
||||
{
|
||||
QString backupPartitionUuid = Utils::getBackupPartitionUuid();
|
||||
if (backupPartitionUuid.isEmpty()) {
|
||||
qCritical("can't open /etc/.bootinfo or can't get RECOVERY_DEV_UUID");
|
||||
return MountResult::CANNOT_GET_BACKUPUUID;
|
||||
}
|
||||
|
||||
QString rootPath = Utils::getSysRootPath();
|
||||
QString backPath = rootPath + BACKUP_PATH;
|
||||
backPath.replace("//", "/");
|
||||
Utils::mkpath(backPath);
|
||||
|
||||
bool res = m_processMount->Do(backupPartitionUuid);
|
||||
if (res) {
|
||||
QString snapshotsPath = rootPath + BACKUP_SNAPSHOTS_PATH;
|
||||
snapshotsPath.replace("//", "/");
|
||||
Utils::mkpath(snapshotsPath);
|
||||
|
||||
if (!Utils::generateExcludePathsFile()) {
|
||||
qCritical("mount success, but generate some important file failed!");
|
||||
return MountResult::GENERATE_IMPORT_FILE_FAIL;
|
||||
}
|
||||
|
||||
return MountResult::MOUNTED;
|
||||
}
|
||||
|
||||
return MountResult::NO_MOUNTED;
|
||||
}
|
||||
|
||||
bool MyMountProxy::umountBackupPartition()
|
||||
{
|
||||
return m_processMount->umountBackupPartition();
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef MYMOUNTPROXY_H
|
||||
#define MYMOUNTPROXY_H
|
||||
|
||||
#include <QObject>
|
||||
#include "myprocess/mountbackupprocess.h"
|
||||
#include "../common/mydefine.h"
|
||||
|
||||
class MyMountProxy : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
MyMountProxy(QObject* parent = nullptr);
|
||||
|
||||
MountResult mountBackupPartition();
|
||||
|
||||
bool umountBackupPartition();
|
||||
|
||||
private:
|
||||
MountBackupProcess* m_processMount;
|
||||
};
|
||||
|
||||
#endif // MYMOUNTPROXY_H
|
|
@ -0,0 +1,127 @@
|
|||
#include "calcbackupsize.h"
|
||||
#include <QDebug>
|
||||
#include <QRegularExpression>
|
||||
|
||||
CalcBackupSize::CalcBackupSize(QObject* parent) :
|
||||
QObject(parent),
|
||||
m_process(new QProcess(this))
|
||||
{
|
||||
connect(m_process, &QProcess::readyRead, this, [&]() {
|
||||
parseResult();
|
||||
});
|
||||
|
||||
connect(m_process, &QProcess::readyReadStandardError, this, [&]() {
|
||||
QByteArray err = m_process->readAllStandardError();
|
||||
qCritical("backup process error: %s", err.data());
|
||||
});
|
||||
|
||||
connect(m_process, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
|
||||
Q_UNUSED(error)
|
||||
m_process->kill();
|
||||
});
|
||||
|
||||
connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinish(int, QProcess::ExitStatus)));
|
||||
}
|
||||
|
||||
CalcBackupSize::~CalcBackupSize()
|
||||
{
|
||||
if (!m_process && m_process->state() != QProcess::NotRunning) {
|
||||
m_process->kill();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算备份大小,单位字节
|
||||
* @param args rsync参数列表
|
||||
* @param block 是否阻塞计算模式。默认true——阻塞计算模式
|
||||
* @return block为true时返回值为待备份数据大小,单位字节;block为false时,默认返回0;
|
||||
*/
|
||||
qint64 CalcBackupSize::start(QStringList args, bool block)
|
||||
{
|
||||
qDebug() << "CalcBackupSize::calcBackupSize invoke begin";
|
||||
|
||||
QString cmd("rsync ");
|
||||
for (const QString& item : args) {
|
||||
cmd += " ";
|
||||
cmd += item;
|
||||
}
|
||||
qDebug() << cmd;
|
||||
|
||||
m_size = 0;
|
||||
|
||||
m_process->start("rsync", args);
|
||||
if (!m_process->waitForStarted()) {
|
||||
qCritical("rsync start failed");
|
||||
return m_size;
|
||||
}
|
||||
|
||||
if (block) {
|
||||
m_process->waitForFinished();
|
||||
}
|
||||
|
||||
qDebug() << "CalcBackupSize::calcBackupSize invoke end";
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解析process的输出结果
|
||||
*/
|
||||
void CalcBackupSize::parseResult()
|
||||
{
|
||||
// 解析结果,结果内容样例如下:
|
||||
/*
|
||||
Number of files: 256,274 (reg: 207,101, dir: 23,764, link: 25,407, special: 2)
|
||||
Number of created files: 256,274 (reg: 207,101, dir: 23,764, link: 25,407, special: 2)
|
||||
Number of deleted files: 0
|
||||
Number of regular files transferred: 207,101
|
||||
Total file size: 12,160,363,663 bytes
|
||||
Total transferred file size: 12,159,780,794 bytes
|
||||
Literal data: 0 bytes
|
||||
Matched data: 0 bytes
|
||||
File list size: 786,254
|
||||
File list generation time: 0.001 seconds
|
||||
File list transfer time: 0.000 seconds
|
||||
Total bytes sent: 8,273,515
|
||||
Total bytes received: 794,093
|
||||
|
||||
sent 8,273,515 bytes received 794,093 bytes 1,209,014.40 bytes/sec
|
||||
total size is 12,160,363,663 speedup is 1,341.08 (DRY RUN)
|
||||
|
||||
*/
|
||||
QString out(m_process->readAll());
|
||||
QStringList lines = out.split("\n");
|
||||
qDebug() << out;
|
||||
for (QString& line : lines) {
|
||||
// 获取文件夹数目
|
||||
if (line.startsWith("Number of files:")) {
|
||||
int indexOfDir = line.indexOf("dir: ");
|
||||
indexOfDir += 5;
|
||||
int indexOfDirEnd = line.indexOf(QRegularExpression("[ )]"), indexOfDir);
|
||||
int numOfDirs = line.mid(indexOfDir, indexOfDirEnd-indexOfDir).replace(",","").trimmed().toInt();
|
||||
// 每个目录下还都有.和..,故总数还要*3
|
||||
numOfDirs *= 3;
|
||||
// ext4格式的目录本身要占用4K空间(4096)
|
||||
m_size += numOfDirs * 4096;
|
||||
}
|
||||
if (line.startsWith("Total transferred file size: ")) {
|
||||
m_size += line.replace("Total transferred file size: ", "").replace("bytes", "").replace(",","").trimmed().toLongLong();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief process结束
|
||||
* @param exitCode
|
||||
*/
|
||||
void CalcBackupSize::processFinish(int exitCode, QProcess::ExitStatus)
|
||||
{
|
||||
qDebug() << "CalcBackupSize::getCalcResult invoke begin";
|
||||
Q_UNUSED(exitCode)
|
||||
|
||||
if (exitCode == QProcess::NormalExit)
|
||||
parseResult();
|
||||
|
||||
emit finished(m_size);
|
||||
|
||||
qDebug() << "CalcBackupSize::getCalcResult invoke end";
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef CALCBACKUPSIZE_H
|
||||
#define CALCBACKUPSIZE_H
|
||||
|
||||
#include <QStringList>
|
||||
#include <QProcess>
|
||||
|
||||
#define GB (1024 * 1024 * 1024)
|
||||
#define MB (1024 * 1024)
|
||||
#define KB (1024)
|
||||
|
||||
class CalcBackupSize : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CalcBackupSize(QObject* parent = nullptr);
|
||||
~CalcBackupSize();
|
||||
|
||||
/**
|
||||
* @brief 计算备份大小,单位字节
|
||||
* @param args rsync参数列表
|
||||
* @param block 是否阻塞计算模式。默认true——阻塞计算模式
|
||||
* @return block为true时返回值为待备份数据大小,单位字节;block为false时,默认返回0
|
||||
*/
|
||||
qint64 start(QStringList args, bool block = true);
|
||||
|
||||
void stop() { m_process->kill(); }
|
||||
|
||||
signals:
|
||||
// 计算结束信号
|
||||
void finished(qint64 size);
|
||||
|
||||
private slots:
|
||||
// process结束槽
|
||||
void processFinish(int exitCode, QProcess::ExitStatus);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 解析process的输出结果
|
||||
*/
|
||||
void parseResult();
|
||||
|
||||
QProcess * m_process;
|
||||
|
||||
qint64 m_size = 0; // 备份大小,单位字节
|
||||
};
|
||||
|
||||
#endif // CALCBACKUPSIZE_H
|
|
@ -0,0 +1,92 @@
|
|||
#include "mksquashfsprocess.h"
|
||||
#include <QDebug>
|
||||
|
||||
MkSquashFSProcess::MkSquashFSProcess(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_p(new QProcess(this))
|
||||
, m_syncProcess(new QProcess(this))
|
||||
{
|
||||
connect(m_p, &QProcess::readyRead, this, [&]() {
|
||||
QString str = QString(m_p->readAll());
|
||||
qDebug() << str;
|
||||
if (str.contains("]") && str.contains("%")) {
|
||||
if (str.split("%").at(0).length() < 3)
|
||||
return;
|
||||
int tmpRate = str.split("%").at(0).right(3).toInt();
|
||||
if (m_currentRate == tmpRate)
|
||||
return;
|
||||
m_currentRate = tmpRate;
|
||||
emit progress(m_currentRate);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_p, &QProcess::readyReadStandardError, this, [&]() {
|
||||
QByteArray err = m_p->readAllStandardError();
|
||||
qCritical() << err;
|
||||
});
|
||||
|
||||
connect(m_p, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
|
||||
Q_UNUSED(error)
|
||||
m_p->kill();
|
||||
});
|
||||
|
||||
connect(m_p, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(mksquashfs_finished(int, QProcess::ExitStatus)));
|
||||
|
||||
connect(m_syncProcess, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
|
||||
Q_UNUSED(error)
|
||||
m_syncProcess->kill();
|
||||
});
|
||||
connect(m_syncProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(sync_finished(int, QProcess::ExitStatus)));
|
||||
}
|
||||
|
||||
MkSquashFSProcess::~MkSquashFSProcess()
|
||||
{
|
||||
if (!m_p && m_p->state() != QProcess::NotRunning) {
|
||||
m_p->kill();
|
||||
}
|
||||
|
||||
if (!m_syncProcess && m_syncProcess->state() != QProcess::NotRunning) {
|
||||
m_syncProcess->kill();
|
||||
}
|
||||
}
|
||||
|
||||
bool MkSquashFSProcess::start(const QStringList &args)
|
||||
{
|
||||
QString cmd("mksquashfs ");
|
||||
for (const QString& item : args) {
|
||||
cmd += " ";
|
||||
cmd += item;
|
||||
}
|
||||
qDebug() << cmd;
|
||||
|
||||
m_p->start("mksquashfs", args);
|
||||
if (!m_p->waitForStarted()) {
|
||||
qCritical("mksquashfs start failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MkSquashFSProcess::mksquashfs_finished(int exitCode, QProcess::ExitStatus)
|
||||
{
|
||||
if (exitCode == QProcess::NormalExit) {
|
||||
m_syncProcess->start("sync");
|
||||
if (!m_syncProcess->waitForStarted()) {
|
||||
emit finished(false);
|
||||
}
|
||||
} else {
|
||||
emit finished(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MkSquashFSProcess::sync_finished(int exitCode, QProcess::ExitStatus)
|
||||
{
|
||||
if (exitCode == QProcess::NormalExit) {
|
||||
emit progress(100);
|
||||
emit finished(true);
|
||||
} else {
|
||||
emit finished(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef MKSQUASHFSPROCESS_H
|
||||
#define MKSQUASHFSPROCESS_H
|
||||
|
||||
#include <QProcess>
|
||||
#include <QObject>
|
||||
|
||||
class MkSquashFSProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MkSquashFSProcess(QObject *parent = nullptr);
|
||||
virtual ~MkSquashFSProcess();
|
||||
|
||||
bool start(const QStringList &args);
|
||||
|
||||
void stop() {
|
||||
m_p->kill();
|
||||
m_syncProcess->kill();
|
||||
}
|
||||
|
||||
signals:
|
||||
// 结果信号
|
||||
void finished(bool result);
|
||||
// 进度百分比
|
||||
void progress(int currentRate);
|
||||
|
||||
private slots:
|
||||
// m_p执行结束
|
||||
void mksquashfs_finished(int exitCode, QProcess::ExitStatus);
|
||||
// m_syncProcess执行结束
|
||||
void sync_finished(int exitCode, QProcess::ExitStatus);
|
||||
|
||||
private:
|
||||
QProcess * m_p;
|
||||
QProcess* m_syncProcess;
|
||||
int m_currentRate;
|
||||
bool m_bSuccess;
|
||||
};
|
||||
|
||||
#endif // MKSQUASHFSPROCESS_H
|
|
@ -0,0 +1,119 @@
|
|||
#ifndef MOUNTBACKUPPROCESS_CPP
|
||||
#define MOUNTBACKUPPROCESS_CPP
|
||||
|
||||
#include <QFile>
|
||||
#include <QtDebug>
|
||||
#include "mountbackupprocess.h"
|
||||
#include "../../common/mydefine.h"
|
||||
#include "../../common/utils.h"
|
||||
|
||||
MountBackupProcess::MountBackupProcess(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_p(new QProcess(this))
|
||||
{
|
||||
connect(m_p, &QProcess::readyReadStandardError, this, [&]() {
|
||||
QByteArray err = m_p->readAllStandardError();
|
||||
qCritical("%s", err.data());
|
||||
});
|
||||
}
|
||||
|
||||
bool MountBackupProcess::Do(const QString& diskUuid)
|
||||
{
|
||||
QString rootPath(Utils::getSysRootPath());
|
||||
|
||||
// 若备份路径下的xml已经存在,则说明已经挂载过了
|
||||
QString backupXmlPath = rootPath + BACKUP_XML_PATH;
|
||||
backupXmlPath.replace("//", "/");
|
||||
QFile file(backupXmlPath);
|
||||
if (file.exists())
|
||||
return true;
|
||||
|
||||
QStringList arguments;
|
||||
QString backupPartion = rootPath + BACKUP_PATH;
|
||||
backupPartion.replace("//","/");
|
||||
arguments << QString("-o") << QString("rw") << QString("/dev/disk/by-uuid/%1").arg(diskUuid) << backupPartion;
|
||||
|
||||
m_p->start("mount", arguments);
|
||||
if (!m_p->waitForStarted()) {
|
||||
qCritical("mount rw /backup process start failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_p->waitForFinished()) {
|
||||
qCritical("mount rw backup process end failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MountBackupProcess::umountBackupPartition()
|
||||
{
|
||||
QStringList arguments;
|
||||
arguments << QString("/backup");
|
||||
m_p->start("umount", arguments);
|
||||
if (!m_p->waitForStarted()) {
|
||||
qCritical("umount /backup process start failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_p->waitForFinished()) {
|
||||
qCritical("umount /backup process end failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 卸载目录挂载
|
||||
* @param mountPath,挂载的目录
|
||||
* @return
|
||||
*/
|
||||
bool MountBackupProcess::umount(const QString& mountPath)
|
||||
{
|
||||
QStringList arguments;
|
||||
arguments << mountPath;
|
||||
m_p->start("umount", arguments);
|
||||
if (!m_p->waitForStarted()) {
|
||||
qCritical() << tr("umount %1 process start failed!").arg(mountPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_p->waitForFinished()) {
|
||||
qCritical() << tr("umount %1 process end failed!").arg(mountPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 挂载
|
||||
* @param source 源
|
||||
* @param target 目标目录
|
||||
* @return
|
||||
*/
|
||||
bool MountBackupProcess::mount(const QString& source, const QString& target, const QString& options)
|
||||
{
|
||||
QStringList arguments;
|
||||
if (!options.isEmpty())
|
||||
arguments << options;
|
||||
arguments << source;
|
||||
arguments << target;
|
||||
|
||||
m_p->start("mount", arguments);
|
||||
if (!m_p->waitForStarted()) {
|
||||
qCritical("mount process start failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_p->waitForFinished()) {
|
||||
qCritical("mount process end failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // MOUNTBACKUPPROCESS_CPP
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef MOUNTBACKUPPROCESS_H
|
||||
#define MOUNTBACKUPPROCESS_H
|
||||
|
||||
#include <QProcess>
|
||||
#include <sys/mount.h>
|
||||
|
||||
class MountBackupProcess : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MountBackupProcess(QObject* parent = nullptr);
|
||||
|
||||
bool Do(const QString& diskUuid);
|
||||
|
||||
bool umountBackupPartition();
|
||||
|
||||
bool umount(const QString& mountPath);
|
||||
bool mount(const QString& source, const QString& target, const QString& options = "");
|
||||
|
||||
private:
|
||||
|
||||
QProcess* m_p;
|
||||
};
|
||||
|
||||
|
||||
#endif // MOUNTBACKUPPROCESS_H
|
|
@ -0,0 +1,130 @@
|
|||
#include "rsyncpathtodirprocess.h"
|
||||
#include <QDebug>
|
||||
|
||||
RsyncPathToDirProcess::RsyncPathToDirProcess(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_p(new QProcess(this)),
|
||||
m_syncProcess(new QProcess(this))
|
||||
{
|
||||
m_currentRate = 0;
|
||||
m_bSuccess = false;
|
||||
|
||||
connect(m_p, &QProcess::readyRead, this, [&]() {
|
||||
QString str = QString(m_p->readAll());
|
||||
qDebug() << str;
|
||||
// if (str.contains("B\/s") && str.contains("%")) {
|
||||
if (str.contains("B/s") && str.contains("%")) {
|
||||
if (str.split("%").at(0).length() < 3)
|
||||
return;
|
||||
int tmpRate = str.split("%").at(0).right(3).toInt();
|
||||
if (m_currentRate == tmpRate)
|
||||
return;
|
||||
m_currentRate = tmpRate;
|
||||
emit progress(m_currentRate);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_p, &QProcess::readyReadStandardError, this, [&]() {
|
||||
QByteArray err = m_p->readAllStandardError();
|
||||
qCritical("backup process error: %s", err.data());
|
||||
});
|
||||
|
||||
connect(m_p, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
|
||||
Q_UNUSED(error)
|
||||
m_p->kill();
|
||||
});
|
||||
|
||||
connect(m_p, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(rsync_finished(int, QProcess::ExitStatus)));
|
||||
|
||||
connect(m_syncProcess, &QProcess::errorOccurred, this, [&](QProcess::ProcessError error) {
|
||||
Q_UNUSED(error)
|
||||
m_syncProcess->kill();
|
||||
});
|
||||
connect(m_syncProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(sync_finished(int, QProcess::ExitStatus)));
|
||||
}
|
||||
|
||||
RsyncPathToDirProcess::~RsyncPathToDirProcess()
|
||||
{
|
||||
if (!m_p && m_p->state() != QProcess::NotRunning) {
|
||||
m_p->kill();
|
||||
}
|
||||
|
||||
if (!m_syncProcess && m_syncProcess->state() != QProcess::NotRunning) {
|
||||
m_syncProcess->kill();
|
||||
}
|
||||
}
|
||||
|
||||
bool RsyncPathToDirProcess::start(QStringList args, bool block)
|
||||
{
|
||||
qDebug() << "RsyncPathToDirProcess::start invoke begin";
|
||||
m_currentRate = 0;
|
||||
m_bSuccess = false;
|
||||
m_block = block;
|
||||
|
||||
QString cmd("rsync");
|
||||
for (const QString& item : args) {
|
||||
cmd += " ";
|
||||
cmd += item;
|
||||
}
|
||||
qDebug() << cmd;
|
||||
|
||||
m_p->start("rsync", args);
|
||||
if (!m_p->waitForStarted()) {
|
||||
qCritical("rsync started failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_block) {
|
||||
if (!m_p->waitForFinished()) {
|
||||
qCritical("rsync finished failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "RsyncPathToDirProcess::start invoke end";
|
||||
return m_bSuccess;
|
||||
}
|
||||
|
||||
void RsyncPathToDirProcess::rsync_finished(int exitCode, QProcess::ExitStatus)
|
||||
{
|
||||
qDebug() << "RsyncPathToDirProcess::rsync_finished invoke begin";
|
||||
if (exitCode == QProcess::NormalExit || exitCode == 24 || exitCode == 23) {
|
||||
if (m_block) {
|
||||
qDebug() << "RsyncPathToDirProcess::rsync_finished block mode";
|
||||
m_bSuccess = true;
|
||||
emit progress(100);
|
||||
emit finished(true);
|
||||
} else {
|
||||
qDebug() << "RsyncPathToDirProcess::rsync_finished unblock mode";
|
||||
emit progress(100);
|
||||
m_syncProcess->start("sync");
|
||||
if (!m_syncProcess->waitForStarted()) {
|
||||
qDebug() << "sync start failed";
|
||||
m_bSuccess = false;
|
||||
emit finished(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qDebug() << "RsyncPathToDirProcess::rsync_finished failed";
|
||||
m_bSuccess = false;
|
||||
emit finished(false);
|
||||
}
|
||||
qDebug() << "RsyncPathToDirProcess::rsync_finished invoke end";
|
||||
}
|
||||
|
||||
void RsyncPathToDirProcess::sync_finished(int exitCode, QProcess::ExitStatus)
|
||||
{
|
||||
qDebug() << "RsyncPathToDirProcess::sync_finished invoke begin";
|
||||
|
||||
if (exitCode == QProcess::NormalExit || exitCode == 24 || exitCode == 23) {
|
||||
qDebug() << "RsyncPathToDirProcess::sync_finished success";
|
||||
m_bSuccess = true;
|
||||
emit finished(true);
|
||||
} else {
|
||||
qDebug() << "RsyncPathToDirProcess::sync_finished failed";
|
||||
m_bSuccess = false;
|
||||
emit finished(false);
|
||||
}
|
||||
|
||||
qDebug() << "RsyncPathToDirProcess::sync_finished invoke end";
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef RSYNCPATHTODIRPROCESS_H
|
||||
#define RSYNCPATHTODIRPROCESS_H
|
||||
|
||||
#include <QProcess>
|
||||
|
||||
class RsyncPathToDirProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RsyncPathToDirProcess(QObject *parent = nullptr);
|
||||
virtual ~RsyncPathToDirProcess();
|
||||
|
||||
bool start(QStringList args, bool block = true);
|
||||
|
||||
inline void stop() {
|
||||
m_p->kill();
|
||||
m_syncProcess->kill();
|
||||
}
|
||||
|
||||
signals:
|
||||
// 结果信号
|
||||
void finished(bool result);
|
||||
// 进度百分比
|
||||
void progress(int currentRate);
|
||||
|
||||
private slots:
|
||||
// m_p执行结束
|
||||
void rsync_finished(int exitCode, QProcess::ExitStatus);
|
||||
// m_syncProcess执行结束
|
||||
void sync_finished(int exitCode, QProcess::ExitStatus);
|
||||
|
||||
private:
|
||||
QProcess * m_p;
|
||||
QProcess* m_syncProcess;
|
||||
int m_currentRate;
|
||||
bool m_bSuccess;
|
||||
bool m_block;
|
||||
};
|
||||
|
||||
#endif // RSYNCPATHTODIRPROCESS_H
|
|
@ -0,0 +1,8 @@
|
|||
#include "mythread.h"
|
||||
|
||||
MyThread::MyThread(QObject *parent) :
|
||||
QThread(parent)
|
||||
{}
|
||||
|
||||
MyThread::~MyThread()
|
||||
{}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef MYTHREAD_H
|
||||
#define MYTHREAD_H
|
||||
|
||||
#include <QThread>
|
||||
|
||||
class MyThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MyThread(QObject *parent = nullptr);
|
||||
virtual ~MyThread();
|
||||
|
||||
signals:
|
||||
void cancelWork();
|
||||
};
|
||||
|
||||
#endif // MYTHREAD_H
|
|
@ -0,0 +1,600 @@
|
|||
#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>
|
||||
</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_name,xml文件中备份点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()) {
|
||||
customizePaths << elePrefixPath.text() + BACKUP_SNAPSHOTS_PATH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 eleUuid = node.firstChildElement(UUID);
|
||||
if (eleUuid.isNull() || eleUuid.text() == AUTO_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;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
#ifndef PARSEBACKUPLIST_H
|
||||
#define PARSEBACKUPLIST_H
|
||||
|
||||
#include <QString>
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QList>
|
||||
#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-移动设备备份;2-异机备份(仅用于业务场景标记,不用于持久化记录);3-自定义路径备份
|
||||
int m_iPosition = -1;
|
||||
// 操作类型,如:系统备份, 系统还原
|
||||
int m_type = -1;
|
||||
// 备份大小
|
||||
QString m_size;
|
||||
// 备份状态,如是否完成
|
||||
QString m_state;
|
||||
// 备份用户id
|
||||
QString m_userId;
|
||||
// 备份机器操作系统
|
||||
QString m_os;
|
||||
// 备份机器架构
|
||||
QString m_arch;
|
||||
// 备份机器引导方式
|
||||
QString m_archdetect;
|
||||
// 备份点所在设备挂载路径(这个暂只在查询中界面展示选择中使用)或自定义的备份路径
|
||||
QString m_path;
|
||||
|
||||
bool isNull() { return m_uuid.isEmpty(); }
|
||||
|
||||
bool operator< (const BackupPoint &other);
|
||||
};
|
||||
|
||||
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 获取xml文件中备份点uuid和backupname的映射
|
||||
* @param uuid_name,xml文件中备份点uuid和backupname的映射
|
||||
* @return
|
||||
*/
|
||||
void getXmlUuidNameMap(QMap<QString, QString> &uuid_name);
|
||||
|
||||
/**
|
||||
* @brief 获取最后一次系统备份
|
||||
* @return
|
||||
*/
|
||||
BackupPoint getLastSysBackupPoint();
|
||||
|
||||
/**
|
||||
* @brief 获取自定义备份路径列表
|
||||
* @param customizePaths
|
||||
*/
|
||||
void getCustomizePaths(QStringList &customizePaths);
|
||||
|
||||
/**
|
||||
* @brief 新增备份节点
|
||||
* @param backupPoint, 备份点信息
|
||||
* @return SUCCESS成功; XML_PARSE_ERR失败
|
||||
*/
|
||||
ParseResult addItem(const BackupPoint& backupPoint);
|
||||
|
||||
/**
|
||||
* @brief 更新备份点信息
|
||||
* @param backupPoint,新的备份点信息
|
||||
* @return SUCCESS成功; XML_PARSE_ERR失败
|
||||
*/
|
||||
ParseResult updateItem(const BackupPoint & backupPoint);
|
||||
|
||||
/**
|
||||
* @brief 删除备份点记录
|
||||
* @param uuid
|
||||
* @return SUCCESS成功; XML_PARSE_ERR失败
|
||||
*/
|
||||
ParseResult deleteItem(const QString& uuid);
|
||||
|
||||
/**
|
||||
* @brief 获取备份列表
|
||||
* @return
|
||||
*/
|
||||
QList<BackupPoint> getBackupPointList();
|
||||
|
||||
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, QDomDocument& doc, QDomNode& eleNode);
|
||||
QDomElement createTextElement(QDomDocument& doc, const QString& tagName, const QString& text);
|
||||
|
||||
private:
|
||||
QString m_xmlPath;
|
||||
};
|
||||
|
||||
#endif // PARSEBACKUPLIST_H
|
|
@ -0,0 +1,529 @@
|
|||
#include "systembackupproxy.h"
|
||||
#include <QStorageInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <kysec/status.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(SystemBackupProxy)
|
||||
|
||||
SystemBackupProxy::SystemBackupProxy()
|
||||
{
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_p = nullptr;
|
||||
m_size = 0;
|
||||
m_isOnlyCheck = true;
|
||||
m_calc = new CalcBackupSize(this);
|
||||
|
||||
connect(this, &SystemBackupProxy::cancel, this, &SystemBackupProxy::cancelEx);
|
||||
}
|
||||
|
||||
SystemBackupProxy::~SystemBackupProxy()
|
||||
{
|
||||
delete m_p;
|
||||
m_p = nullptr;
|
||||
|
||||
delete m_calc;
|
||||
m_calc = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return
|
||||
*/
|
||||
bool SystemBackupProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "SystemBackupProxy::checkEnv invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
MyMountProxy mountProxy;
|
||||
if ( MountResult::MOUNTED != mountProxy.mountBackupPartition() ) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、判断备份是否增量备份
|
||||
isIncBackup();
|
||||
|
||||
// 3、检测空间是否满足备份
|
||||
calcSizeForBackup();
|
||||
|
||||
qDebug() << "SystemBackupProxy::checkEnv invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行备份逻辑
|
||||
*/
|
||||
void SystemBackupProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "SystemBackupProxy::doWorkEx invoke begin";
|
||||
|
||||
m_isOnlyCheck = false;
|
||||
// 环境检测
|
||||
checkEnvEx();
|
||||
|
||||
qDebug() << "SystemBackupProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消操作
|
||||
*/
|
||||
void SystemBackupProxy::cancelEx()
|
||||
{
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_calc)
|
||||
m_calc->stop();
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void SystemBackupProxy::deleteFailedData()
|
||||
{
|
||||
if (m_curUuid.isEmpty())
|
||||
return;
|
||||
|
||||
// 1、删除备份目录
|
||||
QString destPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid;
|
||||
destPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-rf";
|
||||
args << destPath;
|
||||
QProcess::execute("rm", args);
|
||||
|
||||
// 2、删除xml文件中的备份项
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.deleteItem(m_curUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否增量备份
|
||||
* @return true,增量备份; false,全量备份
|
||||
*/
|
||||
bool SystemBackupProxy::isIncBackup()
|
||||
{
|
||||
QString backupPath;
|
||||
ParseBackupList::BackupPoint point;
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
QString xmlPath(Utils::getSysRootPath() + BACKUP_XML_PATH);
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parser(xmlPath);
|
||||
point = parser.getLastSysBackupPoint();
|
||||
if (point.m_uuid.isEmpty())
|
||||
return false;
|
||||
backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + point.m_uuid + "/data";
|
||||
} else {
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
}
|
||||
|
||||
backupPath.replace("//", "/");
|
||||
if (Utils::isDirExist(backupPath) && !m_backupPoint.m_backupName.isEmpty()) {
|
||||
m_backupWrapper.m_baseUuid = point.m_uuid;
|
||||
m_backupWrapper.m_bIncrement = true;
|
||||
m_backupWrapper.m_type = BackupType::INC_BACKUP_SYSTEM;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验剩余空间是否满足备份
|
||||
*/
|
||||
void SystemBackupProxy::checkFreeCapacity(qint64 itotalSize)
|
||||
{
|
||||
qDebug() << "SystemBackupProxy::checkFreeCapacity invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
// 1、计算待备份数据的大小
|
||||
m_size = itotalSize;
|
||||
// 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留500M的空间
|
||||
itotalSize += 500 * MB;
|
||||
|
||||
// 2、计算备份分区剩余空间大小
|
||||
QString backupPath(Utils::getSysRootPath() + BACKUP_PATH);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo backupDisk(backupPath);
|
||||
qint64 freeSize = backupDisk.bytesAvailable();
|
||||
qDebug() << "需要空间" << itotalSize << ", 剩余空间" << freeSize;
|
||||
|
||||
// 3、校验空间是否足够
|
||||
if (itotalSize > freeSize) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
return ;
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
}
|
||||
|
||||
// 仅仅校验,不进行备份
|
||||
if (m_isOnlyCheck)
|
||||
return ;
|
||||
|
||||
// 4、开始备份
|
||||
doBackup();
|
||||
|
||||
qDebug() << "SystemBackupProxy::checkFreeCapacity invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算备份所需空间大小
|
||||
* @return
|
||||
*/
|
||||
void SystemBackupProxy::calcSizeForBackup()
|
||||
{
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
// 新增增量备份点场景
|
||||
args = getRsyncArgs(SystemBackupScene::TRY_INC_SYSTEM_BACKUP);
|
||||
destPath += CHECK_PATH;
|
||||
} else {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(SystemBackupScene::TRY_INC_SYSTEM_BACKUP_AT_BASE);
|
||||
destPath += BACKUP_SNAPSHOTS_PATH;
|
||||
destPath += "/";
|
||||
destPath += m_backupWrapper.m_uuid;
|
||||
destPath += "/data/";
|
||||
}
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(SystemBackupScene::TRY_SYSTEM_BACKUP);
|
||||
destPath += CHECK_PATH;
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
Utils::mkpath(destPath);
|
||||
|
||||
connect(m_calc, &CalcBackupSize::finished, this, &SystemBackupProxy::checkFreeCapacity);
|
||||
m_calc->start(args, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return rsync的参数信息
|
||||
*/
|
||||
QStringList SystemBackupProxy::getRsyncArgs(SystemBackupScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
|
||||
switch (scene) {
|
||||
case SystemBackupScene::SYSTEM_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
break ;
|
||||
case SystemBackupScene::INC_SYSTEM_BACKUP :
|
||||
args << "-avAXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << QString("--link-dest=../../%1/data").arg(m_backupWrapper.m_baseUuid);
|
||||
break ;
|
||||
case SystemBackupScene::INC_SYSTEM_BACKUP_AT_BASE :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
break ;
|
||||
case SystemBackupScene::TRY_SYSTEM_BACKUP :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
break ;
|
||||
case SystemBackupScene::TRY_INC_SYSTEM_BACKUP :
|
||||
args << "-aAXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
args << QString("--link-dest=../../%1/data").arg(m_backupWrapper.m_baseUuid);
|
||||
break ;
|
||||
case SystemBackupScene::TRY_INC_SYSTEM_BACKUP_AT_BASE :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
break ;
|
||||
case SystemBackupScene::EFI_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--ignore-missing-args";
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
if (SystemBackupScene::EFI_BACKUP != scene) {
|
||||
// --exclude=排除路径设置
|
||||
for (const QString & item : m_backupWrapper.m_backupExcludePaths) {
|
||||
args << QString("--exclude=%1").arg(item);
|
||||
}
|
||||
}
|
||||
|
||||
// 系统更新备份不再备份用户数据目录
|
||||
if (AUTO_BACKUP_UUID == m_curUuid) {
|
||||
if (Utils::isHuawei990()) {
|
||||
args << "--exclude=/data";
|
||||
} else {
|
||||
args << "--exclude=/data/usershare";
|
||||
}
|
||||
args << "--exclude=/home";
|
||||
args << "--exclude=/data/home";
|
||||
args << "--exclude=/root";
|
||||
args << "--exclude=/data/root";
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份
|
||||
*/
|
||||
void SystemBackupProxy::doBackup()
|
||||
{
|
||||
qDebug() << "SystemBackupProxy::doBackup invoke begin";
|
||||
|
||||
// 准备
|
||||
if (!doPrepare())
|
||||
return ;
|
||||
|
||||
// 启动备份efi, 修改为和其它目录统一备份,不再单独进行备份
|
||||
// if (!backupEfi()) {
|
||||
// emit checkResult(int(BackupResult::EFI_RSYNC_FAIL));
|
||||
// return ;
|
||||
// }
|
||||
|
||||
// 启动系统备份
|
||||
backupSystem();
|
||||
|
||||
qDebug() << "SystemBackupProxy::doBackup invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份准备
|
||||
* @return true,准备成功;false,准备失败
|
||||
*/
|
||||
bool SystemBackupProxy::doPrepare()
|
||||
{
|
||||
qDebug() << "SystemBackupProxy::doPrepare invoke begin";
|
||||
|
||||
m_bSuccess = false;
|
||||
|
||||
// 1、设置当前备份的Uuid
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
// 新增备份点,不指定uuid的场景
|
||||
m_curUuid += Utils::createUuid();
|
||||
} else {
|
||||
// 指定uuid备份的场景
|
||||
m_curUuid = m_backupWrapper.m_uuid;
|
||||
}
|
||||
|
||||
// 2、准备备份目录及文件
|
||||
m_destPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data";
|
||||
m_destPath.replace("//", "/");
|
||||
if (!Utils::mkpath(m_destPath)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
QString userFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE;
|
||||
userFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(userFile, m_backupWrapper.m_backupPaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(userFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString excludeUserFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
excludeUserFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(excludeUserFile, m_backupWrapper.m_backupExcludePaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(excludeUserFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、记录/backup/snapshots/backuplist.xml文件
|
||||
if (!recordBackupPoint()) {
|
||||
qCritical() << "add or update item to backuplist.xml failed !";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "SystemBackupProxy::doPrepare invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool SystemBackupProxy::recordBackupPoint()
|
||||
{
|
||||
m_backupPoint.m_backupName = m_backupWrapper.m_backupName;
|
||||
m_backupPoint.m_uuid = m_curUuid;
|
||||
m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition;
|
||||
m_backupPoint.m_type = m_backupWrapper.m_type;
|
||||
m_backupPoint.m_size = Utils::StringBySize(m_size);
|
||||
m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING;
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (m_backupWrapper.m_uuid.isEmpty() || !m_backupWrapper.m_bIncrement) {
|
||||
if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份/boot/efi
|
||||
* @return true,备份成功;false,备份失败
|
||||
*/
|
||||
bool SystemBackupProxy::backupEfi()
|
||||
{
|
||||
qDebug() << "SystemBackupProxy::backupEfi invoke begin";
|
||||
|
||||
// /boot/efi分区是自动挂载的,这里不用去挂载
|
||||
QString efiPath = Utils::getSysRootPath() + "/boot/efi";
|
||||
efiPath.replace("//", "/");
|
||||
|
||||
QStringList args;
|
||||
if (Utils::isDirExist(efiPath)) {
|
||||
args = getRsyncArgs(SystemBackupScene::EFI_BACKUP);
|
||||
}
|
||||
|
||||
args << efiPath;
|
||||
QString destPath = m_destPath + "/boot/efi";
|
||||
destPath.replace("//", "/");
|
||||
Utils::mkpath(destPath);
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
bool result = m_p->start(args);
|
||||
delete m_p;
|
||||
m_p = nullptr;
|
||||
|
||||
qDebug() << "SystemBackupProxy::backupEfi invoke end";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份系统
|
||||
* @return true,备份成功;false,备份失败
|
||||
*/
|
||||
bool SystemBackupProxy::backupSystem()
|
||||
{
|
||||
qDebug() << "SystemBackupProxy::backupSystem invoke begin";
|
||||
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
// 新增增量备份点场景
|
||||
args = getRsyncArgs(SystemBackupScene::INC_SYSTEM_BACKUP);
|
||||
} else {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(SystemBackupScene::INC_SYSTEM_BACKUP_AT_BASE);
|
||||
}
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(SystemBackupScene::SYSTEM_BACKUP);
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
QString destPath = m_destPath + "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &SystemBackupProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING;
|
||||
m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath));
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.updateItem(m_backupPoint);
|
||||
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(m_backupPoint.m_time + ","
|
||||
+ m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
+ m_backupWrapper.m_note + "," + m_backupPoint.m_size
|
||||
+ ",," + m_backupWrapper.m_backupName);
|
||||
Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
emit this->workResult(result);
|
||||
});
|
||||
m_p->start(args, false);
|
||||
|
||||
do_kylin_security(m_destPath);
|
||||
|
||||
qDebug() << "SystemBackupProxy::backupSystem invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
void SystemBackupProxy::do_kylin_security(const QString& dstDir)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = kysec_getstatus();
|
||||
if (ret > 0) {
|
||||
QString seFilePath(dstDir + "/.exectl");
|
||||
QFile file(seFilePath);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef SYSTEMBACKUPPROXY_H
|
||||
#define SYSTEMBACKUPPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class SystemBackupProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(SystemBackupProxy)
|
||||
public:
|
||||
// 系统备份的几种场景
|
||||
enum SystemBackupScene {
|
||||
SYSTEM_BACKUP, // 系统备份
|
||||
INC_SYSTEM_BACKUP, // 增量系统备份
|
||||
INC_SYSTEM_BACKUP_AT_BASE, // 在原备份点里增量备份
|
||||
TRY_SYSTEM_BACKUP, // 测试系统备份,可用于计算备份传输数据大小
|
||||
TRY_INC_SYSTEM_BACKUP, // 测试增量系统备份,可用于计算备份传输数据大小
|
||||
TRY_INC_SYSTEM_BACKUP_AT_BASE, // 测试增量系统备份,在原备份点里增量备份,可用于计算备份传输数据大小
|
||||
EFI_BACKUP, // 备份/boot/efi
|
||||
};
|
||||
|
||||
explicit SystemBackupProxy();
|
||||
virtual ~SystemBackupProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private:
|
||||
// 判断是否增量备份
|
||||
bool isIncBackup();
|
||||
|
||||
// 校验剩余空间是否满足备份
|
||||
void checkFreeCapacity(qint64 itotalSize);
|
||||
|
||||
// 计算备份所需空间大小
|
||||
void calcSizeForBackup();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(SystemBackupScene scene);
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool recordBackupPoint();
|
||||
|
||||
// 备份准备
|
||||
bool doPrepare();
|
||||
|
||||
// 备份
|
||||
void doBackup();
|
||||
|
||||
// 备份/boot/efi
|
||||
bool backupEfi();
|
||||
|
||||
// 备份系统
|
||||
bool backupSystem();
|
||||
|
||||
void do_kylin_security(const QString& dstDir);
|
||||
|
||||
// 失败则删除相应数据
|
||||
void deleteFailedData();
|
||||
|
||||
// 是否只是检测
|
||||
bool m_isOnlyCheck;
|
||||
// 是否备份成功
|
||||
bool m_bSuccess;
|
||||
// 是否完成
|
||||
bool m_isFinished;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前备份目标目录
|
||||
QString m_destPath;
|
||||
// 当前备份所需空间大小
|
||||
qint64 m_size;
|
||||
// 计算备份空间大小的进程
|
||||
CalcBackupSize *m_calc;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
|
||||
};
|
||||
|
||||
#endif // SYSTEMBACKUPPROXY_H
|
|
@ -0,0 +1,510 @@
|
|||
#include "systemrestoreproxy.h"
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "../common/utils.h"
|
||||
#include "mymountproxy.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(SystemRestoreProxy)
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
SystemRestoreProxy::SystemRestoreProxy()
|
||||
{
|
||||
m_bSuccess = false;
|
||||
m_p = nullptr;
|
||||
m_bRetainUserData = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
SystemRestoreProxy::~SystemRestoreProxy()
|
||||
{
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool SystemRestoreProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "SystemRestoreProxy::checkEnvEx invoke begin";
|
||||
|
||||
// 1、检测.user.txt是否存在
|
||||
m_userFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + PATHS_USER_FILE;
|
||||
m_userFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_userFile)) {
|
||||
qCritical(".user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、检测.exclude.user.txt是否存在
|
||||
m_excludeUserFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
m_excludeUserFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_excludeUserFile)) {
|
||||
qCritical(".exclude.user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、检测还原点是否存在
|
||||
m_backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
m_backupPath.replace("//", "/");
|
||||
if (Utils::isDirEmpty(m_backupPath)) {
|
||||
qCritical("还原点{uuid}/data目录不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4、检测xml中的还原点是否还存在
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (m_backupPoint.m_uuid.isEmpty()) {
|
||||
qCritical("xml中还原点不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_curUuid = m_backupWrapper.m_uuid;
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "SystemRestoreProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行还原逻辑
|
||||
*/
|
||||
void SystemRestoreProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "SystemRestoreProxy::doWorkEx invoke begin";
|
||||
|
||||
// 1、校验
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
// 2、还原efi(兼容旧版本的备份)
|
||||
if (!restoreEfi()) {
|
||||
qCritical("/boot/efi目录同步失败");
|
||||
emit checkResult(int(BackupResult::EFI_RSYNC_FAIL));
|
||||
return ;
|
||||
}
|
||||
|
||||
// 3、还原系统
|
||||
restoreSystem();
|
||||
|
||||
qDebug() << "SystemRestoreProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 还原efi(兼容旧版本的备份)
|
||||
* @return
|
||||
*/
|
||||
bool SystemRestoreProxy::restoreEfi()
|
||||
{
|
||||
qDebug() << "SystemRestoreProxy::restoreEfi invoke begin";
|
||||
|
||||
// 是否有/boot/efi目录
|
||||
QString efiPath = Utils::getSysRootPath() + "/boot/efi";
|
||||
efiPath.replace("//", "/");
|
||||
if (!Utils::isDirEmpty(efiPath)) {
|
||||
// 1、修复源数据
|
||||
repairEfi();
|
||||
sync();
|
||||
|
||||
// 2、重新rw读写挂载
|
||||
remountEfi();
|
||||
|
||||
// 3、同步efi
|
||||
return rsyncEfi();
|
||||
}
|
||||
|
||||
qDebug() << "SystemRestoreProxy::restoreEfi invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 修复efi目录
|
||||
*/
|
||||
void SystemRestoreProxy::repairEfi()
|
||||
{
|
||||
QString qsEfiPath = m_backupPath + "/efi";
|
||||
if (!Utils::isDirEmpty(qsEfiPath)) {
|
||||
// 存在/efi说明是老备份数据,尽量修正老数据
|
||||
QStringList args;
|
||||
args << "-f";
|
||||
args << qsEfiPath;
|
||||
QString newPath = m_backupPath + "/boot";
|
||||
args << newPath;
|
||||
QProcess::execute("mv", args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新rw读写挂载efi分区
|
||||
*/
|
||||
void SystemRestoreProxy::remountEfi()
|
||||
{
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot/efi";
|
||||
mountPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-o"
|
||||
<< "rw,remount"
|
||||
<< mountPath;
|
||||
QProcess::execute("mount", args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新rw读写挂载boot分区
|
||||
*/
|
||||
void SystemRestoreProxy::remountBoot()
|
||||
{
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot";
|
||||
mountPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-o"
|
||||
<< "rw,remount"
|
||||
<< mountPath;
|
||||
QProcess::execute("mount", args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 同步efi
|
||||
*/
|
||||
bool SystemRestoreProxy::rsyncEfi()
|
||||
{
|
||||
QString efiPath = m_backupPath + "/boot/efi/";
|
||||
if (Utils::isDirEmpty(efiPath))
|
||||
efiPath = efiPath = m_backupPath + "/efi/";
|
||||
if (Utils::isDirEmpty(efiPath))
|
||||
return true;
|
||||
|
||||
QStringList args = getRsyncArgs(SystemRestoreScene::EFI_RESTORE);
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot/efi/";
|
||||
mountPath.replace("//", "/");
|
||||
|
||||
args << efiPath << mountPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
bool result = m_p->start(args);
|
||||
delete m_p;
|
||||
m_p = nullptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList SystemRestoreProxy::getRsyncArgs(SystemRestoreScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
|
||||
QDir dataDir(m_srcPath + "/data");
|
||||
QFile file(m_srcPath + "/etc/uid_list");
|
||||
QDir efiDir(m_srcPath + "/boot/efi");
|
||||
QStringList excludes;
|
||||
|
||||
switch (scene) {
|
||||
case SystemRestoreScene::RESTORE_SYSTEM_WITH_DATA :
|
||||
args << "--exclude=/home";
|
||||
args << "--exclude=/root";
|
||||
if (Utils::isHuawei990()) {
|
||||
args << "--exclude=/data";
|
||||
} else {
|
||||
args << "--exclude=/data/usershare";
|
||||
}
|
||||
// 保留指纹数据,用户密码、角色、权限、生物识别等信息不需要改变
|
||||
args << "--exclude=/var/lib/biometric-auth";
|
||||
args << "--exclude=/data/sec_storage_data";
|
||||
args << "--exclude=/etc/passwd";
|
||||
args << "--exclude=/etc/shadow";
|
||||
args << "--exclude=/etc/group";
|
||||
args << "--exclude=/etc/gshadow";
|
||||
args << "--exclude=/etc/sudoers";
|
||||
args << "--exclude=/data/home";
|
||||
args << "--exclude=/data/root";
|
||||
|
||||
// 云图片作为桌面背景的路径属于用户数据
|
||||
args << "--exclude=/var/lib/AccountsService";
|
||||
|
||||
// 域用户相关信息,还原后保持不退域
|
||||
args << "--exclude=/etc/sssd";
|
||||
args << "--exclude=/var/lib/sss";
|
||||
args << "--exclude=/usr/share/sssd";
|
||||
args << "--exclude=/etc/ipa";
|
||||
args << "--exclude=/etc/krb5.keytab";
|
||||
args << "--exclude=/etc/krb5.conf";
|
||||
args << "--exclude=/var/lib/ipa-client";
|
||||
args << "--exclude=/etc/nsswitch.conf";
|
||||
args << "--exclude=/etc/pam.d";
|
||||
args << "--exclude=/etc/hosts";
|
||||
args << "--exclude=/etc/hostname";
|
||||
args << "--exclude=/etc/hedron";
|
||||
args << "--exclude=/etc/kcm";
|
||||
args << "--exclude=/usr/hedron/hedronagent";
|
||||
args << "--exclude=/etc/.kyinfo";
|
||||
args << "--exclude=/etc/LICENSE";
|
||||
args << "--exclude=/etc/ssl/certs";
|
||||
args << "--exclude=/usr/share/ca-certificates";
|
||||
args << "--exclude=/etc/NetworkManager";
|
||||
|
||||
// 此处不要break,因为还需要排除SYSTEM_RESTORE中的项
|
||||
|
||||
case SystemRestoreScene::SYSTEM_RESTORE :
|
||||
// 还原工具不还原自身
|
||||
args << "--exclude=/usr/bin/backup-daemon";
|
||||
args << "--exclude=/usr/bin/kybackup";
|
||||
args << "--exclude=/usr/bin/mount_fstab_efi";
|
||||
args << "--exclude=/usr/bin/backup-auto-efi";
|
||||
args << "--exclude=/usr/bin/backup-auto";
|
||||
args << "--exclude=/usr/bin/rsync";
|
||||
args << "--exclude=/usr/share/rsync";
|
||||
args << "--exclude=/usr/share/initramfs-tools/hooks/kybackup-hooks";
|
||||
args << "--exclude=/usr/share/initramfs-tools/scripts/local-bottom/kybackup";
|
||||
|
||||
// 以前的出厂备份和grub备份没有备份/data,还原时需要判断/data是否存在,如不存在需要屏蔽掉,不然会将主机上的/data删除,造成问题
|
||||
// 此为兼容以前备份的老数据而改,等以后老的备份估计不存在了可已去掉
|
||||
if (!dataDir.exists()) {
|
||||
args << "--exclude=/data";
|
||||
}
|
||||
|
||||
if (!file.exists()) {
|
||||
args << "--exclude=/etc/uid_list";
|
||||
}
|
||||
|
||||
// 为兼容以前的老备份数据,增加下面几行
|
||||
if (efiDir.isEmpty()) {
|
||||
args << QString("--exclude=/boot/efi");
|
||||
}
|
||||
// 系统安装后有的会将/data/home /data/root挂载到的/home /root上,实际文件是存放在/data/home /data/root下面
|
||||
Utils::excludeFstabBindPath(excludes);
|
||||
// 自定义备份的路径也需要跳过,不进行还原
|
||||
Utils::excludeCustomizePath(excludes);
|
||||
for (const QString& item : excludes) {
|
||||
QDir itemDir(m_srcPath + item);
|
||||
// 以后统一用/home /root这种路径, 兼容老备份数据(原来的U盘备份,在mksquashfs时排除bind挂载的任意一方时,都备份不上)
|
||||
if (item == "/data/home") {
|
||||
QDir homeDir(m_srcPath + "/home");
|
||||
if (!homeDir.isEmpty()) {
|
||||
args << QString("--exclude=/data/home");
|
||||
} else if (!itemDir.isEmpty()) {
|
||||
args << QString("--exclude=/home");
|
||||
} else {
|
||||
args << QString("--exclude=/data/home");
|
||||
args << QString("--exclude=/home");
|
||||
}
|
||||
continue;
|
||||
} else if (item == "/data/root") {
|
||||
QDir homeDir(m_srcPath + "/root");
|
||||
if (!homeDir.isEmpty()) {
|
||||
args << QString("--exclude=/data/root");
|
||||
} else if (!itemDir.isEmpty()) {
|
||||
args << QString("--exclude=/root");
|
||||
} else {
|
||||
args << QString("--exclude=/data/root");
|
||||
args << QString("--exclude=/root");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
args << QString("--exclude=") + item;
|
||||
}
|
||||
|
||||
args << "--exclude-from" << m_excludeUserFile;
|
||||
args << "--files-from" << m_userFile;
|
||||
|
||||
break ;
|
||||
case SystemRestoreScene::EFI_RESTORE :
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 系统还原
|
||||
*/
|
||||
void SystemRestoreProxy::restoreSystem()
|
||||
{
|
||||
// 停止安全防护
|
||||
QProcess::execute("systemctl stop kysec-init.service");
|
||||
|
||||
// 本地系统备份没有img挂载,故下面两个路径相等
|
||||
m_srcPath = m_backupPath;
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
|
||||
// 以读写方式重新挂载boot分区,因为有的机器默认以只读挂载
|
||||
remountBoot();
|
||||
|
||||
QStringList args;
|
||||
// 自动更新的备份还原时保留用户数据
|
||||
if (m_curUuid == AUTO_BACKUP_UUID || m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM_WITH_DATA) {
|
||||
args = getRsyncArgs(SystemRestoreScene::RESTORE_SYSTEM_WITH_DATA);
|
||||
m_bRetainUserData = true;
|
||||
} else {
|
||||
args = getRsyncArgs(SystemRestoreScene::SYSTEM_RESTORE);
|
||||
}
|
||||
|
||||
args << m_srcPath + "/";
|
||||
destPath += "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &SystemRestoreProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
if (result) {
|
||||
QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,,," + m_backupPoint.m_backupName);
|
||||
|
||||
Utils::updateSyncFile();
|
||||
Utils::wait(2);
|
||||
QString fileIfSync = Utils::getSysRootPath() + FILE_IF_SYNC;
|
||||
fileIfSync.replace("//", "/");
|
||||
QFileInfo file(fileIfSync);
|
||||
QDateTime beginTime = file.fileTime(QFileDevice::FileModificationTime);
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(20);
|
||||
Utils::updateSyncFile();
|
||||
while (1) {
|
||||
Utils::wait(2);
|
||||
QFileInfo file1(fileIfSync);
|
||||
QDateTime UpdateTime = file1.fileTime(QFileDevice::FileModificationTime);
|
||||
if (UpdateTime > beginTime)
|
||||
break;
|
||||
}
|
||||
if (FACTORY_BACKUP_UUID == m_curUuid && m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM) {
|
||||
// 出厂还原有的机器上删除/home/xxx有残留,故在此再强制删除一下,sudo rm -rf命令一遍还删除不了(报错:无法删除/home/xx/.config:目录非空,应该是删除后又自动生成了),多删除几次还不是非常干净,^_^
|
||||
removeHome(QString(Utils::getSysRootPath() + "/home").replace("//", "/"));
|
||||
removeHome(QString(Utils::getSysRootPath() + "/data/home").replace("//", "/"));
|
||||
}
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
emit this->workResult(result);
|
||||
Utils::wait(2);
|
||||
|
||||
reboot(RB_AUTOBOOT);
|
||||
} else {
|
||||
emit this->workResult(result);
|
||||
}
|
||||
});
|
||||
|
||||
m_p->start(args, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取备份点里存在家目录的用户列表
|
||||
* @param void
|
||||
* @return 获取备份点里存在家目录的用户列表
|
||||
*/
|
||||
QStringList SystemRestoreProxy::getBackupPointUsers()
|
||||
{
|
||||
// 根据备份点里的/home或/data/home的子目录进行统计
|
||||
QString homePath = m_backupPath + "/home";
|
||||
homePath.replace("//","/");
|
||||
QStringList users = getBackupPointUsers(homePath);
|
||||
QString dataHomePath = m_backupPath + "/data/home";
|
||||
dataHomePath.replace("//","/");
|
||||
users.append(getBackupPointUsers(dataHomePath));
|
||||
return users;
|
||||
}
|
||||
|
||||
QStringList SystemRestoreProxy::getBackupPointUsers(const QString& path)
|
||||
{
|
||||
QDir dir(path);
|
||||
if (dir.exists()) {
|
||||
return dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs);
|
||||
} else {
|
||||
return QStringList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 删除home子目录,此处主要用于删除用户残留信息
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
void SystemRestoreProxy::removeHome(const QString& path)
|
||||
{
|
||||
qDebug() << "SystemRestoreProxy::removeHome invoke begin";
|
||||
|
||||
QDir dir(path);
|
||||
if (dir.exists()) {
|
||||
QStringList retainUsers = getBackupPointUsers();
|
||||
qDebug() << retainUsers;
|
||||
|
||||
QString subcmd("rm -rf ");
|
||||
QStringList list = dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs);
|
||||
for (const QString& item : list) {
|
||||
// 出厂备份里面的/home/oem等保留
|
||||
if (item == "oem")
|
||||
continue ;
|
||||
if (retainUsers.contains(item))
|
||||
continue ;
|
||||
|
||||
QString subPath = path;
|
||||
subPath += "/";
|
||||
subPath += item;
|
||||
QDir subDir(subPath);
|
||||
subDir.removeRecursively();
|
||||
|
||||
qDebug() << (subcmd + subPath);
|
||||
QProcess::execute(subcmd + subPath);
|
||||
}
|
||||
|
||||
// bool needRm = false;
|
||||
// QString subcmd("rm -rf ");
|
||||
// QString delDirs;
|
||||
// QStringList list = dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs);
|
||||
// for (const QString& item : list) {
|
||||
// // 出厂备份里面的/home/oem等保留
|
||||
// if (item == "oem")
|
||||
// continue ;
|
||||
// if (retainUsers.contains(item))
|
||||
// continue ;
|
||||
|
||||
// QString subPath = path;
|
||||
// subPath += "/";
|
||||
// subPath += item;
|
||||
// QDir subDir(subPath);
|
||||
// subDir.removeRecursively();
|
||||
|
||||
// delDirs += "${rootmnt}";
|
||||
// delDirs += path;
|
||||
// delDirs += "/";
|
||||
// delDirs += item;
|
||||
// delDirs += " ";
|
||||
|
||||
// needRm = true;
|
||||
// }
|
||||
|
||||
// if (needRm) {
|
||||
// QString cmd = QString("bash -c \"%1\" ").arg(subcmd + delDirs);
|
||||
// cmd.replace("${rootmnt}", "");
|
||||
// QProcess::execute(cmd);
|
||||
// }
|
||||
}
|
||||
|
||||
qDebug() << "SystemRestoreProxy::removeHome invoke end";
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef SYSTEMRESTOREPROXY_H
|
||||
#define SYSTEMRESTOREPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class SystemRestoreProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(SystemRestoreProxy)
|
||||
public:
|
||||
// 系统还原的几种场景
|
||||
enum SystemRestoreScene {
|
||||
SYSTEM_RESTORE, // 系统还原
|
||||
RESTORE_SYSTEM_WITH_DATA, // 保留用户数据还原
|
||||
EFI_RESTORE, // efi还原
|
||||
};
|
||||
|
||||
explicit SystemRestoreProxy();
|
||||
virtual ~SystemRestoreProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
private:
|
||||
// 还原efi
|
||||
bool restoreEfi();
|
||||
// 修复efi目录
|
||||
void repairEfi();
|
||||
// 以读写方式重新挂载efi分区
|
||||
void remountEfi();
|
||||
// 以读写方式重新挂载boot分区
|
||||
void remountBoot();
|
||||
// 同步efi
|
||||
bool rsyncEfi();
|
||||
// 系统还原
|
||||
void restoreSystem();
|
||||
// 删除home下的用户家目录
|
||||
void removeHome(const QString& path);
|
||||
// 获取备份点里存在家目录的用户列表
|
||||
QStringList getBackupPointUsers();
|
||||
QStringList getBackupPointUsers(const QString& path);
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(SystemRestoreScene scene);
|
||||
|
||||
// .user.txt文件路径
|
||||
QString m_userFile;
|
||||
// .exclude.user.txt文件路径
|
||||
QString m_excludeUserFile;
|
||||
// 备份数据所在的data目录
|
||||
QString m_backupPath;
|
||||
|
||||
// 是否还原成功
|
||||
bool m_bSuccess;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前还原源目录
|
||||
QString m_srcPath;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
// 是否保留用户数据
|
||||
bool m_bRetainUserData;
|
||||
};
|
||||
|
||||
#endif // SYSTEMRESTOREPROXY_H
|
|
@ -0,0 +1,455 @@
|
|||
#include "udiskdatabackupproxy.h"
|
||||
#include <QStorageInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <kysec/status.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(UDiskDataBackupProxy)
|
||||
|
||||
UDiskDataBackupProxy::UDiskDataBackupProxy()
|
||||
{
|
||||
m_isForce = false;
|
||||
}
|
||||
|
||||
UDiskDataBackupProxy::~UDiskDataBackupProxy()
|
||||
{
|
||||
m_isForce = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool UDiskDataBackupProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "UDiskDataBackupProxy::checkEnv invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
// 后来支持无备份分区
|
||||
MyMountProxy mountProxy;
|
||||
MountResult result = mountProxy.mountBackupPartition();
|
||||
// 无备份分区
|
||||
if (MountResult::CANNOT_GET_BACKUPUUID == result) {
|
||||
qInfo() << "There is no backup partition!";
|
||||
|
||||
QString snapshotsPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH;
|
||||
snapshotsPath.replace("//", "/");
|
||||
Utils::mkpath(snapshotsPath);
|
||||
Utils::generateExcludePathsFile();
|
||||
} else if (MountResult::MOUNTED != result) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo udisk(backupPath);
|
||||
QString udisk_type = udisk.fileSystemType();
|
||||
qDebug() << "udisk's filesystemtype is " << udisk_type;
|
||||
if (udisk_type == "vfat") {
|
||||
qCritical() << m_backupWrapper.m_prefixDestPath + " udisk's filesystemtype is vfat";
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT));
|
||||
return false;
|
||||
}
|
||||
if (udisk.isReadOnly()) {
|
||||
// 只读挂载的U盘
|
||||
qCritical() << QString("udisk(%s) is readonly filesystem").arg(m_backupWrapper.m_prefixDestPath);
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_IS_READONLY));
|
||||
return false;
|
||||
}
|
||||
|
||||
QTimer::singleShot(1*1000, this, &UDiskDataBackupProxy::checkDestDirExists);
|
||||
|
||||
// 2、判断备份是否增量备份
|
||||
isIncBackup();
|
||||
|
||||
// 3、检测空间是否满足备份
|
||||
calcSizeForBackupToUdisk();
|
||||
|
||||
qDebug() << "UDiskDataBackupProxy::checkEnv invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行备份逻辑
|
||||
*/
|
||||
void UDiskDataBackupProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "UDiskDataBackupProxy::doWorkEx invoke begin";
|
||||
|
||||
m_isOnlyCheck = false;
|
||||
// 环境检测
|
||||
checkEnvEx();
|
||||
|
||||
qDebug() << "UDiskDataBackupProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消操作
|
||||
*/
|
||||
void UDiskDataBackupProxy::cancelEx()
|
||||
{
|
||||
qDebug() << "UDiskDataBackupProxy::cancelEx invoke begin";
|
||||
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_calc)
|
||||
m_calc->stop();
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
|
||||
qDebug() << "UDiskDataBackupProxy::cancelEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void UDiskDataBackupProxy::deleteFailedData()
|
||||
{
|
||||
if (m_curUuid.isEmpty())
|
||||
return;
|
||||
|
||||
// 1、删除备份目录
|
||||
QString destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid;
|
||||
destPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-rf";
|
||||
args << destPath;
|
||||
QProcess::execute("rm", args);
|
||||
|
||||
// 2、删除xml文件中的备份项
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.deleteItem(m_curUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否增量备份
|
||||
* @return true,增量备份; false,全量备份
|
||||
*/
|
||||
bool UDiskDataBackupProxy::isIncBackup()
|
||||
{
|
||||
QString backupPath;
|
||||
ParseBackupList::BackupPoint point;
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
}
|
||||
|
||||
backupPath.replace("//", "/");
|
||||
if (Utils::isDirExist(backupPath)) {
|
||||
m_backupWrapper.m_bIncrement = true;
|
||||
m_backupWrapper.m_type = BackupType::INC_BACKUP_DATA;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 校验剩余空间是否满足备份
|
||||
*/
|
||||
bool UDiskDataBackupProxy::checkFreeCapacityToUdisk(qint64 itotalSize)
|
||||
{
|
||||
qDebug() << "UDiskDataBackupProxy::checkFreeCapacityToUdisk invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return false;
|
||||
|
||||
// 拔掉U盘的场景
|
||||
if (m_isForce) {
|
||||
emit this->checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 1、计算待备份数据的大小
|
||||
m_size = itotalSize;
|
||||
// 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留500M的空间
|
||||
itotalSize += 5 * MB;
|
||||
|
||||
// 2、计算备份分区剩余空间大小
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo backupDisk(backupPath);
|
||||
qint64 freeSize = backupDisk.bytesAvailable();
|
||||
|
||||
// 3、校验空间是否足够
|
||||
bool result = true;
|
||||
if (itotalSize > freeSize) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
result = false;
|
||||
return result;
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
}
|
||||
|
||||
if (m_isOnlyCheck)
|
||||
return result;
|
||||
|
||||
// 开始备份
|
||||
doBackupToUdisk();
|
||||
|
||||
qDebug() << "UDiskDataBackupProxy::checkFreeCapacityToUdisk invoke end";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算备份所需空间大小
|
||||
* @return 计算备份所需空间大小,单位字节
|
||||
*/
|
||||
void UDiskDataBackupProxy::calcSizeForBackupToUdisk()
|
||||
{
|
||||
QString destPath;
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::TRY_INC_DATA_BACKUP);
|
||||
destPath = m_backupWrapper.m_prefixDestPath;
|
||||
destPath += BACKUP_SNAPSHOTS_PATH;
|
||||
destPath += "/";
|
||||
destPath += m_backupWrapper.m_uuid;
|
||||
destPath += "/data/";
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::TRY_DATA_BACKUP);
|
||||
destPath = Utils::getSysRootPath();
|
||||
destPath += CHECK_PATH;
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
Utils::mkpath(destPath);
|
||||
|
||||
connect(m_calc, &CalcBackupSize::finished, this, &UDiskDataBackupProxy::checkFreeCapacityToUdisk);
|
||||
m_calc->start(args, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份
|
||||
*/
|
||||
void UDiskDataBackupProxy::doBackupToUdisk()
|
||||
{
|
||||
qDebug() << "UDiskDataBackupProxy::doBackupToUdisk invoke begin";
|
||||
|
||||
// 准备
|
||||
if (!doPrepareToUdisk())
|
||||
return ;
|
||||
|
||||
// 启动数据备份
|
||||
backupDataToUdisk();
|
||||
|
||||
qDebug() << "UDiskDataBackupProxy::doBackupToUdisk invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份准备
|
||||
* @return true,准备成功;false,准备失败
|
||||
*/
|
||||
bool UDiskDataBackupProxy::doPrepareToUdisk()
|
||||
{
|
||||
qDebug() << "UDiskDataBackupProxy::doPrepareToUdisk invoke begin";
|
||||
|
||||
m_bSuccess = false;
|
||||
|
||||
// 1、设置当前备份的Uuid
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
// 新增备份点,不指定uuid的场景
|
||||
m_curUuid += Utils::createUuid();
|
||||
} else {
|
||||
// 指定uuid备份的场景
|
||||
m_curUuid = m_backupWrapper.m_uuid;
|
||||
}
|
||||
|
||||
// 2、准备备份目录及文件
|
||||
m_destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data";
|
||||
m_destPath.replace("//", "/");
|
||||
if (!Utils::mkpath(m_destPath)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE;
|
||||
m_userFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(m_userFile, m_backupWrapper.m_backupPaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(m_userFile) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
m_excludeUserFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(m_excludeUserFile, m_backupWrapper.m_backupExcludePaths)) {
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
qCritical() << QString("create file %1 failed !").arg(m_excludeUserFile) ;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、记录/backup/snapshots/backuplist.xml文件
|
||||
if (!recordBackupPointToUdisk()) {
|
||||
qCritical() << "add or update item to backuplist.xml failed !";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "UDiskDataBackupProxy::doPrepareToUdisk invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool UDiskDataBackupProxy::recordBackupPointToUdisk()
|
||||
{
|
||||
m_backupPoint.m_backupName = m_backupWrapper.m_backupName;
|
||||
m_backupPoint.m_uuid = m_curUuid;
|
||||
m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition;
|
||||
m_backupPoint.m_type = m_backupWrapper.m_type;
|
||||
m_backupPoint.m_size = Utils::StringBySize(m_size);
|
||||
m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING;
|
||||
if (0 < m_backupWrapper.m_frontUid)
|
||||
m_backupPoint.m_userId = QString::number(m_backupWrapper.m_frontUid);
|
||||
m_backupPoint.m_os = SystemInfo::m_os;
|
||||
m_backupPoint.m_arch = SystemInfo::m_arch;
|
||||
m_backupPoint.m_archdetect = SystemInfo::m_archDetect;
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (!m_backupWrapper.m_bIncrement) {
|
||||
if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份系统
|
||||
* @return true,备份成功;false,备份失败
|
||||
*/
|
||||
bool UDiskDataBackupProxy::backupDataToUdisk()
|
||||
{
|
||||
qDebug() << "UDiskDataBackupProxy::backupDataToUdisk invoke begin";
|
||||
|
||||
QStringList args;
|
||||
if (m_backupWrapper.m_bIncrement) {
|
||||
// 在原来的备份点上增量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::INC_DATA_BACKUP);
|
||||
} else {
|
||||
// 全量备份场景
|
||||
args = getRsyncArgs(DataBackupScene::DATA_BACKUP);
|
||||
}
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
QString destPath = m_destPath + "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskDataBackupProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isForce = false;
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING;
|
||||
m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath));
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (ParseBackupList::ParseResult::SUCCESS != parse.updateItem(m_backupPoint)) {
|
||||
qCritical() << "update backuplist.xml error in sendBackupResult";
|
||||
result = false;
|
||||
} else {
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(m_backupPoint.m_time + ","
|
||||
+ m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
+ m_backupWrapper.m_note + "," + m_backupPoint.m_size
|
||||
+ "," + QString::number(m_backupWrapper.m_frontUid)
|
||||
+ "," + m_backupWrapper.m_backupName);
|
||||
Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
}
|
||||
emit this->workResult(result);
|
||||
});
|
||||
m_p->start(args, false);
|
||||
|
||||
do_kylin_security(m_destPath);
|
||||
|
||||
qDebug() << "UDiskDataBackupProxy::backupDataToUdisk invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验移动盘是否还在
|
||||
* @return: bool,存在返回true;不存在返回false
|
||||
* @author: zhaominyong
|
||||
* @since: 2021/05/24
|
||||
* @note:
|
||||
* add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据
|
||||
*/
|
||||
bool UDiskDataBackupProxy::checkDestDirExists()
|
||||
{
|
||||
if (!m_isFinished)
|
||||
{
|
||||
// 拔掉U盘后,没有响应的场景(怀疑可能是某应用程序关闭引起,希望不是dbus服务关掉了)
|
||||
if (m_isForce) {
|
||||
emit this->workResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupWrapper.m_prefixDestPath)) {
|
||||
qCritical() << QString("dstDir %s is not exist!").arg(m_backupWrapper.m_prefixDestPath);
|
||||
m_isForce = true;
|
||||
if (m_calc != nullptr)
|
||||
m_calc->stop();
|
||||
if (m_p != nullptr)
|
||||
m_p->stop();
|
||||
// 10s钟后如果还没有退出,则强制退出
|
||||
QTimer::singleShot(10*1000, this, &UDiskDataBackupProxy::checkDestDirExists);
|
||||
} else {
|
||||
QTimer::singleShot(1*1000, this, &UDiskDataBackupProxy::checkDestDirExists);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef UDISKDATABACKUPPROXY_H
|
||||
#define UDISKDATABACKUPPROXY_H
|
||||
|
||||
#include "databackupproxy.h"
|
||||
|
||||
class UDiskDataBackupProxy : public DataBackupProxy
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(UDiskDataBackupProxy)
|
||||
public:
|
||||
explicit UDiskDataBackupProxy();
|
||||
virtual ~UDiskDataBackupProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
public slots:
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private slots:
|
||||
// 校验剩余空间是否满足备份
|
||||
bool checkFreeCapacityToUdisk(qint64 itotalSize);
|
||||
|
||||
// 备份
|
||||
void doBackupToUdisk();
|
||||
|
||||
/**
|
||||
* @brief 校验移动盘是否还在
|
||||
* @return: bool,存在返回true;不存在返回false
|
||||
* @author: zhaominyong
|
||||
* @since: 2021/05/24
|
||||
* @note:
|
||||
* add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据
|
||||
*/
|
||||
bool checkDestDirExists();
|
||||
|
||||
protected:
|
||||
// 失败则删除相应数据
|
||||
virtual void deleteFailedData();
|
||||
// 判断是否增量备份
|
||||
virtual bool isIncBackup();
|
||||
|
||||
private:
|
||||
// 计算备份所需空间大小
|
||||
void calcSizeForBackupToUdisk();
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool recordBackupPointToUdisk();
|
||||
|
||||
// 备份准备
|
||||
bool doPrepareToUdisk();
|
||||
|
||||
// 备份系统
|
||||
bool backupDataToUdisk();
|
||||
|
||||
// 强制结束标志(stop后没反应的情况,系统处于睡眠状态)
|
||||
bool m_isForce;
|
||||
};
|
||||
|
||||
#endif // UDISKDATABACKUPPROXY_H
|
|
@ -0,0 +1,186 @@
|
|||
#include "udiskdatarestoreproxy.h"
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "../common/utils.h"
|
||||
#include "mymountproxy.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(UDiskDataRestoreProxy)
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
UDiskDataRestoreProxy::UDiskDataRestoreProxy()
|
||||
{
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_p = nullptr;
|
||||
m_isForce = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
UDiskDataRestoreProxy::~UDiskDataRestoreProxy()
|
||||
{
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool UDiskDataRestoreProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "UDiskDataRestoreProxy::checkEnvEx invoke begin";
|
||||
|
||||
// 1、检测.user.txt是否存在
|
||||
m_userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + PATHS_USER_FILE;
|
||||
if (!Utils::filsExists(m_userFile)) {
|
||||
qCritical(".user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、检测.exclude.user.txt是否存在
|
||||
m_excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
if (!Utils::filsExists(m_excludeUserFile)) {
|
||||
qCritical(".exclude.user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、检测还原点是否存在
|
||||
m_backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
if (Utils::isDirEmpty(m_backupPath)) {
|
||||
qCritical("还原点{uuid}/data目录不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4、检测xml中的还原点是否还存在
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (m_backupPoint.m_uuid.isEmpty()) {
|
||||
qCritical("xml中还原点不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "UDiskDataRestoreProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行还原逻辑
|
||||
*/
|
||||
void UDiskDataRestoreProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "UDiskDataRestoreProxy::doWorkEx invoke begin";
|
||||
|
||||
// 1、校验
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
// 2、还原数据
|
||||
restoreData();
|
||||
|
||||
qDebug() << "UDiskDataRestoreProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList UDiskDataRestoreProxy::getRsyncArgs(DataRestoreScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
|
||||
switch (scene) {
|
||||
case DataRestoreScene::DATA_RESTORE :
|
||||
args << "--files-from" << m_userFile;
|
||||
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 数据还原
|
||||
*/
|
||||
void UDiskDataRestoreProxy::restoreData()
|
||||
{
|
||||
qDebug() << "UDiskDataRestoreProxy::restoreData invoke begin";
|
||||
|
||||
QStringList args = getRsyncArgs(DataRestoreScene::DATA_RESTORE);
|
||||
|
||||
m_srcPath = m_backupPath;
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
destPath.replace("//", "/");
|
||||
args << m_srcPath + "/";
|
||||
args << destPath + "/";
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskDataRestoreProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
m_isForce = false;
|
||||
m_bSuccess = result;
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
Utils::writeBackupLog(time + "," + m_backupWrapper.m_uuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid)+ "," + m_backupPoint.m_backupName);
|
||||
}
|
||||
emit this->workResult(result);
|
||||
});
|
||||
|
||||
QTimer::singleShot(1*1000, this, &UDiskDataRestoreProxy::checkUdiskExists);
|
||||
m_isFinished = false;
|
||||
m_bSuccess = false;
|
||||
m_p->start(args, false);
|
||||
|
||||
qDebug() << "UDiskDataRestoreProxy::restoreData invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 监控移动设备是否还在
|
||||
* @return true-在;false-不在
|
||||
*/
|
||||
bool UDiskDataRestoreProxy::checkUdiskExists()
|
||||
{
|
||||
if (!m_isFinished) {
|
||||
// 拔掉U盘后,没有响应的场景(怀疑可能是某应用程序关闭引起,希望不是dbus服务关掉了)
|
||||
if (m_isForce) {
|
||||
emit this->workResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupPath)) {
|
||||
if (m_p != nullptr)
|
||||
m_p->stop();
|
||||
// 10s钟后如果还没有退出,则强制退出
|
||||
QTimer::singleShot(10*1000, this, &UDiskDataRestoreProxy::checkUdiskExists);
|
||||
m_isForce = true;
|
||||
} else {
|
||||
QTimer::singleShot(1*1000, this, &UDiskDataRestoreProxy::checkUdiskExists);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef UDISKDATARESTOREPROXY_H
|
||||
#define UDISKDATARESTOREPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class UDiskDataRestoreProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(UDiskDataRestoreProxy)
|
||||
public:
|
||||
// 数据还原的几种场景
|
||||
enum DataRestoreScene {
|
||||
DATA_RESTORE, // 数据还原
|
||||
};
|
||||
|
||||
explicit UDiskDataRestoreProxy();
|
||||
virtual ~UDiskDataRestoreProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
private slots:
|
||||
bool checkUdiskExists();
|
||||
|
||||
private:
|
||||
// 数据还原
|
||||
void restoreData();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(DataRestoreScene scene);
|
||||
|
||||
// .user.txt文件路径
|
||||
QString m_userFile;
|
||||
// .exclude.user.txt文件路径
|
||||
QString m_excludeUserFile;
|
||||
// 备份数据所在的data目录
|
||||
QString m_backupPath;
|
||||
|
||||
// 是否还原成功
|
||||
bool m_bSuccess;
|
||||
// 是否完成
|
||||
bool m_isFinished;
|
||||
// 当前还原源目录
|
||||
QString m_srcPath;
|
||||
// 还原进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
// 强制结束标志(stop后没反应的情况,系统处于睡眠状态)
|
||||
bool m_isForce;
|
||||
};
|
||||
|
||||
#endif // UDISKDATARESTOREPROXY_H
|
|
@ -0,0 +1,306 @@
|
|||
#include "udiskghostImageproxy.h"
|
||||
#include <QStorageInfo>
|
||||
#include <QFileInfo>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <kysec/status.h>
|
||||
#include <unistd.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(UDiskGhostImageProxy)
|
||||
|
||||
UDiskGhostImageProxy::UDiskGhostImageProxy()
|
||||
{
|
||||
m_mksquashfs = nullptr;
|
||||
m_p = nullptr;
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_isForce = false;
|
||||
|
||||
connect(this, &UDiskGhostImageProxy::cancel, this, &UDiskGhostImageProxy::cancelEx);
|
||||
}
|
||||
|
||||
UDiskGhostImageProxy::~UDiskGhostImageProxy()
|
||||
{
|
||||
if (!m_kyimg.isEmpty()) {
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
*/
|
||||
bool UDiskGhostImageProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "UDiskGhostImageProxy::checkEnvEx invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
MyMountProxy mountProxy;
|
||||
MountResult result = mountProxy.mountBackupPartition();
|
||||
// 无备份分区
|
||||
if (MountResult::CANNOT_GET_BACKUPUUID == result) {
|
||||
qInfo() << "There is no backup partition!";
|
||||
|
||||
QString snapshotsPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH;
|
||||
snapshotsPath.replace("//", "/");
|
||||
Utils::mkpath(snapshotsPath);
|
||||
Utils::generateExcludePathsFile();
|
||||
} else if (MountResult::MOUNTED != result) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、校验backuppoint.xml中相应的备份节点是否存在
|
||||
QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList xmlParse(xmlPath);
|
||||
ParseBackupList::BackupPoint backupPoint = xmlParse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (backupPoint.m_backupName.isEmpty()) {
|
||||
emit checkResult(int(BackupResult::GHOST_CANNOT_FIND_BACKUPPOINT));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、校验备份数据是否存在
|
||||
QString dataPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
dataPath.replace("//", "/");
|
||||
if (Utils::isDirEmpty(dataPath)) {
|
||||
emit checkResult(int(BackupResult::GHOST_SRC_DIRECTORY_IS_NOT_EXIST));
|
||||
return false;
|
||||
}
|
||||
qint64 itotalSize = Utils::getDirOrFileSize(dataPath);
|
||||
|
||||
// 4、校验移动设备情况:空间大小、文件格式、挂载模式等
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo udisk(backupPath);
|
||||
QString udisk_type = udisk.fileSystemType();
|
||||
qDebug() << "udisk's filesystemtype is " << udisk_type;
|
||||
if (udisk_type == "vfat") {
|
||||
qCritical() << m_backupWrapper.m_prefixDestPath + " udisk's filesystemtype is vfat";
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT));
|
||||
return false;
|
||||
}
|
||||
if (udisk.isReadOnly()) {
|
||||
// 只读挂载的U盘
|
||||
qCritical() << QString("udisk(%s) is readonly filesystem").arg(m_backupWrapper.m_prefixDestPath);
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_IS_READONLY));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_destPath = m_backupWrapper.m_prefixDestPath + GHOST_PATH;
|
||||
m_destPath.replace("//", "/");
|
||||
Utils::mkpath(m_destPath);
|
||||
m_kyimg = m_destPath + "/" + m_backupWrapper.m_backupName;
|
||||
m_kyimg.replace("//", "/");
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
QStorageInfo storageInfo(m_destPath);
|
||||
qint64 sizeAvailable = storageInfo.bytesAvailable();
|
||||
if (sizeAvailable < itotalSize / 2) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5、依托本地存储先行压缩再拷贝到移动设备,在此查找空闲分区临时借用
|
||||
bool found = false;
|
||||
QHash<QString, qint64> hash = Utils::getAvailableSizeOfPartitions();
|
||||
for (QHash<QString, qint64>::const_iterator it = hash.constBegin(); it != hash.constEnd(); ++it) {
|
||||
QString path = it.key();
|
||||
qint64 leftSize = it.value();
|
||||
if (leftSize > itotalSize / 2) {
|
||||
Utils::mkpath(path + GHOST_PATH);
|
||||
m_kyimg = path + GHOST_PATH + "/" + m_backupWrapper.m_backupName;
|
||||
m_kyimg.replace("//", "/");
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
|
||||
found = true;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_FOR_UDISKIMG_IS_NOT_ENOUGH));
|
||||
return false;
|
||||
}
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "UDiskGhostImageProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务处理
|
||||
*/
|
||||
void UDiskGhostImageProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "UDiskGhostImageProxy::doWorkEx invoke begin";
|
||||
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
doGhostImage();
|
||||
|
||||
qDebug() << "UDiskGhostImageProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务取消
|
||||
*/
|
||||
void UDiskGhostImageProxy::cancelEx()
|
||||
{
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_mksquashfs)
|
||||
m_mksquashfs->stop();
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void UDiskGhostImageProxy::deleteFailedData()
|
||||
{
|
||||
// 1、删除临时镜像文件
|
||||
if (!m_kyimg.isEmpty()) {
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
}
|
||||
|
||||
// 2、删除目标镜像文件
|
||||
QString kyimgFile = m_destPath + "/" + m_backupWrapper.m_backupName;
|
||||
kyimgFile.replace("//", "/");
|
||||
QFile kyimgDest(kyimgFile);
|
||||
if (kyimgDest.exists())
|
||||
kyimgDest.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ghost镜像
|
||||
*/
|
||||
void UDiskGhostImageProxy::doGhostImage()
|
||||
{
|
||||
qDebug() << "UDiskGhostImageProxy::doGhostImage invoke begin";
|
||||
|
||||
QStringList args;
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
args << m_kyimg;
|
||||
|
||||
m_mksquashfs = new MkSquashFSProcess(this);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::progress, this, &UDiskGhostImageProxy::progress);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::finished, this, [&](bool result) {
|
||||
qDebug() << "UDiskGhostImageProxy::finished invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
if (result && !m_isForce) {
|
||||
chown(m_kyimg.toLocal8Bit().data(), m_backupWrapper.m_frontUid, m_backupWrapper.m_gid);
|
||||
|
||||
// 同步到U盘
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskGhostImageProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool resultRsync) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isForce = false;
|
||||
m_isFinished = true;
|
||||
if (resultRsync) {
|
||||
// QFileInfo fileInfo(m_kyimg);
|
||||
// QString imgSize = Utils::StringBySize(fileInfo.size());
|
||||
// QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
// Utils::writeBackupLog(time + ","
|
||||
// + m_backupWrapper.m_uuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
// + m_backupWrapper.m_note + "," + imgSize
|
||||
// + ",," + m_backupWrapper.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
QFile kyimg(m_kyimg);
|
||||
if (kyimg.exists())
|
||||
kyimg.remove();
|
||||
|
||||
emit this->workResult(resultRsync);
|
||||
});
|
||||
|
||||
QStringList arguments;
|
||||
arguments << "-av";
|
||||
arguments << "--info=progress2";
|
||||
arguments << m_kyimg;
|
||||
arguments << m_destPath + "/";
|
||||
m_p->start(arguments, false);
|
||||
emit this->checkResult(int(BackupResult::MKSQUASHFS_DO_SUCCESS));
|
||||
emit this->progress(0);
|
||||
} else {
|
||||
m_isFinished = true;
|
||||
emit this->workResult(false);
|
||||
}
|
||||
|
||||
qDebug() << "UDiskGhostImageProxy::finished invoke end";
|
||||
});
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_mksquashfs->start(args);
|
||||
emit checkResult(int(BackupResult::GHOST_START_SUCCESS));
|
||||
QTimer::singleShot(1*1000, this, &UDiskGhostImageProxy::checkDestDirExists);
|
||||
|
||||
qDebug() << "UDiskGhostImageProxy::doGhostImage invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验移动盘是否还在
|
||||
* @return: bool,存在返回true;不存在返回false
|
||||
* @author: zhaominyong
|
||||
* @since: 2021/05/24
|
||||
* @note:
|
||||
* add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据
|
||||
*/
|
||||
bool UDiskGhostImageProxy::checkDestDirExists()
|
||||
{
|
||||
if (!m_isFinished)
|
||||
{
|
||||
// 拔掉U盘后,没有响应的场景(怀疑可能是某应用程序关闭引起,希望不是dbus服务关掉了)
|
||||
if (m_isForce) {
|
||||
emit this->workResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupWrapper.m_prefixDestPath)) {
|
||||
qCritical() << QString("dstDir %s is not exist!").arg(m_backupWrapper.m_prefixDestPath);
|
||||
if (m_mksquashfs)
|
||||
m_mksquashfs->stop();
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
// 10s钟后如果还没有退出,则强制退出
|
||||
QTimer::singleShot(10*1000, this, &UDiskGhostImageProxy::checkDestDirExists);
|
||||
m_isForce = true;
|
||||
} else {
|
||||
QTimer::singleShot(1*1000, this, &UDiskGhostImageProxy::checkDestDirExists);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#ifndef UDISKGHOSTIMAGEPROXY_H
|
||||
#define UDISKGHOSTIMAGEPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/mksquashfsprocess.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class UDiskGhostImageProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(UDiskGhostImageProxy)
|
||||
public:
|
||||
explicit UDiskGhostImageProxy();
|
||||
virtual ~UDiskGhostImageProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
private:
|
||||
void doGhostImage();
|
||||
bool checkDestDirExists();
|
||||
void deleteFailedData();
|
||||
|
||||
// 存放.kyimg文件的目录
|
||||
QString m_destPath;
|
||||
// .kyimg文件
|
||||
QString m_kyimg;
|
||||
|
||||
// 压缩进程
|
||||
MkSquashFSProcess *m_mksquashfs;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
|
||||
// 是否成功
|
||||
bool m_bSuccess;
|
||||
// 是否结束
|
||||
bool m_isFinished;
|
||||
// 强制结束标志(stop后没反应的情况,系统处于睡眠状态)
|
||||
bool m_isForce;
|
||||
};
|
||||
|
||||
|
||||
#endif // UDISKGHOSTIMAGEPROXY_H
|
|
@ -0,0 +1,619 @@
|
|||
#include "udisksystembackupproxy.h"
|
||||
|
||||
#include <QStorageInfo>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <kysec/status.h>
|
||||
#include "../common/utils.h"
|
||||
#include "../common/mydusizetool.h"
|
||||
#include "mymountproxy.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(UDiskSystemBackupProxy)
|
||||
|
||||
UDiskSystemBackupProxy::UDiskSystemBackupProxy()
|
||||
{
|
||||
m_bSuccess = false;
|
||||
m_isFinished = false;
|
||||
m_p = nullptr;
|
||||
m_size = 0;
|
||||
m_calc = new CalcBackupSize(this);
|
||||
m_isOnlyCheck = true;
|
||||
m_mksquashfs = nullptr;
|
||||
m_isForce = false;
|
||||
|
||||
connect(this, &UDiskSystemBackupProxy::cancel, this, &UDiskSystemBackupProxy::cancelEx);
|
||||
}
|
||||
|
||||
UDiskSystemBackupProxy::~UDiskSystemBackupProxy()
|
||||
{
|
||||
delete m_p;
|
||||
m_p = nullptr;
|
||||
|
||||
delete m_calc;
|
||||
m_calc = nullptr;
|
||||
|
||||
delete m_mksquashfs;
|
||||
m_mksquashfs = nullptr;
|
||||
|
||||
QString rm("rm -rf ");
|
||||
rm += m_imgPath;
|
||||
QProcess::execute(rm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::checkEnv invoke begin";
|
||||
|
||||
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载
|
||||
// 后来支持无备份分区
|
||||
MyMountProxy mountProxy;
|
||||
MountResult result = mountProxy.mountBackupPartition();
|
||||
// 无备份分区
|
||||
if (MountResult::CANNOT_GET_BACKUPUUID == result) {
|
||||
qInfo() << "There is no backup partition!";
|
||||
|
||||
QString snapshotsPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH;
|
||||
snapshotsPath.replace("//", "/");
|
||||
Utils::mkpath(snapshotsPath);
|
||||
Utils::generateExcludePathsFile();
|
||||
} else if (MountResult::MOUNTED != result) {
|
||||
emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo udisk(backupPath);
|
||||
QString udisk_type = udisk.fileSystemType();
|
||||
qDebug() << "udisk's filesystemtype is " << udisk_type;
|
||||
if (udisk_type == "vfat") {
|
||||
qCritical() << m_backupWrapper.m_prefixDestPath + " udisk's filesystemtype is vfat";
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT));
|
||||
return false;
|
||||
}
|
||||
if (udisk.isReadOnly()) {
|
||||
// 只读挂载的U盘
|
||||
qCritical() << QString("udisk(%s) is readonly filesystem").arg(m_backupWrapper.m_prefixDestPath);
|
||||
emit checkResult(int(BackupResult::UDISK_FILESYSTEM_IS_READONLY));
|
||||
return false;
|
||||
}
|
||||
|
||||
QTimer::singleShot(1*1000, this, &UDiskSystemBackupProxy::checkDestDirExists);
|
||||
// 2、计算备份大小
|
||||
calcSizeForBackup();
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::checkEnv invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行备份逻辑
|
||||
*/
|
||||
void UDiskSystemBackupProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::doWorkEx invoke begin";
|
||||
|
||||
m_isOnlyCheck = false;
|
||||
// 环境检测
|
||||
checkEnvEx();
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
void UDiskSystemBackupProxy::cancelEx()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::cancelEx invoke begin";
|
||||
|
||||
m_bCancel = true;
|
||||
if (!m_isFinished) {
|
||||
emit this->checkResult(int(BackupResult::START_CANCEL));
|
||||
|
||||
if (m_calc)
|
||||
m_calc->stop();
|
||||
if (m_mksquashfs)
|
||||
m_mksquashfs->stop();
|
||||
if (m_p)
|
||||
m_p->stop();
|
||||
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
deleteFailedData();
|
||||
emit this->checkResult(int(BackupResult::CANCEL_SUCCESS));
|
||||
}
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::cancelEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 失败则删除相应数据
|
||||
*/
|
||||
void UDiskSystemBackupProxy::deleteFailedData()
|
||||
{
|
||||
if (m_curUuid.isEmpty())
|
||||
return;
|
||||
|
||||
// 1、删除备份目录
|
||||
QString destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid;
|
||||
destPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-rf";
|
||||
args << destPath;
|
||||
QProcess::execute("rm", args);
|
||||
|
||||
// 2、删除xml文件中的备份项
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
parse.deleteItem(m_curUuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否增量备份
|
||||
* @return true,增量备份; false,全量备份
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::isIncBackup()
|
||||
{
|
||||
QString backupPath;
|
||||
ParseBackupList::BackupPoint point;
|
||||
if (m_backupWrapper.m_uuid.isEmpty()) {
|
||||
QString xmlPath(m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH);
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parser(xmlPath);
|
||||
point = parser.getLastSysBackupPoint();
|
||||
if (point.m_uuid.isEmpty())
|
||||
return false;
|
||||
backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + point.m_uuid + "/data";
|
||||
} else {
|
||||
backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
}
|
||||
|
||||
backupPath.replace("//", "/");
|
||||
if (Utils::isDirExist(backupPath)) {
|
||||
m_backupWrapper.m_baseUuid = point.m_uuid;
|
||||
m_backupWrapper.m_bIncrement = true;
|
||||
m_backupWrapper.m_type = BackupType::INC_BACKUP_SYSTEM;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验剩余空间是否满足备份
|
||||
*/
|
||||
void UDiskSystemBackupProxy::checkFreeCapacity(qint64 itotalSize)
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::checkFreeCapacity invoke begin";
|
||||
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
// 拔掉U盘的场景
|
||||
if (m_isForce) {
|
||||
emit this->checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return ;
|
||||
}
|
||||
|
||||
// 1、计算待备份数据的大小
|
||||
m_size = itotalSize;
|
||||
// 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留500M的空间
|
||||
itotalSize += 500 * MB;
|
||||
|
||||
// 2、计算备份分区剩余空间大小
|
||||
QString backupPath(m_backupWrapper.m_prefixDestPath);
|
||||
backupPath.replace("//", "/");
|
||||
QStorageInfo backupDisk(backupPath);
|
||||
qint64 freeSize = backupDisk.bytesAvailable();
|
||||
|
||||
// 3、校验空间是否足够
|
||||
if (itotalSize > freeSize) {
|
||||
emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH));
|
||||
return ;
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
}
|
||||
|
||||
if (m_isOnlyCheck)
|
||||
return ;
|
||||
|
||||
// 4、判断是否需要先压缩成img文件,压缩后一般小于原大小的70%
|
||||
itotalSize = itotalSize * 7 / 10;
|
||||
QHash<QString, QString> hash = Utils::getLeftSizeOfPartitions();
|
||||
for (QHash<QString, QString>::const_iterator it = hash.constBegin(); it != hash.constEnd(); ++it) {
|
||||
QString path = it.key();
|
||||
QString size = it.value();
|
||||
if (size.endsWith("G")) {
|
||||
size.replace("G", "");
|
||||
qint64 leftSize = size.toLongLong() * 1000 * 1000 * 1000;
|
||||
if (itotalSize < leftSize) {
|
||||
m_imgPath = path + IMGBACKUP_PATH;
|
||||
m_imgPath.replace("//", "/");
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5、开始制作img或开始备份
|
||||
if (m_imgPath.isEmpty()) {
|
||||
doBackup();
|
||||
} else {
|
||||
doMksqushfs();
|
||||
}
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::checkFreeCapacity invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算备份所需空间大小
|
||||
* @return 计算备份所需空间大小,单位字节
|
||||
*/
|
||||
void UDiskSystemBackupProxy::calcSizeForBackup()
|
||||
{
|
||||
// 拼接备份源路径和目标路径,测试所需备份空间大小;目标路径为一虚拟路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
destPath += CHECK_PATH;
|
||||
destPath.replace("//", "/");
|
||||
Utils::mkpath(destPath);
|
||||
|
||||
QStringList args = getRsyncArgs(UDiskSystemBackupScene::TRY_SYSTEM_BACKUP);
|
||||
args << srcPath;
|
||||
args << destPath;
|
||||
|
||||
connect(m_calc, &CalcBackupSize::finished, this, &UDiskSystemBackupProxy::checkFreeCapacity);
|
||||
m_calc->start(args, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return rsync的参数信息
|
||||
*/
|
||||
QStringList UDiskSystemBackupProxy::getRsyncArgs(UDiskSystemBackupScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
QStringList excludes;
|
||||
|
||||
switch (scene) {
|
||||
case UDiskSystemBackupScene::SYSTEM_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
break ;
|
||||
case UDiskSystemBackupScene::TRY_SYSTEM_BACKUP :
|
||||
args << "-aAHXrn";
|
||||
args << "--stats";
|
||||
args << "--ignore-missing-args";
|
||||
break ;
|
||||
case UDiskSystemBackupScene::MKSQUASHFS :
|
||||
Utils::excludeFstabBindPath(excludes);
|
||||
// --exclude=排除路径设置
|
||||
for (QString item : m_backupWrapper.m_backupExcludePaths) {
|
||||
if (excludes.contains(item))
|
||||
continue;
|
||||
if (item.endsWith("/*")) {
|
||||
item.replace("/*", "");
|
||||
}
|
||||
|
||||
args << "-e" << item;
|
||||
}
|
||||
args << "-e" << m_imgPath;
|
||||
return args;
|
||||
case UDiskSystemBackupScene::IMG_BACKUP :
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
return args;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
// --exclude=排除路径设置
|
||||
for (const QString & item : m_backupWrapper.m_backupExcludePaths) {
|
||||
args << QString("--exclude=%1").arg(item);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief mksqushfs
|
||||
*/
|
||||
void UDiskSystemBackupProxy::doMksqushfs()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::doMksqushfs invoke begin";
|
||||
|
||||
m_mksquashfs = new MkSquashFSProcess(this);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::progress, this, &UDiskSystemBackupProxy::progress);
|
||||
connect(m_mksquashfs, &MkSquashFSProcess::finished, this, [=](bool result) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
if (result && !m_isForce) {
|
||||
// 开始备份
|
||||
doBackup();
|
||||
} else {
|
||||
m_isFinished = true;
|
||||
emit checkResult(int(BackupResult::MKSQUASHFS_DO_FAIL));
|
||||
}
|
||||
});
|
||||
Utils::mkpath(m_imgPath);
|
||||
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
QString dstImg = m_imgPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
|
||||
QStringList args;
|
||||
args << srcPath << dstImg;
|
||||
args.append(getRsyncArgs(UDiskSystemBackupScene::MKSQUASHFS));
|
||||
|
||||
if (m_mksquashfs->start(args)) {
|
||||
emit checkResult(int(BackupResult::MKSQUASHFS_START_SUCCESS));
|
||||
} else {
|
||||
emit checkResult(int(BackupResult::MKSQUASHFS_DO_FAIL));
|
||||
}
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::doMksqushfs invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份
|
||||
*/
|
||||
void UDiskSystemBackupProxy::doBackup()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::doBackup invoke begin";
|
||||
|
||||
// 准备
|
||||
if (!doPrepare())
|
||||
return ;
|
||||
|
||||
// 启动备份efi, 修改为和其它目录统一备份,不再单独进行备份
|
||||
// if (!backupEfi()) {
|
||||
// emit checkResult(int(BackupResult::EFI_RSYNC_FAIL));
|
||||
// return ;
|
||||
// }
|
||||
|
||||
if (m_imgPath.isEmpty()) {
|
||||
// 启动系统备份
|
||||
backupSystem();
|
||||
} else {
|
||||
// 备份img文件
|
||||
backupImg();
|
||||
}
|
||||
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::doBackup invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份准备
|
||||
* @return true,准备成功;false,准备失败
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::doPrepare()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::doPrepare invoke begin";
|
||||
|
||||
m_bSuccess = false;
|
||||
|
||||
// 1、设置当前备份的Uuid
|
||||
m_curUuid += Utils::createUuid();
|
||||
|
||||
// 2、准备备份目录及文件
|
||||
m_destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data";
|
||||
m_destPath.replace("//", "/");
|
||||
if (!Utils::mkpath(m_destPath)) {
|
||||
qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ;
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE;
|
||||
userFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(userFile, m_backupWrapper.m_backupPaths)) {
|
||||
qCritical() << QString("create file %1 failed !").arg(userFile);
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
excludeUserFile.replace("//", "/");
|
||||
if (!Utils::writeFileByLines(excludeUserFile, m_backupWrapper.m_backupExcludePaths)) {
|
||||
qCritical() << QString("create file %1 failed !").arg(excludeUserFile);
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、记录/backup/snapshots/backuplist.xml文件
|
||||
if (!recordBackupPoint()) {
|
||||
qCritical() << "add or update item to backuplist.xml failed !";
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::doPrepare invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::recordBackupPoint()
|
||||
{
|
||||
m_backupPoint.m_backupName = m_backupWrapper.m_backupName;
|
||||
m_backupPoint.m_uuid = m_curUuid;
|
||||
m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition;
|
||||
m_backupPoint.m_type = m_backupWrapper.m_type;
|
||||
m_backupPoint.m_size = Utils::StringBySize(m_size);
|
||||
m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING;
|
||||
m_backupPoint.m_os = SystemInfo::m_os;
|
||||
m_backupPoint.m_arch = SystemInfo::m_arch;
|
||||
m_backupPoint.m_archdetect = SystemInfo::m_archDetect;
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (m_backupWrapper.m_uuid.isEmpty() || !m_backupWrapper.m_bIncrement) {
|
||||
if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) {
|
||||
emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份系统
|
||||
* @return true,启动备份成功;false,启动备份失败
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::backupSystem()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::backupSystem invoke begin";
|
||||
|
||||
// 全量备份场景
|
||||
QStringList args = getRsyncArgs(UDiskSystemBackupScene::SYSTEM_BACKUP);
|
||||
|
||||
// 拼接备份源路径和目标路径
|
||||
QString srcPath = Utils::getSysRootPath();
|
||||
srcPath += "/";
|
||||
srcPath.replace("//", "/");
|
||||
args << srcPath;
|
||||
QString destPath = m_destPath + "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
return backup(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份系统img文件
|
||||
* @return true,启动备份成功;false,启动备份失败
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::backupImg()
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::backupImg invoke";
|
||||
|
||||
QStringList args;
|
||||
QString srcPath = m_imgPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
|
||||
QString destPath = m_destPath + "/";
|
||||
destPath.replace("//", "/");
|
||||
args << srcPath << destPath;
|
||||
|
||||
return backup(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 备份公共逻辑
|
||||
* @param args
|
||||
* @return true,启动备份成功;false,启动备份失败
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::backup(const QStringList &args)
|
||||
{
|
||||
qDebug() << "UDiskSystemBackupProxy::backup invoke begin";
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskSystemBackupProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
// 如果是取消了操作,则不再发送其它信息
|
||||
if (m_bCancel)
|
||||
return ;
|
||||
|
||||
m_isForce = false;
|
||||
m_isFinished = true;
|
||||
if (result) {
|
||||
m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING;
|
||||
m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath));
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
if (ParseBackupList::ParseResult::SUCCESS != parse.updateItem(m_backupPoint)) {
|
||||
qCritical() << "update backuplist.xml error in sendBackupResult";
|
||||
result = false;
|
||||
} else {
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(m_backupPoint.m_time + ","
|
||||
+ m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","
|
||||
+ m_backupWrapper.m_note + "," + m_backupPoint.m_size
|
||||
+ ",," + m_backupWrapper.m_backupName);
|
||||
|
||||
Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName);
|
||||
m_bSuccess = true;
|
||||
}
|
||||
}
|
||||
emit this->workResult(result);
|
||||
});
|
||||
m_p->start(args, false);
|
||||
emit checkResult(int(BackupResult::BACKUP_START_SUCCESS));
|
||||
|
||||
do_kylin_security(m_destPath);
|
||||
|
||||
qDebug() << "UDiskSystemBackupProxy::backup invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
void UDiskSystemBackupProxy::do_kylin_security(const QString& dstDir)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = kysec_getstatus();
|
||||
if (ret > 0) {
|
||||
QString seFilePath(dstDir + "/.exectl");
|
||||
QFile file(seFilePath);
|
||||
file.open(QIODevice::WriteOnly);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 校验移动盘是否还在
|
||||
* @return: bool,存在返回true;不存在返回false
|
||||
* @author: zhaominyong
|
||||
* @since: 2021/05/24
|
||||
* @note:
|
||||
* add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据
|
||||
*/
|
||||
bool UDiskSystemBackupProxy::checkDestDirExists()
|
||||
{
|
||||
if (!m_isFinished)
|
||||
{
|
||||
// 拔掉U盘后,没有响应的场景(怀疑可能是某应用程序关闭引起,希望不是dbus服务关掉了)
|
||||
if (m_isForce) {
|
||||
emit this->workResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupWrapper.m_prefixDestPath)) {
|
||||
qCritical() << QString("dstDir %s is not exist!").arg(m_backupWrapper.m_prefixDestPath);
|
||||
m_isForce = true;
|
||||
if (m_calc != nullptr)
|
||||
m_calc->stop();
|
||||
if (m_mksquashfs != nullptr)
|
||||
m_mksquashfs->stop();
|
||||
if (m_p != nullptr)
|
||||
m_p->stop();
|
||||
// 10s钟后如果还没有退出,则强制退出
|
||||
QTimer::singleShot(10*1000, this, &UDiskSystemBackupProxy::checkDestDirExists);
|
||||
} else {
|
||||
QTimer::singleShot(1*1000, this, &UDiskSystemBackupProxy::checkDestDirExists);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
#ifndef UDISKSYSTEMBACKUPPROXY_H
|
||||
#define UDISKSYSTEMBACKUPPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/calcbackupsize.h"
|
||||
#include "myprocess/mksquashfsprocess.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class UDiskSystemBackupProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(UDiskSystemBackupProxy)
|
||||
|
||||
public:
|
||||
// 系统备份的几种场景
|
||||
enum UDiskSystemBackupScene {
|
||||
SYSTEM_BACKUP, // 系统备份
|
||||
TRY_SYSTEM_BACKUP, // 测试系统备份,可用于计算备份传输数据大小
|
||||
MKSQUASHFS, // 生成img文件
|
||||
IMG_BACKUP, // 备份img文件
|
||||
};
|
||||
|
||||
explicit UDiskSystemBackupProxy();
|
||||
virtual ~UDiskSystemBackupProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
// 校验剩余空间是否满足备份
|
||||
void checkFreeCapacity(qint64 itotalSize);
|
||||
|
||||
// mksqushfs
|
||||
void doMksqushfs();
|
||||
|
||||
// 备份
|
||||
void doBackup();
|
||||
|
||||
// 任务取消
|
||||
virtual void cancelEx();
|
||||
|
||||
/**
|
||||
* @brief 校验移动盘是否还在
|
||||
* @return: bool,存在返回true;不存在返回false
|
||||
* @author: zhaominyong
|
||||
* @since: 2021/05/24
|
||||
* @note:
|
||||
* add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据
|
||||
*/
|
||||
bool checkDestDirExists();
|
||||
|
||||
private:
|
||||
// 判断是否增量备份
|
||||
bool isIncBackup();
|
||||
|
||||
// 计算备份所需空间大小
|
||||
void calcSizeForBackup();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(UDiskSystemBackupScene scene);
|
||||
|
||||
/**
|
||||
* @brief 记录/backup/snapshots/backuplist.xml文件
|
||||
* @return true-成功;false-失败
|
||||
*/
|
||||
bool recordBackupPoint();
|
||||
|
||||
// 备份准备
|
||||
bool doPrepare();
|
||||
|
||||
// 备份系统
|
||||
bool backupSystem();
|
||||
|
||||
// 备份img文件
|
||||
bool backupImg();
|
||||
|
||||
bool backup(const QStringList &args);
|
||||
|
||||
void do_kylin_security(const QString& dstDir);
|
||||
|
||||
// 失败则删除相应数据
|
||||
void deleteFailedData();
|
||||
|
||||
// 计算备份空间大小的进程
|
||||
CalcBackupSize *m_calc;
|
||||
// 压缩进程
|
||||
MkSquashFSProcess *m_mksquashfs;
|
||||
|
||||
// 是否完成
|
||||
bool m_isFinished;
|
||||
// 是否备份成功
|
||||
bool m_bSuccess;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前备份目标目录
|
||||
QString m_destPath;
|
||||
// 当前备份所需空间大小
|
||||
qint64 m_size;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
// 是否只是检测
|
||||
bool m_isOnlyCheck;
|
||||
// img文件存放路径
|
||||
QString m_imgPath;
|
||||
// 强制结束标志(stop后没反应的情况,系统处于睡眠状态)
|
||||
bool m_isForce;
|
||||
};
|
||||
|
||||
#endif // UDISKSYSTEMBACKUPPROXY_H
|
|
@ -0,0 +1,533 @@
|
|||
#include "udisksystemrestoreproxy.h"
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "../common/utils.h"
|
||||
#include "mymountproxy.h"
|
||||
#include "myprocess/mksquashfsprocess.h"
|
||||
|
||||
IMPLEMENT_DYNCREATE(UDiskSystemRestoreProxy)
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
UDiskSystemRestoreProxy::UDiskSystemRestoreProxy()
|
||||
{
|
||||
m_isFinished = false;
|
||||
m_p = nullptr;
|
||||
m_isForce = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
UDiskSystemRestoreProxy::~UDiskSystemRestoreProxy()
|
||||
{
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 环境检测
|
||||
* @return false,检测失败;true,检测成功
|
||||
*/
|
||||
bool UDiskSystemRestoreProxy::checkEnvEx()
|
||||
{
|
||||
qDebug() << "UDiskSystemRestoreProxy::checkEnvEx invoke begin";
|
||||
|
||||
// 1、检测.user.txt是否存在
|
||||
m_userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + PATHS_USER_FILE;
|
||||
m_userFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_userFile)) {
|
||||
qCritical(".user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2、检测.exclude.user.txt是否存在
|
||||
m_excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + EXCLUDE_PATHS_USER_FILE;
|
||||
m_excludeUserFile.replace("//", "/");
|
||||
if (!Utils::filsExists(m_excludeUserFile)) {
|
||||
qCritical(".exclude.user.txt文件不存在");
|
||||
emit checkResult(int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3、检测还原点是否存在
|
||||
m_backupPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data";
|
||||
m_backupPath.replace("//", "/");
|
||||
if (Utils::isDirEmpty(m_backupPath)) {
|
||||
qCritical("还原点{uuid}/data目录不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4、检测xml中的还原点是否还存在
|
||||
QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
|
||||
xmlPath.replace("//", "/");
|
||||
ParseBackupList parse(xmlPath);
|
||||
m_backupPoint = parse.findBackupPointByUuid(m_backupWrapper.m_uuid);
|
||||
if (m_backupPoint.m_uuid.isEmpty()) {
|
||||
qCritical("xml中还原点不存在");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_curUuid = m_backupWrapper.m_uuid;
|
||||
|
||||
emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS));
|
||||
|
||||
qDebug() << "UDiskSystemRestoreProxy::checkEnvEx invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行还原逻辑
|
||||
*/
|
||||
void UDiskSystemRestoreProxy::doWorkEx()
|
||||
{
|
||||
qDebug() << "UDiskSystemRestoreProxy::doWorkEx invoke begin";
|
||||
|
||||
// 1、校验
|
||||
if (!checkEnvEx())
|
||||
return ;
|
||||
|
||||
// 2、还原efi(兼容旧版本的备份)
|
||||
if (!restoreEfi()) {
|
||||
qCritical("/boot/efi目录同步失败");
|
||||
emit checkResult(int(BackupResult::EFI_RSYNC_FAIL));
|
||||
return ;
|
||||
}
|
||||
|
||||
// 3、还原系统
|
||||
if (doPrepare())
|
||||
restoreSystem();
|
||||
|
||||
qDebug() << "UDiskSystemRestoreProxy::doWorkEx invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 还原efi(兼容旧版本的备份)
|
||||
* @return
|
||||
*/
|
||||
bool UDiskSystemRestoreProxy::restoreEfi()
|
||||
{
|
||||
qDebug() << "UDiskSystemRestoreProxy::restoreEfi invoke begin";
|
||||
|
||||
// 是否有/boot/efi目录
|
||||
QString efiPath = Utils::getSysRootPath() + "/boot/efi";
|
||||
efiPath.replace("//", "/");
|
||||
if (!Utils::isDirEmpty(efiPath)) {
|
||||
// 1、修复源数据
|
||||
repairEfi();
|
||||
|
||||
// 2、重新rw读写挂载
|
||||
remountEfi();
|
||||
|
||||
// 3、同步efi
|
||||
return rsyncEfi();
|
||||
}
|
||||
|
||||
qDebug() << "UDiskSystemRestoreProxy::restoreEfi invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 修复efi目录
|
||||
*/
|
||||
void UDiskSystemRestoreProxy::repairEfi()
|
||||
{
|
||||
QString qsEfiPath = m_backupPath + "/efi";
|
||||
if (!Utils::isDirEmpty(qsEfiPath)) {
|
||||
// 存在/efi说明是老备份数据,尽量修正老数据
|
||||
QStringList args;
|
||||
args << "-f";
|
||||
args << qsEfiPath;
|
||||
QString newPath = m_backupPath + "/boot";
|
||||
args << newPath;
|
||||
QProcess::execute("mv", args);
|
||||
QProcess::execute("sync");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新rw读写挂载efi分区
|
||||
*/
|
||||
void UDiskSystemRestoreProxy::remountEfi()
|
||||
{
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot/efi";
|
||||
mountPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-o"
|
||||
<< "rw,remount"
|
||||
<< mountPath;
|
||||
QProcess::execute("mount", args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新rw读写挂载boot分区
|
||||
*/
|
||||
void UDiskSystemRestoreProxy::remountBoot()
|
||||
{
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot";
|
||||
mountPath.replace("//", "/");
|
||||
QStringList args;
|
||||
args << "-o"
|
||||
<< "rw,remount"
|
||||
<< mountPath;
|
||||
QProcess::execute("mount", args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 同步efi
|
||||
*/
|
||||
bool UDiskSystemRestoreProxy::rsyncEfi()
|
||||
{
|
||||
QString efiPath = m_backupPath + "/boot/efi/";
|
||||
if (Utils::isDirEmpty(efiPath))
|
||||
efiPath = efiPath = m_backupPath + "/efi/";
|
||||
if (Utils::isDirEmpty(efiPath))
|
||||
return true;
|
||||
|
||||
QStringList args = getRsyncArgs(SystemRestoreScene::EFI_RESTORE);
|
||||
QString mountPath = Utils::getSysRootPath() + "/boot/efi/";
|
||||
mountPath.replace("//", "/");
|
||||
|
||||
args << efiPath << mountPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
bool result = m_p->start(args);
|
||||
delete m_p;
|
||||
m_p = nullptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList UDiskSystemRestoreProxy::getRsyncArgs(SystemRestoreScene scene)
|
||||
{
|
||||
QStringList args;
|
||||
args << "-avAHXr";
|
||||
args << "--info=progress2";
|
||||
args << "--no-inc-recursive";
|
||||
args << "--ignore-missing-args";
|
||||
args << "--delete";
|
||||
|
||||
QDir dataDir(m_srcPath + "/data");
|
||||
QFile file(m_srcPath + "/etc/uid_list");
|
||||
QDir efiDir(m_srcPath + "/boot/efi");
|
||||
QStringList excludes;
|
||||
|
||||
switch (scene) {
|
||||
case SystemRestoreScene::RESTORE_SYSTEM_WITH_DATA :
|
||||
args << "--exclude=/home";
|
||||
args << "--exclude=/root";
|
||||
if (Utils::isHuawei990()) {
|
||||
args << "--exclude=/data";
|
||||
} else {
|
||||
args << "--exclude=/data/usershare";
|
||||
}
|
||||
// 保留指纹数据,用户密码、角色、权限、生物识别等信息不需要改变
|
||||
args << "--exclude=/var/lib/biometric-auth";
|
||||
args << "--exclude=/data/sec_storage_data";
|
||||
args << "--exclude=/etc/passwd";
|
||||
args << "--exclude=/etc/shadow";
|
||||
args << "--exclude=/etc/group";
|
||||
args << "--exclude=/etc/gshadow";
|
||||
args << "--exclude=/etc/sudoers";
|
||||
args << "--exclude=/data/home";
|
||||
args << "--exclude=/data/root";
|
||||
|
||||
// 云桌面背景路径属于用户数据
|
||||
args << "--exclude=/var/lib/AccountsService";
|
||||
|
||||
// 域用户相关信息,还原后保持不退域
|
||||
args << "--exclude=/etc/sssd";
|
||||
args << "--exclude=/var/lib/sss";
|
||||
args << "--exclude=/usr/share/sssd";
|
||||
args << "--exclude=/etc/ipa";
|
||||
args << "--exclude=/etc/krb5.keytab";
|
||||
args << "--exclude=/etc/krb5.conf";
|
||||
args << "--exclude=/var/lib/ipa-client";
|
||||
args << "--exclude=/etc/nsswitch.conf";
|
||||
args << "--exclude=/etc/pam.d";
|
||||
args << "--exclude=/etc/hosts";
|
||||
args << "--exclude=/etc/hostname";
|
||||
args << "--exclude=/etc/hedron";
|
||||
args << "--exclude=/etc/kcm";
|
||||
args << "--exclude=/usr/hedron/hedronagent";
|
||||
args << "--exclude=/etc/.kyinfo";
|
||||
args << "--exclude=/etc/LICENSE";
|
||||
args << "--exclude=/etc/ssl/certs";
|
||||
args << "--exclude=/usr/share/ca-certificates";
|
||||
args << "--exclude=/etc/NetworkManager";
|
||||
|
||||
// 此处不要break,因为还需要排除SYSTEM_RESTORE中的项
|
||||
|
||||
case SystemRestoreScene::SYSTEM_RESTORE :
|
||||
// 还原工具不还原自身
|
||||
args << "--exclude=/usr/bin/backup-daemon";
|
||||
args << "--exclude=/usr/bin/kybackup";
|
||||
args << "--exclude=/usr/bin/mount_fstab_efi";
|
||||
args << "--exclude=/usr/bin/backup-auto-efi";
|
||||
args << "--exclude=/usr/bin/backup-auto";
|
||||
args << "--exclude=/usr/bin/rsync";
|
||||
args << "--exclude=/usr/share/rsync";
|
||||
args << "--exclude=/usr/share/initramfs-tools/hooks/kybackup-hooks";
|
||||
args << "--exclude=/usr/share/initramfs-tools/scripts/local-bottom/kybackup";
|
||||
|
||||
// 以前的出厂备份和grub备份没有备份/data,还原时需要判断/data是否存在,如不存在需要屏蔽掉,不然会将主机上的/data删除,造成问题
|
||||
// 此为兼容以前备份的老数据而改,等以后老的备份估计不存在了可已去掉
|
||||
if (!dataDir.exists()) {
|
||||
args << "--exclude=/data";
|
||||
}
|
||||
|
||||
if (!file.exists()) {
|
||||
args << "--exclude=/etc/uid_list";
|
||||
}
|
||||
|
||||
// 为兼容以前的老备份数据,增加下面几行
|
||||
if (efiDir.isEmpty()) {
|
||||
args << QString("--exclude=/boot/efi");
|
||||
}
|
||||
// 系统安装后有的会将/data/home /data/root挂载到的/home /root上,实际文件是存放在/data/home /data/root下面
|
||||
Utils::excludeFstabBindPath(excludes);
|
||||
// 自定义备份的路径也需要跳过,不进行还原
|
||||
Utils::excludeCustomizePath(excludes);
|
||||
for (const QString& item : excludes) {
|
||||
QDir itemDir(m_srcPath + item);
|
||||
// 以后统一用/home /root这种路径, 兼容老备份数据(原来的U盘备份,在mksquashfs时排除bind挂载的任意一方时,都备份不上)
|
||||
if (item == "/data/home") {
|
||||
QDir homeDir(m_srcPath + "/home");
|
||||
if (!homeDir.isEmpty()) {
|
||||
args << QString("--exclude=/data/home");
|
||||
} else if (!itemDir.isEmpty()) {
|
||||
args << QString("--exclude=/home");
|
||||
} else {
|
||||
args << QString("--exclude=/data/home");
|
||||
args << QString("--exclude=/home");
|
||||
}
|
||||
continue;
|
||||
} else if (item == "/data/root") {
|
||||
QDir homeDir(m_srcPath + "/root");
|
||||
if (!homeDir.isEmpty()) {
|
||||
args << QString("--exclude=/data/root");
|
||||
} else if (!itemDir.isEmpty()) {
|
||||
args << QString("--exclude=/root");
|
||||
} else {
|
||||
args << QString("--exclude=/data/root");
|
||||
args << QString("--exclude=/root");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
args << QString("--exclude=") + item;
|
||||
}
|
||||
|
||||
// 异机还原
|
||||
if (m_backupWrapper.m_isOtherMachine) {
|
||||
args << "--exclude=/etc/.bootinfo";
|
||||
args << "--exclude=/etc/fstab";
|
||||
}
|
||||
|
||||
args << "--exclude-from" << m_excludeUserFile;
|
||||
args << "--files-from" << m_userFile;
|
||||
|
||||
break ;
|
||||
case SystemRestoreScene::EFI_RESTORE :
|
||||
break ;
|
||||
default:
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 还原前准备
|
||||
* @return
|
||||
*/
|
||||
bool UDiskSystemRestoreProxy::doPrepare()
|
||||
{
|
||||
qDebug() << "UDiskSystemRestoreProxy::doPrepare invoke begin";
|
||||
|
||||
// 移动设备系统备份如果有img,则需要先将img挂载到/backup/imgbackup目录
|
||||
QString imgPath = m_backupPath + "/" + UDISK_MKSQUASHFS_IMG_NAME;
|
||||
if (Utils::filsExists(imgPath)) {
|
||||
// 1、检测目录/backup/imgbackup是否存在,不存在则创建此目录
|
||||
QString dstImgMountPath = Utils::getSysRootPath() + BACKUP_IMGBACKUP_PATH;
|
||||
dstImgMountPath.replace("//", "/");
|
||||
Utils::mkpath(dstImgMountPath);
|
||||
|
||||
// 2、先卸载/backup/imgbackup上的mount
|
||||
MountBackupProcess *processMount = new MountBackupProcess(this);
|
||||
processMount->umount(dstImgMountPath);
|
||||
|
||||
// 3、将img文件挂载到/backup/imgbackup上
|
||||
if (!processMount->mount(imgPath, dstImgMountPath)) {
|
||||
emit checkResult(int(BackupResult::RESTOREDIR_PREPARE_FAILED));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_srcPath = dstImgMountPath;
|
||||
} else
|
||||
m_srcPath = m_backupPath;
|
||||
|
||||
// 以读写方式重新挂载boot分区,因为有的机器默认以只读挂载
|
||||
remountBoot();
|
||||
|
||||
qDebug() << "UDiskSystemRestoreProxy::doPrepare invoke end";
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 系统还原
|
||||
*/
|
||||
void UDiskSystemRestoreProxy::restoreSystem()
|
||||
{
|
||||
qDebug() << "UDiskSystemRestoreProxy::restoreSystem invoke begin";
|
||||
|
||||
// 理论上开始不会走下面这个U盘拔出的校验
|
||||
if (m_isForce) {
|
||||
qCritical("U盘已拔出");
|
||||
emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR));
|
||||
return ;
|
||||
}
|
||||
|
||||
// 停止安全防护
|
||||
QProcess::execute("systemctl stop kysec-init.service");
|
||||
|
||||
QString destPath = Utils::getSysRootPath();
|
||||
|
||||
QStringList args;
|
||||
// 自动更新的备份还原时保留用户数据
|
||||
if (m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM_WITH_DATA) {
|
||||
args = getRsyncArgs(SystemRestoreScene::RESTORE_SYSTEM_WITH_DATA);
|
||||
} else {
|
||||
args = getRsyncArgs(SystemRestoreScene::SYSTEM_RESTORE);
|
||||
}
|
||||
|
||||
args << m_srcPath + "/";
|
||||
destPath += "/";
|
||||
destPath.replace("//", "/");
|
||||
args << destPath;
|
||||
|
||||
m_p = new RsyncPathToDirProcess(this);
|
||||
connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskSystemRestoreProxy::progress);
|
||||
connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) {
|
||||
m_isForce = false;
|
||||
if (result) {
|
||||
QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss");
|
||||
// Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid));
|
||||
Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,,," + m_backupPoint.m_backupName);
|
||||
|
||||
Utils::updateSyncFile();
|
||||
Utils::wait(2);
|
||||
QString fileIfSync = Utils::getSysRootPath() + FILE_IF_SYNC;
|
||||
fileIfSync.replace("//", "/");
|
||||
QFileInfo file(fileIfSync);
|
||||
QDateTime beginTime = file.fileTime(QFileDevice::FileModificationTime);
|
||||
// sync();
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(20);
|
||||
Utils::updateSyncFile();
|
||||
while (1) {
|
||||
Utils::wait(2);
|
||||
QFileInfo file1(fileIfSync);
|
||||
QDateTime UpdateTime = file1.fileTime(QFileDevice::FileModificationTime);
|
||||
if (UpdateTime > beginTime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_backupWrapper.m_isOtherMachine) {
|
||||
Utils::wait(10);
|
||||
updateGrubUUid();
|
||||
sync();
|
||||
QProcess::execute("sync");
|
||||
Utils::wait(5);
|
||||
}
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupPath))
|
||||
result = false;
|
||||
emit this->workResult(result);
|
||||
m_isFinished = true;
|
||||
|
||||
if (result) {
|
||||
Utils::wait(2);
|
||||
reboot(RB_AUTOBOOT);
|
||||
}
|
||||
});
|
||||
|
||||
QTimer::singleShot(1*1000, this, &UDiskSystemRestoreProxy::checkUdiskExists);
|
||||
m_isFinished = false;
|
||||
m_p->start(args, false);
|
||||
|
||||
qDebug() << "UDiskSystemRestoreProxy::restoreSystem invoke end";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 异机还原时更新grub.cfg中的分区UUID
|
||||
*/
|
||||
void UDiskSystemRestoreProxy::updateGrubUUid()
|
||||
{
|
||||
QString srcFstab = Utils::getSysRootPath() + BACKUP_IMGBACKUP_PATH;
|
||||
srcFstab += FSTAB_PATH;
|
||||
srcFstab.replace("//", "/");
|
||||
QHash<QString, QString> srcPartToUuid = Utils::getPartUuidMap(srcFstab);
|
||||
QString destFstab = Utils::getSysRootPath() + FSTAB_PATH;
|
||||
destFstab.replace("//", "/");
|
||||
QHash<QString, QString> destPartToUuid = Utils::getPartUuidMap(destFstab);
|
||||
|
||||
QString findGrub = Utils::executeCmd("find /boot -name grub.cfg");
|
||||
QStringList grubs = findGrub.split("\n");
|
||||
for (const QString &grub : grubs) {
|
||||
if (grub.isEmpty())
|
||||
continue;
|
||||
QString root = QString("sed -i 's/%1/%2/g' %3").arg(srcPartToUuid.value("/")).arg(destPartToUuid.value("/")).arg(grub);
|
||||
qDebug() << Utils::executeCmd(root);
|
||||
|
||||
QString boot = QString("sed -i 's/%1/%2/g' %3").arg(srcPartToUuid.value("/boot")).arg(destPartToUuid.value("/boot")).arg(grub);
|
||||
qDebug() << Utils::executeCmd(boot);
|
||||
|
||||
QString swap = QString("sed -i 's/%1/%2/g' %3").arg(srcPartToUuid.value("swap")).arg(destPartToUuid.value("swap")).arg(grub);
|
||||
qDebug() << Utils::executeCmd(swap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 监控移动设备是否还在
|
||||
* @return true-在;false-不在
|
||||
*/
|
||||
bool UDiskSystemRestoreProxy::checkUdiskExists()
|
||||
{
|
||||
if (!m_isFinished) {
|
||||
// 拔掉U盘后,没有响应的场景(怀疑可能是某应用程序关闭引起,希望不是dbus服务关掉了)
|
||||
if (m_isForce) {
|
||||
qCritical() << QString("强制退出");
|
||||
emit this->workResult(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Utils::isDirEmpty(m_backupPath)) {
|
||||
qCritical() << QString("srcDir %s is not exist!").arg(m_backupPath);
|
||||
m_isForce = true;
|
||||
if (m_p != nullptr)
|
||||
m_p->stop();
|
||||
// 10s钟后如果还没有退出,则强制退出
|
||||
QTimer::singleShot(10*1000, this, &UDiskSystemRestoreProxy::checkUdiskExists);
|
||||
} else {
|
||||
QTimer::singleShot(1*1000, this, &UDiskSystemRestoreProxy::checkUdiskExists);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#ifndef UDISKSYSTEMRESTOREPROXY_H
|
||||
#define UDISKSYSTEMRESTOREPROXY_H
|
||||
|
||||
#include "workerfactory.h"
|
||||
#include "myprocess/rsyncpathtodirprocess.h"
|
||||
#include "parsebackuplist.h"
|
||||
|
||||
class UDiskSystemRestoreProxy : public Worker
|
||||
{
|
||||
Q_OBJECT
|
||||
DECLARE_DYNCREATE(UDiskSystemRestoreProxy)
|
||||
public:
|
||||
// 系统还原的几种场景
|
||||
enum SystemRestoreScene {
|
||||
RESTORE_SYSTEM_WITH_DATA, // 保留用户数据还原
|
||||
SYSTEM_RESTORE, // 系统还原
|
||||
EFI_RESTORE, // efi还原
|
||||
};
|
||||
|
||||
explicit UDiskSystemRestoreProxy();
|
||||
virtual ~UDiskSystemRestoreProxy();
|
||||
|
||||
public:
|
||||
// 环境检测
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理
|
||||
virtual void doWorkEx();
|
||||
|
||||
private slots:
|
||||
bool checkUdiskExists();
|
||||
|
||||
private:
|
||||
// 还原efi
|
||||
bool restoreEfi();
|
||||
// 修复efi目录
|
||||
void repairEfi();
|
||||
// 以读写方式重新挂载efi分区
|
||||
void remountEfi();
|
||||
// 以读写方式重新挂载boot分区
|
||||
void remountBoot();
|
||||
// 同步efi
|
||||
bool rsyncEfi();
|
||||
// 系统还原
|
||||
void restoreSystem();
|
||||
// 还原前准备
|
||||
bool doPrepare();
|
||||
// 异机还原时更新grub.cfg中的分区UUID
|
||||
void updateGrubUUid();
|
||||
|
||||
/**
|
||||
* @brief 根据场景获取rsync命令参数
|
||||
* @param scene,场景
|
||||
* @return 组装好的rsync的参数信息
|
||||
*/
|
||||
QStringList getRsyncArgs(SystemRestoreScene scene);
|
||||
|
||||
// .user.txt文件路径
|
||||
QString m_userFile;
|
||||
// .exclude.user.txt文件路径
|
||||
QString m_excludeUserFile;
|
||||
// 备份数据所在的data目录
|
||||
QString m_backupPath;
|
||||
|
||||
// 是否还原结束
|
||||
bool m_isFinished;
|
||||
// 当前备份uuid
|
||||
QString m_curUuid;
|
||||
// 当前还原源目录
|
||||
QString m_srcPath;
|
||||
// 备份进程
|
||||
RsyncPathToDirProcess *m_p;
|
||||
// 当前备份节点
|
||||
ParseBackupList::BackupPoint m_backupPoint;
|
||||
// 强制结束标志(stop后没反应的情况,系统处于睡眠状态)
|
||||
bool m_isForce;
|
||||
};
|
||||
|
||||
#endif // UDISKSYSTEMRESTOREPROXY_H
|
|
@ -0,0 +1,113 @@
|
|||
#include "workerfactory.h"
|
||||
#include <QString>
|
||||
|
||||
Worker::Worker() :
|
||||
QObject(nullptr),
|
||||
m_bCancel(false)
|
||||
{}
|
||||
|
||||
Worker::~Worker()
|
||||
{}
|
||||
|
||||
//
|
||||
/**
|
||||
* @brief 环境检测
|
||||
*/
|
||||
void Worker::checkEnv()
|
||||
{
|
||||
checkEnvEx();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 任务处理
|
||||
*/
|
||||
void Worker::doWork()
|
||||
{
|
||||
doWorkEx();
|
||||
}
|
||||
|
||||
// 环境检测,个性化部分派生类去实现
|
||||
bool Worker::checkEnvEx()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 任务处理,个性化部分派生类去实现
|
||||
void Worker::doWorkEx()
|
||||
{}
|
||||
|
||||
// 任务取消,个性化部分派生类去实现
|
||||
void Worker::cancelEx()
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief 根据操作类型和位置创建相应的处理类
|
||||
* @param type 操作类型,如:系统备份, 系统还原
|
||||
* @param position 本地备份还是U盘备份: 0-本地备份;1-移动设备备份
|
||||
* @return Worker派生类对象指针,需调用者释放此对象
|
||||
*/
|
||||
Worker * WorkerFactory::createWorker(int type, int position)
|
||||
{
|
||||
QString className;
|
||||
switch (type) {
|
||||
case BackupType::BACKUP_SYSTEM:
|
||||
case BackupType::INC_BACKUP_SYSTEM:
|
||||
if (BackupPosition::UDISK == position) {
|
||||
className = "UDiskSystemBackupProxy";
|
||||
} else if (BackupPosition::CUSTOMIZE == position) {
|
||||
className = "CustomizeSystemBackupProxy";
|
||||
} else {
|
||||
className = "SystemBackupProxy";
|
||||
}
|
||||
break;
|
||||
case BackupType::RESTORE_SYSTEM:
|
||||
case BackupType::RESTORE_SYSTEM_WITH_DATA:
|
||||
if (BackupPosition::UDISK == position || BackupPosition::OTHER == position) {
|
||||
className = "UDiskSystemRestoreProxy";
|
||||
} else if (BackupPosition::CUSTOMIZE == position) {
|
||||
className = "CustomizeSystemRestoreProxy";
|
||||
} else {
|
||||
className = "SystemRestoreProxy";
|
||||
}
|
||||
break;
|
||||
case BackupType::BACKUP_DATA:
|
||||
case BackupType::INC_BACKUP_DATA:
|
||||
if (BackupPosition::UDISK == position) {
|
||||
className = "UDiskDataBackupProxy";
|
||||
} else if (BackupPosition::CUSTOMIZE == position) {
|
||||
className = "CustomizeDataBackupProxy";
|
||||
} else {
|
||||
className = "DataBackupProxy";
|
||||
}
|
||||
break;
|
||||
case BackupType::RESTORE_DATA:
|
||||
if (BackupPosition::UDISK == position) {
|
||||
className = "UDiskDataRestoreProxy";
|
||||
} else {
|
||||
className = "DataRestoreProxy";
|
||||
}
|
||||
break;
|
||||
case BackupType::DELETE_BACKUP:
|
||||
className = "DeleteBackupProxy";
|
||||
break;
|
||||
case BackupType::GHOST_IMAGE:
|
||||
if (BackupPosition::UDISK == position) {
|
||||
className = "UDiskGhostImageProxy";
|
||||
} else if (BackupPosition::CUSTOMIZE == position) {
|
||||
className = "CustomizeGhostImageProxy";
|
||||
} else {
|
||||
className = "GhostImageProxy";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (className.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Worker * p = qobject_cast<Worker *>(Reflect::createObject(className));
|
||||
return p;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#ifndef WORKERFACTORY_H
|
||||
#define WORKERFACTORY_H
|
||||
|
||||
#include <QObject>
|
||||
#include "../common/mydefine.h"
|
||||
#include "../common/reflect.h"
|
||||
|
||||
/**
|
||||
* @brief 备份还原相关任务处理类基类
|
||||
*/
|
||||
class Worker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Worker();
|
||||
virtual ~Worker();
|
||||
|
||||
signals:
|
||||
// 检测结果信号
|
||||
void checkResult(int result);
|
||||
// 进度百分比
|
||||
void progress(int currentRate);
|
||||
// 工作结果信号
|
||||
void workResult(bool result);
|
||||
// 任务取消
|
||||
void cancel();
|
||||
|
||||
public slots:
|
||||
// 环境检测
|
||||
void checkEnv();
|
||||
|
||||
// 任务处理
|
||||
void doWork();
|
||||
|
||||
protected:
|
||||
// 环境检测,个性化部分派生类去实现
|
||||
virtual bool checkEnvEx();
|
||||
|
||||
// 任务处理,个性化部分派生类去实现
|
||||
virtual void doWorkEx();
|
||||
|
||||
// 任务取消,个性化部分派生类去实现
|
||||
virtual void cancelEx();
|
||||
|
||||
public:
|
||||
void setParam(const BackupWrapper& backupWrapper) { m_backupWrapper = backupWrapper; }
|
||||
|
||||
public:
|
||||
// 同一时间只能运行一个备份/还原等操作
|
||||
BackupWrapper m_backupWrapper;
|
||||
// 是否取消操作
|
||||
bool m_bCancel;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 备份还原相关任务工厂类
|
||||
*/
|
||||
class WorkerFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 根据操作类型和位置创建相应的处理类
|
||||
* @param type 操作类型,如:系统备份, 系统还原
|
||||
* @param position 本地备份还是U盘备份: 0-本地备份;1-移动设备备份
|
||||
* @return Worker派生类对象指针,需调用者释放此对象
|
||||
*/
|
||||
static Worker * createWorker(int type, int position);
|
||||
};
|
||||
|
||||
#endif // WORKERFACTORY_H
|
|
@ -0,0 +1,32 @@
|
|||
#include "mydefine.h"
|
||||
#include <QDBusMetaType>
|
||||
|
||||
// Marshall the MyStructure data into a D-Bus argument
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const BackupWrapper &backupWrapper)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << backupWrapper.m_type << backupWrapper.m_iPosition << backupWrapper.m_comment << backupWrapper.m_backupName
|
||||
<< backupWrapper.m_uuid << backupWrapper.m_backupPaths << backupWrapper.m_backupExcludePaths << backupWrapper.m_prefixDestPath
|
||||
<< backupWrapper.m_note << backupWrapper.m_frontUserName << backupWrapper.m_frontUid
|
||||
<< backupWrapper.m_gid << backupWrapper.m_isOtherMachine;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Retrieve the MyStructure data from the D-Bus argument
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, BackupWrapper &backupWrapper)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> backupWrapper.m_type >> backupWrapper.m_iPosition >> backupWrapper.m_comment >> backupWrapper.m_backupName
|
||||
>> backupWrapper.m_uuid >> backupWrapper.m_backupPaths >> backupWrapper.m_backupExcludePaths >> backupWrapper.m_prefixDestPath
|
||||
>> backupWrapper.m_note >> backupWrapper.m_frontUserName >> backupWrapper.m_frontUid
|
||||
>> backupWrapper.m_gid >> backupWrapper.m_isOtherMachine;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
void BackupWrapper::registerMetaType()
|
||||
{
|
||||
qRegisterMetaType<BackupWrapper>("BackupWrapper");
|
||||
qDBusRegisterMetaType<BackupWrapper>();
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
#ifndef MYDEFINE_H
|
||||
#define MYDEFINE_H
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMetaType>
|
||||
#include <QDBusArgument>
|
||||
|
||||
#define DEFAULT_APP_PATH "/usr/bin"
|
||||
|
||||
#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 CHECK_PATH "/backup/snapshots/check/data/"
|
||||
#define BACKUP_LOG_TEXT_PATH "/backup/log.txt"
|
||||
#define BACKUP_IMGBACKUP_PATH "/backup/imgbackup"
|
||||
#define IMGBACKUP_PATH "/imgbackup"
|
||||
#define UDISK_MKSQUASHFS_IMG_NAME "dst.img"
|
||||
#define UDISK_UNIQUE_SETTINGS "/backup/udisk_unique_file"
|
||||
#define GHOST_PATH "/ghost"
|
||||
|
||||
#define DATA_PATH "/data"
|
||||
|
||||
#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 FILE_IF_SYNC "/etc/file_if_sync"
|
||||
|
||||
#define BACKUP_CLI_NAME "kybackup"
|
||||
|
||||
#define AUTO_BACKUP_UUID "{01234567-0123-0123-0123-0123456789ab}"
|
||||
#define FACTORY_BACKUP_UUID "{00000000-0000-0000-0000-000000000000}"
|
||||
|
||||
#define PATHS_USER_FILE ".user.txt"
|
||||
#define EXCLUDE_PATHS_USER_FILE ".exclude.user.txt"
|
||||
|
||||
#define BACKUP_PARSE_STATE_SUCCESS_STRTING "backup finished"
|
||||
#define BACKUP_PARSE_STATE_FAIL_STRTING "backup unfinished"
|
||||
#define BACKUP_PARSE_STATE_INC_SUCCESS_STRTING "inc backup finished"
|
||||
#define BACKUP_PARSE_STATE_INC_FAIL_STRTING "inc backup unfinished"
|
||||
|
||||
#define THEME_YHKYLIN_BACKUP_TOOLS "yhkylin-backup-tools"
|
||||
|
||||
#define PID_STRING_LEN 1024
|
||||
|
||||
// 蓝色
|
||||
#define COLOR_BLUE "#3790FA"
|
||||
// 蓝黑
|
||||
#define COLOR_BLUE_DARK "#3B4251"
|
||||
// 浅灰
|
||||
#define COLOR_LIGHT_DARK "#F4F4F4"
|
||||
// 灰色
|
||||
#define COLOR_GRAY "#CCCCCC"
|
||||
// 深灰
|
||||
#define COLOR_DARK_GRAY "#393A3E"
|
||||
// 黑灰
|
||||
#define COLOR_BLACK_GRAY "#2D2E32"
|
||||
// 字体灰色
|
||||
#define COLOR_DISABLE_GRAY "#737373"
|
||||
// 黄色
|
||||
#define COLOR_YELLOW "#F8A34C"
|
||||
// 浅蓝
|
||||
#define COLOR_LIGHT_BLUE "#DDEBFF"
|
||||
|
||||
#define END_LINE "\n"
|
||||
|
||||
/**
|
||||
* @brief 备份还原操作类型
|
||||
*/
|
||||
enum BackupType {
|
||||
// 系统备份
|
||||
BACKUP_SYSTEM = 0,
|
||||
// 增量系统备份
|
||||
INC_BACKUP_SYSTEM = 1,
|
||||
// 数据备份
|
||||
BACKUP_DATA = 2,
|
||||
// 增量数据备份
|
||||
INC_BACKUP_DATA = 3,
|
||||
// 系统还原
|
||||
RESTORE_SYSTEM = 4,
|
||||
// 保留用户数据还原
|
||||
RESTORE_SYSTEM_WITH_DATA = 5,
|
||||
// 数据还原
|
||||
RESTORE_DATA = 6,
|
||||
// 增量数据还原,实际没有这个类型,为兼容以前的数据仍然保留
|
||||
INC_RESTORE_DATA = 7,
|
||||
// 删除备份点
|
||||
DELETE_BACKUP = 8,
|
||||
// ghost镜像
|
||||
GHOST_IMAGE = 9,
|
||||
|
||||
// 仅仅初始化BackupType枚举类变量用,没有用于持久化,不用固定其值
|
||||
BACKUP_TYPE_INIT,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 备份信息结构体
|
||||
*/
|
||||
struct BackupWrapper {
|
||||
// 操作类型,如:系统备份, 系统还原
|
||||
int m_type = -1;
|
||||
// 本地备份还是U盘备份: 0-本地备份;1-移动设备备份;2-异机备份;3-自定义路径
|
||||
int m_iPosition = -1;
|
||||
// 备份名称,用于识别备份的,默认是时间
|
||||
QString m_comment;
|
||||
// 备份名称,用来替换m_comment
|
||||
QString m_backupName;
|
||||
// 备份或还原指定的UUID
|
||||
QString m_uuid;
|
||||
// 待备份目录
|
||||
QStringList m_backupPaths;
|
||||
// 备份需要排除的路径
|
||||
QStringList m_backupExcludePaths;
|
||||
// 移动设备挂载路径:备份目标路径/还原点路径(前缀),在向移动设备备份(或从移动设备还原)时使用它来指定对应的移动设备路径
|
||||
QString m_prefixDestPath;
|
||||
// 备注信息
|
||||
QString m_note;
|
||||
// 备份用户名
|
||||
QString m_frontUserName;
|
||||
// 备份用户id
|
||||
int m_frontUid = -1;
|
||||
// 备份用户所属组id
|
||||
int m_gid = -1;
|
||||
// 是否异机备份点: 0-本机备份;1-异机备份
|
||||
int m_isOtherMachine = 0;
|
||||
|
||||
// 下面参数不是入参,是服务端自行跟随业务场景设置
|
||||
// 是否增量备份
|
||||
bool m_bIncrement = false;
|
||||
// 新增备份点时增量备份的基准uuid
|
||||
QString m_baseUuid;
|
||||
// 备份时间(暂用于日志查询)
|
||||
QString m_time;
|
||||
// 备份大小(暂用于日志查询)
|
||||
QString m_size;
|
||||
|
||||
static void registerMetaType();
|
||||
};
|
||||
Q_DECLARE_METATYPE(BackupWrapper)
|
||||
|
||||
extern QDBusArgument &operator<<(QDBusArgument &argument, const BackupWrapper &backupWrapper);
|
||||
|
||||
extern const QDBusArgument &operator>>(const QDBusArgument &argument, BackupWrapper &backupWrapper);
|
||||
|
||||
// 为兼容旧版本对外提供的接口,此处结构前面暂时不变,只在后面增加
|
||||
enum class MountResult {
|
||||
MOUNT_RESULT_INIT,
|
||||
CANNOT_GET_BACKUPUUID,
|
||||
NO_BLKID_EXIST,
|
||||
NO_MOUNTED,
|
||||
GENERATE_IMPORT_FILE_FAIL,
|
||||
MOUNTED
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 备份还原工具状态
|
||||
*/
|
||||
enum class BackupState {
|
||||
// 准备中
|
||||
PREPARING = 1,
|
||||
// 工作中
|
||||
WORKING,
|
||||
|
||||
// 空闲状态
|
||||
BACKUP_STATE_INIT = 99
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 备份位置
|
||||
*/
|
||||
enum BackupPosition
|
||||
{
|
||||
LOCAL, // 本地磁盘
|
||||
UDISK, // 移动设备
|
||||
OTHER, // 移动设备中的其它机器的备份点
|
||||
CUSTOMIZE, // 自定义路径
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 备份还原进展
|
||||
* @note 为兼容以前老版本提供给自动更新模块的接口,此结构前面部分保持老代码结构
|
||||
*/
|
||||
enum class BackupResult {
|
||||
// 备份初始
|
||||
BACKUP_RESULT_INIT,
|
||||
// /etc/.bootinfo读取失败
|
||||
ETC_BOOTINFO_READ_FAIL,
|
||||
// /etc/fstab不存在
|
||||
FSTAB_IS_NOT_EXIST,
|
||||
// 文件锁定应用失败
|
||||
LOCK_PROGRAM_FAIL,
|
||||
//有其他正在进行的备份或者还原
|
||||
OTHER_BACKUP_OR_RESTORE_RUNNING,
|
||||
// 有删除任务正在进行
|
||||
RM_RUNNING,
|
||||
// 正在制作镜像
|
||||
MKSQUASHFS_RUNNING,
|
||||
// 设备uuid不存在
|
||||
NO_BLKID_EXIST,
|
||||
// 挂载/backup分区失败
|
||||
BACKUP_PARTITION_MOUNT_FAIL,
|
||||
// 生成备份导入文件失败
|
||||
GENERATE_BACKUP_IMPORT_FILE_FAIL,
|
||||
// /backup/current目录不存在
|
||||
BACKUP_CURRENT_DIR_IS_NOT_EXIST,
|
||||
// /backup/snapshots目录不存在
|
||||
BACKUP_SNAPSHOTS_DIR_IS_NOT_EXIST,
|
||||
// /backup/snapshots/backuplist.xml文件不存在或打开失败
|
||||
BACKUP_STORAGEINFO_FILE_FAIL_TO_OPEN,
|
||||
// /backup/snapshots/backuplist.xml格式不正确
|
||||
BACKUP_STORAGEINFO_IS_NOT_CORRECT,
|
||||
// 写入 /backup/snapshots/backuplist.xml 失败
|
||||
WRITE_STORAGEINFO_ADD_ITEM_FAIL,
|
||||
// 修改 /backup/snapshots/backuplist.xml 失败
|
||||
WRITE_STORAGEINFO_UPDATE_ITEM_FAIL,
|
||||
// 增量备份未找到对应的uuid
|
||||
INC_NOT_FOUND_UUID,
|
||||
// 增量备份(或还原)未找到对应的目录
|
||||
INC_NOT_FOUND_DIR,
|
||||
// 将备份路径写入(或读出)/backup/snapshots/{uuid}/.user.txt失败
|
||||
WRITE_BACKUP_PATHS_TO_USER_FAILED,
|
||||
// 将备份路径写入(或读出)/backup/snapshots/{uuid}/.exclude.user.txt失败
|
||||
WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED,
|
||||
// /backup备份空间不足
|
||||
BACKUP_CAPACITY_IS_NOT_ENOUGH,
|
||||
// U盘文件系统是只读的
|
||||
UDISK_FILESYSTEM_IS_READONLY,
|
||||
// u盘中创建目录/backup/snapshots失败
|
||||
UDISK_STH_ERROR,
|
||||
// u盘文件系统是vfat格式(容量有限或单个文件大小有限)
|
||||
UDISK_FILESYSTEM_TYPE_IS_VFAT,
|
||||
// DU计算大小失败
|
||||
DU_ERR,
|
||||
// 向U盘备份时先压缩到本地成img文件,本地备份分区空间不足
|
||||
BACKUP_CAPACITY_FOR_UDISKIMG_IS_NOT_ENOUGH,
|
||||
// U盘容量不足
|
||||
UDISK_CAPACITY_IS_NOT_ENOUGH,
|
||||
// /boot/efi同步失败
|
||||
EFI_RSYNC_FAIL,
|
||||
// 备份启动失败
|
||||
BACKUP_PROCESS_START_FAIL,
|
||||
// 备份失败
|
||||
BACKUP_PROCESS_DO_FAIL,
|
||||
|
||||
// 备份进程成功启动
|
||||
BACKUP_START_SUCCESS,
|
||||
// 备份成功,信号未使用此结果
|
||||
BACKUP_DO_SUCCESS,
|
||||
|
||||
// 还原初始
|
||||
RESTORE_RESULT_INIT,
|
||||
// 还原目录准备失败
|
||||
RESTOREDIR_PREPARE_FAILED,
|
||||
// 还原进程开启失败
|
||||
RESTORE_PROCESS_START_FAIL,
|
||||
// 还原失败
|
||||
RESTORE_PROCESS_DO_FAIL,
|
||||
// 还原成功开始
|
||||
RESTORE_START_SUCCESS,
|
||||
// 还原成功,信号未使用此结果
|
||||
RESTORE_DO_SUCCESS,
|
||||
|
||||
// ghost镜像未找到备份点
|
||||
GHOST_CANNOT_FIND_BACKUPPOINT,
|
||||
// ghost源目录不存在
|
||||
GHOST_SRC_DIRECTORY_IS_NOT_EXIST,
|
||||
// ghost进程启动失败
|
||||
GHOST_PROCESS_START_FAIL,
|
||||
// ghost进程启动成功
|
||||
GHOST_START_SUCCESS,
|
||||
|
||||
// 后面的为新版本新增部分
|
||||
|
||||
// 根据操作类型动态创建处理类失败
|
||||
NO_FOUND_DEALCLASS,
|
||||
// 环境检测成功
|
||||
CHECK_ENV_SUCCESS,
|
||||
// mksquashfs启动成功
|
||||
MKSQUASHFS_START_SUCCESS,
|
||||
// mksquashfs压缩img文件失败
|
||||
MKSQUASHFS_DO_FAIL,
|
||||
// mksquashfs压缩img文件成功,开始转移img文件到u盘
|
||||
MKSQUASHFS_DO_SUCCESS,
|
||||
// 开始取消操作
|
||||
START_CANCEL,
|
||||
// 取消操作成功
|
||||
CANCEL_SUCCESS,
|
||||
};
|
||||
|
||||
#endif // MYDEFINE_H
|
|
@ -0,0 +1,114 @@
|
|||
#include "mydusizetool.h"
|
||||
#include <QDebug>
|
||||
#include "utils.h"
|
||||
|
||||
MyDuSizeTool::MyDuSizeTool(QObject* parent) :
|
||||
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 (const QString& x : paths) {
|
||||
cmd.append(QString(" \"%1\"").arg(x));
|
||||
}
|
||||
if (needExclude) {
|
||||
for (const QString& item : excludePaths) {
|
||||
QString arg = QString(" --exclude=\"%1\"").arg(item);
|
||||
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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -0,0 +1,265 @@
|
|||
#include "mylittleparse.h"
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
|
||||
MyLittleParse::MyLittleParse(const QString& path)
|
||||
: file(new QFile(path))
|
||||
, m_e(MyLittleParse::DEFAULT)
|
||||
{
|
||||
}
|
||||
|
||||
MyLittleParse::~MyLittleParse()
|
||||
{
|
||||
file->close();
|
||||
delete file;
|
||||
}
|
||||
|
||||
bool MyLittleParse::add(const QString& key, const QString& value, MyLittleParse::error_enum& e)
|
||||
{
|
||||
QString find_value;
|
||||
if (find(key, find_value, e)) {
|
||||
//key=<不空值>
|
||||
if (!find_value.isEmpty()) {
|
||||
e = MyLittleParse::KEY_EXITS;
|
||||
return false;
|
||||
}
|
||||
//key=<空值>
|
||||
return mod(key, value, e);
|
||||
}
|
||||
|
||||
if (!file->open(QIODevice::ReadWrite)) {
|
||||
e = MyLittleParse::OPEN_FILE_FAIL;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(file);
|
||||
file->readAll();
|
||||
out << key << "=" << value << "\n";
|
||||
|
||||
file->close();
|
||||
e = MyLittleParse::SUCCESS;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MyLittleParse::add(const QString&& key, const QString&& value)
|
||||
{
|
||||
QString _key = key;
|
||||
QString _value = value;
|
||||
return add(_key, _value);
|
||||
}
|
||||
|
||||
bool MyLittleParse::Add(const QString &key, const QString &value)
|
||||
{
|
||||
MyLittleParse::error_enum e;
|
||||
bool t = add(key, value, e);
|
||||
if (!t && e == MyLittleParse::KEY_EXITS) {
|
||||
t = mod(key, value);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
bool MyLittleParse::add(const QString& key, const QString& value)
|
||||
{
|
||||
return add(key, value, m_e);
|
||||
}
|
||||
|
||||
bool MyLittleParse::del(const QString& key, MyLittleParse::error_enum& e)
|
||||
{
|
||||
if (!find_only(key, e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file->open(QIODevice::ReadOnly)) {
|
||||
e = MyLittleParse::OPEN_FILE_FAIL;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(file);
|
||||
QString strAll = out.readAll();
|
||||
file->close();
|
||||
|
||||
QStringList strList = strAll.split("\n");
|
||||
QStringList strDstList;
|
||||
QString tmp_key;
|
||||
for (QString& line : strList) {
|
||||
if (line.trimmed().isEmpty())
|
||||
continue;
|
||||
tmp_key = line.section('=', 0, 0).trimmed();
|
||||
if (tmp_key == key)
|
||||
continue;
|
||||
strDstList << line << "\n";
|
||||
}
|
||||
|
||||
file->open(QIODevice::Truncate | QIODevice::WriteOnly);
|
||||
for (auto s : strDstList)
|
||||
out << s;
|
||||
out.flush();
|
||||
file->close();
|
||||
e = MyLittleParse::SUCCESS;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MyLittleParse::del(const QString&& key)
|
||||
{
|
||||
QString _key = key;
|
||||
return del(_key);
|
||||
}
|
||||
|
||||
bool MyLittleParse::del(const QString& key)
|
||||
{
|
||||
return del(key, m_e);
|
||||
}
|
||||
|
||||
bool MyLittleParse::mod(const QString& key, const QString& value, MyLittleParse::error_enum& e)
|
||||
{
|
||||
if (!find_only(key, e)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file->open(QIODevice::ReadOnly)) {
|
||||
e = MyLittleParse::OPEN_FILE_FAIL;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(file);
|
||||
QString strAll = out.readAll();
|
||||
file->close();
|
||||
|
||||
QStringList strList = strAll.split("\n");
|
||||
QStringList strDstList;
|
||||
QString tmp_key;
|
||||
QString tmp_value;
|
||||
for (QString& line : strList) {
|
||||
tmp_key = line.section('=', 0, 0).trimmed();
|
||||
if (tmp_key == key) {
|
||||
tmp_value = line.section('=', 1, 1).trimmed();
|
||||
if (tmp_value == value) {
|
||||
e = MyLittleParse::REPEAT;
|
||||
file->close();
|
||||
return false;
|
||||
}
|
||||
line.clear();
|
||||
line = key + "=" + value;
|
||||
}
|
||||
strDstList << line << "\n";
|
||||
}
|
||||
|
||||
file->open(QIODevice::Truncate | QIODevice::WriteOnly);
|
||||
for (auto& s : strDstList)
|
||||
out << s;
|
||||
out.flush();
|
||||
file->close();
|
||||
e = MyLittleParse::SUCCESS;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MyLittleParse::mod(const QString& key, const QString& value)
|
||||
{
|
||||
return mod(key, value, m_e);
|
||||
}
|
||||
|
||||
bool MyLittleParse::mod(const QString&& key, const QString&& value)
|
||||
{
|
||||
QString _key = key;
|
||||
QString _value = value;
|
||||
return mod(_key, _value);
|
||||
}
|
||||
|
||||
bool MyLittleParse::Mod(const QString &key, const QString &value)
|
||||
{
|
||||
MyLittleParse::error_enum e;
|
||||
bool t = mod(key, value, e);
|
||||
if (!t && e == MyLittleParse::REPEAT) {
|
||||
return true;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
bool MyLittleParse::find(const QString& key, QString& value, MyLittleParse::error_enum& e)
|
||||
{
|
||||
if (!file->open(QIODevice::ReadOnly)) {
|
||||
e = MyLittleParse::OPEN_FILE_FAIL;
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream out(file);
|
||||
|
||||
QString line;
|
||||
QString tmp_key;
|
||||
|
||||
while (1) {
|
||||
if (out.atEnd())
|
||||
break;
|
||||
line = out.readLine();
|
||||
if (line.trimmed().isEmpty())
|
||||
continue;
|
||||
tmp_key = line.section('=', 0, 0).trimmed();
|
||||
if (key == tmp_key) {
|
||||
value = line.section('=', 1, 1).trimmed();
|
||||
file->close();
|
||||
e = MyLittleParse::SUCCESS;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
file->close();
|
||||
e = MyLittleParse::KEY_NOEXITS;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MyLittleParse::find(const QString& key, QString& value)
|
||||
{
|
||||
return find(key, value, m_e);
|
||||
}
|
||||
|
||||
bool MyLittleParse::find(const QString&& key, QString&& value)
|
||||
{
|
||||
QString _key = key;
|
||||
QString _value = value;
|
||||
return find(_key, _value);
|
||||
}
|
||||
|
||||
bool MyLittleParse::find_only(const QString& key, MyLittleParse::error_enum& e)
|
||||
{
|
||||
QString value;
|
||||
if (find(key, value, e))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MyLittleParse::find_only(const QString& key)
|
||||
{
|
||||
return find_only(key, m_e);
|
||||
}
|
||||
|
||||
bool MyLittleParse::find_only(const QString&& key)
|
||||
{
|
||||
QString _key = key;
|
||||
return find_only(_key);
|
||||
}
|
||||
|
||||
MyLittleParse::error_enum MyLittleParse::getErrEnum() const
|
||||
{
|
||||
return m_e;
|
||||
}
|
||||
|
||||
QString MyLittleParse::getErrMsg()
|
||||
{
|
||||
switch (m_e) {
|
||||
case MyLittleParse::DEFAULT:
|
||||
return "default";
|
||||
case MyLittleParse::KEY_EXITS:
|
||||
return "KEY_EXITS";
|
||||
case MyLittleParse::OPEN_FILE_FAIL:
|
||||
return "OPEN_FILE_FAIL";
|
||||
case MyLittleParse::KEY_NOEXITS:
|
||||
return "KEY_NOEXITS";
|
||||
case MyLittleParse::REPEAT:
|
||||
return "REPEAT";
|
||||
case MyLittleParse::SUCCESS:
|
||||
return "SUCCESS";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "";
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFile>
|
||||
class QString;
|
||||
|
||||
class MyLittleParse {
|
||||
public:
|
||||
enum error_enum {
|
||||
DEFAULT,
|
||||
OPEN_FILE_FAIL,
|
||||
KEY_EXITS, //key存在,value为空, 适用于add
|
||||
REPEAT, //key和value都存在,且重复,适用于mod
|
||||
KEY_NOEXITS, //不能找到key, 适用于find
|
||||
SUCCESS
|
||||
};
|
||||
MyLittleParse(const QString& path);
|
||||
|
||||
~MyLittleParse();
|
||||
|
||||
/**
|
||||
* @brief add
|
||||
* @param key
|
||||
* @param value
|
||||
* @param e
|
||||
* @return
|
||||
*
|
||||
* 文件不存在,返回false, e = OPEN_FILE_FAIL
|
||||
* 如果key不存在, 增加条目 key=value, e = SUCCESS
|
||||
* 如果key存在,=后是空,转到 mod 函数。
|
||||
* 如果key存在,=后不为空,返回false, e = KEY_EXISTS
|
||||
*
|
||||
*/
|
||||
bool add(const QString& key, const QString& value, error_enum& e);
|
||||
bool add(const QString& key, const QString& value);
|
||||
bool add(const QString&& key, const QString&& value);
|
||||
|
||||
/**
|
||||
* @brief Add
|
||||
* @param key
|
||||
* @param value
|
||||
* @return
|
||||
*
|
||||
* 如果key不存在, 增加条目 key=value
|
||||
* 如果key存在,转到 mod 函数。
|
||||
*
|
||||
*/
|
||||
bool Add(const QString& key, const QString& value);
|
||||
|
||||
/**
|
||||
* @brief del
|
||||
* @param key
|
||||
* @param e
|
||||
* @return
|
||||
*
|
||||
* 如果find_only(key) = false,返回false
|
||||
* 文件不存在,返回false, e = OPEN_FILE_FAIL
|
||||
*
|
||||
*/
|
||||
bool del(const QString& key, error_enum& e);
|
||||
bool del(const QString& key);
|
||||
bool del(const QString&& key);
|
||||
|
||||
/**
|
||||
* @brief mod
|
||||
* @param key
|
||||
* @param value
|
||||
* @param e
|
||||
* @return
|
||||
*
|
||||
* 如果find_only(key) = false,返回false
|
||||
* 文件不存在,返回false, e = OPEN_FILE_FAIL
|
||||
* 如果key对应的值和value相等,返回false, e = REPEAT
|
||||
*/
|
||||
bool mod(const QString& key, const QString& value, error_enum& e);
|
||||
bool mod(const QString& key, const QString& value);
|
||||
bool mod(const QString&& key, const QString&& value);
|
||||
|
||||
/**
|
||||
* @brief Mod
|
||||
* @param key
|
||||
* @param value
|
||||
* @return
|
||||
*
|
||||
*
|
||||
* 如果key对应的值和value相等,返回true
|
||||
*/
|
||||
bool Mod(const QString& key, const QString& value);
|
||||
|
||||
/**
|
||||
* @brief find
|
||||
* @param key
|
||||
* @param value
|
||||
* @param e
|
||||
* @return
|
||||
*
|
||||
* 文件不存在,返回false, e = OPEN_FILE_FAIL
|
||||
* 找到key,并赋值给value
|
||||
*/
|
||||
bool find(const QString& key, QString& value, error_enum& e);
|
||||
bool find(const QString& key, QString& value);
|
||||
bool find(const QString&& key, QString&& value);
|
||||
|
||||
/**
|
||||
* @brief find_only
|
||||
* @param key
|
||||
* @param e
|
||||
* @return
|
||||
* 文件不存在,返回false, e = OPEN_FILE_FAIL
|
||||
*/
|
||||
bool find_only(const QString& key, error_enum& e);
|
||||
bool find_only(const QString& key);
|
||||
bool find_only(const QString&& key);
|
||||
|
||||
error_enum getErrEnum() const;
|
||||
|
||||
QString getErrMsg();
|
||||
|
||||
private:
|
||||
QFile* file;
|
||||
error_enum m_e;
|
||||
};
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* brief 工具类——反射,主要用作根据类名动态创建类
|
||||
* author 赵民勇
|
||||
* note :
|
||||
* 1、类需要继承自QObject或其派生数的上层节点包含QObject
|
||||
* 2、暂时只提供无参构造函数注册
|
||||
* 3、需要动态创建的类头文件中引入本头文件,并且在类定义中使用宏DECLARE_DYNAMIC_CLASS(yourClassName); 在类定义文件(.cpp)中使用IMPL_DYNAMIC_CLASS(yourClassName)
|
||||
* 4、例:
|
||||
* 类定义的头文件.h中:
|
||||
* #include <QObject>
|
||||
* #include "../common/reflect.h"
|
||||
* class MyClass : public QObject
|
||||
* {
|
||||
* Q_OBJECT
|
||||
* DECLARE_DYNCREATE(MyClass)
|
||||
* }
|
||||
*
|
||||
* .cpp文件中,代码开始前写上:
|
||||
* IMPLEMENT_DYNCREATE(MyClass)
|
||||
*/
|
||||
|
||||
#include "reflect.h"
|
||||
|
||||
int Reflect::registerClass(const QString& className, Constructor constructor)
|
||||
{
|
||||
QHash<QString, Constructor>& instances = constructors();
|
||||
instances.insert(className, constructor);
|
||||
return instances.size();
|
||||
}
|
||||
|
||||
QObject * Reflect::createObject(const QString& className)
|
||||
{
|
||||
QHash<QString, Constructor>& instances = constructors();
|
||||
if (instances.contains(className)) {
|
||||
Constructor constructor = instances[className];
|
||||
if (constructor != nullptr) {
|
||||
return (*constructor)();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QHash<QString, Constructor>& Reflect::constructors()
|
||||
{
|
||||
static QHash<QString, Constructor> _instances;
|
||||
return _instances;
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* brief 工具类——反射,主要用作根据类名动态创建类
|
||||
* author 赵民勇
|
||||
* note :
|
||||
* 1、类需要继承自QObject或其派生数的上层节点包含QObject
|
||||
* 2、暂时只提供无参构造函数注册
|
||||
* 3、需要动态创建的类头文件中引入本头文件,并且在类定义中使用宏DECLARE_DYNAMIC_CLASS(yourClassName); 在类定义文件(.cpp)中使用IMPL_DYNAMIC_CLASS(yourClassName)
|
||||
* 4、例:
|
||||
* 类定义的头文件.h中:
|
||||
* #include <QObject>
|
||||
* #include "../common/reflect.h"
|
||||
* class MyClass : public QObject
|
||||
* {
|
||||
* Q_OBJECT
|
||||
* DECLARE_DYNCREATE(MyClass)
|
||||
* }
|
||||
*
|
||||
* .cpp文件中,代码开始前写上:
|
||||
* IMPLEMENT_DYNCREATE(MyClass)
|
||||
*/
|
||||
|
||||
#ifndef REFLECT_H
|
||||
#define REFLECT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
|
||||
typedef QObject * (*Constructor)();
|
||||
|
||||
class Reflect
|
||||
{
|
||||
public:
|
||||
static int registerClass(const QString& className, Constructor constructor);
|
||||
|
||||
static QObject * createObject(const QString& className);
|
||||
|
||||
private:
|
||||
static QHash<QString, Constructor>& constructors();
|
||||
};
|
||||
|
||||
#define DECLARE_DYNCREATE(class_name) \
|
||||
public: \
|
||||
static QObject * create##class_name##Object();
|
||||
|
||||
#define IMPLEMENT_DYNCREATE(class_name) \
|
||||
QObject * class_name::create##class_name##Object() \
|
||||
{ \
|
||||
return (QObject *)(new class_name()); \
|
||||
} \
|
||||
static int g_icreate##class_name##Object = Reflect::registerClass(#class_name, class_name::create##class_name##Object);
|
||||
|
||||
|
||||
#endif //!REFLECT_H
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* brief 1.单例模板和其奇特递归模板模式的派生类相互辅助相互制约形成单例使用方式
|
||||
* 2.Singleton模板的默认构造函数是受保护的protected。故只能由派生类来构造
|
||||
* 3.其派生类的构造函数必须含有token类型的参数
|
||||
* author 赵民勇
|
||||
* note 使用方式如下:
|
||||
class MysqlPool :public Singleton<MysqlPool> {
|
||||
public:
|
||||
MysqlPool(token) {};
|
||||
~MysqlPool();
|
||||
...
|
||||
};
|
||||
*/
|
||||
|
||||
#ifndef SINGLETON_H_
|
||||
#define SINGLETON_H_
|
||||
|
||||
template <class T>
|
||||
class Singleton
|
||||
{
|
||||
public:
|
||||
Singleton(const Singleton&) = delete;
|
||||
Singleton& operator= (const Singleton) = delete;
|
||||
public:
|
||||
static T& inst() {
|
||||
static T _{ token{} };
|
||||
return _;
|
||||
}
|
||||
protected:
|
||||
struct token {};
|
||||
Singleton() = default;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @author 赵民勇
|
||||
* @note 基于c++11搞的原子自旋锁, 可用于std::shared_lock<spinlock_mutex>、std::lock_guard<spinlock_mutex>等
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __SPINLOCK_MUTEX_H__
|
||||
#define __SPINLOCK_MUTEX_H__
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
class spinlock_mutex
|
||||
{
|
||||
std::atomic_flag flag = ATOMIC_FLAG_INIT; //注意:不能用初始化列表初始化,拷贝构造和复制构造函数已经删除
|
||||
|
||||
public:
|
||||
spinlock_mutex() {}
|
||||
|
||||
void lock()
|
||||
{
|
||||
while (flag.test_and_set(std::memory_order_acquire));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
flag.clear(std::memory_order_release);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return !flag.test_and_set(std::memory_order_acquire);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //!__SPINLOCK_MUTEX_H__
|
|
@ -0,0 +1,339 @@
|
|||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QtDebug>
|
||||
#include "mydefine.h"
|
||||
|
||||
class SystemInfo
|
||||
{
|
||||
public:
|
||||
// 操作系统
|
||||
static QString m_os;
|
||||
// 架构
|
||||
static QString m_arch;
|
||||
// 引导方式
|
||||
static QString m_archDetect;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 工具类
|
||||
* @author zhaominyong
|
||||
* @since 2021/07/22
|
||||
*/
|
||||
class Utils
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief initSysRootPath, 根据应用程序路径推断系统根目录
|
||||
* @param qsAppPath,应用程序所在路径
|
||||
*/
|
||||
static void initSysRootPath(const QString& qsAppPath);
|
||||
|
||||
/**
|
||||
* @brief getSysRootPath,获取正式系统根目录
|
||||
* @return const QString&,系统根目录
|
||||
* @note
|
||||
* 调用此函数前,需要调用初始化系统根目录函数initSysRootPath;否则,返回默认目录“/”
|
||||
*/
|
||||
static const QString& getSysRootPath() { return m_sysRootPath; }
|
||||
|
||||
/**
|
||||
* @brief customMessageHandler,日志重定向句柄
|
||||
* @param type 日志类型,debug等
|
||||
* @param context 上下文
|
||||
* @param msg 日志信息
|
||||
*/
|
||||
static void customMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||
|
||||
/**
|
||||
* @brief 文件锁,锁定应用程序
|
||||
* @param frontUid,锁定程序的用户id
|
||||
* @return 锁文件的句柄
|
||||
*/
|
||||
static int lockProgram(int frontUid);
|
||||
|
||||
/**
|
||||
* @brief 解除应用程序文件锁
|
||||
* @param lock_file_fd 锁文件的文件描述符
|
||||
* @return 0,解除成功;1,解除失败
|
||||
*/
|
||||
static int unLockProgram(int lock_file_fd);
|
||||
|
||||
/**
|
||||
* @brief 删除锁文件
|
||||
* @return bool
|
||||
*/
|
||||
static bool rmLockFile();
|
||||
|
||||
/**
|
||||
* @brief 检查/etc/.bootinfo是否存在并可读,里面存放备份分区的UUID等信息
|
||||
* @return bool
|
||||
*/
|
||||
static bool checkBootInfoExists();
|
||||
|
||||
/**
|
||||
* @brief 是否有平板模式
|
||||
* @return bool
|
||||
*/
|
||||
static bool isTablet();
|
||||
|
||||
/**
|
||||
* @brief 获取备份分区的UUID
|
||||
* @return 备份分区的UUID
|
||||
*/
|
||||
static QString getBackupPartitionUuid();
|
||||
|
||||
/**
|
||||
* @brief 获取分区对应的UUID映射关系
|
||||
* @param fstab文件路径
|
||||
* @return “分区挂载目录-分区UUID”键值对
|
||||
*/
|
||||
static QHash<QString, QString> getPartUuidMap(const QString &fstab);
|
||||
|
||||
/**
|
||||
* @brief 路径不存在则创建,不支持递归创建
|
||||
* @param path
|
||||
*/
|
||||
static void mkdir(const QString& path);
|
||||
|
||||
/**
|
||||
* @brief 创建路径,支持递归创建
|
||||
* @param path
|
||||
* @return bool
|
||||
*/
|
||||
static bool mkpath(const QString& path);
|
||||
|
||||
/**
|
||||
* @brief 备份还原时,需要排除绑定挂载的路径,因为数据不是存放在挂载路径内
|
||||
* @param excludes,存放需要排除的绑定路径
|
||||
*/
|
||||
static void excludeFstabBindPath(QStringList &excludes);
|
||||
|
||||
/**
|
||||
* @brief 备份还原时,需要一些用户家目录下的路径,因为这些路径备份还原程序无权操作
|
||||
* @param excludes,存放需要排除的路径
|
||||
*/
|
||||
static void excludeSomeHomePath(QStringList &excludes);
|
||||
|
||||
/**
|
||||
* @brief 排除自定义备份路径
|
||||
* @param excludes,存放需要排除的路径
|
||||
*/
|
||||
static void excludeCustomizePath(QStringList &excludes);
|
||||
|
||||
/**
|
||||
* @brief 生成rsync --exclude-from排除路径规则文件
|
||||
* @return
|
||||
*/
|
||||
static bool generateExcludePathsFile();
|
||||
|
||||
/**
|
||||
* @brief 获取系统备份还原排除路径列表
|
||||
* @return 系统备份还原排除路径列表
|
||||
*/
|
||||
static QStringList getFromExcludePathsFile();
|
||||
|
||||
/**
|
||||
* @brief 判断目录是否存在
|
||||
* @param 目录路径
|
||||
* @return true,存在;false,不存在
|
||||
*/
|
||||
static bool isDirExist(const QString& fullDirName);
|
||||
|
||||
/**
|
||||
* @brief 生成Uuid
|
||||
* @return UUID
|
||||
*/
|
||||
static QString createUuid();
|
||||
|
||||
/**
|
||||
* @brief 将列表中内容写入指定文件中
|
||||
* @param fileName,文件全路径
|
||||
* @param lines,内容列表
|
||||
* @return true,成功写入;false,写入失败
|
||||
*/
|
||||
static bool writeFileByLines(const QString& fileName, const QStringList& lines);
|
||||
|
||||
/**
|
||||
* @brief 判断文件是否存在
|
||||
* @param fileName 文件明
|
||||
* @return bool,true-存在;false-不存在
|
||||
* @author zhaominyong
|
||||
* @since 2021/05/29
|
||||
*/
|
||||
static bool filsExists(const QString &fileName);
|
||||
|
||||
/**
|
||||
* @brief 判断目录是否为空
|
||||
* @param fullDirName 目录路径
|
||||
* @return true-目录不存在或为空目录; false-非空目录
|
||||
*/
|
||||
static bool isDirEmpty(const QString& fullDirName);
|
||||
|
||||
/**
|
||||
* @brief 记录备份日志
|
||||
* @param line,日志内容
|
||||
* @return bool, true-成功;false-失败
|
||||
* @author zhaominyong
|
||||
* @since 2021/05/29
|
||||
* @note
|
||||
* 因为系统恢复成功后马上需要reboot,但是此时的文件缓存可能还未能落盘,故此增加此函数,其中调用了系统函数fdatasync确保缓存落盘
|
||||
*/
|
||||
static bool writeBackupLog(QString line);
|
||||
|
||||
/**
|
||||
* @brief 立即写文件
|
||||
* @param fileName 文件名,包含路径
|
||||
* @param content 文件内容
|
||||
* @return bool
|
||||
*/
|
||||
static bool syncWriteFile(const QString &fileName, const QString& content);
|
||||
|
||||
/**
|
||||
* @brief 将字节大小转换为GB等表示的字符串
|
||||
* @param size,qint64,空间大小,单位字节
|
||||
* @return GB/MB/KB等表示的字符串型大小
|
||||
*/
|
||||
static QString StringBySize(qint64 size);
|
||||
|
||||
/**
|
||||
* @brief 获取挂接的移动设备列表
|
||||
* @return MOUNTPOINT,PATH键值对列表(path中如果含有空格时显示不对,建议不用此值)
|
||||
* @author zhaominyong
|
||||
* @since 2021/06/07
|
||||
* @note
|
||||
* for bug 59636 【cpm】【HUAWEI】【KOS】【L0】【V3试制】备份时选择移动设备,会出现一个dev/sdc的路径(一般+必现+不常用功能)
|
||||
* QStorageInfo::mountedVolumes获取的磁盘列表区分不出来是否移动设备
|
||||
*/
|
||||
static QHash<QString, QString> getRemovableStorages();
|
||||
|
||||
/**
|
||||
* @brief 获取挂接的计算机内部磁盘
|
||||
* @return 内部磁盘挂接路径列表
|
||||
*/
|
||||
static QList<QString> getLocalDisks();
|
||||
|
||||
/**
|
||||
* @brief 设置安全状态
|
||||
* @param enable——true,开启保护;false,关闭保护
|
||||
*/
|
||||
static void setKysecStatus(bool enable);
|
||||
|
||||
/**
|
||||
* @brief 启动或关闭kysec-sync-daemon服务
|
||||
* @param enable——true,开启;false,关闭
|
||||
*/
|
||||
static void setKysecDaemon(bool enable);
|
||||
|
||||
/**
|
||||
* @brief 判断程序是否已开启
|
||||
* @param processName
|
||||
* @return true-正在运行;false-未运行
|
||||
*/
|
||||
static bool isRunning(const QString &processName);
|
||||
|
||||
/**
|
||||
* @brief 判断是否990或9006C处理器
|
||||
* @return bool
|
||||
*/
|
||||
static bool isHuawei990();
|
||||
|
||||
/**
|
||||
* @brief popen()函数通过创建一个管道,调用fork()产生一个子进程,执行一个shell以运行命令来开启一个进程。
|
||||
* @param cmd,是一个指向以 NULL 结束的 shell 命令字符串的指针。这行命令将被传到 bin/sh 并使用 -c 标志,shell 将执行这个命令
|
||||
* @param result 输出结果
|
||||
* @note 不建议桌面应用调用,因为会依赖终端使得开机自启无法启动起来
|
||||
*/
|
||||
static void executeCMD(const char* cmd, QString &result);
|
||||
static QString executeCmd(const QString &cmd, const QStringList &args = QStringList());
|
||||
|
||||
/**
|
||||
* @brief 获取备份日志列表
|
||||
* @return
|
||||
*/
|
||||
static QList<BackupWrapper> getBackupLogList();
|
||||
|
||||
/**
|
||||
* @brief 初始化系统信息
|
||||
*/
|
||||
static void initSystemInfo();
|
||||
|
||||
/**
|
||||
* @brief getOs
|
||||
* @return 操作系统名字, 如:
|
||||
* Kylin-Desktop V10-SP1
|
||||
* Build 20210407
|
||||
*/
|
||||
static QString getOs();
|
||||
|
||||
/**
|
||||
* @brief getArch
|
||||
* @return 架构,arch命令的结果,如:x86_64
|
||||
*/
|
||||
static QString getArch();
|
||||
|
||||
/**
|
||||
* @brief getArchDetect
|
||||
* @return archdetect命令的结果,如:amd64/efi
|
||||
*/
|
||||
static QString getArchDetect();
|
||||
|
||||
/**
|
||||
* @brief 获取分区剩余大小
|
||||
* @return
|
||||
*/
|
||||
static QHash<QString, QString> getLeftSizeOfPartitions();
|
||||
|
||||
/**
|
||||
* @brief 获取分区可用大小,主要是/和/data分区
|
||||
* @return 路径和大小(单位:字节)键值对
|
||||
*/
|
||||
static QHash<QString, qint64> getAvailableSizeOfPartitions();
|
||||
|
||||
/**
|
||||
* @brief 获取文件夹或文件的大小
|
||||
* @param path 路径
|
||||
* @return 大小
|
||||
*/
|
||||
static qint64 getDirOrFileSize(const QString &path);
|
||||
|
||||
/**
|
||||
* @brief 记录下备份点uuid及其名称
|
||||
* @param uuid
|
||||
* @param backupName
|
||||
*/
|
||||
static void update_backup_unique_settings(const QString &uuid, const QString &backupName);
|
||||
|
||||
/**
|
||||
* @brief 根据备份点名称,删除备份点uuid记录
|
||||
* @param backupName 备份点名称
|
||||
*/
|
||||
static void deleteBackupUniqueRecord(const QString& backupName);
|
||||
|
||||
/**
|
||||
* @brief 获取备份点Uuid-BackupName键值对
|
||||
* @return Uuid-BackupName键值对
|
||||
*/
|
||||
static QMap<QString, QString> getBackupUuidNameMap();
|
||||
|
||||
/**
|
||||
* @brief 前后两次调用,然后取文件修改时间用于判断缓存数据是否落盘
|
||||
* @return
|
||||
*/
|
||||
static bool updateSyncFile();
|
||||
|
||||
/**
|
||||
* @brief 用事件循环替换sleep,以便事件尽量得到处理
|
||||
* @param sec,等待时间,单位秒
|
||||
* @author zhaominyong
|
||||
* @since 2021/05/29
|
||||
*/
|
||||
static void wait(uint sec);
|
||||
|
||||
private:
|
||||
// 系统根目录,默认"/"
|
||||
static QString m_sysRootPath;
|
||||
};
|
||||
|
||||
#endif // UTILS_H
|
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 87 KiB |