From 0766b733fe3e06dd2a7f9a3cfbf2108ac73abd17 Mon Sep 17 00:00:00 2001 From: Igor Pavlov <87184205+ip7z@users.noreply.github.com> Date: Fri, 4 Sep 2026 00:00:00 +0000 Subject: 26.03 --- .gitattributes | 2 + C/7zDec.c | 73 ++- C/7zTypes.h | 1 + C/7zVersion.h | 6 +- C/Bcj2Enc.c | 7 +- C/BwtSort.c | 6 +- C/Compiler.h | 30 + C/CpuArch.h | 11 + C/Lzma2Enc.c | 22 +- C/LzmaDec.c | 18 +- C/LzmaEnc.c | 13 +- C/Ppmd7Enc.c | 7 +- C/Ppmd8.c | 4 +- C/Util/7z/7zMain.c | 2 +- CPP/7zip/Archive/7z/7zEncode.cpp | 29 +- CPP/7zip/Archive/7z/7zHandler.cpp | 7 +- CPP/7zip/Archive/ApfsHandler.cpp | 2 +- CPP/7zip/Archive/ApmHandler.cpp | 5 +- CPP/7zip/Archive/ArHandler.cpp | 2 +- CPP/7zip/Archive/ArjHandler.cpp | 5 +- CPP/7zip/Archive/Cab/CabHandler.cpp | 50 +- CPP/7zip/Archive/Cab/CabIn.cpp | 83 ++- CPP/7zip/Archive/Cab/CabIn.h | 29 +- CPP/7zip/Archive/Cab/CabItem.h | 35 +- CPP/7zip/Archive/ComHandler.cpp | 21 +- CPP/7zip/Archive/Common/HandlerOut.cpp | 2 +- CPP/7zip/Archive/ExtHandler.cpp | 4 +- CPP/7zip/Archive/FatHandler.cpp | 5 +- CPP/7zip/Archive/GzHandler.cpp | 2 - CPP/7zip/Archive/HfsHandler.cpp | 5 +- CPP/7zip/Archive/Iso/IsoHandler.cpp | 6 +- CPP/7zip/Archive/Iso/IsoIn.cpp | 127 ++-- CPP/7zip/Archive/Iso/IsoIn.h | 24 +- CPP/7zip/Archive/Iso/IsoItem.h | 8 +- CPP/7zip/Archive/LzmaHandler.cpp | 10 +- CPP/7zip/Archive/Nsis/NsisHandler.cpp | 12 +- CPP/7zip/Archive/Nsis/NsisIn.cpp | 149 ++++- CPP/7zip/Archive/Nsis/NsisIn.h | 12 +- CPP/7zip/Archive/NtfsHandler.cpp | 8 +- CPP/7zip/Archive/PeHandler.cpp | 8 +- CPP/7zip/Archive/PpmdHandler.cpp | 80 ++- CPP/7zip/Archive/Rar/Rar5Handler.cpp | 6 +- CPP/7zip/Archive/Rar/RarHandler.cpp | 63 +- CPP/7zip/Archive/SquashfsHandler.cpp | 19 +- CPP/7zip/Archive/SwfHandler.cpp | 2 + CPP/7zip/Archive/Udf/UdfIn.cpp | 6 +- CPP/7zip/Archive/VhdHandler.cpp | 11 +- CPP/7zip/Archive/VhdxHandler.cpp | 2 + CPP/7zip/Archive/Wim/WimHandler.cpp | 129 ++-- CPP/7zip/Archive/Wim/WimHandler.h | 15 +- CPP/7zip/Archive/Wim/WimIn.cpp | 21 +- CPP/7zip/Archive/Wim/WimIn.h | 30 +- CPP/7zip/Archive/Zip/ZipAddCommon.cpp | 2 +- CPP/7zip/Archive/Zip/ZipIn.cpp | 5 +- CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp | 6 +- CPP/7zip/Common/FileStreams.cpp | 6 +- CPP/7zip/Common/LimitedStreams.cpp | 14 +- CPP/7zip/Common/LimitedStreams.h | 16 +- CPP/7zip/Compress/BZip2Encoder.cpp | 2 +- CPP/7zip/Compress/HuffmanDecoder.h | 29 +- CPP/7zip/Compress/LzmaEncoder.cpp | 2 +- CPP/7zip/Compress/Rar3Decoder.cpp | 2 +- CPP/7zip/Crypto/Rar5Aes.cpp | 1 + CPP/7zip/UI/Agent/Agent.cpp | 230 ++++--- CPP/7zip/UI/Agent/Agent.h | 7 + CPP/7zip/UI/Agent/AgentOut.cpp | 164 +++-- CPP/7zip/UI/Agent/AgentProxy.cpp | 848 +++++++++++++++++--------- CPP/7zip/UI/Agent/AgentProxy.h | 96 +-- CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp | 14 +- CPP/7zip/UI/Agent/ArchiveFolderOut.cpp | 3 +- CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | 319 +++++++--- CPP/7zip/UI/Common/ArchiveExtractCallback.h | 21 +- CPP/7zip/UI/Common/ArchiveOpenCallback.cpp | 7 +- CPP/7zip/UI/Common/Bench.cpp | 7 +- CPP/7zip/UI/Common/ExtractingFilePath.cpp | 5 +- CPP/7zip/UI/Common/OpenArchive.cpp | 100 ++- CPP/7zip/UI/Common/PropIDUtils.cpp | 27 +- CPP/7zip/UI/Common/UpdateCallback.cpp | 13 +- CPP/7zip/UI/FileManager/AltStreamsFolder.cpp | 87 +-- CPP/7zip/UI/FileManager/EnumFormatEtc.cpp | 2 + CPP/7zip/UI/FileManager/FSFolder.cpp | 60 +- CPP/7zip/UI/FileManager/PanelItemOpen.cpp | 53 +- CPP/7zip/UI/FileManager/PanelItems.cpp | 57 +- CPP/7zip/UI/FileManager/PanelMenu.cpp | 6 +- CPP/7zip/UI/FileManager/SysIconUtils.cpp | 3 +- CPP/Build.mak | 19 +- CPP/Common/MyCom.h | 2 +- CPP/Common/MyVector.h | 15 + CPP/Windows/FileDir.cpp | 102 ++-- CPP/Windows/FileDir.h | 1 + CPP/Windows/FileIO.cpp | 248 +++++++- CPP/Windows/FileIO.h | 45 +- DOC/7zC.txt | 4 +- DOC/7zFormat.txt | 4 +- DOC/7zip.wxs | 2 +- DOC/Methods.txt | 2 +- DOC/readme.txt | 10 +- DOC/src-history.txt | 50 +- 98 files changed, 2545 insertions(+), 1409 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a4a2554 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.dsp text eol=crlf +*.dsw text eol=crlf diff --git a/C/7zDec.c b/C/7zDec.c index 520cbfd..1149d06 100644 --- a/C/7zDec.c +++ b/C/7zDec.c @@ -99,62 +99,61 @@ static Byte ReadByte(IByteInPtr pp) static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain) { - CPpmd7 ppmd; - CByteInToLook s; - SRes res = SZ_OK; - - s.vt.Read = ReadByte; - s.inStream = inStream; - s.begin = s.end = s.cur = NULL; - s.extra = False; - s.res = SZ_OK; - s.processed = 0; + CPpmd7 *ppmd; + SRes res; + unsigned order; + UInt32 memSize; if (propsSize != 5) return SZ_ERROR_UNSUPPORTED; - - { - unsigned order = props[0]; - UInt32 memSize = GetUi32(props + 1); - if (order < PPMD7_MIN_ORDER || - order > PPMD7_MAX_ORDER || - memSize < PPMD7_MIN_MEM_SIZE || - memSize > PPMD7_MAX_MEM_SIZE) - return SZ_ERROR_UNSUPPORTED; - Ppmd7_Construct(&ppmd); - if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) - return SZ_ERROR_MEM; - Ppmd7_Init(&ppmd, order); - } + order = props[0]; + memSize = GetUi32(props + 1); + if (order < PPMD7_MIN_ORDER || + order > PPMD7_MAX_ORDER || + memSize < PPMD7_MIN_MEM_SIZE || + memSize > PPMD7_MAX_MEM_SIZE) + return SZ_ERROR_UNSUPPORTED; + if ((ppmd = (CPpmd7 *)ISzAlloc_Alloc(allocMain, sizeof(CPpmd7))) == NULL) + return SZ_ERROR_MEM; + Ppmd7_Construct(ppmd); + res = SZ_ERROR_MEM; + if (Ppmd7_Alloc(ppmd, memSize, allocMain)) { - ppmd.rc.dec.Stream = &s.vt; - if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec)) - res = SZ_ERROR_DATA; - else if (!s.extra) + CByteInToLook s; + s.vt.Read = ReadByte; + s.inStream = inStream; + s.begin = s.end = s.cur = NULL; + s.extra = False; + s.res = SZ_OK; + s.processed = 0; + + Ppmd7_Init(ppmd, order); + ppmd->rc.dec.Stream = &s.vt; + res = SZ_ERROR_DATA; + if (Ppmd7z_RangeDec_Init(&ppmd->rc.dec) && !s.extra) { Byte *buf = outBuffer; const Byte *lim = buf + outSize; for (; buf != lim; buf++) { - int sym = Ppmd7z_DecodeSymbol(&ppmd); + int sym = Ppmd7z_DecodeSymbol(ppmd); if (s.extra || sym < 0) break; *buf = (Byte)sym; } - if (buf != lim) - res = SZ_ERROR_DATA; - else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) - { - /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */ - res = SZ_ERROR_DATA; - } + if (buf == lim) + if (Ppmd7z_RangeDec_IsFinishedOK(&ppmd->rc.dec) + // || (Ppmd7z_DecodeSymbol(&ppmd) == PPMD7_SYM_END && Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) + ) + res = SZ_OK; } if (s.extra) res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); else if (s.processed + (size_t)(s.cur - s.begin) != inSize) res = SZ_ERROR_DATA; + Ppmd7_Free(ppmd, allocMain); } - Ppmd7_Free(&ppmd, allocMain); + ISzAlloc_Free(allocMain, ppmd); return res; } diff --git a/C/7zTypes.h b/C/7zTypes.h index 8aaabc8..af47668 100644 --- a/C/7zTypes.h +++ b/C/7zTypes.h @@ -556,6 +556,7 @@ struct ISzAlloc #define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a)) +#define Z7_memset_0_VAR(a) memset(&(a), 0, sizeof(a)) #ifndef Z7_ARRAY_SIZE #define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) diff --git a/C/7zVersion.h b/C/7zVersion.h index 50ccebb..de7efb8 100644 --- a/C/7zVersion.h +++ b/C/7zVersion.h @@ -1,7 +1,7 @@ #define MY_VER_MAJOR 26 -#define MY_VER_MINOR 2 +#define MY_VER_MINOR 3 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "26.02" +#define MY_VERSION_NUMBERS "26.03" #define MY_VERSION MY_VERSION_NUMBERS #ifdef MY_CPU_NAME @@ -10,7 +10,7 @@ #define MY_VERSION_CPU MY_VERSION #endif -#define MY_DATE "2026-06-25" +#define MY_DATE "2026-09-03" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_AUTHOR_NAME "Igor Pavlov" diff --git a/C/Bcj2Enc.c b/C/Bcj2Enc.c index 79460bb..5727cbb 100644 --- a/C/Bcj2Enc.c +++ b/C/Bcj2Enc.c @@ -1,5 +1,5 @@ /* Bcj2Enc.c -- BCJ2 Encoder converter for x86 code (Branch CALL/JUMP variant2) -2023-04-02 : Igor Pavlov : Public domain */ +: Igor Pavlov : Public domain */ #include "Precomp.h" @@ -75,7 +75,10 @@ static BoolInt Bcj2_RangeEnc_ShiftLow(CBcj2Enc *p) p->cache = (Byte)(low >> 24); } p->cacheSize++; - p->low = low << 8; + { + const UInt32 low2 = low << 8; + p->low = low2; + } return False; } diff --git a/C/BwtSort.c b/C/BwtSort.c index 8f64f9d..c8f9135 100644 --- a/C/BwtSort.c +++ b/C/BwtSort.c @@ -564,7 +564,8 @@ UInt32 BlockSort(UInt32 *Indices, const Byte *data, size_t blockSize) const BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0); if (Indices[i] & 0x40000000) { - groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); + const UInt32 temp = ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits); + groupSize += temp; Indices[(size_t)i + 1] &= kIndexMask; } Indices[i] &= kIndexMask; @@ -616,7 +617,8 @@ UInt32 BlockSort(UInt32 *Indices, const Byte *data, size_t blockSize) size_t groupSize = (Indices[i] & ~0xC0000000) >> kNumBitsMax; if (Indices[i] & 0x40000000) { - groupSize += (Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits; + const UInt32 temp = (Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits; + groupSize += temp; Indices[(size_t)i + 1] &= kIndexMask; } Indices[i] &= kIndexMask; diff --git a/C/Compiler.h b/C/Compiler.h index c06b883..707e46d 100644 --- a/C/Compiler.h +++ b/C/Compiler.h @@ -125,6 +125,36 @@ typedef void (*Z7_void_Function)(void); #pragma warning(disable : 4464) // relative include path contains '..' #endif +// #define Z7_ANALYZE_MODE +#if defined(Z7_ANALYZE_MODE) // && defined(Z7_MSC_VER_ORIGINAL) +// for -analyze switch: +#if _MSC_VER >= 1900 +#pragma warning(disable : 6001) // Using uninitialized memory 'ps'. +#pragma warning(disable : 6031) // Return value ignored: 'CoInitialize' +#pragma warning(disable : 6553) // The annotation for function 'RegOpenKeyExW' on _Param_(3) does not apply to a value type. +#pragma warning(disable : 28159) // Random.cpp(21) : Consider using 'GetTickCount64' instead of 'GetTickCount' +#pragma warning(disable : 28160) // ProcessUtils.h(92) : Error annotation: Passing MEM_RELEASE and a non-zero dwSize parameter to VirtualFree is not allowed. This results in the failure of this call +#pragma warning(disable : 28251) // Inconsistent annotation for 'WinMain': this instance has no annotations. See c:\program files (x86)\windows kits\10\include\10.0.26100.0\um\winbase.h(1062). +#pragma warning(disable : 28286) // um\consoleapi.h(236) : For function 'ReadConsoleW', error near the end of 'SAL_readableTo(byteCount(*__formal(3,lpNumberOfCharsRead) * sizeof(TCHAR%)))'. +#pragma warning(disable : 28301) // No annotations for first declaration of 'PNTSTATUS'. See c:\program files (x86)\windows kits\10\include\10.0.26100.0\shared\bcrypt.h(40). +#endif +#if _MSC_VER >= 1600 +#pragma warning(disable : 6011) // Dereferencing NULL pointer 'p->IsDirs' +#pragma warning(disable : 6255) // `_alloca` indicates failure by raising a stack overflow exception. Consider using _malloca instead. +#pragma warning(disable : 6258) // Using TerminateThread does not allow proper thread clean up. +// #pragma warning(disable : 6262) // SfxSetup.c : Function uses '32808' bytes of stack. +#pragma warning(disable : 6320) // Threads.c : Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled. +#pragma warning(disable : 6385) // createcoder.cpp : Invalid data: accessing 'struct CCodecInfo const * * g_Codecs', the readable size is '256' bytes, but '4194244' bytes might be read: Lines: 338, 339, 340, 342, 344 +#pragma warning(disable : 6387) // MyString.cpp : 's' could be '0': this does not adhere to the specification for the function 'wmemcpy' +#endif +#if _MSC_VER == 1600 +#pragma warning(disable : 6200) // compressdialog.cpp : Index '31' is out of valid index range '0' to '9' for non-stack buffer 'g_Levels' +#pragma warning(disable : 6204) // Possible buffer overrun in call to 'memset': use of unchecked parameter 'size' +#pragma warning(disable : 6309) // Argument '1' is null: this does not adhere to function specification of 'GetProcAddress' +#pragma warning(disable : 6386) // myvector.h : Buffer overrun: accessing 'argument 1', the writable size is 'newCapacity*4' bytes, but '8' bytes might be written +#endif +#endif // Z7_ANALYZE_MODE + // == 1200 : -O1 : for __forceinline // >= 1900 : -O1 : for printf #pragma warning(disable : 4710) // function not inlined diff --git a/C/CpuArch.h b/C/CpuArch.h index 348db0a..e6698d8 100644 --- a/C/CpuArch.h +++ b/C/CpuArch.h @@ -209,6 +209,17 @@ MY_CPU_64BIT means that processor can work with 64-bit registers. #endif +#if defined(__s390__) +#if defined(__s390x__) || defined(__LP64__) || (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8) + #define MY_CPU_NAME "s390x" + #define MY_CPU_SIZEOF_POINTER 8 +#else + #define MY_CPU_NAME "s390" + #define MY_CPU_SIZEOF_POINTER 4 +#endif +#endif + + // #undef MY_CPU_NAME // #undef MY_CPU_SIZEOF_POINTER // #define __e2k__ diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c index 72aec69..5d64828 100644 --- a/C/Lzma2Enc.c +++ b/C/Lzma2Enc.c @@ -129,11 +129,10 @@ UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p); static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, size_t *packSizeRes, ISeqOutStreamPtr outStream) { - size_t packSizeLimit = *packSizeRes; + const size_t packSizeLimit = *packSizeRes; size_t packSize = packSizeLimit; UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; - unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); - BoolInt useCopyBlock; + const unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); SRes res; *packSizeRes = 0; @@ -150,22 +149,13 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, if (unpackSize == 0) return res; - if (res == SZ_OK) - useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); - else - { - if (res != SZ_ERROR_OUTPUT_EOF) - return res; - res = SZ_OK; - useCopyBlock = True; - } - - if (useCopyBlock) + if (res == SZ_ERROR_OUTPUT_EOF + || (res == SZ_OK && (packSize + 2 >= unpackSize || packSize > (1 << 16)))) { size_t destPos = 0; PRF(printf("################# COPY ")); - while (unpackSize > 0) + while (unpackSize) { const UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; if (packSizeLimit - destPos < u + 3) @@ -194,6 +184,8 @@ static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, return SZ_OK; } + if (res != SZ_OK) + return res; { size_t destPos = 0; const UInt32 u = unpackSize - 1; diff --git a/C/LzmaDec.c b/C/LzmaDec.c index 69bb8bb..5bc5094 100644 --- a/C/LzmaDec.c +++ b/C/LzmaDec.c @@ -1,5 +1,5 @@ /* LzmaDec.c -- LZMA Decoder -2023-04-07 : Igor Pavlov : Public domain */ +: Igor Pavlov : Public domain */ #include "Precomp.h" @@ -462,8 +462,10 @@ int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit) if (state >= kNumStates) { UInt32 distance; - prob = probs + PosSlot + - ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + { + const unsigned temp = (len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits; + prob = probs + PosSlot + temp; + } TREE_6_DECODE(prob, distance) if (distance >= kStartPosModelIndex) { @@ -857,9 +859,10 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byt if (state < 4) { unsigned posSlot; - prob = probs + PosSlot + - ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << - kNumPosSlotBits); + { + const unsigned temp = (len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) << kNumPosSlotBits; + prob = probs + PosSlot + temp; + } TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot) if (posSlot >= kStartPosModelIndex) { @@ -867,7 +870,8 @@ static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byt if (posSlot < kEndPosModelIndex) { - prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits); + const unsigned temp = (2 | (posSlot & 1)) << numDirectBits; + prob = probs + SpecPos + temp; } else { diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c index 60f1d21..f54e670 100644 --- a/C/LzmaEnc.c +++ b/C/LzmaEnc.c @@ -692,7 +692,10 @@ Z7_NO_INLINE static void Z7_FASTCALL RangeEnc_ShiftLow(CRangeEnc *p) { UInt32 low = (UInt32)p->low; unsigned high = (unsigned)(p->low >> 32); - p->low = (UInt32)(low << 8); + { + const UInt32 low2 = low << 8; + p->low = low2; + } if (low < (UInt32)0xFF000000 || high != 0) { { @@ -958,7 +961,8 @@ static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posS unsigned m; unsigned bit; RC_BIT_0(rc, probs) - probs += (posState << (1 + kLenNumLowBits)); + posState <<= (1 + kLenNumLowBits); + probs += posState; bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit) m = (1 << 1) + bit; bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit) m = (m << 1) + bit; bit = sym & 1; RC_BIT(rc, probs + m, bit) @@ -1000,7 +1004,8 @@ Z7_NO_INLINE static void Z7_FASTCALL LenPriceEnc_UpdateTables( for (posState = 0; posState < numPosStates; posState++) { UInt32 *prices = p->prices[posState]; - const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits)); + const unsigned posState2 = posState << (1 + kLenNumLowBits); + const CLzmaProb *probs = enc->low + posState2; SetPrices_3(probs, a, prices, ProbPrices); SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices); } @@ -2220,7 +2225,7 @@ Z7_NO_INLINE static void FillAlignPrices(CLzmaEnc *p) UInt32 prob; bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; - bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; + bit = sym & 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit; prob = probs[m]; p->alignPrices[i ] = price + GET_PRICEa_0(prob); p->alignPrices[i + 8] = price + GET_PRICEa_1(prob); diff --git a/C/Ppmd7Enc.c b/C/Ppmd7Enc.c index 49cbbe6..975157c 100644 --- a/C/Ppmd7Enc.c +++ b/C/Ppmd7Enc.c @@ -1,5 +1,5 @@ /* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder -2023-09-07 : Igor Pavlov : Public domain +: Igor Pavlov : Public domain This code is based on: PPMd var.H (2001): Dmitry Shkarin : Public domain */ @@ -35,7 +35,10 @@ static void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p) R->Cache = (Byte)((UInt32)R->Low >> 24); } R->CacheSize++; - R->Low = (UInt32)((UInt32)R->Low << 8); + { + const UInt32 low2 = (UInt32)R->Low << 8; + R->Low = low2; + } } #define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; Ppmd7z_RangeEnc_ShiftLow(p); diff --git a/C/Ppmd8.c b/C/Ppmd8.c index 774b30c..bd56480 100644 --- a/C/Ppmd8.c +++ b/C/Ppmd8.c @@ -885,9 +885,9 @@ static PPMD8_CTX_PTR Ppmd8_CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; } } else - { + { const unsigned temp = !SUFFIX(c)->NumStats; s = ONE_STATE(c); - s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24))); + s->Freq = (Byte)(s->Freq + (temp & (s->Freq < 24))); } successor = SUCCESSOR(s); if (successor != upBranch) diff --git a/C/Util/7z/7zMain.c b/C/Util/7z/7zMain.c index 300c363..e49c230 100644 --- a/C/Util/7z/7zMain.c +++ b/C/Util/7z/7zMain.c @@ -967,7 +967,7 @@ int Z7_CDECL main(int numargs, char *args[]) break; } - if (len > tempSize) + if (len > tempSize || !temp) { SzFree(NULL, temp); tempSize = len; diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp index 71d1ddb..049cc17 100644 --- a/CPP/7zip/Archive/7z/7zEncode.cpp +++ b/CPP/7zip/Archive/7z/7zEncode.cpp @@ -323,20 +323,16 @@ HRESULT CEncoder::Encode1( ICompressProgressInfo *compressProgress) { RINOK(EncoderConstr()) - if (!_mixerRef) { RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce)) } - RINOK(_mixer->ReInit2()) CMyComPtr2 mtProgress; CMyComPtr2 mtOutStreamNotify; - CRecordVector tempBufferSpecs; CObjectVector > tempBuffers; - unsigned i; for (i = 1; i < _bindInfo.PackStreams.Size(); i++) @@ -348,34 +344,21 @@ HRESULT CEncoder::Encode1( } const unsigned numMethods = _bindInfo.Coders.Size(); - for (i = 0; i < numMethods; i++) _mixer->SetCoderInfo(i, NULL, NULL, false); - /* inStreamSize can be used by BCJ2 to set optimal range of conversion. But current BCJ2 encoder uses also another way to check exact size of current file. So inStreamSize is not required. */ - /* if (inStreamSize) _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL); */ - - - /* - CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2; - CMyComPtr inStreamSizeCount = inStreamSizeCountSpec; - */ - - CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL; - CMyComPtr outStreamSizeCount; - + // CMyComPtr2_Create inStreamSizeCount; + CMyComPtr2_Create outStreamSizeCount; // inStreamSizeCountSpec->Init(inStream); - // ISequentialInStream *inStreamPointer = inStreamSizeCount; ISequentialInStream *inStreamPointer = inStream; - CRecordVector outStreamPointers; SetFolder(folderItem); @@ -466,11 +449,9 @@ HRESULT CEncoder::Encode1( if (_bindInfo.PackStreams.Size() != 0) { - outStreamSizeCountSpec = new CSequentialOutStreamSizeCount; - outStreamSizeCount = outStreamSizeCountSpec; - outStreamSizeCountSpec->SetStream(mtOutStreamNotify.IsDefined() ? + outStreamSizeCount->SetStream(mtOutStreamNotify.IsDefined() ? mtOutStreamNotify.Interface() : outStream); - outStreamSizeCountSpec->Init(); + outStreamSizeCount->Init(); outStreamPointers.Add(outStreamSizeCount); } @@ -486,7 +467,7 @@ HRESULT CEncoder::Encode1( compressProgress, dataAfterEnd_Error)) if (_bindInfo.PackStreams.Size() != 0) - packSizes.Add(outStreamSizeCountSpec->GetSize()); + packSizes.Add(outStreamSizeCount->GetSize()); for (i = 1; i < _bindInfo.PackStreams.Size(); i++) { diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp index 81dd966..a81f5df 100644 --- a/CPP/7zip/Archive/7z/7zHandler.cpp +++ b/CPP/7zip/Archive/7z/7zHandler.cpp @@ -309,6 +309,11 @@ bool CHandler::IsFolderEncrypted(CNum folderIndex) const inByte.SkipDataNoCheck(idSize); if (id64 == k_AES) return true; + if ((mainByte & 0x10) != 0) + { + inByte.ReadNum(); // NumInStreams + inByte.ReadNum(); // NumOutStreams + } if ((mainByte & 0x20) != 0) inByte.SkipDataNoCheck(inByte.ReadNum()); } @@ -455,7 +460,7 @@ HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const const UInt32 lp = d % 5; if (lc != 3) dest = AddProp32(dest, "lc", lc); if (lp != 0) dest = AddProp32(dest, "lp", lp); - if (pb != 2) dest = AddProp32(dest, "pb", pb); + if (pb != 2) /* dest = */ AddProp32(dest, "pb", pb); } } } diff --git a/CPP/7zip/Archive/ApfsHandler.cpp b/CPP/7zip/Archive/ApfsHandler.cpp index 2876991..0f367f9 100644 --- a/CPP/7zip/Archive/ApfsHandler.cpp +++ b/CPP/7zip/Archive/ApfsHandler.cpp @@ -3829,7 +3829,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val #ifdef APFS_SHOW_ALT_STREAMS if (ref.IsAltStream()) { - // if (inode) + if (inode) { const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex]; ConvertUTF8ToUnicode(attr.Name, s); diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp index e88d2fe..ca46eb1 100644 --- a/CPP/7zip/Archive/ApmHandler.cpp +++ b/CPP/7zip/Archive/ApmHandler.cpp @@ -253,9 +253,10 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallb numBlocks = finish; _items.Add(item); - if (numPadSectors != 0) { - RINOK(stream->Seek(numPadSectors << 9, STREAM_SEEK_CUR, NULL)) + const unsigned offset = numPadSectors << 9; + if (offset) + RINOK(stream->Seek(offset, STREAM_SEEK_CUR, NULL)) } if (++i == numBlocksInMap) break; diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp index 9f672a9..e9afb1b 100644 --- a/CPP/7zip/Archive/ArHandler.cpp +++ b/CPP/7zip/Archive/ArHandler.cpp @@ -249,7 +249,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, bool &filled) RIF(DecimalToNumber32(cur, kUserSize, item.User)) cur += kUserSize; RIF(DecimalToNumber32(cur, kUserSize, item.Group)) cur += kUserSize; RIF(OctalToNumber32(cur, kModeSize, item.Mode)) cur += kModeSize; - RIF(DecimalToNumber(cur, kSizeSize, item.Size)) cur += kSizeSize; + RIF(DecimalToNumber(cur, kSizeSize, item.Size)) // cur += kSizeSize; if (longNameLen != 0 && longNameLen <= item.Size) { diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp index 1d641e4..1a06781 100644 --- a/CPP/7zip/Archive/ArjHandler.cpp +++ b/CPP/7zip/Archive/ArjHandler.cpp @@ -352,7 +352,7 @@ HRESULT CArcHeader::Parse(const Byte *p, unsigned size) pos += size1; size1 = size - pos; RINOK(ReadString(p + pos, size1, Comment)) - pos += size1; + // pos += size1; return S_OK; } @@ -462,8 +462,7 @@ HRESULT CItem::Parse(const Byte *p, unsigned size) pos += size1; size1 = size - pos; RINOK(ReadString(p + pos, size1, Comment)) - pos += size1; - + // pos += size1; return S_OK; } diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 0ad2a0e..f97c686 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -145,10 +145,13 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) // case kpidSolid: prop = _database.IsSolid(); break; case kpidNumBlocks: { + /* UInt32 numFolders = 0; FOR_VECTOR (v, m_Database.Volumes) numFolders += m_Database.Volumes[v].Folders.Size(); prop = numFolders; + */ + prop = (UInt32)m_Database.FolderStartFileIndex.Size(); break; } @@ -292,7 +295,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; } - case kpidIsDir: prop = item.IsDir(); break; + // case kpidIsDir: prop = false; break; case kpidSize: prop = item.Size; break; case kpidAttrib: prop = item.GetWinAttrib(); break; @@ -315,7 +318,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val break; } - case kpidBlock: prop.Set_Int32((Int32)m_Database.GetFolderIndex(&mvItem)); break; + case kpidBlock: prop.Set_Int32((Int32)m_Database.GetGlobalFolderIndex(mvItem)); break; #ifdef CAB_DETAILS @@ -516,8 +519,7 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, return S_FALSE; else { - m_Database.FillSortAndShrink(); - if (!m_Database.Check()) + if (!m_Database.Fill_Sort_Shrink_and_Check()) return S_FALSE; } } @@ -921,9 +923,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, const unsigned index = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[index]; const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; - if (item.IsDir()) - continue; - const int folderIndex = m_Database.GetFolderIndex(&mvItem); + const int folderIndex = m_Database.GetGlobalFolderIndex(mvItem); if (folderIndex != lastFolder) totalUnPacked += lastFolderSize; lastFolder = folderIndex; @@ -967,20 +967,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CItem &item = db.Items[itemIndex]; i++; - if (item.IsDir()) - { - const Int32 askMode = testMode ? - NExtract::NAskMode::kTest : - NExtract::NAskMode::kExtract; - CMyComPtr realOutStream; - RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) - RINOK(extractCallback->PrepareOperation(askMode)) - realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)) - continue; - } - const int folderIndex = m_Database.GetFolderIndex(&mvItem); + const int folderIndex = m_Database.GetGlobalFolderIndex(mvItem); if (folderIndex < 0) { @@ -992,7 +980,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->GetStream(index, &realOutStream, askMode)) RINOK(extractCallback->PrepareOperation(askMode)) realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kDataError)) + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable)) continue; } @@ -1010,9 +998,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, const unsigned indexNext = allFilesMode ? i : indices[i]; const CMvItem &mvItem2 = m_Database.Items[indexNext]; const CItem &item2 = m_Database.Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex]; - if (item2.IsDir()) - continue; - const int newFolderIndex = m_Database.GetFolderIndex(&mvItem2); + const int newFolderIndex = m_Database.GetGlobalFolderIndex(mvItem2); if (newFolderIndex != folderIndex) break; @@ -1073,6 +1059,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, bool keepHistory = false; bool keepInputBuffer = false; bool thereWasNotAlignedChunk = false; + + // printf(" -locFolderIndex=%5i\n", locFolderIndex); for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();) { @@ -1085,6 +1073,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CDatabaseEx &db2 = m_Database.Volumes[volIndex]; if (locFolderIndex < 0) return E_FAIL; + if ((unsigned)locFolderIndex >= db2.Folders.Size()) + { + res = S_FALSE; + break; + } const CFolder &folder2 = db2.Folders[(unsigned)locFolderIndex]; if (bl == 0) @@ -1092,7 +1085,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(InStream_SeekSet(db2.Stream, db2.StartPosition + folder2.DataStart)) } - if (bl == folder2.NumDataBlocks) + if (bl >= folder2.NumDataBlocks) { /* CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit. @@ -1105,13 +1098,14 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (m_Database.Volumes.Size() > 1) { volIndex++; + // printf(" -volIndex=%5u\n", volIndex); locFolderIndex = 0; bl = 0; continue; } } - - bl++; + else + bl++; if (!keepInputBuffer) blockPackData.InitForNewBlock(); @@ -1120,6 +1114,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, res = blockPackData.Read(db2.Stream, db2.ArcInfo.GetDataBlockReserveSize(), packSize, unpackSize); if (res == S_FALSE) break; + // if folder is Continued_To_Next volume, then (unpackSize == 0) in last chunk of volume, but (packSize != 0) + // printf(" -block=%5u unpackSize=%5u packSize=%5u\n", bl - 1, unpackSize, packSize); RINOK(res) keepInputBuffer = (unpackSize == 0); if (keepInputBuffer) diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp index bd6969a..a20d3b0 100644 --- a/CPP/7zip/Archive/Cab/CabIn.cpp +++ b/CPP/7zip/Archive/Cab/CabIn.cpp @@ -31,9 +31,11 @@ void CInArchive::Read(Byte *data, unsigned size) throw CUnexpectedEndException(); } +static const size_t k_Name_Size_Limit = 1 << 13; + void CInArchive::ReadName(AString &s) { - for (size_t i = 0; i < ((size_t)1 << 13); i++) + for (size_t i = 0; i < k_Name_Size_Limit; i++) { Byte b; if (!_inBuffer.ReadByte(b)) @@ -43,8 +45,6 @@ void CInArchive::ReadName(AString &s) s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i); return; } - if (_tempBuf.Size() == i) - _tempBuf.ChangeSize_KeepData(i * 2, i); _tempBuf[i] = b; } @@ -58,7 +58,7 @@ void CInArchive::ReadName(AString &s) } ErrorInNames = true; - s = "[ERROR-LONG-PATH]"; + s = "[LONG_PATH_FILE]"; } void CInArchive::ReadOtherArc(COtherArc &oa) @@ -268,14 +268,14 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) IsArc = true; _inBuffer.SetStream(limitedStream); - if (_tempBuf.Size() == 0) - _tempBuf.Alloc(1 << 12); + _tempBuf.Alloc(k_Name_Size_Limit); Byte p[16]; const unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0); Read(p, nextSize); ai.SetID = Get16(p); ai.CabinetNumber = Get16(p + 2); + // printf("CabinetNumber=%5u \n", ai.CabinetNumber); if (ai.ReserveBlockPresent()) { @@ -302,10 +302,9 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) folder.MethodMinor = p[7]; Skip(ai.PerFolder_AreaSize); db.Folders.AddInReserved(folder); + // printf("folder=%5u DataStart=%8u numBlocks=%8u\n", i, folder.DataStart, folder.NumDataBlocks); } - // for (int iii = 0; iii < 10000; iii++) { - if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset) { // printf("\n!!! Seek Error !!!!\n"); @@ -315,8 +314,14 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) _inBuffer.Init(); } +/* + if (FolderIndex == kContinuedFromPrev || FolderIndex == kContinuedPrevAndNext), + then there are no (FolderIndex == 0) items in that cab volume. + But (FolderIndex == kContinuedToNext) and (FolderIndex == numFolders - 1) items are possible in same volume. + if there are multiple files with (FolderIndex == kContinuedToNext), then they are duplicated + in next volume with (FolderIndex == kContinuedFromPrev or kContinuedPrevAndNext). +*/ db.Items.ClearAndReserve(ai.NumFiles); - for (i = 0; i < ai.NumFiles; i++) { Read(p, 16); @@ -328,18 +333,15 @@ HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) const UInt16 pureTime = Get16(p + 12); item.Time = (((UInt32)pureDate << 16)) | pureTime; item.Attributes = Get16(p + 14); - ReadName(item.Name); - - if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size()) + // printf(" -file=%5u Folder=%5x Offset=%10u size=%10u %s\n", i, item.FolderIndex, item.Offset, item.Size, item.Name.Ptr()); + const unsigned numFolders = db.Folders.Size(); + if (numFolders == 0 || item.GetFolderIndex(numFolders) >= (int)numFolders) { HeaderError = true; return S_FALSE; } } - - // } - return S_OK; } @@ -365,12 +367,8 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex]; const CItem &item1 = db1.Items[p1->ItemIndex]; const CItem &item2 = db2.Items[p2->ItemIndex]; - const bool isDir1 = item1.IsDir(); - const bool isDir2 = item2.IsDir(); - if (isDir1 && !isDir2) return -1; - if (isDir2 && !isDir1) return 1; - const int f1 = mvDb.GetFolderIndex(p1); - const int f2 = mvDb.GetFolderIndex(p2); + const int f1 = mvDb.GetGlobalFolderIndex(*p1); + const int f2 = mvDb.GetGlobalFolderIndex(*p2); RINOZ(MyCompare(f1, f2)) RINOZ(MyCompare(item1.Offset, item2.Offset)) RINOZ(MyCompare(item1.Size, item2.Size)) @@ -379,37 +377,39 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) } -bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) +bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) const { - const CMvItem *p1 = &Items[i1]; - const CMvItem *p2 = &Items[i2]; - const CDatabaseEx &db1 = Volumes[p1->VolumeIndex]; - const CDatabaseEx &db2 = Volumes[p2->VolumeIndex]; - const CItem &item1 = db1.Items[p1->ItemIndex]; - const CItem &item2 = db2.Items[p2->ItemIndex]; - return GetFolderIndex(p1) == GetFolderIndex(p2) + const CMvItem &p1 = Items[i1]; + const CMvItem &p2 = Items[i2]; + const CDatabaseEx &db1 = Volumes[p1.VolumeIndex]; + const CDatabaseEx &db2 = Volumes[p2.VolumeIndex]; + const CItem &item1 = db1.Items[p1.ItemIndex]; + const CItem &item2 = db2.Items[p2.ItemIndex]; + return GetGlobalFolderIndex(p1) == GetGlobalFolderIndex(p2) && item1.Offset == item2.Offset && item1.Size == item2.Size && item1.Name == item2.Name; } -void CMvDatabaseEx::FillSortAndShrink() +bool CMvDatabaseEx::Fill_Sort_Shrink_and_Check() +{ { Items.Clear(); - StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); int offset = 0; FOR_VECTOR (v, Volumes) { - const CDatabaseEx &db = Volumes[v]; - int curOffset = offset; + CDatabaseEx &db = Volumes[v]; if (db.IsTherePrevFolder()) - curOffset--; - StartFolderOfVol.Add(curOffset); - offset += db.GetNumberOfNewFolders(); + offset--; + db.StartGlobalFolderIndex = offset; + // printf("vol=%5u StartGlobalFolderIndex=%8d\n", v, offset); + offset += (int)db.Folders.Size(); + if (offset < -1) // overflow + return false; CMvItem mvItem; mvItem.VolumeIndex = v; @@ -433,15 +433,12 @@ void CMvDatabaseEx::FillSortAndShrink() FOR_VECTOR (i, Items) { - const int folderIndex = GetFolderIndex(&Items[i]); + const int folderIndex = GetGlobalFolderIndex(Items[i]); while (folderIndex >= (int)FolderStartFileIndex.Size()) FolderStartFileIndex.Add(i); } } - -bool CMvDatabaseEx::Check() -{ for (unsigned v = 1; v < Volumes.Size(); v++) { const CDatabaseEx &db1 = Volumes[v]; @@ -465,14 +462,12 @@ bool CMvDatabaseEx::Check() FOR_VECTOR (i, Items) { const CMvItem &mvItem = Items[i]; - const int fIndex = GetFolderIndex(&mvItem); + const int fIndex = GetGlobalFolderIndex(mvItem); if (fIndex >= (int)FolderStartFileIndex.Size()) return false; const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; - if (item.IsDir()) - continue; - const int folderIndex = GetFolderIndex(&mvItem); + const int folderIndex = GetGlobalFolderIndex(mvItem); if (folderIndex != prevFolder) prevFolder = folderIndex; diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h index 06aa34c..1c22bef 100644 --- a/CPP/7zip/Archive/Cab/CabIn.h +++ b/CPP/7zip/Archive/Cab/CabIn.h @@ -97,20 +97,15 @@ struct CDatabase return true; return false; } - - int GetNumberOfNewFolders() const - { - int res = (int)Folders.Size(); - if (IsTherePrevFolder()) - res--; - return res; - } }; struct CDatabaseEx: public CDatabase { CMyComPtr Stream; + int StartGlobalFolderIndex; // == (-1), if there are links to a previous volume that is missing or contains an error + + CDatabaseEx(): StartGlobalFolderIndex(-1) {} }; @@ -123,31 +118,29 @@ struct CMvItem class CMvDatabaseEx { - bool AreItemsEqual(unsigned i1, unsigned i2); + bool AreItemsEqual(unsigned i1, unsigned i2) const; public: CObjectVector Volumes; CRecordVector Items; - CRecordVector StartFolderOfVol; // can be negative - CRecordVector FolderStartFileIndex; + CRecordVector FolderStartFileIndex; // GlobalFolderIndex to Items[] index - int GetFolderIndex(const CMvItem *mvi) const + // out: (returned_value == -1) is possible, if (mvi) refers to a previous volume that is missing or contains an error + int GetGlobalFolderIndex(const CMvItem &mvi) const { - const CDatabaseEx &db = Volumes[mvi->VolumeIndex]; - return StartFolderOfVol[mvi->VolumeIndex] + - db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size()); + const CDatabaseEx &db = Volumes[mvi.VolumeIndex]; + return db.StartGlobalFolderIndex + + db.Items[mvi.ItemIndex].GetFolderIndex(db.Folders.Size()); } void Clear() { Volumes.Clear(); Items.Clear(); - StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); } - void FillSortAndShrink(); - bool Check(); + bool Fill_Sort_Shrink_and_Check(); }; diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h index b7e07d1..8f24ed7 100644 --- a/CPP/7zip/Archive/Cab/CabItem.h +++ b/CPP/7zip/Archive/Cab/CabItem.h @@ -28,14 +28,17 @@ struct CItem UInt32 Offset; UInt32 Size; UInt32 Time; - UInt32 FolderIndex; + unsigned FolderIndex; UInt16 Flags; UInt16 Attributes; UInt64 GetEndOffset() const { return (UInt64)Offset + Size; } - UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; } + /* v26.03: we show all items as files, as original cab extracting software does. + Also we disable FILE_ATTRIBUTE_DIRECTORY in GetWinAttrib(), because some client + software of 7zip still can parse FILE_ATTRIBUTE_DIRECTORY flag from returned Attributes. */ + UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~((UInt32)NHeader::kFileNameIsUtf8_Mask | (UInt32)FILE_ATTRIBUTE_DIRECTORY); } bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; } - bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } + // bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } bool ContinuedFromPrev() const { @@ -43,21 +46,21 @@ struct CItem FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev || FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; } - - bool ContinuedToNext() const - { - return - FolderIndex == NHeader::NFolderIndex::kContinuedToNext || - FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; - } - + // in: (numFolders > 0) is expected + // out: (returned_value >= 0) is expected int GetFolderIndex(unsigned numFolders) const { - if (ContinuedFromPrev()) - return 0; - if (ContinuedToNext()) - return (int)numFolders - 1; - return (int)FolderIndex; + const unsigned folderIndex = FolderIndex; + switch (folderIndex) + { + case NHeader::NFolderIndex::kContinuedFromPrev: + case NHeader::NFolderIndex::kContinuedPrevAndNext: + return 0; + case NHeader::NFolderIndex::kContinuedToNext: + return (int)numFolders - 1; + default: + return (int)folderIndex; + } } }; diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp index 5bbdf07..7706e5d 100644 --- a/CPP/7zip/Archive/ComHandler.cpp +++ b/CPP/7zip/Archive/ComHandler.cpp @@ -579,7 +579,7 @@ HRESULT CDatabase::Check_Item(unsigned index) const unsigned subBits = SectorSizeBits - k_MiniSectorSizeBits; const UInt32 fid = sid >> subBits; if (fid >= NumSectors_in_MiniStream) - return false; + return S_FALSE; sid = Mat[sid]; if (size <= clusterSize) break; @@ -887,12 +887,16 @@ HRESULT CDatabase::Open(IInStream *inStream) } else if (item.IsStorage()) { - if (item.Size != 0) // by specification - return S_FALSE; - if (item.Sid != 0 // by specification + /* some old compound archives don't comply specification for (Size) and (Sid) fields for kStorage items. + But original Windows code ignores these errors. + We also ignore these errors: */ +#if 0 + if (item.Size != 0 // by specification + || ( item.Sid != 0 // by specification && item.Sid != NFatID::kFree // NFatID::kFree is used in some AAF files - && item.Sid != NFatID::kEndOfChain) // NFatID::kEndOfChain is used in QuickSet (selinc) file - return S_FALSE; + && item.Sid != NFatID::kEndOfChain)) // NFatID::kEndOfChain is used in QuickSet (selinc) file + HeadersWarning = true; +#endif } // else if (item.Type == NItemType::kRootStorage) return S_FALSE; else if (item.IsEmptyType()) @@ -1375,9 +1379,10 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) const unsigned subBits = _db.SectorSizeBits - k_MiniSectorSizeBits; const UInt32 fid = sid >> subBits; if (fid >= _db.NumSectors_in_MiniStream) - return false; + return S_FALSE; + const UInt32 temp = ((sid & ((1u << subBits) - 1)) << k_MiniSectorSizeBits); const UInt64 offset = (((UInt64)_db.MiniSids[fid] + 1) << _db.SectorSizeBits) + - ((sid & ((1u << subBits) - 1)) << k_MiniSectorSizeBits); + temp; if (phyPos != offset) { RINOK(InStream_SeekSet(_stream, offset)) diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp index 5a11e30..58770f8 100644 --- a/CPP/7zip/Archive/Common/HandlerOut.cpp +++ b/CPP/7zip/Archive/Common/HandlerOut.cpp @@ -98,7 +98,7 @@ bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIAN if (name.IsPrefixedBy_Ascii_NoCase("memuse")) { - UInt64 v; + UInt64 v = 0; if (!ParseSizeString(name.Ptr(6), value, _memAvail, v)) hres = E_INVALIDARG; _memUsage_Decompress = v; diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp index d379373..27ae94e 100644 --- a/CPP/7zip/Archive/ExtHandler.cpp +++ b/CPP/7zip/Archive/ExtHandler.cpp @@ -2167,9 +2167,9 @@ public: _curRem = 0; _virtPos = 0; _physPos = 0; - if (Vector.Size() > 0) + if (Vector.Size()) { - _physPos = (Vector[0] << BlockBits); + _physPos = (UInt64)Vector[0] << BlockBits; return SeekToPhys(); } return S_OK; diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp index 18fce91..7a0774c 100644 --- a/CPP/7zip/Archive/FatHandler.cpp +++ b/CPP/7zip/Archive/FatHandler.cpp @@ -497,7 +497,8 @@ HRESULT CDatabase::OpenProgressFat(bool changeTotal) return S_OK; if (changeTotal) { - const UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) + + const UInt32 fatBytes = Header.CalcFatSizeInSectors() << Header.SectorSizeLog; + const UInt64 numTotalBytes = fatBytes + ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog); RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes)) } @@ -938,7 +939,7 @@ Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream)) CClusterInStream *streamSpec = new CClusterInStream; CMyComPtr streamTemp = streamSpec; streamSpec->Stream = InStream; - streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog; + streamSpec->StartOffset = (UInt64)Header.DataSector << Header.SectorSizeLog; streamSpec->BlockSizeLog = Header.ClusterSizeLog; streamSpec->Size = item.Size; diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp index ca9d246..9c85bf3 100644 --- a/CPP/7zip/Archive/GzHandler.cpp +++ b/CPP/7zip/Archive/GzHandler.cpp @@ -838,8 +838,6 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, // outStream.Release(); - retResult = NExtract::NOperationResult::kDataError; - if (!_isArc) retResult = NExtract::NOperationResult::kIsNotArc; else if (_needMoreInput) diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp index 5df00ed..1d6492e 100644 --- a/CPP/7zip/Archive/HfsHandler.cpp +++ b/CPP/7zip/Archive/HfsHandler.cpp @@ -1429,7 +1429,10 @@ HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress) const unsigned sector_of_FirstBlock = Get16a(p + 0x1c); // drAlBlSt : first allocation block in volume const UInt32 startBlock = Get16a(p + 0x7c + 2); const UInt32 blockCount = Get16a(p + 0x7c + 4); - SpecOffset = (UInt32)sector_of_FirstBlock << 9; // it's 32-bit here + { + const UInt32 temp = (UInt32)sector_of_FirstBlock << 9; // it's 32-bit here + SpecOffset = temp; + } PhySize2 = SpecOffset + (UInt64)numBlocks * blockSize; SpecOffset += (UInt64)startBlock * blockSize; // before v24.09: // SpecOffset = (UInt64)(1 + startBlock) * blockSize; diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp index c085386..20937bb 100644 --- a/CPP/7zip/Archive/Iso/IsoHandler.cpp +++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp @@ -51,12 +51,12 @@ IMP_IInArchive_ArcProps Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, - IArchiveOpenCallback * /* openArchiveCallback */)) + IArchiveOpenCallback *openCallback)) { COM_TRY_BEGIN Close(); { - RINOK(_archive.Open(stream)) + RINOK(_archive.Open(stream, openCallback)) _stream = stream; } return S_OK; @@ -165,6 +165,8 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) AddErrorMessage(s, "Self-linked directory"); if (_archive.TooDeepDirs) AddErrorMessage(s, "Too deep directory levels"); + if (_archive.TooBigMetadata) + AddErrorMessage(s, "Too big headers"); if (!s.IsEmpty()) prop = s; break; diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index 0054abf..b775dfc 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -94,7 +94,8 @@ Byte CInArchive::ReadByte() throw CSystemException(res); if (processed != kBlockSize) throw CUnexpectedEndException(); - UInt64 end = _position + processed; + _processedBytes += processed; + const UInt64 end = _position + processed; if (PhySize < end) PhySize = end; } @@ -172,22 +173,30 @@ UInt32 CInArchive::ReadUInt32() return val; } -UInt32 CInArchive::ReadDigits(int numDigits) +unsigned CInArchive::ReadDigits(unsigned numDigits) { - UInt32 res = 0; - for (int i = 0; i < numDigits; i++) + unsigned res = 0; + unsigned mode = 0; + for (unsigned i = 0; i < numDigits; i++) { - Byte b = ReadByte(); - if (b < '0' || b > '9') + const Byte b = ReadByte(); + if (mode == 2) + continue; + const unsigned d = (unsigned)b - (unsigned)'0'; + if (d > 9) { - if (b == 0 || b == ' ') // it's bug in some CD's - b = '0'; - else + // what exact cases are possible here? + if (b != 0 && b != ' ') throw CHeaderErrorException(); + if (mode == 1) + mode = 2; + } + else + { + mode = 1; + res *= 10; + res += d; } - UInt32 d = (UInt32)(b - '0'); - res *= 10; - res += d; } return res; } @@ -222,7 +231,7 @@ void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t) t.GmtOffset = (signed char)ReadByte(); } -void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) +void CInArchive::ReadDirRecord(CDirRecord &r, unsigned len, bool isJolietDescriptor) { r.ExtendedAttributeRecordLen = ReadByte(); if (r.ExtendedAttributeRecordLen != 0) @@ -234,29 +243,28 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) r.FileUnitSize = ReadByte(); r.InterleaveGapSize = ReadByte(); r.VolSequenceNumber = ReadUInt16(); - Byte idLen = ReadByte(); + unsigned idLen = ReadByte(); + /* for Descriptor Root Directory Record: + idLen == 1 : by ISO Specification + idLen == 1 : for some Joliet archives + idLen == 2 : for some Joliet archives for UCS-2 (UTF-16BE). + but (len == 34) is fixed for Descriptor Root Directory Record + so we ignore idLen == 2 value in Joliet Descriptor. + */ + if (isJolietDescriptor && idLen == 2) // v26.03 : we support Joliet cases + idLen = 0; r.FileId.Alloc(idLen); ReadBytes((Byte *)r.FileId, idLen); - unsigned padSize = 1 - (idLen & 1); - + idLen += 33; + const unsigned padSize = idLen & 1; // SkipZeros(padSize); Skip(padSize); // it's bug in some cd's. Must be zeros - - unsigned curPos = 33 + idLen + padSize; - if (curPos > len) + idLen += padSize; + if (len < idLen) throw CHeaderErrorException(); - unsigned rem = len - curPos; - r.SystemUse.Alloc(rem); - ReadBytes((Byte *)r.SystemUse, rem); -} - -void CInArchive::ReadDirRecord(CDirRecord &r) -{ - Byte len = ReadByte(); - // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor. - // But maybe we must use real "len" for other records. - len = 34; - ReadDirRecord2(r, len); + len -= idLen; + r.SystemUse.Alloc(len); + ReadBytes((Byte *)r.SystemUse, len); } void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d) @@ -275,7 +283,16 @@ void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d) d.LOptionalPathTableLocation = ReadUInt32Le(); d.MPathTableLocation = ReadUInt32Be(); d.MOptionalPathTableLocation = ReadUInt32Be(); - ReadDirRecord(d.RootDirRecord); + { + unsigned len; + /* len = */ ReadByte(); + // len == 34 is expected by ISO specification + // len == 36 is possible for some Joliet archives + // len == 48 is possible for Rock Ridge? + len = 34; // we ignore (len) value from header because + // next field (VolumeSetId) always starts after 34 bytes + ReadDirRecord(d.RootDirRecord, len, d.IsJoliet()); + } ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId)); ReadBytes(d.PublisherId, sizeof(d.PublisherId)); ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId)); @@ -330,16 +347,16 @@ void CInArchive::SeekToBlock(UInt32 blockIndex) m_BufferPos = 0; } -static const int kNumLevelsMax = 256; +static const unsigned kNumLevelsMax = 256; -void CInArchive::ReadDir(CDir &d, int level) +HRESULT CInArchive::ReadDir(CDir &d, unsigned level) { if (!d.IsDir()) - return; + return S_OK; if (level > kNumLevelsMax) { TooDeepDirs = true; - return; + return S_OK; } { @@ -347,7 +364,7 @@ void CInArchive::ReadDir(CDir &d, int level) if (UniqStartLocations[i] == d.ExtentLocation) { SelfLinkedDirs = true; - return; + return S_OK; } UniqStartLocations.Add(d.ExtentLocation); } @@ -358,26 +375,47 @@ void CInArchive::ReadDir(CDir &d, int level) bool firstItem = true; for (;;) { - UInt64 offset = _position - startPos; + const UInt64 offset = _position - startPos; if (offset >= d.Size) break; - Byte len = ReadByte(); + const unsigned len = ReadByte(); if (len == 0) continue; CDir subItem; - ReadDirRecord2(subItem, len); + ReadDirRecord(subItem, len); if (firstItem && level == 0) IsSusp = subItem.CheckSusp(SuspSkipSize); if (!subItem.IsSystemItem()) + { + if (_numFiles >= (1u << 30)) + { + TooBigMetadata = true; // Too many files + return S_FALSE; + } d._subItems.Add(subItem); + _numFiles++; + } + if (_openCallback && _processedBytes - _processedBytes_prev >= (1 << 24)) + { + _processedBytes_prev = _processedBytes; + RINOK(_openCallback->SetTotal(&_numFiles, &_processedBytes)) + } + if (_processedBytes > _fileSize + (1u << 24)) + { + TooBigMetadata = true; + return S_FALSE; + } firstItem = false; } FOR_VECTOR (i, d._subItems) - ReadDir(d._subItems[i], level + 1); + { + RINOK(ReadDir(d._subItems[i], level + 1)) + } UniqStartLocations.DeleteBack(); + return S_OK; } void CInArchive::CreateRefs(CDir &d) @@ -614,7 +652,7 @@ HRESULT CInArchive::Open2() IsArc = true; (CDirRecord &)_rootDir = vd.RootDirRecord; - ReadDir(_rootDir, 0); + RINOK(ReadDir(_rootDir, 0)) CreateRefs(_rootDir); ReadBootInfo(); @@ -671,10 +709,12 @@ HRESULT CInArchive::Open2() return S_OK; } -HRESULT CInArchive::Open(IInStream *inStream) +HRESULT CInArchive::Open(IInStream *inStream, IArchiveOpenCallback *openCallback) { Clear(); _stream = inStream; + _openCallback = openCallback; + _numFiles = _processedBytes = _processedBytes_prev = 0; try { return Open2(); } catch(const CSystemException &e) { return e.ErrorCode; } catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } @@ -689,6 +729,7 @@ void CInArchive::Clear() HeadersError = false; IncorrectBigEndian = false; TooDeepDirs = false; + TooBigMetadata = false; SelfLinkedDirs = false; UniqStartLocations.Clear(); diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h index e7d1fee..6a031ba 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.h +++ b/CPP/7zip/Archive/Iso/IsoIn.h @@ -237,14 +237,12 @@ struct CRef UInt64 TotalSize; }; -const UInt32 kBlockSize = 1 << 11; +const unsigned kBlockSize = 1 << 11; class CInArchive { - IInStream *_stream; UInt64 _position; - - UInt32 m_BufferPos; + unsigned m_BufferPos; void Skip(size_t size); void SkipZeros(size_t size); @@ -255,23 +253,22 @@ class CInArchive UInt32 ReadUInt32Be(); UInt32 ReadUInt32(); UInt64 ReadUInt64(); - UInt32 ReadDigits(int numDigits); + unsigned ReadDigits(unsigned numDigits); void ReadDateTime(CDateTime &d); void ReadRecordingDateTime(CRecordingDateTime &t); - void ReadDirRecord2(CDirRecord &r, Byte len); - void ReadDirRecord(CDirRecord &r); + void ReadDirRecord(CDirRecord &r, unsigned len, bool isJolietDescriptor = false); void ReadBootRecordDescriptor(CBootRecordDescriptor &d); void ReadVolumeDescriptor(CVolumeDescriptor &d); void SeekToBlock(UInt32 blockIndex); - void ReadDir(CDir &d, int level); + HRESULT ReadDir(CDir &d, unsigned level); void CreateRefs(CDir &d); void ReadBootInfo(); HRESULT Open2(); public: - HRESULT Open(IInStream *inStream); + HRESULT Open(IInStream *inStream, IArchiveOpenCallback *openCallback); void Clear(); UInt64 _fileSize; @@ -291,10 +288,12 @@ public: bool HeadersError; bool IncorrectBigEndian; bool TooDeepDirs; + bool TooBigMetadata; bool SelfLinkedDirs; bool IsSusp; unsigned SuspSkipSize; +private: int _expand_BootEntries_index; CRecordVector UniqStartLocations; @@ -307,12 +306,19 @@ public: PhySize = end; } +public: bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); } UInt64 GetBootItemSize(unsigned index) const; private: CDir _rootDir; + IInStream *_stream; + IArchiveOpenCallback *_openCallback; + UInt64 _numFiles; + UInt64 _processedBytes; + UInt64 _processedBytes_prev; + Byte m_Buffer[kBlockSize]; CBootRecordDescriptor _bootDesc; }; diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h index 65829d0..ef3832a 100644 --- a/CPP/7zip/Archive/Iso/IsoItem.h +++ b/CPP/7zip/Archive/Iso/IsoItem.h @@ -81,8 +81,7 @@ struct CDirRecord bool AreMultiPartEqualWith(const CDirRecord &a) const { return FileId == a.FileId - && (FileFlags & (~NFileFlags::kNonFinalExtent)) == - (a.FileFlags & (~NFileFlags::kNonFinalExtent)); + && ((FileFlags ^ a.FileFlags) & ~NFileFlags::kNonFinalExtent) == 0; } bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; } @@ -90,10 +89,7 @@ struct CDirRecord bool IsSystemItem() const { - if (FileId.Size() != 1) - return false; - Byte b = *(const Byte *)FileId; - return (b == 0 || b == 1); + return FileId.Size() == 1 && *(const Byte *)FileId < 2; } diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp index 7cbabf4..a0c5021 100644 --- a/CPP/7zip/Archive/LzmaHandler.cpp +++ b/CPP/7zip/Archive/LzmaHandler.cpp @@ -185,7 +185,7 @@ Z7_CLASS_IMP_CHandler_IInArchive_1( UInt64 _unpackSize; UInt64 _numStreams; - void GetMethod(NCOM::CPropVariant &prop); + void GetMethod(NCOM::CPropVariant &prop) const; unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); } public: @@ -249,7 +249,7 @@ static char *AddProp32(char *s, const char *name, UInt32 v) return ::ConvertUInt32ToString(v, s); } -void CHandler::GetMethod(NCOM::CPropVariant &prop) +void CHandler::GetMethod(NCOM::CPropVariant &prop) const { if (!_stream) return; @@ -270,7 +270,7 @@ void CHandler::GetMethod(NCOM::CPropVariant &prop) UInt32 lp = d % 5; if (lc != 3) s = AddProp32(s, "lc", lc); if (lp != 0) s = AddProp32(s, "lp", lp); - if (pb != 2) s = AddProp32(s, "pb", pb); + if (pb != 2) /* s = */ AddProp32(s, "pb", pb); } prop = sz; } @@ -568,9 +568,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, opResult = NExtract::NOperationResult::kDataAfterEnd; else if (hres == S_FALSE) opResult = NExtract::NOperationResult::kDataError; - else if (hres == S_OK) - opResult = NExtract::NOperationResult::kOK; - else + else if (hres != S_OK) return hres; // outStream.Release(); diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp index 7ce2e8e..d17dca7 100644 --- a/CPP/7zip/Archive/Nsis/NsisHandler.cpp +++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp @@ -148,7 +148,17 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) prop = v; break; } - + case kpidWarningFlags: + { + UInt32 flags = 0; + if (_archive.CREATEDIR_processing_WasStopped + || _archive.FILENAME_processing_WasStopped) + flags |= kpv_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + case kpidName: { AString s; diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp index 577062e..b6ff749 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.cpp +++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp @@ -17,6 +17,8 @@ namespace NArchive { namespace NNsis { +struct CInArchiveException {}; + static const size_t kInputBufSize = 1 << 20; const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE; @@ -591,7 +593,7 @@ void CInArchive::GetVar2(AString &res, UInt32 index) { if (index >= 10) { - res += 'R'; + res.Add_Char('R'); index -= 10; } UIntToString(res, index); @@ -607,16 +609,16 @@ void CInArchive::GetVar2(AString &res, UInt32 index) } else { - res += '_'; + res.Add_Char('_'); UIntToString(res, index - numInternalVars); - res += '_'; + res.Add_Char('_'); } } } void CInArchive::GetVar(AString &res, UInt32 index) { - res += '$'; + res.Add_Char('$'); GetVar2(res, index); } @@ -737,7 +739,7 @@ void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2) if (id < 0) { - s += '('; + s.Add_Char('('); if (IsUnicode) { for (unsigned i = 0; i < 256; i++) @@ -751,12 +753,12 @@ void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2) } else s += (const char *)p; - s += ')'; + s.Add_Char(')'); } return; } - s += '$'; + s.Add_Char('$'); if (index1 < Z7_ARRAY_SIZE(kShellStrings)) { const char *sz = kShellStrings[index1]; @@ -776,11 +778,11 @@ void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2) } } s += "_ERROR_UNSUPPORTED_SHELL_"; - s += '['; + s.Add_Char('['); UIntToString(s, index1); - s += ','; + s.Add_Char(','); UIntToString(s, index2); - s += ']'; + s.Add_Char(']'); } #ifdef NSIS_SCRIPT @@ -800,9 +802,16 @@ void CInArchive::Add_LangStr(AString &res, UInt32 id) #endif res += "$(LSTR_"; UIntToString(res, id); - res += ')'; + res.Add_Char(')'); } +static const unsigned k_StringLen_Limit = 1 << 16; + +#define CHECK_STRING_LEN(s) \ + { if (s.Len() >= k_StringLen_Limit) \ + { /* s = "[LONG_PATH]"; return; */ throw CInArchiveException(); } } + + void CInArchive::GetNsisString_Raw(const Byte *s) { Raw_AString.Empty(); @@ -811,6 +820,7 @@ void CInArchive::GetNsisString_Raw(const Byte *s) { for (;;) { + CHECK_STRING_LEN(Raw_AString) Byte c = *s++; if (c == 0) return; @@ -846,6 +856,7 @@ void CInArchive::GetNsisString_Raw(const Byte *s) // NSIS-3 ANSI for (;;) { + CHECK_STRING_LEN(Raw_AString) Byte c = *s++; if (c <= NS_3_CODE_SKIP) { @@ -973,6 +984,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) { for (;;) { + CHECK_STRING_LEN(Raw_UString) unsigned c = Get16(p); p += 2; if (c == 0) @@ -1017,6 +1029,7 @@ void CInArchive::GetNsisString_Unicode_Raw(const Byte *p) // NSIS-3 Unicode for (;;) { + CHECK_STRING_LEN(Raw_UString) unsigned c = Get16(p); p += 2; if (c > NS_3_CODE_SKIP) @@ -2124,7 +2137,7 @@ bool CInArchive::PrintSectionBegin(const CSection §, unsigned index) { AString name; if (sect.Flags & SF_BOLD) - name += '!'; + name.Add_Char('!'); AString s2; ReadString2(s2, sect.Name); if (!IsInstaller) @@ -2330,9 +2343,9 @@ void CInArchive::MessageBox_MB_Part(UInt32 param) static const Byte k_InitPluginDir_Commands[] = { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 }; -bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) +bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) const { - for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize) + for (size_t kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize) if (GetCmd(Get32(rawCmds)) != sequence[kkk]) return false; return true; @@ -2410,7 +2423,7 @@ unsigned CInArchive::GetNumSupportedCommands() const #endif -UInt32 CInArchive::GetCmd(UInt32 a) +UInt32 CInArchive::GetCmd(UInt32 a) const { if (!IsPark()) { @@ -2875,21 +2888,58 @@ static bool IsAbsolutePath(const char *s) return (s[0] == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) || IsDrivePath(s); } -void CInArchive::SetItemName(CItem &item, UInt32 strPos) + +static const unsigned k_PathLen_Small_Limit = 60 + 260 * 4; // we reserve some space for multibyte encoding and for prefix +static const unsigned k_PathLen_Break_Limit = 1 << 12; // must be >= k_PathLen_Small_Limit + +#define k_LONG_PATH_DIR "[LONG_PATH]" +#define k_UNKNOWN_PATH_DIR "[UNKNOWN_PATH]" +#define k_LONG_PATH_FILE "[LONG_PATH_FILE]" +#define k_UNKNOWN_PATH_FILE "[UNKNOWN_PATH_FILE]" + +void CInArchive::SetItemName(CItem &item, const UInt32 strPos) { - ReadString2_Raw(strPos); - const bool isAbs = IsAbsolutePathVar(strPos); - if (IsUnicode) + item.Prefix = -1; + if (FILENAME_processing_WasStopped) { - item.NameU = Raw_UString; - if (!isAbs && !IsAbsolutePath(Raw_UString)) - item.Prefix = (int)UPrefixes.Size() - 1; + if (IsUnicode) + item.NameU = k_UNKNOWN_PATH_FILE; + else + item.NameA = k_UNKNOWN_PATH_FILE; } else { - item.NameA = Raw_AString; - if (!isAbs && !IsAbsolutePath(Raw_AString)) - item.Prefix = (int)APrefixes.Size() - 1; + ReadString2_Raw(strPos); + const bool isAbs = IsAbsolutePathVar(strPos); + if (IsUnicode) + { + if (Raw_UString.Len() >= k_PathLen_Small_Limit) + item.NameU = k_LONG_PATH_FILE; + else + { + item.NameU = Raw_UString; + if (!isAbs && !IsAbsolutePath(Raw_UString)) + item.Prefix = (int)UPrefixes.Size() - 1; + } + if (Raw_UString.Len() >= k_PathLen_Break_Limit) + FILENAME_processing_WasStopped = true; + } + else + { + if (Raw_AString.Len() >= k_PathLen_Small_Limit) + item.NameA = k_LONG_PATH_FILE; + else + { + item.NameA = Raw_AString; + if (!isAbs && !IsAbsolutePath(Raw_AString)) + item.Prefix = (int)APrefixes.Size() - 1; + } + if (Raw_AString.Len() >= k_PathLen_Break_Limit) + FILENAME_processing_WasStopped = true; + } + _memUsage_Files += item.NameA.Len() + item.NameU.Len() * 2 + 128; + if (_memUsage_Files >= (1 << 29)) + FILENAME_processing_WasStopped = true; } } @@ -3387,14 +3437,14 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) { case EW_CREATEDIR: { - bool isSetOutPath = (params[1] != 0); + const bool isSetOutPath = (params[1] != 0); - if (isSetOutPath) + if (isSetOutPath && !CREATEDIR_processing_WasStopped) { UInt32 par0 = params[0]; UInt32 resOffset; - Int32 idx = GetVarIndex(par0, resOffset); + const Int32 idx = GetVarIndex(par0, resOffset); if (idx == (Int32)spec_outdir_VarIndex || idx == kVar_OUTDIR) par0 += resOffset; @@ -3407,7 +3457,11 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) Raw_UString.Insert(0, spec_outdir_U); else if (idx == kVar_OUTDIR) Raw_UString.Insert(0, UPrefixes.Back()); - UPrefixes.Add(Raw_UString); + if (Raw_UString.Len() >= k_PathLen_Break_Limit) + CREATEDIR_processing_WasStopped = true; + if (Raw_UString.Len() >= k_PathLen_Small_Limit) + Raw_UString = k_LONG_PATH_DIR; + _memUsage_Dirs += Raw_UString.Len() * 2; } else { @@ -3415,11 +3469,30 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) Raw_AString.Insert(0, spec_outdir_A); else if (idx == kVar_OUTDIR) Raw_AString.Insert(0, APrefixes.Back()); - APrefixes.Add(Raw_AString); + if (Raw_AString.Len() >= k_PathLen_Break_Limit) + CREATEDIR_processing_WasStopped = true; + if (Raw_AString.Len() >= k_PathLen_Small_Limit) + Raw_AString = k_LONG_PATH_DIR; + _memUsage_Dirs += Raw_AString.Len(); + } + _memUsage_Dirs += 64; + if (_memUsage_Dirs >= (1 << 25)) + { + CREATEDIR_processing_WasStopped = true; + if (IsUnicode) + Raw_UString = k_UNKNOWN_PATH_DIR; + else + Raw_AString = k_UNKNOWN_PATH_DIR; } + if (IsUnicode) + UPrefixes.Add(Raw_UString); + else + APrefixes.Add(Raw_AString); } #ifdef NSIS_SCRIPT + if (!s.IsError()) + { s += isSetOutPath ? "SetOutPath" : "CreateDirectory"; AddParam(params[0]); if (params[2] != 0) // 2.51+ & 3.0b3+ @@ -3427,6 +3500,7 @@ HRESULT CInArchive::ReadEntries(const CBlockHeader &bh) SmallSpaceComment(); s += "CreateRestrictedDirectory"; } + } #endif break; @@ -5242,7 +5316,7 @@ HRESULT CInArchive::Parse() } } - if (bhEntries.Num > (1 << 25)) + if (bhEntries.Num > (1 << 24)) return S_FALSE; if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset) return S_FALSE; @@ -5495,7 +5569,12 @@ HRESULT CInArchive::Parse() return E_NOTIMPL; // maybe it's old NSIS archive() if (langtable_size < 10) - return S_FALSE; + { + // return S_FALSE; + } + else + { + if (bhLangTables.Num > (_size - bhLangTables.Offset) / langtable_size) return S_FALSE; @@ -5610,6 +5689,7 @@ HRESULT CInArchive::Parse() AddLF(); } ClearLangComment(); + } } { @@ -6077,6 +6157,7 @@ HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPositio DataStreamOffset -= pos; res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize); } + catch(CInArchiveException &) { res = S_FALSE; } catch(...) { _stream.Release(); @@ -6112,6 +6193,10 @@ void CInArchive::Clear2() LogCmdIsEnabled = false; BadCmd = -1; Is64Bit = false; + CREATEDIR_processing_WasStopped = false; + FILENAME_processing_WasStopped = false; + _memUsage_Dirs = 0; + _memUsage_Files = 0; #ifdef NSIS_SCRIPT Name.Empty(); diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h index 1f8c967..772f13f 100644 --- a/CPP/7zip/Archive/Nsis/NsisIn.h +++ b/CPP/7zip/Archive/Nsis/NsisIn.h @@ -165,8 +165,11 @@ public: #endif CByteBuffer _data; CObjectVector Items; + bool IsArc; bool IsUnicode; bool Is64Bit; + bool CREATEDIR_processing_WasStopped; + bool FILENAME_processing_WasStopped; private: UInt32 _stringsPos; // relative to _data UInt32 NumStringChars; @@ -217,13 +220,14 @@ private: #endif + UInt32 _memUsage_Dirs; + UInt32 _memUsage_Files; + public: CMyComPtr _stream; // it's limited stream that contains only NSIS archive UInt64 StartOffset; // offset in original stream. UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream - bool IsArc; - CDecoder Decoder; CByteBuffer ExeStub; CFirstHeader FirstHeader; @@ -322,7 +326,7 @@ private: void PrintNumComment(const char *name, UInt32 value); void Add_QuStr(const AString &s); void SpaceQuStr(const AString &s); - bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands); + bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands) const; #endif @@ -330,7 +334,7 @@ private: unsigned GetNumSupportedCommands() const; #endif - UInt32 GetCmd(UInt32 a); + UInt32 GetCmd(UInt32 a) const; void FindBadCmd(const CBlockHeader &bh, const Byte *); void DetectNsisType(const CBlockHeader &bh, const Byte *); diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp index 006f0ad..baf6a4d 100644 --- a/CPP/7zip/Archive/NtfsHandler.cpp +++ b/CPP/7zip/Archive/NtfsHandler.cpp @@ -813,7 +813,8 @@ Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) { memset((Byte *)data, 0, size); _virtPos += size; - *processedSize = size; + if (processedSize) + *processedSize = size; return S_OK; } @@ -836,7 +837,8 @@ Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) if (cur > size) cur = size; memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur); - *processedSize = (UInt32)cur; + if (processedSize) + *processedSize = (UInt32)cur; _virtPos += cur; return S_OK; } @@ -1311,7 +1313,7 @@ bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 r // PRF(printf("\nusn = %d", usn)); for (UInt32 i = 1; i < numUsaItems; i++) { - void *pp = p + (i << sectorSizeLog) - 2; + void *pp = p + ((size_t)i << sectorSizeLog) - 2; if (Get16(pp) != usn) return false; SetUi16(pp, Get16(p + usaOffset + i * 2)) diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index f5f66b0..7d78234 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -1562,8 +1562,8 @@ struct CMy_VS_FIXEDFILEINFO UInt32 OS; UInt32 Type; UInt32 Subtype; - UInt32 DateMS; - UInt32 DateLS; + // UInt32 DateMS; + // UInt32 DateLS; bool Parse(const Byte *p); void PrintToTextFile(CTextFile &f, CObjectVector &keys); @@ -1583,8 +1583,8 @@ bool CMy_VS_FIXEDFILEINFO::Parse(const Byte *p) G32(0x20, OS); G32(0x24, Type); G32(0x28, Subtype); - G32(0x2C, DateMS); - G32(0x40, DateLS); + // G32(0x2C, DateMS); + // G32(0x30, DateLS); return true; } diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp index 5f9e1c3..b3b1cdb 100644 --- a/CPP/7zip/Archive/PpmdHandler.cpp +++ b/CPP/7zip/Archive/PpmdHandler.cpp @@ -27,7 +27,7 @@ using namespace NWindows; namespace NArchive { namespace NPpmd { -static const UInt32 kBufSize = (1 << 20); +static const size_t kBufSize = 1 << 20; struct CBuf { @@ -220,58 +220,74 @@ Z7_COM7F_IMF(CHandler::Close()) struct CPpmdCpp { - unsigned Ver; - CPpmd7 _ppmd7; - CPpmd8 _ppmd8; + CPpmd7 *_ppmd7; + CPpmd8 *_ppmd8; - CPpmdCpp(unsigned version) + CPpmdCpp(unsigned version): + _ppmd7(NULL), + _ppmd8(NULL) { - Ver = version; - Ppmd7_Construct(&_ppmd7); - Ppmd8_Construct(&_ppmd8); + if (version == 7) + { + _ppmd7 = new CPpmd7(); + Ppmd7_Construct(_ppmd7); + } + else + { + _ppmd8 = new CPpmd8(); + Ppmd8_Construct(_ppmd8); + } } ~CPpmdCpp() { - Ppmd7_Free(&_ppmd7, &g_BigAlloc); - Ppmd8_Free(&_ppmd8, &g_BigAlloc); + if (_ppmd7) + { + Ppmd7_Free(_ppmd7, &g_BigAlloc); + delete _ppmd7; + } + if (_ppmd8) + { + Ppmd8_Free(_ppmd8, &g_BigAlloc); + delete _ppmd8; + } } - bool Alloc(UInt32 memInMB) + BoolInt Alloc(UInt32 memInMB) { memInMB <<= 20; - if (Ver == 7) - return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0; - return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0; + if (_ppmd7) + return Ppmd7_Alloc(_ppmd7, memInMB, &g_BigAlloc); + return Ppmd8_Alloc(_ppmd8, memInMB, &g_BigAlloc); } void Init(unsigned order, unsigned restor) { - if (Ver == 7) - Ppmd7_Init(&_ppmd7, order); + if (_ppmd7) + Ppmd7_Init(_ppmd7, order); else - Ppmd8_Init(&_ppmd8, order, restor); + Ppmd8_Init(_ppmd8, order, restor); } bool InitRc(CByteInBufWrap *inStream) { - if (Ver == 7) + if (_ppmd7) { - _ppmd7.rc.dec.Stream = &inStream->vt; - return (Ppmd7a_RangeDec_Init(&_ppmd7.rc.dec) != 0); + _ppmd7->rc.dec.Stream = &inStream->vt; + return (Ppmd7a_RangeDec_Init(&_ppmd7->rc.dec) != 0); } else { - _ppmd8.Stream.In = &inStream->vt; - return Ppmd8_Init_RangeDec(&_ppmd8) != 0; + _ppmd8->Stream.In = &inStream->vt; + return Ppmd8_Init_RangeDec(_ppmd8) != 0; } } bool IsFinishedOK() { - if (Ver == 7) - return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7.rc.dec); - return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8); + if (_ppmd7) + return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7->rc.dec); + return Ppmd8_RangeDec_IsFinishedOK(_ppmd8); } }; @@ -311,14 +327,14 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr2_Create lps; lps->Init(extractCallback, true); - CPpmdCpp ppmd(_item.Ver); - if (!ppmd.Alloc(_item.MemInMB)) - return E_OUTOFMEMORY; - opRes = NExtract::NOperationResult::kUnsupportedMethod; if (_item.IsSupported()) { + CPpmdCpp ppmd(_item.Ver); + if (!ppmd.Alloc(_item.MemInMB)) + return E_OUTOFMEMORY; + opRes = NExtract::NOperationResult::kDataError; ppmd.Init(_item.Order, _item.Restor); @@ -336,11 +352,11 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, int sym = 0; Byte *buf = outBuf.Buf; - if (ppmd.Ver == 7) + if (ppmd._ppmd7) { for (i = 0; i < kBufSize; i++) { - sym = Ppmd7a_DecodeSymbol(&ppmd._ppmd7); + sym = Ppmd7a_DecodeSymbol(ppmd._ppmd7); if (inBuf.Extra || sym < 0) break; buf[i] = (Byte)sym; @@ -350,7 +366,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, { for (i = 0; i < kBufSize; i++) { - sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8); + sym = Ppmd8_DecodeSymbol(ppmd._ppmd8); if (inBuf.Extra || sym < 0) break; buf[i] = (Byte)sym; diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp index c15ff52..1e01134 100644 --- a/CPP/7zip/Archive/Rar/Rar5Handler.cpp +++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp @@ -1673,7 +1673,7 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) case kpidExtension: if (_arcs.Size() == 1) { - if (arcInfo->IsVolume()) + if (arcInfo && arcInfo->IsVolume()) { AString s ("part"); UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1; @@ -1809,14 +1809,14 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp size -= num; } - if ((flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0) + if (((UInt32)flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0) return; unsigned numStamps = 0; unsigned curStamp = 0; for (unsigned i = 0; i < 3; i++) - if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) + if (((UInt32)flags & (NTimeRecord::NFlags::kMTime << i)) != 0) { if (i == stampIndex) curStamp = numStamps; diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp index 6c53847..4f181f4 100644 --- a/CPP/7zip/Archive/Rar/RarHandler.cpp +++ b/CPP/7zip/Archive/Rar/RarHandler.cpp @@ -150,8 +150,7 @@ class CInArchive CByteBuffer _comment; CByteBuffer m_FileHeaderData; NHeader::NBlock::CBlock m_BlockHeader; - NCrypto::NRar3::CDecoder *m_RarAESSpec; - CMyComPtr m_RarAES; + CMyComPtr2 m_RarAES; CAlignedBuffer m_DecryptedDataAligned; UInt32 m_DecryptedDataSize; bool m_CryptoMode; @@ -532,12 +531,8 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass error = k_ErrorType_DecryptionError; return S_OK; // return S_FALSE; } - if (!m_RarAES) - { - m_RarAESSpec = new NCrypto::NRar3::CDecoder; - m_RarAES = m_RarAESSpec; - } - // m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld()); + m_RarAES.Create_if_Empty(); + // m_RarAES->SetRar350Mode(ArcInfo.IsEncryptOld()); { // Salt @@ -546,7 +541,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass if (!ReadBytesAndTestSize(salt, kSaltSize)) return S_FALSE; m_Position += kSaltSize; - RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize)) + RINOK(m_RarAES->SetDecoderProperties2(salt, kSaltSize)) } { @@ -567,7 +562,7 @@ HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPass ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); } - m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2); + m_RarAES->SetPassword((const Byte *)buffer, len * 2); } const UInt32 kDecryptedBufferSize = (1 << 12); @@ -1477,22 +1472,17 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, CObjectVector methodItems; - NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; - CMyComPtr copyCoder = copyCoderSpec; + CMyComPtr2_Create copyCoder; CFilterCoder *filterStreamSpec = new CFilterCoder(false); CMyComPtr filterStream = filterStreamSpec; - NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL; - CMyComPtr rar20CryptoDecoder; - NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL; - CMyComPtr rar3CryptoDecoder; + CMyComPtr2 rar20CryptoDecoder; + CMyComPtr2 rar3CryptoDecoder; - CVolsInStream *volsInStreamSpec = NULL; - CMyComPtr volsInStream; + CMyComPtr2 volsInStream; - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; + CMyComPtr2_Create lps; lps->Init(extractCallback, false); bool solidStart = true; @@ -1572,13 +1562,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, outStreamSpec->Init(); realOutStream.Release(); - if (!volsInStream) - { - volsInStreamSpec = new CVolsInStream; - volsInStream = volsInStreamSpec; - } - - volsInStreamSpec->Init(&_arcs, &_items, refItem); + volsInStream.Create_if_Empty(); + volsInStream->Init(&_arcs, &_items, refItem); UInt64 packSize = currentPackSize; @@ -1593,27 +1578,19 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (item.UnPackVersion >= 29) { - if (!rar3CryptoDecoder) - { - rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder; - rar3CryptoDecoder = rar3CryptoDecoderSpec; - } - // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36); + rar3CryptoDecoder.Create_if_Empty(); + // rar3CryptoDecoder->SetRar350Mode(item.UnPackVersion < 36); /* CMyComPtr cryptoProperties; RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2, &cryptoProperties)); */ - RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)) + RINOK(rar3CryptoDecoder->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0)) filterStreamSpec->Filter = rar3CryptoDecoder; } else if (item.UnPackVersion >= 20) { - if (!rar20CryptoDecoder) - { - rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder; - rar20CryptoDecoder = rar20CryptoDecoderSpec; - } + rar20CryptoDecoder.Create_if_Empty(); filterStreamSpec->Filter = rar20CryptoDecoder; } else @@ -1654,7 +1631,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, ((Byte *)buffer)[k * 2] = (Byte)c; ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8); } - rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2); + rar3CryptoDecoder->SetPassword((const Byte *)buffer, len * 2); } else { @@ -1667,7 +1644,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, unicode.DeleteFrom(kPasswordLen_MAX); UnicodeStringToMultiByte2(oemPassword, unicode, CP_OEMCP); } - rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()); + rar20CryptoDecoder->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len()); } } /* @@ -1757,7 +1734,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } - HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, progress); + HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, lps); if (item.IsEncrypted()) filterStreamSpec->ReleaseInStream(); @@ -1765,7 +1742,7 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (outSize == (UInt64)(Int64)-1) currentUnPackSize = outStreamSpec->GetSize(); - int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ? + int opRes = (volsInStream->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ? NExtract::NOperationResult::kOK: NExtract::NOperationResult::kCRCError; outStream.Release(); diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp index 83cb1cf..e841879 100644 --- a/CPP/7zip/Archive/SquashfsHandler.cpp +++ b/CPP/7zip/Archive/SquashfsHandler.cpp @@ -1634,11 +1634,13 @@ HRESULT CHandler::Open2(IInStream *inStream) RINOK(Seek2(offset)) RINOK(ReadMetadataBlock2()) const UInt32 unpackSize = (UInt32)_dynOutStream->GetSize(); - if (unpackSize != kMetadataBlockSize) - if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) - return S_FALSE; + UInt32 remSize = (_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1); + if (remSize == 0 || i != numBlocks - 1) + remSize = kMetadataBlockSize; + if (unpackSize != remSize) + return S_FALSE; const Byte *buf = _dynOutStream->GetBuffer(); - for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;) + for (UInt32 j = 0; j < unpackSize;) { CFrag frag; if (bigFrag) @@ -1723,8 +1725,9 @@ HRESULT CHandler::Open2(IInStream *inStream) // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); RINOK(ReadMetadataBlock2()) const size_t unpackSize = _dynOutStream->GetSize(); - const UInt32 remSize = (i == numBlocks - 1) ? - (size & (kMetadataBlockSize - 1)) : kMetadataBlockSize; + UInt32 remSize = size & (kMetadataBlockSize - 1); + if (remSize == 0 || i != numBlocks - 1) + remSize = kMetadataBlockSize; if (unpackSize != remSize) return S_FALSE; memcpy(_uids + kMetadataBlockSize * i, _dynOutStream->GetBuffer(), remSize); @@ -2171,8 +2174,8 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) if (compressed) { _outStream->Init((Byte *)_cachedBlock, _h.BlockSize); - bool outBufWasWritten; - UInt32 outBufWasWrittenSize; + bool outBufWasWritten = false; + UInt32 outBufWasWrittenSize = 0; HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize); RINOK(res) if (outBufWasWritten) diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp index b143d9a..9586f7d 100644 --- a/CPP/7zip/Archive/SwfHandler.cpp +++ b/CPP/7zip/Archive/SwfHandler.cpp @@ -412,6 +412,8 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (_item.IsZlib()) { _packSizeDefined = true; + if (!_decoderZlibSpec) + return E_FAIL; _packSize = _decoderZlibSpec->GetInputProcessedSize(); opRes = NExtract::NOperationResult::kOK; } diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp index e5332b5..c8ea56e 100644 --- a/CPP/7zip/Archive/Udf/UdfIn.cpp +++ b/CPP/7zip/Archive/Udf/UdfIn.cpp @@ -859,8 +859,10 @@ HRESULT CInArchive::Open2() } } } - - PhySize = (UInt32)(256 + 1) << SecLogSize; + { + const UInt32 temp = (UInt32)(256 + 1) << SecLogSize; + PhySize = temp; + } IsArc = true; // UDF 2.2.3 AnchorVolumeDescriptorPointer diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp index 2fef079..8101c4c 100644 --- a/CPP/7zip/Archive/VhdHandler.cpp +++ b/CPP/7zip/Archive/VhdHandler.cpp @@ -157,10 +157,11 @@ struct CDynHeader CParentLocatorEntry ParentLocators[8]; bool Parse(const Byte *p); - UInt32 NumBitMapSectors() const + UInt32 NumBitMapBytes() const { - UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log)); - return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8); + const UInt32 numSectorsInBlock = (UInt32)1 << (BlockSizeLog - kSectorSize_Log); + const UInt32 NumBitMapSectors = (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8); + return NumBitMapSectors << kSectorSize_Log; } void Clear() { @@ -325,7 +326,7 @@ HRESULT CHandler::InitAndSeek() } _virtPos = _posInArc = 0; BitMapTag = kUnusedBlock; - BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log); + BitMap.Alloc(Dyn.NumBitMapBytes()); return Seek2(0); } @@ -463,7 +464,7 @@ HRESULT CHandler::Open3() Bat.ClearAndReserve(Dyn.NumBlocks); - UInt32 bitmapSize = Dyn.NumBitMapSectors() << kSectorSize_Log; + const UInt32 bitmapSize = Dyn.NumBitMapBytes(); while ((UInt32)Bat.Size() < Dyn.NumBlocks) { diff --git a/CPP/7zip/Archive/VhdxHandler.cpp b/CPP/7zip/Archive/VhdxHandler.cpp index ca450e5..64e6273 100644 --- a/CPP/7zip/Archive/VhdxHandler.cpp +++ b/CPP/7zip/Archive/VhdxHandler.cpp @@ -1170,6 +1170,7 @@ HRESULT CHandler::Open3() HeadersSize = (UInt32)1 << 20; CHeader headers[2]; + Z7_memset_0_ARRAY(headers); { Byte header[kHeader2Size]; for (unsigned i = 0; i < 2; i++) @@ -1224,6 +1225,7 @@ HRESULT CHandler::Open3() } } CRegion regions[2]; + Z7_memset_0_ARRAY(regions); int correctRegionIndex = -1; { diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp index cc24697..d08e060 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.cpp +++ b/CPP/7zip/Archive/Wim/WimHandler.cpp @@ -164,15 +164,12 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) case kpidUnpackVer: { - UInt32 ver1 = _version >> 16; - UInt32 ver2 = (_version >> 8) & 0xFF; - UInt32 ver3 = (_version) & 0xFF; - AString res; - res.Add_UInt32(ver1); + res.Add_UInt32(_version >> 16); res.Add_Dot(); - res.Add_UInt32(ver2); - if (ver3 != 0) + res.Add_UInt32((_version >> 8) & 0xFF); + const UInt32 ver3 = _version & 0xFF; + if (ver3) { res.Add_Dot(); res.Add_UInt32(ver3); @@ -182,27 +179,33 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) } case kpidIsVolume: - if (_xmls.Size() > 0) + if (!_xmls.IsEmpty()) { - UInt16 volIndex = _xmls[0].VolIndex; + const unsigned volIndex = _xmls[0].VolIndex; if (volIndex < _volumes.Size()) prop = (_volumes[volIndex].Header.NumParts > 1); } break; case kpidVolume: - if (_xmls.Size() > 0) + if (!_xmls.IsEmpty()) { - UInt16 volIndex = _xmls[0].VolIndex; + const unsigned volIndex = _xmls[0].VolIndex; if (volIndex < _volumes.Size()) prop = (UInt32)_volumes[volIndex].Header.PartNumber; } break; - case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break; + case kpidNumVolumes: + { + const unsigned n = _volumes.Size(); + if (n) + prop = (UInt32)(n - 1); + break; + } case kpidClusterSize: - if (_xmls.Size() > 0) + if (!_xmls.IsEmpty()) { - UInt16 volIndex = _xmls[0].VolIndex; + const unsigned volIndex = _xmls[0].VolIndex; if (volIndex < _volumes.Size()) { const CHeader &h = _volumes[volIndex].Header; @@ -318,7 +321,8 @@ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) { UInt32 flags = 0; if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; - if (_db.HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (_db.HeadersError || _volError || _error_in_PartNumber) + flags |= kpv_ErrorFlags_HeadersError; if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod; prop = flags; break; @@ -364,19 +368,14 @@ static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &pro if (method >= 0) { char temp[32]; - - if ((unsigned)method < Z7_ARRAY_SIZE(k_Methods)) - MyStringCopy(temp, k_Methods[(unsigned)method]); - else - ConvertUInt32ToString((UInt32)(unsigned)method, temp); - + char *dest = ((unsigned)method < Z7_ARRAY_SIZE(k_Methods)) ? + MyStpCpy(temp, k_Methods[(unsigned)method]) : + ConvertUInt32ToString((UInt32)(unsigned)method, temp); if (chunksSizeBits >= 0) { - size_t pos = strlen(temp); - temp[pos++] = ':'; - ConvertUInt32ToString((unsigned)chunksSizeBits, temp + pos); + *dest++ = ':'; + ConvertUInt32ToString((unsigned)chunksSizeBits, dest); } - prop = temp; } } @@ -389,14 +388,15 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val if (index < _db.SortedItems.Size()) { - unsigned realIndex = _db.SortedItems[index]; + const unsigned realIndex = _db.SortedItems[index]; const CItem &item = _db.Items[realIndex]; const CStreamInfo *si = NULL; const CVolume *vol = NULL; if (item.StreamIndex >= 0) { si = &_db.DataStreams[item.StreamIndex]; - vol = &_volumes[si->PartNumber]; + if (si->PartNumber < _volumes.Size()) + vol = &_volumes[si->PartNumber]; } const CItem *mainItem = &item; @@ -501,7 +501,7 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidIsAltStream: prop = item.IsAltStream; break; case kpidNumAltStreams: { - if (!item.IsAltStream && mainItem->HasMetadata()) + if (!item.IsAltStream && metadata /* mainItem->HasMetadata() */) { UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize; UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6); @@ -525,12 +525,12 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val prop = (UInt32)Get32(metadata + 8); } break; - case kpidCTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; - case kpidATime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; - case kpidMTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; + case kpidCTime: if (metadata /* mainItem->HasMetadata() */ ) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break; + case kpidATime: if (metadata /* mainItem->HasMetadata() */ ) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break; + case kpidMTime: if (metadata /* mainItem->HasMetadata() */ ) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break; case kpidINode: - if (mainItem->HasMetadata() && !_isOldVersion) + if (metadata /* mainItem->HasMetadata() */ && !_isOldVersion) { UInt32 attrib = (UInt32)Get32(metadata + 8); if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) @@ -552,26 +552,26 @@ Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidMethod: if (si) { + int method = -1; + int chunkSizeBits = -1; const CResource &r = si->Resource; if (r.IsSolid()) { if (r.SolidIndex >= 0) { - CSolid &ss = _db.Solids[r.SolidIndex]; - MethodToProp(ss.Method, (int)ss.ChunkSizeBits, prop); + const CSolid &ss = _db.Solids[r.SolidIndex]; + method = ss.Method; + chunkSizeBits = (int)ss.ChunkSizeBits; } } - else + else if (!r.IsCompressed()) + method = 0; + else if (vol) { - int method = 0; - int chunkSizeBits = -1; - if (r.IsCompressed()) - { - method = (int)vol->Header.GetMethod(); - chunkSizeBits = (int)vol->Header.ChunkSizeBits; - } - MethodToProp(method, chunkSizeBits, prop); + method = (int)vol->Header.GetMethod(); + chunkSizeBits = (int)vol->Header.ChunkSizeBits; } + MethodToProp(method, chunkSizeBits, prop); } break; @@ -891,8 +891,14 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal } CHeader header; - HRESULT res = NWim::ReadHeader(curStream, header, _phySize); - + + _db.PhySize = 0; + HRESULT res; + { + res = NWim::ReadHeader(curStream, header, _db.PhySize); + if (i == 1) + _phySize = _db.PhySize; + } if (res != S_OK) { if (i != 1 && res == S_FALSE) @@ -901,12 +907,20 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal } _isArc = true; - _bootIndex = header.BootIndex; - _version = header.Version; - _isOldVersion = header.IsOldVersion(); + if (i == 1) + { + _bootIndex = header.BootIndex; + _version = header.Version; + _isOldVersion = header.IsOldVersion(); + } + if (_firstVolumeIndex >= 0) if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header)) break; + + if (i != 1 && _isOldVersion != header.IsOldVersion()) + _volError = true; + if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream) break; CWimXml xml; @@ -924,17 +938,24 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal return S_FALSE; } - UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size(); + UInt64 totalFiles = xml.GetTotalFilesAndDirs(); + if (totalFiles >= ((UInt32)1 << 30)) + totalFiles = 0; totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items if (totalFiles >= ((UInt32)1 << 30)) totalFiles = 0; res = _db.Open(curStream, header, (unsigned)totalFiles, callback); + if (i == 1) + _phySize = _db.PhySize; } if (res != S_OK) { if (i != 1 && res == S_FALSE) + { + _volError = true; continue; + } return res; } @@ -985,6 +1006,8 @@ Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCal RINOK(_db.GenerateSortedItems(defaultImageIndex, showImageNumber)) RINOK(_db.ExtractReparseStreams(_volumes, callback)) + if (!_db.Check_PartNumber_in_Items(_volumes.Size())) + _error_in_PartNumber = true; /* wchar_t sz[16]; @@ -1012,7 +1035,7 @@ Z7_COM7F_IMF(CHandler::Close()) _xmlInComments = false; _numXmlItems = 0; _numIgnoreItems = 0; - _xmlError = false; + ClearErrors(); _isArc = false; _unsupported = false; return S_OK; @@ -1127,7 +1150,9 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->PrepareOperation(askMode)) Int32 opRes = NExtract::NOperationResult::kOK; - if (streamIndex != prevSuccessStreamIndex || realOutStream) + if (si.PartNumber >= _volumes.Size()) + opRes = NExtract::NOperationResult::kUnavailable; + else if (streamIndex != prevSuccessStreamIndex || realOutStream) { Byte digest[kHashSize]; const CVolume &vol = _volumes[si.PartNumber]; @@ -1172,7 +1197,7 @@ CHandler::CHandler() { _keepMode_ShowImageNumber = false; InitDefaults(); - _xmlError = false; + ClearErrors(); } Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h index 126d233..b477d8e 100644 --- a/CPP/7zip/Archive/Wim/WimHandler.h +++ b/CPP/7zip/Archive/Wim/WimHandler.h @@ -35,6 +35,8 @@ Z7_CLASS_IMP_CHandler_IInArchive_5( bool _isOldVersion; bool _xmlInComments; + bool _error_in_PartNumber; + bool _volError; bool _xmlError; bool _isArc; bool _unsupported; @@ -81,7 +83,18 @@ Z7_CLASS_IMP_CHandler_IInArchive_5( return true; } - bool ThereIsError() const { return _xmlError || _db.ThereIsError(); } + void ClearErrors() + { + _error_in_PartNumber = false; + _volError = false; + _xmlError = false; + } + + bool ThereIsError() const + { + return _error_in_PartNumber || _volError || _xmlError + || _db.ThereIsError(); + } HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType); HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value); diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp index 33fbe82..b2470e1 100644 --- a/CPP/7zip/Archive/Wim/WimIn.cpp +++ b/CPP/7zip/Archive/Wim/WimIn.cpp @@ -1094,6 +1094,7 @@ HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItems if (h.PartNumber != 1 || si.PartNumber != h.PartNumber) continue; + si.Resource.UpdatePhySize(PhySize); const unsigned userImage = Images.Size() + GetStartImageIndex(); CImage &image = Images.AddNew(); @@ -1623,6 +1624,22 @@ static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size) } +bool CDatabase::Check_PartNumber_in_Items(unsigned numVolumes) const +{ + // maybe it's better to check all Items[] or all DataStreams[] items instead + FOR_VECTOR(indexInSorted, SortedItems) + { + const unsigned itemIndex = SortedItems[indexInSorted]; + const CItem &item = Items[itemIndex]; + if (item.StreamIndex < 0) + continue; + const CStreamInfo &si = DataStreams[item.StreamIndex]; + if (si.PartNumber >= numVolumes) + return false; + } + return true; +} + HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, IArchiveOpenCallback *openCallback) { ItemToReparse.Clear(); @@ -1639,7 +1656,7 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, FOR_VECTOR(indexInSorted, SortedItems) { // we use sorted items for faster access - unsigned itemIndex = SortedItems[indexInSorted]; + const unsigned itemIndex = SortedItems[indexInSorted]; const CItem &item = Items[itemIndex]; if (!item.HasMetadata() || item.IsAltStream) @@ -1692,10 +1709,8 @@ HRESULT CDatabase::ExtractReparseStreams(const CObjectVector &volumes, } else { - /* if (si.PartNumber >= volumes.Size()) continue; - */ const CVolume &vol = volumes[si.PartNumber]; /* if (!vol.Stream) diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index ae7cd6b..53a088b 100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -163,12 +163,16 @@ struct CResource UInt64 GetEndLimit() const { return Offset + PackSize; } void Parse(const Byte *p); - void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) + void UpdatePhySize(UInt64 &phySize) const { - Parse(p); UInt64 v = GetEndLimit(); if (phySize < v) - phySize = v; + phySize = v; + } + void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) + { + Parse(p); + UpdatePhySize(phySize); } void WriteTo(Byte *p) const; @@ -391,7 +395,13 @@ struct CImageInfo int ItemIndexInXml; - UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; } + UInt64 GetTotalFilesAndDirs() const + { + UInt64 v = DirCount + FileCount; + if (v < DirCount) + v = 0; + return v; + } CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false), IndexDefined(false), ItemIndexInXml(-1) {} @@ -405,16 +415,21 @@ struct CWimXml CXml Xml; UInt16 VolIndex; + bool IsEncrypted; CObjectVector Images; UString FileName; - bool IsEncrypted; UInt64 GetTotalFilesAndDirs() const { UInt64 sum = 0; FOR_VECTOR (i, Images) - sum += Images[i].GetTotalFilesAndDirs(); + { + const UInt64 v = Images[i].GetTotalFilesAndDirs(); + sum += v; + if (sum < v) + return 0; + } return sum; } @@ -474,6 +489,7 @@ public: int ExludedItem; // -1 : if there are no exclude items CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives + UInt64 PhySize; bool ThereIsError() const { return RefCountError || HeadersError; } unsigned GetNumUserItemsInImage(unsigned imageIndex) const @@ -530,6 +546,7 @@ public: void Clear() { + PhySize = 0; DataStreams.Clear(); MetaStreams.Clear(); Solids.Clear(); @@ -572,6 +589,7 @@ public: */ HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber); + bool Check_PartNumber_in_Items(unsigned numVolumes) const; HRESULT ExtractReparseStreams(const CObjectVector &volumes, IArchiveOpenCallback *openCallback); }; diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp index 43d68c7..ba61710 100644 --- a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp +++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp @@ -410,7 +410,7 @@ HRESULT CAddCommon::Compress( } } } - if (method == NCompressionMethod::kLZMA) + if (method == NCompressionMethod::kLZMA && _lzmaEncoder) _isLzmaEos = _lzmaEncoder->Encoder->IsWriteEndMark(); } diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp index 9d77e87..3bcbe22 100644 --- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ b/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -2393,10 +2393,7 @@ HRESULT CInArchive::ReadVols() { // get volumes required for cd. RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols)) - if (numMissingVols != 0) - { - // cdOK = false; - } + // if (numMissingVols) cdOK = false; } } else if (res != S_FALSE) diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp index e43e8b1..28ac2ea 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp +++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp @@ -534,11 +534,9 @@ static int main2(int numArgs, const char *args[]) dict = (UInt32)1 << kDictSizeLog; if (fileSizeDefined) { - unsigned i; - for (i = 16; i < kDictSizeLog; i++) - if ((UInt32)((UInt32)1 << i) >= fileSize) + for (dict = 1 << 16; dict < ((UInt32)1 << kDictSizeLog); dict <<= 1) + if (dict >= fileSize) break; - dict = (UInt32)1 << i; } } diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp index b7e4fbe..37c1f49 100644 --- a/CPP/7zip/Common/FileStreams.cpp +++ b/CPP/7zip/Common/FileStreams.cpp @@ -882,7 +882,7 @@ Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *pro UInt32 realProcessedSize; BOOL res = TRUE; - if (size > 0) + if (size) { // Seems that Windows doesn't like big amounts writing to stdout. // So we limit portions by 32KB. @@ -892,8 +892,8 @@ Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *pro res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), data, sizeTemp, (DWORD *)&realProcessedSize, NULL); _size += realProcessedSize; - size -= realProcessedSize; - data = (const void *)((const Byte *)data + realProcessedSize); + // size -= realProcessedSize; + // data = (const void *)((const Byte *)data + realProcessedSize); if (processedSize) *processedSize += realProcessedSize; } diff --git a/CPP/7zip/Common/LimitedStreams.cpp b/CPP/7zip/Common/LimitedStreams.cpp index 664cd0c..e2b536d 100644 --- a/CPP/7zip/Common/LimitedStreams.cpp +++ b/CPP/7zip/Common/LimitedStreams.cpp @@ -105,18 +105,20 @@ Z7_COM7F_IMF(CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSi const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); const UInt32 phyBlock = Vector[virtBlock]; - - UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; + const UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()) } - _curRem = blockSize - offsetInBlock; - - for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) - _curRem += (UInt32)1 << BlockSizeLog; + for (unsigned i = 1; i < 64 + && _curRem < size + && _curRem < ((UInt32)1 << 31) - blockSize + && virtBlock + i < Vector.Size() + && phyBlock + i == Vector[virtBlock + i] + ; i++) + _curRem += blockSize; } if (size > _curRem) diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h index 69fcdcd..328efb3 100644 --- a/CPP/7zip/Common/LimitedStreams.h +++ b/CPP/7zip/Common/LimitedStreams.h @@ -14,18 +14,18 @@ Z7_CLASS_IMP_COM_1( CLimitedSequentialInStream , ISequentialInStream ) + bool _wasFinished; CMyComPtr _stream; UInt64 _size; UInt64 _pos; - bool _wasFinished; public: void SetStream(ISequentialInStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } void Init(UInt64 streamSize) { + _wasFinished = false; _size = streamSize; _pos = 0; - _wasFinished = false; } UInt64 GetSize() const { return _pos; } UInt64 GetRem() const { return _size - _pos; } @@ -79,9 +79,9 @@ public: _curRem = 0; _virtPos = 0; _physPos = StartOffset; - if (Vector.Size() > 0) + if (Vector.Size()) { - _physPos = StartOffset + (Vector[0] << BlockSizeLog); + _physPos = StartOffset + ((UInt64)Vector[0] << BlockSizeLog); return SeekToPhys(); } return S_OK; @@ -105,9 +105,9 @@ struct CSeekExtent Z7_CLASS_IMP_IInStream( CExtentsStream ) + unsigned _prevExtentIndex; UInt64 _virtPos; UInt64 _phyPos; - unsigned _prevExtentIndex; public: CMyComPtr Stream; CRecordVector Extents; @@ -115,9 +115,9 @@ public: void ReleaseStream() { Stream.Release(); } void Init() { + _prevExtentIndex = 0; _virtPos = 0; _phyPos = (UInt64)0 - 1; // we need Seek() for Stream - _prevExtentIndex = 0; } }; @@ -127,10 +127,10 @@ Z7_CLASS_IMP_COM_1( CLimitedSequentialOutStream , ISequentialOutStream ) - CMyComPtr _stream; - UInt64 _size; bool _overflow; bool _overflowIsAllowed; + CMyComPtr _stream; + UInt64 _size; public: void SetStream(ISequentialOutStream *stream) { _stream = stream; } void ReleaseStream() { _stream.Release(); } diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp index af0b312..bc93dd5 100644 --- a/CPP/7zip/Compress/BZip2Encoder.cpp +++ b/CPP/7zip/Compress/BZip2Encoder.cpp @@ -436,7 +436,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize) WriteBits2(origPtr, kNumOrigBits + 1); // + 1 for additional high bit flag (Randomised = false) } Byte mtfBuf[256]; - // memset(mtfBuf, 0, sizeof(mtfBuf)); // to disable MSVC warning + Z7_memset_0_ARRAY(mtfBuf); // to suppress MSVC warning in -analyze mode unsigned numInUse; { Byte inUse[256]; diff --git a/CPP/7zip/Compress/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h index 318190d..b05f389 100644 --- a/CPP/7zip/Compress/HuffmanDecoder.h +++ b/CPP/7zip/Compress/HuffmanDecoder.h @@ -481,25 +481,26 @@ public: if (len == 0) continue; const unsigned offset = counts[len]++; - { - Byte *dest = _lens + _limits[(size_t)len - 1] - + ((offset - _poses[len]) << (kNumBitsMax - len)); - const unsigned num = (unsigned)1 << (kNumBitsMax - len); - const unsigned val = (i << 3) + len; - for (unsigned k = 0; k < num; k++) - dest[k] = (Byte)val; - } + const unsigned temp = (offset - _poses[len]) << (kNumBitsMax - len); + Byte *dest = _lens + _limits[(size_t)len - 1] + temp; + unsigned num = 1u << (kNumBitsMax - len); + const unsigned val = (i << 3) + len; + do + *dest++ = (Byte)val; + while (--num); } if (!full) { const unsigned limit = _limits[kNumBitsMax]; - const unsigned num = ((unsigned)1 << kNumBitsMax) - limit; - Byte *dest = _lens + limit; - for (unsigned k = 0; k < num; k++) - dest[k] = (Byte) - // (0x1f << 3); - ((0x1f << 3) + 0x7); + unsigned num = (1u << kNumBitsMax) - limit; + if (num) + { + Byte *dest = _lens + limit; + do + *dest++ = (0x1f << 3) + 7; + while (--num); + } } return true; diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp index bca2eee..8b7a79f 100644 --- a/CPP/7zip/Compress/LzmaEncoder.cpp +++ b/CPP/7zip/Compress/LzmaEncoder.cpp @@ -43,7 +43,7 @@ CEncoder::~CEncoder() static inline wchar_t GetLowCharFast(wchar_t c) { - return c |= 0x20; + return (wchar_t)(c | 0x20); } static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes) diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp index c17d46d..7e4fb2f 100644 --- a/CPP/7zip/Compress/Rar3Decoder.cpp +++ b/CPP/7zip/Compress/Rar3Decoder.cpp @@ -454,7 +454,7 @@ HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing) } } if (InputEofError_Fast()) - return false; + return S_FALSE; const int c = DecodePpmSymbol(); if (c < 0) { diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp index 34ea4ff..ef9607b 100644 --- a/CPP/7zip/Crypto/Rar5Aes.cpp +++ b/CPP/7zip/Crypto/Rar5Aes.cpp @@ -209,6 +209,7 @@ bool CDecoder::CalcKey_and_CheckPassword() { MY_ALIGN_FOR_SHA256 UInt32 pswCheck[SHA256_NUM_DIGEST_WORDS]; + Z7_memset_0_ARRAY(pswCheck); { // Pbkdf HMAC-SHA-256 MY_ALIGN_FOR_SHA256 diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp index 46b740a..b7815c6 100644 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -11,11 +11,14 @@ #include "../../../Windows/FileDir.h" #include "../../../Windows/FileName.h" #include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/System.h" #ifndef Z7_ST #include "../../../Windows/Synchronization.h" #endif +#include "../../Archive/Common/ItemNameUtils.h" + #include "../Common/ArchiveExtractCallback.h" #include "../FileManager/RegistryUtils.h" @@ -109,28 +112,48 @@ Z7_COM7F_IMF(CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder)) return S_OK; } -void CAgentFolder::LoadFolder(unsigned proxyDirIndex) +void CAgentFolder::LoadFolder(unsigned dirIndex) { CProxyItem item; - item.DirIndex = proxyDirIndex; if (_proxy2) { - const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex]; - FOR_VECTOR (i, dir.Items) + CUIntVector vec; + unsigned i = 0; + for (;;) { + const CProxyDir2 &dir = _proxy2->Dirs[dirIndex]; + if (i == dir.Items.Size()) + { + const unsigned num = vec.Size(); + if (num < 2) + return; + dirIndex = vec[num - 2]; + i = vec[num - 1]; + vec.DeleteFrom(num - 2); + continue; + } + + item.DirIndex = dirIndex; item.Index = i; _items.Add(item); - const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; - if (file.DirIndex != -1) - LoadFolder((unsigned)file.DirIndex); + const unsigned index = dir.Items[i]; + i++; + const CProxyFile2 &file = _proxy2->Files[index]; if (_loadAltStreams && file.AltDirIndex != -1) LoadFolder((unsigned)file.AltDirIndex); + if (file.DirIndex != -1) + { + vec.Add(dirIndex); + vec.Add(i); + dirIndex = (unsigned)file.DirIndex; + i = 0; + } } - return; } - - const CProxyDir &dir = _proxy->Dirs[proxyDirIndex]; + + item.DirIndex = dirIndex; + const CProxyDir &dir = _proxy->Dirs[dirIndex]; unsigned i; for (i = 0; i < dir.SubDirs.Size(); i++) { @@ -139,7 +162,7 @@ void CAgentFolder::LoadFolder(unsigned proxyDirIndex) LoadFolder(dir.SubDirs[i]); } - unsigned start = dir.SubDirs.Size(); + const unsigned start = dir.SubDirs.Size(); for (i = 0; i < dir.SubFiles.Size(); i++) { item.Index = start + i; @@ -201,79 +224,39 @@ UString CAgentFolder::GetName(UInt32 index) const return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name; } -void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const + +/* called for (_flatMode == true) from: + CAgentFolder::GetProperty(kpidPrefix) + CAgentFolder::CompareItems(kpidPrefix) +*/ +void CAgentFolder::GetPrefix(const UInt32 index, UString &prefix) const { + prefix.Empty(); if (!_flatMode) - { - prefix.Empty(); return; - } - - const CProxyItem &item = _items[index]; - unsigned proxyIndex = item.DirIndex; - + const unsigned itemDirIndex = _items[index].DirIndex; + if (itemDirIndex == _proxyDirIndex) + return; if (_proxy2) { - // that code is unused. 7-Zip gets prefix via GetItemPrefix() . - - unsigned len = 0; - while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) - { - const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex]; - len += file.NameLen + 1; - proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream); - } - - wchar_t *p = prefix.GetBuf_SetEnd(len) + len; - proxyIndex = item.DirIndex; - while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) - { - const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex]; - p--; - *p = WCHAR_PATH_SEPARATOR; - p -= file.NameLen; - wmemcpy(p, file.Name, file.NameLen); - proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream); - } + const unsigned kLenLimit = 1u << 12; + _proxy2->GetDirPath_as_Prefix_from_Base(itemDirIndex, prefix, _proxyDirIndex, kLenLimit); } else - { - unsigned len = 0; - while (proxyIndex != _proxyDirIndex) - { - const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; - len += dir->NameLen + 1; - proxyIndex = (unsigned)dir->ParentDir; - } - - wchar_t *p = prefix.GetBuf_SetEnd(len) + len; - proxyIndex = item.DirIndex; - while (proxyIndex != _proxyDirIndex) - { - const CProxyDir *dir = &_proxy->Dirs[proxyIndex]; - p--; - *p = WCHAR_PATH_SEPARATOR; - p -= dir->NameLen; - wmemcpy(p, dir->Name, dir->NameLen); - proxyIndex = (unsigned)dir->ParentDir; - } - } + _proxy->GetDirPath_as_Prefix_from_Base(itemDirIndex, prefix, _proxyDirIndex); } -UString CAgentFolder::GetFullPrefix(UInt32 index) const +UString CAgentFolder::GetFullPrefix(const UInt32 index) const { unsigned foldIndex = _proxyDirIndex; - if (_flatMode) foldIndex = _items[index].DirIndex; - if (_proxy2) - return _proxy2->Dirs[foldIndex].PathPrefix; - else - return _proxy->GetDirPath_as_Prefix(foldIndex); + return _proxy2->GetDirPath_as_Prefix(foldIndex); + return _proxy->GetDirPath_as_Prefix(foldIndex); } -Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(UInt32 index)) +Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(const UInt32 index)) { unsigned arcIndex; if (_proxy2) @@ -471,29 +454,48 @@ Z7_COM7F_IMF(CAgentFolder::GetItemName(UInt32 index, const wchar_t **name, unsig } } + +/* called for (_flatMode == true) from: + CPanel::RefreshListCtrl() : to check selected items and focused item. + CPanel::SetItemText() : to show prefix column +*/ Z7_COM7F_IMF(CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) { *name = NULL; *len = 0; +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX if (!_flatMode) return S_OK; if (_proxy2) { const CProxyItem &item = _items[index]; - const UString &s = _proxy2->Dirs[item.DirIndex].PathPrefix; - unsigned baseLen = _proxy2->Dirs[_proxyDirIndex].PathPrefix.Len(); - if (baseLen <= s.Len()) + const CProxyDir2 &dir = _proxy2->Dirs[item.DirIndex]; + const CProxyDir2 &baseDir = _proxy2->Dirs[_proxyDirIndex]; + const UString &s = dir.PathPrefix; + if (dir.IsLongPath) { - *name = (const wchar_t *)s + baseLen; - *len = s.Len() - baseLen; + // in case of IsLongPath we can return reduced prefix or return nothing. + // so caller will call it with full prefix. +#if 1 // 1 - for fast processing of long strings, 0 - for full processing + *name = (const wchar_t *)s; + *len = s.Len(); +#endif } else { - return E_FAIL; - // throw 111l; + if (baseDir.IsLongPath) + return E_FAIL; // throw 1; + const unsigned baseLen = baseDir.PathPrefix.Len(); + if (s.Len() < baseLen) + return E_FAIL; // throw 1; + *name = (const wchar_t *)s + baseLen; + *len = s.Len() - baseLen; } } +#else + UNUSED_VAR(index) +#endif return S_OK; } @@ -552,6 +554,15 @@ int CAgentFolder::CompareItems3(UInt32 index1, UInt32 index2, PROPID propID) return prop1.Compare(prop2); } +int CAgentFolder::ComparePrefixes(const UInt32 index1, const UInt32 index2) +{ + // we use CAgentFolder::_temp1 instead of local vaiables for faster execution. + // it's not allowed to call ComparePrefixes() from different threads simultaneously. + // UString _temp1, _temp2; + GetPrefix(index1, _temp1); + GetPrefix(index2, _temp2); + return CompareFileNames_ForFolderList(_temp1, _temp2); +} int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw) { @@ -591,9 +602,13 @@ int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int { if (!_flatMode) return 0; +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX return CompareFileNames_ForFolderList( _proxy2->Dirs[_items[index1].DirIndex].PathPrefix, _proxy2->Dirs[_items[index2].DirIndex].PathPrefix); +#else + return ComparePrefixes(index1, index2); +#endif } if (propID == kpidExtension) @@ -714,10 +729,7 @@ Z7_COM7F_IMF2(Int32, CAgentFolder::CompareItems(UInt32 index1, UInt32 index2, PR { if (!_flatMode) return 0; - UString prefix1, prefix2; - GetPrefix(index1, prefix1); - GetPrefix(index2, prefix2); - return CompareFileNames_ForFolderList(prefix1, prefix2); + return ComparePrefixes(index1, index2); } UInt32 arcIndex1; @@ -1004,10 +1016,10 @@ Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder * return BindToAltStreams((UInt32)(Int32)-1, resultFolder); { - const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; - FOR_VECTOR (i, dir.Items) + const CUIntVector &subFiles = _proxy2->Dirs[_proxyDirIndex].Items; + FOR_VECTOR (i, subFiles) { - const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; + const CProxyFile2 &file = _proxy2->Files[subFiles[i]]; if (file.AltDirIndex != -1) if (CompareFileNames(file.Name, name) == 0) return BindToAltStreams_Internal((unsigned)file.AltDirIndex, resultFolder); @@ -1234,7 +1246,8 @@ Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) if (propID == kpidReadOnly) { - if (_agentSpec->Is_Attrib_ReadOnly()) + if ((_agentSpec->_proxy && _agentSpec->_proxy->Are_Changed_LongPaths) + || _agentSpec->Is_Attrib_ReadOnly()) prop = true; else prop = _agentSpec->IsThere_ReadOnlyArc(); @@ -1253,8 +1266,8 @@ Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)) } else if (propID == kpidPath) { - bool isAltStreamFolder = false; - prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, isAltStreamFolder); + // Here we allow the return of reduced path: + prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, true); // canReducePath } else switch (propID) { @@ -1406,17 +1419,20 @@ int CAgentFolder::GetRealIndex(unsigned index) const } } -void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const +void CAgentFolder::GetRealIndices( + const UInt32 *indices, const UInt32 numItems, + const bool includeAltStreams, const bool includeFolderSubItemsInFlatMode, + CUIntVector &realIndices) const { if (!_flatMode) { if (_proxy2) - _proxy2->GetRealIndices(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices); + _proxy2->GetRealIndices_Unsorted(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices); else - _proxy->GetRealIndices(_proxyDirIndex, indices, numItems, realIndices); - return; + _proxy->GetRealIndices_Unsorted(_proxyDirIndex, indices, numItems, realIndices); } - + else + { realIndices.Clear(); for (UInt32 i = 0; i < numItems; i++) @@ -1425,13 +1441,14 @@ void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool i if (_proxy2) { const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex]; - _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], includeAltStreams, realIndices); + _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], + includeAltStreams, includeFolderSubItemsInFlatMode, realIndices); continue; } UInt32 arcIndex; { const CProxyDir *dir = &_proxy->Dirs[item.DirIndex]; - unsigned realIndex = item.Index; + const unsigned realIndex = item.Index; if (realIndex < dir->SubDirs.Size()) { if (includeFolderSubItemsInFlatMode) @@ -1449,6 +1466,7 @@ void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool i } realIndices.Add(arcIndex); } + } HeapSort(realIndices.NonConstData(), realIndices.Size()); } @@ -1472,11 +1490,13 @@ Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices, CMyComPtr extractCallback = extractCallbackSpec; UStringVector pathParts; bool isAltStreamFolder = false; + bool isChangedPath = false; if (_proxy2) _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); else - _proxy->GetDirPathParts(_proxyDirIndex, pathParts); - + _proxy->GetDirPathParts_isChanged(_proxyDirIndex, pathParts, isChangedPath); + if (isChangedPath) + return E_NOTIMPL; /* if (_flatMode) pathMode = NExtract::NPathMode::kNoPathnames; @@ -1538,7 +1558,8 @@ Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices, extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix; CUIntVector realIndices; - GetRealIndices(indices, numItems, IntToBool(includeAltStreams), + GetRealIndices(indices, numItems, + (_loadAltStreams && _flatMode) ? false : IntToBool(includeAltStreams), // v26.03 false, // includeFolderSubItemsInFlatMode realIndices); // @@ -1574,7 +1595,8 @@ CAgent::CAgent(): _proxy2(NULL), _updatePathPrefix_is_AltFolder(false), _isDeviceFile(false), - _isHashHandler(false) + _isHashHandler(false), + _progress_for_Open(NULL) { } @@ -1588,6 +1610,8 @@ CAgent::~CAgent() bool CAgent::CanUpdate() const { + if (_proxy && _proxy->Are_Changed_LongPaths) + return false; // FAR plugin uses empty agent to create new archive !!! if (_archiveLink.Arcs.Size() == 0) return true; @@ -1746,6 +1770,16 @@ HRESULT CAgent::ReadItems() else _proxy = new CProxyArc(); + size_t ramSize; + if (NWindows::NSystem::GetRamSize(ramSize)) + { + ramSize = ramSize / 4 * 3; + if (_proxy2) + _proxy2->MemUsage_Limit = ramSize; + else + _proxy->MemUsage_Limit = ramSize; + } + { ThereIsPathProp = false; // ThereIsAltStreamProp = false; @@ -1767,8 +1801,8 @@ HRESULT CAgent::ReadItems() } if (_proxy2) - return _proxy2->Load(GetArc(), NULL); - return _proxy->Load(GetArc(), NULL); + return _proxy2->Load(GetArc(), _progress_for_Open); + return _proxy->Load(GetArc(), _progress_ArchiveOpenCallback_for_Open); } Z7_COM7F_IMF(CAgent::BindToRootFolder(IFolderFolder **resultFolder)) diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h index a63e459..e19ccd8 100644 --- a/CPP/7zip/UI/Agent/Agent.h +++ b/CPP/7zip/UI/Agent/Agent.h @@ -107,11 +107,13 @@ public: int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID); int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw); + int ComparePrefixes(UInt32 index1, UInt32 index2); CAgentFolder(): _isAltStreamFolder(false), _flatMode(false), _loadAltStreams(false), // _loadAltStreams alt streams works in flat mode, but we don't use it now + // _loadAltStreams(true), // for debug _proxyDirIndex(0), _zoneMode(NExtract::NZoneIdMode::kNone) /* , _replaceAltStreamCharsMode(0) */ @@ -161,6 +163,8 @@ public: CMyComPtr _agent; CAgent *_agentSpec; CRecordVector _items; + + UString _temp1, _temp2; }; @@ -241,6 +245,9 @@ public: CObjectVector m_PropValues; #endif + IArchiveOpenCallback *_progress_ArchiveOpenCallback_for_Open; // it's for parsing after archive openning + IProgress *_progress_for_Open; // it's for parsing after archive openning + CAgent(); ~CAgent(); diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp index 265b943..3b2a8b7 100644 --- a/CPP/7zip/UI/Agent/AgentOut.cpp +++ b/CPP/7zip/UI/Agent/AgentOut.cpp @@ -42,7 +42,10 @@ Z7_COM7F_IMF(CAgent::SetFolder(IFolderFolder *folder)) } if (_proxy2) - _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, _updatePathPrefix_is_AltFolder); + { + _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); + _updatePathPrefix_is_AltFolder = _proxy2->IsAltDir(_agentFolder->_proxyDirIndex); + } else _updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); return S_OK; @@ -58,86 +61,140 @@ Z7_COM7F_IMF(CAgent::SetFiles(const wchar_t *folderPrefix, return S_OK; } -static HRESULT EnumerateArchiveItems(CAgent *agent, - const CProxyDir &item, - const UString &prefix, + +static HRESULT EnumerateArchiveItems(const CAgent *agent, CObjectVector &arcItems) { - unsigned i; - - for (i = 0; i < item.SubFiles.Size(); i++) - { - unsigned arcIndex = item.SubFiles[i]; - const CProxyFile &fileItem = agent->_proxy->Files[arcIndex]; - CArcItem ai; - RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) - RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) - ai.IsDir = false; - ai.Name = prefix + fileItem.Name; - ai.Censored = true; // test it - ai.IndexInServer = arcIndex; - arcItems.Add(ai); - } - - for (i = 0; i < item.SubDirs.Size(); i++) + CUIntVector vec; + CArcItem ai; + ai.Censored = true; // test it + unsigned prefixLen = 0; + unsigned dirIndex = k_Proxy_RootDirIndex; // 0 + unsigned i = 0; + for (;;) { - const CProxyDir &dirItem = agent->_proxy->Dirs[item.SubDirs[i]]; - UString fullName = prefix + dirItem.Name; - if (dirItem.IsLeaf()) + const CProxyDir &dir = agent->_proxy->Dirs[dirIndex]; + + if (i == dir.SubDirs.Size()) // we fill SubFiles after SubDirs + { + ai.IsDir = false; + FOR_VECTOR (k, dir.SubFiles) + { + const unsigned arcIndex = dir.SubFiles[k]; + ai.IndexInServer = arcIndex; + RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) + RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) + RINOK(Archive_IsItem_AltStream(agent->GetArc().Archive, arcIndex, ai.IsAltStream)) + ai.Name.DeleteFrom(prefixLen); + const CProxyFile &file = agent->_proxy->Files[arcIndex]; + ai.Name += file.Name; + arcItems.Add(ai); + } + + const unsigned num = vec.Size(); + if (num < 3) + return S_OK; + prefixLen = vec[num - 3]; + dirIndex = vec[num - 2]; + i = vec[num - 1]; + vec.DeleteFrom(num - 3); + continue; + } + + const unsigned subDirIndex = dir.SubDirs[i]; + i++; + const CProxyDir &subDir = agent->_proxy->Dirs[subDirIndex]; + ai.Name.DeleteFrom(prefixLen); + ai.Name += subDir.Name; + if (subDir.IsLeaf()) { - CArcItem ai; - RINOK(agent->GetArc().GetItem_MTime((unsigned)dirItem.ArcIndex, ai.MTime)) + ai.IndexInServer = (unsigned)subDir.ArcIndex; + RINOK(agent->GetArc().GetItem_MTime((unsigned)subDir.ArcIndex, ai.MTime)) ai.IsDir = true; + ai.IsAltStream = false; ai.Size_Defined = false; - ai.Name = fullName; - ai.Censored = true; // test it - ai.IndexInServer = (unsigned)dirItem.ArcIndex; + ai.Size = 0; arcItems.Add(ai); } - RINOK(EnumerateArchiveItems(agent, dirItem, fullName + WCHAR_PATH_SEPARATOR, arcItems)) + + vec.Add(prefixLen); + vec.Add(dirIndex); + vec.Add(i); + ai.Name.Add_PathSepar(); + prefixLen = ai.Name.Len(); + if (prefixLen >= (1 << 15) /* || vec.Size() >= (3 << 14) */ ) // NTFS limit + return E_NOTIMPL; + dirIndex = subDirIndex; + i = 0; } - - return S_OK; } + static HRESULT EnumerateArchiveItems2(const CAgent *agent, unsigned dirIndex, const UString &prefix, CObjectVector &arcItems) { - const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex]; - FOR_VECTOR (i, dir.Items) + CUIntVector vec; + CArcItem ai; + ai.Censored = true; // test it + ai.Name = prefix; + unsigned prefixLen = ai.Name.Len(); + unsigned i = 0; + for (;;) { - unsigned arcIndex = dir.Items[i]; + const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex]; + if (i == dir.Items.Size()) + { + const unsigned num = vec.Size(); + if (num < 3) + return S_OK; + prefixLen = vec[num - 3]; + dirIndex = vec[num - 2]; + i = vec[num - 1]; + vec.DeleteFrom(num - 3); + continue; + } + + const unsigned arcIndex = dir.Items[i]; + i++; + ai.Name.DeleteFrom(prefixLen); const CProxyFile2 &file = agent->_proxy2->Files[arcIndex]; - CArcItem ai; + ai.Name += file.Name; + // v23.03: we normalize slashes: + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath( + ai.Name.Ptr_non_const() + (ai.Name.Len() - file.NameLen), file.NameLen); ai.IndexInServer = arcIndex; - ai.Name = prefix + file.Name; - ai.Censored = true; // test it RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)) - ai.IsDir = file.IsDir(); + ai.Size = 0; ai.Size_Defined = false; ai.IsAltStream = file.IsAltStream; - if (!ai.IsDir) - { + ai.IsDir = file.IsDir(); + if (!file.IsDir()) RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)) - ai.IsDir = false; - } - arcItems.Add(ai); + arcItems.Add(ai); + if (file.AltDirIndex != -1) + RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex, + ai.Name + L':', arcItems)) + + if (file.IsDir()) { - RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex, ai.Name + L':', arcItems)) - } - - if (ai.IsDir) - { - RINOK(EnumerateArchiveItems2(agent, (unsigned)file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems)) + vec.Add(prefixLen); + vec.Add(dirIndex); + vec.Add(i); + ai.Name.Add_PathSepar(); + prefixLen = ai.Name.Len(); + if (prefixLen >= (1 << 15) /* || vec.Size() >= (3 << 14) */ ) // NTFS limit + return E_NOTIMPL; + dirIndex = (unsigned)file.DirIndex; + i = 0; } } - return S_OK; } + struct CAgUpCallbackImp Z7_final: public IUpdateProduceCallback { const CObjectVector *_arcItems; @@ -299,7 +356,7 @@ Z7_COM7F_IMF(CAgent::DoOperation( } else { - RINOK(EnumerateArchiveItems(this, _proxy->Dirs[0], L"", arcItems)) + RINOK(EnumerateArchiveItems(this, arcItems)) } } @@ -510,9 +567,8 @@ HRESULT CAgent::CreateFolder(ISequentialOutStream *outArchiveStream, di.Attrib = FILE_ATTRIBUTE_DIRECTORY; di.Size = 0; - bool isAltStreamFolder = false; if (_proxy2) - di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, isAltStreamFolder); + di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex /* , isAltStreamFolder */); else di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex); di.Name += folderName; diff --git a/CPP/7zip/UI/Agent/AgentProxy.cpp b/CPP/7zip/UI/Agent/AgentProxy.cpp index c8edd19..71b01da 100644 --- a/CPP/7zip/UI/Agent/AgentProxy.cpp +++ b/CPP/7zip/UI/Agent/AgentProxy.cpp @@ -9,7 +9,6 @@ #include #endif -#include "../../../../C/Sort.h" #include "../../../../C/CpuArch.h" #include "../../../Common/UTFConvert.h" @@ -24,10 +23,12 @@ using namespace NWindows; -int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const +#define CHECK_MEM_USAGE { if (MemUsage > MemUsage_Limit) return E_OUTOFMEMORY; } + +int CProxyArc::FindSubDir(const unsigned *items, unsigned right, + const wchar_t *name, unsigned &insertPos) const { - const CRecordVector &subDirs = Dirs[dirIndex].SubDirs; - unsigned left = 0, right = subDirs.Size(); + unsigned left = 0; for (;;) { if (left == right) @@ -36,10 +37,13 @@ int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &inse return -1; } const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); - const unsigned dirIndex2 = subDirs[mid]; + const unsigned dirIndex2 = items[mid]; const int comp = CompareFileNames(name, Dirs[dirIndex2].Name); if (comp == 0) + { + insertPos = mid; // not used, but we set it to suppress compiler warnings return (int)dirIndex2; + } if (comp < 0) right = mid; else @@ -50,88 +54,151 @@ int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &inse int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const { unsigned insertPos; - return FindSubDir(dirIndex, name, insertPos); + const CUIntVector &dirs = Dirs[dirIndex].SubDirs; + return FindSubDir(dirs.ConstData(), dirs.Size(), name, insertPos); } static const wchar_t *AllocStringAndCopy(const wchar_t *s, size_t len) { - wchar_t *p = new wchar_t[len + 1]; - MyStringCopy(p, s); - return p; + ++len; + wchar_t *p = new wchar_t[len]; + return wmemcpy(p, s, len); + // MyStringCopy(p, s); return p; } static const wchar_t *AllocStringAndCopy(const UString &s) { return AllocStringAndCopy(s, s.Len()); } - -unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name) + + +void CProxyArc::MergeSubDirs(CProxyDir &baseDir) { + CUIntVector &dirs2 = baseDir.SubDirs2; + unsigned i = dirs2.Size(); + if (i == 0) + return; + CUIntVector &dirs = baseDir.SubDirs; + unsigned right = dirs.Size(); + unsigned total = right + i; + dirs.ChangeSize_KeepData_plus_AdditionalReserve(total); + unsigned * const items = dirs.NonConstData(); + do + { + const unsigned index = dirs2[--i]; + unsigned insertPos; + if (FindSubDir(items, right, Dirs[index].Name, insertPos) != -1) + throw 1; + const unsigned numItems = right - insertPos; + right = insertPos; + total -= numItems; + memmove(items + total, items + insertPos, numItems * sizeof(*items)); + items[--total] = index; + } + while (i); + dirs2.Clear(); +} + + +unsigned CProxyArc::AddDir(const unsigned dirIndex, const int arcIndex, const UString &name) +{ + CProxyDir &baseDir = Dirs[dirIndex]; + CUIntVector &dirs = baseDir.SubDirs; + CUIntVector &dirs2 = baseDir.SubDirs2; + { + const unsigned numSmallDirs = dirs2.Size(); + if (numSmallDirs * numSmallDirs > dirs.Size()) + MergeSubDirs(baseDir); + } unsigned insertPos; - int subDirIndex = FindSubDir(dirIndex, name, insertPos); - if (subDirIndex != -1) + int subDirIndex = FindSubDir(dirs.ConstData(), dirs.Size(), name, insertPos); + if (subDirIndex == -1) { - if (arcIndex != -1) + unsigned insertPos2; + subDirIndex = FindSubDir(dirs2.ConstData(), dirs2.Size(), name, insertPos2); + if (subDirIndex == -1) { - CProxyDir &item = Dirs[(unsigned)subDirIndex]; - if (item.ArcIndex == -1) - item.ArcIndex = arcIndex; + CUIntVector *subDirsWork = &dirs; + if (dirs.Size() - insertPos >= (1 << 12)) + { + subDirsWork = &dirs2; + insertPos = insertPos2; + } + subDirIndex = (int)Dirs.Size(); + subDirsWork->Insert(insertPos, (unsigned)subDirIndex); + CProxyDir &item = Dirs.AddNew(); + item.NameLen = name.Len(); + MemUsage += (size_t)item.NameLen * sizeof(*item.Name) + + sizeof(CProxyDir) + sizeof(void *) * 3 + 24; + item.Name = AllocStringAndCopy(name); + item.ArcIndex = arcIndex; + item.ParentDir = (int)dirIndex; + return (unsigned)subDirIndex; } - return (unsigned)subDirIndex; } - subDirIndex = (int)Dirs.Size(); - Dirs[dirIndex].SubDirs.Insert(insertPos, (unsigned)subDirIndex); - CProxyDir &item = Dirs.AddNew(); - - item.NameLen = name.Len(); - item.Name = AllocStringAndCopy(name); - item.ArcIndex = arcIndex; - item.ParentDir = (int)dirIndex; + CProxyDir &item = Dirs[(unsigned)subDirIndex]; + if (item.ArcIndex == -1) + item.ArcIndex = arcIndex; return (unsigned)subDirIndex; } -void CProxyDir::Clear() -{ - SubDirs.Clear(); - SubFiles.Clear(); -} -void CProxyArc::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const +void CProxyArc::GetDirPathParts_isChanged(unsigned dirIndex, + UStringVector &pathParts, bool &isChangedPath) const { + isChangedPath = false; pathParts.Clear(); - // while (dirIndex != -1) - for (;;) + while (dirIndex != k_Proxy_RootDirIndex) { const CProxyDir &dir = Dirs[dirIndex]; + if (dir.Is_Changed_LongPath) + isChangedPath = true; dirIndex = (unsigned)dir.ParentDir; - if (dir.ParentDir == -1) - break; pathParts.Insert(0, dir.Name); // 22.00: we normalize name NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]); } } -UString CProxyArc::GetDirPath_as_Prefix(unsigned dirIndex) const + +void CProxyArc::GetDirPath_as_Prefix_from_Base(const unsigned dirIndex, + UString &prefix, const unsigned baseDirIndex) const { - UString s; - // while (dirIndex != -1) - for (;;) + prefix.Empty(); + if (dirIndex == baseDirIndex) + return; + unsigned len = 0; + unsigned i = dirIndex; + do { - const CProxyDir &dir = Dirs[dirIndex]; - dirIndex = (unsigned)dir.ParentDir; - if (dir.ParentDir == -1) - break; - s.InsertAtFront(WCHAR_PATH_SEPARATOR); - s.Insert(0, dir.Name); - // 22.00: we normalize name - NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s.GetBuf(), MyStringLen(dir.Name)); + const CProxyDir &dir = Dirs[i]; + len += dir.NameLen + 1; + i = (unsigned)dir.ParentDir; + } + while (i != baseDirIndex); + + wchar_t *p = prefix.GetBuf_SetEnd(len) + len; + i = dirIndex; + do + { + const CProxyDir &dir = Dirs[i]; + *--p = WCHAR_PATH_SEPARATOR; + p -= dir.NameLen; + wmemcpy(p, dir.Name, dir.NameLen); + i = (unsigned)dir.ParentDir; } + while (i != baseDirIndex); +} + +UString CProxyArc::GetDirPath_as_Prefix(const unsigned dirIndex) const +{ + UString s; + GetDirPath_as_Prefix_from_Base(dirIndex, s, k_Proxy_RootDirIndex); return s; } -void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const +void CProxyArc::AddRealIndices(const unsigned dirIndex, CUIntVector &realIndices) const { const CProxyDir &dir = Dirs[dirIndex]; if (dir.IsLeaf()) @@ -143,7 +210,7 @@ void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) cons realIndices.Add(dir.SubFiles[i]); } -int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const +int CProxyArc::GetRealIndex(const unsigned dirIndex, const unsigned index) const { const CProxyDir &dir = Dirs[dirIndex]; const unsigned numDirItems = dir.SubDirs.Size(); @@ -157,7 +224,8 @@ int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const return (int)dir.SubFiles[index - numDirItems]; } -void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const +void CProxyArc::GetRealIndices_Unsorted(unsigned dirIndex, + const UInt32 *indices, const UInt32 numItems, CUIntVector &realIndices) const { const CProxyDir &dir = Dirs[dirIndex]; realIndices.Clear(); @@ -170,11 +238,9 @@ void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 else realIndices.Add(dir.SubFiles[index - numDirItems]); } - HeapSort(realIndices.NonConstData(), realIndices.Size()); + // HeapSort(realIndices.NonConstData(), realIndices.Size()); } -/////////////////////////////////////////////// -// CProxyArc static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size) { @@ -185,51 +251,68 @@ static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &si return ConvertPropVariantToUInt64(prop, size); } -void CProxyArc::CalculateSizes(unsigned dirIndex, IInArchive *archive) +void CProxyArc::CalculateSizes(IInArchive *archive) { - CProxyDir &dir = Dirs[dirIndex]; - dir.Size = dir.PackSize = 0; - dir.NumSubDirs = dir.SubDirs.Size(); - dir.NumSubFiles = dir.SubFiles.Size(); - dir.CrcIsDefined = true; - dir.Crc = 0; - - unsigned i; - - for (i = 0; i < dir.SubFiles.Size(); i++) + CUIntVector vec; + unsigned dirIndex = 0, i = 0; + for (;;) { - const UInt32 index = (UInt32)dir.SubFiles[i]; - UInt64 size, packSize; - const bool sizeDefined = GetSize(archive, index, kpidSize, size); - dir.Size += size; - GetSize(archive, index, kpidPackSize, packSize); - dir.PackSize += packSize; + CProxyDir &dir = Dirs[dirIndex]; + if (i == 0) { - NCOM::CPropVariant prop; - if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) + dir.Size = dir.PackSize = 0; + dir.NumSubDirs = dir.SubDirs.Size(); + dir.NumSubFiles = dir.SubFiles.Size(); + dir.CrcIsDefined = true; + dir.Crc = 0; + + FOR_VECTOR (k, dir.SubFiles) { - if (prop.vt == VT_UI4) - dir.Crc += prop.ulVal; - else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) - dir.CrcIsDefined = false; + const UInt32 index = (UInt32)dir.SubFiles[k]; + UInt64 size, packSize; + const bool sizeDefined = GetSize(archive, index, kpidSize, size); + dir.Size += size; + GetSize(archive, index, kpidPackSize, packSize); + dir.PackSize += packSize; + { + NCOM::CPropVariant prop; + if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) + { + if (prop.vt == VT_UI4) + dir.Crc += prop.ulVal; + else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) + dir.CrcIsDefined = false; + } + else + dir.CrcIsDefined = false; + } } - else - dir.CrcIsDefined = false; } - } - - for (i = 0; i < dir.SubDirs.Size(); i++) - { - unsigned subDirIndex = dir.SubDirs[i]; - CalculateSizes(subDirIndex, archive); - CProxyDir &f = Dirs[subDirIndex]; - dir.Size += f.Size; - dir.PackSize += f.PackSize; - dir.NumSubFiles += f.NumSubFiles; - dir.NumSubDirs += f.NumSubDirs; - dir.Crc += f.Crc; - if (!f.CrcIsDefined) - dir.CrcIsDefined = false; + + if (i == dir.SubDirs.Size()) + { + const unsigned num = vec.Size(); + if (num < 2) + return; + dirIndex = vec[num - 2]; + i = vec[num - 1]; + vec.DeleteFrom(num - 2); + + CProxyDir &dir2 = Dirs[dirIndex]; + dir2.Size += dir.Size; + dir2.PackSize += dir.PackSize; + dir2.NumSubFiles += dir.NumSubFiles; + dir2.NumSubDirs += dir.NumSubDirs; + dir2.Crc += dir.Crc; + if (!dir.CrcIsDefined) + dir2.CrcIsDefined = false; + continue; + } + + vec.Add(dirIndex); + vec.Add(i + 1); + dirIndex = dir.SubDirs[i]; + i = 0; } } @@ -246,42 +329,54 @@ void CProxyArc::FreeFiles() Files = NULL; } + +static void SetPath_as_LONG_PATH(UString &s, + const unsigned fileIndex, const bool isDir) +{ + s = isDir ? "[LONG_PATH_DIR_" : "[LONG_PATH_FILE_"; + s.Add_UInt32((UInt32)fileIndex); + s.Add_Char(']'); +} + + static const UInt32 k_NumFiles_Max = 0x7fffffff - 15; -HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) +HRESULT CProxyArc::Load(const CArc &arc, IArchiveOpenCallback *progress) { // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { - FreeFiles(); Dirs.Clear(); + Are_Changed_LongPaths = false; Dirs.AddNew(); IInArchive *archive = arc.Archive; - UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)) if (numItems > k_NumFiles_Max) return E_OUTOFMEMORY; - if (progress) - RINOK(progress->SetTotal(numItems)) + { + const UInt64 numItems64 = numItems; + RINOK(progress->SetTotal(&numItems64, NULL)) + } + MemUsage = (UInt64)numItems * sizeof(*Files); + CHECK_MEM_USAGE Z7_ARRAY_NEW(Files, CProxyFile, numItems) memset(Files, 0, (size_t)numItems * sizeof(*Files)); NumFiles = numItems; - UString path; - UString name; + UString path, name; NCOM::CPropVariant prop; for (UInt32 i = 0; i < numItems; i++) { + CHECK_MEM_USAGE if (progress && (i & 0xFFFF) == 0) { const UInt64 currentItemIndex = i; - RINOK(progress->SetCompleted(¤tItemIndex)) + RINOK(progress->SetCompleted(¤tItemIndex, NULL)) } - const wchar_t *s = NULL; unsigned len = 0; bool isPtrName = false; @@ -313,6 +408,7 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) if (!s) #endif { + len = 0; prop.Clear(); RINOK(arc.Archive->GetProperty(i, kpidPath, &prop)) if (prop.vt == VT_BSTR) @@ -328,7 +424,6 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) len = path.Len(); s = path; } - /* RINOK(arc.GetItemPath(i, path)); len = path.Len(); @@ -337,7 +432,6 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) } unsigned curItem = 0; - /* if (arc.Ask_Deleted) { @@ -347,12 +441,22 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); } */ - unsigned namePos = 0; - unsigned numLevels = 0; + bool is_Changed_LongPath = false; + bool isDir; + RINOK(Archive_IsItem_Dir(archive, i, isDir)) - for (unsigned j = 0; j < len; j++) + if (len >= (1 << 15)) + { + Are_Changed_LongPaths = true; + is_Changed_LongPath = true; + SetPath_as_LONG_PATH(path, i, isDir); + s = path; + len = path.Len(); + isPtrName = false; + } + else for (unsigned j = 0; j < len; j++) { const wchar_t c = s[j]; if (c == L'/' @@ -365,12 +469,18 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) if (numLevels <= kLevelLimit) { if (numLevels == kLevelLimit) + { name = "[LONG_PATH]"; + Are_Changed_LongPaths = true; + is_Changed_LongPath = true; + } else name.SetFrom(s + namePos, j - namePos); // 22.00: we can normalize dir here // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); curItem = AddDir(curItem, -1, name); + if (is_Changed_LongPath) + Dirs[curItem].Is_Changed_LongPath = true; } namePos = j + 1; numLevels++; @@ -378,24 +488,16 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) } /* - that code must be implemeted to hide alt streams in list. + that code must be implemented to hide alt streams in list. if (arc.Ask_AltStreams) { bool isAltStream; RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); - if (isAltStream) - { - - } + if (isAltStream){} } */ - - bool isDir; - RINOK(Archive_IsItem_Dir(archive, i, isDir)) - CProxyFile &f = Files[i]; f.Construct(); // optional because memset() in code above - f.NameLen = len - namePos; s += namePos; @@ -403,6 +505,7 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) f.Name = s; else { + MemUsage += 16 + (size_t)f.NameLen * sizeof(*f.Name); f.Name = AllocStringAndCopy(s, f.NameLen); f.NeedDeleteName = true; } @@ -412,16 +515,30 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) name = s; // 22.00: we can normalize dir here // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); - AddDir(curItem, (int)i, name); + curItem = AddDir(curItem, (int)i, name); + if (is_Changed_LongPath) + Dirs[curItem].Is_Changed_LongPath = true; } else + { + MemUsage += Dirs[curItem].SubFiles.IsEmpty() ? 16u : 4u + 1; Dirs[curItem].SubFiles.Add(i); + } } - - CalculateSizes(0, archive); + FOR_VECTOR (k, Dirs) + { + MergeSubDirs(Dirs[k]); + Dirs[k].SubDirs2.ClearAndFree(); // these arryas are small + } + + CalculateSizes(archive); + if (progress) + { + const UInt64 numItems64 = numItems; + RINOK(progress->SetCompleted(&numItems64, NULL)) + } // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); - return S_OK; } @@ -429,12 +546,38 @@ HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) // ---------- for Tree-mode archive ---------- -void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const + +void SetDirPrefix_as_LONG_PATH(UString &s, unsigned fileIndex, + const bool asAltDirPrefix, const bool isDir) +{ + SetPath_as_LONG_PATH(s, fileIndex, isDir); + s.Add_Char(asAltDirPrefix ? ':' : CHAR_PATH_SEPARATOR); +} + + +bool CProxyArc2::IsAltDir(const unsigned dirIndex) const +{ + if (dirIndex == k_Proxy2_RootDirIndex) + return false; + if (dirIndex == k_Proxy2_AltRootDirIndex) + return true; + const CProxyDir2 &dir = Dirs[dirIndex]; + if ((unsigned)dir.ArcIndex >= NumFiles) throw 1; // optional + return (int)dirIndex == Files[(unsigned)dir.ArcIndex].AltDirIndex; +} + + +/* called from: + Agent.cpp: + CAgentFolder::Extract() + ArchiveFolderOut.cpp: + CAgentFolder::GetPathParts() + CAgentFolder::CommonUpdateOperation() +*/ +void CProxyArc2::GetDirPathParts(const unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const { pathParts.Clear(); - isAltStreamDir = false; - if (dirIndex == k_Proxy2_RootDirIndex) return; if (dirIndex == k_Proxy2_AltRootDirIndex) @@ -442,94 +585,220 @@ void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bo isAltStreamDir = true; return; } - - while (dirIndex >= k_Proxy2_NumRootDirs) + int fileIndex = Dirs[dirIndex].ArcIndex; + do { - const CProxyDir2 &dir = Dirs[dirIndex]; - const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; - if (pathParts.IsEmpty() && (int)dirIndex == file.AltDirIndex) + if ((unsigned)fileIndex >= NumFiles) throw 1; // optional + const CProxyFile2 &file = Files[(unsigned)fileIndex]; + // if (pathParts.Size() == 0) // optional + if ((int)dirIndex == file.AltDirIndex) isAltStreamDir = true; + // that code is not optimized for big number of loop iterations. pathParts.Insert(0, file.Name); - const int par = file.Parent; - if (par == -1) - break; - dirIndex = (unsigned)Files[(unsigned)par].DirIndex; - // if ((int)dirIndex == -1) break; + fileIndex = file.Parent; } + while (fileIndex != -1); } -bool CProxyArc2::IsAltDir(unsigned dirIndex) const + +// if Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX is defined, +// { this code is unused mostly. 7-Zip gets prefix via GetItemPrefix(). } +void CProxyArc2::GetDirPath_as_Prefix_from_Base(const unsigned dirIndex, + UString &prefix, const unsigned baseDirIndex, const unsigned lenLimit) const { - if (dirIndex == k_Proxy2_RootDirIndex) - return false; + prefix.Empty(); + if (dirIndex == baseDirIndex) + return; if (dirIndex == k_Proxy2_AltRootDirIndex) - return true; - const CProxyDir2 &dir = Dirs[dirIndex]; - const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; - return ((int)dirIndex == file.AltDirIndex); -} + { + // (baseDirIndex == k_Proxy2_RootDirIndex) is expected + prefix.Add_Colon(); + return; + } -UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const -{ - isAltStreamDir = false; const CProxyDir2 &dir = Dirs[dirIndex]; - if (dirIndex == k_Proxy2_AltRootDirIndex) - isAltStreamDir = true; - else if (dirIndex >= k_Proxy2_NumRootDirs) + int arcIndex = dir.ArcIndex; + if (arcIndex != -1) { - const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; - isAltStreamDir = ((int)dirIndex == file.AltDirIndex); + const CProxyDir2 &baseDir = Dirs[baseDirIndex]; + unsigned len = dir.PrefixLen - baseDir.PrefixLen; + if (len >= lenLimit) + { + const CProxyFile2 &file = Files[(unsigned)arcIndex]; + SetDirPrefix_as_LONG_PATH(prefix, (unsigned)arcIndex, + (int)dirIndex == file.AltDirIndex, // asAltDir, + file.IsDir()); + return; + } + const int baseArcIndex = baseDir.ArcIndex; + wchar_t * const p = prefix.GetBuf_SetEnd(len); + do + { + const CProxyFile2 &file = Files[(unsigned)arcIndex]; + wchar_t c = CHAR_PATH_SEPARATOR; + if ((int)dirIndex == file.AltDirIndex) + c = ':'; + if (len <= file.NameLen) + break; + p[--len] = c; + len -= file.NameLen; + wmemcpy(p + len, file.Name, file.NameLen); + // slash normalization can be omitted, if we want max speed of sorting operation: + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(p + len, file.NameLen); + arcIndex = file.Parent; + if (arcIndex == baseArcIndex) + { + if (len) + break; + return; + } + } + while (arcIndex != -1); } - return dir.PathPrefix; + throw 1; } -void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const + +/* called from: + Agent.cpp: + CAgentFolder::GetFullPrefix() + CAgent::RenameItem() in AgentOut.cpp + CAgentFolder::GetFolderProperty(kpidPath) + GetFolderPath() in PanelFolderChange.cpp + LoadFullPath() + AgentOut.cpp: + CAgent::SetFolder() + CAgentFolder::CommonUpdateOperation() in ArchiveFolderOut.cpp + CAgent::CreateFolder() +*/ +UString CProxyArc2::GetDirPath_as_Prefix(const unsigned dirIndex, const bool canReducePath) const +{ + UString s; + const unsigned lenLimit = canReducePath ? (1u << 14) : (1u << 28); + GetDirPath_as_Prefix_from_Base(dirIndex, s, k_Proxy2_RootDirIndex, lenLimit); + return s; +} + + +void CProxyArc2::AddRealIndices_of_ArcItem(const unsigned arcIndex, + const bool includeAltStreams, const bool includeDirSubItems, + CUIntVector &realIndices) const { realIndices.Add(arcIndex); const CProxyFile2 &file = Files[arcIndex]; - if (file.DirIndex != -1) + if (includeDirSubItems && file.DirIndex != -1) AddRealIndices_of_Dir((unsigned)file.DirIndex, includeAltStreams, realIndices); if (includeAltStreams && file.AltDirIndex != -1) AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices); } -void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const + +void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, + const bool includeAltStreams, + CUIntVector &realIndices) const { - const CRecordVector &subFiles = Dirs[dirIndex].Items; - FOR_VECTOR (i, subFiles) + CUIntVector vec; + unsigned i = 0; + for (;;) { - AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices); + const CProxyDir2 &dir = Dirs[dirIndex]; + if (i == dir.Items.Size()) + { + const unsigned num = vec.Size(); + if (num < 2) + return; + dirIndex = vec[num - 2]; + i = vec[num - 1]; + vec.DeleteFrom(num - 2); + continue; + } + + const unsigned arcIndex = dir.Items[i]; + i++; + realIndices.Add(arcIndex); + const CProxyFile2 &file = Files[arcIndex]; + if (includeAltStreams && file.AltDirIndex != -1) + AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices); + if (file.DirIndex != -1) + { + vec.Add(dirIndex); + vec.Add(i); + dirIndex = (unsigned)file.DirIndex; + i = 0; + } } } -unsigned CProxyArc2::GetRealIndex(unsigned dirIndex, unsigned index) const -{ - return Dirs[dirIndex].Items[index]; -} -void CProxyArc2::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const +void CProxyArc2::GetRealIndices_Unsorted(const unsigned dirIndex, + const UInt32 *indices, const UInt32 numItems, + const bool includeAltStreams, + CUIntVector &realIndices) const { - const CProxyDir2 &dir = Dirs[dirIndex]; + const CUIntVector &items = Dirs[dirIndex].Items; realIndices.Clear(); for (UInt32 i = 0; i < numItems; i++) - { - AddRealIndices_of_ArcItem(dir.Items[indices[i]], includeAltStreams, realIndices); - } - HeapSort(realIndices.NonConstData(), realIndices.Size()); + AddRealIndices_of_ArcItem(items[indices[i]], + includeAltStreams, + true, // includeDirSubItems + realIndices); + // HeapSort(realIndices.NonConstData(), realIndices.Size()); } -void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive) -{ - CProxyDir2 &dir = Dirs[dirIndex]; - dir.Size = dir.PackSize = 0; - dir.NumSubDirs = 0; // dir.SubDirs.Size(); - dir.NumSubFiles = 0; // dir.Files.Size(); - dir.CrcIsDefined = true; - dir.Crc = 0; + +CProxyDir2::CProxyDir2(): + ArcIndex(-1), + PrefixLen(0), + Size(0), + PackSize(0), +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + IsLongPath(false), +#endif + CrcIsDefined(true), + Crc(0), + NumSubDirs(0), + NumSubFiles(0) +{} - FOR_VECTOR (i, dir.Items) + +HRESULT CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive + , IProgress *progress, const UInt64 *completed, unsigned &progressCounter) +{ + CUIntVector vec; +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + UString prefix, name; +#endif + unsigned i = 0; + for (;;) { - UInt32 index = dir.Items[i]; + CProxyDir2 &dir = Dirs[dirIndex]; + // if (i == 0) {} // we can init some (dir) variables here instead of constructor + + if (i == dir.Items.Size()) + { + const unsigned num = vec.Size(); + if (num < 2) + return S_OK; + dirIndex = vec[num - 2]; + i = vec[num - 1]; + vec.DeleteFrom(num - 2); + + CProxyDir2 &dir2 = Dirs[dirIndex]; + dir2.Size += dir.Size; + dir2.PackSize += dir.PackSize; + dir2.NumSubFiles += dir.NumSubFiles; + dir2.NumSubDirs += dir.NumSubDirs; + dir2.Crc += dir.Crc; + if (!dir.CrcIsDefined) + dir2.CrcIsDefined = false; + continue; + } + + if (progress && (++progressCounter & 0xfffff) == 0) + RINOK(progress->SetCompleted(completed)) + + const UInt32 index = dir.Items[i]; + i++; UInt64 size, packSize; const bool sizeDefined = GetSize(archive, index, kpidSize, size); dir.Size += size; @@ -549,56 +818,77 @@ void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive) } const CProxyFile2 &subFile = Files[index]; - if (subFile.DirIndex == -1) - { - dir.NumSubFiles++; - } - else + + if (subFile.NameLen >= (1u << 30) - dir.PrefixLen) + return E_NOTIMPL; + const unsigned prefixLen = dir.PrefixLen + subFile.NameLen + 1; + +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + bool isLongPath = dir.IsLongPath; + if (subFile.AltDirIndex != -1 || subFile.DirIndex != -1) { // 22.00: we normalize name - UString s = subFile.Name; - NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s); - dir.NumSubDirs++; - CProxyDir2 &f = Dirs[subFile.DirIndex]; - f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR; - CalculateSizes((unsigned)subFile.DirIndex, archive); - dir.Size += f.Size; - dir.PackSize += f.PackSize; - dir.NumSubFiles += f.NumSubFiles; - dir.NumSubDirs += f.NumSubDirs; - dir.Crc += f.Crc; - if (!f.CrcIsDefined) - dir.CrcIsDefined = false; + name = subFile.Name; + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); + if (!isLongPath) + { + prefix = dir.PathPrefix; + prefix += name; + if (prefix.Len() >= (1u << 11)) // CProxyDir2::PathPrefix limit + isLongPath = true; + } } +#endif - if (subFile.AltDirIndex == -1) + if (subFile.AltDirIndex != -1) { - // dir.NumSubFiles++; + CProxyDir2 &f = Dirs[subFile.AltDirIndex]; + f.PrefixLen = prefixLen; +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + f.IsLongPath = isLongPath; + if (isLongPath) + SetDirPrefix_as_LONG_PATH(prefix, index, + true, // asAltDirPrefix + subFile.IsDir()); + else + prefix.Add_Colon(); + f.PathPrefix = prefix; + UpdateMemUsage_with_StringLen(f.PathPrefix.Len()); + CHECK_MEM_USAGE + prefix.DeleteBack(); // we delete Colon character +#endif + RINOK(CalculateSizes((unsigned)subFile.AltDirIndex, archive, progress, completed, progressCounter)) } + + if (subFile.DirIndex == -1) + dir.NumSubFiles++; else { - // dir.NumSubDirs++; - CProxyDir2 &f = Dirs[subFile.AltDirIndex]; - f.PathPrefix = dir.PathPrefix + subFile.Name + L':'; - CalculateSizes((unsigned)subFile.AltDirIndex, archive); + CProxyDir2 &f = Dirs[subFile.DirIndex]; + f.PrefixLen = prefixLen; + dir.NumSubDirs++; +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + f.IsLongPath = isLongPath; + if (isLongPath) + SetDirPrefix_as_LONG_PATH(prefix, index, + false, // asAltDirPrefix + true); // isDir + else + prefix.Add_PathSepar(); + f.PathPrefix = prefix; + UpdateMemUsage_with_StringLen(f.PathPrefix.Len()); + CHECK_MEM_USAGE +#endif + if (vec.Size() >= (1u << 28)) // tree levels limit + return E_NOTIMPL; + vec.Add(dirIndex); + vec.Add(i); + dirIndex = (unsigned)subFile.DirIndex; + i = 0; } } } - - -bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const -{ - const CRecordVector &subFiles = Dirs[dirIndex].Items; - FOR_VECTOR (i, subFiles) - { - const CProxyFile2 &file = Files[subFiles[i]]; - if (file.IsDir()) - if (CompareFileNames(name, file.Name) == 0) - return true; - } - return false; -} - + void CProxyArc2::FreeFiles() { @@ -612,54 +902,55 @@ void CProxyArc2::FreeFiles() Files = NULL; } + +void CProxyArc2::AddDir(int arcIndex) +{ + Dirs.AddNew().ArcIndex = arcIndex; + MemUsage += sizeof(Dirs[0]) + sizeof(void *) + 11; +} + HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) { if (!arc.GetRawProps) return E_FAIL; - // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { Dirs.Clear(); FreeFiles(); IInArchive *archive = arc.Archive; - UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)) if (numItems > k_NumFiles_Max) return E_OUTOFMEMORY; if (progress) RINOK(progress->SetTotal(numItems)) - UString fileName; - - - { - // Dirs[0] - root dir - /* CProxyDir2 &dir = */ Dirs.AddNew(); - } - - { - // Dirs[1] - for alt streams of root dir - CProxyDir2 &dir = Dirs.AddNew(); - dir.PathPrefix = ':'; - } + Dirs.AddNew(); // Dirs[0] - root dir + Dirs.AddNew() // Dirs[1] - for alt streams of root dir +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + .PathPrefix.Add_Colon() // = ':'; +#endif + ; + MemUsage = (UInt64)numItems * sizeof(*Files); + CHECK_MEM_USAGE Z7_ARRAY_NEW(Files, CProxyFile2, numItems) memset(Files, 0, (size_t)numItems * sizeof(*Files)); NumFiles = numItems; + UString fileName; UString tempUString; AString tempAString; UInt32 i; for (i = 0; i < numItems; i++) { + CHECK_MEM_USAGE if (progress && (i & 0xFFFFF) == 0) { const UInt64 currentItemIndex = i; RINOK(progress->SetCompleted(¤tItemIndex)) } - CProxyFile2 &file = Files[i]; file.Construct(); @@ -668,7 +959,7 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) UInt32 propType; RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType)) - #ifdef MY_CPU_LE +#ifdef MY_CPU_LE_ if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) { file.Name = (const wchar_t *)p; @@ -677,58 +968,59 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) file.NameLen = size / (unsigned)sizeof(wchar_t) - 1; } else - #endif - if (p && propType == NPropDataType::kUtf8z) - { - tempAString = (const char *)p; - ConvertUTF8ToUnicode(tempAString, tempUString); - file.NameLen = tempUString.Len(); - file.Name = AllocStringAndCopy(tempUString); - file.NeedDeleteName = true; - } - else +#endif { - NCOM::CPropVariant prop; - RINOK(arc.Archive->GetProperty(i, kpidName, &prop)) const wchar_t *s; - if (prop.vt == VT_BSTR) - s = prop.bstrVal; - else if (prop.vt == VT_EMPTY) - s = L"[Content]"; + unsigned len; + if (p && propType == NPropDataType::kUtf8z) + { + tempAString = (const char *)p; + ConvertUTF8ToUnicode(tempAString, tempUString); + s = tempUString.Ptr(); + len = tempUString.Len(); + } else - return E_FAIL; - file.NameLen = MyStringLen(s); - file.Name = AllocStringAndCopy(s, file.NameLen); + { + NCOM::CPropVariant prop; + RINOK(arc.Archive->GetProperty(i, kpidName, &prop)) + if (prop.vt == VT_BSTR) + s = prop.bstrVal; + else if (prop.vt == VT_EMPTY) + s = L"[Content]"; + else + return E_FAIL; + len = MyStringLen(s); + } + file.NameLen = len; + file.Name = AllocStringAndCopy(s, len); + UpdateMemUsage_with_StringLen(len); file.NeedDeleteName = true; } UInt32 parent = (UInt32)(Int32)-1; UInt32 parentType = 0; RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType)) + if (parent >= numItems && parent != (UInt32)(Int32)-1) + return E_FAIL; file.Parent = (Int32)parent; - + /* if (arc.Ask_Deleted) { bool isDeleted = false; RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)) - if (isDeleted) - { - // continue; - // curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); - } + if (isDeleted) {} } - + */ bool isDir; RINOK(Archive_IsItem_Dir(archive, i, isDir)) - if (isDir) { file.DirIndex = (int)Dirs.Size(); - CProxyDir2 &dir = Dirs.AddNew(); - dir.ArcIndex = (int)i; + AddDir((int)i); // arcIndex } if (arc.Ask_AltStream) RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream)) + // if (file.IsAltStream) file.Parent = -1; // for debug } for (i = 0; i < numItems; i++) @@ -746,8 +1038,7 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) if (folderIndex2 == -1) { folderIndex2 = (int)Dirs.Size(); - CProxyDir2 &dir = Dirs.AddNew(); - dir.ArcIndex = file.Parent; + AddDir(file.Parent); // arcIndex } dirIndex = folderIndex2; } @@ -764,27 +1055,38 @@ HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) } } + MemUsage += Dirs[dirIndex].Items.IsEmpty() ? 16u : 4u + 1; + CHECK_MEM_USAGE Dirs[dirIndex].Items.Add(i); } - + + unsigned progressCounter = 0; for (i = 0; i < k_Proxy2_NumRootDirs; i++) - CalculateSizes(i, archive); + { + const UInt64 numItems64 = numItems; + RINOK(CalculateSizes(i, archive, progress, &numItems64, progressCounter)) + } + // OutputDebugStringA("finished"); // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); - return S_OK; } -int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const +int CProxyArc2::FindItem(const unsigned dirIndex, const wchar_t *name, bool foldersOnly) const { - const CProxyDir2 &dir = Dirs[dirIndex]; - FOR_VECTOR (i, dir.Items) + int index = -1; + const CUIntVector &subFiles = Dirs[dirIndex].Items; + FOR_VECTOR (i, subFiles) { - const CProxyFile2 &file = Files[dir.Items[i]]; + const CProxyFile2 &file = Files[subFiles[i]]; if (foldersOnly && file.DirIndex == -1) continue; - if (CompareFileNames(file.Name, name) == 0) + if (CompareFileNames(file.Name, name) != 0) + continue; + if (MyStringCompare(file.Name, name) == 0) return (int)i; + if (index == -1) + index = (int)i; } - return -1; + return index; } diff --git a/CPP/7zip/UI/Agent/AgentProxy.h b/CPP/7zip/UI/Agent/AgentProxy.h index c6736a8..e486cb6 100644 --- a/CPP/7zip/UI/Agent/AgentProxy.h +++ b/CPP/7zip/UI/Agent/AgentProxy.h @@ -27,9 +27,10 @@ struct CProxyDir unsigned NameLen; int ArcIndex; // index in proxy->Files[] ; -1 if there is no item for that folder - int ParentDir; // index in proxy->Dirs[] ; -1 for root folder; ; - CRecordVector SubDirs; - CRecordVector SubFiles; + int ParentDir; // index in proxy->Dirs[] ; -1 for root folder + CUIntVector SubDirs; + CUIntVector SubDirs2; + CUIntVector SubFiles; UInt64 Size; UInt64 PackSize; @@ -37,47 +38,56 @@ struct CProxyDir UInt32 NumSubDirs; UInt32 NumSubFiles; bool CrcIsDefined; + bool Is_Changed_LongPath; - CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {} + CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1), Is_Changed_LongPath(false) {} ~CProxyDir() { delete [](wchar_t *)(void *)Name; } - void Clear(); bool IsLeaf() const { return ArcIndex != -1; } }; class CProxyArc { - int FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const; + int FindSubDir(const unsigned *items, unsigned right, + const wchar_t *name, unsigned &insertPos) const; - void CalculateSizes(unsigned dirIndex, IInArchive *archive); + void CalculateSizes(IInArchive *archive); + void MergeSubDirs(CProxyDir &baseDir); unsigned AddDir(unsigned dirIndex, int arcIndex, const UString &name); void FreeFiles(); public: CObjectVector Dirs; // Dirs[0] - root CProxyFile *Files; // all items from archive in same order unsigned NumFiles; + bool Are_Changed_LongPaths; + UInt64 MemUsage; + UInt64 MemUsage_Limit; - CProxyArc(): Files(NULL), NumFiles(0) {} + CProxyArc(): Files(NULL), NumFiles(0), Are_Changed_LongPaths(false), MemUsage_Limit((UInt64)(Int64)-1) {} ~CProxyArc() { FreeFiles(); } // returns index in Dirs[], or -1, int FindSubDir(unsigned dirIndex, const wchar_t *name) const; - void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const; + void GetDirPathParts_isChanged(unsigned dirIndex, + UStringVector &pathPartsm, bool &isChangedPath) const; // returns full path of Dirs[dirIndex], including back slash UString GetDirPath_as_Prefix(unsigned dirIndex) const; + void GetDirPath_as_Prefix_from_Base(unsigned dirIndex, UString &prefix, unsigned baseDirIndex) const; // AddRealIndices DOES ADD also item represented by dirIndex (if it's Leaf) void AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const; int GetRealIndex(unsigned dirIndex, unsigned index) const; - void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const; + void GetRealIndices_Unsorted(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const; - HRESULT Load(const CArc &arc, IProgress *progress); + HRESULT Load(const CArc &arc, IArchiveOpenCallback *progress); }; // ---------- for Tree-mode archive ---------- +// #define Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + struct CProxyFile2 { int DirIndex; // >= 0 for dir. (index in ProxyArchive2->Dirs) @@ -86,7 +96,7 @@ struct CProxyFile2 const wchar_t *Name; unsigned NameLen; bool NeedDeleteName; - bool Ignore; + bool Ignore; // = false always bool IsAltStream; int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; } @@ -108,17 +118,23 @@ struct CProxyFile2 struct CProxyDir2 { - int ArcIndex; // = -1 for root folders, index in proxy->Files[] - CRecordVector Items; + int ArcIndex; // = -1 for root folders, index in CProxyArc2::Files[] + unsigned PrefixLen; + CUIntVector Items; // indexes in archive and in CProxyArc2::Files[] +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX UString PathPrefix; +#endif UInt64 Size; UInt64 PackSize; +#ifdef Z7_AGENT_PROXY2_USE_DIR_PATH_PREFIX + bool IsLongPath; +#endif bool CrcIsDefined; UInt32 Crc; UInt32 NumSubDirs; UInt32 NumSubFiles; - CProxyDir2(): ArcIndex(-1) {} + CProxyDir2(); }; const unsigned k_Proxy2_RootDirIndex = k_Proxy_RootDirIndex; @@ -127,48 +143,54 @@ const unsigned k_Proxy2_NumRootDirs = 2; class CProxyArc2 { - void CalculateSizes(unsigned dirIndex, IInArchive *archive); + HRESULT CalculateSizes(unsigned dirIndex, IInArchive *archive + , IProgress *progress, const UInt64 *completed, unsigned &progressCounter); // AddRealIndices_of_Dir DOES NOT ADD item itself represented by dirIndex void AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const; void FreeFiles(); + void UpdateMemUsage_with_StringLen(unsigned len) + { + MemUsage += (size_t)len * sizeof(Files->Name[0]) + 16; + } public: CObjectVector Dirs; // Dirs[0] - root folder // Dirs[1] - for alt streams of root dir CProxyFile2 *Files; // all items from archive in same order unsigned NumFiles; + UInt64 MemUsage; + UInt64 MemUsage_Limit; - CProxyArc2(): Files(NULL), NumFiles(0) {} + CProxyArc2(): Files(NULL), NumFiles(0), MemUsage_Limit((UInt64)(Int64)-1) {} ~CProxyArc2() { FreeFiles(); } - bool IsThere_SubDir(unsigned dirIndex, const UString &name) const; - void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const; - UString GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const; + void GetDirPath_as_Prefix_from_Base(unsigned dirIndex, UString &prefix, unsigned baseDirIndex, unsigned lenLimit) const; + UString GetDirPath_as_Prefix(unsigned dirIndex, bool canReducePath = false) const; bool IsAltDir(unsigned dirIndex) const; // AddRealIndices_of_ArcItem DOES ADD item and subItems - void AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const; - unsigned GetRealIndex(unsigned dirIndex, unsigned index) const; - void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const; + void AddRealIndices_of_ArcItem(unsigned arcIndex, + bool includeAltStreams, bool includeDirSubItems, + CUIntVector &realIndices) const; + unsigned GetRealIndex(const unsigned dirIndex, const unsigned index) const + { + return Dirs[dirIndex].Items[index]; + } + void GetRealIndices_Unsorted(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, + bool includeAltStreams, CUIntVector &realIndices) const; HRESULT Load(const CArc &arc, IProgress *progress); - int GetParentDirOfFile(UInt32 arcIndex) const + int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const; + bool IsThere_SubDir(unsigned dirIndex, const wchar_t *name) const { - const CProxyFile2 &file = Files[arcIndex]; - - if (file.Parent == -1) - return file.IsAltStream ? - k_Proxy2_AltRootDirIndex : - k_Proxy2_RootDirIndex; - - const CProxyFile2 &parentFile = Files[file.Parent]; - return file.IsAltStream ? - parentFile.AltDirIndex : - parentFile.DirIndex; + return FindItem(dirIndex, name, true) != -1; // foldersOnly } - - int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const; + + void AddDir(int arcIndex); }; +void SetDirPrefix_as_LONG_PATH(UString &s, unsigned fileIndex, + bool asAltDirPrefix, bool isDir); + #endif diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp index 3fa027d..6430503 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp @@ -114,7 +114,19 @@ Z7_COM7F_IMF(CArchiveFolderManager::OpenFolderFile(IInStream *inStream, return res; } - RINOK(archive->BindToRootFolder(resultFolder)) + agent->_progress_for_Open = progress; + agent->_progress_ArchiveOpenCallback_for_Open = openArchiveCallback; + { + HRESULT hres = E_OUTOFMEMORY; + // IInFolderArchive::BindToRootFolder() doesn't raise exceptions. + // so try/catch is optional + try { + hres = archive->BindToRootFolder(resultFolder); + } catch (...) {} + agent->_progress_for_Open = NULL; + agent->_progress_ArchiveOpenCallback_for_Open = NULL; + RINOK(hres) + } return res; } diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp index 1da6601..44e9d91 100644 --- a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp +++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp @@ -21,10 +21,11 @@ using namespace NDir; void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder) { + bool isChangedPath = false; if (_proxy2) _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder); else - _proxy->GetDirPathParts(_proxyDirIndex, pathParts); + _proxy->GetDirPathParts_isChanged(_proxyDirIndex, pathParts, isChangedPath); } static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path) diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index 7f6da0c..a86dd20 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -161,7 +161,9 @@ static const char * const k_ZoneId_StreamName_With_Colon_Prefix = ":Zone.Identif bool Is_ZoneId_StreamName(const wchar_t *s) { - return StringsAreEqualNoCase_Ascii(s, k_ZoneId_StreamName_With_Colon_Prefix + 1); + UString s2 = s; + Correct_AltStream_Name(s2); + return StringsAreEqualNoCase_Ascii(s2, k_ZoneId_StreamName_With_Colon_Prefix + 1); } void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf) @@ -358,20 +360,19 @@ void CArchiveExtractCallback::Init( _folderArchiveExtractCallback2.Release(); _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); - #ifndef Z7_SFX - +#ifndef Z7_SFX + _baseParentFolder = (UInt32)(Int32)-1; + _use_baseParentFolder_mode = false; ExtractToStreamCallback.Release(); _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); if (ExtractToStreamCallback) { Int32 useStreams = 0; - if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) - useStreams = 0; - if (useStreams == 0) + if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK + || useStreams == 0) ExtractToStreamCallback.Release(); } - - #endif +#endif LocalProgressSpec->Init(extractCallback2, true); LocalProgressSpec->SendProgress = false; @@ -379,11 +380,6 @@ void CArchiveExtractCallback::Init( _removePathParts = removePathParts; _removePartsForAltStreams = removePartsForAltStreams; - #ifndef Z7_SFX - _baseParentFolder = (UInt32)(Int32)-1; - _use_baseParentFolder_mode = false; - #endif - _arc = arc; _dirPathPrefix = directoryPath; _dirPathPrefix_Full = directoryPath; @@ -464,21 +460,16 @@ void CArchiveExtractCallback::CreateComplexDirectory( const UStringVector &dirPathParts, bool isFinal, FString &fullPath) { // we use (_item.IsDir) in this function - bool isAbsPath = false; - if (!dirPathParts.IsEmpty()) { const UString &s = dirPathParts[0]; if (s.IsEmpty()) isAbsPath = true; - #if defined(_WIN32) && !defined(UNDER_CE) - else - { - if (NName::IsDrivePath2(s)) - isAbsPath = true; - } - #endif +#if defined(_WIN32) && !defined(UNDER_CE) + else if (NName::IsDrivePath2(s)) + isAbsPath = true; +#endif } if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) @@ -495,37 +486,73 @@ void CArchiveExtractCallback::CreateComplexDirectory( const bool isFinalDir = (i == dirPathParts.Size() - 1 && isFinal && _item.IsDir); - if (fullPath.IsEmpty()) + if (fullPath.IsEmpty() +#if defined(_WIN32) && !defined(UNDER_CE) + || (_pathMode == NExtract::NPathMode::kAbsPaths + && i == 0 && s.Len() == 2 && NName::IsDrivePath2(s)) +#endif + ) { if (isFinalDir) - _itemFailure = true; + _itemFailure = true; // we don't want to set attributes for root (or root drive) path continue; } - #if defined(_WIN32) && !defined(UNDER_CE) - if (_pathMode == NExtract::NPathMode::kAbsPaths) - if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s)) + // bool need_SetAttrib = isFinalDir; + if (!isFinalDir || !NFile::NFind::DoesDirExist(fullPath)) + { + HRESULT hres = S_OK; +#ifdef _WIN32 + if (!CreateDir(fullPath)) + hres = GetLastError_noZero_HRESULT(); +#else + mode_t mode = g_umask.mask; + if (isFinalDir && _fi.Attrib_Defined) { - if (isFinalDir) + const UInt32 attrib = _fi.Attrib; + if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) { - // we don't want to call SetAttrib() for root drive path - _itemFailure = true; + mode = attrib >> 16; + if (S_ISDIR(mode)) + mode |= (S_IRUSR | S_IWUSR | S_IXUSR); // user/7z must be able to create files in this directory + else + { + // we do not want to use attributes, if it's not directory type. + // SendMessageError("is not directory type in metadata", fullPath); + mode = g_umask.mask; + } + mode &= g_umask.mask; } - continue; } - #endif + // printf("\n mkdir mode = %o\n", (unsigned)mode); + if (mkdir(fullPath, mode) == 0) + { + if (isFinalDir) + _dirAttrib_wasSet = true; + // printf("\n mkdir OK\n"); + // need_SetAttrib = false; + } + else + hres = GetLastError_noZero_HRESULT(); +#endif - HRESULT hres = S_OK; - if (!CreateDir(fullPath)) - hres = GetLastError_noZero_HRESULT(); - if (isFinalDir) - { - if (!NFile::NFind::DoesDirExist(fullPath)) + if (isFinalDir && !NFile::NFind::DoesDirExist(fullPath)) { _itemFailure = true; SendMessageError_with_Error(hres, "Cannot create folder", fullPath); + // need_SetAttrib = false; } } + /* + // this code doesn't process item excluded by "Eliminate duplication of root folder" + // so we will set attributes later + if (need_SetAttrib) + { + // printf("\n SetAttrib \n"); + SetAttrib(fullPath); + _dirAttrib_wasSet = true; + } + */ } } @@ -926,7 +953,38 @@ HRESULT CArchiveExtractCallback::ReadLink() #endif // SUPPORT_LINKS -#ifndef _WIN32 +#ifdef _WIN32 + +#define SET_OWNER +#define SET_NEED_SET_OWNER + +#else + +#define SET_OWNER { SetOwner(); } +#define SET_NEED_SET_OWNER { _needSetOwner = true; } + +void CArchiveExtractCallback::SetOwner() +{ + if (!_needSetOwner) + return; + _needSetOwner = false; + // we want to call chown() only for file itself. + // we don't want to follow link. + // if (_isSymLinkCreated) return; + const FString &path = _diskFilePath; + if (_itemFailure + || path.IsEmpty() + || _stdOutMode + || !_extractMode) + return; + if (_fi.Owner.Id_Defined && + _fi.Group.Id_Defined) + { + // printf("\n SetOwner() %s\n", path.Ptr()); + if (my_chown(path, _fi.Owner.Id, _fi.Group.Id) != 0) + SendMessageError_with_LastError("Cannot set owner", path); + } +} static HRESULT GetOwner(IInArchive *archive, UInt32 index, UInt32 pidName, UInt32 pidId, CProcessedFileInfo::COwnerInfo &res) @@ -1009,7 +1067,7 @@ HRESULT CArchiveExtractCallback::Read_fi_Props() #ifndef _WIN32 if (_ntOptions.ExtractOwner) { - // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath); + // SendMessageError("_ntOptions.ExtractOwner", _diskFilePath); GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner); GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group); } @@ -1043,7 +1101,11 @@ void CArchiveExtractCallback::CorrectPathParts() { pathParts.AddNew(); if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt) + { + const UString s2 = Get_Correct_FsFile_Name(s); + s = s2; needColon = false; + } } #ifdef _WIN32 else if (_pathMode == NExtract::NPathMode::kAbsPaths && @@ -1371,8 +1433,15 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr outFileStream_Loc(_outFileStreamSpec); + + bool needSetAttrib = true; +#ifndef _WIN32 + if (_fi.Attrib_Defined) + { + /* + system open() function uses system umask. + our (g_umask.mask) is more restricted mask. + So we use (mode) parameter in open(,, mode), because our mask for (mode) + is more restricted than system umask. + If we want to set unrestricted (mode) bits for file, then we must + call additional fchmod() function later. + */ + mode_t mode = NWindows::NFile::NIO::k_OutFile_mode_default; // 0666 + const UInt32 attrib = _fi.Attrib; + if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) + { + mode = (attrib >> 16); + // mode &= 07777; // for debug + if (!S_ISREG(mode)) + { + // printf("\n !S_ISREG(mode) = %o\n", (unsigned)mode); + needSetAttrib = false; + } + } + else if (attrib & FILE_ATTRIBUTE_READONLY) + mode &= (mode_t)~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions + if (needSetAttrib) + { + // printf("\n File.mode_for_Create = %o\n", (unsigned)mode); + mode &= g_umask.mask; + // mode = 0777; // for debug + // mode |= S_ISUID | S_ISGID | S_ISVTX; // for debug + _outFileStreamSpec->File.mode_for_Create = mode; + } + needSetAttrib = false; + } +#endif + // printf("\n GetExtractStream Create_ALWAYS_or_Open_ALWAYS : %s\n", fullProcessedPath.Ptr()); if (!_outFileStreamSpec->Create_ALWAYS_or_Open_ALWAYS(fullProcessedPath, !_isSplit)) { // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) @@ -1472,7 +1582,8 @@ HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtrSetTime( + const bool needSetAttrib = (_needSetAttrib && _fi.Attrib_Defined); + if (t.IsSomeTimeDefined() || needSetAttrib) + { + bool needSetTime = true; + if (needSetAttrib) + { + /* + in Linux: { this code branch is not used, + because (mode) was set in open() function in COutFile open function. + If we call Set_Time_and_WinAttrib(), then later COutFile::Close() will call fchmod(). + So we need Set_Time_and_WinAttrib() in linux only if we need insecure nonrestricted (mode) bits with fchmod(). + } + + win10: if (attrib & FILE_ATTRIBUTE_DIRECTORY) + { + NtSetInformationFile() returns (STATUS_INVALID_PARAMETER) + SetFileAttributes() just ignores FILE_ATTRIBUTE_DIRECTORY() + } + */ + // _fi.Attrib |= 0xfffffff; // FOR DEBUG + if (_outFileStreamSpec->File.Set_Time_and_WinAttrib( + t.CTime_Defined ? &t.CTime : NULL, + t.ATime_Defined ? &t.ATime : NULL, + t.MTime_Defined ? &t.MTime : NULL, + (DWORD)_fi.Attrib & ~(DWORD)FILE_ATTRIBUTE_DIRECTORY)) + { + needSetTime = false; + _needSetAttrib = false; + } + else + { + // it's unexpected case. + // we will set timestamp/attributes with another code later + // SendMessageError_with_LastError("Cannot set timestamp and file attribute", _diskFilePath); + } + } + if (needSetTime) + _outFileStreamSpec->SetTime( t.CTime_Defined ? &t.CTime : NULL, t.ATime_Defined ? &t.ATime : NULL, t.MTime_Defined ? &t.MTime : NULL); - // #endif + } RINOK(_outFileStreamSpec->Close()) _outFileStream.Release(); @@ -2096,7 +2246,7 @@ HRESULT CArchiveExtractCallback::SetLink( return SendMessageError("Cannot create temporary link file", fullProcessedPath_from); #if 0 // 1 for debug // here we can write link path to temporary link file placeholder, - // but empty placeholder is better, because we don't want to get any non-eampty data instead of link file. + // but empty placeholder is better, because we don't want to get any non-empty data instead of link file. AString s; ConvertUnicodeToUTF8(link.LinkPath, s); outFile.WriteFull(s, s.Len()); @@ -2543,13 +2693,13 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() link.Parse_from_LinuxData(_outMemBuf, reparseSize) : link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize); if (!needSetReparse) - res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path)); + res = SendMessageError("Incorrect reparse stream", us2fs(_item.Path)); // (link.LinkPath) uses system path separator. // windows: (link.LinkPath) doesn't contain linux separator (slash). } else { - res = SendMessageError_with_LastError("Unknown reparse stream", us2fs(_item.Path)); + res = SendMessageError("Unknown reparse stream", us2fs(_item.Path)); } if (!needSetReparse && _outFileStream) { @@ -2587,8 +2737,14 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() // link.isJunction = true; // for debug link.Normalize_to_RelativeSafe(_removePathParts); RINOK(SetLink(_diskFilePath, link, linkWasSet)) +/* DOCs: + posix: permissions are ignored for access via link. + Linux: the permissions of an ordinary symbolic link are not + used in any operations; the permissions are always 0777 (read, + write, and execute for all user categories), and can't be changed. + So we don't set attributes for placeholder. +*/ /* - // we don't set attributes for placeholder. if (linkWasSet) _isSymLinkCreated = true; // link.IsSymLink(); else @@ -2605,15 +2761,6 @@ HRESULT CArchiveExtractCallback::CloseReparseAndFile() static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi, const CArchiveExtractCallback &callback) { -#ifndef _WIN32 - if (fi.Owner.Id_Defined && - fi.Group.Id_Defined) - { - if (my_chown(path, fi.Owner.Id, fi.Group.Id) != 0) - callback.SendMessageError_with_LastError("Cannot set owner", path); - } -#endif - if (fi.Attrib_Defined) { // const AString s = GetAnsiString(_diskFilePath); @@ -2626,21 +2773,21 @@ static void SetAttrib_Base(const FString &path, const CProcessedFileInfo &fi, } } -void CArchiveExtractCallback::SetAttrib() const +void CArchiveExtractCallback::SetAttrib(const FString &path) const { #ifndef _WIN32 // Linux now doesn't support permissions for symlinks - if (_isSymLinkCreated) - return; + // if (_isSymLinkCreated) return; #endif + // printf("\n SetAttrib %s, \n", path.Ptr()); if (_itemFailure - || _diskFilePath.IsEmpty() + || path.IsEmpty() || _stdOutMode || !_extractMode) return; - SetAttrib_Base(_diskFilePath, _fi, *this); + SetAttrib_Base(path, _fi, *this); } @@ -2688,9 +2835,6 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) GetUnpackSize(); return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize); } - #endif - - #ifndef Z7_SFX if (_hashStreamWasUsed) { @@ -2738,11 +2882,11 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes)) NumFiles++; if (_needSetAttrib) - SetAttrib(); - - RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted))) - - return S_OK; + SetAttrib(_diskFilePath); + + SET_OWNER + + return _extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)); COM_TRY_END } @@ -2987,15 +3131,30 @@ HRESULT CArchiveExtractCallback::SetPostLinks() const RINOK(SetLink2(*this, link, linkWasSet)) if (linkWasSet) { -#ifdef _WIN32 - // Linux now doesn't support permissions for symlinks - SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this); -#endif - + // we set timestamps before SetAttrib(), + // because windows doesn't set timestamps, if file has read-only attribute CFiTimesCAM pt; GetFiTimesCAM(link.item_FileInfo, pt, *_arc); if (pt.IsSomeTimeDefined()) - pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from); + if (!pt.SetLinkFileTime_to_FS(link.fullProcessedPath_from)) + { + // SendMessageError_with_LastError("cannot set timestamp", link.fullProcessedPath_from); + } + +#ifdef _WIN32 + SetAttrib_Base(link.fullProcessedPath_from, link.item_FileInfo, *this); +#else + // Linux now doesn't support permissions for symlinks. + // We set only owner + { + const CProcessedFileInfo &fi = link.item_FileInfo; + if (fi.Owner.Id_Defined && fi.Group.Id_Defined) + { + if (my_chown_Link(link.fullProcessedPath_from, fi.Owner.Id, fi.Group.Id) != 0) + SendMessageError_with_LastError("Cannot set owner", link.fullProcessedPath_from); + } + } +#endif #ifdef Z7_USE_SECURITY_CODE // we set security information after timestamps setting diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h index 3c62763..e1822c7 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h @@ -260,14 +260,6 @@ struct COwnerInfo COwnerInfo Group; #endif - void Clear() - { -#ifndef _WIN32 - Attrib_Defined = false; - Owner.Clear(); -#endif - } - bool IsReparse() const { return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); @@ -386,7 +378,8 @@ private: bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX. // _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file. bool _needSetAttrib; - bool _isSymLinkCreated; + bool _dirAttrib_wasSet; + // bool _isSymLinkCreated; bool _itemFailure; bool _some_pathParts_wereRemoved; @@ -395,6 +388,9 @@ private: #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX) bool _saclEnabled; #endif +#ifndef _WIN32 + bool _needSetOwner; +#endif NExtract::NPathMode::EEnum _pathMode; NExtract::NOverwriteMode::EEnum _overwriteMode; @@ -470,8 +466,11 @@ private: FString Hash_GetFullFilePath(); - void SetAttrib() const; - + void SetAttrib(const FString &path) const; +#ifndef _WIN32 + void SetOwner(); +#endif + public: HRESULT SendMessageError(const char *message, const FString &path) const; HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const; diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp index 8a72936..bf11d12 100644 --- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -394,5 +394,10 @@ Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */)) Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */)) { - return S_OK; + // this call can be used for additional structure parsing after archive openning. + // so we ignore completed + // we just want to process open break + if (!Callback) + return S_OK; + return Callback->Open_CheckBreak(); } diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp index 30fc1e6..6e083ea 100644 --- a/CPP/7zip/UI/Common/Bench.cpp +++ b/CPP/7zip/UI/Common/Bench.cpp @@ -2866,6 +2866,8 @@ static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, un static void PrintChars(IBenchPrintCallback &f, char c, unsigned size) { char s[256]; + if (size >= sizeof(s)) + size = sizeof(s) - 1; memset(s, (Byte)c, size); s[size] = 0; f.Print(s); @@ -4070,7 +4072,8 @@ HRESULT Bench( )); if (start >= freq * 16) { - printCallback->Print(" (Cmplx)"); + if (printCallback) + printCallback->Print(" (Cmplx)"); if (!freqCallback) // we don't want complexity change for old gui lzma benchmark { needSetComplexity = true; @@ -4658,6 +4661,8 @@ HRESULT Bench( } } + if (!printCallback) + return E_NOTIMPL; IBenchPrintCallback &f = *printCallback; if (threadsPassIndex > 0) diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp index e234670..7ca6680 100644 --- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp +++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp @@ -99,10 +99,13 @@ void Correct_AltStream_Name(UString &s) const unsigned kPostfixSize = 6; if (s.Len() >= kPostfixSize && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA")) + { len -= kPostfixSize; + s.DeleteFrom(len); + } for (unsigned i = 0; i < len; i++) { - wchar_t c = s[i]; + const wchar_t c = s[i]; if (c == ':' || c == '\\' || c == '/' || c == 0x202E // RLO ) diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp index c26d4c0..f9e4fae 100644 --- a/CPP/7zip/UI/Common/OpenArchive.cpp +++ b/CPP/7zip/UI/Common/OpenArchive.cpp @@ -524,32 +524,55 @@ static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &res #ifndef Z7_SFX -HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const +HRESULT CArc::GetItem_PathToParent(UInt32 index, const UInt32 parent, UStringVector &parts) const { if (!GetRawProps) return E_FAIL; if (index == parent) return S_OK; - UInt32 curIndex = index; + CRecordVector vec; UString s; - - bool prevWasAltStream = false; - + bool isAltStream = false; + for (;;) { - #ifdef MY_CPU_LE + vec.Add(index); + UInt32 curParent = (UInt32)(Int32)-1; + UInt32 parentType = 0; + RINOK(GetRawProps->GetParent(index, &curParent, &parentType)) + + if (parentType == NParentType::kAltStream) + { + // that case is not expected because + // we don't call GetItem_PathToParent() function for alt stream items + if (vec.Size() != 1) + return E_FAIL; + isAltStream = true; + } + if (parent == curParent) + break; + if (curParent == (UInt32)(Int32)-1) + return E_FAIL; + index = curParent; + } + + unsigned k = vec.Size(); + do + { + index = vec[--k]; +#ifdef MY_CPU_LE const void *p; UInt32 size; UInt32 propType; - RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType)) + RINOK(GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType)) if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) s = (const wchar_t *)p; else - #endif +#endif { NCOM::CPropVariant prop; - RINOK(Archive->GetProperty(curIndex, kpidName, &prop)) + RINOK(Archive->GetProperty(index, kpidName, &prop)) if (prop.vt == VT_BSTR && prop.bstrVal) s.SetFromBstr(prop.bstrVal); else if (prop.vt == VT_EMPTY) @@ -557,51 +580,17 @@ HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &p else return E_FAIL; } - - UInt32 curParent = (UInt32)(Int32)-1; - UInt32 parentType = 0; - RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType)) - - // 18.06: fixed : we don't want to split name to parts - /* - if (parentType != NParentType::kAltStream) - { - for (;;) - { - int pos = s.ReverseFind_PathSepar(); - if (pos < 0) - { - break; - } - parts.Insert(0, s.Ptr(pos + 1)); - s.DeleteFrom(pos); - } - } - */ - - parts.Insert(0, s); - - if (prevWasAltStream) + if (isAltStream && k == 0 && !parts.IsEmpty()) { - { - UString &s2 = parts[parts.Size() - 2]; - s2.Add_Colon(); - s2 += parts.Back(); - } - parts.DeleteBack(); + UString &s2 = parts.Back(); + s2.Add_Colon(); + s2 += s; } - - if (parent == curParent) - return S_OK; - - prevWasAltStream = false; - if (parentType == NParentType::kAltStream) - prevWasAltStream = true; - - if (curParent == (UInt32)(Int32)-1) - return E_FAIL; - curIndex = curParent; + else + parts.Add(s); } + while (k); + return S_OK; } #endif @@ -888,7 +877,7 @@ HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const { /* Good handler must support GetRawProps::GetParent for alt streams. So the following code currently is not used */ - int colon = FindAltStreamColon_in_Path(item.Path); + const int colon = FindAltStreamColon_in_Path(item.Path); if (colon >= 0) { item.MainPath.DeleteFrom((unsigned)colon); @@ -3397,8 +3386,7 @@ HRESULT CArchiveLink::Open(COpenOptions &op) HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) { VolumesSize = 0; - COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; - CMyComPtr callback = openCallbackSpec; + CMyComPtr2_Create openCallbackSpec; openCallbackSpec->Callback = callbackUI; FString prefix, name; @@ -3413,8 +3401,8 @@ HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) openCallbackSpec->SetSubArchiveName(op.filePath); } - op.callback = callback; - op.callbackSpec = openCallbackSpec; + op.callback = openCallbackSpec; + op.callbackSpec = openCallbackSpec.ClsPtr(); HRESULT res = Open(op); diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp index d73680b..85f3fa8 100644 --- a/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -55,27 +55,28 @@ FILE_ATTRIBUTE_ static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' }; -#define MY_ATTR_CHAR(a, n, c) (((a) & (1 << (n))) ? c : '-') +#define MY_POSIX_MODE_CHAR(a, mask, c) (((a) & (mask)) ? (c) : '-') static void ConvertPosixAttribToString(char *s, UInt32 a) throw() { - s[0] = kPosixTypes[(a >> 12) & 0xF]; - for (int i = 6; i >= 0; i -= 3) + *s++ = kPosixTypes[(a >> 12) & 0xF]; + for (unsigned mask = 1 << 8; mask;) { - s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r'); - s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w'); - s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x'); + s[0] = MY_POSIX_MODE_CHAR(a, mask, 'r'); mask >>= 1; + s[1] = MY_POSIX_MODE_CHAR(a, mask, 'w'); mask >>= 1; + s[2] = MY_POSIX_MODE_CHAR(a, mask, 'x'); mask >>= 1; + s += 3; } - if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID - if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID - if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX - s[10] = 0; + if (a & 0x800) s[-7] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID + if (a & 0x400) s[-4] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID + if (a & 0x200) s[-1] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX + *s = 0; a &= ~(UInt32)0xFFFF; - if (a != 0) + if (a) { - s[10] = ' '; - ConvertUInt32ToHex8Digits(a, s + 11); + *s++ = ' '; + ConvertUInt32ToHex8Digits(a, s); } } diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp index e2f1866..bea31ce 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.cpp +++ b/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -840,13 +840,18 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 in { if (index != (UInt32)(Int32)-1) { + // v26.03: we have no way to convert index_in_server to index_in_ArcItems + // so the code was commented: + /* if (ArcItems) { const CArcItem &ai = (*ArcItems)[index]; s = ai.Name; isDir = ai.IsDir; } - else if (Arc) + else + */ + if (Arc) { RINOK(Arc->GetItem_Path(index, s2)) s = s2; @@ -899,9 +904,13 @@ Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt3 { if (index != (UInt32)(Int32)-1) { + // v26.03: we have no way to convert index_in_server to index_in_ArcItems + /* if (ArcItems) s = (*ArcItems)[index].Name; - else if (Arc) + else + */ + if (Arc) { RINOK(Arc->GetItem_Path(index, s2)) s = s2; diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp index 685ac70..3ba811c 100644 --- a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp +++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp @@ -2,27 +2,6 @@ #include "StdAfx.h" -#ifdef __MINGW32_VERSION -// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10) -// for old mingw -#include -#else -#ifndef Z7_OLD_WIN_SDK - #if !defined(_M_IA64) - #include - #endif -#else -typedef LONG NTSTATUS; -typedef struct _IO_STATUS_BLOCK { - union { - NTSTATUS Status; - PVOID Pointer; - }; - ULONG_PTR Information; -} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; -#endif -#endif - #include "../../../Common/ComTry.h" #include "../../../Common/StringConvert.h" #include "../../../Common/Wildcard.h" @@ -511,13 +490,6 @@ static HRESULT UpdateFile(NFsFolder::CCopyStateIO &state, CFSTR inPath, CFSTR ou EXTERN_C_BEGIN -typedef enum -{ - Z7_WIN_FileRenameInformation = 10 -} -Z7_WIN_FILE_INFORMATION_CLASS; - - typedef struct { // #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1) @@ -534,34 +506,6 @@ typedef struct WCHAR FileName[1]; } Z7_WIN_FILE_RENAME_INFORMATION; -#if (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) -#define Z7_WIN_NTSTATUS NTSTATUS -#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK -#else -typedef LONG Z7_WIN_NTSTATUS; -typedef struct -{ - union - { - Z7_WIN_NTSTATUS Status; - PVOID Pointer; - } DUMMYUNIONNAME; - ULONG_PTR Information; -} Z7_WIN_IO_STATUS_BLOCK; -#endif - -typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)( - HANDLE FileHandle, - Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock, - PVOID FileInformation, - ULONG Length, - Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass); - -// NTAPI -typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status); - -#define MY_STATUS_SUCCESS 0 - EXTERN_C_END // static Func_NtSetInformationFile f_NtSetInformationFile; @@ -572,16 +516,6 @@ Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IPr { const CAltStream &ss = Streams[index]; const FString srcPath = _pathPrefix + us2fs(ss.Name); - - const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); - // if (!g_NtSetInformationFile_WasRequested) { - // g_NtSetInformationFile_WasRequested = true; - const - Func_NtSetInformationFile - f_NtSetInformationFile = Z7_GET_PROC_ADDRESS( - Func_NtSetInformationFile, ntdll, - "NtSetInformationFile"); - if (f_NtSetInformationFile) { NIO::CInFile inFile; if (inFile.Open_for_FileRenameInformation(srcPath)) @@ -599,24 +533,9 @@ Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IPr fri->RootDirectory = NULL; fri->FileNameLength = len; memcpy(fri->FileName, destPath.Ptr(), len); - Z7_WIN_IO_STATUS_BLOCK iosb; - const Z7_WIN_NTSTATUS status = f_NtSetInformationFile (inFile.GetHandle(), - &iosb, fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation); - if (status != MY_STATUS_SUCCESS) - { - const - Func_RtlNtStatusToDosError - f_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS( - Func_RtlNtStatusToDosError, ntdll, - "RtlNtStatusToDosError"); - if (f_RtlNtStatusToDosError) - { - const ULONG res = f_RtlNtStatusToDosError(status); - if (res != ERROR_MR_MID_NOT_FOUND) - return HRESULT_FROM_WIN32(res); - } - } - return status; + const DWORD res = inFile.Call_NtSetInformationFile_return_WinError( + fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation); + return HRESULT_FROM_WIN32(res); } } diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp index fc2fd6c..9351993 100644 --- a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp +++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp @@ -32,6 +32,8 @@ static void DeepCopyFormatEtc(FORMATETC *dest, const FORMATETC *src) if (src->ptd) { dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE)); + if (!dest->ptd) + throw 2026; // CNewException() *(dest->ptd) = *(src->ptd); } } diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp index 51dfaa9..00c9353 100644 --- a/CPP/7zip/UI/FileManager/FSFolder.cpp +++ b/CPP/7zip/UI/FileManager/FSFolder.cpp @@ -45,6 +45,26 @@ typedef struct _IO_STATUS_BLOCK { #include "SysIconUtils.h" +EXTERN_C_BEGIN + +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) +#define Z7_WIN_NTSTATUS NTSTATUS +#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK +#else +typedef LONG Z7_WIN_NTSTATUS; +typedef struct +{ + union + { + Z7_WIN_NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + ULONG_PTR Information; +} Z7_WIN_IO_STATUS_BLOCK; +#endif + +EXTERN_C_END + #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501 #ifdef _APISETFILE_ // Windows SDK 8.1 defines in fileapi.h the function GetCompressedFileSizeW only if _WIN32_WINNT >= 0x0501 @@ -445,46 +465,6 @@ bool CFSFolder::ReadFileInfo(CDirItem &di) EXTERN_C_BEGIN - -typedef struct -{ - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - ULONG FileAttributes; - UInt32 Reserved; // it's expected for alignment -} -Z7_WIN_FILE_BASIC_INFORMATION; - - -typedef enum -{ - Z7_WIN_FileDirectoryInformation = 1, - Z7_WIN_FileFullDirectoryInformation, - Z7_WIN_FileBothDirectoryInformation, - Z7_WIN_FileBasicInformation -} -Z7_WIN_FILE_INFORMATION_CLASS; - - -#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) -#define Z7_WIN_NTSTATUS NTSTATUS -#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK -#else -typedef LONG Z7_WIN_NTSTATUS; -typedef struct -{ - union - { - Z7_WIN_NTSTATUS Status; - PVOID Pointer; - } DUMMYUNIONNAME; - ULONG_PTR Information; -} Z7_WIN_IO_STATUS_BLOCK; -#endif - - typedef Z7_WIN_NTSTATUS (WINAPI * Func_NtQueryInformationFile)( HANDLE handle, Z7_WIN_IO_STATUS_BLOCK *io, void *ptr, LONG len, Z7_WIN_FILE_INFORMATION_CLASS cls); diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp index 9d78368..8a902ef 100644 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -871,27 +871,50 @@ bool CPanel::IsVirus_Message(const UString &name) const wchar_t cRLO = (wchar_t)0x202E; bool isVirus = false; bool isSpaceError = false; - name2 = name; - + { + unsigned numSpaces = 0; + for (unsigned i = 0; i < name.Len(); i++) + { + const wchar_t c = name[i]; + switch (c) + { + case ' ': + case '\t': + case 0x00A0: // Non-Breaking Space + case 0x2002: // En Space + case 0x2003: // Em Space + case 0x2004: // Three-Per-Em Space + case 0x2005: // Four-Per-Em Space + case 0x2006: // Six-Per-Em Space + case 0x2007: // Figure Space + case 0x2008: // Punctuation Space + case 0x2009: // Thin Space + case 0x200A: // Hair Space + case 0x200B: // Zero Width Space + case 0x202F: // Narrow Non-Breaking Space + case 0x205F: // Medium Mathematical Space + case 0x3000: // Ideographic Space + numSpaces++; + break; + default: + numSpaces = 0; + break; + } + if (numSpaces <= 1) + name2 += c; + if (numSpaces >= 5) + { + isVirus = true; + isSpaceError = true; + } + } + } if (name2.Find(cRLO) >= 0) { const UString badString(cRLO); name2.Replace(badString, L"[RLO]"); isVirus = true; } - { - const wchar_t * const kVirusSpaces = L" "; - // const unsigned kNumSpaces = strlen(kVirusSpaces); - for (;;) - { - int pos = name2.Find(kVirusSpaces); - if (pos < 0) - break; - isVirus = true; - isSpaceError = true; - name2.Replace(kVirusSpaces, L" "); - } - } #ifdef _WIN32 { diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp index 868ad22..1bc8174 100644 --- a/CPP/7zip/UI/FileManager/PanelItems.cpp +++ b/CPP/7zip/UI/FileManager/PanelItems.cpp @@ -648,9 +648,28 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) // OutputDebugStringA("S1\n"); - UString correctedName; - UString itemName; - UString relPath; + UString correctedName, itemName, relPath, focusedNamePure, selectedName; + bool needCheckSlash = false; + if (state.FocusedName_Defined) + { + focusedNamePure = state.FocusedName; + const int pos = focusedNamePure.ReverseFind_PathSepar(); + if (pos >= 0) + { + focusedNamePure.DeleteFrontal((unsigned)pos + 1); + needCheckSlash = true; + } + } + if (state.SelectedNames.Size() == 1) + { + selectedName = state.SelectedNames[0]; + const int pos = selectedName.ReverseFind_PathSepar(); + if (pos >= 0) + { + selectedName.DeleteFrontal((unsigned)pos + 1); + needCheckSlash = true; + } + } for (UInt32 i = 0; i < numItems; i++) { @@ -667,8 +686,11 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) } bool selected = false; - - if (state.FocusedName_Defined || !state.SelectedNames.IsEmpty()) + + if (state.SelectedNames.Size() > 1 + || (state.SelectedNames.Size() == 1 && selectedName == name) + || (state.FocusedName_Defined && focusedNamePure == name) + || (needCheckSlash && NWindows::NFile::NName::FindSepar(name) >= 0)) { relPath.Empty(); // relPath += GetItemPrefix(i); @@ -875,10 +897,10 @@ HRESULT CPanel::RefreshListCtrl(const CSelectedState &state) SetFocusedSelectedItem(cursorIndex, state.SelectFocused); Print_OnNotify("after SetFocusedSelectedItem"); - + // OutputDebugStringA("Sort before"); SetSortRawStatus(); _listView.SortItems(CompareItems, (LPARAM)this); - + // OutputDebugStringA("=== Sort after"); Print_OnNotify("after Sort"); if (cursorIndex < 0 && _listView.GetItemCount() > 0) @@ -1089,19 +1111,19 @@ void CPanel::OpenSelectedItems(bool tryInternal) indices.Insert(0, realIndex); } - bool dirIsStarted = false; + // bool dirIsStarted = false; FOR_VECTOR (i, indices) { UInt32 index = indices[i]; // CFileInfo &aFile = m_Files[index]; if (IsItem_Folder(index)) { - if (!dirIsStarted) + // if (!dirIsStarted) { if (tryInternal) { OpenFolder(index); - dirIsStarted = true; + // dirIsStarted = true; break; } else @@ -1162,14 +1184,15 @@ void CPanel::GetItemName(unsigned itemIndex, UString &s) const UString CPanel::GetItemPrefix(unsigned itemIndex) const { - if (itemIndex == kParentIndex) - return UString(); - NCOM::CPropVariant prop; - if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK) - throw 2723400; UString prefix; - if (prop.vt == VT_BSTR) - prefix.SetFromBstr(prop.bstrVal); + if (itemIndex != kParentIndex) + { + NCOM::CPropVariant prop; + if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK) + throw 2723400; + if (prop.vt == VT_BSTR) + prefix.SetFromBstr(prop.bstrVal); + } return prefix; } diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp index e655843..231a68f 100644 --- a/CPP/7zip/UI/FileManager/PanelMenu.cpp +++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp @@ -493,9 +493,11 @@ HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder, HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder, HWND hwnd, const UString &path, LPITEMIDLIST *ppidl) { - ULONG eaten = 0; + // ULONG eaten = 0; return shellFolder->ParseDisplayName(hwnd, NULL, - path.Ptr_non_const(), &eaten, ppidl, NULL); + path.Ptr_non_const(), + NULL, // &eaten + ppidl, NULL); } diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp index 72fe5e7..d342181 100644 --- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp +++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp @@ -25,7 +25,7 @@ CExtToIconMap g_Ext_to_Icon_Map; int Shell_GetFileInfo_SysIconIndex_for_CSIDL(int csidl) { LPITEMIDLIST pidl = NULL; - SHGetSpecialFolderLocation(NULL, csidl, &pidl); + if (SHGetSpecialFolderLocation(NULL, csidl, &pidl) == S_OK) if (pidl) { SHFILEINFO shFileInfo; @@ -333,6 +333,7 @@ int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UStrin HIMAGELIST Shell_Get_SysImageList_smallIcons(bool smallIcons) { SHFILEINFO shFileInfo; + Z7_memset_0_VAR(shFileInfo); // optional // shFileInfo.hIcon = NULL; // optional const DWORD_PTR res = SHGetFileInfo(TEXT(""), /* FILE_ATTRIBUTE_ARCHIVE | */ diff --git a/CPP/Build.mak b/CPP/Build.mak index d9fcfb5..355063b 100644 --- a/CPP/Build.mak +++ b/CPP/Build.mak @@ -63,23 +63,24 @@ COMPL_ASM = $(MY_ML) $** $O/$(*B).obj COMPL_ASM = $(MY_ML) -c -Fo$O/ $** !ENDIF +CFLAGS_c_switch = -c -Fo$O/ + !IFDEF OLD_COMPILER CFLAGS_WARN_LEVEL = -W4 !ELSE +!IF "$(CC)" != "clang-cl" +CFLAGS_WARN_LEVEL = -Wall -analyze +!ELSE +CFLAGS_WARN_LEVEL = -Wall --analyze -Xclang -analyzer-output=text +# CFLAGS_c_switch = +!ENDIF CFLAGS_WARN_LEVEL = -Wall !ENDIF -CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ $(CFLAGS_WARN_LEVEL) -WX -EHsc -Gy -GR- -GF +CFLAGS = $(CFLAGS) -nologo $(CFLAGS_c_switch) $(CFLAGS_WARN_LEVEL) -WX -EHsc -Gy -GR- -GF !IF "$(CC)" == "clang-cl" - -CFLAGS = $(CFLAGS) \ - -Werror \ - -Wall \ - -Wextra \ - -Weverything \ - -Wfatal-errors \ - +CFLAGS = $(CFLAGS) -Werror -Wall -Wextra -Weverything -Wfatal-errors !ENDIF # !IFDEF MY_DYNAMIC_LINK diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h index 7dc21ba..b45530a 100644 --- a/CPP/Common/MyCom.h +++ b/CPP/Common/MyCom.h @@ -688,6 +688,6 @@ EXTERN_C_END Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) \ -#define k_My_HRESULT_WritingWasCut 0x20000010 +#define k_My_HRESULT_WritingWasCut ((HRESULT)0x20000010) #endif diff --git a/CPP/Common/MyVector.h b/CPP/Common/MyVector.h index a772785..c806767 100644 --- a/CPP/Common/MyVector.h +++ b/CPP/Common/MyVector.h @@ -92,6 +92,21 @@ public: _size = newSize; } + void ChangeSize_KeepData_plus_AdditionalReserve(const unsigned newSize) + { + if (newSize > _capacity) + { + if (newSize > k_VectorSizeMax) + throw 2021; + const unsigned rem = k_VectorSizeMax - newSize; + unsigned add = newSize >> 2; + if (add > rem) + add = rem; + ReAllocForNewCapacity(newSize + add); + } + _size = newSize; + } + void ClearAndReserve(unsigned newCapacity) { Clear(); diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index ad0d8c9..bf77c15 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp @@ -34,7 +34,9 @@ using namespace NName; #ifndef _WIN32 -static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) +extern +bool FiTime_To_timespec(const CFiTime *ft, timespec &ts); +bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) { if (ft) { @@ -51,7 +53,7 @@ static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) ts.tv_sec = 0; ts.tv_nsec = #ifdef UTIME_OMIT - UTIME_OMIT; // -2 keep old timesptamp + UTIME_OMIT; // -2 keep old timestamp #else // UTIME_NOW; -1 // set to the current time 0; @@ -170,6 +172,10 @@ bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, con bool SetFileAttrib(CFSTR path, DWORD attrib) { + /* win10: + if (attrib == 0), it sets (FILE_ATTRIBUTE_NORMAL) attribute + (FILE_ATTRIBUTE_DIRECTORY and some another attributes are ignored for files). + */ #ifndef _UNICODE if (!g_IsNT) { @@ -1078,7 +1084,7 @@ static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile, ICopyFileProgress *progres } // There is file IO error or process was interrupted by user. // We close output file and delete it. - // DeleteFileAlways doesn't change errno (if successed), but we restore errno. + // DeleteFileAlways doesn't change errno (if succeed), but we restore errno. const int errno_save = errno; DeleteFileAlways(newFile); errno = errno_save; @@ -1240,26 +1246,34 @@ bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, con } -struct C_umask +C_umask::C_umask() { - mode_t mask; - - C_umask() - { - /* by security reasons we restrict attributes according - with process's file mode creation mask (umask) */ - const mode_t um = umask(0); // octal :0022 is expected - mask = 0777 & (~um); // octal: 0755 is expected - umask(um); // restore the umask - // printf("\n umask = 0%03o mask = 0%03o\n", um, mask); - - // mask = 0777; // debug we can disable the restriction: - } -}; +/* + For security purposes, we restrict the file (mode) attributes + using the process's file mode creation mask (umask). + System's umask is used by open(), mkdir(), and other system calls + that create files to modify the permissions placed on newly + created files or directories. + We use (g_umask.mask) for any function that changes the file's access + mode but is not affected by the system's umask. + We use additional mask restiction 0777 for security purposes. + So we don't create the following mode bits for files and directories: + S_ISUID 04000 set-user-ID bit + S_ISGID 02000 set-group-ID bit + S_ISVTX 01000 sticky bit + system's open(), mkdir() also can have similar 0777 restiction for some cases. +*/ + const mode_t um = umask(0); // um = 0022 (octal) is expected + mask = ~um + & 0777; // 0777 is our additional mode restruction : is secure + // & 07777; // for debug : 07777 to support all mode bits : is not secure + // mask = 07777; // for debug : to restore all mode bits + umask(um); // restore original umask that was changed by umask(0) in code above +} -static C_umask g_umask; +C_umask g_umask; -// #define PRF(x) x; +// #define PRF(x) x #define PRF(x) #define TRACE_SetFileAttrib(msg) \ @@ -1273,12 +1287,17 @@ int my_chown(CFSTR path, uid_t owner, gid_t group) return chown(path, owner, group); } +int my_chown_Link(CFSTR path, uid_t owner, gid_t group) +{ + return lchown(path, owner, group); + // return fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW); +} + bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) { TRACE_SetFileAttrib("") - + mode_t mode; struct stat st; - bool use_lstat = true; if (use_lstat) { @@ -1297,20 +1316,26 @@ bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) return false; } } - + mode = st.st_mode; + if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) { TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION") - st.st_mode = attrib >> 16; - if (S_ISDIR(st.st_mode)) + mode = attrib >> 16; + if (S_ISDIR(mode)) { + if (!S_ISDIR(st.st_mode)) + return true; // user/7z must be able to create files in this directory - st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); + mode |= (S_IRUSR | S_IWUSR | S_IXUSR); + } + else + { + if (!S_ISREG(mode) || !S_ISREG(st.st_mode)) + return true; } - else if (!S_ISREG(st.st_mode)) - return true; } - else if (S_ISLNK(st.st_mode)) + else if (S_ISLNK(mode)) { /* for most systems: permissions for symlinks are fixed to rwxrwxrwx. so we don't need chmod() for symlinks. */ @@ -1322,27 +1347,28 @@ bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) { TRACE_SetFileAttrib("Only Windows Attributes") // Only Windows Attributes - if (S_ISDIR(st.st_mode) + if (S_ISDIR(mode) || (attrib & FILE_ATTRIBUTE_READONLY) == 0) return true; - st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions + mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions } int res; + mode &= g_umask.mask; /* - if (S_ISLNK(st.st_mode)) + if (S_ISLNK(mode)) { printf("\nfchmodat()\n"); - TRACE_chmod(path, (st.st_mode) & g_umask.mask) - // AT_SYMLINK_NOFOLLOW is not implemted still in Linux. - res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask, - S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0); + TRACE_chmod(path, (mode)) + // AT_SYMLINK_NOFOLLOW is not implemented still in Linux. + res = fchmodat(AT_FDCWD, path, (mode), + S_ISLNK(mode) ? AT_SYMLINK_NOFOLLOW : 0); } else */ { - TRACE_chmod(path, (st.st_mode) & g_umask.mask) - res = chmod(path, (st.st_mode) & g_umask.mask); + TRACE_chmod(path, mode) + res = chmod(path, mode); } // TRACE_SetFileAttrib("End") return (res == 0); diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h index 9ba98fc..e8d9d31 100644 --- a/CPP/Windows/FileDir.h +++ b/CPP/Windows/FileDir.h @@ -46,6 +46,7 @@ bool SetFileAttrib(CFSTR path, DWORD attrib); #else int my_chown(CFSTR path, uid_t owner, gid_t group); +int my_chown_Link(CFSTR path, uid_t owner, gid_t group); #endif diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp index dc4de14..8be06fc 100644 --- a/CPP/Windows/FileIO.cpp +++ b/CPP/Windows/FileIO.cpp @@ -6,6 +6,29 @@ #include "../../C/Alloc.h" #endif +#ifdef _WIN32 +#ifdef __MINGW32_VERSION +// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10) +// for old mingw +#include +#else +#ifndef Z7_OLD_WIN_SDK + #if !defined(_M_IA64) + #include + #endif +#else +typedef LONG NTSTATUS; +typedef struct _IO_STATUS_BLOCK { + union { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +#endif +#endif +#endif // _WIN32 + // #include /* @@ -33,6 +56,48 @@ HRESULT GetLastError_noZero_HRESULT() extern bool g_IsNT; #endif +#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64) +#define Z7_WIN_NTSTATUS NTSTATUS +#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK +#else +typedef LONG Z7_WIN_NTSTATUS; +typedef struct +{ + union + { + Z7_WIN_NTSTATUS Status; + PVOID Pointer; + } DUMMYUNIONNAME; + ULONG_PTR Information; +} Z7_WIN_IO_STATUS_BLOCK; +#endif + +typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)( + HANDLE FileHandle, + Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock, + PVOID FileInformation, + ULONG Length, + Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass); +// NTAPI +typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status); + +Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +static Func_NtSetInformationFile g_NtSetInformationFile; +static Func_RtlNtStatusToDosError g_RtlNtStatusToDosError; +static struct C_Init_NtSetInformationFile +{ + C_Init_NtSetInformationFile() + { + const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); + g_NtSetInformationFile = Z7_GET_PROC_ADDRESS( + Func_NtSetInformationFile, ntdll, + "NtSetInformationFile"); + g_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS( + Func_RtlNtStatusToDosError, ntdll, + "RtlNtStatusToDosError"); + } +} g_C_Init_NtSetInformationFile; + using namespace NWindows; using namespace NFile; using namespace NName; @@ -353,7 +418,7 @@ void CInFile::CalcDeviceSize(CFSTR s) WinXP 64-bit: HDD \\.\PhysicalDrive0 (MBR): - GetPartitionInfo == GeometryEx : corrrect size? (includes tail) + GetPartitionInfo == GeometryEx : correct size? (includes tail) Geometry : smaller than GeometryEx (no tail, maybe correct too?) MyGetDiskFreeSpace : FAIL Size correction is slow and block size (kClusterSize) must be small? @@ -365,8 +430,8 @@ void CInFile::CalcDeviceSize(CFSTR s) CD-ROM drive (ISO): MyGetDiskFreeSpace : correct size. Same size can be calculated after correction - Geometry == CdRomGeometry : smaller than corrrect size - GetPartitionInfo == GeometryEx : larger than corrrect size + Geometry == CdRomGeometry : smaller than correct size + GetPartitionInfo == GeometryEx : larger than correct size Floppy \\.\a: (FAT): Geometry : correct size. @@ -539,6 +604,70 @@ bool COutFile::Open_Disposition(CFSTR fileName, DWORD creationDisposition) bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes) { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); } +DWORD CFileBase::Call_NtSetInformationFile_return_WinError( + void *data, ULONG len, Z7_WIN_FILE_INFORMATION_CLASS fileInformationClass) const +{ + if (!g_NtSetInformationFile) + return ERROR_PROC_NOT_FOUND; + Z7_WIN_IO_STATUS_BLOCK ioStatus; + Z7_memset_0_VAR(ioStatus); // optional + const Z7_WIN_NTSTATUS status = g_NtSetInformationFile(_handle, + &ioStatus, data, len, fileInformationClass); + if (status == 0) // MY_STATUS_SUCCESS + return 0; + if (g_RtlNtStatusToDosError) + { + const ULONG res = g_RtlNtStatusToDosError(status); + if (res != ERROR_MR_MID_NOT_FOUND) + return res; + } + return 1; +} + + +#define SET_TIME_FIELD_IF_DEFINED(dest, src) \ +{ if (src) { \ + dest.LowPart = (src)->dwLowDateTime; \ + dest.HighPart = (LONG)(src)->dwHighDateTime; \ + } \ +} + +bool COutFile::Set_Time_and_WinAttrib(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime, DWORD attrib) throw() +{ +#ifdef _WIN32 + // similar to GetAttrib_PosixHighDetect(attrib) + if (attrib & 0xF0000000) + attrib &= 0x3FFF; +#endif + + Z7_WIN_FILE_BASIC_INFORMATION fbi; + Z7_memset_0_VAR(fbi); + SET_TIME_FIELD_IF_DEFINED (fbi.CreationTime, cTime) + SET_TIME_FIELD_IF_DEFINED (fbi.LastAccessTime, aTime) + SET_TIME_FIELD_IF_DEFINED (fbi.LastWriteTime, mTime) + // fbi.ChangeTime.QuadPart = 0; + /* + if (attrib == 0) + { win10: NtSetInformationFile() doesn't change file attribute + if (attrib & FILE_ATTRIBUTE_DIRECTORY) + { win10: NtSetInformationFile() returns (STATUS_INVALID_PARAMETER) } + we provide similar attribute processing as + SetFileAttributes(): + - we ignore (FILE_ATTRIBUTE_DIRECTORY) + - we write (FILE_ATTRIBUTE_NORMAL) instead of (0) + */ + attrib &= ~(DWORD)FILE_ATTRIBUTE_DIRECTORY; + if (attrib == 0) + attrib = FILE_ATTRIBUTE_NORMAL; + fbi.FileAttributes = attrib; + const DWORD wres = Call_NtSetInformationFile_return_WinError( + &fbi, sizeof(fbi), Z7_WIN_FileBasicInformation); + if (wres == 0) + return true; + SetLastError(wres); + return false; +} + bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); } @@ -628,10 +757,16 @@ bool COutFile::SetLength_KeepPosition(UInt64 length) throw() #include #include +extern +bool FiTime_To_timespec(const CFiTime *ft, timespec &ts); + namespace NWindows { namespace NFile { namespace NDir { + +extern C_umask g_umask; + bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); } @@ -644,6 +779,34 @@ bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode) #endif Close(); + /* + The mode argument specifies the file mode bits to be + applied when a new file is created. If neither O_CREAT nor + O_TMPFILE is specified in flags, then mode is ignored (and + can thus be specified as 0, or simply omitted). + + The effective mode is modified by the process's umask in + the usual way: in the absence of a default ACL, the mode of + the created file is (mode & ~umask). + + Note that mode applies only to future accesses of the newly + created file; the open() call that creates a read-only file + may well return a read/write file descriptor. + + POSIX: if other bits (~0777) are set in mode : the effect is unspecified + Linux: + S_ISUID 04000 set-user-ID bit + S_ISGID 02000 set-group-ID bit + S_ISVTX 01000 sticky bit + + S_ISVTX can be set, but it's useless for file in modern linux. + by security reasons: + open() ignores S_ISUID + open() ignores S_ISGID, if S_IXGRP is set. + */ + // mode |= S_ISUID | S_ISGID | S_ISVTX; // for debug + // printf("\n open() mode=%o\n", (unsigned)(mode)); + _handle = ::open(name, flags, mode); return _handle != -1; @@ -740,7 +903,7 @@ bool CFileBase::SeekToBegin() const throw() bool CInFile::Open(const char *name) { - return CFileBase::OpenBinary(name, O_RDONLY); + return CFileBase::OpenBinary(name, O_RDONLY, k_OutFile_mode_default); } bool CInFile::OpenShared(const char *name, bool) @@ -903,11 +1066,64 @@ bool COutFile::SetLength(UInt64 length) throw() return (iret == 0); } +// #define PRF(x) x +#define PRF(x) + bool COutFile::Close() { - const bool res = CFileBase::Close(); - if (!res) - return res; + bool res = true; + if (_handle == -1) + return true; + { + // bool res2 = true; + if (mode_for_Close_defined) + { + PRF(printf("\n COutFile::Close() mode=%o\n", (unsigned)(mode_for_Close));) + // fchmod() function ignores the file creation mask set by umask() + // so we can restore any of (07777) mode bits + // mode_for_Close |= (0xffff << 12); // for debug + if (fchmod(_handle, mode_for_Close) == 0) + { + mode_for_Close_defined = false; + PRF(printf("\n COutFile::Close() fchmod() == 0\n");) + } + // else res2 = false; + } + { + if (MTime_defined || ATime_defined) + { + struct timespec times[2]; + FiTime_To_timespec(ATime_defined ? &ATime : NULL, times[0]); + FiTime_To_timespec(MTime_defined ? &MTime : NULL, times[1]); + // futimens : POSIX.1-2008 + if (futimens(_handle, times) == 0) + { + PRF(printf("\n futimens() OK \n");) + ATime_defined = false; + MTime_defined = false; + } + else + { + PRF(printf("\n futimens() ERROR: %d=%s\n", errno, strerror(errno));) + } + } + } + res = CFileBase::Close(); + if (!res) + return res; + // res = res2; + } + if (mode_for_Close_defined) + { + // chmod() ignores the file creation mask set by umask() + // so we can restore any of (07777) mode bits + // const int res_chmod = + chmod(Path, mode_for_Close); + mode_for_Close_defined = false; + // if (res_chmod != 0 && res == true) res = false; + // PRF(printf("\n COutFile::Close() chmod res=%d\n", (int)res_chmod);) + } + if (CTime_defined || ATime_defined || MTime_defined) { /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, @@ -942,6 +1158,24 @@ bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime */ } +bool COutFile::Set_Time_and_WinAttrib( + const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD attrib) throw() +{ + PRF(printf("\n Set_Time_and_WinAttrib() mode=%o\n", (unsigned)(attrib >> 16));) + SetTime(cTime, aTime, mTime); + // we will use fchmod() or chmod() later in Close() fucntion. + // fchmod() or chmod() are not limited by system umask. + // but for security reasons we use the system mask (g_umask.mask) derived from umask(). + mode_t mode = k_OutFile_mode_default; // 0666 + if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) + mode = (attrib >> 16); + else if (attrib & FILE_ATTRIBUTE_READONLY) + mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions + mode_for_Close = mode & NDir::g_umask.mask; + mode_for_Close_defined = true; + return true; +} + bool COutFile::SetMTime(const CFiTime *mTime) throw() { if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h index a202df5..9c32137 100644 --- a/CPP/Windows/FileIO.h +++ b/CPP/Windows/FileIO.h @@ -19,6 +19,27 @@ #include #endif +typedef enum +{ + Z7_WIN_FileDirectoryInformation = 1, + Z7_WIN_FileFullDirectoryInformation, + Z7_WIN_FileBothDirectoryInformation, + Z7_WIN_FileBasicInformation, + Z7_WIN_FileRenameInformation = 10 +} Z7_WIN_FILE_INFORMATION_CLASS; + +// FILE_BASIC_INFORMATION / FILE_BASIC_INFO +typedef struct +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; + ULONG Reserved; // it's expected dummy variable for alignment : optional +} +Z7_WIN_FILE_BASIC_INFORMATION; + #else #include @@ -205,6 +226,9 @@ public: return false; return file.GetFileInformation(info); } + + DWORD Call_NtSetInformationFile_return_WinError(void *data, ULONG len, + Z7_WIN_FILE_INFORMATION_CLASS fileInformationClass) const; }; #ifndef UNDER_CE @@ -323,6 +347,8 @@ public: bool Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes); + bool Set_Time_and_WinAttrib(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD attrib) throw(); + bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); bool SetMTime(const CFiTime *mTime) throw(); bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); @@ -338,6 +364,15 @@ public: #else // _WIN32 +namespace NDir { +struct C_umask +{ + mode_t mask; + C_umask(); +}; +extern C_umask g_umask; +} + namespace NIO { bool GetReparseData(CFSTR path, CByteBuffer &reparseData); @@ -347,6 +382,7 @@ bool GetReparseData(CFSTR path, CByteBuffer &reparseData); bool SetSymLink(CFSTR from, CFSTR to); bool SetSymLink_UString(CFSTR from, const UString &to); +const mode_t k_OutFile_mode_default = 0666; class CFileBase { @@ -359,7 +395,7 @@ protected: UInt64 Size; // it can be larger than real available size */ - bool OpenBinary(const char *name, int flags, mode_t mode = 0666); + bool OpenBinary(const char *name, int flags, mode_t mode /* = k_OutFile_mode_default */); public: bool PreserveATime; #if 0 @@ -411,9 +447,11 @@ class COutFile: public CFileBase bool CTime_defined; bool ATime_defined; bool MTime_defined; + bool mode_for_Close_defined; CFiTime CTime; CFiTime ATime; CFiTime MTime; + mode_t mode_for_Close; AString Path; ssize_t write_part(const void *data, size_t size) throw(); @@ -425,9 +463,11 @@ public: CTime_defined(false), ATime_defined(false), MTime_defined(false), - mode_for_Create(0666) + mode_for_Close_defined(false), + mode_for_Create(k_OutFile_mode_default) // 0666 {} + ~COutFile() { Close(); } bool Close(); bool Open_EXISTING(CFSTR fileName); @@ -454,6 +494,7 @@ public: return SetLength(length); } bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); + bool Set_Time_and_WinAttrib(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD attrib) throw(); bool SetMTime(const CFiTime *mTime) throw(); }; diff --git a/DOC/7zC.txt b/DOC/7zC.txt index 939b720..8c76b94 100644 --- a/DOC/7zC.txt +++ b/DOC/7zC.txt @@ -165,8 +165,8 @@ Memory usage for archive Decompressing: - Memory for LZMA decompressing structures - Main pool: - Memory for decompressed solid block - - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these - temprorary buffers can be about 15% of solid block size. + - Memory for temporary buffers, if BCJ2 filter is used. Usually these + temporary buffers can be about 15% of solid block size. 7z Decoder doesn't allocate memory for compressed blocks. diff --git a/DOC/7zFormat.txt b/DOC/7zFormat.txt index 74cdfa4..0347196 100644 --- a/DOC/7zFormat.txt +++ b/DOC/7zFormat.txt @@ -398,7 +398,7 @@ FilesInfo if(External != 0) UINT64 DataIndex [] - for(Definded Items) + for(Defined Items) REAL_UINT64 Time [] @@ -425,7 +425,7 @@ FilesInfo if(External != 0) UINT64 DataIndex [] - for(Definded Attributes) + for(Defined Attributes) UINT32 Attributes [] } diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index 44e71e1..2ddcfb7 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs @@ -1,7 +1,7 @@ - + diff --git a/DOC/Methods.txt b/DOC/Methods.txt index 3e5707c..cd5fa04 100644 --- a/DOC/Methods.txt +++ b/DOC/Methods.txt @@ -137,7 +137,7 @@ List of defined IDs 05 - LZ5 06 - LIZARD - 12 xx - reserverd (Denis Anisimov) + 12 xx - reserved (Denis Anisimov) 01 - WavPack2 FE - eSplitter diff --git a/DOC/readme.txt b/DOC/readme.txt index fd01e3b..dd2171f 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt @@ -1,4 +1,4 @@ -7-Zip 26.02 Sources +7-Zip 26.03 Sources ------------------- 7-Zip is a file archiver for Windows. @@ -12,7 +12,7 @@ License Info 7-Zip is free software distributed under the GNU LGPL (except for unRar code). Also some code is licensed under the "BSD 3-clause License". -Read "License.txt" for more infomation about license. +Read "License.txt" for more information about license. Notes about unRAR license: @@ -111,8 +111,8 @@ Compiling 7-Zip for Unix/Linux ------------------------------ There are several options to compile 7-Zip with different compilers: gcc and clang. -Also 7-Zip code contains two versions for some parts of code: in C and in Assembeler. -So if you compile the version with Assembeler code, you will get faster 7-Zip binary. +Also 7-Zip code contains two versions for some parts of code: in C and in Assembler. +So if you compile the version with Assembler code, you will get faster 7-Zip binary. 7-Zip's assembler code uses the following syntax for different platforms: @@ -144,7 +144,7 @@ Then you can compile `makefile.gcc` with the command: make -j -f makefile.gcc Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile -7-Zip binaries with optimized code and optimzing options. +7-Zip binaries with optimized code and optimizing options. To compile with GCC without assembler: cd CPP/7zip/Bundles/Alone2 diff --git a/DOC/src-history.txt b/DOC/src-history.txt index 7858175..717cf91 100644 --- a/DOC/src-history.txt +++ b/DOC/src-history.txt @@ -1,9 +1,17 @@ HISTORY of the 7-Zip source code -------------------------------- +26.03 2026-09-03 +------------------------- +- Improved support for Joliet ISO images and Compound archives. +- Some bugs and vulnerabilities were fixed. +- CVE-2026-58052 : 7-Zip failed to preserve the Mark-of-the-Web when extracting a crafted archive. + + 26.02 2026-06-25 ------------------------- - Some bugs and vulnerabilities were fixed. +- CVE-2026-14266 : XZ Decompression Heap-based Buffer Overflow Remote Code Execution. 26.01 2026-04-27 @@ -19,7 +27,15 @@ HISTORY of the 7-Zip source code to form the final path to the output directory. -spor : 7-Zip will replace asterisk (*) character in the path specified in the -o{dir_path} with the archive name. This is the default option. -- some bugs were fixed. +- Some bugs and vulnerabilities were fixed. +- CVE-2026-48092 : A heap memory disclosure via SquashFS fragment offset integer overflow on 32-bit builds. +- CVE-2026-48095 : A heap buffer overflow in the NTFS archive handler. +- CVE-2026-48101 : An uninitialized memory disclosure vulnerability in the UEFI archive handler. +- CVE-2026-48102 : A heap out-of-bounds read in the UDF archive handler. +- CVE-2026-48103 : A heap out-of-bounds read in the WIM archive handler. +- CVE-2026-48104 : An uninitialized heap read in the SquashFS archive handler. +- CVE-2026-48111 : An out-of-bounds read vulnerability UEFI archive handler. +- CVE-2026-48112 : A heap out-of-bounds read in 7-Zip Ar archive handler. 26.00 2026-02-12 @@ -145,7 +161,7 @@ HISTORY of the 7-Zip source code - 7-Zip now can unpack ZIP and SquashFS archives that use ZSTD compression method. - 7-Zip now supports fast hash algorithm XXH64 that is used in ZSTD. - Speed optimizations for archive unpacking: rar, zip, gz, wim, cab. -- Speed optimizations for hash caclulation: CRC-32, CRC-64, Blake2sp. +- Speed optimizations for hash calculation: CRC-32, CRC-64, Blake2sp. - The bug was fixed: 7-Zip for Linux could fail for multivolume creation in some cases. - Some bugs were fixed. @@ -164,7 +180,7 @@ HISTORY of the 7-Zip source code // virtual ~IUnknown() {} So 7-Zip's dynamically linked shared libraries (codecs) are not compatible between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip). -- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers. +- Some optimizations in filters code: BCJ, BCJ2, Swap* and others. - If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp files in system's TEMP folder. 7-Zip uses temp file for additional compressed data stream, if size of such compressed stream is larger than predefined limit: @@ -419,7 +435,7 @@ HISTORY of the 7-Zip source code 9.09 2009-12-12 ------------------------- - The bug was fixed: - Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c + Utf16_To_Utf8 functions in UTFConvert.cpp and 7zMain.c incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8. @@ -457,7 +473,7 @@ HISTORY of the 7-Zip source code ------------------------- - BUGS was fixed: 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases. - 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties. + 7zIn.cpp: 7-Zip incorrectly work with archive, containing archive properties. 4.58 alpha 9 2008-04-29 ------------------------- @@ -513,7 +529,7 @@ HISTORY of the 7-Zip source code - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF. - ZIP name updating: If zip file contains extra field and you try to change properties of files, - 7-zip tries to delete all extra fileds (except for WzAES). + 7-zip tries to delete all extra fields (except for WzAES). And that code could hang. - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run. - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp @@ -581,7 +597,7 @@ HISTORY of the 7-Zip source code data++ fixed version: data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1; - It could lead to very small cpmpression ratio decreasing when block needs move. + It could lead to very small compression ratio decreasing when block needs move. 4.30 beta 2005-11-18 @@ -606,7 +622,7 @@ HISTORY of the 7-Zip source code 4.25 beta 2005-07-31 ------------------------- -- More 64-bit compatibilty +- More 64-bit compatibility 4.24 beta 2005-07-06 @@ -628,7 +644,7 @@ HISTORY of the 7-Zip source code 4.14 beta 2005-01-11 ------------------------- - STL using was reduced -- 7za now supports Split(001) archves +- 7za now supports Split(001) archives 4.10 beta 2004-10-21 @@ -746,7 +762,7 @@ HISTORY of the 7-Zip source code - SDK/Stream/WindowOut.h now it uses only required memory (dictionary size). - Project/Archiver/Resource - contains common resurces + contains common resources 2.30 Beta 19 2002-04-11 @@ -766,7 +782,7 @@ HISTORY of the 7-Zip source code 2.30 Beta 17 2002-03-03 ------------------------- -- ARJ suppport. +- ARJ support. 2.30 Beta 16 2002-02-24 @@ -824,14 +840,14 @@ HISTORY of the 7-Zip source code Compress/LZ/MatchFinder/Patricia.h: Compress/PPM/PPMd/SubAlloc.h: using VirtualAlloc for memory allocating -- Exlorer/ContextMenu.cpp: +- Explorer/ContextMenu.cpp: Testing supporting. CreateProcess instead WinExec - Format/Common/IArchiveHandler.h: - Exlorer/ProxyHandler.cpp: + Explorer/ProxyHandler.cpp: FAR/Plugin.cpp: New properties names: Method, HostOS. -- Exlorer/OverwriteDialog.cpp: +- Explorer/OverwriteDialog.cpp: FAR/OverwriteDialog.cpp: Windows/PropVariantConversions.h Using National time format was eliminated. @@ -840,16 +856,16 @@ HISTORY of the 7-Zip source code 2.30 Beta 10 2002-01-11 ------------------------- -- Exlorer/ContextMenu.cpp: bug with context menu on +- Explorer/ContextMenu.cpp: bug with context menu on Windows NT4 in Unicode version was fixed. - Format/7z/UpdateArchiveEngine.cpp: bug was fixed - Updating in Beta 8 and 9 didn't work. -- Exlorer/CCompressDialog.cpp: history growing bug was fixed. +- Explorer/CCompressDialog.cpp: history growing bug was fixed. 2.30 Beta 9 2002-01-08 ------------------------- -- SDK/Common/Vector.h: sopporting sorted object vectors . +- SDK/Common/Vector.h: supporting sorted object vectors . - Lang features. - Two new match finders: pat3h and pat4h. - SDK/Archive/Zip/InEngine.cpp: bug was fixed. -- cgit v1.2.3-55-g6feb