From c1e7f440bd0ee3e860a0e55706a70aa3398ecf5a Mon Sep 17 00:00:00 2001 From: zhaominyong Date: Sat, 11 Dec 2021 09:49:09 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=B6=E6=AE=B5=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backup-daemon/backup-daemon.pro | 2 + backup-daemon/main.cpp | 36 -- .../myprocess/mountbackupprocess.cpp | 51 +- backup-daemon/myprocess/mountbackupprocess.h | 4 + backup-daemon/systemrestoreproxy.cpp | 19 +- backup-daemon/systemrestoreproxy.h | 2 + backup-daemon/udisksystemrestoreproxy.cpp | 418 ++++++++++++++++ backup-daemon/udisksystemrestoreproxy.h | 76 +++ common/mydefine.cpp | 4 +- kybackup/component/ringsprogressbar.cpp | 5 +- kybackup/module/selectrestorepoint.cpp | 2 +- kybackup/module/systembackup.cpp | 1 + kybackup/module/systemrestore.cpp | 471 ++++++++++++++++-- kybackup/module/systemrestore.h | 14 +- 14 files changed, 1019 insertions(+), 86 deletions(-) create mode 100644 backup-daemon/udisksystemrestoreproxy.cpp create mode 100644 backup-daemon/udisksystemrestoreproxy.h diff --git a/backup-daemon/backup-daemon.pro b/backup-daemon/backup-daemon.pro index 88d7f0f..fc25d4e 100755 --- a/backup-daemon/backup-daemon.pro +++ b/backup-daemon/backup-daemon.pro @@ -43,6 +43,7 @@ HEADERS += \ systembackupproxy.h \ systemrestoreproxy.h \ udisksystembackupproxy.h \ + udisksystemrestoreproxy.h \ workerfactory.h SOURCES += \ @@ -65,6 +66,7 @@ SOURCES += \ systembackupproxy.cpp \ systemrestoreproxy.cpp \ udisksystembackupproxy.cpp \ + udisksystemrestoreproxy.cpp \ workerfactory.cpp # Default rules for deployment. diff --git a/backup-daemon/main.cpp b/backup-daemon/main.cpp index bf30a89..d1e0d8a 100755 --- a/backup-daemon/main.cpp +++ b/backup-daemon/main.cpp @@ -4,24 +4,6 @@ #include "../common/mydefine.h" #include "backupmanager_adaptor.h" -// test begin -#include -#include "../common/reflect.h" -#include "mymountproxy.h" -#include "parsebackuplist.h" - -void testXml() -{ - ParseBackupList parse("/backup/snapshots/backuplist.xml"); -} - -void testLog() -{ - Utils::getBackupLogList(); -} - -// test end - int main(int argc, char *argv[]) { // 以防客户端传入的参数中的中文信息乱码 @@ -37,24 +19,6 @@ int main(int argc, char *argv[]) qInstallMessageHandler(Utils::customMessageHandler); Utils::initSystemInfo(); - // test begin - qDebug() << QString("测试 begin"); - -// MyMountProxy * proxy = (MyMountProxy*)Reflect::createObject("MyMountProxy"); -// proxy->mountBackupPartition(); - -// BackupWrapper backupWrapper; -// backupWrapper.m_backupName = "赵民勇test"; -// backupWrapper.m_backupPaths << "/"; -// backupWrapper.m_backupExcludePaths = Utils::getFromExcludePathsFile(); -// MyBackupManager manager; -// manager.goBackup(backupWrapper); - - testLog(); - - qDebug() << QString("测试 end"); - // test end - MyBackupManager* backup_deamon = new MyBackupManager; new ManagerAdaptor(backup_deamon); QDBusConnection conn = QDBusConnection::systemBus(); diff --git a/backup-daemon/myprocess/mountbackupprocess.cpp b/backup-daemon/myprocess/mountbackupprocess.cpp index 3733e8a..dfe588d 100755 --- a/backup-daemon/myprocess/mountbackupprocess.cpp +++ b/backup-daemon/myprocess/mountbackupprocess.cpp @@ -35,12 +35,12 @@ bool MountBackupProcess::Do(const QString& diskUuid) m_p->start("mount", arguments); if (!m_p->waitForStarted()) { - qFatal("mount rw /backup process start failed!"); + qCritical("mount rw /backup process start failed!"); return false; } if (!m_p->waitForFinished()) { - qFatal("mount rw backup process end failed!"); + qCritical("mount rw backup process end failed!"); return false; } @@ -53,12 +53,55 @@ bool MountBackupProcess::umountBackupPartition() arguments << QString("/backup"); m_p->start("umount", arguments); if (!m_p->waitForStarted()) { - qFatal("mount ro backup process start failed!"); + qCritical("mount ro backup process start failed!"); return false; } if (!m_p->waitForFinished()) { - qFatal("mount ro backup process end failed!"); + qCritical("mount ro backup process end failed!"); + return false; + } + + return true; +} + +/** + * @brief 卸载目录挂载 + * @param mountPath,挂载的目录 + * @return + */ +bool MountBackupProcess::umount(const QString& mountPath) +{ + if (0 == ::umount(mountPath.toUtf8().data())) + return true; + + qCritical() << QString("%1 umount failed, error is %2(%3)").arg(mountPath).arg(strerror(errno)).arg(QString::number(errno)); + + return false; +} + +/** + * @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; } diff --git a/backup-daemon/myprocess/mountbackupprocess.h b/backup-daemon/myprocess/mountbackupprocess.h index fc89bbb..82afbe0 100755 --- a/backup-daemon/myprocess/mountbackupprocess.h +++ b/backup-daemon/myprocess/mountbackupprocess.h @@ -2,6 +2,7 @@ #define MOUNTBACKUPPROCESS_H #include +#include class MountBackupProcess : public QObject { Q_OBJECT @@ -12,6 +13,9 @@ public: bool umountBackupPartition(); + static bool umount(const QString& mountPath); + bool mount(const QString& source, const QString& target, const QString& options = ""); + private: QProcess* m_p; diff --git a/backup-daemon/systemrestoreproxy.cpp b/backup-daemon/systemrestoreproxy.cpp index 9433a67..b3c4e03 100644 --- a/backup-daemon/systemrestoreproxy.cpp +++ b/backup-daemon/systemrestoreproxy.cpp @@ -146,6 +146,20 @@ void SystemRestoreProxy::remountEfi() 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 */ @@ -292,6 +306,9 @@ void SystemRestoreProxy::restoreSystem() 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) { @@ -316,7 +333,7 @@ void SystemRestoreProxy::restoreSystem() QFileInfo file(fileIfSync); QDateTime beginTime = file.fileTime(QFileDevice::FileModificationTime); if (Utils::isHuawei990() && FACTORY_BACKUP_UUID == m_curUuid && m_backupWrapper.m_type == BackupType::RESTORE_SYSTEM) { - // 出厂还原有的机器上删除/home/xxx有残留,故在此再强制删除一下,妈的sudo rm -rf命令一遍还删除不了(报错:无法删除/home/xx/.config:目录非空,应该是删除后又自动生成了),多删除几次还不是非常干净,贱 ^_^ + // 出厂还原有的机器上删除/home/xxx有残留,故在此再强制删除一下,sudo rm -rf命令一遍还删除不了(报错:无法删除/home/xx/.config:目录非空,应该是删除后又自动生成了),多删除几次还不是非常干净,^_^ removeHome(Utils::getSysRootPath() + "/home"); removeHome(Utils::getSysRootPath() + "/data/home"); } diff --git a/backup-daemon/systemrestoreproxy.h b/backup-daemon/systemrestoreproxy.h index dba4dd5..68a3b33 100644 --- a/backup-daemon/systemrestoreproxy.h +++ b/backup-daemon/systemrestoreproxy.h @@ -34,6 +34,8 @@ private: void repairEfi(); // 以读写方式重新挂载efi分区 void remountEfi(); + // 以读写方式重新挂载boot分区 + void remountBoot(); // 同步efi bool rsyncEfi(); // 系统还原 diff --git a/backup-daemon/udisksystemrestoreproxy.cpp b/backup-daemon/udisksystemrestoreproxy.cpp new file mode 100644 index 0000000..8f6b07c --- /dev/null +++ b/backup-daemon/udisksystemrestoreproxy.cpp @@ -0,0 +1,418 @@ +#include "udisksystemrestoreproxy.h" +#include +#include +#include +#include +#include +#include +#include "../common/utils.h" +#include "mymountproxy.h" +#include "myprocess/mksquashfsprocess.h" + +IMPLEMENT_DYNCREATE(UDiskSystemRestoreProxy) + +/** + * @brief 构造函数 + */ +UDiskSystemRestoreProxy::UDiskSystemRestoreProxy() +{ + m_isFinished = false; + m_p = nullptr; +} + +/** + * @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; + } + + 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); + } +} + +/** + * @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::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); + 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 还原前准备 + * @return + */ +bool UDiskSystemRestoreProxy::doPrepare() +{ + // 移动设备系统备份如果有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::umount(dstImgMountPath); + + // 3、将img文件挂载到/backup/imgbackup上 + MountBackupProcess *processMount = new MountBackupProcess; + if (processMount->mount(imgPath, dstImgMountPath)) { + emit checkResult(int(BackupResult::RESTOREDIR_PREPARE_FAILED)); + return false; + } + + m_srcPath = dstImgMountPath; + } else + m_srcPath = m_backupPath; + + // 以读写方式重新挂载boot分区,因为有的机器默认以只读挂载 + remountBoot(); + + return true; +} + +/** + * @brief 系统还原 + */ +void UDiskSystemRestoreProxy::restoreSystem() +{ + QString destPath = Utils::getSysRootPath(); + + QStringList args = getRsyncArgs(SystemRestoreScene::SYSTEM_RESTORE); + + args << m_srcPath + "/"; + args << destPath + "/"; + + m_p = new RsyncPathToDirProcess(this); + connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskSystemRestoreProxy::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::updateSyncFile(); + QString fileIfSync = Utils::getSysRootPath() + FILE_IF_SYNC; + fileIfSync.replace("//", "/"); + QFileInfo file(fileIfSync); + QDateTime beginTime = file.fileTime(QFileDevice::FileModificationTime); + Utils::wait(10); + 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(20); + updateGrubUUid(); + sync(); + Utils::wait(5); + } + + emit this->workResult(result); + Utils::wait(2); + reboot(RB_AUTOBOOT); + } + + if (Utils::isDirEmpty(m_backupPath)) + result = false; + emit this->workResult(result); + m_isFinished = true; + }); + + QTimer::singleShot(1*1000, this, &UDiskSystemRestoreProxy::checkUdiskExists); + m_isFinished = false; + m_p->start(args, false); +} + +/** + * @brief 异机还原时更新grub.cfg中的分区UUID + */ +void UDiskSystemRestoreProxy::updateGrubUUid() +{ + QString srcFstab = Utils::getSysRootPath() + BACKUP_IMGBACKUP_PATH; + srcFstab += FSTAB_PATH; + srcFstab.replace("//", "/"); + QHash srcPartToUuid = Utils::getPartUuidMap(srcFstab); + QString destFstab = Utils::getSysRootPath() + FSTAB_PATH; + QHash 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) { + if (Utils::isDirEmpty(m_backupPath) && m_p != nullptr) + m_p->stop(); + else + QTimer::singleShot(1*1000, this, &UDiskSystemRestoreProxy::checkUdiskExists); + } + + return true; +} + + diff --git a/backup-daemon/udisksystemrestoreproxy.h b/backup-daemon/udisksystemrestoreproxy.h new file mode 100644 index 0000000..edb2f97 --- /dev/null +++ b/backup-daemon/udisksystemrestoreproxy.h @@ -0,0 +1,76 @@ +#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 { + 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; +}; + +#endif // UDISKSYSTEMRESTOREPROXY_H diff --git a/common/mydefine.cpp b/common/mydefine.cpp index 8b36b52..406a451 100755 --- a/common/mydefine.cpp +++ b/common/mydefine.cpp @@ -8,7 +8,7 @@ QDBusArgument &operator<<(QDBusArgument &argument, const BackupWrapper &backupWr 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_gid << backupWrapper.m_isOtherMachine; argument.endStructure(); return argument; } @@ -20,7 +20,7 @@ const QDBusArgument &operator>>(const QDBusArgument &argument, BackupWrapper &ba 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_gid >> backupWrapper.m_isOtherMachine; argument.endStructure(); return argument; } diff --git a/kybackup/component/ringsprogressbar.cpp b/kybackup/component/ringsprogressbar.cpp index 587d848..632b331 100755 --- a/kybackup/component/ringsprogressbar.cpp +++ b/kybackup/component/ringsprogressbar.cpp @@ -31,8 +31,9 @@ void RingsProgressbar::paintEvent(QPaintEvent *) p.setBrush(QBrush(QColor(COLOR_BLUE))); //画圆弧 - pen.setCapStyle(Qt::RoundCap); - p.setPen(pen); + // pen.setCapStyle(Qt::RoundCap); + // pen.setColor(QColor(COLOR_BLUE)); + // p.setPen(pen); p.drawPie(QRectF(5 , 5, side - 10, side - 10), (90-m_rotateAngle)*16, m_rotateAngle*16); //画遮罩 diff --git a/kybackup/module/selectrestorepoint.cpp b/kybackup/module/selectrestorepoint.cpp index d6fe5ef..8b91d69 100644 --- a/kybackup/module/selectrestorepoint.cpp +++ b/kybackup/module/selectrestorepoint.cpp @@ -96,7 +96,7 @@ void SelectRestorePoint::insertLines(const QList & continue; //hide factory backup - if (backupPoint.m_uuid == FACTORY_BACKUP_UUID) + if (backupPoint.m_uuid == FACTORY_BACKUP_UUID && Utils::isHuawei990()) continue; //udisk unique diff --git a/kybackup/module/systembackup.cpp b/kybackup/module/systembackup.cpp index 551fdd0..c121b64 100755 --- a/kybackup/module/systembackup.cpp +++ b/kybackup/module/systembackup.cpp @@ -779,6 +779,7 @@ void SystemBackup::initFifthWidget() labelTip->setGeometry(101, 261, 520, 30); labelTip->setAlignment(Qt::AlignCenter); labelTip->setFontWordWrap(true); + // 不要使用电脑,以防数据丢失 labelTip->setDeplayText(tr("Do not use computers in case of data loss")); connect(this, &SystemBackup::backupWarnning, labelTip, [=](const QString& msg) { labelTip->setDeplayText(msg); diff --git a/kybackup/module/systemrestore.cpp b/kybackup/module/systemrestore.cpp index 587aef4..29627e5 100755 --- a/kybackup/module/systemrestore.cpp +++ b/kybackup/module/systemrestore.cpp @@ -31,6 +31,8 @@ SystemRestore::SystemRestore(QWidget *parent) : // 界面手写代码创建,作为练手 initFirstWidget(); initSecondWidget(); + initThirdWidget(); + initLastWidget(); } SystemRestore::~SystemRestore() @@ -184,12 +186,6 @@ void SystemRestore::on_next_clicked(bool checked) */ void SystemRestore::on_button_beginRestore_clicked(bool checked) { - on_next_clicked(); - emit this->startCheckEnv(); - return; - - // -------以上为测试代码------- - Q_UNUSED(checked) // 出厂还原,不用去选择备份点 @@ -221,7 +217,7 @@ void SystemRestore::on_button_beginRestore_clicked(bool checked) } /** - * @brief 初始化第二界面 + * @brief 初始化第二界面--检测中 */ void SystemRestore::initSecondWidget() { @@ -340,6 +336,7 @@ void SystemRestore::initSecondWidget() nextStep->setAutoRepeat(true); connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) { this->on_next_clicked(checked); + this->startRestore(); }); hlayoutCenterFont5->addWidget(nextStep); // 重新检测按钮 @@ -348,10 +345,6 @@ void SystemRestore::initSecondWidget() recheck->setText(tr("recheck")); recheck->setEnabled(true); recheck->setAutoRepeat(true); - connect(recheck, &MyPushButton::clicked, this, [=](bool checked) { - Q_UNUSED(checked) - emit this->startCheckEnv(); - }); hlayoutCenterFont5->addWidget(recheck); hlayoutCenterFont5->addStretch(); vlayoutCenterFont->addLayout(hlayoutCenterFont5); @@ -449,6 +442,12 @@ void SystemRestore::initSecondWidget() preStep->setVisible(true); }); + // 重新检查 + connect(recheck, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + emit this->startCheckEnv(); + }); + addWidget(second); } @@ -501,35 +500,29 @@ void SystemRestore::on_checkEnv_end(int result) // 没有找到相应的处理逻辑 errTip = tr("No processing logic was found in the service"); break; - case int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL): - // 备份分区挂载失败 - errMsg = tr("Failed to mount the backup partition"); - // 检查是否有备份分区 - errTip = tr("Check whether there is a backup partition"); + case int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED): + // ".user.txt文件不存在" + errMsg = tr(".user.txt file is not exists"); + // 备份点可能被损坏 + errTip = tr("Backup points may be corrupted"); break; - case int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT): - // 移动设备的文件系统是vfat格式 - errMsg = tr("The filesystem of device is vfat format"); - // 请换成ext4、ntfs等格式 - errTip = tr("Please change filesystem format to ext3、ext4 or ntfs"); + case int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED): + // .exclude.user.txt文件不存在 + errMsg = tr(".exclude.user.txt file is not exists"); + // 备份点可能被损坏 + errTip = tr("Backup points may be corrupted"); break; - case int(BackupResult::UDISK_FILESYSTEM_IS_READONLY): - // 移动设备是只读的 - errMsg = tr("The device is read only"); - // 请修改为可读写权限的 - errTip = tr("Please chmod to rw"); + case int(BackupResult::INC_NOT_FOUND_DIR): + // 备份点数据目录不存在 + errMsg = tr("The backup point data directory does not exist"); + // 备份点可能被损坏 + errTip = tr("Backup points may be corrupted"); break; - case int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH): - // 备份空间不足 - errMsg = tr("The storage for backup is not enough"); - // 建议释放空间后重试 - errTip = tr("Retry after release space"); - break; - case int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING): - // 其它备份还原等操作正在执行 - errMsg = tr("Other backup or restore task is being performed"); - // 请稍后重试 - errTip = tr("Please try again later"); + case int(BackupResult::EFI_RSYNC_FAIL): + // 同步/boot/efi失败 + errMsg = tr("Failed to rsync /boot/efi"); + // 请检查/boot/efi分区挂载方式 + errTip = tr("Check the mounting mode of the /boot/efi partition"); break; default: bRst = true; @@ -543,4 +536,408 @@ void SystemRestore::on_checkEnv_end(int result) m_pInterface = nullptr; } +/** + * @brief 第三个页面-还原中 + */ +void SystemRestore::initThirdWidget() +{ + QWidget *third = new QWidget; + + // 流程进度提示栏 + CircleLable *one = new CircleLable("1", third, 24, QColor(COLOR_BLUE)); + LineLabel *line1 = new LineLabel(third, QColor(COLOR_BLUE), QSize(200, 24)); + CircleLable *two = new CircleLable("2", third, 24, QColor(COLOR_BLUE)); + LineLabel *line2 = new LineLabel(third, QColor(COLOR_GRAY), QSize(200, 24)); + CircleLable *three = new CircleLable("3", third); + QHBoxLayout *layoutLine1 = new QHBoxLayout; + layoutLine1->addStretch(); + layoutLine1->addWidget(one); + layoutLine1->addWidget(line1); + layoutLine1->addWidget(two); + layoutLine1->addWidget(line2); + layoutLine1->addWidget(three); + layoutLine1->addStretch(); + + MyLabel *label1 = new MyLabel(tr("checking"), third); + label1->setIsOriginal(true); + label1->setFontColor(QColor(COLOR_BLUE)); + MyLabel *label2 = new MyLabel(tr("restoring"), third); + label2->setIsOriginal(true); + label2->setFontColor(QColor(COLOR_BLUE)); + MyLabel *label3 = new MyLabel(tr("finished"), third); + label3->setIsOriginal(true); + QHBoxLayout *layoutLine2 = new QHBoxLayout; + layoutLine2->addSpacing(100); + layoutLine2->addWidget(label1); + layoutLine2->addStretch(); + layoutLine2->addWidget(label2); + layoutLine2->addStretch(); + layoutLine2->addWidget(label3); + layoutLine2->addSpacing(100); + + // ------------ 中部布局begin------------- + QWidget *centerFont = new QWidget(third); + QVBoxLayout *vlayoutCenterFont = new QVBoxLayout; + + // 中部第一行 + QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout; + // 检测等待图标 + QLabel *loadingGif = new QLabel(centerFont); + // 环境检测等待动画 + QMovie *movie = new QMovie(":/images/loading.gif", QByteArray(), centerFont); + loadingGif->setMovie(movie); + // 进度条 + RingsProgressbar *progressBar = new RingsProgressbar(centerFont); + progressBar->setFixedSize(100, 100); + hlayoutCenterFont1->addStretch(); + hlayoutCenterFont1->addWidget(loadingGif); + hlayoutCenterFont1->addWidget(progressBar); + hlayoutCenterFont1->addStretch(); + + // 第二行 + QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout; + // 提醒 + MyLabel *labelTip = new MyLabel(centerFont); + labelTip->setAlignment(Qt::AlignCenter); + labelTip->setIsOriginal(true); + labelTip->setFontWordWrap(true); + // 不要使用电脑,以防数据丢失 + labelTip->setDeplayText(tr("Do not use computers in case of data loss")); + hlayoutCenterFont2->addStretch(); + hlayoutCenterFont2->addWidget(labelTip); + hlayoutCenterFont2->addStretch(); + + vlayoutCenterFont->addLayout(hlayoutCenterFont1); + vlayoutCenterFont->addLayout(hlayoutCenterFont2); + vlayoutCenterFont->addStretch(); + centerFont->setLayout(vlayoutCenterFont); + + // ------------ 中部布局end------------- + QHBoxLayout *layoutLine3 = new QHBoxLayout; + layoutLine3->addStretch(); + layoutLine3->addSpacing(80); + layoutLine3->addWidget(centerFont); + layoutLine3->addStretch(); + + // 布局 + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addSpacing(40); + vlayout->addLayout(layoutLine1); + vlayout->addLayout(layoutLine2); + vlayout->addSpacing(50); + vlayout->addLayout(layoutLine3); + vlayout->addStretch(); + third->setLayout(vlayout); + + // 开始备份 + connect(this, &SystemRestore::startRestore, this, [=] { + progressBar->setPersent(20); + movie->start(); + + // 开始备份 + this->on_restore_start(); + }); + + // 进度 + connect(this, &SystemRestore::progress, this, [=](int state, int rate) { + Q_UNUSED(state) + progressBar->setPersent(rate); + }); + + addWidget(third); +} + +/** + * @brief 开始还原 + */ +void SystemRestore::on_restore_start() +{ + GlobelBackupInfo::inst().setIsBusy(true); + m_systemRestoreState = SystemRestoreState::RESTORING; + m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this); + connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &SystemRestore::on_checkRestore_end); + connect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &SystemRestore::progress); + connect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &SystemRestore::on_restore_end); + + // 是否已存在备份、还原等操作 + bool isActive = false; + if(int(BackupState::BACKUP_STATE_INIT) != m_pInterface->getBackupState(isActive)){ + on_checkEnv_end(int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING)); + + return; + } + + BackupWrapper backupWrapper; + backupWrapper.m_type = m_isRetainUserData ? BackupType::RESTORE_SYSTEM_WITH_DATA : BackupType::RESTORE_SYSTEM; + backupWrapper.m_iPosition = m_devPath.isEmpty() ? BackupPosition::LOCAL : BackupPosition::UDISK; + backupWrapper.m_prefixDestPath = m_devPath; + backupWrapper.m_isOtherMachine = m_isOtherMachine ? 1 : 0; + backupWrapper.m_frontUid = getuid(); + backupWrapper.m_gid = getgid(); + m_pInterface->goRestore(backupWrapper); +} + +/** + * @brief 系统还原校验结果处理 + * @param result + */ +void SystemRestore::on_checkRestore_end(int result) +{ + bool bRst = false; + QString errMsg, errTip; + switch (result) { + case int(BackupResult::LOCK_PROGRAM_FAIL): + // 程序锁定失败,请重试 + errMsg = tr("Program lock failed, please retry"); + // 可能有其它备份/还原等任务在执行 + errTip = tr("There may be other backups or restores being performed"); + break; + case int(BackupResult::NO_FOUND_DEALCLASS): + // 不支持的任务类型 + errMsg = tr("Unsupported task type"); + // 没有找到相应的处理逻辑 + errTip = tr("No processing logic was found in the service"); + break; + case int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED): + // ".user.txt文件不存在" + errMsg = tr("The .user.txt file is not exists"); + // 备份点可能被损坏 + errTip = tr("Backup points may be corrupted"); + break; + case int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED): + // .exclude.user.txt文件不存在 + errMsg = tr("The .exclude.user.txt file is not exists"); + // 备份点可能被损坏 + errTip = tr("Backup points may be corrupted"); + break; + case int(BackupResult::INC_NOT_FOUND_DIR): + // 备份点数据目录不存在 + errMsg = tr("The backup point data directory does not exist"); + // 备份点可能被损坏 + errTip = tr("Backup points may be corrupted"); + break; + case int(BackupResult::EFI_RSYNC_FAIL): + // 同步/boot/efi失败 + errMsg = tr("Failed to rsync /boot/efi"); + // 请检查/boot/efi分区挂载方式 + errTip = tr("Check the mounting mode of the /boot/efi partition"); + break; + case int(BackupResult::RESTOREDIR_PREPARE_FAILED): + // 还原目录准备失败 + errMsg = tr("Failed to prepare the restore directory"); + // 更多信息请参考日志/var/log/backup.log + errTip = tr("Refer to log :/var/log/backup.log for more information"); + break; + default: + bRst = true; + break; + } + + if (!bRst) { + GlobelBackupInfo::inst().setIsBusy(false); + m_systemRestoreState = SystemRestoreState::IDEL; + this->on_next_clicked(true); + emit this->checkRestoreResult(bRst, errMsg, errTip); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &SystemRestore::on_checkRestore_end); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &SystemRestore::progress); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &SystemRestore::on_restore_end); + delete m_pInterface; + m_pInterface = nullptr; + } +} + +/** + * @brief 系统还原结束 + * @param result-false 失败; true 成功 + */ +void SystemRestore::on_restore_end(bool result) +{ + m_systemRestoreState = SystemRestoreState::IDEL; + + this->on_next_clicked(true); + if (result) { + emit checkRestoreResult(result); + } else { + // 还原过程中出现错误 + QString errMsg = tr("An error occurred during restore"); + // 错误信息参考日志文件:/var/log/backup.log + QString errTip = tr("Error messages refer to log file : /var/log/backup.log"); + emit checkRestoreResult(result, errMsg, errTip); + } + + GlobelBackupInfo::inst().setIsBusy(false); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &SystemRestore::on_checkRestore_end); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &SystemRestore::progress); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &SystemRestore::on_restore_end); + delete m_pInterface; + m_pInterface = nullptr; +} + +/** + * @brief 初始化最后一页 + */ +void SystemRestore::initLastWidget() +{ + QWidget *last = new QWidget; + + // 流程进度提示栏 + CircleLable *one = new CircleLable("1", last, 24, QColor(COLOR_BLUE)); + LineLabel *line1 = new LineLabel(last, QColor(COLOR_BLUE), QSize(200, 24)); + CircleLable *two = new CircleLable("2", last, 24, QColor(COLOR_BLUE)); + LineLabel *line2 = new LineLabel(last, QColor(COLOR_GRAY), QSize(200, 24)); + CircleLable *three = new CircleLable("3", last, 24, QColor(COLOR_BLUE)); + QHBoxLayout *layoutLine1 = new QHBoxLayout; + layoutLine1->addStretch(); + layoutLine1->addWidget(one); + layoutLine1->addWidget(line1); + layoutLine1->addWidget(two); + layoutLine1->addWidget(line2); + layoutLine1->addWidget(three); + layoutLine1->addStretch(); + + MyLabel *label1 = new MyLabel(tr("checking"), last); + label1->setIsOriginal(true); + label1->setFontColor(QColor(COLOR_BLUE)); + MyLabel *label2 = new MyLabel(tr("restoring"), last); + label2->setIsOriginal(true); + label2->setFontColor(QColor(COLOR_BLUE)); + MyLabel *label3 = new MyLabel(tr("finished"), last); + label3->setIsOriginal(true); + label3->setFontColor(QColor(COLOR_BLUE)); + QHBoxLayout *layoutLine2 = new QHBoxLayout; + layoutLine2->addSpacing(100); + layoutLine2->addWidget(label1); + layoutLine2->addStretch(); + layoutLine2->addWidget(label2); + layoutLine2->addStretch(); + layoutLine2->addWidget(label3); + layoutLine2->addSpacing(100); + + // ------------ 中部布局begin------------- + QWidget *centerFont = new QWidget(last); + QVBoxLayout *vlayoutCenterFont = new QVBoxLayout; + + // 中部第一行 + QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout; + // 备份结果对错图标 + QLabel *resultLogo = new QLabel(centerFont); + resultLogo->setFixedSize(20,20); + hlayoutCenterFont1->addWidget(resultLogo); + // 检测中大标题 + MyLabel *bigTitle = new MyLabel(centerFont); + bigTitle->setFontSize(24); + bigTitle->setMaximumWidth(700); + hlayoutCenterFont1->addWidget(bigTitle); + hlayoutCenterFont1->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont1); + + // 第二行 + QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout; + hlayoutCenterFont2->addSpacing(10); + // 备份结果错误提示:黑点和文字 + CircleLable *dot1 = new CircleLable(QString(""), centerFont, 6, Qt::black); + hlayoutCenterFont2->addWidget(dot1); + hlayoutCenterFont2->addSpacing(5); + MyLabel *labelError1 = new MyLabel(centerFont); + labelError1->setMinimumWidth(400); + labelError1->setMaximumWidth(600); + labelError1->setIsOriginal(true); + labelError1->setWordWrap(true); + labelError1->adjustSize(); + hlayoutCenterFont2->addWidget(labelError1); + hlayoutCenterFont2->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont2); + + // 第三行 + QHBoxLayout *hlayoutCenterFont3 = new QHBoxLayout; + hlayoutCenterFont3->addSpacing(10); + // 检测中的记录:黑点2和文字2 + CircleLable *dot2 = new CircleLable(QString(""), centerFont, 6, Qt::black); + hlayoutCenterFont3->addWidget(dot2); + hlayoutCenterFont3->addSpacing(5); + MyLabel *labelError2 = new MyLabel(centerFont); + //labelError2->setMinimumWidth(400); + //labelError2->setMaximumWidth(600); + labelError2->setIsOriginal(true); + labelError2->setWordWrap(true); + labelError2->adjustSize(); + hlayoutCenterFont3->addWidget(labelError2); + hlayoutCenterFont3->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont3); + + // 第四行 + vlayoutCenterFont->addSpacing(30); + + // 第五行 + QHBoxLayout *hlayoutCenterFont5 = new QHBoxLayout; + hlayoutCenterFont5->addSpacing(100); + // 再试一次 + MyPushButton *retry = new MyPushButton(centerFont); + retry->setFixedSize(97, 36); + retry->setText(tr("retry")); + retry->setEnabled(true); + retry->setAutoRepeat(true); + hlayoutCenterFont5->addWidget(retry); + hlayoutCenterFont5->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont5); + + vlayoutCenterFont->addStretch(); + centerFont->setLayout(vlayoutCenterFont); + // ------------ 中部布局end------------- + + QHBoxLayout *layoutLine3 = new QHBoxLayout; + layoutLine3->addStretch(); + layoutLine3->addWidget(centerFont); + layoutLine3->addStretch(); + + // 布局 + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addSpacing(40); + vlayout->addLayout(layoutLine1); + vlayout->addLayout(layoutLine2); + vlayout->addSpacing(50); + vlayout->addLayout(layoutLine3); + vlayout->addStretch(); + last->setLayout(vlayout); + + // 还原检测结果 + connect(this, &SystemRestore::checkRestoreResult, this, [=](bool result, const QString &errMsg, const QString &errTip) { + if (result) { + QIcon icon = QIcon::fromTheme("ukui-dialog-success", QIcon(":/symbos/ukui-dialog-success.png")); + resultLogo->setPixmap(icon.pixmap(QSize(20,20))); + resultLogo->setVisible(true); + // 系统还原成功 + bigTitle->setDeplayText(tr("Successfully restoring the system")); + dot1->setVisible(true); + dot2->setVisible(false); + labelError1->setVisible(true); + // 系统将自动重启 + labelError1->setDeplayText(tr("The system will automatically reboot")); + labelError2->setVisible(false); + retry->setVisible(false); + } else { + QIcon icon = QIcon::fromTheme("dialog-error.png", QIcon(":/symbos/dialog-error.png")); + resultLogo->setPixmap(icon.pixmap(QSize(20,20))); + resultLogo->setVisible(true); + // 系统还原失败 + bigTitle->setDeplayText(tr("Restoring the system failed")); + dot1->setVisible(true); + dot2->setVisible(true); + labelError1->setDeplayText(errMsg); + labelError2->setDeplayText(errTip); + retry->setVisible(true); + } + }); + + // 再试一次 + connect(retry, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + this->setCurrentIndex(SystemRestorePage::RESTORE_PAGE); + this->startRestore(); + }); + + addWidget(last); +} + + diff --git a/kybackup/module/systemrestore.h b/kybackup/module/systemrestore.h index 4e9aa63..feef8fe 100755 --- a/kybackup/module/systemrestore.h +++ b/kybackup/module/systemrestore.h @@ -13,14 +13,14 @@ public: { IDEL = 0, // 空闲 CHECKING, // 环境校验中 - BACKUPING // 备份中 + RESTORING // 还原中 }; enum SystemRestorePage { HOME_PAGE, // 首页 CHECK_ENV_PAGE, // 环境检测页 - BACKUP_PAGE, // 还原中页 + RESTORE_PAGE, // 还原中页 LAST_PAGE, // 结束页 }; @@ -31,10 +31,15 @@ public: private: void initFirstWidget(); void initSecondWidget(); + void initThirdWidget(); + void initLastWidget(); signals: void startCheckEnv(); void checkEnvResult(bool result, const QString &errMsg = "", const QString &errTip = ""); + void startRestore(); + void progress(int state, int rate); + void checkRestoreResult(bool result, const QString &errMsg = "", const QString &errTip = ""); public slots: void on_pre_clicked(bool checked = false); @@ -42,6 +47,9 @@ public slots: void on_button_beginRestore_clicked(bool checked = false); void on_checkEnv_start(); void on_checkEnv_end(int result); + void on_restore_start(); + void on_checkRestore_end(int result); + void on_restore_end(bool result); private: // 是否保留用户数据 @@ -54,7 +62,7 @@ private: QString m_uuid; // 还原点的UUID QString m_devPath; // 如果是从移动设备进行还原,此中保存移动设备挂载路径 - bool m_isOtherMachine; + bool m_isOtherMachine; // 是否异机备份点还原 // 系统备份状态 int m_systemRestoreState; };