diff -Nru 7zip-21.07+dfsg/Asm/x86/7zAsm.asm 7zip-22.01/Asm/x86/7zAsm.asm --- 7zip-21.07+dfsg/Asm/x86/7zAsm.asm 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/Asm/x86/7zAsm.asm 2022-05-16 14:00:00.000000000 +0000 @@ -1,7 +1,12 @@ ; 7zAsm.asm -- ASM macros -; 2021-12-25 : Igor Pavlov : Public domain +; 2022-05-16 : Igor Pavlov : Public domain +; UASM can require these changes +; OPTION FRAMEPRESERVEFLAGS:ON +; OPTION PROLOGUE:NONE +; OPTION EPILOGUE:NONE + ifdef @wordsize ; @wordsize is defined only in JWASM and ASMC and is not defined in MASM ; @wordsize eq 8 for 64-bit x64 diff -Nru 7zip-21.07+dfsg/Asm/x86/Sha256Opt.asm 7zip-22.01/Asm/x86/Sha256Opt.asm --- 7zip-21.07+dfsg/Asm/x86/Sha256Opt.asm 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/Asm/x86/Sha256Opt.asm 2022-04-17 10:00:00.000000000 +0000 @@ -1,5 +1,5 @@ ; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions -; 2021-03-10 : Igor Pavlov : Public domain +; 2022-04-17 : Igor Pavlov : Public domain include 7zAsm.asm @@ -54,14 +54,20 @@ .686 .xmm endif - + +; jwasm-based assemblers for linux and linker from new versions of binutils +; can generate incorrect code for load [ARRAY + offset] instructions. +; 22.00: we load K_CONST offset to (rTable) register to avoid jwasm+binutils problem + rTable equ r0 + ; rTable equ K_CONST + ifdef x64 rNum equ REG_ABI_PARAM_2 if (IS_LINUX eq 0) LOCAL_SIZE equ (16 * 2) endif else - rNum equ r0 + rNum equ r3 LOCAL_SIZE equ (16 * 1) endif @@ -103,15 +109,18 @@ movdqa [r4 + 16], xmm9 endif else ; x86 + push r3 + push r5 + mov r5, r4 + NUM_PUSH_REGS equ 2 + PARAM_OFFSET equ (REG_SIZE * (1 + NUM_PUSH_REGS)) if (IS_CDECL gt 0) - mov rState, [r4 + REG_SIZE * 1] - mov rData, [r4 + REG_SIZE * 2] - mov rNum, [r4 + REG_SIZE * 3] + mov rState, [r4 + PARAM_OFFSET] + mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1] + mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2] else ; fastcall - mov rNum, [r4 + REG_SIZE * 1] + mov rNum, [r4 + PARAM_OFFSET] endif - push r5 - mov r5, r4 and r4, -16 sub r4, LOCAL_SIZE endif @@ -129,6 +138,7 @@ else ; x86 mov r4, r5 pop r5 + pop r3 endif MY_ENDP endm @@ -171,7 +181,7 @@ RND4 macro k - movdqa msg, xmmword ptr [K_CONST + (k) * 16] + movdqa msg, xmmword ptr [rTable + (k) * 16] paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4))) MY_sha256rnds2 state0_N, state1_N pshufd msg, msg, 0eH @@ -210,6 +220,8 @@ MY_PROC Sha256_UpdateBlocks_HW, 3 MY_PROLOG + lea rTable, [K_CONST] + cmp rNum, 0 je end_c diff -Nru 7zip-21.07+dfsg/C/7zip_gcc_c.mak 7zip-22.01/C/7zip_gcc_c.mak --- 7zip-21.07+dfsg/C/7zip_gcc_c.mak 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/7zip_gcc_c.mak 2022-07-15 08:00:00.000000000 +0000 @@ -16,12 +16,32 @@ -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -LDFLAGS_STATIC = -DNDEBUG -# -static - ifdef SystemDrive IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef IS_MINGW +LDFLAGS_STATIC_2 = -static +else +ifndef DEF_FILE +ifndef IS_NOT_STANDALONE +ifndef MY_DYNAMIC_LINK +ifneq ($(CC), clang) +LDFLAGS_STATIC_2 = +# -static +# -static-libstdc++ -static-libgcc +endif +endif +endif endif +endif + +LDFLAGS_STATIC = -DNDEBUG $(LDFLAGS_STATIC_2) ifdef DEF_FILE @@ -62,15 +82,22 @@ ifdef IS_MINGW +ifdef MSYSTEM +RM = rm -f +MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) +else RM = del MY_MKDIR=mkdir -LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 +DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll +endif + +LIB2 = -lOle32 -loleaut32 -luuid -ladvapi32 -lUser32 CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE # -Wno-delete-non-virtual-dtor -DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll else @@ -306,7 +333,10 @@ $(CC) $(CFLAGS) $< $O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c $(CC) $(CFLAGS) $< - +$O/7zipInstall.o: ../../../C/Util/7zipInstall/7zipInstall.c + $(CC) $(CFLAGS) $< +$O/7zipUninstall.o: ../../../C/Util/7zipUninstall/7zipUninstall.c + $(CC) $(CFLAGS) $< clean: diff -Nru 7zip-21.07+dfsg/C/7zTypes.h 7zip-22.01/C/7zTypes.h --- 7zip-21.07+dfsg/C/7zTypes.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/7zTypes.h 2022-04-01 10:00:00.000000000 +0000 @@ -1,5 +1,5 @@ /* 7zTypes.h -- Basic types -2021-12-25 : Igor Pavlov : Public domain */ +2022-04-01 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H @@ -133,10 +133,6 @@ #define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) */ -// gcc / clang : (sizeof(long) == sizeof(void*)) in 32/64 bits -typedef long INT_PTR; -typedef unsigned long UINT_PTR; - #define TEXT(quote) quote #define FILE_ATTRIBUTE_READONLY 0x0001 @@ -520,6 +516,14 @@ #endif +#define k_PropVar_TimePrec_0 0 +#define k_PropVar_TimePrec_Unix 1 +#define k_PropVar_TimePrec_DOS 2 +#define k_PropVar_TimePrec_HighPrec 3 +#define k_PropVar_TimePrec_Base 16 +#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7) +#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9) + EXTERN_C_END #endif diff -Nru 7zip-21.07+dfsg/C/7zVersion.h 7zip-22.01/C/7zVersion.h --- 7zip-21.07+dfsg/C/7zVersion.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/7zVersion.h 2022-07-15 13:00:29.000000000 +0000 @@ -1,7 +1,7 @@ -#define MY_VER_MAJOR 21 -#define MY_VER_MINOR 07 +#define MY_VER_MAJOR 22 +#define MY_VER_MINOR 01 #define MY_VER_BUILD 0 -#define MY_VERSION_NUMBERS "21.07" +#define MY_VERSION_NUMBERS "22.01" #define MY_VERSION MY_VERSION_NUMBERS #ifdef MY_CPU_NAME @@ -10,12 +10,12 @@ #define MY_VERSION_CPU MY_VERSION #endif -#define MY_DATE "2021-12-26" +#define MY_DATE "2022-07-15" #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-2021 Igor Pavlov" +#define MY_COPYRIGHT_CR "Copyright (c) 1999-2022 Igor Pavlov" #ifdef USE_COPYRIGHT_CR #define MY_COPYRIGHT MY_COPYRIGHT_CR diff -Nru 7zip-21.07+dfsg/C/CpuArch.h 7zip-22.01/C/CpuArch.h --- 7zip-21.07+dfsg/C/CpuArch.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/CpuArch.h 2022-07-15 10:00:00.000000000 +0000 @@ -1,5 +1,5 @@ /* CpuArch.h -- CPU specific code -2021-07-13 : Igor Pavlov : Public domain */ +2022-07-15 : Igor Pavlov : Public domain */ #ifndef __CPU_ARCH_H #define __CPU_ARCH_H @@ -123,12 +123,15 @@ #endif -#if defined(__sparc64__) - #define MY_CPU_NAME "sparc64" - #define MY_CPU_64BIT -#elif defined(__sparc__) - #define MY_CPU_NAME "sparc" - /* #define MY_CPU_32BIT */ +#if defined(__riscv) \ + || defined(__riscv__) + #if __riscv_xlen == 32 + #define MY_CPU_NAME "riscv32" + #elif __riscv_xlen == 64 + #define MY_CPU_NAME "riscv64" + #else + #define MY_CPU_NAME "riscv" + #endif #endif diff -Nru 7zip-21.07+dfsg/C/DllSecur.c 7zip-22.01/C/DllSecur.c --- 7zip-21.07+dfsg/C/DllSecur.c 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/DllSecur.c 2022-07-15 08:00:00.000000000 +0000 @@ -1,5 +1,5 @@ /* DllSecur.c -- DLL loading security -2021-12-25 : Igor Pavlov : Public domain */ +2022-07-15 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -11,6 +11,10 @@ #ifndef UNDER_CE +#if defined(__GNUC__) && (__GNUC__ >= 8) + #pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags); #define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400 @@ -34,7 +38,7 @@ #endif // #define MY_CAST_FUNC (void(*)()) -#define MY_CAST_FUNC +#define MY_CAST_FUNC void My_SetDefaultDllDirectories() { diff -Nru 7zip-21.07+dfsg/C/LzmaEnc.c 7zip-22.01/C/LzmaEnc.c --- 7zip-21.07+dfsg/C/LzmaEnc.c 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/LzmaEnc.c 2022-07-15 06:00:00.000000000 +0000 @@ -1,5 +1,5 @@ /* LzmaEnc.c -- LZMA Encoder -2021-11-18: Igor Pavlov : Public domain */ +2022-07-15: Igor Pavlov : Public domain */ #include "Precomp.h" @@ -2970,6 +2970,7 @@ } +// (desiredPackSize == 0) is not allowed SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) { @@ -2990,14 +2991,10 @@ if (reInit) LzmaEnc_Init(p); LzmaEnc_InitPrices(p); - - nowPos64 = p->nowPos64; RangeEnc_Init(&p->rc); p->rc.outStream = &outStream.vt; - - if (desiredPackSize == 0) - return SZ_ERROR_OUTPUT_EOF; - + nowPos64 = p->nowPos64; + res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize); *unpackSize = (UInt32)(p->nowPos64 - nowPos64); diff -Nru 7zip-21.07+dfsg/C/Util/7zipInstall/7zipInstall.c 7zip-22.01/C/Util/7zipInstall/7zipInstall.c --- 7zip-21.07+dfsg/C/Util/7zipInstall/7zipInstall.c 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/Util/7zipInstall/7zipInstall.c 2022-07-15 08:00:00.000000000 +0000 @@ -1,5 +1,5 @@ /* 7zipInstall.c - 7-Zip Installer -2021-09-02 : Igor Pavlov : Public domain */ +2022-07-15 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -22,6 +22,10 @@ #include "resource.h" +#if defined(__GNUC__) && (__GNUC__ >= 8) + #pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + #define LLL_(quote) L##quote #define LLL(quote) LLL_(quote) @@ -70,7 +74,7 @@ #endif #endif -#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix +#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver; diff -Nru 7zip-21.07+dfsg/C/Util/7zipUninstall/7zipUninstall.c 7zip-22.01/C/Util/7zipUninstall/7zipUninstall.c --- 7zip-21.07+dfsg/C/Util/7zipUninstall/7zipUninstall.c 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/C/Util/7zipUninstall/7zipUninstall.c 2022-07-15 08:00:00.000000000 +0000 @@ -1,5 +1,5 @@ /* 7zipUninstall.c - 7-Zip Uninstaller -2021-11-24 : Igor Pavlov : Public domain */ +2022-07-15 : Igor Pavlov : Public domain */ #include "Precomp.h" @@ -17,6 +17,10 @@ #include "resource.h" +#if defined(__GNUC__) && (__GNUC__ >= 8) + #pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + #define LLL_(quote) L##quote #define LLL(quote) LLL_(quote) diff -Nru 7zip-21.07+dfsg/CPP/7zip/7zip_gcc.mak 7zip-22.01/CPP/7zip/7zip_gcc.mak --- 7zip-21.07+dfsg/CPP/7zip/7zip_gcc.mak 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/7zip_gcc.mak 2022-07-15 12:00:00.000000000 +0000 @@ -33,6 +33,11 @@ ifdef SystemDrive IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif endif ifdef IS_MINGW @@ -97,20 +102,30 @@ ifdef IS_MINGW +ifdef MSYSTEM +RM = rm -f +MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) +LIB_HTMLHELP=-lhtmlhelp +else RM = del MY_MKDIR=mkdir -LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 +DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll +endif + +LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 $(LIB_HTMLHELP) LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI) CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE # -Wno-delete-non-virtual-dtor -DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll else RM = rm -f MY_MKDIR=mkdir -p +DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) + # CFLAGS_BASE := $(CFLAGS_BASE) -D_7ZIP_ST # CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE @@ -119,9 +134,6 @@ LIB2 = -lpthread -ldl - -DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS) - endif @@ -130,9 +142,19 @@ ifdef IS_MINGW + +ifdef IS_X64 +AFLAGS_ABI = -win64 +else AFLAGS_ABI = -coff -DABI_CDECL +# -DABI_CDECL +# -DABI_LINUX +# -DABI_CDECL +endif AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $( stream; - HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream); - if (result != S_OK) - { - if (result != S_FALSE) - return result; - } + const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream); + if (result != S_OK && result != S_FALSE) + return result; _stream = stream; if (stream) { - CMyComPtr streamGetSize; - stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); - if (streamGetSize) { - if (streamGetSize->GetSize(&_size) == S_OK) - _size_Defined = true; + CMyComPtr getProps; + stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + { + // access could be changed in first myx pass + if (getProps->GetProps(&_size, + Need_CTime ? &_cTime : NULL, + Need_ATime ? &_aTime : NULL, + Need_MTime ? &_mTime : NULL, + Need_Attrib ? &_attrib : NULL) + == S_OK) + { + _size_Defined = true; + _times_Defined = true; + } + return S_OK; + } + } + { + CMyComPtr streamGetSize; + stream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) + { + if (streamGetSize->GetSize(&_size) == S_OK) + _size_Defined = true; + } + return S_OK; } - return S_OK; } - _index++; - RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - AddFileInfo(result == S_OK); + RINOK(AddFileInfo(result == S_OK)); } return S_OK; } -void CFolderInStream::AddFileInfo(bool isProcessed) +static void AddFt(CRecordVector &vec, const FILETIME &ft) { - Processed.Add(isProcessed); - Sizes.Add(_pos); - CRCs.Add(CRC_GET_DIGEST(_crc)); + vec.AddInReserved(FILETIME_To_UInt64(ft)); +} + +/* +HRESULT ReportItemProps(IArchiveUpdateCallbackArcProp *reportArcProp, + UInt32 index, UInt64 size, const UInt32 *crc) +{ + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, size); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop)); + if (crc) + { + NWindows::NCOM::PropVarEm_Set_UInt32(&prop, *crc); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop)); + } + return reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK); +} +*/ + +HRESULT CFolderInStream::AddFileInfo(bool isProcessed) +{ + // const UInt32 index = _indexes[Processed.Size()]; + Processed.AddInReserved(isProcessed); + Sizes.AddInReserved(_pos); + const UInt32 crc = CRC_GET_DIGEST(_crc); + CRCs.AddInReserved(crc); + TimesDefined.AddInReserved(_times_Defined); + if (Need_CTime) AddFt(CTimes, _cTime); + if (Need_ATime) AddFt(ATimes, _aTime); + if (Need_MTime) AddFt(MTimes, _mTime); + if (Need_Attrib) Attribs.AddInReserved(_attrib); + /* + if (isProcessed && _reportArcProp) + RINOK(ReportItemProps(_reportArcProp, index, _pos, &crc)) + */ + return _updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); } STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize) @@ -95,18 +154,10 @@ } _stream.Release(); - _index++; - AddFileInfo(true); - - _pos = 0; - _crc = CRC_INIT_VAL; - _size_Defined = false; - _size = 0; - - RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + RINOK(AddFileInfo(true)); } - if (_index >= _numFiles) + if (Processed.Size() >= _numFiles) break; RINOK(OpenStream()); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zFolderInStream.h 7zip-22.01/CPP/7zip/Archive/7z/7zFolderInStream.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zFolderInStream.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/7z/7zFolderInStream.h 2022-05-04 10:00:00.000000000 +0000 @@ -23,21 +23,37 @@ UInt64 _pos; UInt32 _crc; bool _size_Defined; + bool _times_Defined; UInt64 _size; + FILETIME _cTime; + FILETIME _aTime; + FILETIME _mTime; + UInt32 _attrib; - const UInt32 *_indexes; unsigned _numFiles; - unsigned _index; + const UInt32 *_indexes; CMyComPtr _updateCallback; HRESULT OpenStream(); - void AddFileInfo(bool isProcessed); + HRESULT AddFileInfo(bool isProcessed); public: CRecordVector Processed; CRecordVector CRCs; CRecordVector Sizes; + CRecordVector CTimes; + CRecordVector ATimes; + CRecordVector MTimes; + CRecordVector Attribs; + CRecordVector TimesDefined; + + bool Need_CTime; + bool Need_ATime; + bool Need_MTime; + bool Need_Attrib; + + // CMyComPtr _reportArcProp; MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize) STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); @@ -45,7 +61,7 @@ void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles); - bool WasFinished() const { return _index == _numFiles; } + bool WasFinished() const { return Processed.Size() == _numFiles; } UInt64 GetFullSize() const { @@ -54,6 +70,13 @@ size += Sizes[i]; return size; } + + CFolderInStream(): + Need_CTime(false), + Need_ATime(false), + Need_MTime(false), + Need_Attrib(false) + {} }; }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zHandler.cpp 7zip-22.01/CPP/7zip/Archive/7z/7zHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/7z/7zHandler.cpp 2022-03-30 12:00:00.000000000 +0000 @@ -278,7 +278,7 @@ { UInt64 value; if (v.GetItem(index, value)) - PropVarEm_Set_FileTime64(prop, value); + PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns); } bool CHandler::IsFolderEncrypted(CNum folderIndex) const diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zHandler.h 7zip-22.01/CPP/7zip/Archive/7z/7zHandler.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zHandler.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/7z/7zHandler.h 2022-05-10 11:00:00.000000000 +0000 @@ -49,9 +49,8 @@ bool _encryptHeaders; // bool _useParents; 9.26 - CBoolPair Write_CTime; - CBoolPair Write_ATime; - CBoolPair Write_MTime; + CHandlerTimeOptions TimeOptions; + CBoolPair Write_Attrib; bool _useMultiThreadMixer; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zHandlerOut.cpp 7zip-22.01/CPP/7zip/Archive/7z/7zHandlerOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zHandlerOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/7z/7zHandlerOut.cpp 2022-05-09 12:00:00.000000000 +0000 @@ -384,16 +384,16 @@ CObjectVector updateItems; - bool need_CTime = (Write_CTime.Def && Write_CTime.Val); - bool need_ATime = (Write_ATime.Def && Write_ATime.Val); - bool need_MTime = (Write_MTime.Def ? Write_MTime.Val : true); + bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val); + bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val); + bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true); bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true); if (db && !db->Files.IsEmpty()) { - if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); - if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); - if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); + if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); + if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); + if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty(); } @@ -719,6 +719,11 @@ int level = GetLevel(); CUpdateOptions options; + options.Need_CTime = need_CTime; + options.Need_ATime = need_ATime; + options.Need_MTime = need_MTime; + options.Need_Attrib = need_Attrib; + options.Method = &methodMode; options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); @@ -817,9 +822,7 @@ _encryptHeaders = false; // _useParents = false; - Write_CTime.Init(); - Write_ATime.Init(); - Write_MTime.Init(); + TimeOptions.Init(); Write_Attrib.Init(); _useMultiThreadMixer = true; @@ -954,10 +957,20 @@ return S_OK; } - if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); - if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); - if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); - + { + bool processed; + RINOK(TimeOptions.Parse(name, value, processed)); + if (processed) + { + if ( TimeOptions.Prec != (UInt32)(Int32)-1 + && TimeOptions.Prec != k_PropVar_TimePrec_0 + && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec + && TimeOptions.Prec != k_PropVar_TimePrec_100ns) + return E_INVALIDARG; + return S_OK; + } + } + if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib); if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zRegister.cpp 7zip-22.01/CPP/7zip/Archive/7z/7zRegister.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zRegister.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/7z/7zRegister.cpp 2022-05-04 11:00:00.000000000 +0000 @@ -15,7 +15,13 @@ "7z", "7z", NULL, 7, k_Signature_Dec, 0, - NArcInfoFlags::kFindSignature, - NULL); + NArcInfoFlags::kFindSignature + | NArcInfoFlags::kCTime + | NArcInfoFlags::kATime + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK(NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(NFileTimeType::kWindows) + , NULL); }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zUpdate.cpp 7zip-22.01/CPP/7zip/Archive/7z/7zUpdate.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zUpdate.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/7z/7zUpdate.cpp 2022-05-04 11:00:00.000000000 +0000 @@ -804,10 +804,20 @@ bool ParseExe; bool ParseAll; + /* + bool Need_ATime; + bool ATime_Defined; + FILETIME ATime; + */ + CAnalysis(): ParseWav(true), ParseExe(false), ParseAll(false) + /* + , Need_ATime(false) + , ATime_Defined(false) + */ {} HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode); @@ -887,6 +897,18 @@ HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze); if (result == S_OK && stream) { + /* + if (Need_ATime) + { + // access time could be changed in analysis pass + CMyComPtr getProps; + stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK) + ATime_Defined = true; + } + */ + size_t size = kAnalysisBufSize; result = ReadStream(stream, Buffer, &size); stream.Release(); @@ -1586,6 +1608,11 @@ CMyComPtr extractCallback; updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback); + /* + CMyComPtr reportArcProp; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp); + */ + // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); /* @@ -1756,6 +1783,7 @@ { CAnalysis analysis; + // analysis.Need_ATime = options.Need_ATime; if (options.AnalysisLevel == 0) { analysis.ParseWav = false; @@ -1790,7 +1818,15 @@ CFilterMode2 fm; if (useFilters) { + // analysis.ATime_Defined = false; RINOK(analysis.GetFilterGroup(i, ui, fm)); + /* + if (analysis.ATime_Defined) + { + ui.ATime = FILETIME_To_UInt64(analysis.ATime); + ui.ATime_WasReadByAnalysis = true; + } + */ } fm.Encrypted = method.PasswordIsDefined; @@ -2374,13 +2410,33 @@ RINOK(lps->SetCur()); + /* + const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size(); + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kAdd)); + } + */ + + CFolderInStream *inStreamSpec = new CFolderInStream; CMyComPtr solidInStream(inStreamSpec); + + // inStreamSpec->_reportArcProp = reportArcProp; + + inStreamSpec->Need_CTime = options.Need_CTime; + inStreamSpec->Need_ATime = options.Need_ATime; + inStreamSpec->Need_MTime = options.Need_MTime; + inStreamSpec->Need_Attrib = options.Need_Attrib; + inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); unsigned startPackIndex = newDatabase.PackSizes.Size(); UInt64 curFolderUnpackSize = totalSize; - // curFolderUnpackSize = (UInt64)(Int64)-1; + // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug RINOK(encoder.Encode( EXTERNAL_CODECS_LOC_VARS @@ -2393,8 +2449,11 @@ if (!inStreamSpec->WasFinished()) return E_FAIL; + UInt64 packSize = 0; + // const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex; for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) - lps->OutSize += newDatabase.PackSizes[startPackIndex]; + packSize += newDatabase.PackSizes[startPackIndex]; + lps->OutSize += packSize; lps->InSize += curFolderUnpackSize; // for () @@ -2403,7 +2462,9 @@ CNum numUnpackStreams = 0; UInt64 skippedSize = 0; - + UInt64 procSize = 0; + // unsigned numProcessedFiles = 0; + for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++) { const CUpdateItem &ui = updateItems[indices[i + subIndex]]; @@ -2429,14 +2490,16 @@ */ if (!inStreamSpec->Processed[subIndex]) { + // we don't add file here skippedSize += ui.Size; - continue; - // file.Name += ".locked"; + continue; // comment it for debug + // name += ".locked"; // for debug } file.Crc = inStreamSpec->CRCs[subIndex]; file.Size = inStreamSpec->Sizes[subIndex]; + procSize += file.Size; // if (file.Size >= 0) // test purposes if (file.Size != 0) { @@ -2450,6 +2513,23 @@ file.HasStream = false; } + if (inStreamSpec->TimesDefined[subIndex]) + { + if (inStreamSpec->Need_CTime) + { file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; } + if (inStreamSpec->Need_ATime + // && !ui.ATime_WasReadByAnalysis + ) + { file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; } + if (inStreamSpec->Need_MTime) + { file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; } + if (inStreamSpec->Need_Attrib) + { + file2.AttribDefined = true; + file2.Attrib = inStreamSpec->Attribs[subIndex]; + } + } + /* file.Parent = ui.ParentFolderIndex; if (ui.TreeFolderIndex >= 0) @@ -2457,9 +2537,22 @@ if (totalSecureDataSize != 0) newDatabase.SecureIDs.Add(ui.SecureIndex); */ + /* + if (reportArcProp) + { + RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size, + file.CrcDefined ? &file.Crc : NULL)) + } + */ + + // numProcessedFiles++; newDatabase.AddFile(file, file2, name); } + // it's optional check to ensure that sizes are correct + if (procSize != curFolderUnpackSize) + return E_FAIL; + // numUnpackStreams = 0 is very bad case for locked files // v3.13 doesn't understand it. newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); @@ -2470,6 +2563,44 @@ complexity -= skippedSize; RINOK(updateCallback->SetTotal(complexity)); } + + /* + if (reportArcProp) + { + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + { + NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop)); + } + RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK)); + } + */ + /* + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kBlockIndex, (UInt32)folderIndex, + NUpdateNotifyOp::kOpFinished)); + } + */ } } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zUpdate.h 7zip-22.01/CPP/7zip/Archive/7z/7zUpdate.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/7z/7zUpdate.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/7z/7zUpdate.h 2022-02-06 08:00:00.000000000 +0000 @@ -62,6 +62,8 @@ bool ATimeDefined; bool MTimeDefined; + // bool ATime_WasReadByAnalysis; + // int SecureIndex; // 0 means (no_security) bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } @@ -76,6 +78,7 @@ CTimeDefined(false), ATimeDefined(false), MTimeDefined(false) + // , ATime_WasReadByAnalysis(false) // SecureIndex(0) {} void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); } @@ -103,6 +106,11 @@ bool RemoveSfxBlock; bool MultiThreadMixer; + bool Need_CTime; + bool Need_ATime; + bool Need_MTime; + bool Need_Attrib; + CUpdateOptions(): Method(NULL), HeaderMethod(NULL), @@ -114,7 +122,11 @@ SolidExtension(false), UseTypeSorting(true), RemoveSfxBlock(false), - MultiThreadMixer(true) + MultiThreadMixer(true), + Need_CTime(false), + Need_ATime(false), + Need_MTime(false), + Need_Attrib(false) {} }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/ApfsHandler.cpp 7zip-22.01/CPP/7zip/Archive/ApfsHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/ApfsHandler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/ApfsHandler.cpp 2022-07-11 12:00:00.000000000 +0000 @@ -0,0 +1,3825 @@ +// ApfsHandler.cpp + +#include "StdAfx.h" + +// #define SHOW_DEBUG_INFO + +#ifdef SHOW_DEBUG_INFO +#include +#define PRF(x) x +#else +#define PRF(x) +#endif + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyLinux.h" +#include "../../Common/UTFConvert.h" + +#include "../../Windows/PropVariantConv.h" +#include "../../Windows/PropVariantUtils.h" +#include "../../Windows/TimeUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamObjects.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#include "Common/ItemNameUtils.h" + +#include "HfsHandler.h" + +// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files. +#define APFS_SHOW_ALT_STREAMS + +#define VI_MINUS1 ((unsigned)(int)-1) +#define IsViDef(x) ((int)(x) != -1) +#define IsViNotDef(x) ((int)(x) == -1) + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); + +namespace NArchive { +namespace NApfs { + +#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10)))) + +static void ConvertByteToHex(unsigned val, char *s) +{ + unsigned t; + t = val >> 4; + s[0] = ValToHex(t); + t = val & 0xF; + s[1] = ValToHex(t); +} + +struct CUuid +{ + Byte Data[16]; + + void SetHex_To_str(char *s) const + { + for (unsigned i = 0; i < 16; i++) + ConvertByteToHex(Data[i], s + i * 2); + s[32] = 0; + } + + void AddHexToString(UString &dest) const + { + char temp[32 + 4]; + SetHex_To_str(temp); + dest += temp; + } + + void SetFrom(const Byte *p) { memcpy(Data, p, 16); } +}; + + +typedef UInt64 oid_t; +typedef UInt64 xid_t; +typedef Int64 paddr_t; + +#define G64o G64 +#define G64x G64 +// #define G64a G64 + +/* +struct prange_t +{ + paddr_t start_paddr; + UInt64 block_count; + + void Parse(const Byte *p) + { + G64a (0, start_paddr); + G64 (8, block_count); + } +}; +*/ + +#define OBJECT_TYPE_NX_SUPERBLOCK 0x1 +#define OBJECT_TYPE_BTREE 0x2 +#define OBJECT_TYPE_BTREE_NODE 0x3 +/* +#define OBJECT_TYPE_SPACEMAN 0x5 +#define OBJECT_TYPE_SPACEMAN_CAB 0x6 +#define OBJECT_TYPE_SPACEMAN_CIB 0x7 +#define OBJECT_TYPE_SPACEMAN_BITMAP 0x8 +#define OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x9 +#define OBJECT_TYPE_EXTENT_LIST_TREE 0xa +*/ +#define OBJECT_TYPE_OMAP 0xb +/* +#define OBJECT_TYPE_CHECKPOINT_MAP 0xc +*/ +#define OBJECT_TYPE_FS 0xd +#define OBJECT_TYPE_FSTREE 0xe +/* +#define OBJECT_TYPE_BLOCKREFTREE 0xf +#define OBJECT_TYPE_SNAPMETATREE 0x10 +#define OBJECT_TYPE_NX_REAPER 0x11 +#define OBJECT_TYPE_NX_REAP_LIST 0x12 +#define OBJECT_TYPE_OMAP_SNAPSHOT 0x13 +#define OBJECT_TYPE_EFI_JUMPSTART 0x14 +#define OBJECT_TYPE_FUSION_MIDDLE_TREE 0x15 +#define OBJECT_TYPE_NX_FUSION_WBC 0x16 +#define OBJECT_TYPE_NX_FUSION_WBC_LIST 0x17 +#define OBJECT_TYPE_ER_STATE 0x18 +#define OBJECT_TYPE_GBITMAP 0x19 +#define OBJECT_TYPE_GBITMAP_TREE 0x1a +#define OBJECT_TYPE_GBITMAP_BLOCK 0x1b +#define OBJECT_TYPE_ER_RECOVERY_BLOCK 0x1c +#define OBJECT_TYPE_SNAP_META_EXT 0x1d +#define OBJECT_TYPE_INTEGRITY_META 0x1e +#define OBJECT_TYPE_FEXT_TREE 0x1f +#define OBJECT_TYPE_RESERVED_20 0x20 + +#define OBJECT_TYPE_INVALID 0x0 +#define OBJECT_TYPE_TEST 0xff +#define OBJECT_TYPE_CONTAINER_KEYBAG 'keys' +#define OBJECT_TYPE_VOLUME_KEYBAG 'recs' +#define OBJECT_TYPE_MEDIA_KEYBAG 'mkey' + +#define OBJ_VIRTUAL 0x0 +#define OBJ_EPHEMERAL 0x80000000 +#define OBJ_PHYSICAL 0x40000000 + +#define OBJ_NOHEADER 0x20000000 +#define OBJ_ENCRYPTED 0x10000000 +#define OBJ_NONPERSISTENT 0x08000000 +*/ +#define OBJECT_TYPE_MASK 0x0000ffff +/* +#define OBJECT_TYPE_FLAGS_MASK 0xffff0000 +#define OBJ_STORAGETYPE_MASK 0xc0000000 +#define OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000 +*/ + +// #define MAX_CKSUM_SIZE 8 + +// obj_phys_t +struct CPhys +{ + // Byte cksum[MAX_CKSUM_SIZE]; + oid_t oid; + xid_t xid; + UInt32 type; + UInt32 subtype; + + UInt32 GetType() const { return type & OBJECT_TYPE_MASK; } + void Parse(const Byte *p); +}; + +void CPhys::Parse(const Byte *p) +{ + // memcpy(cksum, p, MAX_CKSUM_SIZE); + G64o (8, oid); + G64x (0x10, xid); + G32 (0x18, type); + G32 (0x1C, subtype); +} + +#define NX_MAX_FILE_SYSTEMS 100 +/* +#define NX_EPH_INFO_COUNT 4 +#define NX_EPH_MIN_BLOCK_COUNT 8 +#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4 +#define NX_TX_MIN_CHECKPOINT_COUNT 4 +#define NX_EPH_INFO_VERSION_1 1 +*/ + +/* +typedef enum +{ + NX_CNTR_OBJ_CKSUM_SET = 0, + NX_CNTR_OBJ_CKSUM_FAIL = 1, + NX_NUM_COUNTERS = 32 +} counter_id_t; +*/ + +/* Incompatible volume feature flags */ +#define APFS_INCOMPAT_CASE_INSENSITIVE (1 << 0) +/* +#define APFS_INCOMPAT_DATALESS_SNAPS (1 << 1) +#define APFS_INCOMPAT_ENC_ROLLED (1 << 2) +*/ +#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE (1 << 3) +/* +#define APFS_INCOMPAT_INCOMPLETE_RESTORE (1 << 4) +#define APFS_INCOMPAT_SEALED_VOLUME (1 << 5) +#define APFS_INCOMPAT_RESERVED_40 (1 << 6) +*/ + +static const char * const g_APFS_INCOMPAT_Flags[] = +{ + "CASE_INSENSITIVE" + , "DATALESS_SNAPS" + , "ENC_ROLLED" + , "NORMALIZATION_INSENSITIVE" + , "INCOMPLETE_RESTORE" + , "SEALED_VOLUME" +}; + +/* +#define APFS_SUPPORTED_INCOMPAT_MASK \ + ( APFS_INCOMPAT_CASE_INSENSITIVE \ + | APFS_INCOMPAT_DATALESS_SNAPS \ + | APFS_INCOMPAT_ENC_ROLLED \ + | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \ + | APFS_INCOMPAT_INCOMPLETE_RESTORE \ + | APFS_INCOMPAT_SEALED_VOLUME \ + | APFS_INCOMPAT_RESERVED_40 \ +) +*/ + +// superblock_t +struct CSuperBlock +{ + // CPhys o; + // UInt32 magic; + UInt32 block_size; + unsigned block_size_Log; + UInt64 block_count; + // UInt64 features; + // UInt64 readonly_compatible_features; + // UInt64 incompatible_features; + CUuid uuid; + /* + oid_t next_oid; + xid_t next_xid; + UInt32 xp_desc_blocks; + UInt32 xp_data_blocks; + paddr_t xp_desc_base; + paddr_t xp_data_base; + UInt32 xp_desc_next; + UInt32 xp_data_next; + UInt32 xp_desc_index; + UInt32 xp_desc_len; + UInt32 xp_data_index; + UInt32 xp_data_len; + oid_t spaceman_oid; + */ + oid_t omap_oid; + // oid_t reaper_oid; + // UInt32 test_type; + UInt32 max_file_systems; + // oid_t fs_oid[NX_MAX_FILE_SYSTEMS]; + /* + UInt64 counters[NX_NUM_COUNTERS]; // counter_id_t + prange_t blocked_out_prange; + oid_t evict_mapping_tree_oid; + UInt64 flags; + paddr_t efi_jumpstart; + CUuid fusion_uuid; + prange_t keylocker; + UInt64 ephemeral_info[NX_EPH_INFO_COUNT]; + oid_t test_oid; + oid_t fusion_mt_oid; + oid_t fusion_wbc_oid; + prange_t fusion_wbc; + UInt64 newest_mounted_version; + prange_t mkb_locker; + */ + + bool Parse(const Byte *p); +}; + +struct CSuperBlock2 +{ + oid_t fs_oid[NX_MAX_FILE_SYSTEMS]; + void Parse(const Byte *p) + { + for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++) + { + G64o (0xb8 + i * 8, fs_oid[i]); + } + } +}; + + +// we include one additional byte of next field (block_size) +static const unsigned k_SignatureOffset = 32; +static const Byte k_Signature[] = { 'N', 'X', 'S', 'B', 0 }; + +// size must be 4 bytes aligned +static UInt64 Fletcher64(const Byte *data, size_t size) +{ + const UInt32 kMax32 = 0xffffffff; + const UInt64 val = 0; // startVal + UInt64 a = val & kMax32; + UInt64 b = (val >> 32) & kMax32; + for (size_t i = 0; i < size; i += 4) + { + a += GetUi32(data + i); + b += a; + } + a %= kMax32; + b %= kMax32; + b = (UInt32)(kMax32 - ((a + b) % kMax32)); + a = (UInt32)(kMax32 - ((a + b) % kMax32)); + return (a << 32) | b; +} + +static bool CheckFletcher64(const Byte *p, size_t size) +{ + const UInt64 calculated_checksum = Fletcher64(p + 8, size - 8); + const UInt64 stored_checksum = Get64(p); + return (stored_checksum == calculated_checksum); +} + + +static unsigned GetLogSize(UInt32 size) +{ + unsigned k; + for (k = 0; k < 32; k++) + if (((UInt32)1 << k) == size) + return k; + return k; +} + +static const unsigned kApfsHeaderSize = 1 << 12; + +// #define OID_INVALID 0 +#define OID_NX_SUPERBLOCK 1 +// #define OID_RESERVED_COUNT 1024 +// This range of identifiers is reserved for physical, virtual, and ephemeral objects + +bool CSuperBlock::Parse(const Byte *p) +{ + CPhys o; + o.Parse(p); + if (o.oid != OID_NX_SUPERBLOCK) + return false; + if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) + return false; + if (o.subtype != 0) + return false; + if (memcmp(p + k_SignatureOffset, k_Signature, 4) != 0) + return false; + if (!CheckFletcher64(p, kApfsHeaderSize)) + return false; + + G32 (0x24, block_size); + { + unsigned logSize = GetLogSize(block_size); + if (logSize < 12 || logSize > 16) + return false; + block_size_Log = logSize; + } + + G64 (0x28, block_count); + + static const UInt64 kArcSize_MAX = (UInt64)1 << 62; + if (block_count > (kArcSize_MAX >> block_size_Log)) + return false; + + // G64 (0x30, features); + // G64 (0x38, readonly_compatible_features); + // G64 (0x40, incompatible_features); + uuid.SetFrom(p + 0x48); + /* + G64o (0x58, next_oid); + G64x (0x60, next_xid); + G32 (0x68, xp_desc_blocks); + G32 (0x6c, xp_data_blocks); + G64a (0x70, xp_desc_base); + G64a (0x78, xp_data_base); + G32 (0x80, xp_desc_next); + G32 (0x84, xp_data_next); + G32 (0x88, xp_desc_index); + G32 (0x8c, xp_desc_len); + G32 (0x90, xp_data_index); + G32 (0x94, xp_data_len); + G64o (0x98, spaceman_oid); + */ + G64o (0xa0, omap_oid); + // G64o (0xa8, reaper_oid); + // G32 (0xb0, test_type); + G32 (0xb4, max_file_systems); + if (max_file_systems > NX_MAX_FILE_SYSTEMS) + return false; + /* + { + for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++) + { + G64o (0xb8 + i * 8, fs_oid[i]); + } + } + */ + /* + { + for (unsigned i = 0; i < NX_NUM_COUNTERS; i++) + { + G64 (0x3d8 + i * 8, counters[i]); + } + } + blocked_out_prange.Parse(p + 0x4d8); + G64o (0x4e8, evict_mapping_tree_oid); + #define NX_CRYPTO_SW 0x00000004LL + G64 (0x4f0, flags); + G64a (0x4f8, efi_jumpstart); + fusion_uuid.SetFrom(p + 0x500); + keylocker.Parse(p + 0x510); + { + for (unsigned i = 0; i < NX_EPH_INFO_COUNT; i++) + { + G64 (0x520 + i * 8, ephemeral_info[i]); + } + } + G64o (0x540, test_oid); + G64o (0x548, fusion_mt_oid); + G64o (0x550, fusion_wbc_oid); + fusion_wbc.Parse(p + 0x558); + G64 (0x568, newest_mounted_version); // decimal 1412141 001 000 000 + mkb_locker.Parse(p + 0x570); + */ + + return true; +} + + + +struct C_omap_phys +{ + // om_ prefix + // CPhys o; + /* + UInt32 flags; + UInt32 snap_count; + UInt32 tree_type; + UInt32 snapshot_tree_type; + */ + oid_t tree_oid; + /* + oid_t snapshot_tree_oid; + xid_t most_recent_snap; + xid_t pending_revert_min; + xid_t pending_revert_max; + */ + bool Parse(const Byte *p, size_t size, oid_t oid); +}; + +bool C_omap_phys::Parse(const Byte *p, size_t size, oid_t oid) +{ + CPhys o; + if (!CheckFletcher64(p, size)) + return false; + o.Parse(p); + if (o.GetType() != OBJECT_TYPE_OMAP) + return false; + if (o.oid != oid) + return false; + /* + G32 (0x20, flags); + G32 (0x24, snap_count); + G32 (0x28, tree_type); + G32 (0x2C, snapshot_tree_type); + */ + G64o (0x30, tree_oid); + /* + G64o (0x38, snapshot_tree_oid); + G64x (0x40, most_recent_snap); + G64x (0x48, pending_revert_min); + G64x (0x50, pending_revert_max); + */ + return true; +} + + +// #define BTOFF_INVALID 0xffff +/* This value is stored in the off field of nloc_t to indicate that +there's no offset. For example, the last entry in a free +list has no entry after it, so it uses this value for its off field. */ + +// A location within a B-tree node +struct nloc +{ + UInt16 off; + UInt16 len; + + void Parse(const Byte *p) + { + G16 (0, off); + G16 (2, len); + } + UInt32 GetEnd() const { return (UInt32)off + len; } + bool CheckOverLimit(UInt32 limit) + { + return off < limit && len <= limit - off; + } +}; + + +// The location, within a B-tree node, of a key and value +struct kvloc +{ + nloc k; + nloc v; + + void Parse(const Byte *p) + { + k.Parse(p); + v.Parse(p + 4); + } +}; + + +// The location, within a B-tree node, of a fixed-size key and value +struct kvoff +{ + UInt16 k; + UInt16 v; + + void Parse(const Byte *p) + { + G16 (0, k); + G16 (2, v); + } +}; + + +#define BTNODE_ROOT (1 << 0) +#define BTNODE_LEAF (1 << 1) +#define BTNODE_FIXED_KV_SIZE (1 << 2) +/* +#define BTNODE_HASHED (1 << 3) +#define BTNODE_NOHEADER (1 << 4) +#define BTNODE_CHECK_KOFF_INVAL (1 << 15) +*/ + +static const unsigned k_Toc_offset = 0x38; + +// btree_node_phys +struct CBTreeNodePhys +{ + // btn_ prefix + CPhys o; + UInt16 flags; + UInt16 level; // the number of child levels below this node. 0 - for a leaf node, 1 for the immediate parent of a leaf node + UInt32 nkeys; // The number of keys stored in this node. + nloc table_space; + /* + nloc free_space; + nloc key_free_list; + nloc val_free_list; + */ + + bool Is_FIXED_KV_SIZE() const { return (flags & BTNODE_FIXED_KV_SIZE) != 0; } + + bool Parse(const Byte *p, size_t size) + { + if (!CheckFletcher64(p, size)) + return false; + o.Parse(p); + G16 (0x20, flags); + G16 (0x22, level); + G32 (0x24, nkeys); + table_space.Parse(p + 0x28); + /* + free_space.Parse(p + 0x2C); + key_free_list.Parse(p + 0x30); + val_free_list.Parse(p + 0x34); + */ + return true; + } +}; + +/* +#define BTREE_UINT64_KEYS (1 << 0) +#define BTREE_SEQUENTIAL_INSERT (1 << 1) +#define BTREE_ALLOW_GHOSTS (1 << 2) +*/ +#define BTREE_EPHEMERAL (1 << 3) +#define BTREE_PHYSICAL (1 << 4) +/* +#define BTREE_NONPERSISTENT (1 << 5) +#define BTREE_KV_NONALIGNED (1 << 6) +#define BTREE_HASHED (1 << 7) +*/ + +/* + BTREE_EPHEMERAL: The nodes in the B-tree use ephemeral object identifiers to link to child nodes + BTREE_PHYSICAL : The nodes in the B-tree use physical object identifiers to link to child nodes. + If neither flag is set, nodes in the B-tree use virtual object + identifiers to link to their child nodes. +*/ + +// Static information about a B-tree. +struct btree_info_fixed +{ + UInt32 flags; + UInt32 node_size; + UInt32 key_size; + UInt32 val_size; + + void Parse(const Byte *p) + { + G32 (0, flags); + G32 (4, node_size); + G32 (8, key_size); + G32 (12, val_size); + } +}; + +static const unsigned k_btree_info_Size = 0x28; + +struct btree_info +{ + btree_info_fixed fixed; + UInt32 longest_key; + UInt32 longest_val; + UInt64 key_count; + UInt64 node_count; + + bool Is_EPHEMERAL() const { return (fixed.flags & BTREE_EPHEMERAL) != 0; } + bool Is_PHYSICAL() const { return (fixed.flags & BTREE_PHYSICAL) != 0; } + + void Parse(const Byte *p) + { + fixed.Parse(p); + G32 (0x10, longest_key); + G32 (0x14, longest_val); + G64 (0x18, key_count); + G64 (0x20, node_count); + } +}; + + +/* +typedef UInt32 cp_key_class_t; +typedef UInt32 cp_key_os_version_t; +typedef UInt16 cp_key_revision_t; +typedef UInt32 crypto_flags_t; + +struct wrapped_meta_crypto_state +{ + UInt16 major_version; + UInt16 minor_version; + crypto_flags_t cpflags; + cp_key_class_t persistent_class; + cp_key_os_version_t key_os_version; + cp_key_revision_t key_revision; + // UInt16 unused; + + void Parse(const Byte *p) + { + G16 (0, major_version); + G16 (2, minor_version); + G32 (4, cpflags); + G32 (8, persistent_class); + G32 (12, key_os_version); + G16 (16, key_revision); + } +}; +*/ + + +#define APFS_MODIFIED_NAMELEN 32 +#define sizeof__apfs_modified_by_t (APFS_MODIFIED_NAMELEN + 16); + +struct apfs_modified_by_t +{ + Byte id[APFS_MODIFIED_NAMELEN]; + UInt64 timestamp; + xid_t last_xid; + + void Parse(const Byte *p) + { + memcpy(id, p, APFS_MODIFIED_NAMELEN); + p += APFS_MODIFIED_NAMELEN; + G64 (0, timestamp); + G64x (8, last_xid); + } +}; + + +#define APFS_MAX_HIST 8 +#define APFS_VOLNAME_LEN 256 + +struct CApfs +{ + // apfs_ + CPhys o; + // UInt32 magic; + UInt32 fs_index; // e index of the object identifier for this volume's file system in the container's array of file systems. + // UInt64 features; + // UInt64 readonly_compatible_features; + UInt64 incompatible_features; + UInt64 unmount_time; + // UInt64 fs_reserve_block_count; + // UInt64 fs_quota_block_count; + UInt64 fs_alloc_count; + // wrapped_meta_crypto_state meta_crypto; + // UInt32 root_tree_type; + /* The type of the root file-system tree. + The value is typically OBJ_VIRTUAL | OBJECT_TYPE_BTREE, + with a subtype of OBJECT_TYPE_FSTREE */ + + // UInt32 extentref_tree_type; + // UInt32 snap_meta_tree_type; + oid_t omap_oid; + oid_t root_tree_oid; + /* + oid_t extentref_tree_oid; + oid_t snap_meta_tree_oid; + xid_t revert_to_xid; + oid_t revert_to_sblock_oid; + UInt64 next_obj_id; + */ + UInt64 num_files; + UInt64 num_directories; + UInt64 num_symlinks; + UInt64 num_other_fsobjects; + UInt64 num_snapshots; + UInt64 total_blocks_alloced; + UInt64 total_blocks_freed; + CUuid vol_uuid; + UInt64 last_mod_time; + UInt64 fs_flags; + apfs_modified_by_t formatted_by; + apfs_modified_by_t modified_by[APFS_MAX_HIST]; + Byte volname[APFS_VOLNAME_LEN]; + /* + UInt32 next_doc_id; + UInt16 role; // APFS_VOL_ROLE_NONE APFS_VOL_ROLE_SYSTEM .... + UInt16 reserved; + xid_t root_to_xid; + oid_t er_state_oid; + UInt64 cloneinfo_id_epoch; + UInt64 cloneinfo_xid; + oid_t snap_meta_ext_oid; + CUuid volume_group_id; + oid_t integrity_meta_oid; + oid_t fext_tree_oid; + UInt32 fext_tree_type; + UInt32 reserved_type; + oid_t reserved_oid; + */ + + UInt64 GetTotalItems() const + { + return num_files + num_directories + num_symlinks + num_other_fsobjects; + } + + bool IsHashedName() const + { + return + (incompatible_features & APFS_INCOMPAT_CASE_INSENSITIVE) != 0 || + (incompatible_features & APFS_INCOMPAT_NORMALIZATION_INSENSITIVE) != 0; + } + + bool Parse(const Byte *p, size_t size); +}; + + +bool CApfs::Parse(const Byte *p, size_t size) +{ + o.Parse(p); + if (Get32(p + 32) != 0x42535041) // { 'A', 'P', 'S', 'B' }; + return false; + if (o.GetType() != OBJECT_TYPE_FS) + return false; + if (!CheckFletcher64(p, size)) + return false; + // if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) return false; + + G32 (0x24, fs_index); + // G64 (0x28, features); + // G64 (0x30, readonly_compatible_features); + G64 (0x38, incompatible_features); + G64 (0x40, unmount_time); + // G64 (0x48, fs_reserve_block_count); + // G64 (0x50, fs_quota_block_count); + G64 (0x58, fs_alloc_count); + // meta_crypto.Parse(p + 0x60); + // G32 (0x74, root_tree_type); + // G32 (0x78, extentref_tree_type); + // G32 (0x7C, snap_meta_tree_type); + + G64o (0x80, omap_oid); + G64o (0x88, root_tree_oid); + /* + G64o (0x90, extentref_tree_oid); + G64o (0x98, snap_meta_tree_oid); + G64x (0xa0, revert_to_xid); + G64o (0xa8, revert_to_sblock_oid); + G64 (0xb0, next_obj_id); + */ + G64 (0xb8, num_files); + G64 (0xc0, num_directories); + G64 (0xc8, num_symlinks); + G64 (0xd0, num_other_fsobjects); + G64 (0xd8, num_snapshots); + G64 (0xe0, total_blocks_alloced); + G64 (0xe8, total_blocks_freed); + vol_uuid.SetFrom(p + 0xf0); + G64 (0x100, last_mod_time); + G64 (0x108, fs_flags); + p += 0x110; + formatted_by.Parse(p); + p += sizeof__apfs_modified_by_t; + for (unsigned i = 0; i < APFS_MAX_HIST; i++) + { + modified_by[i].Parse(p); + p += sizeof__apfs_modified_by_t; + } + memcpy(volname, p, APFS_VOLNAME_LEN); + p += APFS_VOLNAME_LEN; + /* + G32 (0, next_doc_id); + G16 (4, role); + G16 (6, reserved); + G64x (8, root_to_xid); + G64o (0x10, er_state_oid); + G64 (0x18, cloneinfo_id_epoch); + G64 (0x20, cloneinfo_xid); + G64o (0x28, snap_meta_ext_oid); + volume_group_id.SetFrom(p + 0x30); + G64o (0x40, integrity_meta_oid); + G64o (0x48, fext_tree_oid); + G32 (0x50, fext_tree_type); + G32 (0x54, reserved_type); + G64o (0x58, reserved_oid); + */ + return true; +} + + +#define OBJ_ID_MASK 0x0fffffffffffffff +/* +#define OBJ_TYPE_MASK 0xf000000000000000 +#define SYSTEM_OBJ_ID_MARK 0x0fffffff00000000 +*/ +#define OBJ_TYPE_SHIFT 60 + +typedef enum +{ + APFS_TYPE_ANY = 0, + APFS_TYPE_SNAP_METADATA = 1, + APFS_TYPE_EXTENT = 2, + APFS_TYPE_INODE = 3, + APFS_TYPE_XATTR = 4, + APFS_TYPE_SIBLING_LINK = 5, + APFS_TYPE_DSTREAM_ID = 6, + APFS_TYPE_CRYPTO_STATE = 7, + APFS_TYPE_FILE_EXTENT = 8, + APFS_TYPE_DIR_REC = 9, + APFS_TYPE_DIR_STATS = 10, + APFS_TYPE_SNAP_NAME = 11, + APFS_TYPE_SIBLING_MAP = 12, + APFS_TYPE_FILE_INFO = 13, + APFS_TYPE_MAX_VALID = 13, + APFS_TYPE_MAX = 15, + APFS_TYPE_INVALID = 15 +} j_obj_types; + + +struct j_key_t +{ + UInt64 obj_id_and_type; + + void Parse(const Byte *p) { G64(0, obj_id_and_type); } + unsigned GetType() const { return (unsigned)(obj_id_and_type >> OBJ_TYPE_SHIFT); } + UInt64 GetID() const { return obj_id_and_type & OBJ_ID_MASK; } +}; + + + +#define J_DREC_LEN_MASK 0x000003ff +/* +#define J_DREC_HASH_MASK 0xfffff400 +#define J_DREC_HASH_SHIFT 10 +*/ + +static const unsigned k_SizeOf_j_drec_val = 0x12; + +struct j_drec_val +{ + UInt64 file_id; + UInt64 date_added; /* The time that this directory entry was added to the directory. + It's not updated when modifying the directory entry for example, + by renaming a file without moving it to a different directory. */ + UInt16 flags; + + // bool IsFlags_File() const { return flags == MY_LIN_DT_REG; } + bool IsFlags_Unknown() const { return flags == MY_LIN_DT_UNKNOWN; } + bool IsFlags_Dir() const { return flags == MY_LIN_DT_DIR; } + + // uint8_t xfields[]; + void Parse(const Byte *p) + { + G64 (0, file_id); + G64 (8, date_added); + G16 (0x10, flags); + } +}; + + +struct CItem +{ + // j_key_t hdr; + UInt64 ParentId; + AString Name; + j_drec_val Val; + + unsigned ParentItemIndex; + unsigned RefIndex; + // unsigned iNode_Index; + + void Clear() + { + Name.Empty(); + ParentItemIndex = VI_MINUS1; + RefIndex = VI_MINUS1; + } +}; + + +/* +#define INVALID_INO_NUM 0 +#define ROOT_DIR_PARENT 1 // parent for "root" and "private-dir", there's no inode on disk with this inode number. +*/ +#define ROOT_DIR_INO_NUM 2 // "root" - parent for all main files +#define PRIV_DIR_INO_NUM 3 // "private-dir" +/* +#define SNAP_DIR_INO_NUM 6 // the directory where snapshot metadata is stored. Snapshot inodes are stored in the snapshot metedata tree. +#define PURGEABLE_DIR_INO_NUM 7 +#define MIN_USER_INO_NUM 16 + +#define UNIFIED_ID_SPACE_MARK 0x0800000000000000 +*/ + +typedef enum +{ +/* +INODE_IS_APFS_PRIVATE = 0x00000001, +INODE_MAINTAIN_DIR_STATS = 0x00000002, +INODE_DIR_STATS_ORIGIN = 0x00000004, +INODE_PROT_CLASS_EXPLICIT = 0x00000008, +INODE_WAS_CLONED = 0x00000010, +INODE_FLAG_UNUSED = 0x00000020, +INODE_HAS_SECURITY_EA = 0x00000040, +INODE_BEING_TRUNCATED = 0x00000080, +INODE_HAS_FINDER_INFO = 0x00000100, +INODE_IS_SPARSE = 0x00000200, +INODE_WAS_EVER_CLONED = 0x00000400, +INODE_ACTIVE_FILE_TRIMMED = 0x00000800, +INODE_PINNED_TO_MAIN = 0x00001000, +INODE_PINNED_TO_TIER2 = 0x00002000, +*/ +INODE_HAS_RSRC_FORK = 0x00004000, +/* +INODE_NO_RSRC_FORK = 0x00008000, +INODE_ALLOCATION_SPILLEDOVER = 0x00010000, +INODE_FAST_PROMOTE = 0x00020000, +*/ +INODE_HAS_UNCOMPRESSED_SIZE = 0x00040000, +/* +INODE_IS_PURGEABLE = 0x00080000, +INODE_WANTS_TO_BE_PURGEABLE = 0x00100000, +INODE_IS_SYNC_ROOT = 0x00200000, +INODE_SNAPSHOT_COW_EXEMPTION = 0x00400000, + + +INODE_INHERITED_INTERNAL_FLAGS = \ + ( INODE_MAINTAIN_DIR_STATS \ + | INODE_SNAPSHOT_COW_EXEMPTION), + +INODE_CLONED_INTERNAL_FLAGS = \ + ( INODE_HAS_RSRC_FORK \ + | INODE_NO_RSRC_FORK \ + | INODE_HAS_FINDER_INFO \ + | INODE_SNAPSHOT_COW_EXEMPTION), +*/ +} +j_inode_flags; + + +/* +#define APFS_VALID_INTERNAL_INODE_FLAGS \ +( INODE_IS_APFS_PRIVATE \ +| INODE_MAINTAIN_DIR_STATS \ +| INODE_DIR_STATS_ORIGIN \ +| INODE_PROT_CLASS_EXPLICIT \ +| INODE_WAS_CLONED \ +| INODE_HAS_SECURITY_EA \ +| INODE_BEING_TRUNCATED \ +| INODE_HAS_FINDER_INFO \ +| INODE_IS_SPARSE \ +| INODE_WAS_EVER_CLONED \ +| INODE_ACTIVE_FILE_TRIMMED \ +| INODE_PINNED_TO_MAIN \ +| INODE_PINNED_TO_TIER2 \ +| INODE_HAS_RSRC_FORK \ +| INODE_NO_RSRC_FORK \ +| INODE_ALLOCATION_SPILLEDOVER \ +| INODE_FAST_PROMOTE \ +| INODE_HAS_UNCOMPRESSED_SIZE \ +| INODE_IS_PURGEABLE \ +| INODE_WANTS_TO_BE_PURGEABLE \ +| INODE_IS_SYNC_ROOT \ +| INODE_SNAPSHOT_COW_EXEMPTION) + +#define APFS_INODE_PINNED_MASK (INODE_PINNED_TO_MAIN | INODE_PINNED_TO_TIER2) +*/ + +static const char * const g_INODE_Flags[] = +{ + "IS_APFS_PRIVATE" + , "MAINTAIN_DIR_STATS" + , "DIR_STATS_ORIGIN" + , "PROT_CLASS_EXPLICIT" + , "WAS_CLONED" + , "FLAG_UNUSED" + , "HAS_SECURITY_EA" + , "BEING_TRUNCATED" + , "HAS_FINDER_INFO" + , "IS_SPARSE" + , "WAS_EVER_CLONED" + , "ACTIVE_FILE_TRIMMED" + , "PINNED_TO_MAIN" + , "PINNED_TO_TIER2" + , "HAS_RSRC_FORK" + , "NO_RSRC_FORK" + , "ALLOCATION_SPILLEDOVER" + , "FAST_PROMOTE" + , "HAS_UNCOMPRESSED_SIZE" + , "IS_PURGEABLE" + , "WANTS_TO_BE_PURGEABLE" + , "IS_SYNC_ROOT" + , "SNAPSHOT_COW_EXEMPTION" +}; + + +// bsd stat.h +/* +#define MY__UF_SETTABLE 0x0000ffff // mask of owner changeable flags +#define MY__UF_NODUMP 0x00000001 // do not dump file +#define MY__UF_IMMUTABLE 0x00000002 // file may not be changed +#define MY__UF_APPEND 0x00000004 // writes to file may only append +#define MY__UF_OPAQUE 0x00000008 // directory is opaque wrt. union +#define MY__UF_NOUNLINK 0x00000010 // file entry may not be removed or renamed Not implement in MacOS +#define MY__UF_COMPRESSED 0x00000020 // file entry is compressed +#define MY__UF_TRACKED 0x00000040 // notify about file entry changes +#define MY__UF_DATAVAULT 0x00000080 // entitlement required for reading and writing +#define MY__UF_HIDDEN 0x00008000 // file entry is hidden + +#define MY__SF_SETTABLE 0xffff0000 // mask of superuser changeable flags +#define MY__SF_ARCHIVED 0x00010000 // file is archived +#define MY__SF_IMMUTABLE 0x00020000 // file may not be changed +#define MY__SF_APPEND 0x00040000 // writes to file may only append +#define MY__SF_RESTRICTED 0x00080000 // entitlement required for writing +#define MY__SF_NOUNLINK 0x00100000 // file entry may not be removed, renamed or used as mount point +#define MY__SF_SNAPSHOT 0x00200000 // snapshot inode +Not implement in MacOS +*/ + +static const char * const g_INODE_BSD_Flags[] = +{ + "UF_NODUMP" + , "UF_IMMUTABLE" + , "UF_APPEND" + , "UF_OPAQUE" + , "UF_NOUNLINK" + , "UF_COMPRESSED" + , "UF_TRACKED" + , "UF_DATAVAULT" + , NULL, NULL, NULL, NULL + , NULL, NULL, NULL + , "UF_HIDDEN" + + , "SF_ARCHIVE" + , "SF_IMMUTABLE" + , "SF_APPEND" + , "SF_RESTRICTED" + , "SF_NOUNLINK" + , "SF_SNAPSHOT" +}; + +/* +#define INO_EXT_TYPE_SNAP_XID 1 +#define INO_EXT_TYPE_DELTA_TREE_OID 2 +#define INO_EXT_TYPE_DOCUMENT_ID 3 +*/ +#define INO_EXT_TYPE_NAME 4 +/* +#define INO_EXT_TYPE_PREV_FSIZE 5 +#define INO_EXT_TYPE_RESERVED_6 6 +#define INO_EXT_TYPE_FINDER_INFO 7 +*/ +#define INO_EXT_TYPE_DSTREAM 8 +/* +#define INO_EXT_TYPE_RESERVED_9 9 +#define INO_EXT_TYPE_DIR_STATS_KEY 10 +#define INO_EXT_TYPE_FS_UUID 11 +#define INO_EXT_TYPE_RESERVED_12 12 +#define INO_EXT_TYPE_SPARSE_BYTES 13 +#define INO_EXT_TYPE_RDEV 14 +#define INO_EXT_TYPE_PURGEABLE_FLAGS 15 +#define INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16 +*/ + + +static const unsigned k_SizeOf_j_dstream = 8 * 5; + +struct j_dstream +{ + UInt64 size; + UInt64 alloced_size; + UInt64 default_crypto_id; + UInt64 total_bytes_written; + UInt64 total_bytes_read; + + void Parse(const Byte *p) + { + G64 (0, size); + G64 (0x8, alloced_size); + G64 (0x10, default_crypto_id); + G64 (0x18, total_bytes_written); + G64 (0x20, total_bytes_read); + } +}; + +static const unsigned k_SizeOf_j_file_extent_val = 8 * 3; + +#define J_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffU +// #define J_FILE_EXTENT_FLAG_MASK 0xff00000000000000U +// #define J_FILE_EXTENT_FLAG_SHIFT 56 + +#define EXTENT_GET_LEN(x) ((x) & J_FILE_EXTENT_LEN_MASK) + +struct j_file_extent_val +{ + UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t. + // There are currently no flags defined + UInt64 phys_block_num; // The physical block address that the extent starts at + // UInt64 crypto_id; // The encryption key or the encryption tweak used in this extent. + + void Parse(const Byte *p) + { + G64 (0, len_and_flags); + G64 (0x8, phys_block_num); + // G64 (0x10, crypto_id); + } +}; + + +struct CExtent +{ + UInt64 logical_offset; + UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t. + // There are currently no flags defined + UInt64 phys_block_num; // The physical block address that the extent starts at +}; + + +typedef UInt32 MY__uid_t; +typedef UInt32 MY__gid_t; +typedef UInt16 MY__mode_t; + + +typedef enum +{ + XATTR_DATA_STREAM = 1 << 0, + XATTR_DATA_EMBEDDED = 1 << 1, + XATTR_FILE_SYSTEM_OWNED = 1 << 2, + XATTR_RESERVED_8 = 1 << 3 +} j_xattr_flags; + + +struct CAttr +{ + AString Name; + UInt32 flags; + bool dstream_defined; + bool NeedShow; + CByteBuffer Data; + + j_dstream dstream; + UInt64 Id; + + bool Is_dstream_OK_for_SymLink() const + { + return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0; + } + + UInt64 GetSize() const + { + if (dstream_defined) // dstream has more priority + return dstream.size; + return Data.Size(); + } + + void Clear() + { + dstream_defined = false; + NeedShow = true; + Data.Free(); + Name.Empty(); + } + + bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; } + bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; } +}; + + +// j_inode_val_t +struct CNode +{ + unsigned ItemIndex; // index to CItem. We set it only if Node is directory. + unsigned NumCalcedLinks; // Num links to that node + // unsigned NumItems; // Num Items in that node + + UInt64 parent_id; // The identifier of the file system record for the parent directory. + UInt64 private_id; + UInt64 create_time; + UInt64 mod_time; + UInt64 change_time; + UInt64 access_time; + UInt64 internal_flags; + union + { + UInt32 nchildren; /* The number of directory entries. + is valid only if the inode is a directory */ + UInt32 nlink; /* The number of hard links whose target is this inode. + is valid only if the inode isn't a directory. + Inodes with multiple hard links (nlink > 1) + - The parent_id field refers to the parent directory of the primary link. + - The name field contains the name of the primary link. + - The INO_EXT_TYPE_NAME extended field contains the name of this link. + */ + }; + // cp_key_class_t default_protection_class; + UInt32 write_generation_counter; + UInt32 bsd_flags; + MY__uid_t owner; + MY__gid_t group; + MY__mode_t mode; + UInt16 pad1; + UInt64 uncompressed_size; + + j_dstream dstream; + AString PrimaryName; + + bool dstream_defined; + bool refcnt_defined; + + UInt32 refcnt; // j_dstream_id_val_t + CRecordVector Extents; + CObjectVector Attrs; + unsigned SymLinkIndex; // index in Attrs + unsigned DecmpfsIndex; // index in Attrs + unsigned ResourceIndex; // index in Attrs + + NHfs::CCompressHeader CompressHeader; + + CNode(): + ItemIndex(VI_MINUS1), + NumCalcedLinks(0), + // NumItems(0), + dstream_defined(false), + refcnt_defined(false), + SymLinkIndex(VI_MINUS1), + DecmpfsIndex(VI_MINUS1), + ResourceIndex(VI_MINUS1) + {} + + bool IsDir() const { return MY_LIN_S_ISDIR(mode); } + bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); } + + bool Has_UNCOMPRESSED_SIZE() const { return (internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) != 0; } + + unsigned Get_Type_From_mode() const { return mode >> 12; } + + bool GetSize(unsigned attrIndex, UInt64 &size) const + { + if (IsViNotDef(attrIndex)) + { + if (dstream_defined) + { + size = dstream.size; + return true; + } + size = 0; + if (Has_UNCOMPRESSED_SIZE()) + { + size = uncompressed_size; + return true; + } + if (!IsSymLink()) + return false; + attrIndex = SymLinkIndex; + if (IsViNotDef(attrIndex)) + return false; + } + const CAttr &attr = Attrs[(unsigned)attrIndex]; + if (attr.dstream_defined) + size = attr.dstream.size; + else + size = attr.Data.Size(); + return true; + } + + bool GetPackSize(unsigned attrIndex, UInt64 &size) const + { + if (IsViNotDef(attrIndex)) + { + if (dstream_defined) + { + size = dstream.alloced_size; + return true; + } + size = 0; + + if (IsSymLink()) + attrIndex = SymLinkIndex; + else + { + if (!CompressHeader.IsCorrect || + !CompressHeader.IsSupported) + return false; + const CAttr &attr = Attrs[DecmpfsIndex]; + if (!CompressHeader.IsMethod_Resource()) + { + size = attr.Data.Size() - CompressHeader.DataPos; + return true; + } + attrIndex = ResourceIndex; + } + if (IsViNotDef(attrIndex)) + return false; + } + const CAttr &attr = Attrs[(unsigned)attrIndex]; + if (attr.dstream_defined) + size = attr.dstream.alloced_size; + else + size = attr.Data.Size(); + return true; + } + + void Parse(const Byte *p); +}; + + +// it's used for Attr streams +struct CSmallNode +{ + CRecordVector Extents; + // UInt32 NumLinks; + // CSmallNode(): NumLinks(0) {}; +}; + +static const unsigned k_SizeOf_j_inode_val = 0x5c; + +void CNode::Parse(const Byte *p) +{ + G64 (0, parent_id); + G64 (0x8, private_id); + G64 (0x10, create_time); + G64 (0x18, mod_time); + G64 (0x20, change_time); + G64 (0x28, access_time); + G64 (0x30, internal_flags); + { + G32 (0x38, nchildren); + // G32 (0x38, nlink); + } + // G32 (0x3c, default_protection_class); + G32 (0x40, write_generation_counter); + G32 (0x44, bsd_flags); + G32 (0x48, owner); + G32 (0x4c, group); + G16 (0x50, mode); + // G16 (0x52, pad1); + G64 (0x54, uncompressed_size); +} + + +struct CRef +{ + unsigned ItemIndex; + unsigned NodeIndex; + unsigned ParentRefIndex; + + #ifdef APFS_SHOW_ALT_STREAMS + unsigned AttrIndex; + bool IsAltStream() const { return IsViDef(AttrIndex); } + unsigned GetAttrIndex() const { return AttrIndex; }; + #else + // bool IsAltStream() const { return false; } + unsigned GetAttrIndex() const { return VI_MINUS1; }; + #endif +}; + + +struct CRef2 +{ + unsigned VolIndex; + unsigned RefIndex; +}; + + +struct CVol +{ + CObjectVector Nodes; + CRecordVector NodeIDs; + CObjectVector Items; + CRecordVector Refs; + + CObjectVector SmallNodes; + CRecordVector SmallNodeIDs; + + unsigned StartRef2Index; // ref2_Index for Refs[0] item + unsigned RootRef2Index; // ref2_Index of virtual root folder (Volume1) + CApfs apfs; + bool NodeNotFound; + bool ThereAreUnlinkedNodes; + bool WrongInodeLink; + bool UnsupportedFeature; + + unsigned NumItems_In_PrivateDir; + unsigned NumAltStreams; + + UString RootName; + + bool ThereAreErrors() const + { + return NodeNotFound || ThereAreUnlinkedNodes || WrongInodeLink; + } + + void AddComment(UString &s) const; + + HRESULT FillRefs(); + + CVol(): + StartRef2Index(0), + RootRef2Index(VI_MINUS1), + NodeNotFound(false), + ThereAreUnlinkedNodes(false), + WrongInodeLink(false), + UnsupportedFeature(false), + NumItems_In_PrivateDir(0), + NumAltStreams(0) + {} +}; + + +static void ApfsTimeToFileTime(UInt64 apfsTime, FILETIME &ft, UInt32 &ns100) +{ + const UInt64 s = apfsTime / 1000000000; + const UInt32 ns = (UInt32)(apfsTime % 1000000000); + ns100 = (ns % 100); + const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(s) + ns / 100; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +static void AddComment_Name(UString &s, const char *name) +{ + s += name; + s += ": "; +} + +/* +static void AddComment_Bool(UString &s, const char *name, bool val) +{ + AddComment_Name(s, name); + s += val ? "+" : "-"; + s.Add_LF(); +} +*/ + +static void AddComment_UInt64(UString &s, const char *name, UInt64 v) +{ + AddComment_Name(s, name); + s.Add_UInt64(v); + s.Add_LF(); +} + + +static void AddComment_Time(UString &s, const char *name, UInt64 v) +{ + AddComment_Name(s, name); + + FILETIME ft; + UInt32 ns100; + ApfsTimeToFileTime(v, ft, ns100); + char temp[64]; + ConvertUtcFileTimeToString2(ft, ns100, temp + // , kTimestampPrintLevel_SEC); + , kTimestampPrintLevel_NS); + s += temp; + s.Add_LF(); +} + + +static void AddComment_modified_by_t(UString &s, const char *name, const apfs_modified_by_t &v) +{ + AddComment_Name(s, name); + AString s2; + s2.SetFrom_CalcLen((const char *)v.id, sizeof(v.id)); + s += s2; + s.Add_LF(); + s += " "; + AddComment_Time(s, "timestamp", v.timestamp); + s += " "; + AddComment_UInt64(s, "last_xid", v.last_xid); +} + + +static void AddVolInternalName_toString(UString &s, const CApfs &apfs) +{ + AString temp; + temp.SetFrom_CalcLen((const char *)apfs.volname, sizeof(apfs.volname)); + UString unicode; + ConvertUTF8ToUnicode(temp, unicode); + s += unicode; +} + + +void CVol::AddComment(UString &s) const +{ + AddComment_UInt64(s, "fs_index", apfs.fs_index); + { + AddComment_Name(s, "volume_name"); + AddVolInternalName_toString(s, apfs); + s.Add_LF(); + } + AddComment_Name(s, "vol_uuid"); + apfs.vol_uuid.AddHexToString(s); + s.Add_LF(); + + AddComment_Name(s, "incompatible_features"); + s += FlagsToString(g_APFS_INCOMPAT_Flags, + ARRAY_SIZE(g_APFS_INCOMPAT_Flags), + (UInt32)apfs.incompatible_features); + s.Add_LF(); + + // AddComment_UInt64(s, "reserve_block_count", apfs.fs_reserve_block_count, false); + // AddComment_UInt64(s, "quota_block_count", apfs.fs_quota_block_count); + AddComment_UInt64(s, "fs_alloc_count", apfs.fs_alloc_count); + + AddComment_UInt64(s, "num_files", apfs.num_files); + AddComment_UInt64(s, "num_directories", apfs.num_directories); + AddComment_UInt64(s, "num_symlinks", apfs.num_symlinks); + AddComment_UInt64(s, "num_other_fsobjects", apfs.num_other_fsobjects); + + AddComment_UInt64(s, "Num_Attr_Streams", NumAltStreams); + + AddComment_UInt64(s, "num_snapshots", apfs.num_snapshots); + AddComment_UInt64(s, "total_blocks_alloced", apfs.total_blocks_alloced); + AddComment_UInt64(s, "total_blocks_freed", apfs.total_blocks_freed); + + AddComment_Time(s, "unmounted", apfs.unmount_time); + AddComment_Time(s, "last_modified", apfs.last_mod_time); + AddComment_modified_by_t(s, "formatted_by", apfs.formatted_by); + for (unsigned i = 0; i < ARRAY_SIZE(apfs.modified_by); i++) + { + const apfs_modified_by_t &v = apfs.modified_by[i]; + if (v.last_xid == 0 && v.timestamp == 0 && v.id[0] == 0) + continue; + AString name ("modified_by["); + name.Add_UInt32(i); + name += ']'; + AddComment_modified_by_t(s, name.Ptr(), v); + } +} + + + +struct CKeyValPair +{ + CByteBuffer Key; + CByteBuffer Val; + // unsigned ValPos; // for alognment +}; + + +struct omap_key +{ + oid_t oid; // The object identifier + xid_t xid; // The transaction identifier + void Parse(const Byte *p) + { + G64o (0, oid); + G64x (8, xid); + } +}; + +/* +#define OMAP_VAL_DELETED (1 << 0) +#define OMAP_VAL_SAVED (1 << 1) +#define OMAP_VAL_ENCRYPTED (1 << 2) +#define OMAP_VAL_NOHEADER (1 << 3) +#define OMAP_VAL_CRYPTO_GENERATION (1 << 4) +*/ + +struct omap_val +{ + UInt32 flags; + UInt32 size; + paddr_t paddr; + + void Parse(const Byte *p) + { + G32 (0, flags); + G32 (4, size); + G64 (8, paddr); + } +}; + + +struct CObjectMap +{ + CRecordVector Keys; + CRecordVector Vals; + + bool Parse(const CObjectVector &pairs); + int FindKey(UInt64 id) const { return Keys.FindInSorted(id); } +}; + +bool CObjectMap::Parse(const CObjectVector &pairs) +{ + omap_key prev; + prev.oid = 0; + prev.xid = 0; + FOR_VECTOR (i, pairs) + { + const CKeyValPair &pair = pairs[i]; + if (pair.Key.Size() != 16 || pair.Val.Size() != 16) + return false; + omap_key key; + key.Parse(pair.Key); + omap_val val; + val.Parse(pair.Val); + /* Object map B-trees are sorted by object identifier and then by transaction identifier + but it's possible to have identical Ids in map ? + do we need to look transaction id ? + and search key with largest transaction id? */ + if (key.oid <= prev.oid) + return false; + prev = key; + Keys.Add(key.oid); + Vals.Add(val); + } + return true; +} + + +struct CMap +{ + CObjectVector Pairs; + + CObjectMap Omap; + btree_info bti; + UInt64 NumNodes; + + // we use thnese options to check: + UInt32 Subtype; + bool IsPhysical; + + bool CheckAtFinish() const + { + return NumNodes == bti.node_count && Pairs.Size() == bti.key_count; + } + + CMap(): + NumNodes(0), + Subtype(0), + IsPhysical(true) + {} +}; + + + +struct CDatabase +{ + CRecordVector Refs2; + CObjectVector Vols; + + bool HeadersError; + bool ThereAreAltStreams; + bool UnsupportedFeature; + + CSuperBlock sb; + + IInStream *OpenInStream; + IArchiveOpenCallback *OpenCallback; + UInt64 ProgressVal_Cur; + UInt64 ProgressVal_Prev; + UInt64 ProgressVal_NumFilesTotal; + CObjectVector Buffers; + + UInt32 MethodsMask; + UInt64 GetSize(const UInt32 index) const; + + void Clear() + { + HeadersError = false; + UnsupportedFeature = false; + ThereAreAltStreams = false; + + ProgressVal_Cur = 0; + ProgressVal_Prev = 0; + ProgressVal_NumFilesTotal = 0; + + MethodsMask = 0; + + Vols.Clear(); + Refs2.Clear(); + Buffers.Clear(); + } + + HRESULT SeekReadBlock_FALSE(UInt64 oid, void *data); + void GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const; + HRESULT ReadMap(UInt64 oid, CMap &map, unsigned recurseLevel); + HRESULT ReadObjectMap(UInt64 oid, CObjectMap &map); + HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid); + HRESULT Open2(); + + HRESULT GetAttrStream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream); + + HRESULT GetAttrStream_dstream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream); + + HRESULT GetStream2( + IInStream *apfsInStream, + const CRecordVector *extents, UInt64 rem, + ISequentialInStream **stream); +}; + + +HRESULT CDatabase::SeekReadBlock_FALSE(UInt64 oid, void *data) +{ + if (OpenCallback) + { + if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22)) + { + RINOK(OpenCallback->SetCompleted(NULL, &ProgressVal_Cur)); + ProgressVal_Prev = ProgressVal_Cur; + } + ProgressVal_Cur += sb.block_size; + } + if (oid == 0 || oid >= sb.block_count) + return S_FALSE; + RINOK(OpenInStream->Seek(oid << sb.block_size_Log, STREAM_SEEK_SET, NULL)); + return ReadStream_FALSE(OpenInStream, data, sb.block_size); +} + + + +API_FUNC_static_IsArc IsArc_APFS(const Byte *p, size_t size) +{ + if (size < kApfsHeaderSize) + return k_IsArc_Res_NEED_MORE; + CSuperBlock sb; + if (!sb.Parse(p)) + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + + + +HRESULT CDatabase::ReadMap(UInt64 oid, CMap &map, unsigned recurseLevel) +{ + // is it allowed to use big number of levels ? + if (recurseLevel > (1 << 10)) + return S_FALSE; + + const UInt32 blockSize = sb.block_size; + if (Buffers.Size() <= recurseLevel) + { + Buffers.AddNew(); + if (Buffers.Size() <= recurseLevel) + throw 123; + Buffers.Back().Alloc(blockSize); + } + const Byte *buf; + { + CByteBuffer &buf2 = Buffers[recurseLevel]; + RINOK(SeekReadBlock_FALSE(oid, buf2)); + buf = buf2; + } + + CBTreeNodePhys bt; + if (!bt.Parse(buf, blockSize)) + return S_FALSE; + + map.NumNodes++; + + /* Specification: All values are stored in leaf nodes, which + makes these B+ trees, and the values in nonleaf nodes are object + identifiers of child nodes. + + The entries in the table of contents are sorted by key. The comparison function used for sorting depends on the keys type + - Object map B-trees are sorted by object identifier and then by transaction identifier. + - Free queue B-trees are sorted by transaction identifier and then by physical address. + - File-system records are sorted according to the rules listed in File-System Objects. + */ + + if (bt.o.subtype != map.Subtype) + return S_FALSE; + + unsigned endLimit = blockSize; + + if (recurseLevel == 0) + { + if (bt.o.GetType() != OBJECT_TYPE_BTREE) + return S_FALSE; + if ((bt.flags & BTNODE_ROOT) == 0) + return S_FALSE; + endLimit -= k_btree_info_Size; + map.bti.Parse(buf + endLimit); + btree_info &bti = map.bti; + if (bti.fixed.key_size >= blockSize) + return S_FALSE; + if (bti.Is_EPHEMERAL() && + bti.Is_PHYSICAL()) + return S_FALSE; + if (bti.Is_PHYSICAL() != map.IsPhysical) + return S_FALSE; + // we don't allow volumes with big number of Keys + const UInt32 kNumItemsMax = k_VectorSizeMax; + if (map.bti.node_count > kNumItemsMax) + return S_FALSE; + if (map.bti.key_count > kNumItemsMax) + return S_FALSE; + } + else + { + if (bt.o.GetType() != OBJECT_TYPE_BTREE_NODE) + return S_FALSE; + if ((bt.flags & BTNODE_ROOT) != 0) + return S_FALSE; + if (map.NumNodes > map.bti.node_count + || map.Pairs.Size() > map.bti.key_count) + return S_FALSE; + } + + const bool isLeaf = (bt.flags & BTNODE_LEAF) != 0; + + if (isLeaf) + { + if (bt.level != 0) + return S_FALSE; + } + else + { + if (bt.level == 0) + return S_FALSE; + } + + if (!bt.table_space.CheckOverLimit(endLimit - k_Toc_offset)) + return S_FALSE; + + const unsigned tableEnd = k_Toc_offset + bt.table_space.GetEnd(); + const unsigned keyValRange = endLimit - tableEnd; + const unsigned tocEntrySize = bt.Is_FIXED_KV_SIZE() ? 4 : 8; + if (bt.table_space.len / tocEntrySize < bt.nkeys) + return S_FALSE; + + for (unsigned i = 0; i < bt.nkeys; i++) + { + const Byte *p = buf + k_Toc_offset + bt.table_space.off + i * tocEntrySize; + if (bt.Is_FIXED_KV_SIZE()) + { + kvoff a; + a.Parse(p); + if (a.k + map.bti.fixed.key_size > keyValRange + || a.v > keyValRange) + return S_FALSE; + { + CKeyValPair pair; + + const Byte *p2 = buf + k_Toc_offset + bt.table_space.len; + p2 += a.k; + pair.Key.CopyFrom(p2, map.bti.fixed.key_size); + + p2 = buf + endLimit; + p2 -= a.v; + if (isLeaf) + { + if (a.v < map.bti.fixed.val_size) + return S_FALSE; + pair.Val.CopyFrom(p2, map.bti.fixed.val_size); + // pair.ValPos = endLimit - a.v; + map.Pairs.Add(pair); + continue; + } + { + if (a.v < 8) + return S_FALSE; + // value is only 64-bit for non leaf. + const oid_t oidNext = Get64(p2); + if (map.bti.Is_PHYSICAL()) + { + RINOK(ReadMap(oidNext, map, recurseLevel + 1)); + continue; + } + else + { + // fixme + return S_FALSE; + } + } + } + } + else + { + kvloc a; + a.Parse(p); + if (!a.k.CheckOverLimit(keyValRange) + || a.v.off > keyValRange + || a.v.len > a.v.off) + return S_FALSE; + { + CKeyValPair pair; + const Byte *p2 = buf + k_Toc_offset + bt.table_space.len; + p2 += a.k.off; + pair.Key.CopyFrom(p2, a.k.len); + + p2 = buf + endLimit; + p2 -= a.v.off; + if (isLeaf) + { + pair.Val.CopyFrom(p2, a.v.len); + // pair.ValPos = endLimit - a.v.off; + map.Pairs.Add(pair); + continue; + } + { + if (a.v.off < 8 || a.v.len != 8) + return S_FALSE; + // value is only 64-bit for non leaf. + const oid_t oidNext = Get64(p2); + + if (map.bti.Is_PHYSICAL()) + { + return S_FALSE; + // the code was not tested: + // RINOK(ReadMap(oidNext, map, recurseLevel + 1)); + // continue; + } + else + { + const int index = map.Omap.FindKey(oidNext); + if (index == -1) + return S_FALSE; + const omap_val &ov = map.Omap.Vals[(unsigned)index]; + if (ov.size != blockSize) // change it : it must be multiple of + return S_FALSE; + RINOK(ReadMap(ov.paddr, map, recurseLevel + 1)); + continue; + } + } + } + } + } + + if (recurseLevel == 0) + if (!map.CheckAtFinish()) + return S_FALSE; + return S_OK; +} + + + +HRESULT CDatabase::ReadObjectMap(UInt64 oid, CObjectMap &omap) +{ + CByteBuffer buf; + const size_t blockSize = sb.block_size; + buf.Alloc(blockSize); + RINOK(SeekReadBlock_FALSE(oid, buf)); + C_omap_phys op; + if (!op.Parse(buf, blockSize, oid)) + return S_FALSE; + CMap map; + map.Subtype = OBJECT_TYPE_OMAP; + map.IsPhysical = true; + RINOK(ReadMap(op.tree_oid, map, 0)); + if (!omap.Parse(map.Pairs)) + return S_FALSE; + return S_OK; +} + + + +HRESULT CDatabase::Open2() +{ + Clear(); + CSuperBlock2 sb2; + { + Byte buf[kApfsHeaderSize]; + RINOK(ReadStream_FALSE(OpenInStream, buf, kApfsHeaderSize)); + if (!sb.Parse(buf)) + return S_FALSE; + sb2.Parse(buf); + } + + { + CObjectMap omap; + RINOK(ReadObjectMap(sb.omap_oid, omap)); + unsigned numRefs = 0; + for (unsigned i = 0; i < sb.max_file_systems; i++) + { + const oid_t oid = sb2.fs_oid[i]; + if (oid == 0) + continue; + // for (unsigned k = 0; k < 1; k++) // for debug + RINOK(OpenVolume(omap, oid)); + const unsigned a = Vols.Back().Refs.Size(); + numRefs += a; + if (numRefs < a) + return S_FALSE; // overflow + } + } + + const bool needVolumePrefix = (Vols.Size() > 1); + // const bool needVolumePrefix = true; // for debug + { + unsigned numRefs = 0; + FOR_VECTOR (i, Vols) + { + const unsigned a = Vols[i].Refs.Size(); + numRefs += a; + if (numRefs < a) + return S_FALSE; // overflow + } + numRefs += Vols.Size(); + if (numRefs < Vols.Size()) + return S_FALSE; // overflow + Refs2.Reserve(numRefs); + } + { + FOR_VECTOR (i, Vols) + { + CVol &vol = Vols[i]; + + CRef2 ref2; + ref2.VolIndex = i; + + if (needVolumePrefix) + { + vol.RootName = "Volume"; + vol.RootName.Add_UInt32(1 + (UInt32)i); + vol.RootRef2Index = Refs2.Size(); + ref2.RefIndex = VI_MINUS1; + Refs2.Add(ref2); + } + + vol.StartRef2Index = Refs2.Size(); + const unsigned numItems = vol.Refs.Size(); + for (unsigned k = 0; k < numItems; k++) + { + ref2.RefIndex = k; + Refs2.Add(ref2); + } + } + } + return S_OK; +} + + +HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid) +{ + const size_t blockSize = sb.block_size; + CByteBuffer buf; + { + const int index = omap.FindKey(fs_oid); + if (index == -1) + return S_FALSE; + const omap_val &ov = omap.Vals[(unsigned)index]; + if (ov.size != blockSize) // change it : it must be multiple of + return S_FALSE; + buf.Alloc(blockSize); + RINOK(SeekReadBlock_FALSE(ov.paddr, buf)); + } + + CVol &vol = Vols.AddNew(); + CApfs &apfs = vol.apfs; + + if (!apfs.Parse(buf, blockSize)) + return S_FALSE; + + /* For each volume, read the root file system tree's virtual object + identifier from the apfs_root_tree_oid field, + and then look it up in the volume object map indicated + by the omap_oid field. */ + + CMap map; + { + ReadObjectMap(apfs.omap_oid, map.Omap); + const int index = map.Omap.FindKey(apfs.root_tree_oid); + if (index == -1) + return S_FALSE; + const omap_val &ov = map.Omap.Vals[(unsigned)index]; + if (ov.size != blockSize) // change it : it must be multiple of + return S_FALSE; + map.Subtype = OBJECT_TYPE_FSTREE; + map.IsPhysical = false; + RINOK(ReadMap(ov.paddr, map, 0)); + } + + bool needParseAttr = false; + + { + const bool isHashed = apfs.IsHashedName(); + UInt64 prevId = 1; + + { + const UInt64 numApfsItems = vol.apfs.GetTotalItems() + + 2; // we will have 2 additional hidden directories: root and private-dir + const UInt64 numApfsItems_Reserve = numApfsItems + + 16; // we reserve 16 for some possible unexpected items + if (numApfsItems_Reserve < map.Pairs.Size()) + { + vol.Items.ClearAndReserve((unsigned)numApfsItems_Reserve); + vol.Nodes.ClearAndReserve((unsigned)numApfsItems_Reserve); + vol.NodeIDs.ClearAndReserve((unsigned)numApfsItems_Reserve); + } + if (OpenCallback) + { + const UInt64 numFiles = ProgressVal_NumFilesTotal + numApfsItems; + RINOK(OpenCallback->SetTotal(&numFiles, NULL)); + } + } + + CAttr attr; + CItem item; + + FOR_VECTOR (i, map.Pairs) + { + if (OpenCallback && (i & 0xffff) == 1) + { + const UInt64 numFiles = ProgressVal_NumFilesTotal + + (vol.Items.Size() + vol.Nodes.Size()) / 2; + RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur)); + } + + const CKeyValPair &pair = map.Pairs[i]; + j_key_t jkey; + if (pair.Key.Size() < 8) + return S_FALSE; + const Byte *p = pair.Key; + jkey.Parse(p); + const unsigned type = jkey.GetType(); + const UInt64 id = jkey.GetID(); + if (id < prevId) + return S_FALSE; // IDs must be sorted + prevId = id; + + PRF(printf("\n%6d: id=%6d type = %2d", i, (unsigned)id, type)); + + if (type == APFS_TYPE_INODE) + { + PRF(printf (" INODE")); + if (pair.Key.Size() != 8 || + pair.Val.Size() < k_SizeOf_j_inode_val) + return S_FALSE; + + CNode inode; + inode.Parse(pair.Val); + + if (inode.private_id != id) + { + /* private_id : The unique identifier used by this file's data stream. + This identifier appears in the owning_obj_id field of j_phys_ext_val_t + records that describe the extents where the data is stored. + For an inode that doesn't have data, the value of this + field is the file-system object's identifier. + */ + // APFS_TYPE_EXTENT allow to link physical address extents. + // we don't support case (private_id != id) + UnsupportedFeature = true; + // return S_FALSE; + } + const UInt32 extraSize = (UInt32)pair.Val.Size() - k_SizeOf_j_inode_val; + if (extraSize != 0) + { + if (extraSize < 4) + return S_FALSE; + /* + struct xf_blob + { + uint16_t xf_num_exts; + uint16_t xf_used_data; + uint8_t xf_data[]; + }; + */ + const Byte *p2 = pair.Val + k_SizeOf_j_inode_val; + const UInt32 xf_num_exts = Get16(p2); + const UInt32 xf_used_data = Get16(p2 + 2); + UInt32 offset = 4 + (UInt32)xf_num_exts * 4; + if (offset + xf_used_data != extraSize) + return S_FALSE; + for (unsigned k = 0; k < xf_num_exts; k++) + { + // struct x_field + const Byte *p3 = p2 + 4 + k * 4; + const Byte x_type = p3[0]; + // const Byte x_flags = p3[1]; + const UInt32 x_size = Get16(p3 + 2); + const UInt32 x_size_ceil = (x_size + 7) & ~(UInt32)7; + if (offset + x_size_ceil > extraSize) + return S_FALSE; + const Byte *p4 = p2 + offset; + if (x_type == INO_EXT_TYPE_NAME) + { + if (x_size < 2) + return S_FALSE; + inode.PrimaryName.SetFrom_CalcLen((const char *)p4, x_size); + PRF(printf(" PrimaryName = %s", inode.PrimaryName.Ptr())); + if (inode.PrimaryName.Len() != x_size - 1) + HeadersError = true; + // return S_FALSE; + } + else if (x_type == INO_EXT_TYPE_DSTREAM) + { + if (x_size != k_SizeOf_j_dstream) + return S_FALSE; + if (inode.dstream_defined) + return S_FALSE; + inode.dstream.Parse(p4); + inode.dstream_defined = true; + } + else + { + // UnsupportedFeature = true; + // return S_FALSE; + } + offset += x_size_ceil; + } + if (offset != extraSize) + return S_FALSE; + } + + if (!vol.NodeIDs.IsEmpty()) + if (id <= vol.NodeIDs.Back()) + return S_FALSE; + vol.Nodes.Add(inode); + vol.NodeIDs.Add(id); + continue; + } + + if (type == APFS_TYPE_XATTR) + { + PRF(printf(" XATTR")); + + /* + struct j_xattr_key + { + j_key_t hdr; + uint16_t name_len; + uint8_t name[0]; + } + */ + + UInt32 len; + unsigned nameOffset; + { + nameOffset = 8 + 2; + if (pair.Key.Size() < nameOffset + 1) + return S_FALSE; + len = Get16(p + 8); + } + if (nameOffset + len != pair.Key.Size()) + return S_FALSE; + + attr.Clear(); + attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); + if (attr.Name.Len() != len - 1) + return S_FALSE; + + PRF(printf(" name=%s", attr.Name.Ptr())); + + const unsigned k_SizeOf_j_xattr_val = 4; + if (pair.Val.Size() < k_SizeOf_j_xattr_val) + return S_FALSE; + /* + struct j_xattr_val + { + uint16_t flags; + uint16_t xdata_len; + uint8_t xdata[0]; + } + */ + attr.flags = Get16(pair.Val); + const UInt32 xdata_len = Get16(pair.Val + 2); + + PRF(printf(" flags=%x xdata_len = %d", + (unsigned)attr.flags, + (unsigned)xdata_len)); + + const Byte *p4 = pair.Val + 4; + + if (k_SizeOf_j_xattr_val + xdata_len != pair.Val.Size()) + return S_FALSE; + if (attr.Is_EMBEDDED()) + attr.Data.CopyFrom(p4, xdata_len); + else if (attr.Is_STREAM()) + { + // why (attr.flags == 0x11) here? (0x11 is undocummented flag) + if (k_SizeOf_j_xattr_val + 8 + k_SizeOf_j_dstream != pair.Val.Size()) + return S_FALSE; + attr.Id = Get64(p4); + attr.dstream.Parse(p4 + 8); + attr.dstream_defined = true; + PRF(printf(" streamID=%d", (unsigned)attr.Id)); + } + else + { + // unknown attribute + // UnsupportedFeature = true; + // return S_FALSE; + } + + if (vol.NodeIDs.IsEmpty() || + vol.NodeIDs.Back() != id) + { + return S_FALSE; + // UnsupportedFeature = true; + // continue; + } + + CNode &inode = vol.Nodes.Back(); + + if (attr.Name.IsEqualTo("com.apple.fs.symlink")) + { + inode.SymLinkIndex = inode.Attrs.Size(); + if (attr.Is_dstream_OK_for_SymLink()) + needParseAttr = true; + } + else if (attr.Name.IsEqualTo("com.apple.decmpfs")) + { + inode.DecmpfsIndex = inode.Attrs.Size(); + // if (attr.dstream_defined) + needParseAttr = true; + } + else if (attr.Name.IsEqualTo("com.apple.ResourceFork")) + { + inode.ResourceIndex = inode.Attrs.Size(); + } + inode.Attrs.Add(attr); + continue; + } + + if (type == APFS_TYPE_DSTREAM_ID) + { + PRF(printf(" DSTREAM_ID")); + if (pair.Key.Size() != 8) + return S_FALSE; + // j_dstream_id_val_t + if (pair.Val.Size() != 4) + return S_FALSE; + const UInt32 refcnt = Get32(pair.Val); + + // The data stream record can be deleted when its reference count reaches zero. + PRF(printf(" refcnt = %8d", (unsigned)refcnt)); + + if (vol.NodeIDs.IsEmpty()) + return S_FALSE; + + if (vol.NodeIDs.Back() != id) + { + // is it possible ? + // continue; + return S_FALSE; + } + + CNode &inode = vol.Nodes.Back(); + + if (inode.refcnt_defined) + return S_FALSE; + + inode.refcnt = refcnt; + inode.refcnt_defined = true; + if (inode.refcnt != (UInt32)inode.nlink) + { + // is it possible ? + // return S_FALSE; + } + continue; + } + + if (type == APFS_TYPE_FILE_EXTENT) + { + PRF(printf(" FILE_EXTENT")); + /* + struct j_file_extent_key + { + j_key_t hdr; + uint64_t logical_addr; + } + */ + if (pair.Key.Size() != 16) + return S_FALSE; + // The offset within the file's data, in bytes, for the data stored in this extent + const UInt64 logical_addr = Get64(p + 8); + + j_file_extent_val eval; + if (pair.Val.Size() != k_SizeOf_j_file_extent_val) + return S_FALSE; + eval.Parse(pair.Val); + + if (logical_addr != 0) + { + PRF(printf(" logical_addr = %d", (unsigned)logical_addr)); + } + PRF(printf(" len = %8d pos = %8d", + (unsigned)eval.len_and_flags, + (unsigned)eval.phys_block_num + )); + + CExtent ext; + ext.logical_offset = logical_addr; + ext.len_and_flags = eval.len_and_flags; + ext.phys_block_num = eval.phys_block_num; + + if (vol.NodeIDs.IsEmpty()) + return S_FALSE; + if (vol.NodeIDs.Back() != id) + { + // extents for Attributs; + if (vol.SmallNodeIDs.IsEmpty() || + vol.SmallNodeIDs.Back() != id) + { + vol.SmallNodeIDs.Add(id); + vol.SmallNodes.AddNew(); + } + vol.SmallNodes.Back().Extents.Add(ext); + continue; + // return S_FALSE; + } + + CNode &inode = vol.Nodes.Back(); + inode.Extents.Add(ext); + continue; + } + + if (type == APFS_TYPE_DIR_REC) + { + UInt32 len; + unsigned nameOffset; + + if (isHashed) + { + /* + struct j_drec_hashed_key + { + j_key_t hdr; + UInt32 name_len_and_hash; + uint8_t name[0]; + } + */ + nameOffset = 8 + 4; + if (pair.Key.Size() < nameOffset + 1) + return S_FALSE; + const UInt32 name_len_and_hash = Get32(p + 8); + len = name_len_and_hash & J_DREC_LEN_MASK; + } + else + { + /* + struct j_drec_key + { + j_key_t hdr; + UInt16 name_len; // The length of the name, including the final null character + uint8_t name[0]; // The name, represented as a null-terminated UTF-8 string + } + */ + nameOffset = 8 + 2; + if (pair.Key.Size() < nameOffset + 1) + return S_FALSE; + len = Get16(p + 8); + } + if (nameOffset + len != pair.Key.Size()) + return S_FALSE; + + // CItem item; + item.Clear(); + + item.ParentId = id; + item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len); + if (item.Name.Len() != len - 1) + return S_FALSE; + + if (pair.Val.Size() < k_SizeOf_j_drec_val) + return S_FALSE; + + item.Val.Parse(pair.Val); + + if (pair.Val.Size() > k_SizeOf_j_drec_val) + { + // fixme: parse extra fields; + // UnsupportedFeature = true; + // return S_FALSE; + } + + vol.Items.Add(item); + + /* + if (!vol.NodeIDs.IsEmpty() && vol.NodeIDs.Back() == id) + vol.Nodes.Back().NumItems++; + */ + if (id == PRIV_DIR_INO_NUM) + vol.NumItems_In_PrivateDir++; + + PRF(printf(" next=%6d flags=%2x %s", + (unsigned)item.Val.file_id, + (unsigned)item.Val.flags, + item.Name.Ptr())); + continue; + } + + UnsupportedFeature = true; + // return S_FALSE; + } + ProgressVal_NumFilesTotal += vol.Items.Size(); + } + + + if (needParseAttr) + { + /* we read external streams for attributes + So we can get SymLink for GetProperty(kpidSymLink) later */ + FOR_VECTOR (i, vol.Nodes) + { + CNode &node = vol.Nodes[i]; + + FOR_VECTOR (a, node.Attrs) + { + CAttr &attr = node.Attrs[a]; + if (attr.Data.Size() != 0 || !attr.dstream_defined) + continue; + if (a == node.SymLinkIndex) + { + if (!attr.Is_dstream_OK_for_SymLink()) + continue; + } + else + { + if (a != node.DecmpfsIndex + // && a != node.ResourceIndex + ) + continue; + } + // we don't expect big streams here + // largest dstream for Decmpfs attribute is (2Kib+17) + if (attr.dstream.size > ((UInt32)1 << 16)) + continue; + CMyComPtr inStream; + const HRESULT res = GetAttrStream_dstream(OpenInStream, vol, attr, &inStream); + if (res == S_OK && inStream) + { + CByteBuffer buf2; + const size_t size = (size_t)attr.dstream.size; + buf2.Alloc(size); + if (ReadStream_FAIL(inStream, buf2, size) == S_OK) + attr.Data = buf2; + + ProgressVal_Cur += size; + if (OpenCallback) + if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22)) + { + + RINOK(OpenCallback->SetCompleted( + &ProgressVal_NumFilesTotal, + &ProgressVal_Cur)); + ProgressVal_Prev = ProgressVal_Cur; + } + } + } + + if (node.Has_UNCOMPRESSED_SIZE()) + if (IsViDef(node.DecmpfsIndex)) + { + CAttr &attr = node.Attrs[node.DecmpfsIndex]; + node.CompressHeader.Parse(attr.Data, attr.Data.Size()); + + if (node.CompressHeader.IsCorrect) + if (node.CompressHeader.Method < sizeof(MethodsMask) * 8) + MethodsMask |= ((UInt32)1 << node.CompressHeader.Method); + + if (node.CompressHeader.IsCorrect + && node.CompressHeader.IsSupported + && node.CompressHeader.UnpackSize == node.uncompressed_size) + { + attr.NeedShow = false; + if (node.CompressHeader.IsMethod_Resource() + && IsViDef(node.ResourceIndex)) + node.Attrs[node.ResourceIndex].NeedShow = false; + } + else + { + vol.UnsupportedFeature = true; + } + } + } + } + + const HRESULT res = vol.FillRefs(); + + if (vol.ThereAreErrors()) + HeadersError = true; + if (vol.UnsupportedFeature) + UnsupportedFeature = true; + if (vol.NumAltStreams != 0) + ThereAreAltStreams = true; + + return res; +} + + + +HRESULT CVol::FillRefs() +{ + { + Refs.Reserve(Items.Size()); + // we fill Refs[*] + // we + // and set Nodes[*].ItemIndex for Nodes that are directories; + FOR_VECTOR (i, Items) + { + CItem &item = Items[i]; + const UInt64 id = item.Val.file_id; + // if (item.Id == ROOT_DIR_PARENT) continue; + /* for two root folders items + we don't set Node.ItemIndex; */ + // so nodes + if (id == ROOT_DIR_INO_NUM) + continue; + if (id == PRIV_DIR_INO_NUM) + if (NumItems_In_PrivateDir == 0) // if (inode.NumItems == 0) + continue; + + CRef ref; + ref.ItemIndex = i; + // ref.NodeIndex = VI_MINUS1; + ref.ParentRefIndex = VI_MINUS1; + #ifdef APFS_SHOW_ALT_STREAMS + ref.AttrIndex = VI_MINUS1; + #endif + const int index = NodeIDs.FindInSorted(id); + // const int index = -1; // for debug + ref.NodeIndex = (unsigned)index; + item.RefIndex = Refs.Size(); + Refs.Add(ref); + + if (index == -1) + { + NodeNotFound = true; + continue; + // return S_FALSE; + } + + // item.iNode_Index = index; + CNode &inode = Nodes[(unsigned)index]; + if (!item.Val.IsFlags_Unknown() + && inode.Get_Type_From_mode() != item.Val.flags) + { + Refs.Back().NodeIndex = VI_MINUS1; + WrongInodeLink = true; + continue; + // return S_FALSE; + } + + const bool isDir = inode.IsDir(); + if (isDir) + { + if (IsViDef(inode.ItemIndex)) + { + // hard links to dirs are not supported + Refs.Back().NodeIndex = VI_MINUS1; + WrongInodeLink = true; + continue; + } + inode.ItemIndex = i; + } + inode.NumCalcedLinks++; + + #ifdef APFS_SHOW_ALT_STREAMS + if (!isDir) + { + // we use alt streams only for files + const unsigned numAttrs = inode.Attrs.Size(); + if (numAttrs != 0) + { + ref.ParentRefIndex = item.RefIndex; + for (unsigned k = 0; k < numAttrs; k++) + { + // comment it for debug + const CAttr &attr = inode.Attrs[k]; + if (!attr.NeedShow) + continue; + + if (k == inode.SymLinkIndex) + continue; + ref.AttrIndex = k; + NumAltStreams++; + Refs.Add(ref); + /* + if (attr.dstream_defined) + { + const int idIndex = SmallNodeIDs.FindInSorted(attr.Id); + if (idIndex != -1) + SmallNodes[(unsigned)idIndex].NumLinks++; // for debug + } + */ + } + } + } + #endif + } + } + + + { + // fill ghost nodes + CRef ref; + ref.ItemIndex = VI_MINUS1; + ref.ParentRefIndex = VI_MINUS1; + #ifdef APFS_SHOW_ALT_STREAMS + ref.AttrIndex = VI_MINUS1; + #endif + FOR_VECTOR (i, Nodes) + { + if (Nodes[i].NumCalcedLinks != 0) + continue; + const UInt64 id = NodeIDs[i]; + if (id == ROOT_DIR_INO_NUM || + id == PRIV_DIR_INO_NUM) + continue; + ThereAreUnlinkedNodes = true; + ref.NodeIndex = i; + Refs.Add(ref); + } + } + + /* if want to create Refs for ghost data streams, + we need additional CRef::SmallNodeIndex field */ + + { + /* all Nodes[*].ItemIndex were already filled for directory Nodes, + except of "root" and "private-dir" Nodes. */ + + // now we fill Items[*].ParentItemIndex and Refs[*].ParentRefIndex + + UInt64 prev_ID = (UInt64)(Int64)-1; + unsigned prev_ParentItemIndex = VI_MINUS1; + + FOR_VECTOR (i, Items) + { + CItem &item = Items[i]; + const UInt64 id = item.ParentId; // it's id of parent NODE + if (id != prev_ID) + { + prev_ID = id; + prev_ParentItemIndex = VI_MINUS1; + const int index = NodeIDs.FindInSorted(id); + if (index == -1) + continue; + prev_ParentItemIndex = Nodes[(unsigned)index].ItemIndex; + } + + if (IsViNotDef(prev_ParentItemIndex)) + continue; + item.ParentItemIndex = prev_ParentItemIndex; + if (IsViNotDef(item.RefIndex)) + { + // RefIndex is not set for 2 Items (root folders) + // but there is no node for them usually + continue; + } + CRef &ref = Refs[item.RefIndex]; + + /* + // it's optional check that parent_id is set correclty + if (IsViDef(ref.NodeIndex)) + { + const CNode &node = Nodes[ref.NodeIndex]; + if (node.IsDir() && node.parent_id != id) + return S_FALSE; + } + */ + + /* + if (id == ROOT_DIR_INO_NUM) + { + // ItemIndex in Node for ROOT_DIR_INO_NUM was not set bofere + // probably unused now. + ref.ParentRefIndex = VI_MINUS1; + } + else + */ + ref.ParentRefIndex = Items[prev_ParentItemIndex].RefIndex; + } + } + + { + // check for loops + const unsigned numItems = Items.Size(); + if (numItems + 1 == 0) + return S_FALSE; + CUIntArr arr; + arr.Alloc(numItems); + { + for (unsigned i = 0; i < numItems; i++) + arr[i] = 0; + } + for (unsigned i = 0; i < numItems;) + { + unsigned k = i++; + for (;;) + { + const unsigned a = arr[k]; + if (a != 0) + { + if (a == i) + return S_FALSE; + break; + } + arr[k] = i; + k = Items[k].ParentItemIndex; + if (IsViNotDef(k)) + break; + } + } + } + + return S_OK; +} + + + +class CHandler: + public IInArchive, + public IArchiveGetRawProps, + public IInArchiveGetStream, + public CMyUnknownImp, + public CDatabase +{ + CMyComPtr _stream; +public: + MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) + INTERFACE_IInArchive(;) + INTERFACE_IArchiveGetRawProps(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + + +STDMETHODIMP CHandler::Open(IInStream *inStream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback *callback) +{ + COM_TRY_BEGIN + Close(); + OpenInStream = inStream; + OpenCallback = callback; + RINOK(Open2()); + _stream = inStream; + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::Close() +{ + _stream.Release(); + Clear(); + return S_OK; +} + + +enum +{ + kpidBytesWritten = kpidUserDefined, + kpidBytesRead, + kpidPrimeName, + kpidParentINode, + kpidAddTime, + kpidGeneration, + kpidBsdFlags + // kpidUncompressedSize +}; + +static const CStatProp kProps[] = +{ + { NULL, kpidPath, VT_BSTR }, + { NULL, kpidSize, VT_UI8 }, + { NULL, kpidPackSize, VT_UI8 }, + { NULL, kpidPosixAttrib, VT_UI4 }, + { NULL, kpidMTime, VT_FILETIME }, + { NULL, kpidCTime, VT_FILETIME }, + { NULL, kpidATime, VT_FILETIME }, + { NULL, kpidChangeTime, VT_FILETIME }, + { "Added Time", kpidAddTime, VT_FILETIME }, + { NULL, kpidMethod, VT_BSTR }, + { NULL, kpidINode, VT_UI8 }, + { NULL, kpidLinks, VT_UI4 }, + { NULL, kpidSymLink, VT_BSTR }, + { NULL, kpidUserId, VT_UI4 }, + { NULL, kpidGroupId, VT_UI4 }, + { NULL, kpidCharacts, VT_BSTR }, + #ifdef APFS_SHOW_ALT_STREAMS + { NULL, kpidIsAltStream, VT_BOOL }, + #endif + { "Parent iNode", kpidParentINode, VT_UI8 }, + { "Primary Name", kpidPrimeName, VT_BSTR }, + { "Generation", kpidGeneration, VT_UI4 }, + { "Written Size", kpidBytesWritten, VT_UI8 }, + { "Read Size", kpidBytesRead, VT_UI8 }, + { "BSD Flags", kpidBsdFlags, VT_UI4 } + // , { "Uncompressed Size", kpidUncompressedSize, VT_UI8 } +}; + + +static const Byte kArcProps[] = +{ + kpidName, + kpidCharacts, + kpidId, + kpidClusterSize, + kpidCTime, + kpidMTime, + kpidComment +}; + +IMP_IInArchive_Props_WITH_NAME +IMP_IInArchive_ArcProps + + +static void ApfsTimeToProp(UInt64 hfsTime, NWindows::NCOM::CPropVariant &prop) +{ + if (hfsTime == 0) + return; + FILETIME ft; + UInt32 ns100; + ApfsTimeToFileTime(hfsTime, ft, ns100); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); +} + + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + const CApfs *apfs = NULL; + if (Vols.Size() == 1) + apfs = &Vols[0].apfs; + switch (propID) + { + case kpidPhySize: + prop = (UInt64)sb.block_count << sb.block_size_Log; + break; + case kpidClusterSize: prop = (UInt32)(sb.block_size); break; + case kpidCharacts: NHfs::MethodsMaskToProp(MethodsMask, prop); break; + case kpidMTime: + if (apfs) + ApfsTimeToProp(apfs->modified_by[0].timestamp, prop); + break; + case kpidCTime: + if (apfs) + ApfsTimeToProp(apfs->formatted_by.timestamp, prop); + break; + case kpidIsTree: prop = true; break; + case kpidErrorFlags: + { + UInt32 flags = 0; + if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (flags != 0) + prop = flags; + break; + } + case kpidWarningFlags: + { + UInt32 flags = 0; + if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature; + if (flags != 0) + prop = flags; + break; + } + + case kpidName: + { + if (apfs) + { + UString s; + AddVolInternalName_toString(s, *apfs); + s += ".apfs"; + prop = s; + } + break; + } + + case kpidId: + { + char s[32 + 4]; + sb.uuid.SetHex_To_str(s); + prop = s; + break; + } + + case kpidComment: + { + UString s; + { + AddComment_UInt64(s, "block_size", sb.block_size); + + FOR_VECTOR (i, Vols) + { + if (Vols.Size() > 1) + { + if (i != 0) + { + s += "----"; + s.Add_LF(); + } + AddComment_UInt64(s, "Volume", i + 1); + } + Vols[i].AddComment(s); + } + } + prop = s; + break; + } + + #ifdef APFS_SHOW_ALT_STREAMS + case kpidIsAltStream: + prop = ThereAreAltStreams; + // prop = false; // for debug + break; + #endif + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps) +{ + *numProps = 0; + return S_OK; +} + + +STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) +{ + *name = NULL; + *propID = 0; + return S_OK; +} + + +STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType) +{ + *parentType = NParentType::kDir; + + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + UInt32 parentIndex = (UInt32)(Int32)-1; + + if (IsViDef(ref2.RefIndex)) + { + const CRef &ref = vol.Refs[ref2.RefIndex]; + #ifdef APFS_SHOW_ALT_STREAMS + if (ref.IsAltStream()) + *parentType = NParentType::kAltStream; + #endif + if (IsViDef(ref.ParentRefIndex)) + parentIndex = (UInt32)(ref.ParentRefIndex + vol.StartRef2Index); + else if (index != vol.RootRef2Index && IsViDef(vol.RootRef2Index)) + parentIndex = (UInt32)vol.RootRef2Index; + } + + *parent = parentIndex; + return S_OK; +} + + +STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) +{ + *data = NULL; + *dataSize = 0; + *propType = 0; + UNUSED_VAR(index); + UNUSED_VAR(propID); + return S_OK; +} + + +static void Utf8Name_to_InterName(const AString &src, UString &dest) +{ + ConvertUTF8ToUnicode(src, dest); + NItemName::NormalizeSlashes_in_FileName_for_OsPath(dest); +} + + +static void AddNodeName(UString &s, const CNode &inode, UInt64 id) +{ + s += "node"; + s.Add_UInt64(id); + if (!inode.PrimaryName.IsEmpty()) + { + s += '.'; + UString s2; + Utf8Name_to_InterName(inode.PrimaryName, s2); + s += s2; + } +} + + +void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const +{ + const unsigned kNumLevelsMax = (1 << 10); + const unsigned kLenMax = (1 << 12); + UString s; + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + + if (IsViDef(ref2.RefIndex)) + { + const CRef &ref = vol.Refs[ref2.RefIndex]; + unsigned cur = ref.ItemIndex; + UString s2; + if (IsViNotDef(cur)) + { + if (inode) + AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]); + } + else + { + for (unsigned i = 0;; i++) + { + if (i >= kNumLevelsMax || s.Len() > kLenMax) + { + s.Insert(0, UString("[LONG_PATH]")); + break; + } + const CItem &item = vol.Items[(unsigned)cur]; + Utf8Name_to_InterName(item.Name, s2); + // s2 += "a\\b"; // for debug + s.Insert(0, s2); + cur = item.ParentItemIndex; + if (IsViNotDef(cur)) + break; + // ParentItemIndex was not set for such items + // if (item.ParentId == ROOT_DIR_INO_NUM) break; + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + } + } + + #ifdef APFS_SHOW_ALT_STREAMS + if (IsViDef(ref.AttrIndex) && inode) + { + s += ':'; + Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2); + // s2 += "a\\b"; // for debug + s += s2; + } + #endif + } + + if (!vol.RootName.IsEmpty()) + { + if (IsViDef(ref2.RefIndex)) + s.InsertAtFront(WCHAR_PATH_SEPARATOR); + s.Insert(0, vol.RootName); + } + + path = s; +} + + + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant prop; + + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + + if (IsViNotDef(ref2.RefIndex)) + { + switch (propID) + { + case kpidName: + case kpidPath: + GetItemPath(index, NULL, prop); + break; + case kpidIsDir: + prop = true; + break; + } + prop.Detach(value); + return S_OK; + } + + const CRef &ref = vol.Refs[ref2.RefIndex]; + + const CItem *item = NULL; + if (IsViDef(ref.ItemIndex)) + item = &vol.Items[ref.ItemIndex]; + + const CNode *inode = NULL; + if (IsViDef(ref.NodeIndex)) + inode = &vol.Nodes[ref.NodeIndex]; + + switch (propID) + { + case kpidPath: + GetItemPath(index, inode, prop); + break; + case kpidPrimeName: + { + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && !inode->PrimaryName.IsEmpty()) + { + UString s; + ConvertUTF8ToUnicode(inode->PrimaryName, s); + /* + // for debug: + if (inode.PrimaryName != item.Name) throw 123456; + */ + prop = s; + } + break; + } + + case kpidName: + { + UString s; + #ifdef APFS_SHOW_ALT_STREAMS + if (ref.IsAltStream()) + { + // if (inode) + { + const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex]; + ConvertUTF8ToUnicode(attr.Name, s); + } + } + else + #endif + { + if (item) + ConvertUTF8ToUnicode(item->Name, s); + else if (inode) + AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]); + else + break; + } + // s += "s/1bs\\2"; // for debug: + prop = s; + break; + } + + case kpidSymLink: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex)) + { + const CByteBuffer &buf = inode->Attrs[(unsigned)inode->SymLinkIndex].Data; + if (buf.Size() != 0) + { + AString s; + s.SetFrom_CalcLen((const char *)(const Byte *)buf, (unsigned)buf.Size()); + if (s.Len() == buf.Size() - 1) + { + UString u; + ConvertUTF8ToUnicode(s, u); + prop = u; + } + } + } + } + break; + + case kpidSize: + if (inode) + { + UInt64 size = 0; + if (inode->GetSize(ref.GetAttrIndex(), size) || + !inode->IsDir()) + prop = size; + } + break; + + case kpidPackSize: + if (inode) + { + UInt64 size; + if (inode->GetPackSize(ref.GetAttrIndex(), size) || + !inode->IsDir()) + prop = size; + } + break; + + case kpidMethod: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + if (inode->CompressHeader.IsCorrect) + inode->CompressHeader.MethodToProp(prop); + else if (IsViDef(inode->DecmpfsIndex)) + prop = "decmpfs"; + else if (!inode->IsDir() && !inode->dstream_defined) + { + if (inode->IsSymLink()) + { + if (IsViDef(inode->SymLinkIndex)) + prop = "symlink"; + } + // else prop = "no_dstream"; + } + } + break; + + /* + case kpidUncompressedSize: + if (inode && inode->Has_UNCOMPRESSED_SIZE()) + prop = inode->uncompressed_size; + break; + */ + + case kpidIsDir: + { + bool isDir = false; + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + { + if (inode) + isDir = inode->IsDir(); + else if (item) + isDir = item->Val.IsFlags_Dir(); + } + prop = isDir; + break; + } + + case kpidPosixAttrib: + { + if (inode) + { + UInt32 mode = inode->mode; + #ifdef APFS_SHOW_ALT_STREAMS + if (ref.IsAltStream()) + { + mode &= 0666; // we disable execution + mode |= MY_LIN_S_IFREG; + } + #endif + prop = (UInt32)mode; + } + else if (item && !item->Val.IsFlags_Unknown()) + prop = (UInt32)(item->Val.flags << 12); + break; + } + + case kpidCTime: if (inode) ApfsTimeToProp(inode->create_time, prop); break; + case kpidMTime: if (inode) ApfsTimeToProp(inode->mod_time, prop); break; + case kpidATime: if (inode) ApfsTimeToProp(inode->access_time, prop); break; + case kpidChangeTime: if (inode) ApfsTimeToProp(inode->change_time, prop); break; + case kpidAddTime: if (item) ApfsTimeToProp(item->Val.date_added, prop); break; + + case kpidBytesWritten: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && inode->dstream_defined) + prop = inode->dstream.total_bytes_written; + break; + case kpidBytesRead: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && inode->dstream_defined) + prop = inode->dstream.total_bytes_read; + break; + + #ifdef APFS_SHOW_ALT_STREAMS + case kpidIsAltStream: + prop = ref.IsAltStream(); + break; + #endif + + case kpidCharacts: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop); + } + break; + + case kpidBsdFlags: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + { + FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop); + } + break; + + case kpidGeneration: + #ifdef APFS_SHOW_ALT_STREAMS + // if (!ref.IsAltStream()) + #endif + if (inode) + prop = inode->write_generation_counter; + break; + + case kpidUserId: + if (inode) + prop = (UInt32)inode->owner; + break; + + case kpidGroupId: + if (inode) + prop = (UInt32)inode->group; + break; + + case kpidLinks: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode && !inode->IsDir()) + prop = (UInt32)inode->nlink; + break; + + case kpidINode: + #ifdef APFS_SHOW_ALT_STREAMS + // here we can disable iNode for alt stream. + if (!ref.IsAltStream()) + #endif + if (IsViDef(ref.NodeIndex)) + prop = (UInt32)vol.NodeIDs[ref.NodeIndex]; + break; + + case kpidParentINode: + #ifdef APFS_SHOW_ALT_STREAMS + if (!ref.IsAltStream()) + #endif + if (inode) + prop = (UInt32)inode->parent_id; + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +UInt64 CDatabase::GetSize(const UInt32 index) const +{ + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + if (IsViNotDef(ref2.RefIndex)) + return 0; + const CRef &ref = vol.Refs[ref2.RefIndex]; + if (IsViNotDef(ref.NodeIndex)) + return 0; + const CNode &inode = vol.Nodes[ref.NodeIndex]; + UInt64 size; + if (inode.GetSize(ref.GetAttrIndex(), size)) + return size; + return 0; +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = Refs2.Size(); + if (numItems == 0) + return S_OK; + UInt32 i; + + { + UInt64 totalSize = 0; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + totalSize += GetSize(index); + } + RINOK(extractCallback->SetTotal(totalSize)); + } + + UInt64 currentTotalSize = 0, currentItemSize = 0; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + NHfs::CDecoder decoder; + + for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + { + lps->InSize = currentTotalSize; + lps->OutSize = currentTotalSize; + RINOK(lps->SetCur()); + + const UInt32 index = allFilesMode ? i : indices[i]; + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + + currentItemSize = GetSize(index); + + CMyComPtr realOutStream; + + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + + if (IsViNotDef(ref2.RefIndex)) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + + const CRef &ref = vol.Refs[ref2.RefIndex]; + bool isDir = false; + if (IsViDef(ref.NodeIndex)) + isDir = vol.Nodes[ref.NodeIndex].IsDir(); + else if (IsViDef(ref.ItemIndex)) + isDir = + #ifdef APFS_SHOW_ALT_STREAMS + !ref.IsAltStream() && + #endif + vol.Items[ref.ItemIndex].Val.IsFlags_Dir(); + + if (isDir) + { + RINOK(extractCallback->PrepareOperation(askMode)); + RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); + continue; + } + if (!testMode && !realOutStream) + continue; + RINOK(extractCallback->PrepareOperation(askMode)); + int opRes = NExtract::NOperationResult::kDataError; + + if (IsViDef(ref.NodeIndex)) + { + const CNode &inode = vol.Nodes[ref.NodeIndex]; + if ( + #ifdef APFS_SHOW_ALT_STREAMS + !ref.IsAltStream() && + #endif + !inode.dstream_defined + && inode.Extents.IsEmpty() + && inode.Has_UNCOMPRESSED_SIZE() + && inode.uncompressed_size == inode.CompressHeader.UnpackSize) + { + if (inode.CompressHeader.IsSupported) + { + CMyComPtr inStreamFork; + UInt64 forkSize = 0; + const CByteBuffer *decmpfs_Data = NULL; + + if (inode.CompressHeader.IsMethod_Resource()) + { + if (IsViDef(inode.ResourceIndex)) + { + const CAttr &attr = inode.Attrs[inode.ResourceIndex]; + forkSize = attr.GetSize(); + GetAttrStream(_stream, vol, attr, &inStreamFork); + } + } + else + { + const CAttr &attr = inode.Attrs[inode.DecmpfsIndex]; + decmpfs_Data = &attr.Data; + } + + if (inStreamFork || decmpfs_Data) + { + const HRESULT hres = decoder.Extract( + inStreamFork, realOutStream, + forkSize, + inode.CompressHeader, + decmpfs_Data, + currentTotalSize, extractCallback, + opRes); + if (hres != S_FALSE && hres != S_OK) + return hres; + } + } + else + opRes = NExtract::NOperationResult::kUnsupportedMethod; + } + else + { + CMyComPtr inStream; + if (GetStream(index, &inStream) == S_OK && inStream) + { + RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress)); + opRes = NExtract::NOperationResult::kDataError; + if (copyCoderSpec->TotalSize == currentItemSize) + opRes = NExtract::NOperationResult::kOK; + else if (copyCoderSpec->TotalSize < currentItemSize) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + } + } + + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)); + } + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = Refs2.Size(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + *stream = NULL; + + const CRef2 &ref2 = Refs2[index]; + const CVol &vol = Vols[ref2.VolIndex]; + if (IsViNotDef(ref2.RefIndex)) + return S_FALSE; + + const CRef &ref = vol.Refs[ref2.RefIndex]; + if (IsViNotDef(ref.NodeIndex)) + return S_FALSE; + const CNode &inode = vol.Nodes[ref.NodeIndex]; + + const CRecordVector *extents; + UInt64 rem = 0; + + unsigned attrIndex = ref.GetAttrIndex(); + + if (IsViNotDef(attrIndex) + && !inode.dstream_defined + && inode.IsSymLink()) + { + attrIndex = inode.SymLinkIndex; + if (IsViNotDef(attrIndex)) + return S_FALSE; + } + + if (IsViDef(attrIndex)) + { + const CAttr &attr = inode.Attrs[(unsigned)attrIndex]; + if (!attr.dstream_defined) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + } + const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); + if (idIndex == -1) + return S_FALSE; + extents = &vol.SmallNodes[(unsigned)idIndex].Extents; + rem = attr.dstream.size; + } + else + { + if (IsViDef(ref.ItemIndex)) + if (vol.Items[ref.ItemIndex].Val.IsFlags_Dir()) + return S_FALSE; + if (inode.IsDir()) + return S_FALSE; + if (inode.dstream_defined) + { + rem = inode.dstream.size; + } + else + { + // return S_FALSE; // check it !!! How zero size files are stored with dstream_defined? + } + + extents = &inode.Extents; + } + return GetStream2(_stream, extents, rem, stream); +} + + + +HRESULT CDatabase::GetAttrStream(IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream) +{ + *stream = NULL; + if (!attr.dstream_defined) + { + CBufInStream *streamSpec = new CBufInStream; + CMyComPtr streamTemp = streamSpec; + streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this); + *stream = streamTemp.Detach(); + return S_OK; + } + return GetAttrStream_dstream(apfsInStream, vol, attr, stream); +} + + +HRESULT CDatabase::GetAttrStream_dstream( IInStream *apfsInStream, const CVol &vol, + const CAttr &attr, ISequentialInStream **stream) +{ + const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id); + if (idIndex == -1) + return S_FALSE; + return GetStream2(apfsInStream, + &vol.SmallNodes[(unsigned)idIndex].Extents, + attr.dstream.size, + stream); +} + + +HRESULT CDatabase::GetStream2( + IInStream *apfsInStream, + const CRecordVector *extents, UInt64 rem, + ISequentialInStream **stream) +{ + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr extentStream = extentStreamSpec; + + UInt64 virt = 0; + FOR_VECTOR (i, *extents) + { + const CExtent &e = (*extents)[i]; + if (virt != e.logical_offset) + return S_FALSE; + const UInt64 len = EXTENT_GET_LEN(e.len_and_flags); + if (len == 0) + { + return S_FALSE; + // continue; + } + if (rem == 0) + return S_FALSE; + UInt64 cur = len; + if (cur > rem) + cur = rem; + CSeekExtent se; + se.Phy = (UInt64)e.phys_block_num << sb.block_size_Log; + se.Virt = virt; + virt += cur; + rem -= cur; + extentStreamSpec->Extents.Add(se); + if (rem == 0) + if (i != extents->Size() - 1) + return S_FALSE; + } + + if (rem != 0) + return S_FALSE; + + CSeekExtent se; + se.Phy = 0; + se.Virt = virt; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Stream = apfsInStream; + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + return S_OK; +} + + +REGISTER_ARC_I( + "APFS", "apfs img", NULL, 0xc3, + k_Signature, + k_SignatureOffset, + 0, + IsArc_APFS) + +}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/ArchiveExports.cpp 7zip-22.01/CPP/7zip/Archive/ArchiveExports.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/ArchiveExports.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/ArchiveExports.cpp 2022-04-25 09:00:00.000000000 +0000 @@ -115,6 +115,7 @@ case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break; case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break; case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break; + case NArchive::NHandlerPropID::kTimeFlags: prop = (UInt32)arc.TimeFlags; break; case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break; // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/ArHandler.cpp 7zip-22.01/CPP/7zip/Archive/ArHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/ArHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/ArHandler.cpp 2022-04-30 11:00:00.000000000 +0000 @@ -322,8 +322,8 @@ kpidSize, kpidMTime, kpidPosixAttrib, - kpidUser, - kpidGroup + kpidUserId, + kpidGroupId }; IMP_IInArchive_Props @@ -734,15 +734,11 @@ case kpidMTime: { if (item.MTime != 0) - { - FILETIME fileTime; - NTime::UnixTimeToFileTime(item.MTime, fileTime); - prop = fileTime; - } + PropVariant_SetFrom_UnixTime(prop, item.MTime); break; } - case kpidUser: if (item.User != 0) prop = item.User; break; - case kpidGroup: if (item.Group != 0) prop = item.Group; break; + case kpidUserId: if (item.User != 0) prop = item.User; break; + case kpidGroupId: if (item.Group != 0) prop = item.Group; break; case kpidPosixAttrib: if (item.TextFileIndex < 0) prop = item.Mode; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/ArjHandler.cpp 7zip-22.01/CPP/7zip/Archive/ArjHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/ArjHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/ArjHandler.cpp 2022-02-14 07:00:00.000000000 +0000 @@ -682,15 +682,7 @@ { if (dosTime == 0) return; - FILETIME localFileTime, utc; - if (NTime::DosTimeToFileTime(dosTime, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utc)) - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - else - utc.dwHighDateTime = utc.dwLowDateTime = 0; - prop = utc; + PropVariant_SetFrom_DosTime(prop, dosTime); } static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Bz2Handler.cpp 7zip-22.01/CPP/7zip/Archive/Bz2Handler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Bz2Handler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Bz2Handler.cpp 2022-04-30 11:00:00.000000000 +0000 @@ -305,29 +305,91 @@ } +/* +static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value); +} + +static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value); +} + +static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, + const UInt64 *unpackSize, + const UInt64 *numBlocks) +{ + NCOM::CPropVariant sizeProp; + if (unpackSize) + { + sizeProp = *unpackSize; + RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp)); + RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK)); + } + + if (unpackSize) + { + RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp)); + } + if (numBlocks) + { + NCOM::CPropVariant prop; + prop = *numBlocks; + RINOK(ReportArcProp(reportArcProp, kpidNumBlocks, &prop)); + } + return S_OK; +} +*/ static HRESULT UpdateArchive( UInt64 unpackSize, ISequentialOutStream *outStream, const CProps &props, - IArchiveUpdateCallback *updateCallback) + IArchiveUpdateCallback *updateCallback + // , ArchiveUpdateCallbackArcProp *reportArcProp + ) { - RINOK(updateCallback->SetTotal(unpackSize)); - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - CLocalProgress *localProgressSpec = new CLocalProgress; - CMyComPtr localProgress = localProgressSpec; - localProgressSpec->Init(updateCallback, true); - NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; - CMyComPtr encoder = encoderSpec; - RINOK(props.SetCoderProps(encoderSpec, NULL)); - RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + { + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + if (!fileInStream) + return S_FALSE; + { + CMyComPtr streamGetSize; + fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) + { + UInt64 size; + if (streamGetSize->GetSize(&size) == S_OK) + unpackSize = size; + } + } + RINOK(updateCallback->SetTotal(unpackSize)); + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr localProgress = localProgressSpec; + localProgressSpec->Init(updateCallback, true); + { + NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; + CMyComPtr encoder = encoderSpec; + RINOK(props.SetCoderProps(encoderSpec, NULL)); + RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); + /* + if (reportArcProp) + { + unpackSize = encoderSpec->GetInProcessedSize(); + RINOK(ReportArcProps(reportArcProp, &unpackSize, &encoderSpec->NumBlocks)); + } + */ + } + } return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); } -STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) +STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) { - *type = NFileTimeType::kUnix; + *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; + // *timeType = NFileTimeType::kUnix; return S_OK; } @@ -345,6 +407,11 @@ return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + /* + CMyComPtr reportArcProp; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp); + */ + if (IntToBool(newProps)) { { @@ -396,6 +463,8 @@ return NCompress::CopyStream(_stream, outStream, progress); + // return ReportArcProps(reportArcProp, NULL, NULL); + COM_TRY_END } @@ -410,7 +479,8 @@ "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, k_Signature, 0, - NArcInfoFlags::kKeepName, - IsArc_BZip2) + NArcInfoFlags::kKeepName + , 0 + , IsArc_BZip2) }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Cab/CabHandler.cpp 7zip-22.01/CPP/7zip/Archive/Cab/CabHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Cab/CabHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Cab/CabHandler.cpp 2022-02-14 07:00:00.000000000 +0000 @@ -295,15 +295,7 @@ case kpidMTime: { - FILETIME localFileTime, utcFileTime; - if (NTime::DosTimeToFileTime(item.Time, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - } - else - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - prop = utcFileTime; + PropVariant_SetFrom_DosTime(prop, item.Time); break; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Chm/ChmIn.h 7zip-22.01/CPP/7zip/Archive/Chm/ChmIn.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Chm/ChmIn.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Chm/ChmIn.h 2022-07-14 08:00:00.000000000 +0000 @@ -84,6 +84,11 @@ // unsigned BlockSizeBits; CRecordVector ResetOffsets; + CResetTable(): + UncompressedSize(0), + CompressedSize(0) + {} + bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const { if (blockIndex >= ResetOffsets.Size()) @@ -118,6 +123,13 @@ CResetTable ResetTable; + CLzxInfo(): + Version(0), + ResetIntervalBits(0), + WindowSizeBits(0), + CacheSize(0) + {} + unsigned GetNumDictBits() const { if (Version == 2 || Version == 3) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Common/HandlerOut.cpp 7zip-22.01/CPP/7zip/Archive/Common/HandlerOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Common/HandlerOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Common/HandlerOut.cpp 2022-05-10 12:00:00.000000000 +0000 @@ -240,34 +240,42 @@ } +HRESULT CSingleMethodProps::SetProperty(const wchar_t *name2, const PROPVARIANT &value) +{ + // processed = false; + UString name = name2; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + if (name.IsPrefixedBy_Ascii_NoCase("x")) + { + UInt32 a = 9; + RINOK(ParsePropToUInt32(name.Ptr(1), value, a)); + _level = a; + AddProp_Level(a); + // processed = true; + return S_OK; + } + { + HRESULT hres; + if (SetCommonProperty(name, value, hres)) + { + // processed = true; + return S_OK; + } + } + RINOK(ParseMethodFromPROPVARIANT(name, value)); + return S_OK; +} + + HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { Init(); for (UInt32 i = 0; i < numProps; i++) { - UString name = names[i]; - name.MakeLower_Ascii(); - if (name.IsEmpty()) - return E_INVALIDARG; - const PROPVARIANT &value = values[i]; - if (name[0] == L'x') - { - UInt32 a = 9; - RINOK(ParsePropToUInt32(name.Ptr(1), value, a)); - _level = a; - AddProp_Level(a); - continue; - } - { - HRESULT hres; - if (SetCommonProperty(name, value, hres)) - { - RINOK(hres) - continue; - } - } - RINOK(ParseMethodFromPROPVARIANT(names[i], value)); + RINOK(SetProperty(names[i], values[i])); } return S_OK; @@ -275,4 +283,29 @@ #endif + +static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) +{ + RINOK(PROPVARIANT_to_bool(prop, dest.Val)); + dest.Def = true; + return S_OK; +} + +HRESULT CHandlerTimeOptions::Parse(const UString &name, const PROPVARIANT &prop, bool &processed) +{ + processed = true; + if (name.IsEqualTo_Ascii_NoCase("tm")) { return PROPVARIANT_to_BoolPair(prop, Write_MTime); } + if (name.IsEqualTo_Ascii_NoCase("ta")) { return PROPVARIANT_to_BoolPair(prop, Write_ATime); } + if (name.IsEqualTo_Ascii_NoCase("tc")) { return PROPVARIANT_to_BoolPair(prop, Write_CTime); } + if (name.IsPrefixedBy_Ascii_NoCase("tp")) + { + UInt32 v = 0; + RINOK(ParsePropToUInt32(name.Ptr(2), prop, v)); + Prec = v; + return S_OK; + } + processed = false; + return S_OK; +} + } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Common/HandlerOut.h 7zip-22.01/CPP/7zip/Archive/Common/HandlerOut.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Common/HandlerOut.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Common/HandlerOut.h 2022-05-10 12:00:00.000000000 +0000 @@ -16,6 +16,7 @@ protected: void InitCommon() { + // _Write_MTime = true; #ifndef _7ZIP_ST _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); _numThreads_WasForced = false; @@ -118,11 +119,36 @@ CSingleMethodProps() { InitSingle(); } int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } + HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &values); HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); }; #endif +struct CHandlerTimeOptions +{ + CBoolPair Write_MTime; + CBoolPair Write_ATime; + CBoolPair Write_CTime; + UInt32 Prec; + + void Init() + { + Write_MTime.Init(); + Write_MTime.Val = true; + Write_ATime.Init(); + Write_CTime.Init(); + Prec = (UInt32)(Int32)-1; + } + + CHandlerTimeOptions() + { + Init(); + } + + HRESULT Parse(const UString &name, const PROPVARIANT &prop, bool &processed); +}; + } #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.cpp 7zip-22.01/CPP/7zip/Archive/Common/ItemNameUtils.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Common/ItemNameUtils.cpp 2022-01-09 18:00:00.000000000 +0000 @@ -79,6 +79,29 @@ } +void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *name, unsigned len) +{ + for (unsigned i = 0; i < len; i++) + { + wchar_t c = name[i]; + if (c == L'/') + c = L'_'; + #if WCHAR_PATH_SEPARATOR != L'/' + else if (c == L'\\') + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme + #endif + else + continue; + name[i] = c; + } +} + +void NormalizeSlashes_in_FileName_for_OsPath(UString &name) +{ + NormalizeSlashes_in_FileName_for_OsPath(name.GetBuf(), name.Len()); +} + + bool HasTailSlash(const AString &name, UINT #if defined(_WIN32) && !defined(UNDER_CE) codePage diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.h 7zip-22.01/CPP/7zip/Archive/Common/ItemNameUtils.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Common/ItemNameUtils.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Common/ItemNameUtils.h 2022-01-09 18:00:00.000000000 +0000 @@ -14,6 +14,8 @@ UString GetOsPath_Remove_TailSlash(const UString &name); void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); +void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len); +void NormalizeSlashes_in_FileName_for_OsPath(UString &name); bool HasTailSlash(const AString &name, UINT codePage); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/CpioHandler.cpp 7zip-22.01/CPP/7zip/Archive/CpioHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/CpioHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/CpioHandler.cpp 2022-02-14 07:00:00.000000000 +0000 @@ -652,11 +652,7 @@ case kpidMTime: { if (item.MTime != 0) - { - FILETIME utc; - NTime::UnixTimeToFileTime(item.MTime, utc); - prop = utc; - } + PropVariant_SetFrom_UnixTime(prop, item.MTime); break; } case kpidPosixAttrib: prop = item.Mode; break; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/DllExports2.cpp 7zip-22.01/CPP/7zip/Archive/DllExports2.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/DllExports2.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/DllExports2.cpp 2022-04-30 11:00:00.000000000 +0000 @@ -125,6 +125,24 @@ return S_OK; } +/* +UInt32 g_ClientVersion; +STDAPI SetClientVersion(UInt32 version); +STDAPI SetClientVersion(UInt32 version) +{ + g_ClientVersion = version; + return S_OK; +} +*/ + +/* +STDAPI SetProperty(Int32 id, const PROPVARIANT *value); +STDAPI SetProperty(Int32 id, const PROPVARIANT *value) +{ + return S_OK; +} +*/ + #ifdef EXTERNAL_CODECS CExternalCodecs g_ExternalCodecs; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/DmgHandler.cpp 7zip-22.01/CPP/7zip/Archive/DmgHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/DmgHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/DmgHandler.cpp 2022-07-15 13:00:00.000000000 +0000 @@ -1063,6 +1063,8 @@ subName.DeleteFrom(pos1); } } + else + subName = item.Name; // new apfs dmg can be without braces subName.Trim(); if (!subName.IsEmpty()) { diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/ExtHandler.cpp 7zip-22.01/CPP/7zip/Archive/ExtHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/ExtHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/ExtHandler.cpp 2022-04-30 11:00:00.000000000 +0000 @@ -343,6 +343,8 @@ bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; } bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; } + UInt64 GetPhySize() const { return NumBlocks << BlockBits; } + bool Parse(const Byte *p); }; @@ -638,7 +640,7 @@ CExtTime MTime; CExtTime ATime; CExtTime CTime; - // CExtTime InodeChangeTime; + CExtTime ChangeTime; // CExtTime DTime; UInt64 NumBlocks; @@ -674,14 +676,14 @@ ATime.Extra = 0; CTime.Extra = 0; CTime.Val = 0; - // InodeChangeTime.Extra = 0; + ChangeTime.Extra = 0; // DTime.Extra = 0; LE_16 (0x00, Mode); LE_16 (0x02, Uid); LE_32 (0x04, FileSize); LE_32 (0x08, ATime.Val); - // LE_32 (0x0C, InodeChangeTime.Val); + LE_32 (0x0C, ChangeTime.Val); LE_32 (0x10, MTime.Val); // LE_32 (0x14, DTime.Val); LE_16 (0x18, Gid); @@ -742,7 +744,7 @@ { // UInt16 checksumUpper; // LE_16 (0x82, checksumUpper); - // LE_32 (0x84, InodeChangeTime.Extra); + LE_32 (0x84, ChangeTime.Extra); LE_32 (0x88, MTime.Extra); LE_32 (0x8C, ATime.Extra); LE_32 (0x90, CTime.Val); @@ -1148,7 +1150,7 @@ } _isArc = true; - _phySize = _h.NumBlocks << _h.BlockBits; + _phySize = _h.GetPhySize(); if (_openCallback) { @@ -1744,8 +1746,8 @@ kpidLinks, kpidSymLink, kpidCharacts, - kpidUser, - kpidGroup + kpidUserId, + kpidGroupId }; @@ -1792,11 +1794,7 @@ static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop) { if (val != 0) - { - FILETIME ft; - NTime::UnixTimeToFileTime(val, ft); - prop = ft; - } + PropVariant_SetFrom_UnixTime(prop, val); } STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) @@ -1988,15 +1986,19 @@ return; FILETIME ft; + unsigned low100ns = 0; // if (t.Extra != 0) { // 1901-2446 : Int64 v = (Int64)(Int32)t.Val; v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp - UInt64 ft64 = NTime::UnixTime64ToFileTime64(v); + UInt64 ft64 = NTime::UnixTime64_To_FileTime64(v); const UInt32 ns = (t.Extra >> 2); if (ns < 1000000000) + { ft64 += ns / 100; + low100ns = (unsigned)(ns % 100); + } ft.dwLowDateTime = (DWORD)ft64; ft.dwHighDateTime = (DWORD)(ft64 >> 32); } @@ -2011,7 +2013,7 @@ // NTime::UnixTimeToFileTime(t.Val, ft); // for } */ - prop = ft; + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns); } @@ -2103,10 +2105,9 @@ case kpidCTime: ExtTimeToProp(node.CTime, prop); break; case kpidATime: ExtTimeToProp(node.ATime, prop); break; // case kpidDTime: ExtTimeToProp(node.DTime, prop); break; - // case kpidChangeTime: ExtTimeToProp(node.InodeChangeTime, prop); break; - - case kpidUser: prop = (UInt32)node.Uid; break; - case kpidGroup: prop = (UInt32)node.Gid; break; + case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break; + case kpidUserId: prop = (UInt32)node.Uid; break; + case kpidGroupId: prop = (UInt32)node.Gid; break; case kpidLinks: prop = node.NumLinks; break; case kpidINode: prop = (UInt32)item.Node; break; case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break; @@ -2827,17 +2828,29 @@ } -API_FUNC_static_IsArc IsArc_Ext(const Byte *p, size_t size) +API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); +API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize) { + if (phySize) + *phySize = 0; if (size < kHeaderSize) return k_IsArc_Res_NEED_MORE; CHeader h; if (!h.Parse(p + kHeaderDataOffset)) return k_IsArc_Res_NO; + if (phySize) + *phySize = h.GetPhySize(); return k_IsArc_Res_YES; } + + +API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size); +API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size) +{ + return IsArc_Ext_PhySize(p, size, NULL); } + static const Byte k_Signature[] = { 0x53, 0xEF }; REGISTER_ARC_I( diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/FatHandler.cpp 7zip-22.01/CPP/7zip/Archive/FatHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/FatHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/FatHandler.cpp 2022-03-28 12:00:00.000000000 +0000 @@ -111,14 +111,14 @@ static const UInt32 kHeaderSize = 512; -API_FUNC_static_IsArc IsArc_Fat(const Byte *p, size_t size) +API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); +API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size) { if (size < kHeaderSize) return k_IsArc_Res_NEED_MORE; CHeader h; return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO; } -} bool CHeader::Parse(const Byte *p) { @@ -846,17 +846,18 @@ IMP_IInArchive_Props IMP_IInArchive_ArcProps_WITH_NAME + static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop) { FILETIME localFileTime, utc; - if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime)) + if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime)) if (LocalFileTimeToFileTime(&localFileTime, &utc)) { UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; t64 += ms10 * 100000; utc.dwLowDateTime = (DWORD)t64; utc.dwHighDateTime = (DWORD)(t64 >> 32); - prop = utc; + prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2); } } @@ -892,7 +893,7 @@ case kpidPhySize: prop = PhySize; break; case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; case kpidHeadersSize: prop = GetHeadersSize(); break; - case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break; + case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break; case kpidShortComment: case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break; @@ -920,9 +921,9 @@ case kpidPath: prop = GetItemPath(index); break; case kpidShortName: prop = item.GetShortName(); break; case kpidIsDir: prop = item.IsDir(); break; - case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break; + case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break; case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break; - case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break; + case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break; case kpidAttrib: prop = (UInt32)item.Attrib; break; case kpidSize: if (!item.IsDir()) prop = item.Size; break; case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/GptHandler.cpp 7zip-22.01/CPP/7zip/Archive/GptHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/GptHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/GptHandler.cpp 2021-12-29 09:00:00.000000000 +0000 @@ -23,6 +23,11 @@ using namespace NWindows; namespace NArchive { + +namespace NFat { +API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size); +} + namespace NGpt { #define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 } @@ -51,6 +56,7 @@ UInt64 FirstLba; UInt64 LastLba; UInt64 Flags; + const char *Ext; // detected later Byte Name[kNameLen * 2]; bool IsUnused() const @@ -73,6 +79,7 @@ LastLba = Get64(p + 40); Flags = Get64(p + 48); memcpy(Name, p + 56, kNameLen * 2); + Ext = NULL; } }; @@ -252,6 +259,28 @@ return S_OK; } + + +static const unsigned k_Ntfs_Fat_HeaderSize = 512; + +static const Byte k_NtfsSignature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 }; + +static bool IsNtfs(const Byte *p) +{ + if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA) + return false; + if (memcmp(p + 3, k_NtfsSignature, ARRAY_SIZE(k_NtfsSignature)) != 0) + return false; + switch (p[0]) + { + case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break; + case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break; + default: return false; + } + return true; +} + + STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* openArchiveCallback */) @@ -260,6 +289,42 @@ Close(); RINOK(Open2(stream)); _stream = stream; + + FOR_VECTOR (fileIndex, _items) + { + CPartition &item = _items[fileIndex]; + const int typeIndex = FindPartType(item.Type); + if (typeIndex < 0) + continue; + const CPartType &t = kPartTypes[(unsigned)typeIndex]; + if (t.Ext) + { + item.Ext = t.Ext; + continue; + } + if (t.Type && IsString1PrefixedByString2_NoCase_Ascii(t.Type, "Windows")) + { + CMyComPtr inStream; + if (GetStream(fileIndex, &inStream) == S_OK && inStream) + { + Byte temp[k_Ntfs_Fat_HeaderSize]; + if (ReadStream_FAIL(inStream, temp, k_Ntfs_Fat_HeaderSize) == S_OK) + { + if (IsNtfs(temp)) + { + item.Ext = "ntfs"; + continue; + } + if (NFat::IsArc_Fat(temp, k_Ntfs_Fat_HeaderSize) == k_IsArc_Res_YES) + { + item.Ext = "fat"; + continue; + } + } + } + } + } + return S_OK; COM_TRY_END } @@ -355,13 +420,7 @@ } { s += '.'; - const char *ext = NULL; - int typeIndex = FindPartType(item.Type); - if (typeIndex >= 0) - ext = kPartTypes[(unsigned)typeIndex].Ext; - if (!ext) - ext = "img"; - s += ext; + s += (item.Ext ? item.Ext : "img"); } prop = s; break; @@ -375,7 +434,7 @@ { char s[48]; const char *res; - int typeIndex = FindPartType(item.Type); + const int typeIndex = FindPartType(item.Type); if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type) res = kPartTypes[(unsigned)typeIndex].Type; else diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/GzHandler.cpp 7zip-22.01/CPP/7zip/Archive/GzHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/GzHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/GzHandler.cpp 2022-05-09 12:00:00.000000000 +0000 @@ -475,6 +475,7 @@ NDecoder::CCOMCoder *_decoderSpec; CSingleMethodProps _props; + CHandlerTimeOptions _timeOptions; public: MY_UNKNOWN_IMP4( @@ -487,8 +488,15 @@ STDMETHOD(OpenSeq)(ISequentialInStream *stream); STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); - CHandler() + CHandler(): + _isArc(false), + _decoderSpec(NULL) + {} + + void CreateDecoder() { + if (_decoder) + return; _decoderSpec = new NDecoder::CCOMCoder; _decoder = _decoderSpec; } @@ -528,7 +536,7 @@ case kpidErrorFlags: { UInt32 v = 0; - if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; prop = v; @@ -567,12 +575,13 @@ break; // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break; case kpidMTime: + // gzip specification: MTIME = 0 means no time stamp is available. if (_item.Time != 0) - { - FILETIME utc; - NTime::UnixTimeToFileTime(_item.Time, utc); - prop = utc; - } + PropVariant_SetFrom_UnixTime(prop, _item.Time); + break; + case kpidTimeType: + if (_item.Time != 0) + prop = (UInt32)NFileTimeType::kUnix; break; case kpidSize: { @@ -644,6 +653,7 @@ try { Close(); + CreateDecoder(); _decoderSpec->SetInStream(stream); _decoderSpec->InitInStream(true); RINOK(_item.ReadHeader(_decoderSpec)); @@ -672,7 +682,8 @@ _headerSize = 0; _stream.Release(); - _decoderSpec->ReleaseInStream(); + if (_decoder) + _decoderSpec->ReleaseInStream(); return S_OK; } @@ -699,6 +710,8 @@ extractCallback->PrepareOperation(askMode); + CreateDecoder(); + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; CMyComPtr outStream(outStreamSpec); outStreamSpec->SetStream(realOutStream); @@ -873,21 +886,99 @@ NHostOS::kUnix; #endif + +/* +static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value); +} + +static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value) +{ + return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value); +} + +static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, + const CItem &item, + bool needTime, + bool needCrc, + const UInt64 *unpackSize) +{ + NCOM::CPropVariant timeProp; + NCOM::CPropVariant sizeProp; + if (needTime) + { + FILETIME ft; + NTime::UnixTimeToFileTime(item.Time, ft); + timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix); + } + if (unpackSize) + { + sizeProp = *unpackSize; + RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp)); + } + if (needCrc) + { + NCOM::CPropVariant prop; + prop = item.Crc; + RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop)); + } + { + RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp)); + } + + RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK)); + + if (unpackSize) + { + RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp)); + } + { + RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp)); + } + return S_OK; +} +*/ + static HRESULT UpdateArchive( ISequentialOutStream *outStream, UInt64 unpackSize, CItem &item, const CSingleMethodProps &props, - IArchiveUpdateCallback *updateCallback) + const CHandlerTimeOptions &timeOptions, + IArchiveUpdateCallback *updateCallback + // , IArchiveUpdateCallbackArcProp *reportArcProp + ) { - UInt64 complexity = 0; - RINOK(updateCallback->SetTotal(unpackSize)); - RINOK(updateCallback->SetCompleted(&complexity)); - + UInt64 unpackSizeReal; + { CMyComPtr fileInStream; RINOK(updateCallback->GetStream(0, &fileInStream)); + if (!fileInStream) + return S_FALSE; + + { + CMyComPtr getProps; + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) + { + FILETIME mTime; + UInt64 size; + if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK) + { + unpackSize = size; + if (timeOptions.Write_MTime.Val) + NTime::FileTime_To_UnixTime(mTime, item.Time); + } + } + } + + UInt64 complexity = 0; + RINOK(updateCallback->SetTotal(unpackSize)); + RINOK(updateCallback->SetCompleted(&complexity)); + CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC; CMyComPtr crcStream(inStreamSpec); inStreamSpec->SetStream(fileInStream); @@ -911,14 +1002,50 @@ RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); item.Crc = inStreamSpec->GetCRC(); - item.Size32 = (UInt32)inStreamSpec->GetSize(); + unpackSizeReal = inStreamSpec->GetSize(); + item.Size32 = (UInt32)unpackSizeReal; RINOK(item.WriteFooter(outStream)); + } + /* + if (reportArcProp) + { + RINOK(ReportArcProps(reportArcProp, + item, + props._Write_MTime, // item.Time != 0, + true, // writeCrc + &unpackSizeReal)); + } + */ return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK); } + STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) { - *timeType = NFileTimeType::kUnix; + /* + if (_item.Time != 0) + { + we set NFileTimeType::kUnix in precision, + and we return NFileTimeType::kUnix in kpidTimeType + so GetFileTimeType() value is not used in any version of 7-zip. + } + else // (_item.Time == 0) + { + kpidMTime and kpidTimeType are not defined + before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList(); + 22.00 : GetFileTimeType() value is not used + } + */ + + UInt32 t; + t = NFileTimeType::kUnix; + if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val) + { + t = GET_FileTimeType_NotDefined_for_GetFileTimeType; + // t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21 + // t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21 + } + *timeType = t; return S_OK; } @@ -936,6 +1063,11 @@ return E_FAIL; RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); + /* + CMyComPtr reportArcProp; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp); + */ + CItem newItem; if (!IntToBool(newProps)) @@ -945,11 +1077,12 @@ else { newItem.HostOS = kHostOS; + if (_timeOptions.Write_MTime.Val) { NCOM::CPropVariant prop; RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)); if (prop.vt == VT_FILETIME) - NTime::FileTimeToUnixTime(prop.filetime, newItem.Time); + NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time); else if (prop.vt == VT_EMPTY) newItem.Time = 0; else @@ -990,7 +1123,7 @@ return E_INVALIDARG; size = prop.uhVal.QuadPart; } - return UpdateArchive(outStream, size, newItem, _props, updateCallback); + return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback); } if (indexInArchive != 0) @@ -1022,6 +1155,14 @@ } RINOK(_stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL)); + /* + if (reportArcProp) + ReportArcProps(reportArcProp, newItem, + _props._Write_MTime, + false, // writeCrc + NULL); // unpacksize + */ + return NCompress::CopyStream(_stream, outStream, progress); COM_TRY_END @@ -1029,16 +1170,48 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { - return _props.SetProperties(names, values, numProps); + _timeOptions.Init(); + _props.Init(); + + for (UInt32 i = 0; i < numProps; i++) + { + UString name = names[i]; + name.MakeLower_Ascii(); + if (name.IsEmpty()) + return E_INVALIDARG; + const PROPVARIANT &value = values[i]; + { + bool processed = false; + RINOK(_timeOptions.Parse(name, value, processed)); + if (processed) + { + if (_timeOptions.Write_CTime.Val || + _timeOptions.Write_ATime.Val) + return E_INVALIDARG; + if ( _timeOptions.Prec != (UInt32)(Int32)-1 + && _timeOptions.Prec != k_PropVar_TimePrec_0 + && _timeOptions.Prec != k_PropVar_TimePrec_Unix + && _timeOptions.Prec != k_PropVar_TimePrec_HighPrec + && _timeOptions.Prec != k_PropVar_TimePrec_Base) + return E_INVALIDARG; + continue; + } + } + RINOK(_props.SetProperty(name, value)); + } + return S_OK; } static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 }; REGISTER_ARC_IO( "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF, - k_Signature, - 0, - NArcInfoFlags::kKeepName, - IsArc_Gz) + k_Signature, 0, + NArcInfoFlags::kKeepName + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix) + , IsArc_Gz) }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/HandlerCont.cpp 7zip-22.01/CPP/7zip/Archive/HandlerCont.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/HandlerCont.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/HandlerCont.cpp 2022-01-31 08:00:00.000000000 +0000 @@ -14,6 +14,10 @@ namespace NArchive { +namespace NExt { +API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size); +} + STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -132,11 +136,12 @@ } static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' }; - +// static const Byte k_Ext_Signature[] = { 0x53, 0xEF }; +// static const unsigned k_Ext_Signature_offset = 0x438; static const char *GetImgExt(ISequentialInStream *stream) { - const size_t kHeaderSize = 1 << 10; + const size_t kHeaderSize = 1 << 11; Byte buf[kHeaderSize]; if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK) { @@ -146,6 +151,8 @@ return "gpt"; return "mbr"; } + if (NExt::IsArc_Ext(buf, kHeaderSize) == k_IsArc_Res_YES) + return "ext"; } return NULL; } @@ -208,6 +215,33 @@ return S_OK; } + +class CHandlerImgProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + CHandlerImg &Handler; + CMyComPtr _ratioProgress; + + CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {} + + // MY_UNKNOWN_IMP1(ICompressProgressInfo) + MY_UNKNOWN_IMP + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + + +STDMETHODIMP CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + UInt64 inSize2; + if (Handler.Get_PackSizeProcessed(inSize2)) + inSize = &inSize2; + return _ratioProgress->SetRatioInfo(inSize, outSize); +} + + STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { @@ -227,10 +261,6 @@ return S_OK; RINOK(extractCallback->PrepareOperation(askMode)); - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(extractCallback, false); - int opRes = NExtract::NOperationResult::kDataError; ClearStreamVars(); @@ -242,6 +272,19 @@ if (hres == S_OK && inStream) { + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + if (Init_PackSizeProcessed()) + { + CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this); + CMyComPtr imgProgress = imgProgressSpec; + imgProgressSpec->_ratioProgress = progress; + progress.Release(); + progress = imgProgress; + } + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); CMyComPtr copyCoder = copyCoderSpec; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/HandlerCont.h 7zip-22.01/CPP/7zip/Archive/HandlerCont.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/HandlerCont.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/HandlerCont.h 2022-04-30 11:00:00.000000000 +0000 @@ -94,7 +94,19 @@ virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; virtual void CloseAtError(); + + // returns (true), if Get_PackSizeProcessed() is required in Extract() + virtual bool Init_PackSizeProcessed() + { + return false; + } public: + virtual bool Get_PackSizeProcessed(UInt64 &size) + { + size = 0; + return false; + } + MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) INTERFACE_IInArchive_Img(PURE) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/HfsHandler.cpp 7zip-22.01/CPP/7zip/Archive/HfsHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/HfsHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/HfsHandler.cpp 2022-07-10 12:00:00.000000000 +0000 @@ -7,19 +7,19 @@ #include "../../Common/ComTry.h" #include "../../Common/MyString.h" -#include "../../Windows/PropVariant.h" +#include "../../Windows/PropVariantUtils.h" #include "../Common/LimitedStreams.h" #include "../Common/RegisterArc.h" #include "../Common/StreamObjects.h" #include "../Common/StreamUtils.h" -#include "../Compress/ZlibDecoder.h" +#include "HfsHandler.h" /* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files and resource forks. In most cases it looks useless. So we disable it. */ -// #define HFS_SHOW_ALT_STREAMS +#define HFS_SHOW_ALT_STREAMS #define Get16(p) GetBe16(p) #define Get32(p) GetBe32(p) @@ -80,6 +80,8 @@ }; static const unsigned kNumFixedExtents = 8; +static const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; + void CFork::Parse(const Byte *p) { @@ -227,6 +229,121 @@ RECORD_TYPE_FILE_THREAD }; + + +// static const UInt32 kMethod_1_NO_COMPRESSION = 1; // in xattr +static const UInt32 kMethod_ZLIB_ATTR = 3; +static const UInt32 kMethod_ZLIB_RSRC = 4; +// static const UInt32 kMethod_DEDUP = 5; // de-dup within the generation store +// macos 10.10 +static const UInt32 kMethod_LZVN_ATTR = 7; +static const UInt32 kMethod_LZVN_RSRC = 8; +static const UInt32 kMethod_COPY_ATTR = 9; +static const UInt32 kMethod_COPY_RSRC = 10; +// macos 10.11 +// static const UInt32 kMethod_LZFSE_ATTR = 11; +static const UInt32 kMethod_LZFSE_RSRC = 12; + +static const char * const g_Methods[] = +{ + NULL + , NULL + , NULL + , "ZLIB-attr" + , "ZLIB-rsrc" + , NULL + , NULL + , "LZVN-attr" + , "LZVN-rsrc" + , "COPY-attr" + , "COPY-rsrc" + , "LZFSE-attr" + , "LZFSE-rsrc" +}; + + +static const Byte k_COPY_Uncompressed_Marker = 0xcc; +static const Byte k_LZVN_Uncompressed_Marker = 6; + +void CCompressHeader::Parse(const Byte *p, size_t dataSize) +{ + Clear(); + + if (dataSize < k_decmpfs_HeaderSize) + return; + if (GetUi32(p) != 0x636D7066) // magic == "fpmc" + return; + Method = GetUi32(p + 4); + UnpackSize = GetUi64(p + 8); + dataSize -= k_decmpfs_HeaderSize; + IsCorrect = true; + + if ( Method == kMethod_ZLIB_RSRC + || Method == kMethod_COPY_RSRC + || Method == kMethod_LZVN_RSRC + || Method == kMethod_LZFSE_RSRC) + { + IsResource = true; + if (dataSize == 0) + IsSupported = ( + Method != kMethod_LZFSE_RSRC && + Method != kMethod_COPY_RSRC); + return; + } + + if ( Method == kMethod_ZLIB_ATTR + || Method == kMethod_COPY_ATTR + || Method == kMethod_LZVN_ATTR + // || Method == kMethod_LZFSE_ATTR + ) + { + if (dataSize == 0) + return; + const Byte b = p[k_decmpfs_HeaderSize]; + if ( (Method == kMethod_ZLIB_ATTR && (b & 0xf) == 0xf) + || (Method == kMethod_COPY_ATTR && b == k_COPY_Uncompressed_Marker) + || (Method == kMethod_LZVN_ATTR && b == k_LZVN_Uncompressed_Marker)) + { + dataSize--; + // if (UnpackSize > dataSize) + if (UnpackSize != dataSize) + return; + DataPos = k_decmpfs_HeaderSize + 1; + IsSupported = true; + } + else + { + if (Method != kMethod_COPY_ATTR) + IsSupported = true; + DataPos = k_decmpfs_HeaderSize; + } + } +} + + +void CCompressHeader::MethodToProp(NWindows::NCOM::CPropVariant &prop) const +{ + if (!IsCorrect) + return; + const UInt32 method = Method; + const char *p = NULL; + if (method < ARRAY_SIZE(g_Methods)) + p = g_Methods[method]; + AString s; + if (p) + s = p; + else + s.Add_UInt32(method); + // if (!IsSupported) s += "-unsuported"; + prop = s; +} + +void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop) +{ + FLAGS_TO_PROP(g_Methods, methodsMask, prop); +} + + struct CItem { UString Name; @@ -240,7 +357,7 @@ UInt32 ID; UInt32 CTime; UInt32 MTime; - // UInt32 AttrMTime; + UInt32 AttrMTime; UInt32 ATime; // UInt32 BackupDate; @@ -265,54 +382,79 @@ CFork DataFork; CFork ResourceFork; - // for compressed attribute - UInt64 UnpackSize; - size_t DataPos; - UInt32 PackSize; - unsigned Method; - bool UseAttr; - bool UseInlineData; - - CItem(): UseAttr(false), UseInlineData(false) {} + // for compressed attribute (decmpfs) + int decmpfs_AttrIndex; + CCompressHeader CompressHeader; + + CItem(): + decmpfs_AttrIndex(-1) + {} bool IsDir() const { return Type == RECORD_TYPE_FOLDER; } - const CFork &GetFork(bool isResource) const { return (const CFork & )*(isResource ? &ResourceFork: &DataFork ); } + // const CFork *GetFork(bool isResource) const { return (isResource ? &ResourceFork: &DataFork); } }; + struct CAttr { UInt32 ID; - UInt32 Size; - size_t Pos; + bool Fork_defined; + + // UInt32 Size; // for (Fork_defined == false) case + // size_t DataPos; // for (Fork_defined == false) case + CByteBuffer Data; + + CFork Fork; + UString Name; + + UInt64 GetSize() const + { + if (Fork_defined) + return Fork.Size; + return Data.Size(); + } + + CAttr(): + Fork_defined(false) + // Size(0), + // DataPos(0), + {} }; + +static const int kAttrIndex_Item = -1; +static const int kAttrIndex_Resource = -2; + struct CRef { unsigned ItemIndex; int AttrIndex; int Parent; - bool IsResource; - bool IsAltStream() const { return IsResource || AttrIndex >= 0; } - CRef(): AttrIndex(-1), Parent(-1), IsResource(false) {} + CRef(): AttrIndex(kAttrIndex_Item), Parent(-1) {} + bool IsResource() const { return AttrIndex == kAttrIndex_Resource; } + bool IsAltStream() const { return AttrIndex != kAttrIndex_Item; } + bool IsItem() const { return AttrIndex == kAttrIndex_Item; } }; + class CDatabase { HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream); HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector *overflowExtentsArray); HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress); HRESULT LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress); - bool Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip); + bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip); public: CRecordVector Refs; CObjectVector Items; CObjectVector Attrs; - CByteBuffer AttrBuf; + // CByteBuffer AttrBuf; CVolHeader Header; bool HeadersError; + bool UnsupportedFeature; bool ThereAreAltStreams; // bool CaseSensetive; UString ResFileName; @@ -321,6 +463,7 @@ UInt64 PhySize; UInt64 PhySize2; UInt64 ArcFileSize; + UInt32 MethodsMask; void Clear() { @@ -328,25 +471,30 @@ PhySize = 0; PhySize2 = 0; ArcFileSize = 0; + MethodsMask = 0; HeadersError = false; + UnsupportedFeature = false; ThereAreAltStreams = false; // CaseSensetive = false; + Refs.Clear(); Items.Clear(); Attrs.Clear(); - AttrBuf.Free(); + // AttrBuf.Free(); } UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const { if (ref.AttrIndex >= 0) - return Attrs[ref.AttrIndex].Size; + return Attrs[ref.AttrIndex].GetSize(); const CItem &item = Items[ref.ItemIndex]; + if (ref.IsResource()) + return item.ResourceFork.Size; if (item.IsDir()) return 0; - if (item.UseAttr) - return item.UnpackSize; - return item.GetFork(ref.IsResource).Size; + else if (item.CompressHeader.IsCorrect) + return item.CompressHeader.UnpackSize; + return item.DataFork.Size; } void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const; @@ -380,7 +528,7 @@ const CRef &ref = Refs[cur]; const UString *s; - if (ref.IsResource) + if (ref.IsResource()) s = &ResFileName; else if (ref.AttrIndex >= 0) s = &Attrs[ref.AttrIndex].Name; @@ -405,7 +553,7 @@ const UString *s; wchar_t delimChar = L':'; - if (ref.IsResource) + if (ref.IsResource()) s = &ResFileName; else if (ref.AttrIndex >= 0) s = &Attrs[ref.AttrIndex].Name; @@ -596,6 +744,8 @@ UInt32 node = hr.FirstLeafNode; if (node == 0) return S_OK; + if (hr.TotalNodes == 0) + return S_FALSE; CByteArr usedBuf(hr.TotalNodes); memset(usedBuf, 0, hr.TotalNodes); @@ -617,7 +767,7 @@ for (unsigned i = 0; i < desc.NumRecords; i++) { - const UInt32 nodeSize = (1 << hr.NodeSizeLog); + const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); const Byte *r = p + nodeOffset + nodeSize - i * 2; const UInt32 offs = Get16(r - 2); UInt32 recSize = Get16(r - 4) - offs; @@ -630,7 +780,7 @@ if (Get16(r) != kKeyLen) return S_FALSE; - Byte forkType = r[2]; + const Byte forkType = r[2]; unsigned forkTypeIndex; if (forkType == kExtentForkType_Data) forkTypeIndex = 0; @@ -640,8 +790,8 @@ continue; CObjectVector &overflowExtents = overflowExtentsArray[forkTypeIndex]; - UInt32 id = Get32(r + 4); - UInt32 startBlock = Get32(r + 8); + const UInt32 id = Get32(r + 4); + const UInt32 startBlock = Get32(r + 8); r += 2 + kKeyLen; bool needNew = true; @@ -691,7 +841,7 @@ unsigned i; for (i = 0; i < len; i++) { - wchar_t c = Get16(data + i * 2); + const wchar_t c = Get16(data + i * 2); if (c == 0) break; p[i] = c; @@ -704,7 +854,7 @@ { for (unsigned i = 0;; i++) { - char c = name[i]; + const char c = name[i]; if (c == 0) return true; if (Get16(data + i * 2) != (Byte)c) @@ -713,7 +863,7 @@ } static const UInt32 kAttrRecordType_Inline = 0x10; -// static const UInt32 kAttrRecordType_Fork = 0x20; +static const UInt32 kAttrRecordType_Fork = 0x20; // static const UInt32 kAttrRecordType_Extents = 0x30; HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress) @@ -721,6 +871,7 @@ if (fork.NumBlocks == 0) return S_OK; + CByteBuffer AttrBuf; RINOK(ReadFile(fork, AttrBuf, inStream)); const Byte *p = (const Byte *)AttrBuf; @@ -734,7 +885,9 @@ UInt32 node = hr.FirstLeafNode; if (node == 0) return S_OK; - + if (hr.TotalNodes == 0) + return S_FALSE; + CByteArr usedBuf(hr.TotalNodes); memset(usedBuf, 0, hr.TotalNodes); @@ -755,7 +908,7 @@ for (unsigned i = 0; i < desc.NumRecords; i++) { - const UInt32 nodeSize = (1 << hr.NodeSizeLog); + const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog); const Byte *r = p + nodeOffset + nodeSize - i * 2; const UInt32 offs = Get16(r - 2); UInt32 recSize = Get16(r - 4) - offs; @@ -764,18 +917,18 @@ return S_FALSE; r = p + nodeOffset + offs; - UInt32 keyLen = Get16(r); + const UInt32 keyLen = Get16(r); // UInt16 pad = Get16(r + 2); - UInt32 fileID = Get32(r + 4); - unsigned startBlock = Get32(r + 8); + const UInt32 fileID = Get32(r + 4); + const unsigned startBlock = Get32(r + 8); if (startBlock != 0) { // that case is still unsupported - HeadersError = true; + UnsupportedFeature = true; continue; } - unsigned nameLen = Get16(r + 12); + const unsigned nameLen = Get16(r + 12); if (keyLen + 2 > recSize || keyLen != kHeadSize - 2 + nameLen * 2) @@ -790,36 +943,56 @@ if (recSize < 4) return S_FALSE; - UInt32 recordType = Get32(r); - if (recordType != kAttrRecordType_Inline) + const UInt32 recordType = Get32(r); + + if (progress && (Attrs.Size() & 0xFFF) == 0) { - // Probably only kAttrRecordType_Inline now is used in real HFS files - HeadersError = true; - continue; + const UInt64 numFiles = 0; + RINOK(progress->SetCompleted(&numFiles, NULL)); } - const UInt32 kRecordHeaderSize = 16; - if (recSize < kRecordHeaderSize) - return S_FALSE; - UInt32 dataSize = Get32(r + 12); - - r += kRecordHeaderSize; - recSize -= kRecordHeaderSize; - - if (recSize < dataSize) + if (Attrs.Size() >= ((UInt32)1 << 31)) return S_FALSE; CAttr &attr = Attrs.AddNew(); attr.ID = fileID; - attr.Pos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; - attr.Size = dataSize; LoadName(name, nameLen, attr.Name); - if (progress && (i & 0xFFF) == 0) + if (recordType == kAttrRecordType_Fork) { - const UInt64 numFiles = 0; - RINOK(progress->SetCompleted(&numFiles, NULL)); + // 22.00 : some hfs files contain it; + /* spec: If the attribute has more than 8 extents, there will be additional + records (of type kAttrRecordType_Extents) for this attribute. */ + if (recSize != 8 + kForkRecSize) + return S_FALSE; + if (Get32(r + 4) != 0) // reserved + return S_FALSE; + attr.Fork.Parse(r + 8); + attr.Fork_defined = true; + continue; } + else if (recordType != kAttrRecordType_Inline) + { + UnsupportedFeature = true; + continue; + } + + const unsigned kRecordHeaderSize = 16; + if (recSize < kRecordHeaderSize) + return S_FALSE; + if (Get32(r + 4) != 0 || Get32(r + 8) != 0) // reserved + return S_FALSE; + const UInt32 dataSize = Get32(r + 12); + + r += kRecordHeaderSize; + recSize -= kRecordHeaderSize; + + if (recSize < dataSize) + return S_FALSE; + + attr.Data.CopyFrom(r, dataSize); + // attr.DataPos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize; + // attr.Size = dataSize; } node = desc.fLink; @@ -827,62 +1000,28 @@ return S_OK; } -static const UInt32 kMethod_Attr = 3; // data stored in attribute file -static const UInt32 kMethod_Resource = 4; // data stored in resource fork -bool CDatabase::Parse_decmpgfs(const CAttr &attr, CItem &item, bool &skip) +bool CDatabase::Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip) { + const CAttr &attr = Attrs[attrIndex]; skip = false; - if (!attr.Name.IsEqualTo("com.apple.decmpfs")) - return true; - if (item.UseAttr || !item.DataFork.IsEmpty()) + if (item.CompressHeader.IsCorrect || !item.DataFork.IsEmpty()) return false; - const UInt32 k_decmpfs_headerSize = 16; - UInt32 dataSize = attr.Size; - if (dataSize < k_decmpfs_headerSize) - return false; - const Byte *r = AttrBuf + attr.Pos; - if (GetUi32(r) != 0x636D7066) // magic == "fpmc" - return false; - item.Method = GetUi32(r + 4); - item.UnpackSize = GetUi64(r + 8); - dataSize -= k_decmpfs_headerSize; - r += k_decmpfs_headerSize; - if (item.Method == kMethod_Resource) + item.CompressHeader.Parse(attr.Data, attr.Data.Size()); + + if (item.CompressHeader.IsCorrect) { - if (dataSize != 0) - return false; - item.UseAttr = true; + item.decmpfs_AttrIndex = attrIndex; + skip = true; + if (item.CompressHeader.Method < sizeof(MethodsMask) * 8) + MethodsMask |= ((UInt32)1 << item.CompressHeader.Method); } - else if (item.Method == kMethod_Attr) - { - if (dataSize == 0) - return false; - Byte b = r[0]; - if ((b & 0xF) == 0xF) - { - dataSize--; - if (item.UnpackSize > dataSize) - return false; - item.DataPos = attr.Pos + k_decmpfs_headerSize + 1; - item.PackSize = dataSize; - item.UseAttr = true; - item.UseInlineData = true; - } - else - { - item.DataPos = attr.Pos + k_decmpfs_headerSize; - item.PackSize = dataSize; - item.UseAttr = true; - } - } - else - return false; - skip = true; + return true; } + HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress) { CByteBuffer buf; @@ -911,7 +1050,8 @@ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC); CByteArr usedBuf(hr.TotalNodes); - memset(usedBuf, 0, hr.TotalNodes); + if (hr.TotalNodes != 0) + memset(usedBuf, 0, hr.TotalNodes); CFork resFork; @@ -1000,7 +1140,7 @@ item.CTime = Get32(r + 0xC); item.MTime = Get32(r + 0x10); - // item.AttrMTime = Get32(r + 0x14); + item.AttrMTime = Get32(r + 0x14); item.ATime = Get32(r + 0x18); // item.BackupDate = Get32(r + 0x1C); @@ -1037,7 +1177,6 @@ else { numFiles++; - const unsigned kForkRecSize = 16 + kNumFixedExtents * 8; if (recSize != kForkRecSize * 2) return S_FALSE; @@ -1051,7 +1190,7 @@ { if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog)) HeadersError = true; - ThereAreAltStreams = true; + // ThereAreAltStreams = true; } } if (progress && (Items.Size() & 0xFFF) == 0) @@ -1086,14 +1225,18 @@ { const CAttr &attr = Attrs[i]; - int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); + const int itemIndex = FindItemIndex(IdToIndexMap, attr.ID); if (itemIndex < 0) { HeadersError = true; continue; } - if (!Parse_decmpgfs(attr, Items[itemIndex], skipAttr[i])) - HeadersError = true; + + if (attr.Name.IsEqualTo("com.apple.decmpfs")) + { + if (!Parse_decmpgfs(i, Items[itemIndex], skipAttr[i])) + HeadersError = true; + } } } @@ -1117,13 +1260,13 @@ if (item.ResourceFork.IsEmpty()) continue; - if (item.UseAttr && item.Method == kMethod_Resource) + if (item.CompressHeader.IsSupported && item.CompressHeader.IsMethod_Resource()) continue; - CRef resRef; - resRef.ItemIndex = i; - resRef.IsResource = true; - resRef.Parent = Refs.Size() - 1; - Refs.Add(resRef); + + ThereAreAltStreams = true; + ref.AttrIndex = kAttrIndex_Resource; + ref.Parent = Refs.Size() - 1; + Refs.Add(ref); #endif } @@ -1135,9 +1278,9 @@ FOR_VECTOR (i, Refs) { CRef &ref = Refs[i]; - if (ref.IsResource) + if (ref.IsResource()) continue; - CItem &item = Items[ref.ItemIndex]; + const CItem &item = Items[ref.ItemIndex]; ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID); if (ref.Parent >= 0) { @@ -1158,13 +1301,15 @@ continue; const CAttr &attr = Attrs[i]; - int refIndex = FindItemIndex(IdToIndexMap, attr.ID); + const int refIndex = FindItemIndex(IdToIndexMap, attr.ID); if (refIndex < 0) { HeadersError = true; continue; } + ThereAreAltStreams = true; + CRef ref; ref.AttrIndex = i; ref.Parent = refIndex; @@ -1381,13 +1526,6 @@ HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream); - HRESULT ExtractZlibFile( - ISequentialOutStream *realOutStream, - const CItem &item, - NCompress::NZlib::CDecoder *_zlibDecoderSpec, - CByteBuffer &buf, - UInt64 progressStart, - IArchiveExtractCallback *extractCallback); public: MY_UNKNOWN_IMP3(IInArchive, IArchiveGetRawProps, IInArchiveGetStream) INTERFACE_IInArchive(;) @@ -1404,12 +1542,22 @@ kpidCTime, kpidMTime, kpidATime, - kpidPosixAttrib + kpidChangeTime, + kpidPosixAttrib, + /* + kpidUserId, + kpidGroupId, + */ +#ifdef HFS_SHOW_ALT_STREAMS + kpidIsAltStream, +#endif + kpidMethod }; static const Byte kArcProps[] = { kpidMethod, + kpidCharacts, kpidClusterSize, kpidFreeSpace, kpidCTime, @@ -1421,9 +1569,11 @@ static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) { + if (hfsTime == 0) + return; FILETIME ft; HfsTimeToFileTime(hfsTime, ft); - prop = ft; + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base); } STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) @@ -1434,6 +1584,7 @@ { case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break; case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break; + case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break; case kpidPhySize: { UInt64 v = SpecOffset + PhySize; @@ -1447,10 +1598,13 @@ case kpidMTime: HfsTimeToProp(Header.MTime, prop); break; case kpidCTime: { - FILETIME localFt, ft; - HfsTimeToFileTime(Header.CTime, localFt); - if (LocalFileTimeToFileTime(&localFt, &ft)) - prop = ft; + if (Header.CTime != 0) + { + FILETIME localFt, ft; + HfsTimeToFileTime(Header.CTime, localFt); + if (LocalFileTimeToFileTime(&localFt, &ft)) + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base); + } break; } case kpidIsTree: prop = true; break; @@ -1458,6 +1612,7 @@ { UInt32 flags = 0; if (HeadersError) flags |= kpv_ErrorFlags_HeadersError; + if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature; if (flags != 0) prop = flags; break; @@ -1502,7 +1657,7 @@ { const CRef &ref = Refs[index]; const UString *s; - if (ref.IsResource) + if (ref.IsResource()) s = &ResFileName; else if (ref.AttrIndex >= 0) s = &Attrs[ref.AttrIndex].Name; @@ -1530,8 +1685,9 @@ { case kpidPath: GetItemPath(index, prop); break; case kpidName: + { const UString *s; - if (ref.IsResource) + if (ref.IsResource()) s = &ResFileName; else if (ref.AttrIndex >= 0) s = &Attrs[ref.AttrIndex].Name; @@ -1539,22 +1695,31 @@ s = &item.Name; prop = *s; break; + } case kpidPackSize: { UInt64 size; if (ref.AttrIndex >= 0) - size = Attrs[ref.AttrIndex].Size; + size = Attrs[ref.AttrIndex].GetSize(); + else if (ref.IsResource()) + size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; else if (item.IsDir()) break; - else if (item.UseAttr) + else if (item.CompressHeader.IsCorrect) { - if (item.Method == kMethod_Resource) - size = item.ResourceFork.NumBlocks << Header.BlockSizeLog; + if (item.CompressHeader.IsMethod_Resource()) + size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog; + else if (item.decmpfs_AttrIndex >= 0) + { + // size = item.PackSize; + const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; + size = attr.Data.Size() - item.CompressHeader.DataPos; + } else - size = item.PackSize; + size = 0; } else - size = item.GetFork(ref.IsResource).NumBlocks << Header.BlockSizeLog; + size = (UInt64)item.DataFork.NumBlocks << Header.BlockSizeLog; prop = size; break; } @@ -1562,24 +1727,34 @@ { UInt64 size; if (ref.AttrIndex >= 0) - size = Attrs[ref.AttrIndex].Size; + size = Attrs[ref.AttrIndex].GetSize(); + else if (ref.IsResource()) + size = item.ResourceFork.Size; else if (item.IsDir()) break; - else if (item.UseAttr) - size = item.UnpackSize; + else if (item.CompressHeader.IsCorrect) + size = item.CompressHeader.UnpackSize; else - size = item.GetFork(ref.IsResource).Size; + size = item.DataFork.Size; prop = size; break; } - case kpidIsDir: prop = item.IsDir(); break; + case kpidIsDir: prop = (ref.IsItem() && item.IsDir()); break; case kpidIsAltStream: prop = ref.IsAltStream(); break; - case kpidCTime: HfsTimeToProp(item.CTime, prop); break; case kpidMTime: HfsTimeToProp(item.MTime, prop); break; case kpidATime: HfsTimeToProp(item.ATime, prop); break; + case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break; + case kpidPosixAttrib: if (ref.IsItem()) prop = (UInt32)item.FileMode; break; + /* + case kpidUserId: prop = (UInt32)item.OwnerID; break; + case kpidGroupId: prop = (UInt32)item.GroupID; break; + */ - case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break; + case kpidMethod: + if (ref.IsItem()) + item.CompressHeader.MethodToProp(prop); + break; } prop.Detach(value); return S_OK; @@ -1607,65 +1782,77 @@ static const UInt32 kCompressionBlockSize = 1 << 16; -HRESULT CHandler::ExtractZlibFile( - ISequentialOutStream *outStream, - const CItem &item, - NCompress::NZlib::CDecoder *_zlibDecoderSpec, - CByteBuffer &buf, - UInt64 progressStart, - IArchiveExtractCallback *extractCallback) -{ - CMyComPtr inStream; - const CFork &fork = item.ResourceFork; - RINOK(GetForkStream(fork, &inStream)); +CDecoder::CDecoder() +{ + _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); + _zlibDecoder = _zlibDecoderSpec; + + _lzfseDecoderSpec = new NCompress::NLzfse::CDecoder(); + _lzfseDecoder = _lzfseDecoderSpec; + _lzfseDecoderSpec->LzvnMode = true; +} + +HRESULT CDecoder::ExtractResourceFork_ZLIB( + ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback) +{ const unsigned kHeaderSize = 0x100 + 8; - RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize)); - UInt32 dataPos = Get32(buf); - UInt32 mapPos = Get32(buf + 4); - UInt32 dataSize = Get32(buf + 8); - UInt32 mapSize = Get32(buf + 12); + + const size_t kBufSize = kCompressionBlockSize; + _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + RINOK(ReadStream_FALSE(inStream, _buf, kHeaderSize)); + Byte *buf = _buf; + const UInt32 dataPos = Get32(buf); + const UInt32 mapPos = Get32(buf + 4); + const UInt32 dataSize = Get32(buf + 8); + const UInt32 mapSize = Get32(buf + 12); const UInt32 kResMapSize = 50; if (mapSize != kResMapSize - || dataPos + dataSize != mapPos - || mapPos + mapSize != fork.Size) + || dataPos > mapPos + || dataSize != mapPos - dataPos + || mapSize > forkSize + || mapPos != forkSize - mapSize) return S_FALSE; - UInt32 dataSize2 = Get32(buf + 0x100); - if (4 + dataSize2 != dataSize || dataSize2 < 8) + const UInt32 dataSize2 = Get32(buf + 0x100); + if (4 + dataSize2 != dataSize + || dataSize2 < 8 + || dataSize2 > dataSize) return S_FALSE; - UInt32 numBlocks = GetUi32(buf + 0x100 + 4); + const UInt32 numBlocks = GetUi32(buf + 0x100 + 4); if (((dataSize2 - 4) >> 3) < numBlocks) return S_FALSE; - if (item.UnpackSize > (UInt64)numBlocks * kCompressionBlockSize) - return S_FALSE; - - if (item.UnpackSize + kCompressionBlockSize < (UInt64)numBlocks * kCompressionBlockSize) - return S_FALSE; + { + const UInt64 up = unpackSize + kCompressionBlockSize - 1; + if (up < unpackSize || up / kCompressionBlockSize != numBlocks) + return S_FALSE; + } - UInt32 tableSize = (numBlocks << 3); + const UInt32 tableSize = (numBlocks << 3); - CByteBuffer tableBuf(tableSize); + _tableBuf.AllocAtLeast(tableSize); - RINOK(ReadStream_FALSE(inStream, tableBuf, tableSize)); + RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)); + const Byte *tableBuf = _tableBuf; UInt32 prev = 4 + tableSize; UInt32 i; for (i = 0; i < numBlocks; i++) { - UInt32 offset = GetUi32(tableBuf + i * 8); - UInt32 size = GetUi32(tableBuf + i * 8 + 4); - if (size == 0) - return S_FALSE; - if (prev != offset) - return S_FALSE; - if (offset > dataSize2 || - size > dataSize2 - offset) + const UInt32 offs = GetUi32(tableBuf + i * 8); + const UInt32 size = GetUi32(tableBuf + i * 8 + 4); + if (size == 0 + || prev != offs + || offs > dataSize2 + || size > dataSize2 - offs) return S_FALSE; - prev = offset + size; + prev = offs + size; } if (prev != dataSize2) @@ -1674,26 +1861,29 @@ CBufInStream *bufInStreamSpec = new CBufInStream; CMyComPtr bufInStream = bufInStreamSpec; + // bool padError = false; UInt64 outPos = 0; + for (i = 0; i < numBlocks; i++) { - UInt64 rem = item.UnpackSize - outPos; + const UInt64 rem = unpackSize - outPos; if (rem == 0) return S_FALSE; UInt32 blockSize = kCompressionBlockSize; if (rem < kCompressionBlockSize) blockSize = (UInt32)rem; - UInt32 size = GetUi32(tableBuf + i * 8 + 4); + const UInt32 size = GetUi32(tableBuf + i * 8 + 4); - if (size > buf.Size() || size > kCompressionBlockSize + 1) + if (size > kCompressionBlockSize + 1) return S_FALSE; RINOK(ReadStream_FALSE(inStream, buf, size)); if ((buf[0] & 0xF) == 0xF) { - // that code was not tested. Are there HFS archives with uncompressed block + // (buf[0] = 0xff) is marker of uncompressed block in APFS + // that code was not tested in HFS if (size - 1 != blockSize) return S_FALSE; @@ -1704,54 +1894,251 @@ } else { - UInt64 blockSize64 = blockSize; + const UInt64 blockSize64 = blockSize; bufInStreamSpec->Init(buf, size); RINOK(_zlibDecoderSpec->Code(bufInStream, outStream, NULL, &blockSize64, NULL)); - if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize || - _zlibDecoderSpec->GetInputProcessedSize() != size) + if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize) return S_FALSE; + const UInt64 inSize = _zlibDecoderSpec->GetInputProcessedSize(); + if (inSize != size) + { + if (inSize > size) + return S_FALSE; + // apfs file can contain junk (non-zeros) after data block. + /* + if (!padError) + { + const Byte *p = buf + (UInt32)inSize; + const Byte *e = p + (size - (UInt32)inSize); + do + { + if (*p != 0) + { + padError = true; + break; + } + } + while (++p != e); + } + */ + } } outPos += blockSize; - const UInt64 progressPos = progressStart + outPos; - RINOK(extractCallback->SetCompleted(&progressPos)); + if ((i & 0xFF) == 0) + { + const UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)); + } } - if (outPos != item.UnpackSize) + if (outPos != unpackSize) return S_FALSE; + // if (padError) return S_FALSE; + /* We check Resource Map Are there HFS files with another values in Resource Map ??? */ RINOK(ReadStream_FALSE(inStream, buf, mapSize)); - UInt32 types = Get16(buf + 24); - UInt32 names = Get16(buf + 26); - UInt32 numTypes = Get16(buf + 28); + const UInt32 types = Get16(buf + 24); + const UInt32 names = Get16(buf + 26); + const UInt32 numTypes = Get16(buf + 28); if (numTypes != 0 || types != 28 || names != kResMapSize) return S_FALSE; - UInt32 resType = Get32(buf + 30); - UInt32 numResources = Get16(buf + 34); - UInt32 resListOffset = Get16(buf + 36); + const UInt32 resType = Get32(buf + 30); + const UInt32 numResources = Get16(buf + 34); + const UInt32 resListOffset = Get16(buf + 36); if (resType != 0x636D7066) // cmpf return S_FALSE; if (numResources != 0 || resListOffset != 10) return S_FALSE; - UInt32 entryId = Get16(buf + 38); - UInt32 nameOffset = Get16(buf + 40); + const UInt32 entryId = Get16(buf + 38); + const UInt32 nameOffset = Get16(buf + 40); // Byte attrib = buf[42]; - UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; + const UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF; if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0) return S_FALSE; return S_OK; } + + +HRESULT CDecoder::ExtractResourceFork_LZFSE( + ISequentialInStream *inStream, ISequentialOutStream *outStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback) +{ + const UInt32 kNumBlocksMax = (UInt32)1 << 29; + if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize) + return S_FALSE; + const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize); + const UInt32 numBlocks2 = numBlocks + 1; + const UInt32 tableSize = (numBlocks2 << 2); + if (tableSize > forkSize) + return S_FALSE; + _tableBuf.AllocAtLeast(tableSize); + RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize)); + const Byte *tableBuf = _tableBuf; + + { + UInt32 prev = GetUi32(tableBuf); + if (prev != tableSize) + return S_FALSE; + for (UInt32 i = 1; i < numBlocks2; i++) + { + const UInt32 offs = GetUi32(tableBuf + i * 4); + if (offs <= prev) + return S_FALSE; + prev = offs; + } + if (prev != forkSize) + return S_FALSE; + } + + const size_t kBufSize = kCompressionBlockSize; + _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header + + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr bufInStream = bufInStreamSpec; + + UInt64 outPos = 0; + + for (UInt32 i = 0; i < numBlocks; i++) + { + const UInt64 rem = unpackSize - outPos; + if (rem == 0) + return S_FALSE; + UInt32 blockSize = kCompressionBlockSize; + if (rem < kCompressionBlockSize) + blockSize = (UInt32)rem; + + const UInt32 size = + GetUi32(tableBuf + i * 4 + 4) - + GetUi32(tableBuf + i * 4); + + if (size > kCompressionBlockSize + 1) + return S_FALSE; + + RINOK(ReadStream_FALSE(inStream, _buf, size)); + const Byte *buf = _buf; + + if (buf[0] == k_LZVN_Uncompressed_Marker) + { + if (size - 1 != blockSize) + return S_FALSE; + if (outStream) + { + RINOK(WriteStream(outStream, buf, blockSize)); + } + } + else + { + const UInt64 blockSize64 = blockSize; + const UInt64 packSize64 = size; + bufInStreamSpec->Init(buf, size); + RINOK(_lzfseDecoderSpec->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL)); + // in/out sizes were checked in Code() + } + + outPos += blockSize; + if ((i & 0xFF) == 0) + { + const UInt64 progressPos = progressStart + outPos; + RINOK(extractCallback->SetCompleted(&progressPos)); + } + } + + return S_OK; +} + + +HRESULT CDecoder::Extract( + ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, + UInt64 forkSize, + const CCompressHeader &compressHeader, + const CByteBuffer *data, + UInt64 progressStart, IArchiveExtractCallback *extractCallback, + int &opRes) +{ + opRes = NExtract::NOperationResult::kDataError; + + if (compressHeader.IsMethod_Uncompressed_Inline()) + { + const size_t packSize = data->Size() - compressHeader.DataPos; + if (realOutStream) + { + RINOK(WriteStream(realOutStream, *data + compressHeader.DataPos, packSize)); + } + opRes = NExtract::NOperationResult::kOK; + return S_OK; + } + + if (compressHeader.Method == kMethod_ZLIB_ATTR || + compressHeader.Method == kMethod_LZVN_ATTR) + { + CBufInStream *bufInStreamSpec = new CBufInStream; + CMyComPtr bufInStream = bufInStreamSpec; + const size_t packSize = data->Size() - compressHeader.DataPos; + bufInStreamSpec->Init(*data + compressHeader.DataPos, packSize); + + if (compressHeader.Method == kMethod_ZLIB_ATTR) + { + const HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, + NULL, &compressHeader.UnpackSize, NULL); + if (hres == S_OK) + if (_zlibDecoderSpec->GetOutputProcessedSize() == compressHeader.UnpackSize + && _zlibDecoderSpec->GetInputProcessedSize() == packSize) + opRes = NExtract::NOperationResult::kOK; + return hres; + } + { + const UInt64 packSize64 = packSize; + const HRESULT hres = _lzfseDecoder->Code(bufInStream, realOutStream, + &packSize64, &compressHeader.UnpackSize, NULL); + if (hres == S_OK) + { + // in/out sizes were checked in Code() + opRes = NExtract::NOperationResult::kOK; + } + return hres; + } + } + + HRESULT hres; + if (compressHeader.Method == NHfs::kMethod_ZLIB_RSRC) + { + hres = ExtractResourceFork_ZLIB( + inStreamFork, realOutStream, + forkSize, compressHeader.UnpackSize, + progressStart, extractCallback); + } + else if (compressHeader.Method == NHfs::kMethod_LZVN_RSRC) + { + hres = ExtractResourceFork_LZFSE( + inStreamFork, realOutStream, + forkSize, compressHeader.UnpackSize, + progressStart, extractCallback); + } + else + { + opRes = NExtract::NOperationResult::kUnsupportedMethod; + hres = S_FALSE; + } + + if (hres == S_OK) + opRes = NExtract::NOperationResult::kOK; + return hres; +} + + STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)(Int32)-1); + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = Refs.Size(); if (numItems == 0) @@ -1770,12 +2157,13 @@ const size_t kBufSize = kCompressionBlockSize; CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header - NCompress::NZlib::CDecoder *_zlibDecoderSpec = NULL; - CMyComPtr _zlibDecoder; + CDecoder decoder; - for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize) + for (i = 0;; i++, currentTotalSize += currentItemSize) { RINOK(extractCallback->SetCompleted(¤tTotalSize)); + if (i == numItems) + break; UInt32 index = allFilesMode ? i : indices[i]; const CRef &ref = Refs[index]; const CItem &item = Items[ref.ItemIndex]; @@ -1787,7 +2175,7 @@ NExtract::NAskMode::kExtract; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - if (ref.AttrIndex < 0 && item.IsDir()) + if (ref.IsItem() && item.IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK)); @@ -1795,89 +2183,91 @@ } if (!testMode && !realOutStream) continue; + RINOK(extractCallback->PrepareOperation(askMode)); + UInt64 pos = 0; - int res = NExtract::NOperationResult::kDataError; + int opRes = NExtract::NOperationResult::kDataError; + const CFork *fork = NULL; + if (ref.AttrIndex >= 0) { - res = NExtract::NOperationResult::kOK; - if (realOutStream) - { - const CAttr &attr = Attrs[ref.AttrIndex]; - RINOK(WriteStream(realOutStream, AttrBuf + attr.Pos, attr.Size)); - } - } - else if (item.UseAttr) - { - if (item.UseInlineData) + const CAttr &attr = Attrs[ref.AttrIndex]; + if (attr.Fork_defined && attr.Data.Size() == 0) + fork = &attr.Fork; + else { - res = NExtract::NOperationResult::kOK; + opRes = NExtract::NOperationResult::kOK; if (realOutStream) { - RINOK(WriteStream(realOutStream, AttrBuf + item.DataPos, (size_t)item.UnpackSize)); + RINOK(WriteStream(realOutStream, + // AttrBuf + attr.Pos, attr.Size + attr.Data, attr.Data.Size() + )); } } + } + else if (ref.IsResource()) + fork = &item.ResourceFork; + else if (item.CompressHeader.IsSupported) + { + CMyComPtr inStreamFork; + UInt64 forkSize = 0; + const CByteBuffer *decmpfs_Data = NULL; + + if (item.CompressHeader.IsMethod_Resource()) + { + const CFork &resourceFork = item.ResourceFork; + forkSize = resourceFork.Size; + GetForkStream(resourceFork, &inStreamFork); + } else { - if (!_zlibDecoder) - { - _zlibDecoderSpec = new NCompress::NZlib::CDecoder(); - _zlibDecoder = _zlibDecoderSpec; - } - - if (item.Method == kMethod_Attr) - { - CBufInStream *bufInStreamSpec = new CBufInStream; - CMyComPtr bufInStream = bufInStreamSpec; - bufInStreamSpec->Init(AttrBuf + item.DataPos, item.PackSize); - - HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream, NULL, &item.UnpackSize, NULL); - if (hres != S_FALSE) - { - if (hres != S_OK) - return hres; - if (_zlibDecoderSpec->GetOutputProcessedSize() == item.UnpackSize && - _zlibDecoderSpec->GetInputProcessedSize() == item.PackSize) - res = NExtract::NOperationResult::kOK; - } - } - else - { - HRESULT hres = ExtractZlibFile(realOutStream, item, _zlibDecoderSpec, buf, - currentTotalSize, extractCallback); - if (hres != S_FALSE) - { - if (hres != S_OK) - return hres; - res = NExtract::NOperationResult::kOK; - } - } + const CAttr &attr = Attrs[item.decmpfs_AttrIndex]; + decmpfs_Data = &attr.Data; + } + + if (inStreamFork || decmpfs_Data) + { + const HRESULT hres = decoder.Extract( + inStreamFork, realOutStream, + forkSize, + item.CompressHeader, + decmpfs_Data, + currentTotalSize, extractCallback, + opRes); + if (hres != S_FALSE && hres != S_OK) + return hres; } } + else if (item.CompressHeader.IsCorrect) + opRes = NExtract::NOperationResult::kUnsupportedMethod; else + fork = &item.DataFork; + + if (fork) { - const CFork &fork = item.GetFork(ref.IsResource); - if (fork.IsOk(Header.BlockSizeLog)) + if (fork->IsOk(Header.BlockSizeLog)) { - res = NExtract::NOperationResult::kOK; + opRes = NExtract::NOperationResult::kOK; unsigned extentIndex; - for (extentIndex = 0; extentIndex < fork.Extents.Size(); extentIndex++) + for (extentIndex = 0; extentIndex < fork->Extents.Size(); extentIndex++) { - if (res != NExtract::NOperationResult::kOK) + if (opRes != NExtract::NOperationResult::kOK) break; - if (fork.Size == pos) + if (fork->Size == pos) break; - const CExtent &e = fork.Extents[extentIndex]; + const CExtent &e = fork->Extents[extentIndex]; RINOK(_stream->Seek(SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog), STREAM_SEEK_SET, NULL)); UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog; while (extentRem != 0) { - UInt64 rem = fork.Size - pos; + const UInt64 rem = fork->Size - pos; if (rem == 0) { // Here we check that there are no extra (empty) blocks in last extent. if (extentRem >= ((UInt64)1 << Header.BlockSizeLog)) - res = NExtract::NOperationResult::kDataError; + opRes = NExtract::NOperationResult::kDataError; break; } size_t cur = kBufSize; @@ -1888,7 +2278,7 @@ RINOK(ReadStream(_stream, buf, &cur)); if (cur == 0) { - res = NExtract::NOperationResult::kDataError; + opRes = NExtract::NOperationResult::kDataError; break; } if (realOutStream) @@ -1901,12 +2291,12 @@ RINOK(extractCallback->SetCompleted(&processed)); } } - if (extentIndex != fork.Extents.Size() || fork.Size != pos) - res = NExtract::NOperationResult::kDataError; + if (extentIndex != fork->Extents.Size() || fork->Size != pos) + opRes = NExtract::NOperationResult::kDataError; } } realOutStream.Release(); - RINOK(extractCallback->SetOperationResult(res)); + RINOK(extractCallback->SetOperationResult(opRes)); } return S_OK; COM_TRY_END @@ -1969,13 +2359,27 @@ *stream = 0; const CRef &ref = Refs[index]; + const CFork *fork = NULL; if (ref.AttrIndex >= 0) - return S_FALSE; - const CItem &item = Items[ref.ItemIndex]; - if (item.IsDir() || item.UseAttr) - return S_FALSE; - - return GetForkStream(item.GetFork(ref.IsResource), stream); + { + const CAttr &attr = Attrs[ref.AttrIndex]; + if (!attr.Fork_defined || attr.Data.Size() != 0) + return S_FALSE; + fork = &attr.Fork; + } + else + { + const CItem &item = Items[ref.ItemIndex]; + if (ref.IsResource()) + fork = &item.ResourceFork; + else if (item.IsDir()) + return S_FALSE; + else if (item.CompressHeader.IsCorrect) + return S_FALSE; + else + fork = &item.DataFork; + } + return GetForkStream(*fork, stream); } static const Byte k_Signature[] = { diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/HfsHandler.h 7zip-22.01/CPP/7zip/Archive/HfsHandler.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/HfsHandler.h 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/HfsHandler.h 2022-07-10 12:00:00.000000000 +0000 @@ -0,0 +1,85 @@ +// HfsHandler.h + +#ifndef __HFS_HANDLER_H +#define __HFS_HANDLER_H + +#include "../../Windows/PropVariant.h" + +#include "../Compress/LzfseDecoder.h" +#include "../Compress/ZlibDecoder.h" + +namespace NArchive { +namespace NHfs { + +static const UInt32 k_decmpfs_HeaderSize = 16; + +struct CCompressHeader +{ + UInt64 UnpackSize; + UInt32 Method; + Byte DataPos; + bool IsCorrect; + bool IsSupported; + bool IsResource; + + bool IsMethod_Compressed_Inline() const { return DataPos == k_decmpfs_HeaderSize; } + bool IsMethod_Uncompressed_Inline() const { return DataPos == k_decmpfs_HeaderSize + 1; } + bool IsMethod_Resource() const { return IsResource; } + + void Parse(const Byte *p, size_t size); + + void Clear() + { + UnpackSize = 0; + Method = 0; + DataPos = 0; + IsCorrect = false; + IsSupported = false; + IsResource = false; + } + + CCompressHeader() { Clear(); } + + void MethodToProp(NWindows::NCOM::CPropVariant &prop) const; +}; + +void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop); + + +class CDecoder +{ + NCompress::NZlib::CDecoder *_zlibDecoderSpec; + CMyComPtr _zlibDecoder; + + NCompress::NLzfse::CDecoder *_lzfseDecoderSpec; + CMyComPtr _lzfseDecoder; + + CByteBuffer _tableBuf; + CByteBuffer _buf; + + HRESULT ExtractResourceFork_ZLIB( + ISequentialInStream *inStream, ISequentialOutStream *realOutStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback); + + HRESULT ExtractResourceFork_LZFSE( + ISequentialInStream *inStream, ISequentialOutStream *realOutStream, + UInt64 forkSize, UInt64 unpackSize, + UInt64 progressStart, IArchiveExtractCallback *extractCallback); + +public: + + HRESULT Extract( + ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream, + UInt64 forkSize, + const CCompressHeader &compressHeader, + const CByteBuffer *data, + UInt64 progressStart, IArchiveExtractCallback *extractCallback, + int &opRes); + + CDecoder(); +}; + +}} + +#endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/IArchive.h 7zip-22.01/CPP/7zip/Archive/IArchive.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/IArchive.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/IArchive.h 2022-05-10 12:00:00.000000000 +0000 @@ -38,9 +38,11 @@ { enum EEnum { - kWindows, + kNotDefined = -1, + kWindows = 0, kUnix, - kDOS + kDOS, + k1ns }; } @@ -60,8 +62,31 @@ const UInt32 kHardLinks = 1 << 11; // the handler supports hard links const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums) + const UInt32 kCTime = 1 << 14; + const UInt32 kCTime_Default = 1 << 15; + const UInt32 kATime = 1 << 16; + const UInt32 kATime_Default = 1 << 17; + const UInt32 kMTime = 1 << 18; + const UInt32 kMTime_Default = 1 << 19; + // const UInt32 kTTime_Reserved = 1 << 20; + // const UInt32 kTTime_Reserved_Default = 1 << 21; } +namespace NArcInfoTimeFlags +{ + const unsigned kTime_Prec_Mask_bit_index = 0; + const unsigned kTime_Prec_Mask_num_bits = 26; + + const unsigned kTime_Prec_Default_bit_index = 27; + const unsigned kTime_Prec_Default_num_bits = 5; +} + +#define TIME_PREC_TO_ARC_FLAGS_MASK(x) \ + ((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (x))) + +#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(x) \ + ((UInt32)(x) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index) + namespace NArchive { namespace NHandlerPropID @@ -79,8 +104,8 @@ kSignatureOffset, // VT_UI4 kAltStreams, // VT_BOOL kNtSecure, // VT_BOOL - kFlags // VT_UI4 - // kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR) + kFlags, // VT_UI4 + kTimeFlags // VT_UI4 }; } @@ -123,6 +148,7 @@ kInArcIndex, kBlockIndex, kOutArcIndex + // kArcProp }; } @@ -133,7 +159,8 @@ enum { kOK = 0 - // , kError + // kError = 1, + // kError_FileChanged }; } } @@ -461,9 +488,10 @@ kSkip, kDelete, kHeader, - kHashRead - - // kNumDefined + kHashRead, + kInFileChanged + // , kOpFinished + // , kNumDefined }; }; @@ -493,6 +521,20 @@ }; /* +#define INTERFACE_IArchiveUpdateCallbackArcProp(x) \ + STDMETHOD(ReportProp)(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x; \ + STDMETHOD(ReportRawProp)(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x; \ + STDMETHOD(ReportFinished)(UInt32 indexType, UInt32 index, Int32 opRes) x; \ + STDMETHOD(DoNeedArcProp)(PROPID propID, Int32 *answer) x; \ + + +ARCHIVE_INTERFACE(IArchiveUpdateCallbackArcProp, 0x85) +{ + INTERFACE_IArchiveUpdateCallbackArcProp(PURE); +}; +*/ + +/* UpdateItems() ------------- @@ -636,9 +678,40 @@ typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); typedef HRESULT (WINAPI *Func_SetLargePageMode)(); + // typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version); typedef IOutArchive * (*Func_CreateOutArchive)(); typedef IInArchive * (*Func_CreateInArchive)(); } + +/* + if there is no time in archive, external MTime of archive + will be used instead of _item.Time from archive. + For 7-zip before 22.00 we need to return some supported value. + But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00. + So we return highest precision value supported by old 7-Zip. + new 7-Zip 22.00 doesn't use that value in usual cases. +*/ + + +#define DECLARE_AND_SET_CLIENT_VERSION_VAR +#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ + NFileTimeType::kWindows + +/* +extern UInt32 g_ClientVersion; + +#define GET_CLIENT_VERSION(major, minor) \ + ((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor))) + +#define DECLARE_AND_SET_CLIENT_VERSION_VAR \ + UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR); + +#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ + ((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \ + (UInt32)(Int32)NFileTimeType::kNotDefined : \ + NFileTimeType::kWindows)) +*/ + #endif Binary files /tmp/tmp31dy55h3/fTEGYrrEu9/7zip-21.07+dfsg/CPP/7zip/Archive/Icons/apfs.ico and /tmp/tmp31dy55h3/irsltrFGU8/7zip-22.01/CPP/7zip/Archive/Icons/apfs.ico differ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoHandler.cpp 7zip-22.01/CPP/7zip/Archive/Iso/IsoHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Iso/IsoHandler.cpp 2022-05-03 12:00:00.000000000 +0000 @@ -6,9 +6,6 @@ #include "../../../Common/MyLinux.h" #include "../../../Common/StringConvert.h" -#include "../../../Windows/PropVariant.h" -#include "../../../Windows/TimeUtils.h" - #include "../../Common/LimitedStreams.h" #include "../../Common/ProgressUtils.h" @@ -34,8 +31,8 @@ // kpidCTime, // kpidATime, kpidPosixAttrib, - // kpidUser, - // kpidGroup, + // kpidUserId, + // kpidGroupId, // kpidLinks, kpidSymLink }; @@ -127,8 +124,8 @@ prop = s; break; } - case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; } - case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; } + case kpidCTime: { vol.CTime.GetFileTime(prop); break; } + case kpidMTime: { vol.MTime.GetFileTime(prop); break; } } } @@ -242,8 +239,8 @@ case kpidPosixAttrib: /* case kpidLinks: - case kpidUser: - case kpidGroup: + case kpidUserId: + case kpidGroupId: */ { if (_archive.IsSusp) @@ -254,8 +251,8 @@ case kpidPosixAttrib: t = k_Px_Mode; break; /* case kpidLinks: t = k_Px_Links; break; - case kpidUser: t = k_Px_User; break; - case kpidGroup: t = k_Px_Group; break; + case kpidUserId: t = k_Px_User; break; + case kpidGroupId: t = k_Px_Group; break; */ } UInt32 v; @@ -276,9 +273,8 @@ // case kpidCTime: // case kpidATime: { - FILETIME utc; - if (/* propID == kpidMTime && */ item.DateTime.GetFileTime(utc)) - prop = utc; + // if + item.DateTime.GetFileTime(prop); /* else { diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoIn.cpp 7zip-22.01/CPP/7zip/Archive/Iso/IsoIn.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoIn.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Iso/IsoIn.cpp 2022-01-10 15:00:00.000000000 +0000 @@ -587,6 +587,8 @@ for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) if (VolDescs[MainVolDescIndex].IsJoliet()) break; + /* FIXME: some volume can contain Rock Ridge, that is better than + Joliet volume. So we need some way to detect such case */ // MainVolDescIndex = 0; // to read primary volume const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; if (vd.LogicalBlockSize != kBlockSize) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoIn.h 7zip-22.01/CPP/7zip/Archive/Iso/IsoIn.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoIn.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Iso/IsoIn.h 2022-05-03 12:00:00.000000000 +0000 @@ -127,17 +127,18 @@ bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } - bool GetFileTime(FILETIME &ft) const + bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const { - UInt64 value; - bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value); + UInt64 v; + const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v); if (res) { - value -= (Int64)((Int32)GmtOffset * 15 * 60); - value *= 10000000; + v -= (Int64)((Int32)GmtOffset * 15 * 60); + v *= 10000000; + if (Hundredths < 100) + v += (UInt32)Hundredths * 100000; + prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2); } - ft.dwLowDateTime = (DWORD)value; - ft.dwHighDateTime = (DWORD)(value >> 32); return res; } }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoItem.h 7zip-22.01/CPP/7zip/Archive/Iso/IsoItem.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Iso/IsoItem.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Iso/IsoItem.h 2022-05-03 12:00:00.000000000 +0000 @@ -25,17 +25,16 @@ Byte Second; signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. - bool GetFileTime(FILETIME &ft) const + bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const { - UInt64 value; - bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value); + UInt64 v; + const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v); if (res) { - value -= (Int64)((Int32)GmtOffset * 15 * 60); - value *= 10000000; + v -= (Int64)((Int32)GmtOffset * 15 * 60); + v *= 10000000; + prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base); } - ft.dwLowDateTime = (DWORD)value; - ft.dwHighDateTime = (DWORD)(value >> 32); return res; } }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/LpHandler.cpp 7zip-22.01/CPP/7zip/Archive/LpHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/LpHandler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/LpHandler.cpp 2022-02-02 11:00:00.000000000 +0000 @@ -0,0 +1,1173 @@ +// LpHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" +#include "../../../C/Sha256.h" + +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" +#include "../../Common/MyBuffer.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/LimitedStreams.h" +#include "../Common/ProgressUtils.h" +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "../Compress/CopyCoder.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) +#define Get64(p) GetUi64(p) + +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); + +using namespace NWindows; + +namespace NArchive { + +namespace NExt { +API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize); +} + +namespace NLp { + +/* +Android 10+ use Android's Dynamic Partitions to allow the +different read-only system partitions (e.g. system, vendor, product) +to share the same pool of storage space (as LVM in Linux). +Name for partition: "super" (for GPT) or "super.img" (for file). +Dynamic Partition Tools: lpmake +All partitions that are A/B-ed should be named as follows (slots are always named a, b, etc.): +boot_a, boot_b, system_a, system_b, vendor_a, vendor_b. +*/ + +#define LP_METADATA_MAJOR_VERSION 10 +// #define LP_METADATA_MINOR_VERSION_MIN 0 +// #define LP_METADATA_MINOR_VERSION_MAX 2 + +// #define LP_SECTOR_SIZE 512 +static const unsigned kSectorSizeLog = 9; + +/* Amount of space reserved at the start of every super partition to avoid + * creating an accidental boot sector. */ +#define LP_PARTITION_RESERVED_BYTES 4096 +#define LP_METADATA_GEOMETRY_SIZE 4096 +#define LP_METADATA_HEADER_MAGIC 0x414C5030 + +#define SIGNATURE { 0x67, 0x44, 0x6c, 0x61, 0x34, 0, 0, 0 } +static const unsigned k_SignatureSize = 8; +static const Byte k_Signature[k_SignatureSize] = SIGNATURE; + +// The length (36) is the same as the maximum length of a GPT partition name. +static const unsigned kNameLen = 36; + +static void AddName36ToString(AString &s, const char *name, bool strictConvert) +{ + for (unsigned i = 0; i < kNameLen; i++) + { + char c = name[i]; + if (c == 0) + return; + if (strictConvert && c < 32) + c = '_'; + s += c; + } +} + + +static const unsigned k_Geometry_Size = 0x34; + +// LpMetadataGeometry +struct CGeometry +{ + // UInt32 magic; + // UInt32 struct_size; + // Byte checksum[32]; /* SHA256 checksum of this struct, with this field set to 0. */ + + /* Maximum amount of space a single copy of the metadata can use, + a multiple of LP_SECTOR_SIZE. */ + UInt32 metadata_max_size; + + /* Number of copies of the metadata to keep. + For Non-A/B: 1, For A/B: 2, for A/B/C: 3. + A backup copy of each slot is kept */ + UInt32 metadata_slot_count; + + /* minimal alignment for partition and extent sizes, a multiple of LP_SECTOR_SIZE. */ + UInt32 logical_block_size; + + bool Parse(const Byte *p) + { + G32 (40, metadata_max_size); + G32 (44, metadata_slot_count); + G32 (48, logical_block_size); + if (metadata_slot_count == 0 || metadata_slot_count >= ((UInt32)1 << 20)) + return false; + if (metadata_max_size == 0) + return false; + if ((metadata_max_size & (((UInt32)1 << kSectorSizeLog) - 1)) != 0) + return false; + return true; + } + + UInt64 GetTotalMetadataSize() const + { + // there are 2 copies of GEOMETRY and METADATA slots + return LP_PARTITION_RESERVED_BYTES + + LP_METADATA_GEOMETRY_SIZE * 2 + + ((UInt64)metadata_max_size * metadata_slot_count) * 2; + } +}; + + + +// LpMetadataTableDescriptor +struct CDescriptor +{ + UInt32 offset; /* Location of the table, relative to end of the metadata header. */ + UInt32 num_entries; /* Number of entries in the table. */ + UInt32 entry_size; /* Size of each entry in the table, in bytes. */ + + void Parse(const Byte *p) + { + G32 (0, offset); + G32 (4, num_entries); + G32 (8, entry_size); + } + + bool CheckLimits(UInt32 limit) const + { + if (entry_size == 0) + return false; + const UInt32 size = num_entries * entry_size; + if (size / entry_size != num_entries) + return false; + if (offset > limit || limit - offset < size) + return false; + return true; + } +}; + + +// #define LP_PARTITION_ATTR_NONE 0x0 +// #define LP_PARTITION_ATTR_READONLY (1 << 0) + +/* This flag is only intended to be used with super_empty.img and super.img on + * retrofit devices. On these devices there are A and B super partitions, and + * we don't know ahead of time which slot the image will be applied to. + * + * If set, the partition name needs a slot suffix applied. The slot suffix is + * determined by the metadata slot number (0 = _a, 1 = _b). + */ +// #define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1) + +/* This flag is applied automatically when using MetadataBuilder::NewForUpdate. + * It signals that the partition was created (or modified) for a snapshot-based + * update. If this flag is not present, the partition was likely flashed via + * fastboot. + */ +// #define LP_PARTITION_ATTR_UPDATED (1 << 2) + +/* This flag marks a partition as disabled. It should not be used or mapped. */ +// #define LP_PARTITION_ATTR_DISABLED (1 << 3) + +static const char * const g_PartitionAttr[] = +{ + "READONLY" + , "SLOT_SUFFIXED" + , "UPDATED" + , "DISABLED" +}; + +static unsigned const k_MetaPartition_Size = 52; + +// LpMetadataPartition +struct CPartition +{ + /* ASCII characters: alphanumeric or _. at least one ASCII character, + (name) must be unique across all partition names. */ + char name[kNameLen]; + + UInt32 attributes; /* (LP_PARTITION_ATTR_*). */ + + /* Index of the first extent owned by this partition. The extent will + * start at logical sector 0. Gaps between extents are not allowed. */ + UInt32 first_extent_index; + + /* Number of extents in the partition. Every partition must have at least one extent. */ + UInt32 num_extents; + + /* Group this partition belongs to. */ + UInt32 group_index; + + void Parse(const Byte *p) + { + memcpy(name, p, kNameLen); + G32 (36, attributes); + G32 (40, first_extent_index); + G32 (44, num_extents); + G32 (48, group_index); + } + + // calced properties: + UInt32 MethodsMask; + UInt64 NumSectors; + UInt64 NumSectors_Pack; + const char *Ext; + + UInt64 GetSize() const { return NumSectors << kSectorSizeLog; } + UInt64 GetPackSize() const { return NumSectors_Pack << kSectorSizeLog; } + + CPartition(): + MethodsMask(0), + NumSectors(0), + NumSectors_Pack(0), + Ext(NULL) + {} +}; + + + + +#define LP_TARGET_TYPE_LINEAR 0 +/* This extent is a dm-zero target. The index is ignored and must be 0. */ +#define LP_TARGET_TYPE_ZERO 1 + +static const char * const g_Methods[] = +{ + "RAW" // "LINEAR" + , "ZERO" +}; + +static unsigned const k_MetaExtent_Size = 24; + +// LpMetadataExtent +struct CExtent +{ + UInt64 num_sectors; /* Length in 512-byte sectors. */ + UInt32 target_type; /* Target type for device-mapper (LP_TARGET_TYPE_*). */ + + /* for LINEAR: The sector on the physical partition that this extent maps onto. + for ZERO: must be 0. */ + UInt64 target_data; + + /* for LINEAR: index into the block devices table. + for ZERO: must be 0. */ + UInt32 target_source; + + bool IsRAW() const { return target_type == LP_TARGET_TYPE_LINEAR; } + + void Parse(const Byte *p) + { + G64 (0, num_sectors); + G32 (8, target_type); + G64 (12, target_data); + G32 (20, target_source); + } +}; + + +/* This flag is only intended to be used with super_empty.img and super.img on + * retrofit devices. If set, the group needs a slot suffix to be interpreted + * correctly. The suffix is automatically applied by ReadMetadata(). + */ +// #define LP_GROUP_SLOT_SUFFIXED (1 << 0) +static unsigned const k_Group_Size = 48; + +// LpMetadataPartitionGroup +struct CGroup +{ + char name[kNameLen]; + UInt32 flags; /* (LP_GROUP_*). */ + UInt64 maximum_size; /* Maximum size in bytes. If 0, the group has no maximum size. */ + + void Parse(const Byte *p) + { + memcpy(name, p, kNameLen); + G32 (36, flags); + G64 (40, maximum_size); + } +}; + + + + +/* This flag is only intended to be used with super_empty.img and super.img on + * retrofit devices. On these devices there are A and B super partitions, and + * we don't know ahead of time which slot the image will be applied to. + * + * If set, the block device needs a slot suffix applied before being used with + * IPartitionOpener. The slot suffix is determined by the metadata slot number + * (0 = _a, 1 = _b). + */ +// #define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0) + +static unsigned const k_Device_Size = 64; + +/* This struct defines an entry in the block_devices table. There must be at + * least one device, and the first device must represent the partition holding + * the super metadata. + */ +// LpMetadataBlockDevice +struct CDevice +{ + /* 0: First usable sector for allocating logical partitions. this will be + * the first sector after the initial geometry blocks, followed by the + * space consumed by metadata_max_size*metadata_slot_count*2. + */ + UInt64 first_logical_sector; + + /* 8: Alignment for defining partitions or partition extents. For example, + * an alignment of 1MiB will require that all partitions have a size evenly + * divisible by 1MiB, and that the smallest unit the partition can grow by + * is 1MiB. + * + * Alignment is normally determined at runtime when growing or adding + * partitions. If for some reason the alignment cannot be determined, then + * this predefined alignment in the geometry is used instead. By default + * it is set to 1MiB. + */ + UInt32 alignment; + + /* 12: Alignment offset for "stacked" devices. For example, if the "super" + * partition itself is not aligned within the parent block device's + * partition table, then we adjust for this in deciding where to place + * |first_logical_sector|. + * + * Similar to |alignment|, this will be derived from the operating system. + * If it cannot be determined, it is assumed to be 0. + */ + UInt32 alignment_offset; + + /* 16: Block device size, as specified when the metadata was created. This + * can be used to verify the geometry against a target device. + */ + UInt64 size; + + /* 24: Partition name in the GPT*/ + char partition_name[kNameLen]; + + /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */ + UInt32 flags; + + void Parse(const Byte *p) + { + memcpy(partition_name, p + 24, kNameLen); + G64 (0, first_logical_sector); + G32 (8, alignment); + G32 (12, alignment_offset); + G64 (16, size); + G32 (60, flags); + } +}; + + +/* This device uses Virtual A/B. Note that on retrofit devices, the expanded + * header may not be present. + */ +// #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1 + +static const char * const g_Header_Flags[] = +{ + "VIRTUAL_AB" +}; + + +static const unsigned k_LpMetadataHeader10_size = 128; +static const unsigned k_LpMetadataHeader12_size = 256; + +struct LpMetadataHeader +{ + /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */ + UInt32 magic; + + /* 4: Version number required to read this metadata. If the version is not + * equal to the library version, the metadata should be considered + * incompatible. + */ + UInt16 major_version; + + /* 6: Minor version. A library supporting newer features should be able to + * read metadata with an older minor version. However, an older library + * should not support reading metadata if its minor version is higher. + */ + UInt16 minor_version; + + /* 8: The size of this header struct. */ + UInt32 header_size; + + /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as + * if this field were set to 0. + */ + // Byte header_checksum[32]; + + /* 44: The total size of all tables. This size is contiguous; tables may not + * have gaps in between, and they immediately follow the header. + */ + UInt32 tables_size; + + /* 48: SHA256 checksum of all table contents. */ + Byte tables_checksum[32]; + + /* 80: Partition table descriptor. */ + CDescriptor partitions; + /* 92: Extent table descriptor. */ + CDescriptor extents; + /* 104: Updateable group descriptor. */ + CDescriptor groups; + /* 116: Block device table. */ + CDescriptor block_devices; + + /* Everything past here is header version 1.2+, and is only included if + * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must + * zero these additional fields. + */ + + /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are + * independent of the version number and intended to be informational only. + * New flags can be added without bumping the version. + */ + // UInt32 flags; + + /* 132: Reserved (zero), pad to 256 bytes. */ + // Byte reserved[124]; + + void Parse128(const Byte *p) + { + G32 (0, magic); + G16 (4, major_version); + G16 (6, minor_version); + G32 (8, header_size) + // Byte header_checksum[32]; + G32 (44, tables_size) + memcpy (tables_checksum, p + 48, 32); + partitions.Parse(p + 80); + extents.Parse(p + 92); + groups.Parse(p + 104); + block_devices.Parse(p + 116); + /* Everything past here is header version 1.2+, and is only included if + * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must + * zero these additional fields. + */ + } +}; + + +static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum) +{ + CSha256 sha; + Sha256_Init(&sha); + Sha256_Update(&sha, data, size); + Byte calced[32]; + Sha256_Final(&sha, calced); + return memcmp(checksum, calced, 32) == 0; +} + +static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset) +{ + Byte checksum[32]; + Byte *shaData = &data[hashOffset]; + memcpy(checksum, shaData, 32); + memset(shaData, 0, 32); + return CheckSha256(data, size, checksum); +} + + + +class CHandler: + public IInArchive, + public IInArchiveGetStream, + public CMyUnknownImp +{ + CRecordVector _items; + CRecordVector Extents; + + CMyComPtr _stream; + UInt64 _totalSize; + // UInt64 _usedSize; + // UInt64 _headersSize; + + CGeometry geom; + UInt16 Major_version; + UInt16 Minor_version; + UInt32 Flags; + + Int32 _mainFileIndex; + UInt32 MethodsMask; + bool _headerWarning; + AString GroupsString; + AString DevicesString; + AString DeviceArcName; + + HRESULT Open2(IInStream *stream); + +public: + MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) + INTERFACE_IInArchive(;) + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); +}; + + +static void AddComment_UInt64(AString &s, const char *name, UInt64 val) +{ + s.Add_Space(); + s += name; + s += '='; + s.Add_UInt64(val); +} + + +static bool IsBufZero(const Byte *data, size_t size) +{ + for (size_t i = 0; i < size; i += 4) + if (*(const UInt32 *)(const void *)(data + i) != 0) + return false; + return true; +} + + +HRESULT CHandler::Open2(IInStream *stream) +{ + RINOK(stream->Seek(LP_PARTITION_RESERVED_BYTES, STREAM_SEEK_SET, NULL)); + { + Byte buf[k_Geometry_Size]; + RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size)); + if (memcmp(buf, k_Signature, k_SignatureSize) != 0) + return S_FALSE; + if (!geom.Parse(buf)) + return S_FALSE; + if (!CheckSha256_csOffset(buf, k_Geometry_Size, 8)) + return S_FALSE; + } + + CByteBuffer buffer; + RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); + buffer.Alloc(LP_METADATA_GEOMETRY_SIZE * 2); + { + // buffer.Size() >= LP_PARTITION_RESERVED_BYTES + RINOK(ReadStream_FALSE(stream, buffer, LP_PARTITION_RESERVED_BYTES)); + if (!IsBufZero(buffer, LP_PARTITION_RESERVED_BYTES)) + { + _headerWarning = true; + // return S_FALSE; + } + } + + RINOK(ReadStream_FALSE(stream, buffer, LP_METADATA_GEOMETRY_SIZE * 2)); + // we check that 2 copies of GEOMETRY are identical: + if (memcmp(buffer, buffer + LP_METADATA_GEOMETRY_SIZE, LP_METADATA_GEOMETRY_SIZE) != 0 + || !IsBufZero(buffer + k_Geometry_Size, LP_METADATA_GEOMETRY_SIZE - k_Geometry_Size)) + { + _headerWarning = true; + // return S_FALSE; + } + + RINOK(ReadStream_FALSE(stream, buffer, k_LpMetadataHeader10_size)); + LpMetadataHeader header; + header.Parse128(buffer); + if (header.magic != LP_METADATA_HEADER_MAGIC || + header.major_version != LP_METADATA_MAJOR_VERSION || + header.header_size < k_LpMetadataHeader10_size) + return S_FALSE; + Flags = 0; + if (header.header_size > k_LpMetadataHeader10_size) + { + if (header.header_size != k_LpMetadataHeader12_size) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, buffer + k_LpMetadataHeader10_size, + header.header_size - k_LpMetadataHeader10_size)); + Flags = Get32(buffer + k_LpMetadataHeader10_size); + } + Major_version = header.major_version; + Minor_version = header.minor_version; + + if (!CheckSha256_csOffset(buffer, header.header_size, 12)) + return S_FALSE; + + if (geom.metadata_max_size < header.tables_size || + geom.metadata_max_size - header.tables_size < header.header_size) + return S_FALSE; + + buffer.AllocAtLeast(header.tables_size); + RINOK(ReadStream_FALSE(stream, buffer, header.tables_size)); + + const UInt64 totalMetaSize = geom.GetTotalMetadataSize(); + // _headersSize = _totalSize; + _totalSize = totalMetaSize; + + if (!CheckSha256(buffer, header.tables_size, header.tables_checksum)) + return S_FALSE; + + { + const CDescriptor &d = header.partitions; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_MetaPartition_Size) + return S_FALSE; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CPartition part; + part.Parse(buffer + d.offset + i * d.entry_size); + const UInt32 extLimit = part.first_extent_index + part.num_extents; + if (extLimit < part.first_extent_index || + extLimit > header.extents.num_entries || + part.group_index >= header.groups.num_entries) + return S_FALSE; + _items.Add(part); + } + } + { + const CDescriptor &d = header.extents; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_MetaExtent_Size) + return S_FALSE; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CExtent e; + e.Parse(buffer + d.offset + i * d.entry_size); + // if (e.target_type > LP_TARGET_TYPE_ZERO) return S_FALSE; + if (e.IsRAW()) + { + if (e.target_source >= header.block_devices.num_entries) + return S_FALSE; + const UInt64 endSector = e.target_data + e.num_sectors; + const UInt64 endOffset = endSector << kSectorSizeLog; + if (_totalSize < endOffset) + _totalSize = endOffset; + } + MethodsMask |= (UInt32)1 << e.target_type; + Extents.Add(e); + } + } + + // _usedSize = _totalSize; + { + const CDescriptor &d = header.groups; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_Group_Size) + return S_FALSE; + AString s; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CGroup g; + g.Parse(buffer + d.offset + i * d.entry_size); + if (_totalSize < g.maximum_size) + _totalSize = g.maximum_size; + s += " "; + AddName36ToString(s, g.name, true); + AddComment_UInt64(s, "maximum_size", g.maximum_size); + AddComment_UInt64(s, "flags", g.flags); + s.Add_LF(); + } + GroupsString = s; + } + + { + const CDescriptor &d = header.block_devices; + if (!d.CheckLimits(header.tables_size)) + return S_FALSE; + if (d.entry_size != k_Device_Size) + return S_FALSE; + AString s; + // CRecordVector devices; + for (UInt32 i = 0; i < d.num_entries; i++) + { + CDevice v; + v.Parse(buffer + d.offset + i * d.entry_size); + // if (i == 0) + { + // it's super_device is first device; + if (totalMetaSize > (v.first_logical_sector << kSectorSizeLog)) + return S_FALSE; + } + if (_totalSize < v.size) + _totalSize = v.size; + s += " "; + if (i == 0) + AddName36ToString(DeviceArcName, v.partition_name, true); + // devices.Add(v); + AddName36ToString(s, v.partition_name, true); + AddComment_UInt64(s, "size", v.size); + AddComment_UInt64(s, "first_logical_sector", v.first_logical_sector); + AddComment_UInt64(s, "alignment", v.alignment); + AddComment_UInt64(s, "alignment_offset", v.alignment_offset); + AddComment_UInt64(s, "flags", v.flags); + s.Add_LF(); + } + DevicesString = s; + } + + { + FOR_VECTOR (i, _items) + { + CPartition &part = _items[i]; + if (part.first_extent_index > Extents.Size() || + part.num_extents > Extents.Size() - part.first_extent_index) + return S_FALSE; + + UInt64 numSectors = 0; + UInt64 numSectors_Pack = 0; + UInt32 methods = 0; + for (UInt32 k = 0; k < part.num_extents; k++) + { + const CExtent &e = Extents[part.first_extent_index + k]; + numSectors += e.num_sectors; + if (e.IsRAW()) + numSectors_Pack += e.num_sectors; + methods |= (UInt32)1 << e.target_type; + } + part.NumSectors = numSectors; + part.NumSectors_Pack = numSectors_Pack; + part.MethodsMask = methods; + } + } + + return S_OK; +} + + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 * /* maxCheckStartPosition */, + IArchiveOpenCallback * /* openArchiveCallback */) +{ + COM_TRY_BEGIN + Close(); + RINOK(Open2(stream)); + _stream = stream; + + int mainFileIndex = -1; + unsigned numNonEmptyParts = 0; + + FOR_VECTOR (fileIndex, _items) + { + CPartition &item = _items[fileIndex]; + if (item.NumSectors != 0) + { + mainFileIndex = fileIndex; + numNonEmptyParts++; + CMyComPtr parseStream; + if (GetStream(fileIndex, &parseStream) == S_OK && parseStream) + { + const size_t kParseSize = 1 << 11; + Byte buf[kParseSize]; + if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK) + { + UInt64 extSize; + if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES) + if (extSize == item.GetSize()) + item.Ext = "ext"; + } + } + } + } + if (numNonEmptyParts == 1) + _mainFileIndex = mainFileIndex; + + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::Close() +{ + _totalSize = 0; + // _usedSize = 0; + // _headersSize = 0; + _items.Clear(); + Extents.Clear(); + _stream.Release(); + _mainFileIndex = -1; + _headerWarning = false; + MethodsMask = 0; + GroupsString.Empty(); + DevicesString.Empty(); + DeviceArcName.Empty(); + return S_OK; +} + + +static const Byte kProps[] = +{ + kpidPath, + kpidSize, + kpidPackSize, + kpidCharacts, + kpidMethod, + kpidNumBlocks, + kpidOffset +}; + +static const Byte kArcProps[] = +{ + kpidUnpackVer, + kpidMethod, + kpidClusterSize, + // kpidHeadersSize, + // kpidFreeSpace, + kpidName, + kpidComment +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + switch (propID) + { + case kpidMainSubfile: + { + if (_mainFileIndex >= 0) + prop = (UInt32)_mainFileIndex; + break; + } + case kpidPhySize: prop = _totalSize; break; + + // case kpidFreeSpace: if (_usedSize != 0) prop = _totalSize - _usedSize; break; + // case kpidHeadersSize: prop = _headersSize; break; + + case kpidMethod: + { + const UInt32 m = MethodsMask; + if (m != 0) + { + FLAGS_TO_PROP(g_Methods, m, prop); + } + break; + } + + case kpidUnpackVer: + { + AString s; + s.Add_UInt32(Major_version); + s += '.'; + s.Add_UInt32(Minor_version); + prop = s; + break; + } + + case kpidClusterSize: + prop = geom.logical_block_size; + break; + + case kpidComment: + { + AString s; + + s += "metadata_slot_count: "; + s.Add_UInt32(geom.metadata_slot_count); + s.Add_LF(); + + s += "metadata_max_size: "; + s.Add_UInt32(geom.metadata_max_size); + s.Add_LF(); + + if (Flags != 0) + { + s += "flags: "; + s += FlagsToString(g_Header_Flags, ARRAY_SIZE(g_Header_Flags), Flags); + s.Add_LF(); + } + + if (!GroupsString.IsEmpty()) + { + s += "Groups:"; + s.Add_LF(); + s += GroupsString; + } + + if (!DevicesString.IsEmpty()) + { + s += "BlockDevices:"; + s.Add_LF(); + s += DevicesString; + } + + if (!s.IsEmpty()) + prop = s; + break; + } + + case kpidName: + if (!DeviceArcName.IsEmpty()) + prop = DeviceArcName + ".lpimg"; + break; + + case kpidWarningFlags: + if (_headerWarning) + { + UInt32 v = kpv_ErrorFlags_HeadersError; + prop = v; + } + break; + } + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + *numItems = _items.Size(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + const CPartition &item = _items[index]; + + switch (propID) + { + case kpidPath: + { + AString s; + AddName36ToString(s, item.name, false); + if (s.IsEmpty()) + s.Add_UInt32(index); + if (item.num_extents != 0) + { + s += '.'; + s += (item.Ext ? item.Ext : "img"); + } + prop = s; + break; + } + + case kpidSize: prop = item.GetSize(); break; + case kpidPackSize: prop = item.GetPackSize(); break; + case kpidNumBlocks: prop = item.num_extents; break; + case kpidMethod: + { + const UInt32 m = item.MethodsMask; + if (m != 0) + { + FLAGS_TO_PROP(g_Methods, m, prop); + } + break; + } + case kpidOffset: + if (item.num_extents != 0) + if (item.first_extent_index < Extents.Size()) + prop = Extents[item.first_extent_index].target_data << kSectorSizeLog; + break; + + case kpidCharacts: + { + AString s; + s += "group:"; + s.Add_UInt32(item.group_index); + s.Add_Space(); + s += FlagsToString(g_PartitionAttr, ARRAY_SIZE(g_PartitionAttr), item.attributes); + prop = s; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + + +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = NULL; + + const CPartition &item = _items[index]; + + if (item.first_extent_index > Extents.Size() + || item.num_extents > Extents.Size() - item.first_extent_index) + return S_FALSE; + + if (item.num_extents == 0) + return CreateLimitedInStream(_stream, 0, 0, stream); + + if (item.num_extents == 1) + { + const CExtent &e = Extents[item.first_extent_index]; + if (e.IsRAW()) + { + const UInt64 pos = e.target_data << kSectorSizeLog; + if ((pos >> kSectorSizeLog) != e.target_data) + return S_FALSE; + const UInt64 size = item.GetSize(); + if (pos + size < pos) + return S_FALSE; + return CreateLimitedInStream(_stream, pos, size, stream); + } + } + + CExtentsStream *extentStreamSpec = new CExtentsStream(); + CMyComPtr extentStream = extentStreamSpec; + + // const unsigned kNumDebugExtents = 10; + extentStreamSpec->Extents.Reserve(item.num_extents + 1 + // + kNumDebugExtents + ); + + UInt64 virt = 0; + for (UInt32 k = 0; k < item.num_extents; k++) + { + const CExtent &e = Extents[item.first_extent_index + k]; + + CSeekExtent se; + { + const UInt64 numSectors = e.num_sectors; + if (numSectors == 0) + { + continue; + // return S_FALSE; + } + const UInt64 numBytes = numSectors << kSectorSizeLog; + if ((numBytes >> kSectorSizeLog) != numSectors) + return S_FALSE; + if (numBytes >= ((UInt64)1 << 63) - virt) + return S_FALSE; + + se.Virt = virt; + virt += numBytes; + } + + const UInt64 phySector = e.target_data; + if (e.target_type == LP_TARGET_TYPE_ZERO) + { + if (phySector != 0) + return S_FALSE; + se.SetAs_ZeroFill(); + } + else if (e.target_type == LP_TARGET_TYPE_LINEAR) + { + se.Phy = phySector << kSectorSizeLog; + if ((se.Phy >> kSectorSizeLog) != phySector) + return S_FALSE; + if (se.Phy >= ((UInt64)1 << 63)) + return S_FALSE; + } + else + return S_FALSE; + + extentStreamSpec->Extents.AddInReserved(se); + + /* + { + // for debug + const UInt64 kAdd = (e.num_sectors << kSectorSizeLog) / kNumDebugExtents; + for (unsigned i = 0; i < kNumDebugExtents; i++) + { + se.Phy += kAdd; + // se.Phy += (UInt64)1 << 63; // for debug + // se.Phy += 1; // for debug + se.Virt += kAdd; + extentStreamSpec->Extents.AddInReserved(se); + } + } + */ + } + + CSeekExtent se; + se.Phy = 0; + se.Virt = virt; + extentStreamSpec->Extents.Add(se); + extentStreamSpec->Stream = _stream; + extentStreamSpec->Init(); + *stream = extentStream.Detach(); + + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) +{ + COM_TRY_BEGIN + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); + if (allFilesMode) + numItems = _items.Size(); + if (numItems == 0) + return S_OK; + UInt64 totalSize = 0; + UInt32 i; + for (i = 0; i < numItems; i++) + { + const UInt32 index = allFilesMode ? i : indices[i]; + totalSize += _items[index].GetSize(); + } + extractCallback->SetTotal(totalSize); + + totalSize = 0; + + NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder(); + CMyComPtr copyCoder = copyCoderSpec; + + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(extractCallback, false); + + for (i = 0; i < numItems; i++) + { + lps->InSize = totalSize; + lps->OutSize = totalSize; + RINOK(lps->SetCur()); + CMyComPtr outStream; + const Int32 askMode = testMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract; + const UInt32 index = allFilesMode ? i : indices[i]; + + RINOK(extractCallback->GetStream(index, &outStream, askMode)); + + const UInt64 size = _items[index].GetSize(); + totalSize += size; + if (!testMode && !outStream) + continue; + + RINOK(extractCallback->PrepareOperation(askMode)); + + CMyComPtr inStream; + const HRESULT hres = GetStream(index, &inStream); + int opRes = NExtract::NOperationResult::kUnsupportedMethod; + if (hres != S_FALSE) + { + if (hres != S_OK) + return hres; + RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress)); + opRes = NExtract::NOperationResult::kDataError; + if (copyCoderSpec->TotalSize == size) + opRes = NExtract::NOperationResult::kOK; + else if (copyCoderSpec->TotalSize < size) + opRes = NExtract::NOperationResult::kUnexpectedEnd; + } + outStream.Release(); + RINOK(extractCallback->SetOperationResult(opRes)); + } + + return S_OK; + COM_TRY_END +} + + +REGISTER_ARC_I( + "LP", "lpimg img", NULL, 0xc1, + k_Signature, + LP_PARTITION_RESERVED_BYTES, + 0, + NULL) + +}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/LzhHandler.cpp 7zip-22.01/CPP/7zip/Archive/LzhHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/LzhHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/LzhHandler.cpp 2022-02-14 07:00:00.000000000 +0000 @@ -487,22 +487,11 @@ case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break; case kpidMTime: { - FILETIME utc; UInt32 unixTime; if (item.GetUnixTime(unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); + PropVariant_SetFrom_UnixTime(prop, unixTime); else - { - FILETIME localFileTime; - if (DosTimeToFileTime(item.ModifiedTime, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utc)) - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - else - utc.dwHighDateTime = utc.dwLowDateTime = 0; - } - prop = utc; + PropVariant_SetFrom_DosTime(prop, item.ModifiedTime); break; } // case kpidAttrib: prop = (UInt32)item.Attributes; break; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/NtfsHandler.cpp 7zip-22.01/CPP/7zip/Archive/NtfsHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/NtfsHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/NtfsHandler.cpp 2022-05-01 11:00:00.000000000 +0000 @@ -278,7 +278,7 @@ { UInt64 CTime; UInt64 MTime; - // UInt64 ThisRecMTime; + UInt64 ThisRecMTime; UInt64 ATime; UInt32 Attrib; @@ -300,7 +300,7 @@ return false; G64(p + 0x00, CTime); G64(p + 0x08, MTime); - // G64(p + 0x10, ThisRecMTime); + G64(p + 0x10, ThisRecMTime); G64(p + 0x18, ATime); G32(p + 0x20, Attrib); SecurityId = 0; @@ -2301,6 +2301,7 @@ kpidMTime, kpidCTime, kpidATime, + kpidChangeTime, kpidAttrib, kpidLinks, kpidINode, @@ -2577,7 +2578,7 @@ case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break; case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break; case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break; - // case kpidRecMTime: if (fn) NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break; + case kpidChangeTime: NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break; /* case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/PeHandler.cpp 7zip-22.01/CPP/7zip/Archive/PeHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/PeHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/PeHandler.cpp 2022-02-14 08:00:00.000000000 +0000 @@ -885,11 +885,7 @@ static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop) { if (unixTime != 0) - { - FILETIME ft; - NTime::UnixTimeToFileTime(unixTime, ft); - prop = ft; - } + PropVariant_SetFrom_UnixTime(prop, unixTime); } STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/PpmdHandler.cpp 7zip-22.01/CPP/7zip/Archive/PpmdHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/PpmdHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/PpmdHandler.cpp 2022-03-28 12:00:00.000000000 +0000 @@ -174,7 +174,7 @@ { // time can be in Unix format ??? FILETIME utc; - if (NTime::DosTimeToFileTime(_item.Time, utc)) + if (NTime::DosTime_To_FileTime(_item.Time, utc)) prop = utc; break; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.cpp 7zip-22.01/CPP/7zip/Archive/Rar/Rar5Handler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Rar/Rar5Handler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Rar/Rar5Handler.cpp 2022-05-04 11:00:00.000000000 +0000 @@ -1591,14 +1591,14 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop) { unsigned size; - int offset = item.FindExtra(NExtraID::kTime, size); + const int offset = item.FindExtra(NExtraID::kTime, size); if (offset < 0) return; const Byte *p = item.Extra + (unsigned)offset; UInt64 flags; { - unsigned num = ReadVarInt(p, size, &flags); + const unsigned num = ReadVarInt(p, size, &flags); if (num == 0) return; p += num; @@ -1610,8 +1610,8 @@ unsigned numStamps = 0; unsigned curStamp = 0; - unsigned i; - for (i = 0; i < 3; i++) + + for (unsigned i = 0; i < 3; i++) if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0) { if (i == stampIndex) @@ -1620,20 +1620,28 @@ } FILETIME ft; - + + unsigned timePrec = 0; + unsigned ns100 = 0; + if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) { curStamp *= 4; if (curStamp + 4 > size) return; - const Byte *p2 = p + curStamp; - UInt64 val = NTime::UnixTimeToFileTime64(Get32(p2)); + p += curStamp; + UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p)); numStamps *= 4; + timePrec = k_PropVar_TimePrec_Unix; if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) { - const UInt32 ns = Get32(p2 + numStamps) & 0x3FFFFFFF; + const UInt32 ns = Get32(p + numStamps) & 0x3FFFFFFF; if (ns < 1000000000) + { val += ns / 100; + ns100 = (unsigned)(ns % 100); + timePrec = k_PropVar_TimePrec_1ns; + } } ft.dwLowDateTime = (DWORD)val; ft.dwHighDateTime = (DWORD)(val >> 32); @@ -1643,12 +1651,12 @@ curStamp *= 8; if (curStamp + 8 > size) return; - const Byte *p2 = p + curStamp; - ft.dwLowDateTime = Get32(p2); - ft.dwHighDateTime = Get32(p2 + 4); + p += curStamp; + ft.dwLowDateTime = Get32(p); + ft.dwHighDateTime = Get32(p + 4); } - prop = ft; + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, timePrec, ns100); } @@ -1715,21 +1723,13 @@ { TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop); if (prop.vt == VT_EMPTY && item.Has_UnixMTime()) - { - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(item.UnixMTime, ft); - prop = ft; - } + PropVariant_SetFrom_UnixTime(prop, item.UnixMTime); if (prop.vt == VT_EMPTY && ref.Parent >= 0) { const CItem &baseItem = _items[_refs[ref.Parent].Item]; TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop); if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime()) - { - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(baseItem.UnixMTime, ft); - prop = ft; - } + PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime); } break; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Rar/RarHandler.cpp 7zip-22.01/CPP/7zip/Archive/Rar/RarHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Rar/RarHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Rar/RarHandler.cpp 2022-05-04 11:00:00.000000000 +0000 @@ -360,7 +360,7 @@ static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime) { rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); - unsigned numDigits = (mask & 3); + const unsigned numDigits = (mask & 3); rarTime.SubTime[0] = rarTime.SubTime[1] = rarTime.SubTime[2] = 0; @@ -405,8 +405,8 @@ item.MTime.LowSecond = 0; item.MTime.SubTime[0] = - item.MTime.SubTime[1] = - item.MTime.SubTime[2] = 0; + item.MTime.SubTime[1] = + item.MTime.SubTime[2] = 0; p += kFileHeaderSize; size -= kFileHeaderSize; @@ -941,31 +941,32 @@ return S_OK; } -static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result) +static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &ft) { - if (!NTime::DosTimeToFileTime(rarTime.DosTime, result)) + if (!NTime::DosTime_To_FileTime(rarTime.DosTime, ft)) return false; - UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime; - value += (UInt64)rarTime.LowSecond * 10000000; - value += ((UInt64)rarTime.SubTime[2] << 16) + - ((UInt64)rarTime.SubTime[1] << 8) + - ((UInt64)rarTime.SubTime[0]); - result.dwLowDateTime = (DWORD)value; - result.dwHighDateTime = DWORD(value >> 32); + UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + v += (UInt32)rarTime.LowSecond * 10000000; + v += + ((UInt32)rarTime.SubTime[2] << 16) + + ((UInt32)rarTime.SubTime[1] << 8) + + ((UInt32)rarTime.SubTime[0]); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); return true; } static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) { - FILETIME localFileTime, utcFileTime; - if (RarTimeToFileTime(rarTime, localFileTime)) - { - if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - } + FILETIME localFileTime, utc; + if (RarTimeToFileTime(rarTime, localFileTime) + && LocalFileTimeToFileTime(&localFileTime, &utc)) + prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns); + /* else - utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; - prop = utcFileTime; + utc.dwHighDateTime = utc.dwLowDateTime = 0; + // prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns); + */ } STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Rar/RarVol.h 7zip-22.01/CPP/7zip/Archive/Rar/RarVol.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Rar/RarVol.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Rar/RarVol.h 2022-02-15 13:00:00.000000000 +0000 @@ -52,7 +52,7 @@ ext.IsEqualTo_Ascii_NoCase("r01")) { _changed = ext; - _before = name.Left(dotPos + 1); + _before.SetFrom(name.Ptr(), dotPos + 1); return true; } } @@ -60,16 +60,23 @@ if (newStyle) { - unsigned i = base.Len(); + unsigned k = base.Len(); + + for (; k != 0; k--) + if (IsDigit(base[k - 1])) + break; + + unsigned i = k; for (; i != 0; i--) if (!IsDigit(base[i - 1])) break; - if (i != base.Len()) + if (i != k) { - _before = base.Left(i); - _changed = base.Ptr(i); + _before.SetFrom(base.Ptr(), i); + _changed.SetFrom(base.Ptr(i), k - i); + _after.Insert(0, base.Ptr(k)); return true; } } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/RpmHandler.cpp 7zip-22.01/CPP/7zip/Archive/RpmHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/RpmHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/RpmHandler.cpp 2022-02-14 07:00:00.000000000 +0000 @@ -215,11 +215,7 @@ void SetTime(NCOM::CPropVariant &prop) const { if (_time_Defined && _buildTime != 0) - { - FILETIME ft; - NTime::UnixTimeToFileTime(_buildTime, ft); - prop = ft; - } + PropVariant_SetFrom_UnixTime(prop, _buildTime); } void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/SparseHandler.cpp 7zip-22.01/CPP/7zip/Archive/SparseHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/SparseHandler.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/SparseHandler.cpp 2022-02-01 10:00:00.000000000 +0000 @@ -0,0 +1,548 @@ +// SparseHandler.cpp + +#include "StdAfx.h" + +#include "../../../C/CpuArch.h" + +#include "../../Common/ComTry.h" + +#include "../../Windows/PropVariantUtils.h" + +#include "../Common/RegisterArc.h" +#include "../Common/StreamUtils.h" + +#include "HandlerCont.h" + +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); + +using namespace NWindows; + +namespace NArchive { +namespace NSparse { + +// libsparse and simg2img + +struct CHeader +{ + // UInt32 magic; /* 0xed26ff3a */ + // UInt16 major_version; /* (0x1) - reject images with higher major versions */ + // UInt16 minor_version; /* (0x0) - allow images with higer minor versions */ + UInt16 file_hdr_sz; /* 28 bytes for first revision of the file format */ + UInt16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */ + UInt32 BlockSize; /* block size in bytes, must be a multiple of 4 (4096) */ + UInt32 NumBlocks; /* total blocks in the non-sparse output image */ + UInt32 NumChunks; /* total chunks in the sparse input image */ + // UInt32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" as 0. */ + + void Parse(const Byte *p) + { + // G16 (4, major_version); + // G16 (6, minor_version); + G16 (8, file_hdr_sz); + G16 (10, chunk_hdr_sz); + G32 (12, BlockSize); + G32 (16, NumBlocks); + G32 (20, NumChunks); + // G32 (24, image_checksum); + } +}; + +// #define SPARSE_HEADER_MAGIC 0xed26ff3a + +#define CHUNK_TYPE_RAW 0xCAC1 +#define CHUNK_TYPE_FILL 0xCAC2 +#define CHUNK_TYPE_DONT_CARE 0xCAC3 +#define CHUNK_TYPE_CRC32 0xCAC4 + +#define MY__CHUNK_TYPE_FILL 0 +#define MY__CHUNK_TYPE_DONT_CARE 1 +#define MY__CHUNK_TYPE_RAW__START 2 + +static const char * const g_Methods[] = +{ + "RAW" + , "FILL" + , "SPARSE" // "DONT_CARE" + , "CRC32" +}; + +static const unsigned kFillSize = 4; + +struct CChunk +{ + UInt32 VirtBlock; + Byte Fill [kFillSize]; + UInt64 PhyOffset; +}; + +static const Byte k_Signature[] = { 0x3a, 0xff, 0x26, 0xed, 1, 0 }; + + +class CHandler: public CHandlerImg +{ + CRecordVector Chunks; + UInt64 _virtSize_fromChunks; + unsigned _blockSizeLog; + UInt32 _chunkIndexPrev; + + UInt64 _packSizeProcessed; + UInt64 _phySize; + UInt32 _methodFlags; + bool _isArc; + bool _headersError; + bool _unexpectedEnd; + // bool _unsupported; + UInt32 NumChunks; // from header + + HRESULT Seek2(UInt64 offset) + { + _posInArc = offset; + return Stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + + void InitSeekPositions() + { + /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()). + So we must reset these variables before first call of Read() */ + Reset_VirtPos(); + Reset_PosInArc(); + _chunkIndexPrev = 0; + _packSizeProcessed = 0; + } + + // virtual functions + bool Init_PackSizeProcessed() + { + _packSizeProcessed = 0; + return true; + } + bool Get_PackSizeProcessed(UInt64 &size) + { + size = _packSizeProcessed; + return true; + } + + HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback); + HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed); + +public: + INTERFACE_IInArchive_Img(;) + + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + + +static const Byte kProps[] = +{ + kpidSize, + kpidPackSize +}; + +static const Byte kArcProps[] = +{ + kpidClusterSize, + kpidNumBlocks, + kpidMethod +}; + +IMP_IInArchive_Props +IMP_IInArchive_ArcProps + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidMainSubfile: prop = (UInt32)0; break; + case kpidClusterSize: prop = (UInt32)((UInt32)1 << _blockSizeLog); break; + case kpidNumBlocks: prop = (UInt32)NumChunks; break; + case kpidPhySize: if (_phySize != 0) prop = _phySize; break; + + case kpidMethod: + { + FLAGS_TO_PROP(g_Methods, _methodFlags, prop); + break; + } + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_headersError) v |= kpv_ErrorFlags_HeadersError; + if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + if (!Stream && v == 0 && _isArc) + v = kpv_ErrorFlags_HeadersError; + if (v != 0) + prop = v; + break; + } + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NCOM::CPropVariant prop; + + switch (propID) + { + case kpidSize: prop = _size; break; + case kpidPackSize: prop = _phySize; break; + case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break; + } + + prop.Detach(value); + return S_OK; + COM_TRY_END +} + + +static unsigned GetLogSize(UInt32 size) +{ + unsigned k; + for (k = 0; k < 32; k++) + if (((UInt32)1 << k) == size) + return k; + return k; +} + + +HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback) +{ + const unsigned kHeaderSize = 28; + const unsigned kChunkHeaderSize = 12; + CHeader h; + { + Byte buf[kHeaderSize]; + RINOK(ReadStream_FALSE(stream, buf, kHeaderSize)); + if (memcmp(buf, k_Signature, 6) != 0) + return S_FALSE; + h.Parse(buf); + } + + if (h.file_hdr_sz != kHeaderSize || + h.chunk_hdr_sz != kChunkHeaderSize) + return S_FALSE; + + NumChunks = h.NumChunks; + + const unsigned logSize = GetLogSize(h.BlockSize); + if (logSize < 2 || logSize >= 32) + return S_FALSE; + _blockSizeLog = logSize; + + _size = (UInt64)h.NumBlocks << logSize; + + if (h.NumChunks >= (UInt32)(Int32)-2) // it's our limit + return S_FALSE; + + _isArc = true; + Chunks.Reserve(h.NumChunks + 1); + UInt64 offset = kHeaderSize; + UInt32 virtBlock = 0; + UInt32 i; + + for (i = 0; i < h.NumChunks; i++) + { + { + const UInt32 mask = ((UInt32)1 << 16) - 1; + if ((i & mask) == mask && openCallback) + { + RINOK(openCallback->SetCompleted(NULL, &offset)); + } + } + Byte buf[kChunkHeaderSize]; + { + size_t processed = kChunkHeaderSize; + RINOK(ReadStream(stream, buf, &processed)); + if (kChunkHeaderSize != processed) + { + offset += kChunkHeaderSize; + break; + } + } + const UInt32 type = Get32(&buf[0]); + const UInt32 numBlocks = Get32(&buf[4]); + UInt32 size = Get32(&buf[8]); + + if (type < CHUNK_TYPE_RAW || + type > CHUNK_TYPE_CRC32) + return S_FALSE; + if (size < kChunkHeaderSize) + return S_FALSE; + CChunk c; + c.PhyOffset = offset + kChunkHeaderSize; + c.VirtBlock = virtBlock; + offset += size; + size -= kChunkHeaderSize; + _methodFlags |= ((UInt32)1 << (type - CHUNK_TYPE_RAW)); + + if (numBlocks > h.NumBlocks - virtBlock) + return S_FALSE; + + if (type == CHUNK_TYPE_CRC32) + { + // crc chunk must be last chunk (i == h.NumChunks -1); + if (size != kFillSize || numBlocks != 0) + return S_FALSE; + { + size_t processed = kFillSize; + RINOK(ReadStream(stream, c.Fill, &processed)); + if (kFillSize != processed) + break; + } + continue; + } + // else + { + if (numBlocks == 0) + return S_FALSE; + + if (type == CHUNK_TYPE_DONT_CARE) + { + if (size != 0) + return S_FALSE; + c.PhyOffset = MY__CHUNK_TYPE_DONT_CARE; + } + else if (type == CHUNK_TYPE_FILL) + { + if (size != kFillSize) + return S_FALSE; + c.PhyOffset = MY__CHUNK_TYPE_FILL; + size_t processed = kFillSize; + RINOK(ReadStream(stream, c.Fill, &processed)); + if (kFillSize != processed) + break; + } + else if (type == CHUNK_TYPE_RAW) + { + /* Here we require (size == virtSize). + Probably original decoder also requires it. + But maybe size of last chunk can be non-aligned with blockSize ? */ + const UInt32 virtSize = (numBlocks << _blockSizeLog); + if (size != virtSize || numBlocks != (virtSize >> _blockSizeLog)) + return S_FALSE; + } + else + return S_FALSE; + + virtBlock += numBlocks; + Chunks.AddInReserved(c); + if (type == CHUNK_TYPE_RAW) + RINOK(stream->Seek(offset, STREAM_SEEK_SET, NULL)); + } + } + + if (i != h.NumChunks) + _unexpectedEnd = true; + else if (virtBlock != h.NumBlocks) + _headersError = true; + + _phySize = offset; + + { + CChunk c; + c.VirtBlock = virtBlock; + c.PhyOffset = offset; + Chunks.AddInReserved(c); + } + _virtSize_fromChunks = (UInt64)virtBlock << _blockSizeLog; + + Stream = stream; + return S_OK; +} + + +STDMETHODIMP CHandler::Close() +{ + Chunks.Clear(); + _isArc = false; + _virtSize_fromChunks = 0; + // _unsupported = false; + _headersError = false; + _unexpectedEnd = false; + _phySize = 0; + _methodFlags = 0; + + _chunkIndexPrev = 0; + _packSizeProcessed = 0; + + // CHandlerImg: + Clear_HandlerImg_Vars(); + Stream.Release(); + return S_OK; +} + + +STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream) +{ + COM_TRY_BEGIN + *stream = NULL; + if (Chunks.Size() < 1) + return S_FALSE; + if (Chunks.Size() < 2 && _virtSize_fromChunks != 0) + return S_FALSE; + // if (_unsupported) return S_FALSE; + InitSeekPositions(); + CMyComPtr streamTemp = this; + *stream = streamTemp.Detach(); + return S_OK; + COM_TRY_END +} + + + +HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed) +{ + processed = 0; + if (offset > _phySize || offset + size > _phySize) + { + // we don't expect these cases, if (_phySize) was set correctly. + return S_FALSE; + } + if (offset != _posInArc) + { + const HRESULT res = Seek2(offset); + if (res != S_OK) + { + Reset_PosInArc(); // we don't trust seek_pos in case of error + return res; + } + } + { + size_t size2 = size; + const HRESULT res = ReadStream(Stream, data, &size2); + processed = (UInt32)size2; + _packSizeProcessed += size2; + _posInArc += size2; + if (res != S_OK) + Reset_PosInArc(); // we don't trust seek_pos in case of reading error + return res; + } +} + + +STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize) + *processedSize = 0; + // const unsigned kLimit = (1 << 16) + 1; if (size > kLimit) size = kLimit; // for debug + if (_virtPos >= _virtSize_fromChunks) + return S_OK; + { + const UInt64 rem = _virtSize_fromChunks - _virtPos; + if (size > rem) + size = (UInt32)rem; + if (size == 0) + return S_OK; + } + + UInt32 chunkIndex = _chunkIndexPrev; + if (chunkIndex + 1 >= Chunks.Size()) + return S_FALSE; + { + const UInt32 blockIndex = (UInt32)(_virtPos >> _blockSizeLog); + if (blockIndex < Chunks[chunkIndex ].VirtBlock || + blockIndex >= Chunks[chunkIndex + 1].VirtBlock) + { + unsigned left = 0, right = Chunks.Size() - 1; + for (;;) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + if (mid == left) + break; + if (blockIndex < Chunks[mid].VirtBlock) + right = mid; + else + left = mid; + } + chunkIndex = left; + _chunkIndexPrev = chunkIndex; + } + } + + const CChunk &c = Chunks[chunkIndex]; + const UInt64 offset = _virtPos - ((UInt64)c.VirtBlock << _blockSizeLog); + { + const UInt32 numBlocks = Chunks[chunkIndex + 1].VirtBlock - c.VirtBlock; + const UInt64 rem = ((UInt64)numBlocks << _blockSizeLog) - offset; + if (size > rem) + size = (UInt32)rem; + } + + const UInt64 phyOffset = c.PhyOffset; + + if (phyOffset >= MY__CHUNK_TYPE_RAW__START) + { + UInt32 processed = 0; + const HRESULT res = ReadPhy(phyOffset + offset, data, size, processed); + if (processedSize) + *processedSize = processed; + _virtPos += processed; + return res; + } + + unsigned b = 0; + + if (phyOffset == MY__CHUNK_TYPE_FILL) + { + const Byte b0 = c.Fill [0]; + const Byte b1 = c.Fill [1]; + const Byte b2 = c.Fill [2]; + const Byte b3 = c.Fill [3]; + if (b0 != b1 || + b0 != b2 || + b0 != b3) + { + if (processedSize) + *processedSize = size; + _virtPos += size; + Byte *dest = (Byte *)data; + while (size >= 4) + { + dest[0] = b0; + dest[1] = b1; + dest[2] = b2; + dest[3] = b3; + dest += 4; + size -= 4; + } + if (size > 0) dest[0] = b0; + if (size > 1) dest[1] = b1; + if (size > 2) dest[2] = b2; + return S_OK; + } + b = b0; + } + else if (phyOffset != MY__CHUNK_TYPE_DONT_CARE) + return S_FALSE; + + memset(data, b, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; +} + +REGISTER_ARC_I( + "Sparse", "simg img", NULL, 0xc2, + k_Signature, + 0, + 0, + NULL) + +}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/SplitHandler.cpp 7zip-22.01/CPP/7zip/Archive/SplitHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/SplitHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/SplitHandler.cpp 2022-05-15 07:00:00.000000000 +0000 @@ -162,7 +162,10 @@ numLetters++; } } - else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01")) + else if (ext2.Len() >= 2 && ( + StringsAreEqual_Ascii(ext2.RightPtr(2), "01") + || StringsAreEqual_Ascii(ext2.RightPtr(2), "00") + )) { while (numLetters < ext2.Len()) { @@ -170,7 +173,7 @@ break; numLetters++; } - if (numLetters != ext.Len()) + if (numLetters != ext2.Len()) return S_FALSE; } else diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/SquashfsHandler.cpp 7zip-22.01/CPP/7zip/Archive/SquashfsHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/SquashfsHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/SquashfsHandler.cpp 2022-05-02 11:00:00.000000000 +0000 @@ -76,7 +76,7 @@ , "XZ" }; -static const UInt32 kMetadataBlockSizeLog = 13; +static const unsigned kMetadataBlockSizeLog = 13; static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog); enum @@ -408,7 +408,7 @@ UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h) { - bool be = _h.be; + const bool be = _h.be; if (size < 4) return 0; { @@ -541,7 +541,7 @@ UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h) { - bool be = _h.be; + const bool be = _h.be; if (size < 12) return 0; @@ -843,8 +843,8 @@ CData _inodesData; CData _dirs; CRecordVector _frags; - // CByteBuffer _uids; - // CByteBuffer _gids; + CByteBuffer _uids; + CByteBuffer _gids; CHeader _h; bool _noPropsLZMA; bool _needCheckLzma; @@ -891,14 +891,20 @@ _cachedUnpackBlockSize = 0; } + HRESULT Seek2(UInt64 offset) + { + return _stream->Seek(offset, STREAM_SEEK_SET, NULL); + } + HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, UInt32 inSize, UInt32 outSizeMax); HRESULT ReadMetadataBlock(UInt32 &packSize); + HRESULT ReadMetadataBlock2(); HRESULT ReadData(CData &data, UInt64 start, UInt64 end); HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); HRESULT ScanInodes(UInt64 ptr); - // HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); + HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); HRESULT Open2(IInStream *inStream); AString GetPath(int index) const; bool GetPackSize(int index, UInt64 &res, bool fillOffsets); @@ -938,9 +944,9 @@ kpidSize, kpidPackSize, kpidMTime, - kpidPosixAttrib - // kpidUser, - // kpidGroup, + kpidPosixAttrib, + kpidUserId, + kpidGroupId // kpidLinks, // kpidOffset }; @@ -1280,14 +1286,14 @@ HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize) { Byte temp[3]; - unsigned offset = _h.NeedCheckData() ? 3 : 2; + const unsigned offset = _h.NeedCheckData() ? 3 : 2; if (offset > packSize) return S_FALSE; RINOK(ReadStream_FALSE(_stream, temp, offset)); // if (NeedCheckData && Major < 4) checkByte must be = 0xFF - bool be = _h.be; + const bool be = _h.be; UInt32 size = Get16(temp); - bool isCompressed = ((size & kNotCompressedBit16) == 0); + const bool isCompressed = ((size & kNotCompressedBit16) == 0); if (size != kNotCompressedBit16) size &= ~kNotCompressedBit16; @@ -1311,12 +1317,20 @@ return S_OK; } + +HRESULT CHandler::ReadMetadataBlock2() +{ + _dynOutStreamSpec->Init(); + UInt32 packSize = kMetadataBlockSize + 3; // check it + return ReadMetadataBlock(packSize); +} + HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end) { if (end < start || end - start >= ((UInt64)1 << 32)) return S_FALSE; const UInt32 size = (UInt32)(end - start); - RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); + RINOK(Seek2(start)); _dynOutStreamSpec->Init(); UInt32 packPos = 0; while (packPos != size) @@ -1395,7 +1409,7 @@ CRecordVector tempItems; while (rem != 0) { - bool be = _h.be; + const bool be = _h.be; UInt32 count; CTempItem tempItem; if (_h.Major <= 2) @@ -1519,15 +1533,15 @@ return S_OK; } -/* HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) { - size_t size = num * 4; - ids.SetCapacity(size); - RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); + const size_t size = (size_t)num * 4; + ids.Alloc(size); + if (num == 0) + return S_OK; + RINOK(Seek2(start)); return ReadStream_FALSE(_stream, ids, size); } -*/ HRESULT CHandler::Open2(IInStream *inStream) { @@ -1560,24 +1574,22 @@ if (_h.NumFrags > kNumFilesMax) return S_FALSE; _frags.ClearAndReserve(_h.NumFrags); - unsigned bigFrag = (_h.Major > 2); + const unsigned bigFrag = (_h.Major > 2); - unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); - UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; - size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); + const unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); + const UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; + const size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); CByteBuffer data(numBlocksBytes); - RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); + RINOK(Seek2(_h.FragTable)); RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); - bool be = _h.be; + const bool be = _h.be; for (UInt32 i = 0; i < numBlocks; i++) { - UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); - RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - _dynOutStreamSpec->Init(); - UInt32 packSize = kMetadataBlockSize + 3; - RINOK(ReadMetadataBlock(packSize)); - UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize(); + const UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); + RINOK(Seek2(offset)); + RINOK(ReadMetadataBlock2()); + const UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize(); if (unpackSize != kMetadataBlockSize) if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) return S_FALSE; @@ -1605,8 +1617,6 @@ return S_FALSE; } - // RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL)); - RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)); RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)); @@ -1655,7 +1665,6 @@ int rootNodeIndex; RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex)); - /* if (_h.Major < 4) { RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids)); @@ -1663,33 +1672,34 @@ } else { - UInt32 size = _h.NumIDs * 4; - _uids.SetCapacity(size); + const UInt32 size = (UInt32)_h.NumIDs * 4; + _uids.Alloc(size); - UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; - UInt32 numBlocksBytes = numBlocks << 3; + const UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; + const UInt32 numBlocksBytes = numBlocks << 3; CByteBuffer data; - data.SetCapacity(numBlocksBytes); - RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL)); + data.Alloc(numBlocksBytes); + RINOK(Seek2(_h.UidTable)); RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); for (UInt32 i = 0; i < numBlocks; i++) { - UInt64 offset = GetUi64(data + i * 8); - UInt32 unpackSize, packSize; - RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); + const UInt64 offset = GetUi64(data + i * 8); + RINOK(Seek2(offset)); + // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); + RINOK(ReadMetadataBlock2()); + const size_t unpackSize = _dynOutStreamSpec->GetSize(); if (unpackSize != kMetadataBlockSize) if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1))) return S_FALSE; + memcpy(_uids + kMetadataBlockSize * i, _dynOutStreamSpec->GetBuffer(), unpackSize); } } - */ { const UInt32 alignSize = 1 << 12; Byte buf[alignSize]; - RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL)); + RINOK(Seek2(_h.Size)); UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); _sizeCalculated = _h.Size; if (rem != 0) @@ -1710,7 +1720,7 @@ { unsigned len = 0; int indexMem = index; - bool be = _h.be; + const bool be = _h.be; do { const CItem &item = _items[index]; @@ -1804,9 +1814,9 @@ totalPack = 0; const CItem &item = _items[index]; const CNode &node = _nodes[item.Node]; - UInt32 ptr = _nodesPos[item.Node]; + const UInt32 ptr = _nodesPos[item.Node]; const Byte *p = _inodesData.Data + ptr; - bool be = _h.be; + const bool be = _h.be; UInt32 type = node.Type; UInt32 offset; @@ -1936,11 +1946,7 @@ case kpidBigEndian: prop = _h.be; break; case kpidCTime: if (_h.CTime != 0) - { - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft); - prop = ft; - } + PropVariant_SetFrom_UnixTime(prop, _h.CTime); break; case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; // case kpidNumBlocks: prop = _h.NumFrags; break; @@ -1979,8 +1985,8 @@ NWindows::NCOM::CPropVariant prop; const CItem &item = _items[index]; const CNode &node = _nodes[item.Node]; - bool isDir = node.IsDir(); - bool be = _h.be; + const bool isDir = node.IsDir(); + const bool be = _h.be; switch (propID) { @@ -2031,9 +2037,7 @@ if (offset != 0) { const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset; - FILETIME ft; - NWindows::NTime::UnixTimeToFileTime(Get32(p), ft); - prop = ft; + PropVariant_SetFrom_UnixTime(prop, Get32(p)); } break; } @@ -2043,31 +2047,38 @@ prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; break; } - /* - case kpidUser: + case kpidUserId: { - UInt32 offset = node.Uid * 4; + const UInt32 offset = (UInt32)node.Uid * 4; if (offset < _uids.Size()) prop = (UInt32)Get32(_uids + offset); break; } - case kpidGroup: + case kpidGroupId: { - if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) + if (_h.Major < 4) { - UInt32 offset = node.Uid * 4; - if (offset < _uids.Size()) - prop = (UInt32)Get32(_uids + offset); + if (node.Gid == _h.GetSpecGuidIndex()) + { + const UInt32 offset = (UInt32)node.Uid * 4; + if (offset < _uids.Size()) + prop = (UInt32)Get32(_uids + offset); + } + else + { + const UInt32 offset = (UInt32)node.Gid * 4; + if (offset < _gids.Size()) + prop = (UInt32)Get32(_gids + offset); + } } else { - UInt32 offset = node.Gid * 4; - if (offset < _gids.Size()) - prop = (UInt32)Get32(_gids + offset); + const UInt32 offset = (UInt32)node.Gid * 4; + if (offset < _uids.Size()) + prop = (UInt32)Get32(_uids + offset); } break; } - */ /* case kpidLinks: if (_h.Major >= 3 && node.Type != kType_FILE) @@ -2128,7 +2139,7 @@ packBlockSize != _cachedPackBlockSize) { ClearCache(); - RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL)); + RINOK(Seek2(blockOffset)); _limitedInStreamSpec->Init(packBlockSize); if (compressed) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHandler.cpp 7zip-22.01/CPP/7zip/Archive/Tar/TarHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarHandler.cpp 2022-05-18 12:00:00.000000000 +0000 @@ -36,22 +36,34 @@ kpidSize, kpidPackSize, kpidMTime, + kpidCTime, + kpidATime, kpidPosixAttrib, kpidUser, kpidGroup, + kpidUserId, + kpidGroupId, kpidSymLink, kpidHardLink, - kpidCharacts - // kpidLinkType + kpidCharacts, + kpidComment + , kpidDeviceMajor + , kpidDeviceMinor + // , kpidDevice + // , kpidHeadersSize // for debug + // , kpidOffset // for debug }; static const Byte kArcProps[] = { kpidHeadersSize, kpidCodePage, - kpidCharacts + kpidCharacts, + kpidComment }; +static const char *k_Characts_Prefix = "PREFIX"; + IMP_IInArchive_Props IMP_IInArchive_ArcProps @@ -60,14 +72,14 @@ NCOM::CPropVariant prop; switch (propID) { - case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; - case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; + case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break; + case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break; case kpidErrorFlags: { UInt32 flags = 0; if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; - else switch (_error) + else switch (_arc._error) { case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; @@ -82,7 +94,7 @@ case kpidWarningFlags: { - if (_warning) + if (_arc._is_Warning) prop = kpv_ErrorFlags_HeadersError; break; } @@ -107,37 +119,38 @@ case kpidCharacts: { - prop = _encodingCharacts.GetCharactsString(); + AString s; + if (_arc._are_Gnu) s.Add_OptSpaced("GNU"); + if (_arc._are_Posix) s.Add_OptSpaced("POSIX"); + if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM"); + if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix); + if (_arc._are_LongName) s.Add_OptSpaced("LongName"); + if (_arc._are_LongLink) s.Add_OptSpaced("LongLink"); + if (_arc._are_Pax) s.Add_OptSpaced("PAX"); + if (_arc._are_pax_path) s.Add_OptSpaced("path"); + if (_arc._are_pax_link) s.Add_OptSpaced("linkpath"); + if (_arc._are_mtime) s.Add_OptSpaced("mtime"); + if (_arc._are_atime) s.Add_OptSpaced("atime"); + if (_arc._are_ctime) s.Add_OptSpaced("ctime"); + if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR"); + s.Add_OptSpaced(_encodingCharacts.GetCharactsString()); + prop = s; break; } - } - prop.Detach(value); - return S_OK; -} -HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item) -{ - item.HeaderPos = _phySize; - EErrorType error; - HRESULT res = ReadItem(stream, filled, item, error); - if (error == k_ErrorType_Warning) - _warning = true; - else if (error != k_ErrorType_OK) - _error = error; - RINOK(res); - if (filled) - { - /* - if (item.IsSparse()) - _isSparse = true; - */ - if (item.IsPaxExtendedHeader()) - _thereIsPaxExtendedHeader = true; - if (item.IsThereWarning()) - _warning = true; + case kpidComment: + { + if (_arc.PaxGlobal_Defined) + { + AString s; + _arc.PaxGlobal.Print_To_String(s); + if (!s.IsEmpty()) + prop = s; + } + break; + } } - _phySize += item.HeaderSize; - _headersSize += item.HeaderSize; + prop.Detach(value); return S_OK; } @@ -199,16 +212,20 @@ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); } - _phySizeDefined = true; + _arc._phySize_Defined = true; // bool utf8_OK = true; + _arc.SeqStream = stream; + _arc.InStream = stream; + _arc.OpenCallback = callback; + + CItemEx item; for (;;) { - CItemEx item; - bool filled; - RINOK(ReadItem2(stream, filled, item)); - if (!filled) + _arc.NumFiles = _items.Size(); + RINOK(_arc.ReadItem(item)); + if (!_arc.filled) break; _isArc = true; @@ -228,10 +245,10 @@ _items.Add(item); - RINOK(stream->Seek((Int64)item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); - if (_phySize > endPos) + RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize)); + if (_arc._phySize > endPos) { - _error = k_ErrorType_UnexpectedEnd; + _arc._error = k_ErrorType_UnexpectedEnd; break; } /* @@ -241,6 +258,7 @@ break; } */ + /* if (callback) { if (_items.Size() == 1) @@ -249,10 +267,11 @@ } if ((_items.Size() & 0x3FF) == 0) { - UInt64 numFiles = _items.Size(); + const UInt64 numFiles = _items.Size(); RINOK(callback->SetCompleted(&numFiles, &_phySize)); } } + */ } /* @@ -266,7 +285,7 @@ if (_items.Size() == 0) { - if (_error != k_ErrorType_OK) + if (_arc._error != k_ErrorType_OK) { _isArc = false; return S_FALSE; @@ -294,6 +313,7 @@ STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback) { COM_TRY_BEGIN + // for (int i = 0; i < 10; i++) // for debug { Close(); RINOK(Open2(stream, openArchiveCallback)); @@ -314,16 +334,11 @@ STDMETHODIMP CHandler::Close() { _isArc = false; - _warning = false; - _error = k_ErrorType_OK; - _phySizeDefined = false; - _phySize = 0; - _headersSize = 0; + _arc.Clear(); + _curIndex = 0; _latestIsRead = false; - // _isSparse = false; - _thereIsPaxExtendedHeader = false; _encodingCharacts.Clear(); _items.Clear(); _seqStream.Release(); @@ -351,12 +366,12 @@ { if (_latestIsRead) { - UInt64 packSize = _latestItem.GetPackSizeAligned(); + const UInt64 packSize = _latestItem.Get_PackSize_Aligned(); RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); - _phySize += copyCoderSpec->TotalSize; + _arc._phySize += copyCoderSpec->TotalSize; if (copyCoderSpec->TotalSize != packSize) { - _error = k_ErrorType_UnexpectedEnd; + _arc._error = k_ErrorType_UnexpectedEnd; return S_FALSE; } _latestIsRead = false; @@ -364,11 +379,12 @@ } else { - bool filled; - RINOK(ReadItem2(_seqStream, filled, _latestItem)); - if (!filled) + _arc.SeqStream = _seqStream; + _arc.InStream = NULL; + RINOK(_arc.ReadItem(_latestItem)); + if (!_arc.filled) { - _phySizeDefined = true; + _arc._phySize_Defined = true; return E_INVALIDARG; } _latestIsRead = true; @@ -390,6 +406,69 @@ prop = dest; } + +static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop) +{ + UInt64 v; + if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v)) + return; + if (pt.Ns != 0) + v += pt.Ns / 100; + FILETIME ft; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, + k_PropVar_TimePrec_Base + pt.NumDigits, pt.Ns % 100); +} + + +#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10)))) + +static void AddByteToHex2(unsigned val, AString &s) +{ + unsigned t; + t = val >> 4; + s += ValToHex(t); + t = val & 0xF; + s += ValToHex(t); +} + +static void AddSpecCharToString(const char c, AString &s) +{ + if ((Byte)c <= 0x20 || (Byte)c > 127) + { + s += '['; + AddByteToHex2((Byte)(c), s); + s += ']'; + } + else + s += c; +} + +static void AddSpecUInt64(AString &s, const char *name, UInt64 v) +{ + if (v != 0) + { + s.Add_OptSpaced(name); + if (v > 1) + { + s += ':'; + s.Add_UInt64(v); + } + } +} + +static void AddSpecBools(AString &s, const char *name, bool b1, bool b2) +{ + if (b1) + { + s.Add_OptSpaced(name); + if (b2) + s += '*'; + } +} + + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -413,49 +492,189 @@ { case kpidPath: TarStringToUnicode(item->Name, prop, true); break; case kpidIsDir: prop = item->IsDir(); break; - case kpidSize: prop = item->GetUnpackSize(); break; - case kpidPackSize: prop = item->GetPackSizeAligned(); break; + case kpidSize: prop = item->Get_UnpackSize(); break; + case kpidPackSize: prop = item->Get_PackSize_Aligned(); break; case kpidMTime: - if (item->MTime != 0) + { + /* + // for debug: + PropVariant_SetFrom_UnixTime(prop, 1 << 30); + prop.wReserved1 = k_PropVar_TimePrec_Base + 1; + prop.wReserved2 = 12; + break; + */ + + if (item->PaxTimes.MTime.IsDefined()) + PaxTimeToProp(item->PaxTimes.MTime, prop); + else + // if (item->MTime != 0) { + // we allow (item->MTime == 0) FILETIME ft; - if (NTime::UnixTime64ToFileTime(item->MTime, ft)) - prop = ft; + if (NTime::UnixTime64_To_FileTime(item->MTime, ft)) + { + unsigned prec = k_PropVar_TimePrec_Unix; + if (item->MTime_IsBin) + { + /* we report here that it's Int64-UnixTime + instead of basic UInt32-UnixTime range */ + prec = k_PropVar_TimePrec_Base; + } + prop.SetAsTimeFrom_FT_Prec(ft, prec); + } } break; + } + case kpidATime: + if (item->PaxTimes.ATime.IsDefined()) + PaxTimeToProp(item->PaxTimes.ATime, prop); + break; + case kpidCTime: + if (item->PaxTimes.CTime.IsDefined()) + PaxTimeToProp(item->PaxTimes.CTime, prop); + break; case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break; - case kpidUser: TarStringToUnicode(item->User, prop); break; - case kpidGroup: TarStringToUnicode(item->Group, prop); break; - case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; - case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break; - // case kpidLinkType: prop = (int)item->LinkFlag; break; + + case kpidUser: + if (!item->User.IsEmpty()) + TarStringToUnicode(item->User, prop); + break; + case kpidGroup: + if (!item->Group.IsEmpty()) + TarStringToUnicode(item->Group, prop); + break; + + case kpidUserId: + // if (item->UID != 0) + prop = (UInt32)item->UID; + break; + case kpidGroupId: + // if (item->GID != 0) + prop = (UInt32)item->GID; + break; + + case kpidDeviceMajor: + if (item->DeviceMajor_Defined) + // if (item->DeviceMajor != 0) + prop = (UInt32)item->DeviceMajor; + break; + + case kpidDeviceMinor: + if (item->DeviceMinor_Defined) + // if (item->DeviceMinor != 0) + prop = (UInt32)item->DeviceMinor; + break; + /* + case kpidDevice: + if (item->DeviceMajor_Defined) + if (item->DeviceMinor_Defined) + prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor); + break; + */ + + case kpidSymLink: + if (item->Is_SymLink()) + if (!item->LinkName.IsEmpty()) + TarStringToUnicode(item->LinkName, prop); + break; + case kpidHardLink: + if (item->Is_HardLink()) + if (!item->LinkName.IsEmpty()) + TarStringToUnicode(item->LinkName, prop); + break; + case kpidCharacts: { - AString s = item->EncodingCharacts.GetCharactsString(); - if (item->IsThereWarning()) + AString s; { s.Add_Space_if_NotEmpty(); - s += "HEADER_ERROR"; + AddSpecCharToString(item->LinkFlag, s); } - prop = s; + if (item->IsMagic_GNU()) + s.Add_OptSpaced("GNU"); + else if (item->IsMagic_Posix_ustar_00()) + s.Add_OptSpaced("POSIX"); + else + { + s.Add_Space_if_NotEmpty(); + for (unsigned i = 0; i < sizeof(item->Magic); i++) + AddSpecCharToString(item->Magic[i], s); + } + + if (item->IsSignedChecksum) + s.Add_OptSpaced("SignedChecksum"); + + if (item->Prefix_WasUsed) + s.Add_OptSpaced(k_Characts_Prefix); + + s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString()); + + // AddSpecUInt64(s, "LongName", item->Num_LongName_Records); + // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records); + AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2); + AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2); + + if (item->MTime_IsBin) + s.Add_OptSpaced("bin_mtime"); + if (item->PackSize_IsBin) + s.Add_OptSpaced("bin_psize"); + if (item->Size_IsBin) + s.Add_OptSpaced("bin_size"); + + AddSpecUInt64(s, "PAX", item->Num_Pax_Records); + + if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime"); + if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime"); + if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime"); + + if (item->pax_path_WasUsed) + s.Add_OptSpaced("pax_path"); + if (item->pax_link_WasUsed) + s.Add_OptSpaced("pax_linkpath"); + if (item->pax_size_WasUsed) + s.Add_OptSpaced("pax_size"); + + if (item->IsThereWarning()) + s.Add_OptSpaced("WARNING"); + if (item->HeaderError) + s.Add_OptSpaced("ERROR"); + if (item->Pax_Error) + s.Add_OptSpaced("PAX_error"); + if (!item->PaxExtra.RawLines.IsEmpty()) + s.Add_OptSpaced("PAX_unsupported_line"); + if (item->Pax_Overflow) + s.Add_OptSpaced("PAX_overflow"); + if (!s.IsEmpty()) + prop = s; break; } + case kpidComment: + { + AString s; + item->PaxExtra.Print_To_String(s); + if (!s.IsEmpty()) + prop = s; + break; + } + // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug + // case kpidOffset: prop = item->HeaderPos; break; // for debug } prop.Detach(value); return S_OK; COM_TRY_END } + HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN ISequentialInStream *stream = _seqStream; - bool seqMode = (_stream == NULL); + const bool seqMode = (_stream == NULL); if (!seqMode) stream = _stream; - bool allFilesMode = (numItems == (UInt32)(Int32)-1); + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (_stream && numItems == 0) @@ -463,7 +682,7 @@ UInt64 totalSize = 0; UInt32 i; for (i = 0; i < numItems; i++) - totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize(); + totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize(); extractCallback->SetTotal(totalSize); UInt64 totalPackSize; @@ -503,9 +722,9 @@ item = &_items[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - UInt64 unpackSize = item->GetUnpackSize(); + const UInt64 unpackSize = item->Get_UnpackSize(); totalSize += unpackSize; - totalPackSize += item->GetPackSizeAligned(); + totalPackSize += item->Get_PackSize_Aligned(); if (item->IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); @@ -539,7 +758,7 @@ Int32 opRes = NExtract::NOperationResult::kOK; CMyComPtr inStream2; - if (!item->IsSparse()) + if (!item->Is_Sparse()) inStream2 = inStream; else { @@ -549,7 +768,7 @@ } { - if (item->IsSymLink()) + if (item->Is_SymLink()) { RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())); } @@ -557,9 +776,9 @@ { if (!seqMode) { - RINOK(_stream->Seek((Int64)item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + RINOK(_stream->Seek((Int64)item->Get_DataPos(), STREAM_SEEK_SET, NULL)); } - streamSpec->Init(item->GetPackSizeAligned()); + streamSpec->Init(item->Get_PackSize_Aligned()); RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress)); } if (outStreamSpec->GetRem() != 0) @@ -628,7 +847,7 @@ unsigned left = 0, right = item.SparseBlocks.Size(); for (;;) { - unsigned mid = (left + right) / 2; + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); if (mid == left) break; if (_virtPos < item.SparseBlocks[mid].Offset) @@ -648,7 +867,7 @@ UInt64 phyPos = PhyOffsets[left] + relat; if (_needStartSeek || _phyPos != phyPos) { - RINOK(Handler->_stream->Seek((Int64)(item.GetDataPosition() + phyPos), STREAM_SEEK_SET, NULL)); + RINOK(Handler->_stream->Seek((Int64)(item.Get_DataPos() + phyPos), STREAM_SEEK_SET, NULL)); _needStartSeek = false; _phyPos = phyPos; } @@ -698,7 +917,7 @@ const CItemEx &item = _items[index]; - if (item.IsSparse()) + if (item.Is_Sparse()) { CSparseStream *streamSpec = new CSparseStream; CMyComPtr streamTemp = streamSpec; @@ -718,24 +937,30 @@ return S_OK; } - if (item.IsSymLink()) + if (item.Is_SymLink()) { Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); return S_OK; } - return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); + return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream); COM_TRY_END } + void CHandler::Init() { _forceCodePage = false; _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; - _thereIsPaxExtendedHeader = false; + _posixMode = false; + _posixMode_WasForced = false; + // TimeOptions.Clear(); + _handlerTimeOptions.Init(); + // _handlerTimeOptions.Write_MTime.Val = true; // it's default already } + STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { Init(); @@ -768,8 +993,54 @@ else if (name.IsPrefixedBy_Ascii_NoCase("memuse")) { } + else if (name.IsEqualTo("m")) + { + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + const UString s = prop.bstrVal; + if (s.IsEqualTo_Ascii_NoCase("pax") || + s.IsEqualTo_Ascii_NoCase("posix")) + _posixMode = true; + else if (s.IsEqualTo_Ascii_NoCase("gnu")) + _posixMode = false; + else + return E_INVALIDARG; + _posixMode_WasForced = true; + } else + { + /* + if (name.IsPrefixedBy_Ascii_NoCase("td")) + { + name.Delete(0, 3); + if (prop.vt == VT_EMPTY) + { + if (name.IsEqualTo_Ascii_NoCase("n")) + { + // TimeOptions.UseNativeDigits = true; + } + else if (name.IsEqualTo_Ascii_NoCase("r")) + { + // TimeOptions.RemoveZeroDigits = true; + } + else + return E_INVALIDARG; + } + else + { + UInt32 numTimeDigits = 0; + RINOK(ParsePropToUInt32(name, prop, numTimeDigits)); + TimeOptions.NumDigits_WasForced = true; + TimeOptions.NumDigits = numTimeDigits; + } + } + */ + bool processed = false; + RINOK(_handlerTimeOptions.Parse(name, prop, processed)); + if (processed) + continue; return E_INVALIDARG; + } } return S_OK; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHandler.h 7zip-22.01/CPP/7zip/Archive/Tar/TarHandler.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHandler.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarHandler.h 2022-03-22 10:00:00.000000000 +0000 @@ -9,7 +9,7 @@ #include "../../Compress/CopyCoder.h" -#include "../IArchive.h" +#include "../Common/HandlerOut.h" #include "TarIn.h" @@ -29,31 +29,26 @@ CMyComPtr _stream; CMyComPtr _seqStream; private: - UInt32 _curIndex; - bool _latestIsRead; - CItemEx _latestItem; - - UInt64 _phySize; - UInt64 _headersSize; - bool _phySizeDefined; - EErrorType _error; - bool _warning; bool _isArc; - - // bool _isSparse; - bool _thereIsPaxExtendedHeader; - + bool _posixMode_WasForced; + bool _posixMode; bool _forceCodePage; UInt32 _specifiedCodePage; UInt32 _curCodePage; UInt32 _openCodePage; - + // CTimeOptions TimeOptions; + CHandlerTimeOptions _handlerTimeOptions; CEncodingCharacts _encodingCharacts; + UInt32 _curIndex; + bool _latestIsRead; + CItemEx _latestItem; + + CArchive _arc; + NCompress::CCopyCoder *copyCoderSpec; CMyComPtr copyCoder; - HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo); HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); HRESULT SkipTo(UInt32 index); void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHandlerOut.cpp 7zip-22.01/CPP/7zip/Archive/Tar/TarHandlerOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHandlerOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarHandlerOut.cpp 2022-03-27 13:00:00.000000000 +0000 @@ -2,15 +2,16 @@ #include "StdAfx.h" +// #include + #include "../../../Common/ComTry.h" -#include "../../../Common/Defs.h" #include "../../../Common/MyLinux.h" #include "../../../Common/StringConvert.h" -#include "../../../Common/UTFConvert.h" -#include "../../../Windows/PropVariant.h" #include "../../../Windows/TimeUtils.h" +#include "../Common/ItemNameUtils.h" + #include "TarHandler.h" #include "TarUpdate.h" @@ -21,10 +22,35 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) { - *type = NFileTimeType::kUnix; + UInt32 t = NFileTimeType::kUnix; + const UInt32 prec = _handlerTimeOptions.Prec; + if (prec != (UInt32)(Int32)-1) + { + t = NFileTimeType::kWindows; + if (prec == k_PropVar_TimePrec_0 || + prec == k_PropVar_TimePrec_100ns) + t = NFileTimeType::kWindows; + else if (prec == k_PropVar_TimePrec_HighPrec) + t = k_PropVar_TimePrec_1ns; + else if (prec >= k_PropVar_TimePrec_Base) + t = prec; + } + // 7-Zip before 22.00 fails, if unknown typeType. + *type = t; return S_OK; } + +void Get_AString_From_UString(const UString &s, AString &res, + UINT codePage, unsigned utfFlags) +{ + if (codePage == CP_UTF8) + ConvertUnicodeToUTF8_Flags(s, res, utfFlags); + else + UnicodeStringToMultiByte2(res, s, codePage); +} + + HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, UINT codePage, unsigned utfFlags, bool convertSlash) { @@ -36,14 +62,7 @@ UString s = prop.bstrVal; if (convertSlash) NItemName::ReplaceSlashes_OsToUnix(s); - - if (codePage == CP_UTF8) - { - ConvertUnicodeToUTF8_Flags(s, res, utfFlags); - // if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG; - } - else - UnicodeStringToMultiByte2(res, s, codePage); + Get_AString_From_UString(s, res, codePage, utfFlags); } else if (prop.vt != VT_EMPTY) return E_INVALIDARG; @@ -70,12 +89,106 @@ } +static HRESULT GetTime(UInt32 i, UInt32 pid, IArchiveUpdateCallback *callback, + CPaxTime &pt) +{ + pt.Clear(); + NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pid, &prop)); + return Prop_To_PaxTime(prop, pt); +} + + +/* +static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i, + UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined) +{ + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, kpidDevice, &prop)); + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt != VT_UI8) + return E_INVALIDARG; + { + const UInt64 v = prop.uhVal.QuadPart; + majo = MY_dev_major(v); + mino = MY_dev_minor(v); + majo_defined = true; + mino_defined = true; + } + return S_OK; +} +*/ + +static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i, + UInt32 pid, UInt32 &id, bool &defined) +{ + defined = false; + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pid, &prop)); + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt == VT_UI4) + { + id = prop.ulVal; + defined = true; + return S_OK; + } + return E_INVALIDARG; +} + + +static HRESULT GetUser(IArchiveUpdateCallback *callback, UInt32 i, + UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id, + UINT codePage, unsigned utfFlags) +{ + // printf("\ncallback->GetProperty(i, pidId, &prop))\n"); + + bool isSet = false; + { + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pidId, &prop)); + if (prop.vt == VT_UI4) + { + isSet = true; + id = prop.ulVal; + // printf("\ncallback->GetProperty(i, pidId, &prop)); = %d \n", (unsigned)id); + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + { + NWindows::NCOM::CPropVariant prop; + RINOK(callback->GetProperty(i, pidName, &prop)); + if (prop.vt == VT_BSTR) + { + const UString s = prop.bstrVal; + Get_AString_From_UString(s, name, codePage, utfFlags); + if (!isSet) + id = 0; + } + else if (prop.vt == VT_UI4) + { + id = prop.ulVal; + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + + + STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *callback) { COM_TRY_BEGIN - if ((_stream && (_error != k_ErrorType_OK || _warning /* || _isSparse */)) || _seqStream) + if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning + /* || _isSparse */ + )) || _seqStream) return E_NOTIMPL; CObjectVector updateItems; const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); @@ -131,25 +244,30 @@ else ui.Mode = prop.ulVal; // 21.07 : we clear high file type bits as GNU TAR. - ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; + // we will clear it later + // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT; } - { - NCOM::CPropVariant prop; - RINOK(callback->GetProperty(i, kpidMTime, &prop)); - if (prop.vt == VT_EMPTY) - ui.MTime = 0; - else if (prop.vt != VT_FILETIME) - return E_INVALIDARG; - else - ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime); - } - + if (_handlerTimeOptions.Write_MTime.Val) + RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime)) + if (_handlerTimeOptions.Write_ATime.Val) + RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime)) + if (_handlerTimeOptions.Write_CTime.Val) + RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime)) + RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true)); if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') ui.Name += '/'; - RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage, utfFlags, false)); - RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage, utfFlags, false)); + // ui.Name += '/'; // for debug + + if (_posixMode) + { + RINOK(GetDevice(callback, i, kpidDeviceMajor, ui.DeviceMajor, ui.DeviceMajor_Defined)); + RINOK(GetDevice(callback, i, kpidDeviceMinor, ui.DeviceMinor, ui.DeviceMinor_Defined)); + } + + RINOK(GetUser(callback, i, kpidUser, kpidUserId, ui.User, ui.UID, codePage, utfFlags)); + RINOK(GetUser(callback, i, kpidGroup, kpidGroupId, ui.Group, ui.GID, codePage, utfFlags)); } if (IntToBool(newData)) @@ -169,13 +287,44 @@ updateItems.Add(ui); } - if (_thereIsPaxExtendedHeader) + if (_arc._are_Pax_Items) { - // we restore original order of files, if there is pax header block + // we restore original order of files, if there are pax items updateItems.Sort(CompareUpdateItems, NULL); } + + CUpdateOptions options; + + options.CodePage = codePage; + options.UtfFlags = utfFlags; + options.PosixMode = _posixMode; + + options.Write_MTime = _handlerTimeOptions.Write_MTime; + options.Write_ATime = _handlerTimeOptions.Write_ATime; + options.Write_CTime = _handlerTimeOptions.Write_CTime; - return UpdateArchive(_stream, outStream, _items, updateItems, codePage, utfFlags, callback); + // options.TimeOptions = TimeOptions; + + const UInt32 prec = _handlerTimeOptions.Prec; + if (prec != (UInt32)(Int32)-1) + { + unsigned numDigits = 0; + if (prec == 0) + numDigits = 7; + else if (prec == k_PropVar_TimePrec_HighPrec + || prec >= k_PropVar_TimePrec_1ns) + numDigits = 9; + else if (prec >= k_PropVar_TimePrec_Base) + numDigits = prec - k_PropVar_TimePrec_Base; + options.TimeOptions.NumDigitsMax = numDigits; + // options.TimeOptions.RemoveZeroMode = + // k_PaxTimeMode_DontRemoveZero; // pure for debug + // k_PaxTimeMode_RemoveZero_if_PureSecondOnly; // optimized code + // k_PaxTimeMode_RemoveZero_Always; // original pax code + } + + return UpdateArchive(_stream, outStream, _items, updateItems, + options, callback); COM_TRY_END } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHeader.cpp 7zip-22.01/CPP/7zip/Archive/Tar/TarHeader.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHeader.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarHeader.cpp 2022-03-21 11:00:00.000000000 +0000 @@ -18,9 +18,82 @@ // const char * const kGNUTar = "GNUtar "; // 7 chars and a null // const char * const kEmpty = "\0\0\0\0\0\0\0\0"; // 7-Zip used kUsTar_00 before 21.07: - // const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; + const char k_Posix_ustar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ; // GNU TAR uses such header: - const char kUsTar_GNU[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ; + const char k_GNU_ustar__[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ; } +/* +pre-POSIX.1-1988 (i.e. v7) tar header: +----- +Link indicator: +'0' or 0 : Normal file +'1' : Hard link +'2' : Symbolic link +Some pre-POSIX.1-1988 tar implementations indicated a directory by having +a trailing slash (/) in the name. + +Numeric values : octal with leading zeroes. +For historical reasons, a final NUL or space character should also be used. +Thus only 11 octal digits can be stored from 12 bytes field. + +2001 star : introduced a base-256 coding that is indicated by +setting the high-order bit of the leftmost byte of a numeric field. +GNU-tar and BSD-tar followed this idea. + +versions of tar from before the first POSIX standard from 1988 +pad the values with spaces instead of zeroes. + +UStar +----- +UStar (Unix Standard TAR) : POSIX IEEE P1003.1 : 1988. + 257 signature: "ustar", 0, "00" + 265 32 Owner user name + 297 32 Owner group name + 329 8 Device major number + 337 8 Device minor number + 345 155 Filename prefix + +POSIX.1-2001/pax +---- +format is known as extended tar format or pax format +vendor-tagged vendor-specific enhancements. +tags Defined by the POSIX standard: + atime, mtime, path, linkpath, uname, gname, size, uid, gid, ... + + +PAX EXTENSION +----------- +Hard links +A further difference from the ustar header block is that data blocks +for files of typeflag 1 (hard link) may be included, +which means that the size field may be greater than zero. +Archives created by pax -o linkdata shall include these data +blocks with the hard links. +* + +compatiblity +------------ + 7-Zip 16.03 supports "PaxHeader/" + 7-Zip 20.01 supports "PaxHeaders.X/" with optional "./" + 7-Zip 21.02 supports "@PaxHeader" with optional "./" "./" + + GNU tar --format=posix uses "PaxHeaders/" in folder of file + + +GNU TAR format +============== +v7 - Unix V7 +oldgnu - GNU tar <=1.12 : writes zero in last character in name +gnu - GNU tar 1.13 : doesn't write zero in last character in name + as 7-zip 21.07 +ustar - POSIX.1-1988 +posix (pax) - POSIX.1-2001 + + gnu tar: + if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) { + major_t devmajor = major (st->stat.st_rdev); + minor_t devminor = minor (st->stat.st_rdev); } +*/ + }}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHeader.h 7zip-22.01/CPP/7zip/Archive/Tar/TarHeader.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarHeader.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarHeader.h 2022-03-21 11:00:00.000000000 +0000 @@ -59,6 +59,9 @@ const char kGnu_LongName = 'L'; const char kSparse = 'S'; const char kLabel = 'V'; + const char kPax = 'x'; // Extended header with meta data for the next file in the archive (POSIX.1-2001) + const char kPax_2 = 'X'; + const char kGlobal = 'g'; // Global extended header with meta data (POSIX.1-2001) const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR. data: list of files created by the --incremental (-G) option Each file name is preceded by either @@ -66,6 +69,7 @@ - 'N' (file is a directory, or is not stored in the archive.) Each file name is terminated by a null + an additional null after the last file name. */ + // 'A'-'Z' Vendor specific extensions (POSIX.1-1988) } extern const char * const kLongLink; // = "././@LongLink"; @@ -76,8 +80,8 @@ // extern const char * const kUsTar; // = "ustar"; // 5 chars // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0" - // extern const char kUsTar_00[8]; - extern const char kUsTar_GNU[8]; + extern const char k_Posix_ustar_00[8]; + extern const char k_GNU_ustar__[8]; } } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarIn.cpp 7zip-22.01/CPP/7zip/Archive/Tar/TarIn.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarIn.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarIn.cpp 2022-03-02 11:00:00.000000000 +0000 @@ -12,6 +12,45 @@ #include "TarIn.h" +#define NUM_UNROLL_BYTES (8 * 4) + +MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size); +MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size) +{ + const Byte *p = (const Byte *)data; + + for (; size != 0 && ((unsigned)(ptrdiff_t)p & (NUM_UNROLL_BYTES - 1)) != 0; size--) + if (*p++ != 0) + return true; + + if (size >= NUM_UNROLL_BYTES) + { + const Byte *lim = p + size; + size &= (NUM_UNROLL_BYTES - 1); + lim -= size; + do + { + if (*(const UInt64 *)(const void *)(p ) != 0) return true; + if (*(const UInt64 *)(const void *)(p + 8 * 1) != 0) return true; + if (*(const UInt64 *)(const void *)(p + 8 * 2) != 0) return true; + if (*(const UInt64 *)(const void *)(p + 8 * 3) != 0) return true; + // if (*(const UInt32 *)(const void *)(p ) != 0) return true; + // if (*(const UInt32 *)(const void *)(p + 4 * 1) != 0) return true; + // if (*(const UInt32 *)(const void *)(p + 4 * 2) != 0) return true; + // if (*(const UInt32 *)(const void *)(p + 4 * 3) != 0) return true; + p += NUM_UNROLL_BYTES; + } + while (p != lim); + } + + for (; size != 0; size--) + if (*p++ != 0) + return true; + + return false; +} + + namespace NArchive { namespace NTar { @@ -41,10 +80,11 @@ return (*end == ' ' || *end == 0); } -static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, bool allowEmpty = false) +static bool OctalToNumber32(const char *srcString, UInt32 &res, bool allowEmpty = false) { + const unsigned kSize = 8; UInt64 res64; - if (!OctalToNumber(srcString, size, res64, allowEmpty)) + if (!OctalToNumber(srcString, kSize, res64, allowEmpty)) return false; res = (UInt32)res64; return (res64 <= 0xFFFFFFFF); @@ -52,68 +92,61 @@ #define RIF(x) { if (!(x)) return S_OK; } -/* -static bool IsEmptyData(const char *buf, size_t size) -{ - for (unsigned i = 0; i < size; i++) - if (buf[i] != 0) - return false; - return true; -} -*/ - -static bool IsRecordLast(const char *buf) -{ - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) - if (buf[i] != 0) - return false; - return true; -} - static void ReadString(const char *s, unsigned size, AString &result) { result.SetFrom_CalcLen(s, size); } -static bool ParseInt64(const char *p, Int64 &val) +static bool ParseInt64(const char *p, Int64 &val, bool &isBin) { - UInt32 h = GetBe32(p); + const UInt32 h = GetBe32(p); val = (Int64)GetBe64(p + 4); + isBin = true; if (h == (UInt32)1 << 31) return ((val >> 63) & 1) == 0; if (h == (UInt32)(Int32)-1) return ((val >> 63) & 1) != 0; - UInt64 uv; - bool res = OctalToNumber(p, 12, uv); - val = (Int64)uv; + isBin = false; + UInt64 u; + const bool res = OctalToNumber(p, 12, u); + val = (Int64)u; return res; } -static bool ParseInt64_MTime(const char *p, Int64 &val) +static bool ParseInt64_MTime(const char *p, Int64 &val, bool &isBin) { // rare case tar : ZEROs in Docker-Windows TARs // rare case tar : spaces + isBin = false; if (GetUi32(p) != 0) for (unsigned i = 0; i < 12; i++) if (p[i] != ' ') - return ParseInt64(p, val); + return ParseInt64(p, val, isBin); val = 0; return true; } -static bool ParseSize(const char *p, UInt64 &val) +static bool ParseSize(const char *p, UInt64 &val, bool &isBin) { if (GetBe32(p) == (UInt32)1 << 31) { // GNU extension + isBin = true; val = GetBe64(p + 4); return ((val >> 63) & 1) == 0; } + isBin = false; return OctalToNumber(p, 12, val, true // 20.03: allow empty size for 'V' Label entry ); } +static bool ParseSize(const char *p, UInt64 &val) +{ + bool isBin; + return ParseSize(p, val, isBin); +} + #define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; } API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size) @@ -126,26 +159,27 @@ UInt32 mode; // we allow empty Mode value for LongName prefix items - CHECK(OctalToNumber32(p, 8, mode, true)); p += 8; + CHECK(OctalToNumber32(p, mode, true)); p += 8; - // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; + // if (!OctalToNumber32(p, item.UID)) item.UID = 0; p += 8; - // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; + // if (!OctalToNumber32(p, item.GID)) item.GID = 0; p += 8; UInt64 packSize; Int64 time; UInt32 checkSum; - CHECK(ParseSize(p, packSize)); p += 12; - CHECK(ParseInt64_MTime(p, time)); p += 12; - CHECK(OctalToNumber32(p, 8, checkSum)); + bool isBin; + CHECK(ParseSize(p, packSize, isBin)); p += 12; + CHECK(ParseInt64_MTime(p, time, isBin)); p += 12; + CHECK(OctalToNumber32(p, checkSum)); return k_IsArc_Res_YES; } -static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) + +HRESULT CArchive::GetNextItemReal(CItemEx &item) { char buf[NFileHeader::kRecordSize]; - char *p = buf; error = k_ErrorType_OK; filled = false; @@ -154,7 +188,7 @@ for (;;) { size_t processedSize = NFileHeader::kRecordSize; - RINOK(ReadStream(stream, buf, &processedSize)); + RINOK(ReadStream(SeqStream, buf, &processedSize)); if (processedSize == 0) { if (!thereAreEmptyRecords) @@ -180,10 +214,14 @@ return S_OK; } - if (!IsRecordLast(buf)) + if (IsBufNonZero(buf, NFileHeader::kRecordSize)) break; item.HeaderSize += NFileHeader::kRecordSize; thereAreEmptyRecords = true; + if (OpenCallback) + { + RINOK(Progress(item, 0)); + } } if (thereAreEmptyRecords) { @@ -191,52 +229,69 @@ return S_OK; } + char *p = buf; + error = k_ErrorType_Corrupted; - ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize; - item.NameCouldBeReduced = + + // ReadString(p, NFileHeader::kNameSize, item.Name); + p += NFileHeader::kNameSize; + + /* + item.Name_CouldBeReduced = (item.Name.Len() == NFileHeader::kNameSize || item.Name.Len() == NFileHeader::kNameSize - 1); + */ // we allow empty Mode value for LongName prefix items - RIF(OctalToNumber32(p, 8, item.Mode, true)); p += 8; + RIF(OctalToNumber32(p, item.Mode, true)); p += 8; - if (!OctalToNumber32(p, 8, item.UID)) { item.UID = 0; } p += 8; - if (!OctalToNumber32(p, 8, item.GID)) { item.GID = 0; } p += 8; + if (!OctalToNumber32(p, item.UID)) { item.UID = 0; } p += 8; + if (!OctalToNumber32(p, item.GID)) { item.GID = 0; } p += 8; - RIF(ParseSize(p, item.PackSize)); + RIF(ParseSize(p, item.PackSize, item.PackSize_IsBin)); item.Size = item.PackSize; + item.Size_IsBin = item.PackSize_IsBin; p += 12; - RIF(ParseInt64_MTime(p, item.MTime)); p += 12; + RIF(ParseInt64_MTime(p, item.MTime, item.MTime_IsBin)); p += 12; UInt32 checkSum; - RIF(OctalToNumber32(p, 8, checkSum)); + RIF(OctalToNumber32(p, checkSum)); memset(p, ' ', 8); p += 8; item.LinkFlag = *p++; ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize; - item.LinkNameCouldBeReduced = + + /* + item.LinkName_CouldBeReduced = (item.LinkName.Len() == NFileHeader::kNameSize || item.LinkName.Len() == NFileHeader::kNameSize - 1); + */ memcpy(item.Magic, p, 8); p += 8; ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize; ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize; - item.DeviceMajorDefined = (p[0] != 0); if (item.DeviceMajorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMajor)); } p += 8; - item.DeviceMinorDefined = (p[0] != 0); if (item.DeviceMinorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMinor)); } p += 8; + item.DeviceMajor_Defined = (p[0] != 0); if (item.DeviceMajor_Defined) { RIF(OctalToNumber32(p, item.DeviceMajor)); } p += 8; + item.DeviceMinor_Defined = (p[0] != 0); if (item.DeviceMinor_Defined) { RIF(OctalToNumber32(p, item.DeviceMinor)); } p += 8; - if (p[0] != 0) + if (p[0] != 0 + && item.IsMagic_ustar_5chars() + && (item.LinkFlag != 'L' )) { - AString prefix; - ReadString(p, NFileHeader::kPrefixSize, prefix); - if (!prefix.IsEmpty() - && item.IsUstarMagic() - && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ )) - item.Name = prefix + '/' + item.Name; + item.Prefix_WasUsed = true; + ReadString(p, NFileHeader::kPrefixSize, item.Name); + item.Name += '/'; + unsigned i; + for (i = 0; i < NFileHeader::kNameSize; i++) + if (buf[i] == 0) + break; + item.Name.AddFrom(buf, i); } - + else + ReadString(buf, NFileHeader::kNameSize, item.Name); + p += NFileHeader::kPrefixSize; if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink) @@ -255,22 +310,25 @@ /* TAR standard requires sum of unsigned byte values. - But some TAR programs use sum of signed byte values. + But some old TAR programs use sum of signed byte values. So we check both values. */ - UInt32 checkSumReal = 0; - Int32 checkSumReal_Signed = 0; - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + // for (int y = 0; y < 100; y++) // for debug { - char c = buf[i]; - checkSumReal_Signed += (signed char)c; - checkSumReal += (Byte)buf[i]; - } - - if (checkSumReal != checkSum) - { - if ((UInt32)checkSumReal_Signed != checkSum) - return S_OK; + UInt32 sum0 = 0; + { + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + sum0 += (Byte)buf[i]; + } + if (sum0 != checkSum) + { + Int32 sum = 0; + for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) + sum += (signed char)buf[i]; + if ((UInt32)sum != checkSum) + return S_OK; + item.IsSignedChecksum = true; + } } item.HeaderSize += NFileHeader::kRecordSize; @@ -280,7 +338,7 @@ Byte isExtended = (Byte)buf[482]; if (isExtended != 0 && isExtended != 1) return S_OK; - RIF(ParseSize(buf + 483, item.Size)); + RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin)); UInt64 min = 0; for (unsigned i = 0; i < 4; i++) { @@ -309,7 +367,7 @@ while (isExtended != 0) { size_t processedSize = NFileHeader::kRecordSize; - RINOK(ReadStream(stream, buf, &processedSize)); + RINOK(ReadStream(SeqStream, buf, &processedSize)); if (processedSize != NFileHeader::kRecordSize) { error = k_ErrorType_UnexpectedEnd; @@ -317,6 +375,12 @@ } item.HeaderSize += NFileHeader::kRecordSize; + + if (OpenCallback) + { + RINOK(Progress(item, 0)); + } + isExtended = (Byte)buf[21 * 24]; if (isExtended != 0 && isExtended != 1) return S_OK; @@ -346,172 +410,711 @@ return S_OK; } + if (item.PackSize >= (UInt64)1 << 63) + return S_OK; + filled = true; error = k_ErrorType_OK; return S_OK; } -static HRESULT ReadDataToString(ISequentialInStream *stream, CItemEx &item, AString &s, EErrorType &error) +HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset) { - const unsigned packSize = (unsigned)item.GetPackSizeAligned(); - size_t processedSize = packSize; - HRESULT res = ReadStream(stream, s.GetBuf(packSize), &processedSize); - item.HeaderSize += (unsigned)processedSize; - s.ReleaseBuf_CalcLen((unsigned)item.PackSize); - RINOK(res); - if (processedSize != packSize) - error = k_ErrorType_UnexpectedEnd; + const UInt64 pos = item.Get_DataPos() + posOffset; + if (NumFiles - NumFiles_Prev < (1 << 16) + // && NumRecords - NumRecords_Prev < (1 << 16) + && pos - Pos_Prev < ((UInt32)1 << 28)) + return S_OK; + { + Pos_Prev = pos; + NumFiles_Prev = NumFiles; + // NumRecords_Prev = NumRecords; + // Sleep(100); // for debug + return OpenCallback->SetCompleted(&NumFiles, &pos); + } +} + + +HRESULT CArchive::ReadDataToBuffer(const CItemEx &item, + CTempBuffer &tb, size_t stringLimit) +{ + tb.Init(); + UInt64 packSize = item.Get_PackSize_Aligned(); + if (packSize == 0) + return S_OK; + + UInt64 pos; + + { + size_t size = stringLimit; + if (size > packSize) + size = (size_t)packSize; + tb.Buffer.AllocAtLeast(size); + size_t processedSize = size; + const HRESULT res = ReadStream(SeqStream, tb.Buffer, &processedSize); + pos = processedSize; + if (processedSize != size) + { + error = k_ErrorType_UnexpectedEnd; + return res; + } + RINOK(res); + + packSize -= size; + + size_t i; + const Byte *p = tb.Buffer; + for (i = 0; i < size; i++) + if (p[i] == 0) + break; + if (i >= item.PackSize) + tb.StringSize_IsConfirmed = true; + if (i > item.PackSize) + { + tb.StringSize = (size_t)item.PackSize; + tb.IsNonZeroTail = true; + } + else + { + tb.StringSize = i; + if (i != size) + { + tb.StringSize_IsConfirmed = true; + if (IsBufNonZero(p + i, size - i)) + tb.IsNonZeroTail = true; + } + } + + if (packSize == 0) + return S_OK; + } + + if (InStream) + { + RINOK(InStream->Seek((Int64)packSize, STREAM_SEEK_CUR, NULL)); + return S_OK; + } + const unsigned kBufSize = 1 << 15; + Buffer.AllocAtLeast(kBufSize); + + do + { + if (OpenCallback) + { + RINOK(Progress(item, pos)); + } + + unsigned size = kBufSize; + if (size > packSize) + size = (unsigned)packSize; + size_t processedSize = size; + const HRESULT res = ReadStream(SeqStream, Buffer, &processedSize); + if (processedSize != size) + { + error = k_ErrorType_UnexpectedEnd; + return res; + } + if (!tb.IsNonZeroTail) + { + if (IsBufNonZero(Buffer, size)) + tb.IsNonZeroTail = true; + } + packSize -= size; + pos += size; + } + while (packSize != 0); return S_OK; } + + -static bool ParsePaxLongName(const AString &src, AString &dest) +struct CPaxInfo: public CPaxTimes { - dest.Empty(); - for (unsigned pos = 0;;) + bool DoubleTagError; + bool TagParsingError; + bool UnknownLines_Overflow; + bool Size_Defined; + bool UID_Defined; + bool GID_Defined; + bool Path_Defined; + bool Link_Defined; + bool User_Defined; + bool Group_Defined; + + UInt64 Size; + UInt32 UID; + UInt32 GID; + + AString Path; + AString Link; + AString User; + AString Group; + AString UnknownLines; + + bool ParseID(const AString &val, bool &defined, UInt32 &res) { - if (pos >= src.Len()) + if (defined) + DoubleTagError = true; + if (val.IsEmpty()) return false; - const char *start = src.Ptr(pos); - const char *end; - const UInt32 lineLen = ConvertStringToUInt32(start, &end); - if (end == start) + const char *end2; + res = ConvertStringToUInt32(val.Ptr(), &end2); + if (*end2 != 0) return false; - if (*end != ' ') + defined = true; + return true; + } + + bool ParsePax(const CTempBuffer &tb, bool isFile); +}; + + +static bool ParsePaxTime(const AString &src, CPaxTime &pt, bool &doubleTagError) +{ + if (pt.IsDefined()) + doubleTagError = true; + pt.Clear(); + const char *s = src.Ptr(); + bool isNegative = false; + if (*s == '-') + { + isNegative = true; + s++; + } + const char *end; + { + UInt64 sec = ConvertStringToUInt64(s, &end); + if (s == end) return false; - if (lineLen > src.Len() - pos) + if (sec >= ((UInt64)1 << 63)) return false; - unsigned offset = (unsigned)(end - start) + 1; - if (lineLen < offset) + if (isNegative) + sec = -(Int64)sec; + pt.Sec = sec; + } + if (*end == 0) + { + pt.Ns = 0; + pt.NumDigits = 0; + return true; + } + if (*end != '.') + return false; + s = end + 1; + + UInt32 ns = 0; + unsigned i; + const unsigned kNsDigits = 9; + for (i = 0;; i++) + { + const char c = s[i]; + if (c == 0) + break; + if (c < '0' || c > '9') return false; - if (IsString1PrefixedByString2(src.Ptr(pos + offset), "path=")) + // we ignore digits after 9 digits as GNU TAR + if (i < kNsDigits) + { + ns *= 10; + ns += c - '0'; + } + } + pt.NumDigits = (i < kNsDigits ? i : kNsDigits); + while (i < kNsDigits) + { + ns *= 10; + i++; + } + if (isNegative && ns != 0) + { + pt.Sec--; + ns = (UInt32)1000 * 1000 * 1000 - ns; + } + pt.Ns = ns; + return true; +} + + +bool CPaxInfo::ParsePax(const CTempBuffer &tb, bool isFile) +{ + DoubleTagError = false; + TagParsingError = false; + UnknownLines_Overflow = false; + Size_Defined = false; + UID_Defined = false; + GID_Defined = false; + Path_Defined = false; + Link_Defined = false; + User_Defined = false; + Group_Defined = false; + + // CPaxTimes::Clear(); + + const char *s = (const char *)(const void *)(const Byte *)tb.Buffer; + size_t rem = tb.StringSize; + + Clear(); + + AString name, val; + + while (rem != 0) + { + unsigned i; + for (i = 0;; i++) { - offset += 5; // "path=" - dest = src.Mid(pos + offset, lineLen - offset); - if (dest.IsEmpty()) + if (i > 24 || i >= rem) // we use limitation for size of (size) field return false; - if (dest.Back() != '\n') + if (s[i] == ' ') + break; + } + if (i == 0) + return false; + const char *end; + const UInt32 size = ConvertStringToUInt32(s, &end); + const unsigned offset = (unsigned)(end - s) + 1; + if (size > rem + || size <= offset + 1 + || offset != i + 1 + || s[size - 1] != '\n') + return false; + + for (i = offset; i < size; i++) + if (s[i] == 0) return false; - dest.DeleteBack(); - return true; + + for (i = offset; i < size - 1; i++) + if (s[i] == '=') + break; + if (i == size - 1) + return false; + + name.SetFrom(s + offset, i - offset); + val.SetFrom(s + i + 1, size - 1 - (i + 1)); + + bool parsed = false; + if (isFile) + { + bool isDetectedName = true; + // only lower case (name) is supported + if (name.IsEqualTo("path")) + { + if (Path_Defined) + DoubleTagError = true; + Path = val; + Path_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("linkpath")) + { + if (Link_Defined) + DoubleTagError = true; + Link = val; + Link_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("uname")) + { + if (User_Defined) + DoubleTagError = true; + User = val; + User_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("gname")) + { + if (Group_Defined) + DoubleTagError = true; + Group = val; + Group_Defined = true; + parsed = true; + } + else if (name.IsEqualTo("uid")) + { + parsed = ParseID(val, UID_Defined, UID); + } + else if (name.IsEqualTo("gid")) + { + parsed = ParseID(val, GID_Defined, GID); + } + else if (name.IsEqualTo("size")) + { + if (Size_Defined) + DoubleTagError = true; + Size_Defined = false; + if (!val.IsEmpty()) + { + const char *end2; + Size = ConvertStringToUInt64(val.Ptr(), &end2); + if (*end2 == 0) + { + Size_Defined = true; + parsed = true; + } + } + } + else if (name.IsEqualTo("mtime")) + { parsed = ParsePaxTime(val, MTime, DoubleTagError); } + else if (name.IsEqualTo("atime")) + { parsed = ParsePaxTime(val, ATime, DoubleTagError); } + else if (name.IsEqualTo("ctime")) + { parsed = ParsePaxTime(val, CTime, DoubleTagError); } + else + isDetectedName = false; + if (isDetectedName && !parsed) + TagParsingError = true; } - pos += lineLen; + if (!parsed) + { + if (!UnknownLines_Overflow) + { + const unsigned addSize = size - offset; + if (UnknownLines.Len() + addSize < (1 << 16)) + UnknownLines.AddFrom(s + offset, addSize); + else + UnknownLines_Overflow = true; + } + } + + s += size; + rem -= size; } + return true; } -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error) + +HRESULT CArchive::ReadItem2(CItemEx &item) { + // CItem + + item.SparseBlocks.Clear(); + item.PaxTimes.Clear(); + + // CItemEx + item.HeaderSize = 0; + item.Num_Pax_Records = 0; - bool flagL = false; - bool flagK = false; - AString nameL; - AString nameK; - AString pax; + item.LongName_WasUsed = false; + item.LongName_WasUsed_2 = false; + + item.LongLink_WasUsed = false; + item.LongLink_WasUsed_2 = false; + + item.HeaderError = false; + item.IsSignedChecksum = false; + item.Prefix_WasUsed = false; - for (;;) + item.Pax_Error = false; + item.Pax_Overflow = false; + item.pax_path_WasUsed = false; + item.pax_link_WasUsed = false; + item.pax_size_WasUsed = false; + + item.PaxExtra.Clear(); + + item.EncodingCharacts.Clear(); + + // CArchive temp variable + + NameBuf.Init(); + LinkBuf.Init(); + PaxBuf.Init(); + PaxBuf_global.Init(); + + for (unsigned recordIndex = 0;; recordIndex++) { - RINOK(GetNextItemReal(stream, filled, item, error)); + if (OpenCallback) + { + RINOK(Progress(item, 0)); + } + + RINOK(GetNextItemReal(item)); + + // NumRecords++; + if (!filled) { - if (error == k_ErrorType_OK && (flagL || flagK)) + if (error == k_ErrorType_OK) + if (item.LongName_WasUsed || + item.LongLink_WasUsed || + item.Num_Pax_Records != 0) error = k_ErrorType_Corrupted; - return S_OK; } if (error != k_ErrorType_OK) return S_OK; - if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName || // file contains a long name - item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongLink) // file contains a long linkname + const char lf = item.LinkFlag; + if (lf == NFileHeader::NLinkFlag::kGnu_LongName || + lf == NFileHeader::NLinkFlag::kGnu_LongLink) { - AString *name; - if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName) - { if (flagL) return S_OK; flagL = true; name = &nameL; } - else - { if (flagK) return S_OK; flagK = true; name = &nameK; } - + // GNU tar ignores item.Name after LinkFlag test + // 22.00 : now we also ignore item.Name here + /* if (item.Name != NFileHeader::kLongLink && item.Name != NFileHeader::kLongLink2) + { + break; + // return S_OK; + } + */ + + CTempBuffer *tb = + lf == NFileHeader::NLinkFlag::kGnu_LongName ? + &NameBuf : + &LinkBuf; + + /* + if (item.PackSize > (1 << 29)) + { + // break; return S_OK; - if (item.PackSize > (1 << 14)) - return S_OK; + } + */ - RINOK(ReadDataToString(stream, item, *name, error)); + const unsigned kLongNameSizeMax = (unsigned)1 << 14; + RINOK(ReadDataToBuffer(item, *tb, kLongNameSizeMax)); if (error != k_ErrorType_OK) return S_OK; + if (lf == NFileHeader::NLinkFlag::kGnu_LongName) + { + item.LongName_WasUsed_2 = + item.LongName_WasUsed; + item.LongName_WasUsed = true; + } + else + { + item.LongLink_WasUsed_2 = + item.LongLink_WasUsed; + item.LongLink_WasUsed = true; + } + + if (!tb->StringSize_IsConfirmed) + tb->StringSize = 0; + item.HeaderSize += item.Get_PackSize_Aligned(); + if (tb->StringSize == 0 || + tb->StringSize + 1 != item.PackSize) + item.HeaderError = true; + if (tb->IsNonZeroTail) + item.HeaderError = true; continue; } - switch (item.LinkFlag) + if (lf == NFileHeader::NLinkFlag::kGlobal || + lf == NFileHeader::NLinkFlag::kPax || + lf == NFileHeader::NLinkFlag::kPax_2) { - case 'g': - case 'x': - case 'X': - { - const char *s = item.Name.Ptr(); - if (IsString1PrefixedByString2(s, "./")) - s += 2; - if (IsString1PrefixedByString2(s, "./")) - s += 2; - if ( IsString1PrefixedByString2(s, "PaxHeader/") - || IsString1PrefixedByString2(s, "PaxHeaders.X/") - || IsString1PrefixedByString2(s, "PaxHeaders.4467/") - || StringsAreEqual_Ascii(s, "@PaxHeader") - ) - { - RINOK(ReadDataToString(stream, item, pax, error)); - if (error != k_ErrorType_OK) - return S_OK; - continue; - } - break; + // GNU tar ignores item.Name after LinkFlag test + // 22.00 : now we also ignore item.Name here + /* + if (item.PackSize > (UInt32)1 << 26) + { + break; // we don't want big PaxBuf files + // return S_OK; } - case NFileHeader::NLinkFlag::kDumpDir: + */ + const unsigned kParsingPaxSizeMax = (unsigned)1 << 26; + + const bool isStartHeader = (item.HeaderSize == NFileHeader::kRecordSize); + + CTempBuffer *tb = (lf == NFileHeader::NLinkFlag::kGlobal ? &PaxBuf_global : &PaxBuf); + + RINOK(ReadDataToBuffer(item, *tb, kParsingPaxSizeMax)); + if (error != k_ErrorType_OK) + return S_OK; + + item.HeaderSize += item.Get_PackSize_Aligned(); + + if (tb->StringSize != item.PackSize + || tb->StringSize == 0 + || tb->IsNonZeroTail) + item.Pax_Error = true; + + item.Num_Pax_Records++; + if (lf != NFileHeader::NLinkFlag::kGlobal) { - break; - // GNU Extensions to the Archive Format + item.PaxExtra.RecordPath = item.Name; + continue; } - case NFileHeader::NLinkFlag::kSparse: + // break; // for debug { - break; - // GNU Extensions to the Archive Format + if (PaxGlobal_Defined) + _is_PaxGlobal_Error = true; + CPaxInfo paxInfo; + if (paxInfo.ParsePax(PaxBuf_global, false)) + { + PaxGlobal.RawLines = paxInfo.UnknownLines; + PaxGlobal.RecordPath = item.Name; + PaxGlobal_Defined = true; + } + else + _is_PaxGlobal_Error = true; + if (isStartHeader) + { + // we skip global pax header info after parsing + item.HeaderPos += item.HeaderSize; + item.HeaderSize = 0; + } } - default: - if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0)) - return S_OK; + continue; } - if (flagL) + /* + if (lf == NFileHeader::NLinkFlag::kDumpDir || + lf == NFileHeader::NLinkFlag::kSparse) { - item.Name = nameL; - item.NameCouldBeReduced = false; + // GNU Extensions to the Archive Format + break; } - - if (flagK) + if (lf > '7' || (lf < '0' && lf != 0)) { - item.LinkName = nameK; - item.LinkNameCouldBeReduced = false; + break; + // return S_OK; } - - error = k_ErrorType_OK; - - if (!pax.IsEmpty()) + */ + break; + } + + // we still use name from main header, if long_name is bad + if (item.LongName_WasUsed && NameBuf.StringSize != 0) + { + NameBuf.CopyToString(item.Name); + // item.Name_CouldBeReduced = false; + } + + if (item.LongLink_WasUsed) + { + // we use empty link, if long_link is bad + LinkBuf.CopyToString(item.LinkName); + // item.LinkName_CouldBeReduced = false; + } + + error = k_ErrorType_OK; + + if (PaxBuf.StringSize != 0) + { + CPaxInfo paxInfo; + if (!paxInfo.ParsePax(PaxBuf, true)) + item.Pax_Error = true; + else { - AString name; - if (ParsePaxLongName(pax, name)) - item.Name = name; - else + if (paxInfo.Path_Defined) // if (!paxInfo.Path.IsEmpty()) + { + item.Name = paxInfo.Path; + item.pax_path_WasUsed = true; + } + if (paxInfo.Link_Defined) // (!paxInfo.Link.IsEmpty()) + { + item.LinkName = paxInfo.Link; + item.pax_link_WasUsed = true; + } + if (paxInfo.User_Defined) + { + item.User = paxInfo.User; + // item.pax_uname_WasUsed = true; + } + if (paxInfo.Group_Defined) + { + item.Group = paxInfo.Group; + // item.pax_gname_WasUsed = true; + } + if (paxInfo.UID_Defined) + { + item.UID = (UInt32)paxInfo.UID; + } + if (paxInfo.GID_Defined) + { + item.GID = (UInt32)paxInfo.GID; + } + + if (paxInfo.Size_Defined) { - // no "path" property is allowed in pax4467 - // error = k_ErrorType_Warning; + const UInt64 piSize = paxInfo.Size; + // GNU TAR ignores (item.Size) in that case + if (item.Size != 0 && item.Size != piSize) + item.Pax_Error = true; + item.Size = piSize; + item.PackSize = piSize; + item.pax_size_WasUsed = true; } - pax.Empty(); + + item.PaxTimes = paxInfo; + item.PaxExtra.RawLines = paxInfo.UnknownLines; + if (paxInfo.UnknownLines_Overflow) + item.Pax_Overflow = true; + if (paxInfo.TagParsingError) + item.Pax_Error = true; + if (paxInfo.DoubleTagError) + item.Pax_Error = true; } + } - return S_OK; + return S_OK; +} + + + +HRESULT CArchive::ReadItem(CItemEx &item) +{ + item.HeaderPos = _phySize; + + const HRESULT res = ReadItem2(item); + + /* + if (error == k_ErrorType_Warning) + _is_Warning = true; + else + */ + + if (error != k_ErrorType_OK) + _error = error; + + RINOK(res); + + if (filled) + { + if (item.IsMagic_GNU()) + _are_Gnu = true; + else if (item.IsMagic_Posix_ustar_00()) + _are_Posix = true; + + if (item.Num_Pax_Records != 0) + _are_Pax = true; + + if (item.PaxTimes.MTime.IsDefined()) _are_mtime = true; + if (item.PaxTimes.ATime.IsDefined()) _are_atime = true; + if (item.PaxTimes.CTime.IsDefined()) _are_ctime = true; + + if (item.pax_path_WasUsed) + _are_pax_path = true; + if (item.pax_link_WasUsed) + _are_pax_link = true; + if (item.LongName_WasUsed) + _are_LongName = true; + if (item.LongLink_WasUsed) + _are_LongLink = true; + if (item.Prefix_WasUsed) + _pathPrefix_WasUsed = true; + /* + if (item.IsSparse()) + _isSparse = true; + */ + if (item.Is_PaxExtendedHeader()) + _are_Pax_Items = true; + if (item.IsThereWarning() + || item.HeaderError + || item.Pax_Error) + _is_Warning = true; } + + const UInt64 headerEnd = item.HeaderPos + item.HeaderSize; + // _headersSize += headerEnd - _phySize; + // we don't count skipped records + _headersSize += item.HeaderSize; + _phySize = headerEnd; + return S_OK; } }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarIn.h 7zip-22.01/CPP/7zip/Archive/Tar/TarIn.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarIn.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarIn.h 2022-02-28 10:00:00.000000000 +0000 @@ -3,7 +3,7 @@ #ifndef __ARCHIVE_TAR_IN_H #define __ARCHIVE_TAR_IN_H -#include "../../IStream.h" +#include "../IArchive.h" #include "TarItem.h" @@ -14,11 +14,133 @@ { k_ErrorType_OK, k_ErrorType_Corrupted, - k_ErrorType_UnexpectedEnd, - k_ErrorType_Warning + k_ErrorType_UnexpectedEnd + // , k_ErrorType_Warning +}; + + +struct CTempBuffer +{ + CByteBuffer Buffer; + size_t StringSize; // num characters before zero Byte (StringSize <= item.PackSize) + bool IsNonZeroTail; + bool StringSize_IsConfirmed; + + void CopyToString(AString &s) + { + s.Empty(); + if (StringSize != 0) + s.SetFrom((const char *)(const void *)(const Byte *)Buffer, (unsigned)StringSize); + } + + void Init() + { + StringSize = 0; + IsNonZeroTail = false; + StringSize_IsConfirmed = false; + } +}; + + +class CArchive +{ +public: + bool _phySize_Defined; + bool _is_Warning; + bool PaxGlobal_Defined; + bool _is_PaxGlobal_Error; + bool _are_Pax_Items; + bool _are_Gnu; + bool _are_Posix; + bool _are_Pax; + bool _are_mtime; + bool _are_atime; + bool _are_ctime; + bool _are_pax_path; + bool _are_pax_link; + bool _are_LongName; + bool _are_LongLink; + bool _pathPrefix_WasUsed; + // bool _isSparse; + + // temp internal vars for ReadItem(): + bool filled; +private: + EErrorType error; + +public: + UInt64 _phySize; + UInt64 _headersSize; + EErrorType _error; + + ISequentialInStream *SeqStream; + IInStream *InStream; + IArchiveOpenCallback *OpenCallback; + UInt64 NumFiles; + UInt64 NumFiles_Prev; + UInt64 Pos_Prev; + // UInt64 NumRecords; + // UInt64 NumRecords_Prev; + + CPaxExtra PaxGlobal; + + void Clear() + { + SeqStream = NULL; + InStream = NULL; + OpenCallback = NULL; + NumFiles = 0; + NumFiles_Prev = 0; + Pos_Prev = 0; + // NumRecords = 0; + // NumRecords_Prev = 0; + + PaxGlobal.Clear(); + PaxGlobal_Defined = false; + _is_PaxGlobal_Error = false; + _are_Pax_Items = false; // if there are final paxItems + _are_Gnu = false; + _are_Posix = false; + _are_Pax = false; + _are_mtime = false; + _are_atime = false; + _are_ctime = false; + _are_pax_path = false; + _are_pax_link = false; + _are_LongName = false; + _are_LongLink = false; + _pathPrefix_WasUsed = false; + // _isSparse = false; + + _is_Warning = false; + _error = k_ErrorType_OK; + + _phySize_Defined = false; + _phySize = 0; + _headersSize = 0; + } + +private: + CTempBuffer NameBuf; + CTempBuffer LinkBuf; + CTempBuffer PaxBuf; + CTempBuffer PaxBuf_global; + + CByteBuffer Buffer; + + HRESULT ReadDataToBuffer(const CItemEx &item, CTempBuffer &tb, size_t stringLimit); + HRESULT Progress(const CItemEx &item, UInt64 posOffset); + HRESULT GetNextItemReal(CItemEx &item); + HRESULT ReadItem2(CItemEx &itemInfo); +public: + CArchive() + { + // we will call Clear() in CHandler::Close(). + // Clear(); // it's not required here + } + HRESULT ReadItem(CItemEx &itemInfo); }; -HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error); API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarItem.h 7zip-22.01/CPP/7zip/Archive/Tar/TarItem.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarItem.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarItem.h 2022-03-24 11:00:00.000000000 +0000 @@ -6,8 +6,6 @@ #include "../../../Common/MyLinux.h" #include "../../../Common/UTFConvert.h" -#include "../Common/ItemNameUtils.h" - #include "TarHeader.h" namespace NArchive { @@ -19,50 +17,149 @@ UInt64 Size; }; + +enum EPaxTimeRemoveZeroMode +{ + k_PaxTimeMode_DontRemoveZero, + k_PaxTimeMode_RemoveZero_if_PureSecondOnly, + k_PaxTimeMode_RemoveZero_Always +}; + +struct CTimeOptions +{ + EPaxTimeRemoveZeroMode RemoveZeroMode; + unsigned NumDigitsMax; + + void Init() + { + RemoveZeroMode = k_PaxTimeMode_RemoveZero_if_PureSecondOnly; + NumDigitsMax = 0; + } + CTimeOptions() { Init(); } +}; + + +struct CPaxTime +{ + Int32 NumDigits; // -1 means undefined + UInt32 Ns; // it's smaller than 1G. Even if (Sec < 0), larger (Ns) value means newer files. + Int64 Sec; // can be negative + + Int64 GetSec() const { return NumDigits != -1 ? Sec : 0; } + + bool IsDefined() const { return NumDigits != -1; } + // bool IsDefined_And_nonZero() const { return NumDigits != -1 && (Sec != 0 || Ns != 0); } + + void Clear() + { + NumDigits = -1; + Ns = 0; + Sec = 0; + } + CPaxTime() { Clear(); } + + /* + void ReducePrecison(int numDigits) + { + // we don't use this->NumDigits here + if (numDigits > 0) + { + if (numDigits >= 9) + return; + UInt32 r = 1; + for (unsigned i = numDigits; i < 9; i++) + r *= 10; + Ns /= r; + Ns *= r; + return; + } + Ns = 0; + if (numDigits == 0) + return; + UInt32 r; + if (numDigits == -1) r = 60; + else if (numDigits == -2) r = 60 * 60; + else if (numDigits == -3) r = 60 * 60 * 24; + else return; + Sec /= r; + Sec *= r; + } + */ +}; + + +struct CPaxTimes +{ + CPaxTime MTime; + CPaxTime ATime; + CPaxTime CTime; + + void Clear() + { + MTime.Clear(); + ATime.Clear(); + CTime.Clear(); + } + + /* + void ReducePrecison(int numDigits) + { + MTime.ReducePrecison(numDigits); + CTime.ReducePrecison(numDigits); + ATime.ReducePrecison(numDigits); + } + */ +}; + + struct CItem { - AString Name; UInt64 PackSize; UInt64 Size; Int64 MTime; + char LinkFlag; + bool DeviceMajor_Defined; + bool DeviceMinor_Defined; + UInt32 Mode; UInt32 UID; UInt32 GID; UInt32 DeviceMajor; UInt32 DeviceMinor; + AString Name; AString LinkName; AString User; AString Group; char Magic[8]; - char LinkFlag; - bool DeviceMajorDefined; - bool DeviceMinorDefined; + + CPaxTimes PaxTimes; CRecordVector SparseBlocks; - void SetDefaultWriteFields() + void SetMagic_Posix(bool posixMode) { - DeviceMajorDefined = false; - DeviceMinorDefined = false; - UID = 0; - GID = 0; - memcpy(Magic, NFileHeader::NMagic::kUsTar_GNU, 8); + memcpy(Magic, posixMode ? + NFileHeader::NMagic::k_Posix_ustar_00 : + NFileHeader::NMagic::k_GNU_ustar__, + 8); } - bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } - bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } - bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } - UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; } - bool IsPaxExtendedHeader() const + bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } + bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } + bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } + + UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; } + + bool Is_PaxExtendedHeader() const { switch (LinkFlag) { - case 'g': - case 'x': - case 'X': // Check it + case NFileHeader::NLinkFlag::kPax: + case NFileHeader::NLinkFlag::kPax_2: + case NFileHeader::NLinkFlag::kGlobal: return true; } return false; @@ -72,6 +169,17 @@ { return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); } + + void Set_LinkFlag_for_File(UInt32 mode) + { + Byte lf = NFileHeader::NLinkFlag::kNormal; + if (MY_LIN_S_ISCHR(mode)) lf = NFileHeader::NLinkFlag::kCharacter; + else if (MY_LIN_S_ISBLK(mode)) lf = NFileHeader::NLinkFlag::kBlock; + else if (MY_LIN_S_ISFIFO(mode)) lf = NFileHeader::NLinkFlag::kFIFO; + // else if (MY_LIN_S_ISDIR(mode)) lf = NFileHeader::NLinkFlag::kDirectory; + // else if (MY_LIN_S_ISLNK(mode)) lf = NFileHeader::NLinkFlag::kSymLink; + LinkFlag = lf; + } UInt32 Get_FileTypeMode_from_LinkFlag() const { @@ -82,10 +190,10 @@ case NFileHeader::NLinkFlag::kDumpDir: return MY_LIN_S_IFDIR; */ - case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK; - case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK; - case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR; - case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO; + case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK; + case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK; + case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR; + case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO; // case return MY_LIN_S_IFSOCK; } @@ -104,20 +212,41 @@ case NFileHeader::NLinkFlag::kOldNormal: case NFileHeader::NLinkFlag::kNormal: case NFileHeader::NLinkFlag::kSymLink: - return NItemName::HasTailSlash(Name, CP_OEMCP); + if (Name.IsEmpty()) + return false; + // GNU TAR uses last character as directory marker + // we also do it + return Name.Back() == '/'; + // return NItemName::HasTailSlash(Name, CP_OEMCP); } return false; } - bool IsUstarMagic() const + bool IsMagic_ustar_5chars() const + { + for (unsigned i = 0; i < 5; i++) + if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i]) + return false; + return true; + } + + bool IsMagic_Posix_ustar_00() const + { + for (unsigned i = 0; i < 8; i++) + if (Magic[i] != NFileHeader::NMagic::k_Posix_ustar_00[i]) + return false; + return true; + } + + bool IsMagic_GNU() const { - for (int i = 0; i < 5; i++) - if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i]) + for (unsigned i = 0; i < 8; i++) + if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i]) return false; return true; } - UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } + UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); } bool IsThereWarning() const { @@ -163,18 +292,67 @@ }; +struct CPaxExtra +{ + AString RecordPath; + AString RawLines; + + void Clear() + { + RecordPath.Empty(); + RawLines.Empty(); + } + + void Print_To_String(AString &s) const + { + if (!RecordPath.IsEmpty()) + { + s += RecordPath; + s.Add_LF(); + } + if (!RawLines.IsEmpty()) + s += RawLines; + } +}; + struct CItemEx: public CItem { + bool HeaderError; + + bool IsSignedChecksum; + bool Prefix_WasUsed; + + bool Pax_Error; + bool Pax_Overflow; + bool pax_path_WasUsed; + bool pax_link_WasUsed; + bool pax_size_WasUsed; + + bool MTime_IsBin; + bool PackSize_IsBin; + bool Size_IsBin; + + bool LongName_WasUsed; + bool LongName_WasUsed_2; + + bool LongLink_WasUsed; + bool LongLink_WasUsed_2; + + // bool Name_CouldBeReduced; + // bool LinkName_CouldBeReduced; + UInt64 HeaderPos; - unsigned HeaderSize; - bool NameCouldBeReduced; - bool LinkNameCouldBeReduced; + UInt64 HeaderSize; + + UInt64 Num_Pax_Records; + CPaxExtra PaxExtra; CEncodingCharacts EncodingCharacts; - UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } - UInt64 GetFullSize() const { return HeaderSize + PackSize; } + UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; } + // UInt64 GetFullSize() const { return HeaderSize + PackSize; } + UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); } }; }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarOut.cpp 7zip-22.01/CPP/7zip/Archive/Tar/TarOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarOut.cpp 2022-03-30 12:00:00.000000000 +0000 @@ -2,6 +2,10 @@ #include "StdAfx.h" +#include "../../../../C/7zCrc.h" + +#include "../../../Common/IntToString.h" + #include "../../Common/StreamUtils.h" #include "TarOut.h" @@ -9,23 +13,27 @@ namespace NArchive { namespace NTar { -HRESULT COutArchive::WriteBytes(const void *data, unsigned size) -{ - Pos += size; - return WriteStream(m_Stream, data, size); -} +using namespace NFileHeader; + +// it's path prefix assigned by 7-Zip to show that file path was cut +#define K_PREFIX_PATH_CUT "@PathCut" + +static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1; -static bool WriteOctal_8(char *s, UInt32 val) +static void WriteOctal_8(char *s, UInt32 val) { const unsigned kNumDigits = 8 - 1; if (val >= ((UInt32)1 << (kNumDigits * 3))) - return false; + { + val = 0; + // return false; + } for (unsigned i = 0; i < kNumDigits; i++) { s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); val >>= 3; } - return true; + // return true; } static void WriteBin_64bit(char *s, UInt64 val) @@ -68,61 +76,93 @@ unsigned len = src.Len(); if (len == 0) return; - // 21.07: we don't require additional 0 character at the end + // 21.07: new gnu : we don't require additional 0 character at the end + // if (len >= maxSize) if (len > maxSize) { len = maxSize; - // return false; + /* + // oldgnu needs 0 character at the end + len = maxSize - 1; + dest[len] = 0; + */ } memcpy(dest, src.Ptr(), len); - // return true; } -#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; } +// #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; } +#define RETURN_IF_NOT_TRUE(x) { x; } #define COPY_STRING_CHECK(dest, src, size) \ CopyString(dest, src, size); dest += (size); #define WRITE_OCTAL_8_CHECK(dest, src) \ - RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src)); + RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src)) -HRESULT COutArchive::WriteHeaderReal(const CItem &item) +HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax + // , bool zero_PackSize + // , bool zero_MTime + ) { - char record[NFileHeader::kRecordSize]; - memset(record, 0, NFileHeader::kRecordSize); + /* + if (isPax) { we don't use Glob_Name and Prefix } + if (!isPax) + { + we use Glob_Name if it's not empty + we use Prefix if it's not empty + } + */ + char record[kRecordSize]; + memset(record, 0, kRecordSize); char *cur = record; - COPY_STRING_CHECK (cur, item.Name, NFileHeader::kNameSize); + COPY_STRING_CHECK (cur, + (!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name, + kNameSize); - WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8; + WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8; // & k_7_oct_digits_Val_Max WRITE_OCTAL_8_CHECK (cur, item.UID); cur += 8; WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8; - WriteOctal_12(cur, item.PackSize); cur += 12; - WriteOctal_12_Signed(cur, item.MTime); cur += 12; + WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12; + WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12; - memset(cur, ' ', 8); // checksum field + // we will use binary init for checksum instead of memset + // checksum field: + // memset(cur, ' ', 8); cur += 8; *cur++ = item.LinkFlag; - COPY_STRING_CHECK (cur, item.LinkName, NFileHeader::kNameSize); + COPY_STRING_CHECK (cur, item.LinkName, kNameSize); memcpy(cur, item.Magic, 8); cur += 8; - COPY_STRING_CHECK (cur, item.User, NFileHeader::kUserNameSize); - COPY_STRING_CHECK (cur, item.Group, NFileHeader::kGroupNameSize); + COPY_STRING_CHECK (cur, item.User, kUserNameSize); + COPY_STRING_CHECK (cur, item.Group, kGroupNameSize); - if (item.DeviceMajorDefined) - WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor); + const bool needDevice = (IsPosixMode && !isPax); + + if (item.DeviceMajor_Defined) + WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor) + else if (needDevice) + WRITE_OCTAL_8_CHECK (cur, 0) cur += 8; - if (item.DeviceMinorDefined) - WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor); + + if (item.DeviceMinor_Defined) + WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor) + else if (needDevice) + WRITE_OCTAL_8_CHECK (cur, 0) cur += 8; - if (item.IsSparse()) + if (!isPax && !Prefix.IsEmpty()) + { + COPY_STRING_CHECK (cur, Prefix, kPrefixSize); + } + + if (item.Is_Sparse()) { record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0); WriteOctal_12(record + 483, item.Size); @@ -136,31 +176,31 @@ } { - UInt32 checkSum = 0; + UInt32 sum = (unsigned)(' ') * 8; // we use binary init { - for (unsigned i = 0; i < NFileHeader::kRecordSize; i++) - checkSum += (Byte)record[i]; + for (unsigned i = 0; i < kRecordSize; i++) + sum += (Byte)record[i]; } - /* we use GNU TAR scheme: - checksum field is formatted differently from the + /* checksum field is formatted differently from the other fields: it has [6] digits, a null, then a space. */ - // WRITE_OCTAL_8_CHECK(record + 148, checkSum); + // WRITE_OCTAL_8_CHECK(record + 148, sum); const unsigned kNumDigits = 6; for (unsigned i = 0; i < kNumDigits; i++) { - record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7)); - checkSum >>= 3; + record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7)); + sum >>= 3; } - record[148 + 6] = 0; + // record[148 + 6] = 0; // we need it, if we use memset(' ') init + record[148 + 7] = ' '; // we need it, if we use binary init } - RINOK(WriteBytes(record, NFileHeader::kRecordSize)); + RINOK(Write_Data(record, kRecordSize)); - if (item.IsSparse()) + if (item.Is_Sparse()) { for (unsigned i = 4; i < item.SparseBlocks.Size();) { - memset(record, 0, NFileHeader::kRecordSize); + memset(record, 0, kRecordSize); for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++) { const CSparseBlock &sb = item.SparseBlocks[i]; @@ -169,7 +209,7 @@ WriteOctal_12(p + 12, sb.Size); } record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0); - RINOK(WriteBytes(record, NFileHeader::kRecordSize)); + RINOK(Write_Data(record, kRecordSize)); } } @@ -177,101 +217,426 @@ } -/* OLD_GNU_TAR: writes short name with zero at the end - NEW_GNU_TAR: writes short name without zero at the end */ +static void AddPaxLine(AString &s, const char *name, const AString &val) +{ + // s.Add_LF(); // for debug + const unsigned len = 3 + (unsigned)strlen(name) + val.Len(); + AString n; + for (unsigned numDigits = 1;; numDigits++) + { + n.Empty(); + n.Add_UInt32(numDigits + len); + if (numDigits == n.Len()) + break; + } + s += n; + s.Add_Space(); + s += name; + s += '='; + s += val; + s.Add_LF(); +} + + +static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt, + const CTimeOptions &options) +{ + unsigned numDigits = pt.NumDigits; + if (numDigits > options.NumDigitsMax) + numDigits = options.NumDigitsMax; + + bool needNs = false; + UInt32 ns = 0; + if (numDigits != 0) + { + ns = pt.Ns; + // if (ns != 0) before reduction, we show all digits after digits reduction + needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero); + UInt32 d = 1; + for (unsigned k = numDigits; k < 9; k++) + d *= 10; + ns /= d; + ns *= d; + } + + AString v; + { + Int64 sec = pt.Sec; + if (pt.Sec < 0) + { + sec = -sec; + v += '-'; + if (ns != 0) + { + ns = 1000*1000*1000 - ns; + sec--; + } + } + v.Add_UInt64(sec); + } + + if (needNs) + { + AString d; + d.Add_UInt32(ns); + while (d.Len() < 9) + d.InsertAtFront('0'); + // here we have precision + while (d.Len() > (unsigned)numDigits) + d.DeleteBack(); + // GNU TAR reduces '0' digits. + if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always) + while (!d.IsEmpty() && d.Back() == '0') + d.DeleteBack(); + + if (!d.IsEmpty()) + { + v += '.'; + v += d; + // v += "1234567009999"; // for debug + // for (int y = 0; y < 1000; y++) v += '8'; // for debug + } + } + + AddPaxLine(s, name, v); +} + + +static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v) +{ + if (v > k_7_oct_digits_Val_Max) + { + AString s2; + s2.Add_UInt32(v); + AddPaxLine(s, name, s2); + } +} + + +/* OLD_GNU_TAR: writes name with zero at the end + NEW_GNU_TAR: can write name filled with all kNameSize characters */ static const unsigned kNameSize_Max = - NFileHeader::kNameSize; // NEW_GNU_TAR / 7-Zip 21.07 - // NFileHeader::kNameSize - 1; // OLD_GNU_TAR / old 7-Zip + kNameSize; // NEW_GNU_TAR / 7-Zip 21.07 + // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip #define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max) + HRESULT COutArchive::WriteHeader(const CItem &item) { - if (DOES_NAME_FIT_IN_FIELD(item.Name) && - DOES_NAME_FIT_IN_FIELD(item.LinkName)) - return WriteHeaderReal(item); + Glob_Name.Empty(); + Prefix.Empty(); - // here we can get all fields from main (item) or create new empty item - /* - CItem mi; - mi.SetDefaultWriteFields(); - */ - - CItem mi = item; - mi.LinkName.Empty(); - // SparseBlocks will be ignored by IsSparse() - // mi.SparseBlocks.Clear(); - - mi.Name = NFileHeader::kLongLink; - // 21.07 : we set Mode and MTime props as in GNU TAR: - mi.Mode = 0644; // octal - mi.MTime = 0; - - for (int i = 0; i < 2; i++) - { - const AString *name; - // We suppose that GNU TAR also writes item for long link before item for LongName? - if (i == 0) + unsigned namePos = 0; + bool needPathCut = false; + bool allowPrefix = false; + + if (!DOES_NAME_FIT_IN_FIELD(item.Name)) + { + const char *s = item.Name; + const char *p = s + item.Name.Len() - 1; + for (; *p == '/' && p != s; p--) + {} + for (; p != s && p[-1] != '/'; p--) + {} + namePos = (unsigned)(p - s); + needPathCut = true; + } + + if (IsPosixMode) + { + AString s; + + if (needPathCut) + { + const unsigned nameLen = item.Name.Len() - namePos; + if ( item.LinkFlag >= NLinkFlag::kNormal + && item.LinkFlag <= NLinkFlag::kDirectory + && namePos > 1 + && nameLen != 0 + // && IsPrefixAllowed + && item.IsMagic_Posix_ustar_00()) + { + /* GNU TAR decoder supports prefix field, only if (magic) + signature matches 6-bytes "ustar\0". + so here we use prefix field only in posix mode with posix signature */ + + allowPrefix = true; + // allowPrefix = false; // for debug + if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max) + { + needPathCut = false; + /* we will set Prefix and Glob_Name later, for such conditions: + if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */ + } + } + + if (needPathCut) + AddPaxLine(s, "path", item.Name); + } + + // AddPaxLine(s, "testname", AString("testval")); // for debug + + if (item.LinkName.Len() > kNameSize_Max) + AddPaxLine(s, "linkpath", item.LinkName); + + const UInt64 kPaxSize_Limit = ((UInt64)1 << 33); + // const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug + // bool zero_PackSize = false; + if (item.PackSize >= kPaxSize_Limit) + { + /* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB + But old 7-Zip doesn't detect "size" property from pax header. + So we write real size (>= 8 GiB) to main record in binary format, + and old 7-Zip can decode size correctly */ + // zero_PackSize = true; + AString v; + v.Add_UInt64(item.PackSize); + AddPaxLine(s, "size", v); + } + + /* GNU TAR encoder can set "devmajor" / "devminor" attributes, + but GNU TAR decoder doesn't parse "devmajor" / "devminor" */ + if (item.DeviceMajor_Defined) + AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor); + if (item.DeviceMinor_Defined) + AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor); + + AddPax_UInt32_ifBig(s, "uid", item.UID); + AddPax_UInt32_ifBig(s, "gid", item.GID); + + const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33); + const bool zero_MTime = ( + item.MTime < 0 || + item.MTime >= (Int64)kPax_MTime_Limit); + + const CPaxTime &mtime = item.PaxTimes.MTime; + if (mtime.IsDefined()) + { + bool needPax = false; + if (zero_MTime) + needPax = true; + else if (TimeOptions.NumDigitsMax > 0) + if (mtime.Ns != 0 || + (mtime.NumDigits != 0 && + TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero)) + needPax = true; + if (needPax) + AddPaxTime(s, "mtime", mtime, TimeOptions); + } + + if (item.PaxTimes.ATime.IsDefined()) + AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions); + if (item.PaxTimes.CTime.IsDefined()) + AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions); + + if (item.User.Len() > kUserNameSize) + AddPaxLine(s, "uname", item.User); + if (item.Group.Len() > kGroupNameSize) + AddPaxLine(s, "gname", item.Group); + + /* + // for debug + AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a); + */ + + const unsigned paxSize = s.Len(); + if (paxSize != 0) + { + CItem mi = item; + mi.LinkName.Empty(); + // SparseBlocks will be ignored by Is_Sparse() + // mi.SparseBlocks.Clear(); + // we use "PaxHeader/*" for compatibility with previous 7-Zip decoder + + // GNU TAR writes empty for these fields; + mi.User.Empty(); + mi.Group.Empty(); + mi.UID = 0; + mi.GID = 0; + + mi.DeviceMajor_Defined = false; + mi.DeviceMinor_Defined = false; + + mi.Name = "PaxHeader/@PaxHeader"; + mi.Mode = 0644; // octal + if (zero_MTime) + mi.MTime = 0; + mi.LinkFlag = NLinkFlag::kPax; + // mi.LinkFlag = 'Z'; // for debug + mi.PackSize = paxSize; + // for (unsigned y = 0; y < 1; y++) { // for debug + RINOK(WriteHeaderReal(mi, true)); // isPax + RINOK(Write_Data_And_Residual(s, paxSize)); + // } // for debug + /* + we can send (zero_MTime) for compatibility with gnu tar output. + we can send (zero_MTime = false) for better compatibility with old 7-Zip + */ + // return WriteHeaderReal(item); + /* + false, // isPax + false, // zero_PackSize + false); // zero_MTime + */ + } + } + else // !PosixMode + if (!DOES_NAME_FIT_IN_FIELD(item.Name) || + !DOES_NAME_FIT_IN_FIELD(item.LinkName)) + { + // here we can get all fields from main (item) or create new empty item + /* + CItem mi; + mi.SetDefaultWriteFields(); + */ + CItem mi = item; + mi.LinkName.Empty(); + // SparseBlocks will be ignored by Is_Sparse() + // mi.SparseBlocks.Clear(); + mi.Name = kLongLink; + // mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug + // 21.07 : we set Mode and MTime props as in GNU TAR: + mi.Mode = 0644; // octal + mi.MTime = 0; + + mi.User.Empty(); + mi.Group.Empty(); + /* + gnu tar sets "root" for such items: + uid_to_uname (0, &uname); + gid_to_gname (0, &gname); + */ + /* + mi.User = "root"; + mi.Group = "root"; + */ + mi.UID = 0; + mi.GID = 0; + mi.DeviceMajor_Defined = false; + mi.DeviceMinor_Defined = false; + + + for (unsigned i = 0; i < 2; i++) { - mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink; - name = &item.LinkName; + const AString *name; + // We suppose that GNU TAR also writes item for long link before item for LongName? + if (i == 0) + { + mi.LinkFlag = NLinkFlag::kGnu_LongLink; + name = &item.LinkName; + } + else + { + mi.LinkFlag = NLinkFlag::kGnu_LongName; + name = &item.Name; + } + if (DOES_NAME_FIT_IN_FIELD(*name)) + continue; + // GNU TAR writes null character after NAME to file. We do same here: + const unsigned nameStreamSize = name->Len() + 1; + mi.PackSize = nameStreamSize; + // for (unsigned y = 0; y < 3; y++) { // for debug + RINOK(WriteHeaderReal(mi)); + RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize)); + // } + + // for debug + /* + const unsigned kSize = (1 << 29) + 16; + CByteBuffer buf; + buf.Alloc(kSize); + memset(buf, 0, kSize); + memcpy(buf, name->Ptr(), name->Len()); + const unsigned nameStreamSize = kSize; + mi.PackSize = nameStreamSize; + // for (unsigned y = 0; y < 3; y++) { // for debug + RINOK(WriteHeaderReal(mi)); + RINOK(WriteBytes(buf, nameStreamSize)); + RINOK(FillDataResidual(nameStreamSize)); + */ } + } + + // bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR + + if (!DOES_NAME_FIT_IN_FIELD(item.Name)) + { + const unsigned nameLen = item.Name.Len() - namePos; + if (!needPathCut) + Prefix.SetFrom(item.Name, namePos - 1); else { - mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName; - name = &item.Name; + Glob_Name = K_PREFIX_PATH_CUT "/_pc_"; + + if (namePos == 0) + Glob_Name += "root"; + else + { + Glob_Name += "crc32/"; + char temp[12]; + ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp); + Glob_Name += temp; + } + + if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max) + Glob_Name.Add_Slash(); + else + { + Prefix = Glob_Name; + Glob_Name.Empty(); + } } - if (DOES_NAME_FIT_IN_FIELD(*name)) - continue; - // GNU TAR writes null character after NAME to file. We do same here: - const unsigned nameStreamSize = name->Len() + 1; - mi.PackSize = nameStreamSize; - RINOK(WriteHeaderReal(mi)); - RINOK(WriteBytes(name->Ptr(), nameStreamSize)); - RINOK(FillDataResidual(nameStreamSize)); + Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen); } - // 21.07: WriteHeaderReal() writes short part of (Name) and (LinkName). return WriteHeaderReal(item); - /* - mi = item; - if (!DOES_NAME_FIT_IN_FIELD(mi.Name)) - mi.Name.SetFrom(item.Name, kNameSize_Max); - if (!DOES_NAME_FIT_IN_FIELD(mi.LinkName)) - mi.LinkName.SetFrom(item.LinkName, kNameSize_Max); - return WriteHeaderReal(mi); - */ } -HRESULT COutArchive::FillDataResidual(UInt64 dataSize) + +HRESULT COutArchive::Write_Data(const void *data, unsigned size) +{ + Pos += size; + return WriteStream(Stream, data, size); +} + +HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize) { - unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1)); - if (lastRecordSize == 0) + const unsigned v = ((unsigned)dataSize & (kRecordSize - 1)); + if (v == 0) return S_OK; - unsigned rem = NFileHeader::kRecordSize - lastRecordSize; - Byte buf[NFileHeader::kRecordSize]; + const unsigned rem = kRecordSize - v; + Byte buf[kRecordSize]; memset(buf, 0, rem); - return WriteBytes(buf, rem); + return Write_Data(buf, rem); } + +HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size) +{ + RINOK(Write_Data(data, size)); + return Write_AfterDataResidual(size); +} + + HRESULT COutArchive::WriteFinishHeader() { - Byte record[NFileHeader::kRecordSize]; - memset(record, 0, NFileHeader::kRecordSize); + Byte record[kRecordSize]; + memset(record, 0, kRecordSize); const unsigned kNumFinishRecords = 2; /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB) we also can use cluster alignment: - const unsigned numBlocks = (unsigned)(Pos / NFileHeader::kRecordSize) + kNumFinishRecords; + const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords; const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1)); */ for (unsigned i = 0; i < kNumFinishRecords; i++) { - RINOK(WriteBytes(record, NFileHeader::kRecordSize)); + RINOK(Write_Data(record, kRecordSize)); } return S_OK; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarOut.h 7zip-22.01/CPP/7zip/Archive/Tar/TarOut.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarOut.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarOut.h 2022-02-22 10:00:00.000000000 +0000 @@ -14,21 +14,38 @@ class COutArchive { - CMyComPtr m_Stream; + CMyComPtr Stream; + + AString Glob_Name; + AString Prefix; + + HRESULT WriteHeaderReal(const CItem &item, bool isPax = false + // , bool zero_PackSize = false + // , bool zero_MTime = false + ); + + HRESULT Write_Data(const void *data, unsigned size); + HRESULT Write_Data_And_Residual(const void *data, unsigned size); - HRESULT WriteBytes(const void *data, unsigned size); - HRESULT WriteHeaderReal(const CItem &item); public: UInt64 Pos; - + bool IsPosixMode; + // bool IsPrefixAllowed; // it's used only if (IsPosixMode == true) + CTimeOptions TimeOptions; + void Create(ISequentialOutStream *outStream) { - m_Stream = outStream; + Stream = outStream; } - HRESULT WriteHeader(const CItem &item); - HRESULT FillDataResidual(UInt64 dataSize); + HRESULT Write_AfterDataResidual(UInt64 dataSize); HRESULT WriteFinishHeader(); + + COutArchive(): + Pos(0), + IsPosixMode(false) + // , IsPrefixAllowed(true) + {} }; }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarRegister.cpp 7zip-22.01/CPP/7zip/Archive/Tar/TarRegister.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarRegister.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarRegister.cpp 2022-05-04 11:00:00.000000000 +0000 @@ -15,9 +15,17 @@ "tar", "tar ova", 0, 0xEE, k_Signature, NFileHeader::kUstarMagic_Offset, - NArcInfoFlags::kStartOpen | - NArcInfoFlags::kSymLinks | - NArcInfoFlags::kHardLinks, - IsArc_Tar) + NArcInfoFlags::kStartOpen + | NArcInfoFlags::kSymLinks + | NArcInfoFlags::kHardLinks + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + // | NArcInfoTimeFlags::kCTime + // | NArcInfoTimeFlags::kATime + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::k1ns) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix) + , IsArc_Tar) }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarUpdate.cpp 7zip-22.01/CPP/7zip/Archive/Tar/TarUpdate.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarUpdate.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarUpdate.cpp 2022-03-28 12:00:00.000000000 +0000 @@ -2,6 +2,8 @@ #include "StdAfx.h" +// #include + #include "../../../Windows/TimeUtils.h" #include "../../Common/LimitedStreams.h" @@ -15,18 +17,161 @@ namespace NArchive { namespace NTar { +static void FILETIME_To_PaxTime(const FILETIME &ft, CPaxTime &pt) +{ + UInt32 ns; + pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, ns); + pt.Ns = ns * 100; + pt.NumDigits = 7; +} + + +HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt) +{ + pt.Clear(); + if (prop.vt == VT_EMPTY) + { + // pt.Sec = 0; + return S_OK; + } + if (prop.vt != VT_FILETIME) + return E_INVALIDARG; + { + UInt32 ns; + pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(prop.filetime, ns); + ns *= 100; + pt.NumDigits = 7; + const unsigned prec = prop.wReserved1; + if (prec >= k_PropVar_TimePrec_Base) + { + pt.NumDigits = prec - k_PropVar_TimePrec_Base; + if (prop.wReserved2 < 100) + ns += prop.wReserved2; + } + pt.Ns = ns; + return S_OK; + } +} + + +static HRESULT GetTime(IStreamGetProp *getProp, UInt32 pid, CPaxTime &pt) +{ + pt.Clear(); + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pid, &prop)); + return Prop_To_PaxTime(prop, pt); +} + + +static HRESULT GetUser(IStreamGetProp *getProp, + UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id, + UINT codePage, unsigned utfFlags) +{ + // printf("\nGetUser\n"); + // we keep old values, if both GetProperty() return VT_EMPTY + // we clear old values, if any of GetProperty() returns non-VT_EMPTY; + bool isSet = false; + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pidId, &prop)); + if (prop.vt == VT_UI4) + { + isSet = true; + id = prop.ulVal; + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pidName, &prop)); + if (prop.vt == VT_BSTR) + { + const UString s = prop.bstrVal; + Get_AString_From_UString(s, name, codePage, utfFlags); + // printf("\ngetProp->GetProperty(pidName, &prop) : %s" , name.Ptr()); + if (!isSet) + id = 0; + } + else if (prop.vt == VT_UI4) + { + id = prop.ulVal; + name.Empty(); + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + + +/* +static HRESULT GetDevice(IStreamGetProp *getProp, + UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined) +{ + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(kpidDevice, &prop)); + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt != VT_UI8) + return E_INVALIDARG; + { + printf("\nTarUpdate.cpp :: GetDevice()\n"); + const UInt64 v = prop.uhVal.QuadPart; + majo = MY_dev_major(v); + mino = MY_dev_minor(v); + majo_defined = true; + mino_defined = true; + } + return S_OK; +} +*/ + +static HRESULT GetDevice(IStreamGetProp *getProp, + UInt32 pid, UInt32 &id, bool &defined) +{ + defined = false; + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(pid, &prop)); + if (prop.vt == VT_EMPTY) + return S_OK; + if (prop.vt == VT_UI4) + { + id = prop.ulVal; + defined = true; + return S_OK; + } + return E_INVALIDARG; +} + + HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CObjectVector &inputItems, const CObjectVector &updateItems, - UINT codePage, unsigned utfFlags, + const CUpdateOptions &options, IArchiveUpdateCallback *updateCallback) { COutArchive outArchive; outArchive.Create(outStream); outArchive.Pos = 0; + outArchive.IsPosixMode = options.PosixMode; + outArchive.TimeOptions = options.TimeOptions; CMyComPtr outSeekStream; outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream); + if (outSeekStream) + { + /* + // for debug + Byte buf[1 << 14]; + memset (buf, 0, sizeof(buf)); + RINOK(outStream->Write(buf, sizeof(buf), NULL)); + */ + // we need real outArchive.Pos, if outSeekStream->SetSize() will be used. + RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &outArchive.Pos)); + } + CMyComPtr opCallback; updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); @@ -40,7 +185,7 @@ if (ui.NewData) complexity += ui.Size; else - complexity += inputItems[(unsigned)ui.IndexInArc].GetFullSize(); + complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned(); } RINOK(updateCallback->SetTotal(complexity)); @@ -58,21 +203,31 @@ complexity = 0; - for (i = 0; i < updateItems.Size(); i++) + // const int kNumReduceDigits = -1; // for debug + + for (i = 0;; i++) { lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); + if (i == updateItems.Size()) + return outArchive.WriteFinishHeader(); + const CUpdateItem &ui = updateItems[i]; CItem item; if (ui.NewProps) { - item.SetDefaultWriteFields(); - item.Mode = ui.Mode; + item.SetMagic_Posix(options.PosixMode); item.Name = ui.Name; item.User = ui.User; item.Group = ui.Group; + item.UID = ui.UID; + item.GID = ui.GID; + item.DeviceMajor = ui.DeviceMajor; + item.DeviceMinor = ui.DeviceMinor; + item.DeviceMajor_Defined = ui.DeviceMajor_Defined; + item.DeviceMinor_Defined = ui.DeviceMinor_Defined; if (ui.IsDir) { @@ -81,11 +236,15 @@ } else { - item.LinkFlag = NFileHeader::NLinkFlag::kNormal; item.PackSize = ui.Size; + item.Set_LinkFlag_for_File(ui.Mode); } - - item.MTime = ui.MTime; + + // 22.00 + item.Mode = ui.Mode & ~(UInt32)MY_LIN_S_IFMT; + item.PaxTimes = ui.PaxTimes; + // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug + item.MTime = ui.PaxTimes.MTime.GetSec(); } else item = inputItems[(unsigned)ui.IndexInArc]; @@ -93,7 +252,8 @@ AString symLink; if (ui.NewData || ui.NewProps) { - RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, utfFlags, true)); + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, + options.CodePage, options.UtfFlags, true)); if (!symLink.IsEmpty()) { item.LinkFlag = NFileHeader::NLinkFlag::kSymLink; @@ -120,7 +280,7 @@ } else { - HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); + const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); if (res == S_FALSE) needWrite = false; @@ -128,31 +288,105 @@ { RINOK(res); - if (fileInStream) + if (!fileInStream) + { + item.PackSize = 0; + item.Size = 0; + } + else { CMyComPtr getProps; - fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); - if (getProps) + CMyComPtr getProp; + fileInStream->QueryInterface(IID_IStreamGetProp, (void **)&getProp); + if (getProp) + { + if (options.Write_MTime.Val) RINOK(GetTime(getProp, kpidMTime, item.PaxTimes.MTime)) + if (options.Write_ATime.Val) RINOK(GetTime(getProp, kpidATime, item.PaxTimes.ATime)) + if (options.Write_CTime.Val) RINOK(GetTime(getProp, kpidCTime, item.PaxTimes.CTime)) + + if (options.PosixMode) + { + /* + RINOK(GetDevice(getProp, item.DeviceMajor, item.DeviceMinor, + item.DeviceMajor_Defined, item.DeviceMinor_Defined)); + */ + bool defined = false; + UInt32 val = 0; + RINOK(GetDevice(getProp, kpidDeviceMajor, val, defined)); + if (defined) + { + item.DeviceMajor = val; + item.DeviceMajor_Defined = true; + item.DeviceMinor = 0; + item.DeviceMinor_Defined = false; + RINOK(GetDevice(getProp, kpidDeviceMinor, item.DeviceMinor, item.DeviceMinor_Defined)); + } + } + + RINOK(GetUser(getProp, kpidUser, kpidUserId, item.User, item.UID, options.CodePage, options.UtfFlags)); + RINOK(GetUser(getProp, kpidGroup, kpidGroupId, item.Group, item.GID, options.CodePage, options.UtfFlags)); + + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(kpidPosixAttrib, &prop)); + if (prop.vt == VT_EMPTY) + item.Mode = + MY_LIN_S_IRWXO + | MY_LIN_S_IRWXG + | MY_LIN_S_IRWXU + | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG); + else if (prop.vt != VT_UI4) + return E_INVALIDARG; + else + item.Mode = prop.ulVal; + // 21.07 : we clear high file type bits as GNU TAR. + item.Set_LinkFlag_for_File(item.Mode); + item.Mode &= ~(UInt32)MY_LIN_S_IFMT; + } + + { + NWindows::NCOM::CPropVariant prop; + RINOK(getProp->GetProperty(kpidSize, &prop)); + if (prop.vt != VT_UI8) + return E_INVALIDARG; + const UInt64 size = prop.uhVal.QuadPart; + item.PackSize = size; + item.Size = size; + } + /* + printf("\nNum digits = %d %d\n", + (int)item.PaxTimes.MTime.NumDigits, + (int)item.PaxTimes.MTime.Ns); + */ + } + else { - FILETIME mTime; - UInt64 size2; - if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK) + fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); + if (getProps) { - item.PackSize = size2; - item.Size = size2; - item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; + FILETIME mTime, aTime, cTime; + UInt64 size2; + if (getProps->GetProps(&size2, + options.Write_CTime.Val ? &cTime : NULL, + options.Write_ATime.Val ? &aTime : NULL, + options.Write_MTime.Val ? &mTime : NULL, + NULL) == S_OK) + { + item.PackSize = size2; + item.Size = size2; + if (options.Write_MTime.Val) FILETIME_To_PaxTime(mTime, item.PaxTimes.MTime); + if (options.Write_ATime.Val) FILETIME_To_PaxTime(aTime, item.PaxTimes.ATime); + if (options.Write_CTime.Val) FILETIME_To_PaxTime(cTime, item.PaxTimes.CTime); + } } } } - else - { - item.PackSize = 0; - item.Size = 0; - } { + // we must request kpidHardLink after updateCallback->GetStream() AString hardLink; - RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, utfFlags, true)); + RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, + options.CodePage, options.UtfFlags, true)); if (!hardLink.IsEmpty()) { item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; @@ -165,37 +399,98 @@ } } + // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug + + if (ui.NewProps) + item.MTime = item.PaxTimes.MTime.GetSec(); + if (needWrite) { - UInt64 fileHeaderStartPos = outArchive.Pos; + const UInt64 headerPos = outArchive.Pos; + // item.PackSize = ((UInt64)1 << 33); // for debug RINOK(outArchive.WriteHeader(item)); if (fileInStream) { - RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); - outArchive.Pos += copyCoderSpec->TotalSize; - if (copyCoderSpec->TotalSize != item.PackSize) + for (unsigned numPasses = 0;; numPasses++) { + /* we support 2 attempts to write header: + pass-0: main pass: + pass-1: additional pass, if size_of_file and size_of_header are changed */ + if (numPasses >= 2) + { + // opRes = NArchive::NUpdate::NOperationResult::kError_FileChanged; + // break; + return E_FAIL; + } + + const UInt64 dataPos = outArchive.Pos; + RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); + outArchive.Pos += copyCoderSpec->TotalSize; + RINOK(outArchive.Write_AfterDataResidual(copyCoderSpec->TotalSize)); + + // if (numPasses >= 10) // for debug + if (copyCoderSpec->TotalSize == item.PackSize) + break; + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kOutArcIndex, (UInt32)ui.IndexInClient, + NUpdateNotifyOp::kInFileChanged)) + } + if (!outSeekStream) return E_FAIL; - UInt64 backOffset = outArchive.Pos - fileHeaderStartPos; - RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL)); - outArchive.Pos = fileHeaderStartPos; + const UInt64 nextPos = outArchive.Pos; + RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL)); + outArchive.Pos = headerPos; item.PackSize = copyCoderSpec->TotalSize; + RINOK(outArchive.WriteHeader(item)); - RINOK(outSeekStream->Seek((Int64)item.PackSize, STREAM_SEEK_CUR, NULL)); - outArchive.Pos += item.PackSize; + + // if (numPasses >= 10) // for debug + if (outArchive.Pos == dataPos) + { + const UInt64 alignedSize = nextPos - dataPos; + if (alignedSize != 0) + { + RINOK(outSeekStream->Seek(alignedSize, STREAM_SEEK_CUR, NULL)); + outArchive.Pos += alignedSize; + } + break; + } + + // size of header was changed. + // we remove data after header and try new attempt, if required + CMyComPtr fileSeekStream; + fileInStream->QueryInterface(IID_IInStream, (void **)&fileSeekStream); + if (!fileSeekStream) + return E_FAIL; + RINOK(fileSeekStream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(outSeekStream->SetSize(outArchive.Pos)); + if (item.PackSize == 0) + break; } - RINOK(outArchive.FillDataResidual(item.PackSize)); } } complexity += item.PackSize; + fileInStream.Release(); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } else { + // (ui.NewData == false) + + if (opCallback) + { + RINOK(opCallback->ReportOperation( + NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, + NUpdateNotifyOp::kReplicate)) + } + const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc]; - UInt64 size; + UInt64 size, pos; if (ui.NewProps) { @@ -216,44 +511,37 @@ item.PackSize = existItem.PackSize; } - item.DeviceMajorDefined = existItem.DeviceMajorDefined; - item.DeviceMinorDefined = existItem.DeviceMinorDefined; + item.DeviceMajor_Defined = existItem.DeviceMajor_Defined; + item.DeviceMinor_Defined = existItem.DeviceMinor_Defined; item.DeviceMajor = existItem.DeviceMajor; item.DeviceMinor = existItem.DeviceMinor; item.UID = existItem.UID; item.GID = existItem.GID; RINOK(outArchive.WriteHeader(item)); - RINOK(inStream->Seek((Int64)existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); - size = existItem.PackSize; + size = existItem.Get_PackSize_Aligned(); + pos = existItem.Get_DataPos(); } else { - RINOK(inStream->Seek((Int64)existItem.HeaderPos, STREAM_SEEK_SET, NULL)); - size = existItem.GetFullSize(); + size = existItem.Get_FullSize_Aligned(); + pos = existItem.HeaderPos; } - - streamSpec->Init(size); - if (opCallback) + if (size != 0) { - RINOK(opCallback->ReportOperation( - NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, - NUpdateNotifyOp::kReplicate)) + RINOK(inStream->Seek((Int64)pos, STREAM_SEEK_SET, NULL)); + streamSpec->Init(size); + // 22.00 : we copy Residual data from old archive to new archive instead of zeroing + RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); + if (copyCoderSpec->TotalSize != size) + return E_FAIL; + outArchive.Pos += size; + // RINOK(outArchive.Write_AfterDataResidual(existItem.PackSize)); + complexity += size; } - - RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); - if (copyCoderSpec->TotalSize != size) - return E_FAIL; - outArchive.Pos += size; - RINOK(outArchive.FillDataResidual(existItem.PackSize)); - complexity += size; } } - - lps->InSize = lps->OutSize = complexity; - RINOK(lps->SetCur()); - return outArchive.WriteFinishHeader(); } }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarUpdate.h 7zip-22.01/CPP/7zip/Archive/Tar/TarUpdate.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Tar/TarUpdate.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Tar/TarUpdate.h 2022-03-24 11:00:00.000000000 +0000 @@ -15,27 +15,60 @@ int IndexInArc; unsigned IndexInClient; UInt64 Size; - Int64 MTime; + // Int64 MTime; UInt32 Mode; bool NewData; bool NewProps; bool IsDir; + bool DeviceMajor_Defined; + bool DeviceMinor_Defined; + UInt32 UID; + UInt32 GID; + UInt32 DeviceMajor; + UInt32 DeviceMinor; AString Name; AString User; AString Group; - CUpdateItem(): Size(0), IsDir(false) {} + CPaxTimes PaxTimes; + + CUpdateItem(): + Size(0), + IsDir(false), + DeviceMajor_Defined(false), + DeviceMinor_Defined(false), + UID(0), + GID(0) + {} +}; + + +struct CUpdateOptions +{ + UINT CodePage; + unsigned UtfFlags; + bool PosixMode; + CBoolPair Write_MTime; + CBoolPair Write_ATime; + CBoolPair Write_CTime; + CTimeOptions TimeOptions; }; + HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CObjectVector &inputItems, const CObjectVector &updateItems, - UINT codePage, unsigned utfFlags, + const CUpdateOptions &options, IArchiveUpdateCallback *updateCallback); HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, UINT codePage, unsigned utfFlags, bool convertSlash); +HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt); + +void Get_AString_From_UString(const UString &s, AString &res, + UINT codePage, unsigned utfFlags); + }} #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfHandler.cpp 7zip-22.01/CPP/7zip/Archive/Udf/UdfHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Udf/UdfHandler.cpp 2022-06-29 12:00:00.000000000 +0000 @@ -27,11 +27,17 @@ return; if (t.IsLocal()) numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60); - FILETIME ft; - UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10; - ft.dwLowDateTime = (UInt32)v; - ft.dwHighDateTime = (UInt32)(v >> 32); - prop = ft; + const UInt32 m0 = d[9]; + const UInt32 m1 = d[10]; + const UInt32 m2 = d[11]; + unsigned numDigits = 0; + UInt64 v = numSecs * 10000000; + if (m0 < 100 && m1 < 100 && m2 < 100) + { + v += m0 * 100000 + m1 * 1000 + m2 * 10; + numDigits = 6; + } + prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + numDigits); } static const Byte kProps[] = @@ -41,14 +47,23 @@ kpidSize, kpidPackSize, kpidMTime, - kpidATime + kpidATime, + kpidCTime, + kpidChangeTime, + // kpidUserId, + // kpidGroupId, + // kpidPosixAttrib, + kpidLinks }; static const Byte kArcProps[] = { - kpidComment, + kpidUnpackVer, kpidClusterSize, - kpidCTime + kpidSectorSize, + kpidCTime, + kpidMTime, + kpidComment }; IMP_IInArchive_Props @@ -62,6 +77,18 @@ { case kpidPhySize: prop = _archive.PhySize; break; + case kpidUnpackVer: + { + if (_archive.LogVols.Size() == 1) + { + UString s; + const CLogVol &vol = _archive.LogVols[0]; + vol.DomainId.AddUdfVersionTo(s); + if (!s.IsEmpty()) + prop = s; + } + break; + } case kpidComment: { UString comment = _archive.GetComment(); @@ -83,12 +110,21 @@ } break; + case kpidSectorSize: prop = ((UInt32)1 << _archive.SecLogSize); break; + case kpidCTime: if (_archive.LogVols.Size() == 1) { const CLogVol &vol = _archive.LogVols[0]; if (vol.FileSets.Size() >= 1) - UdfTimeToFileTime(vol.FileSets[0].RecodringTime, prop); + UdfTimeToFileTime(vol.FileSets[0].RecordingTime, prop); + } + break; + case kpidMTime: + if (_archive.PrimeVols.Size() == 1) + { + const CPrimeVol &pv = _archive.PrimeVols[0]; + UdfTimeToFileTime(pv.RecordingTime, prop); } break; @@ -153,6 +189,7 @@ { const CLogVol &vol = _archive.LogVols[volIndex]; bool showFileSetName = (vol.FileSets.Size() > 1); + // showFileSetName = true; // for debug FOR_VECTOR (fsIndex, vol.FileSets) { const CFileSet &fs = vol.FileSets[fsIndex]; @@ -205,6 +242,15 @@ case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break; case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; + case kpidCTime: + if (item.IsExtended) + UdfTimeToFileTime(item.CreateTime, prop); + break; + case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break; + // case kpidUserId: prop = item.Uid; break; + // case kpidGroupId: prop = item.Gid; break; + // case kpidPosixAttrib: prop = (UInt32)item.Permissions; break; + case kpidLinks: prop = (UInt32)item.FileLinkCount; break; } } prop.Detach(value); @@ -247,7 +293,7 @@ if (size < len) return S_FALSE; - int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; UInt32 logBlockNumber = extent.Pos; const CPartition &partition = _archive.Partitions[partitionIndex]; UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) + diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfHandler.h 7zip-22.01/CPP/7zip/Archive/Udf/UdfHandler.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfHandler.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Udf/UdfHandler.h 2022-06-28 13:00:00.000000000 +0000 @@ -24,9 +24,9 @@ public IInArchiveGetStream, public CMyUnknownImp { + CRecordVector _refs2; CMyComPtr _inStream; CInArchive _archive; - CRecordVector _refs2; public: MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream) INTERFACE_IInArchive(;) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfIn.cpp 7zip-22.01/CPP/7zip/Archive/Udf/UdfIn.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfIn.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Udf/UdfIn.cpp 2022-06-29 12:00:00.000000000 +0000 @@ -10,6 +10,8 @@ #include "../../../../C/CpuArch.h" +#include "../../../Windows/PropVariantUtils.h" + #include "../../Common/RegisterArc.h" #include "../../Common/StreamUtils.h" @@ -25,6 +27,10 @@ #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) +#define G16(_offs_, dest) dest = Get16(p + (_offs_)); +#define G32(_offs_, dest) dest = Get32(p + (_offs_)); +#define G64(_offs_, dest) dest = Get64(p + (_offs_)); + namespace NArchive { namespace NUdf { @@ -39,7 +45,6 @@ static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33; #define CRC16_INIT_VAL 0 -// #define CRC16_GET_DIGEST(crc) (crc) #define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8))) #define kCrc16Poly 0x1021 @@ -57,22 +62,20 @@ } } -static UInt32 MY_FAST_CALL Crc16_Update(UInt32 v, const void *data, size_t size) +static UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size) { + UInt32 v = CRC16_INIT_VAL; const Byte *p = (const Byte *)data; - for (; size > 0 ; size--, p++) + const Byte *pEnd = p + size; + for (; p != pEnd; p++) v = CRC16_UPDATE_BYTE(v, *p); return v; } -static UInt32 MY_FAST_CALL Crc16Calc(const void *data, size_t size) -{ - return Crc16_Update(CRC16_INIT_VAL, data, size); -} - static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit; +// ---------- ECMA Part 1 ---------- void CDString::Parse(const Byte *p, unsigned size) { @@ -82,16 +85,17 @@ static UString ParseDString(const Byte *data, unsigned size) { UString res; - if (size > 0) + if (size != 0) { wchar_t *p; - Byte type = data[0]; + const Byte type = *data++; + size--; if (type == 8) { p = res.GetBuf(size); - for (unsigned i = 1; i < size; i++) + for (unsigned i = 0; i < size; i++) { - wchar_t c = data[i]; + const wchar_t c = data[i]; if (c == 0) break; *p++ = c; @@ -99,10 +103,11 @@ } else if (type == 16) { + size &= ~(unsigned)1; p = res.GetBuf(size / 2); - for (unsigned i = 1; i + 2 <= size; i += 2) + for (unsigned i = 0; i < size; i += 2) { - wchar_t c = GetBe16(data + i); + const wchar_t c = GetBe16(data + i); if (c == 0) break; *p++ = c; @@ -116,75 +121,117 @@ return res; } +UString CDString32::GetString() const +{ + const unsigned size = Data[sizeof(Data) - 1]; + return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); +} + UString CDString128::GetString() const { - unsigned size = Data[sizeof(Data) - 1]; + const unsigned size = Data[sizeof(Data) - 1]; return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1))); } UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); } -void CTime::Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } +void CTime::Parse(const Byte *p) { memcpy(Data, p, sizeof(Data)); } -/* -void CRegId::Parse(const Byte *buf) + +static void AddCommentChars(UString &dest, const char *s, size_t size) { - Flags = buf[0]; - memcpy(Id, buf + 1, sizeof(Id)); - memcpy(Suffix, buf + 24, sizeof(Suffix)); + for (size_t i = 0; i < size; i++) + { + char c = s[i]; + if (c == 0) + break; + if (c < 0x20) + c = '_'; + dest += (wchar_t)c; + } } -*/ -// ECMA 3/7.1 -struct CExtent +void CRegId::Parse(const Byte *p) { - UInt32 Len; - UInt32 Pos; + Flags = p[0]; + memcpy(Id, p + 1, sizeof(Id)); + memcpy(Suffix, p + 24, sizeof(Suffix)); +} - void Parse(const Byte *buf); -}; +void CRegId::AddCommentTo(UString &s) const +{ + AddCommentChars(s, Id, sizeof(Id)); +} -void CExtent::Parse(const Byte *buf) +void CRegId::AddUdfVersionTo(UString &s) const { - Len = Get32(buf); - Pos = Get32(buf + 4); + // use it only for "Domain Identifier Suffix" and "UDF Identifier Suffix" + // UDF 2.1.5.3 + // Revision in hex (3 digits) + const Byte minor = Suffix[0]; + const Byte major = Suffix[1]; + if (major != 0 || minor != 0) + { + char temp[16]; + ConvertUInt32ToHex(major, temp); + s += temp; + s += '.'; + ConvertUInt32ToHex8Digits(minor, temp); + s += &temp[8 - 2]; + } } + +// ---------- ECMA Part 3: Volume Structure ---------- + +void CExtent::Parse(const Byte *p) +{ + /* Len shall be less than < 2^30. + Unless otherwise specified, the length shall be an integral multiple of the logical sector size. + If (Len == 0), no extent is specified and (Pos) shall contain 0 */ + G32 (0, Len); + G32 (4, Pos); +} + + // ECMA 3/7.2 struct CTag { UInt16 Id; - UInt16 Version; + // UInt16 Version; // Byte Checksum; // UInt16 SerialNumber; // UInt16 Crc; - // UInt16 CrcLen; - // UInt32 TagLocation; + UInt16 CrcLen; + // UInt32 TagLocation; // the number of the logical sector - HRESULT Parse(const Byte *buf, size_t size); + HRESULT Parse(const Byte *p, size_t size); }; -HRESULT CTag::Parse(const Byte *buf, size_t size) +HRESULT CTag::Parse(const Byte *p, size_t size) { if (size < 16) return S_FALSE; - Byte sum = 0; - int i; - for (i = 0; i < 4; i++) sum = (Byte)(sum + buf[i]); - for (i = 5; i < 16; i++) sum = (Byte)(sum + buf[i]); - if (sum != buf[4] || buf[5] != 0) return S_FALSE; - - Id = Get16(buf); - Version = Get16(buf + 2); - // SerialNumber = Get16(buf + 6); - UInt32 crc = Get16(buf + 8); - UInt32 crcLen = Get16(buf + 10); - // TagLocation = Get32(buf + 12); + { + unsigned sum = 0; + for (unsigned i = 0; i < 16; i++) + sum = sum + p[i]; + if ((Byte)(sum - p[4]) != p[4] || p[5] != 0) + return S_FALSE; + } + Id = Get16(p); + const UInt16 Version = Get16(p + 2); + if (Version != 2 && Version != 3) + return S_FALSE; + // SerialNumber = Get16(p + 6); + const UInt32 crc = Get16(p + 8); + CrcLen = Get16(p + 10); + // TagLocation = Get32(p + 12); - if (size >= 16 + crcLen) - if (crc == Crc16Calc(buf + 16, (size_t)crcLen)) + if (size >= 16 + (size_t)CrcLen) + if (crc == Crc16Calc(p + 16, (size_t)CrcLen)) return S_OK; return S_FALSE; } @@ -210,52 +257,78 @@ DESC_TYPE_Terminal = 260, DESC_TYPE_File = 261, DESC_TYPE_ExtendedAttrHeader = 262, - DESC_TYPE_UnallocatedSpace = 263, + DESC_TYPE_UnallocatedSpaceEntry = 263, DESC_TYPE_SpaceBitmap = 264, DESC_TYPE_PartitionIntegrity = 265, DESC_TYPE_ExtendedFile = 266 }; -void CLogBlockAddr::Parse(const Byte *buf) +void CLogBlockAddr::Parse(const Byte *p) { - Pos = Get32(buf); - PartitionRef = Get16(buf + 4); + G32 (0, Pos); + G16 (4, PartitionRef); } -void CShortAllocDesc::Parse(const Byte *buf) +void CShortAllocDesc::Parse(const Byte *p) { - Len = Get32(buf); - Pos = Get32(buf + 4); + G32 (0, Len); + G32 (4, Pos); } /* -void CADImpUse::Parse(const Byte *buf) +void CADImpUse::Parse(const Byte *p) { - Flags = Get16(buf); - UdfUniqueId = Get32(buf + 2); + G16 (0, Flags); + G32 (2, UdfUniqueId); } */ -void CLongAllocDesc::Parse(const Byte *buf) +void CLongAllocDesc::Parse(const Byte *p) { - Len = Get32(buf); - Location.Parse(buf + 4); - // memcpy(ImplUse, buf + 10, sizeof(ImplUse)); + G32 (0, Len); + Location.Parse(p + 4); + // memcpy(ImplUse, p + 10, sizeof(ImplUse)); // adImpUse.Parse(ImplUse); } -bool CInArchive::CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const + +void CPrimeVol::Parse(const Byte *p) +{ + // G32 (16, VolumeDescriptorSequenceNumber); + G32 (20, PrimaryVolumeDescriptorNumber); + VolumeId.Parse(p + 24); + G16 (56, VolumeSequenceNumber); + G16 (58, MaximumVolumeSequenceNumber); + // G16 (60, InterchangeLevel); + // G16 (62, MaximumInterchangeLevel); + // G32 (64, CharacterSetList) + // G32 (68, MaximumCharacterSetList) + VolumeSetId.Parse(p + 72); + // 200 64 Descriptor Character Set charspec (1/7.2.1) + // 264 64 Explanatory Character Set charspec (1/7.2.1) + // VolumeAbstract.Parse(p + 328); + // VolumeCopyrightNotice.Parse(p + 336); + ApplicationId.Parse(p + 344); + RecordingTime.Parse(p + 376); + ImplId.Parse(p + 388); + // 420 64 Implementation Use bytes + // G32 (484, PredecessorVolumeDescriptorSequenceLocation); + // G16 (488, Flags); +} + + + +bool CInArchive::CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const { const CLogVol &vol = LogVols[volIndex]; - if (partitionRef >= (int)vol.PartitionMaps.Size()) + if (partitionRef >= vol.PartitionMaps.Size()) return false; const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; - return (offset + len) <= (((UInt64)partition.Pos + partition.Len) << SecLogSize); + return ((UInt64)blockPos * vol.BlockSize + len) <= ((UInt64)partition.Len << SecLogSize); } -bool CInArchive::CheckItemExtents(int volIndex, const CItem &item) const +bool CInArchive::CheckItemExtents(unsigned volIndex, const CItem &item) const { FOR_VECTOR (i, item.Extents) { @@ -266,7 +339,7 @@ return true; } -HRESULT CInArchive::Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) +HRESULT CInArchive::Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf) { if (!CheckExtent(volIndex, partitionRef, blockPos, len)) return S_FALSE; @@ -274,20 +347,20 @@ const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize; RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); - HRESULT res = ReadStream_FALSE(_stream, buf, len); - if (res == S_FALSE && offset + len > FileSize) + offset += len; + UpdatePhySize(offset); + const HRESULT res = ReadStream_FALSE(_stream, buf, len); + if (res == S_FALSE && offset > FileSize) UnexpectedEnd = true; - RINOK(res); - UpdatePhySize(offset + len); - return S_OK; + return res; } -HRESULT CInArchive::Read(int volIndex, const CLongAllocDesc &lad, Byte *buf) +HRESULT CInArchive::ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf) { return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf); } -HRESULT CInArchive::ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf) +HRESULT CInArchive::ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf) { if (item.Size >= (UInt32)1 << 30) return S_FALSE; @@ -301,7 +374,7 @@ FOR_VECTOR (i, item.Extents) { const CMyExtent &e = item.Extents[i]; - UInt32 len = e.GetLen(); + const UInt32 len = e.GetLen(); RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos)); pos += len; } @@ -311,36 +384,70 @@ void CIcbTag::Parse(const Byte *p) { - // PriorDirectNum = Get32(p); - // StrategyType = Get16(p + 4); - // StrategyParam = Get16(p + 6); - // MaxNumOfEntries = Get16(p + 8); + // G32 (0, PriorDirectNum); + // G16 (4, StrategyType); + // G16 (6, StrategyParam); + // G16 (8, MaxNumOfEntries); FileType = p[11]; // ParentIcb.Parse(p + 12); - Flags = Get16(p + 18); + G16 (18, Flags); } + +// ECMA 4/14.9 File Entry +// UDF FileEntry 2.3.6 + +// ECMA 4/14.17 Extended File Entry + void CItem::Parse(const Byte *p) { - // Uid = Get32(p + 36); - // Gid = Get32(p + 40); - // Permissions = Get32(p + 44); - // FileLinkCount = Get16(p + 48); + // (-1) can be stored in Uid/Gid. + // G32 (36, Uid); + // G32 (40, Gid); + // G32 (44, Permissions); + G16 (48, FileLinkCount); // RecordFormat = p[50]; // RecordDisplayAttr = p[51]; - // RecordLen = Get32(p + 52); - Size = Get64(p + 56); - NumLogBlockRecorded = Get64(p + 64); + // G32 (52, RecordLen); + G64 (56, Size); + if (IsExtended) + { + // The sum of all Information Length fields for all streams of a file (including the default stream). If this file has no + // streams, the Object Size shall be equal to the Information Length. + // G64 (64, ObjectSize); + p += 8; + } + G64 (64, NumLogBlockRecorded); ATime.Parse(p + 72); MTime.Parse(p + 84); - // AttrtTime.Parse(p + 96); - // CheckPoint = Get32(p + 108); + if (IsExtended) + { + CreateTime.Parse(p + 96); + p += 12; + } + AttribTime.Parse(p + 96); + // G32 (108, CheckPoint); + /* + if (IsExtended) + { + // Get32(p + 112); // reserved + p += 4; + } // ExtendedAttrIcb.Parse(p + 112); + if (IsExtended) + { + StreamDirectoryIcb.Parse(p + 128); + p += 16; + } + */ + // ImplId.Parse(p + 128); - // UniqueId = Get64(p + 160); + // G64 (160, UniqueId); } -// 4/14.4 + +// ECMA 4/14.4 + struct CFileId { // UInt16 FileVersion; @@ -350,38 +457,40 @@ CLongAllocDesc Icb; bool IsItLinkParent() const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; } - HRESULT Parse(const Byte *p, size_t size, size_t &processed); + size_t Parse(const Byte *p, size_t size); }; -HRESULT CFileId::Parse(const Byte *p, size_t size, size_t &processed) +size_t CFileId::Parse(const Byte *p, size_t size) { - processed = 0; + size_t processed = 0; if (size < 38) - return S_FALSE; + return 0; CTag tag; RINOK(tag.Parse(p, size)); if (tag.Id != DESC_TYPE_FileId) - return S_FALSE; + return 0; // FileVersion = Get16(p + 16); FileCharacteristics = p[18]; - unsigned idLen = p[19]; + const unsigned idLen = p[19]; Icb.Parse(p + 20); - unsigned impLen = Get16(p + 36); + const unsigned impLen = Get16(p + 36); if (size < 38 + idLen + impLen) - return S_FALSE; - // ImplUse.SetCapacity(impLen); + return 0; processed = 38; - // memcpy(ImplUse, p + processed, impLen); + // ImplUse.CopyFrom(p + processed, impLen); processed += impLen; Id.Parse(p + processed, idLen); processed += idLen; for (;(processed & 3) != 0; processed++) if (p[processed] != 0) - return S_FALSE; - return (processed <= size) ? S_OK : S_FALSE; + return 0; + if ((size_t)tag.CrcLen + 16 != processed) return 0; + return (processed <= size) ? processed : 0; } -HRESULT CInArchive::ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) + + +HRESULT CInArchive::ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) { if (Files.Size() % 100 == 0) RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes)); @@ -389,12 +498,12 @@ return S_FALSE; CFile &file = Files.Back(); const CLogVol &vol = LogVols[volIndex]; - unsigned partitionRef = lad.Location.PartitionRef; + const unsigned partitionRef = lad.Location.PartitionRef; if (partitionRef >= vol.PartitionMaps.Size()) return S_FALSE; CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex]; - UInt32 key = lad.Location.Pos; + const UInt32 key = lad.Location.Pos; UInt32 value; const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1; if (partition.Map.Find(key, value)) @@ -416,32 +525,47 @@ return S_OK; } -HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) + +// (fsIndex = -1) means that it's metadata file + +HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed) { - if (Items.Size() > kNumItemsMax) + if (Items.Size() >= kNumItemsMax) return S_FALSE; - Items.Add(CItem()); - CItem &item = Items.Back(); + CItem &item = Items.AddNew(); const CLogVol &vol = LogVols[volIndex]; - if (lad.GetLen() != vol.BlockSize) + const size_t size = lad.GetLen(); + if (size != vol.BlockSize) return S_FALSE; - const size_t size = lad.GetLen(); CByteBuffer buf(size); - RINOK(Read(volIndex, lad, buf)); + RINOK(ReadLad(volIndex, lad, buf)); CTag tag; const Byte *p = buf; RINOK(tag.Parse(p, size)); - if (size < 176) + + item.IsExtended = (tag.Id == DESC_TYPE_ExtendedFile); + const size_t kExtendOffset = item.IsExtended ? 40 : 0; + + if (size < kExtendOffset + 176) return S_FALSE; - if (tag.Id != DESC_TYPE_File) + if (tag.Id != DESC_TYPE_File && + tag.Id != DESC_TYPE_ExtendedFile) return S_FALSE; item.IcbTag.Parse(p + 16); - if (item.IcbTag.FileType != ICB_FILE_TYPE_DIR && + + if (fsIndex < 0) + { + if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA && + item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR) + return S_FALSE; + } + else if ( + item.IcbTag.FileType != ICB_FILE_TYPE_DIR && item.IcbTag.FileType != ICB_FILE_TYPE_FILE) return S_FALSE; @@ -449,12 +573,12 @@ _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size; - UInt32 extendedAttrLen = Get32(p + 168); - UInt32 allocDescriptorsLen = Get32(p + 172); + const UInt32 extendedAttrLen = Get32(p + 168 + kExtendOffset); + const UInt32 allocDescriptorsLen = Get32(p + 172 + kExtendOffset); if ((extendedAttrLen & 3) != 0) return S_FALSE; - size_t pos = 176; + size_t pos = 176 + kExtendOffset; if (extendedAttrLen > size - pos) return S_FALSE; /* @@ -472,10 +596,10 @@ */ pos += extendedAttrLen; - int desctType = item.IcbTag.GetDescriptorType(); + const int descType = item.IcbTag.GetDescriptorType(); if (allocDescriptorsLen > size - pos) return S_FALSE; - if (desctType == ICB_DESC_TYPE_INLINE) + if (descType == ICB_DESC_TYPE_INLINE) { item.IsInline = true; item.InlineData.CopyFrom(p + pos, allocDescriptorsLen); @@ -483,12 +607,12 @@ else { item.IsInline = false; - if (desctType != ICB_DESC_TYPE_SHORT && desctType != ICB_DESC_TYPE_LONG) + if (descType != ICB_DESC_TYPE_SHORT && descType != ICB_DESC_TYPE_LONG) return S_FALSE; for (UInt32 i = 0; i < allocDescriptorsLen;) { CMyExtent e; - if (desctType == ICB_DESC_TYPE_SHORT) + if (descType == ICB_DESC_TYPE_SHORT) { if (i + 8 > allocDescriptorsLen) return S_FALSE; @@ -516,6 +640,9 @@ if (item.IcbTag.IsDir()) { + if (fsIndex < 0) + return S_FALSE; + if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item)) return S_FALSE; CByteBuffer buf2; @@ -525,13 +652,17 @@ item.InlineData.Free(); const Byte *p2 = buf2; - const size_t size2 = buf2.Size(); - size_t processedTotal = 0; - for (; processedTotal < size2;) + size_t size2 = buf2.Size(); + while (size2 != 0) { - size_t processedCur; CFileId fileId; - RINOK(fileId.Parse(p2 + processedTotal, size2 - processedTotal, processedCur)); + { + const size_t cur = fileId.Parse(p2, size2); + if (cur == 0) + return S_FALSE; + p2 += cur; + size2 -= cur; + } if (!fileId.IsItLinkParent()) { CFile file; @@ -545,12 +676,11 @@ return S_FALSE; item.SubFiles.Add(Files.Size()); - if (Files.Size() > kNumFilesMax) + if (Files.Size() >= kNumFilesMax) return S_FALSE; Files.Add(file); RINOK(ReadFileItem(volIndex, fsIndex, fileId.Icb, numRecurseAllowed)); } - processedTotal += processedCur; } } else @@ -567,6 +697,7 @@ return S_OK; } + HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed) { if ((_numRefs & 0xFFF) == 0) @@ -591,6 +722,7 @@ return S_OK; } + API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size) { UInt32 res = k_IsArc_Res_NO; @@ -608,7 +740,11 @@ CTag tag; if (tag.Parse(p + offset, bufSize) == S_OK) if (tag.Id == DESC_TYPE_AnchorVolPtr) - return k_IsArc_Res_YES; + { + if (Get32(p + offset + 12) == 256 && // TagLocation + tag.CrcLen >= 16) + return k_IsArc_Res_YES; + } } } } @@ -656,7 +792,7 @@ { if (SecLogSize < 8) return S_FALSE; - UInt32 offset = (UInt32)256 << SecLogSize; + const UInt32 offset = (UInt32)256 << SecLogSize; if (offset >= fileSize) continue; RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); @@ -668,71 +804,86 @@ CTag tag; if (tag.Parse(buf, readSize) == S_OK) if (tag.Id == DESC_TYPE_AnchorVolPtr) - break; + { + if (Get32(buf + 12) == 256 && + tag.CrcLen >= 16) // TagLocation + break; + } } } PhySize = (UInt32)(256 + 1) << SecLogSize; IsArc = true; + // UDF 2.2.3 AnchorVolumeDescriptorPointer + CExtent extentVDS; extentVDS.Parse(buf + 16); { CExtent extentVDS2; extentVDS2.Parse(buf + 24); - UpdatePhySize(((UInt64)extentVDS.Pos << SecLogSize) + extentVDS.Len); - UpdatePhySize(((UInt64)extentVDS2.Pos << SecLogSize) + extentVDS2.Len); + UpdatePhySize(extentVDS); + UpdatePhySize(extentVDS2); } for (UInt32 location = 0; ; location++) { - const size_t bufSize = (size_t)1 << SecLogSize; - if (((UInt64)(location + 1) << SecLogSize) > extentVDS.Len) + if (location >= (extentVDS.Len >> SecLogSize)) return S_FALSE; - UInt64 offs = (UInt64)(extentVDS.Pos + location) << SecLogSize; - RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL)); - HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); - if (res == S_FALSE && offs + bufSize > FileSize) - UnexpectedEnd = true; - RINOK(res); - - - CTag tag; + const size_t bufSize = (size_t)1 << SecLogSize; { - const size_t pos = 0; - RINOK(tag.Parse(buf + pos, bufSize - pos)); + const UInt64 offs = ((UInt64)extentVDS.Pos + location) << SecLogSize; + RINOK(_stream->Seek(offs, STREAM_SEEK_SET, NULL)); + const HRESULT res = ReadStream_FALSE(_stream, buf, bufSize); + if (res == S_FALSE && offs + bufSize > FileSize) + UnexpectedEnd = true; + RINOK(res); } + + CTag tag; + RINOK(tag.Parse(buf, bufSize)); + if (tag.Id == DESC_TYPE_Terminating) break; - + + if (tag.Id == DESC_TYPE_PrimVol) + { + CPrimeVol &pm = PrimeVols.AddNew(); + pm.Parse(buf); + continue; + } + if (tag.Id == DESC_TYPE_Partition) { // Partition Descriptor - // ECMA 167 3/10.5 - // UDF / 2.2.14 - + // ECMA 3/10.5 + // UDF 2.2.14 if (Partitions.Size() >= kNumPartitionsMax) return S_FALSE; CPartition partition; - // UInt32 volDescSeqNumer = Get32(buf + 16); - // partition.Flags = Get16(buf + 20); + // const UInt32 volDescSeqNumer = Get32(buf + 16); + partition.Flags = Get16(buf + 20); partition.Number = Get16(buf + 22); - // partition.ContentsId.Parse(buf + 24); + partition.ContentsId.Parse(buf + 24); // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse)); - // ContentsUse is Partition Header Description. + // ContentsUse contains Partition Header Description. + // ECMA 4/14.3 + // UDF PartitionHeaderDescriptor 2.3.3 - // partition.AccessType = Get32(buf + 184); + partition.AccessType = Get32(buf + 184); partition.Pos = Get32(buf + 188); partition.Len = Get32(buf + 192); - // partition.ImplId.Parse(buf + 196); + partition.ImplId.Parse(buf + 196); // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse)); PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len)); Partitions.Add(partition); + continue; } - else if (tag.Id == DESC_TYPE_LogicalVol) + + if (tag.Id == DESC_TYPE_LogicalVol) { /* Logical Volume Descriptor ECMA 3/10.6 @@ -740,46 +891,65 @@ if (LogVols.Size() >= kNumLogVolumesMax) return S_FALSE; - CLogVol vol; + CLogVol &vol = LogVols.AddNew(); + vol.Id.Parse(buf + 84); vol.BlockSize = Get32(buf + 212); - // vol.DomainId.Parse(buf + 216); - + if (vol.BlockSize != ((UInt32)1 << SecLogSize)) + { + // UDF 2.2.4.2 LogicalBlockSize + // UDF probably doesn't allow different sizes + return S_FALSE; + } + /* if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30)) return S_FALSE; - - // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); - vol.FileSetLocation.Parse(buf + 248); + */ + + vol.DomainId.Parse(buf + 216); + + // ECMA 4/3.1 + // UDF 2.2.4.4 LogicalVolumeContentsUse /* the extent in which the first File Set Descriptor Sequence of the logical volume is recorded */ + vol.FileSetLocation.Parse(buf + 248); + // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse)); + + vol.ImplId.Parse(buf + 272); + // memcpy(vol.ImplUse, buf + 304, sizeof(vol.ImplUse)); + // vol.IntegritySequenceExtent.Parse(buf + 432); - // UInt32 mapTableLength = Get32(buf + 264); - UInt32 numPartitionMaps = Get32(buf + 268); + const UInt32 mapTableLen = Get32(buf + 264); + const UInt32 numPartitionMaps = Get32(buf + 268); if (numPartitionMaps > kNumPartitionsMax) return S_FALSE; - // vol.ImplId.Parse(buf + 272); - // memcpy(vol.ImplUse, buf + 128, sizeof(vol.ImplUse)); PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps)); + size_t pos = 440; + if (mapTableLen > bufSize - pos) + return S_FALSE; + const size_t posLimit = pos + mapTableLen; + for (UInt32 i = 0; i < numPartitionMaps; i++) { - if (pos + 2 > bufSize) + // ECMA 3/10.7 Partition maps + if (pos + 2 > posLimit) return S_FALSE; CPartitionMap pm; - pm.Type = buf[pos]; + pm.Type = buf[pos + 0]; // pm.Length = buf[pos + 1]; - Byte len = buf[pos + 1]; - - if (pos + len > bufSize) + const Byte len = buf[pos + 1]; + if (pos + len > posLimit) return S_FALSE; // memcpy(pm.Data, buf + pos + 2, pm.Length - 2); if (pm.Type == 1) { - if (len != 6) // < 6 + // ECMA 3/10.7.2 + if (len != 6) return S_FALSE; - // pm.VolSeqNumber = Get16(buf + pos + 2); + pm.VolumeSequenceNumber = Get16(buf + pos + 2); pm.PartitionNumber = Get16(buf + pos + 4); PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber)); } @@ -790,28 +960,60 @@ /* ECMA 10.7.3 / Type 2 Partition Map 62 bytes: Partition Identifier. */ - /* UDF 2.6 - 2.2.8 Virtual Partition Map - This is an extension of ECMA 167 to expand its scope to include - sequentially written media (eg. CD-R). This extension is for a - Partition Map entry to describe a virtual space. */ + /* UDF + 2.2.8 "*UDF Virtual Partition" + 2.2.9 "*UDF Sparable Partition" + 2.2.10 "*UDF Metadata Partition" + */ - // It's not implemented still. - if (Get16(buf + pos + 2) != 0) + if (Get16(buf + pos + 2) != 0) // reserved return S_FALSE; - // pm.VolSeqNumber = Get16(buf + pos + 36); + + pm.PartitionTypeId.Parse(buf + pos + 4); + pm.VolumeSequenceNumber = Get16(buf + pos + 36); pm.PartitionNumber = Get16(buf + pos + 38); + + if (memcmp(pm.PartitionTypeId.Id, "*UDF Metadata Partition", 23) != 0) + return S_FALSE; + + // UDF 2.2.10 Metadata Partition Map + pm.MetadataFileLocation = Get32(buf + pos + 40); + // pm.MetadataMirrorFileLocation = Get32(buf + pos + 44); + // pm.MetadataBitmapFileLocation = Get32(buf + pos + 48); + // pm.AllocationUnitSize = Get32(buf + pos + 52); + // pm.AlignmentUnitSize = Get16(buf + pos + 56); + // pm.Flags = buf[pos + 58]; + PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber)); // Unsupported = true; - return S_FALSE; + // return S_FALSE; } else return S_FALSE; pos += len; vol.PartitionMaps.Add(pm); } - LogVols.Add(vol); + continue; } + + /* + if (tag.Id == DESC_TYPE_UnallocSpace) + { + // UInt32 volDescSeqNumer = Get32(buf + 16); + const UInt32 numAlocDescs = Get32(buf + 20); + // we need examples for (numAlocDescs != 0) case + if (numAlocDescs > (bufSize - 24) / 8) + return S_FALSE; + for (UInt32 i = 0; i < numAlocDescs; i++) + { + CExtent e; + e.Parse(buf + 24 + i * 8); + } + continue; + } + else + continue; + */ } UInt64 totalSize = 0; @@ -823,12 +1025,18 @@ FOR_VECTOR (pmIndex, vol.PartitionMaps) { CPartitionMap &pm = vol.PartitionMaps[pmIndex]; - unsigned i; - for (i = 0; i < Partitions.Size(); i++) + for (unsigned i = 0;; i++) { + if (i == Partitions.Size()) + return S_FALSE; CPartition &part = Partitions[i]; if (part.Number == pm.PartitionNumber) { + pm.PartitionIndex = i; + if (pm.Type == 2) + break; + + /* if (part.VolIndex >= 0) { // it's for 2.60. Fix it @@ -836,15 +1044,85 @@ return S_FALSE; // return S_FALSE; } - pm.PartitionIndex = i; part.VolIndex = volIndex; + */ totalSize += (UInt64)part.Len << SecLogSize; break; } } - if (i == Partitions.Size()) + } + } + + for (volIndex = 0; volIndex < LogVols.Size(); volIndex++) + { + CLogVol &vol = LogVols[volIndex]; + FOR_VECTOR (pmIndex, vol.PartitionMaps) + { + CPartitionMap &pm = vol.PartitionMaps[pmIndex]; + if (pm.Type != 2) + continue; + + { + CLongAllocDesc lad; + lad.Len = vol.BlockSize; + lad.Location.Pos = pm.MetadataFileLocation; + // lad.Location.Pos = pm.MetadataMirrorFileLocation; + + lad.Location.PartitionRef = (UInt16)pmIndex; + + /* we need correct PartitionMaps[lad.Location.PartitionRef].PartitionIndex. + so we can use pmIndex or find (Type==1) PartitionMap */ + FOR_VECTOR (pmIndex2, vol.PartitionMaps) + { + const CPartitionMap &pm2 = vol.PartitionMaps[pmIndex2]; + if (pm2.PartitionNumber == pm.PartitionNumber && pm2.Type == 1) + { + lad.Location.PartitionRef = (UInt16)pmIndex2; + break; + } + } + + RINOK(ReadItem(volIndex, + -1, // (fsIndex = -1) means that it's metadata + lad, + 1)); // numRecurseAllowed + } + { + const CItem &item = Items.Back(); + if (!CheckItemExtents(volIndex, item)) + return S_FALSE; + if (item.Extents.Size() != 1) + return S_FALSE; + + const CMyExtent &e = item.Extents[0]; + const CPartition &part = Partitions[pm.PartitionIndex]; + CPartition mp = part; + mp.IsMetadata = true; + // mp.Number = part.Number; + mp.Pos = part.Pos + e.Pos; + mp.Len = e.Len >> SecLogSize; + pm.PartitionIndex = Partitions.Add(mp); + } + // Items.DeleteBack(); // we can delete that metadata item + + /* + // short version of code to read metadata file. + RINOK(CInArchive::Read(volIndex, pmIndex, pm.MetadataFileLocation, 224, buf)); + CTag tag; + RINOK(tag.Parse(buf, 224)); + if (tag.Id != DESC_TYPE_ExtendedFile) return S_FALSE; + CShortAllocDesc sad; + sad.Parse(buf + 216); + const CPartition &part = Partitions[pm.PartitionIndex]; + CPartition mp = part; + mp.IsMetadata = true; + // mp.Number = part.Number; + mp.Pos = part.Pos + sad.Pos; + mp.Len = sad.Len >> SecLogSize; + pm.PartitionIndex = Partitions.Add(mp); + */ } } @@ -865,37 +1143,41 @@ if (nextExtent.GetLen() < 512) return S_FALSE; CByteBuffer buf2(nextExtent.GetLen()); - RINOK(Read(volIndex, nextExtent, buf2)); + RINOK(ReadLad(volIndex, nextExtent, buf2)); const Byte *p = buf2; - size_t size = nextExtent.GetLen(); + const size_t size = nextExtent.GetLen(); CTag tag; RINOK(tag.Parse(p, size)); + /* + // commented in 22.01 if (tag.Id == DESC_TYPE_ExtendedFile) { // ECMA 4 / 14.17 // 2.60 ?? return S_FALSE; } + */ if (tag.Id != DESC_TYPE_FileSet) return S_FALSE; PRF(printf("\n FileSet", volIndex)); CFileSet fs; - fs.RecodringTime.Parse(p + 16); + fs.RecordingTime.Parse(p + 16); // fs.InterchangeLevel = Get16(p + 18); // fs.MaxInterchangeLevel = Get16(p + 20); - // fs.FileSetNumber = Get32(p + 40); - // fs.FileSetDescNumber = Get32(p + 44); + fs.FileSetNumber = Get32(p + 40); + fs.FileSetDescNumber = Get32(p + 44); - // fs.Id.Parse(p + 304); - // fs.CopyrightId.Parse(p + 336); - // fs.AbstractId.Parse(p + 368); + fs.LogicalVolumeId.Parse(p + 112); + fs.Id.Parse(p + 304); + fs.CopyrightId.Parse(p + 336); + fs.AbstractId.Parse(p + 368); fs.RootDirICB.Parse(p + 400); - // fs.DomainId.Parse(p + 416); + fs.DomainId.Parse(p + 416); // fs.SystemStreamDirICB.Parse(p + 464); @@ -907,7 +1189,7 @@ FOR_VECTOR (fsIndex, vol.FileSets) { CFileSet &fs = vol.FileSets[fsIndex]; - unsigned fileIndex = Files.Size(); + const unsigned fileIndex = Files.Size(); Files.AddNew(); RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB, kNumRecursionLevelsMax)); RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax)); @@ -937,16 +1219,16 @@ FOR_VECTOR (extentIndex, item.Extents) { const CMyExtent &extent = item.Extents[extentIndex]; - UInt32 len = extent.GetLen(); + const UInt32 len = extent.GetLen(); if (len == 0) continue; if (size < len) break; - int partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; - UInt32 logBlockNumber = extent.Pos; + const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex; + const UInt32 logBlockNumber = extent.Pos; const CPartition &partition = Partitions[partitionIndex]; - UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + + const UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)logBlockNumber * vol.BlockSize; UpdatePhySize(offset + len); } @@ -984,7 +1266,8 @@ if (readSize == 0) break; - if (readSize == secSize && NoEndAnchor) + // some udf contain many EndAnchors + if (readSize == secSize /* && NoEndAnchor */) { CTag tag; if (tag.Parse(buf, readSize) == S_OK && @@ -1051,6 +1334,7 @@ Partitions.Clear(); LogVols.Clear(); + PrimeVols.Clear(); Items.Clear(); Files.Clear(); _fileNameLengthTotal = 0; @@ -1060,16 +1344,291 @@ _processedProgressBytes = 0; } + +static const char * const g_PartitionTypes[] = +{ + "Pseudo-Overwritable" // UDF + , "Read-Only" + , "Write-Once" + , "Rewritable" + , "Overwritable" +}; + + +static void AddComment_Align(UString &s) +{ + s += " "; +} + +static void AddComment_PropName(UString &s, const char *name) +{ + AddComment_Align(s); + s += name; + s += ": "; +} + +static void AddComment_UInt32(UString &s, const char *name, UInt32 val) +{ + AddComment_PropName(s, name); + s.Add_UInt32(val); + s.Add_LF(); +} + +static void AddComment_UInt32_2(UString &s, const char *name, UInt32 val) +{ + AddComment_Align(s); + AddComment_UInt32(s, name, val); +} + + +static void AddComment_UInt64(UString &s, const char *name, UInt64 val) +{ + AddComment_PropName(s, name); + s.Add_UInt64(val); + s.Add_LF(); +} + +static void AddComment_RegId(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + s.Add_LF(); +} + +static void AddComment_RegId_Domain(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + UString s2; + ri.AddUdfVersionTo(s2); + if (!s2.IsEmpty()) + { + s += "::"; + s += s2; + } + } + s.Add_LF(); +} + + +// UDF 6.3.1 OS Class + +static const char * const g_OsClasses[] = +{ + NULL + , "DOS" + , "OS/2" + , "Macintosh OS" + , "UNIX" + , "Windows 9x" + , "Windows NT" + , "OS/400" + , "BeOS" + , "Windows CE" +}; + +// UDF 6.3.2 OS Identifier + +static const char * const g_OsIds_Unix[] = +{ + NULL // "Generic" + , "AIX" + , "SUN OS / Solaris" + , "HP/UX" + , "Silicon Graphics Irix" + , "Linux" + , "MKLinux" + , "FreeBSD" + , "NetBSD" +}; + +static void AddOs_Class_Id(UString &s, const char *p) +{ + // UDF 2.1.5.3 Implementation Identifier Suffix + // Appendix 6.3 Operating System Identifiers. + const Byte osClass = p[0]; + if (osClass != 0) + { + s += "::"; + s += TypeToString(g_OsClasses, ARRAY_SIZE(g_OsClasses), osClass); + } + const Byte osId = p[1]; + if (osId != 0) + { + s += "::"; + if (osClass == 4) // unix + { + s += TypeToString(g_OsIds_Unix, ARRAY_SIZE(g_OsIds_Unix), osId); + } + else + s.Add_UInt32(osId); + } +} + + +static void AddComment_RegId_Impl(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + AddOs_Class_Id(s, ri.Suffix); + } + s.Add_LF(); +} + + +static void AddComment_RegId_UdfId(UString &s, const char *name, const CRegId &ri) +{ + AddComment_PropName(s, name); + ri.AddCommentTo(s); + { + // UDF 2.1.5.3 + // UDF Identifier Suffix format + UString s2; + ri.AddUdfVersionTo(s2); + if (!s2.IsEmpty()) + { + s += "::"; + s += s2; + } + AddOs_Class_Id(s, &ri.Suffix[2]); + } + s.Add_LF(); +} + +static void AddComment_DString32(UString &s, const char *name, const CDString32 &d) +{ + AddComment_Align(s); + AddComment_PropName(s, name); + s += d.GetString(); + s.Add_LF(); +} + UString CInArchive::GetComment() const { - UString res; - FOR_VECTOR (i, LogVols) + UString s; { - if (i != 0) - res.Add_Space(); - res += LogVols[i].GetName(); + s += "Primary Volumes:"; + s.Add_LF(); + FOR_VECTOR (i, PrimeVols) + { + if (i != 0) + s.Add_LF(); + const CPrimeVol &pv = PrimeVols[i]; + // AddComment_UInt32(s, "VolumeDescriptorSequenceNumber", pv.VolumeDescriptorSequenceNumber); + // if (PrimeVols.Size() != 1 || pv.PrimaryVolumeDescriptorNumber != 0) + AddComment_UInt32(s, "PrimaryVolumeDescriptorNumber", pv.PrimaryVolumeDescriptorNumber); + // if (pv.MaximumVolumeSequenceNumber != 1 || pv.VolumeSequenceNumber != 1) + AddComment_UInt32(s, "VolumeSequenceNumber", pv.VolumeSequenceNumber); + if (pv.MaximumVolumeSequenceNumber != 1) + AddComment_UInt32(s, "MaximumVolumeSequenceNumber", pv.MaximumVolumeSequenceNumber); + AddComment_PropName(s, "VolumeId"); + s += pv.VolumeId.GetString(); + s.Add_LF(); + AddComment_PropName(s, "VolumeSetId"); + s += pv.VolumeSetId.GetString(); + s.Add_LF(); + // AddComment_UInt32(s, "InterchangeLevel", pv.InterchangeLevel); + // AddComment_UInt32(s, "MaximumInterchangeLevel", pv.MaximumInterchangeLevel); + AddComment_RegId(s, "ApplicationId", pv.ApplicationId); + AddComment_RegId_Impl(s, "ImplementationId", pv.ImplId); + } } - return res; + { + s += "Partitions:"; + s.Add_LF(); + FOR_VECTOR (i, Partitions) + { + if (i != 0) + s.Add_LF(); + const CPartition &part = Partitions[i]; + AddComment_UInt32(s, "PartitionIndex", i); + AddComment_UInt32(s, "PartitionNumber", part.Number); + if (part.IsMetadata) + AddComment_UInt32(s, "IsMetadata", 1); + else + { + AddComment_RegId(s, "ContentsId", part.ContentsId); + AddComment_RegId_Impl(s, "ImplementationId", part.ImplId); + AddComment_PropName(s, "AccessType"); + s += TypeToString(g_PartitionTypes, ARRAY_SIZE(g_PartitionTypes), part.AccessType); + s.Add_LF(); + } + AddComment_UInt64(s, "Size", (UInt64)part.Len << SecLogSize); + AddComment_UInt64(s, "Pos", (UInt64)part.Pos << SecLogSize); + } + } + s += "Logical Volumes:"; + s.Add_LF(); + { + FOR_VECTOR (i, LogVols) + { + if (i != 0) + s.Add_LF(); + const CLogVol &vol = LogVols[i]; + if (LogVols.Size() != 1) + AddComment_UInt32(s, "Number", i); + AddComment_PropName(s, "Id"); + s += vol.Id.GetString(); + s.Add_LF(); + AddComment_UInt32(s, "BlockSize", vol.BlockSize); + AddComment_RegId_Domain(s, "DomainId", vol.DomainId); + AddComment_RegId_Impl(s, "ImplementationId", vol.ImplId); + // AddComment_UInt64(s, "IntegritySequenceExtent_Len", vol.IntegritySequenceExtent.Len); + // AddComment_UInt64(s, "IntegritySequenceExtent_Pos", (UInt64)vol.IntegritySequenceExtent.Pos << SecLogSize); + + s += " Partition Maps:"; + s.Add_LF(); + { + FOR_VECTOR (j, vol.PartitionMaps) + { + if (j != 0) + s.Add_LF(); + const CPartitionMap &pm = vol.PartitionMaps[j]; + AddComment_UInt32_2(s, "PartitionMap", j); + AddComment_UInt32_2(s, "Type", pm.Type); + AddComment_UInt32_2(s, "VolumeSequenceNumber", pm.VolumeSequenceNumber); + AddComment_UInt32_2(s, "PartitionNumber", pm.PartitionNumber); + if (pm.Type == 2) + { + AddComment_UInt32_2(s, "MetadataFileLocation", pm.MetadataFileLocation); + // AddComment_UInt32_2(s, "MetadataMirrorFileLocation", pm.MetadataMirrorFileLocation); + // AddComment_UInt32_2(s, "MetadataBitmapFileLocation", pm.MetadataBitmapFileLocation); + // AddComment_UInt32_2(s, "AllocationUnitSize", pm.AllocationUnitSize); + // AddComment_UInt32_2(s, "AlignmentUnitSize", pm.AlignmentUnitSize); + // AddComment_UInt32_2(s, "Flags", pm.Flags); + AddComment_Align(s); AddComment_RegId_UdfId(s, "PartitionTypeId", pm.PartitionTypeId); + } + } + } + s += " File Sets:"; + s.Add_LF(); + { + FOR_VECTOR (j, vol.FileSets) + { + if (j != 0) + s.Add_LF(); + const CFileSet &fs = vol.FileSets[j]; + AddComment_Align(s); AddComment_UInt32(s, "FileSetNumber", fs.FileSetNumber); + AddComment_Align(s); AddComment_UInt32(s, "FileSetDescNumber", fs.FileSetDescNumber); + + AddComment_Align(s); + AddComment_PropName(s, "LogicalVolumeId"); + s += fs.LogicalVolumeId.GetString(); + s.Add_LF(); + + AddComment_DString32(s, "Id", fs.Id); + AddComment_DString32(s, "CopyrightId", fs.CopyrightId); + AddComment_DString32(s, "AbstractId", fs.AbstractId); + + AddComment_Align(s); + AddComment_RegId_Domain(s, "DomainId", fs.DomainId); + } + } + } + } + return s; } static UString GetSpecName(const UString &name) @@ -1089,7 +1648,7 @@ res.Insert(0, addString + WCHAR_PATH_SEPARATOR); } -UString CInArchive::GetItemPath(int volIndex, int fsIndex, int refIndex, +UString CInArchive::GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, bool showVolName, bool showFsName) const { // showVolName = true; @@ -1101,9 +1660,10 @@ for (;;) { const CRef &ref = fs.Refs[refIndex]; - refIndex = ref.Parent; - if (refIndex < 0) + // we break on root file (that probably has empty name) + if (ref.Parent < 0) break; + refIndex = ref.Parent; UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName())); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfIn.h 7zip-22.01/CPP/7zip/Archive/Udf/UdfIn.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Udf/UdfIn.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Udf/UdfIn.h 2022-06-29 12:00:00.000000000 +0000 @@ -17,16 +17,15 @@ // ---------- ECMA Part 1 ---------- // ECMA 1/7.2.12 +// UDF 2.1.3 -/* struct CDString32 { Byte Data[32]; - void Parse(const Byte *buf); - // UString GetString() const; + void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); } + UString GetString() const; }; -*/ struct CDString128 { @@ -46,6 +45,7 @@ // ECMA 1/7.3 +// UDF 2.1.4 timestamp struct CTime { @@ -65,9 +65,9 @@ }; -// ECMA 1/7.4 +// ECMA 1/7.4 regid +// UDF 2.1.5 EntityID -/* struct CRegId { Byte Flags; @@ -75,44 +75,97 @@ char Suffix[8]; void Parse(const Byte *buf); + void AddCommentTo(UString &s) const; + void AddUdfVersionTo(UString &s) const; }; -*/ + + // ---------- ECMA Part 3: Volume Structure ---------- -// ECMA 3/10.5 +// ECMA 3/7.1 -struct CPartition +struct CExtent +{ + UInt32 Len; + UInt32 Pos; // logical sector number + + void Parse(const Byte *p); +}; + + +// ECMA 3/10.1 +// UDF 2.2.2 PrimaryVolumeDescriptor + +struct CPrimeVol { + // UInt32 VolumeDescriptorSequenceNumber; + UInt32 PrimaryVolumeDescriptorNumber; + CDString32 VolumeId; + UInt16 VolumeSequenceNumber; + UInt16 MaximumVolumeSequenceNumber; + // UInt16 InterchangeLevel; + // UInt16 MaximumInterchangeLevel; + // UInt32 CharacterSetList; + // UInt32 MaximumCharacterSetList; + CDString128 VolumeSetId; + // charspec DescriptorCharacterSet; // (1/7.2.1) + // charspec ExplanatoryCharacterSet; // (1/7.2.1) + // CExtent VolumeAbstract; + // CExtent VolumeCopyrightNotice; + CRegId ApplicationId; + CTime RecordingTime; + CRegId ImplId; + // bytes ImplementationUse + // UInt32 PredecessorVolumeDescriptorSequenceLocation; // UInt16 Flags; - UInt16 Number; - // CRegId ContentsId; - // Byte ContentsUse[128]; - // UInt32 AccessType; + void Parse(const Byte *p); +}; + + +// ECMA 3/10.5 +// UDF 2.2.14 PartitionDescriptor + +struct CPartition +{ UInt32 Pos; UInt32 Len; - // CRegId ImplId; + UInt16 Flags; + UInt16 Number; + CRegId ContentsId; + // Byte ContentsUse[128]; + UInt32 AccessType; + + CRegId ImplId; // Byte ImplUse[128]; - int VolIndex; + // int VolIndex; CMap32 Map; - CPartition(): VolIndex(-1) {} + bool IsMetadata; + + CPartition(): + // VolIndex(-1), + IsMetadata(false) {} // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); } // bool IsAllocated() const { return ((Flags & 1) != 0); } }; + +// ECMA 4/7.1 lb_addr + struct CLogBlockAddr { UInt32 Pos; UInt16 PartitionRef; - void Parse(const Byte *buf); + void Parse(const Byte *p); }; + enum EShortAllocDescType { SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0, @@ -121,16 +174,18 @@ SHORT_ALLOC_DESC_TYPE_NextExtent = 3 }; + +// ECMA 4/14.14.1 short_ad + struct CShortAllocDesc { UInt32 Len; UInt32 Pos; - // 4/14.14.1 // UInt32 GetLen() const { return Len & 0x3FFFFFFF; } // UInt32 GetType() const { return Len >> 30; } // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *buf); + void Parse(const Byte *p); }; /* @@ -138,10 +193,13 @@ { UInt16 Flags; UInt32 UdfUniqueId; - void Parse(const Byte *buf); + void Parse(const Byte *p); }; */ +// ECMA 4/14.14.2 long_ad +// UDF 2.3.10.1 + struct CLongAllocDesc { UInt32 Len; @@ -153,29 +211,48 @@ UInt32 GetLen() const { return Len & 0x3FFFFFFF; } UInt32 GetType() const { return Len >> 30; } bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } - void Parse(const Byte *buf); + void Parse(const Byte *p); }; + +// ECMA 3/10.7 Partition maps +// UDF 2.2.8-2.2.10 Partition Maps + struct CPartitionMap { + unsigned PartitionIndex; + Byte Type; // Byte Len; - // Type - 1 - // UInt16 VolSeqNumber; + // ECMA 10.7.2 + UInt16 VolumeSequenceNumber; UInt16 PartitionNumber; + + CRegId PartitionTypeId; - // Byte Data[256]; + // UDF 2.2.10 Metadata Partition Map + UInt32 MetadataFileLocation; + // UInt32 MetadataMirrorFileLocation; + // UInt32 MetadataBitmapFileLocation; + // UInt32 AllocationUnitSize; // (Blocks) + // UInt16 AlignmentUnitSize; // (Blocks) + // Byte Flags; - int PartitionIndex; + // Byte Data[256]; + // CPartitionMap(): PartitionIndex(-1) {} }; -// ECMA 4/14.6 + +// ECMA 4/14.6.6 enum EIcbFileType { ICB_FILE_TYPE_DIR = 4, - ICB_FILE_TYPE_FILE = 5 + ICB_FILE_TYPE_FILE = 5, + + ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File + ICB_FILE_TYPE_METADATA_MIRROR = 251 }; enum EIcbDescriptorType @@ -186,6 +263,9 @@ ICB_DESC_TYPE_INLINE = 3 }; +// ECMA 4/14.6 +// UDF 3.3.2 + struct CIcbTag { // UInt32 PriorDirectNum; @@ -201,33 +281,35 @@ void Parse(const Byte *p); }; +// ECMA 4/14.4.3 // const Byte FILEID_CHARACS_Existance = (1 << 0); const Byte FILEID_CHARACS_Parent = (1 << 3); struct CFile { + int ItemIndex; // UInt16 FileVersion; // Byte FileCharacteristics; // CByteBuffer ImplUse; CDString Id; - int ItemIndex; - CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {} UString GetName() const { return Id.GetString(); } }; + struct CMyExtent { UInt32 Pos; UInt32 Len; - unsigned PartitionRef; + unsigned PartitionRef; // index in CLogVol::PartitionMaps UInt32 GetLen() const { return Len & 0x3FFFFFFF; } UInt32 GetType() const { return Len >> 30; } bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; } }; + struct CItem { CIcbTag IcbTag; @@ -235,26 +317,30 @@ // UInt32 Uid; // UInt32 Gid; // UInt32 Permissions; - // UInt16 FileLinkCount; + UInt16 FileLinkCount; // Byte RecordFormat; // Byte RecordDisplayAttr; // UInt32 RecordLen; UInt64 Size; UInt64 NumLogBlockRecorded; + // UInt64 ObjectSize; + CTime ATime; CTime MTime; - // CTime AttrtTime; + CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of. + CTime CreateTime; // UInt32 CheckPoint; // CLongAllocDesc ExtendedAttrIcb; // CRegId ImplId; // UInt64 UniqueId; + bool IsExtended; bool IsInline; CByteBuffer InlineData; CRecordVector Extents; CUIntVector SubFiles; - void Parse(const Byte *buf); + void Parse(const Byte *p); bool IsRecAndAlloc() const { @@ -279,53 +365,65 @@ bool IsDir() const { return IcbTag.IsDir(); } }; + struct CRef { - int Parent; unsigned FileIndex; + int Parent; }; // ECMA 4 / 14.1 struct CFileSet { - CTime RecodringTime; + CRecordVector Refs; + + CTime RecordingTime; // UInt16 InterchangeLevel; // UInt16 MaxInterchangeLevel; - // UInt32 FileSetNumber; - // UInt32 FileSetDescNumber; - // CDString32 Id; - // CDString32 CopyrightId; - // CDString32 AbstractId; + UInt32 FileSetNumber; + UInt32 FileSetDescNumber; + CDString128 LogicalVolumeId; + CDString32 Id; + CDString32 CopyrightId; + CDString32 AbstractId; CLongAllocDesc RootDirICB; - // CRegId DomainId; + CRegId DomainId; // CLongAllocDesc SystemStreamDirICB; - - CRecordVector Refs; }; +/* 8.3 Volume descriptors +8.4 +A Volume Descriptor Sequence: + shall contain one or more Primary Volume Descriptors. +*/ + // ECMA 3/10.6 +// UDF 2.2.4 LogicalVolumeDescriptor struct CLogVol { - CDString128 Id; + CObjectVector PartitionMaps; + CObjectVector FileSets; + UInt32 BlockSize; - // CRegId DomainId; + CDString128 Id; + CRegId DomainId; // Byte ContentsUse[16]; CLongAllocDesc FileSetLocation; // UDF - // CRegId ImplId; + CRegId ImplId; // Byte ImplUse[128]; - - CObjectVector PartitionMaps; - CObjectVector FileSets; + // CExtent IntegritySequenceExtent; UString GetName() const { return Id.GetString(); } }; + + struct CProgressVirt { virtual HRESULT SetTotal(UInt64 numBytes) PURE; @@ -335,15 +433,42 @@ class CInArchive { +public: + CObjectVector LogVols; + CObjectVector Items; + CObjectVector Files; + CObjectVector Partitions; + + unsigned SecLogSize; + UInt64 PhySize; + UInt64 FileSize; + + bool IsArc; + bool Unsupported; + bool UnexpectedEnd; + bool NoEndAnchor; + + CObjectVector PrimeVols; + + HRESULT Open(IInStream *inStream, CProgressVirt *progress); + void Clear(); + + UString GetComment() const; + UString GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex, + bool showVolName, bool showFsName) const; + + bool CheckItemExtents(unsigned volIndex, const CItem &item) const; + +private: IInStream *_stream; CProgressVirt *_progress; - HRESULT Read(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); - HRESULT Read(int volIndex, const CLongAllocDesc &lad, Byte *buf); - HRESULT ReadFromFile(int volIndex, const CItem &item, CByteBuffer &buf); + HRESULT Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf); + HRESULT ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf); + HRESULT ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf); - HRESULT ReadFileItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); - HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); + HRESULT ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); + HRESULT ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed); HRESULT Open2(); HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed); @@ -354,37 +479,18 @@ unsigned _numRefs; UInt32 _numExtents; UInt64 _inlineExtentsSize; - bool CheckExtent(int volIndex, int partitionRef, UInt32 blockPos, UInt32 len) const; - -public: - CObjectVector Partitions; - CObjectVector LogVols; - - CObjectVector Items; - CObjectVector Files; - - unsigned SecLogSize; - UInt64 PhySize; - UInt64 FileSize; - - bool IsArc; - bool Unsupported; - bool UnexpectedEnd; - bool NoEndAnchor; + bool CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const; void UpdatePhySize(UInt64 val) { if (PhySize < val) PhySize = val; } - HRESULT Open(IInStream *inStream, CProgressVirt *progress); - void Clear(); - - UString GetComment() const; - UString GetItemPath(int volIndex, int fsIndex, int refIndex, - bool showVolName, bool showFsName) const; - bool CheckItemExtents(int volIndex, const CItem &item) const; + void UpdatePhySize(const CExtent &e) + { + UpdatePhySize(((UInt64)e.Pos << SecLogSize) + e.Len); + } }; API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/VhdHandler.cpp 7zip-22.01/CPP/7zip/Archive/VhdHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/VhdHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/VhdHandler.cpp 2022-02-02 07:00:00.000000000 +0000 @@ -921,7 +921,8 @@ CLimitedInStream *streamSpec = new CLimitedInStream; CMyComPtr streamTemp = streamSpec; streamSpec->SetStream(Stream); - streamSpec->InitAndSeek(0, Footer.CurrentSize); + // fixme : check (startOffset = 0) + streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize); RINOK(streamSpec->SeekToStart()); *stream = streamTemp.Detach(); return S_OK; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/VhdxHandler.cpp 7zip-22.01/CPP/7zip/Archive/VhdxHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/VhdxHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/VhdxHandler.cpp 2021-12-29 08:00:00.000000000 +0000 @@ -171,6 +171,20 @@ UInt64 LogOffset; CGuid Guids[3]; + bool IsEqualTo(const CHeader &h) const + { + if (SequenceNumber != h.SequenceNumber) + return false; + if (LogLength != h.LogLength) + return false; + if (LogOffset != h.LogOffset) + return false; + for (unsigned i = 0; i < 3; i++) + if (!Guids[i].IsEqualTo(h.Guids[i])) + return false; + return true; + }; + bool Parse(Byte *p); }; @@ -1174,7 +1188,18 @@ unsigned mainIndex; if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0; else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1; - else return S_FALSE; + else + { + /* Disk2vhd v2.02 can create image with 2 full copies of headers. + It's violation of VHDX specification: + "A header is current if it is the only valid header + or if it is valid and its SequenceNumber field is + greater than the other header's SequenceNumber". + but we support such Disk2vhd archives. */ + if (!headers[0].IsEqualTo(headers[1])) + return S_FALSE; + mainIndex = 0; + } const CHeader &h = headers[mainIndex]; Header = h; @@ -1567,6 +1592,7 @@ void CHandler::AddComment(UString &s) const { + AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize); AddComment_UInt64(s, "PhysicalSize", _phySize); if (!_errorMessage.IsEmpty()) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/VmdkHandler.cpp 7zip-22.01/CPP/7zip/Archive/VmdkHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/VmdkHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/VmdkHandler.cpp 2022-02-15 13:00:00.000000000 +0000 @@ -138,7 +138,7 @@ int eq = s.Find('='); if (eq < 0 || (qu >= 0 && eq > qu)) return false; - name = s.Left(eq); + name.SetFrom(s.Ptr(), eq); name.Trim(); val = s.Ptr(eq + 1); val.Trim(); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimHandler.cpp 7zip-22.01/CPP/7zip/Archive/Wim/WimHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Wim/WimHandler.cpp 2022-03-30 12:00:00.000000000 +0000 @@ -355,6 +355,7 @@ prop.vt = VT_FILETIME; prop.filetime.dwLowDateTime = Get32(p); prop.filetime.dwHighDateTime = Get32(p + 4); + prop.Set_FtPrec(k_PropVar_TimePrec_100ns); } @@ -842,7 +843,7 @@ int dotPos = name.ReverseFind_Dot(); if (dotPos < 0) dotPos = name.Len(); - _before = name.Left(dotPos); + _before.SetFrom(name.Ptr(), dotPos); _after = name.Ptr(dotPos); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimHandlerOut.cpp 7zip-22.01/CPP/7zip/Archive/Wim/WimHandlerOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimHandlerOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Wim/WimHandlerOut.cpp 2022-01-08 17:00:00.000000000 +0000 @@ -32,8 +32,8 @@ unsigned left = 0, right = sorted.Size(); while (left != right) { - unsigned mid = (left + right) / 2; - unsigned index = sorted[mid]; + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned index = sorted[mid]; const Byte *hash2 = streams[index].Hash; unsigned i; @@ -124,9 +124,9 @@ unsigned left = 0, right = indexes.Size(); while (left != right) { - unsigned mid = (left + right) / 2; - unsigned index = indexes[mid]; - int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned index = indexes[mid]; + const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); if (comp == 0) return index; if (comp < 0) @@ -203,8 +203,8 @@ unsigned left = 0, right = Dirs.Size(); while (left != right) { - unsigned mid = (left + right) / 2; - int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name); + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name); if (comp == 0) { index = mid; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimIn.cpp 7zip-22.01/CPP/7zip/Archive/Wim/WimIn.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimIn.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Wim/WimIn.cpp 2022-01-07 17:00:00.000000000 +0000 @@ -567,9 +567,12 @@ for (unsigned i = 0; i < len; i++) { wchar_t c = Get16(meta + i * 2); - // 18.06 - if (c == CHAR_PATH_SEPARATOR || c == '/') - c = '_'; + if (c == L'/') + c = L'_'; + #if WCHAR_PATH_SEPARATOR != L'/' + else if (c == L'\\') + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // 22.00 : WSL scheme + #endif dest[i] = c; } } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimRegister.cpp 7zip-22.01/CPP/7zip/Archive/Wim/WimRegister.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Wim/WimRegister.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Wim/WimRegister.cpp 2022-05-04 11:00:00.000000000 +0000 @@ -10,13 +10,20 @@ namespace NWim { REGISTER_ARC_IO( - "wim", "wim swm esd ppkg", 0, 0xE6, - kSignature, - 0, - NArcInfoFlags::kAltStreams | - NArcInfoFlags::kNtSecure | - NArcInfoFlags::kSymLinks | - NArcInfoFlags::kHardLinks + "wim", "wim swm esd ppkg", NULL, 0xE6 + , kSignature, 0 + , NArcInfoFlags::kAltStreams + | NArcInfoFlags::kNtSecure + | NArcInfoFlags::kSymLinks + | NArcInfoFlags::kHardLinks + | NArcInfoFlags::kCTime + // | NArcInfoFlags::kCTime_Default + | NArcInfoFlags::kATime + // | NArcInfoFlags::kATime_Default + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows) , NULL) }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/XzHandler.cpp 7zip-22.01/CPP/7zip/Archive/XzHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/XzHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/XzHandler.cpp 2022-05-03 11:00:00.000000000 +0000 @@ -1089,7 +1089,8 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) { - *timeType = NFileTimeType::kUnix; + *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType; + // *timeType = NFileTimeType::kUnix; return S_OK; } @@ -1136,7 +1137,6 @@ if (prop.vt != VT_UI8) return E_INVALIDARG; dataSize = prop.uhVal.QuadPart; - RINOK(updateCallback->SetTotal(dataSize)); } NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder; @@ -1266,15 +1266,28 @@ } } - CMyComPtr fileInStream; - RINOK(updateCallback->GetStream(0, &fileInStream)); - - CLocalProgress *lps = new CLocalProgress; - CMyComPtr progress = lps; - lps->Init(updateCallback, true); - - RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress)); - + { + CMyComPtr fileInStream; + RINOK(updateCallback->GetStream(0, &fileInStream)); + if (!fileInStream) + return S_FALSE; + { + CMyComPtr streamGetSize; + fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize); + if (streamGetSize) + { + UInt64 size; + if (streamGetSize->GetSize(&size) == S_OK) + dataSize = size; + } + } + RINOK(updateCallback->SetTotal(dataSize)); + CLocalProgress *lps = new CLocalProgress; + CMyComPtr progress = lps; + lps->Init(updateCallback, true); + RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress)); + } + return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK); } @@ -1415,9 +1428,9 @@ REGISTER_ARC_IO( "xz", "xz txz", "* .tar", 0xC, - XZ_SIG, - 0, - NArcInfoFlags::kKeepName, - NULL) + XZ_SIG, 0 + , NArcInfoFlags::kKeepName + , 0 + , NULL) }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHandler.cpp 7zip-22.01/CPP/7zip/Archive/Zip/ZipHandler.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipHandler.cpp 2022-05-07 12:00:00.000000000 +0000 @@ -190,6 +190,8 @@ kpidVolumeIndex, kpidOffset // kpidIsAltStream + // , kpidChangeTime // for debug + // , 255 // for debug }; static const Byte kArcProps[] = @@ -347,6 +349,34 @@ return S_OK; } + +static bool NtfsUnixTimeToProp(bool fromCentral, + const CExtraBlock &extra, + unsigned ntfsIndex, unsigned unixIndex, NWindows::NCOM::CPropVariant &prop) +{ + { + FILETIME ft; + if (extra.GetNtfsTime(ntfsIndex, ft)) + { + PropVariant_SetFrom_NtfsTime(prop, ft); + return true; + } + } + { + UInt32 unixTime = 0; + if (!extra.GetUnixTime(fromCentral, unixIndex, unixTime)) + return false; + /* + // we allow unixTime == 0 + if (unixTime == 0) + return false; + */ + PropVariant_SetFrom_UnixTime(prop, unixTime); + return true; + } +} + + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -392,6 +422,30 @@ case kpidPackSize: prop = item.PackSize; break; + case kpidCTime: + NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kCTime, + NFileHeader::NUnixTime::kCTime, prop); + break; + + case kpidATime: + NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kATime, + NFileHeader::NUnixTime::kATime, prop); + break; + + case kpidMTime: + { + if (!NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kMTime, + NFileHeader::NUnixTime::kMTime, prop)) + { + if (item.Time != 0) + PropVariant_SetFrom_DosTime(prop, item.Time); + } + break; + } + case kpidTimeType: { FILETIME ft; @@ -399,7 +453,7 @@ UInt32 type; if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) type = NFileTimeType::kWindows; - else if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) + else if (extra.GetUnixTime(item.FromCentral, NFileHeader::NUnixTime::kMTime, unixTime)) type = NFileTimeType::kUnix; else type = NFileTimeType::kDOS; @@ -407,64 +461,28 @@ break; } - case kpidCTime: - { - FILETIME utc; - bool defined = true; - if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc)) - { - UInt32 unixTime = 0; - if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); - else - defined = false; - } - if (defined) - prop = utc; - break; - } - - case kpidATime: - { - FILETIME utc; - bool defined = true; - if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc)) - { - UInt32 unixTime = 0; - if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); - else - defined = false; - } - if (defined) - prop = utc; - - break; - } - - case kpidMTime: - { - FILETIME utc; - bool defined = true; - if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc)) - { - UInt32 unixTime = 0; - if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime)) - NTime::UnixTimeToFileTime(unixTime, utc); - else + /* + // for debug to get Dos time values: + case kpidChangeTime: if (item.Time != 0) PropVariant_SetFrom_DosTime(prop, item.Time); break; + // for debug + // time difference (dos - utc) + case 255: + { + if (NtfsUnixTimeToProp(item.FromCentral, extra, + NFileHeader::NNtfsExtra::kMTime, + NFileHeader::NUnixTime::kMTime, prop)) + { + FILETIME localFileTime; + if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime)) { - FILETIME localFileTime; - if (item.Time == 0) - defined = false; - else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) || - !LocalFileTimeToFileTime(&localFileTime, &utc)) - utc.dwHighDateTime = utc.dwLowDateTime = 0; + UInt64 t1 = FILETIME_To_UInt64(prop.filetime); + UInt64 t2 = FILETIME_To_UInt64(localFileTime); + prop.Set_Int64(t2 - t1); } } - if (defined) - prop = utc; break; } + */ case kpidAttrib: prop = item.GetWinAttrib(); break; @@ -1122,7 +1140,18 @@ AString_Wipe charPassword; if (password) { - UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP); + /* + // 22.00: do we need UTF-8 passwords here ? + if (item.IsUtf8()) // 22.00 + { + // throw 1; + ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword); + } + else + */ + { + UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP); + } /* if (wzAesMode || pkAesMode) { @@ -1341,6 +1370,8 @@ if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted()) { + // for debug : we can disable this code (kStore + 50), if we want to test CopyCoder+Filter + // here we use filter without CopyCoder readFromFilter = false; COutStreamWithPadPKCS7 *padStreamSpec = NULL; @@ -1425,33 +1456,44 @@ const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed); if (processed + padSize > coderPackSize) truncatedError = true; + else if (processed + padSize < coderPackSize) + dataAfterEnd = true; else { - if (processed + padSize < coderPackSize) - dataAfterEnd = true; - else { - // here we can PKCS7 padding data from reminder (it can be inside stream buffer in coder). + // here we check PKCS7 padding data from reminder (it can be inside stream buffer in coder). CMyComPtr readInStream; coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream); - if (readInStream) + // CCopyCoder() for kStore doesn't read data outside of (item.Size) + if (readInStream || id == NFileHeader::NCompressionMethod::kStore) { - // change pad size, it we support another block size in ZipStron - // here we request more to detect error with data after end. + // change pad size, if we support another block size in ZipStrong. + // here we request more data to detect error with data after end. const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16; Byte buf[kBufSize]; - UInt32 processedSize; - RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize)); + UInt32 processedSize = 0; + if (readInStream) + { + RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize)); + } if (processedSize > padSize) dataAfterEnd = true; else { - if (ReadStream_FALSE(filterStream, buf + processedSize, padSize - processedSize) != S_OK) - padError = true; - else - for (unsigned i = 0; i < padSize; i++) - if (buf[i] != padSize) - padError = true; + size_t processedSize2 = kBufSize - processedSize; + result = ReadStream(filterStream, buf + processedSize, &processedSize2); + if (result == S_OK) + { + processedSize2 += processedSize; + if (processedSize2 > padSize) + dataAfterEnd = true; + else if (processedSize2 < padSize) + truncatedError = true; + else + for (unsigned i = 0; i < padSize; i++) + if (buf[i] != padSize) + padError = true; + } } } } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHandler.h 7zip-22.01/CPP/7zip/Archive/Zip/ZipHandler.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHandler.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipHandler.h 2022-05-07 11:00:00.000000000 +0000 @@ -57,7 +57,9 @@ int m_MainMethod; bool m_ForceAesMode; - bool m_WriteNtfsTimeExtra; + + CHandlerTimeOptions TimeOptions; + bool _removeSfxBlock; bool m_ForceLocal; bool m_ForceUtf8; @@ -71,7 +73,8 @@ _props.Init(); m_MainMethod = -1; m_ForceAesMode = false; - m_WriteNtfsTimeExtra = true; + TimeOptions.Init(); + TimeOptions.Prec = k_PropVar_TimePrec_0; _removeSfxBlock = false; m_ForceLocal = false; m_ForceUtf8 = false; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp 7zip-22.01/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp 2022-05-07 12:00:00.000000000 +0000 @@ -30,7 +30,7 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) { - *timeType = NFileTimeType::kDOS; + *timeType = TimeOptions.Prec; return S_OK; } @@ -207,27 +207,58 @@ } */ + // 22.00 : kpidTimeType is useless here : the code was disabled + /* { CPropVariant prop; RINOK(callback->GetProperty(i, kpidTimeType, &prop)); if (prop.vt == VT_UI4) - ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows); + ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows); else - ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra; + ui.NtfsTime_IsDefined = _Write_NtfsTime; } - RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime)); - RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime)); - RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime)); + */ - { - FILETIME localFileTime = { 0, 0 }; - if (ui.Ntfs_MTime.dwHighDateTime != 0 || - ui.Ntfs_MTime.dwLowDateTime != 0) - if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime)) - return E_INVALIDARG; - FileTimeToDosTime(localFileTime, ui.Time); + if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime)); + if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime)); + if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime)); + + if (TimeOptions.Prec != k_PropVar_TimePrec_DOS) + { + if (TimeOptions.Prec == k_PropVar_TimePrec_Unix || + TimeOptions.Prec == k_PropVar_TimePrec_Base) + ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime); + else + { + /* + // if we want to store zero timestamps as zero timestamp, use the following: + ui.Write_NtfsTime = + _Write_MTime || + _Write_ATime || + _Write_CTime; + */ + + // We treat zero timestamp as no timestamp + ui.Write_NtfsTime = + ! FILETIME_IsZero (ui.Ntfs_MTime) || + ! FILETIME_IsZero (ui.Ntfs_ATime) || + ! FILETIME_IsZero (ui.Ntfs_CTime); + } } + /* + how 0 in dos time works: + win10 explorer extract : some random date 1601-04-25. + winrar 6.10 : write time. + 7zip : MTime of archive is used + how 0 in tar works: + winrar 6.10 : 1970 + 0 in dos field can show that there is no timestamp. + we write correct 1970-01-01 in dos field, to support correct extraction in Win10. + */ + + UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time); + NItemName::ReplaceSlashes_OsToUnix(name); bool needSlash = ui.IsDir; @@ -441,11 +472,21 @@ if (mainMethod != NFileHeader::NCompressionMethod::kStore) options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore); + CUpdateOptions uo; + uo.Write_MTime = TimeOptions.Write_MTime.Val; + uo.Write_ATime = TimeOptions.Write_ATime.Val; + uo.Write_CTime = TimeOptions.Write_CTime.Val; + /* + uo.Write_NtfsTime = _Write_NtfsTime && + (_Write_MTime || _Write_ATime || _Write_CTime); + uo.Write_UnixTime = _Write_UnixTime; + */ + return Update( EXTERNAL_CODECS_VARS m_Items, updateItems, outStream, m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, - options, callback); + uo, options, callback); COM_TRY_END2 } @@ -494,10 +535,9 @@ return E_INVALIDARG; } } - else if (name.IsEqualTo("tc")) - { - RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra)); - } + + + else if (name.IsEqualTo("cl")) { RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)); @@ -532,7 +572,12 @@ } else { - RINOK(_props.SetProperty(name, prop)); + bool processed = false; + RINOK(TimeOptions.Parse(name, prop, processed)); + if (!processed) + { + RINOK(_props.SetProperty(name, prop)); + } } // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop)); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHeader.h 7zip-22.01/CPP/7zip/Archive/Zip/ZipHeader.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipHeader.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipHeader.h 2022-05-05 11:00:00.000000000 +0000 @@ -88,14 +88,15 @@ { kZip64 = 0x01, kNTFS = 0x0A, + kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK kStrongEncrypt = 0x17, kIzNtSecurityDescriptor = 0x4453, - kUnixTime = 0x5455, - kUnixExtra = 0x5855, + kUnixTime = 0x5455, // "UT" (time) Info-ZIP + kUnix1 = 0x5855, // Info-ZIP kIzUnicodeComment = 0x6375, kIzUnicodeName = 0x7075, - kUnix2Extra = 0x7855, - kUnix3Extra = 0x7875, + kUnix2 = 0x7855, // Info-ZIP + kUnixN = 0x7875, // Info-ZIP kWzAES = 0x9901, kApkAlign = 0xD935 }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipIn.cpp 7zip-22.01/CPP/7zip/Archive/Zip/ZipIn.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipIn.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipIn.cpp 2022-05-06 12:00:00.000000000 +0000 @@ -1045,9 +1045,24 @@ if (cdItem) { - if (isOK && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos)) - { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }} - + if (isOK) + { + if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos)) + { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }} + /* + else if (size == 8) + { + size -= 8; + const UInt64 v = ReadUInt64(); + // soong_zip, an AOSP tool (written in the Go) writes incorrect value. + // we can ignore that minor error here + if (v != cdItem->LocalHeaderPos) + isOK = false; // ignore error + // isOK = false; // force error + } + */ + } + if (isOK && ZIP64_IS_16_MAX(cdItem->Disk)) { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }} } @@ -1926,7 +1941,7 @@ { if (left >= right) return -1; - const unsigned index = (left + right) / 2; + const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2); const CItemEx &item2 = items[index]; if (item.Disk < item2.Disk) right = index; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipItem.cpp 7zip-22.01/CPP/7zip/Archive/Zip/ZipItem.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipItem.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipItem.cpp 2022-05-05 11:00:00.000000000 +0000 @@ -30,11 +30,12 @@ { { NExtraID::kZip64, "Zip64" }, { NExtraID::kNTFS, "NTFS" }, + { NExtraID::kUnix0, "UNIX" }, { NExtraID::kStrongEncrypt, "StrongCrypto" }, { NExtraID::kUnixTime, "UT" }, - { NExtraID::kUnixExtra, "UX" }, - { NExtraID::kUnix2Extra, "Ux" }, - { NExtraID::kUnix3Extra, "ux" }, + { NExtraID::kUnix1, "UX" }, + { NExtraID::kUnix2, "Ux" }, + { NExtraID::kUnixN, "ux" }, { NExtraID::kIzUnicodeComment, "uc" }, { NExtraID::kIzUnicodeName, "up" }, { NExtraID::kIzNtSecurityDescriptor, "SD" }, @@ -50,6 +51,23 @@ if (pair.Value == ID) { s += pair.Name; + if (ID == NExtraID::kUnixTime) + { + if (Data.Size() >= 1) + { + s += ':'; + const Byte flags = Data[0]; + if (flags & 1) s += 'M'; + if (flags & 2) s += 'A'; + if (flags & 4) s += 'C'; + const UInt32 size = (UInt32)(Data.Size()) - 1; + if (size % 4 == 0) + { + s += ':'; + s.Add_UInt32(size / 4); + } + } + } /* if (ID == NExtraID::kApkAlign && Data.Size() >= 2) { @@ -133,14 +151,22 @@ return false; } -bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const +bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const { + /* Info-Zip : + The central-header extra field contains the modification + time only, or no timestamp at all. + Size of Data is used to flag its presence or absence + If "Flags" indicates that Modtime is present in the local header + field, it MUST be present in the central header field, too + */ + res = 0; UInt32 size = (UInt32)Data.Size(); if (ID != NExtraID::kUnixTime || size < 5) return false; const Byte *p = (const Byte *)Data; - Byte flags = *p++; + const Byte flags = *p++; size--; if (isCentral) { @@ -168,18 +194,35 @@ } -bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const +// Info-ZIP's abandoned "Unix1 timestamps & owner ID info" + +bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const { res = 0; - const size_t size = Data.Size(); - unsigned offset = index * 4; - if (ID != NExtraID::kUnixExtra || size < offset + 4) + const unsigned offset = index * 4; + if (Data.Size() < offset + 4) + return false; + if (ID != NExtraID::kUnix0 && + ID != NExtraID::kUnix1) return false; const Byte *p = (const Byte *)Data + offset; res = GetUi32(p); return true; } +/* +// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps" +bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const +{ + res = 0; + const unsigned offset = index * 4; + if (ID != NExtraID::kUnix0 || Data.Size() < offset) + return false; + const Byte *p = (const Byte *)Data + offset; + res = GetUi32(p); + return true; +} +*/ bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const { @@ -199,7 +242,7 @@ { const CExtraSubBlock &sb = SubBlocks[i]; if (sb.ID == NFileHeader::NExtraID::kUnixTime) - return sb.ExtractUnixTime(isCentral, index, res); + return sb.Extract_UnixTime(isCentral, index, res); } } @@ -214,8 +257,9 @@ FOR_VECTOR (i, SubBlocks) { const CExtraSubBlock &sb = SubBlocks[i]; - if (sb.ID == NFileHeader::NExtraID::kUnixExtra) - return sb.ExtractUnixExtraTime(index, res); + if (sb.ID == NFileHeader::NExtraID::kUnix0 || + sb.ID == NFileHeader::NExtraID::kUnix1) + return sb.Extract_Unix01_Time(index, res); } } return false; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipItem.h 7zip-22.01/CPP/7zip/Archive/Zip/ZipItem.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipItem.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipItem.h 2022-05-05 11:00:00.000000000 +0000 @@ -31,8 +31,9 @@ CByteBuffer Data; bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; - bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; - bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const; + bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const; + bool Extract_Unix01_Time(unsigned index, UInt32 &res) const; + // bool Extract_Unix_Time(unsigned index, UInt32 &res) const; bool CheckIzUnicode(const AString &s) const; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipOut.cpp 7zip-22.01/CPP/7zip/Archive/Zip/ZipOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipOut.cpp 2022-05-08 11:00:00.000000000 +0000 @@ -4,6 +4,7 @@ #include "../../../../C/7zCrc.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/OffsetStream.h" #include "ZipOut.h" @@ -110,6 +111,40 @@ WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size()); } + +static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8); +static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4); + +void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs) +{ + if (writeNtfs) + { + // windows explorer ignores that extra + Write16(NFileHeader::NExtraID::kNTFS); + Write16(k_Ntfs_ExtraSize); + Write32(0); // reserved + Write16(NFileHeader::NNtfsExtra::kTagTime); + Write16(8 * 3); + WriteNtfsTime(item.Ntfs_MTime); + WriteNtfsTime(item.Ntfs_ATime); + WriteNtfsTime(item.Ntfs_CTime); + } + + if (item.Write_UnixTime) + { + // windows explorer ignores that extra + // by specification : should we write to local header also? + Write16(NFileHeader::NExtraID::kUnixTime); + Write16(k_UnixTime_ExtraSize); + const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime); + Write8(flags); + UInt32 unixTime; + NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime); + Write32(unixTime); + } +} + + void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck) { m_LocalHeaderPos = m_CurPos; @@ -122,8 +157,14 @@ if (needCheck && m_IsZip64) isZip64 = true; + // Why don't we write NTFS timestamps to local header? + // Probably we want to reduce size of archive? + const bool writeNtfs = false; // do not write NTFS timestamp to local header + // const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header const UInt32 localExtraSize = (UInt32)( (isZip64 ? (4 + 8 + 8): 0) + + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0) + + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0) + item.Get_UtfName_ExtraSize() + item.LocalExtra.GetSize()); if ((UInt16)localExtraSize != localExtraSize) @@ -168,13 +209,12 @@ Write64(packSize); } + WriteTimeExtra(item, writeNtfs); + WriteUtfName(item); WriteExtra(item.LocalExtra); - // Why don't we write NTFS timestamps to local header? - // Probably we want to reduce size of archive? - const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos); if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize) throw CSystemException(E_FAIL); @@ -231,10 +271,10 @@ void COutArchive::WriteCentralHeader(const CItemOut &item) { - bool isUnPack64 = DOES_NEED_ZIP64(item.Size); - bool isPack64 = DOES_NEED_ZIP64(item.PackSize); - bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); - bool isZip64 = isPack64 || isUnPack64 || isPosition64; + const bool isUnPack64 = DOES_NEED_ZIP64(item.Size); + const bool isPack64 = DOES_NEED_ZIP64(item.PackSize); + const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); + const bool isZip64 = isPack64 || isUnPack64 || isPosition64; Write32(NSignature::kCentralFileHeader); Write8(item.MadeByVersion.Version); @@ -249,10 +289,11 @@ Write16((UInt16)item.Name.Len()); const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); - const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8); + const bool writeNtfs = item.Write_NtfsTime; const size_t centralExtraSize = (isZip64 ? 4 + zip64ExtraSize : 0) - + (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) + + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0) + + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0) + item.Get_UtfName_ExtraSize() + item.CentralExtra.GetSize(); @@ -283,18 +324,7 @@ Write64(item.LocalHeaderPos); } - if (item.NtfsTimeIsDefined) - { - Write16(NFileHeader::NExtraID::kNTFS); - Write16(kNtfsExtraSize); - Write32(0); // reserved - Write16(NFileHeader::NNtfsExtra::kTagTime); - Write16(8 * 3); - WriteNtfsTime(item.Ntfs_MTime); - WriteNtfsTime(item.Ntfs_ATime); - WriteNtfsTime(item.Ntfs_CTime); - } - + WriteTimeExtra(item, writeNtfs); WriteUtfName(item); WriteExtra(item.CentralExtra); @@ -304,15 +334,15 @@ void COutArchive::WriteCentralDir(const CObjectVector &items, const CByteBuffer *comment) { - UInt64 cdOffset = GetCurPos(); + const UInt64 cdOffset = GetCurPos(); FOR_VECTOR (i, items) WriteCentralHeader(items[i]); - UInt64 cd64EndOffset = GetCurPos(); - UInt64 cdSize = cd64EndOffset - cdOffset; - bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); - bool cdSize64 = DOES_NEED_ZIP64(cdSize); - bool items64 = items.Size() >= 0xFFFF; - bool isZip64 = (cdOffset64 || cdSize64 || items64); + const UInt64 cd64EndOffset = GetCurPos(); + const UInt64 cdSize = cd64EndOffset - cdOffset; + const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); + const bool cdSize64 = DOES_NEED_ZIP64(cdSize); + const bool items64 = items.Size() >= 0xFFFF; + const bool isZip64 = (cdOffset64 || cdSize64 || items64); // isZip64 = true; // to test Zip64 diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipOut.h 7zip-22.01/CPP/7zip/Archive/Zip/ZipOut.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipOut.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipOut.h 2022-01-26 12:00:00.000000000 +0000 @@ -18,7 +18,8 @@ FILETIME Ntfs_MTime; FILETIME Ntfs_ATime; FILETIME Ntfs_CTime; - bool NtfsTimeIsDefined; + bool Write_NtfsTime; + bool Write_UnixTime; // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra. @@ -32,7 +33,10 @@ return 4 + 5 + size; } - CItemOut(): NtfsTimeIsDefined(false) {} + CItemOut(): + Write_NtfsTime(false), + Write_UnixTime(false) + {} }; @@ -62,6 +66,7 @@ Write32(ft.dwHighDateTime); } + void WriteTimeExtra(const CItemOut &item, bool writeNtfs); void WriteUtfName(const CItemOut &item); void WriteExtra(const CExtraBlock &extra); void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipRegister.cpp 7zip-22.01/CPP/7zip/Archive/Zip/ZipRegister.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipRegister.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipRegister.cpp 2022-05-08 11:00:00.000000000 +0000 @@ -20,9 +20,19 @@ "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1, k_Signature, 0, - NArcInfoFlags::kFindSignature | - NArcInfoFlags::kMultiSignature | - NArcInfoFlags::kUseGlobalOffset, - IsArc_Zip) + NArcInfoFlags::kFindSignature + | NArcInfoFlags::kMultiSignature + | NArcInfoFlags::kUseGlobalOffset + | NArcInfoFlags::kCTime + // | NArcInfoFlags::kCTime_Default + | NArcInfoFlags::kATime + // | NArcInfoFlags::kATime_Default + | NArcInfoFlags::kMTime + | NArcInfoFlags::kMTime_Default + , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix) + | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS) + | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows) + , IsArc_Zip) }} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.cpp 7zip-22.01/CPP/7zip/Archive/Zip/ZipUpdate.cpp --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipUpdate.cpp 2022-05-07 12:00:00.000000000 +0000 @@ -74,7 +74,9 @@ item.Ntfs_MTime = ui.Ntfs_MTime; item.Ntfs_ATime = ui.Ntfs_ATime; item.Ntfs_CTime = ui.Ntfs_CTime; - item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; + + item.Write_UnixTime = ui.Write_UnixTime; + item.Write_NtfsTime = ui.Write_NtfsTime; } static void SetFileHeader( @@ -476,12 +478,9 @@ } -static inline bool IsZero_FILETIME(const FILETIME &ft) -{ - return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); -} - -static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream, +static void UpdatePropsFromStream( + const CUpdateOptions &options, + CUpdateItem &item, ISequentialInStream *fileInStream, IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) { CMyComPtr getProps; @@ -505,36 +504,100 @@ } item.Size = size; } - - if (!IsZero_FILETIME(mTime)) - { - item.Ntfs_MTime = mTime; - FILETIME loc = { 0, 0 }; - if (FileTimeToLocalFileTime(&mTime, &loc)) + + if (options.Write_MTime) + if (!FILETIME_IsZero(mTime)) { - item.Time = 0; - NTime::FileTimeToDosTime(loc, item.Time); + item.Ntfs_MTime = mTime; + NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time); } - } - if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime; - if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime; + if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime; + if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime; item.Attrib = attrib; } +/* +static HRESULT ReportProps( + IArchiveUpdateCallbackArcProp *reportArcProp, + UInt32 index, + const CItemOut &item, + bool isAesMode) +{ + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + + NCOM::PropVarEm_Set_UInt64(&prop, item.Size); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop)); + + NCOM::PropVarEm_Set_UInt64(&prop, item.PackSize); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidPackSize, &prop)); + + if (!isAesMode) + { + NCOM::PropVarEm_Set_UInt32(&prop, item.Crc); + RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop)); + } + + RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK)); + + // if (opCallback) RINOK(opCallback->ReportOperation(NEventIndexType::kOutArcIndex, index, NUpdateNotifyOp::kOpFinished)) + + return S_OK; +} +*/ + +/* +struct CTotalStats +{ + UInt64 Size; + UInt64 PackSize; + + void UpdateWithItem(const CItemOut &item) + { + Size += item.Size; + PackSize += item.PackSize; + } +}; + +static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp, + CTotalStats &st) +{ + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.Size); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kArcProp, 0, kpidSize, &prop)); + } + { + NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.PackSize); + RINOK(reportArcProp->ReportProp( + NEventIndexType::kArcProp, 0, kpidPackSize, &prop)); + } + return S_OK; +} +*/ + + static HRESULT Update2St( DECL_EXTERNAL_CODECS_LOC_VARS COutArchive &archive, CInArchive *inArchive, const CObjectVector &inputItems, CObjectVector &updateItems, + const CUpdateOptions &updateOptions, const CCompressionMethodMode *options, bool outSeqMode, const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity, - IArchiveUpdateCallbackFile *opCallback) + IArchiveUpdateCallbackFile *opCallback + // , IArchiveUpdateCallbackArcProp *reportArcProp + ) { CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; @@ -575,7 +638,8 @@ } else { - CMyComPtr fileInStream; + CMyComPtr fileInStream; + { HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); if (res == S_FALSE) { @@ -596,7 +660,7 @@ } // seqMode = true; // to test seqMode - UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); + UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity); CCompressingResult compressingResult; @@ -629,10 +693,11 @@ SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); archive.WriteLocalHeader_Replace(item); - - RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); - unpackSizeTotal += item.Size; - packSizeTotal += item.PackSize; + } + // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode())) + RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); + unpackSizeTotal += item.Size; + packSizeTotal += item.PackSize; } } else @@ -656,6 +721,14 @@ archive.WriteCentralDir(items, comment); + /* + CTotalStats stat; + stat.Size = unpackSizeTotal; + stat.PackSize = packSizeTotal; + if (reportArcProp) + RINOK(ReportArcProps(reportArcProp, stat)) + */ + lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1; return lps->SetCur(); } @@ -667,6 +740,7 @@ CInArchive *inArchive, const CObjectVector &inputItems, CObjectVector &updateItems, + const CUpdateOptions &updateOptions, const CCompressionMethodMode &options, bool outSeqMode, const CByteBuffer *comment, IArchiveUpdateCallback *updateCallback) @@ -674,6 +748,11 @@ CMyComPtr opCallback; updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); + /* + CMyComPtr reportArcProp; + updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp); + */ + bool unknownComplexity = false; UInt64 complexity = 0; UInt64 numFilesToCompress = 0; @@ -901,11 +980,23 @@ return Update2St( EXTERNAL_CODECS_LOC_VARS archive, inArchive, - inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback); + inputItems, updateItems, + updateOptions, + &options2, outSeqMode, + comment, updateCallback, totalComplexity, + opCallback + // , reportArcProp + ); #ifndef _7ZIP_ST + /* + CTotalStats stat; + stat.Size = 0; + stat.PackSize = 0; + */ + CObjectVector items; CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; @@ -1021,7 +1112,7 @@ RINOK(res); if (!fileInStream) return E_INVALIDARG; - UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); + UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } @@ -1122,6 +1213,13 @@ memRef.WriteToStream(memManager.GetBlockSize(), outStream); archive.MoveCurPos(item.PackSize); memRef.FreeOpt(&memManager); + /* + if (reportArcProp) + { + stat.UpdateWithItem(item); + RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode())); + } + */ } else { @@ -1202,6 +1300,14 @@ options.IsRealAesMode(), options.AesKeyMode, item); archive.WriteLocalHeader_Replace(item); + + /* + if (reportArcProp) + { + stat.UpdateWithItem(item); + RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode())); + } + */ } else { @@ -1230,7 +1336,14 @@ RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL)); archive.WriteCentralDir(items, comment); - + + /* + if (reportArcProp) + { + RINOK(ReportArcProps(reportArcProp, stat)); + } + */ + complexity += kCentralHeaderSize * updateItems.Size() + 1; mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL); @@ -1472,6 +1585,7 @@ CObjectVector &updateItems, ISequentialOutStream *seqOutStream, CInArchive *inArchive, bool removeSfx, + const CUpdateOptions &updateOptions, const CCompressionMethodMode &compressionMethodMode, IArchiveUpdateCallback *updateCallback) { @@ -1529,6 +1643,7 @@ EXTERNAL_CODECS_LOC_VARS outArchive, inArchive, inputItems, updateItems, + updateOptions, compressionMethodMode, outSeqMode, inArchive ? &inArchive->ArcInfo.Comment : NULL, updateCallback); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.h 7zip-22.01/CPP/7zip/Archive/Zip/ZipUpdate.h --- 7zip-21.07+dfsg/CPP/7zip/Archive/Zip/ZipUpdate.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Archive/Zip/ZipUpdate.h 2022-05-07 12:00:00.000000000 +0000 @@ -30,7 +30,9 @@ bool NewData; bool NewProps; bool IsDir; - bool NtfsTimeIsDefined; + bool Write_NtfsTime; + bool Write_UnixTime; + // bool Write_UnixTime_ATime; bool IsUtf8; // bool IsAltStream; int IndexInArc; @@ -50,30 +52,50 @@ void Clear() { IsDir = false; - NtfsTimeIsDefined = false; + + Write_NtfsTime = false; + Write_UnixTime = false; + IsUtf8 = false; // IsAltStream = false; + Time = 0; Size = 0; Name.Empty(); Name_Utf.Free(); Comment.Free(); + + FILETIME_Clear(Ntfs_MTime); + FILETIME_Clear(Ntfs_ATime); + FILETIME_Clear(Ntfs_CTime); } CUpdateItem(): IsDir(false), - NtfsTimeIsDefined(false), + Write_NtfsTime(false), + Write_UnixTime(false), IsUtf8(false), // IsAltStream(false), + Time(0), Size(0) {} }; + +struct CUpdateOptions +{ + bool Write_MTime; + bool Write_ATime; + bool Write_CTime; +}; + + HRESULT Update( DECL_EXTERNAL_CODECS_LOC_VARS const CObjectVector &inputItems, CObjectVector &updateItems, ISequentialOutStream *seqOutStream, CInArchive *inArchive, bool removeSfx, + const CUpdateOptions &updateOptions, const CCompressionMethodMode &compressionMethodMode, IArchiveUpdateCallback *updateCallback); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone/makefile.gcc 7zip-22.01/CPP/7zip/Bundles/Alone/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Alone/makefile.gcc 2022-07-14 11:00:00.000000000 +0000 @@ -13,11 +13,20 @@ MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -41,7 +50,7 @@ LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ -D_7ZIP_LARGE_PAGES \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone2/makefile 7zip-22.01/CPP/7zip/Bundles/Alone2/makefile --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone2/makefile 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Alone2/makefile 2022-01-09 19:00:00.000000000 +0000 @@ -18,7 +18,6 @@ $O\FileLink.obj \ $O\FileSystem.obj \ $O\MemoryLock.obj \ - $O\PropVariantConv.obj \ $O\Registry.obj \ $O\SystemInfo.obj \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone2/makefile.gcc 7zip-22.01/CPP/7zip/Bundles/Alone2/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone2/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Alone2/makefile.gcc 2022-07-14 07:00:00.000000000 +0000 @@ -9,6 +9,15 @@ include ../Format7zF/Arc_gcc.mak ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ -D_7ZIP_LARGE_PAGES \ @@ -81,7 +90,6 @@ WIN_OBJS_2 = \ $O/ErrorMsg.o \ $O/FileLink.o \ - $O/PropVariantConv.o \ $O/SystemInfo.o \ 7ZIP_COMMON_OBJS_2 = \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone7z/makefile.gcc 7zip-22.01/CPP/7zip/Bundles/Alone7z/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Alone7z/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Alone7z/makefile.gcc 2022-07-15 12:00:00.000000000 +0000 @@ -6,6 +6,15 @@ # USE_ASM = 1 # ST_MODE = 1 +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + include ../../LzmaDec_gcc.mak @@ -17,7 +26,7 @@ LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -41,7 +50,7 @@ LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ -D_7ZIP_LARGE_PAGES \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Fm/makefile 7zip-22.01/CPP/7zip/Bundles/Fm/makefile --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Fm/makefile 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Fm/makefile 2022-01-09 19:00:00.000000000 +0000 @@ -20,7 +20,6 @@ $O\MemoryLock.obj \ $O\Menu.obj \ $O\ProcessUtils.obj \ - $O\PropVariantConv.obj \ $O\Registry.obj \ $O\ResourceString.obj \ $O\SystemInfo.obj \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Fm/resource.rc 7zip-22.01/CPP/7zip/Bundles/Fm/resource.rc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Fm/resource.rc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Fm/resource.rc 2022-01-05 09:00:00.000000000 +0000 @@ -3,5 +3,5 @@ STRINGTABLE BEGIN - 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs" + 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs apfs" END diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak 7zip-22.01/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak 2022-07-14 11:00:00.000000000 +0000 @@ -3,12 +3,20 @@ LOCAL_FLAGS_ST = MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -59,6 +67,7 @@ $O/FileIO.o \ $O/FileName.o \ $O/PropVariant.o \ + $O/PropVariantConv.o \ $O/PropVariantUtils.o \ $O/System.o \ $O/TimeUtils.o \ @@ -82,6 +91,7 @@ $O/UniqBlocks.o \ AR_OBJS = \ + $O/ApfsHandler.o \ $O/ApmHandler.o \ $O/ArHandler.o \ $O/ArjHandler.o \ @@ -101,6 +111,7 @@ $O/HandlerCont.o \ $O/HfsHandler.o \ $O/IhexHandler.o \ + $O/LpHandler.o \ $O/LzhHandler.o \ $O/LzmaHandler.o \ $O/MachoHandler.o \ @@ -112,6 +123,7 @@ $O/PpmdHandler.o \ $O/QcowHandler.o \ $O/RpmHandler.o \ + $O/SparseHandler.o \ $O/SplitHandler.o \ $O/SquashfsHandler.o \ $O/SwfHandler.o \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/Arc.mak 7zip-22.01/CPP/7zip/Bundles/Format7zF/Arc.mak --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/Arc.mak 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Format7zF/Arc.mak 2022-06-15 10:00:00.000000000 +0000 @@ -24,6 +24,7 @@ $O\FileIO.obj \ $O\FileName.obj \ $O\PropVariant.obj \ + $O\PropVariantConv.obj \ $O\PropVariantUtils.obj \ $O\Synchronization.obj \ $O\System.obj \ @@ -53,6 +54,7 @@ $O\VirtThread.obj \ AR_OBJS = \ + $O\ApfsHandler.obj \ $O\ApmHandler.obj \ $O\ArHandler.obj \ $O\ArjHandler.obj \ @@ -72,6 +74,7 @@ $O\HandlerCont.obj \ $O\HfsHandler.obj \ $O\IhexHandler.obj \ + $O\LpHandler.obj \ $O\LzhHandler.obj \ $O\LzmaHandler.obj \ $O\MachoHandler.obj \ @@ -83,6 +86,7 @@ $O\PpmdHandler.obj \ $O\QcowHandler.obj \ $O\RpmHandler.obj \ + $O\SparseHandler.obj \ $O\SplitHandler.obj \ $O\SquashfsHandler.obj \ $O\SwfHandler.obj \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/Format7z.dsp 7zip-22.01/CPP/7zip/Bundles/Format7zF/Format7z.dsp --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/Format7z.dsp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Format7zF/Format7z.dsp 2022-07-08 12:00:00.000000000 +0000 @@ -2763,6 +2763,10 @@ # End Group # Begin Source File +SOURCE=..\..\Archive\ApfsHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\ApmHandler.cpp # End Source File # Begin Source File @@ -2843,6 +2847,10 @@ # End Source File # Begin Source File +SOURCE=..\..\Archive\HfsHandler.h +# End Source File +# Begin Source File + SOURCE=..\..\Archive\IArchive.h # End Source File # Begin Source File @@ -2851,6 +2859,10 @@ # End Source File # Begin Source File +SOURCE=..\..\Archive\LpHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\LzhHandler.cpp # End Source File # Begin Source File @@ -2905,6 +2917,10 @@ # End Source File # Begin Source File +SOURCE=..\..\Archive\SparseHandler.cpp +# End Source File +# Begin Source File + SOURCE=..\..\Archive\SplitHandler.cpp # End Source File # Begin Source File @@ -3029,6 +3045,14 @@ # End Source File # Begin Source File +SOURCE=..\..\..\Windows\PropVariantConv.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariantConv.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Windows\PropVariantUtils.cpp # End Source File # Begin Source File diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/makefile.gcc 7zip-22.01/CPP/7zip/Bundles/Format7zF/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Format7zF/makefile.gcc 2022-07-14 11:00:00.000000000 +0000 @@ -8,6 +8,16 @@ include Arc_gcc.mak ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + + +ifdef IS_MINGW LOCAL_FLAGS_WIN = \ -D_7ZIP_LARGE_PAGES \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/resource.rc 7zip-22.01/CPP/7zip/Bundles/Format7zF/resource.rc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/Format7zF/resource.rc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/Format7zF/resource.rc 2022-01-05 09:00:00.000000000 +0000 @@ -28,10 +28,11 @@ 22 ICON "../../Archive/Icons/ntfs.ico" 23 ICON "../../Archive/Icons/xz.ico" 24 ICON "../../Archive/Icons/squashfs.ico" +25 ICON "../../Archive/Icons/apfs.ico" STRINGTABLE BEGIN - 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24" + 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 apfs:25" END diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp 7zip-22.01/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp --- 7zip-21.07+dfsg/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp 2022-06-09 13:00:00.000000000 +0000 @@ -515,7 +515,7 @@ if (inStreamSpec) { - if (!inStreamSpec->File.GetLength(fileSize)) + if (!inStreamSpec->GetLength(fileSize)) throw "Cannot get file length"; fileSizeDefined = true; if (!stdOutMode) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/LzmaCon/makefile.gcc 7zip-22.01/CPP/7zip/Bundles/LzmaCon/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/LzmaCon/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/LzmaCon/makefile.gcc 2022-07-15 11:00:00.000000000 +0000 @@ -10,6 +10,15 @@ MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST @@ -30,7 +39,7 @@ LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW SYS_OBJS = \ $O/Registry.o \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Bundles/SFXCon/makefile.gcc 7zip-22.01/CPP/7zip/Bundles/SFXCon/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/Bundles/SFXCon/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Bundles/SFXCon/makefile.gcc 2022-07-14 11:00:00.000000000 +0000 @@ -11,11 +11,20 @@ MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -35,7 +44,7 @@ LOCAL_FLAGS_SYS = -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_SYS = \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/FileStreams.cpp 7zip-22.01/CPP/7zip/Common/FileStreams.cpp --- 7zip-21.07+dfsg/CPP/7zip/Common/FileStreams.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/FileStreams.cpp 2022-07-12 14:00:00.000000000 +0000 @@ -2,18 +2,33 @@ #include "StdAfx.h" +// #include + #ifndef _WIN32 #include #include #include -#include "../../Windows/FileFind.h" +#include +#include + +// for major()/minor(): +#if defined(__FreeBSD__) || defined(BSD) +#include +#else +#include +#endif + #endif +#include "../../Windows/FileFind.h" + #ifdef SUPPORT_DEVICE_FILE #include "../../../C/Alloc.h" #include "../../Common/Defs.h" #endif +#include "../PropID.h" + #include "FileStreams.h" static inline HRESULT GetLastError_HRESULT() @@ -37,12 +52,19 @@ #endif CInFileStream::CInFileStream(): - #ifdef SUPPORT_DEVICE_FILE + #ifdef SUPPORT_DEVICE_FILE VirtPos(0), PhyPos(0), Buf(0), BufSize(0), - #endif + #endif + #ifndef _WIN32 + _uid(0), + _gid(0), + StoreOwnerId(false), + StoreOwnerName(false), + #endif + _info_WasLoaded(false), SupportHardLinks(false), Callback(NULL), CallbackRef(0) @@ -56,7 +78,7 @@ #endif if (Callback) - Callback->InFileStream_On_Destroy(CallbackRef); + Callback->InFileStream_On_Destroy(this, CallbackRef); } STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) @@ -306,8 +328,14 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) { + if (!_info_WasLoaded) + RINOK(ReloadProps()); + const BY_HANDLE_FILE_INFORMATION &info = _info; + /* BY_HANDLE_FILE_INFORMATION info; - if (File.GetFileInformation(&info)) + if (!File.GetFileInformation(&info)) + return GetLastError_HRESULT(); + */ { if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; if (cTime) *cTime = info.ftCreationTime; @@ -316,13 +344,18 @@ if (attrib) *attrib = info.dwFileAttributes; return S_OK; } - return GetLastError_HRESULT(); } STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) { + if (!_info_WasLoaded) + RINOK(ReloadProps()); + const BY_HANDLE_FILE_INFORMATION &info = _info; + /* BY_HANDLE_FILE_INFORMATION info; - if (File.GetFileInformation(&info)) + if (!File.GetFileInformation(&info)) + return GetLastError_HRESULT(); + */ { props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; props->VolID = info.dwVolumeSerialNumber; @@ -335,27 +368,114 @@ props->MTime = info.ftLastWriteTime; return S_OK; } - return GetLastError_HRESULT(); } +STDMETHODIMP CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value) +{ + if (!_info_WasLoaded) + RINOK(ReloadProps()); + + if (!_info_WasLoaded) + return S_OK; + + NWindows::NCOM::CPropVariant prop; + + #ifdef SUPPORT_DEVICE_FILE + if (File.IsDeviceFile) + { + switch (propID) + { + case kpidSize: + if (File.SizeDefined) + prop = File.Size; + break; + // case kpidAttrib: prop = (UInt32)0; break; + case kpidPosixAttrib: + { + prop = (UInt32)NWindows::NFile::NFind::NAttributes:: + Get_PosixMode_From_WinAttrib(0); + /* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute + so we don't use MY_LIN_S_IFBLK here */ + // prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug + break; + } + /* + case kpidDeviceMajor: + prop = (UInt32)8; // id for SCSI type device (sda) + break; + case kpidDeviceMinor: + prop = (UInt32)0; + break; + */ + } + } + else + #endif + { + switch (propID) + { + case kpidSize: + { + const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow; + prop = size; + break; + } + case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break; + case kpidPosixAttrib: + prop = (UInt32)NWindows::NFile::NFind::NAttributes:: + Get_PosixMode_From_WinAttrib(_info.dwFileAttributes); + // | (UInt32)(1 << 21); // for debug + break; + } + } + prop.Detach(value); + return S_OK; +} + + +STDMETHODIMP CInFileStream::ReloadProps() +{ + #ifdef SUPPORT_DEVICE_FILE + if (File.IsDeviceFile) + { + memset(&_info, 0, sizeof(_info)); + if (File.SizeDefined) + { + _info.nFileSizeHigh = (DWORD)(File.Size >> 32); + _info.nFileSizeLow = (DWORD)(File.Size); + } + _info.nNumberOfLinks = 1; + _info_WasLoaded = true; + return S_OK; + } + #endif + _info_WasLoaded = File.GetFileInformation(&_info); + if (!_info_WasLoaded) + return GetLastError_HRESULT(); + return S_OK; +} + + #elif !defined(_WIN32) STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) { + if (!_info_WasLoaded) + RINOK(ReloadProps()); + const struct stat &st = _info; + /* struct stat st; if (File.my_fstat(&st) != 0) return GetLastError_HRESULT(); - + */ + if (size) *size = (UInt64)st.st_size; - #ifdef __APPLE__ - if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, *cTime); - if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, *aTime); - if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, *mTime); - #else - if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, *cTime); - if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, *aTime); - if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, *mTime); - #endif + if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime); + if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime); + if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime); if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); return S_OK; @@ -365,9 +485,14 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) { + if (!_info_WasLoaded) + RINOK(ReloadProps()); + const struct stat &st = _info; + /* struct stat st; if (File.my_fstat(&st) != 0) return GetLastError_HRESULT(); + */ props->Size = (UInt64)st.st_size; /* @@ -381,15 +506,9 @@ props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long) props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); - #ifdef __APPLE__ - NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, props->CTime); - NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, props->ATime); - NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, props->MTime); - #else - NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, props->CTime); - NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, props->ATime); - NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, props->MTime); - #endif + FiTime_To_FILETIME (ST_CTIME(st), props->CTime); + FiTime_To_FILETIME (ST_ATIME(st), props->ATime); + FiTime_To_FILETIME (ST_MTIME(st), props->MTime); /* printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n" @@ -402,8 +521,130 @@ return S_OK; } +STDMETHODIMP CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value) +{ + if (!_info_WasLoaded) + RINOK(ReloadProps()); + + if (!_info_WasLoaded) + return S_OK; + + const struct stat &st = _info; + + NWindows::NCOM::CPropVariant prop; + { + switch (propID) + { + case kpidSize: prop = (UInt64)st.st_size; break; + case kpidAttrib: + prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); + break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break; + case kpidPosixAttrib: prop = (UInt32)st.st_mode; break; + + case kpidDeviceMajor: + { + // printf("\nst.st_rdev = %d\n", st.st_rdev); + if (S_ISCHR(st.st_mode) || + S_ISBLK(st.st_mode)) + prop = (UInt32)(major(st.st_rdev)); // + 1000); + // prop = (UInt32)12345678; // for debug + break; + } + + case kpidDeviceMinor: + if (S_ISCHR(st.st_mode) || + S_ISBLK(st.st_mode)) + prop = (UInt32)(minor(st.st_rdev)); // + 100); + // prop = (UInt32)(st.st_rdev); // for debug + // printf("\nst.st_rdev = %d\n", st.st_rdev); + // prop = (UInt32)123456789; // for debug + break; + + /* + case kpidDevice: + if (S_ISCHR(st.st_mode) || + S_ISBLK(st.st_mode)) + prop = (UInt64)(st.st_rdev); + break; + */ + + case kpidUserId: + { + if (StoreOwnerId) + prop = (UInt32)st.st_uid; + break; + } + case kpidGroupId: + { + if (StoreOwnerId) + prop = (UInt32)st.st_gid; + break; + } + case kpidUser: + { + if (StoreOwnerName) + { + const uid_t uid = st.st_uid; + { + if (!OwnerName.IsEmpty() && _uid == uid) + prop = OwnerName; + else + { + const passwd *pw = getpwuid(uid); + if (pw) + { + // we can use utf-8 here. + // prop = pw->pw_name; + } + } + } + } + break; + } + case kpidGroup: + { + if (StoreOwnerName) + { + const uid_t gid = st.st_gid; + { + if (!OwnerGroup.IsEmpty() && _gid == gid) + prop = OwnerGroup; + else + { + const group *gr = getgrgid(gid); + if (gr) + { + // we can use utf-8 here. + // prop = gr->gr_name; + } + } + } + } + break; + } + } + } + prop.Detach(value); + return S_OK; +} + + +STDMETHODIMP CInFileStream::ReloadProps() +{ + _info_WasLoaded = (File.my_fstat(&_info) == 0); + if (!_info_WasLoaded) + return GetLastError_HRESULT(); + return S_OK; +} + #endif + + + ////////////////////////// // COutFileStream diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/FileStreams.h 7zip-22.01/CPP/7zip/Common/FileStreams.h --- 7zip-21.07+dfsg/CPP/7zip/Common/FileStreams.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/FileStreams.h 2022-06-09 13:00:00.000000000 +0000 @@ -14,10 +14,14 @@ #include "../IStream.h" +#include "UniqBlocks.h" + + +class CInFileStream; struct IInFileStream_Callback { virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0; - virtual void InFileStream_On_Destroy(UINT_PTR val) = 0; + virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) = 0; }; class CInFileStream: @@ -25,10 +29,11 @@ public IStreamGetSize, public IStreamGetProps, public IStreamGetProps2, + public IStreamGetProp, public CMyUnknownImp { -public: NWindows::NFile::NIO::CInFile File; +public: #ifdef USE_WIN_FILE @@ -42,22 +47,46 @@ #endif - bool SupportHardLinks; + #ifdef _WIN32 + BY_HANDLE_FILE_INFORMATION _info; + #else + struct stat _info; + UInt32 _uid; + UInt32 _gid; + UString OwnerName; + UString OwnerGroup; + bool StoreOwnerId; + bool StoreOwnerName; + #endif + bool _info_WasLoaded; + bool SupportHardLinks; IInFileStream_Callback *Callback; UINT_PTR CallbackRef; virtual ~CInFileStream(); CInFileStream(); + + void Set_PreserveATime(bool v) + { + File.PreserveATime = v; + } + + bool GetLength(UInt64 &length) const throw() + { + return File.GetLength(length); + } bool Open(CFSTR fileName) { + _info_WasLoaded = false; return File.Open(fileName); } bool OpenShared(CFSTR fileName, bool shareForWrite) { + _info_WasLoaded = false; return File.OpenShared(fileName, shareForWrite); } @@ -65,6 +94,7 @@ MY_QUERYINTERFACE_ENTRY(IStreamGetSize) MY_QUERYINTERFACE_ENTRY(IStreamGetProps) MY_QUERYINTERFACE_ENTRY(IStreamGetProps2) + MY_QUERYINTERFACE_ENTRY(IStreamGetProp) MY_QUERYINTERFACE_END MY_ADDREF_RELEASE @@ -74,6 +104,8 @@ STDMETHOD(GetSize)(UInt64 *size); STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib); STDMETHOD(GetProps2)(CStreamFileProps *props); + STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value); + STDMETHOD(ReloadProps)(); }; class CStdInFileStream: @@ -110,11 +142,11 @@ UInt64 ProcessedSize; - bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) + bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) { return File.SetTime(cTime, aTime, mTime); } - bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); } + bool SetMTime(const CFiTime *mTime) { return File.SetMTime(mTime); } MY_UNKNOWN_IMP1(IOutStream) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/InBuffer.cpp 7zip-22.01/CPP/7zip/Common/InBuffer.cpp --- 7zip-21.07+dfsg/CPP/7zip/Common/InBuffer.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/InBuffer.cpp 2022-02-09 08:00:00.000000000 +0000 @@ -77,7 +77,8 @@ { if (!ReadBlock()) { - NumExtraBytes++; + // 22.00: we don't increment (NumExtraBytes) here + // NumExtraBytes++; b = 0xFF; return false; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/LimitedStreams.cpp 7zip-22.01/CPP/7zip/Common/LimitedStreams.cpp --- 7zip-21.07+dfsg/CPP/7zip/Common/LimitedStreams.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/LimitedStreams.cpp 2022-02-01 08:00:00.000000000 +0000 @@ -154,44 +154,70 @@ { if (processedSize) *processedSize = 0; - if (_virtPos >= Extents.Back().Virt) + const UInt64 virt = _virtPos; + if (virt >= Extents.Back().Virt) return S_OK; if (size == 0) return S_OK; - unsigned left = 0, right = Extents.Size() - 1; - for (;;) + unsigned left = _prevExtentIndex; + if (virt < Extents[left].Virt || + virt >= Extents[left + 1].Virt) { - unsigned mid = (left + right) / 2; - if (mid == left) - break; - if (_virtPos < Extents[mid].Virt) - right = mid; - else - left = mid; + left = 0; + unsigned right = Extents.Size() - 1; + for (;;) + { + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + if (mid == left) + break; + if (virt < Extents[mid].Virt) + right = mid; + else + left = mid; + } + _prevExtentIndex = left; } - const CSeekExtent &extent = Extents[left]; - UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt); - if (_needStartSeek || _phyPos != phyPos) { - _needStartSeek = false; - _phyPos = phyPos; - RINOK(SeekToPhys()); + const UInt64 rem = Extents[left + 1].Virt - virt; + if (size > rem) + size = (UInt32)rem; } - UInt64 rem = Extents[left + 1].Virt - _virtPos; - if (size > rem) - size = (UInt32)rem; + const CSeekExtent &extent = Extents[left]; + + if (extent.Is_ZeroFill()) + { + memset(data, 0, size); + _virtPos += size; + if (processedSize) + *processedSize = size; + return S_OK; + } + + { + const UInt64 phy = extent.Phy + (virt - extent.Virt); + if (_phyPos != phy) + { + _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error + RINOK(Stream->Seek((Int64)phy, STREAM_SEEK_SET, NULL)); + _phyPos = phy; + } + } - HRESULT res = Stream->Read(data, size, &size); - _phyPos += size; + const HRESULT res = Stream->Read(data, size, &size); _virtPos += size; + if (res == S_OK) + _phyPos += size; + else + _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error if (processedSize) *processedSize = size; return res; } + STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) { switch (seekOrigin) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/LimitedStreams.h 7zip-22.01/CPP/7zip/Common/LimitedStreams.h --- 7zip-21.07+dfsg/CPP/7zip/Common/LimitedStreams.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/LimitedStreams.h 2022-02-01 08:00:00.000000000 +0000 @@ -101,21 +101,26 @@ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); }; + + +const UInt64 k_SeekExtent_Phy_Type_ZeroFill = (UInt64)(Int64)-1; + struct CSeekExtent { - UInt64 Phy; UInt64 Virt; + UInt64 Phy; + + void SetAs_ZeroFill() { Phy = k_SeekExtent_Phy_Type_ZeroFill; } + bool Is_ZeroFill() const { return Phy == k_SeekExtent_Phy_Type_ZeroFill; } }; class CExtentsStream: public IInStream, public CMyUnknownImp { - UInt64 _phyPos; UInt64 _virtPos; - bool _needStartSeek; - - HRESULT SeekToPhys() { return Stream->Seek((Int64)_phyPos, STREAM_SEEK_SET, NULL); } + UInt64 _phyPos; + unsigned _prevExtentIndex; public: CMyComPtr Stream; @@ -129,11 +134,13 @@ void Init() { _virtPos = 0; - _phyPos = 0; - _needStartSeek = true; + _phyPos = (UInt64)0 - 1; // we need Seek() for Stream + _prevExtentIndex = 0; } }; + + class CLimitedSequentialOutStream: public ISequentialOutStream, public CMyUnknownImp diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/PropId.cpp 7zip-22.01/CPP/7zip/Common/PropId.cpp --- 7zip-21.07+dfsg/CPP/7zip/Common/PropId.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/PropId.cpp 2022-05-03 11:00:00.000000000 +0000 @@ -104,5 +104,12 @@ VT_UI8, VT_BOOL, VT_BSTR, - VT_BSTR + VT_BSTR, + VT_BSTR, + VT_BOOL, + VT_FILETIME, // kpidChangeTime + VT_UI4, + VT_UI4, + VT_UI4, + VT_UI4 // kpidDeviceMinor }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/RegisterArc.h 7zip-22.01/CPP/7zip/Common/RegisterArc.h --- 7zip-21.07+dfsg/CPP/7zip/Common/RegisterArc.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/RegisterArc.h 2022-05-18 09:00:00.000000000 +0000 @@ -7,7 +7,7 @@ struct CArcInfo { - UInt16 Flags; + UInt32 Flags; Byte Id; Byte SignatureSize; UInt16 SignatureOffset; @@ -17,6 +17,8 @@ const char *Ext; const char *AddExt; + UInt32 TimeFlags; + Func_CreateInArchive CreateInArchive; Func_CreateOutArchive CreateOutArchive; Func_IsArc IsArc; @@ -39,22 +41,22 @@ #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); } #endif -#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \ - static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, crIn, crOut, isArc } ; \ +#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ + static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, tf, crIn, crOut, isArc } ; \ -#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \ - REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \ +#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ + REGISTER_ARC_V (n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \ struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \ static CRegisterArc g_RegisterArc; #define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \ IMP_CreateArcIn_2(cls) \ - REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, NULL, isArc) + REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, 0, CreateArc, NULL, isArc) #define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \ IMP_CreateArcIn_2(cls) \ - REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, CreateArc, NULL, isArc) + REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, 0, CreateArc, NULL, isArc) #define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \ REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc) @@ -63,15 +65,15 @@ REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc) -#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, isArc) \ +#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, tf, isArc) \ IMP_CreateArcIn \ IMP_CreateArcOut \ - REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, CreateArcOut, isArc) + REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) -#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, isArc) \ +#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, tf, isArc) \ IMP_CreateArcIn \ IMP_CreateArcOut \ - REGISTER_ARC_V(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, CreateArcOut, isArc) \ + REGISTER_ARC_V(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) \ struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \ static CRegisterArcDecSig g_RegisterArc; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/UniqBlocks.cpp 7zip-22.01/CPP/7zip/Common/UniqBlocks.cpp --- 7zip-21.07+dfsg/CPP/7zip/Common/UniqBlocks.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/UniqBlocks.cpp 2022-01-08 17:00:00.000000000 +0000 @@ -11,10 +11,10 @@ unsigned left = 0, right = Sorted.Size(); while (left != right) { - unsigned mid = (left + right) / 2; - unsigned index = Sorted[mid]; + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned index = Sorted[mid]; const CByteBuffer &buf = Bufs[index]; - size_t sizeMid = buf.Size(); + const size_t sizeMid = buf.Size(); if (size < sizeMid) right = mid; else if (size > sizeMid) @@ -23,7 +23,7 @@ { if (size == 0) return index; - int cmp = memcmp(data, buf, size); + const int cmp = memcmp(data, buf, size); if (cmp == 0) return index; if (cmp < 0) diff -Nru 7zip-21.07+dfsg/CPP/7zip/Common/UniqBlocks.h 7zip-22.01/CPP/7zip/Common/UniqBlocks.h --- 7zip-21.07+dfsg/CPP/7zip/Common/UniqBlocks.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Common/UniqBlocks.h 2022-04-02 13:00:00.000000000 +0000 @@ -3,9 +3,24 @@ #ifndef __UNIQ_BLOCKS_H #define __UNIQ_BLOCKS_H -#include "../../Common/MyTypes.h" #include "../../Common/MyBuffer.h" -#include "../../Common/MyVector.h" +#include "../../Common/MyString.h" + +struct C_UInt32_UString_Map +{ + CRecordVector Numbers; + UStringVector Strings; + + void Add_UInt32(const UInt32 n) + { + Numbers.AddToUniqueSorted(n); + } + int Find(const UInt32 n) + { + return Numbers.FindInSorted(n); + } +}; + struct CUniqBlocks { diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/BitlDecoder.h 7zip-22.01/CPP/7zip/Compress/BitlDecoder.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/BitlDecoder.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/BitlDecoder.h 2022-01-28 08:00:00.000000000 +0000 @@ -155,6 +155,10 @@ MY_FORCE_INLINE bool ReadAlignedByte_FromBuf(Byte &b) { + if (this->_stream.NumExtraBytes != 0) + if (this->_stream.NumExtraBytes >= 4 + || kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3)) + return false; if (this->_bitPos == kNumBigValueBits) return this->_stream.ReadByte_FromBuf(b); b = (Byte)(_normalValue & 0xFF); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/BZip2Encoder.cpp 7zip-22.01/CPP/7zip/Compress/BZip2Encoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/BZip2Encoder.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/BZip2Encoder.cpp 2022-02-07 11:00:00.000000000 +0000 @@ -98,8 +98,8 @@ bool needLeave = true; try { - UInt32 blockSize = Encoder->ReadRleBlock(m_Block); - m_PackSize = Encoder->m_InStream.GetProcessedSize(); + const UInt32 blockSize = Encoder->ReadRleBlock(m_Block); + m_UnpackSize = Encoder->m_InStream.GetProcessedSize(); m_BlockIndex = Encoder->NextBlockIndex; if (++Encoder->NextBlockIndex == Encoder->NumThreads) Encoder->NextBlockIndex = 0; @@ -222,7 +222,8 @@ Byte prevByte; if (m_InStream.ReadByte(prevByte)) { - UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; + NumBlocks++; + const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1; unsigned numReps = 1; buffer[i++] = prevByte; while (i < blockSize) // "- 1" to support RLE @@ -722,8 +723,8 @@ if (Encoder->Progress) { - UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize(); - res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize); + const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize(); + res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize); } Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set(); @@ -744,6 +745,7 @@ HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress) { + NumBlocks = 0; #ifndef _7ZIP_ST Progress = progress; RINOK(Create()); @@ -831,9 +833,9 @@ RINOK(ti.EncodeBlock3(blockSize)); if (progress) { - UInt64 packSize = m_InStream.GetProcessedSize(); - UInt64 unpackSize = m_OutStream.GetProcessedSize(); - RINOK(progress->SetRatioInfo(&packSize, &unpackSize)); + const UInt64 unpackSize = m_InStream.GetProcessedSize(); + const UInt64 packSize = m_OutStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&unpackSize, &packSize)); } } } @@ -845,7 +847,10 @@ WriteByte(kFinSig5); WriteCrc(CombinedCrc.GetDigest()); - return Flush(); + RINOK(Flush()); + if (!m_InStream.WasFinished()) + return E_FAIL; + return S_OK; } STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/BZip2Encoder.h 7zip-22.01/CPP/7zip/Compress/BZip2Encoder.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/BZip2Encoder.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/BZip2Encoder.h 2022-02-07 11:00:00.000000000 +0000 @@ -129,7 +129,7 @@ // it's not member of this thread. We just need one event per thread NWindows::NSynchronization::CAutoResetEvent CanWriteEvent; - UInt64 m_PackSize; + UInt64 m_UnpackSize; Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size. HRESULT Create(); @@ -195,6 +195,10 @@ CThreadInfo ThreadsInfo; #endif + UInt64 NumBlocks; + + UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); } + UInt32 ReadRleBlock(Byte *buf); void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte); diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/DeflateDecoder.cpp 7zip-22.01/CPP/7zip/Compress/DeflateDecoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/DeflateDecoder.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/DeflateDecoder.cpp 2022-01-26 08:00:00.000000000 +0000 @@ -426,7 +426,6 @@ { AlignToByte(); UInt32 i = 0; - if (!m_InBitStream.ExtraBitsWereRead()) { for (i = 0; i < size; i++) { diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/LzfseDecoder.cpp 7zip-22.01/CPP/7zip/Compress/LzfseDecoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/LzfseDecoder.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/LzfseDecoder.cpp 2022-07-07 11:00:00.000000000 +0000 @@ -89,11 +89,8 @@ -HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize) +HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize, UInt32 packSize) { - UInt32 packSize; - RINOK(GetUInt32(packSize)); - PRF(printf("\nLZVN %7u %7u", unpackSize, packSize)); UInt32 D = 0; @@ -854,6 +851,16 @@ UInt64 prevOut = 0; UInt64 prevIn = 0; + if (LzvnMode) + { + const UInt64 unpackSize = *outSize; + const UInt64 packSize = *inSize; + if (unpackSize > (UInt32)(Int32)-1 + || packSize > (UInt32)(Int32)-1) + return S_FALSE; + RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize)); + } + else for (;;) { const UInt64 pos = m_OutWindowStream.GetProcessedSize(); @@ -889,7 +896,12 @@ if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2) res = DecodeLzfse(cur, (Byte)v); else if (v == 0x6E) // 'n' - res = DecodeLzvn(cur); + { + UInt32 packSize; + res = GetUInt32(packSize); + if (res == S_OK) + res = DecodeLzvn(cur, packSize); + } else if (v == 0x2D) // '-' res = DecodeUncompressed(cur); else diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/LzfseDecoder.h 7zip-22.01/CPP/7zip/Compress/LzfseDecoder.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/LzfseDecoder.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/LzfseDecoder.h 2022-07-07 11:00:00.000000000 +0000 @@ -41,14 +41,23 @@ HRESULT GetUInt32(UInt32 &val); HRESULT DecodeUncompressed(UInt32 unpackSize); - HRESULT DecodeLzvn(UInt32 unpackSize); + HRESULT DecodeLzvn(UInt32 unpackSize, UInt32 packSize); HRESULT DecodeLzfse(UInt32 unpackSize, Byte version); STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); public: + bool LzvnMode; MY_UNKNOWN_IMP + CDecoder(): + LzvnMode(false) + {} + + // sizes are checked in Code() + // UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); } + // UInt64 GetOutputProcessedSize() const { return m_OutWindowStream.GetProcessedSize(); } + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/LzmaEncoder.cpp 7zip-22.01/CPP/7zip/Compress/LzmaEncoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/LzmaEncoder.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/LzmaEncoder.cpp 2022-02-09 08:00:00.000000000 +0000 @@ -9,14 +9,15 @@ #include "LzmaEncoder.h" -#include "../../Common/IntToString.h" -#include "../../Windows/TimeUtils.h" - // #define LOG_LZMA_THREADS #ifdef LOG_LZMA_THREADS + #include +#include "../../Common/IntToString.h" +#include "../../Windows/TimeUtils.h" + EXTERN_C_BEGIN void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]); EXTERN_C_END diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar1Decoder.cpp 7zip-22.01/CPP/7zip/Compress/Rar1Decoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar1Decoder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar1Decoder.cpp 2020-09-28 09:31:27.000000000 +0000 @@ -0,0 +1,518 @@ +// Rar1Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +#include "Rar1Decoder.h" + +namespace NCompress { +namespace NRar1 { + +static const unsigned kNumBits = 12; + +static const Byte kShortLen1[16 * 3] = +{ + 0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, + 1,3,4,4,5,6,7,8,8,4,4,5,6,6,0,0, + 1,4,4,4,5,6,7,8,8,4,4,5,6,6,4,0 +}; + +static const Byte kShortLen2[16 * 3] = +{ + 0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, + 2,3,3,3,4,4,5,6,6,4,4,5,6,6,0,0, + 2,3,3,4,4,4,5,6,6,4,4,5,6,6,4,0 +}; + +static const Byte PosL1[kNumBits + 1] = { 0,0,2,1,2,2,4,5,4,4,8,0,224 }; +static const Byte PosL2[kNumBits + 1] = { 0,0,0,5,2,2,4,5,4,4,8,2,220 }; + +static const Byte PosHf0[kNumBits + 1] = { 0,0,0,0,8,8,8,9,0,0,0,0,224 }; +static const Byte PosHf1[kNumBits + 1] = { 0,0,0,0,0,4,40,16,16,4,0,47,130 }; +static const Byte PosHf2[kNumBits + 1] = { 0,0,0,0,0,2,5,46,64,116,24,0,0 }; +static const Byte PosHf3[kNumBits + 1] = { 0,0,0,0,0,0,2,14,202,33,6,0,0 }; +static const Byte PosHf4[kNumBits + 1] = { 0,0,0,0,0,0,0,0,255,2,0,0,0 }; + +static const UInt32 kHistorySize = (1 << 16); + +CDecoder::CDecoder(): + _isSolid(false), + _solidAllowed(false) + { } + +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } + +HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len) +{ + if (len == 0) + return S_FALSE; + if (m_UnpackSize < len) + return S_FALSE; + m_UnpackSize -= len; + return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE; +} + + +UInt32 CDecoder::DecodeNum(const Byte *numTab) +{ + /* + { + // we can check that tables are correct + UInt32 sum = 0; + for (unsigned i = 0; i <= kNumBits; i++) + sum += ((UInt32)numTab[i] << (kNumBits - i)); + if (sum != (1 << kNumBits)) + throw 111; + } + */ + + UInt32 val = m_InBitStream.GetValue(kNumBits); + UInt32 sum = 0; + unsigned i = 2; + + for (;;) + { + UInt32 num = numTab[i]; + UInt32 cur = num << (kNumBits - i); + if (val < cur) + break; + i++; + val -= cur; + sum += num; + } + m_InBitStream.MovePos(i); + return ((val >> (kNumBits - i)) + sum); +} + + +HRESULT CDecoder::ShortLZ() +{ + NumHuf = 0; + + if (LCount == 2) + { + if (ReadBits(1)) + return CopyBlock(LastDist, LastLength); + LCount = 0; + } + + UInt32 bitField = m_InBitStream.GetValue(8); + + UInt32 len, dist; + { + const Byte *xors = (AvrLn1 < 37) ? kShortLen1 : kShortLen2; + const Byte *lens = xors + 16 + Buf60; + for (len = 0; ((bitField ^ xors[len]) >> (8 - lens[len])) != 0; len++); + m_InBitStream.MovePos(lens[len]); + } + + if (len >= 9) + { + if (len == 9) + { + LCount++; + return CopyBlock(LastDist, LastLength); + } + + LCount = 0; + + if (len == 14) + { + len = DecodeNum(PosL2) + 5; + dist = 0x8000 + ReadBits(15) - 1; + LastLength = len; + LastDist = dist; + return CopyBlock(dist, len); + } + + UInt32 saveLen = len; + dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3]; + + len = DecodeNum(PosL1); + + if (len == 0xff && saveLen == 10) + { + Buf60 ^= 16; + return S_OK; + } + if (dist >= 256) + { + len++; + if (dist >= MaxDist3 - 1) + len++; + } + } + else + { + LCount = 0; + AvrLn1 += len; + AvrLn1 -= AvrLn1 >> 4; + + unsigned distancePlace = DecodeNum(PosHf2) & 0xff; + + dist = ChSetA[distancePlace]; + + if (distancePlace != 0) + { + PlaceA[dist]--; + UInt32 lastDistance = ChSetA[(size_t)distancePlace - 1]; + PlaceA[lastDistance]++; + ChSetA[distancePlace] = lastDistance; + ChSetA[(size_t)distancePlace - 1] = dist; + } + } + + m_RepDists[m_RepDistPtr++] = dist; + m_RepDistPtr &= 3; + len += 2; + LastLength = len; + LastDist = dist; + return CopyBlock(dist, len); +} + + +HRESULT CDecoder::LongLZ() +{ + UInt32 len; + UInt32 dist; + UInt32 distancePlace, newDistancePlace; + UInt32 oldAvr2, oldAvr3; + + NumHuf = 0; + Nlzb += 16; + if (Nlzb > 0xff) + { + Nlzb = 0x90; + Nhfb >>= 1; + } + oldAvr2 = AvrLn2; + + if (AvrLn2 >= 64) + len = DecodeNum(AvrLn2 < 122 ? PosL1 : PosL2); + else + { + UInt32 bitField = m_InBitStream.GetValue(16); + if (bitField < 0x100) + { + len = bitField; + m_InBitStream.MovePos(16); + } + else + { + for (len = 0; ((bitField << len) & 0x8000) == 0; len++); + + m_InBitStream.MovePos(len + 1); + } + } + + AvrLn2 += len; + AvrLn2 -= AvrLn2 >> 5; + + { + const Byte *tab; + if (AvrPlcB >= 0x2900) tab = PosHf2; + else if (AvrPlcB >= 0x0700) tab = PosHf1; + else tab = PosHf0; + distancePlace = DecodeNum(tab); // [0, 256] + } + + AvrPlcB += distancePlace; + AvrPlcB -= AvrPlcB >> 8; + + distancePlace &= 0xff; + + for (;;) + { + dist = ChSetB[distancePlace]; + newDistancePlace = NToPlB[dist++ & 0xff]++; + if (dist & 0xff) + break; + CorrHuff(ChSetB,NToPlB); + } + + ChSetB[distancePlace] = ChSetB[newDistancePlace]; + ChSetB[newDistancePlace] = dist; + + dist = ((dist & 0xff00) >> 1) | ReadBits(7); + + oldAvr3 = AvrLn3; + + if (len != 1 && len != 4) + { + if (len == 0 && dist <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } + else if (AvrLn3 > 0) + AvrLn3--; + } + + len += 3; + + if (dist >= MaxDist3) + len++; + if (dist <= 256) + len += 8; + + if (oldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && oldAvr2 < 0x40)) + MaxDist3 = 0x7f00; + else + MaxDist3 = 0x2001; + + m_RepDists[m_RepDistPtr++] = --dist; + m_RepDistPtr &= 3; + LastLength = len; + LastDist = dist; + + return CopyBlock(dist, len); +} + + +HRESULT CDecoder::HuffDecode() +{ + UInt32 curByte, newBytePlace; + UInt32 len; + UInt32 dist; + unsigned bytePlace; + { + const Byte *tab; + + if (AvrPlc >= 0x7600) tab = PosHf4; + else if (AvrPlc >= 0x5e00) tab = PosHf3; + else if (AvrPlc >= 0x3600) tab = PosHf2; + else if (AvrPlc >= 0x0e00) tab = PosHf1; + else tab = PosHf0; + + bytePlace = DecodeNum(tab); // [0, 256] + } + + if (StMode) + { + if (bytePlace == 0) + { + if (ReadBits(1)) + { + NumHuf = 0; + StMode = false; + return S_OK; + } + len = ReadBits(1) + 3; + dist = DecodeNum(PosHf2); + dist = (dist << 5) | ReadBits(5); + if (dist == 0) + return S_FALSE; + return CopyBlock(dist - 1, len); + } + bytePlace--; // bytePlace is [0, 255] + } + else if (NumHuf++ >= 16 && FlagsCnt == 0) + StMode = true; + + bytePlace &= 0xff; + AvrPlc += bytePlace; + AvrPlc -= AvrPlc >> 8; + Nhfb += 16; + + if (Nhfb > 0xff) + { + Nhfb = 0x90; + Nlzb >>= 1; + } + + m_UnpackSize--; + m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8)); + + for (;;) + { + curByte = ChSet[bytePlace]; + newBytePlace = NToPl[curByte++ & 0xff]++; + if ((curByte & 0xff) <= 0xa1) + break; + CorrHuff(ChSet, NToPl); + } + + ChSet[bytePlace] = ChSet[newBytePlace]; + ChSet[newBytePlace] = curByte; + return S_OK; +} + + +void CDecoder::GetFlagsBuf() +{ + UInt32 flags, newFlagsPlace; + UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256] + + if (flagsPlace >= ARRAY_SIZE(ChSetC)) + return; + + for (;;) + { + flags = ChSetC[flagsPlace]; + FlagBuf = flags >> 8; + newFlagsPlace = NToPlC[flags++ & 0xff]++; + if ((flags & 0xff) != 0) + break; + CorrHuff(ChSetC, NToPlC); + } + + ChSetC[flagsPlace] = ChSetC[newFlagsPlace]; + ChSetC[newFlagsPlace] = flags; +} + + +void CDecoder::CorrHuff(UInt32 *CharSet,UInt32 *NumToPlace) +{ + int i; + for (i = 7; i >= 0; i--) + for (int j = 0; j < 32; j++, CharSet++) + *CharSet = (*CharSet & ~0xff) | i; + memset(NumToPlace, 0, sizeof(NToPl)); + for (i = 6; i >= 0; i--) + NumToPlace[i] = (7 - i) * 32; +} + + + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */) +{ + if (!inSize || !outSize) + return E_INVALIDARG; + + if (_isSolid && !_solidAllowed) + return S_FALSE; + + _solidAllowed = false; + + if (!m_OutWindowStream.Create(kHistorySize)) + return E_OUTOFMEMORY; + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + + m_UnpackSize = *outSize; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(_isSolid); + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + + // InitData + + FlagsCnt = 0; + FlagBuf = 0; + StMode = false; + LCount = 0; + + if (!_isSolid) + { + AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; + AvrPlc = 0x3500; + MaxDist3 = 0x2001; + Nhfb = Nlzb = 0x80; + + { + // InitStructures + for (unsigned i = 0; i < kNumRepDists; i++) + m_RepDists[i] = 0; + m_RepDistPtr = 0; + LastLength = 0; + LastDist = 0; + } + + // InitHuff + + for (UInt32 i = 0; i < 256; i++) + { + Place[i] = PlaceA[i] = PlaceB[i] = i; + UInt32 c = (~i + 1) & 0xff; + PlaceC[i] = c; + ChSet[i] = ChSetB[i] = i << 8; + ChSetA[i] = i; + ChSetC[i] = c << 8; + } + memset(NToPl, 0, sizeof(NToPl)); + memset(NToPlB, 0, sizeof(NToPlB)); + memset(NToPlC, 0, sizeof(NToPlC)); + CorrHuff(ChSetB, NToPlB); + } + + if (m_UnpackSize > 0) + { + GetFlagsBuf(); + FlagsCnt = 8; + } + + while (m_UnpackSize != 0) + { + if (!StMode) + { + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt = 7; + } + + if (FlagBuf & 0x80) + { + FlagBuf <<= 1; + if (Nlzb > Nhfb) + { + RINOK(LongLZ()); + continue; + } + } + else + { + FlagBuf <<= 1; + + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt = 7; + } + + if ((FlagBuf & 0x80) == 0) + { + FlagBuf <<= 1; + RINOK(ShortLZ()); + continue; + } + + FlagBuf <<= 1; + + if (Nlzb <= Nhfb) + { + RINOK(LongLZ()); + continue; + } + } + } + + RINOK(HuffDecode()); + } + + _solidAllowed = true; + return m_OutWindowStream.Flush(); +} + + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + 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; } +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar1Decoder.h 7zip-22.01/CPP/7zip/Compress/Rar1Decoder.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar1Decoder.h 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar1Decoder.h 2018-03-09 15:09:30.000000000 +0000 @@ -0,0 +1,79 @@ +// Rar1Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR1_DECODER_H +#define __COMPRESS_RAR1_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NRar1 { + +const UInt32 kNumRepDists = 4; + +class CDecoder : + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + CLzOutWindow m_OutWindowStream; + NBitm::CDecoder m_InBitStream; + + UInt64 m_UnpackSize; + + UInt32 LastDist; + UInt32 LastLength; + + UInt32 m_RepDistPtr; + UInt32 m_RepDists[kNumRepDists]; + + bool _isSolid; + bool _solidAllowed; + + bool StMode; + int FlagsCnt; + UInt32 FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3; + unsigned Buf60, NumHuf, LCount; + UInt32 Nhfb, Nlzb, MaxDist3; + + UInt32 ChSet[256], ChSetA[256], ChSetB[256], ChSetC[256]; + UInt32 Place[256], PlaceA[256], PlaceB[256], PlaceC[256]; + UInt32 NToPl[256], NToPlB[256], NToPlC[256]; + + UInt32 ReadBits(unsigned numBits); + HRESULT CopyBlock(UInt32 distance, UInt32 len); + UInt32 DecodeNum(const Byte *numTab); + HRESULT ShortLZ(); + HRESULT LongLZ(); + HRESULT HuffDecode(); + void GetFlagsBuf(); + void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace); + void OldUnpWriteBuf(); + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + +public: + CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + +}; + +}} + +#endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar2Decoder.cpp 7zip-22.01/CPP/7zip/Compress/Rar2Decoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar2Decoder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar2Decoder.cpp 2021-01-03 15:48:36.000000000 +0000 @@ -0,0 +1,439 @@ +// Rar2Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +#include + +#include "Rar2Decoder.h" + +namespace NCompress { +namespace NRar2 { + +namespace NMultimedia { + +Byte CFilter::Decode(int &channelDelta, Byte deltaByte) +{ + D4 = D3; + D3 = D2; + D2 = LastDelta - D1; + D1 = LastDelta; + int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3); + + Byte realValue = (Byte)(predictedValue - deltaByte); + + { + int i = ((int)(signed char)deltaByte) << 3; + + Dif[0] += abs(i); + Dif[1] += abs(i - D1); + Dif[2] += abs(i + D1); + Dif[3] += abs(i - D2); + Dif[4] += abs(i + D2); + Dif[5] += abs(i - D3); + Dif[6] += abs(i + D3); + Dif[7] += abs(i - D4); + Dif[8] += abs(i + D4); + Dif[9] += abs(i - channelDelta); + Dif[10] += abs(i + channelDelta); + } + + channelDelta = LastDelta = (signed char)(realValue - LastChar); + LastChar = realValue; + + if (((++ByteCount) & 0x1F) == 0) + { + UInt32 minDif = Dif[0]; + UInt32 numMinDif = 0; + Dif[0] = 0; + + for (unsigned i = 1; i < ARRAY_SIZE(Dif); i++) + { + if (Dif[i] < minDif) + { + minDif = Dif[i]; + numMinDif = i; + } + Dif[i] = 0; + } + + switch (numMinDif) + { + case 1: if (K1 >= -16) K1--; break; + case 2: if (K1 < 16) K1++; break; + case 3: if (K2 >= -16) K2--; break; + case 4: if (K2 < 16) K2++; break; + case 5: if (K3 >= -16) K3--; break; + case 6: if (K3 < 16) K3++; break; + case 7: if (K4 >= -16) K4--; break; + case 8: if (K4 < 16) K4++; break; + case 9: if (K5 >= -16) K5--; break; + case 10:if (K5 < 16) K5++; break; + } + } + + return realValue; +} +} + +static const UInt32 kHistorySize = 1 << 20; + +// static const UInt32 kWindowReservSize = (1 << 22) + 256; + +CDecoder::CDecoder(): + _isSolid(false), + _solidAllowed(false), + m_TablesOK(false) +{ +} + +void CDecoder::InitStructures() +{ + m_MmFilter.Init(); + for (unsigned i = 0; i < kNumRepDists; i++) + m_RepDists[i] = 0; + m_RepDistPtr = 0; + m_LastLength = 0; + memset(m_LastLevels, 0, kMaxTableSize); +} + +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } + +#define RIF(x) { if (!(x)) return false; } + +bool CDecoder::ReadTables(void) +{ + m_TablesOK = false; + + Byte levelLevels[kLevelTableSize]; + Byte lens[kMaxTableSize]; + + m_AudioMode = (ReadBits(1) == 1); + + if (ReadBits(1) == 0) + memset(m_LastLevels, 0, kMaxTableSize); + + unsigned numLevels; + + if (m_AudioMode) + { + m_NumChannels = ReadBits(2) + 1; + if (m_MmFilter.CurrentChannel >= m_NumChannels) + m_MmFilter.CurrentChannel = 0; + numLevels = m_NumChannels * kMMTableSize; + } + else + numLevels = kHeapTablesSizesSum; + + unsigned i; + for (i = 0; i < kLevelTableSize; i++) + levelLevels[i] = (Byte)ReadBits(4); + RIF(m_LevelDecoder.Build(levelLevels)); + + i = 0; + + do + { + UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream); + if (sym < kTableDirectLevels) + { + lens[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask); + i++; + } + else + { + if (sym == kTableLevelRepNumber) + { + unsigned num = ReadBits(2) + 3; + if (i == 0) + return false; + num += i; + if (num > numLevels) + { + // return false; + num = numLevels; // original unRAR + } + Byte v = lens[(size_t)i - 1]; + do + lens[i++] = v; + while (i < num); + } + else + { + unsigned num; + if (sym == kTableLevel0Number) + num = ReadBits(3) + 3; + else if (sym == kTableLevel0Number2) + num = ReadBits(7) + 11; + else + return false; + num += i; + if (num > numLevels) + { + // return false; + num = numLevels; // original unRAR + } + do + lens[i++] = 0; + while (i < num); + } + } + } + while (i < numLevels); + + if (m_InBitStream.ExtraBitsWereRead()) + return false; + + if (m_AudioMode) + for (i = 0; i < m_NumChannels; i++) + { + RIF(m_MMDecoders[i].Build(&lens[i * kMMTableSize])); + } + else + { + RIF(m_MainDecoder.Build(&lens[0])); + RIF(m_DistDecoder.Build(&lens[kMainTableSize])); + RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize])); + } + + memcpy(m_LastLevels, lens, kMaxTableSize); + + m_TablesOK = true; + + return true; +} + +bool CDecoder::ReadLastTables() +{ + // it differs a little from pure RAR sources; + // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2; + // + 2 works for: return 0xFF; in CInBuffer::ReadByte. + if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect; + // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; + { + if (m_AudioMode) + { + UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream); + if (symbol == 256) + return ReadTables(); + if (symbol >= kMMTableSize) + return false; + } + else + { + UInt32 sym = m_MainDecoder.Decode(&m_InBitStream); + if (sym == kReadTableNumber) + return ReadTables(); + if (sym >= kMainTableSize) + return false; + } + } + return true; +} + + +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; + /* + Byte byPredict = m_Predictor.Predict(); + Byte byReal = (Byte)(byPredict - (Byte)symbol); + m_Predictor.Update(byReal, byPredict); + */ + Byte byReal = m_MmFilter.Decode((Byte)symbol); + m_OutWindowStream.PutByte(byReal); + if (++m_MmFilter.CurrentChannel == m_NumChannels) + m_MmFilter.CurrentChannel = 0; + } + return true; +} + +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) + { + m_OutWindowStream.PutByte(Byte(sym)); + pos--; + continue; + } + else if (sym >= kMatchNumber) + { + if (sym >= kMainTableSize) + return false; + sym -= kMatchNumber; + length = kNormalMatchMinLen + UInt32(kLenStart[sym]) + + m_InBitStream.ReadBits(kLenDirectBits[sym]); + sym = m_DistDecoder.Decode(&m_InBitStream); + if (sym >= kDistTableSize) + return false; + distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]); + if (distance >= kDistLimit3) + { + length += 2 - ((distance - kDistLimit4) >> 31); + // length++; + // if (distance >= kDistLimit4) + // length++; + } + } + else if (sym == kRepBothNumber) + { + length = m_LastLength; + if (length == 0) + return false; + distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3]; + } + else if (sym < kLen2Number) + { + distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3]; + sym = m_LenDecoder.Decode(&m_InBitStream); + if (sym >= kLenTableSize) + return false; + length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]); + if (distance >= kDistLimit2) + { + length++; + if (distance >= kDistLimit3) + { + length += 2 - ((distance - kDistLimit4) >> 31); + // length++; + // if (distance >= kDistLimit4) + // length++; + } + } + } + else if (sym < kReadTableNumber) + { + sym -= kLen2Number; + distance = kLen2DistStarts[sym] + + m_InBitStream.ReadBits(kLen2DistDirectBits[sym]); + length = 2; + } + else // (sym == kReadTableNumber) + return true; + + m_RepDists[m_RepDistPtr++ & 3] = distance; + m_LastLength = length; + if (!m_OutWindowStream.CopyBlock(distance, length)) + return false; + pos -= length; + } + return true; +} + +HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + if (!inSize || !outSize) + return E_INVALIDARG; + + if (_isSolid && !_solidAllowed) + return S_FALSE; + _solidAllowed = false; + + if (!m_OutWindowStream.Create(kHistorySize)) + return E_OUTOFMEMORY; + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + + m_PackSize = *inSize; + + UInt64 pos = 0, unPackSize = *outSize; + + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(_isSolid); + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + + // CCoderReleaser coderReleaser(this); + if (!_isSolid) + { + InitStructures(); + if (unPackSize == 0) + { + if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect; + if (!ReadTables()) + return S_FALSE; + _solidAllowed = true; + return S_OK; + } + ReadTables(); + } + + if (!m_TablesOK) + return S_FALSE; + + UInt64 startPos = m_OutWindowStream.GetProcessedSize(); + while (pos < unPackSize) + { + UInt32 blockSize = 1 << 20; + if (blockSize > unPackSize - pos) + blockSize = (UInt32)(unPackSize - pos); + UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize(); + if (m_AudioMode) + { + if (!DecodeMm(blockSize)) + return S_FALSE; + } + else + { + 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) + { + const UInt64 packSize = m_InBitStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)); + } + } + if (pos > unPackSize) + return S_FALSE; + + if (!ReadLastTables()) + return S_FALSE; + + _solidAllowed = true; + + return m_OutWindowStream.Flush(); +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + 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; } +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar2Decoder.h 7zip-22.01/CPP/7zip/Compress/Rar2Decoder.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar2Decoder.h 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar2Decoder.h 2018-03-09 15:09:17.000000000 +0000 @@ -0,0 +1,172 @@ +// Rar2Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR2_DECODER_H +#define __COMPRESS_RAR2_DECODER_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "LzOutWindow.h" + +namespace NCompress { +namespace NRar2 { + +const unsigned kNumRepDists = 4; +const unsigned kDistTableSize = 48; + +const unsigned kMMTableSize = 256 + 1; + +const UInt32 kMainTableSize = 298; +const UInt32 kLenTableSize = 28; + +const UInt32 kDistTableStart = kMainTableSize; +const UInt32 kLenTableStart = kDistTableStart + kDistTableSize; + +const UInt32 kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize; + +const UInt32 kLevelTableSize = 19; + +const UInt32 kMMTablesSizesSum = kMMTableSize * 4; + +const UInt32 kMaxTableSize = kMMTablesSizesSum; + +const UInt32 kTableDirectLevels = 16; +const UInt32 kTableLevelRepNumber = kTableDirectLevels; +const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1; +const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1; + +const UInt32 kLevelMask = 0xF; + + +const UInt32 kRepBothNumber = 256; +const UInt32 kRepNumber = kRepBothNumber + 1; +const UInt32 kLen2Number = kRepNumber + 4; + +const UInt32 kLen2NumNumbers = 8; +const UInt32 kReadTableNumber = kLen2Number + kLen2NumNumbers; +const UInt32 kMatchNumber = kReadTableNumber + 1; + +const Byte kLenStart [kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224}; +const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; + +const UInt32 kDistStart [kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040}; +const Byte kDistDirectBits[kDistTableSize] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; + +const Byte kLevelDirectBits[kLevelTableSize] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7}; + +const Byte kLen2DistStarts[kLen2NumNumbers]={0,4,8,16,32,64,128,192}; +const Byte kLen2DistDirectBits[kLen2NumNumbers]={2,2,3, 4, 5, 6, 6, 6}; + +const UInt32 kDistLimit2 = 0x101 - 1; +const UInt32 kDistLimit3 = 0x2000 - 1; +const UInt32 kDistLimit4 = 0x40000 - 1; + +const UInt32 kMatchMaxLen = 255 + 2; +const UInt32 kMatchMaxLenMax = 255 + 5; +const UInt32 kNormalMatchMinLen = 3; + +namespace NMultimedia { + +struct CFilter +{ + int K1,K2,K3,K4,K5; + int D1,D2,D3,D4; + int LastDelta; + UInt32 Dif[11]; + UInt32 ByteCount; + int LastChar; + + Byte Decode(int &channelDelta, Byte delta); + + void Init() { memset(this, 0, sizeof(*this)); } + +}; + +const unsigned kNumChanelsMax = 4; + +class CFilter2 +{ +public: + CFilter m_Filters[kNumChanelsMax]; + int m_ChannelDelta; + unsigned CurrentChannel; + + void Init() { memset(this, 0, sizeof(*this)); } + Byte Decode(Byte delta) + { + return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta); + } + +}; + +} + +typedef NBitm::CDecoder CBitDecoder; + +const unsigned kNumHuffmanBits = 15; + +class CDecoder : + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + CLzOutWindow m_OutWindowStream; + CBitDecoder m_InBitStream; + + UInt32 m_RepDistPtr; + UInt32 m_RepDists[kNumRepDists]; + + UInt32 m_LastLength; + + bool _isSolid; + bool _solidAllowed; + bool m_TablesOK; + bool m_AudioMode; + + NHuffman::CDecoder m_MainDecoder; + NHuffman::CDecoder m_DistDecoder; + NHuffman::CDecoder m_LenDecoder; + NHuffman::CDecoder m_MMDecoders[NMultimedia::kNumChanelsMax]; + NHuffman::CDecoder m_LevelDecoder; + + UInt64 m_PackSize; + + unsigned m_NumChannels; + NMultimedia::CFilter2 m_MmFilter; + + Byte m_LastLevels[kMaxTableSize]; + + + void InitStructures(); + UInt32 ReadBits(unsigned numBits); + bool ReadTables(); + bool ReadLastTables(); + + bool DecodeMm(UInt32 pos); + bool DecodeLz(Int32 pos); + + HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + +public: + CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + +}; + +}} + +#endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Decoder.cpp 7zip-22.01/CPP/7zip/Compress/Rar3Decoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Decoder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar3Decoder.cpp 2020-08-27 12:28:39.000000000 +0000 @@ -0,0 +1,935 @@ +// Rar3Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#include "StdAfx.h" + +#include "../../../C/Alloc.h" + +#include "../Common/StreamUtils.h" + +#include "Rar3Decoder.h" + +namespace NCompress { +namespace NRar3 { + +static const UInt32 kNumAlignReps = 15; + +static const UInt32 kSymbolReadTable = 256; +static const UInt32 kSymbolRep = 259; + +static const Byte kDistDirectBits[kDistTableSize] = + {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 18,18,18,18,18,18,18,18,18,18,18,18}; + +static const Byte kLen2DistStarts[kNumLen2Symbols] = {0,4,8,16,32,64,128,192}; +static const Byte kLen2DistDirectBits[kNumLen2Symbols] = {2,2,3, 4, 5, 6, 6, 6}; + +static const UInt32 kDistLimit3 = 0x2000 - 2; +static const UInt32 kDistLimit4 = 0x40000 - 2; + +static const UInt32 kNormalMatchMinLen = 3; + +static const UInt32 kVmDataSizeMax = 1 << 16; +static const UInt32 kVmCodeSizeMax = 1 << 16; + +extern "C" { + +static Byte Wrap_ReadByte(const IByteIn *pp) throw() +{ + CByteIn *p = CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj); + return p->BitDecoder.Stream.ReadByte(); +} + +static Byte Wrap_ReadBits8(const IByteIn *pp) throw() +{ + CByteIn *p = CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj); + return (Byte)p->BitDecoder.ReadByteFromAligned(); +} + +} + + +CDecoder::CDecoder(): + _window(0), + _winPos(0), + _wrPtr(0), + _lzSize(0), + _writtenFileSize(0), + _vmData(0), + _vmCode(0), + _isSolid(false), + _solidAllowed(false) +{ + Ppmd7_Construct(&_ppmd); + + UInt32 start = 0; + for (UInt32 i = 0; i < kDistTableSize; i++) + { + kDistStart[i] = start; + start += ((UInt32)1 << kDistDirectBits[i]); + } +} + +CDecoder::~CDecoder() +{ + InitFilters(); + ::MidFree(_vmData); + ::MidFree(_window); + Ppmd7_Free(&_ppmd, &g_BigAlloc); +} + +HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size) +{ + return WriteStream(_outStream, data, size); +} + +HRESULT CDecoder::WriteData(const Byte *data, UInt32 size) +{ + HRESULT res = S_OK; + if (_writtenFileSize < _unpackSize) + { + UInt32 curSize = size; + UInt64 remain = _unpackSize - _writtenFileSize; + if (remain < curSize) + curSize = (UInt32)remain; + res = WriteDataToStream(data, curSize); + } + _writtenFileSize += size; + return res; +} + +HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr) +{ + if (startPtr <= endPtr) + return WriteData(_window + startPtr, endPtr - startPtr); + RINOK(WriteData(_window + startPtr, kWindowSize - startPtr)); + return WriteData(_window, endPtr); +} + +void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef) +{ + CTempFilter *tempFilter = _tempFilters[tempFilterIndex]; + tempFilter->InitR[6] = (UInt32)_writtenFileSize; + NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize); + NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32)); + CFilter *filter = _filters[tempFilter->FilterIndex]; + if (!filter->IsSupported) + _unsupportedFilter = true; + if (!_vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData)) + _unsupportedFilter = true; + delete tempFilter; + _tempFilters[tempFilterIndex] = NULL; + _numEmptyTempFilters++; +} + +HRESULT CDecoder::WriteBuf() +{ + UInt32 writtenBorder = _wrPtr; + UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask; + FOR_VECTOR (i, _tempFilters) + { + CTempFilter *filter = _tempFilters[i]; + if (!filter) + continue; + if (filter->NextWindow) + { + filter->NextWindow = false; + continue; + } + UInt32 blockStart = filter->BlockStart; + UInt32 blockSize = filter->BlockSize; + if (((blockStart - writtenBorder) & kWindowMask) < writeSize) + { + if (writtenBorder != blockStart) + { + RINOK(WriteArea(writtenBorder, blockStart)); + writtenBorder = blockStart; + writeSize = (_winPos - writtenBorder) & kWindowMask; + } + if (blockSize <= writeSize) + { + UInt32 blockEnd = (blockStart + blockSize) & kWindowMask; + if (blockStart < blockEnd || blockEnd == 0) + _vm.SetMemory(0, _window + blockStart, blockSize); + else + { + UInt32 tailSize = kWindowSize - blockStart; + _vm.SetMemory(0, _window + blockStart, tailSize); + _vm.SetMemory(tailSize, _window, blockEnd); + } + NVm::CBlockRef outBlockRef; + ExecuteFilter(i, outBlockRef); + while (i + 1 < _tempFilters.Size()) + { + CTempFilter *nextFilter = _tempFilters[i + 1]; + if (!nextFilter + || nextFilter->BlockStart != blockStart + || nextFilter->BlockSize != outBlockRef.Size + || nextFilter->NextWindow) + break; + _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); + ExecuteFilter(++i, outBlockRef); + } + WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size); + _writtenFileSize += outBlockRef.Size; + writtenBorder = blockEnd; + writeSize = (_winPos - writtenBorder) & kWindowMask; + } + else + { + for (unsigned j = i; j < _tempFilters.Size(); j++) + { + CTempFilter *filter2 = _tempFilters[j]; + if (filter2 && filter2->NextWindow) + filter2->NextWindow = false; + } + _wrPtr = writtenBorder; + return S_OK; // check it + } + } + } + + _wrPtr = _winPos; + return WriteArea(writtenBorder, _winPos); +} + +void CDecoder::InitFilters() +{ + _lastFilter = 0; + _numEmptyTempFilters = 0; + unsigned i; + for (i = 0; i < _tempFilters.Size(); i++) + delete _tempFilters[i]; + _tempFilters.Clear(); + for (i = 0; i < _filters.Size(); i++) + delete _filters[i]; + _filters.Clear(); +} + +static const unsigned MAX_UNPACK_FILTERS = 8192; + +bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize) +{ + CMemBitDecoder inp; + inp.Init(_vmData, codeSize); + + UInt32 filterIndex; + + if (firstByte & 0x80) + { + filterIndex = inp.ReadEncodedUInt32(); + if (filterIndex == 0) + InitFilters(); + else + filterIndex--; + } + else + filterIndex = _lastFilter; + + if (filterIndex > (UInt32)_filters.Size()) + return false; + _lastFilter = filterIndex; + bool newFilter = (filterIndex == (UInt32)_filters.Size()); + + CFilter *filter; + if (newFilter) + { + // check if too many filters + if (filterIndex > MAX_UNPACK_FILTERS) + return false; + filter = new CFilter; + _filters.Add(filter); + } + else + { + filter = _filters[filterIndex]; + filter->ExecCount++; + } + + if (_numEmptyTempFilters != 0) + { + unsigned num = _tempFilters.Size(); + CTempFilter **tempFilters = &_tempFilters.Front(); + + unsigned w = 0; + for (unsigned i = 0; i < num; i++) + { + CTempFilter *tf = tempFilters[i]; + if (tf) + tempFilters[w++] = tf; + } + + _tempFilters.DeleteFrom(w); + _numEmptyTempFilters = 0; + } + + if (_tempFilters.Size() > MAX_UNPACK_FILTERS) + return false; + CTempFilter *tempFilter = new CTempFilter; + _tempFilters.Add(tempFilter); + tempFilter->FilterIndex = filterIndex; + + UInt32 blockStart = inp.ReadEncodedUInt32(); + if (firstByte & 0x40) + blockStart += 258; + tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask; + if (firstByte & 0x20) + filter->BlockSize = inp.ReadEncodedUInt32(); + tempFilter->BlockSize = filter->BlockSize; + tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart; + + memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR)); + tempFilter->InitR[3] = NVm::kGlobalOffset; + tempFilter->InitR[4] = tempFilter->BlockSize; + tempFilter->InitR[5] = filter->ExecCount; + if (firstByte & 0x10) + { + UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs); + for (unsigned i = 0; i < NVm::kNumGpRegs; i++) + if (initMask & (1 << i)) + tempFilter->InitR[i] = inp.ReadEncodedUInt32(); + } + + bool isOK = true; + if (newFilter) + { + UInt32 vmCodeSize = inp.ReadEncodedUInt32(); + if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0) + return false; + for (UInt32 i = 0; i < vmCodeSize; i++) + _vmCode[i] = (Byte)inp.ReadBits(8); + isOK = filter->PrepareProgram(_vmCode, vmCodeSize); + } + + { + Byte *globalData = &tempFilter->GlobalData[0]; + for (unsigned i = 0; i < NVm::kNumGpRegs; i++) + NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]); + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize); + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why? + NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], filter->ExecCount); + } + + if (firstByte & 8) + { + UInt32 dataSize = inp.ReadEncodedUInt32(); + if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize) + return false; + CRecordVector &globalData = tempFilter->GlobalData; + unsigned requiredSize = (unsigned)(dataSize + NVm::kFixedGlobalSize); + if (globalData.Size() < requiredSize) + globalData.ChangeSize_KeepData(requiredSize); + Byte *dest = &globalData[NVm::kFixedGlobalSize]; + for (UInt32 i = 0; i < dataSize; i++) + dest[i] = (Byte)inp.ReadBits(8); + } + + return isOK; +} + +bool CDecoder::ReadVmCodeLZ() +{ + UInt32 firstByte = ReadBits(8); + UInt32 len = (firstByte & 7) + 1; + if (len == 7) + len = ReadBits(8) + 7; + else if (len == 8) + len = ReadBits(16); + if (len > kVmDataSizeMax) + return false; + for (UInt32 i = 0; i < len; i++) + _vmData[i] = (Byte)ReadBits(8); + return AddVmCode(firstByte, len); +} + + +// int CDecoder::DecodePpmSymbol() { return Ppmd7a_DecodeSymbol(&_ppmd); } +#define DecodePpmSymbol() Ppmd7a_DecodeSymbol(&_ppmd) + + +bool CDecoder::ReadVmCodePPM() +{ + int firstByte = DecodePpmSymbol(); + if (firstByte < 0) + return false; + UInt32 len = (firstByte & 7) + 1; + if (len == 7) + { + int b1 = DecodePpmSymbol(); + if (b1 < 0) + return false; + len = b1 + 7; + } + else if (len == 8) + { + int b1 = DecodePpmSymbol(); + if (b1 < 0) + return false; + int b2 = DecodePpmSymbol(); + if (b2 < 0) + return false; + len = b1 * 256 + b2; + } + if (len > kVmDataSizeMax) + return false; + if (InputEofError_Fast()) + return false; + for (UInt32 i = 0; i < len; i++) + { + int b = DecodePpmSymbol(); + if (b < 0) + return false; + _vmData[i] = (Byte)b; + } + return AddVmCode(firstByte, len); +} + +#define RIF(x) { if (!(x)) return S_FALSE; } + +UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); } + +// ---------- PPM ---------- + +HRESULT CDecoder::InitPPM() +{ + unsigned maxOrder = (unsigned)ReadBits(7); + + bool reset = ((maxOrder & 0x20) != 0); + UInt32 maxMB = 0; + if (reset) + maxMB = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj); + else + { + if (PpmError || !Ppmd7_WasAllocated(&_ppmd)) + return S_FALSE; + } + if (maxOrder & 0x40) + PpmEscChar = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj); + + _ppmd.rc.dec.Stream = &m_InBitStream.IByteIn_obj; + m_InBitStream.IByteIn_obj.Read = Wrap_ReadBits8; + + Ppmd7a_RangeDec_Init(&_ppmd.rc.dec); + + m_InBitStream.IByteIn_obj.Read = Wrap_ReadByte; + + if (reset) + { + PpmError = true; + maxOrder = (maxOrder & 0x1F) + 1; + if (maxOrder > 16) + maxOrder = 16 + (maxOrder - 16) * 3; + if (maxOrder == 1) + { + Ppmd7_Free(&_ppmd, &g_BigAlloc); + return S_FALSE; + } + if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc)) + return E_OUTOFMEMORY; + Ppmd7_Init(&_ppmd, maxOrder); + PpmError = false; + } + return S_OK; +} + + +HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing) +{ + keepDecompressing = false; + if (PpmError) + return S_FALSE; + do + { + if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) + { + RINOK(WriteBuf()); + if (_writtenFileSize > _unpackSize) + { + keepDecompressing = false; + return S_OK; + } + } + if (InputEofError_Fast()) + return false; + int c = DecodePpmSymbol(); + if (c < 0) + { + PpmError = true; + return S_FALSE; + } + if (c == PpmEscChar) + { + int nextCh = DecodePpmSymbol(); + if (nextCh < 0) + { + PpmError = true; + return S_FALSE; + } + if (nextCh == 0) + return ReadTables(keepDecompressing); + if (nextCh == 2 || nextCh == -1) + return S_OK; + if (nextCh == 3) + { + if (!ReadVmCodePPM()) + { + PpmError = true; + return S_FALSE; + } + continue; + } + if (nextCh == 4 || nextCh == 5) + { + UInt32 dist = 0; + UInt32 len = 4; + if (nextCh == 4) + { + for (int i = 0; i < 3; i++) + { + int c2 = DecodePpmSymbol(); + if (c2 < 0) + { + PpmError = true; + return S_FALSE; + } + dist = (dist << 8) + (Byte)c2; + } + dist++; + len += 28; + } + int c2 = DecodePpmSymbol(); + if (c2 < 0) + { + PpmError = true; + return S_FALSE; + } + len += c2; + if (dist >= _lzSize) + return S_FALSE; + CopyBlock(dist, len); + num -= (Int32)len; + continue; + } + } + PutByte((Byte)c); + num--; + } + while (num >= 0); + keepDecompressing = true; + return S_OK; +} + +// ---------- LZ ---------- + +HRESULT CDecoder::ReadTables(bool &keepDecompressing) +{ + keepDecompressing = true; + m_InBitStream.BitDecoder.AlignToByte(); + if (ReadBits(1) != 0) + { + _lzMode = false; + return InitPPM(); + } + + TablesRead = false; + TablesOK = false; + + _lzMode = true; + PrevAlignBits = 0; + PrevAlignCount = 0; + + Byte levelLevels[kLevelTableSize]; + Byte lens[kTablesSizesSum]; + + if (ReadBits(1) == 0) + memset(m_LastLevels, 0, kTablesSizesSum); + + unsigned i; + + for (i = 0; i < kLevelTableSize; i++) + { + UInt32 len = ReadBits(4); + if (len == 15) + { + UInt32 zeroCount = ReadBits(4); + if (zeroCount != 0) + { + zeroCount += 2; + while (zeroCount-- > 0 && i < kLevelTableSize) + levelLevels[i++]=0; + i--; + continue; + } + } + levelLevels[i] = (Byte)len; + } + + RIF(m_LevelDecoder.Build(levelLevels)); + + i = 0; + + do + { + UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym < 16) + { + lens[i] = Byte((sym + m_LastLevels[i]) & 15); + i++; + } + else if (sym > kLevelTableSize) + return S_FALSE; + else + { + 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; + v = lens[(size_t)i - 1]; + } + do + lens[i++] = v; + while (i < num); + } + } + while (i < kTablesSizesSum); + + if (InputEofError()) + return S_FALSE; + + TablesRead = true; + + // original code has check here: + /* + if (InAddr > ReadTop) + { + keepDecompressing = false; + return true; + } + */ + + 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, lens, kTablesSizesSum); + + TablesOK = true; + + return S_OK; +} + +/* +class CCoderReleaser +{ + CDecoder *m_Coder; +public: + CCoderReleaser(CDecoder *coder): m_Coder(coder) {} + ~CCoderReleaser() + { + m_Coder->ReleaseStreams(); + } +}; +*/ + +HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing) +{ + if (ReadBits(1) == 0) + { + // new file + keepDecompressing = false; + TablesRead = (ReadBits(1) == 0); + return S_OK; + } + TablesRead = false; + return ReadTables(keepDecompressing); +} + + +HRESULT CDecoder::DecodeLZ(bool &keepDecompressing) +{ + UInt32 rep0 = _reps[0]; + UInt32 rep1 = _reps[1]; + UInt32 rep2 = _reps[2]; + UInt32 rep3 = _reps[3]; + UInt32 len = _lastLength; + for (;;) + { + if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos) + { + RINOK(WriteBuf()); + if (_writtenFileSize > _unpackSize) + { + keepDecompressing = false; + return S_OK; + } + } + + if (InputEofError_Fast()) + return S_FALSE; + + UInt32 sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym < 256) + { + PutByte((Byte)sym); + continue; + } + else if (sym == kSymbolReadTable) + { + RINOK(ReadEndOfBlock(keepDecompressing)); + break; + } + else if (sym == 257) + { + if (!ReadVmCodeLZ()) + return S_FALSE; + continue; + } + else if (sym == 258) + { + if (len == 0) + return S_FALSE; + } + else if (sym < kSymbolRep + 4) + { + if (sym != kSymbolRep) + { + UInt32 dist; + if (sym == kSymbolRep + 1) + dist = rep1; + else + { + if (sym == kSymbolRep + 2) + dist = rep2; + else + { + dist = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = dist; + } + + const UInt32 sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym2 >= kLenTableSize) + return S_FALSE; + len = 2 + sym2; + if (sym2 >= 8) + { + unsigned num = (sym2 >> 2) - 1; + len = 2 + ((4 + (sym2 & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num); + } + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + if (sym < 271) + { + sym -= 263; + rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits_upto8(kLen2DistDirectBits[sym]); + len = 2; + } + else if (sym < 299) + { + sym -= 271; + len = kNormalMatchMinLen + sym; + if (sym >= 8) + { + unsigned num = (sym >> 2) - 1; + len = kNormalMatchMinLen + ((4 + (sym & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num); + } + const UInt32 sym2 = m_DistDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym2 >= kDistTableSize) + return S_FALSE; + rep0 = kDistStart[sym2]; + unsigned numBits = kDistDirectBits[sym2]; + if (sym2 >= (kNumAlignBits * 2) + 2) + { + if (numBits > kNumAlignBits) + rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits); + if (PrevAlignCount > 0) + { + PrevAlignCount--; + rep0 += PrevAlignBits; + } + else + { + const UInt32 sym3 = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder); + if (sym3 < (1 << kNumAlignBits)) + { + rep0 += sym3; + PrevAlignBits = sym3; + } + else if (sym3 == (1 << kNumAlignBits)) + { + PrevAlignCount = kNumAlignReps; + rep0 += PrevAlignBits; + } + else + return S_FALSE; + } + } + else + rep0 += m_InBitStream.BitDecoder.ReadBits_upto8(numBits); + len += ((UInt32)(kDistLimit4 - rep0) >> 31) + ((UInt32)(kDistLimit3 - rep0) >> 31); + } + else + return S_FALSE; + } + if (rep0 >= _lzSize) + return S_FALSE; + CopyBlock(rep0, len); + } + _reps[0] = rep0; + _reps[1] = rep1; + _reps[2] = rep2; + _reps[3] = rep3; + _lastLength = len; + + return S_OK; +} + + +HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress) +{ + _writtenFileSize = 0; + _unsupportedFilter = false; + + if (!_isSolid) + { + _lzSize = 0; + _winPos = 0; + _wrPtr = 0; + for (unsigned i = 0; i < kNumReps; i++) + _reps[i] = 0; + _lastLength = 0; + memset(m_LastLevels, 0, kTablesSizesSum); + TablesRead = false; + PpmEscChar = 2; + PpmError = true; + InitFilters(); + // _errorMode = false; + } + + /* + if (_errorMode) + return S_FALSE; + */ + + if (!_isSolid || !TablesRead) + { + bool keepDecompressing; + RINOK(ReadTables(keepDecompressing)); + if (!keepDecompressing) + { + _solidAllowed = true; + return S_OK; + } + } + + for (;;) + { + bool keepDecompressing; + if (_lzMode) + { + if (!TablesOK) + return S_FALSE; + RINOK(DecodeLZ(keepDecompressing)) + } + else + { + RINOK(DecodePPM(1 << 18, keepDecompressing)) + } + + if (InputEofError()) + return S_FALSE; + + UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)); + if (!keepDecompressing) + break; + } + + _solidAllowed = true; + + RINOK(WriteBuf()); + UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize)); + if (_writtenFileSize < _unpackSize) + return S_FALSE; + + if (_unsupportedFilter) + return E_NOTIMPL; + + return S_OK; +} + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try + { + if (!inSize) + return E_INVALIDARG; + + if (_isSolid && !_solidAllowed) + return S_FALSE; + _solidAllowed = false; + + if (!_vmData) + { + _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax); + if (!_vmData) + return E_OUTOFMEMORY; + _vmCode = _vmData + kVmDataSizeMax; + } + + if (!_window) + { + _window = (Byte *)::MidAlloc(kWindowSize); + if (!_window) + return E_OUTOFMEMORY; + } + if (!m_InBitStream.BitDecoder.Create(1 << 20)) + return E_OUTOFMEMORY; + if (!_vm.Create()) + return E_OUTOFMEMORY; + + + m_InBitStream.BitDecoder.SetStream(inStream); + m_InBitStream.BitDecoder.Init(); + _outStream = outStream; + + // CCoderReleaser coderReleaser(this); + _unpackSize = outSize ? *outSize : (UInt64)(Int64)-1; + return CodeReal(progress); + } + 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. +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size < 1) + return E_INVALIDARG; + _isSolid = ((data[0] & 1) != 0); + return S_OK; +} + +}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Decoder.h 7zip-22.01/CPP/7zip/Compress/Rar3Decoder.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Decoder.h 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar3Decoder.h 2020-06-28 18:04:16.000000000 +0000 @@ -0,0 +1,282 @@ +// Rar3Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ + +#ifndef __COMPRESS_RAR3_DECODER_H +#define __COMPRESS_RAR3_DECODER_H + +#include "../../../C/Ppmd7.h" + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" + +#include "../Common/InBuffer.h" + +#include "BitmDecoder.h" +#include "HuffmanDecoder.h" +#include "Rar3Vm.h" + +namespace NCompress { +namespace NRar3 { + +const UInt32 kWindowSize = 1 << 22; +const UInt32 kWindowMask = (kWindowSize - 1); + +const UInt32 kNumReps = 4; +const UInt32 kNumLen2Symbols = 8; +const UInt32 kLenTableSize = 28; +const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize; +const UInt32 kDistTableSize = 60; + +const unsigned kNumAlignBits = 4; +const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1; + +const UInt32 kLevelTableSize = 20; + +const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize; + +class CBitDecoder +{ + UInt32 _value; + unsigned _bitPos; +public: + CInBuffer Stream; + + bool Create(UInt32 bufSize) { return Stream.Create(bufSize); } + void SetStream(ISequentialInStream *inStream) { Stream.SetStream(inStream);} + + void Init() + { + Stream.Init(); + _bitPos = 0; + _value = 0; + } + + bool ExtraBitsWereRead() const + { + return (Stream.NumExtraBytes > 4 || _bitPos < (Stream.NumExtraBytes << 3)); + } + + UInt64 GetProcessedSize() const { return Stream.GetProcessedSize() - (_bitPos >> 3); } + + void AlignToByte() + { + _bitPos &= ~(unsigned)7; + _value = _value & ((1 << _bitPos) - 1); + } + + UInt32 GetValue(unsigned numBits) + { + if (_bitPos < numBits) + { + _bitPos += 8; + _value = (_value << 8) | Stream.ReadByte(); + if (_bitPos < numBits) + { + _bitPos += 8; + _value = (_value << 8) | Stream.ReadByte(); + } + } + return _value >> (_bitPos - numBits); + } + + void MovePos(unsigned numBits) + { + _bitPos -= numBits; + _value = _value & ((1 << _bitPos) - 1); + } + + UInt32 ReadBits(unsigned numBits) + { + UInt32 res = GetValue(numBits); + MovePos(numBits); + return res; + } + + UInt32 ReadBits_upto8(unsigned numBits) + { + if (_bitPos < numBits) + { + _bitPos += 8; + _value = (_value << 8) | Stream.ReadByte(); + } + _bitPos -= numBits; + UInt32 res = _value >> _bitPos; + _value = _value & ((1 << _bitPos) - 1); + return res; + } + + Byte ReadByteFromAligned() + { + if (_bitPos == 0) + return Stream.ReadByte(); + unsigned bitsPos = _bitPos - 8; + Byte b = (Byte)(_value >> bitsPos); + _value = _value & ((1 << bitsPos) - 1); + _bitPos = bitsPos; + return b; + } +}; + + +struct CByteIn +{ + IByteIn IByteIn_obj; + CBitDecoder BitDecoder; +}; + + +struct CFilter: public NVm::CProgram +{ + CRecordVector GlobalData; + UInt32 BlockStart; + UInt32 BlockSize; + UInt32 ExecCount; + + CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {} +}; + +struct CTempFilter: public NVm::CProgramInitState +{ + UInt32 BlockStart; + UInt32 BlockSize; + bool NextWindow; + + UInt32 FilterIndex; + + CTempFilter() + { + // all filters must contain at least FixedGlobal block + AllocateEmptyFixedGlobal(); + } +}; + +const unsigned kNumHuffmanBits = 15; + +class CDecoder: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + CByteIn m_InBitStream; + Byte *_window; + UInt32 _winPos; + UInt32 _wrPtr; + UInt64 _lzSize; + UInt64 _unpackSize; + UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written + ISequentialOutStream *_outStream; + NHuffman::CDecoder m_MainDecoder; + UInt32 kDistStart[kDistTableSize]; + NHuffman::CDecoder m_DistDecoder; + NHuffman::CDecoder m_AlignDecoder; + NHuffman::CDecoder m_LenDecoder; + NHuffman::CDecoder m_LevelDecoder; + + UInt32 _reps[kNumReps]; + UInt32 _lastLength; + + Byte m_LastLevels[kTablesSizesSum]; + + Byte *_vmData; + Byte *_vmCode; + NVm::CVm _vm; + CRecordVector _filters; + CRecordVector _tempFilters; + unsigned _numEmptyTempFilters; + UInt32 _lastFilter; + + bool _isSolid; + bool _solidAllowed; + // bool _errorMode; + + bool _lzMode; + bool _unsupportedFilter; + + UInt32 PrevAlignBits; + UInt32 PrevAlignCount; + + bool TablesRead; + bool TablesOK; + + CPpmd7 _ppmd; + int PpmEscChar; + bool PpmError; + + HRESULT WriteDataToStream(const Byte *data, UInt32 size); + HRESULT WriteData(const Byte *data, UInt32 size); + HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr); + void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef); + HRESULT WriteBuf(); + + void InitFilters(); + bool AddVmCode(UInt32 firstByte, UInt32 codeSize); + bool ReadVmCodeLZ(); + bool ReadVmCodePPM(); + + UInt32 ReadBits(unsigned numBits); + + HRESULT InitPPM(); + // int DecodePpmSymbol(); + HRESULT DecodePPM(Int32 num, bool &keepDecompressing); + + HRESULT ReadTables(bool &keepDecompressing); + HRESULT ReadEndOfBlock(bool &keepDecompressing); + HRESULT DecodeLZ(bool &keepDecompressing); + HRESULT CodeReal(ICompressProgressInfo *progress); + + bool InputEofError() const { return m_InBitStream.BitDecoder.ExtraBitsWereRead(); } + bool InputEofError_Fast() const { return (m_InBitStream.BitDecoder.Stream.NumExtraBytes > 2); } + +public: + CDecoder(); + ~CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + + void CopyBlock(UInt32 dist, UInt32 len) + { + _lzSize += len; + UInt32 pos = (_winPos - dist - 1) & kWindowMask; + Byte *window = _window; + UInt32 winPos = _winPos; + if (kWindowSize - winPos > len && kWindowSize - pos > len) + { + const Byte *src = window + pos; + Byte *dest = window + winPos; + _winPos += len; + do + *dest++ = *src++; + while (--len != 0); + return; + } + do + { + window[winPos] = window[pos]; + winPos = (winPos + 1) & kWindowMask; + pos = (pos + 1) & kWindowMask; + } + while (--len != 0); + _winPos = winPos; + } + + void PutByte(Byte b) + { + UInt32 wp = _winPos; + _window[wp] = b; + _winPos = (wp + 1) & kWindowMask; + _lzSize++; + } +}; + +}} + +#endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Vm.cpp 7zip-22.01/CPP/7zip/Compress/Rar3Vm.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Vm.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar3Vm.cpp 2020-09-28 09:34:40.000000000 +0000 @@ -0,0 +1,1139 @@ +// Rar3Vm.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +/* +Note: + Due to performance considerations Rar VM may set Flags C incorrectly + for some operands (SHL x, 0, ... ). + Check implementation of concrete VM command + to see if it sets flags right. +*/ + +#include "StdAfx.h" + +#include + +#include "../../../C/7zCrc.h" +#include "../../../C/Alloc.h" + +#include "../../Common/Defs.h" + +#include "Rar3Vm.h" + +namespace NCompress { +namespace NRar3 { + +UInt32 CMemBitDecoder::ReadBits(unsigned numBits) +{ + UInt32 res = 0; + for (;;) + { + unsigned b = _bitPos < _bitSize ? (unsigned)_data[_bitPos >> 3] : 0; + unsigned avail = (unsigned)(8 - (_bitPos & 7)); + if (numBits <= avail) + { + _bitPos += numBits; + return res | ((b >> (avail - numBits)) & ((1 << numBits) - 1)); + } + numBits -= avail; + res |= (UInt32)(b & ((1 << avail) - 1)) << numBits; + _bitPos += avail; + } +} + +UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); } + +UInt32 CMemBitDecoder::ReadEncodedUInt32() +{ + unsigned v = (unsigned)ReadBits(2); + UInt32 res = ReadBits(4 << v); + if (v == 1 && res < 16) + res = 0xFFFFFF00 | (res << 4) | ReadBits(4); + return res; +} + +namespace NVm { + +static const UInt32 kStackRegIndex = kNumRegs - 1; + +#ifdef RARVM_VM_ENABLE + +static const UInt32 FLAG_C = 1; +static const UInt32 FLAG_Z = 2; +static const UInt32 FLAG_S = 0x80000000; + +static const Byte CF_OP0 = 0; +static const Byte CF_OP1 = 1; +static const Byte CF_OP2 = 2; +static const Byte CF_OPMASK = 3; +static const Byte CF_BYTEMODE = 4; +static const Byte CF_JUMP = 8; +static const Byte CF_PROC = 16; +static const Byte CF_USEFLAGS = 32; +static const Byte CF_CHFLAGS = 64; + +static const Byte kCmdFlags[]= +{ + /* CMD_MOV */ CF_OP2 | CF_BYTEMODE, + /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JMP */ CF_OP1 | CF_JUMP, + /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS, + /* CMD_PUSH */ CF_OP1, + /* CMD_POP */ CF_OP1, + /* CMD_CALL */ CF_OP1 | CF_PROC, + /* CMD_RET */ CF_OP0 | CF_PROC, + /* CMD_NOT */ CF_OP1 | CF_BYTEMODE, + /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS, + /* CMD_PUSHA */ CF_OP0, + /* CMD_POPA */ CF_OP0, + /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS, + /* CMD_POPF */ CF_OP0 | CF_CHFLAGS, + /* CMD_MOVZX */ CF_OP2, + /* CMD_MOVSX */ CF_OP2, + /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE, + /* CMD_MUL */ CF_OP2 | CF_BYTEMODE, + /* CMD_DIV */ CF_OP2 | CF_BYTEMODE, + /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , + /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS , + /* CMD_PRINT */ CF_OP0 +}; + +#endif + + +CVm::CVm(): Mem(NULL) {} + +bool CVm::Create() +{ + if (!Mem) + Mem = (Byte *)::MyAlloc(kSpaceSize + 4); + return (Mem != NULL); +} + +CVm::~CVm() +{ + ::MyFree(Mem); +} + +// CVm::Execute can change CProgram object: it clears progarm if VM returns error. + +bool CVm::Execute(CProgram *prg, const CProgramInitState *initState, + CBlockRef &outBlockRef, CRecordVector &outGlobalData) +{ + memcpy(R, initState->InitR, sizeof(initState->InitR)); + R[kStackRegIndex] = kSpaceSize; + R[kNumRegs] = 0; + Flags = 0; + + UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize); + if (globalSize != 0) + memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize); + UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize); + if (staticSize != 0) + memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize); + + bool res = true; + + #ifdef RARVM_STANDARD_FILTERS + if (prg->StandardFilterIndex >= 0) + res = ExecuteStandardFilter(prg->StandardFilterIndex); + else + #endif + { + #ifdef RARVM_VM_ENABLE + res = ExecuteCode(prg); + if (!res) + { + prg->Commands.Clear(); + prg->Commands.Add(CCommand()); + prg->Commands.Back().OpCode = CMD_RET; + } + #else + res = false; + #endif + } + + UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask; + UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask; + if (newBlockPos + newBlockSize >= kSpaceSize) + newBlockPos = newBlockSize = 0; + outBlockRef.Offset = newBlockPos; + outBlockRef.Size = newBlockSize; + + outGlobalData.Clear(); + UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize); + dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize); + if (dataSize != 0) + { + dataSize += kFixedGlobalSize; + outGlobalData.ClearAndSetSize(dataSize); + memcpy(&outGlobalData[0], Mem + kGlobalOffset, dataSize); + } + + return res; +} + +#ifdef RARVM_VM_ENABLE + +#define SET_IP(IP) \ + if ((IP) >= numCommands) return true; \ + if (--maxOpCount <= 0) return false; \ + cmd = commands + (IP); + +#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0) +#define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); } +#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S +#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res) + +UInt32 CVm::GetOperand32(const COperand *op) const +{ + switch (op->Type) + { + case OP_TYPE_REG: return R[op->Data]; + case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]); + default: return op->Data; + } +} + +void CVm::SetOperand32(const COperand *op, UInt32 val) +{ + switch (op->Type) + { + case OP_TYPE_REG: R[op->Data] = val; return; + case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return; + } +} + +Byte CVm::GetOperand8(const COperand *op) const +{ + switch (op->Type) + { + case OP_TYPE_REG: return (Byte)R[op->Data]; + case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];; + default: return (Byte)op->Data; + } +} + +void CVm::SetOperand8(const COperand *op, Byte val) +{ + switch (op->Type) + { + case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return; + case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return; + } +} + +UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const +{ + if (byteMode) + return GetOperand8(op); + return GetOperand32(op); +} + +void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val) +{ + if (byteMode) + SetOperand8(op, (Byte)(val & 0xFF)); + else + SetOperand32(op, val); +} + +bool CVm::ExecuteCode(const CProgram *prg) +{ + Int32 maxOpCount = 25000000; + const CCommand *commands = &prg->Commands[0]; + const CCommand *cmd = commands; + UInt32 numCommands = prg->Commands.Size(); + if (numCommands == 0) + return false; + + for (;;) + { + switch (cmd->OpCode) + { + case CMD_MOV: + SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2)); + break; + case CMD_MOVB: + SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2)); + break; + case CMD_CMP: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 - GetOperand32(&cmd->Op2); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_CMPB: + { + Byte v1 = GetOperand8(&cmd->Op1); + Byte res = (Byte)((v1 - GetOperand8(&cmd->Op2)) & 0xFF); + Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res); + } + break; + case CMD_ADD: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 + GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_ADDB: + { + Byte v1 = GetOperand8(&cmd->Op1); + Byte res = (Byte)((v1 + GetOperand8(&cmd->Op2)) & 0xFF); + SetOperand8(&cmd->Op1, (Byte)res); + Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)); + } + break; + case CMD_ADC: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC; + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_SUB: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + UInt32 res = v1 - GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SUBB: + { + UInt32 v1 = GetOperand8(&cmd->Op1); + UInt32 res = v1 - GetOperand8(&cmd->Op2); + SetOperand8(&cmd->Op1, (Byte)res); + Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S); + } + break; + case CMD_SBB: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + UInt32 FC = (Flags & FLAG_C); + UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC; + // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S); + if (cmd->ByteMode) + res &= 0xFF; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S)); + } + break; + case CMD_INC: + { + UInt32 res = GetOperand32(&cmd->Op1) + 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_INCB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) + 1); + SetOperand8(&cmd->Op1, res);; + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_DEC: + { + UInt32 res = GetOperand32(&cmd->Op1) - 1; + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_DECB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) - 1); + SetOperand8(&cmd->Op1, res);; + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_XOR: + { + UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_XORB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_AND: + { + UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ANDB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_OR: + { + UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + FLAGS_UPDATE_SZ; + } + break; + case CMD_ORB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_TEST: + { + UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2); + FLAGS_UPDATE_SZ; + } + break; + case CMD_TESTB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2)); + FLAGS_UPDATE_SZ_B; + } + break; + case CMD_NOT: + SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1)); + break; + case CMD_NEG: + { + UInt32 res = 0 - GetOperand32(&cmd->Op1); + SetOperand32(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S); + } + break; + case CMD_NEGB: + { + Byte res = (Byte)(0 - GetOperand8(&cmd->Op1)); + SetOperand8(&cmd->Op1, res); + Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res); + } + break; + + case CMD_SHL: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = v1 << v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0); + } + break; + case CMD_SHLB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(v1 << v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0); + } + break; + case CMD_SHR: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = v1 >> v2; + SetOperand32(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SHRB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(v1 >> v2); + SetOperand8(&cmd->Op1, res); + Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SAR: + { + UInt32 v1 = GetOperand32(&cmd->Op1); + int v2 = (int)GetOperand32(&cmd->Op2); + UInt32 res = UInt32(((Int32)v1) >> v2); + SetOperand32(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + case CMD_SARB: + { + Byte v1 = GetOperand8(&cmd->Op1); + int v2 = (int)GetOperand8(&cmd->Op2); + Byte res = (Byte)(((signed char)v1) >> v2); + SetOperand8(&cmd->Op1, res); + Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C); + } + break; + + case CMD_JMP: + SET_IP_OP1; + continue; + case CMD_JZ: + if ((Flags & FLAG_Z) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JNZ: + if ((Flags & FLAG_Z) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JS: + if ((Flags & FLAG_S) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JNS: + if ((Flags & FLAG_S) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JB: + if ((Flags & FLAG_C) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JBE: + if ((Flags & (FLAG_C | FLAG_Z)) != 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JA: + if ((Flags & (FLAG_C | FLAG_Z)) == 0) + { + SET_IP_OP1; + continue; + } + break; + case CMD_JAE: + if ((Flags & FLAG_C) == 0) + { + SET_IP_OP1; + continue; + } + break; + + case CMD_PUSH: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1)); + break; + case CMD_POP: + SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask])); + R[kStackRegIndex] += 4; + break; + case CMD_CALL: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1)); + SET_IP_OP1; + continue; + + case CMD_PUSHA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4) + SetValue32(&Mem[SP & kSpaceMask], R[i]); + R[kStackRegIndex] -= kNumRegs * 4; + } + break; + case CMD_POPA: + { + for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4) + R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]); + } + break; + case CMD_PUSHF: + R[kStackRegIndex] -= 4; + SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags); + break; + case CMD_POPF: + Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + R[kStackRegIndex] += 4; + break; + + case CMD_MOVZX: + SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2)); + break; + case CMD_MOVSX: + SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2)); + break; + case CMD_XCHG: + { + UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1); + SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2)); + SetOperand(cmd->ByteMode, &cmd->Op2, v1); + } + break; + case CMD_MUL: + { + UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2); + SetOperand32(&cmd->Op1, res); + } + break; + case CMD_MULB: + { + Byte res = (Byte)(GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2)); + SetOperand8(&cmd->Op1, res); + } + break; + case CMD_DIV: + { + UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2); + if (divider != 0) + { + UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider; + SetOperand(cmd->ByteMode, &cmd->Op1, res); + } + } + break; + + case CMD_RET: + { + if (R[kStackRegIndex] >= kSpaceSize) + return true; + UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]); + SET_IP(ip); + R[kStackRegIndex] += 4; + continue; + } + case CMD_PRINT: + break; + } + cmd++; + --maxOpCount; + } +} + +////////////////////////////////////////////////////// +// Read program + +static void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode) +{ + if (inp.ReadBit()) + { + op.Type = OP_TYPE_REG; + op.Data = inp.ReadBits(kNumRegBits); + } + else if (inp.ReadBit() == 0) + { + op.Type = OP_TYPE_INT; + if (byteMode) + op.Data = inp.ReadBits(8); + else + op.Data = inp.ReadEncodedUInt32(); + } + else + { + op.Type = OP_TYPE_REGMEM; + if (inp.ReadBit() == 0) + { + op.Data = inp.ReadBits(kNumRegBits); + op.Base = 0; + } + else + { + if (inp.ReadBit() == 0) + op.Data = inp.ReadBits(kNumRegBits); + else + op.Data = kNumRegs; + op.Base = inp.ReadEncodedUInt32(); + } + } +} + +void CProgram::ReadProgram(const Byte *code, UInt32 codeSize) +{ + CMemBitDecoder inp; + inp.Init(code, codeSize); + + StaticData.Clear(); + + if (inp.ReadBit()) + { + UInt32 dataSize = inp.ReadEncodedUInt32() + 1; + for (UInt32 i = 0; inp.Avail() && i < dataSize; i++) + StaticData.Add((Byte)inp.ReadBits(8)); + } + + while (inp.Avail()) + { + Commands.Add(CCommand()); + CCommand *cmd = &Commands.Back(); + + if (inp.ReadBit() == 0) + cmd->OpCode = (ECommand)inp.ReadBits(3); + else + cmd->OpCode = (ECommand)(8 + inp.ReadBits(5)); + + if (kCmdFlags[(unsigned)cmd->OpCode] & CF_BYTEMODE) + cmd->ByteMode = (inp.ReadBit()) ? true : false; + else + cmd->ByteMode = 0; + + int opNum = (kCmdFlags[(unsigned)cmd->OpCode] & CF_OPMASK); + + if (opNum > 0) + { + DecodeArg(inp, cmd->Op1, cmd->ByteMode); + if (opNum == 2) + DecodeArg(inp, cmd->Op2, cmd->ByteMode); + else + { + if (cmd->Op1.Type == OP_TYPE_INT && (kCmdFlags[(unsigned)cmd->OpCode] & (CF_JUMP | CF_PROC))) + { + int dist = cmd->Op1.Data; + if (dist >= 256) + dist -= 256; + else + { + if (dist >= 136) + dist -= 264; + else if (dist >= 16) + dist -= 8; + else if (dist >= 8) + dist -= 16; + dist += Commands.Size() - 1; + } + cmd->Op1.Data = dist; + } + } + } + + if (cmd->ByteMode) + { + switch (cmd->OpCode) + { + case CMD_MOV: cmd->OpCode = CMD_MOVB; break; + case CMD_CMP: cmd->OpCode = CMD_CMPB; break; + case CMD_ADD: cmd->OpCode = CMD_ADDB; break; + case CMD_SUB: cmd->OpCode = CMD_SUBB; break; + case CMD_INC: cmd->OpCode = CMD_INCB; break; + case CMD_DEC: cmd->OpCode = CMD_DECB; break; + case CMD_XOR: cmd->OpCode = CMD_XORB; break; + case CMD_AND: cmd->OpCode = CMD_ANDB; break; + case CMD_OR: cmd->OpCode = CMD_ORB; break; + case CMD_TEST: cmd->OpCode = CMD_TESTB; break; + case CMD_NEG: cmd->OpCode = CMD_NEGB; break; + case CMD_SHL: cmd->OpCode = CMD_SHLB; break; + case CMD_SHR: cmd->OpCode = CMD_SHRB; break; + case CMD_SAR: cmd->OpCode = CMD_SARB; break; + case CMD_MUL: cmd->OpCode = CMD_MULB; break; + } + } + } +} + +#endif + + +#ifdef RARVM_STANDARD_FILTERS + +enum EStandardFilter +{ + SF_E8, + SF_E8E9, + SF_ITANIUM, + SF_RGB, + SF_AUDIO, + SF_DELTA + // SF_UPCASE +}; + +static const struct CStandardFilterSignature +{ + UInt32 Length; + UInt32 CRC; + EStandardFilter Type; +} +kStdFilters[]= +{ + { 53, 0xad576887, SF_E8 }, + { 57, 0x3cd7e57e, SF_E8E9 }, + { 120, 0x3769893f, SF_ITANIUM }, + { 29, 0x0e06077d, SF_DELTA }, + { 149, 0x1c2c5dc8, SF_RGB }, + { 216, 0xbc85e701, SF_AUDIO } + // { 40, 0x46b9c560, SF_UPCASE } +}; + +static int FindStandardFilter(const Byte *code, UInt32 codeSize) +{ + UInt32 crc = CrcCalc(code, codeSize); + for (unsigned i = 0; i < ARRAY_SIZE(kStdFilters); i++) + { + const CStandardFilterSignature &sfs = kStdFilters[i]; + if (sfs.CRC == crc && sfs.Length == codeSize) + return i; + } + return -1; +} + +#endif + + +bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize) +{ + IsSupported = false; + + #ifdef RARVM_VM_ENABLE + Commands.Clear(); + #endif + + #ifdef RARVM_STANDARD_FILTERS + StandardFilterIndex = -1; + #endif + + bool isOK = false; + + Byte xorSum = 0; + for (UInt32 i = 0; i < codeSize; i++) + xorSum ^= code[i]; + + if (xorSum == 0 && codeSize != 0) + { + IsSupported = true; + isOK = true; + #ifdef RARVM_STANDARD_FILTERS + StandardFilterIndex = FindStandardFilter(code, codeSize); + if (StandardFilterIndex >= 0) + return true; + #endif + + #ifdef RARVM_VM_ENABLE + ReadProgram(code + 1, codeSize - 1); + #else + IsSupported = false; + #endif + } + + #ifdef RARVM_VM_ENABLE + Commands.Add(CCommand()); + Commands.Back().OpCode = CMD_RET; + #endif + + return isOK; +} + +void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize) +{ + if (pos < kSpaceSize && data != Mem + pos) + memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos)); +} + +#ifdef RARVM_STANDARD_FILTERS + +static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9) +{ + if (dataSize <= 4) + return; + dataSize -= 4; + const UInt32 kFileSize = 0x1000000; + Byte cmpMask = (Byte)(e9 ? 0xFE : 0xFF); + for (UInt32 curPos = 0; curPos < dataSize;) + { + curPos++; + if (((*data++) & cmpMask) == 0xE8) + { + UInt32 offset = curPos + fileOffset; + UInt32 addr = GetValue32(data); + if (addr < kFileSize) + SetValue32(data, addr - offset); + else if ((addr & 0x80000000) != 0 && ((addr + offset) & 0x80000000) == 0) + SetValue32(data, addr + kFileSize); + data += 4; + curPos += 4; + } + } +} + + +static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset) +{ + if (dataSize <= 21) + return; + fileOffset >>= 4; + dataSize -= 21; + dataSize += 15; + dataSize >>= 4; + dataSize += fileOffset; + do + { + unsigned m = ((UInt32)0x334B0000 >> (data[0] & 0x1E)) & 3; + if (m) + { + m++; + do + { + Byte *p = data + ((size_t)m * 5 - 8); + if (((p[3] >> m) & 15) == 5) + { + const UInt32 kMask = 0xFFFFF; + // UInt32 raw = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16); + UInt32 raw = GetUi32(p); + UInt32 v = raw >> m; + v -= fileOffset; + v &= kMask; + raw &= ~(kMask << m); + raw |= (v << m); + // p[0] = (Byte)raw; p[1] = (Byte)(raw >> 8); p[2] = (Byte)(raw >> 16); + SetUi32(p, raw); + } + } + while (++m <= 4); + } + data += 16; + } + while (++fileOffset != dataSize); +} + + +static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels) +{ + UInt32 srcPos = 0; + const UInt32 border = dataSize * 2; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + Byte prevByte = 0; + for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels) + data[destPos] = (prevByte = (Byte)(prevByte - data[srcPos++])); + } +} + +static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR) +{ + Byte *destData = srcData + dataSize; + const UInt32 kNumChannels = 3; + + for (UInt32 curChannel = 0; curChannel < kNumChannels; curChannel++) + { + Byte prevByte = 0; + + for (UInt32 i = curChannel; i < dataSize; i += kNumChannels) + { + unsigned int predicted; + if (i < width) + predicted = prevByte; + else + { + unsigned int upperLeftByte = destData[i - width]; + unsigned int upperByte = destData[i - width + 3]; + predicted = prevByte + upperByte - upperLeftByte; + int pa = abs((int)(predicted - prevByte)); + int pb = abs((int)(predicted - upperByte)); + int pc = abs((int)(predicted - upperLeftByte)); + if (pa <= pb && pa <= pc) + predicted = prevByte; + else + if (pb <= pc) + predicted = upperByte; + else + predicted = upperLeftByte; + } + destData[i] = prevByte = (Byte)(predicted - *(srcData++)); + } + } + if (dataSize < 3) + return; + const UInt32 border = dataSize - 2; + for (UInt32 i = posR; i < border; i += 3) + { + Byte g = destData[i + 1]; + destData[i ] = (Byte)(destData[i ] + g); + destData[i + 2] = (Byte)(destData[i + 2] + g); + } +} + +static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels) +{ + Byte *destData = srcData + dataSize; + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + UInt32 prevByte = 0, prevDelta = 0, dif[7]; + Int32 D1 = 0, D2 = 0, D3; + Int32 K1 = 0, K2 = 0, K3 = 0; + memset(dif, 0, sizeof(dif)); + + for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++) + { + D3 = D2; + D2 = prevDelta - D1; + D1 = prevDelta; + + UInt32 predicted = 8 * prevByte + K1 * D1 + K2 * D2 + K3 * D3; + predicted = (predicted >> 3) & 0xFF; + + UInt32 curByte = *(srcData++); + + predicted -= curByte; + destData[i] = (Byte)predicted; + prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte); + prevByte = predicted; + + Int32 D = ((Int32)(signed char)curByte) << 3; + + dif[0] += abs(D); + dif[1] += abs(D - D1); + dif[2] += abs(D + D1); + dif[3] += abs(D - D2); + dif[4] += abs(D + D2); + dif[5] += abs(D - D3); + dif[6] += abs(D + D3); + + if ((byteCount & 0x1F) == 0) + { + UInt32 minDif = dif[0], numMinDif = 0; + dif[0] = 0; + for (unsigned j = 1; j < ARRAY_SIZE(dif); j++) + { + if (dif[j] < minDif) + { + minDif = dif[j]; + numMinDif = j; + } + dif[j] = 0; + } + switch (numMinDif) + { + case 1: if (K1 >= -16) K1--; break; + case 2: if (K1 < 16) K1++; break; + case 3: if (K2 >= -16) K2--; break; + case 4: if (K2 < 16) K2++; break; + case 5: if (K3 >= -16) K3--; break; + case 6: if (K3 < 16) K3++; break; + } + } + } + } +} + +/* +static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize) +{ + UInt32 srcPos = 0, destPos = dataSize; + while (srcPos < dataSize) + { + Byte curByte = data[srcPos++]; + if (curByte == 2 && (curByte = data[srcPos++]) != 2) + curByte -= 32; + data[destPos++] = curByte; + } + return destPos - dataSize; +} +*/ + +bool CVm::ExecuteStandardFilter(unsigned filterIndex) +{ + UInt32 dataSize = R[4]; + if (dataSize >= kGlobalOffset) + return false; + EStandardFilter filterType = kStdFilters[filterIndex].Type; + + switch (filterType) + { + case SF_E8: + case SF_E8E9: + E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9)); + break; + + case SF_ITANIUM: + ItaniumDecode(Mem, dataSize, R[6]); + break; + + case SF_DELTA: + { + if (dataSize >= kGlobalOffset / 2) + return false; + UInt32 numChannels = R[0]; + if (numChannels == 0 || numChannels > 1024) // unrar 5.5.5 + return false; + SetBlockPos(dataSize); + DeltaDecode(Mem, dataSize, numChannels); + break; + } + + case SF_RGB: + { + if (dataSize >= kGlobalOffset / 2 || dataSize < 3) // unrar 5.5.5 + return false; + UInt32 width = R[0]; + UInt32 posR = R[1]; + if (width < 3 || width - 3 > dataSize || posR > 2) // unrar 5.5.5 + return false; + SetBlockPos(dataSize); + RgbDecode(Mem, dataSize, width, posR); + break; + } + + case SF_AUDIO: + { + if (dataSize >= kGlobalOffset / 2) + return false; + UInt32 numChannels = R[0]; + if (numChannels == 0 || numChannels > 128) // unrar 5.5.5 + return false; + SetBlockPos(dataSize); + AudioDecode(Mem, dataSize, numChannels); + break; + } + + /* + case SF_UPCASE: + if (dataSize >= kGlobalOffset / 2) + return false; + UInt32 destSize = UpCaseDecode(Mem, dataSize); + SetBlockSize(destSize); + SetBlockPos(dataSize); + break; + */ + } + return true; +} + +#endif + +}}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Vm.h 7zip-22.01/CPP/7zip/Compress/Rar3Vm.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar3Vm.h 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar3Vm.h 2017-06-12 16:04:54.000000000 +0000 @@ -0,0 +1,195 @@ +// Rar3Vm.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR3_VM_H +#define __COMPRESS_RAR3_VM_H + +#include "../../../C/CpuArch.h" + +#include "../../Common/MyVector.h" + +#define RARVM_STANDARD_FILTERS +// #define RARVM_VM_ENABLE + +namespace NCompress { +namespace NRar3 { + +class CMemBitDecoder +{ + const Byte *_data; + UInt32 _bitSize; + UInt32 _bitPos; +public: + void Init(const Byte *data, UInt32 byteSize) + { + _data = data; + _bitSize = (byteSize << 3); + _bitPos = 0; + } + UInt32 ReadBits(unsigned numBits); + UInt32 ReadBit(); + bool Avail() const { return (_bitPos < _bitSize); } + + UInt32 ReadEncodedUInt32(); +}; + +namespace NVm { + +inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); } +inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value); } + +const unsigned kNumRegBits = 3; +const UInt32 kNumRegs = 1 << kNumRegBits; +const UInt32 kNumGpRegs = kNumRegs - 1; + +const UInt32 kSpaceSize = 0x40000; +const UInt32 kSpaceMask = kSpaceSize - 1; +const UInt32 kGlobalOffset = 0x3C000; +const UInt32 kGlobalSize = 0x2000; +const UInt32 kFixedGlobalSize = 64; + +namespace NGlobalOffset +{ + const UInt32 kBlockSize = 0x1C; + const UInt32 kBlockPos = 0x20; + const UInt32 kExecCount = 0x2C; + const UInt32 kGlobalMemOutSize = 0x30; +} + + +#ifdef RARVM_VM_ENABLE + +enum ECommand +{ + CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC, + CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB, + CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT, + CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF, + CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT, + + CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB, + CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB, + CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB +}; + +enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE}; + +// Addr in COperand object can link (point) to CVm object!!! + +struct COperand +{ + EOpType Type; + UInt32 Data; + UInt32 Base; + COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {} +}; + +struct CCommand +{ + ECommand OpCode; + bool ByteMode; + COperand Op1, Op2; +}; + +#endif + + +struct CBlockRef +{ + UInt32 Offset; + UInt32 Size; +}; + + +class CProgram +{ + #ifdef RARVM_VM_ENABLE + void ReadProgram(const Byte *code, UInt32 codeSize); +public: + CRecordVector Commands; + #endif + +public: + #ifdef RARVM_STANDARD_FILTERS + int StandardFilterIndex; + #endif + + bool IsSupported; + CRecordVector StaticData; + + bool PrepareProgram(const Byte *code, UInt32 codeSize); +}; + + +struct CProgramInitState +{ + UInt32 InitR[kNumGpRegs]; + CRecordVector GlobalData; + + void AllocateEmptyFixedGlobal() + { + GlobalData.ClearAndSetSize(NVm::kFixedGlobalSize); + memset(&GlobalData[0], 0, NVm::kFixedGlobalSize); + } +}; + + +class CVm +{ + static UInt32 GetValue(bool byteMode, const void *addr) + { + if (byteMode) + return(*(const Byte *)addr); + else + return GetUi32(addr); + } + + static void SetValue(bool byteMode, void *addr, UInt32 value) + { + if (byteMode) + *(Byte *)addr = (Byte)value; + else + SetUi32(addr, value); + } + + UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); } + + void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); } + void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); } +public: + static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); } + +private: + + #ifdef RARVM_VM_ENABLE + UInt32 GetOperand32(const COperand *op) const; + void SetOperand32(const COperand *op, UInt32 val); + Byte GetOperand8(const COperand *op) const; + void SetOperand8(const COperand *op, Byte val); + UInt32 GetOperand(bool byteMode, const COperand *op) const; + void SetOperand(bool byteMode, const COperand *op, UInt32 val); + bool ExecuteCode(const CProgram *prg); + #endif + + #ifdef RARVM_STANDARD_FILTERS + bool ExecuteStandardFilter(unsigned filterIndex); + #endif + + Byte *Mem; + UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization) + UInt32 Flags; + +public: + CVm(); + ~CVm(); + bool Create(); + void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize); + bool Execute(CProgram *prg, const CProgramInitState *initState, + CBlockRef &outBlockRef, CRecordVector &outGlobalData); + const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; } +}; + +#endif + +}}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar5Decoder.cpp 7zip-22.01/CPP/7zip/Compress/Rar5Decoder.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar5Decoder.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar5Decoder.cpp 2020-09-28 09:37:30.000000000 +0000 @@ -0,0 +1,980 @@ +// Rar5Decoder.cpp +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#include "StdAfx.h" + +// #include + +#include "../Common/StreamUtils.h" + +#include "Rar5Decoder.h" + +namespace NCompress { +namespace NRar5 { + +static const size_t kInputBufSize = 1 << 20; + +void CBitDecoder::Prepare2() throw() +{ + const unsigned kSize = 16; + if (_buf > _bufLim) + return; + + size_t rem = _bufLim - _buf; + if (rem != 0) + memmove(_bufBase, _buf, rem); + + _bufLim = _bufBase + rem; + _processedSize += (_buf - _bufBase); + _buf = _bufBase; + + if (!_wasFinished) + { + UInt32 processed = (UInt32)(kInputBufSize - rem); + _hres = _stream->Read(_bufLim, (UInt32)processed, &processed); + _bufLim += processed; + _wasFinished = (processed == 0); + if (_hres != S_OK) + { + _wasFinished = true; + // throw CInBufferException(result); + } + } + + rem = _bufLim - _buf; + _bufCheck = _buf; + if (rem < kSize) + memset(_bufLim, 0xFF, kSize - rem); + else + _bufCheck = _bufLim - kSize; + + SetCheck2(); +} + + +enum FilterType +{ + FILTER_DELTA = 0, + FILTER_E8, + FILTER_E8E9, + FILTER_ARM +}; + +static const size_t kWriteStep = (size_t)1 << 22; + +CDecoder::CDecoder(): + _isSolid(false), + _solidAllowed(false), + _wasInit(false), + _dictSizeLog(0), + _window(NULL), + _winPos(0), + _lzSize(0), + _lzEnd(0), + _writtenFileSize(0), + _winSizeAllocated(0), + _inputBuf(NULL) +{ +} + +CDecoder::~CDecoder() +{ + ::MidFree(_window); + ::MidFree(_inputBuf); +} + +HRESULT CDecoder::WriteData(const Byte *data, size_t size) +{ + HRESULT res = S_OK; + if (!_unpackSize_Defined || _writtenFileSize < _unpackSize) + { + size_t cur = size; + if (_unpackSize_Defined) + { + UInt64 rem = _unpackSize - _writtenFileSize; + if (cur > rem) + cur = (size_t)rem; + } + res = WriteStream(_outStream, data, cur); + if (res != S_OK) + _writeError = true; + } + _writtenFileSize += size; + return res; +} + +HRESULT CDecoder::ExecuteFilter(const CFilter &f) +{ + bool useDest = false; + + Byte *data = _filterSrc; + UInt32 dataSize = f.Size; + + // printf("\nType = %d offset = %9d size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize); + + switch (f.Type) + { + case FILTER_E8: + case FILTER_E8E9: + { + // printf(" FILTER_E8"); + if (dataSize > 4) + { + dataSize -= 4; + UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart); + + const UInt32 kFileSize = (UInt32)1 << 24; + Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE); + + for (UInt32 curPos = 0; curPos < dataSize;) + { + curPos++; + if (((*data++) & cmpMask) == 0xE8) + { + UInt32 offset = (curPos + fileOffset) & (kFileSize - 1); + UInt32 addr = GetUi32(data); + + if (addr < kFileSize) + { + SetUi32(data, addr - offset); + } + else if (addr > ((UInt32)0xFFFFFFFF - offset)) // (addr > ~(offset)) + { + SetUi32(data, addr + kFileSize); + } + + data += 4; + curPos += 4; + } + } + } + break; + } + + case FILTER_ARM: + { + if (dataSize >= 4) + { + dataSize -= 4; + UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart); + + for (UInt32 curPos = 0; curPos <= dataSize; curPos += 4) + { + Byte *d = data + curPos; + if (d[3] == 0xEB) + { + UInt32 offset = d[0] | ((UInt32)d[1] << 8) | ((UInt32)d[2] << 16); + offset -= (fileOffset + curPos) >> 2; + d[0] = (Byte)offset; + d[1] = (Byte)(offset >> 8); + d[2] = (Byte)(offset >> 16); + } + } + } + break; + } + + case FILTER_DELTA: + { + // printf(" channels = %d", f.Channels); + _filterDst.AllocAtLeast(dataSize); + if (!_filterDst.IsAllocated()) + return E_OUTOFMEMORY; + + Byte *dest = _filterDst; + UInt32 numChannels = f.Channels; + + for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++) + { + Byte prevByte = 0; + for (UInt32 destPos = curChannel; destPos < dataSize; destPos += numChannels) + dest[destPos] = (prevByte = (Byte)(prevByte - *data++)); + } + useDest = true; + break; + } + + default: + _unsupportedFilter = true; + memset(_filterSrc, 0, f.Size); + // return S_OK; // unrar + } + + return WriteData(useDest ? + (const Byte *)_filterDst : + (const Byte *)_filterSrc, + f.Size); +} + + +HRESULT CDecoder::WriteBuf() +{ + DeleteUnusedFilters(); + + for (unsigned i = 0; i < _filters.Size();) + { + const CFilter &f = _filters[i]; + + UInt64 blockStart = f.Start; + + size_t lzAvail = (size_t)(_lzSize - _lzWritten); + if (lzAvail == 0) + break; + + if (blockStart > _lzWritten) + { + UInt64 rem = blockStart - _lzWritten; + size_t size = lzAvail; + if (size > rem) + size = (size_t)rem; + if (size != 0) + { + RINOK(WriteData(_window + _winPos - lzAvail, size)); + _lzWritten += size; + } + continue; + } + + UInt32 blockSize = f.Size; + size_t offset = (size_t)(_lzWritten - blockStart); + if (offset == 0) + { + _filterSrc.AllocAtLeast(blockSize); + if (!_filterSrc.IsAllocated()) + return E_OUTOFMEMORY; + } + + size_t blockRem = (size_t)blockSize - offset; + size_t size = lzAvail; + if (size > blockRem) + size = blockRem; + memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size); + _lzWritten += size; + offset += size; + if (offset != blockSize) + return S_OK; + + _numUnusedFilters = ++i; + RINOK(ExecuteFilter(f)); + } + + DeleteUnusedFilters(); + + if (!_filters.IsEmpty()) + return S_OK; + + size_t lzAvail = (size_t)(_lzSize - _lzWritten); + RINOK(WriteData(_window + _winPos - lzAvail, lzAvail)); + _lzWritten += lzAvail; + return S_OK; +} + + +static UInt32 ReadUInt32(CBitDecoder &bi) +{ + unsigned numBytes = bi.ReadBits9fix(2) + 1; + UInt32 v = 0; + for (unsigned i = 0; i < numBytes; i++) + v += ((UInt32)bi.ReadBits9fix(8) << (i * 8)); + return v; +} + + +static const unsigned MAX_UNPACK_FILTERS = 8192; + +HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream) +{ + DeleteUnusedFilters(); + + if (_filters.Size() >= MAX_UNPACK_FILTERS) + { + RINOK(WriteBuf()); + DeleteUnusedFilters(); + if (_filters.Size() >= MAX_UNPACK_FILTERS) + { + _unsupportedFilter = true; + InitFilters(); + } + } + + _bitStream.Prepare(); + + CFilter f; + UInt32 blockStart = ReadUInt32(_bitStream); + f.Size = ReadUInt32(_bitStream); + + if (f.Size > ((UInt32)1 << 22)) + { + _unsupportedFilter = true; + f.Size = 0; // unrar 5.5.5 + } + + f.Type = (Byte)_bitStream.ReadBits9fix(3); + f.Channels = 0; + if (f.Type == FILTER_DELTA) + f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1); + f.Start = _lzSize + blockStart; + + if (f.Start < _filterEnd) + _unsupportedFilter = true; + else + { + _filterEnd = f.Start + f.Size; + if (f.Size != 0) + _filters.Add(f); + } + + return S_OK; +} + + +#define RIF(x) { if (!(x)) return S_FALSE; } + +HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream) +{ + if (_progress) + { + const UInt64 packSize = _bitStream.GetProcessedSize(); + RINOK(_progress->SetRatioInfo(&packSize, &_writtenFileSize)); + } + + _bitStream.AlignToByte(); + _bitStream.Prepare(); + + { + unsigned flags = _bitStream.ReadByteInAligned(); + unsigned checkSum = _bitStream.ReadByteInAligned(); + checkSum ^= flags; + unsigned num = (flags >> 3) & 3; + if (num == 3) + return S_FALSE; + UInt32 blockSize = _bitStream.ReadByteInAligned(); + checkSum ^= blockSize; + + if (num != 0) + { + unsigned b = _bitStream.ReadByteInAligned(); + checkSum ^= b; + blockSize += (UInt32)b << 8; + if (num > 1) + { + b = _bitStream.ReadByteInAligned(); + checkSum ^= b; + blockSize += (UInt32)b << 16; + } + } + + if (checkSum != 0x5A) + return S_FALSE; + + unsigned blockSizeBits7 = (flags & 7) + 1; + blockSize += (blockSizeBits7 >> 3); + if (blockSize == 0) + return S_FALSE; + blockSize--; + blockSizeBits7 &= 7; + + _bitStream._blockEndBits7 = (Byte)blockSizeBits7; + _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize; + + _bitStream.SetCheck2(); + + _isLastBlock = ((flags & 0x40) != 0); + + if ((flags & 0x80) == 0) + { + if (!_tableWasFilled) + if (blockSize != 0 || blockSizeBits7 != 0) + return S_FALSE; + return S_OK; + } + + _tableWasFilled = false; + } + + { + Byte lens2[kLevelTableSize]; + + for (unsigned i = 0; i < kLevelTableSize;) + { + _bitStream.Prepare(); + unsigned len = (unsigned)_bitStream.ReadBits9fix(4); + if (len == 15) + { + unsigned num = (unsigned)_bitStream.ReadBits9fix(4); + if (num != 0) + { + num += 2; + num += i; + if (num > kLevelTableSize) + num = kLevelTableSize; + do + lens2[i++] = 0; + while (i < num); + continue; + } + } + lens2[i++] = (Byte)len; + } + + if (_bitStream.IsBlockOverRead()) + return S_FALSE; + + RIF(m_LevelDecoder.Build(lens2)); + } + + Byte lens[kTablesSizesSum]; + unsigned i = 0; + + do + { + if (_bitStream._buf >= _bitStream._bufCheck2) + { + if (_bitStream._buf >= _bitStream._bufCheck) + _bitStream.Prepare(); + if (_bitStream.IsBlockOverRead()) + return S_FALSE; + } + + UInt32 sym = m_LevelDecoder.Decode(&_bitStream); + + if (sym < 16) + lens[i++] = (Byte)sym; + else if (sym > kLevelTableSize) + return S_FALSE; + else + { + unsigned num = ((sym - 16) & 1) * 4; + num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3); + num += i; + if (num > kTablesSizesSum) + num = kTablesSizesSum; + Byte v = 0; + if (sym < 16 + 2) + { + if (i == 0) + 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; + if (_bitStream.InputEofError()) + return S_FALSE; + + 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])); + + _useAlignBits = false; + // _useAlignBits = true; + for (i = 0; i < kAlignTableSize; i++) + if (lens[kMainTableSize + kDistTableSize + (size_t)i] != kNumAlignBits) + { + _useAlignBits = true; + break; + } + + _tableWasFilled = true; + return S_OK; +} + + +static inline unsigned SlotToLen(CBitDecoder &_bitStream, unsigned slot) +{ + if (slot < 8) + return slot + 2; + unsigned numBits = (slot >> 2) - 1; + return 2 + ((4 | (slot & 3)) << numBits) + _bitStream.ReadBits9(numBits); +} + + +static const UInt32 kSymbolRep = 258; +// static const unsigned kMaxMatchLen = 0x1001 + 3; + +HRESULT CDecoder::DecodeLZ() +{ + CBitDecoder _bitStream; + _bitStream._stream = _inStream; + _bitStream._bufBase = _inputBuf; + _bitStream.Init(); + + UInt32 rep0 = _reps[0]; + + UInt32 remLen = 0; + + size_t limit; + { + size_t rem = _winSize - _winPos; + if (rem > kWriteStep) + rem = kWriteStep; + limit = _winPos + rem; + } + + for (;;) + { + if (_winPos >= limit) + { + RINOK(WriteBuf()); + if (_unpackSize_Defined && _writtenFileSize > _unpackSize) + break; // return S_FALSE; + + { + size_t rem = _winSize - _winPos; + + if (rem == 0) + { + _winPos = 0; + rem = _winSize; + } + if (rem > kWriteStep) + rem = kWriteStep; + limit = _winPos + rem; + } + + if (remLen != 0) + { + size_t winPos = _winPos; + size_t winMask = _winMask; + size_t pos = (winPos - (size_t)rep0 - 1) & winMask; + + Byte *win = _window; + do + { + if (winPos >= limit) + break; + win[winPos] = win[pos]; + winPos++; + pos = (pos + 1) & winMask; + } + while (--remLen != 0); + + _lzSize += winPos - _winPos; + _winPos = winPos; + continue; + } + } + + if (_bitStream._buf >= _bitStream._bufCheck2) + { + if (_bitStream.InputEofError()) + break; // return S_FALSE; + if (_bitStream._buf >= _bitStream._bufCheck) + _bitStream.Prepare2(); + + UInt64 processed = _bitStream.GetProcessedSize_Round(); + if (processed >= _bitStream._blockEnd) + { + if (processed > _bitStream._blockEnd) + break; // return S_FALSE; + { + unsigned bits7 = _bitStream.GetProcessedBits7(); + if (bits7 > _bitStream._blockEndBits7) + break; // return S_FALSE; + if (bits7 == _bitStream._blockEndBits7) + { + if (_isLastBlock) + { + _reps[0] = rep0; + + if (_bitStream.InputEofError()) + break; + + /* + // packSize can be 15 bytes larger for encrypted archive + if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize()) + break; + */ + + return _bitStream._hres; + // break; + } + RINOK(ReadTables(_bitStream)); + continue; + } + } + } + + // that check is not required, but it can help, if there is BUG in another code + if (!_tableWasFilled) + break; // return S_FALSE; + } + + UInt32 sym = m_MainDecoder.Decode(&_bitStream); + + if (sym < 256) + { + size_t winPos = _winPos; + _window[winPos] = (Byte)sym; + _winPos = winPos + 1; + _lzSize++; + continue; + } + + UInt32 len; + + if (sym < kSymbolRep + kNumReps) + { + if (sym >= kSymbolRep) + { + if (sym != kSymbolRep) + { + UInt32 dist; + if (sym == kSymbolRep + 1) + dist = _reps[1]; + else + { + if (sym == kSymbolRep + 2) + dist = _reps[2]; + else + { + dist = _reps[3]; + _reps[3] = _reps[2]; + } + _reps[2] = _reps[1]; + } + _reps[1] = rep0; + rep0 = dist; + } + + const UInt32 sym2 = m_LenDecoder.Decode(&_bitStream); + if (sym2 >= kLenTableSize) + break; // return S_FALSE; + len = SlotToLen(_bitStream, sym2); + } + else + { + if (sym == 256) + { + RINOK(AddFilter(_bitStream)); + continue; + } + else // if (sym == 257) + { + len = _lastLen; + // if (len = 0), we ignore that symbol, like original unRAR code, but it can mean error in stream. + // if (len == 0) return S_FALSE; + if (len == 0) + continue; + } + } + } + else if (sym >= kMainTableSize) + break; // return S_FALSE; + else + { + _reps[3] = _reps[2]; + _reps[2] = _reps[1]; + _reps[1] = rep0; + len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps)); + + rep0 = m_DistDecoder.Decode(&_bitStream); + + if (rep0 >= 4) + { + if (rep0 >= _numCorrectDistSymbols) + break; // return S_FALSE; + unsigned numBits = (rep0 >> 1) - 1; + rep0 = (2 | (rep0 & 1)) << numBits; + + if (numBits < kNumAlignBits) + rep0 += _bitStream.ReadBits9(numBits); + else + { + len += (numBits >= 7); + len += (numBits >= 12); + len += (numBits >= 17); + + if (_useAlignBits) + { + // if (numBits > kNumAlignBits) + rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits); + UInt32 a = m_AlignDecoder.Decode(&_bitStream); + if (a >= kAlignTableSize) + break; // return S_FALSE; + rep0 += a; + } + else + rep0 += _bitStream.ReadBits32(numBits); + } + } + } + + _lastLen = len; + + if (rep0 >= _lzSize) + _lzError = true; + + { + UInt32 lenCur = len; + size_t winPos = _winPos; + size_t pos = (winPos - (size_t)rep0 - 1) & _winMask; + { + size_t rem = limit - winPos; + // size_t rem = _winSize - winPos; + + if (lenCur > rem) + { + lenCur = (UInt32)rem; + remLen = len - lenCur; + } + } + + Byte *win = _window; + _lzSize += lenCur; + _winPos = winPos + lenCur; + if (_winSize - pos >= lenCur) + { + const Byte *src = win + pos; + Byte *dest = win + winPos; + do + *dest++ = *src++; + while (--lenCur != 0); + } + else + { + do + { + win[winPos] = win[pos]; + winPos++; + pos = (pos + 1) & _winMask; + } + while (--lenCur != 0); + } + } + } + + if (_bitStream._hres != S_OK) + return _bitStream._hres; + + return S_FALSE; +} + + +HRESULT CDecoder::CodeReal() +{ + _unsupportedFilter = false; + _lzError = false; + _writeError = false; + + if (!_isSolid || !_wasInit) + { + size_t clearSize = _winSize; + if (_lzSize < _winSize) + clearSize = (size_t)_lzSize; + memset(_window, 0, clearSize); + + _wasInit = true; + _lzSize = 0; + _lzWritten = 0; + _winPos = 0; + + for (unsigned i = 0; i < kNumReps; i++) + _reps[i] = (UInt32)0 - 1; + + _lastLen = 0; + _tableWasFilled = false; + } + + _isLastBlock = false; + + InitFilters(); + + _filterEnd = 0; + _writtenFileSize = 0; + + _lzFileStart = _lzSize; + _lzWritten = _lzSize; + + HRESULT res = DecodeLZ(); + + HRESULT res2 = S_OK; + if (!_writeError && res != E_OUTOFMEMORY) + res2 = WriteBuf(); + + /* + if (res == S_OK) + if (InputEofError()) + res = S_FALSE; + */ + + if (res == S_OK) + { + _solidAllowed = true; + res = res2; + } + + if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize) + return S_FALSE; + return res; +} + + +// Original unRAR claims that maximum possible filter block size is (1 << 16) now, +// and (1 << 17) is minimum win size required to support filter. +// Original unRAR uses (1 << 18) for "extra safety and possible filter area size expansion" +// We can use any win size. + +static const unsigned kWinSize_Log_Min = 17; + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) +{ + try + { + if (_isSolid && !_solidAllowed) + return S_FALSE; + _solidAllowed = false; + + if (_dictSizeLog >= sizeof(size_t) * 8) + return E_NOTIMPL; + + if (!_isSolid) + _lzEnd = 0; + else + { + if (_lzSize < _lzEnd) + { + if (_window) + { + UInt64 rem = _lzEnd - _lzSize; + if (rem >= _winSize) + memset(_window, 0, _winSize); + else + { + size_t pos = (size_t)_lzSize & _winSize; + size_t rem2 = _winSize - pos; + if (rem2 > rem) + rem2 = (size_t)rem; + memset(_window + pos, 0, rem2); + rem -= rem2; + memset(_window, 0, (size_t)rem); + } + } + _lzEnd &= ((((UInt64)1) << 33) - 1); + _lzSize = _lzEnd; + _winPos = (size_t)(_lzSize & _winSize); + } + _lzEnd = _lzSize; + } + + size_t newSize; + { + unsigned newSizeLog = _dictSizeLog; + if (newSizeLog < kWinSize_Log_Min) + newSizeLog = kWinSize_Log_Min; + newSize = (size_t)1 << newSizeLog; + _numCorrectDistSymbols = newSizeLog * 2; + } + + // If dictionary was reduced, we use allocated dictionary block + // for compatibility with original unRAR decoder. + + if (_window && newSize < _winSizeAllocated) + _winSize = _winSizeAllocated; + else if (!_window || _winSize != newSize) + { + if (!_isSolid) + { + ::MidFree(_window); + _window = NULL; + _winSizeAllocated = 0; + } + + Byte *win; + + { + win = (Byte *)::MidAlloc(newSize); + if (!win) + return E_OUTOFMEMORY; + memset(win, 0, newSize); + } + + if (_isSolid && _window) + { + // original unRAR claims: + // "Archiving code guarantees that win size does not grow in the same solid stream", + // but the original unRAR decoder still supports such grow case. + + Byte *winOld = _window; + size_t oldSize = _winSize; + size_t newMask = newSize - 1; + size_t oldMask = _winSize - 1; + size_t winPos = _winPos; + for (size_t i = 1; i <= oldSize; i++) + win[(winPos - i) & newMask] = winOld[(winPos - i) & oldMask]; + ::MidFree(_window); + } + + _window = win; + _winSizeAllocated = newSize; + _winSize = newSize; + } + + _winMask = _winSize - 1; + _winPos &= _winMask; + + if (!_inputBuf) + { + _inputBuf = (Byte *)::MidAlloc(kInputBufSize); + if (!_inputBuf) + return E_OUTOFMEMORY; + } + + _inStream = inStream; + _outStream = outStream; + + /* + _packSize = 0; + _packSize_Defined = (inSize != NULL); + if (_packSize_Defined) + _packSize = *inSize; + */ + + _unpackSize = 0; + _unpackSize_Defined = (outSize != NULL); + if (_unpackSize_Defined) + _unpackSize = *outSize; + + if ((Int64)_unpackSize >= 0) + _lzEnd += _unpackSize; + else + _lzEnd = 0; + + _progress = progress; + + HRESULT res = CodeReal(); + + if (res != S_OK) + return res; + if (_lzError) + return S_FALSE; + if (_unsupportedFilter) + return E_NOTIMPL; + return S_OK; + } + // catch(const CInBufferException &e) { return e.ErrorCode; } + // catch(...) { return S_FALSE; } + catch(...) { return E_OUTOFMEMORY; } + // CNewException is possible here. But probably CNewException is caused + // by error in data stream. +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + if (size != 2) + return E_NOTIMPL; + _dictSizeLog = (Byte)((data[0] & 0xF) + 17); + _isSolid = ((data[1] & 1) != 0); + return S_OK; +} + +}} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/Rar5Decoder.h 7zip-22.01/CPP/7zip/Compress/Rar5Decoder.h --- 7zip-21.07+dfsg/CPP/7zip/Compress/Rar5Decoder.h 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/Rar5Decoder.h 2018-04-22 17:13:47.000000000 +0000 @@ -0,0 +1,307 @@ +// Rar5Decoder.h +// According to unRAR license, this code may not be used to develop +// a program that creates RAR archives + +#ifndef __COMPRESS_RAR5_DECODER_H +#define __COMPRESS_RAR5_DECODER_H + +#include "../../../C/CpuArch.h" + +#include "../../Common/MyBuffer2.h" +#include "../../Common/MyCom.h" +#include "../../Common/MyException.h" +#include "../../Common/MyVector.h" + +#include "../ICoder.h" + +#include "HuffmanDecoder.h" + +namespace NCompress { +namespace NRar5 { + + +/* +struct CInBufferException: public CSystemException +{ + CInBufferException(HRESULT errorCode): CSystemException(errorCode) {} +}; +*/ + +class CBitDecoder +{ +public: + const Byte *_buf; + unsigned _bitPos; + bool _wasFinished; + Byte _blockEndBits7; + const Byte *_bufCheck2; + const Byte *_bufCheck; + Byte *_bufLim; + Byte *_bufBase; + + UInt64 _processedSize; + UInt64 _blockEnd; + + ISequentialInStream *_stream; + HRESULT _hres; + + void SetCheck2() + { + _bufCheck2 = _bufCheck; + if (_bufCheck > _buf) + { + UInt64 processed = GetProcessedSize_Round(); + if (_blockEnd < processed) + _bufCheck2 = _buf; + else + { + UInt64 delta = _blockEnd - processed; + if ((size_t)(_bufCheck - _buf) > delta) + _bufCheck2 = _buf + (size_t)delta; + } + } + } + + bool IsBlockOverRead() const + { + UInt64 v = GetProcessedSize_Round(); + if (v < _blockEnd) + return false; + if (v > _blockEnd) + return true; + return _bitPos > _blockEndBits7; + } + + /* + CBitDecoder() throw(): + _buf(0), + _bufLim(0), + _bufBase(0), + _stream(0), + _processedSize(0), + _wasFinished(false) + {} + */ + + void Init() throw() + { + _blockEnd = 0; + _blockEndBits7 = 0; + + _bitPos = 0; + _processedSize = 0; + _buf = _bufBase; + _bufLim = _bufBase; + _bufCheck = _buf; + _bufCheck2 = _buf; + _wasFinished = false; + } + + void Prepare2() throw(); + + void Prepare() throw() + { + if (_buf >= _bufCheck) + Prepare2(); + } + + bool ExtraBitsWereRead() const + { + return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0); + } + + bool InputEofError() const { return ExtraBitsWereRead(); } + + unsigned GetProcessedBits7() const { return _bitPos; } + UInt64 GetProcessedSize_Round() const { return _processedSize + (_buf - _bufBase); } + UInt64 GetProcessedSize() const { return _processedSize + (_buf - _bufBase) + ((_bitPos + 7) >> 3); } + + void AlignToByte() + { + _buf += (_bitPos + 7) >> 3; + _bitPos = 0; + } + + Byte ReadByteInAligned() + { + return *_buf++; + } + + UInt32 GetValue(unsigned numBits) const + { + UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2]; + v >>= (24 - numBits - _bitPos); + return v & ((1 << numBits) - 1); + } + + void MovePos(unsigned numBits) + { + _bitPos += numBits; + _buf += (_bitPos >> 3); + _bitPos &= 7; + } + + UInt32 ReadBits9(unsigned numBits) + { + const Byte *buf = _buf; + UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; + v &= ((UInt32)0xFFFF >> _bitPos); + numBits += _bitPos; + v >>= (16 - numBits); + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v; + } + + UInt32 ReadBits9fix(unsigned numBits) + { + const Byte *buf = _buf; + UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1]; + UInt32 mask = ((1 << numBits) - 1); + numBits += _bitPos; + v >>= (16 - numBits); + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v & mask; + } + + UInt32 ReadBits32(unsigned numBits) + { + UInt32 mask = ((1 << numBits) - 1); + numBits += _bitPos; + const Byte *buf = _buf; + UInt32 v = GetBe32(buf); + if (numBits > 32) + { + v <<= (numBits - 32); + v |= (UInt32)buf[4] >> (40 - numBits); + } + else + v >>= (32 - numBits); + _buf = buf + (numBits >> 3); + _bitPos = numBits & 7; + return v & mask; + } +}; + + +struct CFilter +{ + Byte Type; + Byte Channels; + UInt32 Size; + UInt64 Start; +}; + + +const unsigned kNumReps = 4; +const unsigned kLenTableSize = 11 * 4; +const unsigned kMainTableSize = 256 + 1 + 1 + kNumReps + kLenTableSize; +const unsigned kDistTableSize = 64; +const unsigned kNumAlignBits = 4; +const unsigned kAlignTableSize = (1 << kNumAlignBits); +const unsigned kLevelTableSize = 20; +const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize; + +const unsigned kNumHuffmanBits = 15; + +class CDecoder: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ + bool _useAlignBits; + bool _isLastBlock; + bool _unpackSize_Defined; + // bool _packSize_Defined; + + bool _unsupportedFilter; + bool _lzError; + bool _writeError; + + bool _isSolid; + bool _solidAllowed; + bool _tableWasFilled; + bool _wasInit; + + Byte _dictSizeLog; + + // CBitDecoder _bitStream; + Byte *_window; + size_t _winPos; + size_t _winSize; + size_t _winMask; + + UInt64 _lzSize; + + unsigned _numCorrectDistSymbols; + unsigned _numUnusedFilters; + + UInt64 _lzWritten; + UInt64 _lzFileStart; + UInt64 _unpackSize; + // UInt64 _packSize; + UInt64 _lzEnd; + UInt64 _writtenFileSize; + size_t _winSizeAllocated; + + UInt32 _reps[kNumReps]; + UInt32 _lastLen; + + UInt64 _filterEnd; + CMidBuffer _filterSrc; + CMidBuffer _filterDst; + + CRecordVector _filters; + + ISequentialInStream *_inStream; + ISequentialOutStream *_outStream; + ICompressProgressInfo *_progress; + Byte *_inputBuf; + + NHuffman::CDecoder m_MainDecoder; + NHuffman::CDecoder m_DistDecoder; + NHuffman::CDecoder m_AlignDecoder; + NHuffman::CDecoder m_LenDecoder; + NHuffman::CDecoder m_LevelDecoder; + + + void InitFilters() + { + _numUnusedFilters = 0; + _filters.Clear(); + } + + void DeleteUnusedFilters() + { + if (_numUnusedFilters != 0) + { + _filters.DeleteFrontal(_numUnusedFilters); + _numUnusedFilters = 0; + } + } + + HRESULT WriteData(const Byte *data, size_t size); + HRESULT ExecuteFilter(const CFilter &f); + HRESULT WriteBuf(); + HRESULT AddFilter(CBitDecoder &_bitStream); + + HRESULT ReadTables(CBitDecoder &_bitStream); + HRESULT DecodeLZ(); + HRESULT CodeReal(); + +public: + CDecoder(); + ~CDecoder(); + + MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2) + + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); +}; + +}} + +#endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/Compress/RarCodecsRegister.cpp 7zip-22.01/CPP/7zip/Compress/RarCodecsRegister.cpp --- 7zip-21.07+dfsg/CPP/7zip/Compress/RarCodecsRegister.cpp 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Compress/RarCodecsRegister.cpp 2016-04-25 10:21:14.000000000 +0000 @@ -0,0 +1,33 @@ +// RarCodecsRegister.cpp + +#include "StdAfx.h" + +#include "../Common/RegisterCodec.h" + +#include "Rar1Decoder.h" +#include "Rar2Decoder.h" +#include "Rar3Decoder.h" +#include "Rar5Decoder.h" + +namespace NCompress { + +#define CREATE_CODEC(x) REGISTER_CODEC_CREATE(CreateCodec ## x, NRar ## x::CDecoder()) + +CREATE_CODEC(1) +CREATE_CODEC(2) +CREATE_CODEC(3) +CREATE_CODEC(5) + +#define RAR_CODEC(x, name) { CreateCodec ## x, NULL, 0x40300 + x, "Rar" name, 1, false } + +REGISTER_CODECS_VAR +{ + RAR_CODEC(1, "1"), + RAR_CODEC(2, "2"), + RAR_CODEC(3, "3"), + RAR_CODEC(5, "5"), +}; + +REGISTER_CODECS(Rar) + +} diff -Nru 7zip-21.07+dfsg/CPP/7zip/Guid.txt 7zip-22.01/CPP/7zip/Guid.txt --- 7zip-21.07+dfsg/CPP/7zip/Guid.txt 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/Guid.txt 2022-06-06 10:00:00.000000000 +0000 @@ -19,6 +19,7 @@ 0F IOutFolderArchive 10 IFolderArchiveUpdateCallback2 11 IFolderScanProgress + 12 IFolderSetZoneIdMode 20 IFileExtractCallback.h::IGetProp 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old) @@ -34,6 +35,7 @@ 07 IOutStreamFinish 08 IStreamGetProps 09 IStreamGetProps2 + 0A IStreamGetProp 04 ICoder.h @@ -106,6 +108,8 @@ 82 IArchiveUpdateCallback2 83 IArchiveUpdateCallbackFile 84 IArchiveGetDiskProperty + 85 IArchiveUpdateCallbackArcProp (Reserved) + A0 IOutArchive @@ -169,6 +173,10 @@ 0C xz 0D ppmd + C0 AVB + C1 LP + C2 Sparse + C3 APFS C4 Vhdx C5 Base64 C6 COFF diff -Nru 7zip-21.07+dfsg/CPP/7zip/IStream.h 7zip-22.01/CPP/7zip/IStream.h --- 7zip-21.07+dfsg/CPP/7zip/IStream.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/IStream.h 2022-02-15 11:00:00.000000000 +0000 @@ -133,4 +133,11 @@ STDMETHOD(GetProps2)(CStreamFileProps *props) PURE; }; + +STREAM_INTERFACE(IStreamGetProp, 0x0a) +{ + STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) PURE; + STDMETHOD(ReloadProps)() PURE; +}; + #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/PropID.h 7zip-22.01/CPP/7zip/PropID.h --- 7zip-21.07+dfsg/CPP/7zip/PropID.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/PropID.h 2022-05-03 11:00:00.000000000 +0000 @@ -105,7 +105,11 @@ kpidCopyLink, kpidArcFileName, kpidIsHash, - + kpidChangeTime, + kpidUserId, + kpidGroupId, + kpidDeviceMajor, + kpidDeviceMinor, kpid_NUM_DEFINED, @@ -127,4 +131,46 @@ const UInt32 kpv_ErrorFlags_CrcError = 1 << 10; // const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11; +/* +linux ctime : + file metadata was last changed. + changing the file modification time + counts as a metadata change, so will also have the side effect of updating the ctime. + +PROPVARIANT for timestamps in 7-Zip: +{ + vt = VT_FILETIME + wReserved1: set precision level + 0 : base value (backward compatibility value) + only filetime is used (7 digits precision). + wReserved2 and wReserved3 can contain random data + 1 : Unix (1 sec) + 2 : DOS (2 sec) + 3 : High Precision (1 ns) + 16 - 3 : (reserved) = 1 day + 16 - 2 : (reserved) = 1 hour + 16 - 1 : (reserved) = 1 minute + 16 + 0 : 1 sec (0 digits after point) + 16 + (1,2,3,4,5,6,7,8,9) : set subsecond precision level : + (number of decimal digits after point) + 16 + 9 : 1 ns (9 digits after point) + wReserved2 = ns % 100 : if (8 or 9 digits pecision) + = 0 : if not (8 or 9 digits pecision) + wReserved3 = 0; + filetime +} + +NOTE: TAR-PAX archives created by GNU TAR don't keep + whole information about original level of precision, + and timestamp are stored in reduced form, where tail zero + digits after point are removed. + So 7-Zip can return different precision levels for different items for such TAR archives. +*/ + +/* +TimePrec returned by IOutArchive::GetFileTimeType() +is used only for updating, when we compare MTime timestamp +from archive with timestamp from directory. +*/ + #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/Agent.cpp 7zip-22.01/CPP/7zip/UI/Agent/Agent.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/Agent.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/Agent.cpp 2022-06-03 10:00:00.000000000 +0000 @@ -25,6 +25,10 @@ CCodecs *g_CodecsObj; +static const bool k_keepEmptyDirPrefixes = + false; // 22.00 + // true; // 21.07 + #ifdef EXTERNAL_CODECS CExternalCodecs g_ExternalCodecs; const CExternalCodecs *g_ExternalCodecs_Ptr; @@ -114,9 +118,9 @@ item.Index = i; _items.Add(item); const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; - if (file.DirIndex >= 0) + if (file.DirIndex != -1) LoadFolder(file.DirIndex); - if (_loadAltStreams && file.AltDirIndex >= 0) + if (_loadAltStreams && file.AltDirIndex != -1) LoadFolder(file.AltDirIndex); } return; @@ -211,21 +215,21 @@ unsigned len = 0; while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs) { - const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[proxyIndex].ArcIndex]; + const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex]; len += file.NameLen + 1; - proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream); + proxyIndex = (file.Parent == -1) ? 0 : _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[_proxy2->Dirs[proxyIndex].ArcIndex]; + 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 < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream); + proxyIndex = (file.Parent == -1) ? 0 : _proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream); } } else @@ -327,7 +331,7 @@ /* if (propID == kpidNumAltStreams) { - if (item.AltDirIndex >= 0) + if (item.AltDirIndex != -1) prop = _proxy2->Dirs[item.AltDirIndex].Items.Size(); } else @@ -887,12 +891,12 @@ if (_proxy2) { int index = _proxy2->FindItem(_proxyDirIndex, name, true); - if (index < 0) + if (index == -1) return E_INVALIDARG; return BindToFolder_Internal(_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder); } int index = _proxy->FindSubDir(_proxyDirIndex, name); - if (index < 0) + if (index == -1) return E_INVALIDARG; return BindToFolder_Internal(index, resultFolder); COM_TRY_END @@ -956,7 +960,7 @@ { unsigned arcIndex = _proxy2->Dirs[_proxyDirIndex].ArcIndex; const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (item.AltDirIndex < 0) + if (item.AltDirIndex == -1) return S_OK; altDirIndex = item.AltDirIndex; // parentFolder = _parentFolder; @@ -972,7 +976,7 @@ SET_realIndex_AND_dir_2 unsigned arcIndex = dir->Items[realIndex]; const CProxyFile2 &item = _proxy2->Files[arcIndex]; - if (item.AltDirIndex < 0) + if (item.AltDirIndex == -1) return S_OK; return BindToAltStreams_Internal(item.AltDirIndex, resultFolder); } @@ -1000,7 +1004,7 @@ FOR_VECTOR (i, dir.Items) { const CProxyFile2 &file = _proxy2->Files[dir.Items[i]]; - if (file.AltDirIndex >= 0) + if (file.AltDirIndex != -1) if (CompareFileNames(file.Name, name) == 0) return BindToAltStreams_Internal(file.AltDirIndex, resultFolder); } @@ -1036,7 +1040,7 @@ arcIndex = dir->Items[realIndex]; } - if (_proxy2->Files[arcIndex].AltDirIndex >= 0) + if (_proxy2->Files[arcIndex].AltDirIndex != -1) *isSupported = BoolToInt(true); return S_OK; } @@ -1062,18 +1066,18 @@ else { const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex]; - const CProxyFile2 &file = _proxy2->Files[fold.ArcIndex]; - int parentIndex = file.Parent; - if (parentIndex < 0) + const CProxyFile2 &file = _proxy2->Files[(unsigned)fold.ArcIndex]; + const int parentIndex = file.Parent; + if (parentIndex == -1) proxyDirIndex = k_Proxy2_RootDirIndex; else - proxyDirIndex = _proxy2->Files[parentIndex].DirIndex; + proxyDirIndex = _proxy2->Files[(unsigned)parentIndex].DirIndex; } } else { int parent = _proxy->Dirs[_proxyDirIndex].ParentDir; - if (parent < 0) + if (parent == -1) return S_OK; proxyDirIndex = parent; } @@ -1239,8 +1243,8 @@ const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex]; if (propID == kpidName) { - if (dir.ArcIndex >= 0) - prop = _proxy2->Files[dir.ArcIndex].Name; + if (dir.ArcIndex != -1) + prop = _proxy2->Files[(unsigned)dir.ArcIndex].Name; } else if (propID == kpidPath) { @@ -1477,8 +1481,8 @@ false, // multiArchives pathMode, overwriteMode, - true // keepEmptyDirPrefixes - ); + _zoneMode, + k_keepEmptyDirPrefixes); if (extractCallback2) extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize()); @@ -1500,6 +1504,15 @@ extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon); + extractCallbackSpec->InitBeforeNewArchive(); + + #if defined(_WIN32) && !defined(UNDER_CE) + if (_zoneMode != NExtract::NZoneIdMode::kNone) + { + ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf); + } + #endif + extractCallbackSpec->Init( extractNtOptions, NULL, &_agentSpec->GetArc(), @@ -1645,8 +1658,8 @@ CArc &arc = _archiveLink.Arcs.Back(); if (!inStream) { - arc.MTimeDefined = !fi.IsDevice; - arc.MTime = fi.MTime; + arc.MTime.Set_From_FiTime(fi.MTime); + arc.MTime.Def = !fi.IsDevice; } ArchiveType = GetTypeOfArc(arc); @@ -1783,8 +1796,8 @@ false, // multiArchives pathMode, overwriteMode, - true // keepEmptyDirPrefixes - ); + NExtract::NZoneIdMode::kNone, + k_keepEmptyDirPrefixes); CExtractNtOptions extractNtOptions; extractNtOptions.AltStreams.Val = true; // change it!!! diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/Agent.h 7zip-22.01/CPP/7zip/UI/Agent/Agent.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/Agent.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/Agent.h 2022-06-01 11:00:00.000000000 +0000 @@ -58,7 +58,7 @@ public IArchiveFolder, public IArchiveFolderInternal, public IInArchiveGetStream, - // public IFolderSetReplaceAltStreamCharsMode, + public IFolderSetZoneIdMode, #ifdef NEW_FOLDER_INTERFACE public IFolderOperations, public IFolderSetFlatMode, @@ -78,7 +78,7 @@ MY_QUERYINTERFACE_ENTRY(IArchiveFolder) MY_QUERYINTERFACE_ENTRY(IArchiveFolderInternal) MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream) - // MY_QUERYINTERFACE_ENTRY(IFolderSetReplaceAltStreamCharsMode) + MY_QUERYINTERFACE_ENTRY(IFolderSetZoneIdMode) #ifdef NEW_FOLDER_INTERFACE MY_QUERYINTERFACE_ENTRY(IFolderOperations) MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode) @@ -92,7 +92,7 @@ void GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const; - // INTERFACE_FolderSetReplaceAltStreamCharsMode(;) + INTERFACE_IFolderSetZoneIdMode(;) INTERFACE_FolderFolder(;) INTERFACE_FolderAltStreams(;) @@ -123,6 +123,7 @@ _isAltStreamFolder(false), _flatMode(false), _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now + , _zoneMode(NExtract::NZoneIdMode::kNone) /* , _replaceAltStreamCharsMode(0) */ {} @@ -169,6 +170,7 @@ bool _flatMode; bool _loadAltStreams; // in Flat mode // Int32 _replaceAltStreamCharsMode; + NExtract::NZoneIdMode::EEnum _zoneMode; }; class CAgent: diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/AgentOut.cpp 7zip-22.01/CPP/7zip/UI/Agent/AgentOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/AgentOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/AgentOut.cpp 2022-02-22 06:00:00.000000000 +0000 @@ -12,6 +12,8 @@ #include "../../Common/FileStreams.h" +#include "../../Archive/Common/ItemNameUtils.h" + #include "Agent.h" #include "UpdateCallbackAgent.h" @@ -67,8 +69,8 @@ unsigned arcIndex = item.SubFiles[i]; const CProxyFile &fileItem = agent->_proxy->Files[arcIndex]; CArcItem ai; - RINOK(agent->GetArc().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); - RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); + 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 @@ -83,9 +85,9 @@ if (dirItem.IsLeaf()) { CArcItem ai; - RINOK(agent->GetArc().GetItemMTime(dirItem.ArcIndex, ai.MTime, ai.MTimeDefined)); + RINOK(agent->GetArc().GetItem_MTime(dirItem.ArcIndex, ai.MTime)); ai.IsDir = true; - ai.SizeDefined = false; + ai.Size_Defined = false; ai.Name = fullName; ai.Censored = true; // test it ai.IndexInServer = dirItem.ArcIndex; @@ -111,18 +113,18 @@ ai.IndexInServer = arcIndex; ai.Name = prefix + file.Name; ai.Censored = true; // test it - RINOK(agent->GetArc().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined)); + RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime)); ai.IsDir = file.IsDir(); - ai.SizeDefined = false; + ai.Size_Defined = false; ai.IsAltStream = file.IsAltStream; if (!ai.IsDir) { - RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined)); + RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined)); ai.IsDir = false; } arcItems.Add(ai); - if (file.AltDirIndex >= 0) + if (file.AltDirIndex != -1) { RINOK(EnumerateArchiveItems2(agent, file.AltDirIndex, ai.Name + L':', arcItems)); } @@ -264,10 +266,13 @@ #endif } - NFileTimeType::EEnum fileTimeType; + NFileTimeType::EEnum fileTimeType = NFileTimeType::kNotDefined; UInt32 value; RINOK(outArchive->GetFileTimeType(&value)); - + // we support any future fileType here. + // 22.00: + fileTimeType = (NFileTimeType::EEnum)value; + /* switch (value) { case NFileTimeType::kWindows: @@ -276,8 +281,11 @@ fileTimeType = NFileTimeType::EEnum(value); break; default: + { return E_FAIL; + } } + */ CObjectVector arcItems; @@ -389,11 +397,11 @@ FOR_VECTOR(i, updatePairs2) { const CUpdatePair2 &up = updatePairs2[i]; - if (up.DirIndex >= 0 && up.NewData) + if (up.DirIndex != -1 && up.NewData) { - const CDirItem &di = dirItems.Items[up.DirIndex]; + const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; if (!di.IsDir() && di.Size == 0) - processedItems[up.DirIndex] = 1; + processedItems[(unsigned)up.DirIndex] = 1; } } } @@ -452,7 +460,7 @@ if (curIndex < realIndices.Size()) if (realIndices[curIndex] == i) { - RINOK(GetArc().GetItemPath2(i, deletePath)); + RINOK(GetArc().GetItem_Path2(i, deletePath)); RINOK(updateCallback100->DeleteOperation(deletePath)); curIndex++; @@ -548,11 +556,14 @@ true, // includeFolderSubItemsInFlatMode realIndices); - int mainRealIndex = _agentFolder->GetRealIndex(indices[0]); - - UString fullPrefix = _agentFolder->GetFullPrefix(indices[0]); - UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]); - UString newItemPath = fullPrefix + newItemName; + const UInt32 ind0 = indices[0]; + const int mainRealIndex = _agentFolder->GetRealIndex(ind0); + const UString fullPrefix = _agentFolder->GetFullPrefix(ind0); + UString name = _agentFolder->GetName(ind0); + // 22.00 : we normalize name + NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); + const UString oldItemPath = fullPrefix + name; + const UString newItemPath = fullPrefix + newItemName; UStringVector newNames; @@ -568,10 +579,10 @@ if (realIndices[curIndex] == i) { up2.NewProps = true; - RINOK(GetArc().IsItemAnti(i, up2.IsAnti)); // it must work without that line too. + RINOK(GetArc().IsItem_Anti(i, up2.IsAnti)); // it must work without that line too. UString oldFullPath; - RINOK(GetArc().GetItemPath2(i, oldFullPath)); + RINOK(GetArc().GetItem_Path2(i, oldFullPath)); if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath)) return E_INVALIDARG; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/AgentProxy.cpp 7zip-22.01/CPP/7zip/UI/Agent/AgentProxy.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/AgentProxy.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/AgentProxy.cpp 2022-01-25 08:00:00.000000000 +0000 @@ -18,6 +18,8 @@ #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" +#include "../../Archive/Common/ItemNameUtils.h" + #include "AgentProxy.h" using namespace NWindows; @@ -33,12 +35,12 @@ insertPos = left; return -1; } - unsigned mid = (left + right) / 2; - unsigned dirIndex2 = subDirs[mid]; - int compare = CompareFileNames(name, Dirs[dirIndex2].Name); - if (compare == 0) + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned dirIndex2 = subDirs[mid]; + const int comp = CompareFileNames(name, Dirs[dirIndex2].Name); + if (comp == 0) return dirIndex2; - if (compare < 0) + if (comp < 0) right = mid; else left = mid + 1; @@ -67,12 +69,12 @@ { unsigned insertPos; int subDirIndex = FindSubDir(dirIndex, name, insertPos); - if (subDirIndex >= 0) + if (subDirIndex != -1) { - if (arcIndex >= 0) + if (arcIndex != -1) { - CProxyDir &item = Dirs[subDirIndex]; - if (item.ArcIndex < 0) + CProxyDir &item = Dirs[(unsigned)subDirIndex]; + if (item.ArcIndex == -1) item.ArcIndex = arcIndex; } return subDirIndex; @@ -98,27 +100,31 @@ void CProxyArc::GetDirPathParts(int dirIndex, UStringVector &pathParts) const { pathParts.Clear(); - while (dirIndex >= 0) + while (dirIndex != -1) { const CProxyDir &dir = Dirs[dirIndex]; dirIndex = dir.ParentDir; - if (dirIndex < 0) + if (dirIndex == -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(int dirIndex) const { UString s; - while (dirIndex >= 0) + while (dirIndex != -1) { const CProxyDir &dir = Dirs[dirIndex]; dirIndex = dir.ParentDir; - if (dirIndex < 0) + if (dirIndex == -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)); } return s; } @@ -251,7 +257,7 @@ { if (progress && (i & 0xFFFF) == 0) { - UInt64 currentItemIndex = i; + const UInt64 currentItemIndex = i; RINOK(progress->SetCompleted(¤tItemIndex)); } @@ -259,9 +265,9 @@ unsigned len = 0; bool isPtrName = false; - #if WCHAR_PATH_SEPARATOR != L'/' - wchar_t replaceFromChar = 0; - #endif + #if WCHAR_PATH_SEPARATOR != L'/' + wchar_t separatorChar = WCHAR_PATH_SEPARATOR; + #endif #if defined(MY_CPU_LE) && defined(_WIN32) // it works only if (sizeof(wchar_t) == 2) @@ -278,9 +284,9 @@ len = size / 2 - 1; s = (const wchar_t *)p; isPtrName = true; - #if WCHAR_PATH_SEPARATOR != L'/' - replaceFromChar = L'\\'; - #endif + #if WCHAR_PATH_SEPARATOR != L'/' + separatorChar = L'/'; // 0 + #endif } } if (!s) @@ -297,7 +303,7 @@ return E_FAIL; if (len == 0) { - RINOK(arc.GetDefaultItemPath(i, path)); + RINOK(arc.GetItem_DefaultPath(i, path)); len = path.Len(); s = path; } @@ -328,16 +334,12 @@ for (unsigned j = 0; j < len; j++) { const wchar_t c = s[j]; - if (c == WCHAR_PATH_SEPARATOR || c == L'/') - { + if (c == L'/' #if WCHAR_PATH_SEPARATOR != L'/' - if (c == replaceFromChar) - { - // s.ReplaceOneCharAtPos(j, WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT); - continue; - } + || (c == separatorChar) #endif - + ) + { const unsigned kLevelLimit = 1 << 10; if (numLevels <= kLevelLimit) { @@ -345,6 +347,8 @@ name = "[LONG_PATH]"; 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); } namePos = j + 1; @@ -384,6 +388,8 @@ if (isDir) { name = s; + // 22.00: we can normalize dir here + // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name); AddDir(curItem, (int)i, name); } else @@ -418,14 +424,14 @@ while (dirIndex >= (int)k_Proxy2_NumRootDirs) { const CProxyDir2 &dir = Dirs[dirIndex]; - const CProxyFile2 &file = Files[dir.ArcIndex]; + const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; if (pathParts.IsEmpty() && dirIndex == file.AltDirIndex) isAltStreamDir = true; pathParts.Insert(0, file.Name); int par = file.Parent; - if (par < 0) + if (par == -1) break; - dirIndex = Files[par].DirIndex; + dirIndex = Files[(unsigned)par].DirIndex; } } @@ -436,7 +442,7 @@ if (dirIndex == k_Proxy2_AltRootDirIndex) return true; const CProxyDir2 &dir = Dirs[dirIndex]; - const CProxyFile2 &file = Files[dir.ArcIndex]; + const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; return ((int)dirIndex == file.AltDirIndex); } @@ -448,7 +454,7 @@ isAltStreamDir = true; else if (dirIndex >= k_Proxy2_NumRootDirs) { - const CProxyFile2 &file = Files[dir.ArcIndex]; + const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex]; isAltStreamDir = ((int)dirIndex == file.AltDirIndex); } return dir.PathPrefix; @@ -458,9 +464,9 @@ { realIndices.Add(arcIndex); const CProxyFile2 &file = Files[arcIndex]; - if (file.DirIndex >= 0) + if (file.DirIndex != -1) AddRealIndices_of_Dir(file.DirIndex, includeAltStreams, realIndices); - if (includeAltStreams && file.AltDirIndex >= 0) + if (includeAltStreams && file.AltDirIndex != -1) AddRealIndices_of_Dir(file.AltDirIndex, includeAltStreams, realIndices); } @@ -520,15 +526,18 @@ } const CProxyFile2 &subFile = Files[index]; - if (subFile.DirIndex < 0) + if (subFile.DirIndex == -1) { dir.NumSubFiles++; } else { + // 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 + subFile.Name + WCHAR_PATH_SEPARATOR; + f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR; CalculateSizes(subFile.DirIndex, archive); dir.Size += f.Size; dir.PackSize += f.PackSize; @@ -539,7 +548,7 @@ dir.CrcIsDefined = false; } - if (subFile.AltDirIndex < 0) + if (subFile.AltDirIndex == -1) { // dir.NumSubFiles++; } @@ -688,12 +697,12 @@ if (file.IsAltStream) { - if (file.Parent < 0) + if (file.Parent == -1) dirIndex = k_Proxy2_AltRootDirIndex; else { - int &folderIndex2 = Files[file.Parent].AltDirIndex; - if (folderIndex2 < 0) + int &folderIndex2 = Files[(unsigned)file.Parent].AltDirIndex; + if (folderIndex2 == -1) { folderIndex2 = Dirs.Size(); CProxyDir2 &dir = Dirs.AddNew(); @@ -704,12 +713,12 @@ } else { - if (file.Parent < 0) + if (file.Parent == -1) dirIndex = k_Proxy2_RootDirIndex; else { - dirIndex = Files[file.Parent].DirIndex; - if (dirIndex < 0) + dirIndex = Files[(unsigned)file.Parent].DirIndex; + if (dirIndex == -1) return E_FAIL; } } @@ -731,7 +740,7 @@ FOR_VECTOR (i, dir.Items) { const CProxyFile2 &file = Files[dir.Items[i]]; - if (foldersOnly && file.DirIndex < 0) + if (foldersOnly && file.DirIndex == -1) continue; if (CompareFileNames(file.Name, name) == 0) return i; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/AgentProxy.h 7zip-22.01/CPP/7zip/UI/Agent/AgentProxy.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/AgentProxy.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/AgentProxy.h 2022-01-08 19:00:00.000000000 +0000 @@ -38,7 +38,7 @@ ~CProxyDir() { delete [](wchar_t *)(void *)Name; } void Clear(); - bool IsLeaf() const { return ArcIndex >= 0; } + bool IsLeaf() const { return ArcIndex != -1; } }; class CProxyArc @@ -82,7 +82,7 @@ int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; } - bool IsDir() const { return DirIndex >= 0; } + bool IsDir() const { return DirIndex != -1; } CProxyFile2(): DirIndex(-1), AltDirIndex(-1), Parent(-1), Name(NULL), NameLen(0), @@ -145,7 +145,7 @@ { const CProxyFile2 &file = Files[arcIndex]; - if (file.Parent < 0) + if (file.Parent == -1) return file.IsAltStream ? k_Proxy2_AltRootDirIndex : k_Proxy2_RootDirIndex; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/ArchiveFolder.cpp 7zip-22.01/CPP/7zip/UI/Agent/ArchiveFolder.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/ArchiveFolder.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/ArchiveFolder.cpp 2022-06-01 11:00:00.000000000 +0000 @@ -16,6 +16,12 @@ } */ +STDMETHODIMP CAgentFolder::SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode) +{ + _zoneMode = zoneMode; + return S_OK; +} + STDMETHODIMP CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, const wchar_t *path, IFolderOperationsExtractCallback *callback) diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp 7zip-22.01/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp 2022-01-08 19:00:00.000000000 +0000 @@ -210,7 +210,7 @@ FOR_VECTOR (i, pathParts) { int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]); - if (next < 0) + if (next == -1) break; _proxyDirIndex = next; } @@ -226,7 +226,7 @@ { bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder); int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly); - if (index < 0) + if (index == -1) break; const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]]; @@ -235,7 +235,7 @@ _proxyDirIndex = file.DirIndex; else { - if (file.AltDirIndex >= 0) + if (file.AltDirIndex != -1) _proxyDirIndex = file.AltDirIndex; break; } @@ -351,7 +351,7 @@ } else { - if (_proxy->FindSubDir(_proxyDirIndex, name) >= 0) + if (_proxy->FindSubDir(_proxyDirIndex, name) != -1) return ERROR_ALREADY_EXISTS; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Agent/IFolderArchive.h 7zip-22.01/CPP/7zip/UI/Agent/IFolderArchive.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Agent/IFolderArchive.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Agent/IFolderArchive.h 2022-06-01 11:00:00.000000000 +0000 @@ -116,4 +116,13 @@ INTERFACE_IFolderScanProgress(PURE) }; + +#define INTERFACE_IFolderSetZoneIdMode(x) \ + STDMETHOD(SetZoneIdMode)(NExtract::NZoneIdMode::EEnum zoneMode) x; \ + +FOLDER_ARCHIVE_INTERFACE(IFolderSetZoneIdMode, 0x12) +{ + INTERFACE_IFolderSetZoneIdMode(PURE) +}; + #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Client7z/Client7z.cpp 7zip-22.01/CPP/7zip/UI/Client7z/Client7z.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Client7z/Client7z.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Client7z/Client7z.cpp 2022-05-18 12:00:00.000000000 +0000 @@ -33,17 +33,29 @@ HINSTANCE g_hInstance = 0; #endif -// You can find the list of all GUIDs in Guid.txt file. -// use another CLSIDs, if you want to support other formats (zip, rar, ...). -// {23170F69-40C1-278A-1000-000110070000} - -DEFINE_GUID(CLSID_CFormat7z, - 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); -DEFINE_GUID(CLSID_CFormatXz, - 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x0C, 0x00, 0x00); +// You can find full list of all GUIDs supported by 7-Zip in Guid.txt file. +// 7z format GUID: {23170F69-40C1-278A-1000-000110070000} -#define CLSID_Format CLSID_CFormat7z -// #define CLSID_Format CLSID_CFormatXz +#define DEFINE_GUID_ARC(name, id) DEFINE_GUID(name, \ + 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00); + +enum +{ + kId_Zip = 1, + kId_BZip2 = 2, + kId_7z = 7, + kId_Xz = 0xC, + kId_Tar = 0xEE, + kId_GZip = 0xEF +}; + +// use another id, if you want to support other formats (zip, Xz, ...). +// DEFINE_GUID_ARC (CLSID_Format, kId_Zip) +// DEFINE_GUID_ARC (CLSID_Format, kId_BZip2) +// DEFINE_GUID_ARC (CLSID_Format, kId_Xz) +// DEFINE_GUID_ARC (CLSID_Format, kId_Tar) +// DEFINE_GUID_ARC (CLSID_Format, kId_GZip) +DEFINE_GUID_ARC (CLSID_Format, kId_7z) using namespace NWindows; using namespace NFile; @@ -229,6 +241,86 @@ static const char * const kHeadersError = "Headers Error"; +struct CArcTime +{ + FILETIME FT; + UInt16 Prec; + Byte Ns100; + bool Def; + + CArcTime() + { + Clear(); + } + + void Clear() + { + FT.dwHighDateTime = FT.dwLowDateTime = 0; + Prec = 0; + Ns100 = 0; + Def = false; + } + + bool IsZero() const + { + return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0; + } + + int GetNumDigits() const + { + if (Prec == k_PropVar_TimePrec_Unix || + Prec == k_PropVar_TimePrec_DOS) + return 0; + if (Prec == k_PropVar_TimePrec_HighPrec) + return 9; + if (Prec == k_PropVar_TimePrec_0) + return 7; + int digits = (int)Prec - (int)k_PropVar_TimePrec_Base; + if (digits < 0) + digits = 0; + return digits; + } + + void Write_To_FiTime(CFiTime &dest) const + { + #ifdef _WIN32 + dest = FT; + #else + if (FILETIME_To_timespec(FT, dest)) + if ((Prec == k_PropVar_TimePrec_Base + 8 || + Prec == k_PropVar_TimePrec_Base + 9) + && Ns100 != 0) + { + dest.tv_nsec += Ns100; + } + #endif + } + + void Set_From_Prop(const PROPVARIANT &prop) + { + FT = prop.filetime; + unsigned prec = 0; + unsigned ns100 = 0; + const unsigned prec_Temp = prop.wReserved1; + if (prec_Temp != 0 + && prec_Temp <= k_PropVar_TimePrec_1ns + && prop.wReserved3 == 0) + { + const unsigned ns100_Temp = prop.wReserved2; + if (ns100_Temp < 100) + { + ns100 = ns100_Temp; + prec = prec_Temp; + } + } + Prec = (UInt16)prec; + Ns100 = (Byte)ns100; + Def = true; + } +}; + + + class CArchiveExtractCallback: public IArchiveExtractCallback, public ICryptoGetTextPassword, @@ -257,11 +349,10 @@ bool _extractMode; struct CProcessedFileInfo { - FILETIME MTime; + CArcTime MTime; UInt32 Attrib; bool isDir; - bool AttribDefined; - bool MTimeDefined; + bool Attrib_Defined; } _processedFileInfo; COutFileStream *_outFileStreamSpec; @@ -328,32 +419,31 @@ if (prop.vt == VT_EMPTY) { _processedFileInfo.Attrib = 0; - _processedFileInfo.AttribDefined = false; + _processedFileInfo.Attrib_Defined = false; } else { if (prop.vt != VT_UI4) return E_FAIL; _processedFileInfo.Attrib = prop.ulVal; - _processedFileInfo.AttribDefined = true; + _processedFileInfo.Attrib_Defined = true; } } RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir)); { + _processedFileInfo.MTime.Clear(); // Get Modified Time NCOM::CPropVariant prop; RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop)); - _processedFileInfo.MTimeDefined = false; switch (prop.vt) { case VT_EMPTY: // _processedFileInfo.MTime = _utcMTimeDefault; break; case VT_FILETIME: - _processedFileInfo.MTime = prop.filetime; - _processedFileInfo.MTimeDefined = true; + _processedFileInfo.MTime.Set_From_Prop(prop); break; default: return E_FAIL; @@ -483,12 +573,16 @@ if (_outFileStream) { - if (_processedFileInfo.MTimeDefined) - _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime); + if (_processedFileInfo.MTime.Def) + { + CFiTime ft; + _processedFileInfo.MTime.Write_To_FiTime(ft); + _outFileStreamSpec->SetMTime(&ft); + } RINOK(_outFileStreamSpec->Close()); } _outFileStream.Release(); - if (_extractMode && _processedFileInfo.AttribDefined) + if (_extractMode && _processedFileInfo.Attrib_Defined) SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib); PrintNewLine(); return S_OK; @@ -513,17 +607,14 @@ ////////////////////////////////////////////////////////////// // Archive Creating callback class -struct CDirItem +struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase { - UInt64 Size; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; - UString Name; - FString FullPath; - UInt32 Attrib; + UString Path_For_Handler; + FString FullPath; // for filesystem - bool isDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; } + CDirItem(const NWindows::NFile::NFind::CFileInfo &fi): + CFileInfoBase(fi) + {} }; class CArchiveUpdateCallback: @@ -618,16 +709,17 @@ } { - const CDirItem &dirItem = (*DirItems)[index]; + const CDirItem &di = (*DirItems)[index]; switch (propID) { - case kpidPath: prop = dirItem.Name; break; - case kpidIsDir: prop = dirItem.isDir(); break; - case kpidSize: prop = dirItem.Size; break; - case kpidAttrib: prop = dirItem.Attrib; break; - case kpidCTime: prop = dirItem.CTime; break; - case kpidATime: prop = dirItem.ATime; break; - case kpidMTime: prop = dirItem.MTime; break; + case kpidPath: prop = di.Path_For_Handler; break; + case kpidIsDir: prop = di.IsDir(); break; + case kpidSize: prop = di.Size; break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break; + case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break; + case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break; } } prop.Detach(value); @@ -657,9 +749,9 @@ RINOK(Finilize()); const CDirItem &dirItem = (*DirItems)[index]; - GetStream2(dirItem.Name); + GetStream2(dirItem.Path_For_Handler); - if (dirItem.isDir()) + if (dirItem.IsDir()) return S_OK; { @@ -848,7 +940,6 @@ unsigned i; for (i = 1; i < params.Size(); i++) { - CDirItem di; const FString &name = params[i]; NFind::CFileInfo fi; @@ -857,13 +948,10 @@ PrintError("Can't find file", name); return 1; } + + CDirItem di(fi); - di.Attrib = fi.Attrib; - di.Size = fi.Size; - di.CTime = fi.CTime; - di.ATime = fi.ATime; - di.MTime = fi.MTime; - di.Name = fs2us(name); + di.Path_For_Handler = fs2us(name); di.FullPath = name; dirItems.Add(di); } @@ -894,12 +982,14 @@ { const wchar_t *names[] = { + L"m", L"s", L"x" }; const unsigned kNumProps = ARRAY_SIZE(names); NCOM::CPropVariant values[kNumProps] = { + L"lzma", false, // solid mode OFF (UInt32)9 // compression level = 9 - ultra }; @@ -910,7 +1000,11 @@ PrintError("ISetProperties unsupported"); return 1; } - RINOK(setProperties->SetProperties(names, values, kNumProps)); + if (setProperties->SetProperties(names, values, kNumProps) != S_OK) + { + PrintError("SetProperties() error"); + return 1; + } } */ @@ -1035,7 +1129,13 @@ CMyComPtr setProperties; archive->QueryInterface(IID_ISetProperties, (void **)&setProperties); if (setProperties) - setProperties->SetProperties(names, values, kNumProps); + { + if (setProperties->SetProperties(names, values, kNumProps) != S_OK) + { + PrintError("SetProperties() error"); + return 1; + } + } */ HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Client7z/makefile.gcc 7zip-22.01/CPP/7zip/UI/Client7z/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/UI/Client7z/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Client7z/makefile.gcc 2022-07-15 12:00:00.000000000 +0000 @@ -6,6 +6,16 @@ ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + + +ifdef IS_MINGW SYS_OBJS = \ $O/resource.o \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.cpp 7zip-22.01/CPP/7zip/UI/Common/ArchiveCommandLine.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ArchiveCommandLine.cpp 2022-06-01 11:00:00.000000000 +0000 @@ -160,7 +160,11 @@ kSymLinks_AllowDangerous, kSymLinks, kNtSecurity, + + kStoreOwnerId, + kStoreOwnerName, + kZoneFile, kAltStreams, kReplaceColonForAltStream, kWriteToAltStreamIfColon, @@ -304,7 +308,11 @@ { "snld", SWFRM_MINUS }, { "snl", SWFRM_MINUS }, { "sni", SWFRM_SIMPLE }, + + { "snoi", SWFRM_MINUS }, + { "snon", SWFRM_MINUS }, + { "snz", SWFRM_STRING_SINGL(0) }, { "sns", SWFRM_MINUS }, { "snr", SWFRM_SIMPLE }, { "snc", SWFRM_SIMPLE }, @@ -1032,9 +1040,9 @@ if (parser[NKey::kCaseSensitive].ThereIs) { + options.CaseSensitive = g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus; - options.CaseSensitiveChange = true; - options.CaseSensitive = g_CaseSensitive; + options.CaseSensitive_Change = true; } @@ -1367,6 +1375,9 @@ SetBoolPair(parser, NKey::kAltStreams, options.AltStreams); SetBoolPair(parser, NKey::kHardLinks, options.HardLinks); SetBoolPair(parser, NKey::kSymLinks, options.SymLinks); + + SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId); + SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName); CBoolPair symLinks_AllowDangerous; SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous); @@ -1420,12 +1431,28 @@ nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs; nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs; + nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName + if (parser[NKey::kPreserveATime].ThereIs) nt.PreserveATime = true; if (parser[NKey::kShareForWrite].ThereIs) nt.OpenShareForWrite = true; } - + + if (parser[NKey::kZoneFile].ThereIs) + { + eo.ZoneMode = NExtract::NZoneIdMode::kAll; + const UString &s = parser[NKey::kZoneFile].PostStrings[0]; + if (!s.IsEmpty()) + { + if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone; + else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll; + else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice; + else + throw CArcCmdLineException("Unsupported -snz:", s); + } + } + options.Censor.AddPathsToCensor(NWildcard::k_AbsPath); options.Censor.ExtendExclude(); @@ -1549,6 +1576,9 @@ updateOptions.NtSecurity = options.NtSecurity; updateOptions.HardLinks = options.HardLinks; updateOptions.SymLinks = options.SymLinks; + + updateOptions.StoreOwnerId = options.StoreOwnerId; + updateOptions.StoreOwnerName = options.StoreOwnerName; updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; if (updateOptions.EMailMode) diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.h 7zip-22.01/CPP/7zip/UI/Common/ArchiveCommandLine.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveCommandLine.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ArchiveCommandLine.h 2022-04-17 12:00:00.000000000 +0000 @@ -51,7 +51,7 @@ bool HelpMode; // bool LargePages; - bool CaseSensitiveChange; + bool CaseSensitive_Change; bool CaseSensitive; bool IsInTerminal; @@ -97,6 +97,9 @@ CBoolPair AltStreams; CBoolPair HardLinks; CBoolPair SymLinks; + + CBoolPair StoreOwnerId; + CBoolPair StoreOwnerName; CUpdateOptions UpdateOptions; CHashOptions HashOptions; @@ -117,7 +120,7 @@ CArcCmdLineOptions(): HelpMode(false), // LargePages(false), - CaseSensitiveChange(false), + CaseSensitive_Change(false), CaseSensitive(false), IsInTerminal(false), diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp 7zip-22.01/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp 2022-06-09 13:00:00.000000000 +0000 @@ -95,6 +95,83 @@ #endif // _USE_SECURITY_CODE + +#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) + +static const char * const kOfficeExtensions = + " doc dot wbk" + " docx docm dotx dotm docb wll wwl" + " xls xlt xlm" + " xlsx xlsm xltx xltm xlsb xla xlam" + " ppt pot pps ppa ppam" + " pptx pptm potx potm ppam ppsx ppsm sldx sldm" + " "; + +static bool FindExt2(const char *p, const UString &name) +{ + const int pathPos = name.ReverseFind_PathSepar(); + const int dotPos = name.ReverseFind_Dot(); + if (dotPos < 0 + || dotPos < pathPos + || dotPos == (int)name.Len() - 1) + return false; + + AString s; + for (unsigned pos = dotPos + 1;; pos++) + { + const wchar_t c = name[pos]; + if (c <= 0) + break; + if (c >= 0x80) + return false; + s += (char)MyCharLower_Ascii((char)c); + } + for (unsigned i = 0; p[i] != 0;) + { + unsigned j; + for (j = i; p[j] != ' '; j++); + if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0) + return true; + i = j + 1; + } + return false; +} + + +static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); + +void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf) +{ + FString fileName = fileName2; + fileName += k_ZoneId_StreamName; + + buf.Free(); + NIO::CInFile file; + if (!file.Open(fileName)) + return; + UInt64 fileSize; + if (!file.GetLength(fileSize)) + return; + if (fileSize == 0 || fileSize >= ((UInt32)1 << 16)) + return; + buf.Alloc((size_t)fileSize); + size_t processed; + if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize) + return; + buf.Free(); +} + +static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf) +{ + NIO::COutFile file; + if (!file.Create(fileName, true)) + return false; + return file.WriteFull(buf, buf.Size()); +} + +#endif + + #ifdef SUPPORT_LINKS int CHardLinkNode::Compare(const CHardLinkNode &a) const @@ -190,9 +267,9 @@ CArchiveExtractCallback::CArchiveExtractCallback(): _arc(NULL), - WriteCTime(true), - WriteATime(true), - WriteMTime(true), + Write_CTime(true), + Write_ATime(true), + Write_MTime(true), _multiArchives(false) { LocalProgressSpec = new CLocalProgress(); @@ -204,6 +281,13 @@ } +void CArchiveExtractCallback::InitBeforeNewArchive() +{ + #if defined(_WIN32) && !defined(UNDER_CE) + ZoneBuf.Free(); + #endif +} + void CArchiveExtractCallback::Init( const CExtractNtOptions &ntOptions, const NWildcard::CCensorNode *wildcardCensor, @@ -240,13 +324,19 @@ _progressTotal_Defined = true; _extractCallback2 = extractCallback2; + _compressProgress.Release(); _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); + + _callbackMessage.Release(); _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage); + + _folderArchiveExtractCallback2.Release(); _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); #ifndef _SFX + ExtractToStreamCallback.Release(); _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); if (ExtractToStreamCallback) { @@ -416,26 +506,22 @@ } -HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) +HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, CArcTime &ft) { - filetimeIsDefined = false; - filetime.dwLowDateTime = 0; - filetime.dwHighDateTime = 0; + ft.Clear(); NCOM::CPropVariant prop; RINOK(_arc->Archive->GetProperty(index, propID, &prop)); if (prop.vt == VT_FILETIME) - { - filetime = prop.filetime; - filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); - } + ft.Set_From_Prop(prop); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } + HRESULT CArchiveExtractCallback::GetUnpackSize() { - return _arc->GetItemSize(_index, _curSize, _curSizeDefined); + return _arc->GetItem_Size(_index, _curSize, _curSizeDefined); } static void AddPathToMessage(UString &s, const FString &path) @@ -454,8 +540,9 @@ HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) { DWORD errorCode = GetLastError(); + if (errorCode == 0) + errorCode = (DWORD)E_FAIL; UString s (message); - if (errorCode != 0) { s += " : "; s += NError::MyFormatMessage(errorCode); @@ -843,13 +930,58 @@ #endif // SUPPORT_LINKS +#ifndef _WIN32 + +static HRESULT GetOwner(IInArchive *archive, + UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res) +{ + { + NWindows::NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, pidId, &prop)); + if (prop.vt == VT_UI4) + { + res.Id_Defined = true; + res.Id = prop.ulVal; // for debug + // res.Id++; // for debug + // if (pidId == kpidGroupId) res.Id += 7; // for debug + // res.Id = 0; // for debug + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + { + NWindows::NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, pidName, &prop)); + if (prop.vt == VT_BSTR) + { + const UString s = prop.bstrVal; + ConvertUnicodeToUTF8(s, res.Name); + } + else if (prop.vt == VT_UI4) + { + res.Id_Defined = true; + res.Id = prop.ulVal; + } + else if (prop.vt != VT_EMPTY) + return E_INVALIDARG; + } + return S_OK; +} + +#endif + HRESULT CArchiveExtractCallback::Read_fi_Props() { IInArchive *archive = _arc->Archive; const UInt32 index = _index; - _fi.AttribDefined = false; + _fi.Attrib_Defined = false; + + #ifndef _WIN32 + _fi.Owner.Clear(); + _fi.Group.Clear(); + #endif { NCOM::CPropVariant prop; @@ -868,15 +1000,25 @@ if (prop.vt == VT_UI4) { _fi.Attrib = prop.ulVal; - _fi.AttribDefined = true; + _fi.Attrib_Defined = true; } else if (prop.vt != VT_EMPTY) return E_FAIL; } - RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined)); - RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined)); - RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined)); + RINOK(GetTime(index, kpidCTime, _fi.CTime)); + RINOK(GetTime(index, kpidATime, _fi.ATime)); + RINOK(GetTime(index, kpidMTime, _fi.MTime)); + + #ifndef _WIN32 + if (_ntOptions.ExtractOwner) + { + // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath); + GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner); + GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group); + } + #endif + return S_OK; } @@ -923,6 +1065,39 @@ } +void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt) +{ + pt.CTime_Defined = false; + pt.ATime_Defined = false; + pt.MTime_Defined = false; + + if (Write_MTime) + { + if (_fi.MTime.Def) + { + _fi.MTime.Write_To_FiTime(pt.MTime); + pt.MTime_Defined = true; + } + else if (_arc->MTime.Def) + { + _arc->MTime.Write_To_FiTime(pt.MTime); + pt.MTime_Defined = true; + } + } + + if (Write_CTime && _fi.CTime.Def) + { + _fi.CTime.Write_To_FiTime(pt.CTime); + pt.CTime_Defined = true; + } + + if (Write_ATime && _fi.ATime.Def) + { + _fi.ATime.Write_To_FiTime(pt.ATime); + pt.ATime_Defined = true; + } +} + void CArchiveExtractCallback::CreateFolders() { @@ -948,30 +1123,9 @@ return; CDirPathTime pt; - - pt.CTime = _fi.CTime; - pt.CTimeDefined = (WriteCTime && _fi.CTimeDefined); - - pt.ATime = _fi.ATime; - pt.ATimeDefined = (WriteATime && _fi.ATimeDefined); - - pt.MTimeDefined = false; - - if (WriteMTime) - { - if (_fi.MTimeDefined) - { - pt.MTime = _fi.MTime; - pt.MTimeDefined = true; - } - else if (_arc->MTimeDefined) - { - pt.MTime = _arc->MTime; - pt.MTimeDefined = true; - } - } - - if (pt.MTimeDefined || pt.ATimeDefined || pt.CTimeDefined) + GetFiTimesCAM(pt); + + if (pt.IsSomeTimeDefined()) { pt.Path = fullPathNew; pt.SetDirTime(); @@ -1006,10 +1160,13 @@ /* (fileInfo) can be symbolic link. we can show final file properties here. */ + FILETIME ft1; + FiTime_To_FILETIME(fileInfo.MTime, ft1); + Int32 overwriteResult; RINOK(_extractCallback2->AskOverwrite( - fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, _item.Path, - _fi.MTimeDefined ? &_fi.MTime : NULL, + fs2us(realFullProcessedPath), &ft1, &fileInfo.Size, _item.Path, + _fi.MTime.Def ? &_fi.MTime.FT : NULL, _curSizeDefined ? &_curSize : NULL, &overwriteResult)) @@ -1126,7 +1283,7 @@ const UInt32 index = _index; bool isAnti = false; - RINOK(_arc->IsItemAnti(index, isAnti)); + RINOK(_arc->IsItem_Anti(index, isAnti)); CorrectPathParts(); UString processedPath (MakePathFromParts(_item.PathParts)); @@ -1147,8 +1304,8 @@ #ifdef SUPPORT_ALT_STREAMS if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1) { - int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex)); - if (renIndex >= 0) + const int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex)); + if (renIndex != -1) { const CIndexToPathPair &pair = _renamedFiles[(unsigned)renIndex]; fullProcessedPath = pair.Path; @@ -1224,8 +1381,8 @@ RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)); if (defined) { - int linkIndex = _hardLinks.IDs.FindInSorted2(h); - if (linkIndex >= 0) + const int linkIndex = _hardLinks.IDs.FindInSorted2(h); + if (linkIndex != -1) { FString &hl = _hardLinks.Links[(unsigned)linkIndex]; if (hl.IsEmpty()) @@ -1733,11 +1890,34 @@ _curSize = processedSize; _curSizeDefined = true; + #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) + if (ZoneBuf.Size() != 0 + && !_item.IsAltStream) + { + // if (NFind::DoesFileExist_Raw(tempFilePath)) + if (ZoneMode != NExtract::NZoneIdMode::kOffice || + FindExt2(kOfficeExtensions, _diskFilePath)) + { + // we must write zone file before setting of timestamps + const FString path = _diskFilePath + k_ZoneId_StreamName; + if (!WriteZoneFile(path, ZoneBuf)) + { + // we can't write it in FAT + // SendMessageError_with_LastError("Can't write Zone.Identifier stream", path); + } + } + } + #endif + + CFiTimesCAM t; + GetFiTimesCAM(t); + // #ifdef _WIN32 - _outFileStreamSpec->SetTime( - (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, - (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, - (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); + if (t.IsSomeTimeDefined()) + _outFileStreamSpec->SetTime( + t.CTime_Defined ? &t.CTime : NULL, + t.ATime_Defined ? &t.ATime : NULL, + t.MTime_Defined ? &t.MTime : NULL); // #endif RINOK(_outFileStreamSpec->Close()); @@ -2065,19 +2245,30 @@ void CArchiveExtractCallback::SetAttrib() { - #ifndef _WIN32 + #ifndef _WIN32 // Linux now doesn't support permissions for symlinks if (_isSymLinkCreated) return; - #endif + #endif if (_itemFailure || _diskFilePath.IsEmpty() || _stdOutMode - || !_extractMode - || !_fi.AttribDefined) + || !_extractMode) return; - + + #ifndef _WIN32 + if (_fi.Owner.Id_Defined && + _fi.Group.Id_Defined) + { + if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0) + { + SendMessageError_with_LastError("Cannot set owner", _diskFilePath); + } + } + #endif + + if (_fi.Attrib_Defined) { // const AString s = GetAnsiString(_diskFilePath); // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib); @@ -2276,7 +2467,7 @@ CInFileStream *inStreamSpec = new CInFileStream; CMyComPtr inStreamRef = inStreamSpec; - inStreamSpec->File.PreserveATime = _ntOptions.PreserveATime; + inStreamSpec->Set_PreserveATime(_ntOptions.PreserveATime); if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite)) { RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath)); @@ -2318,9 +2509,9 @@ bool CDirPathTime::SetDirTime() const { return NDir::SetDirTime(Path, - CTimeDefined ? &CTime : NULL, - ATimeDefined ? &ATime : NULL, - MTimeDefined ? &MTime : NULL); + CTime_Defined ? &CTime : NULL, + ATime_Defined ? &ATime : NULL, + MTime_Defined ? &MTime : NULL); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 7zip-22.01/CPP/7zip/UI/Common/ArchiveExtractCallback.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ArchiveExtractCallback.h 2022-06-09 16:00:00.000000000 +0000 @@ -60,6 +60,8 @@ bool ReplaceColonForAltStream; bool WriteToAltStreamIfColon; + bool ExtractOwner; + bool PreAllocateOutFile; // used for hash arcs only, when we open external files @@ -69,6 +71,7 @@ CExtractNtOptions(): ReplaceColonForAltStream(false), WriteToAltStreamIfColon(false), + ExtractOwner(false), PreserveATime(false), OpenShareForWrite(false) { @@ -163,16 +166,27 @@ -struct CDirPathTime +struct CFiTimesCAM { - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; - - bool CTimeDefined; - bool ATimeDefined; - bool MTimeDefined; + CFiTime CTime; + CFiTime ATime; + CFiTime MTime; + + bool CTime_Defined; + bool ATime_Defined; + bool MTime_Defined; + + bool IsSomeTimeDefined() const + { + return + CTime_Defined | + ATime_Defined | + MTime_Defined; + } +}; +struct CDirPathTime: public CFiTimesCAM +{ FString Path; bool SetDirTime() const; @@ -216,6 +230,25 @@ #endif // SUPPORT_LINKS +#ifndef _WIN32 + +struct COwnerInfo +{ + bool Id_Defined; + UInt32 Id; + AString Name; + + void Clear() + { + Id_Defined = false; + Id = 0; + Name.Empty(); + } +}; + +#endif + + class CArchiveExtractCallback: public IArchiveExtractCallback, public IArchiveExtractCallbackMessage, @@ -256,32 +289,33 @@ bool _extractMode; - bool WriteCTime; - bool WriteATime; - bool WriteMTime; + bool Write_CTime; + bool Write_ATime; + bool Write_MTime; bool _encrypted; struct CProcessedFileInfo { - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; + CArcTime CTime; + CArcTime ATime; + CArcTime MTime; UInt32 Attrib; - - bool CTimeDefined; - bool ATimeDefined; - bool MTimeDefined; - bool AttribDefined; + bool Attrib_Defined; + + #ifndef _WIN32 + COwnerInfo Owner; + COwnerInfo Group; + #endif bool IsReparse() const { - return (AttribDefined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); + return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0); } bool IsLinuxSymLink() const { - return (AttribDefined && MY_LIN_S_ISLNK(Attrib >> 16)); + return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16)); } void SetFromPosixAttrib(UInt32 a) @@ -294,10 +328,14 @@ FILE_ATTRIBUTE_ARCHIVE; if ((a & 0222) == 0) // (& S_IWUSR) in p7zip Attrib |= FILE_ATTRIBUTE_READONLY; + // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink() + a &= MY_LIN_S_IFMT; + if (a == MY_LIN_S_IFLNK) + Attrib |= (a << 16); #else Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION; #endif - AttribDefined = true; + Attrib_Defined = true; } } _fi; @@ -359,7 +397,7 @@ #endif void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath); - HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined); + HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft); HRESULT GetUnpackSize(); FString Hash_GetFullFilePath(); @@ -372,6 +410,10 @@ HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2); public: + #if defined(_WIN32) && !defined(UNDER_CE) + NExtract::NZoneIdMode::EEnum ZoneMode; + CByteBuffer ZoneBuf; + #endif CLocalProgress *LocalProgressSpec; @@ -405,11 +447,17 @@ void InitForMulti(bool multiArchives, NExtract::NPathMode::EEnum pathMode, NExtract::NOverwriteMode::EEnum overwriteMode, + NExtract::NZoneIdMode::EEnum zoneMode, bool keepAndReplaceEmptyDirPrefixes) { _multiArchives = multiArchives; _pathMode = pathMode; _overwriteMode = overwriteMode; + #if defined(_WIN32) && !defined(UNDER_CE) + ZoneMode = zoneMode; + #else + UNUSED_VAR(zoneMode) + #endif _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes; NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0; } @@ -427,6 +475,8 @@ #endif + void InitBeforeNewArchive(); + void Init( const CExtractNtOptions &ntOptions, const NWildcard::CCensorNode *wildcardCensor, @@ -483,6 +533,7 @@ HRESULT Read_fi_Props(); void CorrectPathParts(); + void GetFiTimesCAM(CFiTimesCAM &pt); void CreateFolders(); bool _isRenamed; @@ -533,4 +584,6 @@ bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item); +void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf); + #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp 7zip-22.01/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp 2022-04-06 09:00:00.000000000 +0000 @@ -34,7 +34,8 @@ return Callback->Open_SetCompleted(files, bytes); COM_TRY_END } - + + STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -51,10 +52,11 @@ case kpidName: prop = fs2us(_fileInfo.Name); break; case kpidIsDir: prop = _fileInfo.IsDir(); break; case kpidSize: prop = _fileInfo.Size; break; - case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break; - case kpidCTime: prop = _fileInfo.CTime; break; - case kpidATime: prop = _fileInfo.ATime; break; - case kpidMTime: prop = _fileInfo.MTime; break; + case kpidAttrib: prop = (UInt32)_fileInfo.GetWinAttrib(); break; + case kpidPosixAttrib: prop = (UInt32)_fileInfo.GetPosixAttrib(); break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break; } prop.Detach(value); return S_OK; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/CompressCall2.cpp 7zip-22.01/CPP/7zip/UI/Common/CompressCall2.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/CompressCall2.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/CompressCall2.cpp 2022-06-06 10:00:00.000000000 +0000 @@ -152,19 +152,12 @@ static HRESULT ExtractGroupCommand(const UStringVector &arcPaths, - bool showDialog, const UString &outFolder, bool testMode, bool elimDup = false, - const char *kType = NULL) + bool showDialog, CExtractOptions &eo, const char *kType = NULL) { MY_TRY_BEGIN CREATE_CODECS - CExtractOptions eo; - eo.OutputDir = us2fs(outFolder); - eo.TestMode = testMode; - eo.ElimDup.Val = elimDup; - eo.ElimDup.Def = elimDup; - CExtractCallbackImp *ecs = new CExtractCallbackImp; CMyComPtr extractCallback = ecs; @@ -228,15 +221,26 @@ return result; } -void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup) +void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, + bool showDialog, bool elimDup, UInt32 writeZone) { - ExtractGroupCommand(arcPaths, showDialog, outFolder, false, elimDup); + CExtractOptions eo; + eo.OutputDir = us2fs(outFolder); + eo.TestMode = false; + eo.ElimDup.Val = elimDup; + eo.ElimDup.Def = elimDup; + if (writeZone != (UInt32)(Int32)-1) + eo.ZoneMode = (NExtract::NZoneIdMode::EEnum)writeZone; + ExtractGroupCommand(arcPaths, showDialog, eo); } void TestArchives(const UStringVector &arcPaths, bool hashMode) { - ExtractGroupCommand(arcPaths, true, UString(), true, - false, // elimDup + CExtractOptions eo; + eo.TestMode = true; + ExtractGroupCommand(arcPaths, + true, // showDialog + eo, hashMode ? "hash" : NULL); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/CompressCall.cpp 7zip-22.01/CPP/7zip/UI/Common/CompressCall.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/CompressCall.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/CompressCall.cpp 2022-05-26 11:00:00.000000000 +0000 @@ -252,7 +252,7 @@ ErrorMessageHRESULT(result); } -void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup) +void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone) { MY_TRY_BEGIN UString params ('x'); @@ -263,6 +263,11 @@ } if (elimDup) params += " -spe"; + if (writeZone != (UInt32)(Int32)-1) + { + params += " -snz"; + params.Add_UInt32(writeZone); + } if (showDialog) params += kShowDialogSwitch; ExtractGroupCommand(arcPaths, params, false); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/CompressCall.h 7zip-22.01/CPP/7zip/UI/Common/CompressCall.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/CompressCall.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/CompressCall.h 2022-05-26 11:00:00.000000000 +0000 @@ -15,7 +15,7 @@ const UStringVector &names, bool email, bool showDialog, bool waitFinish); -void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup); +void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone); void TestArchives(const UStringVector &arcPaths, bool hashMode = false); void CalcChecksum(const UStringVector &paths, diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/DirItem.h 7zip-22.01/CPP/7zip/UI/Common/DirItem.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/DirItem.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/DirItem.h 2022-05-13 13:00:00.000000000 +0000 @@ -10,6 +10,8 @@ #include "../../../Common/MyString.h" #include "../../../Windows/FileFind.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/UniqBlocks.h" @@ -80,50 +82,213 @@ INTERFACE_IDirItemsCallback(=0) }; -struct CDirItem + +struct CArcTime +{ + FILETIME FT; + UInt16 Prec; + Byte Ns100; + bool Def; + + CArcTime() + { + Clear(); + } + + void Clear() + { + FT.dwHighDateTime = FT.dwLowDateTime = 0; + Prec = 0; + Ns100 = 0; + Def = false; + } + + bool IsZero() const + { + return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0; + } + + int CompareWith(const CArcTime &a) const + { + const int res = CompareFileTime(&FT, &a.FT); + if (res != 0) + return res; + if (Ns100 < a.Ns100) return -1; + if (Ns100 > a.Ns100) return 1; + return 0; + } + + UInt64 Get_FILETIME_as_UInt64() const + { + return (((UInt64)FT.dwHighDateTime) << 32) + FT.dwLowDateTime; + } + + UInt32 Get_DosTime() const + { + FILETIME ft2 = FT; + if ((Prec == k_PropVar_TimePrec_Base + 8 || + Prec == k_PropVar_TimePrec_Base + 9) + && Ns100 != 0) + { + UInt64 u64 = Get_FILETIME_as_UInt64(); + // we round up even small (ns < 100ns) as FileTimeToDosTime() + if (u64 % 20000000 == 0) + { + u64++; + ft2.dwHighDateTime = (DWORD)(u64 >> 32); + ft2.dwHighDateTime = (DWORD)u64; + } + } + // FileTimeToDosTime() is expected to round up in Windows + UInt32 dosTime; + // we use simplified code with utctime->dos. + // do we need local time instead here? + NWindows::NTime::FileTime_To_DosTime(ft2, dosTime); + return dosTime; + } + + int GetNumDigits() const + { + if (Prec == k_PropVar_TimePrec_Unix || + Prec == k_PropVar_TimePrec_DOS) + return 0; + if (Prec == k_PropVar_TimePrec_HighPrec) + return 9; + if (Prec == k_PropVar_TimePrec_0) + return 7; + int digits = (int)Prec - (int)k_PropVar_TimePrec_Base; + if (digits < 0) + digits = 0; + return digits; + } + + void Write_To_FiTime(CFiTime &dest) const + { + #ifdef _WIN32 + dest = FT; + #else + if (FILETIME_To_timespec(FT, dest)) + if ((Prec == k_PropVar_TimePrec_Base + 8 || + Prec == k_PropVar_TimePrec_Base + 9) + && Ns100 != 0) + { + dest.tv_nsec += Ns100; + } + #endif + } + + // (Def) is not set + void Set_From_FILETIME(const FILETIME &ft) + { + FT = ft; + // Prec = k_PropVar_TimePrec_CompatNTFS; + Prec = k_PropVar_TimePrec_Base + 7; + Ns100 = 0; + } + + // (Def) is not set + // it set full form precision: k_PropVar_TimePrec_Base + numDigits + void Set_From_FiTime(const CFiTime &ts) + { + #ifdef _WIN32 + FT = ts; + Prec = k_PropVar_TimePrec_Base + 7; + // Prec = k_PropVar_TimePrec_Base; // for debug + // Prec = 0; // for debug + Ns100 = 0; + #else + unsigned ns100; + FiTime_To_FILETIME_ns100(ts, FT, ns100); + Ns100 = (Byte)ns100; + Prec = k_PropVar_TimePrec_Base + 9; + #endif + } + + void Set_From_Prop(const PROPVARIANT &prop) + { + FT = prop.filetime; + unsigned prec = 0; + unsigned ns100 = 0; + const unsigned prec_Temp = prop.wReserved1; + if (prec_Temp != 0 + && prec_Temp <= k_PropVar_TimePrec_1ns + && prop.wReserved3 == 0) + { + const unsigned ns100_Temp = prop.wReserved2; + if (ns100_Temp < 100) + { + ns100 = ns100_Temp; + prec = prec_Temp; + } + } + Prec = (UInt16)prec; + Ns100 = (Byte)ns100; + Def = true; + } +}; + + +struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase { - UInt64 Size; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; UString Name; - #ifndef UNDER_CE + #ifndef UNDER_CE CByteBuffer ReparseData; - #ifdef _WIN32 + #ifdef _WIN32 // UString ShortName; CByteBuffer ReparseData2; // fixed (reduced) absolute links for WIM format bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; } - #else + #else bool AreReparseData() const { return ReparseData.Size() != 0; } - #endif // _WIN32 + #endif // _WIN32 - #endif // !UNDER_CE + #endif // !UNDER_CE - UInt32 Attrib; + void Copy_From_FileInfoBase(const NWindows::NFile::NFind::CFileInfoBase &fi) + { + (NWindows::NFile::NFind::CFileInfoBase &)*this = fi; + } + int PhyParent; int LogParent; int SecureIndex; - bool IsAltStream; - - CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {} - - bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; } - bool IsReadOnly() const { return (Attrib & FILE_ATTRIBUTE_READONLY) != 0; } - bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } - - #ifdef _WIN32 - UInt32 GetPosixAttrib() const - { - UInt32 v = IsDir() ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG; - /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY). - So extracting at Linux will be allowed to write files inside (0777) directories. */ - v |= ((IsReadOnly() && !IsDir()) ? 0555 : 0777); - return v; + #ifdef _WIN32 + #else + int OwnerNameIndex; + int OwnerGroupIndex; + #endif + + CDirItem(): + PhyParent(-1) + , LogParent(-1) + , SecureIndex(-1) + #ifdef _WIN32 + #else + , OwnerNameIndex(-1) + , OwnerGroupIndex(-1) + #endif + { } - #endif + + + CDirItem(const NWindows::NFile::NFind::CFileInfo &fi, + int phyParent, int logParent, int secureIndex): + CFileInfoBase(fi) + , Name(fs2us(fi.Name)) + #if defined(_WIN32) && !defined(UNDER_CE) + // , ShortName(fs2us(fi.ShortName)) + #endif + , PhyParent(phyParent) + , LogParent(logParent) + , SecureIndex(secureIndex) + #ifdef _WIN32 + #else + , OwnerNameIndex(-1) + , OwnerGroupIndex(-1) + #endif + {} }; @@ -145,6 +310,7 @@ bool ScanAltStreams; bool ExcludeDirItems; bool ExcludeFileItems; + bool ShareForWrite; /* it must be called after anotrher checks */ bool CanIncludeItem(bool isDir) const @@ -160,7 +326,7 @@ const FString &phyPrefix); #endif - #if defined(_WIN32) && !defined(UNDER_CE) + #if defined(_WIN32) && !defined(UNDER_CE) CUniqBlocks SecureBlocks; CByteBuffer TempSecureBuf; @@ -170,7 +336,17 @@ HRESULT AddSecurityItem(const FString &path, int &secureIndex); HRESULT FillFixedReparse(); - #endif + #endif + + #ifndef _WIN32 + + C_UInt32_UString_Map OwnerNameMap; + C_UInt32_UString_Map OwnerGroupMap; + bool StoreOwnerName; + + HRESULT FillDeviceSizes(); + + #endif IDirItemsCallback *Callback; @@ -204,20 +380,25 @@ }; + + struct CArcItem { UInt64 Size; - FILETIME MTime; UString Name; + CArcTime MTime; // it can be mtime of archive file, if MTime is not defined for item in archive bool IsDir; bool IsAltStream; - bool SizeDefined; - bool MTimeDefined; + bool Size_Defined; bool Censored; UInt32 IndexInServer; - int TimeType; - CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {} + CArcItem(): + IsDir(false), + IsAltStream(false), + Size_Defined(false), + Censored(false) + {} }; #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/EnumDirItems.cpp 7zip-22.01/CPP/7zip/UI/Common/EnumDirItems.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/EnumDirItems.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/EnumDirItems.cpp 2022-06-27 13:00:00.000000000 +0000 @@ -5,6 +5,12 @@ #include // #include +#ifndef _WIN32 +#include +#include +#include "../../../Common/UTFConvert.h" +#endif + #include "../../../Common/Wildcard.h" #include "../../../Windows/FileDir.h" @@ -23,32 +29,60 @@ using namespace NFile; using namespace NName; + +static bool FindFile_KeepDots(NFile::NFind::CFileInfo &fi, const FString &path, bool followLink) +{ + const bool res = fi.Find(path, followLink); + if (!res) + return res; + if (path.IsEmpty()) + return res; + // we keep name "." and "..", if it's without tail slash + const FChar *p = path.RightPtr(1); + if (*p != '.') + return res; + if (p != path.Ptr()) + { + FChar c = p[-1]; + if (!IS_PATH_SEPAR(c)) + { + if (c != '.') + return res; + p--; + if (p != path.Ptr()) + { + c = p[-1]; + if (!IS_PATH_SEPAR(c)) + return res; + } + } + } + fi.Name = p; + return res; +} + + void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex, const NFind::CFileInfo &fi) { - CDirItem di; - di.Size = fi.Size; - di.CTime = fi.CTime; - di.ATime = fi.ATime; - di.MTime = fi.MTime; - di.Attrib = fi.Attrib; - di.IsAltStream = fi.IsAltStream; + /* + CDirItem di(fi); di.PhyParent = phyParent; di.LogParent = logParent; di.SecureIndex = secureIndex; - di.Name = fs2us(fi.Name); - #if defined(_WIN32) && !defined(UNDER_CE) - // di.ShortName = fs2us(fi.ShortName); - #endif Items.Add(di); + */ + VECTOR_ADD_NEW_OBJECT (Items, CDirItem(fi, phyParent, logParent, secureIndex)) if (fi.IsDir()) Stat.NumDirs++; + #ifdef _WIN32 else if (fi.IsAltStream) { Stat.NumAltStreams++; Stat.AltStreamsSize += fi.Size; } + #endif else { Stat.NumFiles++; @@ -148,9 +182,13 @@ ScanAltStreams(false) , ExcludeDirItems(false) , ExcludeFileItems(false) - #ifdef _USE_SECURITY_CODE + , ShareForWrite(false) + #ifdef _USE_SECURITY_CODE , ReadSecure(false) - #endif + #endif + #ifndef _WIN32 + , StoreOwnerName(false) + #endif , Callback(NULL) { #ifdef _USE_SECURITY_CODE @@ -379,7 +417,7 @@ const FString &filePath = filePaths[i]; NFind::CFileInfo fi; const FString phyPath = phyPrefix + filePath; - if (!fi.Find(phyPath FOLLOW_LINK_PARAM)) + if (!FindFile_KeepDots(fi, phyPath FOLLOW_LINK_PARAM)) { RINOK(AddError(phyPath)); continue; @@ -658,15 +696,14 @@ if (!enterToSubFolders) return S_OK; - #ifndef _WIN32 + #ifndef _WIN32 if (fi.IsPosixLink()) { // here we can try to resolve posix link // if the link to dir, then can we follow it return S_OK; // we don't follow posix link } - #endif - + #else if (dirItems.SymLinks && fi.HasReparsePoint()) { /* 20.03: in SymLinks mode: we don't enter to directory that @@ -677,6 +714,7 @@ */ return S_OK; } + #endif nextNode = &curNode; } @@ -826,7 +864,7 @@ } else #endif - if (!fi.Find(fullPath FOLLOW_LINK_PARAM2)) + if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2)) { RINOK(dirItems.AddError(fullPath)); continue; @@ -914,15 +952,14 @@ } else { - #ifndef _WIN32 + #ifndef _WIN32 if (fi.IsPosixLink()) { // here we can try to resolve posix link // if the link to dir, then can we follow it continue; // we don't follow posix link } - #endif - + #else if (dirItems.SymLinks) { if (fi.HasReparsePoint()) @@ -932,6 +969,7 @@ continue; } } + #endif nextNode = &curNode; newParts.Add(name); // don't change it to fi.Name. It's for shortnames support } @@ -973,7 +1011,7 @@ } else { - if (!fi.Find(fullPath FOLLOW_LINK_PARAM2)) + if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2)) { if (!nextNode.AreThereIncludeItems()) continue; @@ -1136,15 +1174,18 @@ } dirItems.ReserveDown(); - #if defined(_WIN32) && !defined(UNDER_CE) + #if defined(_WIN32) && !defined(UNDER_CE) RINOK(dirItems.FillFixedReparse()); - #endif + #endif + + #ifndef _WIN32 + RINOK(dirItems.FillDeviceSizes()); + #endif return S_OK; } - #if defined(_WIN32) && !defined(UNDER_CE) HRESULT CDirItems::FillFixedReparse() @@ -1281,6 +1322,149 @@ #endif +#ifndef _WIN32 + +HRESULT CDirItems::FillDeviceSizes() +{ + { + FOR_VECTOR (i, Items) + { + CDirItem &item = Items[i]; + + if (S_ISBLK(item.mode) && item.Size == 0) + { + const FString phyPath = GetPhyPath(i); + NIO::CInFile inFile; + inFile.PreserveATime = true; + if (inFile.OpenShared(phyPath, ShareForWrite)) // fixme: OpenShared ?? + { + UInt64 size = 0; + if (inFile.GetLength(size)) + item.Size = size; + } + } + if (StoreOwnerName) + { + OwnerNameMap.Add_UInt32(item.uid); + OwnerGroupMap.Add_UInt32(item.gid); + } + } + } + + if (StoreOwnerName) + { + UString u; + AString a; + { + FOR_VECTOR (i, OwnerNameMap.Numbers) + { + // 200K/sec speed + u.Empty(); + const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]); + // printf("\ngetpwuid=%s\n", pw->pw_name); + if (pw) + { + a = pw->pw_name; + ConvertUTF8ToUnicode(a, u); + } + OwnerNameMap.Strings.Add(u); + } + } + { + FOR_VECTOR (i, OwnerGroupMap.Numbers) + { + u.Empty(); + const group *gr = getgrgid(OwnerGroupMap.Numbers[i]); + if (gr) + { + // printf("\ngetgrgid %d %s\n", OwnerGroupMap.Numbers[i], gr->gr_name); + a = gr->gr_name; + ConvertUTF8ToUnicode(a, u); + } + OwnerGroupMap.Strings.Add(u); + } + } + + FOR_VECTOR (i, Items) + { + CDirItem &item = Items[i]; + { + const int index = OwnerNameMap.Find(item.uid); + if (index < 0) throw 1; + item.OwnerNameIndex = index; + } + { + const int index = OwnerGroupMap.Find(item.gid); + if (index < 0) throw 1; + item.OwnerGroupIndex = index; + } + } + } + + + // if (NeedOwnerNames) + { + /* + { + for (unsigned i = 0 ; i < 10000; i++) + { + const passwd *pw = getpwuid(i); + if (pw) + { + UString u; + ConvertUTF8ToUnicode(AString(pw->pw_name), u); + OwnerNameMap.Add(i, u); + OwnerNameMap.Add(i, u); + OwnerNameMap.Add(i, u); + } + const group *gr = getgrgid(i); + if (gr) + { + // we can use utf-8 here. + UString u; + ConvertUTF8ToUnicode(AString(gr->gr_name), u); + OwnerGroupMap.Add(i, u); + } + } + } + */ + /* + { + FOR_VECTOR (i, OwnerNameMap.Strings) + { + AString s; + ConvertUnicodeToUTF8(OwnerNameMap.Strings[i], s); + printf("\n%5d %s", (unsigned)OwnerNameMap.Numbers[i], s.Ptr()); + } + } + { + printf("\n\n=========Groups\n"); + FOR_VECTOR (i, OwnerGroupMap.Strings) + { + AString s; + ConvertUnicodeToUTF8(OwnerGroupMap.Strings[i], s); + printf("\n%5d %s", (unsigned)OwnerGroupMap.Numbers[i], s.Ptr()); + } + } + */ + } + /* + for (unsigned i = 0 ; i < 100000000; i++) + { + // const passwd *pw = getpwuid(1000); + // pw = pw; + int pos = OwnerNameMap.Find(1000); + if (pos < 0 - (int)i) + throw 1; + } + */ + + return S_OK; +} + +#endif + + static const char * const kCannotFindArchive = "Cannot find archive"; @@ -1351,11 +1535,18 @@ #ifdef _WIN32 +static bool IsDotsName(const wchar_t *s) +{ + return s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)); +} + // This code converts all short file names to long file names. static void ConvertToLongName(const UString &prefix, UString &name) { - if (name.IsEmpty() || DoesNameContainWildcard(name)) + if (name.IsEmpty() + || DoesNameContainWildcard(name) + || IsDotsName(name)) return; NFind::CFileInfo fi; const FString path (us2fs(prefix + name)); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/Extract.cpp 7zip-22.01/CPP/7zip/UI/Common/Extract.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/Extract.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/Extract.cpp 2022-06-09 13:00:00.000000000 +0000 @@ -239,18 +239,18 @@ Sorted list for file paths was sorted with case insensitive compare function. But FindInSorted function did binary search via case sensitive compare function */ -int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name); -int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name) +int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name); +int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name) { - unsigned left = 0, right = fileName.Size(); + unsigned left = 0, right = fileNames.Size(); while (left != right) { - unsigned mid = (left + right) / 2; - const UString &midValue = fileName[mid]; - int compare = CompareFileNames(name, midValue); - if (compare == 0) + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const UString &midVal = fileNames[mid]; + const int comp = CompareFileNames(name, midVal); + if (comp == 0) return (int)mid; - if (compare < 0) + if (comp < 0) right = mid; else left = mid + 1; @@ -314,8 +314,13 @@ CArchiveExtractCallback *ecs = new CArchiveExtractCallback; CMyComPtr ec(ecs); - bool multi = (numArcs > 1); - ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode, + + const bool multi = (numArcs > 1); + + ecs->InitForMulti(multi, + options.PathMode, + options.OverwriteMode, + options.ZoneMode, false // keepEmptyDirParts ); #ifndef _SFX @@ -335,12 +340,18 @@ if (skipArcs[i]) continue; + ecs->InitBeforeNewArchive(); + const UString &arcPath = arcPaths[i]; NFind::CFileInfo fi; if (options.StdInMode) { - fi.Size = 0; - fi.Attrib = 0; + // do we need ctime and mtime? + fi.ClearBase(); + fi.Size = 0; // (UInt64)(Int64)-1; + fi.SetAsFile(); + // NTime::GetCurUtc_FiTime(fi.MTime); + // fi.CTime = fi.ATime = fi.MTime; } else { @@ -417,6 +428,15 @@ continue; } + #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) + if (options.ZoneMode != NExtract::NZoneIdMode::kNone + && !options.StdInMode) + { + ReadZoneFile_Of_BaseFile(us2fs(arcPath), ecs->ZoneBuf); + } + #endif + + if (arcLink.Arcs.Size() != 0) { if (arcLink.GetArc()->IsHashHandler(op)) @@ -490,11 +510,16 @@ */ CArc &arc = arcLink.Arcs.Back(); - arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); - arc.MTime = fi.MTime; + arc.MTime.Def = !options.StdInMode + #ifdef _WIN32 + && !fi.IsDevice + #endif + ; + if (arc.MTime.Def) + arc.MTime.Set_From_FiTime(fi.MTime); UInt64 packProcessed; - bool calcCrc = + const bool calcCrc = #ifndef _SFX (hash != NULL); #else diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/Extract.h 7zip-22.01/CPP/7zip/UI/Common/Extract.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/Extract.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/Extract.h 2022-06-03 11:00:00.000000000 +0000 @@ -25,6 +25,7 @@ bool OverwriteMode_Force; NExtract::NPathMode::EEnum PathMode; NExtract::NOverwriteMode::EEnum OverwriteMode; + NExtract::NZoneIdMode::EEnum ZoneMode; FString OutputDir; CExtractNtOptions NtOptions; @@ -36,7 +37,8 @@ PathMode_Force(false), OverwriteMode_Force(false), PathMode(NExtract::NPathMode::kFullPaths), - OverwriteMode(NExtract::NOverwriteMode::kAsk) + OverwriteMode(NExtract::NOverwriteMode::kAsk), + ZoneMode(NExtract::NZoneIdMode::kNone) {} }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ExtractingFilePath.cpp 7zip-22.01/CPP/7zip/UI/Common/ExtractingFilePath.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ExtractingFilePath.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ExtractingFilePath.cpp 2022-01-09 19:00:00.000000000 +0000 @@ -34,10 +34,19 @@ || #endif c == WCHAR_PATH_SEPARATOR) + { + #if WCHAR_PATH_SEPARATOR != L'/' + // 22.00 : WSL replacement for backslash + if (c == WCHAR_PATH_SEPARATOR) + c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; + else + #endif + c = '_'; s.ReplaceOneCharAtPos(i, - '_' // default + c // (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters ); + } } } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ExtractMode.h 7zip-22.01/CPP/7zip/UI/Common/ExtractMode.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ExtractMode.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ExtractMode.h 2022-05-26 11:00:00.000000000 +0000 @@ -29,6 +29,16 @@ }; } +namespace NZoneIdMode +{ + enum EEnum + { + kNone, + kAll, + kOffice + }; +} + } #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/HashCalc.cpp 7zip-22.01/CPP/7zip/UI/Common/HashCalc.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/HashCalc.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/HashCalc.cpp 2022-04-04 15:00:00.000000000 +0000 @@ -15,6 +15,7 @@ #include "../../Common/StreamUtils.h" #include "../../Archive/Common/ItemNameUtils.h" +#include "../../Archive/IArchive.h" #include "EnumDirItems.h" #include "HashCalc.h" @@ -309,8 +310,6 @@ } -void HashHexToString(char *dest, const Byte *data, UInt32 size); - static void AddHashResultLine( AString &_s, // bool showHash, @@ -463,10 +462,7 @@ { CDirItem di; di.Size = (UInt64)(Int64)-1; - di.Attrib = 0; - di.MTime.dwLowDateTime = 0; - di.MTime.dwHighDateTime = 0; - di.CTime = di.ATime = di.MTime; + di.SetAsFile(); dirItems.Items.Add(di); } else @@ -478,6 +474,8 @@ dirItems.ExcludeDirItems = censor.ExcludeDirItems; dirItems.ExcludeFileItems = censor.ExcludeFileItems; + dirItems.ShareForWrite = options.OpenShareForWrite; + HRESULT res = EnumerateItems(censor, options.PathMode, UString(), @@ -498,14 +496,16 @@ // hb.Init(); hb.NumErrors = dirItems.Stat.NumErrors; - + + UInt64 totalSize = 0; if (options.StdInMode) { RINOK(callback->SetNumFiles(1)); } else { - RINOK(callback->SetTotal(dirItems.Stat.GetTotalBytes())); + totalSize = dirItems.Stat.GetTotalBytes(); + RINOK(callback->SetTotal(totalSize)); } const UInt32 kBufSize = 1 << 15; @@ -537,7 +537,9 @@ { path = dirItems.GetLogPath(i); const CDirItem &di = dirItems.Items[i]; + #ifdef _WIN32 isAltStream = di.IsAltStream; + #endif #ifndef UNDER_CE // if (di.AreReparseData()) @@ -551,7 +553,7 @@ #endif { CInFileStream *inStreamSpec = new CInFileStream; - inStreamSpec->File.PreserveATime = options.PreserveATime; + inStreamSpec->Set_PreserveATime(options.PreserveATime); inStream = inStreamSpec; isDir = di.IsDir(); if (!isDir) @@ -565,6 +567,20 @@ return res; continue; } + if (!options.StdInMode) + { + UInt64 curSize = 0; + if (inStreamSpec->GetSize(&curSize) == S_OK) + { + if (curSize > di.Size) + { + totalSize += curSize - di.Size; + RINOK(callback->SetTotal(totalSize)); + // printf("\ntotal = %d MiB\n", (unsigned)(totalSize >> 20)); + } + } + } + // inStreamSpec->ReloadProps(); } } } @@ -580,6 +596,7 @@ { if ((step & 0xFF) == 0) { + // printf("\ncompl = %d\n", (unsigned)(completeValue >> 20)); RINOK(callback->SetCompleted(&completeValue)); } UInt32 size; @@ -1679,8 +1696,11 @@ if (_isArc && !CanUpdate()) return E_NOTIMPL; - // const UINT codePage = CP_UTF8; // // (_forceCodePage ? _specifiedCodePage : _openCodePage); - // const unsigned utfFlags = g_Unicode_To_UTF8_Flags; + /* + CMyComPtr reportArcProp; + callback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp); + */ + CObjectVector updateItems; UInt64 complexity = 0; @@ -1827,6 +1847,8 @@ if (ui.NewData) { UInt64 currentComplexity = ui.Size; + UInt64 fileSize = 0; + CMyComPtr fileInStream; bool needWrite = true; { @@ -1840,6 +1862,15 @@ if (fileInStream) { + CMyComPtr streamGetSize; + fileInStream->QueryInterface(IID_IStreamGetSize, (void **)&streamGetSize); + if (streamGetSize) + { + UInt64 size; + if (streamGetSize->GetSize(&size) == S_OK) + currentComplexity = size; + } + /* CMyComPtr getProps; fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps); if (getProps) @@ -1852,6 +1883,7 @@ // item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);; } } + */ } else { @@ -1865,7 +1897,6 @@ if (needWrite && fileInStream && !isDir) { - UInt64 fileSize = 0; for (UInt32 step = 0;; step++) { if ((step & 0xFF) == 0) @@ -1901,6 +1932,36 @@ } complexity += currentComplexity; + + /* + if (reportArcProp) + { + PROPVARIANT prop; + prop.vt = VT_EMPTY; + prop.wReserved1 = 0; + + NCOM::PropVarEm_Set_UInt64(&prop, fileSize); + RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidSize, &prop)); + + for (unsigned k = 0; k < hb.Hashers.Size(); k++) + { + const CHasherState &hs = hb.Hashers[k]; + + if (hs.DigestSize == 4 && hs.Name.IsEqualTo_Ascii_NoCase("crc32")) + { + NCOM::PropVarEm_Set_UInt32(&prop, GetUi32(hs.Digests[k_HashCalc_Index_Current])); + RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidCRC, &prop)); + } + else + { + RINOK(reportArcProp->ReportRawProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, + kpidChecksum, hs.Digests[k_HashCalc_Index_Current], + hs.DigestSize, NPropDataType::kRaw)); + } + RINOK(reportArcProp->ReportFinished(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, NArchive::NUpdate::NOperationResult::kOK)); + } + } + */ RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } else diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/HashCalc.h 7zip-22.01/CPP/7zip/UI/Common/HashCalc.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/HashCalc.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/HashCalc.h 2022-02-08 11:00:00.000000000 +0000 @@ -16,6 +16,12 @@ const unsigned k_HashCalc_ExtraSize = 8; const unsigned k_HashCalc_NumGroups = 4; +/* + if (size <= 8) : upper case : reversed byte order : it shows 32-bit/64-bit number, if data contains little-endian number + if (size > 8) : lower case : original byte order (as big-endian byte sequence) +*/ +void HashHexToString(char *dest, const Byte *data, UInt32 size); + enum { k_HashCalc_Index_Current, diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/LoadCodecs.cpp 7zip-22.01/CPP/7zip/UI/Common/LoadCodecs.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/LoadCodecs.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/LoadCodecs.cpp 2022-05-11 09:00:00.000000000 +0000 @@ -33,8 +33,6 @@ #include "StdAfx.h" -#include "../../../../C/7zVersion.h" - #include "../../../Common/MyCom.h" #include "../../../Common/StringToInt.h" #include "../../../Common/StringConvert.h" @@ -275,6 +273,9 @@ #define MY_GET_FUNC(dest, type, func) *(void **)(&dest) = (func); // #define MY_GET_FUNC(dest, type, func) dest = (type)(func); +#define MY_GET_FUNC_LOC(dest, type, func) \ + type dest; MY_GET_FUNC(dest, type, func) + HRESULT CCodecs::LoadCodecs() { CCodecLib &lib = Libs.Back(); @@ -286,8 +287,7 @@ if (lib.GetMethodProperty) { UInt32 numMethods = 1; - Func_GetNumberOfMethods getNumberOfMethods; - MY_GET_FUNC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib.GetProc("GetNumberOfMethods")); + MY_GET_FUNC_LOC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib.GetProc("GetNumberOfMethods")); if (getNumberOfMethods) { RINOK(getNumberOfMethods(&numMethods)); @@ -304,8 +304,7 @@ } } - Func_GetHashers getHashers; - MY_GET_FUNC (getHashers, Func_GetHashers, lib.Lib.GetProc("GetHashers")); + MY_GET_FUNC_LOC (getHashers, Func_GetHashers, lib.Lib.GetProc("GetHashers")); if (getHashers) { RINOK(getHashers(&lib.ComHashers)); @@ -414,17 +413,14 @@ const NDLL::CLibrary &lib = Libs.Back().Lib; Func_GetHandlerProperty getProp = NULL; - Func_GetHandlerProperty2 getProp2; - MY_GET_FUNC (getProp2, Func_GetHandlerProperty2, lib.GetProc("GetHandlerProperty2")); - Func_GetIsArc getIsArc; - MY_GET_FUNC (getIsArc, Func_GetIsArc, lib.GetProc("GetIsArc")); + MY_GET_FUNC_LOC (getProp2, Func_GetHandlerProperty2, lib.GetProc("GetHandlerProperty2")); + MY_GET_FUNC_LOC (getIsArc, Func_GetIsArc, lib.GetProc("GetIsArc")); UInt32 numFormats = 1; if (getProp2) { - Func_GetNumberOfFormats getNumberOfFormats; - MY_GET_FUNC (getNumberOfFormats, Func_GetNumberOfFormats, lib.GetProc("GetNumberOfFormats")); + MY_GET_FUNC_LOC (getNumberOfFormats, Func_GetNumberOfFormats, lib.GetProc("GetNumberOfFormats")); if (getNumberOfFormats) { RINOK(getNumberOfFormats(&numFormats)); @@ -477,6 +473,11 @@ item.Flags |= kArcFlagsPars[j + 1]; } } + + { + bool defined = false; + RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kTimeFlags, item.TimeFlags, defined)); + } CByteBuffer sig; RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig)); @@ -567,8 +568,7 @@ /* { - Func_LibStartup _LibStartup; - MY_GET_FUNC (_LibStartup, Func_LibStartup, lib.Lib.GetProc("LibStartup")); + MY_GET_FUNC_LOC (_LibStartup, Func_LibStartup, lib.Lib.GetProc("LibStartup")); if (_LibStartup) { HRESULT res = _LibStartup(); @@ -585,21 +585,31 @@ #ifdef _7ZIP_LARGE_PAGES if (g_LargePageSize != 0) { - Func_SetLargePageMode setLargePageMode; - MY_GET_FUNC (setLargePageMode, Func_SetLargePageMode, lib.Lib.GetProc("SetLargePageMode")); + MY_GET_FUNC_LOC (setLargePageMode, Func_SetLargePageMode, lib.Lib.GetProc("SetLargePageMode")); if (setLargePageMode) setLargePageMode(); } #endif - if (CaseSensitiveChange) + if (CaseSensitive_Change) { - Func_SetCaseSensitive setCaseSensitive; - MY_GET_FUNC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib.GetProc("SetCaseSensitive")); + MY_GET_FUNC_LOC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib.GetProc("SetCaseSensitive")); if (setCaseSensitive) setCaseSensitive(CaseSensitive ? 1 : 0); } + /* + { + MY_GET_FUNC_LOC (setClientVersion, Func_SetClientVersion, lib.Lib.GetProc("SetClientVersion")); + if (setClientVersion) + { + // const UInt32 kVersion = (MY_VER_MAJOR << 16) | MY_VER_MINOR; + setClientVersion(g_ClientVersion); + } + } + */ + + MY_GET_FUNC (lib.CreateObject, Func_CreateObject, lib.Lib.GetProc("CreateObject")); { unsigned startSize = Codecs.Size() + Hashers.Size(); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/LoadCodecs.h 7zip-22.01/CPP/7zip/UI/Common/LoadCodecs.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/LoadCodecs.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/LoadCodecs.h 2022-05-11 09:00:00.000000000 +0000 @@ -96,6 +96,7 @@ struct CArcInfoEx { UInt32 Flags; + UInt32 TimeFlags; Func_CreateInArchive CreateInArchive; Func_IsArc IsArcFunc; @@ -142,7 +143,7 @@ bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; } bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; } - bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } + bool Flags_NtSecurity() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; } bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; } bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; } @@ -154,6 +155,27 @@ bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; } bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; } + bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; } + bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; } + bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; } + + bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; } + bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; } + bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; } + + UInt32 Get_TimePrecFlags() const + { + return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) & + (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1); + } + + UInt32 Get_DefaultTimePrec() const + { + return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) & + (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1); + } + + UString GetMainExt() const { if (Exts.IsEmpty()) @@ -162,6 +184,15 @@ } int FindExtension(const UString &ext) const; + bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); } + bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); } + bool Is_Xz() const { return Name.IsEqualTo_Ascii_NoCase("xz"); } + bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); } + bool Is_GZip() const { return Name.IsEqualTo_Ascii_NoCase("gzip"); } + bool Is_Tar() const { return Name.IsEqualTo_Ascii_NoCase("tar"); } + bool Is_Zip() const { return Name.IsEqualTo_Ascii_NoCase("zip"); } + bool Is_Rar() const { return Name.IsEqualTo_Ascii_NoCase("rar"); } + /* UString GetAllExtensions() const { @@ -178,11 +209,10 @@ void AddExts(const UString &ext, const UString &addExt); - bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); } - // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); } CArcInfoEx(): Flags(0), + TimeFlags(0), CreateInArchive(NULL), IsArcFunc(NULL) #ifndef _SFX @@ -333,14 +363,14 @@ CRecordVector Hashers; #endif - bool CaseSensitiveChange; + bool CaseSensitive_Change; bool CaseSensitive; CCodecs(): #ifdef EXTERNAL_CODECS NeedSetLibCodecs(true), #endif - CaseSensitiveChange(false), + CaseSensitive_Change(false), CaseSensitive(false) {} diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/OpenArchive.cpp 7zip-22.01/CPP/7zip/UI/Common/OpenArchive.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/OpenArchive.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/OpenArchive.cpp 2022-04-30 08:00:00.000000000 +0000 @@ -209,8 +209,8 @@ unsigned left = 0, right = _items.Size(); while (left != right) { - unsigned mid = (left + right) / 2; - const CParseItem & midItem = _items[mid]; + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const CParseItem &midItem = _items[mid]; if (item.Offset < midItem.Offset) right = mid; else if (item.Offset > midItem.Offset) @@ -262,8 +262,8 @@ void CHandler::AddItem(const CParseItem &item) { AddUnknownItem(item.Offset); - int pos = FindInsertPos(item); - if (pos >= 0) + const int pos = FindInsertPos(item); + if (pos != -1) { _items.Insert((unsigned)pos, item); UInt64 next = item.Offset + item.Size; @@ -482,7 +482,7 @@ return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result); } -static HRESULT Archive_GetArcBoolProp(IInArchive *arc, PROPID propid, bool &result) throw() +static HRESULT Archive_GetArcProp_Bool(IInArchive *arc, PROPID propid, bool &result) throw() { NCOM::CPropVariant prop; result = false; @@ -532,7 +532,7 @@ #ifndef _SFX -HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const +HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const { if (!GetRawProps) return E_FAIL; @@ -616,7 +616,7 @@ -HRESULT CArc::GetItemPath(UInt32 index, UString &result) const +HRESULT CArc::GetItem_Path(UInt32 index, UString &result) const { #ifdef MY_CPU_LE if (GetRawProps) @@ -752,13 +752,13 @@ } if (result.IsEmpty()) - return GetDefaultItemPath(index, result); + return GetItem_DefaultPath(index, result); Convert_UnicodeEsc16_To_UnicodeEscHigh(result); return S_OK; } -HRESULT CArc::GetDefaultItemPath(UInt32 index, UString &result) const +HRESULT CArc::GetItem_DefaultPath(UInt32 index, UString &result) const { result.Empty(); bool isDir; @@ -779,9 +779,9 @@ return S_OK; } -HRESULT CArc::GetItemPath2(UInt32 index, UString &result) const +HRESULT CArc::GetItem_Path2(UInt32 index, UString &result) const { - RINOK(GetItemPath(index, result)); + RINOK(GetItem_Path(index, result)); if (Ask_Deleted) { bool isDeleted = false; @@ -833,7 +833,7 @@ RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir)); item.MainIsDir = item.IsDir; - RINOK(GetItemPath2(index, item.Path)); + RINOK(GetItem_Path2(index, item.Path)); #ifndef _SFX UInt32 mainIndex = index; @@ -885,7 +885,7 @@ } else { - RINOK(GetItemPath2(parentIndex, item.MainPath)); + RINOK(GetItem_Path2(parentIndex, item.MainPath)); RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir)); } } @@ -911,7 +911,7 @@ #ifndef _SFX if (item._use_baseParentFolder_mode) { - RINOK(GetItemPathToParent(mainIndex, (unsigned)item._baseParentFolder, item.PathParts)); + RINOK(GetItem_PathToParent(mainIndex, (unsigned)item._baseParentFolder, item.PathParts)); #ifdef SUPPORT_ALT_STREAMS if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty()) @@ -970,7 +970,7 @@ #endif -HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const +HRESULT CArc::GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const { NCOM::CPropVariant prop; defined = false; @@ -989,24 +989,52 @@ return S_OK; } -HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const +HRESULT CArc::GetItem_MTime(UInt32 index, CArcTime &at) const { + at.Clear(); NCOM::CPropVariant prop; - defined = false; - ft.dwHighDateTime = ft.dwLowDateTime = 0; RINOK(Archive->GetProperty(index, kpidMTime, &prop)); + if (prop.vt == VT_FILETIME) { - ft = prop.filetime; - defined = true; + /* + // for debug + if (FILETIME_IsZero(prop.at) && MTime.Def) + { + at = MTime; + return S_OK; + } + */ + at.Set_From_Prop(prop); + if (at.Prec == 0) + { + // (at.Prec == 0) before version 22. + // so kpidTimeType is required for that code + prop.Clear(); + RINOK(Archive->GetProperty(index, kpidTimeType, &prop)); + if (prop.vt == VT_UI4) + { + UInt32 val = prop.ulVal; + if (val == NFileTimeType::kWindows) + val = k_PropVar_TimePrec_100ns; + /* + else if (val > k_PropVar_TimePrec_1ns) + { + val = k_PropVar_TimePrec_100ns; + // val = k_PropVar_TimePrec_1ns; + // return E_FAIL; // for debug + } + */ + at.Prec = (UInt16)val; + } + } + return S_OK; } - else if (prop.vt != VT_EMPTY) + + if (prop.vt != VT_EMPTY) return E_FAIL; - else if (MTimeDefined) - { - ft = MTime; - defined = true; - } + if (MTime.Def) + at = MTime; return S_OK; } @@ -1020,6 +1048,7 @@ return true; } + static void MakeCheckOrder(CCodecs *codecs, CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2, const Byte *data, size_t dataSize) @@ -1034,7 +1063,7 @@ { if (ai.Signatures.IsEmpty()) { - if (dataSize != 0) // 21.04: no Sinature means Empty Signature + if (dataSize != 0) // 21.04: no Signature means Empty Signature continue; } else @@ -1229,7 +1258,7 @@ HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) { // OkPhySize_Defined = false; - PhySizeDefined = false; + PhySize_Defined = false; PhySize = 0; Offset = 0; AvailPhySize = FileSize - startPos; @@ -1262,12 +1291,12 @@ if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) { - RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined)); + RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySize_Defined)); /* RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); if (!OkPhySize_Defined) { - OkPhySize_Defined = PhySizeDefined; + OkPhySize_Defined = PhySize_Defined; OkPhySize = PhySize; } */ @@ -1277,7 +1306,7 @@ Int64 globalOffset = (Int64)startPos + Offset; AvailPhySize = (UInt64)((Int64)FileSize - globalOffset); - if (PhySizeDefined) + if (PhySize_Defined) { UInt64 endPos = (UInt64)(globalOffset + (Int64)PhySize); if (endPos < FileSize) @@ -1378,9 +1407,9 @@ pi.FileTime_Defined = false; pi.ArcType = ai.Name; - RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType)); + RINOK(Archive_GetArcProp_Bool(archive, kpidIsNotArcType, pi.IsNotArcType)); - // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe)); + // RINOK(Archive_GetArcProp_Bool(archive, kpidIsSelfExe, pi.IsSelfExe)); pi.IsSelfExe = ai.Flags_PreArc(); { @@ -1584,7 +1613,7 @@ return S_OK; bool phySizeCantBeDetected = false; - RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)); + RINOK(Archive_GetArcProp_Bool(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)); if (!phySizeCantBeDetected) { @@ -1724,7 +1753,7 @@ const CArcInfoEx &ai = op.codecs->Formats[i]; if (IgnoreSplit || !op.openType.CanReturnArc) - if (ai.IsSplit()) + if (ai.Is_Split()) continue; if (op.excludedFormats->FindInSorted((int)i) >= 0) continue; @@ -1736,8 +1765,8 @@ if (ai.FindExtension(extension) >= 0 #ifndef _SFX - || (isZip && StringsAreEqualNoCase_Ascii(ai.Name, "zip")) - || (isRar && StringsAreEqualNoCase_Ascii(ai.Name, "rar")) + || (isZip && ai.Is_Zip()) + || (isRar && ai.Is_Rar()) #endif ) { @@ -1811,11 +1840,27 @@ /* check type order: - 1) matched extension, no signuature - 2) matched extension, matched signuature + 0) matched_extension && Backward + 1) matched_extension && (no_signuature || SignatureOffset != 0) + 2) matched_extension && (matched_signature) // 3) no signuature // 4) matched signuature */ + // we move index from orderIndices to orderIndices2 for priority handlers. + + for (unsigned i = 0; i < numFinded; i++) + { + const int index = orderIndices[i]; + if (index < 0) + continue; + const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index]; + if (ai.Flags_BackwardOpen()) + { + // backward doesn't need start signatures + orderIndices2.Add(index); + orderIndices[i] = -1; + } + } MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); @@ -1906,6 +1951,7 @@ // OutputDebugStringW(ai.Name); if (i >= numMainTypes) { + // here we allow mismatched extension only for backward handlers if (!ai.Flags_BackwardOpen() // && !ai.Flags_PureStartOpen() ) @@ -2125,7 +2171,7 @@ const CArcInfoEx &ai = op.codecs->Formats[form]; - if (ai.IsSplit()) + if (ai.Is_Split()) { splitIndex = (int)form; continue; @@ -2234,7 +2280,7 @@ // bool needScan = false; - if (!PhySizeDefined) + if (!PhySize_Defined) { // it's for Z format pi.LenIsUnknown = true; @@ -2726,14 +2772,14 @@ } continue; } - if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0) + if (!ErrorInfo.IsArc_After_NonOpen() || !PhySize_Defined || PhySize == 0) continue; } else { - if (PhySizeDefined && PhySize == 0) + if (PhySize_Defined && PhySize == 0) { - PRF(printf(" phySizeDefined && PhySize == 0 ")); + PRF(printf(" phySize_Defined && PhySize == 0 ")); // we skip that epmty archive case with unusual unexpected (PhySize == 0) from Code function. continue; } @@ -2754,10 +2800,10 @@ else if (Offset != 0) return E_FAIL; - UInt64 arcRem = FileSize - pi.Offset; + const UInt64 arcRem = FileSize - pi.Offset; UInt64 phySize = arcRem; - bool phySizeDefined = PhySizeDefined; - if (phySizeDefined) + const bool phySize_Defined = PhySize_Defined; + if (phySize_Defined) { if (pi.Offset + PhySize > FileSize) { @@ -2783,7 +2829,7 @@ bool needScan = false; - if (isOpen && !phySizeDefined) + if (isOpen && !phySize_Defined) { // it's for Z format, or bzip2,gz,xz with phySize that was not detected pi.LenIsUnknown = true; @@ -2802,7 +2848,7 @@ /* if (needSkipFullArc) - if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize) + if (pi.Offset == 0 && phySize_Defined && pi.Size >= fileSize) continue; */ if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) @@ -2830,7 +2876,7 @@ RINOK(ReadParseItemProps(archive, ai, pi)); - if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */) + if (pi.Offset < startArcPos && !mode.EachPos /* && phySize_Defined */) { /* It's for DMG format. This code deletes all previous items that are included to current item */ @@ -2849,7 +2895,7 @@ } - if (isOpen && mode.CanReturnArc && phySizeDefined) + if (isOpen && mode.CanReturnArc && phySize_Defined) { // if (pi.Offset + pi.Size >= fileSize) bool openCur = false; @@ -2993,12 +3039,12 @@ Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); - RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree)); - RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted)); - RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream)); - RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux)); - RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode)); - RINOK(Archive_GetArcBoolProp(Archive, kpidReadOnly, IsReadOnly)); + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsTree, IsTree)); + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsDeleted, Ask_Deleted)); + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAltStream, Ask_AltStream)); + RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAux, Ask_Aux)); + RINOK(Archive_GetArcProp_Bool(Archive, kpidINode, Ask_INode)); + RINOK(Archive_GetArcProp_Bool(Archive, kpidReadOnly, IsReadOnly)); const UString fileName = ExtractFileNameFromPath(Path); UString extension; @@ -3092,7 +3138,7 @@ FOR_VECTOR (i, op.codecs->Formats) { const CArcInfoEx &ai = op.codecs->Formats[i]; - if (ai.IsSplit()) + if (ai.Is_Split()) continue; UString path3 = path2; path3 += '.'; @@ -3299,7 +3345,7 @@ break; CArc arc2; - RINOK(arc.GetItemPath(mainSubfile, arc2.Path)); + RINOK(arc.GetItem_Path(mainSubfile, arc2.Path)); bool zerosTailIsAllowed; RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)); @@ -3343,7 +3389,7 @@ break; } RINOK(result); - RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined)); + RINOK(arc.GetItem_MTime(mainSubfile, arc2.MTime)); Arcs.Add(arc2); } IsOpen = !Arcs.IsEmpty(); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/OpenArchive.h 7zip-22.01/CPP/7zip/UI/Common/OpenArchive.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/OpenArchive.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/OpenArchive.h 2022-04-07 11:00:00.000000000 +0000 @@ -8,6 +8,7 @@ #include "ArchiveOpenCallback.h" #include "LoadCodecs.h" #include "Property.h" +#include "DirItem.h" #ifndef _SFX @@ -260,6 +261,9 @@ } }; + + + class CArc { HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive); @@ -268,7 +272,7 @@ #ifndef _SFX // parts.Back() can contain alt stream name "nams:AltName" - HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; + HRESULT GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; #endif public: @@ -289,19 +293,21 @@ UString DefaultName; int FormatIndex; // -1 means Parser UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile - FILETIME MTime; - bool MTimeDefined; + + // CFiTime MTime; + // bool MTime_Defined; + CArcTime MTime; Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler UInt64 PhySize; // UInt64 OkPhySize; - bool PhySizeDefined; + bool PhySize_Defined; // bool OkPhySize_Defined; UInt64 FileSize; UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file // bool offsetDefined; - UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; } + UInt64 GetEstmatedPhySize() const { return PhySize_Defined ? PhySize : FileSize; } UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive @@ -323,7 +329,7 @@ // void Set_ErrorFlagsText(); CArc(): - MTimeDefined(false), + // MTime_Defined(false), IsTree(false), IsReadOnly(false), Ask_Deleted(false), @@ -343,17 +349,29 @@ return Archive->Close(); } - HRESULT GetItemPath(UInt32 index, UString &result) const; - HRESULT GetDefaultItemPath(UInt32 index, UString &result) const; + HRESULT GetItem_Path(UInt32 index, UString &result) const; + HRESULT GetItem_DefaultPath(UInt32 index, UString &result) const; // GetItemPath2 adds [DELETED] dir prefix for deleted items. - HRESULT GetItemPath2(UInt32 index, UString &result) const; + HRESULT GetItem_Path2(UInt32 index, UString &result) const; HRESULT GetItem(UInt32 index, CReadArcItem &item) const; - HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const; - HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const; - HRESULT IsItemAnti(UInt32 index, bool &result) const + HRESULT GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const; + + /* if (GetProperty() returns vt==VT_EMPTY), this function sets + timestamp from archive file timestamp (MTime). + So (at) will be set in most cases (at.Def == true) + if (at.Prec == 0) + { + it means that (Prec == 0) was returned for (kpidMTime), + and no value was returned for (kpidTimeType). + it can mean Windows precision or unknown precision. + } + */ + HRESULT GetItem_MTime(UInt32 index, CArcTime &at) const; + + HRESULT IsItem_Anti(UInt32 index, bool &result) const { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/PropIDUtils.cpp 7zip-22.01/CPP/7zip/UI/Common/PropIDUtils.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/PropIDUtils.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/PropIDUtils.cpp 2022-05-13 13:00:00.000000000 +0000 @@ -136,10 +136,37 @@ if (prop.vt == VT_FILETIME) { const FILETIME &ft = prop.filetime; - if ((ft.dwHighDateTime == 0 && - ft.dwLowDateTime == 0)) + unsigned ns100 = 0; + int numDigits = kTimestampPrintLevel_NTFS; + const unsigned prec = prop.wReserved1; + const unsigned ns100_Temp = prop.wReserved2; + if (prec != 0 + && prec <= k_PropVar_TimePrec_1ns + && ns100_Temp < 100 + && prop.wReserved3 == 0) + { + ns100 = ns100_Temp; + if (prec == k_PropVar_TimePrec_Unix || + prec == k_PropVar_TimePrec_DOS) + numDigits = 0; + else if (prec == k_PropVar_TimePrec_HighPrec) + numDigits = 9; + else + { + numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; + if ( + // numDigits < kTimestampPrintLevel_DAY // for debuf + numDigits < kTimestampPrintLevel_SEC + ) + + numDigits = kTimestampPrintLevel_NTFS; + } + } + if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0 && ns100 == 0) return; - ConvertUtcFileTimeToString(prop.filetime, dest, level); + if (level > numDigits) + level = numDigits; + ConvertUtcFileTimeToString2(ft, ns100, dest, level); return; } @@ -198,6 +225,24 @@ ConvertUInt64ToHex(v, dest + 2); return; } + + /* + case kpidDevice: + { + UInt64 v = 0; + if (prop.vt == VT_UI4) + v = prop.ulVal; + else if (prop.vt == VT_UI8) + v = (UInt64)prop.uhVal.QuadPart; + else + break; + ConvertUInt32ToString(MY_dev_major(v), dest); + dest += strlen(dest); + *dest++ = ','; + ConvertUInt32ToString(MY_dev_minor(v), dest); + return; + } + */ } ConvertPropVariantToShortString(prop, dest); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateCallback.cpp 7zip-22.01/CPP/7zip/UI/Common/UpdateCallback.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateCallback.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/UpdateCallback.cpp 2022-07-12 14:00:00.000000000 +0000 @@ -4,6 +4,19 @@ // #include +#ifndef _WIN32 +// #include +// #include + +// for major()/minor(): +#if defined(__FreeBSD__) || defined(BSD) +#include +#else +#include +#endif + +#endif + #ifndef _7ZIP_ST #include "../../../Windows/Synchronization.h" #endif @@ -66,6 +79,18 @@ StoreNtSecurity(false), StoreHardLinks(false), StoreSymLinks(false), + + #ifndef _WIN32 + StoreOwnerId(false), + StoreOwnerName(false), + #endif + + /* + , Need_ArcMTime_Report(false), + , ArcMTime_WasReported(false), + */ + Need_LatestMTime(false), + LatestMTime_Defined(false), ProcessedItemsStatuses(NULL) { @@ -134,16 +159,17 @@ COM_TRY_END } + STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; switch (propID) { case kpidIsDir: prop = true; break; - case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break; - case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break; - case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break; - case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break; + case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->GetWinAttrib(); break; + case kpidCTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->CTime); break; + case kpidATime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->ATime); break; + case kpidMTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->MTime); break; case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break; } prop.Detach(value); @@ -446,25 +472,46 @@ { case kpidPath: prop = DirItems->GetLogPath((unsigned)up.DirIndex); break; case kpidIsDir: prop = di.IsDir(); break; - case kpidSize: prop = di.IsDir() ? (UInt64)0 : di.Size; break; - case kpidAttrib: prop = di.Attrib; break; - case kpidCTime: prop = di.CTime; break; - case kpidATime: prop = di.ATime; break; - case kpidMTime: prop = di.MTime; break; + case kpidSize: prop = (UInt64)(di.IsDir() ? (UInt64)0 : di.Size); break; + case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break; + case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break; + case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break; + case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break; + case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break; + + #if defined(_WIN32) case kpidIsAltStream: prop = di.IsAltStream; break; - #if defined(_WIN32) && !defined(UNDER_CE) // case kpidShortName: prop = di.ShortName; break; - #endif - case kpidPosixAttrib: - { - #ifdef _WIN32 - prop = di.GetPosixAttrib(); - #else - if (di.Attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) - prop = (UInt32)(di.Attrib >> 16); - #endif + #else + + case kpidDeviceMajor: + /* + printf("\ndi.mode = %o\n", di.mode); + printf("\nst.st_rdev major = %d\n", (unsigned)major(di.rdev)); + printf("\nst.st_rdev minor = %d\n", (unsigned)minor(di.rdev)); + */ + if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) + prop = (UInt32)major(di.rdev); break; - } + + case kpidDeviceMinor: + if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) + prop = (UInt32)minor(di.rdev); + break; + + // case kpidDevice: if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) prop = (UInt64)(di.rdev); break; + + case kpidUserId: if (StoreOwnerId) prop = (UInt32)di.uid; break; + case kpidGroupId: if (StoreOwnerId) prop = (UInt32)di.gid; break; + case kpidUser: + if (di.OwnerNameIndex >= 0) + prop = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; + break; + case kpidGroup: + if (di.OwnerGroupIndex >= 0) + prop = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; + break; + #endif } } prop.Detach(value); @@ -565,12 +612,41 @@ CInFileStream *inStreamSpec = new CInFileStream; CMyComPtr inStreamLoc(inStreamSpec); + /* + // for debug: + #ifdef _WIN32 + inStreamSpec->StoreOwnerName = true; + inStreamSpec->OwnerName = "user_name"; + inStreamSpec->OwnerName += di.Name; + inStreamSpec->OwnerName += "11111111112222222222222333333333333"; + inStreamSpec->OwnerGroup = "gname_"; + inStreamSpec->OwnerGroup += inStreamSpec->OwnerName; + #endif + */ + + #ifndef _WIN32 + inStreamSpec->StoreOwnerId = StoreOwnerId; + inStreamSpec->StoreOwnerName = StoreOwnerName; + + // if (StoreOwner) + { + inStreamSpec->_uid = di.uid; + inStreamSpec->_gid = di.gid; + if (di.OwnerNameIndex >= 0) + inStreamSpec->OwnerName = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; + if (di.OwnerGroupIndex >= 0) + inStreamSpec->OwnerGroup = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; + } + #endif + inStreamSpec->SupportHardLinks = StoreHardLinks; - inStreamSpec->File.PreserveATime = PreserveATime; + inStreamSpec->Set_PreserveATime(PreserveATime + || mode == NUpdateNotifyOp::kAnalyze); // 22.00 : we don't change access time in Analyze pass. const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex); _openFiles_Indexes.Add(index); _openFiles_Paths.Add(path); + // _openFiles_Streams.Add(inStreamSpec); /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding for correct working if exception was raised in GetPhyPath */ @@ -579,14 +655,30 @@ if (!inStreamSpec->OpenShared(path, ShareForWrite)) { - DWORD error = ::GetLastError(); - HRESULT hres = Callback->OpenFileError(path, error); + const DWORD error = ::GetLastError(); + const HRESULT hres = Callback->OpenFileError(path, error); if (StopAfterOpenError) if (hres == S_OK || hres == S_FALSE) return HRESULT_FROM_WIN32(error); return hres; } + /* + { + // for debug: + Byte b = 0; + UInt32 processedSize = 0; + if (inStreamSpec->Read(&b, 1, &processedSize) != S_OK || + processedSize != 1) + return E_FAIL; + } + */ + + if (Need_LatestMTime) + { + inStreamSpec->ReloadProps(); + } + // #if defined(USE_WIN_FILE) || !defined(_WIN32) if (StoreHardLinks) { @@ -643,6 +735,8 @@ { COM_TRY_BEGIN + // if (op == NUpdateNotifyOp::kOpFinished) return Callback->ReportFinished(indexType, index); + bool isDir = false; if (indexType == NArchive::NEventIndexType::kOutArcIndex) @@ -676,7 +770,7 @@ } else if (Arc) { - RINOK(Arc->GetItemPath(index, s2)); + RINOK(Arc->GetItem_Path(index, s2)); s = s2; RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir)); } @@ -731,7 +825,7 @@ s = (*ArcItems)[index].Name; else if (Arc) { - RINOK(Arc->GetItemPath(index, s2)); + RINOK(Arc->GetItem_Path(index, s2)); s = s2; } if (Archive) @@ -752,6 +846,51 @@ COM_TRY_END } + +/* +STDMETHODIMP CArchiveUpdateCallback::DoNeedArcProp(PROPID propID, Int32 *answer) +{ + *answer = 0; + if (Need_ArcMTime_Report && propID == kpidComboMTime) + *answer = 1; + return S_OK; +} + +STDMETHODIMP CArchiveUpdateCallback::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) +{ + if (indexType == NArchive::NEventIndexType::kArcProp) + { + if (propID == kpidComboMTime) + { + ArcMTime_WasReported = true; + if (value->vt == VT_FILETIME) + { + Reported_ArcMTime.Set_From_Prop(*value); + Reported_ArcMTime.Def = true; + } + else + { + Reported_ArcMTime.Clear(); + if (value->vt != VT_EMPTY) + return E_FAIL; // for debug + } + } + } + return Callback->ReportProp(indexType, index, propID, value); +} + +STDMETHODIMP CArchiveUpdateCallback::ReportRawProp(UInt32 indexType, UInt32 index, + PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) +{ + return Callback->ReportRawProp(indexType, index, propID, data, dataSize, propType); +} + +STDMETHODIMP CArchiveUpdateCallback::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) +{ + return Callback->ReportFinished(indexType, index, opRes); +} +*/ + STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size) { if (VolumesSizes.Size() == 0) @@ -805,7 +944,7 @@ #endif { MT_LOCK - UInt32 index = (UInt32)val; + const UInt32 index = (UInt32)val; FOR_VECTOR(i, _openFiles_Indexes) { if (_openFiles_Indexes[i] == index) @@ -818,21 +957,31 @@ return HRESULT_FROM_WIN32(error); } -void CArchiveUpdateCallback::InFileStream_On_Destroy(UINT_PTR val) +void CArchiveUpdateCallback::InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) { - { MT_LOCK - UInt32 index = (UInt32)val; + if (Need_LatestMTime) + { + if (stream->_info_WasLoaded) + { + const CFiTime &ft = ST_MTIME(stream->_info); + if (!LatestMTime_Defined + || Compare_FiTime(&LatestMTime, &ft) < 0) + LatestMTime = ft; + LatestMTime_Defined = true; + } + } + const UInt32 index = (UInt32)val; FOR_VECTOR(i, _openFiles_Indexes) { if (_openFiles_Indexes[i] == index) { _openFiles_Indexes.Delete(i); _openFiles_Paths.Delete(i); + // _openFiles_Streams.Delete(i); return; } } - } /* 21.02 : this function can be called in destructor. And destructor can be called after some exception. If we don't want to throw exception in desctructors or after another exceptions, diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateCallback.h 7zip-22.01/CPP/7zip/UI/Common/UpdateCallback.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateCallback.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/UpdateCallback.h 2022-04-09 12:00:00.000000000 +0000 @@ -45,6 +45,13 @@ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \ virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \ virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x; \ + + /* + virtual HRESULT ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x; \ + virtual HRESULT ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x; \ + virtual HRESULT ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) x; \ + */ + /* virtual HRESULT CloseProgress() { return S_OK; } */ struct IUpdateCallbackUI @@ -70,6 +77,7 @@ class CArchiveUpdateCallback: public IArchiveUpdateCallback2, public IArchiveUpdateCallbackFile, + // public IArchiveUpdateCallbackArcProp, public IArchiveExtractCallbackMessage, public IArchiveGetRawProps, public IArchiveGetRootProps, @@ -92,6 +100,7 @@ public: MY_QUERYINTERFACE_BEGIN2(IArchiveUpdateCallback2) MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackFile) + // MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackArcProp) MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage) MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps) MY_QUERYINTERFACE_ENTRY(IArchiveGetRootProps) @@ -106,6 +115,7 @@ INTERFACE_IArchiveUpdateCallback2(;) INTERFACE_IArchiveUpdateCallbackFile(;) + // INTERFACE_IArchiveUpdateCallbackArcProp(;) INTERFACE_IArchiveExtractCallbackMessage(;) INTERFACE_IArchiveGetRawProps(;) INTERFACE_IArchiveGetRootProps(;) @@ -115,10 +125,11 @@ CRecordVector _openFiles_Indexes; FStringVector _openFiles_Paths; + // CRecordVector< CInFileStream* > _openFiles_Streams; bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); } virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error); - virtual void InFileStream_On_Destroy(UINT_PTR val); + virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val); CRecordVector VolumesSizes; FString VolName; @@ -148,8 +159,22 @@ bool StoreHardLinks; bool StoreSymLinks; + bool StoreOwnerId; + bool StoreOwnerName; + + /* + bool Need_ArcMTime_Report; + bool ArcMTime_WasReported; + CArcTime Reported_ArcMTime; + */ + bool Need_LatestMTime; + bool LatestMTime_Defined; + CFiTime LatestMTime; + Byte *ProcessedItemsStatuses; + + CArchiveUpdateCallback(); bool IsDir(const CUpdatePair2 &up) const diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/Update.cpp 7zip-22.01/CPP/7zip/UI/Common/Update.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/Update.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/Update.cpp 2022-04-09 12:00:00.000000000 +0000 @@ -2,6 +2,8 @@ #include "StdAfx.h" +// #include + #include "Update.h" #include "../../../Common/StringConvert.h" @@ -101,7 +103,7 @@ _length = 0; } - bool SetMTime(const FILETIME *mTime); + bool SetMTime(const CFiTime *mTime); HRESULT Close(); UInt64 GetSize() const { return _length; } @@ -131,7 +133,7 @@ return res; } -bool COutMultiVolStream::SetMTime(const FILETIME *mTime) +bool COutMultiVolStream::SetMTime(const CFiTime *mTime) { bool res = true; FOR_VECTOR (i, Streams) @@ -545,11 +547,46 @@ if (!outArchive) throw kUpdateIsNotSupoorted; + // we need to set properties to get fileTimeType. + RINOK(SetProperties(outArchive, options.MethodMode.Properties)); + NFileTimeType::EEnum fileTimeType; { + /* + how we compare file_in_archive::MTime with dirItem.MTime + for GetUpdatePairInfoList(): + + if (kpidMTime is not defined), external MTime of archive is used. + + before 22.00: + if (kpidTimeType is defined) + { + kpidTimeType is used as precision. + (kpidTimeType > kDOS) is not allowed. + } + else GetFileTimeType() value is used as precision. + + 22.00: + if (kpidMTime is defined) + { + if (kpidMTime::precision != 0), then kpidMTime::precision is used as precision. + else + { + if (kpidTimeType is defined), kpidTimeType is used as precision. + else GetFileTimeType() value is used as precision. + } + } + else external MTime of archive is used as precision. + */ + UInt32 value; RINOK(outArchive->GetFileTimeType(&value)); + + // we support any future fileType here. + fileTimeType = (NFileTimeType::EEnum)value; + /* + old 21.07 code: switch (value) { case NFileTimeType::kWindows: @@ -560,13 +597,26 @@ default: return E_FAIL; } + */ } + // bool noTimestampExpected = false; { const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; + + // if (arcInfo.Flags_KeepName()) noTimestampExpected = true; + if (arcInfo.Is_Xz() || + arcInfo.Is_BZip2()) + { + /* 7-zip before 22.00 returns NFileTimeType::kUnix for xz and bzip2, + but we want to set timestamp without reduction to unix. */ + // noTimestampExpected = true; + fileTimeType = NFileTimeType::kNotDefined; // it means not defined + } + if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) return E_NOTIMPL; - if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) + if (options.NtSecurity.Val && !arcInfo.Flags_NtSecurity()) return E_NOTIMPL; if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler()) return E_NOTIMPL; @@ -626,7 +676,7 @@ if (needRename) { up2.NewProps = true; - RINOK(arc->IsItemAnti(i, up2.IsAnti)); + RINOK(arc->IsItem_Anti(i, up2.IsAnti)); up2.NewNameIndex = (int)newNames.Add(dest); } updatePairs2.Add(up2); @@ -661,6 +711,7 @@ else stat.NumDirs++; } + #ifdef _WIN32 else if (di.IsAltStream) { if (up.IsAnti) @@ -671,6 +722,7 @@ stat.AltStreamsSize += di.Size; } } + #endif else { if (up.IsAnti) @@ -740,6 +792,8 @@ updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; + updateCallbackSpec->StoreOwnerName = options.StoreOwnerName.Val; + updateCallbackSpec->StoreOwnerId = options.StoreOwnerId.Val; updateCallbackSpec->Arc = arc; updateCallbackSpec->ArcItems = &arcItems; @@ -755,6 +809,12 @@ if (options.RenamePairs.Size() != 0) updateCallbackSpec->NewNames = &newNames; + if (options.SetArcMTime) + { + // updateCallbackSpec->Need_ArcMTime_Report = true; + updateCallbackSpec->Need_LatestMTime = true; + } + CMyComPtr outSeekStream; CMyComPtr outStream; @@ -838,8 +898,6 @@ */ } - RINOK(SetProperties(outArchive, options.MethodMode.Properties)); - if (options.SfxMode) { CInFileStream *sfxStreamSpec = new CInFileStream; @@ -909,24 +967,71 @@ if (options.SetArcMTime) { - FILETIME ft; - ft.dwLowDateTime = 0; - ft.dwHighDateTime = 0; - FOR_VECTOR (i, updatePairs2) + CFiTime ft; + FiTime_Clear(ft); + bool isDefined = false; + + // bool needNormalizeAfterStream; + // needParse; + /* + if (updateCallbackSpec->ArcMTime_WasReported) + { + isDefined = updateCallbackSpec->Reported_ArcMTime.Def; + if (isDefined) + updateCallbackSpec->Reported_ArcMTime.Write_To_FiTime(ft); + else + fileTimeType = NFileTimeType::kNotDefined; + } + if (!isDefined) + */ { - const CUpdatePair2 &pair2 = updatePairs2[i]; - const FILETIME *ft2 = NULL; - if (pair2.NewProps && pair2.DirIndex >= 0) - ft2 = &dirItems.Items[(unsigned)pair2.DirIndex].MTime; - else if (pair2.UseArcProps && pair2.ArcIndex >= 0) - ft2 = &arcItems[(unsigned)pair2.ArcIndex].MTime; - if (ft2) + if (updateCallbackSpec->LatestMTime_Defined) { - if (::CompareFileTime(&ft, ft2) < 0) - ft = *ft2; + // CArcTime at = StreamCallback_ArcMTime; + // updateCallbackSpec->StreamCallback_ArcMTime.Write_To_FiTime(ft); + // we must normalize with precision from archive; + ft = updateCallbackSpec->LatestMTime; + isDefined = true; + } + + FOR_VECTOR (i, updatePairs2) + { + const CUpdatePair2 &pair2 = updatePairs2[i]; + CFiTime ft2; + bool ft2_Defined = false; + /* we use full precision of dirItem, if dirItem is defined + and (dirItem will be used or dirItem is sameTime in dir and arc */ + if (pair2.DirIndex >= 0 && + (pair2.NewProps || pair2.IsSameTime)) + { + ft2 = dirItems.Items[(unsigned)pair2.DirIndex].MTime; + ft2_Defined = true; + } + else if (pair2.UseArcProps && pair2.ArcIndex >= 0) + { + const CArcItem &arcItem = arcItems[(unsigned)pair2.ArcIndex]; + if (arcItem.MTime.Def) + { + arcItem.MTime.Write_To_FiTime(ft2); + ft2_Defined = true; + } + } + if (ft2_Defined) + { + if (Compare_FiTime(&ft, &ft2) < 0) + { + ft = ft2; + isDefined = true; + } + } } + /* + if (fileTimeType != NFileTimeType::kNotDefined) + FiTime_Normalize_With_Prec(ft, fileTimeType); + */ } - if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) + // if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) + if (isDefined) { if (outStreamSpec) outStreamSpec->SetMTime(&ft); @@ -1046,26 +1151,9 @@ else ai.Censored = Censor_CheckPath(censor, item); - RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); - RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); - - { - CPropVariant prop; - RINOK(archive->GetProperty(i, kpidTimeType, &prop)); - if (prop.vt == VT_UI4) - { - ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; - switch (ai.TimeType) - { - case NFileTimeType::kWindows: - case NFileTimeType::kUnix: - case NFileTimeType::kDOS: - break; - default: - return E_FAIL; - } - } - } + // ai.MTime will be set to archive MTime, if not present in archive item + RINOK(arc.GetItem_MTime(i, ai.MTime)); + RINOK(arc.GetItem_Size(i, ai.Size, ai.Size_Defined)); ai.IndexInServer = i; arcItems.AddInReserved(ai); @@ -1198,8 +1286,10 @@ EISDIR #endif ); + #ifdef _WIN32 if (fi.IsDevice) return E_NOTIMPL; + #endif if (!options.StdOutMode && options.UpdateArchiveItself) if (fi.IsReadOnly()) @@ -1262,8 +1352,14 @@ } CArc &arc = arcLink.Arcs.Back(); - arc.MTimeDefined = !fi.IsDevice; - arc.MTime = fi.MTime; + arc.MTime.Def = + #ifdef _WIN32 + !fi.IsDevice; + #else + true; + #endif + if (arc.MTime.Def) + arc.MTime.Set_From_FiTime(fi.MTime); if (arc.ErrorInfo.ThereIsTail) { @@ -1307,10 +1403,11 @@ if (options.StdInMode) { CDirItem di; + di.ClearBase(); di.Name = options.StdInFileName; di.Size = (UInt64)(Int64)-1; - di.Attrib = 0; - NTime::GetCurUtcFileTime(di.MTime); + di.SetAsFile(); + NTime::GetCurUtc_FiTime(di.MTime); di.CTime = di.ATime = di.MTime; dirItems.Items.Add(di); } @@ -1336,8 +1433,14 @@ dirItems.ScanAltStreams = options.AltStreams.Val; dirItems.ExcludeDirItems = censor.ExcludeDirItems; dirItems.ExcludeFileItems = censor.ExcludeFileItems; + + dirItems.ShareForWrite = options.OpenShareForWrite; + + #ifndef _WIN32 + dirItems.StoreOwnerName = options.StoreOwnerName.Val; + #endif - HRESULT res = EnumerateItems(censor, + const HRESULT res = EnumerateItems(censor, options.PathMode, UString(), // options.AddPathPrefix, dirItems); @@ -1351,6 +1454,8 @@ RINOK(callback->FinishScanning(dirItems.Stat)); + // 22.00: we don't need parent folder, if absolute path mode + if (options.PathMode != NWildcard::k_AbsPath) if (censor.Pairs.Size() == 1) { NFind::CFileInfo fi; @@ -1366,11 +1471,7 @@ if (fi.Find(prefix)) if (fi.IsDir()) { - parentDirItem.Size = fi.Size; - parentDirItem.CTime = fi.CTime; - parentDirItem.ATime = fi.ATime; - parentDirItem.MTime = fi.MTime; - parentDirItem.Attrib = fi.Attrib; + parentDirItem.Copy_From_FileInfoBase(fi); parentDirItem_Ptr = &parentDirItem; int secureIndex = -1; @@ -1723,8 +1824,8 @@ is_SameSize = (fileInfo.Size == dirItem.Size); if (is_SameSize - && CompareFileTime(&fileInfo.MTime, &dirItem.MTime) == 0 - && CompareFileTime(&fileInfo.CTime, &dirItem.CTime) == 0) + && Compare_FiTime(&fileInfo.MTime, &dirItem.MTime) == 0 + && Compare_FiTime(&fileInfo.CTime, &dirItem.CTime) == 0) { RINOK(callback->DeletingAfterArchiving(phyPath, false)); DeleteFileAlways(phyPath); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/Update.h 7zip-22.01/CPP/7zip/UI/Common/Update.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/Update.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/Update.h 2022-02-24 12:00:00.000000000 +0000 @@ -112,6 +112,9 @@ CBoolPair HardLinks; CBoolPair SymLinks; + CBoolPair StoreOwnerId; + CBoolPair StoreOwnerName; + bool DeleteAfterCompressing; bool SetArcMTime; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdatePair.cpp 7zip-22.01/CPP/7zip/UI/Common/UpdatePair.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdatePair.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/UpdatePair.cpp 2022-04-06 12:00:00.000000000 +0000 @@ -3,6 +3,7 @@ #include "StdAfx.h" #include +// #include #include "../../../Common/Wildcard.h" @@ -14,30 +15,90 @@ using namespace NWindows; using namespace NTime; -static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2) + +/* + a2.Prec = + { + 0 (k_PropVar_TimePrec_0): + if GetProperty(kpidMTime) returned 0 and + GetProperty(kpidTimeType) did not returned VT_UI4. + 7z, wim, tar in 7-Zip before v21) + in that case we use + (prec) that is set by IOutArchive::GetFileTimeType() + } +*/ + +static int MyCompareTime(unsigned prec, const CFiTime &f1, const CArcTime &a2) { - switch (fileTimeType) + // except of precision, we also have limitation, when timestamp is out of range + + /* if (Prec) in archive item is defined, then use global (prec) */ + if (a2.Prec != k_PropVar_TimePrec_0) + prec = a2.Prec; + + CArcTime a1; + a1.Set_From_FiTime(f1); + /* Set_From_FiTime() must set full form precision: + k_PropVar_TimePrec_Base + numDigits + windows: 7 digits, non-windows: 9 digits */ + + if (prec == k_PropVar_TimePrec_DOS) { - case NFileTimeType::kWindows: - return ::CompareFileTime(&time1, &time2); - case NFileTimeType::kUnix: - { - UInt32 unixTime1, unixTime2; - FileTimeToUnixTime(time1, unixTime1); - FileTimeToUnixTime(time2, unixTime2); - return MyCompare(unixTime1, unixTime2); - } - case NFileTimeType::kDOS: - { - UInt32 dosTime1, dosTime2; - FileTimeToDosTime(time1, dosTime1); - FileTimeToDosTime(time2, dosTime2); - return MyCompare(dosTime1, dosTime2); - } + const UInt32 dosTime1 = a1.Get_DosTime(); + const UInt32 dosTime2 = a2.Get_DosTime(); + return MyCompare(dosTime1, dosTime2); } - throw 4191618; + + if (prec == k_PropVar_TimePrec_Unix) + { + const Int64 u2 = FileTime_To_UnixTime64(a2.FT); + if (u2 == 0 || u2 == (UInt32)0xFFFFFFFF) + { + // timestamp probably was saturated in archive to 32-bit + // so we use saturated 32-bit value for disk file too. + UInt32 u1; + FileTime_To_UnixTime(a1.FT, u1); + const UInt32 u2_32 = (UInt32)u2; + return MyCompare(u1, u2_32); + } + + const Int64 u1 = FileTime_To_UnixTime64(a1.FT); + return MyCompare(u1, u2); + // prec = k_PropVar_TimePrec_Base; // for debug + } + + if (prec == k_PropVar_TimePrec_0) + prec = k_PropVar_TimePrec_Base + 7; + else if (prec == k_PropVar_TimePrec_HighPrec) + prec = k_PropVar_TimePrec_Base + 9; + else if (prec < k_PropVar_TimePrec_Base) + prec = k_PropVar_TimePrec_Base; + else if (prec > k_PropVar_TimePrec_Base + 9) + prec = k_PropVar_TimePrec_Base + 7; + + // prec now is full form: k_PropVar_TimePrec_Base + numDigits; + if (prec > a1.Prec && a1.Prec >= k_PropVar_TimePrec_Base) + prec = a1.Prec; + + const unsigned numDigits = prec - k_PropVar_TimePrec_Base; + if (numDigits >= 7) + { + const int comp = CompareFileTime(&a1.FT, &a2.FT); + if (comp != 0 || numDigits == 7) + return comp; + return MyCompare(a1.Ns100, a2.Ns100); + } + UInt32 d = 1; + for (unsigned k = numDigits; k < 7; k++) + d *= 10; + const UInt64 v1 = a1.Get_FILETIME_as_UInt64() / d * d; + const UInt64 v2 = a2.Get_FILETIME_as_UInt64() / d * d; + // printf("\ndelta=%d numDigits=%d\n", (unsigned)(v1- v2), numDigits); + return MyCompare(v1, v2); } + + static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:"; static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:"; static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):"; @@ -64,8 +125,8 @@ static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param) { - unsigned i1 = *p1; - unsigned i2 = *p2; + const unsigned i1 = *p1; + const unsigned i2 = *p2; const CObjectVector &arcItems = *(const CObjectVector *)param; int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]); if (res != 0) @@ -81,8 +142,8 @@ { CUIntVector dirIndices, arcIndices; - unsigned numDirItems = dirItems.Items.Size(); - unsigned numArcItems = arcItems.Size(); + const unsigned numDirItems = dirItems.Items.Size(); + const unsigned numArcItems = arcItems.Size(); CIntArr duplicatedArcItem(numArcItems); { @@ -184,7 +245,7 @@ } else { - int dupl = duplicatedArcItem[arcIndex]; + const int dupl = duplicatedArcItem[arcIndex]; if (dupl != 0) ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name); @@ -195,14 +256,17 @@ pair.DirIndex = dirIndex2; pair.ArcIndex = arcIndex2; - switch (ai->MTimeDefined ? MyCompareTime( - ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType, - di->MTime, ai->MTime): 0) + int compResult = 0; + if (ai->MTime.Def) + { + compResult = MyCompareTime(fileTimeType, di->MTime, ai->MTime); + } + switch (compResult) { case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break; case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break; default: - pair.State = (ai->SizeDefined && di->Size == ai->Size) ? + pair.State = (ai->Size_Defined && di->Size == ai->Size) ? NUpdateArchive::NPairState::kSameFiles : NUpdateArchive::NPairState::kUnknowNewerFiles; } @@ -211,7 +275,10 @@ arcIndex++; } - if ((di && di->IsAltStream) || + if ( + #ifdef _WIN32 + (di && di->IsAltStream) || + #endif (ai && ai->IsAltStream)) { if (prevHostName) diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateProduce.cpp 7zip-22.01/CPP/7zip/UI/Common/UpdateProduce.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateProduce.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/UpdateProduce.cpp 2022-02-08 16:00:00.000000000 +0000 @@ -63,6 +63,8 @@ break; } + up2.IsSameTime = ((unsigned)pair.State == NUpdateArchive::NPairState::kSameFiles); + operationChain.Add(up2); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateProduce.h 7zip-22.01/CPP/7zip/UI/Common/UpdateProduce.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/UpdateProduce.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/UpdateProduce.h 2022-02-08 16:00:00.000000000 +0000 @@ -17,6 +17,7 @@ int NewNameIndex; bool IsMainRenameItem; + bool IsSameTime; void SetAs_NoChangeArcItem(unsigned arcIndex) // int { @@ -37,7 +38,8 @@ DirIndex(-1), ArcIndex(-1), NewNameIndex(-1), - IsMainRenameItem(false) + IsMainRenameItem(false), + IsSameTime(false) {} }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ZipRegistry.cpp 7zip-22.01/CPP/7zip/UI/Common/ZipRegistry.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ZipRegistry.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ZipRegistry.cpp 2022-06-03 10:00:00.000000000 +0000 @@ -33,12 +33,45 @@ return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName)); } +static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value) +{ + if (value == (UInt32)(Int32)-1) + key.DeleteValue(name); + else + key.SetValue(name, value); +} + + +static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value) +{ + if (key.QueryValue(name, value) != ERROR_SUCCESS) + value = (UInt32)(Int32)-1; +} + + static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b) { if (b.Def) key.SetValue(name, b.Val); } +static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val) +{ + bool oldVal = false; + if (key.GetValue_IfOk(name, oldVal) == ERROR_SUCCESS) + if (val == oldVal) + return; + key.SetValue(name, val); +} + +static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoolPair &b) +{ + if (b.Def) + Key_Set_bool_if_Changed(key, name, b.Val); + else + key.DeleteValue(name); +} + static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b) { b.Val = false; @@ -169,6 +202,13 @@ static LPCTSTR const kAltStreams = TEXT("AltStreams"); static LPCTSTR const kHardLinks = TEXT("HardLinks"); static LPCTSTR const kSymLinks = TEXT("SymLinks"); +static LPCTSTR const kPreserveATime = TEXT("PreserveATime"); + +static LPCTSTR const kTimePrec = TEXT("TimePrec"); +static LPCTSTR const kMTime = TEXT("MTime"); +static LPCTSTR const kATime = TEXT("ATime"); +static LPCTSTR const kCTime = TEXT("CTime"); +static LPCTSTR const kSetArcMTime = TEXT("SetArcMTime"); static void SetRegString(CKey &key, LPCWSTR name, const UString &value) { @@ -178,26 +218,12 @@ key.SetValue(name, value); } -static void SetRegUInt32(CKey &key, LPCTSTR name, UInt32 value) -{ - if (value == (UInt32)(Int32)-1) - key.DeleteValue(name); - else - key.SetValue(name, value); -} - static void GetRegString(CKey &key, LPCWSTR name, UString &value) { if (key.QueryValue(name, value) != ERROR_SUCCESS) value.Empty(); } -static void GetRegUInt32(CKey &key, LPCTSTR name, UInt32 &value) -{ - if (key.QueryValue(name, value) != ERROR_SUCCESS) - value = (UInt32)(Int32)-1; -} - static LPCWSTR const kMemUse = L"MemUse" #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4) L"32"; @@ -212,10 +238,11 @@ CKey key; CreateMainKey(key, kKeyName); - Key_Set_BoolPair(key, kNtSecur, NtSecurity); - Key_Set_BoolPair(key, kAltStreams, AltStreams); - Key_Set_BoolPair(key, kHardLinks, HardLinks); - Key_Set_BoolPair(key, kSymLinks, SymLinks); + Key_Set_BoolPair_Delete_IfNotDef (key, kNtSecur, NtSecurity); + Key_Set_BoolPair_Delete_IfNotDef (key, kAltStreams, AltStreams); + Key_Set_BoolPair_Delete_IfNotDef (key, kHardLinks, HardLinks); + Key_Set_BoolPair_Delete_IfNotDef (key, kSymLinks, SymLinks); + Key_Set_BoolPair_Delete_IfNotDef (key, kPreserveATime, PreserveATime); key.SetValue(kShowPassword, ShowPassword); key.SetValue(kLevel, (UInt32)Level); @@ -235,16 +262,22 @@ CKey fk; fk.Create(optionsKey, fo.FormatID); - SetRegUInt32(fk, kLevel, fo.Level); - SetRegUInt32(fk, kDictionary, fo.Dictionary); - SetRegUInt32(fk, kOrder, fo.Order); - SetRegUInt32(fk, kBlockSize, fo.BlockLogSize); - SetRegUInt32(fk, kNumThreads, fo.NumThreads); - SetRegString(fk, kMethod, fo.Method); SetRegString(fk, kOptions, fo.Options); SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); SetRegString(fk, kMemUse, fo.MemUse); + + Key_Set_UInt32(fk, kLevel, fo.Level); + Key_Set_UInt32(fk, kDictionary, fo.Dictionary); + Key_Set_UInt32(fk, kOrder, fo.Order); + Key_Set_UInt32(fk, kBlockSize, fo.BlockLogSize); + Key_Set_UInt32(fk, kNumThreads, fo.NumThreads); + + Key_Set_UInt32(fk, kTimePrec, fo.TimePrec); + Key_Set_BoolPair_Delete_IfNotDef (fk, kMTime, fo.MTime); + Key_Set_BoolPair_Delete_IfNotDef (fk, kATime, fo.ATime); + Key_Set_BoolPair_Delete_IfNotDef (fk, kCTime, fo.CTime); + Key_Set_BoolPair_Delete_IfNotDef (fk, kSetArcMTime, fo.SetArcMTime); } } } @@ -269,6 +302,7 @@ Key_Get_BoolPair(key, kAltStreams, AltStreams); Key_Get_BoolPair(key, kHardLinks, HardLinks); Key_Get_BoolPair(key, kSymLinks, SymLinks); + Key_Get_BoolPair(key, kPreserveATime, PreserveATime); key.GetValue_Strings(kArcHistory, ArcPaths); @@ -290,11 +324,17 @@ GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod); GetRegString(fk, kMemUse, fo.MemUse); - GetRegUInt32(fk, kLevel, fo.Level); - GetRegUInt32(fk, kDictionary, fo.Dictionary); - GetRegUInt32(fk, kOrder, fo.Order); - GetRegUInt32(fk, kBlockSize, fo.BlockLogSize); - GetRegUInt32(fk, kNumThreads, fo.NumThreads); + Key_Get_UInt32(fk, kLevel, fo.Level); + Key_Get_UInt32(fk, kDictionary, fo.Dictionary); + Key_Get_UInt32(fk, kOrder, fo.Order); + Key_Get_UInt32(fk, kBlockSize, fo.BlockLogSize); + Key_Get_UInt32(fk, kNumThreads, fo.NumThreads); + + Key_Get_UInt32(fk, kTimePrec, fo.TimePrec); + Key_Get_BoolPair(fk, kMTime, fo.MTime); + Key_Get_BoolPair(fk, kATime, fo.ATime); + Key_Get_BoolPair(fk, kCTime, fo.CTime); + Key_Get_BoolPair(fk, kSetArcMTime, fo.SetArcMTime); Formats.Add(fo); } @@ -478,6 +518,7 @@ static LPCTSTR const kContextMenu = TEXT("ContextMenu"); static LPCTSTR const kMenuIcons = TEXT("MenuIcons"); static LPCTSTR const kElimDup = TEXT("ElimDupExtract"); +static LPCTSTR const kWriteZoneId = TEXT("WriteZoneIdExtract"); void CContextMenuInfo::Save() const { @@ -488,6 +529,8 @@ Key_Set_BoolPair(key, kCascadedMenu, Cascaded); Key_Set_BoolPair(key, kMenuIcons, MenuIcons); Key_Set_BoolPair(key, kElimDup, ElimDup); + + Key_Set_UInt32(key, kWriteZoneId, WriteZone); if (Flags_Def) key.SetValue(kContextMenu, Flags); @@ -504,6 +547,8 @@ ElimDup.Val = true; ElimDup.Def = false; + WriteZone = (UInt32)(Int32)-1; + Flags = (UInt32)(Int32)-1; Flags_Def = false; @@ -517,5 +562,7 @@ Key_Get_BoolPair_true(key, kElimDup, ElimDup); Key_Get_BoolPair(key, kMenuIcons, MenuIcons); + Key_Get_UInt32(key, kWriteZoneId, WriteZone); + Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Common/ZipRegistry.h 7zip-22.01/CPP/7zip/UI/Common/ZipRegistry.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Common/ZipRegistry.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Common/ZipRegistry.h 2022-06-03 10:00:00.000000000 +0000 @@ -10,6 +10,16 @@ #include "ExtractMode.h" +/* +CBoolPair::Def in writing functions means: + if ( CBoolPair::Def ), we write CBoolPair::Val + if ( !CBoolPair::Def ) + { + in NCompression functions we delete registry value + in another functions we do nothing + } +*/ + namespace NExtract { struct CInfo @@ -75,12 +85,29 @@ UInt32 BlockLogSize; UInt32 NumThreads; + UInt32 TimePrec; + CBoolPair MTime; + CBoolPair ATime; + CBoolPair CTime; + CBoolPair SetArcMTime; + CSysString FormatID; UString Method; UString Options; UString EncryptionMethod; UString MemUse; + void Reset_TimePrec() + { + TimePrec = (UInt32)(Int32)-1; + } + + bool IsSet_TimePrec() const + { + return TimePrec != (UInt32)(Int32)-1; + } + + void Reset_BlockLogSize() { BlockLogSize = (UInt32)(Int32)-1; @@ -93,7 +120,12 @@ // Options.Empty(); // EncryptionMethod.Empty(); } - CFormatOptions() { ResetForLevelChange(); } + CFormatOptions() + { + // TimePrec = 0; + Reset_TimePrec(); + ResetForLevelChange(); + } }; struct CInfo @@ -111,6 +143,8 @@ CBoolPair HardLinks; CBoolPair SymLinks; + CBoolPair PreserveATime; + void Save() const; void Load(); }; @@ -152,9 +186,18 @@ CBoolPair Cascaded; CBoolPair MenuIcons; CBoolPair ElimDup; - + bool Flags_Def; UInt32 Flags; + UInt32 WriteZone; + + /* + CContextMenuInfo(): + Flags_Def(0), + WriteZone((UInt32)(Int32)-1), + Flags((UInt32)(Int32)-1) + {} + */ void Save() const; void Load(); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/Console.dsp 7zip-22.01/CPP/7zip/UI/Console/Console.dsp --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/Console.dsp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/Console.dsp 2022-07-14 06:00:00.000000000 +0000 @@ -345,6 +345,10 @@ # End Source File # Begin Source File +SOURCE=..\..\..\Windows\SecurityUtils.h +# End Source File +# Begin Source File + SOURCE=..\..\..\Windows\Synchronization.h # End Source File # Begin Source File diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp 7zip-22.01/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp 2022-04-29 17:00:00.000000000 +0000 @@ -56,6 +56,9 @@ HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError) { + // 22.00: + // ScanErrors.AddError(path, systemError); + ClosePercentsAndFlush(); if (_se) @@ -66,6 +69,10 @@ _se->Flush(); } return HRESULT_FROM_WIN32(systemError); + + // 22.00: commented + // CommonError(path, systemError, true); + // return S_OK; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/ExtractCallbackConsole.h 7zip-22.01/CPP/7zip/UI/Console/ExtractCallbackConsole.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/ExtractCallbackConsole.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/ExtractCallbackConsole.h 2022-04-29 17:00:00.000000000 +0000 @@ -15,12 +15,33 @@ #include "OpenCallbackConsole.h" +/* +struct CErrorPathCodes2 +{ + FStringVector Paths; + CRecordVector Codes; + + void AddError(const FString &path, DWORD systemError) + { + Paths.Add(path); + Codes.Add(systemError); + } + void Clear() + { + Paths.Clear(); + Codes.Clear(); + } +}; +*/ + class CExtractScanConsole: public IDirItemsCallback { CStdOutStream *_so; CStdOutStream *_se; CPercentPrinter _percent; + // CErrorPathCodes2 ScanErrors; + bool NeedPercents() const { return _percent._so != NULL; } void ClosePercentsAndFlush() diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/List.cpp 7zip-22.01/CPP/7zip/UI/Console/List.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/List.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/List.cpp 2022-05-18 12:00:00.000000000 +0000 @@ -124,6 +124,13 @@ , "Read-only" , "Out Name" , "Copy Link" + , "ArcFileName" + , "IsHash" + , "Metadata Changed" + , "User ID" + , "Group ID" + , "Device Major" + , "Device Minor" }; static const char kEmptyAttribChar = '.'; @@ -303,22 +310,18 @@ void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); } }; -struct CListFileTimeDef -{ - FILETIME Val; - bool Def; - CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; } +struct CListFileTimeDef: public CArcTime +{ void Update(const CListFileTimeDef &t) { - if (t.Def && (!Def || CompareFileTime(&Val, &t.Val) < 0)) - { - Val = t.Val; - Def = true; - } + if (t.Def && (!Def || CompareWith(t) < 0)) + (*this) = t; } }; + + struct CListStat { CListUInt64Def Size; @@ -493,12 +496,24 @@ g_StdOut << LinesString; } -static void PrintTime(char *dest, const FILETIME *ft) +static void PrintTime(char *dest, const CListFileTimeDef &t, bool showNS) { *dest = 0; - if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0) + if (t.IsZero()) return; - ConvertUtcFileTimeToString(*ft, dest, kTimestampPrintLevel_SEC); + int prec = kTimestampPrintLevel_SEC; + if (showNS) + { + prec = kTimestampPrintLevel_NTFS; + if (t.Prec != 0) + { + prec = t.GetNumDigits(); + if (prec < kTimestampPrintLevel_DAY) + prec = kTimestampPrintLevel_NTFS; + } + } + + ConvertUtcFileTimeToString2(t.FT, t.Ns100, dest, prec); } #ifndef _SFX @@ -631,7 +646,13 @@ { case kpidSize: if (st.Size.Def) prop = st.Size.Val; break; case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break; - case kpidMTime: if (st.MTime.Def) prop = st.MTime.Val; break; + case kpidMTime: + { + const CListFileTimeDef &mtime = st.MTime; + if (mtime.Def) + prop.SetAsTimeFrom_FT_Prec_Ns100(mtime.FT, mtime.Prec, mtime.Ns100); + break; + } default: RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop)); } @@ -653,7 +674,9 @@ } else if (prop.vt == VT_FILETIME) { - PrintTime(temp + tempPos, &prop.filetime); + CListFileTimeDef t; + t.Set_From_Prop(prop); + PrintTime(temp + tempPos, t, techMode); if (techMode) g_StdOut << temp + tempPos; else @@ -726,7 +749,7 @@ char s[64]; s[0] = 0; if (st.MTime.Def) - PrintTime(s, &st.MTime.Val); + PrintTime(s, st.MTime, false); // showNS PrintString(f.TextAdjustment, f.Width, s); } else if (f.PropID == kpidPath) @@ -770,16 +793,14 @@ static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t) { - t.Val.dwLowDateTime = 0; - t.Val.dwHighDateTime = 0; - t.Def = false; + /* maybe we could call CArc::GetItemMTime(UInt32 index, CArcTime &ft, bool &defined) here + that can set default timestamp, if not defined */ + t.Clear(); + // t.Def = false; CPropVariant prop; RINOK(archive->GetProperty(index, kpidMTime, &prop)); if (prop.vt == VT_FILETIME) - { - t.Val = prop.filetime; - t.Def = true; - } + t.Set_From_Prop(prop); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; @@ -879,7 +900,8 @@ static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop) { UString s; - ConvertPropertyToString2(s, prop, propID); + const int levelTopLimit = 9; // 1ns level + ConvertPropertyToString2(s, prop, propID, levelTopLimit); if (!s.IsEmpty()) { AString nameA; @@ -1249,7 +1271,7 @@ if (NConsoleClose::TestBreakSignal()) return E_ABORT; - HRESULT res = arc.GetItemPath2(i, fp.FilePath); + HRESULT res = arc.GetItem_Path2(i, fp.FilePath); if (stdInMode && res == E_INVALIDARG) break; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/Main.cpp 7zip-22.01/CPP/7zip/UI/Console/Main.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/Main.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/Main.cpp 2022-04-29 18:00:00.000000000 +0000 @@ -75,6 +75,8 @@ const CExternalCodecs *g_ExternalCodecs_Ptr; #endif +DECLARE_AND_SET_CLIENT_VERSION_VAR + #if defined(PROG_VARIANT_Z) #define PROG_POSTFIX "z" #define PROG_POSTFIX_2 " (z)" @@ -510,7 +512,7 @@ , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT)) return; FILETIME curTimeFT; - NTime::GetCurUtcFileTime(curTimeFT); + NTime::GetCurUtc_FiTime(curTimeFT); #ifndef UNDER_CE @@ -845,7 +847,7 @@ #if !defined(UNDER_CE) CONSOLE_SCREEN_BUFFER_INFO consoleInfo; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo)) - consoleWidth = (unsigned)consoleInfo.dwSize.X; + consoleWidth = (unsigned)(unsigned short)consoleInfo.dwSize.X; #endif #else @@ -859,7 +861,7 @@ CREATE_CODECS_OBJECT - codecs->CaseSensitiveChange = options.CaseSensitiveChange; + codecs->CaseSensitive_Change = options.CaseSensitive_Change; codecs->CaseSensitive = options.CaseSensitive; ThrowException_if_Error(codecs->Load()); Codecs_AddHashArcHandler(codecs); @@ -952,9 +954,11 @@ so << endl << "Formats:" << endl; - const char * const kArcFlags = "KSNFMGOPBELHXC"; + const char * const kArcFlags = "KSNFMGOPBELHXCc+a+m+r+"; + const char * const kArcTimeFlags = "wudn"; const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags); - + const unsigned kNumArcTimeFlags = (unsigned)strlen(kArcTimeFlags); + for (i = 0; i < codecs->Formats.Size(); i++) { const CArcInfoEx &arc = codecs->Formats[i]; @@ -967,12 +971,22 @@ so << (char)(arc.UpdateEnabled ? 'C' : ' '); - for (unsigned b = 0; b < kNumArcFlags; b++) { - so << (char) - ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' '); + unsigned b; + for (b = 0; b < kNumArcFlags; b++) + so << (char)((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : '.'); + so << ' '; } - + + if (arc.TimeFlags != 0) + { + unsigned b; + for (b = 0; b < kNumArcTimeFlags; b++) + so << (char)((arc.TimeFlags & ((UInt32)1 << b)) != 0 ? kArcTimeFlags[b] : '.'); + so << arc.Get_DefaultTimePrec(); + so << ' '; + } + so << ' '; PrintString(so, arc.Name, 8); so << ' '; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/makefile.gcc 7zip-22.01/CPP/7zip/UI/Console/makefile.gcc --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/makefile.gcc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/makefile.gcc 2022-07-14 11:00:00.000000000 +0000 @@ -9,11 +9,20 @@ LOCAL_FLAGS_ST = MT_OBJS = +ifdef SystemDrive +IS_MINGW = 1 +else +ifdef SYSTEMDRIVE +# ifdef OS +IS_MINGW = 1 +endif +endif + ifdef ST_MODE LOCAL_FLAGS_ST = -D_7ZIP_ST -ifdef SystemDrive +ifdef IS_MINGW MT_OBJS = \ $O/Threads.o \ @@ -31,7 +40,7 @@ LOCAL_FLAGS_WIN= -ifdef SystemDrive +ifdef IS_MINGW LOCAL_FLAGS_WIN = \ -D_7ZIP_LARGE_PAGES \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/PercentPrinter.cpp 7zip-22.01/CPP/7zip/UI/Console/PercentPrinter.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/PercentPrinter.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/PercentPrinter.cpp 2022-04-13 08:00:00.000000000 +0000 @@ -63,7 +63,8 @@ { char c = '%'; UInt64 val = 0; - if (Total == (UInt64)(Int64)-1) + if (Total == (UInt64)(Int64)-1 || + (Total == 0 && Completed != 0)) { val = Completed >> 20; c = 'M'; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp 7zip-22.01/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp 2022-04-29 10:00:00.000000000 +0000 @@ -11,6 +11,8 @@ #include "../../../Windows/Synchronization.h" #endif +// #include "../Common/PropIDUtils.h" + #include "ConsoleClose.h" #include "UserInputUtils.h" #include "UpdateCallbackConsole.h" @@ -195,6 +197,22 @@ } } +/* +void CCallbackConsoleBase::CommonError(const char *message) +{ + ClosePercents2(); + + if (_se) + { + if (_so) + _so->Flush(); + + *_se << endl << kError << message << endl; + _se->Flush(); + } +} +*/ + HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError) { @@ -519,6 +537,28 @@ return CheckBreak2(); } + +/* +void CCallbackConsoleBase::PrintInfoLine(const UString &s) +{ + if (LogLevel < 1000) + return; + + MT_LOCK + + const bool show2 = (_so != NULL); + + if (show2) + { + ClosePercents_for_so(); + _so->PrintUString(s, _tempA); + *_so << endl; + if (NeedFlush) + _so->Flush(); + } +} +*/ + HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) { if (StdOutMode) @@ -562,10 +602,19 @@ return ReadingFileError_Base(path, systemError); } -HRESULT CUpdateCallbackConsole::SetOperationResult(Int32) +HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 /* opRes */) { MT_LOCK _percent.Files++; + /* + if (opRes != NArchive::NUpdate::NOperationResult::kOK) + { + if (opRes == NArchive::NUpdate::NOperationResult::kError_FileChanged) + { + CommonError("Input file changed"); + } + } + */ return S_OK; } @@ -616,6 +665,8 @@ case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break; case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break; case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break; + case NUpdateNotifyOp::kInFileChanged: s = "Size of input file was changed:"; requiredLevel = 10; break; + // case NUpdateNotifyOp::kOpFinished: s = "Finished"; requiredLevel = 100; break; default: { temp[0] = 'o'; @@ -710,3 +761,119 @@ } return S_OK; } + +/* +void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU); + +static void GetPropName(PROPID propID, UString &nameU) +{ + AString nameA; + GetPropName(propID, NULL, nameA, nameU); + // if (!nameA.IsEmpty()) + nameU = nameA; +} + + +static void AddPropNamePrefix(UString &s, PROPID propID) +{ + UString name; + GetPropName(propID, name); + s += name; + s += " = "; +} + +void CCallbackConsoleBase::PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value) +{ + AddPropNamePrefix(s, propID); + { + UString dest; + const int level = 9; // we show up to ns precision level + ConvertPropertyToString2(dest, *value, propID, level); + s += dest; + } + PrintInfoLine(s); +} + +static void Add_IndexType_Index(UString &s, UInt32 indexType, UInt32 index) +{ + if (indexType == NArchive::NEventIndexType::kArcProp) + { + } + else + { + if (indexType == NArchive::NEventIndexType::kBlockIndex) + { + s += "#"; + } + else if (indexType == NArchive::NEventIndexType::kOutArcIndex) + { + } + else + { + s += "indexType_"; + s.Add_UInt32(indexType); + s.Add_Space(); + } + s.Add_UInt32(index); + } + s += ": "; +} + +HRESULT CUpdateCallbackConsole::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) +{ + UString s; + Add_IndexType_Index(s, indexType, index); + PrintPropInfo(s, propID, value); + return S_OK; +} + +static inline char GetHex(Byte value) +{ + return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10))); +} + +static void AddHexToString(UString &dest, const Byte *data, UInt32 size) +{ + for (UInt32 i = 0; i < size; i++) + { + Byte b = data[i]; + dest += GetHex((Byte)((b >> 4) & 0xF)); + dest += GetHex((Byte)(b & 0xF)); + } +} + +void HashHexToString(char *dest, const Byte *data, UInt32 size); + +HRESULT CUpdateCallbackConsole::ReportRawProp(UInt32 indexType, UInt32 index, + PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) +{ + UString s; + propType = propType; + Add_IndexType_Index(s, indexType, index); + AddPropNamePrefix(s, propID); + if (propID == kpidChecksum) + { + char temp[k_HashCalc_DigestSize_Max + 8]; + HashHexToString(temp, (const Byte *)data, dataSize); + s += temp; + } + else + AddHexToString(s, (const Byte *)data, dataSize); + PrintInfoLine(s); + return S_OK; +} + +HRESULT CUpdateCallbackConsole::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) +{ + UString s; + Add_IndexType_Index(s, indexType, index); + s += "finished"; + if (opRes != NArchive::NUpdate::NOperationResult::kOK) + { + s += ": "; + s.Add_UInt32(opRes); + } + PrintInfoLine(s); + return S_OK; +} +*/ diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Console/UpdateCallbackConsole.h 7zip-22.01/CPP/7zip/UI/Console/UpdateCallbackConsole.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Console/UpdateCallbackConsole.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Console/UpdateCallbackConsole.h 2022-04-29 10:00:00.000000000 +0000 @@ -35,7 +35,8 @@ CStdOutStream *_se; void CommonError(const FString &path, DWORD systemError, bool isWarning); - + // void CommonError(const char *message); + HRESULT ScanError_Base(const FString &path, DWORD systemError); HRESULT OpenFileError_Base(const FString &name, DWORD systemError); HRESULT ReadingFileError_Base(const FString &name, DWORD systemError); @@ -89,6 +90,8 @@ HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog); + // void PrintInfoLine(const UString &s); + // void PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value); }; class CUpdateCallbackConsole: public IUpdateCallbackUI2, public CCallbackConsoleBase diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Explorer/ContextMenu.cpp 7zip-22.01/CPP/7zip/UI/Explorer/ContextMenu.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/Explorer/ContextMenu.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Explorer/ContextMenu.cpp 2022-05-26 11:00:00.000000000 +0000 @@ -102,6 +102,7 @@ _isMenuForFM(false), _dropMode(false), _bitmap(NULL), + _writeZone((UInt32)(Int32)-1), IsSeparator(false), IsRoot(true), CurrentSubCommand(0) @@ -560,6 +561,7 @@ ci.Load(); _elimDup = ci.ElimDup; + _writeZone = ci.WriteZone; HBITMAP bitmap = NULL; if (ci.MenuIcons.Val) @@ -1167,7 +1169,8 @@ { ExtractArchives(_fileNames, cmi.Folder, (cmdID == kExtract), // showDialog - (cmdID == kExtractTo) && _elimDup.Val // elimDup + (cmdID == kExtractTo) && _elimDup.Val, // elimDup + _writeZone ); break; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Explorer/ContextMenu.h 7zip-22.01/CPP/7zip/UI/Explorer/ContextMenu.h --- 7zip-21.07+dfsg/CPP/7zip/UI/Explorer/ContextMenu.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Explorer/ContextMenu.h 2022-06-06 10:00:00.000000000 +0000 @@ -129,6 +129,7 @@ HBITMAP _bitmap; CBoolPair _elimDup; + UInt32 _writeZone; bool IsSeparator; bool IsRoot; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/Explorer/resource.rc 7zip-22.01/CPP/7zip/UI/Explorer/resource.rc --- 7zip-21.07+dfsg/CPP/7zip/UI/Explorer/resource.rc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/Explorer/resource.rc 2022-07-14 12:00:00.000000000 +0000 @@ -7,4 +7,4 @@ 1 24 MOVEABLE PURE "7-zip.dll.manifest" #endif -IDI_ICON ICON "..\FileManager\FM.ico" +IDI_ICON ICON "../FileManager/FM.ico" diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/FSFolderCopy.cpp 7zip-22.01/CPP/7zip/UI/FileManager/FSFolderCopy.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/FSFolderCopy.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/FSFolderCopy.cpp 2022-07-15 08:00:00.000000000 +0000 @@ -29,6 +29,9 @@ extern bool g_IsNT; #endif +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + namespace NFsFolder { HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib) @@ -245,7 +248,9 @@ my_CopyFileExA = NULL; if (!g_IsNT) { - my_CopyFileExA = (Func_CopyFileExA)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA"); + my_CopyFileExA = (Func_CopyFileExA) + MY_CAST_FUNC + ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "CopyFileExA"); } else #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/FSFolder.cpp 7zip-22.01/CPP/7zip/UI/FileManager/FSFolder.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/FSFolder.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/FSFolder.cpp 2022-07-14 08:00:00.000000000 +0000 @@ -2,11 +2,24 @@ #include "StdAfx.h" +#if defined(_MSC_VER) +#include +#else +#if defined(__GNUC__) && (__GNUC__ >= 10) + // new mingw: + #include +#else + // old mingw: + #include +#endif +#endif + #include "../../../Common/ComTry.h" #include "../../../Common/Defs.h" #include "../../../Common/StringConvert.h" #include "../../../Common/UTFConvert.h" +#include "../../../Windows/DLL.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileIO.h" #include "../../../Windows/FileName.h" @@ -56,12 +69,15 @@ kpidMTime, kpidCTime, kpidATime, + #ifdef FS_SHOW_LINKS_INFO + kpidChangeTime, + #endif kpidAttrib, kpidPackSize, - #ifdef FS_SHOW_LINKS_INFO + #ifdef FS_SHOW_LINKS_INFO kpidINode, kpidLinks, - #endif + #endif kpidComment, kpidNumSubDirs, kpidNumSubFiles, @@ -199,19 +215,23 @@ */ } - #ifndef UNDER_CE + #ifndef UNDER_CE fi.Reparse.Free(); fi.PackSize_Defined = false; - #ifdef FS_SHOW_LINKS_INFO + #ifdef FS_SHOW_LINKS_INFO fi.FileInfo_Defined = false; fi.FileInfo_WasRequested = false; fi.FileIndex = 0; fi.NumLinks = 0; - #endif + fi.ChangeTime_Defined = false; + fi.ChangeTime_WasRequested = false; + #endif fi.PackSize = fi.Size; + + #ifdef FS_SHOW_LINKS_INFO if (fi.HasReparsePoint()) { fi.FileInfo_WasRequested = true; @@ -221,8 +241,9 @@ fi.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow; fi.FileInfo_Defined = true; } + #endif - #endif + #endif // UNDER_CE /* unsigned fileIndex = */ Files.Add(fi); @@ -396,7 +417,9 @@ #endif + #ifdef FS_SHOW_LINKS_INFO + bool CFSFolder::ReadFileInfo(CDirItem &di) { di.FileInfo_WasRequested = true; @@ -409,7 +432,71 @@ di.FileInfo_Defined = true; return true; } -#endif + + +typedef struct +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; + UInt32 Reserved; // it's expected for alignment +} +MY__FILE_BASIC_INFORMATION; + + +typedef enum +{ + MY__FileDirectoryInformation = 1, + MY__FileFullDirectoryInformation, + MY__FileBothDirectoryInformation, + MY__FileBasicInformation +} +MY__FILE_INFORMATION_CLASS; + + +typedef NTSTATUS (WINAPI * Func_NtQueryInformationFile)( + HANDLE handle, IO_STATUS_BLOCK *io, + void *ptr, LONG len, MY__FILE_INFORMATION_CLASS cls); + +#define MY__STATUS_SUCCESS 0 + +static Func_NtQueryInformationFile f_NtQueryInformationFile; +static bool g_NtQueryInformationFile_WasRequested = false; + +void CFSFolder::ReadChangeTime(CDirItem &di) +{ + di.ChangeTime_WasRequested = true; + + if (!g_NtQueryInformationFile_WasRequested) + { + g_NtQueryInformationFile_WasRequested = true; + f_NtQueryInformationFile = (Func_NtQueryInformationFile) + My_GetProcAddress(::GetModuleHandleW(L"ntdll.dll"), + "NtQueryInformationFile"); + } + if (!f_NtQueryInformationFile) + return; + + NIO::CInFile file; + if (!file.Open_for_ReadAttributes(_path + GetRelPath(di))) + return; + MY__FILE_BASIC_INFORMATION fbi; + IO_STATUS_BLOCK IoStatusBlock; + const NTSTATUS status = f_NtQueryInformationFile(file.GetHandle(), &IoStatusBlock, + &fbi, sizeof(fbi), MY__FileBasicInformation); + if (status != MY__STATUS_SUCCESS) + return; + if (IoStatusBlock.Information != sizeof(fbi)) + return; + di.ChangeTime.dwLowDateTime = fbi.ChangeTime.u.LowPart; + di.ChangeTime.dwHighDateTime = fbi.ChangeTime.u.HighPart; + di.ChangeTime_Defined = true; +} + +#endif // FS_SHOW_LINKS_INFO + STDMETHODIMP CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { @@ -492,7 +579,14 @@ prop = fi.FileIndex; #endif break; - + + case kpidChangeTime: + if (!fi.ChangeTime_WasRequested) + ReadChangeTime(fi); + if (fi.ChangeTime_Defined) + prop = fi.ChangeTime; + break; + #endif case kpidAttrib: prop = (UInt32)fi.Attrib; break; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/FSFolder.h 7zip-22.01/CPP/7zip/UI/FileManager/FSFolder.h --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/FSFolder.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/FSFolder.h 2022-04-14 10:00:00.000000000 +0000 @@ -18,6 +18,7 @@ class CFSFolder; #define FS_SHOW_LINKS_INFO +// #define FS_SHOW_CHANGE_TIME struct CDirItem: public NWindows::NFile::NFind::CFileInfo { @@ -26,10 +27,13 @@ #endif #ifdef FS_SHOW_LINKS_INFO + FILETIME ChangeTime; UInt64 FileIndex; UInt32 NumLinks; bool FileInfo_Defined; bool FileInfo_WasRequested; + bool ChangeTime_Defined; + bool ChangeTime_WasRequested; #endif #ifndef UNDER_CE @@ -158,6 +162,7 @@ #ifdef FS_SHOW_LINKS_INFO bool ReadFileInfo(CDirItem &di); + void ReadChangeTime(CDirItem &di); #endif public: diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/HelpUtils.cpp 7zip-22.01/CPP/7zip/UI/FileManager/HelpUtils.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/HelpUtils.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/HelpUtils.cpp 2022-04-22 12:00:00.000000000 +0000 @@ -12,7 +12,20 @@ #else +// #define USE_EXTERNAL_HELP + +#if defined(_MSC_VER) +#endif + +#ifdef USE_EXTERNAL_HELP + +#include "../../../Windows/ProcessUtils.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileName.h" + +#else #include +#endif #include "../../../Common/StringConvert.h" @@ -25,8 +38,37 @@ FString path = NWindows::NDLL::GetModuleDirPrefix(); path += kHelpFileName; path += topicFile; + #ifdef USE_EXTERNAL_HELP + FString prog; + + #ifdef UNDER_CE + prog = "\\Windows\\"; + #else + if (!NWindows::NFile::NDir::GetWindowsDir(prog)) + return; + NWindows::NFile::NName::NormalizeDirPathPrefix(prog); + #endif + prog += "hh.exe"; + + UString params; + params += '"'; + params += fs2us(path); + params += '"'; + + NWindows::CProcess process; + const WRes wres = process.Create(fs2us(prog), params, NULL); // curDir); + if (wres != 0) + { + /* + HRESULT hres = HRESULT_FROM_WIN32(wres); + ErrorMessageHRESULT(hres, imageName); + return hres; + */ + } + #else // HWND hwnd = NULL; HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0); + #endif } #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPage2.rc 7zip-22.01/CPP/7zip/UI/FileManager/MenuPage2.rc --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPage2.rc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/MenuPage2.rc 2022-06-06 10:00:00.000000000 +0000 @@ -1,6 +1,8 @@ #include "../GUI/ExtractDialogRes.h" -#define y 82 +#define y 96 + +#define zoneX 90 CAPTION "7-Zip" BEGIN @@ -10,8 +12,17 @@ CONTROL "Icons in context menu", IDX_SYSTEM_ICON_IN_MENU, MY_CHECKBOX, m, m + 42, xc, 10 CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX, m, m + 56, xc, 10 - LTEXT "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 70, xc, 8 + LTEXT "Propagate Zone.Id stream:", IDT_SYSTEM_ZONE, m, m + 70, xc - zoneX, 8 + COMBOBOX IDC_SYSTEM_ZONE, m + xc - zoneX, m + 70 - 2, zoneX, 50, MY_COMBO + + LTEXT "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 84, xc, 8 CONTROL "List", IDL_SYSTEM_OPTIONS, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP, m, m + y, xc, yc - y END + + +STRINGTABLE +BEGIN + IDT_ZONE_FOR_OFFICE "For Office files" +END diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPage.cpp 7zip-22.01/CPP/7zip/UI/FileManager/MenuPage.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPage.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/MenuPage.cpp 2022-06-11 12:00:00.000000000 +0000 @@ -32,6 +32,7 @@ IDX_SYSTEM_CASCADED_MENU, IDX_SYSTEM_ICON_IN_MENU, IDX_EXTRACT_ELIM_DUP, + IDT_SYSTEM_ZONE, IDT_SYSTEM_CONTEXT_MENU_ITEMS }; @@ -80,6 +81,16 @@ #define KEY_WOW64_32KEY (0x0200) #endif + +static void LoadLang_Spec(UString &s, UInt32 id, const char *eng) +{ + LangString(id, s); + if (s.IsEmpty()) + s = eng; + s.RemoveChar(L'&'); +} + + bool CMenuPage::OnInit() { _initMode = true; @@ -176,6 +187,44 @@ CheckButton(IDX_EXTRACT_ELIM_DUP, ci.ElimDup.Val); _listView.Attach(GetItem(IDL_SYSTEM_OPTIONS)); + _zoneCombo.Attach(GetItem(IDC_SYSTEM_ZONE)); + + { + unsigned wz = ci.WriteZone; + if (wz == (UInt32)(Int32)-1) + wz = 0; + for (unsigned i = 0; i <= 3; i++) + { + unsigned val = i; + UString s; + if (i == 3) + { + if (wz < 3) + break; + val = wz; + } + else + { + #define MY_IDYES 406 + #define MY_IDNO 407 + if (i == 0) + LoadLang_Spec(s, MY_IDNO, "No"); + else if (i == 1) + LoadLang_Spec(s, MY_IDYES, "Yes"); + else + LangString(IDT_ZONE_FOR_OFFICE, s); + } + if (s.IsEmpty()) + s.Add_UInt32(val); + if (i == 0) + s.Insert(0, L"* "); + const int index = (int)_zoneCombo.AddString(s); + _zoneCombo.SetItemData(index, val); + if (val == wz) + _zoneCombo.SetCurSel(index); + } + } + const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT; _listView.SetExtendedListViewStyle(newFlags, newFlags); @@ -266,7 +315,11 @@ #endif - if (_cascaded_Changed || _menuIcons_Changed || _elimDup_Changed || _flags_Changed) + if (_cascaded_Changed + || _menuIcons_Changed + || _elimDup_Changed + || _writeZone_Changed + || _flags_Changed) { CContextMenuInfo ci; ci.Cascaded.Val = IsButtonCheckedBool(IDX_SYSTEM_CASCADED_MENU); @@ -278,6 +331,13 @@ ci.ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP); ci.ElimDup.Def = _elimDup_Changed; + { + int zoneIndex = (int)_zoneCombo.GetItemData_of_CurSel(); + if (zoneIndex <= 0) + zoneIndex = -1; + ci.WriteZone = (UInt32)(Int32)zoneIndex; + } + ci.Flags = 0; for (unsigned i = 0; i < ARRAY_SIZE(kMenuItems); i++) @@ -321,6 +381,7 @@ case IDX_SYSTEM_CASCADED_MENU: _cascaded_Changed = true; break; case IDX_SYSTEM_ICON_IN_MENU: _menuIcons_Changed = true; break; case IDX_EXTRACT_ELIM_DUP: _elimDup_Changed = true; break; + // case IDX_EXTRACT_WRITE_ZONE: _writeZone_Changed = true; break; default: return CPropertyPage::OnButtonClicked(buttonID, buttonHWND); @@ -330,6 +391,19 @@ return true; } + +bool CMenuPage::OnCommand(int code, int itemID, LPARAM param) +{ + if (code == CBN_SELCHANGE && itemID == IDC_SYSTEM_ZONE) + { + _writeZone_Changed = true; + Changed(); + return true; + } + return CPropertyPage::OnCommand(code, itemID, param); +} + + bool CMenuPage::OnNotify(UINT controlID, LPNMHDR lParam) { if (lParam->hwndFrom == HWND(_listView)) diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPage.h 7zip-22.01/CPP/7zip/UI/FileManager/MenuPage.h --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPage.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/MenuPage.h 2022-05-30 12:00:00.000000000 +0000 @@ -4,6 +4,7 @@ #define __MENU_PAGE_H #include "../../../Windows/Control/PropertyPage.h" +#include "../../../Windows/Control/ComboBox.h" #include "../../../Windows/Control/ListView.h" struct CShellDll @@ -24,6 +25,7 @@ bool _cascaded_Changed; bool _menuIcons_Changed; bool _elimDup_Changed; + bool _writeZone_Changed; bool _flags_Changed; void Clear_MenuChanged() @@ -31,6 +33,7 @@ _cascaded_Changed = false; _menuIcons_Changed = false; _elimDup_Changed = false; + _writeZone_Changed = false; _flags_Changed = false; } @@ -39,6 +42,7 @@ #endif NWindows::NControl::CListView _listView; + NWindows::NControl::CComboBox _zoneCombo; virtual bool OnInit(); virtual void OnNotifyHelp(); @@ -46,6 +50,7 @@ virtual bool OnItemChanged(const NMLISTVIEW *info); virtual LONG OnApply(); virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + virtual bool OnCommand(int code, int itemID, LPARAM param); public: }; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPageRes.h 7zip-22.01/CPP/7zip/UI/FileManager/MenuPageRes.h --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MenuPageRes.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/MenuPageRes.h 2022-06-06 10:00:00.000000000 +0000 @@ -8,4 +8,8 @@ #define IDX_SYSTEM_INTEGRATE_TO_MENU_2 2310 +#define IDT_SYSTEM_ZONE 3440 +#define IDT_ZONE_FOR_OFFICE 3441 + #define IDL_SYSTEM_OPTIONS 100 +#define IDC_SYSTEM_ZONE 101 diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MyCom2.h 7zip-22.01/CPP/7zip/UI/FileManager/MyCom2.h --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MyCom2.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/MyCom2.h 2022-07-14 08:00:00.000000000 +0000 @@ -7,8 +7,9 @@ #define MY_ADDREF_RELEASE_MT \ STDMETHOD_(ULONG, AddRef)() { InterlockedIncrement((LONG *)&__m_RefCount); return __m_RefCount; } \ -STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); if (__m_RefCount != 0) \ - return __m_RefCount; delete this; return 0; } +STDMETHOD_(ULONG, Release)() { InterlockedDecrement((LONG *)&__m_RefCount); \ + if (__m_RefCount != 0) return __m_RefCount; \ + delete this; return 0; } #define MY_UNKNOWN_IMP_SPEC_MT2(i1, i) \ MY_QUERYINTERFACE_BEGIN \ diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MyLoadMenu.cpp 7zip-22.01/CPP/7zip/UI/FileManager/MyLoadMenu.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/MyLoadMenu.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/MyLoadMenu.cpp 2022-01-14 16:00:00.000000000 +0000 @@ -380,7 +380,8 @@ kTimestampPrintLevel_MIN, kTimestampPrintLevel_SEC, // 1,2,3,4,5,6, - kTimestampPrintLevel_NTFS + kTimestampPrintLevel_NTFS, + kTimestampPrintLevel_NS }; unsigned last = kMenuID_Time; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelCopy.cpp 7zip-22.01/CPP/7zip/UI/FileManager/PanelCopy.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelCopy.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PanelCopy.cpp 2022-06-06 10:00:00.000000000 +0000 @@ -4,6 +4,8 @@ #include "../../../Common/MyException.h" +#include "../Common/ZipRegistry.h" + #include "../GUI/HashGUI.h" #include "ExtractCallback.h" @@ -70,6 +72,15 @@ HRESULT result2; + { + CMyComPtr setZoneMode; + FolderOperations.QueryInterface(IID_IFolderSetZoneIdMode, &setZoneMode); + if (setZoneMode) + { + RINOK(setZoneMode->SetZoneIdMode(options->ZoneIdMode)); + } + } + if (options->testMode) { CMyComPtr archiveFolder; @@ -126,6 +137,14 @@ UStringVector *messages, bool &usePassword, UString &password) { + if (options.NeedRegistryZone && !options.testMode) + { + CContextMenuInfo ci; + ci.Load(); + if (ci.WriteZone != (UInt32)(Int32)-1) + options.ZoneIdMode = (NExtract::NZoneIdMode::EEnum)(int)(Int32)ci.WriteZone; + } + if (IsHashFolder()) { if (!options.testMode) @@ -221,7 +240,7 @@ title = LangString(titleID); } - UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE); + const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE); extracter.MainWindow = GetParent(); extracter.MainTitle = progressWindowTitle; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/Panel.cpp 7zip-22.01/CPP/7zip/UI/FileManager/Panel.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/Panel.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/Panel.cpp 2022-06-03 11:00:00.000000000 +0000 @@ -20,6 +20,7 @@ #include "../Common/ArchiveName.h" #include "../Common/CompressCall.h" +#include "../Common/ZipRegistry.h" #include "../Agent/IFolderArchive.h" @@ -971,9 +972,13 @@ outFolder += '*'; outFolder.Add_PathSepar(); + CContextMenuInfo ci; + ci.Load(); + ::ExtractArchives(paths, outFolder , true // showDialog , false // elimDup + , ci.WriteZone ); } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelCrc.cpp 7zip-22.01/CPP/7zip/UI/FileManager/PanelCrc.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelCrc.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PanelCrc.cpp 2022-06-01 10:00:00.000000000 +0000 @@ -351,6 +351,7 @@ options.streamMode = true; options.showErrorMessages = true; options.hashMethods.Add(methodName); + options.NeedRegistryZone = false; UStringVector messages; return srcPanel.CopyTo(options, indices, &messages); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/Panel.h 7zip-22.01/CPP/7zip/UI/FileManager/Panel.h --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/Panel.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/Panel.h 2022-05-31 12:00:00.000000000 +0000 @@ -244,6 +244,9 @@ bool replaceAltStreamChars; bool showErrorMessages; + bool NeedRegistryZone; + NExtract::NZoneIdMode::EEnum ZoneIdMode; + UString folder; UStringVector hashMethods; @@ -258,6 +261,8 @@ includeAltStreams(true), replaceAltStreamChars(false), showErrorMessages(false), + NeedRegistryZone(true), + ZoneIdMode(NExtract::NZoneIdMode::kNone), VirtFileSystemSpec(NULL), VirtFileSystem(NULL) {} diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelItemOpen.cpp 7zip-22.01/CPP/7zip/UI/FileManager/PanelItemOpen.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelItemOpen.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PanelItemOpen.cpp 2022-06-06 10:00:00.000000000 +0000 @@ -1403,7 +1403,7 @@ } - +/* #if defined(_WIN32) && !defined(UNDER_CE) static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier"); #endif @@ -1441,6 +1441,7 @@ } #endif +*/ /* class CBufSeqOutStream_WithFile: @@ -1654,6 +1655,7 @@ password = fl.Password; } + /* #if defined(_WIN32) && !defined(UNDER_CE) CByteBuffer zoneBuf; #ifndef _UNICODE @@ -1666,16 +1668,25 @@ ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf); } #endif + */ CVirtFileSystem *virtFileSystemSpec = NULL; CMyComPtr virtFileSystem; - bool isAltStream = IsItem_AltStream(index); + const bool isAltStream = IsItem_AltStream(index); CCopyToOptions options; options.includeAltStreams = true; options.replaceAltStreamChars = isAltStream; + { + // CContextMenuInfo ci; + // ci.Load(); + // if (ci.WriteZone != (UInt32)(Int32)-1) + // we use kAll when we unpack just one file. + options.ZoneIdMode = NExtract::NZoneIdMode::kAll; + options.NeedRegistryZone = false; + } if (tryAsArchive) { @@ -1706,7 +1717,7 @@ options.folder = fs2us(tempDirNorm); options.showErrorMessages = true; - HRESULT result = CopyTo(options, indices, &messages, usePassword, password); + const HRESULT result = CopyTo(options, indices, &messages, usePassword, password); if (_parentFolders.Size() > 0) { @@ -1759,6 +1770,7 @@ } + /* #if defined(_WIN32) && !defined(UNDER_CE) if (zoneBuf.Size() != 0) { @@ -1768,6 +1780,7 @@ } } #endif + */ if (tryAsArchive) diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelItems.cpp 7zip-22.01/CPP/7zip/UI/FileManager/PanelItems.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelItems.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PanelItems.cpp 2022-01-23 12:00:00.000000000 +0000 @@ -29,6 +29,7 @@ switch (propID) { case kpidATime: + case kpidChangeTime: case kpidAttrib: case kpidPackSize: case kpidINode: @@ -56,6 +57,7 @@ case kpidCTime: case kpidATime: case kpidMTime: + case kpidChangeTime: return LVCFMT_LEFT; } @@ -201,7 +203,7 @@ for (i = 0; i < _listViewInfo.Columns.Size(); i++) { const CColumnInfo &columnInfo = _listViewInfo.Columns[i]; - int index = _columns.FindItem_for_PropID(columnInfo.PropID); + const int index = _columns.FindItem_for_PropID(columnInfo.PropID); if (index >= 0) { CPropColumn &item = _columns[index]; @@ -650,7 +652,7 @@ relPath += name; if (relPath == state.FocusedName) cursorIndex = listViewItemCount; - if (state.SelectedNames.FindInSorted(relPath) >= 0) + if (state.SelectedNames.FindInSorted(relPath) != -1) selected = true; } diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelMenu.cpp 7zip-22.01/CPP/7zip/UI/FileManager/PanelMenu.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelMenu.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PanelMenu.cpp 2022-04-28 11:00:00.000000000 +0000 @@ -111,7 +111,7 @@ val = ConvertSizeToString(v); } else - ConvertPropertyToString2(val, prop, propID); + ConvertPropertyToString2(val, prop, propID, 9); // we send 9 - is ns precision } if (!val.IsEmpty()) diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelOperations.cpp 7zip-22.01/CPP/7zip/UI/FileManager/PanelOperations.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PanelOperations.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PanelOperations.cpp 2022-07-15 08:00:00.000000000 +0000 @@ -24,6 +24,9 @@ using namespace NFile; using namespace NName; +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + #ifndef _UNICODE extern bool g_IsNT; #endif @@ -96,7 +99,7 @@ } #ifndef _UNICODE -typedef int (WINAPI * SHFileOperationWP)(LPSHFILEOPSTRUCTW lpFileOp); +typedef int (WINAPI * Func_SHFileOperationW)(LPSHFILEOPSTRUCTW lpFileOp); #endif /* @@ -192,9 +195,10 @@ #ifdef _UNICODE /* res = */ ::SHFileOperationW(&fo); #else - SHFileOperationWP shFileOperationW = (SHFileOperationWP) + Func_SHFileOperationW shFileOperationW = (Func_SHFileOperationW) + MY_CAST_FUNC ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHFileOperationW"); - if (shFileOperationW == 0) + if (!shFileOperationW) return; /* res = */ shFileOperationW(&fo); #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PropertyName.rc 7zip-22.01/CPP/7zip/UI/FileManager/PropertyName.rc --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PropertyName.rc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PropertyName.rc 2022-04-27 13:00:00.000000000 +0000 @@ -97,4 +97,11 @@ IDS_PROP_READ_ONLY "Read-only" IDS_PROP_OUT_NAME "Out Name" IDS_PROP_COPY_LINK "Copy Link" + IDS_PROP_ARC_FILE_NAME "ArcFileName" + IDS_PROP_IS_HASH "IsHash" + IDS_PROP_CHANGE_TIME "Metadata Changed" + IDS_PROP_USER_ID "User ID" + IDS_PROP_GROUP_ID "Group ID" + IDS_PROP_DEVICE_MAJOR "Device Major" + IDS_PROP_DEVICE_MINOR "Device Minor" END diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PropertyNameRes.h 7zip-22.01/CPP/7zip/UI/FileManager/PropertyNameRes.h --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/PropertyNameRes.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/PropertyNameRes.h 2022-04-01 12:00:00.000000000 +0000 @@ -93,3 +93,10 @@ #define IDS_PROP_READ_ONLY 1093 #define IDS_PROP_OUT_NAME 1094 #define IDS_PROP_COPY_LINK 1095 +#define IDS_PROP_ARC_FILE_NAME 1096 +#define IDS_PROP_IS_HASH 1097 +#define IDS_PROP_CHANGE_TIME 1098 +#define IDS_PROP_USER_ID 1099 +#define IDS_PROP_GROUP_ID 1100 +#define IDS_PROP_DEVICE_MAJOR 1101 +#define IDS_PROP_DEVICE_MINOR 1102 diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/SysIconUtils.cpp 7zip-22.01/CPP/7zip/UI/FileManager/SysIconUtils.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/SysIconUtils.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/SysIconUtils.cpp 2022-07-15 08:00:00.000000000 +0000 @@ -12,6 +12,9 @@ #include +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + #ifndef _UNICODE extern bool g_IsNT; #endif @@ -39,15 +42,16 @@ } #ifndef _UNICODE -typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); +typedef int (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags); static struct CSHGetFileInfoInit { - SHGetFileInfoWP shGetFileInfoW; + Func_SHGetFileInfoW shGetFileInfoW; CSHGetFileInfoInit() { - shGetFileInfoW = (SHGetFileInfoWP) - ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW"); + shGetFileInfoW = (Func_SHGetFileInfoW) + MY_CAST_FUNC + ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW"); } } g_SHGetFileInfoInit; #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/TextPairs.cpp 7zip-22.01/CPP/7zip/UI/FileManager/TextPairs.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/FileManager/TextPairs.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/FileManager/TextPairs.cpp 2022-07-14 08:00:00.000000000 +0000 @@ -104,13 +104,16 @@ int CPairsStorage::FindID(const UString &id, int &insertPos) const { - int left = 0, right = Pairs.Size(); + unsigned left = 0, right = Pairs.Size(); while (left != right) { - int mid = (left + right) / 2; - int compResult = ComparePairIDs(id, Pairs[mid].ID); + const unsigned mid = (left + right) / 2; + const int compResult = ComparePairIDs(id, Pairs[mid].ID); if (compResult == 0) + { + insertPos = mid; // to disable GCC warning return mid; + } if (compResult < 0) right = mid; else @@ -129,7 +132,7 @@ void CPairsStorage::AddPair(const CTextPair &pair) { int insertPos; - int pos = FindID(pair.ID, insertPos); + const int pos = FindID(pair.ID, insertPos); if (pos >= 0) Pairs[pos] = pair; else @@ -138,7 +141,7 @@ void CPairsStorage::DeletePair(const UString &id) { - int pos = FindID(id); + const int pos = FindID(id); if (pos >= 0) Pairs.Delete(pos); } @@ -146,7 +149,7 @@ bool CPairsStorage::GetValue(const UString &id, UString &value) const { value.Empty(); - int pos = FindID(id); + const int pos = FindID(id); if (pos < 0) return false; value = Pairs[pos].Value; @@ -155,7 +158,7 @@ UString CPairsStorage::GetValue(const UString &id) const { - int pos = FindID(id); + const int pos = FindID(id); if (pos < 0) return UString(); return Pairs[pos].Value; diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialog.cpp 7zip-22.01/CPP/7zip/UI/GUI/CompressDialog.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialog.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/CompressDialog.cpp 2022-07-14 08:00:00.000000000 +0000 @@ -16,6 +16,7 @@ #include "../FileManager/BrowseDialog.h" #include "../FileManager/FormatUtils.h" #include "../FileManager/HelpUtils.h" +#include "../FileManager/PropertyName.h" #include "../FileManager/SplitUtils.h" #include "../Explorer/MyMessages.h" @@ -36,6 +37,9 @@ #include "ExtractRes.h" #ifdef LANG + +// #define IDS_OPTIONS 2100 + static const UInt32 kLangIDs[] = { IDT_COMPRESS_ARCHIVE, @@ -49,6 +53,8 @@ IDT_COMPRESS_THREADS, IDT_COMPRESS_PARAMETERS, + IDB_COMPRESS_OPTIONS, // IDS_OPTIONS + IDG_COMPRESS_OPTIONS, IDX_COMPRESS_SFX, IDX_COMPRESS_SHARED, @@ -57,11 +63,6 @@ IDT_COMPRESS_MEMORY, IDT_COMPRESS_MEMORY_DE, - IDX_COMPRESS_NT_SYM_LINKS, - IDX_COMPRESS_NT_HARD_LINKS, - IDX_COMPRESS_NT_ALT_STREAMS, - IDX_COMPRESS_NT_SECUR, - IDG_COMPRESS_ENCRYPTION, IDT_COMPRESS_ENCRYPTION_METHOD, IDX_COMPRESS_ENCRYPT_FILE_NAMES, @@ -71,7 +72,7 @@ IDX_PASSWORD_SHOW, IDT_SPLIT_TO_VOLUMES, - IDT_COMPRESS_PATH_MODE + IDT_COMPRESS_PATH_MODE, }; #endif @@ -89,8 +90,6 @@ static LPCSTR const kExeExt = ".exe"; -#define k7zFormat "7z" - static const UInt32 g_Levels[] = { IDS_METHOD_STORE, @@ -119,6 +118,8 @@ kSha1, kCrc32, kCrc64, + kGnu, + kPosix }; static LPCSTR const kMethodsNames[] = @@ -135,6 +136,8 @@ , "SHA1" , "CRC32" , "CRC64" + , "GNU" + , "POSIX" }; static const EMethodID g_7zMethods[] = @@ -186,6 +189,12 @@ // kLZMA }; +static const EMethodID g_TarMethods[] = +{ + kGnu, + kPosix +}; + static const EMethodID g_HashMethods[] = { kSha256 @@ -202,6 +211,13 @@ static const UInt32 kFF_MemUse = 1 << 5; static const UInt32 kFF_SFX = 1 << 6; +/* +static const UInt32 kFF_Time_Win = 1 << 10; +static const UInt32 kFF_Time_Unix = 1 << 11; +static const UInt32 kFF_Time_DOS = 1 << 12; +static const UInt32 kFF_Time_1ns = 1 << 13; +*/ + struct CFormatInfo { LPCSTR Name; @@ -233,23 +249,26 @@ kFF_MultiThread | kFF_MemUse }, { - k7zFormat, + "7z", (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), METHODS_PAIR(g_7zMethods), kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt | kFF_EncryptFileNames | kFF_MemUse | kFF_SFX + // | kFF_Time_Win }, { "Zip", (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9), METHODS_PAIR(g_ZipMethods), kFF_MultiThread | kFF_Encrypt | kFF_MemUse + // | kFF_Time_Win | kFF_Time_Unix | kFF_Time_DOS }, { "GZip", (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9), METHODS_PAIR(g_GZipMethods), kFF_MemUse + // | kFF_Time_Unix }, { "BZip2", @@ -272,14 +291,16 @@ { "Tar", (1 << 0), - 0, NULL, + METHODS_PAIR(g_TarMethods), 0 + // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns }, { "wim", (1 << 0), 0, NULL, 0 + // | kFF_Time_Win }, { "Hash", @@ -335,22 +356,6 @@ }; void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal); -bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2); - -void CCompressDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2) -{ - CheckButton(id, GetBoolsVal(b1, b2)); -} - -void CCompressDialog::GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2) -{ - bool val = IsButtonCheckedBool(id); - bool oldVal = GetBoolsVal(b1, b2); - if (val != oldVal) - b1.Def = b2.Def = true; - b1.Val = b2.Val = val; -} - void CCompressDialog::SetMethods(const CObjectVector &userCodecs) { @@ -375,12 +380,13 @@ } } - + bool CCompressDialog::OnInit() { #ifdef LANG LangSetWindowText(*this, IDD_COMPRESS); LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); + // LangSetDlgItemText(*this, IDB_COMPRESS_OPTIONS, IDS_OPTIONS); // IDG_COMPRESS_OPTIONS #endif { @@ -435,11 +441,6 @@ CheckButton(IDX_PASSWORD_SHOW, m_RegistryInfo.ShowPassword); CheckButton(IDX_COMPRESS_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders); - CheckButton_TwoBools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks); - CheckButton_TwoBools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks); - CheckButton_TwoBools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams); - CheckButton_TwoBools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); - UpdatePasswordControl(); { @@ -490,7 +491,7 @@ CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite); CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing); - FormatChanged(); + FormatChanged(false); // isChanged // OnButtonSFX(); @@ -552,6 +553,13 @@ UpdatePasswordControl(); return true; } + case IDB_COMPRESS_OPTIONS: + { + COptionsDialog dialog(this); + if (dialog.Create(*this) == IDOK) + ShowOptionsString(); + return true; + } } return CModalDialog::OnButtonClicked(buttonID, buttonHWND); } @@ -588,8 +596,43 @@ EnableItem(id, enable); } +static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s); + +static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res) +{ + if (!b1.Def && b2.Def) + res.Val = b2.Val; + else + res.Val = b1.Val; +} + +#define SET_GUI_BOOL(name) \ + Combine_Two_BoolPairs(Info. name, m_RegistryInfo. name, name) + + +static void Set_Final_BoolPairs( + const CBool1 &gui, + CBoolPair &cmd, + CBoolPair ®) +{ + if (!cmd.Def) + { + reg.Val = gui.Val; + reg.Def = gui.Val; + } + if (gui.Supported) + { + cmd.Val = gui.Val; + cmd.Def = gui.Val; + } + else + cmd.Init(); +} + +#define SET_FINAL_BOOL_PAIRS(name) \ + Set_Final_BoolPairs(name, Info. name, m_RegistryInfo. name) -void CCompressDialog::FormatChanged() +void CCompressDialog::FormatChanged(bool isChanged) { SetLevel(); SetSolidBlockSize(); @@ -615,18 +658,26 @@ CheckSFXControlsEnable(); { - const CArcInfoEx &ai = Get_ArcInfoEx(); - - ShowItem_Bool(IDX_COMPRESS_NT_SYM_LINKS, ai.Flags_SymLinks()); - ShowItem_Bool(IDX_COMPRESS_NT_HARD_LINKS, ai.Flags_HardLinks()); - ShowItem_Bool(IDX_COMPRESS_NT_ALT_STREAMS, ai.Flags_AltStreams()); - ShowItem_Bool(IDX_COMPRESS_NT_SECUR, ai.Flags_NtSecure()); - - ShowItem_Bool(IDG_COMPRESS_NTFS, - ai.Flags_SymLinks() - || ai.Flags_HardLinks() - || ai.Flags_AltStreams() - || ai.Flags_NtSecure()); + if (!isChanged) + { + SET_GUI_BOOL (SymLinks); + SET_GUI_BOOL (HardLinks); + SET_GUI_BOOL (AltStreams); + SET_GUI_BOOL (NtSecurity); + SET_GUI_BOOL (PreserveATime); + } + + PreserveATime.Supported = true; + + { + const CArcInfoEx &ai = Get_ArcInfoEx(); + SymLinks.Supported = ai.Flags_SymLinks(); + HardLinks.Supported = ai.Flags_HardLinks(); + AltStreams.Supported = ai.Flags_AltStreams(); + NtSecurity.Supported = ai.Flags_NtSecurity(); + } + + ShowOptionsString(); } // CheckVolumeEnable(); @@ -821,7 +872,7 @@ s.Add_LF(); s.Add_LF(); - s += LangString(IDS_MEM_ERROR); + AddLangString(s, IDS_MEM_ERROR); } @@ -933,17 +984,32 @@ Info.EncryptHeaders = IsButtonCheckedBool(IDX_COMPRESS_ENCRYPT_FILE_NAMES); - GetButton_Bools(IDX_COMPRESS_NT_SYM_LINKS, Info.SymLinks, m_RegistryInfo.SymLinks); - GetButton_Bools(IDX_COMPRESS_NT_HARD_LINKS, Info.HardLinks, m_RegistryInfo.HardLinks); - GetButton_Bools(IDX_COMPRESS_NT_ALT_STREAMS, Info.AltStreams, m_RegistryInfo.AltStreams); - GetButton_Bools(IDX_COMPRESS_NT_SECUR, Info.NtSecurity, m_RegistryInfo.NtSecurity); + /* (Info) is for saving to registry: + (CBoolPair::Val) will be set as (false), if it was (false) + in registry at dialog creation, and user didn't click checkbox. + in another case (CBoolPair::Val) will be set as (true) */ + + { + /* Info properties could be for another archive types. + so we disable unsupported properties in Info */ + // const CArcInfoEx &ai = Get_ArcInfoEx(); + + SET_FINAL_BOOL_PAIRS (SymLinks); + SET_FINAL_BOOL_PAIRS (HardLinks); + SET_FINAL_BOOL_PAIRS (AltStreams); + SET_FINAL_BOOL_PAIRS (NtSecurity); + + SET_FINAL_BOOL_PAIRS (PreserveATime); + } { - const CArcInfoEx &ai = Get_ArcInfoEx(); - if (!ai.Flags_SymLinks()) Info.SymLinks.Val = false; - if (!ai.Flags_HardLinks()) Info.HardLinks.Val = false; - if (!ai.Flags_AltStreams()) Info.AltStreams.Val = false; - if (!ai.Flags_NtSecure()) Info.NtSecurity.Val = false; + const NCompression::CFormatOptions &fo = Get_FormatOptions(); + + Info.TimePrec = fo.TimePrec; + Info.MTime = fo.MTime; + Info.CTime = fo.CTime; + Info.ATime = fo.ATime; + Info.SetArcMTime = fo.SetArcMTime; } m_Params.GetText(Info.Options); @@ -1031,7 +1097,7 @@ { const bool isSFX = IsSFX(); SaveOptionsInMem(); - FormatChanged(); + FormatChanged(true); // isChanged SetArchiveName2(isSFX); return true; } @@ -1057,6 +1123,7 @@ SetMemoryUsage(); if (Get_ArcInfoEx().Flags_HashHandler()) SetArchiveName2(false); + return true; } @@ -1188,6 +1255,7 @@ m_ArchivePath.SetText(fileName); } + int CCompressDialog::FindRegistryFormat(const UString &name) { FOR_VECTOR (i, m_RegistryInfo.Formats) @@ -1199,7 +1267,8 @@ return -1; } -int CCompressDialog::FindRegistryFormatAlways(const UString &name) + +unsigned CCompressDialog::FindRegistryFormat_Always(const UString &name) { int index = FindRegistryFormat(name); if (index < 0) @@ -1211,6 +1280,14 @@ return index; } + +NCompression::CFormatOptions &CCompressDialog::Get_FormatOptions() +{ + const CArcInfoEx &ai = Get_ArcInfoEx(); + return m_RegistryInfo.Formats[FindRegistryFormat_Always(ai.Name)]; +} + + int CCompressDialog::GetStaticFormatIndex() { const CArcInfoEx &ai = Get_ArcInfoEx(); @@ -1293,8 +1370,11 @@ const CArcInfoEx &ai = Get_ArcInfoEx(); if (GetLevel() == 0 && !ai.Flags_HashHandler()) { - MethodChanged(); - return; + if (!ai.Is_Tar()) + { + MethodChanged(); + return; + } } UString defaultMethod; { @@ -1308,7 +1388,7 @@ const bool isSfx = IsSFX(); bool weUseSameMethod = false; - const bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); + const bool is7z = ai.Is_7z(); for (unsigned m = 0;; m++) { @@ -1367,12 +1447,12 @@ bool CCompressDialog::IsZipFormat() { - return Get_ArcInfoEx().Name.IsEqualTo_Ascii_NoCase("zip"); + return Get_ArcInfoEx().Is_Zip(); } bool CCompressDialog::IsXzFormat() { - return Get_ArcInfoEx().Name.IsEqualTo_Ascii_NoCase("xz"); + return Get_ArcInfoEx().Is_Xz(); } void CCompressDialog::SetEncryptionMethod() @@ -1380,13 +1460,13 @@ _encryptionMethod.ResetContent(); _default_encryptionMethod_Index = -1; const CArcInfoEx &ai = Get_ArcInfoEx(); - if (ai.Name.IsEqualTo_Ascii_NoCase("7z")) + if (ai.Is_7z()) { ComboBox_AddStringAscii(_encryptionMethod, "AES-256"); _encryptionMethod.SetCurSel(0); _default_encryptionMethod_Index = 0; } - else if (ai.Name.IsEqualTo_Ascii_NoCase("zip")) + else if (ai.Is_Zip()) { int index = FindRegistryFormat(ai.Name); UString encryptionMethod; @@ -1929,7 +2009,7 @@ } } - const bool is7z = ai.Name.IsEqualTo_Ascii_NoCase("7z"); + const bool is7z = ai.Is_7z(); const UInt64 cs = Get_Lzma2_ChunkSize(dict); @@ -2549,11 +2629,16 @@ void CCompressDialog::SaveOptionsInMem() { + /* these options are for (Info.FormatIndex). + If it's called just after format changing, + then it's format that was selected before format changing + So we store previous format properties */ + m_Params.GetText(Info.Options); Info.Options.Trim(); const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex]; - const int index = FindRegistryFormatAlways(ai.Name); + const unsigned index = FindRegistryFormat_Always(ai.Name); NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index]; fo.Options = Info.Options; fo.Level = GetLevelSpec(); @@ -2587,7 +2672,512 @@ fo.MemUse = Get_MemUse_Spec(); } + unsigned CCompressDialog::GetFormatIndex() { return (unsigned)m_Format.GetItemData_of_CurSel(); } + + + +static void AddText_from_BoolPair(AString &s, const char *name, const CBoolPair &bp) +{ + if (bp.Def) + { + s.Add_OptSpaced(name); + if (!bp.Val) + s += "-"; + } + /* + else if (bp.Val) + { + s.Add_OptSpaced("["); + s += name; + s += "]"; + } + */ +} + + +static void AddText_from_Bool1(AString &s, const char *name, const CBool1 &b) +{ + if (b.Supported && b.Val) + s.Add_OptSpaced(name); +} + + +void CCompressDialog::ShowOptionsString() +{ + NCompression::CFormatOptions &fo = Get_FormatOptions(); + + AString s; + if (fo.IsSet_TimePrec()) + { + s.Add_OptSpaced("tp"); + s.Add_UInt32(fo.TimePrec); + } + AddText_from_BoolPair(s, "tm", fo.MTime); + AddText_from_BoolPair(s, "tc", fo.CTime); + AddText_from_BoolPair(s, "ta", fo.ATime); + AddText_from_BoolPair(s, "-stl", fo.SetArcMTime); + + // const CArcInfoEx &ai = Get_ArcInfoEx(); + AddText_from_Bool1(s, "SL", SymLinks); + AddText_from_Bool1(s, "HL", HardLinks); + AddText_from_Bool1(s, "AS", AltStreams); + AddText_from_Bool1(s, "Sec", NtSecurity); + + // AddText_from_Bool1(s, "Preserve", PreserveATime); + + SetItemText(IDT_COMPRESS_OPTIONS, GetUnicodeString(s)); +} + + + + + +// ---------- OPTIONS ---------- + + +void COptionsDialog::CheckButton_Bool1(UINT id, const CBool1 &b1) +{ + CheckButton(id, b1.Val); +} + +void COptionsDialog::GetButton_Bool1(UINT id, CBool1 &b1) +{ + b1.Val = IsButtonCheckedBool(id); +} + + +void COptionsDialog::CheckButton_BoolBox( + bool supported, const CBoolPair &b2, CBoolBox &bb) +{ + const bool isSet = b2.Def; + const bool val = isSet ? b2.Val : bb.DefaultVal; + + bb.IsSupported = supported; + + CheckButton (bb.Set_Id, isSet); + ShowItem_Bool (bb.Set_Id, supported); + CheckButton (bb.Id, val); + EnableItem (bb.Id, isSet); + ShowItem_Bool (bb.Id, supported); +} + +void COptionsDialog::GetButton_BoolBox(CBoolBox &bb) +{ + // we save value for invisible buttons too + bb.BoolPair.Val = IsButtonCheckedBool (bb.Id); + bb.BoolPair.Def = IsButtonCheckedBool (bb.Set_Id); +} + + +void COptionsDialog::Store_TimeBoxes() +{ + TimePrec = GetPrecSpec(); + GetButton_BoolBox (MTime); + GetButton_BoolBox (CTime); + GetButton_BoolBox (ATime); + GetButton_BoolBox (ZTime); +} + + +UInt32 COptionsDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax) +{ + if (c.GetCount() <= defMax) + return (UInt32)(Int32)-1; + return (UInt32)c.GetItemData_of_CurSel(); +} + +static const unsigned kTimePrec_Win = 0; +static const unsigned kTimePrec_Unix = 1; +static const unsigned kTimePrec_DOS = 2; +static const unsigned kTimePrec_1ns = 3; + +static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL) +{ + // s += " : "; + { + AString s2; + s2.Add_UInt32(val); + s += s2; + } + s.Add_Space(); + s += unit; + if (sys) + { + s += " : "; + s += sys; + } +} + +int COptionsDialog::AddPrec(unsigned prec, bool isDefault) +{ + UString s; + UInt32 writePrec = prec; + if (isDefault) + { + // s += "* "; + // writePrec = (UInt32)(Int32)-1; + } + if (prec == kTimePrec_Win) AddTimeOption(s, 100, NsString, "Windows"); + else if (prec == kTimePrec_Unix) AddTimeOption(s, 1, SecString, "Unix"); + else if (prec == kTimePrec_DOS) AddTimeOption(s, 2, SecString, "DOS"); + else if (prec == kTimePrec_1ns) AddTimeOption(s, 1, NsString, "Linux"); + else if (prec == k_PropVar_TimePrec_Base) AddTimeOption(s, 1, SecString); + else if (prec >= k_PropVar_TimePrec_Base) + { + UInt32 d = 1; + for (unsigned i = prec; i < k_PropVar_TimePrec_Base + 9; i++) + d *= 10; + AddTimeOption(s, d, NsString); + } + else + s.Add_UInt32(prec); + const int index = (int)m_Prec.AddString(s); + m_Prec.SetItemData(index, writePrec); + return index; +} + + +void COptionsDialog::SetPrec() +{ + // const CFormatInfo &fi = g_Formats[cd->GetStaticFormatIndex()]; + const CArcInfoEx &ai = cd->Get_ArcInfoEx(); + + // UInt32 flags = fi.Flags; + + UInt32 flags = ai.Get_TimePrecFlags(); + UInt32 defaultPrec = ai.Get_DefaultTimePrec(); + if (defaultPrec != 0) + flags |= ((UInt32)1 << defaultPrec); + + // const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + + // unsigned defaultPrec = kTimePrec_Win; + + if (ai.Is_GZip()) + defaultPrec = kTimePrec_Unix; + + { + UString s; + s += GetNameOfProperty(kpidType, L"type"); + s += ": "; + s += ai.Name; + if (ai.Is_Tar()) + { + const int methodID = cd->GetMethodID(); + + // for debug + // defaultPrec = kTimePrec_Unix; + // flags = (UInt32)1 << kTimePrec_Unix; + + s += ":"; + if (methodID >= 0 && (unsigned)methodID < ARRAY_SIZE(kMethodsNames)) + s += kMethodsNames[methodID]; + if (methodID == kPosix) + { + // for debug + // flags |= (UInt32)1 << kTimePrec_Win; + // flags |= (UInt32)1 << kTimePrec_1ns; + } + } + else + { + // if (is_for_MethodChanging) return; + } + + SetItemText(IDT_COMPRESS_TIME_INFO, s); + } + + m_Prec.ResetContent(); + _auto_Prec = defaultPrec; + + unsigned selectedPrec = defaultPrec; + { + // if (TimePrec >= kTimePrec_Win && TimePrec <= kTimePrec_DOS) + if ((Int32)TimePrec >= 0) + selectedPrec = TimePrec; + } + + int curSel = -1; + int defaultPrecIndex = -1; + for (unsigned prec = 0; + // prec <= k_PropVar_TimePrec_HighPrec; + prec <= k_PropVar_TimePrec_1ns; + prec++) + { + if (((flags >> prec) & 1) == 0) + continue; + const bool isDefault = (defaultPrec == prec); + const int index = AddPrec(prec, isDefault); + if (isDefault) + defaultPrecIndex = index; + if (selectedPrec == prec) + curSel = index; + } + + if (curSel < 0 && selectedPrec > kTimePrec_DOS) + curSel = AddPrec(selectedPrec, false); // isDefault + if (curSel < 0) + curSel = defaultPrecIndex; + if (curSel >= 0) + m_Prec.SetCurSel(curSel); + + { + const bool isSet = IsSet_TimePrec(); + const int count = m_Prec.GetCount(); + const bool showPrec = (count != 0); + ShowItem_Bool(IDC_COMPRESS_TIME_PREC, showPrec); + ShowItem_Bool(IDT_COMPRESS_TIME_PREC, showPrec); + EnableItem(IDC_COMPRESS_TIME_PREC, isSet && (count > 1)); + + CheckButton(IDX_COMPRESS_PREC_SET, isSet); + const bool setIsSupported = isSet || (count > 1); + EnableItem(IDX_COMPRESS_PREC_SET, setIsSupported); + ShowItem_Bool(IDX_COMPRESS_PREC_SET, setIsSupported); + } + + SetTimeMAC(); +} + + +void COptionsDialog::SetTimeMAC() +{ + const CArcInfoEx &ai = cd->Get_ArcInfoEx(); + + const + bool m_allow = ai.Flags_MTime(); + bool c_allow = ai.Flags_CTime(); + bool a_allow = ai.Flags_ATime(); + + if (ai.Is_Tar()) + { + const int methodID = cd->GetMethodID(); + c_allow = false; + a_allow = false; + if (methodID == kPosix) + { + // c_allow = true; // do we need it as change time ? + a_allow = true; + } + } + + if (ai.Is_Zip()) + { + // const int methodID = GetMethodID(); + UInt32 prec = GetPrec(); + if (prec == (UInt32)(Int32)-1) + prec = _auto_Prec; + if (prec != kTimePrec_Win) + { + c_allow = false; + a_allow = false; + } + } + + + /* + MTime.DefaultVal = true; + CTime.DefaultVal = false; + ATime.DefaultVal = false; + */ + + MTime.DefaultVal = ai.Flags_MTime_Default(); + CTime.DefaultVal = ai.Flags_CTime_Default(); + ATime.DefaultVal = ai.Flags_ATime_Default(); + + ZTime.DefaultVal = false; + + const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + + CheckButton_BoolBox (m_allow, fo.MTime, MTime ); + CheckButton_BoolBox (c_allow, fo.CTime, CTime ); + CheckButton_BoolBox (a_allow, fo.ATime, ATime ); + CheckButton_BoolBox (true, fo.SetArcMTime, ZTime); + + if (m_allow && !fo.MTime.Def) + { + const bool isSingleFile = ai.Flags_KeepName(); + if (!isSingleFile) + { + // we can hide changing checkboxes for MTime here: + ShowItem_Bool (MTime.Set_Id, false); + EnableItem (MTime.Id, false); + } + } + // On_CheckBoxSet_Prec_Clicked(); + // const bool isSingleFile = ai.Flags_KeepName(); + // mtime for Gz can be +} + + + +void COptionsDialog::On_CheckBoxSet_Prec_Clicked() +{ + const bool isSet = IsButtonCheckedBool(IDX_COMPRESS_PREC_SET); + if (!isSet) + { + // We save current MAC boxes to memory before SetPrec() + Store_TimeBoxes(); + Reset_TimePrec(); + SetPrec(); + } + EnableItem(IDC_COMPRESS_TIME_PREC, isSet); +} + +void COptionsDialog::On_CheckBoxSet_Clicked(const CBoolBox &bb) +{ + const bool isSet = IsButtonCheckedBool(bb.Set_Id); + if (!isSet) + CheckButton(bb.Id, bb.DefaultVal); + EnableItem(bb.Id, isSet); +} + + + + +#ifdef LANG +static const UInt32 kLangIDs_Options[] = +{ + IDX_COMPRESS_NT_SYM_LINKS, + IDX_COMPRESS_NT_HARD_LINKS, + IDX_COMPRESS_NT_ALT_STREAMS, + IDX_COMPRESS_NT_SECUR, + + IDG_COMPRESS_TIME, + IDT_COMPRESS_TIME_PREC, + IDX_COMPRESS_MTIME, + IDX_COMPRESS_CTIME, + IDX_COMPRESS_ATIME, + IDX_COMPRESS_ZTIME, + IDX_COMPRESS_PRESERVE_ATIME +}; +#endif + + +bool COptionsDialog::OnInit() +{ + #ifdef LANG + LangSetWindowText(*this, IDB_COMPRESS_OPTIONS); // IDS_OPTIONS + LangSetDlgItems(*this, kLangIDs_Options, ARRAY_SIZE(kLangIDs_Options)); + // LangSetDlgItemText(*this, IDB_COMPRESS_TIME_DEFAULT, IDB_COMPRESS_TIME_DEFAULT); + // LangSetDlgItemText(*this, IDX_COMPRESS_TIME_DEFAULT, IDX_COMPRESS_TIME_DEFAULT); + #endif + + LangString(IDS_COMPRESS_SEC, SecString); + if (SecString.IsEmpty()) + SecString = "sec"; + LangString(IDS_COMPRESS_NS, NsString); + if (NsString.IsEmpty()) + NsString = "ns"; + + { + // const CArcInfoEx &ai = cd->Get_ArcInfoEx(); + + ShowItem_Bool ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks.Supported); + ShowItem_Bool ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks.Supported); + ShowItem_Bool ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams.Supported); + ShowItem_Bool ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity.Supported); + + ShowItem_Bool ( IDG_COMPRESS_NTFS, + cd->SymLinks.Supported + || cd->HardLinks.Supported + || cd->AltStreams.Supported + || cd->NtSecurity.Supported); + } + + /* we read property from two sources: + 1) command line : (Info) + 2) registry : (m_RegistryInfo) + (Info) has priority, if both are no defined */ + + CheckButton_Bool1 ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks); + CheckButton_Bool1 ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks); + CheckButton_Bool1 ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams); + CheckButton_Bool1 ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity); + + CheckButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime); + + m_Prec.Attach (GetItem(IDC_COMPRESS_TIME_PREC)); + + MTime.SetIDs ( IDX_COMPRESS_MTIME, IDX_COMPRESS_MTIME_SET); + CTime.SetIDs ( IDX_COMPRESS_CTIME, IDX_COMPRESS_CTIME_SET); + ATime.SetIDs ( IDX_COMPRESS_ATIME, IDX_COMPRESS_ATIME_SET); + ZTime.SetIDs ( IDX_COMPRESS_ZTIME, IDX_COMPRESS_ZTIME_SET); + + { + const NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + TimePrec = fo.TimePrec; + MTime.BoolPair = fo.MTime; + CTime.BoolPair = fo.CTime; + ATime.BoolPair = fo.ATime; + ZTime.BoolPair = fo.SetArcMTime; + } + + SetPrec(); + + NormalizePosition(); + + return CModalDialog::OnInit(); +} + + +bool COptionsDialog::OnCommand(int code, int itemID, LPARAM lParam) +{ + if (code == CBN_SELCHANGE) + { + switch (itemID) + { + case IDC_COMPRESS_TIME_PREC: + { + Store_TimeBoxes(); + SetTimeMAC(); // for zip/tar + return true; + } + } + } + return CModalDialog::OnCommand(code, itemID, lParam); +} + + +bool COptionsDialog::OnButtonClicked(int buttonID, HWND buttonHWND) +{ + switch (buttonID) + { + case IDX_COMPRESS_PREC_SET: { On_CheckBoxSet_Prec_Clicked(); return true; } + case IDX_COMPRESS_MTIME_SET: { On_CheckBoxSet_Clicked (MTime); return true; } + case IDX_COMPRESS_CTIME_SET: { On_CheckBoxSet_Clicked (CTime); return true; } + case IDX_COMPRESS_ATIME_SET: { On_CheckBoxSet_Clicked (ATime); return true; } + case IDX_COMPRESS_ZTIME_SET: { On_CheckBoxSet_Clicked (ZTime); return true; } + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} + + +void COptionsDialog::OnOK() +{ + GetButton_Bool1 (IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks); + GetButton_Bool1 (IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks); + GetButton_Bool1 (IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams); + GetButton_Bool1 (IDX_COMPRESS_NT_SECUR, cd->NtSecurity); + GetButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime); + + Store_TimeBoxes(); + { + NCompression::CFormatOptions &fo = cd->Get_FormatOptions(); + fo.TimePrec = TimePrec; + fo.MTime = MTime.BoolPair; + fo.CTime = CTime.BoolPair; + fo.ATime = ATime.BoolPair; + fo.SetArcMTime = ZTime.BoolPair; + } + + CModalDialog::OnOK(); +} + +void COptionsDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialog.h 7zip-22.01/CPP/7zip/UI/GUI/CompressDialog.h --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialog.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/CompressDialog.h 2022-04-18 13:00:00.000000000 +0000 @@ -59,6 +59,14 @@ CBoolPair HardLinks; CBoolPair AltStreams; CBoolPair NtSecurity; + + CBoolPair PreserveATime; + + UInt32 TimePrec; + CBoolPair MTime; + CBoolPair CTime; + CBoolPair ATime; + CBoolPair SetArcMTime; UString ArcPath; // in: Relative or abs ; out: Relative or abs @@ -89,11 +97,46 @@ Method.Empty(); Options.Empty(); EncryptionMethod.Empty(); + TimePrec = (UInt32)(Int32)(-1); } }; } +struct CBool1 +{ + bool Val; + bool Supported; + + CBool1(): Val(false), Supported(false) {} + + void Init() + { + Val = false; + Supported = false; + } + + void SetTrueTrue() + { + Val = true; + Supported = true; + } + + void SetVal_as_Supported(bool val) + { + Val = val; + Supported = true; + } + + /* + bool IsVal_True_and_Defined() const + { + return Def && Val; + } + */ +}; + + class CCompressDialog: public NWindows::NControl::CModalDialog { NWindows::NControl::CComboBox m_ArchivePath; @@ -126,8 +169,6 @@ int _default_encryptionMethod_Index; - NCompression::CInfo m_RegistryInfo; - int m_PrevFormat; UString DirPrefix; UString StartDirPrefix; @@ -137,23 +178,25 @@ UInt64 _ramSize_Reduced; // full for 64-bit and reduced for 32-bit UInt64 _ramUsage_Auto; - void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2); - void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2); +public: + NCompression::CInfo m_RegistryInfo; + + CBool1 SymLinks; + CBool1 HardLinks; + CBool1 AltStreams; + CBool1 NtSecurity; + CBool1 PreserveATime; void SetArchiveName(const UString &name); int FindRegistryFormat(const UString &name); - int FindRegistryFormatAlways(const UString &name); + unsigned FindRegistryFormat_Always(const UString &name); const CArcInfoEx &Get_ArcInfoEx() { return (*ArcFormats)[GetFormatIndex()]; } - NCompression::CFormatOptions &Get_FormatOptions() - { - const CArcInfoEx &ai = Get_ArcInfoEx(); - return m_RegistryInfo.Formats[ FindRegistryFormatAlways(ai.Name) ]; - } + NCompression::CFormatOptions &Get_FormatOptions(); void CheckSFXNameChange(); void SetArchiveName2(bool prevWasSFX); @@ -237,6 +280,12 @@ UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); } + /* + UInt32 GetPrecSpec() { return GetComboValue(m_Prec, 1); } + UInt32 GetPrec() { return GetComboValue(m_Prec, 0); } + */ + + int AddOrder(UInt32 size); int AddOrder_Auto(); @@ -271,6 +320,7 @@ void PrintMemUsage(UINT res, UInt64 value); void SetMemoryUsage(); void SetParams(); + void SaveOptionsInMem(); void UpdatePasswordControl(); @@ -283,7 +333,7 @@ void CheckSFXControlsEnable(); // void CheckVolumeEnable(); void EnableMultiCombo(unsigned id); - void FormatChanged(); + void FormatChanged(bool isChanged); void OnButtonSetArchive(); bool IsSFX(); @@ -300,6 +350,8 @@ MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); } + void ShowOptionsString(); + public: const CObjectVector *ArcFormats; CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0 @@ -313,11 +365,103 @@ INT_PTR Create(HWND wndParent = 0) { - BIG_DIALOG_SIZE(400, 304); + BIG_DIALOG_SIZE(400, 320); return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent); } CCompressDialog(): CurrentDirWasChanged(false) {}; }; + + + +class COptionsDialog: public NWindows::NControl::CModalDialog +{ + struct CBoolBox + { + bool IsSupported; + bool DefaultVal; + CBoolPair BoolPair; + + int Id; + int Set_Id; + + void SetIDs(int id, int set_Id) + { + Id = id; + Set_Id = set_Id; + } + + CBoolBox(): + IsSupported(false), + DefaultVal(false) + {} + }; + + CCompressDialog *cd; + + NWindows::NControl::CComboBox m_Prec; + + UInt32 _auto_Prec; + UInt32 TimePrec; + + void Reset_TimePrec() { TimePrec = (UInt32)(Int32)-1; } + bool IsSet_TimePrec() const { return TimePrec != (UInt32)(Int32)-1; } + + CBoolBox MTime; + CBoolBox CTime; + CBoolBox ATime; + CBoolBox ZTime; + + UString SecString; + UString NsString; + + + void CheckButton_Bool1(UINT id, const CBool1 &b1); + void GetButton_Bool1(UINT id, CBool1 &b1); + void CheckButton_BoolBox(bool supported, const CBoolPair &b2, CBoolBox &bb); + void GetButton_BoolBox(CBoolBox &bb); + + void Store_TimeBoxes(); + + UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0); + UInt32 GetPrecSpec() + { + UInt32 prec = GetComboValue(m_Prec, 1); + if (prec == _auto_Prec) + prec = (UInt32)(Int32)-1; + return prec; + } + UInt32 GetPrec() { return GetComboValue(m_Prec, 0); } + + // void OnButton_TimeDefault(); + int AddPrec(unsigned prec, bool isDefault); + void SetPrec(); + void SetTimeMAC(); + + void On_CheckBoxSet_Prec_Clicked(); + void On_CheckBoxSet_Clicked(const CBoolBox &bb); + + virtual bool OnInit(); + virtual bool OnCommand(int code, int itemID, LPARAM lParam); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + virtual void OnOK(); + virtual void OnHelp(); + +public: + + INT_PTR Create(HWND wndParent = 0) + { + BIG_DIALOG_SIZE(240, 232); + return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS_OPTIONS), wndParent); + } + + COptionsDialog(CCompressDialog *cdLoc): + cd(cdLoc) + // , TimePrec(0) + { + Reset_TimePrec(); + }; +}; + #endif diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialog.rc 7zip-22.01/CPP/7zip/UI/GUI/CompressDialog.rc --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialog.rc 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/CompressDialog.rc 2022-04-21 13:00:00.000000000 +0000 @@ -2,7 +2,7 @@ #include "../../GuiCommon.rc" #define xc 400 -#define yc 354 +#define yc 320 #undef gSize #undef gSpace @@ -20,10 +20,6 @@ #define gSize 192 #define gSpace 24 -#define ntSize2 168 -#define ntSizeX (ntSize2 - m - m) -#define ntPosX m + m -#define ntPosY 292 #define g1xs 88 #define g0xs (gSize - g1xs) @@ -99,18 +95,9 @@ LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m, 256, gSize, 8 EDITTEXT IDE_COMPRESS_PARAMETERS, m, 268, gSize, 14, ES_AUTOHSCROLL - - GROUPBOX "NTFS", IDG_COMPRESS_NTFS, m, ntPosY, ntSize2, 68 - - CONTROL "Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, MY_CHECKBOX, - ntPosX, ntPosY + 12, ntSizeX, 10 - CONTROL "Store hard links", IDX_COMPRESS_NT_HARD_LINKS, MY_CHECKBOX, - ntPosX, ntPosY + 26, ntSizeX, 10 - CONTROL "Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, MY_CHECKBOX, - ntPosX, ntPosY + 40, ntSizeX, 10 - CONTROL "Store file security", IDX_COMPRESS_NT_SECUR, MY_CHECKBOX, - ntPosX, ntPosY + 54, ntSizeX, 10 - + PUSHBUTTON "Options", IDB_COMPRESS_OPTIONS, m, 292, bxs, bys + LTEXT "", IDT_COMPRESS_OPTIONS, m + bxs + m, 294, gSize - bxs - m, 16, SS_NOPREFIX + LTEXT "&Update mode:", IDT_COMPRESS_UPDATE_MODE, g4x, 41, 80, 8 COMBOBOX IDC_COMPRESS_UPDATE_MODE, g4x + 84, 39, g4xs - 84, 80, MY_COMBO @@ -225,4 +212,10 @@ IDS_COMPRESS_SOLID "Solid" IDS_SPLIT_CONFIRM "Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes?" + + IDS_COMPRESS_SEC "sec" + IDS_COMPRESS_NS "ns" END + + +#include "CompressOptionsDialog.rc" diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialogRes.h 7zip-22.01/CPP/7zip/UI/GUI/CompressDialogRes.h --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressDialogRes.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/CompressDialogRes.h 2022-04-18 14:00:00.000000000 +0000 @@ -1,5 +1,6 @@ #define IDD_COMPRESS 4000 #define IDD_COMPRESS_2 14000 +#define IDD_COMPRESS_OPTIONS 14001 #define IDC_COMPRESS_ARCHIVE 100 #define IDB_COMPRESS_SET_ARCHIVE 101 @@ -28,6 +29,10 @@ #define IDT_COMPRESS_ARCHIVE_FOLDER 130 +// #define IDB_COMPRESS_OPTIONS 140 +#define IDB_COMPRESS_OPTIONS 2100 +#define IDT_COMPRESS_OPTIONS 141 + #define IDT_COMPRESS_PATH_MODE 3410 #define IDT_PASSWORD_ENTER 3801 @@ -86,3 +91,31 @@ #define IDT_SPLIT_TO_VOLUMES 7302 #define IDS_INCORRECT_VOLUME_SIZE 7307 #define IDS_SPLIT_CONFIRM 7308 + + +// Options Dialog + +#define IDG_COMPRESS_TIME 4080 +#define IDT_COMPRESS_TIME_PREC 4081 +#define IDX_COMPRESS_MTIME 4082 +#define IDX_COMPRESS_CTIME 4083 +#define IDX_COMPRESS_ATIME 4084 +#define IDX_COMPRESS_ZTIME 4085 +#define IDX_COMPRESS_PRESERVE_ATIME 4086 + +#define IDS_COMPRESS_SEC 4090 +#define IDS_COMPRESS_NS 4091 + +#define IDC_COMPRESS_TIME_PREC 190 +#define IDT_COMPRESS_TIME_INFO 191 + +#define IDX_COMPRESS_PREC_SET 201 +#define IDX_COMPRESS_MTIME_SET 202 +#define IDX_COMPRESS_CTIME_SET 203 +#define IDX_COMPRESS_ATIME_SET 204 +#define IDX_COMPRESS_ZTIME_SET 205 + +// #define IDX_COMPRESS_NT_SYM_LINKS_SET 210 +// #define IDX_COMPRESS_NT_HARD_LINKS_SET 211 +// #define IDX_COMPRESS_NT_ALT_STREAMS_SET 212 +// #define IDX_COMPRESS_NT_SECUR_SET 213 diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressOptionsDialog.rc 7zip-22.01/CPP/7zip/UI/GUI/CompressOptionsDialog.rc --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/CompressOptionsDialog.rc 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/CompressOptionsDialog.rc 2022-04-21 13:00:00.000000000 +0000 @@ -0,0 +1,76 @@ +#include "CompressDialogRes.h" +#include "../../GuiCommon.rc" + +#define xc 240 +#define yc 232 + +#define g5x m +#define g5x2 (g5x + m) +#define g5xs (xc) +#define g5xs2 (g5xs - m - m) + +#define ntPosX g5x2 +#define ntPosY m +#define ntSizeX g5xs2 +#define precSizeX 76 + +#define ntSizeY 72 +#define timePosY (ntPosY + ntSizeY + 20) + +#define ceSize 18 +#define ceString ":" + + +IDD_COMPRESS_OPTIONS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT +CAPTION "Options" +BEGIN + GROUPBOX "NTFS", IDG_COMPRESS_NTFS, g5x, ntPosY, g5xs, ntSizeY + + CONTROL "Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, MY_CHECKBOX, + ntPosX, ntPosY + 12, ntSizeX, 10 + CONTROL "Store hard links", IDX_COMPRESS_NT_HARD_LINKS, MY_CHECKBOX, + ntPosX, ntPosY + 26, ntSizeX, 10 + CONTROL "Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, MY_CHECKBOX, + ntPosX, ntPosY + 40, ntSizeX, 10 + CONTROL "Store file security", IDX_COMPRESS_NT_SECUR, MY_CHECKBOX, + ntPosX, ntPosY + 54, ntSizeX, 10 + + LTEXT "", IDT_COMPRESS_TIME_INFO, g5x, timePosY - 14, g5xs, 8 + + + GROUPBOX "Time", IDG_COMPRESS_TIME, g5x, timePosY, g5xs, 112 + +// CONTROL "Default", IDX_COMPRESS_TIME_DEFAULT, MY_CHECKBOX, +// ntPosX, timePosY + 10, ntSizeX, 16 + + CONTROL ceString, IDX_COMPRESS_PREC_SET, MY_CHECKBOX, ntPosX, timePosY + 14, ceSize, 10 + LTEXT "Timestamp precision:", IDT_COMPRESS_TIME_PREC, + ntPosX + ceSize, timePosY + 14, ntSizeX - precSizeX - ceSize, 8 + COMBOBOX IDC_COMPRESS_TIME_PREC, ntPosX + ntSizeX - precSizeX, timePosY + 12, precSizeX, 70, MY_COMBO + + // PUSHBUTTON "Default", IDB_COMPRESS_TIME_DEFAULT, ntPosX + ntSizeX - bxs, timePosY + 22, bxs, bys, WS_GROUP + + CONTROL ceString, IDX_COMPRESS_MTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 28, ceSize, 10 + CONTROL "Store modification time", IDX_COMPRESS_MTIME, MY_CHECKBOX, + ntPosX + ceSize, timePosY + 28, ntSizeX - ceSize, 10 + + CONTROL ceString, IDX_COMPRESS_CTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 42, ceSize, 10 + CONTROL "Store creation time", IDX_COMPRESS_CTIME, MY_CHECKBOX, + ntPosX + ceSize, timePosY + 42, ntSizeX - ceSize, 10 + + CONTROL ceString, IDX_COMPRESS_ATIME_SET, MY_CHECKBOX, ntPosX, timePosY + 56, ceSize, 10 + CONTROL "Store last access time", IDX_COMPRESS_ATIME, MY_CHECKBOX, + ntPosX + ceSize, timePosY + 56, ntSizeX - ceSize, 10 + + CONTROL ceString, IDX_COMPRESS_ZTIME_SET, MY_CHECKBOX | BS_MULTILINE, ntPosX, timePosY + 72, ceSize, 16 + CONTROL "Set archive time to latest file time", IDX_COMPRESS_ZTIME, MY_CHECKBOX | BS_MULTILINE, + ntPosX + ceSize, timePosY + 72, ntSizeX - ceSize, 16 + + CONTROL "Do not change source files last access time", IDX_COMPRESS_PRESERVE_ATIME, MY_CHECKBOX | BS_MULTILINE, + ntPosX, timePosY + 92, ntSizeX, 16 + + + DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys + PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys +END diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/GUI.cpp 7zip-22.01/CPP/7zip/UI/GUI/GUI.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/GUI.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/GUI.cpp 2022-05-18 12:00:00.000000000 +0000 @@ -75,6 +75,8 @@ bool g_LVN_ITEMACTIVATE_Support; bool g_LVN_ITEMACTIVATE_Support = true; +DECLARE_AND_SET_CLIENT_VERSION_VAR + static void ErrorMessage(LPCWSTR message) { MessageBoxW(NULL, message, L"7-Zip", MB_ICONERROR | MB_OK); @@ -135,7 +137,7 @@ CREATE_CODECS_OBJECT - codecs->CaseSensitiveChange = options.CaseSensitiveChange; + codecs->CaseSensitive_Change = options.CaseSensitive_Change; codecs->CaseSensitive = options.CaseSensitive; ThrowException_if_Error(codecs->Load()); Codecs_AddHashArcHandler(codecs); diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/GUI.dsp 7zip-22.01/CPP/7zip/UI/GUI/GUI.dsp --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/GUI.dsp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/GUI.dsp 2022-05-18 12:00:00.000000000 +0000 @@ -773,6 +773,10 @@ # End Source File # Begin Source File +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + SOURCE=..\..\..\..\C\Alloc.c # SUBTRACT CPP /YX /Yc /Yu # End Source File @@ -1211,5 +1215,17 @@ SOURCE=..\..\Archive\Common\OutStreamWithCRC.h # End Source File # End Group +# Begin Group "7-Zip" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\IArchive.h +# End Source File +# Begin Source File + +SOURCE=..\..\ICoder.h +# End Source File +# End Group # End Target # End Project diff -Nru 7zip-21.07+dfsg/CPP/7zip/UI/GUI/UpdateGUI.cpp 7zip-22.01/CPP/7zip/UI/GUI/UpdateGUI.cpp --- 7zip-21.07+dfsg/CPP/7zip/UI/GUI/UpdateGUI.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/7zip/UI/GUI/UpdateGUI.cpp 2022-05-18 12:00:00.000000000 +0000 @@ -61,6 +61,53 @@ return HRESULT_FROM_WIN32(ei.SystemError); } + +// parse command line properties + +static bool ParseProp_Time_BoolPair(const CProperty &prop, const char *name, CBoolPair &bp) +{ + if (!prop.Name.IsPrefixedBy_Ascii_NoCase(name)) + return false; + const UString rem = prop.Name.Ptr((unsigned)strlen(name)); + UString val = prop.Value; + if (!rem.IsEmpty()) + { + if (!val.IsEmpty()) + return true; + val = rem; + } + bool res; + if (StringToBool(val, res)) + { + bp.Val = res; + bp.Def = true; + } + return true; +} + +static void ParseProp( + const CProperty &prop, + NCompressDialog::CInfo &di) +{ + if (ParseProp_Time_BoolPair(prop, "tm", di.MTime)) return; + if (ParseProp_Time_BoolPair(prop, "tc", di.CTime)) return; + if (ParseProp_Time_BoolPair(prop, "ta", di.ATime)) return; +} + +static void ParseProperties( + const CObjectVector &properties, + NCompressDialog::CInfo &di) +{ + FOR_VECTOR (i, properties) + { + ParseProp(properties[i], di); + } +} + + + + + static void AddProp_UString(CObjectVector &properties, const char *name, const UString &value) { CProperty prop; @@ -81,10 +128,31 @@ AddProp_UString(properties, name, UString(value ? "on": "off")); } -static bool IsThereMethodOverride(bool is7z, const UString &propertiesString) + +static void AddProp_BoolPair(CObjectVector &properties, + const char *name, const CBoolPair &bp) +{ + if (bp.Def) + AddProp_bool(properties, name, bp.Val); +} + + + +static void SplitOptionsToStrings(const UString &src, UStringVector &strings) +{ + SplitString(src, strings); + FOR_VECTOR (i, strings) + { + UString &s = strings[i]; + if (s.Len() > 2 + && s[0] == '-' + && MyCharLower_Ascii(s[1]) == 'm') + s.DeleteFrontal(2); + } +} + +static bool IsThereMethodOverride(bool is7z, const UStringVector &strings) { - UStringVector strings; - SplitString(propertiesString, strings); FOR_VECTOR (i, strings) { const UString &s = strings[i]; @@ -106,17 +174,11 @@ } static void ParseAndAddPropertires(CObjectVector &properties, - const UString &propertiesString) + const UStringVector &strings) { - UStringVector strings; - SplitString(propertiesString, strings); FOR_VECTOR (i, strings) { - UString s = strings[i]; - if (s.Len() > 2 - && s[0] == '-' - && MyCharLower_Ascii(s[1]) == 'm') - s.DeleteFrontal(2); + const UString &s = strings[i]; CProperty property; const int index = s.Find(L'='); if (index < 0) @@ -142,58 +204,49 @@ static void SetOutProperties( CObjectVector &properties, + const NCompressDialog::CInfo &di, bool is7z, - UInt32 level, - bool setMethod, - const UString &method, - UInt64 dict64, - bool orderMode, - UInt32 order, - bool solidIsSpecified, UInt64 solidBlockSize, - // bool multiThreadIsAllowed, - UInt32 numThreads, - const UString &encryptionMethod, - bool encryptHeadersIsAllowed, bool encryptHeaders, - const NCompression::CMemUse &memUse, - bool /* sfxMode */) + bool setMethod) { - if (level != (UInt32)(Int32)-1) - AddProp_UInt32(properties, "x", (UInt32)level); + if (di.Level != (UInt32)(Int32)-1) + AddProp_UInt32(properties, "x", (UInt32)di.Level); if (setMethod) { - if (!method.IsEmpty()) - AddProp_UString(properties, is7z ? "0": "m", method); - if (dict64 != (UInt64)(Int64)-1) + if (!di.Method.IsEmpty()) + AddProp_UString(properties, is7z ? "0": "m", di.Method); + if (di.Dict64 != (UInt64)(Int64)-1) { AString name; if (is7z) name = "0"; - name += (orderMode ? "mem" : "d"); - AddProp_Size(properties, name, dict64); + name += (di.OrderMode ? "mem" : "d"); + AddProp_Size(properties, name, di.Dict64); } - if (order != (UInt32)(Int32)-1) + if (di.Order != (UInt32)(Int32)-1) { AString name; if (is7z) name = "0"; - name += (orderMode ? "o" : "fb"); - AddProp_UInt32(properties, name, (UInt32)order); + name += (di.OrderMode ? "o" : "fb"); + AddProp_UInt32(properties, name, (UInt32)di.Order); } } - if (!encryptionMethod.IsEmpty()) - AddProp_UString(properties, "em", encryptionMethod); + if (!di.EncryptionMethod.IsEmpty()) + AddProp_UString(properties, "em", di.EncryptionMethod); + + if (di.EncryptHeadersIsAllowed) + AddProp_bool(properties, "he", di.EncryptHeaders); - if (encryptHeadersIsAllowed) - AddProp_bool(properties, "he", encryptHeaders); - if (solidIsSpecified) - AddProp_Size(properties, "s", solidBlockSize); + if (di.SolidIsSpecified) + AddProp_Size(properties, "s", di.SolidBlockSize); if ( - // multiThreadIsAllowed && - numThreads != (UInt32)(Int32)-1) - AddProp_UInt32(properties, "mt", numThreads); + // di.MultiThreadIsAllowed && + di.NumThreads != (UInt32)(Int32)-1) + AddProp_UInt32(properties, "mt", di.NumThreads); + const NCompression::CMemUse &memUse = di.MemUsage; if (memUse.IsDefined) { const char *kMemUse = "memuse"; @@ -208,8 +261,16 @@ else AddProp_Size(properties, kMemUse, memUse.Val); } + + AddProp_BoolPair(properties, "tm", di.MTime); + AddProp_BoolPair(properties, "tc", di.CTime); + AddProp_BoolPair(properties, "ta", di.ATime); + + if (di.TimePrec != (UInt32)(Int32)-1) + AddProp_UInt32(properties, "tp", di.TimePrec); } + struct C_UpdateMode_ToAction_Pair { NCompressDialog::NUpdateMode::EEnum UpdateMode; @@ -358,6 +419,10 @@ di.HardLinks = options.HardLinks; di.AltStreams = options.AltStreams; di.NtSecurity = options.NtSecurity; + if (options.SetArcMTime) + di.SetArcMTime.SetTrueTrue(); + if (options.PreserveATime) + di.PreserveATime.SetTrueTrue(); if (callback->PasswordIsDefined) di.Password = callback->Password; @@ -373,6 +438,8 @@ di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode; } + ParseProperties(options.MethodMode.Properties, di); + if (dialog.Create(hwndParent) != IDOK) return E_ABORT; @@ -382,6 +449,9 @@ options.HardLinks = di.HardLinks; options.AltStreams = di.AltStreams; options.NtSecurity = di.NtSecurity; + options.SetArcMTime = di.SetArcMTime.Val; + if (di.PreserveATime.Def) + options.PreserveATime = di.PreserveATime.Val; #if defined(_WIN32) && !defined(UNDER_CE) curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged; @@ -411,29 +481,21 @@ if (callback->PasswordIsDefined) callback->Password = di.Password; + // we clear command line options, and fill options form Dialog options.MethodMode.Properties.Clear(); - bool is7z = archiverInfo.Name.IsEqualTo_Ascii_NoCase("7z"); - bool methodOverride = IsThereMethodOverride(is7z, di.Options); + const bool is7z = archiverInfo.Is_7z(); + + UStringVector optionStrings; + SplitOptionsToStrings(di.Options, optionStrings); + const bool methodOverride = IsThereMethodOverride(is7z, optionStrings); - SetOutProperties( - options.MethodMode.Properties, + SetOutProperties(options.MethodMode.Properties, di, is7z, - di.Level, - !methodOverride, - di.Method, - di.Dict64, - di.OrderMode, di.Order, - di.SolidIsSpecified, di.SolidBlockSize, - // di.MultiThreadIsAllowed, - di.NumThreads, - di.EncryptionMethod, - di.EncryptHeadersIsAllowed, di.EncryptHeaders, - di.MemUsage, - di.SFXMode); + !methodOverride); // setMethod options.OpenShareForWrite = di.OpenShareForWrite; - ParseAndAddPropertires(options.MethodMode.Properties, di.Options); + ParseAndAddPropertires(options.MethodMode.Properties, optionStrings); if (di.SFXMode) options.SfxMode = true; diff -Nru 7zip-21.07+dfsg/CPP/Common/Common.h 7zip-22.01/CPP/Common/Common.h --- 7zip-21.07+dfsg/CPP/Common/Common.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/Common.h 2022-01-06 19:00:00.000000000 +0000 @@ -35,7 +35,7 @@ So we can use MY_ARRAY_NEW macro instead of new[] operator. */ #if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64) - #define MY_ARRAY_NEW(p, T, size) p = new T[(size > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : size]; + #define MY_ARRAY_NEW(p, T, size) p = new T[((size) > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : (size)]; #else #define MY_ARRAY_NEW(p, T, size) p = new T[size]; #endif diff -Nru 7zip-21.07+dfsg/CPP/Common/MyCom.h 7zip-22.01/CPP/Common/MyCom.h --- 7zip-21.07+dfsg/CPP/Common/MyCom.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/MyCom.h 2022-03-27 13:00:00.000000000 +0000 @@ -67,6 +67,7 @@ template HRESULT QueryInterface(REFGUID iid, Q** pp) const throw() { + // if (*pp) throw 20220216; // for debug return _p->QueryInterface(iid, (void**)pp); } }; diff -Nru 7zip-21.07+dfsg/CPP/Common/MyLinux.h 7zip-22.01/CPP/Common/MyLinux.h --- 7zip-21.07+dfsg/CPP/Common/MyLinux.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/MyLinux.h 2022-02-26 08:00:00.000000000 +0000 @@ -3,6 +3,18 @@ #ifndef __MY_LIN_LINUX_H #define __MY_LIN_LINUX_H +// #include "../../C/7zTypes.h" + +#define MY_LIN_DT_UNKNOWN 0 +#define MY_LIN_DT_FIFO 1 +#define MY_LIN_DT_CHR 2 +#define MY_LIN_DT_DIR 4 +#define MY_LIN_DT_BLK 6 +#define MY_LIN_DT_REG 8 +#define MY_LIN_DT_LNK 10 +#define MY_LIN_DT_SOCK 12 +#define MY_LIN_DT_WHT 14 + #define MY_LIN_S_IFMT 00170000 #define MY_LIN_S_IFSOCK 0140000 #define MY_LIN_S_IFLNK 0120000 @@ -39,4 +51,25 @@ #define MY_LIN_S_IWOTH 00002 #define MY_LIN_S_IXOTH 00001 +/* +// major/minor encoding for makedev(): MMMMMmmmmmmMMMmm: + +inline UInt32 MY_dev_major(UInt64 dev) +{ + return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff); +} + +inline UInt32 MY_dev_minor(UInt64 dev) +{ + return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~0xff); +} + +inline UInt64 MY_dev_makedev(UInt32 __major, UInt32 __minor) +{ + return (__minor & 0xff) | ((__major & 0xfff) << 8) + | ((UInt64) (__minor & ~0xff) << 12) + | ((UInt64) (__major & ~0xfff) << 32); +} +*/ + #endif diff -Nru 7zip-21.07+dfsg/CPP/Common/MyString.cpp 7zip-22.01/CPP/Common/MyString.cpp --- 7zip-21.07+dfsg/CPP/Common/MyString.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/MyString.cpp 2022-02-21 06:00:00.000000000 +0000 @@ -30,8 +30,8 @@ } */ -#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, _size_) -#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, _size_) +#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, (_size_)) +#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, (_size_)) int FindCharPosInString(const char *s, char c) throw() @@ -190,8 +190,8 @@ { for (;;) { - unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true; - unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false; + const unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true; + const unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false; } } @@ -199,8 +199,8 @@ { for (;;) { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; + const wchar_t c1 = *s1++; + const wchar_t c2 = *s2++; if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; if (c1 == 0) return true; } @@ -213,10 +213,10 @@ const char *s1 = _chars; for (;;) { - char c2 = *s++; + const char c2 = *s++; if (c2 == 0) return true; - char c1 = *s1++; + const char c1 = *s1++; if (MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; @@ -228,10 +228,10 @@ const wchar_t *s1 = _chars; for (;;) { - char c2 = *s++; + const char c2 = *s++; if (c2 == 0) return true; - wchar_t c1 = *s1++; + const wchar_t c1 = *s1++; if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) return false; } @@ -241,7 +241,7 @@ { for (;;) { - char c = *a; + const char c = *a; if (c != *u) return false; if (c == 0) @@ -255,7 +255,7 @@ { for (;;) { - unsigned char c = (unsigned char)*a; + const unsigned char c = (unsigned char)*a; if (c != *u) return false; if (c == 0) @@ -269,8 +269,8 @@ { for (;;) { - char c1 = *s1++; - char c2 = *s2++; + const char c1 = *s1++; + const char c2 = *s2++; if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; if (c1 == 0) @@ -282,8 +282,8 @@ { for (;;) { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; + const wchar_t c1 = *s1++; + const wchar_t c2 = *s2++; if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; if (c1 == 0) @@ -295,8 +295,8 @@ { for (;;) { - wchar_t c1 = *s1++; - char c2 = *s2++; + const wchar_t c1 = *s1++; + const char c2 = *s2++; if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))) return false; if (c1 == 0) @@ -308,8 +308,8 @@ { for (;;) { - wchar_t c2 = *s2++; if (c2 == 0) return true; - wchar_t c1 = *s1++; if (c1 != c2) return false; + const wchar_t c2 = *s2++; if (c2 == 0) return true; + const wchar_t c1 = *s1++; if (c1 != c2) return false; } } @@ -317,8 +317,8 @@ { for (;;) { - unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true; - wchar_t c1 = *s1++; if (c1 != c2) return false; + const unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true; + const wchar_t c1 = *s1++; if (c1 != c2) return false; } } @@ -326,8 +326,8 @@ { for (;;) { - char c2 = *s2++; if (c2 == 0) return true; - char c1 = *s1++; + const char c2 = *s2++; if (c2 == 0) return true; + const char c1 = *s1++; if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) return false; } @@ -337,8 +337,8 @@ { for (;;) { - char c2 = *s2++; if (c2 == 0) return true; - wchar_t c1 = *s1++; + const char c2 = *s2++; if (c2 == 0) return true; + const wchar_t c1 = *s1++; if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) return false; } @@ -348,8 +348,8 @@ { for (;;) { - wchar_t c2 = *s2++; if (c2 == 0) return true; - wchar_t c1 = *s1++; + const wchar_t c2 = *s2++; if (c2 == 0) return true; + const wchar_t c1 = *s1++; if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; } @@ -360,12 +360,12 @@ { for (;;) { - wchar_t c1 = *s1++; - wchar_t c2 = *s2++; + const wchar_t c1 = *s1++; + const wchar_t c2 = *s2++; if (c1 != c2) { - wchar_t u1 = MyCharUpper(c1); - wchar_t u2 = MyCharUpper(c2); + const wchar_t u1 = MyCharUpper(c1); + const wchar_t u2 = MyCharUpper(c2); if (u1 < u2) return -1; if (u1 > u2) return 1; } @@ -401,14 +401,13 @@ MoveItems(index + size, index); } -#define k_Alloc_Len_Limit 0x40000000 +#define k_Alloc_Len_Limit (0x40000000 - 2) void AString::ReAlloc(unsigned newLimit) { - if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130220; - // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1); - char *newBuf = MY_STRING_NEW_char(newLimit + 1); - memcpy(newBuf, _chars, (size_t)(_len + 1)); + // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, (size_t)_len + 1); + char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1); + memcpy(newBuf, _chars, (size_t)_len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = newLimit; @@ -416,9 +415,9 @@ void AString::ReAlloc2(unsigned newLimit) { - if (newLimit >= k_Alloc_Len_Limit) throw 20130220; - // MY_STRING_REALLOC(_chars, char, newLimit + 1, 0); - char *newBuf = MY_STRING_NEW_char(newLimit + 1); + if (newLimit > k_Alloc_Len_Limit) throw 20130220; + // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, 0); + char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1); newBuf[0] = 0; MY_STRING_DELETE(_chars); _chars = newBuf; @@ -427,8 +426,8 @@ void AString::SetStartLen(unsigned len) { - _chars = 0; - _chars = MY_STRING_NEW_char(len + 1); + _chars = NULL; + _chars = MY_STRING_NEW_char((size_t)len + 1); _len = len; _limit = len; } @@ -439,20 +438,30 @@ next += next / 2; next += 16; next &= ~(unsigned)15; - ReAlloc(next - 1); + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len) + throw 20130220; + ReAlloc(next); + // Grow(1); } void AString::Grow(unsigned n) { - unsigned freeSize = _limit - _len; + const unsigned freeSize = _limit - _len; if (n <= freeSize) return; - unsigned next = _len + n; next += next / 2; next += 16; next &= ~(unsigned)15; - ReAlloc(next - 1); + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len || next - _len < n) + throw 20130220; + ReAlloc(next); } AString::AString(unsigned num, const char *s) @@ -500,7 +509,7 @@ AString::AString() { - _chars = 0; + _chars = NULL; _chars = MY_STRING_NEW_char(kStartStringCapacity); _len = 0; _limit = kStartStringCapacity - 1; @@ -548,7 +557,7 @@ unsigned len = MyStringLen(s); if (len > _limit) { - char *newBuf = MY_STRING_NEW_char(len + 1); + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -565,7 +574,7 @@ unsigned len = s._len; if (len > _limit) { - char *newBuf = MY_STRING_NEW_char(len + 1); + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -590,7 +599,7 @@ } if (len > _limit) { - char *newBuf = MY_STRING_NEW_char(len + 1); + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -614,7 +623,7 @@ } if (len > _limit) { - char *newBuf = MY_STRING_NEW_char(len + 1); + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -631,6 +640,7 @@ void AString::Add_Space() { operator+=(' '); } void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } void AString::Add_LF() { operator+=('\n'); } +void AString::Add_Slash() { operator+=('/'); } AString &AString::operator+=(const char *s) { @@ -667,11 +677,23 @@ _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); } +void AString::AddFrom(const char *s, unsigned len) // no check +{ + if (len != 0) + { + Grow(len); + memcpy(_chars + _len, s, len); + len += _len; + _chars[len] = 0; + _len = len; + } +} + void AString::SetFrom(const char *s, unsigned len) // no check { if (len > _limit) { - char *newBuf = MY_STRING_NEW_char(len + 1); + char *newBuf = MY_STRING_NEW_char((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -976,9 +998,8 @@ void UString::ReAlloc(unsigned newLimit) { - if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130221; - // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1); - wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1); + // MY_STRING_REALLOC(_chars, wchar_t, (size_t)newLimit + 1, (size_t)_len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); wmemcpy(newBuf, _chars, _len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; @@ -987,9 +1008,9 @@ void UString::ReAlloc2(unsigned newLimit) { - if (newLimit >= k_Alloc_Len_Limit) throw 20130221; + if (newLimit > k_Alloc_Len_Limit) throw 20130221; // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); - wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); newBuf[0] = 0; MY_STRING_DELETE(_chars); _chars = newBuf; @@ -999,7 +1020,7 @@ void UString::SetStartLen(unsigned len) { _chars = 0; - _chars = MY_STRING_NEW_wchar_t(len + 1); + _chars = MY_STRING_NEW_wchar_t((size_t)len + 1); _len = len; _limit = len; } @@ -1010,19 +1031,28 @@ next += next / 2; next += 16; next &= ~(unsigned)15; - ReAlloc(next - 1); + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len) + throw 20130220; + ReAlloc(next); } void UString::Grow(unsigned n) { - unsigned freeSize = _limit - _len; + const unsigned freeSize = _limit - _len; if (n <= freeSize) return; - unsigned next = _len + n; next += next / 2; next += 16; next &= ~(unsigned)15; + next--; + if (next < _len || next > k_Alloc_Len_Limit) + next = k_Alloc_Len_Limit; + if (next <= _len || next - _len < n) + throw 20130220; ReAlloc(next - 1); } @@ -1149,7 +1179,7 @@ unsigned len = MyStringLen(s); if (len > _limit) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -1166,7 +1196,7 @@ unsigned len = s._len; if (len > _limit) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -1180,7 +1210,7 @@ { if (len > _limit) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -1218,7 +1248,7 @@ if (len > _limit) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -1258,7 +1288,7 @@ unsigned len = MyStringLen(s); if (len > _limit) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); MY_STRING_DELETE(_chars); _chars = newBuf; _limit = len; @@ -1566,15 +1596,24 @@ void UString2::ReAlloc2(unsigned newLimit) { - if (newLimit >= k_Alloc_Len_Limit) throw 20130221; + // wrong (_len) is allowed after this function + if (newLimit > k_Alloc_Len_Limit) throw 20130221; // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); - _chars = MY_STRING_NEW_wchar_t(newLimit + 1); + if (_chars) + { + MY_STRING_DELETE(_chars); + _chars = NULL; + // _len = 0; + } + _chars = MY_STRING_NEW_wchar_t((size_t)newLimit + 1); + _chars[0] = 0; + // _len = newLimit; } void UString2::SetStartLen(unsigned len) { - _chars = 0; - _chars = MY_STRING_NEW_wchar_t(len + 1); + _chars = NULL; + _chars = MY_STRING_NEW_wchar_t((size_t)len + 1); _len = len; } @@ -1591,7 +1630,7 @@ UString2::UString2(const wchar_t *s) { - unsigned len = MyStringLen(s); + const unsigned len = MyStringLen(s); SetStartLen(len); wmemcpy(_chars, s, len + 1); } @@ -1628,7 +1667,7 @@ unsigned len = MyStringLen(s); if (len > _len) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); if (_chars) MY_STRING_DELETE(_chars); _chars = newBuf; @@ -1643,7 +1682,7 @@ unsigned len = MyStringLen(s); if (len > _len) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); if (_chars) MY_STRING_DELETE(_chars); _chars = newBuf; @@ -1662,7 +1701,7 @@ unsigned len = s._len; if (len > _len) { - wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); + wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1); if (_chars) MY_STRING_DELETE(_chars); _chars = newBuf; diff -Nru 7zip-21.07+dfsg/CPP/Common/MyString.h 7zip-22.01/CPP/Common/MyString.h --- 7zip-21.07+dfsg/CPP/Common/MyString.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/MyString.h 2022-03-15 09:00:00.000000000 +0000 @@ -378,6 +378,7 @@ void Add_Space_if_NotEmpty(); void Add_OptSpaced(const char *s); void Add_LF(); + void Add_Slash(); void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); } AString &operator+=(const char *s); @@ -386,12 +387,12 @@ void Add_UInt32(UInt32 v); void Add_UInt64(UInt64 v); + void AddFrom(const char *s, unsigned len); // no check void SetFrom(const char *s, unsigned len); // no check void SetFrom_CalcLen(const char *s, unsigned len); AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } AString Left(unsigned count) const { return AString(count, *this); } - // void MakeUpper() { MyStringUpper(_chars); } // void MakeLower() { MyStringLower(_chars); } void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } diff -Nru 7zip-21.07+dfsg/CPP/Common/MyVector.h 7zip-22.01/CPP/Common/MyVector.h --- 7zip-21.07+dfsg/CPP/Common/MyVector.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/MyVector.h 2022-03-27 13:00:00.000000000 +0000 @@ -5,6 +5,8 @@ #include +const unsigned k_VectorSizeMax = ((unsigned)1 << 31) - 1; + template class CRecordVector { @@ -17,31 +19,41 @@ memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T)); } - void ReserveOnePosition() + void ReAllocForNewCapacity(const unsigned newCapacity) { - if (_size == _capacity) - { - unsigned newCapacity = _capacity + (_capacity >> 2) + 1; - T *p; - MY_ARRAY_NEW(p, T, newCapacity); - // p = new T[newCapacity]; - if (_size != 0) - memcpy(p, _items, (size_t)_size * sizeof(T)); - delete []_items; - _items = p; - _capacity = newCapacity; - } + T *p; + MY_ARRAY_NEW(p, T, newCapacity); + // p = new T[newCapacity]; + if (_size != 0) + memcpy(p, _items, (size_t)_size * sizeof(T)); + delete []_items; + _items = p; + _capacity = newCapacity; } public: + void ReserveOnePosition() + { + if (_size != _capacity) + return; + if (_capacity >= k_VectorSizeMax) + throw 2021; + const unsigned rem = k_VectorSizeMax - _capacity; + unsigned add = (_capacity >> 2) + 1; + if (add > rem) + add = rem; + ReAllocForNewCapacity(_capacity + add); + } + CRecordVector(): _items(NULL), _size(0), _capacity(0) {} - CRecordVector(const CRecordVector &v): _items(0), _size(0), _capacity(0) + CRecordVector(const CRecordVector &v): _items(NULL), _size(0), _capacity(0) { - unsigned size = v.Size(); + const unsigned size = v.Size(); if (size != 0) { + // MY_ARRAY_NEW(_items, T, size) _items = new T[size]; _size = size; _capacity = size; @@ -66,22 +78,25 @@ { if (newCapacity > _capacity) { - T *p; - MY_ARRAY_NEW(p, T, newCapacity); - // p = new T[newCapacity]; - if (_size != 0) - memcpy(p, _items, (size_t)_size * sizeof(T)); - delete []_items; - _items = p; - _capacity = newCapacity; + if (newCapacity > k_VectorSizeMax) + throw 2021; + ReAllocForNewCapacity(newCapacity); } } + void ChangeSize_KeepData(unsigned newSize) + { + Reserve(newSize); + _size = newSize; + } + void ClearAndReserve(unsigned newCapacity) { Clear(); if (newCapacity > _capacity) { + if (newCapacity > k_VectorSizeMax) + throw 2021; delete []_items; _items = NULL; _capacity = 0; @@ -97,22 +112,6 @@ _size = newSize; } - void ChangeSize_KeepData(unsigned newSize) - { - if (newSize > _capacity) - { - T *p; - MY_ARRAY_NEW(p, T, newSize) - // p = new T[newSize]; - if (_size != 0) - memcpy(p, _items, (size_t)_size * sizeof(T)); - delete []_items; - _items = p; - _capacity = newSize; - } - _size = newSize; - } - void ReserveDown() { if (_size == _capacity) @@ -120,6 +119,7 @@ T *p = NULL; if (_size != 0) { + // MY_ARRAY_NEW(p, T, _size) p = new T[_size]; memcpy(p, _items, (size_t)_size * sizeof(T)); } @@ -178,7 +178,7 @@ { if (&v == this) return *this; - unsigned size = v.Size(); + const unsigned size = v.Size(); if (size > _capacity) { delete []_items; @@ -196,24 +196,45 @@ CRecordVector& operator+=(const CRecordVector &v) { - unsigned size = v.Size(); - Reserve(_size + size); + const unsigned size = v.Size(); if (size != 0) + { + if (_size >= k_VectorSizeMax || size > k_VectorSizeMax - _size) + throw 2021; + const unsigned newSize = _size + size; + Reserve(newSize); memcpy(_items + _size, v._items, (size_t)size * sizeof(T)); - _size += size; + _size = newSize; + } return *this; } unsigned Add(const T item) { ReserveOnePosition(); - _items[_size] = item; - return _size++; + const unsigned size = _size; + _size = size + 1; + _items[size] = item; + return size; + } + + /* + unsigned Add2(const T &item) + { + ReserveOnePosition(); + const unsigned size = _size; + _size = size + 1; + _items[size] = item; + return size; } + */ - void AddInReserved(const T item) + unsigned AddInReserved(const T item) { - _items[_size++] = item; + const unsigned size = _size; + _size = size + 1; + _items[size] = item; + return size; } void Insert(unsigned index, const T item) @@ -224,6 +245,13 @@ _size++; } + void InsertInReserved(unsigned index, const T item) + { + MoveItems(index + 1, index); + _items[index] = item; + _size++; + } + void MoveToFront(unsigned index) { if (index != 0) @@ -254,7 +282,8 @@ { while (left != right) { - unsigned mid = (left + right) / 2; + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; const T midVal = (*this)[mid]; if (item == midVal) return (int)mid; @@ -270,9 +299,10 @@ { while (left != right) { - unsigned mid = (left + right) / 2; + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; - int comp = item.Compare(midVal); + const int comp = item.Compare(midVal); if (comp == 0) return (int)mid; if (comp < 0) @@ -298,7 +328,8 @@ unsigned left = 0, right = _size; while (left != right) { - unsigned mid = (left + right) / 2; + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; const T midVal = (*this)[mid]; if (item == midVal) return mid; @@ -316,9 +347,10 @@ unsigned left = 0, right = _size; while (left != right) { - unsigned mid = (left + right) / 2; + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; - int comp = item.Compare(midVal); + const int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) @@ -431,29 +463,35 @@ CObjectVector() {} CObjectVector(const CObjectVector &v) { - unsigned size = v.Size(); + const unsigned size = v.Size(); _v.ConstructReserve(size); for (unsigned i = 0; i < size; i++) - _v.AddInReserved(new T(v[i])); + AddInReserved(v[i]); } CObjectVector& operator=(const CObjectVector &v) { if (&v == this) return *this; Clear(); - unsigned size = v.Size(); + const unsigned size = v.Size(); _v.Reserve(size); for (unsigned i = 0; i < size; i++) - _v.AddInReserved(new T(v[i])); + AddInReserved(v[i]); return *this; } CObjectVector& operator+=(const CObjectVector &v) { - unsigned size = v.Size(); - _v.Reserve(Size() + size); - for (unsigned i = 0; i < size; i++) - _v.AddInReserved(new T(v[i])); + const unsigned addSize = v.Size(); + if (addSize != 0) + { + const unsigned size = Size(); + if (size >= k_VectorSizeMax || addSize > k_VectorSizeMax - size) + throw 2021; + _v.Reserve(size + addSize); + for (unsigned i = 0; i < addSize; i++) + AddInReserved(v[i]); + } return *this; } @@ -466,14 +504,37 @@ void MoveToFront(unsigned index) { _v.MoveToFront(index); } - unsigned Add(const T& item) { return _v.Add(new T(item)); } + unsigned Add(const T& item) + { + _v.ReserveOnePosition(); + return AddInReserved(item); + } + + unsigned AddInReserved(const T& item) + { + return _v.AddInReserved(new T(item)); + } + + void ReserveOnePosition() + { + _v.ReserveOnePosition(); + } + + unsigned AddInReserved_Ptr_of_new(T *ptr) + { + return _v.AddInReserved(ptr); + } + + #define VECTOR_ADD_NEW_OBJECT(v, a) \ + (v).ReserveOnePosition(); \ + (v).AddInReserved_Ptr_of_new(new a); - void AddInReserved(const T& item) { _v.AddInReserved(new T(item)); } T& AddNew() { + _v.ReserveOnePosition(); T *p = new T; - _v.Add(p); + _v.AddInReserved(p); return *p; } @@ -484,12 +545,17 @@ return *p; } - void Insert(unsigned index, const T& item) { _v.Insert(index, new T(item)); } + void Insert(unsigned index, const T& item) + { + _v.ReserveOnePosition(); + _v.InsertInReserved(index, new T(item)); + } T& InsertNew(unsigned index) { + _v.ReserveOnePosition(); T *p = new T; - _v.Insert(index, p); + _v.InsertInReserved(index, p); return *p; } @@ -514,7 +580,7 @@ void DeleteFrom(unsigned index) { - unsigned size = _v.Size(); + const unsigned size = _v.Size(); for (unsigned i = index; i < size; i++) delete (T *)_v[i]; _v.DeleteFrom(index); @@ -564,9 +630,10 @@ unsigned left = 0, right = Size(); while (left != right) { - unsigned mid = (left + right) / 2; + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; - int comp = item.Compare(midVal); + const int comp = item.Compare(midVal); if (comp == 0) return (int)mid; if (comp < 0) @@ -582,9 +649,10 @@ unsigned left = 0, right = Size(); while (left != right) { - unsigned mid = (left + right) / 2; + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; - int comp = item.Compare(midVal); + const int comp = item.Compare(midVal); if (comp == 0) return mid; if (comp < 0) @@ -602,9 +670,10 @@ unsigned left = 0, right = Size(); while (left != right) { - unsigned mid = (left + right) / 2; + // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); + const unsigned mid = (left + right) / 2; const T& midVal = (*this)[mid]; - int comp = item.Compare(midVal); + const int comp = item.Compare(midVal); if (comp == 0) { right = mid + 1; diff -Nru 7zip-21.07+dfsg/CPP/Common/MyWindows.h 7zip-22.01/CPP/Common/MyWindows.h --- 7zip-21.07+dfsg/CPP/Common/MyWindows.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/MyWindows.h 2022-03-27 13:00:00.000000000 +0000 @@ -76,7 +76,6 @@ DWORD dwHighDateTime; } FILETIME; -#define HRESULT LONG #define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) #define FAILED(hr) ((HRESULT)(hr) < 0) typedef ULONG PROPID; @@ -150,6 +149,7 @@ VT_VARIANT = 12, VT_UNKNOWN = 13, VT_DECIMAL = 14, + VT_I1 = 16, VT_UI1 = 17, VT_UI2 = 18, diff -Nru 7zip-21.07+dfsg/CPP/Common/NewHandler.cpp 7zip-22.01/CPP/Common/NewHandler.cpp --- 7zip-21.07+dfsg/CPP/Common/NewHandler.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/NewHandler.cpp 2022-03-27 13:00:00.000000000 +0000 @@ -97,19 +97,33 @@ static void *a[kDebugSize]; static int index = 0; +static bool wasInit = false; +static CRITICAL_SECTION cs; + static int numAllocs = 0; void * __cdecl operator new(size_t size) { + if (!wasInit) + { + InitializeCriticalSection(&cs); + wasInit = true; + } + EnterCriticalSection(&cs); + numAllocs++; + int loc = numAllocs; void *p = HeapAlloc(GetProcessHeap(), 0, size); + /* if (index < kDebugSize) { a[index] = p; index++; } + */ + printf("Alloc %6d, size = %8u\n", loc, (unsigned)size); + LeaveCriticalSection(&cs); if (p == 0) throw CNewException(); - printf("Alloc %6d, size = %8u\n", numAllocs, (unsigned)size); return p; } @@ -123,6 +137,7 @@ } ~CC() { + printf("\nDestructor: %d\n", numAllocs); for (int i = 0; i < kDebugSize; i++) if (a[i] != 0) return; @@ -134,6 +149,7 @@ { if (p == 0) return; + EnterCriticalSection(&cs); /* for (int i = 0; i < index; i++) if (a[i] == p) @@ -142,6 +158,7 @@ HeapFree(GetProcessHeap(), 0, p); numAllocs--; printf("Free %d\n", numAllocs); + LeaveCriticalSection(&cs); } #endif diff -Nru 7zip-21.07+dfsg/CPP/Common/StringToInt.cpp 7zip-22.01/CPP/Common/StringToInt.cpp --- 7zip-21.07+dfsg/CPP/Common/StringToInt.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/StringToInt.cpp 2022-03-27 13:00:00.000000000 +0000 @@ -26,6 +26,33 @@ CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte) CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t) +/* +Int32 ConvertStringToInt32(const char *s, const char **end) throw() +{ + if (end) + *end = s; + const char *s2 = s; + if (*s == '-') + s2++; + if (*s2 == 0) + return 0; + const char *end2; + UInt32 res = ConvertStringToUInt32(s2, &end2); + if (*s == '-') + { + if (res > ((UInt32)1 << (32 - 1))) + return 0; + } + else if ((res & ((UInt32)1 << (32 - 1))) != 0) + return 0; + if (end) + *end = end2; + if (*s == '-') + return -(Int32)res; + return (Int32)res; +} +*/ + Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw() { if (end) diff -Nru 7zip-21.07+dfsg/CPP/Common/StringToInt.h 7zip-22.01/CPP/Common/StringToInt.h --- 7zip-21.07+dfsg/CPP/Common/StringToInt.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Common/StringToInt.h 2022-03-27 13:00:00.000000000 +0000 @@ -10,6 +10,7 @@ UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw(); UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw(); +// Int32 ConvertStringToInt32(const char *s, const char **end) throw(); Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw(); UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw(); diff -Nru 7zip-21.07+dfsg/CPP/Windows/FileDir.cpp 7zip-22.01/CPP/Windows/FileDir.cpp --- 7zip-21.07+dfsg/CPP/Windows/FileDir.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/FileDir.cpp 2022-03-31 14:00:00.000000000 +0000 @@ -17,7 +17,6 @@ #include "../Common/StringConvert.h" #include "../Common/C_FileIO.h" -#include "TimeUtils.h" #endif #include "FileDir.h" @@ -32,6 +31,30 @@ using namespace NFile; using namespace NName; +#ifndef _WIN32 + +static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts) +{ + if (ft) + { + ts = *ft; + return true; + } + // else + { + ts.tv_sec = 0; + ts.tv_nsec = + #ifdef UTIME_OMIT + UTIME_OMIT; // -2 keep old timesptamp + #else + // UTIME_NOW; -1 // set to the current time + 0; + #endif + return false; + } +} +#endif + namespace NWindows { namespace NFile { namespace NDir { @@ -86,7 +109,7 @@ #endif // UNDER_CE -bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) { #ifndef _UNICODE if (!g_IsNT) @@ -920,39 +943,11 @@ // #define UTIME_OMIT -2 #endif -static bool FILETME_To_timespec(const FILETIME *ft, timespec &ts) -{ - if (ft) - { - const Int64 sec = NTime::FileTimeToUnixTime64(*ft); - // time_t is long - const time_t sec2 = (time_t)sec; - if (sec2 == sec) - { - ts.tv_sec = sec2; - const UInt64 winTime = (((UInt64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime; - ts.tv_nsec = (long)((winTime % 10000000) * 100); - return true; - } - } - // else - { - ts.tv_sec = 0; - ts.tv_nsec = - #ifdef UTIME_OMIT - UTIME_OMIT; // keep old timesptamp - #else - // UTIME_NOW; // set to the current time - 0; - #endif - return false; - } -} -bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) { // need testing /* @@ -998,12 +993,18 @@ UNUSED_VAR(cTime) bool needChange; - needChange = FILETME_To_timespec(aTime, times[0]); - needChange |= FILETME_To_timespec(mTime, times[1]); + needChange = FiTime_To_timespec(aTime, times[0]); + needChange |= FiTime_To_timespec(mTime, times[1]); + + /* + if (mTime) + { + printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); + } + */ if (!needChange) return true; - const int flags = 0; // follow link // = AT_SYMLINK_NOFOLLOW; // don't follow link return utimensat(AT_FDCWD, path, times, flags) == 0; @@ -1039,6 +1040,10 @@ #define TRACE_chmod(s, mode) \ PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode))); +int my_chown(CFSTR path, uid_t owner, gid_t group) +{ + return chown(path, owner, group); +} bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) { diff -Nru 7zip-21.07+dfsg/CPP/Windows/FileDir.h 7zip-22.01/CPP/Windows/FileDir.h --- 7zip-21.07+dfsg/CPP/Windows/FileDir.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/FileDir.h 2022-03-28 10:00:00.000000000 +0000 @@ -14,7 +14,12 @@ bool GetWindowsDir(FString &path); bool GetSystemDir(FString &path); -bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); +/* +WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file +but linux : allows unix time = 0 in filesystem +*/ + +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); #ifdef _WIN32 @@ -27,6 +32,9 @@ SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute bits that are related to current system only. */ +#else + +int my_chown(CFSTR path, uid_t owner, gid_t group); #endif diff -Nru 7zip-21.07+dfsg/CPP/Windows/FileFind.cpp 7zip-22.01/CPP/Windows/FileFind.cpp --- 7zip-21.07+dfsg/CPP/Windows/FileFind.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/FileFind.cpp 2022-03-31 13:00:00.000000000 +0000 @@ -7,6 +7,8 @@ #ifndef _WIN32 #include /* Definition of AT_* constants */ #include "TimeUtils.h" +// for major +// #include #endif #include "FileFind.h" @@ -62,24 +64,35 @@ namespace NFind { +/* +#ifdef _WIN32 #define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; +#else +#define MY_CLEAR_FILETIME(ft) ft.tv_sec = 0; ft.tv_nsec = 0; +#endif +*/ void CFileInfoBase::ClearBase() throw() { Size = 0; - MY_CLEAR_FILETIME(CTime); - MY_CLEAR_FILETIME(ATime); - MY_CLEAR_FILETIME(MTime); + FiTime_Clear(CTime); + FiTime_Clear(ATime); + FiTime_Clear(MTime); + + #ifdef _WIN32 Attrib = 0; // ReparseTag = 0; IsAltStream = false; IsDevice = false; - - #ifndef _WIN32 + #else + dev = 0; ino = 0; - nlink = 0; mode = 0; - #endif + nlink = 0; + uid = 0; + gid = 0; + rdev = 0; + #endif } bool CFileInfo::IsDots() const throw() @@ -439,6 +452,20 @@ bool CFileInfo::Find(CFSTR path, bool followLink) { #ifdef SUPPORT_DEVICE_FILE + + if (IS_PATH_SEPAR(path[0]) && + IS_PATH_SEPAR(path[1]) && + path[2] == '.' && + path[3] == 0) + { + // 22.00 : it's virtual directory for devices + // IsDevice = true; + ClearBase(); + Name = path + 2; + Attrib = FILE_ATTRIBUTE_DIRECTORY; + return true; + } + if (IsDevicePath(path)) { ClearBase(); @@ -469,7 +496,7 @@ #if defined(_WIN32) && !defined(UNDER_CE) - int colonPos = FindAltStreamColon(path); + const int colonPos = FindAltStreamColon(path); if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0) { UString streamName = fs2us(path + (unsigned)colonPos); @@ -635,7 +662,7 @@ return Fill_From_ByHandleFileInfo(path); } -bool CFileInfo::Fill_From_ByHandleFileInfo(CFSTR path) +bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path) { BY_HANDLE_FILE_INFORMATION info; if (!NIO::CFileBase::GetFileInformation(path, &info)) @@ -950,13 +977,6 @@ } -void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft) -{ - UInt64 v = NTime::UnixTime64ToFileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); - ft.dwLowDateTime = (DWORD)v; - ft.dwHighDateTime = (DWORD)(v >> 32); -} - UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode) { UInt32 attrib = S_ISDIR(mode) ? @@ -984,7 +1004,7 @@ void CFileInfo::SetFrom_stat(const struct stat &st) { - IsDevice = false; + // IsDevice = false; if (S_ISDIR(st.st_mode)) { @@ -995,7 +1015,7 @@ Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename } - Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); + // Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); // NTime::UnixTimeToFileTime(st.st_ctime, CTime); // NTime::UnixTimeToFileTime(st.st_mtime, MTime); @@ -1010,27 +1030,89 @@ */ // timespec_To_FILETIME(st.st_birthtimespec, CTime); // #else - timespec_To_FILETIME(st.st_ctimespec, CTime); + // timespec_To_FILETIME(st.st_ctimespec, CTime); // #endif - timespec_To_FILETIME(st.st_mtimespec, MTime); - timespec_To_FILETIME(st.st_atimespec, ATime); + // timespec_To_FILETIME(st.st_mtimespec, MTime); + // timespec_To_FILETIME(st.st_atimespec, ATime); + CTime = st.st_ctimespec; + MTime = st.st_mtimespec; + ATime = st.st_atimespec; + #else - timespec_To_FILETIME(st.st_ctim, CTime); - timespec_To_FILETIME(st.st_mtim, MTime); - timespec_To_FILETIME(st.st_atim, ATime); + // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100); + // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100); + // timespec_To_FILETIME(st.st_atim, ATime, &ATime_ns100); + CTime = st.st_ctim; + MTime = st.st_mtim; + ATime = st.st_atim; + #endif dev = st.st_dev; ino = st.st_ino; - nlink = st.st_nlink; mode = st.st_mode; + nlink = st.st_nlink; + uid = st.st_uid; + gid = st.st_gid; + rdev = st.st_rdev; + + /* + printf("\n sizeof timespec = %d", (int)sizeof(timespec)); + printf("\n sizeof st_rdev = %d", (int)sizeof(rdev)); + printf("\n sizeof st_ino = %d", (int)sizeof(ino)); + printf("\n sizeof mode_t = %d", (int)sizeof(mode_t)); + printf("\n sizeof nlink_t = %d", (int)sizeof(nlink_t)); + printf("\n sizeof uid_t = %d", (int)sizeof(uid_t)); + printf("\n"); + */ + /* + printf("\n st_rdev = %llx", (long long)rdev); + printf("\n st_dev = %llx", (long long)dev); + printf("\n dev : major = %5x minor = %5x", (unsigned)major(dev), (unsigned)minor(dev)); + printf("\n st_ino = %lld", (long long)(ino)); + printf("\n rdev : major = %5x minor = %5x", (unsigned)major(rdev), (unsigned)minor(rdev)); + printf("\n size = %lld \n", (long long)(Size)); + printf("\n"); + */ +} + +/* +int Uid_To_Uname(uid_t uid, AString &name) +{ + name.Empty(); + struct passwd *passwd; + + if (uid != 0 && uid == cached_no_such_uid) + { + *uname = xstrdup (""); + return; + } + + if (!cached_uname || uid != cached_uid) + { + passwd = getpwuid (uid); + if (passwd) + { + cached_uid = uid; + assign_string (&cached_uname, passwd->pw_name); + } + else + { + cached_no_such_uid = uid; + *uname = xstrdup (""); + return; + } + } + *uname = xstrdup (cached_uname); } +*/ bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink) { struct stat st; if (MY__lstat(path, &st, followLink) != 0) return false; + // printf("\nFind_DontFill_Name : name=%s\n", path); SetFrom_stat(st); return true; } @@ -1232,6 +1314,7 @@ if (res != 0) return false; + // printf("\nname=%s\n", de.Name.Ptr()); fileInfo.SetFrom_stat(st); fileInfo.Name = de.Name; return true; diff -Nru 7zip-21.07+dfsg/CPP/Windows/FileFind.h 7zip-22.01/CPP/Windows/FileFind.h --- 7zip-21.07+dfsg/CPP/Windows/FileFind.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/FileFind.h 2022-03-31 13:00:00.000000000 +0000 @@ -9,10 +9,14 @@ #include #endif +#include "../Common/MyLinux.h" #include "../Common/MyString.h" #include "../Common/MyWindows.h" + #include "Defs.h" +#include "FileIO.h" + namespace NWindows { namespace NFile { namespace NFind { @@ -32,6 +36,7 @@ DWORD GetFileAttrib(CFSTR path); +#ifdef _WIN32 namespace NAttributes { @@ -42,21 +47,38 @@ inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; } inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; } inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; } + + inline UInt32 Get_PosixMode_From_WinAttrib(DWORD attrib) + { + UInt32 v = IsDir(attrib) ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG; + /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY). + So extracting at Linux will be allowed to write files inside (0777) directories. */ + v |= ((IsReadOnly(attrib) && !IsDir(attrib)) ? 0555 : 0777); + return v; + } } +#else + +UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode); + +#endif + class CFileInfoBase { + #ifdef _WIN32 bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); } + #endif public: UInt64 Size; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; + CFiTime CTime; + CFiTime ATime; + CFiTime MTime; + #ifdef _WIN32 DWORD Attrib; bool IsAltStream; bool IsDevice; - #ifdef _WIN32 /* #ifdef UNDER_CE DWORD ObjectID; @@ -64,24 +86,25 @@ UINT32 ReparseTag; #endif */ - #else - dev_t dev; + #else + dev_t dev; /* ID of device containing file */ ino_t ino; - nlink_t nlink; mode_t mode; + nlink_t nlink; + uid_t uid; /* user ID of owner */ + gid_t gid; /* group ID of owner */ + dev_t rdev; /* device ID (defined, if S_ISCHR(mode) || S_ISBLK(mode)) */ // bool Use_lstat; - #endif + #endif CFileInfoBase() { ClearBase(); } void ClearBase() throw(); - - void SetAsDir() - { - Attrib = FILE_ATTRIBUTE_DIRECTORY; - #ifndef _WIN32 - Attrib |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16)); - #endif - } + + #ifdef _WIN32 + + bool Fill_From_ByHandleFileInfo(CFSTR path); + void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16)); + void SetAsFile() { Attrib = 0; } bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } @@ -96,13 +119,33 @@ bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } - #ifndef _WIN32 - bool IsPosixLink() const + UInt32 GetWinAttrib() const { return Attrib; } + UInt32 GetPosixAttrib() const { - const UInt32 mod = Attrib >> 16; - return S_ISLNK(mod); + return NAttributes::Get_PosixMode_From_WinAttrib(Attrib); } - #endif + bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; } + + #else + + UInt32 GetPosixAttrib() const { return mode; } + UInt32 GetWinAttrib() const { return Get_WinAttribPosix_From_PosixMode(mode); } + + bool IsDir() const { return S_ISDIR(mode); } + void SetAsDir() { mode = S_IFDIR; } + void SetAsFile() { mode = S_IFREG; } + + bool IsReadOnly() const + { + // does linux support writing to ReadOnly files? + if ((mode & 0222) == 0) // S_IWUSR in p7zip + return true; + return false; + } + + bool IsPosixLink() const { return S_ISLNK(mode); } + + #endif bool IsOsSymLink() const { @@ -126,7 +169,7 @@ bool Find_FollowLink(CFSTR path) { return Find(path, true); } #ifdef _WIN32 - bool Fill_From_ByHandleFileInfo(CFSTR path); + // bool Fill_From_ByHandleFileInfo(CFSTR path); // bool FollowReparse(CFSTR path, bool isDir); #else bool Find_DontFill_Name(CFSTR path, bool followLink = false); @@ -287,16 +330,8 @@ } */ -UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode); - // UInt32 Get_WinAttrib_From_stat(const struct stat &st); -#if defined(_AIX) - #define MY_ST_TIMESPEC st_timespec -#else - #define MY_ST_TIMESPEC timespec -#endif -void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft); #endif // WIN32 diff -Nru 7zip-21.07+dfsg/CPP/Windows/FileIO.cpp 7zip-22.01/CPP/Windows/FileIO.cpp --- 7zip-21.07+dfsg/CPP/Windows/FileIO.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/FileIO.cpp 2022-03-31 13:00:00.000000000 +0000 @@ -8,6 +8,14 @@ // #include +/* +#ifndef _WIN32 +// for ioctl BLKGETSIZE64 +#include +#include +#endif +*/ + #include "FileIO.h" #include "FileName.h" @@ -615,7 +623,7 @@ namespace NFile { namespace NDir { -bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); +bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime); } namespace NIO { @@ -629,6 +637,19 @@ Close(); _handle = ::open(name, flags, 0666); return _handle != -1; + + /* + if (_handle == -1) + return false; + if (IsString1PrefixedByString2(name, "/dev/")) + { + // /dev/sda + // IsDeviceFile = true; // for debug + // SizeDefined = false; + // SizeDefined = (GetDeviceSize_InBytes(Size) == 0); + } + return true; + */ } bool CFileBase::Close() @@ -638,6 +659,10 @@ if (close(_handle) != 0) return false; _handle = -1; + /* + IsDeviceFile = false; + SizeDefined = false; + */ return true; } @@ -651,15 +676,35 @@ const off_t lengthTemp = seek(0, SEEK_END); seek(curPos, SEEK_SET); length = (UInt64)lengthTemp; + + /* + // 22.00: + if (lengthTemp == 1) + if (IsDeviceFile && SizeDefined) + { + length = Size; + return true; + } + */ + return (lengthTemp != -1); } off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const { + /* + if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END) + { + printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove); + distanceToMove += Size; + moveMethod = SEEK_SET; + } + */ + // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove); // off_t res = ::lseek(_handle, distanceToMove, moveMethod); + // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove); return ::lseek(_handle, distanceToMove, moveMethod); - // printf(" res = %lld", (long long)res); // return res; } @@ -694,6 +739,28 @@ return Open(name); } + +/* +int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks) +{ + // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition + // #include + return ioctl(_handle, BLKGETSIZE64, numBlocks); + // in block size +} + +int CFileBase::GetDeviceSize_InBytes(UInt64 &size) +{ + size = 0; + unsigned long long numBlocks; + int res = my_ioctl_BLKGETSIZE64(&numBlocks); + if (res == 0) + size = numBlocks; // another blockSize s possible? + printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size); + return res; +} +*/ + /* On Linux (32-bit and 64-bit): read(), write() (and similar system calls) will transfer at most @@ -802,7 +869,7 @@ return res; } -bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() +bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw() { // On some OS (cygwin, MacOSX ...), you must close the file before updating times // return true; @@ -811,9 +878,22 @@ if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false; if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; return true; + + /* + struct timespec times[2]; + UNUSED_VAR(cTime) + if (!aTime && !mTime) + return true; + bool needChange; + needChange = FiTime_To_timespec(aTime, times[0]); + needChange |= FiTime_To_timespec(mTime, times[1]); + if (!needChange) + return true; + return futimens(_handle, times) == 0; + */ } -bool COutFile::SetMTime(const FILETIME *mTime) throw() +bool COutFile::SetMTime(const CFiTime *mTime) throw() { if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; return true; diff -Nru 7zip-21.07+dfsg/CPP/Windows/FileIO.h 7zip-22.01/CPP/Windows/FileIO.h --- 7zip-21.07+dfsg/CPP/Windows/FileIO.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/FileIO.h 2022-03-31 13:00:00.000000000 +0000 @@ -30,6 +30,8 @@ #include "../Common/MyString.h" #include "../Common/MyBuffer.h" +#include "../Windows/TimeUtils.h" + #include "Defs.h" HRESULT GetLastError_noZero_HRESULT(); @@ -94,6 +96,12 @@ UString GetPath() const; }; +#ifdef _WIN32 +#define CFiInfo BY_HANDLE_FILE_INFORMATION +#define ST_MTIME(st) (st).ftLastWriteTime +#else +#define CFiInfo stat +#endif #ifdef _WIN32 @@ -142,6 +150,8 @@ CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {}; ~CFileBase() { Close(); } + HANDLE GetHandle() const { return _handle; } + bool Close() throw(); bool GetPosition(UInt64 &position) const throw(); @@ -213,6 +223,15 @@ #ifndef UNDER_CE + bool Open_for_ReadAttributes(CFSTR fileName) + { + return Create(fileName, FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); + // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. + } + bool OpenReparse(CFSTR fileName) { // 17.02 fix: to support Windows XP compatibility junctions: @@ -240,8 +259,8 @@ bool Create(CFSTR fileName, bool createAlways); bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes); - bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); - bool SetMTime(const FILETIME *mTime) 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(); bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); bool WriteFull(const void *data, size_t size) throw(); @@ -270,6 +289,12 @@ protected: int _handle; + /* + bool IsDeviceFile; + bool SizeDefined; + UInt64 Size; // it can be larger than real available size + */ + bool OpenBinary(const char *name, int flags); public: bool PreserveATime; @@ -283,6 +308,11 @@ off_t seekToCur() const throw(); // bool SeekToBegin() throw(); int my_fstat(struct stat *st) const { return fstat(_handle, st); } + /* + int my_ioctl_BLKGETSIZE64(unsigned long long *val); + int GetDeviceSize_InBytes(UInt64 &size); + void CalcDeviceSize(CFSTR s); + */ }; class CInFile: public CFileBase @@ -301,9 +331,9 @@ bool ATime_defined; bool MTime_defined; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; + CFiTime CTime; + CFiTime ATime; + CFiTime MTime; AString Path; ssize_t write_part(const void *data, size_t size) throw(); @@ -333,8 +363,8 @@ { return SetLength(length); } - bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); - bool SetMTime(const FILETIME *mTime) throw(); + bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); + bool SetMTime(const CFiTime *mTime) throw(); }; } diff -Nru 7zip-21.07+dfsg/CPP/Windows/MemoryLock.cpp 7zip-22.01/CPP/Windows/MemoryLock.cpp --- 7zip-21.07+dfsg/CPP/Windows/MemoryLock.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/MemoryLock.cpp 2022-07-14 12:00:00.000000000 +0000 @@ -21,7 +21,7 @@ typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength); } -#define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff)GetProcAddress(hModule, name) +#define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff) (void(*)()) GetProcAddress(hModule, name) #endif bool EnablePrivilege(LPCTSTR privilegeName, bool enable) diff -Nru 7zip-21.07+dfsg/CPP/Windows/PropVariantConv.cpp 7zip-22.01/CPP/Windows/PropVariantConv.cpp --- 7zip-21.07+dfsg/CPP/Windows/PropVariantConv.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/PropVariantConv.cpp 2022-03-29 11:00:00.000000000 +0000 @@ -9,7 +9,7 @@ #define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; } -bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw() +bool ConvertUtcFileTimeToString2(const FILETIME &utc, unsigned ns100, char *s, int level) throw() { *s = 0; FILETIME ft; @@ -18,7 +18,10 @@ SYSTEMTIME st; if (!BOOLToBool(FileTimeToSystemTime(&ft, &st))) + { + // win10 : that function doesn't work, if bit 63 of 64-bit FILETIME is set. return false; + } { unsigned val = st.wYear; @@ -71,6 +74,12 @@ numDigits = (unsigned)level; s += numDigits; } + if (level >= kTimestampPrintLevel_NTFS + 1) + { + *s++ = (char)('0' + (ns100 / 10)); + if (level >= kTimestampPrintLevel_NTFS + 2) + *s++ = (char)('0' + (ns100 % 10)); + } } } } @@ -80,6 +89,25 @@ } +bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw() +{ + return ConvertUtcFileTimeToString2(utc, 0, s, level); +} + +bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *dest, int level) throw() +{ + char s[32]; + bool res = ConvertUtcFileTimeToString2(ft, ns100, s, level); + for (unsigned i = 0;; i++) + { + Byte c = (Byte)s[i]; + dest[i] = c; + if (c == 0) + break; + } + return res; +} + bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw() { char s[32]; @@ -106,7 +134,19 @@ case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; - case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return; + case VT_FILETIME: + { + // const unsigned prec = prop.wReserved1; + int level = 0; + /* + if (prec == 0) + level = 7; + else if (prec > 16 && prec <= 16 + 9) + level = prec - 16; + */ + ConvertUtcFileTimeToString(prop.filetime, dest, level); + return; + } // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; @@ -127,7 +167,19 @@ case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return; case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return; case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return; - case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return; + case VT_FILETIME: + { + // const unsigned prec = prop.wReserved1; + int level = 0; + /* + if (prec == 0) + level = 7; + else if (prec > 16 && prec <= 16 + 9) + level = prec - 16; + */ + ConvertUtcFileTimeToString(prop.filetime, dest, level); + return; + } // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return; case VT_I2: ConvertInt64ToString(prop.iVal, dest); return; case VT_I4: ConvertInt64ToString(prop.lVal, dest); return; diff -Nru 7zip-21.07+dfsg/CPP/Windows/PropVariantConv.h 7zip-22.01/CPP/Windows/PropVariantConv.h --- 7zip-21.07+dfsg/CPP/Windows/PropVariantConv.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/PropVariantConv.h 2022-03-29 11:00:00.000000000 +0000 @@ -10,11 +10,14 @@ #define kTimestampPrintLevel_DAY -3 // #define kTimestampPrintLevel_HOUR -2 #define kTimestampPrintLevel_MIN -1 -#define kTimestampPrintLevel_SEC 0 +#define kTimestampPrintLevel_SEC 0 #define kTimestampPrintLevel_NTFS 7 +#define kTimestampPrintLevel_NS 9 bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw(); bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); +bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, char *s, int level = kTimestampPrintLevel_SEC) throw(); +bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw(); // provide at least 32 bytes for buffer including zero-end // don't send VT_BSTR to these functions diff -Nru 7zip-21.07+dfsg/CPP/Windows/PropVariant.cpp 7zip-22.01/CPP/Windows/PropVariant.cpp --- 7zip-21.07+dfsg/CPP/Windows/PropVariant.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/PropVariant.cpp 2022-03-30 12:00:00.000000000 +0000 @@ -193,7 +193,7 @@ } #define SET_PROP_id_dest(id, dest) \ - if (vt != id) { InternalClear(); vt = id; } dest = value; + if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0; void CPropVariant::Set_Int32(Int32 value) throw() { @@ -217,67 +217,83 @@ // SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart) SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime) +#define CASE_SIMPLE_VT_VALUES \ + case VT_EMPTY: \ + case VT_BOOL: \ + case VT_FILETIME: \ + case VT_UI8: \ + case VT_UI4: \ + case VT_UI2: \ + case VT_UI1: \ + case VT_I8: \ + case VT_I4: \ + case VT_I2: \ + case VT_I1: \ + case VT_UINT: \ + case VT_INT: \ + case VT_NULL: \ + case VT_ERROR: \ + case VT_R4: \ + case VT_R8: \ + case VT_CY: \ + case VT_DATE: \ + + +/* + ::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME) + So we handle VT_FILETIME and another simple types directly + we call system functions for VT_BSTR and for unknown typed +*/ + +CPropVariant::~CPropVariant() +{ + switch ((unsigned)vt) + { + CASE_SIMPLE_VT_VALUES + // vt = VT_EMPTY; // it's optional + return; + } + ::VariantClear((tagVARIANT *)this); +} + HRESULT PropVariant_Clear(PROPVARIANT *prop) throw() { - switch (prop->vt) + switch ((unsigned)prop->vt) { - case VT_EMPTY: - case VT_UI1: - case VT_I1: - case VT_I2: - case VT_UI2: - case VT_BOOL: - case VT_I4: - case VT_UI4: - case VT_R4: - case VT_INT: - case VT_UINT: - case VT_ERROR: - case VT_FILETIME: - case VT_UI8: - case VT_R8: - case VT_CY: - case VT_DATE: + CASE_SIMPLE_VT_VALUES prop->vt = VT_EMPTY; - prop->wReserved1 = 0; - prop->wReserved2 = 0; - prop->wReserved3 = 0; - prop->uhVal.QuadPart = 0; - return S_OK; - } - return ::VariantClear((VARIANTARG *)prop); - // return ::PropVariantClear(prop); - // PropVariantClear can clear VT_BLOB. + break; + default: + { + const HRESULT res = ::VariantClear((VARIANTARG *)prop); + if (res != S_OK || prop->vt != VT_EMPTY) + return res; + break; + } + } + prop->wReserved1 = 0; + prop->wReserved2 = 0; + prop->wReserved3 = 0; + prop->uhVal.QuadPart = 0; + return S_OK; } HRESULT CPropVariant::Clear() throw() { if (vt == VT_EMPTY) + { + wReserved1 = 0; return S_OK; + } return PropVariant_Clear(this); } HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw() { - ::VariantClear((tagVARIANT *)this); - switch (pSrc->vt) + Clear(); + switch ((unsigned)pSrc->vt) { - case VT_UI1: - case VT_I1: - case VT_I2: - case VT_UI2: - case VT_BOOL: - case VT_I4: - case VT_UI4: - case VT_R4: - case VT_INT: - case VT_UINT: - case VT_ERROR: - case VT_FILETIME: - case VT_UI8: - case VT_R8: - case VT_CY: - case VT_DATE: + CASE_SIMPLE_VT_VALUES memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); return S_OK; } @@ -287,12 +303,13 @@ HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() { - HRESULT hr = Clear(); + const HRESULT hr = Clear(); if (FAILED(hr)) return hr; // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); *(PROPVARIANT *)this = *pSrc; pSrc->vt = VT_EMPTY; + pSrc->wReserved1 = 0; return S_OK; } @@ -300,21 +317,25 @@ { if (pDest->vt != VT_EMPTY) { - HRESULT hr = PropVariant_Clear(pDest); + const HRESULT hr = PropVariant_Clear(pDest); if (FAILED(hr)) return hr; } // memcpy(pDest, this, sizeof(PROPVARIANT)); *pDest = *(PROPVARIANT *)this; vt = VT_EMPTY; + wReserved1 = 0; return S_OK; } HRESULT CPropVariant::InternalClear() throw() { if (vt == VT_EMPTY) + { + wReserved1 = 0; return S_OK; - HRESULT hr = Clear(); + } + const HRESULT hr = Clear(); if (FAILED(hr)) { vt = VT_ERROR; @@ -325,7 +346,7 @@ void CPropVariant::InternalCopy(const PROPVARIANT *pSrc) { - HRESULT hr = Copy(pSrc); + const HRESULT hr = Copy(pSrc); if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) @@ -335,11 +356,12 @@ } } + int CPropVariant::Compare(const CPropVariant &a) throw() { if (vt != a.vt) return MyCompare(vt, a.vt); - switch (vt) + switch ((unsigned)vt) { case VT_EMPTY: return 0; // case VT_I1: return MyCompare(cVal, a.cVal); @@ -352,7 +374,15 @@ case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart); case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); case VT_BOOL: return -MyCompare(boolVal, a.boolVal); - case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime); + case VT_FILETIME: + { + const int res = CompareFileTime(&filetime, &a.filetime); + if (res != 0) + return res; + const unsigned v1 = Get_Ns100(); + const unsigned v2 = a.Get_Ns100(); + return MyCompare(v1, v2); + } case VT_BSTR: return 0; // Not implemented default: return 0; } diff -Nru 7zip-21.07+dfsg/CPP/Windows/PropVariant.h 7zip-22.01/CPP/Windows/PropVariant.h --- 7zip-21.07+dfsg/CPP/Windows/PropVariant.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/PropVariant.h 2022-05-15 10:00:00.000000000 +0000 @@ -29,11 +29,14 @@ p->uhVal.QuadPart = v; } -inline void PropVarEm_Set_FileTime64(PROPVARIANT *p, UInt64 v) throw() +inline void PropVarEm_Set_FileTime64_Prec(PROPVARIANT *p, UInt64 v, unsigned prec) throw() { p->vt = VT_FILETIME; p->filetime.dwLowDateTime = (DWORD)v; p->filetime.dwHighDateTime = (DWORD)(v >> 32); + p->wReserved1 = (WORD)prec; + p->wReserved2 = 0; + p->wReserved3 = 0; } inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw() @@ -63,7 +66,51 @@ // uhVal.QuadPart = 0; bstrVal = 0; } - ~CPropVariant() throw() { Clear(); } + + + void Set_FtPrec(unsigned prec) + { + wReserved1 = (WORD)prec; + wReserved2 = 0; + wReserved3 = 0; + } + + void SetAsTimeFrom_FT_Prec(const FILETIME &ft, unsigned prec) + { + operator=(ft); + Set_FtPrec(prec); + } + + void SetAsTimeFrom_Ft64_Prec(UInt64 v, unsigned prec) + { + FILETIME ft; + ft.dwLowDateTime = (DWORD)(UInt32)v; + ft.dwHighDateTime = (DWORD)(UInt32)(v >> 32); + operator=(ft); + Set_FtPrec(prec); + } + + void SetAsTimeFrom_FT_Prec_Ns100(const FILETIME &ft, unsigned prec, unsigned ns100) + { + operator=(ft); + wReserved1 = (WORD)prec; + wReserved2 = (WORD)ns100; + wReserved3 = 0; + } + + unsigned Get_Ns100() const + { + const unsigned prec = wReserved1; + const unsigned ns100 = wReserved2; + if (prec == 0 + && prec <= k_PropVar_TimePrec_1ns + && ns100 < 100 + && wReserved3 == 0) + return ns100; + return 0; + } + + ~CPropVariant(); CPropVariant(const PROPVARIANT &varSrc); CPropVariant(const CPropVariant &varSrc); CPropVariant(BSTR bstrSrc); @@ -118,7 +165,6 @@ HRESULT InternalClear() throw(); void InternalCopy(const PROPVARIANT *pSrc); - int Compare(const CPropVariant &a) throw(); }; diff -Nru 7zip-21.07+dfsg/CPP/Windows/SecurityUtils.cpp 7zip-22.01/CPP/Windows/SecurityUtils.cpp --- 7zip-21.07+dfsg/CPP/Windows/SecurityUtils.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/SecurityUtils.cpp 2022-07-15 08:00:00.000000000 +0000 @@ -2,10 +2,11 @@ #include "StdAfx.h" -#include "../Common/MyString.h" - #include "SecurityUtils.h" +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC + namespace NWindows { namespace NSecurity { @@ -52,8 +53,10 @@ } */ +extern "C" { + #ifndef _UNICODE -typedef BOOL (WINAPI * LookupAccountNameWP)( +typedef BOOL (WINAPI * Func_LookupAccountNameW)( LPCWSTR lpSystemName, LPCWSTR lpAccountName, PSID Sid, @@ -64,13 +67,17 @@ ); #endif +} + static PSID GetSid(LPWSTR accountName) { #ifndef _UNICODE HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll")); if (hModule == NULL) return NULL; - LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW"); + Func_LookupAccountNameW lookupAccountNameW = (Func_LookupAccountNameW) + MY_CAST_FUNC + GetProcAddress(hModule, "LookupAccountNameW"); if (lookupAccountNameW == NULL) return NULL; #endif diff -Nru 7zip-21.07+dfsg/CPP/Windows/SecurityUtils.h 7zip-22.01/CPP/Windows/SecurityUtils.h --- 7zip-21.07+dfsg/CPP/Windows/SecurityUtils.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/SecurityUtils.h 2022-07-15 10:00:00.000000000 +0000 @@ -7,6 +7,31 @@ #include "Defs.h" +#ifndef _UNICODE + +extern "C" { +typedef NTSTATUS (NTAPI *Func_LsaOpenPolicy)(PLSA_UNICODE_STRING SystemName, + PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); +typedef NTSTATUS (NTAPI *Func_LsaClose)(LSA_HANDLE ObjectHandle); +typedef NTSTATUS (NTAPI *Func_LsaAddAccountRights)(LSA_HANDLE PolicyHandle, + PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); +#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) +} + +#define POLICY_FUNC_CALL(fff, str) \ + if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; \ + Func_ ## fff v = (Func_ ## fff) (void(*)()) GetProcAddress(hModule, str); \ + if (!v) return MY_STATUS_NOT_IMPLEMENTED; \ + const NTSTATUS res = v + +#else + +#define POLICY_FUNC_CALL(fff, str) \ + const NTSTATUS res = ::fff + +#endif + + namespace NWindows { namespace NSecurity { @@ -53,15 +78,9 @@ }; -#ifndef _UNICODE -typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName, - PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle); -typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle); -typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle, - PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights ); -#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L) -#endif + + struct CPolicy { protected: @@ -82,43 +101,17 @@ NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes, ACCESS_MASK desiredAccess) { - #ifndef _UNICODE - if (hModule == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy"); - if (lsaOpenPolicy == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - #endif - Close(); - return - #ifdef _UNICODE - ::LsaOpenPolicy - #else - lsaOpenPolicy - #endif + POLICY_FUNC_CALL (LsaOpenPolicy, "LsaOpenPolicy") (systemName, objectAttributes, desiredAccess, &_handle); + return res; } NTSTATUS Close() { if (_handle == NULL) return 0; - - #ifndef _UNICODE - if (hModule == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose"); - if (lsaClose == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - #endif - - NTSTATUS res = - #ifdef _UNICODE - ::LsaClose - #else - lsaClose - #endif + POLICY_FUNC_CALL (LsaClose, "LsaClose") (_handle); _handle = NULL; return res; @@ -137,21 +130,9 @@ NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights) { - #ifndef _UNICODE - if (hModule == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights"); - if (lsaAddAccountRights == NULL) - return MY_STATUS_NOT_IMPLEMENTED; - #endif - - return - #ifdef _UNICODE - ::LsaAddAccountRights - #else - lsaAddAccountRights - #endif + POLICY_FUNC_CALL (LsaAddAccountRights, "LsaAddAccountRights") (_handle, accountSid, userRights, countOfRights); + return res; } NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights) { return AddAccountRights(accountSid, userRights, 1); } diff -Nru 7zip-21.07+dfsg/CPP/Windows/Shell.cpp 7zip-22.01/CPP/Windows/Shell.cpp --- 7zip-21.07+dfsg/CPP/Windows/Shell.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/Shell.cpp 2022-07-15 10:00:00.000000000 +0000 @@ -258,14 +258,21 @@ #ifndef _UNICODE -typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath); +extern "C" { +typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath); +typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi); +} + +#define MY_CAST_FUNC (void(*)()) +// #define MY_CAST_FUNC bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) { path.Empty(); - SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP) + Func_SHGetPathFromIDListW shGetPathFromIDListW = (Func_SHGetPathFromIDListW) + MY_CAST_FUNC ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW"); - if (shGetPathFromIDListW == 0) + if (!shGetPathFromIDListW) return false; const unsigned len = MAX_PATH * 2; bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len))); @@ -273,14 +280,14 @@ return result; } -typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi); static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) { NWindows::NCOM::CComInitializer comInitializer; - SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP) + Func_SHBrowseForFolderW shBrowseForFolderW = (Func_SHBrowseForFolderW) + MY_CAST_FUNC ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW"); - if (shBrowseForFolderW == 0) + if (!shBrowseForFolderW) return false; LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo); if (itemIDList == NULL) diff -Nru 7zip-21.07+dfsg/CPP/Windows/TimeUtils.cpp 7zip-22.01/CPP/Windows/TimeUtils.cpp --- 7zip-21.07+dfsg/CPP/Windows/TimeUtils.cpp 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/TimeUtils.cpp 2022-03-29 10:00:00.000000000 +0000 @@ -22,7 +22,7 @@ (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond; -bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw() +bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw() { #if defined(_WIN32) && !defined(UNDER_CE) return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft)); @@ -43,7 +43,7 @@ static const UInt32 kHighDosTime = 0xFF9FBF7D; static const UInt32 kLowDosTime = 0x210000; -bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw() +bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw() { #if defined(_WIN32) && !defined(UNDER_CE) @@ -121,49 +121,86 @@ return true; } -UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw() + +bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw() +{ + FILETIME loc = { 0, 0 }; + const UInt64 u1 = FILETIME_To_UInt64(utc); + const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec. + if (u1 >= kDelta) + { + if (!FileTimeToLocalFileTime(&utc, &loc)) + loc = utc; + else + { + const UInt64 u2 = FILETIME_To_UInt64(loc); + const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2); + if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time + loc = utc; + } + } + return FileTime_To_DosTime(loc, dosTime); +} + +UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw() { return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond; } -void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw() +void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw() { - UInt64 v = UnixTimeToFileTime64(unixTime); + const UInt64 v = UnixTime_To_FileTime64(unixTime); ft.dwLowDateTime = (DWORD)v; ft.dwHighDateTime = (DWORD)(v >> 32); } -UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw() +UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw() { return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; } -bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw() + +bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw() { if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset)) { - ft.dwLowDateTime = ft.dwHighDateTime = (UInt32)(Int32)-1; + fileTime = (UInt64)(Int64)-1; return false; } - Int64 v = (Int64)kUnixTimeOffset + unixTime; - if (v < 0) + if (unixTime < -(Int64)kUnixTimeOffset) { - ft.dwLowDateTime = ft.dwHighDateTime = 0; + fileTime = 0; return false; } - UInt64 v2 = (UInt64)v * kNumTimeQuantumsInSecond; - ft.dwLowDateTime = (DWORD)v2; - ft.dwHighDateTime = (DWORD)(v2 >> 32); + fileTime = UnixTime64_To_FileTime64(unixTime); return true; } -Int64 FileTimeToUnixTime64(const FILETIME &ft) throw() + +bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw() { - UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + UInt64 v; + const bool res = UnixTime64_To_FileTime64(unixTime, v); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + return res; +} + + +Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw() +{ + const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; +} + +Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw() +{ + const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond); return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset; } -bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime) throw() +bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw() { UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; winTime /= kNumTimeQuantumsInSecond; @@ -173,9 +210,9 @@ return false; } winTime -= kUnixTimeOffset; - if (winTime > 0xFFFFFFFF) + if (winTime > (UInt32)0xFFFFFFFF) { - unixTime = 0xFFFFFFFF; + unixTime = (UInt32)0xFFFFFFFF; return false; } unixTime = (UInt32)winTime; @@ -202,12 +239,13 @@ return true; } -void GetCurUtcFileTime(FILETIME &ft) throw() + +void GetCurUtc_FiTime(CFiTime &ft) throw() { + #ifdef _WIN32 + // Both variants provide same low resolution on WinXP: about 15 ms. // But GetSystemTimeAsFileTime is much faster. - #ifdef _WIN32 - #ifdef UNDER_CE SYSTEMTIME st; GetSystemTime(&st); @@ -216,8 +254,22 @@ GetSystemTimeAsFileTime(&ft); #endif - #else + #else + FiTime_Clear(ft); + struct timeval now; + if (gettimeofday(&now, 0 ) == 0) + { + ft.tv_sec = now.tv_sec; + ft.tv_nsec = now.tv_usec * 1000; + } + + #endif +} + +#ifndef _WIN32 +void GetCurUtcFileTime(FILETIME &ft) throw() +{ UInt64 v = 0; struct timeval now; if (gettimeofday(&now, 0 ) == 0) @@ -227,8 +279,126 @@ } ft.dwLowDateTime = (DWORD)v; ft.dwHighDateTime = (DWORD)(v >> 32); - - #endif } +#endif + }} + + +#ifdef _WIN32 + +/* +void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) +{ + if (prec == k_PropVar_TimePrec_0 + || prec == k_PropVar_TimePrec_HighPrec + || prec >= k_PropVar_TimePrec_100ns) + return; + UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + + int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; + UInt32 d; + if (prec == k_PropVar_TimePrec_DOS) + { + // we round up as windows DosDateTimeToFileTime() + v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1; + d = NWindows::NTime::kNumTimeQuantumsInSecond * 2; + } + else + { + if (prec == k_PropVar_TimePrec_Unix) + numDigits = 0; + else if (numDigits < 0) + return; + d = 1; + for (unsigned k = numDigits; k < 7; k++) + d *= 10; + } + v /= d; + v *= d; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} +*/ + +#else + +/* +void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec) +{ + if (prec >= k_PropVar_TimePrec_1ns + || prec == k_PropVar_TimePrec_HighPrec) + return; + + int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base; + UInt32 d; + if (prec == k_PropVar_TimePrec_Unix || + prec == (int)k_PropVar_TimePrec_Base) + { + ft.tv_nsec = 0; + return; + } + if (prec == k_PropVar_TimePrec_DOS) + { + // we round up as windows DosDateTimeToFileTime() + const unsigned sec1 = (ft.tv_sec & 1); + if (ft.tv_nsec == 0 && sec1 == 0) + return; + ft.tv_nsec = 0; + ft.tv_sec += 2 - sec1; + return; + } + { + if (prec == k_PropVar_TimePrec_0 + || numDigits < 0) + numDigits = 7; + d = 1; + for (unsigned k = numDigits; k < 9; k++) + d *= 10; + ft.tv_nsec /= d; + ft.tv_nsec *= d; + } +} +*/ + +int Compare_FiTime(const CFiTime *a1, const CFiTime *a2) +{ + if (a1->tv_sec < a2->tv_sec) return -1; + if (a1->tv_sec > a2->tv_sec) return 1; + if (a1->tv_nsec < a2->tv_nsec) return -1; + if (a1->tv_nsec > a2->tv_nsec) return 1; + return 0; +} + +bool FILETIME_To_timespec(const FILETIME &ft, timespec &ts) +{ + UInt32 quantums; + const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums); + // time_t is long + const time_t sec2 = (time_t)sec; + if (sec2 == sec) + { + ts.tv_sec = sec2; + ts.tv_nsec = (long)(quantums * 100); + return true; + } + return false; +} + +void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100) +{ + const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); + ns100 = (unsigned)((UInt64)ts.tv_nsec % 100); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft) +{ + const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +#endif diff -Nru 7zip-21.07+dfsg/CPP/Windows/TimeUtils.h 7zip-22.01/CPP/Windows/TimeUtils.h --- 7zip-21.07+dfsg/CPP/Windows/TimeUtils.h 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/CPP/Windows/TimeUtils.h 2022-04-06 09:00:00.000000000 +0000 @@ -5,28 +5,142 @@ #include "../Common/MyTypes.h" #include "../Common/MyWindows.h" +#include "PropVariant.h" + +inline UInt64 FILETIME_To_UInt64(const FILETIME &ft) +{ + return (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime; +} + +inline void FILETIME_Clear(FILETIME &ft) +{ + ft.dwLowDateTime = 0; + ft.dwHighDateTime = 0; +} + +inline bool FILETIME_IsZero(const FILETIME &ft) +{ + return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); +} + + +#ifdef _WIN32 + #define CFiTime FILETIME + #define Compare_FiTime ::CompareFileTime + inline void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft) + { + ft = ts; + } + /* + inline void FILETIME_To_FiTime(const FILETIME &ft, CFiTime &ts) + { + ts = ft; + } + */ + inline void FiTime_Clear(CFiTime &ft) + { + ft.dwLowDateTime = 0; + ft.dwHighDateTime = 0; + } +#else + + #include + + #if defined(_AIX) + #define CFiTime st_timespec + #else + #define CFiTime timespec + #endif + int Compare_FiTime(const CFiTime *a1, const CFiTime *a2); + bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts); + void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft); + void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100); + inline void FiTime_Clear(CFiTime &ft) + { + ft.tv_sec = 0; + ft.tv_nsec = 0; + } + + #ifdef __APPLE__ + #define ST_MTIME(st) st.st_mtimespec + #define ST_ATIME(st) st.st_atimespec + #define ST_CTIME(st) st.st_ctimespec + #else + #define ST_MTIME(st) st.st_mtim + #define ST_ATIME(st) st.st_atim + #define ST_CTIME(st) st.st_ctim + #endif + +#endif + +// void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec); namespace NWindows { namespace NTime { -bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw(); -bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); +bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &fileTime) throw(); +bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw(); +bool FileTime_To_DosTime(const FILETIME &fileTime, UInt32 &dosTime) throw(); // UInt32 Unix Time : for dates 1970-2106 -UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw(); -void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) throw(); +UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw(); +void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &fileTime) throw(); // Int64 Unix Time : negative values for dates before 1970 -UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw(); -bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &fileTime) throw(); - -bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); -Int64 FileTimeToUnixTime64(const FILETIME &ft) throw(); +UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw(); // no check +bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw(); +bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &fileTime) throw(); + +Int64 FileTime64_To_UnixTime64(UInt64 ft64) throw(); +bool FileTime_To_UnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw(); +Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw(); +Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw(); bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw(); + +void GetCurUtc_FiTime(CFiTime &ft) throw(); +#ifdef _WIN32 +#define GetCurUtcFileTime GetCurUtc_FiTime +#else void GetCurUtcFileTime(FILETIME &ft) throw(); +#endif }} +inline void PropVariant_SetFrom_UnixTime(NWindows::NCOM::CPropVariant &prop, UInt32 unixTime) +{ + FILETIME ft; + NWindows::NTime::UnixTime_To_FileTime(unixTime, ft); + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix); +} + +inline void PropVariant_SetFrom_NtfsTime(NWindows::NCOM::CPropVariant &prop, const FILETIME &ft) +{ + prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_100ns); +} + +inline void PropVariant_SetFrom_FiTime(NWindows::NCOM::CPropVariant &prop, const CFiTime &fts) +{ + #ifdef _WIN32 + PropVariant_SetFrom_NtfsTime(prop, fts); + #else + unsigned ns100; + FILETIME ft; + FiTime_To_FILETIME_ns100(fts, ft, ns100); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100); + #endif +} + +inline bool PropVariant_SetFrom_DosTime(NWindows::NCOM::CPropVariant &prop, UInt32 dosTime) +{ + FILETIME localFileTime, utc; + if (!NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime)) + return false; + if (!LocalFileTimeToFileTime(&localFileTime, &utc)) + return false; + prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_DOS); + return true; +} + #endif diff -Nru 7zip-21.07+dfsg/debian/changelog 7zip-22.01/debian/changelog --- 7zip-21.07+dfsg/debian/changelog 2022-02-23 08:53:04.000000000 +0000 +++ 7zip-22.01/debian/changelog 2023-03-06 15:45:55.000000000 +0000 @@ -1,3 +1,85 @@ +7zip (22.01-1~simonarons) jammy; urgency=medium + + * Version with RAR support. + + -- Simon Arons Mon, 06 Mar 2023 15:45:55 +0000 + +7zip (22.01+dfsg-8) unstable; urgency=medium + + * Upgrade Debian standards + + -- YOKOTA Hiroshi Sun, 18 Dec 2022 21:09:42 +0900 + +7zip (22.01+dfsg-7) unstable; urgency=medium + + Reproducible build tester in Sid (unstable) fails to strip some debug infos + like build paths. This makes fail to reproducible build. + + * Rediff patches + * Revert "Enable link time optimization (LTO)" + + -- YOKOTA Hiroshi Fri, 09 Dec 2022 20:26:57 +0900 + +7zip (22.01+dfsg-6) unstable; urgency=medium + + * Remove unwanted hack for object files + + -- YOKOTA Hiroshi Wed, 07 Dec 2022 21:34:51 +0900 + +7zip (22.01+dfsg-5) unstable; urgency=medium + + * Enable link time optimization (LTO) + * Manually de-reference pointers + + -- YOKOTA Hiroshi Sat, 03 Dec 2022 19:40:39 +0900 + +7zip (22.01+dfsg-4) unstable; urgency=medium + + * Revert "Enable link time optimization (LTO)" + * Revert "Manually de-reference pointers" + + -- YOKOTA Hiroshi Sat, 27 Aug 2022 20:28:56 +0900 + +7zip (22.01+dfsg-3) unstable; urgency=medium + + * Enable link time optimization (LTO) + * Manually de-reference pointers + + -- YOKOTA Hiroshi Sat, 27 Aug 2022 15:02:19 +0900 + +7zip (22.01+dfsg-2) unstable; urgency=medium + + * Rebuild with GCC 12 (Closes: #1012886) + + -- YOKOTA Hiroshi Sat, 23 Jul 2022 10:16:24 +0900 + +7zip (22.01+dfsg-1) unstable; urgency=medium + + * New upstream version 22.01+dfsg + * Rediff patches + + -- YOKOTA Hiroshi Sat, 16 Jul 2022 23:15:07 +0900 + +7zip (22.00+dfsg-2) unstable; urgency=medium + + * Initialize uninitialized value + + -- YOKOTA Hiroshi Tue, 21 Jun 2022 15:07:28 +0900 + +7zip (22.00+dfsg-1) unstable; urgency=medium + + * New upstream version 22.00+dfsg + * Rediff patches + + -- YOKOTA Hiroshi Tue, 21 Jun 2022 13:19:35 +0900 + +7zip (21.07+dfsg-5) unstable; urgency=medium + + * Upgrade Debian standards + * ftbfs fix with GCC-12 + + -- YOKOTA Hiroshi Fri, 17 Jun 2022 08:22:16 +0900 + 7zip (21.07+dfsg-4) unstable; urgency=medium * More generalize STDIN handling when in password input diff -Nru 7zip-21.07+dfsg/debian/control 7zip-22.01/debian/control --- 7zip-21.07+dfsg/debian/control 2021-12-28 08:55:14.000000000 +0000 +++ 7zip-22.01/debian/control 2022-12-18 12:04:23.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: YOKOTA Hiroshi Uploaders: Dylan Aïssi Build-Depends: debhelper-compat (= 13) -Standards-Version: 4.6.0 +Standards-Version: 4.6.2 Rules-Requires-Root: no Homepage: https://www.7-zip.org/ Vcs-Git: https://salsa.debian.org/debian/7zip.git diff -Nru 7zip-21.07+dfsg/debian/patches/0001-Accept-Debian-build-flags.patch 7zip-22.01/debian/patches/0001-Accept-Debian-build-flags.patch --- 7zip-21.07+dfsg/debian/patches/0001-Accept-Debian-build-flags.patch 2022-02-23 08:21:34.000000000 +0000 +++ 7zip-22.01/debian/patches/0001-Accept-Debian-build-flags.patch 2022-12-09 11:20:29.000000000 +0000 @@ -8,10 +8,10 @@ 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak -index e065a94..0ce6bbc 100644 +index 2a24e06..090e498 100755 --- a/CPP/7zip/7zip_gcc.mak +++ b/CPP/7zip/7zip_gcc.mak -@@ -77,7 +77,7 @@ endif +@@ -82,7 +82,7 @@ endif else @@ -20,7 +20,7 @@ # -s is not required for clang, do we need it for GGC ??? # -s -@@ -126,7 +126,7 @@ endif +@@ -138,7 +138,7 @@ endif @@ -29,7 +29,7 @@ ifdef IS_MINGW -@@ -154,7 +154,7 @@ CXX_WARN_FLAGS = +@@ -179,7 +179,7 @@ CXX_WARN_FLAGS = #-Wno-invalid-offsetof #-Wno-reorder @@ -38,7 +38,7 @@ STATIC_TARGET= ifdef COMPL_STATIC -@@ -167,7 +167,7 @@ all: $(O) $(PROGPATH) $(STATIC_TARGET) +@@ -192,7 +192,7 @@ all: $(O) $(PROGPATH) $(STATIC_TARGET) $(O): $(MY_MKDIR) $(O) diff -Nru 7zip-21.07+dfsg/debian/patches/0002-Use-GCC-10-warning-options.patch 7zip-22.01/debian/patches/0002-Use-GCC-10-warning-options.patch --- 7zip-21.07+dfsg/debian/patches/0002-Use-GCC-10-warning-options.patch 2022-02-23 08:21:34.000000000 +0000 +++ 7zip-22.01/debian/patches/0002-Use-GCC-10-warning-options.patch 2022-12-09 11:20:29.000000000 +0000 @@ -8,7 +8,7 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPP/7zip/warn_gcc.mak b/CPP/7zip/warn_gcc.mak -index afc0c9d..230d2f0 100644 +index afc0c9d..230d2f0 100755 --- a/CPP/7zip/warn_gcc.mak +++ b/CPP/7zip/warn_gcc.mak @@ -50,7 +50,7 @@ CFLAGS_WARN_GCC_PPMD_UNALIGNED = \ diff -Nru 7zip-21.07+dfsg/debian/patches/0003-Disable-hardware-acceleration-support-on-armel.patch 7zip-22.01/debian/patches/0003-Disable-hardware-acceleration-support-on-armel.patch --- 7zip-21.07+dfsg/debian/patches/0003-Disable-hardware-acceleration-support-on-armel.patch 2022-02-23 08:21:34.000000000 +0000 +++ 7zip-22.01/debian/patches/0003-Disable-hardware-acceleration-support-on-armel.patch 2022-12-09 11:20:29.000000000 +0000 @@ -18,7 +18,7 @@ 7 files changed, 14 insertions(+) diff --git a/C/Aes.c b/C/Aes.c -index 9ad66c5..2af4298 100644 +index 9ad66c5..2af4298 100755 --- a/C/Aes.c +++ b/C/Aes.c @@ -56,6 +56,7 @@ static Byte InvS[256]; @@ -38,7 +38,7 @@ #ifdef USE_HW_AES diff --git a/C/AesOpt.c b/C/AesOpt.c -index 1bdc9a8..60058bc 100644 +index 1bdc9a8..60058bc 100755 --- a/C/AesOpt.c +++ b/C/AesOpt.c @@ -508,6 +508,7 @@ VAES_COMPAT_STUB (AesCtr_Code_HW) @@ -58,7 +58,7 @@ #ifdef USE_HW_AES diff --git a/C/Sha1.c b/C/Sha1.c -index 7adeb44..b6ee739 100644 +index 7adeb44..b6ee739 100755 --- a/C/Sha1.c +++ b/C/Sha1.c @@ -33,6 +33,7 @@ This code is based on public domain code of Steve Reid from Wei Dai's Crypto++ l @@ -78,7 +78,7 @@ void MY_FAST_CALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); diff --git a/C/Sha1Opt.c b/C/Sha1Opt.c -index dcedfbc..574d469 100644 +index dcedfbc..574d469 100755 --- a/C/Sha1Opt.c +++ b/C/Sha1Opt.c @@ -214,6 +214,7 @@ void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t @@ -98,7 +98,7 @@ #ifdef USE_HW_SHA diff --git a/C/Sha256.c b/C/Sha256.c -index c03b75a..e997ad4 100644 +index c03b75a..e997ad4 100755 --- a/C/Sha256.c +++ b/C/Sha256.c @@ -33,6 +33,7 @@ This code is based on public domain code from Wei Dai's Crypto++ library. */ @@ -118,7 +118,7 @@ void MY_FAST_CALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks); diff --git a/C/Sha256Opt.c b/C/Sha256Opt.c -index cc8c53e..b13cf7b 100644 +index cc8c53e..b13cf7b 100755 --- a/C/Sha256Opt.c +++ b/C/Sha256Opt.c @@ -214,6 +214,7 @@ void MY_FAST_CALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size @@ -138,7 +138,7 @@ #ifdef USE_HW_SHA diff --git a/CPP/7zip/Crypto/MyAes.cpp b/CPP/7zip/Crypto/MyAes.cpp -index 7e7cced..0df7b2f 100644 +index 7e7cced..0df7b2f 100755 --- a/CPP/7zip/Crypto/MyAes.cpp +++ b/CPP/7zip/Crypto/MyAes.cpp @@ -86,6 +86,7 @@ STDMETHODIMP CAesCoder::SetInitVector(const Byte *data, UInt32 size) diff -Nru 7zip-21.07+dfsg/debian/patches/0004-Guard-ARM-v8-feature-from-old-architecture.patch 7zip-22.01/debian/patches/0004-Guard-ARM-v8-feature-from-old-architecture.patch --- 7zip-21.07+dfsg/debian/patches/0004-Guard-ARM-v8-feature-from-old-architecture.patch 2022-02-23 08:21:34.000000000 +0000 +++ 7zip-22.01/debian/patches/0004-Guard-ARM-v8-feature-from-old-architecture.patch 2022-12-09 11:20:29.000000000 +0000 @@ -8,7 +8,7 @@ 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/C/7zCrc.c b/C/7zCrc.c -index c7ec353..230d8a5 100644 +index c7ec353..230d8a5 100755 --- a/C/7zCrc.c +++ b/C/7zCrc.c @@ -81,8 +81,9 @@ UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const U diff -Nru 7zip-21.07+dfsg/debian/patches/0005-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch 7zip-22.01/debian/patches/0005-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch --- 7zip-21.07+dfsg/debian/patches/0005-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch 2022-02-23 08:21:34.000000000 +0000 +++ 7zip-22.01/debian/patches/0005-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch 2022-12-09 11:20:29.000000000 +0000 @@ -10,10 +10,10 @@ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp -index c2c748b..30f451e 100644 +index 5e95204..9b5394e 100755 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp -@@ -883,22 +883,11 @@ bool GetCurrentDir(FString &path) +@@ -906,22 +906,11 @@ bool GetCurrentDir(FString &path) { path.Empty(); diff -Nru 7zip-21.07+dfsg/debian/patches/0006-Disable-local-echo-display-when-in-input-passwords-C.patch 7zip-22.01/debian/patches/0006-Disable-local-echo-display-when-in-input-passwords-C.patch --- 7zip-21.07+dfsg/debian/patches/0006-Disable-local-echo-display-when-in-input-passwords-C.patch 2022-02-23 08:30:30.000000000 +0000 +++ 7zip-22.01/debian/patches/0006-Disable-local-echo-display-when-in-input-passwords-C.patch 2022-12-09 11:20:29.000000000 +0000 @@ -9,7 +9,7 @@ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CPP/7zip/UI/Console/UserInputUtils.cpp b/CPP/7zip/UI/Console/UserInputUtils.cpp -index b3ca88e..6f60a78 100644 +index b3ca88e..6f60a78 100755 --- a/CPP/7zip/UI/Console/UserInputUtils.cpp +++ b/CPP/7zip/UI/Console/UserInputUtils.cpp @@ -56,9 +56,18 @@ NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream) @@ -70,7 +70,7 @@ bool res = g_StdIn.ScanUStringUntilNewLine(psw); diff --git a/CPP/Common/StdInStream.h b/CPP/Common/StdInStream.h -index 7f27e92..23c7bf8 100644 +index 7f27e92..23c7bf8 100755 --- a/CPP/Common/StdInStream.h +++ b/CPP/Common/StdInStream.h @@ -23,6 +23,7 @@ public: diff -Nru 7zip-21.07+dfsg/debian/patches/0007-Manually-de-reference-pointers.patch 7zip-22.01/debian/patches/0007-Manually-de-reference-pointers.patch --- 7zip-21.07+dfsg/debian/patches/0007-Manually-de-reference-pointers.patch 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/debian/patches/0007-Manually-de-reference-pointers.patch 2022-12-09 11:20:29.000000000 +0000 @@ -0,0 +1,119 @@ +From: YOKOTA Hiroshi +Date: Sun, 21 Aug 2022 16:50:54 +0900 +Subject: Manually de-reference pointers + +Implicit de-reference breaks link time optimization (LTO). + +Pointer type mismatch breaks LTO because it violates strict-aliasing rules. + +C/Aes.h: + typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks); +C/AesOpt.c: + void MY_FAST_CALL name(__m128i *p, __m128i *data, size_t numBlocks) + void MY_FAST_CALL name(v128 *p, v128 *data, size_t numBlocks) +--- + C/AesOpt.c | 28 ++++++++++++++++++++++++++-- + 1 file changed, 26 insertions(+), 2 deletions(-) + +diff --git a/C/AesOpt.c b/C/AesOpt.c +index 60058bc..1a81546 100755 +--- a/C/AesOpt.c ++++ b/C/AesOpt.c +@@ -61,7 +61,7 @@ + #endif + + #define AES_FUNC_START(name) \ +- void MY_FAST_CALL name(__m128i *p, __m128i *data, size_t numBlocks) ++ void MY_FAST_CALL name(UInt32 *d_p, Byte *d_data, size_t numBlocks) + + #define AES_FUNC_START2(name) \ + AES_FUNC_START (name); \ +@@ -77,6 +77,9 @@ AES_FUNC_START (name) + + AES_FUNC_START2 (AesCbc_Encode_HW) + { ++ __m128i *p = (__m128i *)(void *)d_p; ++ __m128i *data = (__m128i *)(void *)d_data; ++ + __m128i m = *p; + const __m128i k0 = p[2]; + const __m128i k1 = p[3]; +@@ -218,6 +221,9 @@ AES_FUNC_START2 (AesCbc_Encode_HW) + + AES_FUNC_START2 (AesCbc_Decode_HW) + { ++ __m128i *p = (__m128i *)(void *)d_p; ++ __m128i *data = (__m128i *)(void *)d_data; ++ + __m128i iv = *p; + const __m128i *wStart = p + *(const UInt32 *)(p + 1) * 2 + 2 - 1; + const __m128i *dataEnd; +@@ -271,6 +277,9 @@ AES_FUNC_START2 (AesCbc_Decode_HW) + + AES_FUNC_START2 (AesCtr_Code_HW) + { ++ __m128i *p = (__m128i *)(void *)d_p; ++ __m128i *data = (__m128i *)(void *)d_data; ++ + __m128i ctr = *p; + UInt32 numRoundsMinus2 = *(const UInt32 *)(p + 1) * 2 - 1; + const __m128i *dataEnd; +@@ -344,6 +353,9 @@ AES_FUNC_START (name) + + VAES_FUNC_START2 (AesCbc_Decode_HW_256) + { ++ __m128i *p = (__m128i *)(void *)d_p; ++ __m128i *data = (__m128i *)(void *)d_data; ++ + __m128i iv = *p; + const __m128i *dataEnd; + UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; +@@ -415,6 +427,9 @@ AVX2: _mm256_add_epi64 : vpaddq ymm, ymm, ymm + + VAES_FUNC_START2 (AesCtr_Code_HW_256) + { ++ __m128i *p = (__m128i *)(void *)d_p; ++ __m128i *data = (__m128i *)(void *)d_data; ++ + __m128i ctr = *p; + UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1; + const __m128i *dataEnd; +@@ -553,7 +568,7 @@ VAES_COMPAT_STUB (AesCtr_Code_HW) + typedef uint8x16_t v128; + + #define AES_FUNC_START(name) \ +- void MY_FAST_CALL name(v128 *p, v128 *data, size_t numBlocks) ++ void MY_FAST_CALL name(UInt32 *d_p, Byte *d_data, size_t numBlocks) + + #define AES_FUNC_START2(name) \ + AES_FUNC_START (name); \ +@@ -573,6 +588,9 @@ AES_FUNC_START (name) + + AES_FUNC_START2 (AesCbc_Encode_HW) + { ++ v128 *p = (v128 *)(void *)d_p; ++ v128 *data = (v128 *)(void *)d_data; ++ + v128 m = *p; + const v128 k0 = p[2]; + const v128 k1 = p[3]; +@@ -674,6 +692,9 @@ AES_FUNC_START2 (AesCbc_Encode_HW) + + AES_FUNC_START2 (AesCbc_Decode_HW) + { ++ v128 *p = (v128 *)(void *)d_p; ++ v128 *data = (v128 *)(void *)d_data; ++ + v128 iv = *p; + const v128 *wStart = p + ((size_t)*(const UInt32 *)(p + 1)) * 2; + const v128 *dataEnd; +@@ -726,6 +747,9 @@ AES_FUNC_START2 (AesCbc_Decode_HW) + + AES_FUNC_START2 (AesCtr_Code_HW) + { ++ v128 *p = (v128 *)(void *)d_p; ++ v128 *data = (v128 *)(void *)d_data; ++ + uint64x2_t ctr = vreinterpretq_u64_u8(*p); + const v128 *wEnd = p + ((size_t)*(const UInt32 *)(p + 1)) * 2; + const v128 *dataEnd; diff -Nru 7zip-21.07+dfsg/debian/patches/0008-Remove-unwanted-hack-for-object-files.patch 7zip-22.01/debian/patches/0008-Remove-unwanted-hack-for-object-files.patch --- 7zip-21.07+dfsg/debian/patches/0008-Remove-unwanted-hack-for-object-files.patch 1970-01-01 00:00:00.000000000 +0000 +++ 7zip-22.01/debian/patches/0008-Remove-unwanted-hack-for-object-files.patch 2022-12-09 11:20:29.000000000 +0000 @@ -0,0 +1,23 @@ +From: YOKOTA Hiroshi +Date: Wed, 7 Dec 2022 19:26:44 +0900 +Subject: Remove unwanted hack for object files + +"-fPIC" is not needed for a normal executable file. +--- + CPP/7zip/7zip_gcc.mak | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak +index 090e498..525c24e 100755 +--- a/CPP/7zip/7zip_gcc.mak ++++ b/CPP/7zip/7zip_gcc.mak +@@ -25,8 +25,7 @@ endif + CFLAGS_BASE_LIST = -c + # CFLAGS_BASE_LIST = -S + CFLAGS_BASE = -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \ +- -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \ +- -fPIC ++ -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + + # -D_7ZIP_AFFINITY_DISABLE + diff -Nru 7zip-21.07+dfsg/debian/patches/series 7zip-22.01/debian/patches/series --- 7zip-21.07+dfsg/debian/patches/series 2022-02-23 08:21:34.000000000 +0000 +++ 7zip-22.01/debian/patches/series 2022-12-09 11:20:29.000000000 +0000 @@ -4,3 +4,5 @@ 0004-Guard-ARM-v8-feature-from-old-architecture.patch 0005-Use-getcwd-3-POSIX-extension-to-avoid-PATH_MAX-macro.patch 0006-Disable-local-echo-display-when-in-input-passwords-C.patch +0007-Manually-de-reference-pointers.patch +0008-Remove-unwanted-hack-for-object-files.patch diff -Nru 7zip-21.07+dfsg/debian/rules 7zip-22.01/debian/rules --- 7zip-21.07+dfsg/debian/rules 2022-01-22 01:39:00.000000000 +0000 +++ 7zip-22.01/debian/rules 2023-03-06 15:45:55.000000000 +0000 @@ -12,7 +12,6 @@ override_dh_auto_build: $(MAKE) -C CPP/7zip/Bundles/Alone2 -f ../../cmpl_gcc.mak \ CROSS_COMPILE="$(DEB_HOST_GNU_TYPE)-" \ - DISABLE_RAR=1 \ DEB_CFLAGS="$(CFLAGS) -pipe" \ DEB_CXXFLAGS="$(CXXFLAGS) -pipe" \ DEB_CPPFLAGS="$(CPPFLAGS)" \ diff -Nru 7zip-21.07+dfsg/DOC/7zip.wxs 7zip-22.01/DOC/7zip.wxs --- 7zip-21.07+dfsg/DOC/7zip.wxs 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/DOC/7zip.wxs 2022-07-15 17:17:34.000000000 +0000 @@ -1,7 +1,7 @@ - - + + diff -Nru 7zip-21.07+dfsg/DOC/readme.txt 7zip-22.01/DOC/readme.txt --- 7zip-21.07+dfsg/DOC/readme.txt 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/DOC/readme.txt 2022-07-15 17:16:55.000000000 +0000 @@ -1,9 +1,9 @@ -7-Zip 21.07 Sources +7-Zip 22.01 Sources ------------------- 7-Zip is a file archiver for Windows. -7-Zip Copyright (C) 1999-2021 Igor Pavlov. +7-Zip Copyright (C) 1999-2022 Igor Pavlov. License Info diff -Nru 7zip-21.07+dfsg/DOC/src-history.txt 7zip-22.01/DOC/src-history.txt --- 7zip-21.07+dfsg/DOC/src-history.txt 2021-12-28 04:38:06.000000000 +0000 +++ 7zip-22.01/DOC/src-history.txt 2022-06-19 12:53:08.000000000 +0000 @@ -1,6 +1,12 @@ HISTORY of the 7-Zip source code -------------------------------- +22.00 2022-06-16 +------------------------- +- 7-Zip interfaces now support high precision (1 ns) timestamps with reserved + fields of tagPROPVARIANT (VT_FILETIME). + + 21.07 2021-12-26 ------------------------- - The sorting order of files in archives was slightly changed to be more consistent