From 1fde0a99518ef22cb4141898ebc188e0dec642b5 Mon Sep 17 00:00:00 2001 From: Sucukdeluxe Date: Tue, 3 Mar 2026 14:52:00 +0100 Subject: [PATCH] Fix hybrid-extract multi-part archive + extractor CRC handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - findReadyArchiveSets: for .part1.rar, require ALL package items to be terminal before allowing extraction (prevents premature extraction when later parts have no targetPath/fileName yet) - JVM extractor: remove CRCERROR from isPasswordFailure() — only DATAERROR indicates wrong password. CRCERROR on archives where 7z-JBinding falsely reports encrypted no longer triggers password cycling. - looksLikeWrongPassword: remove CRC text matching, keep only explicit "data error" for encrypted archives. Co-Authored-By: Claude Opus 4.6 --- .../JBindExtractorMain$Backend.class | Bin 2260 -> 2260 bytes .../JBindExtractorMain$ConflictMode.class | Bin 2014 -> 2014 bytes ...JBindExtractorMain$ExtractionRequest.class | Bin 2539 -> 2539 bytes .../JBindExtractorMain$ProgressTracker.class | Bin 1387 -> 1387 bytes ...ExtractorMain$SevenZipArchiveContext.class | Bin 1663 -> 1663 bytes ...ExtractorMain$SevenZipVolumeCallback.class | Bin 3729 -> 3729 bytes ...ExtractorMain$WrongPasswordException.class | Bin 458 -> 458 bytes .../extractor/JBindExtractorMain.class | Bin 19259 -> 19209 bytes .../extractor/JBindExtractorMain.java | 9 +++++++-- src/main/download-manager.ts | 15 +++++++++++++++ 10 files changed, 22 insertions(+), 2 deletions(-) diff --git a/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$Backend.class b/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$Backend.class index 41ca622c4afda3cf1d1170888ace9bf531733082..dd1c61514feaa251baab10d9e4e5b95f2d0dec36 100644 GIT binary patch delta 97 zcmca2ctvo-MmEOk$(z{pf#f4LL(V1!Hl}6KJsHfM#+i0RR_t7{UMm delta 97 zcmca2ctvo-MmEN>$(z{pf#f4LL(W}IvG5fx)^+!dM2M^cL3_*=db~iJ{*y}2^2S_Hc^~la<5Mi3bAj>qDL6K=bgE7+r26LuG3=T|- k8C;l_PUd6}0;-E)59Xc5z{@n9L5gVxgF4gH$$Qw90G8Ah3;+NC delta 83 zcmcb|e~*6y6C2}%$;@o}K+>2^2S_Hc^~g?R5Mi3mAj>p^L6K<|gE7-=26Lvl3=T~5 k7+jbZOy*<{0;-E)59Xc7z{@m=L5gWIgF4fM$$Qw90E)sCyZ`_I diff --git a/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$ExtractionRequest.class b/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$ExtractionRequest.class index f2ccd338a03a7aa6cc9a6da5a03dc3836582427b..b6f04dc83335c0adb0e2111ecd9824bfef73e034 100644 GIT binary patch delta 85 zcmaDY{91U!H+J5Y3@l7*7`U0%G6*rPo6O9i#kg{^9+->-lPzF!J(#=&CRsUkfNG4u NWIUMc0h2p9jR0m38ZZC= delta 85 zcmaDY{91U!H+J473@l8`8Mv8NFbFZNoXpIj#kgd$9+->-lPzF!J(#=&CRsUkfNG4u NWIUMc0h2p9jR0Ch8R`H4 diff --git a/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$ProgressTracker.class b/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$ProgressTracker.class index 8c1da8f36d621da21b9cd4c61b76568c2756569e..cb5c698152bc1395edc6abd7fcaf7d203ed87d15 100644 GIT binary patch delta 113 zcmV-%0FM9b3hN56#RCz(00aWO00{!W01^Vg02czmlhy+(1;hXa0>zUC1Zf?}00sid z00#og01*Pr038C&03`y?06qfH07C-NlZ*sD3Df`x0@VNx0@jn$1YH%`01E=z022b+ T02Bh<02u<_05<~PlSKt4E)5^0 delta 113 zcmV-%0FM9b3hN56#RCz!00aWJ00{!R01^Vb02czhlhy+(1-}3V0>G071Zf?^00siY z00#ob01*Pm038Cz03`y-06qfC07C-IlZ*sD3C{os0?+^s0@0Jx1YH%>01E=u022b% T02Bh)02u<=05<~KlSKt46k{JP diff --git a/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$SevenZipArchiveContext.class b/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$SevenZipArchiveContext.class index 603dad76daea868cb8fab512cff5f787a4c59ae0..2ada884e8fcea04e72e72a270c27d2ade357dafd 100644 GIT binary patch delta 101 zcmey*^Pgvf8>{FG1{S8544h1_82Ff8GYB)iVUT2cJ2{%Q&GI7yJJV+d0j94&(Ju@l zOy3!#nSL^;F#TpwXZppU!St6wpXon?88ah;B{Ktq6*Dt~BQpzw2Q%AbDK;m@N0VdO FlmNn(8KVFI delta 101 zcmV-r0Gj{*4F3$UMgqW0`&kW0{8$g0{Q?p0{j3u0{Z|u0{#F&0{;L=0|Ap720{Vd HlU)WP0Sz57 diff --git a/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$SevenZipVolumeCallback.class b/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$SevenZipVolumeCallback.class index 10566c8785787dd66b950b221e59af4ccaf3d083..9aaa95389f55811fb6e2d39c672cf091b332bd87 100644 GIT binary patch delta 219 zcmWNL%}N4c07cJmC21UgQoTpWfr^(Hb5IG$PcPJx$CY G)%pjANF-7K delta 219 zcmWNL!Ab&A07dU`qH=srQ3z>?rZ}1~6%^4TF-gTrG-NiRR*Tkc0-;r#0#|{&4=L~m z{DnTIeQ$d?oO9>7dG6=cPy1S7T^l5o#i&S1#{_ofKPR@d#k&R5~o!Z#cymR|*mhB4#)U`=N87@_!sROQD zucbO|wdklrR|BpUbE6k-HKnIF`ub#`ncKdI?MG^nxpz-T3Yj>=ST!CL@u)MN>|N0O E2O!}iT>t<8 diff --git a/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$WrongPasswordException.class b/resources/extractor-jvm/classes/com/sucukdeluxe/extractor/JBindExtractorMain$WrongPasswordException.class index 6826c5e095029799a4bdf95f507bb9ce8b0b1d67..dd31ed6b3518260e59c23af15f30214ee3ca796b 100644 GIT binary patch delta 17 ZcmX@be2RI)YDU(r46IDsCU0Pr0suK~1m=kZ-x-mzL(!GbHDH0 zd(Zkm|9iio-FVw>G#~lrlg|J^5q*5nye2urR9UgCqN<^xzQKq`5zK8KzsK(F?(XU~ z0paT^9v6MdsqPahp2T|*V(M!uSFfmEvbu3eP4%+X4OK>b6G4}^t$m{z>hP3`r}2!q zkeqFMN5yxc8o}V*+V1oFFbDt-ySLx}WwTQ_xk8@#@*j?G>RjNn%)J`cxDI7*-pszellFk4JRw@90;issY> zDLkiF$si|8^~#Rr6v|wR8lDt!P4RJ`KvqIyj$zna3*r9bE}OM z%`w??j1-H2xiYl7j5JXg)22*_S1Cb@vCZ4z^?Qw!D9Y1v%ac_~foz26wO)Tk3wyfB z?_J{YuQO5_tH?J}Iu9$2G#Np?_8O0STZMbYs^UBc>!vJ~rijPVQuA|Fa!B2#c1~1h zTh|tub#kfXhU2mjH*E5B_)NSbU!|!uO?;j<84E?CJw1N9N;9N+oxi(%gWNPrrP)+0 z8thqVb7Xz;&F~n_RjCa6Sbs-X=i23-j!o=-h1hLRpD)YD9eMVX!Ua{w| zTFABO^5u1UHgGZXX^~2c;RQ|^2f3uXYooW@f1{CV5hAvB zroD5$w{4-vx31CaH&Y#$A%CQp2tX*5eSTUEM|wu#Qn!;`+FDc|Vv`L=X*w^^VJjv6T-Dzog4 zTNnysG1%95*LC=fv;!gPlE;^1-xqggB~RMP%bPfzA*p@Mrf$2DekcxS*>rcPv`d`M zN-*55(vRpK@nx3X#*J)gs9Zg-V*cW)x=OqBcehGErk{wSDJxCA^izfYL#6vg&y-Bd z9(qurhgA9*{am~}rNZ(EJ*rTjO244T#Ki1c!>?4@OZ&vy>^#eUI-t-&mHO$Bcrg2_ z)sHh++02rP#>S@lhDvs6fC0gh%KEx069eK2m7b(~xc*EyMtX{K$deiw@!Dq)tT|=v zxp|J2l3rHkahDg~oN310bXcX|&~suz&YXnj5n{(yg?S*;NH2=sobC8~k(8SidyD~m z%_4=k2k4r43Y`#3b4&0Khj!&&K-)|7G9bOej7abqB;s+rm!A{yr1*(5ZR!zzP6uv1 z9`%j^P!93~(yRQ-z~bM0(7{wN(eLQLSbjvDb6$(DiUqEc=wY6XgNRXx22$uXakpzC z9ubeY?&A6B?p7QYJ?;wY2(Qwy`jxD&0U8;sN5rS@g}i1)o-3FauQ0 zq@~EtCS65I$w1h zP*Bpr8~2oC2js?RPz;ufkjfh{J))djA3fM27xH8!gGs_EKB)&3$4j7(*z4%W;YUHy z^?@#8FHez%x+pFVU>g|G%L=Y1saXM?5zU%LANs=@x3NB63MH(K^bw-IB TWyO&o zKF2n`rZy1_thN($*aZf>0b;Qmve3sz!WPX$BE}b3qNiP`sV7kq0(+Ba-;=$6Sz=dLq&0@v>3F6;0`#X%- zH~Pr9jI}@lhjtTK@H>!zH*;$TIIQiEi?=`_-U_pD2h7LsK^6W0ns6tq!rPz)e+X@O z2W-b((2IBSnRgfL$Gf2)?}1lQzzHUavv?o8kIF9i2zzN*RLo6IIynm2VA2p?7yhM_ z5+HO^Y@ItLAS<02u8Yy(9K7cj3D8z$a z0*cW@Co#aM(I`xk)OQvjYdl!wjW-ktZs17FY|z7AArHzR<@7LM4E=aZ z5O+$z7>bQyp>kQM6q{@&n=wevUYKJug>%LNNbaY+P{!DuUP!wlr3K=ld6Q}-bQVA? zC-7~C&O6Ld?{X`@2buUj!{-B-iRYjcKjh?n1hx1vEW=M=1%Aqj{0uhZpW${q&+Ypc z7{uHqUGQguk>VuzJ#_<)q>?Ko1V z9KLtuavJAAX_zOT<^r)vSTsa+%>%Tgh7Y>NAT1S#tK5O5O?{)MhoGm~IY14UolNDE z8u(kxNO`O;A12aN$fId6mkKx|MViBXlNy zUh?v~FBk+Gr3L5|`x?zhg_c8nnX}2hV&M=>Z^i+-x+bDD+40QJ;1x%5L7kQUjhoro z14&NV=Z+nO$?ic~F+kT2((0x@xZg^x|9XX&SKMT!b)gmUPTn5~DHx>d2dR^%S6Qih z-1Mbc{~&GQ*)l8L6q>a;2cc-p{u6XFpILoO1`v0dU;mw9CvOCjTxt8W>}=oYOy1Y= z5=6;`R{HKhfG1e=;+W`Gxl}Gu4WR*T9~2m*Q%_Ys9Ts8_yN1cymBdGM^eFMm$cg;HFM!t zKn8!~%G)4c-ZQxT88A6ie&}M6yjvDBnIvTNXa^f(!^}Y&pDj< zGhYZ-?!C9(jRSY1>EJ(~JOBXW>GM6N70Cg4dj0gO`ue(hBQC-t3cilZ5R8@O3(B=o z8IK{DT3vpZ)!o_I(P;$2;|jiscOk^pUR_gBRbN%vylD2k=7xFIvlleiR|$!?6+9s% zV(Y4}oRsk-f-ZlPXN?JJ@m&QY-ow-C$>bc%Uln{GW+NEf8$3S0PfVXx@I(AaO-ac! ze5~Ln_^Dc*k`eeEf$}$*;0&Hu@Ne1@k8g&@>lRDCRPgV3ni2c_u1>$N(c@n!hA#+B z|6s(qv-7I2b**z1cwOyn1r7dAPkURjjNc$gOIoiV=P0~Eh<~TxeR$f$8~I+rf5IyW zQ9gIe+D>=9+oyh(A|((g_#7NF5>bRiI)(IPK$xPAMW=dyrlMA+&Is_FtdLPm80!{R z)i>79UQoq4DN-Q?wjzvZb$i`@*2$WEo^@{TMz&4S3dK+?LZsK_^UrQ?b#JI!!7gLq zvt=5|d$;DwGztOpgbTLIlz@;}?{0Ukb~~#*t37@ZC%30XHKxUmOjIaI^H9i?Oev~8 zEiaI!kQH(eV%psP^5wn`?^?fmp3A>drVLhGAX64MOJo{@pe$SLa&9VjE?QcYZ)1y; zt56=C<8|#Uc2A4T8*={{tQ7lmDC87IjUM)Yduzvf5lkvj=qg|?8Qj-JuXTBS zM%Fb>p+Xw3o=(feiK^b3o-kRVDFT>|1G8GJDpqJJm8d1w?6gu5_W~3Afyx!CfF3sB z?PzaX=<=?0%T%e}XiXnEL!p`4epjz*^>q4Vnyo%=Em%62!`tD@7d|pU0o5o}3(vEQ zc?E%H2B4eZHYZp;mIM zO2(R!HU!z}WV$jM6HFkFLf4X;DeP)#ar=B(g;$M}$;;nPXG=%>3a_VyVGy+|)In?1 zeHqIQoeKHLucl`nOj@VeT<&UFNCywXquD&T{inUZi6XOIW5J8Z?Q-qR7QjDA|y-D zR>A)eOT$-e4z1Yh%l|dup}mn~8<6!jk83v_li<7r7bH5a9v@eV$JB(vGXDKZ;kIEW zZJ5En5U?&3S|^LG$Ag}K4}$@YfCNVw)G-F|1_>Y$yrCXr?x^Q`zT-8i2LA%tXE|6?5f<9uG ztrrhH1SW0{KMazt2Xqm;Sb{W?MhhxpE6C_(J#AWqWYEhP71HcOe^~Q&)~gr1ty7&- zZGmiu84m{W*=|VS-chX=#l4rf$EJT^CXuNCxC(UW1p~Ij2<(7tT*Gy!Q!^P22E!Fw zf==*-3}cX)t+3rsZ9xq5;!Q!^THRZRZ`gylBZ$B40=;fmFTOSW({9Fhf_SP6p0oww zbdBQ$Fgb#Frdx9dYl#r5f^e(U8pIE3dFq@RTN00-sW~N6qW`ZO3_UQxVzTIi_=VbD zk`(x=DAE#X#;=3;t!8eEj6H)74Rhmi7|r`z2a&iQM&kx99GiG=*FzrO0EPH7n2Z6K zj+>zhZ-Pd=8J6M}SdO$o4@!>8awJOJO~(<3ngpFsmYi$?qtD)>AH zs<~`dAY5Uwg-&XaPJu~WF-6w%_si^N&Iwpye{UCc8>s5%Iq8H!Tm z@ThcoR4OuBj21aa`D%HEIcaQ&Gz_2{(ys901hu0gzD68nGhhU}>}@8|39ef2aAu!^ zEPR)VbQ&h%87ScgQU!hhHFy>l;D@jXKVsLNgLU{ZY{O4Dn?Hp^_&IapNX7KaoM6X1 z2hWE~>+PJZB3(nWY(8HxWNRw(DT%x#U*>^i)m&6tXsYtkRTG(HjbA$_rghZBy zm_G)L4EhU*!7m{m|IRVK0O|M-2-xv!7?0m_kiTQ(-)jMm1%qii7m$mhs?^FOWyZD} z_Jpz3au5Z!IB}Sm9%Wo*WogE{?hzkpj}BSX3Ow-}fd~ww<9oLrMvwu_Bx^<_ATIC$ zMKI#Ep(J>Sm5ZB`i>tCfqKm*)pzTrgF zQ55JY1{8{Alp|mqnW2#4pq%328XB#kHh@m=0LO5G^UcN(cFjz#vf`|bV+^U)8rvf6 z;RDKkIT#~(lfW-NJtYU&FDYy-P17y|UIa7yoC^cL&B9v8vrgfY(Po;%T zGu83oD$edgbQ zUt$-0E1N&acCQ@eODv1me#5lT>R^E0WwbGT#%Q-^e2M+ZXt8hrCNyCm{iHggB-wUg zC%kM+9#?Co#hmH+U65oKHNduoFxlBpOZ&*xPsk##tqMsb*m?b| zkb-_%-A~u?^inge9X5Swc6~o>;@MI&{VX(VvG>FHA^ZDivx+m#fg71>&QKZYqnn>* zcs+xYSkn6h5M)so}dai zOqFnys^B=ygi|yN&e0q=Pjlfrs=*kl#j!MxtJaq@GbDZ=i(skAv(f^$F&Hj6;(!+0 zuqBPV3`x68(gKe3)sR7r8fEyppTY6YfXpzzJD8m!YYI8%B{ThEH)qc;#c3C1=bEP# zGnt3(thUFRVy#^CVxzQ%C)pC;Y_xl8sNO8*EMCHlT?SFq3`q>rO3NAasaXjDamW_2 zEs;y9z4WUg$KK88ZT<9{&?bWP-{O26o>40xh1wYNLa_f3b3Z*WRHJpaUg`~*!cWt^BM$;;;HeSs=@jx{a^@_CN)3jDR`FgdA08K;hOMWQuG(RZW zikbHP8^j$I!m$c5E5qmKq>}~bVIhJO=J#ak# zO7C-9&-f?s*9VXYi?}_@Z5y{AmL)|L{g{v9T3*M0_zV92gue$+ Pp-;;!)Jr?*Gcf)?n&sp< diff --git a/resources/extractor-jvm/src/com/sucukdeluxe/extractor/JBindExtractorMain.java b/resources/extractor-jvm/src/com/sucukdeluxe/extractor/JBindExtractorMain.java index 413b830..d01a45c 100644 --- a/resources/extractor-jvm/src/com/sucukdeluxe/extractor/JBindExtractorMain.java +++ b/resources/extractor-jvm/src/com/sucukdeluxe/extractor/JBindExtractorMain.java @@ -356,7 +356,10 @@ public final class JBindExtractorMain { if (!encrypted || result == null) { return false; } - return result == ExtractOperationResult.CRCERROR || result == ExtractOperationResult.DATAERROR; + // Only DATAERROR reliably indicates wrong password. CRCERROR can also mean + // a genuinely corrupt or incomplete archive, and 7z-JBinding sometimes + // falsely reports encrypted=true for non-encrypted RAR files. + return result == ExtractOperationResult.DATAERROR; } private static boolean looksLikeWrongPassword(Throwable error, boolean encrypted) { @@ -367,7 +370,9 @@ public final class JBindExtractorMain { if (text.contains("wrong password") || text.contains("falsches passwort")) { return true; } - return encrypted && (text.contains("crc") || text.contains("data error") || text.contains("checksum")); + // Only "data error" suggests wrong password. CRC errors can also mean + // corrupt/incomplete archives, so we don't treat them as password failures. + return encrypted && text.contains("data error"); } private static boolean shouldUseZip4j(File archiveFile) { diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index 9eed2af..62e2523 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -4988,11 +4988,26 @@ export class DownloadManager extends EventEmitter { } } + // Pre-compute: does the package still have any non-terminal items? + const packageHasPendingItems = pkg.itemIds.some((itemId) => { + const item = this.session.items[itemId]; + return item != null && item.status !== "completed" && item.status !== "failed" && item.status !== "cancelled"; + }); + for (const candidate of candidates) { const partsOnDisk = collectArchiveCleanupTargets(candidate, dirFiles); const allPartsCompleted = partsOnDisk.every((part) => completedPaths.has(pathKey(part))); if (allPartsCompleted) { const candidateBase = path.basename(candidate).toLowerCase(); + + // For multi-part archives (.part1.rar), require ALL package items to be terminal. + // partsOnDisk only contains parts found ON DISK — pending parts that haven't been + // downloaded yet (no targetPath, no fileName) would slip through the regular checks. + if (/\.part0*1\.rar$/i.test(candidateBase) && packageHasPendingItems) { + logger.info(`Hybrid-Extract: ${path.basename(candidate)} übersprungen – Paket hat noch ausstehende Items`); + continue; + } + const hasUnstartedParts = [...pendingPaths].some((pendingPath) => { const pendingName = path.basename(pendingPath).toLowerCase(); return this.looksLikeArchivePart(pendingName, candidateBase);