From 8a5edddba4eed4322de0daa0a97888ca7c9ba6bb Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Tue, 11 Nov 2025 11:30:15 +0800 Subject: [PATCH] fix: keep renamed file content during compression - copy aliased entries into a temp directory before invoking createArchive - update FileEntry paths to point at the real copies and clear aliases - cleanup the temp copies on success, failure, cancel, and reset - ensures libzip sees actual files instead of symlink paths Log: fix bug Bug: https://pms.uniontech.com/bug-view-340081.html --- src/source/mainwindow.cpp | 138 ++++++++++++++++++++++++++++++++++++++ src/source/mainwindow.h | 14 ++++ 2 files changed, 152 insertions(+) diff --git a/src/source/mainwindow.cpp b/src/source/mainwindow.cpp index 93b1353f..29064c40 100644 --- a/src/source/mainwindow.cpp +++ b/src/source/mainwindow.cpp @@ -50,6 +50,11 @@ #include #include #include +#include +#include +#include +#include +#include #ifdef DTKCORE_CLASS_DConfigFile #include DCORE_USE_NAMESPACE @@ -58,6 +63,40 @@ DCORE_USE_NAMESPACE static QMutex mutex; // 静态全局变量只在定义该变量的源文件内有效 #define FILE_TRUNCATION_LENGTH 70 +namespace { + +bool copyDirectoryRecursively(const QString &sourcePath, const QString &targetPath) +{ + QDir sourceDir(sourcePath); + if (!sourceDir.exists()) { + return false; + } + + if (!QDir().mkpath(targetPath)) { + return false; + } + + const QFileInfoList entries = sourceDir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Files | QDir::Hidden | QDir::System); + for (const QFileInfo &info : entries) { + const QString srcFilePath = info.absoluteFilePath(); + const QString dstFilePath = targetPath + QDir::separator() + info.fileName(); + if (info.isDir()) { + if (!copyDirectoryRecursively(srcFilePath, dstFilePath)) { + return false; + } + } else { + QFile::remove(dstFilePath); + if (!QFile::copy(srcFilePath, dstFilePath)) { + return false; + } + } + } + + return true; +} + +} // namespace + MainWindow::MainWindow(QWidget *parent) : DMainWindow(parent) , m_strProcessID(QString::number(QCoreApplication::applicationPid())) // 获取应用进程号 @@ -1015,6 +1054,11 @@ void MainWindow::slotCompress(const QVariant &val) // 构建压缩文件数据 listEntry = m_pCompressPage->getEntrys(); + + if (!prepareCompressAliasEntries(listEntry)) { + return; + } + strDestination = m_stCompressParameter.strTargetPath + QDir::separator() + m_stCompressParameter.strArchiveName; // 构建压缩参数 @@ -1089,6 +1133,7 @@ void MainWindow::slotCompress(const QVariant &val) m_ePageID = PI_CompressProgress; refreshPage(); } else { + cleanupCompressAliasEntries(); // 无可用插件 showErrorMessage(FI_Compress, EI_NoPlugin); } @@ -1305,6 +1350,8 @@ void MainWindow::handleJobNormalFinished(ArchiveJob::JobType eType, ErrorType eE // zip压缩包添加注释 addArchiveComment(); + + cleanupCompressAliasEntries(); } break; // 添加文件至压缩包 @@ -1544,6 +1591,7 @@ void MainWindow::handleJobCancelFinished(ArchiveJob::JobType eType) } else { m_ePageID = PI_Compress; } + cleanupCompressAliasEntries(); } break; // 添加文件至压缩包 @@ -1643,6 +1691,8 @@ void MainWindow::handleJobErrorFinished(ArchiveJob::JobType eJobType, ErrorType } } + cleanupCompressAliasEntries(); + } break; // 压缩包追加文件错误 @@ -1938,6 +1988,8 @@ void MainWindow::resetMainwindow() maxFileSize_ = 0; #endif + cleanupCompressAliasEntries(); + m_ePageID = PI_Home; m_operationtype = Operation_NULL; // 重置操作类型 m_iCompressedWatchTimerID = 0; // 初始化定时器返回值 @@ -2079,6 +2131,92 @@ void MainWindow::ConstructAddOptionsByThread(const QString &path) } } +bool MainWindow::prepareCompressAliasEntries(QList &listEntry) +{ + m_needCleanupCompressAlias = false; + m_strCompressAliasRoot.clear(); + + bool hasAlias = false; + QString aliasRoot; + + for (FileEntry &entry : listEntry) { + if (entry.strAlias.isEmpty()) { + continue; + } + + if (entry.strFullPath.isEmpty()) { + continue; + } + + if (!hasAlias) { + const QString baseDir = TEMPPATH + QDir::separator() + m_strProcessID + QDir::separator() + "compress_alias"; + if (!QDir().mkpath(baseDir)) { + showWarningDialog(tr("Failed to create temporary directory, please check and try again.")); + return false; + } + aliasRoot = baseDir + QDir::separator() + QUuid::createUuid().toString(QUuid::WithoutBraces); + if (!QDir().mkpath(aliasRoot)) { + showWarningDialog(tr("Failed to create temporary directory, please check and try again.")); + return false; + } + } + + const QString aliasName = entry.strAlias; + const QString targetPath = aliasRoot + QDir::separator() + aliasName; + + if (entry.isDirectory) { + QDir(targetPath).removeRecursively(); + if (!copyDirectoryRecursively(entry.strFullPath, targetPath)) { + showWarningDialog(tr("Failed to prepare renamed item \"%1\" for compression, please check permissions and available space.") + .arg(aliasName)); + if (!aliasRoot.isEmpty()) { + QDir(aliasRoot).removeRecursively(); + } + return false; + } + } else { + QFile::remove(targetPath); + if (!QFile::copy(entry.strFullPath, targetPath)) { + showWarningDialog(tr("Failed to prepare renamed item \"%1\" for compression, please check permissions and available space.") + .arg(aliasName)); + if (!aliasRoot.isEmpty()) { + QDir(aliasRoot).removeRecursively(); + } + return false; + } + } + + entry.strFullPath = targetPath; + entry.strAlias.clear(); + hasAlias = true; + } + + if (hasAlias) { + m_strCompressAliasRoot = aliasRoot; + m_needCleanupCompressAlias = true; + } else { + m_strCompressAliasRoot.clear(); + m_needCleanupCompressAlias = false; + } + + return true; +} + +void MainWindow::cleanupCompressAliasEntries() +{ + if (m_strCompressAliasRoot.isEmpty()) { + m_needCleanupCompressAlias = false; + return; + } + + QDir aliasRoot(m_strCompressAliasRoot); + if (aliasRoot.exists()) { + aliasRoot.removeRecursively(); + } + m_strCompressAliasRoot.clear(); + m_needCleanupCompressAlias = false; +} + void MainWindow::showSuccessInfo(SuccessInfo eSuccessInfo, ErrorType eErrorType) { m_pSuccessPage->setSuccessType(eSuccessInfo); diff --git a/src/source/mainwindow.h b/src/source/mainwindow.h index 6c594802..1929ba54 100644 --- a/src/source/mainwindow.h +++ b/src/source/mainwindow.h @@ -214,6 +214,18 @@ public : */ void ConstructAddOptionsByThread(const QString &path); + /** + * @brief prepareCompressAliasEntries 为重命名文件准备临时别名文件 + * @param listEntry 待压缩的文件信息 + * @return 是否准备成功 + */ + bool prepareCompressAliasEntries(QList &listEntry); + + /** + * @brief cleanupCompressAliasEntries 清理临时别名文件 + */ + void cleanupCompressAliasEntries(); + /** * @brief showSuccessInfo 显示成功信息 * @param eSuccessInfo 成功信息 @@ -575,6 +587,8 @@ private Q_SLOTS: #endif QString m_strCurrentName; + QString m_strCompressAliasRoot; + bool m_needCleanupCompressAlias = false; }; class TitleWidget : public QWidget