From 1f12b938100ff09c8fabd1de56c6ef0af44da040 Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Mon, 2 Feb 2026 14:38:43 +0800 Subject: [PATCH 1/2] fix: remove empty files left when split-volume encrypted extraction fails (e.g. wrong password) Log: as title Bug: https://pms.uniontech.com/bug-view-343249.html --- .../archiveinterface/cliinterface.cpp | 59 +++++++++++++++++++ .../interface/archiveinterface/cliinterface.h | 7 +++ 2 files changed, 66 insertions(+) diff --git a/3rdparty/interface/archiveinterface/cliinterface.cpp b/3rdparty/interface/archiveinterface/cliinterface.cpp index bf8c0ca8..a6c45e83 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.cpp +++ b/3rdparty/interface/archiveinterface/cliinterface.cpp @@ -1110,6 +1110,59 @@ bool CliInterface::moveExtractTempFilesToDest(const QList &files, con return moveSuccess; } +void CliInterface::removeExtractedFilesOnFailure(const QString &strTargetPath, const QList &entries) +{ + QList listToRemove = entries; + if (listToRemove.isEmpty()) { + listToRemove = DataManager::get_instance().archiveData().mapFileEntry.values(); + } + if (listToRemove.isEmpty()) { + return; + } + + QDir targetDir(strTargetPath); + if (!targetDir.exists()) { + return; + } + + QList > paths; // path, isDirectory + for (const FileEntry &entry : listToRemove) { + QString relPath = entry.strFullPath; + if (relPath.endsWith(QLatin1Char('/'))) { + relPath.chop(1); + } + if (relPath.isEmpty()) { + continue; + } + paths.append(qMakePair(targetDir.absoluteFilePath(relPath), entry.isDirectory)); + } + + for (const auto &p : paths) { + const QString &path = p.first; + if (!p.second) { // 文件 + QFileInfo fi(path); + if (fi.exists() && fi.isFile() && fi.size() == 0) { + QFile::remove(path); + } + } + } + // 空目录可能有多层,循环直到本轮没有可删的空目录 + bool removed; + do { + removed = false; + for (const auto &p : paths) { + if (!p.second) { + continue; + } + QDir d(p.first); + if (d.exists() && d.isEmpty()) { + d.removeRecursively(); + removed = true; + } + } + } while (removed); +} + bool CliInterface::handleLongNameExtract(const QList &files) { ExtractionOptions &options = m_extractOptions; @@ -1284,6 +1337,7 @@ void CliInterface::readStdout(bool handleAll) // 第二个判断条件是处理rar的list,当rar文件含有comment信息的时候需要根据空行解析 if (!line.isEmpty() || (m_listEmptyLines && m_workStatus == WT_List)) { if (!handleLine(QString::fromLocal8Bit(line), m_workStatus)) { + emit signalprogress(100); killProcess(); return; } @@ -1328,6 +1382,11 @@ void CliInterface::extractProcessFinished(int exitCode, QProcess::ExitStatus exi m_indexOfListRootEntry = 0; m_isEmptyArchive = false; + // 解压失败(如分卷加密包输错密码)且为全部解压到目标路径时,清理已生成的 size 为 0 等残留文件 + if (0 != exitCode && m_extractOptions.bAllExtract && !m_extractOptions.strTargetPath.isEmpty()) { + removeExtractedFilesOnFailure(m_extractOptions.strTargetPath, m_files); + } + if (!m_extractOptions.bAllExtract && (!(m_extractOptions.strTargetPath.startsWith("/tmp") && m_extractOptions.strTargetPath.contains("/deepin-compressor-") && m_extractOptions.strDestination.isEmpty()))) { if (0 == exitCode) { // job正常结束 // 提取操作和打开解压列表文件非第一层的文件 diff --git a/3rdparty/interface/archiveinterface/cliinterface.h b/3rdparty/interface/archiveinterface/cliinterface.h index ac9a4066..8b934e40 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.h +++ b/3rdparty/interface/archiveinterface/cliinterface.h @@ -193,6 +193,13 @@ class CliInterface : public ReadWriteArchiveInterface */ bool moveExtractTempFilesToDest(const QList &files, const ExtractionOptions &options); + /** + * @brief removeExtractedFilesOnFailure 解压失败时清理已生成的文件(如分卷加密包输错密码时产生的 size 为 0 的文件) + * @param strTargetPath 解压目标路径 + * @param entries 本次解压涉及的条目列表(可为空,为空时从 ArchiveData 获取全部) + */ + void removeExtractedFilesOnFailure(const QString &strTargetPath, const QList &entries); + bool handleLongNameExtract(const QList &files); private slots: From 450e707901536e5aae214df398cb3aa49ff9c2be Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Thu, 26 Feb 2026 13:22:44 +0800 Subject: [PATCH 2/2] fix: [unrar] can not extract rar files with longFilenames prevent extracting RAR files with long filenames when unrar tool is missing Log: as title Bug: https://pms.uniontech.com/bug-view-343139.html --- .../archiveinterface/cliinterface.cpp | 28 +++++++++++++++++++ .../interface/archiveinterface/cliinterface.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/3rdparty/interface/archiveinterface/cliinterface.cpp b/3rdparty/interface/archiveinterface/cliinterface.cpp index a6c45e83..3e56a528 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.cpp +++ b/3rdparty/interface/archiveinterface/cliinterface.cpp @@ -201,6 +201,14 @@ PluginFinishType CliInterface::extractFiles(const QList &files, const } } } + + if (bHandleLongName && !checkMoveCapability()) { + qWarning() << "Long filename detected, but moveProgram (" << m_cliProps->property("moveProgram").toString() << ") is not available."; + qWarning() << "Archive format:" << m_mimetype.name() << "Skipping long name handling."; + qWarning() << "The extraction tool will report errors for files with names exceeding system limit (255 bytes)."; + bHandleLongName = false; + } + if (destPath.startsWith("/tmp") && destPath.contains("/deepin-compressor-")) { // 打开解压列表文件 if (!QDir(destPath).exists()) { QDir(destPath).mkpath(destPath); @@ -242,6 +250,7 @@ PluginFinishType CliInterface::extractFiles(const QList &files, const } else { password = options.password; } + if (!bLnfs) { for (QMap::const_iterator iter = arcData.mapFileEntry.begin(); iter != arcData.mapFileEntry.end(); iter++) { if (NAME_MAX < iter.value().strFileName.toLocal8Bit().length()) { @@ -250,6 +259,14 @@ PluginFinishType CliInterface::extractFiles(const QList &files, const } } } + + if (bHandleLongName && !checkMoveCapability()) { + qWarning() << "Long filename detected, but moveProgram (" << m_cliProps->property("moveProgram").toString() << ") is not available."; + qWarning() << "Archive format:" << m_mimetype.name() << "Skipping long name handling."; + qWarning() << "The extraction tool will report errors for files with names exceeding system limit (255 bytes)."; + bHandleLongName = false; + } + if (bHandleLongName) { if (!handleLongNameExtract(arcData.mapFileEntry.values())) { m_eErrorType = ET_FileWriteError; @@ -1110,6 +1127,17 @@ bool CliInterface::moveExtractTempFilesToDest(const QList &files, con return moveSuccess; } +bool CliInterface::checkMoveCapability() +{ + bool hasMoveCapability = false; + QString moveProgram = m_cliProps->property("moveProgram").toString(); + if (!moveProgram.isEmpty()) { + QString moveProgramPath = QStandardPaths::findExecutable(moveProgram); + hasMoveCapability = !moveProgramPath.isEmpty(); + } + return hasMoveCapability; +} + void CliInterface::removeExtractedFilesOnFailure(const QString &strTargetPath, const QList &entries) { QList listToRemove = entries; diff --git a/3rdparty/interface/archiveinterface/cliinterface.h b/3rdparty/interface/archiveinterface/cliinterface.h index 8b934e40..64913354 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.h +++ b/3rdparty/interface/archiveinterface/cliinterface.h @@ -202,6 +202,8 @@ class CliInterface : public ReadWriteArchiveInterface bool handleLongNameExtract(const QList &files); + bool checkMoveCapability(); + private slots: /** * @brief readStdout 读取命令行输出