去掉备份分区依赖

This commit is contained in:
zhaominyong 2022-04-19 16:13:38 +08:00
parent 16327ed35e
commit 63b47630e1
14 changed files with 807 additions and 16 deletions

View File

@ -31,6 +31,7 @@ HEADERS += \
../common/spinlock_mutex.h \ ../common/spinlock_mutex.h \
../common/utils.h \ ../common/utils.h \
backupmanager_adaptor.h \ backupmanager_adaptor.h \
customizesystembackupproxy.h \
databackupproxy.h \ databackupproxy.h \
datarestoreproxy.h \ datarestoreproxy.h \
deletebackupproxy.h \ deletebackupproxy.h \
@ -59,6 +60,7 @@ SOURCES += \
../common/reflect.cpp \ ../common/reflect.cpp \
../common/utils.cpp \ ../common/utils.cpp \
backupmanager_adaptor.cpp \ backupmanager_adaptor.cpp \
customizesystembackupproxy.cpp \
databackupproxy.cpp \ databackupproxy.cpp \
datarestoreproxy.cpp \ datarestoreproxy.cpp \
deletebackupproxy.cpp \ deletebackupproxy.cpp \

View File

@ -0,0 +1,556 @@
#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;
m_isForce = false;
connect(this, &CustomizeSystemBackupProxy::cancel, this, &CustomizeSystemBackupProxy::cancelEx);
}
CustomizeSystemBackupProxy::~CustomizeSystemBackupProxy()
{
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 CustomizeSystemBackupProxy::checkEnvEx()
{
qDebug() << "CustomizeSystemBackupProxy::checkEnv invoke begin";
// 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备都得保证/backup挂载上); 若没挂载,挂载
MyMountProxy mountProxy;
if ( MountResult::MOUNTED != mountProxy.mountBackupPartition() ) {
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();
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, &CustomizeSystemBackupProxy::checkDestDirExists);
// 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 = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH;
xmlPath.replace("//", "/");
ParseBackupList parse(xmlPath);
parse.deleteItem(m_curUuid);
}
/**
* @brief
* @return true, false
*/
bool CustomizeSystemBackupProxy::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 CustomizeSystemBackupProxy::checkFreeCapacity(qint64 itotalSize)
{
qDebug() << "CustomizeSystemBackupProxy::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));
} 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() << "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::SYSTEM_BACKUP :
args << "-avAHXr";
args << "--info=progress2";
args << "--no-inc-recursive";
args << "--ignore-missing-args";
break ;
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;
}
args << "-e" << m_imgPath;
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 ;
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(CustomizeSystemBackupScene::MKSQUASHFS));
if (m_mksquashfs->start(args)) {
emit checkResult(int(BackupResult::MKSQUASHFS_START_SUCCESS));
} else {
emit checkResult(int(BackupResult::MKSQUASHFS_DO_FAIL));
}
qDebug() << "CustomizeSystemBackupProxy::doMksqushfs invoke end";
}
/**
* @brief
*/
void CustomizeSystemBackupProxy::doBackup()
{
qDebug() << "CustomizeSystemBackupProxy::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() << "CustomizeSystemBackupProxy::doBackup 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;
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 truefalse
*/
bool CustomizeSystemBackupProxy::backupSystem()
{
qDebug() << "CustomizeSystemBackupProxy::backupSystem invoke begin";
// 全量备份场景
QStringList args = getRsyncArgs(CustomizeSystemBackupScene::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 truefalse
*/
bool CustomizeSystemBackupProxy::backupImg()
{
qDebug() << "CustomizeSystemBackupProxy::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 truefalse
*/
bool CustomizeSystemBackupProxy::backup(const QStringList &args)
{
qDebug() << "CustomizeSystemBackupProxy::backup invoke begin";
emit checkResult(int(BackupResult::BACKUP_START_SUCCESS));
do_kylin_security(m_destPath);
qDebug() << "CustomizeSystemBackupProxy::backup invoke end";
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();
}
}
/**
* @brief
* @return: bool,truefalse
* @author: zhaominyong
* @since: 2021/05/24
* @note:
* add by zhaominyong at 2021/05/24 for bug:54377 U盘的过程中拔出U盘
*/
bool CustomizeSystemBackupProxy::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();
// 10s钟后如果还没有退出则强制退出
QTimer::singleShot(10*1000, this, &CustomizeSystemBackupProxy::checkDestDirExists);
} else {
QTimer::singleShot(1*1000, this, &CustomizeSystemBackupProxy::checkDestDirExists);
}
}
return true;
}

View File

@ -1,4 +1,118 @@
#ifndef CUSTOMIZESYSTEMBACKUPPROXY_H #ifndef CUSTOMIZESYSTEMBACKUPPROXY_H
#define 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 {
SYSTEM_BACKUP, // 系统备份
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();
// 备份
void doBackup();
// 任务取消
virtual void cancelEx();
/**
* @brief
* @return: bool,truefalse
* @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(CustomizeSystemBackupScene 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;
// 当前备份节点
ParseBackupList::BackupPoint m_backupPoint;
// 是否只是检测
bool m_isOnlyCheck;
// img文件存放路径
QString m_imgPath;
// 强制结束标志(stop后没反应的情况系统处于睡眠状态)
bool m_isForce;
};
#endif // CUSTOMIZESYSTEMBACKUPPROXY_H #endif // CUSTOMIZESYSTEMBACKUPPROXY_H

View File

@ -25,7 +25,7 @@ public:
QString m_backupName; QString m_backupName;
// 备份时间 // 备份时间
QString m_time; QString m_time;
// 本地备份还是U盘备份: 0-本地备份1-移动设备备份2-异机备份(仅用于业务场景标记,不用于持久化记录) // 本地备份还是U盘备份: 0-本地备份1-移动设备备份2-异机备份(仅用于业务场景标记,不用于持久化记录)3-自定义路径备份
int m_iPosition = -1; int m_iPosition = -1;
// 操作类型,如:系统备份, 系统还原 // 操作类型,如:系统备份, 系统还原
int m_type = -1; int m_type = -1;

View File

@ -1,6 +1,5 @@
#include "udisksystembackupproxy.h" #include "udisksystembackupproxy.h"
#include "systembackupproxy.h"
#include <QStorageInfo> #include <QStorageInfo>
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>

View File

@ -54,6 +54,8 @@ Worker * WorkerFactory::createWorker(int type, int position)
case BackupType::INC_BACKUP_SYSTEM: case BackupType::INC_BACKUP_SYSTEM:
if (BackupPosition::UDISK == position) { if (BackupPosition::UDISK == position) {
className = "UDiskSystemBackupProxy"; className = "UDiskSystemBackupProxy";
} else if (BackupPosition::CUSTOMIZE == position) {
className = "CustomizeSystemBackupProxy";
} else { } else {
className = "SystemBackupProxy"; className = "SystemBackupProxy";
} }
@ -62,6 +64,8 @@ Worker * WorkerFactory::createWorker(int type, int position)
case BackupType::RESTORE_SYSTEM_WITH_DATA: case BackupType::RESTORE_SYSTEM_WITH_DATA:
if (BackupPosition::UDISK == position) { if (BackupPosition::UDISK == position) {
className = "UDiskSystemRestoreProxy"; className = "UDiskSystemRestoreProxy";
} else if (BackupPosition::CUSTOMIZE == position) {
className = "CustomizeSystemRestoreProxy";
} else { } else {
className = "SystemRestoreProxy"; className = "SystemRestoreProxy";
} }
@ -70,6 +74,8 @@ Worker * WorkerFactory::createWorker(int type, int position)
case BackupType::INC_BACKUP_DATA: case BackupType::INC_BACKUP_DATA:
if (BackupPosition::UDISK == position) { if (BackupPosition::UDISK == position) {
className = "UDiskDataBackupProxy"; className = "UDiskDataBackupProxy";
} else if (BackupPosition::CUSTOMIZE == position) {
className = "CustomizeDataBackupProxy";
} else { } else {
className = "DataBackupProxy"; className = "DataBackupProxy";
} }
@ -77,6 +83,8 @@ Worker * WorkerFactory::createWorker(int type, int position)
case BackupType::RESTORE_DATA: case BackupType::RESTORE_DATA:
if (BackupPosition::UDISK == position) { if (BackupPosition::UDISK == position) {
className = "UDiskDataRestoreProxy"; className = "UDiskDataRestoreProxy";
} else if (BackupPosition::CUSTOMIZE == position) {
className = "CustomizeDataRestoreProxy";
} else { } else {
className = "DataRestoreProxy"; className = "DataRestoreProxy";
} }
@ -87,6 +95,8 @@ Worker * WorkerFactory::createWorker(int type, int position)
case BackupType::GHOST_IMAGE: case BackupType::GHOST_IMAGE:
if (BackupPosition::UDISK == position) { if (BackupPosition::UDISK == position) {
className = "UDiskGhostImageProxy"; className = "UDiskGhostImageProxy";
} else if (BackupPosition::CUSTOMIZE == position) {
className = "CustomizeGhostImageProxy";
} else { } else {
className = "GhostImageProxy"; className = "GhostImageProxy";
} }

View File

@ -90,7 +90,7 @@ enum BackupType {
struct BackupWrapper { struct BackupWrapper {
// 操作类型,如:系统备份, 系统还原 // 操作类型,如:系统备份, 系统还原
int m_type = -1; int m_type = -1;
// 本地备份还是U盘备份: 0-本地备份1-移动设备备份 // 本地备份还是U盘备份: 0-本地备份1-移动设备备份;2-异机备份3-自定义路径
int m_iPosition = -1; int m_iPosition = -1;
// 备份名称,用于识别备份的,默认是时间 // 备份名称,用于识别备份的,默认是时间
QString m_comment; QString m_comment;
@ -163,7 +163,8 @@ enum BackupPosition
{ {
LOCAL, // 本地磁盘 LOCAL, // 本地磁盘
UDISK, // 移动设备 UDISK, // 移动设备
OTHER // 移动设备中的其它机器的备份点 OTHER, // 移动设备中的其它机器的备份点
CUSTOMIZE, // 自定义路径
}; };
/** /**

View File

@ -457,6 +457,7 @@ bool Utils::generateExcludePathsFile()
in << "/var/lib/kmre" << END_LINE; in << "/var/lib/kmre" << END_LINE;
in << "/var/lib/udisks2" << END_LINE; in << "/var/lib/udisks2" << END_LINE;
in << "/var/log" << END_LINE; in << "/var/log" << END_LINE;
in << "*/backup/snapshots" << END_LINE;
// 系统安装后有的会将/data/home /data/root挂载到的/home /root上实际文件是存放在/data/home /data/root下面为了统一标准保留/home /root排除/data/home /data/root // 系统安装后有的会将/data/home /data/root挂载到的/home /root上实际文件是存放在/data/home /data/root下面为了统一标准保留/home /root排除/data/home /data/root
QStringList excludes; QStringList excludes;
@ -511,6 +512,7 @@ QStringList Utils::getFromExcludePathsFile()
list << "/var/lib/kmre"; list << "/var/lib/kmre";
list << "/var/lib/udisks2"; list << "/var/lib/udisks2";
list << "/var/log"; list << "/var/log";
list << "*/backup/snapshots";
// 系统安装后有的会将/data/home /data/root挂载到的/home /root上实际文件是存放在/data/home /data/root下面 // 系统安装后有的会将/data/home /data/root挂载到的/home /root上实际文件是存放在/data/home /data/root下面
QStringList excludes; QStringList excludes;

View File

@ -0,0 +1,40 @@
#include "filefilterproxymodelforbackup.h"
#include <QFileSystemModel>
#include "../../common/mydefine.h"
FileFilterProxyModeForBackup::FileFilterProxyModeForBackup(QObject *parent) :
QSortFilterProxyModel(parent)
{}
FileFilterProxyModeForBackup::~FileFilterProxyModeForBackup()
{}
bool FileFilterProxyModeForBackup::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
QFileSystemModel* fileModel = qobject_cast<QFileSystemModel*>(sourceModel());
if (fileModel != nullptr && fileModel->isDir(index0)) {
QString fileName = fileModel->fileName(index0);
// 防命令注入
// 1、形如mkdir '`id&>id_bak_test.txt`'中的文件夹名称
if (fileName.contains(QRegularExpression(".*`.*`.*")))
return false;
// 2、形如$()的文件夹名称
if (fileName.contains(QRegularExpression(".*\\$\\(.*\\).*")))
return false;
// 3、形如${}的文件夹名称
if (fileName.contains(QRegularExpression(".*\\$\\{.*\\}.*")))
return false;
// 4、包含[;、&、|]等可以包含并执行系统命令或用于连续执行系统命令的符号
if (fileName.contains(QRegularExpression("[;&|]+")))
return false;
QString filePath = fileModel->filePath(index0);
return !(filePath.endsWith(BACKUP_SNAPSHOTS_PATH) || filePath == BACKUP_PATH);
} else {
return false;
}
}

View File

@ -1,4 +1,17 @@
#ifndef FILEFILTERPROXYMODELFORBACKUP_H #ifndef FILEFILTERPROXYMODELFORBACKUP_H
#define FILEFILTERPROXYMODELFORBACKUP_H #define FILEFILTERPROXYMODELFORBACKUP_H
#include <QSortFilterProxyModel>
class FileFilterProxyModeForBackup : public QSortFilterProxyModel
{
Q_OBJECT
public:
FileFilterProxyModeForBackup(QObject *parent = nullptr);
~FileFilterProxyModeForBackup();
protected:
virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
};
#endif // FILEFILTERPROXYMODELFORBACKUP_H #endif // FILEFILTERPROXYMODELFORBACKUP_H

View File

@ -1,6 +1,7 @@
#include "myfileselect.h" #include "myfileselect.h"
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QLineEdit> #include <QLineEdit>
#include "filefilterproxymodelforbackup.h"
MyFileSelect::MyFileSelect(QWidget* parent) : MyFileSelect::MyFileSelect(QWidget* parent) :
QFileDialog(parent) QFileDialog(parent)
@ -9,6 +10,9 @@ MyFileSelect::MyFileSelect(QWidget* parent) :
this->setFileMode(QFileDialog::ExistingFiles); this->setFileMode(QFileDialog::ExistingFiles);
this->setFilter(QDir::System | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); this->setFilter(QDir::System | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
FileFilterProxyModeForBackup *proxy = new FileFilterProxyModeForBackup;
this->setProxyModel(proxy);
QDialogButtonBox* button = this->findChild<QDialogButtonBox*>("buttonBox"); QDialogButtonBox* button = this->findChild<QDialogButtonBox*>("buttonBox");
disconnect(button, SIGNAL(accepted()), this, SLOT(accept())); disconnect(button, SIGNAL(accepted()), this, SLOT(accept()));
connect(button, SIGNAL(accepted()), this, SLOT(goAccept())); connect(button, SIGNAL(accepted()), this, SLOT(goAccept()));

View File

@ -41,6 +41,7 @@ HEADERS += \
component/backuplistwidget.h \ component/backuplistwidget.h \
component/circlelabel.h \ component/circlelabel.h \
component/clicklabel.h \ component/clicklabel.h \
component/filefilterproxymodelforbackup.h \
component/hoverwidget.h \ component/hoverwidget.h \
component/imageutil.h \ component/imageutil.h \
component/linelabel.h \ component/linelabel.h \
@ -88,6 +89,7 @@ SOURCES += \
component/backuplistwidget.cpp \ component/backuplistwidget.cpp \
component/circlelabel.cpp \ component/circlelabel.cpp \
component/clicklabel.cpp \ component/clicklabel.cpp \
component/filefilterproxymodelforbackup.cpp \
component/hoverwidget.cpp \ component/hoverwidget.cpp \
component/imageutil.cpp \ component/imageutil.cpp \
component/linelabel.cpp \ component/linelabel.cpp \

View File

@ -288,13 +288,12 @@ void MainDialog::mountBackupPartition()
exit(1); exit(1);
} else if (int(MountResult::CANNOT_GET_BACKUPUUID) == reply.value()) { } else if (int(MountResult::CANNOT_GET_BACKUPUUID) == reply.value()) {
// 没有找到备份分区,只能备份到移动设备中 // 没有找到备份分区,只能备份到移动设备中
MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Information"), // MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Information"),
QObject::tr("Please check if the backup partition exists which can be created when you install the Operating System."), // QObject::tr("Please check if the backup partition exists which can be created when you install the Operating System."),
QObject::tr("Ok")); // QObject::tr("Ok"));
// // 此时还未进入应用的事件循环中故不能使用qApp->quit();
// GlobelBackupInfo::inst().setHasBackupPartition(false); // exit(1);
// 此时还未进入应用的事件循环中故不能使用qApp->quit(); GlobelBackupInfo::inst().setHasBackupPartition(false);
exit(1);
} else if (int(MountResult::MOUNTED) != reply.value()) { } else if (int(MountResult::MOUNTED) != reply.value()) {
// 挂载备份分区失败 // 挂载备份分区失败
MessageBoxUtils::QMESSAGE_BOX_CRITICAL(this, QObject::tr("Warning"), MessageBoxUtils::QMESSAGE_BOX_CRITICAL(this, QObject::tr("Warning"),

View File

@ -5,10 +5,13 @@
#include <QMovie> #include <QMovie>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QFileDialog>
#include <QtGlobal>
#include <unistd.h> #include <unistd.h>
#include "../component/clicklabel.h" #include "../component/clicklabel.h"
#include "../component/circlelabel.h" #include "../component/circlelabel.h"
#include "../component/filefilterproxymodelforbackup.h"
#include "../component/myiconlabel.h" #include "../component/myiconlabel.h"
#include "../component/mylabel.h" #include "../component/mylabel.h"
#include "../component/mylineedit.h" #include "../component/mylineedit.h"
@ -246,8 +249,49 @@ void SystemBackup::initSecondWidget()
comboSelect->addItem(iconFolder, qsPreDevPath + disk.rootPath() + BACKUP_SNAPSHOTS_PATH); comboSelect->addItem(iconFolder, qsPreDevPath + disk.rootPath() + BACKUP_SNAPSHOTS_PATH);
} }
}); });
connect(comboSelect, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=]() {
this->m_prefixDestPath = "";
});
m_udector->getStorageInfo(); m_udector->getStorageInfo();
QPushButton *buttonBrowse = new QPushButton;
buttonBrowse->setText(tr("Browse..."));
connect(buttonBrowse, &QPushButton::clicked, this, [=](){
// 是否自定义路径?自定义路径备份文件不受保护,可能导致备份文件丢失或损坏
if (!MessageBoxUtils::QMESSAGE_BOX_WARNING_CANCEL(this, QObject::tr("Information"),
QObject::tr("Are you sure to continue customizing the path\n"
"The custom path backup file is not protected, which may cause the backup file to be lost or damaged"),
QObject::tr("Ok"), QObject::tr("Cancel")))
{
return ;
}
QFileDialog fileDialog(this);
fileDialog.setWindowTitle(tr("Please select a path"));
fileDialog.setViewMode(QFileDialog::List);
fileDialog.setFileMode(QFileDialog::DirectoryOnly);
fileDialog.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
QList<QUrl> siderUrls;
siderUrls << QUrl::fromLocalFile(Utils::getSysRootPath());
siderUrls << QUrl::fromLocalFile(Utils::getSysRootPath() + "/data");
fileDialog.setSidebarUrls(siderUrls);
FileFilterProxyModeForBackup *proxy = new FileFilterProxyModeForBackup;
fileDialog.setProxyModel(proxy);
if (fileDialog.exec() == QDialog::Accepted) {
QStringList selectFiles = fileDialog.selectedFiles();
if (!selectFiles.isEmpty()) {
comboSelect->setCurrentIndex(-1);
QString fileName = selectFiles.at(0);
this->m_prefixDestPath = fileName;
QLineEdit * edit = new QLineEdit;
comboSelect->setLineEdit(edit);
edit->setText(tr("customize path : ") + fileName + BACKUP_SNAPSHOTS_PATH);
edit->setReadOnly(true);
}
}
});
hlayoutLine2->addWidget(comboSelect); hlayoutLine2->addWidget(comboSelect);
hlayoutLine2->addWidget(buttonBrowse);
hlayoutLine2->addSpacing(40); hlayoutLine2->addSpacing(40);
vlayout->addLayout(hlayoutLine2); vlayout->addLayout(hlayoutLine2);
vlayout->addSpacing(30); vlayout->addSpacing(30);
@ -272,9 +316,14 @@ void SystemBackup::initSecondWidget()
connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) { connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) {
// 备份路径选择索引 // 备份路径选择索引
int index = comboSelect->currentIndex(); int index = comboSelect->currentIndex();
// 第一个选项是本地系统备份 if (index >= 0) {
this->m_isLocal = GlobelBackupInfo::inst().hasBackupPartition() && (index == 0); // 第一个选项是本地系统备份
this->m_prefixDestPath = this->m_udiskPaths.at(index); this->m_isLocal = GlobelBackupInfo::inst().hasBackupPartition() && (index == 0);
this->m_prefixDestPath = this->m_udiskPaths.at(index);
} else {
// 自定义备份位置的场景
this->m_isLocal = true;
}
this->on_next_clicked(checked); this->on_next_clicked(checked);
emit this->startCheckEnv(); emit this->startCheckEnv();
}); });
@ -561,7 +610,7 @@ void SystemBackup::on_checkEnv_start()
BackupWrapper backupWrapper; BackupWrapper backupWrapper;
backupWrapper.m_backupName = m_backupName; backupWrapper.m_backupName = m_backupName;
backupWrapper.m_type = BackupType::BACKUP_SYSTEM; backupWrapper.m_type = BackupType::BACKUP_SYSTEM;
backupWrapper.m_iPosition = m_isLocal ? BackupPosition::LOCAL : BackupPosition::UDISK; backupWrapper.m_iPosition = m_isLocal ? (this->m_prefixDestPath.isEmpty() ? BackupPosition::LOCAL : BackupPosition::CUSTOMIZE) : BackupPosition::UDISK;
QString backupPath = Utils::getSysRootPath(); QString backupPath = Utils::getSysRootPath();
backupPath += "/"; backupPath += "/";
backupPath.replace("//", "/"); backupPath.replace("//", "/");
@ -1062,7 +1111,7 @@ void SystemBackup::on_backup_start()
BackupWrapper backupWrapper; BackupWrapper backupWrapper;
backupWrapper.m_backupName = m_backupName; backupWrapper.m_backupName = m_backupName;
backupWrapper.m_type = BackupType::BACKUP_SYSTEM; backupWrapper.m_type = BackupType::BACKUP_SYSTEM;
backupWrapper.m_iPosition = m_isLocal ? BackupPosition::LOCAL : BackupPosition::UDISK; backupWrapper.m_iPosition = m_isLocal ? (this->m_prefixDestPath.isEmpty() ? BackupPosition::LOCAL : BackupPosition::CUSTOMIZE) : BackupPosition::UDISK;
QString backupPath = Utils::getSysRootPath(); QString backupPath = Utils::getSysRootPath();
backupPath += "/"; backupPath += "/";
backupPath.replace("//", "/"); backupPath.replace("//", "/");