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

605 lines
19 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

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

#include "udisksystembackupproxy.h"
#include <QStorageInfo>
#include <QDateTime>
#include <QDebug>
#include <QTimer>
#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));
qDebug() << "UDiskSystemBackupProxy::backup 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 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;
}