@@ -470,23 +470,47 @@ PluginFinishType CliInterface::addFiles(const QList<FileEntry> &files, const Com
470470 QFileInfo (m_strArchiveName).path (),
471471 sRenameList );
472472
473- if (options.bTar_7z ) { // 压缩tar.7z文件
473+ if (options.bTar_7z ) { // 压缩tar.7z:用两个 QProcess 管道,避免 shell 拼接与密码特殊字符问题
474474 m_isTar7z = true ;
475- m_filesSize = options.qTotalSize ; // 待压缩文件总大小
476- m_scriptPath = QDir::tempPath () + " /tempScript_" + QString::number (QDateTime::currentDateTime ().toMSecsSinceEpoch ()) + " .sh" ;
477- QFile scriptFile (m_scriptPath);
478- if (scriptFile.open (QIODevice::WriteOnly | QIODevice::Text)) {
479- QTextStream out (&scriptFile);
480- out << " #!/bin/bash\n " ;
481- for (const QString &arg : arguments) {
482- out << arg << " \n " ;
483- }
484- scriptFile.close ();
485- QProcess::execute (" chmod" , { " +x" , m_scriptPath });
486- ret = runProcess (m_scriptPath, QStringList ());
487- } else {
488- qWarning () << " Failed to create temporary script file." ;
475+ m_filesSize = options.qTotalSize ;
476+ const QString archivePath = temp_archiveName.isEmpty () ? m_strArchiveName : temp_archiveName;
477+ QStringList tarArgs = m_cliProps->getTar7zTarArgs (fileList, sRenameList );
478+ QStringList sevenZArgs = m_cliProps->getTar7z7zArgs (archivePath, password, options.bHeaderEncryption ,
479+ options.iCompressionLevel , options.strCompressionMethod ,
480+ options.strEncryptionMethod , options.iVolumeSize );
481+ QString tarPath = QStandardPaths::findExecutable (QStringLiteral (" tar" ));
482+ QString sevenZPath = QStandardPaths::findExecutable (m_cliProps->property (" addProgram" ).toString ());
483+ if (tarPath.isEmpty () || sevenZPath.isEmpty ()) {
489484 ret = false ;
485+ } else {
486+ m_tar7z_7z = new QProcess ();
487+ m_tarProcess = new QProcess ();
488+ m_tarProcess->setStandardOutputProcess (m_tar7z_7z);
489+ m_tar7z_7z->setProcessChannelMode (QProcess::MergedChannels);
490+ connect (m_tar7z_7z, &QProcess::readyReadStandardOutput, this , [this ]() { readStdout (); });
491+ connect (m_tar7z_7z, QOverload<int , QProcess::ExitStatus>::of (&QProcess::finished), this , &CliInterface::processFinished);
492+ m_stdOutData.clear ();
493+ m_isProcessKilled = false ;
494+ m_tarProcess->start (tarPath, tarArgs);
495+ if (m_tarProcess->waitForStarted (5000 )) {
496+ m_tar7z_7z->start (sevenZPath, sevenZArgs);
497+ // 不在此处 waitForStarted(7z),避免 7z 等 stdin 时阻塞主线程导致卡死
498+ ret = m_tar7z_7z->state () == QProcess::Starting || m_tar7z_7z->state () == QProcess::Running;
499+ if (ret) {
500+ m_processId = m_tar7z_7z->processId ();
501+ m_childProcessId = QVector<qint64>() << m_tarProcess->processId ();
502+ }
503+ connect (m_tar7z_7z, &QProcess::errorOccurred, this , [this ](QProcess::ProcessError) {
504+ if (m_tar7z_7z && m_tar7z_7z->state () == QProcess::NotRunning) {
505+ processFinished (-1 , QProcess::CrashExit);
506+ }
507+ });
508+ } else {
509+ ret = false ;
510+ }
511+ if (!ret) {
512+ deleteProcess ();
513+ }
490514 }
491515 } else {
492516 QString processName = m_cliProps->property (" addProgram" ).toString ();
@@ -507,7 +531,11 @@ PluginFinishType CliInterface::addFiles(const QList<FileEntry> &files, const Com
507531 qInfo () << " mtp 压缩完成,现在开始移动" ;
508532 QStringList args_list;
509533 args_list << temp_archiveName << m_strArchiveName;
510- m_process->waitForFinished ();
534+ if (m_tar7z_7z) {
535+ m_tar7z_7z->waitForFinished (-1 );
536+ } else if (m_process) {
537+ m_process->waitForFinished ();
538+ }
511539 QProcess mover;
512540 ret = 0 == mover.execute (" mv" , args_list);
513541 ret = mover.exitCode () == QProcess::NormalExit;
@@ -795,22 +823,53 @@ bool CliInterface::runProcess(const QString &programName, const QStringList &arg
795823 return true ;
796824}
797825
826+ bool CliInterface::killTar7zPipelineIfActive ()
827+ {
828+ if (!m_tar7z_7z) {
829+ return false ;
830+ }
831+ if (m_tarProcess && m_tarProcess->state () != QProcess::NotRunning) {
832+ m_tarProcess->kill ();
833+ }
834+ if (m_tar7z_7z->state () != QProcess::NotRunning) {
835+ m_tar7z_7z->kill ();
836+ }
837+ m_isProcessKilled = true ;
838+ return true ;
839+ }
840+
798841void CliInterface::deleteProcess ()
799842{
843+ if (m_tar7z_7z) {
844+ m_tar7z_7z->blockSignals (true );
845+ if (m_tar7z_7z->state () != QProcess::NotRunning) {
846+ m_tar7z_7z->kill ();
847+ m_tar7z_7z->waitForFinished (500 );
848+ }
849+ delete m_tar7z_7z;
850+ m_tar7z_7z = nullptr ;
851+ if (m_tarProcess) {
852+ m_tarProcess->blockSignals (true );
853+ if (m_tarProcess->state () != QProcess::NotRunning) {
854+ m_tarProcess->kill ();
855+ m_tarProcess->waitForFinished (500 );
856+ }
857+ delete m_tarProcess;
858+ m_tarProcess = nullptr ;
859+ }
860+ return ;
861+ }
800862 if (m_process) {
801863 readStdout (true );
802864 m_process->blockSignals (true ); // delete m_process之前需要断开所有m_process信号,防止重复处理
803865 delete m_process;
804866 m_process = nullptr ;
805- if (!m_scriptPath.isEmpty ()) {
806- QFile::remove (m_scriptPath);
807- }
808867 }
809868}
810869
811870void CliInterface::handleProgress (const QString &line)
812871{
813- if (m_process && m_process->program ().at (0 ).contains (" 7z" )) { // 解析7z相关进度、文件名
872+ if (m_tar7z_7z || ( m_process && m_process->program ().at (0 ).contains (" 7z" ))) { // 解析7z相关进度、文件名(含 tar.7z 管道)
814873 int pos = line.indexOf (QLatin1Char (' %' ));
815874 if (pos > 1 ) {
816875 int percentage = line.midRef (pos - 3 , 3 ).toInt ();
@@ -904,24 +963,6 @@ void CliInterface::handleProgress(const QString &line)
904963
905964 emit signalCurFileName (fileName);
906965 }
907- } else if (m_process && m_process->program ().at (0 ).contains (" tempScript" )) {
908- // 处理tar.7z进度
909- // "\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]"
910- // "\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]"
911- int pos = line.lastIndexOf (" + [Content]" );
912- if (pos > 1 ) {
913- int mPos = line.lastIndexOf (" M " );
914- int bPos = line.lastIndexOf (" \b " , mPos );
915- QString tempLine = line.left (mPos );
916- // 已经压缩的文件大小
917- qint64 compressedSize = tempLine.right (tempLine.size () - bPos - 1 ).toLongLong ();
918- // 计算文件大小计算百分比
919- qint64 percentage = compressedSize * 1024 * 1024 * 100 / m_filesSize;
920-
921- emit signalprogress (percentage);
922- // 无法获取正在压缩的某个文件名
923- // emit signalCurFileName();
924- }
925966 }
926967}
927968
@@ -1031,9 +1072,14 @@ PluginFinishType CliInterface::handleCorrupt()
10311072
10321073void CliInterface::writeToProcess (const QByteArray &data)
10331074{
1034- Q_ASSERT (m_process);
10351075 Q_ASSERT (!data.isNull ());
1036-
1076+ // tar.7z 管道下 stdin 为 tar 输出,不能写入,密码已通过命令行传入
1077+ if (m_tar7z_7z) {
1078+ return ;
1079+ }
1080+ if (!m_process) {
1081+ return ;
1082+ }
10371083 // m_process->write(data);
10381084 m_process->pty ()->write (data);
10391085}
@@ -1290,14 +1336,17 @@ void CliInterface::readStdout(bool handleAll)
12901336 return ;
12911337 }
12921338
1293- Q_ASSERT (m_process);
1339+ QProcess *outProcess = m_tar7z_7z ? m_tar7z_7z : m_process;
1340+ if (!outProcess) {
1341+ return ;
1342+ }
12941343
1295- if (!m_process ->bytesAvailable ()) { // 无数据
1344+ if (!outProcess ->bytesAvailable ()) { // 无数据
12961345 return ;
12971346 }
12981347
12991348 // 获取命令行输出
1300- QByteArray dd = m_process ->readAllStandardOutput ();
1349+ QByteArray dd = outProcess ->readAllStandardOutput ();
13011350 m_stdOutData += dd;
13021351
13031352 // 换行分割
@@ -1309,12 +1358,10 @@ void CliInterface::readStdout(bool handleAll)
13091358 // }
13101359 bool isWrongPwd = isWrongPasswordMsg (lines.last ());
13111360
1312- if ((m_process->program ().at (0 ).contains (" 7z" ) && m_process->program ().at (1 ) != " l" ) && !isWrongPwd) {
1313- handleAll = true ; // 7z进度行结束无\n
1314- }
1315-
1316- if ((m_process->program ().at (0 ).contains (" tempScript" )) && !isWrongPwd) {
1317- handleAll = true ; // compress .tar.7z progressline has no \n
1361+ // 7z 或 tar.7z 管道:进度行结束无 \n
1362+ bool is7zAdd = m_tar7z_7z || (m_process && m_process->program ().at (0 ).contains (" 7z" ) && m_process->program ().at (1 ) != " l" );
1363+ if (is7zAdd && !isWrongPwd) {
1364+ handleAll = true ;
13181365 }
13191366
13201367 bool foundErrorMessage = (isWrongPwd || isDiskFullMsg (QLatin1String (lines.last ()))
@@ -1331,7 +1378,7 @@ void CliInterface::readStdout(bool handleAll)
13311378 // because the last line might be incomplete we leave it for now
13321379 // note, this last line may be an empty string if the stdoutdata ends
13331380 // with a newline
1334- if (m_process->program ().at (0 ).contains (" unrar" )) { // 针对unrar的命令行截取
1381+ if (m_process && m_process ->program ().at (0 ).contains (" unrar" )) { // 针对unrar的命令行截取
13351382 m_stdOutData.clear ();
13361383 if (lines.count () > 0 ) {
13371384 if (!(lines[lines.count () - 1 ].endsWith (" %" ) || lines[lines.count () - 1 ].endsWith (" OK " ))) {
0 commit comments