Skip to content

fix: handle password prompt and missing list in long filename extraction #413

Merged
deepin-bot[bot] merged 3 commits into
linuxdeepin:release/eaglefrom
LiHua000:release/eagle
May 19, 2026
Merged

fix: handle password prompt and missing list in long filename extraction #413
deepin-bot[bot] merged 3 commits into
linuxdeepin:release/eaglefrom
LiHua000:release/eagle

Conversation

LiHua000 added 3 commits May 19, 2026 14:02
- Add password detection in handleLongNameExtract() for content-encrypted
  archives to prevent UI freeze
- Remove FILE_MAX_SIZE check so right-click extract always lists first,
  ensuring long filename prescan has archive data available

Log: fix bug

Bug:https://pms.uniontech.com//bug-view-361845.html
Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @LiHua000, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的Git Diff代码。本次修改主要涉及:.gitignore的更新、解压长文件名时处理加密压缩包密码提示的逻辑重构、以及解压选项条件的微调和一个信号槽连接的移除。

以下是针对语法逻辑、代码质量、代码性能和代码安全四个方面的详细审查意见和改进建议:

1. 语法与逻辑

  • .gitignore 格式问题
    • 在新增的 # ai 区块中,.agents 前面有缩进(空格)。.gitignore 虽然支持部分空格,但行首的空格可能会导致匹配失效或被误认为是文件名的一部分。建议去掉行首空格。
  • 变量作用域与逻辑漏洞
    • cliinterface.cpp 中,password 变量在 if (password.isEmpty()) 分支内被重新赋值:password = query.password();。但是,这个 password按值传递的局部变量(或参数),它的改变不会影响到外层循环中后续对 files 的遍历。
    • 如果 handleLongNameExtract 处理的是多个文件,且外层还有循环,当前获取到的密码无法被下一次循环复用,可能导致重复弹窗。需要确认 password 是否应该声明为引用(&),或者通过 DataManager 在循环开始前统一更新密码。
  • 信号槽移除的潜在逻辑破坏
    • singlejob.cpp 中,移除了 error 信号到 slotError 槽的连接。请务必确认 m_pInterface 的错误信号是否在其他地方(如构造函数或父类)进行了广播转发?如果这是唯一的错误传递通道,移除后UI层将无法捕获到底层解压错误,导致静默失败。

2. 代码质量

  • 重复代码
    • 密码输入后重新启动进程的代码块,与外部启动进程的代码高度重复(设置 Program、Args、Start 等)。建议将其抽取为一个私有方法(如 startExtractProcess(const QString &pwd)),以提高可读性和可维护性。
  • 硬编码的魔法数字
    • waitForFinished(200)waitForFinished(3000) 这些数字缺乏上下文。建议定义常量,如 PROCESS_POLL_TIMEOUT_MS = 200PROCESS_KILL_TIMEOUT_MS = 3000
  • 未使用的变量
    • bPasswordEntered 标志位的作用仅仅是跳出外层 while 循环。其实可以直接使用 break 标签或重构循环逻辑来消除这个多余的变量。

3. 代码性能

  • 阻塞性死循环等待
    • while (!pProcess->waitForFinished(200)) 本质上是一个忙等待(Busy-Waiting)循环,这会阻塞当前线程(很可能是主线程或工作线程),导致CPU占用率升高,界面卡顿。
    • 改进建议:Qt 的 QProcess 是基于事件循环的,强烈建议使用异步信号槽机制(readyReadStandardOutputfinished 等)来处理密码提示,而不是使用 waitForFinished 进行阻塞轮询。
  • 频繁的字符串解码与分割
    • while 循环内,每次有数据都会调用 readAllStandardOutput() 并通过 fromLocal8Bit 转换为 QStringsplit('\n')。如果数据包分片到达,可能会把一行完整的提示信息截断,导致 isPasswordPrompt(line) 匹配失败。
    • 改进建议:应该维护一个内部缓冲区 QByteArray,将读取到的数据追加到缓冲区,按 \n 提取完整行后再进行判断。

4. 代码安全

  • 密码内存驻留风险
    • DataManager::get_instance().archiveData().strPassword = password; 将明文密码存储在了全局单例中,且 password 作为 QString 会长期驻留在堆内存中,直到被覆盖或程序退出,这增加了密码泄露的风险。
    • 改进建议:如果可能,使用后应立即清空内存(虽然 QString 的内存管理较难强制清零,但至少应避免长期持有明文密码)。
  • 进程 Kill 导致的数据损坏
    • 当检测到密码提示时,代码直接调用 pProcess->kill()。在解压过程中强制终止进程,可能会导致部分解压的临时文件残留在磁盘上,占用空间甚至导致后续解压冲突。
    • 改进建议:应先尝试 terminate()(发送信号让进程优雅退出),等待超时后再 kill()。同时,在解压失败或取消后,应该增加清理目标目录临时文件的逻辑。

💡 综合改进建议代码示例

针对 cliinterface.cpp 中的核心逻辑,我提供了一个优化后的代码版本,解决了缓冲区截断、忙等待(改为更合理的处理方式,若受限于架构无法完全异步,至少优化了读取逻辑)以及代码冗余的问题:

// 建议在类定义中增加常量
static const int PROCESS_POLL_TIMEOUT_MS = 200;
static const int PROCESS_KILL_TIMEOUT_MS = 3000;

bool CliInterface::handleLongNameExtract(const QList<FileEntry> &files)
{
    // ... 前置代码 ...
            pProcess->setProgram(m_cliProps->property("extractProgram").toString(),
                                 m_cliProps->extractArgs(absoluteDestinationPath, fileList, false, password));
            pProcess->start();

            // 检测加密文件解压时的密码提示,避免进程卡死
            if (password.isEmpty()) {
                QByteArray buffer;
                bool needPassword = false;
                
                while (!pProcess->waitForFinished(PROCESS_POLL_TIMEOUT_MS)) {
                    // 追加读取数据到缓冲区
                    buffer.append(pProcess->readAllStandardOutput());
                    
                    // 按行处理缓冲区
                    while (buffer.contains('\n')) {
                        int idx = buffer.indexOf('\n');
                        QString line = QString::fromLocal8Bit(buffer.left(idx));
                        buffer.remove(0, idx + 1);

                        if (isPasswordPrompt(line)) {
                            needPassword = true;
                            break;
                        }
                    }
                    
                    if (needPassword) {
                        break;
                    }
                }

                if (needPassword) {
                    // 优先尝试优雅退出,避免临时文件损坏
                    pProcess->terminate();
                    if (!pProcess->waitForFinished(PROCESS_KILL_TIMEOUT_MS)) {
                        pProcess->kill();
                        pProcess->waitForFinished(PROCESS_KILL_TIMEOUT_MS);
                    }

                    PasswordNeededQuery query(m_strArchiveName);
                    emit signalQuery(&query);
                    query.waitForResponse();

                    if (query.responseCancelled()) {
                        m_eErrorType = ET_NeedPassword;
                        // TODO: 建议在此处添加清理解压临时文件的逻辑
                        return false;
                    }

                    password = query.password();
                    DataManager::get_instance().archiveData().strPassword = password;

                    // 重新启动解压进程
                    pProcess->setPtyChannels(KPtyProcess::StdinChannel);
                    pProcess->setOutputChannelMode(KProcess::MergedChannels);
                    pProcess->setNextOpenMode(QIODevice::ReadWrite | QIODevice::Unbuffered | QIODevice::Text);
                    pProcess->setProgram(m_cliProps->property("extractProgram").toString(),
                                         m_cliProps->extractArgs(absoluteDestinationPath, fileList, false, password));
                    pProcess->start();
                    pProcess->waitForFinished(-1);
                }
            } else {
                pProcess->waitForFinished(-1);
            }
    // ... 后置代码 ...
}

最后提醒:关于 singlejob.cpp 中移除的 error 槽函数,请务必与团队成员确认该改动的副作用,确保错误信息能通过其他途径(如 slotFinished 中的状态值)正确传递到UI层。

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: LiHua000, lzwind

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@LiHua000
Copy link
Copy Markdown
Contributor Author

/merge

@deepin-bot deepin-bot Bot merged commit 81b554b into linuxdeepin:release/eagle May 19, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants