diff --git a/3rdparty/cli7zplugin/cli7zplugin.cpp b/3rdparty/cli7zplugin/cli7zplugin.cpp index 648eca804..0a7b8ee55 100644 --- a/3rdparty/cli7zplugin/cli7zplugin.cpp +++ b/3rdparty/cli7zplugin/cli7zplugin.cpp @@ -151,9 +151,6 @@ bool Cli7zPlugin::isOpenFileFailed(const QString &line) void Cli7zPlugin::killProcess(bool emitFinished) { Q_UNUSED(emitFinished); - if (killTar7zPipelineIfActive()) { - return; - } if (!m_process) { return; } diff --git a/3rdparty/interface/archiveinterface/cliinterface.cpp b/3rdparty/interface/archiveinterface/cliinterface.cpp index 214847c65..2176be6af 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.cpp +++ b/3rdparty/interface/archiveinterface/cliinterface.cpp @@ -470,47 +470,23 @@ PluginFinishType CliInterface::addFiles(const QList &files, const Com QFileInfo(m_strArchiveName).path(), sRenameList); - if (options.bTar_7z) { // 压缩tar.7z:用两个 QProcess 管道,避免 shell 拼接与密码特殊字符问题 + if (options.bTar_7z) { // 压缩tar.7z文件 m_isTar7z = true; - m_filesSize = options.qTotalSize; - const QString archivePath = temp_archiveName.isEmpty() ? m_strArchiveName : temp_archiveName; - QStringList tarArgs = m_cliProps->getTar7zTarArgs(fileList, sRenameList); - QStringList sevenZArgs = m_cliProps->getTar7z7zArgs(archivePath, password, options.bHeaderEncryption, - options.iCompressionLevel, options.strCompressionMethod, - options.strEncryptionMethod, options.iVolumeSize); - QString tarPath = QStandardPaths::findExecutable(QStringLiteral("tar")); - QString sevenZPath = QStandardPaths::findExecutable(m_cliProps->property("addProgram").toString()); - if (tarPath.isEmpty() || sevenZPath.isEmpty()) { - ret = false; - } else { - m_tar7z_7z = new QProcess(); - m_tarProcess = new QProcess(); - m_tarProcess->setStandardOutputProcess(m_tar7z_7z); - m_tar7z_7z->setProcessChannelMode(QProcess::MergedChannels); - connect(m_tar7z_7z, &QProcess::readyReadStandardOutput, this, [this]() { readStdout(); }); - connect(m_tar7z_7z, QOverload::of(&QProcess::finished), this, &CliInterface::processFinished); - m_stdOutData.clear(); - m_isProcessKilled = false; - m_tarProcess->start(tarPath, tarArgs); - if (m_tarProcess->waitForStarted(5000)) { - m_tar7z_7z->start(sevenZPath, sevenZArgs); - // 不在此处 waitForStarted(7z),避免 7z 等 stdin 时阻塞主线程导致卡死 - ret = m_tar7z_7z->state() == QProcess::Starting || m_tar7z_7z->state() == QProcess::Running; - if (ret) { - m_processId = m_tar7z_7z->processId(); - m_childProcessId = QVector() << m_tarProcess->processId(); - } - connect(m_tar7z_7z, &QProcess::errorOccurred, this, [this](QProcess::ProcessError) { - if (m_tar7z_7z && m_tar7z_7z->state() == QProcess::NotRunning) { - processFinished(-1, QProcess::CrashExit); - } - }); - } else { - ret = false; - } - if (!ret) { - deleteProcess(); + m_filesSize = options.qTotalSize; // 待压缩文件总大小 + m_scriptPath = QDir::tempPath() + "/tempScript_" + QString::number(QDateTime::currentDateTime().toMSecsSinceEpoch()) + ".sh"; + QFile scriptFile(m_scriptPath); + if (scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&scriptFile); + out << "#!/bin/bash\n"; + for (const QString &arg : arguments) { + out << arg << "\n"; } + scriptFile.close(); + QProcess::execute("chmod", { "+x", m_scriptPath }); + ret = runProcess(m_scriptPath, QStringList()); + } else { + qWarning() << "Failed to create temporary script file."; + ret = false; } } else { QString processName = m_cliProps->property("addProgram").toString(); @@ -531,11 +507,7 @@ PluginFinishType CliInterface::addFiles(const QList &files, const Com qInfo() << "mtp 压缩完成,现在开始移动"; QStringList args_list; args_list << temp_archiveName << m_strArchiveName; - if (m_tar7z_7z) { - m_tar7z_7z->waitForFinished(-1); - } else if (m_process) { - m_process->waitForFinished(); - } + m_process->waitForFinished(); QProcess mover; ret = 0 == mover.execute("mv", args_list); ret = mover.exitCode() == QProcess::NormalExit; @@ -823,53 +795,22 @@ bool CliInterface::runProcess(const QString &programName, const QStringList &arg return true; } -bool CliInterface::killTar7zPipelineIfActive() -{ - if (!m_tar7z_7z) { - return false; - } - if (m_tarProcess && m_tarProcess->state() != QProcess::NotRunning) { - m_tarProcess->kill(); - } - if (m_tar7z_7z->state() != QProcess::NotRunning) { - m_tar7z_7z->kill(); - } - m_isProcessKilled = true; - return true; -} - void CliInterface::deleteProcess() { - if (m_tar7z_7z) { - m_tar7z_7z->blockSignals(true); - if (m_tar7z_7z->state() != QProcess::NotRunning) { - m_tar7z_7z->kill(); - m_tar7z_7z->waitForFinished(500); - } - delete m_tar7z_7z; - m_tar7z_7z = nullptr; - if (m_tarProcess) { - m_tarProcess->blockSignals(true); - if (m_tarProcess->state() != QProcess::NotRunning) { - m_tarProcess->kill(); - m_tarProcess->waitForFinished(500); - } - delete m_tarProcess; - m_tarProcess = nullptr; - } - return; - } if (m_process) { readStdout(true); m_process->blockSignals(true); // delete m_process之前需要断开所有m_process信号,防止重复处理 delete m_process; m_process = nullptr; + if(!m_scriptPath.isEmpty()) { + QFile::remove(m_scriptPath); + } } } void CliInterface::handleProgress(const QString &line) { - if (m_tar7z_7z || (m_process && m_process->program().at(0).contains("7z"))) { // 解析7z相关进度、文件名(含 tar.7z 管道) + if (m_process && m_process->program().at(0).contains("7z")) { // 解析7z相关进度、文件名 int pos = line.indexOf(QLatin1Char('%')); if (pos > 1) { int percentage = line.midRef(pos - 3, 3).toInt(); @@ -963,6 +904,29 @@ void CliInterface::handleProgress(const QString &line) emit signalCurFileName(fileName); } + } else if (m_process && m_process->program().at(0).contains("tempScript")) { + // 处理tar.7z进度 + // "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 7M + [Content]" + // "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b274M 1 + [Content]" + int pos = line.lastIndexOf(" + [Content]"); + if (pos > 1) { + int mPos = line.lastIndexOf("M "); + int bPos = line.lastIndexOf("\b", mPos); + QString tempLine = line.left(mPos); + // 已经压缩的文件大小 + qint64 compressedSize = tempLine.right(tempLine.size() - bPos - 1).toLongLong(); + // 计算文件大小计算百分比 + qint64 percentage = compressedSize * 1024 * 1024 * 100 / m_filesSize; + + emit signalprogress(percentage); + // tar.7z 无法获取正在压缩的单个文件名,但可以提示正在打包成 tar 文件 + // 发送 tar 文件名提示(去掉 .7z 后缀,显示正在打包的 tar 文件名) + QString tarFileName = QFileInfo(m_strArchiveName).fileName(); + if (tarFileName.endsWith(".7z", Qt::CaseInsensitive)) { + tarFileName = tarFileName.left(tarFileName.length() - 3); + } + emit signalCurFileName(tarFileName); + } } } @@ -1072,14 +1036,9 @@ PluginFinishType CliInterface::handleCorrupt() void CliInterface::writeToProcess(const QByteArray &data) { + Q_ASSERT(m_process); Q_ASSERT(!data.isNull()); - // tar.7z 管道下 stdin 为 tar 输出,不能写入,密码已通过命令行传入 - if (m_tar7z_7z) { - return; - } - if (!m_process) { - return; - } + // m_process->write(data); m_process->pty()->write(data); } @@ -1336,17 +1295,14 @@ void CliInterface::readStdout(bool handleAll) return; } - QProcess *outProcess = m_tar7z_7z ? m_tar7z_7z : m_process; - if (!outProcess) { - return; - } + Q_ASSERT(m_process); - if (!outProcess->bytesAvailable()) { // 无数据 + if (!m_process->bytesAvailable()) { // 无数据 return; } // 获取命令行输出 - QByteArray dd = outProcess->readAllStandardOutput(); + QByteArray dd = m_process->readAllStandardOutput(); m_stdOutData += dd; // 换行分割 @@ -1358,10 +1314,12 @@ void CliInterface::readStdout(bool handleAll) // } bool isWrongPwd = isWrongPasswordMsg(lines.last()); - // 7z 或 tar.7z 管道:进度行结束无 \n - bool is7zAdd = m_tar7z_7z || (m_process && m_process->program().at(0).contains("7z") && m_process->program().at(1) != "l"); - if (is7zAdd && !isWrongPwd) { - handleAll = true; + if ((m_process->program().at(0).contains("7z") && m_process->program().at(1) != "l") && !isWrongPwd) { + handleAll = true; // 7z进度行结束无\n + } + + if ((m_process->program().at(0).contains("tempScript")) && !isWrongPwd) { + handleAll = true; // compress .tar.7z progressline has no \n } bool foundErrorMessage = (isWrongPwd || isDiskFullMsg(QLatin1String(lines.last())) @@ -1378,7 +1336,7 @@ void CliInterface::readStdout(bool handleAll) // because the last line might be incomplete we leave it for now // note, this last line may be an empty string if the stdoutdata ends // with a newline - if (m_process && m_process->program().at(0).contains("unrar")) { // 针对unrar的命令行截取 + if (m_process->program().at(0).contains("unrar")) { // 针对unrar的命令行截取 m_stdOutData.clear(); if (lines.count() > 0) { if (!(lines[lines.count() - 1].endsWith("%") || lines[lines.count() - 1].endsWith("OK "))) { diff --git a/3rdparty/interface/archiveinterface/cliinterface.h b/3rdparty/interface/archiveinterface/cliinterface.h index 089dba380..64913354f 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.h +++ b/3rdparty/interface/archiveinterface/cliinterface.h @@ -143,12 +143,6 @@ class CliInterface : public ReadWriteArchiveInterface */ virtual void killProcess(bool emitFinished = true) = 0; - /** - * @brief killTar7zPipelineIfActive 若当前为 tar.7z 管道则结束两个进程 - * @return 若已结束管道返回 true,否则 false - */ - bool killTar7zPipelineIfActive(); - /** * @brief handleProgress 解析进度并发送进度信号 * @param line @@ -242,8 +236,6 @@ private slots: protected: CliProperties *m_cliProps = nullptr; // 命令属性 /*KProcess*/KPtyProcess *m_process = nullptr; // 工作进程 - QProcess *m_tarProcess = nullptr; // 仅 tar.7z 管道:tar 进程 - QProcess *m_tar7z_7z = nullptr; // 仅 tar.7z 管道:7z 进程(输出来自此进程) PluginFinishType m_finishType = PFT_Nomral; // 插件结束类型 QString m_strEncryptedFileName = QString(); // 当前被解压的加密文件名 QVector m_childProcessId; // 压缩tar.7z文件的子进程Id @@ -270,6 +262,7 @@ private slots: QMap m_mapLongName; // 长文件名统计 QMap m_mapLongDirName; // 长文件夹统计 QMap m_mapRealDirValue; // 真实文件统计 + QString m_scriptPath; // 脚本路径 }; #endif // CLIINTERFACE_H diff --git a/3rdparty/interface/archiveinterface/cliproperties.cpp b/3rdparty/interface/archiveinterface/cliproperties.cpp index bff03b70e..e71e89187 100644 --- a/3rdparty/interface/archiveinterface/cliproperties.cpp +++ b/3rdparty/interface/archiveinterface/cliproperties.cpp @@ -51,9 +51,76 @@ QStringList CliProperties::addArgs(const QString &archive, const QStringList &fi Q_ASSERT(!password.isEmpty()); } - // tar.7z 已改为 getTar7zTarArgs/getTar7z7zArgs + QProcess 管道,不再用脚本,此处不再拼命令串 if (isTar7z) { - return QStringList(); + // tar.7z压缩命令重命名:tar --transform='flags=r;s|oldname1|newname1|' --transform='flags=r;s|oldname2|newname3|' .... + // tar.7z压缩命令: tar cf - -C /home/username/Desktop/ 1.txt -C /home/username/Desktop/2/3/ 4K | 7z a - si new.tar.7z + const QString oneSpace = " "; //一个空格 + QVector strold = {" ", "!", "$", "&", "*", "(", ")", "<", ">", "+", "-", ";"}; + QVector strnew = {"\\ ", "\\!", "\\$", "\\&", "\\*", "\\(", "\\)", "\\<", "\\>", "\\+", "\\-", "\\;"}; + // 注意字符转意,待优化 + + QStringList args; + + QString tmp = "tar cf - "; + //重命名文件 + if(!renameList.isEmpty()) { + tmp = "tar "; + for (QString sRename: renameList) { + tmp = tmp + sRename + oneSpace; + } + tmp = tmp + "-cf - "; + } + for (QString file : files) { + for (int n = 0; n < strold.length(); ++n) { + file.replace(strold[n], strnew[n]); + } + + if (file.endsWith('/')) { + file.chop(1); + } + + int pos = file.lastIndexOf('/'); + if (pos > 0) { + //此处传进来的files是绝对路径,处理和dev分支有点区别, + tmp += "-C " + file.mid(0, pos + 1) + oneSpace + file.mid(pos + 1) + oneSpace; + } + } + + tmp += "| 7z a -si "; + if (!password.isEmpty()) { + for (QString &val : substitutePasswordSwitch(password, headerEncryption)) { + tmp += val + oneSpace; + } + } + + if (compressionLevel > -1) { + tmp += substituteCompressionLevelSwitch(compressionLevel) + oneSpace; + } + + if (!compressionMethod.isEmpty()) { + tmp += substituteCompressionMethodSwitch(compressionMethod) + oneSpace; + } + + if (!encryptionMethod.isEmpty()) { + tmp += substituteEncryptionMethodSwitch(encryptionMethod) + oneSpace; + } + if (volumeSize > 0) { + tmp += substituteMultiVolumeSwitch(volumeSize) + oneSpace; + } + + if (!m_progressarg.isEmpty()) { + tmp += m_progressarg + oneSpace; + } + + QString tmparchive = archive; + for (int n = 0; n < strold.length(); ++n) { + tmparchive.replace(strold[n], strnew[n]); + } + + tmp += tmparchive; + args << tmp; + // qInfo() << tmp; + return args; } else { QStringList args; for (const QString &s : qAsConst(m_addSwitch)) { @@ -91,72 +158,6 @@ QStringList CliProperties::addArgs(const QString &archive, const QStringList &fi } } -QStringList CliProperties::getTar7zTarArgs(const QStringList &files, const QStringList &renameList) -{ - QStringList args; - if (renameList.isEmpty()) { - args << QStringLiteral("cf") << QStringLiteral("-"); - } else { - args << renameList; - args << QStringLiteral("-cf") << QStringLiteral("-"); - } - for (QString file : files) { - if (file.endsWith(QLatin1Char('/'))) { - file.chop(1); - } - int pos = file.lastIndexOf(QLatin1Char('/')); - if (pos > 0) { - args << QStringLiteral("-C") << file.mid(0, pos) << file.mid(pos + 1); - } else if (pos == 0) { - args << QStringLiteral("-C") << QStringLiteral("/") << file.mid(1); - } else { - args << QStringLiteral("-C") << QStringLiteral(".") << file; - } - } - return args; -} - -QStringList CliProperties::getTar7z7zArgs(const QString &archive, const QString &password, bool headerEncryption, - int compressionLevel, const QString &compressionMethod, - const QString &encryptionMethod, int volumeSize) -{ - QStringList args; - args << QStringLiteral("a") << QStringLiteral("-si") << archive; - if (!password.isEmpty()) { - // 单参数 -p+密码,避免 7z 再从 stdin 提示输入导致管道卡死 - args << (QStringLiteral("-p") + password); - } - if (compressionLevel > -1) { - const QString s = substituteCompressionLevelSwitch(compressionLevel); - if (!s.isEmpty()) { - args << s; - } - } - if (!compressionMethod.isEmpty()) { - const QString s = substituteCompressionMethodSwitch(compressionMethod); - if (!s.isEmpty()) { - args << s; - } - } - if (!encryptionMethod.isEmpty()) { - const QString s = substituteEncryptionMethodSwitch(encryptionMethod); - if (!s.isEmpty()) { - args << s; - } - } - if (volumeSize > 0) { - const QString s = substituteMultiVolumeSwitch(volumeSize); - if (!s.isEmpty()) { - args << s; - } - } - if (!m_progressarg.isEmpty()) { - args << m_progressarg; - } - args.removeAll(QString()); - return args; -} - QStringList CliProperties::commentArgs(const QString &archive, const QString &commentfile) { QStringList args; diff --git a/3rdparty/interface/archiveinterface/cliproperties.h b/3rdparty/interface/archiveinterface/cliproperties.h index 7677e82f9..57a363c33 100644 --- a/3rdparty/interface/archiveinterface/cliproperties.h +++ b/3rdparty/interface/archiveinterface/cliproperties.h @@ -83,12 +83,6 @@ class CliProperties : public QObject bool isTar7z, const QString &globalWorkDir, const QStringList &renameList = QStringList()); - /** tar.7z 管道:仅 tar 参数(QStringList,无 shell 拼接),供 QProcess 使用 */ - QStringList getTar7zTarArgs(const QStringList &files, const QStringList &renameList = QStringList()); - /** tar.7z 管道:仅 7z 参数(密码用 "-p" + 独立 argv,无 shell),供 QProcess 使用 */ - QStringList getTar7z7zArgs(const QString &archive, const QString &password, bool headerEncryption, - int compressionLevel, const QString &compressionMethod, - const QString &encryptionMethod, int volumeSize); QStringList commentArgs(const QString &archive, const QString &commentfile); QStringList deleteArgs(const QString &archive, const QList &files, const QString &password); QStringList extractArgs(const QString &archive, const QStringList &files, bool preservePaths, const QString &password); diff --git a/src/source/mainwindow.cpp b/src/source/mainwindow.cpp index f936edbdf..90b581aa6 100644 --- a/src/source/mainwindow.cpp +++ b/src/source/mainwindow.cpp @@ -2606,7 +2606,16 @@ bool MainWindow::handleArguments_Open(const QStringList &listParam) qInfo() << "打开文件"; m_eStartupType = StartupType::ST_Normal; // 加载单个压缩包数据 - loadArchive(listParam[0]); + static bool firstLoad = true; + if (UiTools::isWayland() && firstLoad) { + firstLoad = false; + auto path = listParam[0]; + QTimer::singleShot(200, [this, &path]() { + loadArchive(path); + }); + } else { + loadArchive(listParam[0]); + } return true; }