diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2018-01-12 00:16:32 +0300 |
---|---|---|
committer | Kornel <kornel@geekhood.net> | 2018-01-12 00:16:32 +0300 |
commit | da28077952faf9e716ed7987b842d31617a10125 (patch) | |
tree | 5903be6aa5f1405d54028cec42432c46df818af5 | |
parent | b5dc853b2496447f0a54b3b25cb2659b575c56ef (diff) |
18.0018.00
44 files changed, 852 insertions, 365 deletions
diff --git a/C/7zVersion.h b/C/7zVersion.h index a0f56279..5e17019a 100644 --- a/C/7zVersion.h +++ b/C/7zVersion.h @@ -1,7 +1,7 @@ -#define MY_VER_MAJOR 17 -#define MY_VER_MINOR 01 +#define MY_VER_MAJOR 18 +#define MY_VER_MINOR 00 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "17.01 beta" +#define MY_VERSION_NUMBERS "18.00 beta" #define MY_VERSION MY_VERSION_NUMBERS #ifdef MY_CPU_NAME @@ -10,12 +10,12 @@ #define MY_VERSION_CPU MY_VERSION #endif -#define MY_DATE "2017-08-28" +#define MY_DATE "2018-01-10" #undef MY_COPYRIGHT #undef MY_VERSION_COPYRIGHT_DATE #define MY_AUTHOR_NAME "Igor Pavlov" #define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" -#define MY_COPYRIGHT_CR "Copyright (c) 1999-2017 Igor Pavlov" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2018 Igor Pavlov" #ifdef USE_COPYRIGHT_CR #define MY_COPYRIGHT MY_COPYRIGHT_CR @@ -377,11 +377,17 @@ static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size) static void SeqInFilter_Construct(CSeqInFilter *p) { p->buf = NULL; + p->StateCoder.p = NULL; p->p.Read = SeqInFilter_Read; } static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) { + if (p->StateCoder.p) + { + p->StateCoder.Free(p->StateCoder.p, alloc); + p->StateCoder.p = NULL; + } if (p->buf) { ISzAlloc_Free(alloc, p->buf); diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index 65be1146..b0bfb164 100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -180,7 +180,7 @@ UInt32 CInArchive::ReadDigits(int numDigits) Byte b = ReadByte(); if (b < '0' || b > '9') { - if (b == 0) // it's bug in some CD's + if (b == 0 || b == ' ') // it's bug in some CD's b = '0'; else throw CHeaderErrorException(); diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp index 30a60843..4edaa918 100644 --- a/CPP/7zip/Archive/PeHandler.cpp +++ b/CPP/7zip/Archive/PeHandler.cpp @@ -109,7 +109,8 @@ void CVersion::ToProp(NCOM::CPropVariant &prop) prop = sz; } -static const unsigned kHeaderSize = 4 + 20; +static const unsigned kCoffHeaderSize = 20; +static const unsigned kPeHeaderSize = 4 + kCoffHeaderSize; static const unsigned k_OptHeader32_Size_MIN = 96; static const unsigned k_OptHeader64_Size_MIN = 112; @@ -125,15 +126,14 @@ struct CHeader UInt16 OptHeaderSize; UInt16 Flags; - bool Parse(const Byte *p); + void ParseBase(const Byte *p); + bool ParseCoff(const Byte *p); + bool ParsePe(const Byte *p); bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; } }; -bool CHeader::Parse(const Byte *p) +void CHeader::ParseBase(const Byte *p) { - if (Get32(p) != k_Signature32) - return false; - p += 4; G16( 0, Machine); G16( 2, NumSections); G32( 4, Time); @@ -141,6 +141,13 @@ bool CHeader::Parse(const Byte *p) G32(12, NumSymbols); G16(16, OptHeaderSize); G16(18, Flags); +} + +bool CHeader::ParsePe(const Byte *p) +{ + if (Get32(p) != k_Signature32) + return false; + ParseBase(p + 4); return OptHeaderSize >= k_OptHeader32_Size_MIN; } @@ -399,39 +406,67 @@ static const CUInt32PCharPair g_HeaderCharacts[] = { 15, "Big-Endian" } }; -static const CUInt32PCharPair g_DllCharacts[] = -{ - { 5, "HighEntropyVA" }, - { 6, "Relocated" }, - { 7, "Integrity" }, - { 8, "NX-Compatible" }, - { 9, "NoIsolation" }, - { 10, "NoSEH" }, - { 11, "NoBind" }, - { 12, "AppContainer" }, - { 13, "WDM" }, - { 14, "GuardCF" }, - { 15, "TerminalServerAware" } + + +// IMAGE_DLLCHARACTERISTICS_* constants + +static const char * const g_DllCharacts[] = +{ + NULL + , NULL + , NULL + , NULL + , NULL + , "HighEntropyVA" + , "Relocated" + , "Integrity" + , "NX-Compatible" + , "NoIsolation" + , "NoSEH" + , "NoBind" + , "AppContainer" + , "WDM" + , "GuardCF" + , "TerminalServerAware" }; -static const CUInt32PCharPair g_SectFlags[] = -{ - { 3, "NoPad" }, - { 5, "Code" }, - { 6, "InitializedData" }, - { 7, "UninitializedData" }, - { 9, "Comments" }, - { 11, "Remove" }, - { 12, "COMDAT" }, - { 15, "GP" }, - { 24, "ExtendedRelocations" }, - { 25, "Discardable" }, - { 26, "NotCached" }, - { 27, "NotPaged" }, - { 28, "Shared" }, - { 29, "Execute" }, - { 30, "Read" }, - { 31, "Write" } + +// IMAGE_SCN_* constants: + +static const char * const g_SectFlags[] = +{ + NULL + , NULL + , NULL + , "NoPad" + , NULL + , "Code" + , "InitializedData" + , "UninitializedData" + , "Other" + , "Comments" + , NULL // OVER + , "Remove" + , "COMDAT" + , NULL + , "NO_DEFER_SPEC_EXC" + , "GP" // MEM_FARDATA + , NULL // SYSHEAP + , "PURGEABLE" // 16BIT + , "LOCKED" + , "PRELOAD" + , NULL + , NULL + , NULL + , NULL + , "ExtendedRelocations" + , "Discardable" + , "NotCached" + , "NotPaged" + , "Shared" + , "Execute" + , "Read" + , "Write" }; static const CUInt32PCharPair g_MachinePairs[] = @@ -699,7 +734,6 @@ class CHandler: { CMyComPtr<IInStream> _stream; CObjectVector<CSection> _sections; - UInt32 _peOffset; CHeader _header; UInt32 _totalSize; Int32 _mainSubfile; @@ -720,9 +754,12 @@ class CHandler: bool _parseResources; bool _checksumError; + bool IsOpt() const { return _header.OptHeaderSize != 0; } + COptHeader _optHeader; bool _allowTail; + bool _coffMode; HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection); HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); @@ -742,7 +779,10 @@ class CHandler: } public: - CHandler(): _allowTail(false) {} + CHandler(bool coffMode = false): + _coffMode(coffMode), + _allowTail(coffMode) + {} MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IArchiveAllowTail) INTERFACE_IInArchive(;) @@ -841,6 +881,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) NCOM::CPropVariant prop; switch (propID) { + case kpidPhySize: prop = _totalSize; break; + case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break; + case kpidShortComment: + if (!_versionShortString.IsEmpty()) + prop = _versionShortString; + else + { + PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); + } + break; + + case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break; + + // case kpidIsSelfExe: prop = !_header.IsDll(); break; + // case kpidError: + case kpidWarning: if (_checksumError) prop = "Checksum error"; break; + + case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break; + case kpidMTime: + case kpidCTime: TimeToProp(_header.Time, prop); break; + case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break; + case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + + default: + if (IsOpt()) + switch (propID) + { + case kpidSectAlign: prop = _optHeader.SectAlign; break; case kpidFileAlign: prop = _optHeader.FileAlign; break; case kpidLinkerVer: @@ -857,37 +925,17 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidInitDataSize: prop = _optHeader.InitDataSize; break; case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break; case kpidImageSize: prop = _optHeader.ImageSize; break; - case kpidPhySize: prop = _totalSize; break; case kpidHeadersSize: prop = _optHeader.HeadersSize; break; case kpidChecksum: prop = _optHeader.CheckSum; break; - case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break; - case kpidShortComment: - if (!_versionShortString.IsEmpty()) - prop = _versionShortString; - else - { - PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); - } - break; - case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break; case kpidExtension: if (_header.IsDll()) prop = _optHeader.IsSybSystem_EFI() ? "efi" : "dll"; break; - - // case kpidIsSelfExe: prop = !_header.IsDll(); break; - // case kpidError: - case kpidWarning: if (_checksumError) prop = "Checksum error"; break; - - case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break; case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break; case kpidSubSystem: TYPE_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break; - case kpidMTime: - case kpidCTime: TimeToProp(_header.Time, prop); break; - case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break; case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break; case kpidStackReserve: prop = _optHeader.StackReserve; break; case kpidStackCommit: prop = _optHeader.StackCommit; break; @@ -898,8 +946,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break; // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break; // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break; - - case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break; + } } prop.Detach(value); return S_OK; @@ -1056,7 +1103,24 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val case kpidMTime: case kpidCTime: TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break; - case kpidCharacts: if (item.IsRealSect) FLAGS_TO_PROP(g_SectFlags, item.Flags, prop); break; + case kpidCharacts: + if (item.IsRealSect) + { + UInt32 flags = item.Flags; + const UInt32 MY__IMAGE_SCN_ALIGN_MASK = 0x00F00000; + AString s = FlagsToString(g_SectFlags, ARRAY_SIZE(g_SectFlags), item.Flags & ~MY__IMAGE_SCN_ALIGN_MASK); + const UInt32 align = ((flags >> 20) & 0xF); + if (align != 0) + { + char sz[32]; + ConvertUInt32ToString(1 << (align - 1), sz); + s.Add_Space(); + s += "align_"; + s += sz; + } + prop = s; + } + break; case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break; } } @@ -2114,6 +2178,23 @@ HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchi return S_OK; } + +bool CHeader::ParseCoff(const Byte *p) +{ + ParseBase(p); + if (PointerToSymbolTable < kCoffHeaderSize) + return false; + if (NumSymbols >= (1 << 24)) + return false; + if (OptHeaderSize != 0 && OptHeaderSize < k_OptHeader32_Size_MIN) + return false; + for (unsigned i = 0; i < ARRAY_SIZE(g_MachinePairs); i++) + if (Machine == g_MachinePairs[i].Value) + return true; + return false; +} + + static inline bool CheckPeOffset(UInt32 pe) { // ((pe & 7) == 0) is for most PE files. But there is unusual EFI-PE file that uses unaligned pe value. @@ -2133,10 +2214,10 @@ API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size) UInt32 pe = Get32(p + 0x3C); if (!CheckPeOffset(pe)) return k_IsArc_Res_NO; - if (pe + kHeaderSize > size) + if (pe + kPeHeaderSize > size) return k_IsArc_Res_NEED_MORE; CHeader header; - if (!header.Parse(p + pe)) + if (!header.ParsePe(p + pe)) return k_IsArc_Res_NO; return k_IsArc_Res_YES; } @@ -2144,32 +2225,47 @@ API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size) HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) { + UInt32 coffOffset = 0; + if (_coffMode) { - Byte h[kStartSize]; - _mainSubfile = -1; - RINOK(ReadStream_FALSE(stream, h, kStartSize)); - if (h[0] != 'M' || h[1] != 'Z') - return S_FALSE; - /* most of PE files contain 0x0090 at offset 2. - But some rare PE files contain another values. So we don't use that check. - if (Get16(h + 2) != 0x90) return false; */ - _peOffset = Get32(h + 0x3C); - if (!CheckPeOffset(_peOffset)) + Byte h[kCoffHeaderSize]; + RINOK(ReadStream_FALSE(stream, h, kCoffHeaderSize)); + if (!_header.ParseCoff(h)) return S_FALSE; } + else { - Byte h[kHeaderSize]; - RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL)); - RINOK(ReadStream_FALSE(stream, h, kHeaderSize)); - if (!_header.Parse(h)) - return S_FALSE; + UInt32 _peOffset; + { + Byte h[kStartSize]; + RINOK(ReadStream_FALSE(stream, h, kStartSize)); + if (h[0] != 'M' || h[1] != 'Z') + return S_FALSE; + /* most of PE files contain 0x0090 at offset 2. + But some rare PE files contain another values. So we don't use that check. + if (Get16(h + 2) != 0x90) return false; */ + _peOffset = Get32(h + 0x3C); + if (!CheckPeOffset(_peOffset)) + return S_FALSE; + coffOffset = _peOffset + 4; + } + { + Byte h[kPeHeaderSize]; + RINOK(stream->Seek(_peOffset, STREAM_SEEK_SET, NULL)); + RINOK(ReadStream_FALSE(stream, h, kPeHeaderSize)); + if (!_header.ParsePe(h)) + return S_FALSE; + } } - UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize; - _totalSize = _peOffset + kHeaderSize + bufSize; + const UInt32 optStart = coffOffset + kCoffHeaderSize; + const UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize; + _totalSize = optStart + bufSize; CByteBuffer buffer(bufSize); RINOK(ReadStream_FALSE(stream, buffer, bufSize)); + + if (_header.OptHeaderSize != 0) if (!_optHeader.Parse(buffer, _header.OptHeaderSize)) return S_FALSE; @@ -2207,7 +2303,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) for (i = 0; i < _sections.Size(); i++) _sections[i].UpdateTotalSize(_totalSize); - bool thereISDebug; + bool thereISDebug = false; + if (IsOpt()) + { RINOK(LoadDebugSections(stream, thereISDebug)); const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate]; @@ -2256,8 +2354,9 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) _totalSize += (UInt32)k; } } + } - if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= 512) + if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= optStart) { if (_header.NumSymbols >= (1 << 24)) return S_FALSE; @@ -2306,11 +2405,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } + if (IsOpt()) if (_optHeader.CheckSum != 0) { RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); UInt32 checkSum = 0; - RINOK(CalcCheckSum(stream, _totalSize, _peOffset + kHeaderSize + k_CheckSum_Field_Offset, checkSum)); + RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum)); _checksumError = (checkSum != _optHeader.CheckSum); } @@ -2333,6 +2433,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) const CSection § = _sections[i]; CMixItem mixItem; mixItem.SectionIndex = i; + if (IsOpt()) if (_parseResources && sect.Name == ".rsrc" && _items.IsEmpty()) { const unsigned numMixItems = _mixItems.Size(); @@ -2480,6 +2581,8 @@ STDMETHODIMP CHandler::Close() { _totalSize = 0; _checksumError = false; + _mainSubfile = -1; + _stream.Release(); _sections.Clear(); _mixItems.Clear(); @@ -2675,10 +2778,41 @@ REGISTER_ARC_I( 0, NArcInfoFlags::kPreArc, IsArc_Pe) - + } +namespace NCoff { +API_FUNC_static_IsArc IsArc_Coff(const Byte *p, size_t size) +{ + if (size < NPe::kCoffHeaderSize) + return k_IsArc_Res_NEED_MORE; + NPe::CHeader header; + if (!header.ParseCoff(p)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +/* +static const Byte k_Signature[] = +{ + 2, 0x4C, 0x01, // x86 + 2, 0x64, 0x86, // x64 + 2, 0x64, 0xAA // ARM64 +}; +REGISTER_ARC_I_CLS( +*/ + +REGISTER_ARC_I_CLS_NO_SIG( + NPe::CHandler(true), + "COFF", "obj", 0, 0xC6, + // k_Signature, + 0, + // NArcInfoFlags::kMultiSignature | + NArcInfoFlags::kStartOpen, + IsArc_Coff) +} namespace NTe { diff --git a/CPP/7zip/Common/CWrappers.cpp b/CPP/7zip/Common/CWrappers.cpp index 5e1f8e3f..d6b04206 100644 --- a/CPP/7zip/Common/CWrappers.cpp +++ b/CPP/7zip/Common/CWrappers.cpp @@ -28,14 +28,23 @@ HRESULT SResToHRESULT(SRes res) throw() switch (res) { case SZ_OK: return S_OK; - case SZ_ERROR_DATA: return S_FALSE; - case SZ_ERROR_CRC: return S_FALSE; + + case SZ_ERROR_DATA: + case SZ_ERROR_CRC: + case SZ_ERROR_INPUT_EOF: + return S_FALSE; + case SZ_ERROR_MEM: return E_OUTOFMEMORY; case SZ_ERROR_PARAM: return E_INVALIDARG; case SZ_ERROR_PROGRESS: return E_ABORT; case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL; - // case SZ_ERROR_THREAD: return E_FAIL; - // case SZ_ERROR_READ: return E_FAIL; + // case SZ_ERROR_OUTPUT_EOF: + // case SZ_ERROR_READ: + // case SZ_ERROR_WRITE: + // case SZ_ERROR_THREAD: + // case SZ_ERROR_ARCHIVE: + // case SZ_ERROR_NO_ARCHIVE: + // return E_FAIL; } if (res < 0) return res; diff --git a/CPP/7zip/Compress/BZip2Const.h b/CPP/7zip/Compress/BZip2Const.h index 588f5ae0..0efecba3 100644 --- a/CPP/7zip/Compress/BZip2Const.h +++ b/CPP/7zip/Compress/BZip2Const.h @@ -50,6 +50,17 @@ const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize)); const unsigned kRleModeRepSize = 4; +/* +The number of selectors stored in bzip2 block: +(numSelectors <= 18001) - must work with any decoder. +(numSelectors == 18002) - works with bzip2 1.0.6 decoder and all derived decoders. +(numSelectors > 18002) + 7-Zip decoder doesn't support it. + bzip2 1.0.6 decoder can overflow selector[18002] arrays. But there are another + arrays after selector arrays. So the compiled code works. + lbzip2 2.5 encoder can write up to (18001 + 7) selectors. +*/ + }} #endif diff --git a/CPP/7zip/Compress/BZip2Decoder.cpp b/CPP/7zip/Compress/BZip2Decoder.cpp index 62fa26d0..b414d088 100644 --- a/CPP/7zip/Compress/BZip2Decoder.cpp +++ b/CPP/7zip/Compress/BZip2Decoder.cpp @@ -411,9 +411,13 @@ SRes CBase::ReadBlock2() lens[state4] = (Byte)state3; state5 = 0; } + + // lbzip2 2.5 can produce dummy tree, where lens[i] = kMaxHuffmanLen + // BuildFull() returns error for such tree /* for (unsigned i = state4; i < kMaxAlphaSize; i++) lens[i] = 0; + if (!huffs[state2].Build(lens)) */ if (!huffs[state2].BuildFull(lens, state4)) return SZ_ERROR_DATA; @@ -474,7 +478,7 @@ SRes CBase::ReadBlock2() for (len = kNumTableBits + 1; val >= huff->_limits[len]; len++); /* if (len > kNumBitsMax) - return SZ_ERROR_DATA; + return SZ_ERROR_DATA; // that check is required, if NHuffman::Build() was used instead of BuildFull() */ if (_numBits < len) { diff --git a/CPP/7zip/Compress/Rar1Decoder.cpp b/CPP/7zip/Compress/Rar1Decoder.cpp index 0a552506..f5f3a79d 100644 --- a/CPP/7zip/Compress/Rar1Decoder.cpp +++ b/CPP/7zip/Compress/Rar1Decoder.cpp @@ -29,7 +29,7 @@ public: }; */ -CDecoder::CDecoder(): m_IsSolid(false) { } +CDecoder::CDecoder(): m_IsSolid(false), _errorMode(false) { } void CDecoder::InitStructures() { @@ -406,9 +406,14 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * InitData(); if (!m_IsSolid) { + _errorMode = false; InitStructures(); InitHuff(); } + + if (_errorMode) + return S_FALSE; + if (m_UnpackSize > 0) { GetFlagsBuf(); @@ -477,9 +482,9 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) { try { return CodeReal(inStream, outStream, inSize, outSize, progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(const CLzOutWindowException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } + catch(const CInBufferException &e) { _errorMode = true; return e.ErrorCode; } + catch(const CLzOutWindowException &e) { _errorMode = true; return e.ErrorCode; } + catch(...) { _errorMode = true; return S_FALSE; } } STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) diff --git a/CPP/7zip/Compress/Rar1Decoder.h b/CPP/7zip/Compress/Rar1Decoder.h index 630f0893..01b606b3 100644 --- a/CPP/7zip/Compress/Rar1Decoder.h +++ b/CPP/7zip/Compress/Rar1Decoder.h @@ -39,6 +39,7 @@ public: Int64 m_UnpackSize; bool m_IsSolid; + bool _errorMode; UInt32 ReadBits(int numBits); HRESULT CopyBlock(UInt32 distance, UInt32 len); diff --git a/CPP/7zip/Compress/Rar2Decoder.cpp b/CPP/7zip/Compress/Rar2Decoder.cpp index e906deef..1488444e 100644 --- a/CPP/7zip/Compress/Rar2Decoder.cpp +++ b/CPP/7zip/Compress/Rar2Decoder.cpp @@ -130,7 +130,7 @@ bool CDecoder::ReadTables(void) i = 0; - while (i < numLevels) + do { UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream); if (sym < kTableDirectLevels) @@ -144,10 +144,7 @@ bool CDecoder::ReadTables(void) { unsigned num = ReadBits(2) + 3; if (i == 0) - { - // return false; - continue; // original unRAR - } + return false; num += i; if (num > numLevels) { @@ -180,6 +177,10 @@ bool CDecoder::ReadTables(void) } } } + while (i < numLevels); + + if (m_InBitStream.ExtraBitsWereRead()) + return false; if (m_AudioMode) for (i = 0; i < m_NumChannels; i++) @@ -244,6 +245,8 @@ bool CDecoder::DecodeMm(UInt32 pos) while (pos-- != 0) { UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); + if (m_InBitStream.ExtraBitsWereRead()) + return false; if (symbol >= 256) return symbol == 256; /* @@ -264,6 +267,8 @@ bool CDecoder::DecodeLz(Int32 pos) while (pos > 0) { UInt32 sym = m_MainDecoder.Decode(&m_InBitStream); + if (m_InBitStream.ExtraBitsWereRead()) + return false; UInt32 length, distance; if (sym < 256) { @@ -389,15 +394,19 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * if (!DecodeLz((Int32)blockSize)) return S_FALSE; } + + if (m_InBitStream.ExtraBitsWereRead()) + return S_FALSE; + UInt64 globalPos = m_OutWindowStream.GetProcessedSize(); pos = globalPos - blockStartPos; if (pos < blockSize) if (!ReadTables()) return S_FALSE; pos = globalPos - startPos; - if (progress != 0) + if (progress) { - UInt64 packSize = m_InBitStream.GetProcessedSize(); + const UInt64 packSize = m_InBitStream.GetProcessedSize(); RINOK(progress->SetRatioInfo(&packSize, &pos)); } } diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp index c6d045aa..4da89a65 100644 --- a/CPP/7zip/Compress/Rar3Decoder.cpp +++ b/CPP/7zip/Compress/Rar3Decoder.cpp @@ -94,7 +94,8 @@ CDecoder::CDecoder(): _writtenFileSize(0), _vmData(0), _vmCode(0), - m_IsSolid(false) + m_IsSolid(false), + _errorMode(false) { Ppmd7_Construct(&_ppmd); } @@ -135,7 +136,7 @@ HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr) return WriteData(_window, endPtr); } -void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef) +void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef) { CTempFilter *tempFilter = _tempFilters[tempFilterIndex]; tempFilter->InitR[6] = (UInt32)_writtenFileSize; @@ -405,7 +406,7 @@ bool CDecoder::ReadVmCodePPM() #define RIF(x) { if (!(x)) return S_FALSE; } -UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); } +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); } // ---------- PPM ---------- @@ -414,7 +415,7 @@ HRESULT CDecoder::InitPPM() unsigned maxOrder = (unsigned)ReadBits(7); bool reset = ((maxOrder & 0x20) != 0); - int maxMB = 0; + UInt32 maxMB = 0; if (reset) maxMB = (Byte)ReadBits(8); else @@ -556,12 +557,13 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing) PrevAlignCount = 0; Byte levelLevels[kLevelTableSize]; - Byte newLevels[kTablesSizesSum]; + Byte lens[kTablesSizesSum]; if (ReadBits(1) == 0) memset(m_LastLevels, 0, kTablesSizesSum); - int i; + unsigned i; + for (i = 0; i < kLevelTableSize; i++) { UInt32 length = ReadBits(4); @@ -579,39 +581,44 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing) } levelLevels[i] = (Byte)length; } + RIF(m_LevelDecoder.Build(levelLevels)); + i = 0; - while (i < kTablesSizesSum) + + do { UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder); if (sym < 16) { - newLevels[i] = Byte((sym + m_LastLevels[i]) & 15); + lens[i] = Byte((sym + m_LastLevels[i]) & 15); i++; } else if (sym > kLevelTableSize) return S_FALSE; else { - int num; - if (((sym - 16) & 1) == 0) - num = ReadBits(3) + 3; - else - num = ReadBits(7) + 11; - if (sym < 18) + unsigned num = ((sym - 16) & 1) * 4; + num += num + 3 + (unsigned)ReadBits(num + 3); + num += i; + if (num > kTablesSizesSum) + num = kTablesSizesSum; + Byte v = 0; + if (sym < 16 + 2) { if (i == 0) return S_FALSE; - for (; num > 0 && i < kTablesSizesSum; num--, i++) - newLevels[i] = newLevels[(size_t)i - 1]; - } - else - { - for (; num > 0 && i < kTablesSizesSum; num--) - newLevels[i++] = 0; + v = lens[(size_t)i - 1]; } + do + lens[i++] = v; + while (i < num); } } + while (i < kTablesSizesSum); + + if (InputEofError()) + return S_FALSE; TablesRead = true; @@ -624,12 +631,12 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing) } */ - RIF(m_MainDecoder.Build(&newLevels[0])); - RIF(m_DistDecoder.Build(&newLevels[kMainTableSize])); - RIF(m_AlignDecoder.Build(&newLevels[kMainTableSize + kDistTableSize])); - RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize])); + RIF(m_MainDecoder.Build(&lens[0])); + RIF(m_DistDecoder.Build(&lens[kMainTableSize])); + RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize])); + RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize])); - memcpy(m_LastLevels, newLevels, kTablesSizesSum); + memcpy(m_LastLevels, lens, kTablesSizesSum); TablesOK = true; @@ -769,7 +776,7 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) if (sym2 >= kDistTableSize) return S_FALSE; rep0 = kDistStart[sym2]; - int numBits = kDistDirectBits[sym2]; + unsigned numBits = kDistDirectBits[sym2]; if (sym2 >= (kNumAlignBits * 2) + 2) { if (numBits > kNumAlignBits) @@ -835,8 +842,12 @@ HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress) PpmEscChar = 2; PpmError = true; InitFilters(); + _errorMode = false; } + if (_errorMode) + return S_FALSE; + if (!m_IsSolid || !TablesRead) { bool keepDecompressing; @@ -915,8 +926,8 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream _unpackSize = outSize ? *outSize : (UInt64)(Int64)-1; return CodeReal(progress); } - catch(const CInBufferException &e) { return e.ErrorCode; } - catch(...) { return S_FALSE; } + catch(const CInBufferException &e) { _errorMode = true; return e.ErrorCode; } + catch(...) { _errorMode = true; return S_FALSE; } // CNewException is possible here. But probably CNewException is caused // by error in data stream. } diff --git a/CPP/7zip/Compress/Rar3Decoder.h b/CPP/7zip/Compress/Rar3Decoder.h index f2a9e345..f3c1528c 100644 --- a/CPP/7zip/Compress/Rar3Decoder.h +++ b/CPP/7zip/Compress/Rar3Decoder.h @@ -31,7 +31,7 @@ const UInt32 kLenTableSize = 28; const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize; const UInt32 kDistTableSize = 60; -const int kNumAlignBits = 4; +const unsigned kNumAlignBits = 4; const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1; const UInt32 kLevelTableSize = 20; @@ -158,7 +158,7 @@ struct CTempFilter: public NVm::CProgramInitState } }; -const int kNumHuffmanBits = 15; +const unsigned kNumHuffmanBits = 15; class CDecoder: public ICompressCoder, @@ -192,6 +192,7 @@ class CDecoder: UInt32 _lastFilter; bool m_IsSolid; + bool _errorMode; bool _lzMode; bool _unsupportedFilter; @@ -209,7 +210,7 @@ class CDecoder: HRESULT WriteDataToStream(const Byte *data, UInt32 size); HRESULT WriteData(const Byte *data, UInt32 size); HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr); - void ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef); + void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef); HRESULT WriteBuf(); void InitFilters(); @@ -217,7 +218,7 @@ class CDecoder: bool ReadVmCodeLZ(); bool ReadVmCodePPM(); - UInt32 ReadBits(int numBits); + UInt32 ReadBits(unsigned numBits); HRESULT InitPPM(); int DecodePpmSymbol(); diff --git a/CPP/7zip/Compress/Rar5Decoder.cpp b/CPP/7zip/Compress/Rar5Decoder.cpp index 64cce79b..e6c3e467 100644 --- a/CPP/7zip/Compress/Rar5Decoder.cpp +++ b/CPP/7zip/Compress/Rar5Decoder.cpp @@ -421,7 +421,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) Byte lens[kTablesSizesSum]; unsigned i = 0; - while (i < kTablesSizesSum) + do { if (_bitStream._buf >= _bitStream._bufCheck2) { @@ -439,34 +439,24 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) return S_FALSE; else { - sym -= 16; - unsigned sh = ((sym & 1) << 2); - unsigned num = (unsigned)_bitStream.ReadBits9(3 + sh) + 3 + (sh << 1); - + unsigned num = ((sym - 16) & 1) * 4; + num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3); num += i; if (num > kTablesSizesSum) num = kTablesSizesSum; - - if (sym < 2) + Byte v = 0; + if (sym < 16 + 2) { if (i == 0) - { - // return S_FALSE; - continue; // original unRAR - } - Byte v = lens[(size_t)i - 1]; - do - lens[i++] = v; - while (i < num); - } - else - { - do - lens[i++] = 0; - while (i < num); + return S_FALSE; + v = lens[(size_t)i - 1]; } + do + lens[i++] = v; + while (i < num); } } + while (i < kTablesSizesSum); if (_bitStream.IsBlockOverRead()) return S_FALSE; diff --git a/CPP/7zip/Compress/ShrinkDecoder.cpp b/CPP/7zip/Compress/ShrinkDecoder.cpp index bd7c2461..41f0e352 100644 --- a/CPP/7zip/Compress/ShrinkDecoder.cpp +++ b/CPP/7zip/Compress/ShrinkDecoder.cpp @@ -13,6 +13,7 @@ namespace NCompress { namespace NShrink { +static const UInt32 kEmpty = 256; // kNumItems; static const UInt32 kBufferSize = (1 << 18); static const unsigned kNumMinBits = 9; @@ -34,20 +35,15 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * outBuffer.Init(); { - unsigned i; - for (i = 0; i < 257; i++) - _parents[i] = (UInt16)i; - for (; i < kNumItems; i++) - _parents[i] = kNumItems; - for (i = 0; i < kNumItems; i++) - _suffixes[i] = 0; + for (unsigned i = 0; i < kNumItems; i++) + _parents[i] = kEmpty; } - UInt64 prevPos = 0, inPrev = 0; + UInt64 outPrev = 0, inPrev = 0; unsigned numBits = kNumMinBits; unsigned head = 257; int lastSym = -1; - Byte lastChar2 = 0; + Byte lastChar = 0; bool moreOut = false; HRESULT res = S_FALSE; @@ -67,18 +63,22 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * break; } eofCheck = true; - // Is specSym(=256) allowed after end of stream - // Do we need to read it here + // Is specSym(=256) allowed after end of stream ? + // Do we need to read it here ? } if (progress) { - if (nowPos - prevPos >= (1 << 18) - || _inProcessed - inPrev >= (1 << 20)) + if (nowPos - outPrev >= (1 << 20) || _inProcessed - inPrev >= (1 << 20)) { - prevPos = nowPos; + outPrev = nowPos; inPrev = _inProcessed; - RINOK(progress->SetRatioInfo(&_inProcessed, &nowPos)); + res = progress->SetRatioInfo(&_inProcessed, &nowPos); + if (res != SZ_OK) + { + // break; + return res; + } } } @@ -105,23 +105,30 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * continue; } if (sym != 2) + { break; + // continue; // info-zip just ignores such code + } { + /* + ---------- Free leaf nodes ---------- + Note : that code can mark _parents[lastSym] as free, and next + inserted node will be Orphan in that case. + */ + unsigned i; - for (i = 257; i < kNumItems; i++) + for (i = 256; i < kNumItems; i++) _stack[i] = 0; for (i = 257; i < kNumItems; i++) { unsigned par = _parents[i]; - if (par != kNumItems) + if (par != kEmpty) _stack[par] = 1; } for (i = 257; i < kNumItems; i++) if (_stack[i] == 0) - _parents[i] = kNumItems; - + _parents[i] = kEmpty; head = 257; - continue; } } @@ -137,27 +144,22 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * bool needPrev = false; if (head < kNumItems && lastSym >= 0) { - while (head < kNumItems && _parents[head] != kNumItems) + while (head < kNumItems && _parents[head] != kEmpty) head++; if (head < kNumItems) { - if (head == (unsigned)lastSym) - { - // we need to fix the code for that case - // _parents[head] is not allowed to link to itself - res = E_NOTIMPL; - break; - } + /* + if (head == lastSym), it updates Orphan to self-linked Orphan and creates two problems: + 1) we must check _stack[i++] overflow in code that walks tree nodes. + 2) self-linked node can not be removed. So such self-linked nodes can occupy all _parents items. + */ needPrev = true; _parents[head] = (UInt16)lastSym; - _suffixes[head] = (Byte)lastChar2; + _suffixes[head] = (Byte)lastChar; head++; } } - if (_parents[sym] == kNumItems) - break; - lastSym = sym; unsigned cur = sym; unsigned i = 0; @@ -166,10 +168,17 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream * { _stack[i++] = _suffixes[cur]; cur = _parents[cur]; + // don't change that code: + // Orphan Check and self-linked Orphan check (_stack overflow check); + if (cur == kEmpty || i >= kNumItems) + break; } + if (cur == kEmpty || i >= kNumItems) + break; + _stack[i++] = (Byte)cur; - lastChar2 = (Byte)cur; + lastChar = (Byte)cur; if (needPrev) _suffixes[(size_t)head - 1] = (Byte)cur; diff --git a/CPP/7zip/Compress/ShrinkDecoder.h b/CPP/7zip/Compress/ShrinkDecoder.h index 2f01596a..b095b5f4 100644 --- a/CPP/7zip/Compress/ShrinkDecoder.h +++ b/CPP/7zip/Compress/ShrinkDecoder.h @@ -19,8 +19,8 @@ class CDecoder : public ICompressGetInStreamProcessedSize, public CMyUnknownImp { - UInt64 _inProcessed; bool _fullStreamMode; + UInt64 _inProcessed; UInt16 _parents[kNumItems]; Byte _suffixes[kNumItems]; diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp index 648a3d4d..dc1f4ce6 100644 --- a/CPP/7zip/Crypto/Rar5Aes.cpp +++ b/CPP/7zip/Crypto/Rar5Aes.cpp @@ -162,8 +162,9 @@ void CDecoder::Hmac_Convert_32Bytes(Byte *data) const }; +static CKey g_Key; + #ifndef _7ZIP_ST - static CKey g_Key; static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection; #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection); #else diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp index dbcd6fff..e52e47d0 100644 --- a/CPP/7zip/UI/Agent/Agent.cpp +++ b/CPP/7zip/UI/Agent/Agent.cpp @@ -1507,11 +1507,18 @@ STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices, #endif - HRESULT result = _agentSpec->GetArchive()->Extract(&realIndices.Front(), - realIndices.Size(), testMode, extractCallback); - if (result == S_OK) - result = extractCallbackSpec->SetDirsTimes(); - return result; + { + CArchiveExtractCallback_Closer ecsCloser(extractCallbackSpec); + + HRESULT res = _agentSpec->GetArchive()->Extract(&realIndices.Front(), + realIndices.Size(), testMode, extractCallback); + + HRESULT res2 = ecsCloser.Close(); + if (res == S_OK) + res = res2; + return res; + } + COM_TRY_END } diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp index ad21bc88..56f4fbd8 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -124,6 +124,7 @@ enum Enum kTechMode, kShareForWrite, + kStopAfterOpenError, kCaseSensitive, kArcNameMode, @@ -245,6 +246,7 @@ static const CSwitchForm kSwitchForms[] = { "slt" }, { "ssw" }, + { "sse" }, { "ssc", NSwitchType::kMinus }, { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet }, @@ -1299,6 +1301,8 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) if (parser[NKey::kShareForWrite].ThereIs) updateOptions.OpenShareForWrite = true; + if (parser[NKey::kStopAfterOpenError].ThereIs) + updateOptions.StopAfterOpenError = true; updateOptions.PathMode = censorPathMode; diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp index fa14655f..0571a452 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -182,6 +182,7 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r #endif CArchiveExtractCallback::CArchiveExtractCallback(): + _arc(NULL), WriteCTime(true), WriteATime(true), WriteMTime(true), @@ -205,8 +206,8 @@ void CArchiveExtractCallback::Init( const UStringVector &removePathParts, bool removePartsForAltStreams, UInt64 packSize) { - _extractedFolderPaths.Clear(); - _extractedFolderIndices.Clear(); + ClearExtractedDirsInfo(); + _outFileStream.Release(); #ifdef SUPPORT_LINKS _hardLinks.Clear(); @@ -368,7 +369,7 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat } } -HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) +HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) { filetimeIsDefined = false; NCOM::CPropVariant prop; @@ -734,7 +735,8 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre return E_FAIL; UString s; CReparseAttr reparse; - isOkReparse = reparse.Parse((const Byte *)data, dataSize); + DWORD errorCode = 0; + isOkReparse = reparse.Parse((const Byte *)data, dataSize, errorCode); if (isOkReparse) { isHardLink = false; @@ -1270,7 +1272,8 @@ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) if (FillLinkData(data, fs2us(existPath), !isJunction)) { CReparseAttr attr; - if (!attr.Parse(data, data.Size())) + DWORD errorCode = 0; + if (!attr.Parse(data, data.Size(), errorCode)) { RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))); // return E_FAIL; @@ -1447,6 +1450,33 @@ STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) } +HRESULT CArchiveExtractCallback::CloseFile() +{ + if (!_outFileStream) + return S_OK; + + HRESULT hres = S_OK; + _outFileStreamSpec->SetTime( + (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, + (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, + (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); + + const UInt64 processedSize = _outFileStreamSpec->ProcessedSize; + if (_fileLengthWasSet && _curSize > processedSize) + { + bool res = _outFileStreamSpec->File.SetLength(processedSize); + _fileLengthWasSet = res; + if (!res) + hres = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path)); + } + _curSize = processedSize; + _curSizeDefined = true; + RINOK(_outFileStreamSpec->Close()); + _outFileStream.Release(); + return hres; +} + + STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes) { COM_TRY_BEGIN @@ -1475,27 +1505,7 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes) #endif - if (_outFileStream) - { - HRESULT hres = S_OK; - _outFileStreamSpec->SetTime( - (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, - (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, - (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); - const UInt64 processedSize = _outFileStreamSpec->ProcessedSize; - if (_fileLengthWasSet && _curSize > processedSize) - { - bool res = _outFileStreamSpec->File.SetLength(processedSize); - _fileLengthWasSet = res; - if (!res) - hres = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path)); - } - _curSize = processedSize; - _curSizeDefined = true; - RINOK(_outFileStreamSpec->Close()); - _outFileStream.Release(); - RINOK(hres); - } + RINOK(CloseFile()); #ifdef _USE_SECURITY_CODE if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) @@ -1620,8 +1630,12 @@ static unsigned GetNumSlashes(const FChar *s) } } + HRESULT CArchiveExtractCallback::SetDirsTimes() { + if (!_arc) + return S_OK; + CRecordVector<CExtrRefSortPair> pairs; pairs.ClearAndSetSize(_extractedFolderPaths.Size()); unsigned i; @@ -1637,8 +1651,8 @@ HRESULT CArchiveExtractCallback::SetDirsTimes() for (i = 0; i < pairs.Size(); i++) { - int pairIndex = pairs[i].Index; - int index = _extractedFolderIndices[pairIndex]; + unsigned pairIndex = pairs[i].Index; + UInt32 index = _extractedFolderIndices[pairIndex]; FILETIME CTime; FILETIME ATime; @@ -1658,5 +1672,18 @@ HRESULT CArchiveExtractCallback::SetDirsTimes() (WriteATime && ATimeDefined) ? &ATime : NULL, (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); } + + ClearExtractedDirsInfo(); return S_OK; } + + +HRESULT CArchiveExtractCallback::CloseArc() +{ + HRESULT res = CloseFile(); + HRESULT res2 = SetDirsTimes(); + if (res == S_OK) + res = res2; + _arc = NULL; + return res; +} diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h index e458f503..4b96b523 100644 --- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h +++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h @@ -249,7 +249,7 @@ class CArchiveExtractCallback: #endif void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); - HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); + HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); HRESULT GetUnpackSize(); HRESULT SendMessageError(const char *message, const FString &path); @@ -343,9 +343,44 @@ public: } #endif + HRESULT CloseArc(); + +private: + void ClearExtractedDirsInfo() + { + _extractedFolderPaths.Clear(); + _extractedFolderIndices.Clear(); + } + + HRESULT CloseFile(); HRESULT SetDirsTimes(); }; + +struct CArchiveExtractCallback_Closer +{ + CArchiveExtractCallback *_ref; + + CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {} + + HRESULT Close() + { + HRESULT res = S_OK; + if (_ref) + { + res = _ref->CloseArc(); + _ref = NULL; + } + return res; + } + + ~CArchiveExtractCallback_Closer() + { + Close(); + } +}; + + bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); #endif diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp index 12793b78..0eee7443 100644 --- a/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -386,15 +386,27 @@ HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi, return S_OK; const FString path = phyPrefix + fi.Name; CByteBuffer &buf = dirItem.ReparseData; + DWORD res = 0; if (NIO::GetReparseData(path, buf)) { CReparseAttr attr; - if (attr.Parse(buf, buf.Size())) + if (attr.Parse(buf, buf.Size(), res)) return S_OK; + // we ignore unknown reparse points + if (res != ERROR_INVALID_REPARSE_DATA) + res = 0; } - DWORD res = ::GetLastError(); + else + { + res = ::GetLastError(); + if (res == 0) + res = ERROR_INVALID_FUNCTION; + } + buf.Free(); - return AddError(path , res); + if (res == 0) + return S_OK; + return AddError(path, res); } #endif @@ -865,7 +877,8 @@ void CDirItems::FillFixedReparse() continue; CReparseAttr attr; - if (!attr.Parse(item.ReparseData, item.ReparseData.Size())) + DWORD errorCode = 0; + if (!attr.Parse(item.ReparseData, item.ReparseData.Size(), errorCode)) continue; if (attr.IsRelative()) continue; diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp index e8b2e6b7..c49daa1d 100644 --- a/CPP/7zip/UI/Common/Extract.cpp +++ b/CPP/7zip/UI/Common/Extract.cpp @@ -197,6 +197,9 @@ static HRESULT DecompressArchive( HRESULT result; Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0; + + CArchiveExtractCallback_Closer ecsCloser(ecs); + if (options.StdInMode) { result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs); @@ -206,8 +209,11 @@ static HRESULT DecompressArchive( } else result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs); - if (result == S_OK && !options.StdInMode) - result = ecs->SetDirsTimes(); + + HRESULT res2 = ecsCloser.Close(); + if (result == S_OK) + result = res2; + return callback->ExtractResult(result); } diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp index 4b796f0d..8a194840 100644 --- a/CPP/7zip/UI/Common/PropIDUtils.cpp +++ b/CPP/7zip/UI/Common/PropIDUtils.cpp @@ -224,7 +224,6 @@ static inline void AddHexToString(AString &res, unsigned v) { res += (char)GetHex(v >> 4); res += (char)GetHex(v & 0xF); - res += ' '; } /* @@ -269,6 +268,14 @@ struct CSecID2Name const char *sz; }; +static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id) +{ + for (unsigned i = 0; i < num; i++) + if (pairs[i].n == id) + return i; + return -1; +} + static const CSecID2Name sid_32_Names[] = { { 544, "Administrators" }, @@ -359,22 +366,22 @@ static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize) if (v0 == 32 && num == 2) { UInt32 v1 = Get32(p + 12); - for (unsigned i = 0; i < ARRAY_SIZE(sid_32_Names); i++) - if (sid_32_Names[i].n == v1) - { - s += sid_32_Names[i].sz; - return; - } + int index = FindPairIndex(sid_32_Names, ARRAY_SIZE(sid_32_Names), v1); + if (index >= 0) + { + s += sid_32_Names[index].sz; + return; + } } if (v0 == 21 && num == 5) { UInt32 v4 = Get32(p + 8 + 4 * 4); - for (unsigned i = 0; i < ARRAY_SIZE(sid_21_Names); i++) - if (sid_21_Names[i].n == v4) - { - s += sid_21_Names[i].sz; - return; - } + int index = FindPairIndex(sid_21_Names, ARRAY_SIZE(sid_21_Names), v4); + if (index >= 0) + { + s += sid_21_Names[index].sz; + return; + } } if (v0 == 80 && num == 6) { @@ -419,20 +426,13 @@ static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos) ParseSid(s, p + pos, size - pos, sidSize); } -static void AddUInt32ToString(AString &s, UInt32 val) -{ - char sz[16]; - ConvertUInt32ToString(val, sz); - s += sz; -} - static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset) { UInt32 control = Get16(p + 2); if ((flags & control) == 0) return; UInt32 pos = Get32(p + offset); - s += ' '; + s.Add_Space(); s += strName; if (pos >= size) return; @@ -443,7 +443,7 @@ static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName if (Get16(p) != 2) // revision return; UInt32 num = Get32(p + 4); - AddUInt32ToString(s, num); + s.Add_UInt32(num); /* UInt32 aclSize = Get16(p + 2); @@ -466,7 +466,7 @@ static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName size -= 8; UInt32 sidSize = 0; - s += ' '; + s.Add_Space(); ParseSid(s, p, size, sidSize); if (sidSize == 0) return; @@ -508,12 +508,12 @@ void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s) return; } ParseOwner(s, data, size, Get32(data + 4)); - s += ' '; + s.Add_Space(); ParseOwner(s, data, size, Get32(data + 8)); ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12); ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16); - s += ' '; - AddUInt32ToString(s, size); + s.Add_Space(); + s.Add_UInt32(size); // s += '\n'; // s += Data_To_Hex(data, size); } @@ -567,11 +567,38 @@ bool CheckNtSecure(const Byte *data, UInt32 size) throw() #endif + + +// IO_REPARSE_TAG_* + +static const CSecID2Name k_ReparseTags[] = +{ + { 0xA0000003, "MOUNT_POINT" }, + { 0xC0000004, "HSM" }, + { 0x80000005, "DRIVE_EXTENDER" }, + { 0x80000006, "HSM2" }, + { 0x80000007, "SIS" }, + { 0x80000008, "WIM" }, + { 0x80000009, "CSV" }, + { 0x8000000A, "DFS" }, + { 0x8000000B, "FILTER_MANAGER" }, + { 0xA000000C, "SYMLINK" }, + { 0xA0000010, "IIS_CACHE" }, + { 0x80000012, "DFSR" }, + { 0x80000013, "DEDUP" }, + { 0xC0000014, "APPXSTRM" }, + { 0x80000014, "NFS" }, + { 0x80000015, "FILE_PLACEHOLDER" }, + { 0x80000016, "DFM" }, + { 0x80000017, "WOF" } +}; + bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s) { s.Empty(); NFile::CReparseAttr attr; - if (attr.Parse(data, size)) + DWORD errorCode = 0; + if (attr.Parse(data, size, errorCode)) { if (!attr.IsSymLink()) s += "Junction: "; @@ -593,19 +620,48 @@ bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s) if (Get16(data + 6) != 0) // padding return false; - char hex[16]; - ConvertUInt32ToHex8Digits(tag, hex); - s += hex; - s.Add_Space(); + /* + #define _my_IO_REPARSE_TAG_DEDUP (0x80000013L) + if (tag == _my_IO_REPARSE_TAG_DEDUP) + { + } + */ + + { + int index = FindPairIndex(k_ReparseTags, ARRAY_SIZE(k_ReparseTags), tag); + if (index >= 0) + s += k_ReparseTags[index].sz; + else + { + s += "REPARSE:"; + char hex[16]; + ConvertUInt32ToHex8Digits(tag, hex); + s += hex; + } + } - data += 8; + s += ":"; + s.Add_UInt32(len); - for (UInt32 i = 0; i < len; i++) + if (len != 0) { - unsigned b = ((const Byte *)data)[i]; - s += (char)GetHex((b >> 4) & 0xF); - s += (char)GetHex(b & 0xF); + s.Add_Space(); + + data += 8; + + for (UInt32 i = 0; i < len; i++) + { + if (i >= 8) + { + s += "..."; + break; + } + unsigned b = data[i]; + s += (char)GetHex((b >> 4) & 0xF); + s += (char)GetHex(b & 0xF); + } } + return true; } diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp index ba1a81b0..f1826957 100644 --- a/CPP/7zip/UI/Common/Update.cpp +++ b/CPP/7zip/UI/Common/Update.cpp @@ -735,6 +735,7 @@ static HRESULT Compress( CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; + updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError; updateCallbackSpec->StdInMode = options.StdInMode; updateCallbackSpec->Callback = callback; diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h index 0301ae76..dc9ff5d3 100644 --- a/CPP/7zip/UI/Common/Update.h +++ b/CPP/7zip/UI/Common/Update.h @@ -92,6 +92,7 @@ struct CUpdateOptions FString SfxModule; bool OpenShareForWrite; + bool StopAfterOpenError; bool StdInMode; UString StdInFileName; @@ -127,6 +128,7 @@ struct CUpdateOptions EMailMode(false), EMailRemoveAfter(false), OpenShareForWrite(false), + StopAfterOpenError(false), ArcNameMode(k_ArcNameMode_Smart), PathMode(NWildcard::k_RelatPath), diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp index ae3c4831..fd46dda8 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.cpp +++ b/CPP/7zip/UI/Common/UpdateCallback.cpp @@ -55,6 +55,7 @@ CArchiveUpdateCallback::CArchiveUpdateCallback(): Comment(NULL), ShareForWrite(false), + StopAfterOpenError(false), StdInMode(false), KeepOriginalItemNames(false), @@ -346,7 +347,8 @@ STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PR // if (di.IsDir()) { CReparseAttr attr; - if (attr.Parse(di.ReparseData, di.ReparseData.Size())) + DWORD errorCode = 0; + if (attr.Parse(di.ReparseData, di.ReparseData.Size(), errorCode)) { UString simpleName = attr.GetPath(); if (attr.IsRelative()) @@ -512,7 +514,12 @@ STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStrea #endif if (!inStreamSpec->OpenShared(path, ShareForWrite)) { - return Callback->OpenFileError(path, ::GetLastError()); + DWORD error = ::GetLastError(); + HRESULT hres = Callback->OpenFileError(path, error); + if (StopAfterOpenError) + if (hres == S_OK || hres == S_FALSE) + return HRESULT_FROM_WIN32(error); + return hres; } if (StoreHardLinks) diff --git a/CPP/7zip/UI/Common/UpdateCallback.h b/CPP/7zip/UI/Common/UpdateCallback.h index d5ac4129..9e6925f6 100644 --- a/CPP/7zip/UI/Common/UpdateCallback.h +++ b/CPP/7zip/UI/Common/UpdateCallback.h @@ -136,6 +136,7 @@ public: const UString *Comment; bool ShareForWrite; + bool StopAfterOpenError; bool StdInMode; bool KeepOriginalItemNames; diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp index a4bfc1c6..897a2757 100644 --- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp @@ -95,6 +95,16 @@ void PrintSize_bytes_Smart(AString &s, UInt64 val) s += ')'; } +void PrintSize_bytes_Smart_comma(AString &s, UInt64 val) +{ + if (val == (UInt64)(Int64)-1) + return; + s += ", "; + PrintSize_bytes_Smart(s, val); +} + + + void Print_DirItemsStat(AString &s, const CDirItemsStat &st) { if (st.NumDirs != 0) @@ -103,14 +113,12 @@ void Print_DirItemsStat(AString &s, const CDirItemsStat &st) s += ", "; } Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files"); - s += ", "; - PrintSize_bytes_Smart(s, st.FilesSize); + PrintSize_bytes_Smart_comma(s, st.FilesSize); if (st.NumAltStreams != 0) { s.Add_LF(); Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams"); - s += ", "; - PrintSize_bytes_Smart(s, st.AltStreamsSize); + PrintSize_bytes_Smart_comma(s, st.AltStreamsSize); } } @@ -244,7 +252,7 @@ static const char * const kTab = " "; static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size) { *_so << kTab << "Path: " << path << endl; - if (size) + if (size && *size != (UInt64)(Int64)-1) { AString s; PrintSize_bytes_Smart(s, *size); diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index ed47bdc6..436a6cd1 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -150,6 +150,7 @@ static const char * const kHelpString = " -spe : eliminate duplication of root folder for extract command\n" " -spf : use fully qualified file paths\n" " -ssc[-] : set sensitive case mode\n" + " -sse : stop archive creating, if it can't open some input file\n" " -ssw : compress shared files\n" " -stl : set archive timestamp from the most recently modified file\n" " -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n" diff --git a/CPP/7zip/UI/FileManager/LinkDialog.cpp b/CPP/7zip/UI/FileManager/LinkDialog.cpp index 70b0ba65..ddef365c 100644 --- a/CPP/7zip/UI/FileManager/LinkDialog.cpp +++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp @@ -55,7 +55,8 @@ static bool GetSymLink(CFSTR path, CReparseAttr &attr) if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize)) return false; - if (!attr.Parse(buf, returnedSize)) + DWORD errorCode = 0; + if (!attr.Parse(buf, returnedSize, errorCode)) return false; CByteBuffer data2; @@ -291,7 +292,8 @@ void CLinkDialog::OnButton_Link() } CReparseAttr attr; - if (!attr.Parse(data, data.Size())) + DWORD errorCode = 0; + if (!attr.Parse(data, data.Size(), errorCode)) { ShowError(L"Internal conversion error"); return; diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp index 6e1e434f..1f93f862 100644 --- a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp +++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp @@ -827,7 +827,8 @@ void CPanel::OpenFolder(int index) SetNewFolder(newFolder); LoadFullPath(); RefreshListCtrl(); - _listView.SetItemState_Selected(_listView.GetFocusedItem()); + // 17.02: fixed : now we don't select first item + // _listView.SetItemState_Selected(_listView.GetFocusedItem()); _listView.EnsureVisible(_listView.GetFocusedItem(), false); } diff --git a/CPP/7zip/UI/FileManager/PanelListNotify.cpp b/CPP/7zip/UI/FileManager/PanelListNotify.cpp index d7785d12..9061e585 100644 --- a/CPP/7zip/UI/FileManager/PanelListNotify.cpp +++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp @@ -702,6 +702,8 @@ void CPanel::Refresh_StatusBar() wchar_t temp[32]; ConvertUInt32ToString(indices.Size(), temp); + wcscat(temp, L" / "); + ConvertUInt32ToString(_selectedStatusVector.Size(), temp + wcslen(temp)); // UString s1 = MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, NumberToString(indices.Size())); // UString s1 = MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size())); diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp index 945a41f8..3db65be4 100644 --- a/CPP/7zip/UI/FileManager/PanelMenu.cpp +++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp @@ -403,82 +403,117 @@ void CPanel::EditPaste() // InvokeSystemCommand("paste"); } + + +struct CFolderPidls +{ + LPITEMIDLIST parent; + CRecordVector<LPITEMIDLIST> items; + + CFolderPidls(): parent(NULL) {} + ~CFolderPidls() + { + FOR_VECTOR (i, items) + CoTaskMemFree(items[i]); + CoTaskMemFree(parent); + } +}; + + HRESULT CPanel::CreateShellContextMenu( const CRecordVector<UInt32> &operatedIndices, CMyComPtr<IContextMenu> &systemContextMenu) { systemContextMenu.Release(); - UString folderPath = GetFsPath(); + const UString folderPath = GetFsPath(); CMyComPtr<IShellFolder> desktopFolder; RINOK(::SHGetDesktopFolder(&desktopFolder)); if (!desktopFolder) { - // ShowMessage("Failed to get Desktop folder."); + // ShowMessage("Failed to get Desktop folder"); return E_FAIL; } - // Separate the file from the folder. - - - // Get a pidl for the folder the file - // is located in. - LPITEMIDLIST parentPidl; + CFolderPidls pidls; DWORD eaten; + + // if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer" RINOK(desktopFolder->ParseDisplayName( - GetParent(), 0, (wchar_t *)(const wchar_t *)folderPath, - &eaten, &parentPidl, 0)); + GetParent(), NULL, (wchar_t *)(const wchar_t *)folderPath, + &eaten, &pidls.parent, NULL)); + + /* + STRRET pName; + res = desktopFolder->GetDisplayNameOf(pidls.parent, SHGDN_NORMAL, &pName); + WCHAR dir[MAX_PATH]; + if (!SHGetPathFromIDListW(pidls.parent, dir)) + dir[0] = 0; + */ + + if (!pidls.parent) + return E_FAIL; + + if (operatedIndices.IsEmpty()) + { + // how to get IContextMenu, if there are no selected files? + return E_FAIL; + + /* + xp64 : + 1) we can't use GetUIObjectOf() with (numItems == 0), it throws exception + 2) we can't use desktopFolder->GetUIObjectOf() with absolute pidls of folder + context menu items are different in that case: + "Open / Explorer" for folder + "Delete" for "My Computer" icon + "Preperties" for "System" + */ + /* + parentFolder = desktopFolder; + pidls.items.AddInReserved(pidls.parent); + pidls.parent = NULL; + */ + + // CreateViewObject() doesn't show all context menu items + /* + HRESULT res = parentFolder->CreateViewObject( + GetParent(), IID_IContextMenu, (void**)&systemContextMenu); + */ + } - // Get an IShellFolder for the folder - // the file is located in. CMyComPtr<IShellFolder> parentFolder; - RINOK(desktopFolder->BindToObject(parentPidl, - 0, IID_IShellFolder, (void**)&parentFolder)); + RINOK(desktopFolder->BindToObject(pidls.parent, + NULL, IID_IShellFolder, (void**)&parentFolder)); if (!parentFolder) { - // ShowMessage("Invalid file name."); + // ShowMessage("Invalid file name"); return E_FAIL; } - // Get a pidl for the file itself. - CRecordVector<LPITEMIDLIST> pidls; - pidls.ClearAndReserve(operatedIndices.Size()); + pidls.items.ClearAndReserve(operatedIndices.Size()); FOR_VECTOR (i, operatedIndices) { LPITEMIDLIST pidl; - UString fileName = GetItemRelPath2(operatedIndices[i]); + const UString fileName = GetItemRelPath2(operatedIndices[i]); RINOK(parentFolder->ParseDisplayName(GetParent(), 0, - (wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0)); - pidls.AddInReserved(pidl); - } - - ITEMIDLIST temp; - if (pidls.Size() == 0) - { - temp.mkid.cb = 0; - /* - LPITEMIDLIST pidl; - HRESULT result = parentFolder->ParseDisplayName(GetParent(), 0, - L"." WSTRING_PATH_SEPARATOR, &eaten, &pidl, 0); - if (result != NOERROR) - return; - */ - pidls.Add(&temp); + (wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0)); + pidls.items.AddInReserved(pidl); } + + // Get IContextMenu for items - // Get the IContextMenu for the file. - CMyComPtr<IContextMenu> cm; - RINOK( parentFolder->GetUIObjectOf(GetParent(), pidls.Size(), - (LPCITEMIDLIST *)&pidls.Front(), IID_IContextMenu, 0, (void**)&cm)); - if (!cm) + RINOK(parentFolder->GetUIObjectOf(GetParent(), pidls.items.Size(), + (LPCITEMIDLIST *)&pidls.items.Front(), IID_IContextMenu, 0, (void**)&systemContextMenu)); + + if (!systemContextMenu) { - // ShowMessage("Unable to get context menu interface."); + // ShowMessage("Unable to get context menu interface"); return E_FAIL; } - systemContextMenu = cm; return S_OK; } + void CPanel::CreateSystemMenu(HMENU menuSpec, const CRecordVector<UInt32> &operatedIndices, CMyComPtr<IContextMenu> &systemContextMenu) diff --git a/CPP/7zip/UI/FileManager/PanelSelect.cpp b/CPP/7zip/UI/FileManager/PanelSelect.cpp index 268b64af..8cfb23f4 100644 --- a/CPP/7zip/UI/FileManager/PanelSelect.cpp +++ b/CPP/7zip/UI/FileManager/PanelSelect.cpp @@ -218,6 +218,8 @@ void CPanel::InvertSelection() FOR_VECTOR (i, _selectedStatusVector) if (_selectedStatusVector[i]) numSelected++; + // 17.02: fixed : now we invert item even, if single item is selected + /* if (numSelected == 1) { int focused = _listView.GetFocusedItem(); @@ -229,6 +231,7 @@ void CPanel::InvertSelection() _selectedStatusVector[realIndex] = false; } } + */ } FOR_VECTOR (i, _selectedStatusVector) _selectedStatusVector[i] = !_selectedStatusVector[i]; diff --git a/CPP/7zip/UI/FileManager/PanelSplitFile.cpp b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp index 3f7111a1..7cab2cf9 100644 --- a/CPP/7zip/UI/FileManager/PanelSplitFile.cpp +++ b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp @@ -77,8 +77,6 @@ UString CVolSeqName::GetNextName() return UnchangedPart + ChangedPart; } -static const UInt32 kBufSize = (1 << 20); - class CThreadSplit: public CProgressThreadVirt { HRESULT ProcessVirt(); @@ -89,30 +87,84 @@ public: CRecordVector<UInt64> VolumeSizes; }; + +class CPreAllocOutFile +{ + UInt64 _preAllocSize; +public: + NIO::COutFile File; + UInt64 Written; + + CPreAllocOutFile(): _preAllocSize(0), Written(0) {} + + ~CPreAllocOutFile() + { + SetCorrectFileLength(); + } + + void PreAlloc(UInt64 preAllocSize) + { + _preAllocSize = 0; + if (File.SetLength(preAllocSize)) + _preAllocSize = preAllocSize; + File.SeekToBegin(); + } + + bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw() + { + bool res = File.Write(data, size, processedSize); + Written += processedSize; + return res; + } + + void Close() + { + SetCorrectFileLength(); + Written = 0; + _preAllocSize = 0; + File.Close(); + } + + void SetCorrectFileLength() + { + if (Written < _preAllocSize) + { + File.SetLength(Written); + _preAllocSize = 0; + } + } +}; + + +static const UInt32 kBufSize = (1 << 20); + HRESULT CThreadSplit::ProcessVirt() { NIO::CInFile inFile; if (!inFile.Open(FilePath)) return GetLastError(); - NIO::COutFile outFile; - CMyBuffer bufferObject; - if (!bufferObject.Allocate(kBufSize)) + + CPreAllocOutFile outFile; + + CMyBuffer buffer; + if (!buffer.Allocate(kBufSize)) return E_OUTOFMEMORY; - Byte *buffer = (Byte *)(void *)bufferObject; - UInt64 curVolSize = 0; + CVolSeqName seqName; seqName.SetNumDigits(NumVolumes); + UInt64 length; if (!inFile.GetLength(length)) return GetLastError(); CProgressSync &sync = ProgressDialog.Sync; sync.Set_NumBytesTotal(length); - UInt64 pos = 0; + UInt64 pos = 0; + UInt64 prev = 0; UInt64 numFiles = 0; unsigned volIndex = 0; - + for (;;) { UInt64 volSize; @@ -121,46 +173,65 @@ HRESULT CThreadSplit::ProcessVirt() else volSize = VolumeSizes.Back(); - UInt32 needSize = (UInt32)(MyMin((UInt64)kBufSize, volSize - curVolSize)); + UInt32 needSize = kBufSize; + { + const UInt64 rem = volSize - outFile.Written; + if (needSize > rem) + needSize = (UInt32)rem; + } UInt32 processedSize; if (!inFile.Read(buffer, needSize, processedSize)) return GetLastError(); if (processedSize == 0) - break; + return S_OK; needSize = processedSize; - if (curVolSize == 0) + + if (outFile.Written == 0) { FString name = VolBasePath; name += '.'; name += us2fs(seqName.GetNextName()); sync.Set_FilePath(fs2us(name)); - sync.Set_NumFilesCur(numFiles++); - if (!outFile.Create(name, false)) + if (!outFile.File.Create(name, false)) { HRESULT res = GetLastError(); AddErrorPath(name); return res; } + UInt64 expectSize = volSize; + if (pos < length) + { + const UInt64 rem = length - pos; + if (expectSize > rem) + expectSize = rem; + } + outFile.PreAlloc(expectSize); } + if (!outFile.Write(buffer, needSize, processedSize)) return GetLastError(); if (needSize != processedSize) throw g_Message_FileWriteError; - curVolSize += processedSize; - if (curVolSize == volSize) + + pos += processedSize; + + if (outFile.Written == volSize) { outFile.Close(); + sync.Set_NumFilesCur(++numFiles); if (volIndex < VolumeSizes.Size()) volIndex++; - curVolSize = 0; } - pos += processedSize; - RINOK(sync.Set_NumBytesCur(pos)); + + if (pos - prev >= ((UInt32)1 << 22) || outFile.Written == 0) + { + RINOK(sync.Set_NumBytesCur(pos)); + prev = pos; + } } - sync.Set_NumFilesCur(numFiles); - return S_OK; } + void CApp::Split() { int srcPanelIndex = GetFocusedPanelIndex(); diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp index 1d301c0e..cbb2dda0 100644 --- a/CPP/7zip/UI/GUI/CompressDialog.cpp +++ b/CPP/7zip/UI/GUI/CompressDialog.cpp @@ -861,6 +861,7 @@ bool CCompressDialog::OnCommand(int code, int itemID, LPARAM lParam) { bool isSFX = IsSFX(); SaveOptionsInMem(); + m_Solid.ResetContent(); SetLevel(); SetSolidBlockSize(); SetNumThreads(); diff --git a/CPP/Build.mak b/CPP/Build.mak index 22b8e162..5bcd1b8b 100644 --- a/CPP/Build.mak +++ b/CPP/Build.mak @@ -15,11 +15,11 @@ O=O !ENDIF !IF "$(CPU)" == "AMD64" -MY_ML = ml64 -Dx64 +MY_ML = ml64 -Dx64 -WX !ELSEIF "$(CPU)" == "ARM" -MY_ML = armasm +MY_ML = armasm -WX !ELSE -MY_ML = ml +MY_ML = ml -WX !ENDIF @@ -32,9 +32,9 @@ LFLAGS = $(LFLAGS) /ENTRY:mainACRTStartup !IFNDEF NEW_COMPILER LFLAGS = $(LFLAGS) -OPT:NOWIN98 !ENDIF -# !IF "$(CPU)" != "ARM" +!IF "$(CPU)" != "ARM" && "$(CPU)" != "ARM64" CFLAGS = $(CFLAGS) -Gr -# !ENDIF +!ENDIF LIBS = $(LIBS) user32.lib advapi32.lib shell32.lib !ENDIF @@ -82,9 +82,9 @@ LFLAGS = $(LFLAGS) /LARGEADDRESSAWARE !IFDEF DEF_FILE LFLAGS = $(LFLAGS) -DLL -DEF:$(DEF_FILE) !ELSE -# !IF "$(CPU)" != "ARM" +!IF "$(CPU)" != "ARM" && "$(CPU)" != "ARM64" LFLAGS = $(LFLAGS) /FIXED -# !ENDIF +!ENDIF # /BASE:0x400000 !ENDIF diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h index 32c285fb..5ca5448b 100644 --- a/CPP/Windows/FileIO.h +++ b/CPP/Windows/FileIO.h @@ -45,7 +45,11 @@ struct CReparseAttr UString PrintName; CReparseAttr(): Tag(0), Flags(0) {} - bool Parse(const Byte *p, size_t size); + + // Parse() + // returns true and (errorCode = 0), if (correct MOUNT_POINT or SYMLINK) + // returns false and (errorCode = ERROR_REPARSE_TAG_MISMATCH), if not (MOUNT_POINT or SYMLINK) + bool Parse(const Byte *p, size_t size, DWORD &errorCode); bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction bool IsSymLink() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; } @@ -171,7 +175,12 @@ public: bool OpenReparse(CFSTR fileName) { - return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, + // 17.02 fix: to support Windows XP compatibility junctions: + // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ + return + Create(fileName, 0, + // Open(fileName, + FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); } diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp index 9e706ead..3e2f6431 100644 --- a/CPP/Windows/FileLink.cpp +++ b/CPP/Windows/FileLink.cpp @@ -194,8 +194,9 @@ static void GetString(const Byte *p, unsigned len, UString &res) res.ReleaseBuf_SetLen(i); } -bool CReparseAttr::Parse(const Byte *p, size_t size) +bool CReparseAttr::Parse(const Byte *p, size_t size, DWORD &errorCode) { + errorCode = ERROR_INVALID_REPARSE_DATA; if (size < 8) return false; Tag = Get32(p); @@ -209,8 +210,10 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) */ if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && Tag != _my_IO_REPARSE_TAG_SYMLINK) - // return true; + { + errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID return false; + } if (Get16(p + 6) != 0) // padding return false; @@ -247,6 +250,7 @@ bool CReparseAttr::Parse(const Byte *p, size_t size) GetString(p + subOffs, subLen >> 1, SubsName); GetString(p + printOffs, printLen >> 1, PrintName); + errorCode = 0; return true; } diff --git a/DOC/7zip.inf b/DOC/7zip.inf index 2510f42e..b7bcfa3d 100644 --- a/DOC/7zip.inf +++ b/DOC/7zip.inf @@ -10,8 +10,8 @@ AppName = "7-Zip" InstallDir = %CE1%\%AppName% [Strings] -AppVer = "17.01" -AppDate = "2017-08-28" +AppVer = "18.00" +AppDate = "2018-01-10" [CEDevice] ; ProcessorType = 2577 ; ARM diff --git a/DOC/7zip.nsi b/DOC/7zip.nsi index 5ba331d1..56b134b7 100644 --- a/DOC/7zip.nsi +++ b/DOC/7zip.nsi @@ -1,8 +1,8 @@ ;-------------------------------- ;Defines -!define VERSION_MAJOR 17 -!define VERSION_MINOR 01 +!define VERSION_MAJOR 18 +!define VERSION_MINOR 00 !define VERSION_POSTFIX_FULL " beta" !ifdef WIN64 !ifdef IA64 diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs index 33b677e9..cdd40015 100644 --- a/DOC/7zip.wxs +++ b/DOC/7zip.wxs @@ -1,7 +1,7 @@ <?xml version="1.0"?> -<?define VerMajor = "17" ?> -<?define VerMinor = "01" ?> +<?define VerMajor = "18" ?> +<?define VerMinor = "00" ?> <?define VerBuild = "00" ?> <?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?> <?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?> diff --git a/DOC/License.txt b/DOC/License.txt index c4f905d3..bcd31d65 100644 --- a/DOC/License.txt +++ b/DOC/License.txt @@ -3,7 +3,7 @@ License for use and distribution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 7-Zip Copyright (C) 1999-2017 Igor Pavlov. + 7-Zip Copyright (C) 1999-2018 Igor Pavlov. Licenses for files are: diff --git a/DOC/readme.txt b/DOC/readme.txt index 1da3094e..4979093a 100644 --- a/DOC/readme.txt +++ b/DOC/readme.txt @@ -1,9 +1,9 @@ -7-Zip 17.00 beta Sources +7-Zip 18.00 beta Sources ------------------------ 7-Zip is a file archiver for Windows. -7-Zip Copyright (C) 1999-2017 Igor Pavlov. +7-Zip Copyright (C) 1999-2018 Igor Pavlov. License Info |