diff --git a/backup-daemon/backup-daemon.pro b/backup-daemon/backup-daemon.pro index b3b77dc..3da6736 100755 --- a/backup-daemon/backup-daemon.pro +++ b/backup-daemon/backup-daemon.pro @@ -33,6 +33,7 @@ HEADERS += \ mybackupmanager.h \ mymountproxy.h \ myprocess/calcbackupsize.h \ + myprocess/mksquashfsprocess.h \ myprocess/mountbackupprocess.h \ myprocess/rsyncpathtodirprocess.h \ mythread.h \ @@ -52,6 +53,7 @@ SOURCES += \ mybackupmanager.cpp \ mymountproxy.cpp \ myprocess/calcbackupsize.cpp \ + myprocess/mksquashfsprocess.cpp \ myprocess/mountbackupprocess.cpp \ myprocess/rsyncpathtodirprocess.cpp \ mythread.cpp \ diff --git a/backup-daemon/mybackupmanager.cpp b/backup-daemon/mybackupmanager.cpp index 7d09d12..d2cb59f 100755 --- a/backup-daemon/mybackupmanager.cpp +++ b/backup-daemon/mybackupmanager.cpp @@ -124,7 +124,9 @@ int MyBackupManager::goBackup(const BackupWrapper& backupWrapper) worker->setParam(backupWrapper); connect(worker, &Worker::checkResult, this, [&](int result) { emit this->sendEnvCheckResult(result); - if (result != int(BackupResult::CHECK_ENV_SUCCESS)) { + if ( result != int(BackupResult::CHECK_ENV_SUCCESS) + || result != int(BackupResult::MKSQUASHFS_START_SUCCESS) + || result != int(BackupResult::BACKUP_START_SUCCESS)) { this->finished(); } }); diff --git a/backup-daemon/myprocess/calcbackupsize.cpp b/backup-daemon/myprocess/calcbackupsize.cpp index 032d66a..da53f96 100755 --- a/backup-daemon/myprocess/calcbackupsize.cpp +++ b/backup-daemon/myprocess/calcbackupsize.cpp @@ -116,7 +116,9 @@ void CalcBackupSize::processFinish(int exitCode, QProcess::ExitStatus) qDebug() << "CalcBackupSize::getCalcResult invoke begin"; Q_UNUSED(exitCode) - parseResult(); + if (exitCode == QProcess::NormalExit) + parseResult(); + emit finished(m_size); qDebug() << "CalcBackupSize::getCalcResult invoke end"; diff --git a/backup-daemon/myprocess/mksquashfsprocess.cpp b/backup-daemon/myprocess/mksquashfsprocess.cpp new file mode 100644 index 0000000..bbc0a75 --- /dev/null +++ b/backup-daemon/myprocess/mksquashfsprocess.cpp @@ -0,0 +1,83 @@ +#include "mksquashfsprocess.h" +#include + +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()); + 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) +{ + 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 finished(true); + } else { + emit finished(false); + } +} + diff --git a/backup-daemon/myprocess/mksquashfsprocess.h b/backup-daemon/myprocess/mksquashfsprocess.h new file mode 100644 index 0000000..addc16d --- /dev/null +++ b/backup-daemon/myprocess/mksquashfsprocess.h @@ -0,0 +1,40 @@ +#ifndef MKSQUASHFSPROCESS_H +#define MKSQUASHFSPROCESS_H + +#include +#include + +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 diff --git a/backup-daemon/myprocess/rsyncpathtodirprocess.cpp b/backup-daemon/myprocess/rsyncpathtodirprocess.cpp index 23ed7c7..babbc3d 100755 --- a/backup-daemon/myprocess/rsyncpathtodirprocess.cpp +++ b/backup-daemon/myprocess/rsyncpathtodirprocess.cpp @@ -47,6 +47,10 @@ 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) diff --git a/backup-daemon/myprocess/rsyncpathtodirprocess.h b/backup-daemon/myprocess/rsyncpathtodirprocess.h index c5e6164..5c2030e 100755 --- a/backup-daemon/myprocess/rsyncpathtodirprocess.h +++ b/backup-daemon/myprocess/rsyncpathtodirprocess.h @@ -7,8 +7,8 @@ class RsyncPathToDirProcess : public QObject { Q_OBJECT public: - RsyncPathToDirProcess(QObject *parent = nullptr); - ~RsyncPathToDirProcess(); + explicit RsyncPathToDirProcess(QObject *parent = nullptr); + virtual ~RsyncPathToDirProcess(); bool start(QStringList args, bool block = true); diff --git a/backup-daemon/udisksystembackupproxy.cpp b/backup-daemon/udisksystembackupproxy.cpp index 1bdad9c..f21595f 100644 --- a/backup-daemon/udisksystembackupproxy.cpp +++ b/backup-daemon/udisksystembackupproxy.cpp @@ -19,6 +19,7 @@ UDiskSystemBackupProxy::UDiskSystemBackupProxy() m_size = 0; m_calc = new CalcBackupSize(this); m_isOnlyCheck = true; + m_mksquashfs = nullptr; } UDiskSystemBackupProxy::~UDiskSystemBackupProxy() @@ -28,6 +29,13 @@ UDiskSystemBackupProxy::~UDiskSystemBackupProxy() delete m_calc; m_calc = nullptr; + + delete m_mksquashfs; + m_mksquashfs = nullptr; + + QString rm("rm -rf "); + rm += m_imgPath; + QProcess::execute(rm); } /** @@ -128,8 +136,29 @@ void UDiskSystemBackupProxy::checkFreeCapacity(qint64 itotalSize) if (m_isOnlyCheck) return ; - // 开始备份 - doBackup(); + // 4、判断是否需要先压缩成img文件,压缩后一般小于原大小的70% + itotalSize = itotalSize * 7 / 10; + QHash hash = Utils::getLeftSizeOfPartitions(); + for (QHash::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"; } @@ -165,6 +194,7 @@ void UDiskSystemBackupProxy::calcSizeForBackup() QStringList UDiskSystemBackupProxy::getRsyncArgs(UDiskSystemBackupScene scene) { QStringList args; + QStringList excludes; switch (scene) { case UDiskSystemBackupScene::SYSTEM_BACKUP : @@ -178,6 +208,20 @@ QStringList UDiskSystemBackupProxy::getRsyncArgs(UDiskSystemBackupScene scene) 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; + } + return args; + case UDiskSystemBackupScene::IMG_BACKUP : default: return args; } @@ -190,6 +234,39 @@ QStringList UDiskSystemBackupProxy::getRsyncArgs(UDiskSystemBackupScene scene) return args; } +/** + * @brief mksqushfs + */ +void UDiskSystemBackupProxy::doMksqushfs() +{ + qDebug() << "UDiskSystemBackupProxy::doMksqushfs invoke begin"; + + m_mksquashfs = new MkSquashFSProcess(this); + connect(m_mksquashfs, &MkSquashFSProcess::finished, this, [=](bool result) { + if (result) { + // 开始备份 + doBackup(); + } else { + 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_DO_FAIL)); + } + + qDebug() << "UDiskSystemBackupProxy::doMksqushfs invoke end"; +} + /** * @brief 备份 */ @@ -207,8 +284,14 @@ void UDiskSystemBackupProxy::doBackup() // return ; // } - // 启动系统备份 - backupSystem(); + if (m_imgPath.isEmpty()) { + // 启动系统备份 + backupSystem(); + } else { + // 备份img文件 + backupImg(); + } + qDebug() << "UDiskSystemBackupProxy::doBackup invoke end"; } @@ -230,24 +313,24 @@ bool UDiskSystemBackupProxy::doPrepare() 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) ; + 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)); - qCritical() << QString("create file %1 failed !").arg(userFile) ; 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)); - qCritical() << QString("create file %1 failed !").arg(excludeUserFile) ; return false; } @@ -297,7 +380,7 @@ bool UDiskSystemBackupProxy::recordBackupPoint() /** * @brief 备份系统 - * @return true,备份成功;false,备份失败 + * @return true,启动备份成功;false,启动备份失败 */ bool UDiskSystemBackupProxy::backupSystem() { @@ -315,6 +398,35 @@ bool UDiskSystemBackupProxy::backupSystem() 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 << 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) { @@ -333,10 +445,11 @@ bool UDiskSystemBackupProxy::backupSystem() emit this->workResult(result); }); m_p->start(args, false); + emit checkResult(int(BackupResult::BACKUP_START_SUCCESS)); do_kylin_security(m_destPath); - qDebug() << "UDiskSystemBackupProxy::backupSystem invoke end"; + qDebug() << "UDiskSystemBackupProxy::backup invoke end"; return true; } @@ -368,6 +481,8 @@ bool UDiskSystemBackupProxy::checkDestDirExists() if (m_calc) m_calc->stop(); + if (m_mksquashfs) + m_mksquashfs->stop(); if (m_p) m_p->stop(); diff --git a/backup-daemon/udisksystembackupproxy.h b/backup-daemon/udisksystembackupproxy.h index 13c5193..dc5cf13 100644 --- a/backup-daemon/udisksystembackupproxy.h +++ b/backup-daemon/udisksystembackupproxy.h @@ -2,9 +2,10 @@ #define UDISKSYSTEMBACKUPPROXY_H #include "workerfactory.h" +#include "myprocess/calcbackupsize.h" +#include "myprocess/mksquashfsprocess.h" #include "myprocess/rsyncpathtodirprocess.h" #include "parsebackuplist.h" -#include "myprocess/calcbackupsize.h" class UDiskSystemBackupProxy : public Worker { @@ -16,6 +17,8 @@ public: enum UDiskSystemBackupScene { SYSTEM_BACKUP, // 系统备份 TRY_SYSTEM_BACKUP, // 测试系统备份,可用于计算备份传输数据大小 + MKSQUASHFS, // 生成img文件 + IMG_BACKUP, // 备份img文件 }; explicit UDiskSystemBackupProxy(); @@ -31,10 +34,18 @@ public: // 任务取消 virtual void cancelEx(); +signals: + private slots: // 校验剩余空间是否满足备份 void checkFreeCapacity(qint64 itotalSize); + // mksqushfs + void doMksqushfs(); + + // 备份 + void doBackup(); + private: // 判断是否增量备份 bool isIncBackup(); @@ -58,12 +69,14 @@ private: // 备份准备 bool doPrepare(); - // 备份 - void doBackup(); - // 备份系统 bool backupSystem(); + // 备份img文件 + bool backupImg(); + + bool backup(const QStringList &args); + void do_kylin_security(const QString& dstDir); /** @@ -78,6 +91,8 @@ private: // 计算备份空间大小的进程 CalcBackupSize *m_calc; + // 压缩进程 + MkSquashFSProcess *m_mksquashfs; // 是否备份成功 bool m_bSuccess; @@ -93,6 +108,8 @@ private: ParseBackupList::BackupPoint m_backupPoint; // 是否只是检测 bool m_isOnlyCheck; + // img文件存放路径 + QString m_imgPath; }; #endif // UDISKSYSTEMBACKUPPROXY_H diff --git a/common/mydefine.h b/common/mydefine.h index 960e1bd..282385d 100755 --- a/common/mydefine.h +++ b/common/mydefine.h @@ -14,6 +14,11 @@ #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 DATA_PATH "/data" #define BOOTINFO_PATH "/etc/.bootinfo" #define FSTAB_PATH "/etc/fstab" @@ -251,7 +256,12 @@ enum class BackupResult { // 根据操作类型动态创建处理类失败 NO_FOUND_DEALCLASS, + // 环境检测成功 CHECK_ENV_SUCCESS, + // mksquashfs启动成功 + MKSQUASHFS_START_SUCCESS, + // mksquashfs压缩img文件失败 + MKSQUASHFS_DO_FAIL, }; #endif // MYDEFINE_H diff --git a/common/utils.cpp b/common/utils.cpp index 8992b38..d528f1b 100755 --- a/common/utils.cpp +++ b/common/utils.cpp @@ -212,7 +212,7 @@ QString Utils::getBackupPartitionUuid() // like: // # /dev/add4 LABEL=KYLIN-BACKUP // UUID=40be1cac-cd92-49db-8a98-68ee21ddbc49 /backup ext4 noauto 0 0 - int indexOfSpace = line.indexOf(QRegularExpression("[ \t]"), 0); + int indexOfSpace = line.indexOf(QRegularExpression("[ \t]+"), 0); QString uuid = line.mid(0, indexOfSpace); uuid.replace("UUID=", ""); restoreUuid = uuid.trimmed(); @@ -228,7 +228,7 @@ QString Utils::getBackupPartitionUuid() preLine.replace("# ", ""); preLine.replace("#", ""); - int indexOfSpace = preLine.indexOf(QRegularExpression("[ \t]"), 0); + int indexOfSpace = preLine.indexOf(QRegularExpression("[ \t]+"), 0); QString uuid = preLine.mid(0, indexOfSpace); uuid.replace("UUID=", ""); restoreUuid = uuid.trimmed(); @@ -270,7 +270,7 @@ QHash Utils::getPartUuidMap(const QString &fstab) // 配置文件/etc/fstab每行6个域: , 形如: // UUID=232f5fb4-53e0-46b9-ba9b-22bfec64f2a2 /boot ext4 rw,relatime 0 0 - QStringList list = line.split(QRegularExpression("[ \t]")); + QStringList list = line.split(QRegularExpression("[ \t]+")); QStringList fields; for (int i = 0; i < list.size(); ++i) { QString field = list.at(i); @@ -285,7 +285,7 @@ QHash Utils::getPartUuidMap(const QString &fstab) // like: // # /dev/add4 LABEL=KYLIN-BACKUP // UUID=40be1cac-cd92-49db-8a98-68ee21ddbc49 /backup ext4 noauto 0 0 - int indexOfSpace = line.indexOf(QRegularExpression("[ \t]"), 0); + int indexOfSpace = line.indexOf(QRegularExpression("[ \t]+"), 0); QString uuid = line.mid(0, indexOfSpace); uuid.replace("UUID=", ""); uuid = uuid.trimmed(); @@ -299,7 +299,7 @@ QHash Utils::getPartUuidMap(const QString &fstab) preLine.replace("# ", ""); preLine.replace("#", ""); - int indexOfSpace = preLine.indexOf(QRegularExpression("[ \t]"), 0); + int indexOfSpace = preLine.indexOf(QRegularExpression("[ \t]+"), 0); QString uuid = preLine.mid(0, indexOfSpace); uuid.replace("UUID=", ""); uuid = uuid.trimmed(); @@ -367,7 +367,7 @@ void Utils::excludeFstabBindPath(QStringList &excludes) // 配置文件/etc/fstab每行6个域: , 形如: // UUID=232f5fb4-53e0-46b9-ba9b-22bfec64f2a2 /boot ext4 rw,relatime 0 0 - QStringList list = line.split(QRegularExpression("[ \t]")); + QStringList list = line.split(QRegularExpression("[ \t]+")); QStringList fields; for (int i = 0; i < list.size(); ++i) { QString field = list.at(i); @@ -957,3 +957,51 @@ QString Utils::getArchDetect() return arch.replace("\n", ""); } +/** + * @brief 获取分区剩余大小 + * @return + */ +QHash Utils::getLeftSizeOfPartitions() +{ + QString root = Utils::getSysRootPath(); + QString backup = Utils::getSysRootPath() + BACKUP_PATH; + backup.replace("//", "/"); + QString data = Utils::getSysRootPath() + DATA_PATH; + data.replace("//", "/"); + + QStringList args; + args << "-h"; + args << backup; + args << data; + args << root; + + QHash hash; + + QProcess df; + df.start("df", args); + if (df.waitForFinished()) { + QString result(df.readAll()); + QStringList lines = result.split("\n"); +/* +文件系统 容量 已用 可用 已用% 挂载点 +/dev/nvme0n1p4 26G 45M 25G 1% /backup +/dev/nvme0n1p3 98G 54G 40G 58% / +/dev/nvme0n1p5 90G 8.6G 77G 11% /data +*/ + // 排除第一行标题 + for (int i = 1; i < lines.size(); ++i) { + QString line = lines.at(i); + line = line.trimmed(); + if (line.isEmpty()) + continue; + + QStringList fields = line.split(QRegularExpression("[ \t]+")); + if (fields.size() != 6) + continue; + QString path = fields.at(5); + QString left = fields.at(3); + hash.insert(path, left); + } + } + return hash; +} diff --git a/common/utils.h b/common/utils.h index 2b23f3a..9700850 100755 --- a/common/utils.h +++ b/common/utils.h @@ -248,6 +248,12 @@ public: */ static QString getArchDetect(); + /** + * @brief 获取分区剩余大小 + * @return + */ + static QHash getLeftSizeOfPartitions(); + private: // 系统根目录,默认"/" static QString m_sysRootPath; diff --git a/kybackup/module/systemrestore.cpp b/kybackup/module/systemrestore.cpp index c67ce30..bfa909c 100644 --- a/kybackup/module/systemrestore.cpp +++ b/kybackup/module/systemrestore.cpp @@ -20,6 +20,7 @@ SystemRestore::SystemRestore(QWidget *parent) : QStackedWidget(parent) { + m_isRetainUserData = false; // 界面手写代码创建,作为练手 initFirstWidget(); } @@ -148,6 +149,6 @@ void SystemRestore::on_next_clicked(bool checked) */ void SystemRestore::on_retainUserData_checked(bool checked) { - // TODO + m_isRetainUserData = checked; }