From cccd64f35e6fce405e200c5cefc5e70c204f7b08 Mon Sep 17 00:00:00 2001 From: gongheng Date: Thu, 20 Nov 2025 13:32:59 +0800 Subject: [PATCH] Fix: [smb] Compressed file seek detection -- Compressed file seek detection Log: fix issue Bug: Bug: https://pms.uniontech.com/bug-view-278613.html --- .../archiveinterface/cliinterface.cpp | 31 +++++++++++++++ 3rdparty/interface/common.cpp | 39 +++++++++++++++++++ 3rdparty/interface/common.h | 5 +++ 3rdparty/interface/commonstruct.h | 1 + .../libarchive/libarchiveplugin.cpp | 5 +++ 3rdparty/libzipplugin/libzipplugin.cpp | 12 ++++++ src/source/common/uistruct.h | 1 + src/source/mainwindow.cpp | 24 ++++++++++++ 8 files changed, 118 insertions(+) diff --git a/3rdparty/interface/archiveinterface/cliinterface.cpp b/3rdparty/interface/archiveinterface/cliinterface.cpp index 0209b23cf..833d0a871 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.cpp +++ b/3rdparty/interface/archiveinterface/cliinterface.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include "common.h" #include @@ -73,6 +74,16 @@ PluginFinishType CliInterface::list() m_workStatus = WT_List; + // 是否支持seek + if(!m_common->isSupportSeek(m_strArchiveName)) { + QTimer::singleShot(1000, this, [=]() { + m_eErrorType = ET_FileSeekError; + emit signalprogress(100); + emit signalFinished(PFT_Error); + }); + return PFT_Error; + } + bool ret = false; ret = runProcess(m_cliProps->property("listProgram").toString(), m_cliProps->listArgs(m_strArchiveName, DataManager::get_instance().archiveData().strPassword)); @@ -89,6 +100,16 @@ PluginFinishType CliInterface::testArchive() PluginFinishType CliInterface::extractFiles(const QList &files, const ExtractionOptions &options) { + // 是否支持seek + if(!m_common->isSupportSeek(m_strArchiveName)) { + QTimer::singleShot(1000, this, [=]() { + m_eErrorType = ET_FileSeekError; + emit signalprogress(100); + emit signalFinished(PFT_Error); + }); + return PFT_Nomral; + } + bool bDlnfs = m_common->isSubpathOfDlnfs(options.strTargetPath); setProperty("dlnfs", bDlnfs); ArchiveData arcData = DataManager::get_instance().archiveData(); @@ -302,6 +323,16 @@ bool CliInterface::doKill() PluginFinishType CliInterface::addFiles(const QList &files, const CompressOptions &options) { + // 是否支持seek + if (!files.isEmpty() && !m_common->isSupportSeek(m_strArchiveName)) { + QTimer::singleShot(1000, this, [=]() { + m_eErrorType = ET_FileSeekError; + emit signalprogress(100); + emit signalFinished(PFT_Error); + }); + return PFT_Nomral; + } + setPassword(QString()); m_workStatus = WT_Add; m_files = files; diff --git a/3rdparty/interface/common.cpp b/3rdparty/interface/common.cpp index c9a8082d4..f8aefb785 100644 --- a/3rdparty/interface/common.cpp +++ b/3rdparty/interface/common.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include @@ -445,6 +446,44 @@ bool Common::isSubpathOfDlnfs(const QString &path) }); } +bool Common::isSupportSeek(QString sFileName) +{ + QFileInfo info(sFileName); + if(info.exists()) { + QFile file(sFileName); + if(file.open(QIODevice::ReadOnly)) { + if (file.seek(0)) { + file.close(); + return true; // 支持 seek + } + } + file.close(); + } else { + // 指定临时文件的目录 + QString tempDir = info.absoluteDir().path(); // 替换为你的目录路径 + QString fileTemplate = tempDir + "/tempfile_XXXXXX"; // 文件名模板 + // 创建 QTemporaryFile + QTemporaryFile tempFile(fileTemplate); + tempFile.setAutoRemove(true); + // 尝试打开临时文件 + if (tempFile.open()) { + tempFile.write("test\n"); + tempFile.flush(); + } + tempFile.close(); + QString sFileName = tempFile.fileName(); + QFile file(sFileName); + if(file.open(QIODevice::ReadOnly)) { + if (file.seek(0)) { + file.close(); + return true; // 支持 seek + } + } + file.close(); + } + return false; +} + bool Common::findDlnfsPath(const QString &target, Compare func) { Q_ASSERT(func); diff --git a/3rdparty/interface/common.h b/3rdparty/interface/common.h index b439c8b4c..57cf29690 100644 --- a/3rdparty/interface/common.h +++ b/3rdparty/interface/common.h @@ -42,6 +42,11 @@ class Common: public QObject QString handleLongNameforPath(const QString &strFilePath, const QString &entryName, QMap &mapLongDirName, QMap &mapRealDirValue); //当前文件系统是否支持长文件 bool isSubpathOfDlnfs(const QString &path); + /** + * @brief isSupportSeek 是否支持seek操作 + * @param sFileName 文件名 + */ + bool isSupportSeek(QString sFileName); private: //通过mount对应方法判断文件系统是否支持长文件 bool findDlnfsPath(const QString &target, Compare func); diff --git a/3rdparty/interface/commonstruct.h b/3rdparty/interface/commonstruct.h index d6f8a11e0..d1623e41e 100644 --- a/3rdparty/interface/commonstruct.h +++ b/3rdparty/interface/commonstruct.h @@ -39,6 +39,7 @@ enum ErrorType { ET_UserCancelOpertion, // 用户取消操作 ET_ExistVolume, // 分卷已存在 + ET_FileSeekError // 文件不支持seek }; //加密类型 diff --git a/3rdparty/libarchive/libarchive/libarchiveplugin.cpp b/3rdparty/libarchive/libarchive/libarchiveplugin.cpp index 2f3f61fa7..976c5603c 100644 --- a/3rdparty/libarchive/libarchive/libarchiveplugin.cpp +++ b/3rdparty/libarchive/libarchive/libarchiveplugin.cpp @@ -69,6 +69,11 @@ PluginFinishType LibarchivePlugin::list() QString fileName = fInfo.fileName(); //因为tar.bz2、tar.lzma、tar.Z直接list时间较长,所以先用7z解压再list处理 if (fileName.endsWith(".tar.bz2") || fileName.endsWith(".tar.lzma") || fileName.endsWith(".tar.Z")) { + // 是否支持seek + if (!m_common->isSupportSeek(m_strArchiveName)) { + m_eErrorType = ET_FileSeekError; + return PFT_Error; + } // 设置解压临时路径 QString strProcessID = QString::number(QCoreApplication::applicationPid()); // 获取应用进程号 QString tempFilePath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) diff --git a/3rdparty/libzipplugin/libzipplugin.cpp b/3rdparty/libzipplugin/libzipplugin.cpp index 4edbd29ed..f654918b2 100644 --- a/3rdparty/libzipplugin/libzipplugin.cpp +++ b/3rdparty/libzipplugin/libzipplugin.cpp @@ -83,6 +83,12 @@ PluginFinishType LibzipPlugin::list() int errcode = 0; zip_error_t err; + // 是否支持seek + if (!m_common->isSupportSeek(m_strArchiveName)) { + m_eErrorType = ET_FileSeekError; + return PFT_Error; + } + // 打开压缩包文件 zip_t *archive = zip_open(QFile::encodeName(m_strArchiveName).constData(), ZIP_RDONLY, &errcode); // 打开压缩包文件 zip_error_init_with_code(&err, errcode); @@ -136,6 +142,12 @@ PluginFinishType LibzipPlugin::extractFiles(const QList &files, const // m_bHandleCurEntry = false; //false:提取使用选中文件及子文件 true:提取使用选中文件 zip_error_t err; + // 是否支持seek + if (!m_common->isSupportSeek(m_strArchiveName)) { + m_eErrorType = ET_FileSeekError; + return PFT_Error; + } + // 打开压缩包 zip_t *archive = zip_open(QFile::encodeName(m_strArchiveName).constData(), ZIP_RDONLY, &errcode); zip_error_init_with_code(&err, errcode); diff --git a/src/source/common/uistruct.h b/src/source/common/uistruct.h index 17075efcb..8487b3396 100644 --- a/src/source/common/uistruct.h +++ b/src/source/common/uistruct.h @@ -181,6 +181,7 @@ enum ErrorInfo { EI_InsufficientDiskSpace, // 磁盘空间不足 EI_ArchiveNoData, // 压缩包无数据 EI_ExistVolume, // 分卷已存在 + EI_FileSeekError // seek失败 }; // 启动应用的方式 diff --git a/src/source/mainwindow.cpp b/src/source/mainwindow.cpp index 8395a9d81..af262fb89 100644 --- a/src/source/mainwindow.cpp +++ b/src/source/mainwindow.cpp @@ -1808,6 +1808,10 @@ void MainWindow::handleJobErrorFinished(ArchiveJob::JobType eJobType, ErrorType case ET_ExistVolume: showErrorMessage(FI_Compress, EI_ExistVolume, true); break; + // ftp目录不支持seek操作 + case ET_FileSeekError: + showErrorMessage(FI_Compress, EI_FileSeekError, true); + break; default: { showErrorMessage(FI_Compress, EI_CreatArchiveFailed, true); break; @@ -1863,6 +1867,10 @@ void MainWindow::handleJobErrorFinished(ArchiveJob::JobType eJobType, ErrorType case ET_WrongPassword: showErrorMessage(FI_Load, EI_WrongPassword); break; + // ftp目录不支持seek操作 + case ET_FileSeekError: + showErrorMessage(FI_Load, EI_FileSeekError); + break; default: showErrorMessage(FI_Load, EI_ArchiveDamaged); break; @@ -1949,6 +1957,10 @@ void MainWindow::handleJobErrorFinished(ArchiveJob::JobType eJobType, ErrorType !(StartupType::ST_ExtractHere == m_eStartupType || StartupType::ST_Extractto == m_eStartupType)); break; } + // ftp目录不支持seek操作 + case ET_FileSeekError: + showErrorMessage(FI_Uncompress, EI_FileSeekError); + break; case ET_PluginError: { // 无可用插件 showErrorMessage(FI_Uncompress, EI_NoPlugin); @@ -2317,6 +2329,10 @@ void MainWindow::showErrorMessage(FailureInfo fFailureInfo, ErrorInfo eErrorInfo m_pFailurePage->setFailureDetail(tr("The compressed volumes already exist")); } break; + case EI_FileSeekError: { + m_pFailurePage->setFailureDetail(tr("No compression support in current directory. Download the files to a local device.")); + } + break; default: break; } @@ -2343,6 +2359,10 @@ void MainWindow::showErrorMessage(FailureInfo fFailureInfo, ErrorInfo eErrorInfo m_pFailurePage->setFailureDetail(tr("Some volumes are missing")); } break; + case EI_FileSeekError: { + m_pFailurePage->setFailureDetail(tr("Can't open compressed packages in current directory. Download the compressed package to a local device.")); + } + break; default: break; } @@ -2384,6 +2404,10 @@ void MainWindow::showErrorMessage(FailureInfo fFailureInfo, ErrorInfo eErrorInfo m_pFailurePage->setFailureDetail(tr("Insufficient disk space")); } break; + case EI_FileSeekError: { + m_pFailurePage->setFailureDetail(tr("No extraction support in current directory. Download the compressed package to a local device.")); + } + break; default: break; }