mirror of
https://github.com/ip7z/7zip.git
synced 2025-12-06 07:12:00 +01:00
22.00
This commit is contained in:
parent
f19f813537
commit
a3e1d22737
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -55,13 +55,19 @@ ifndef x64
|
|||
.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 @@ MY_PROLOG macro
|
|||
movdqa [r4 + 16], xmm9
|
||||
endif
|
||||
else ; x86
|
||||
if (IS_CDECL gt 0)
|
||||
mov rState, [r4 + REG_SIZE * 1]
|
||||
mov rData, [r4 + REG_SIZE * 2]
|
||||
mov rNum, [r4 + REG_SIZE * 3]
|
||||
else ; fastcall
|
||||
mov rNum, [r4 + REG_SIZE * 1]
|
||||
endif
|
||||
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 + PARAM_OFFSET]
|
||||
mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1]
|
||||
mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2]
|
||||
else ; fastcall
|
||||
mov rNum, [r4 + PARAM_OFFSET]
|
||||
endif
|
||||
and r4, -16
|
||||
sub r4, LOCAL_SIZE
|
||||
endif
|
||||
|
|
@ -129,6 +138,7 @@ MY_EPILOG macro
|
|||
else ; x86
|
||||
mov r4, r5
|
||||
pop r5
|
||||
pop r3
|
||||
endif
|
||||
MY_ENDP
|
||||
endm
|
||||
|
|
@ -171,7 +181,7 @@ pre2 equ 2
|
|||
|
||||
|
||||
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 @@ endm
|
|||
MY_PROC Sha256_UpdateBlocks_HW, 3
|
||||
MY_PROLOG
|
||||
|
||||
lea rTable, [K_CONST]
|
||||
|
||||
cmp rNum, 0
|
||||
je end_c
|
||||
|
||||
|
|
|
|||
14
C/7zTypes.h
14
C/7zTypes.h
|
|
@ -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 @@ typedef int WRes;
|
|||
#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 @@ struct ISzAlloc
|
|||
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#define MY_VER_MAJOR 21
|
||||
#define MY_VER_MINOR 07
|
||||
#define MY_VER_MAJOR 22
|
||||
#define MY_VER_MINOR 00
|
||||
#define MY_VER_BUILD 0
|
||||
#define MY_VERSION_NUMBERS "21.07"
|
||||
#define MY_VERSION_NUMBERS "22.00"
|
||||
#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-06-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
|
||||
|
|
|
|||
|
|
@ -382,6 +382,8 @@ $O/VirtThread.o: ../../Common/VirtThread.cpp
|
|||
$(CXX) $(CXXFLAGS) $<
|
||||
|
||||
|
||||
$O/ApfsHandler.o: ../../Archive/ApfsHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/ApmHandler.o: ../../Archive/ApmHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp
|
||||
|
|
@ -390,6 +392,8 @@ $O/ArHandler.o: ../../Archive/ArHandler.cpp
|
|||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/ArjHandler.o: ../../Archive/ArjHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/AvbHandler.o: ../../Archive/AvbHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/Base64Handler.o: ../../Archive/Base64Handler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp
|
||||
|
|
@ -426,6 +430,8 @@ $O/HfsHandler.o: ../../Archive/HfsHandler.cpp
|
|||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/IhexHandler.o: ../../Archive/IhexHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/LpHandler.o: ../../Archive/LpHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/LzhHandler.o: ../../Archive/LzhHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp
|
||||
|
|
@ -448,6 +454,8 @@ $O/QcowHandler.o: ../../Archive/QcowHandler.cpp
|
|||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/RpmHandler.o: ../../Archive/RpmHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/SparseHandler.o: ../../Archive/SparseHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/SplitHandler.o: ../../Archive/SplitHandler.cpp
|
||||
$(CXX) $(CXXFLAGS) $<
|
||||
$O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "7zFolderInStream.h"
|
||||
|
||||
namespace NArchive {
|
||||
|
|
@ -13,16 +15,16 @@ void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
|
|||
_updateCallback = updateCallback;
|
||||
_indexes = indexes;
|
||||
_numFiles = numFiles;
|
||||
_index = 0;
|
||||
|
||||
Processed.ClearAndReserve(numFiles);
|
||||
CRCs.ClearAndReserve(numFiles);
|
||||
Sizes.ClearAndReserve(numFiles);
|
||||
|
||||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_size = 0;
|
||||
if (Need_CTime) CTimes.ClearAndReserve(numFiles);
|
||||
if (Need_ATime) ATimes.ClearAndReserve(numFiles);
|
||||
if (Need_MTime) MTimes.ClearAndReserve(numFiles);
|
||||
if (Need_Attrib) Attribs.ClearAndReserve(numFiles);
|
||||
TimesDefined.ClearAndReserve(numFiles);
|
||||
|
||||
_stream.Release();
|
||||
}
|
||||
|
|
@ -32,44 +34,101 @@ HRESULT CFolderInStream::OpenStream()
|
|||
_pos = 0;
|
||||
_crc = CRC_INIT_VAL;
|
||||
_size_Defined = false;
|
||||
_times_Defined = false;
|
||||
_size = 0;
|
||||
FILETIME_Clear(_cTime);
|
||||
FILETIME_Clear(_aTime);
|
||||
FILETIME_Clear(_mTime);
|
||||
_attrib = 0;
|
||||
|
||||
while (_index < _numFiles)
|
||||
while (Processed.Size() < _numFiles)
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> 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<IStreamGetSize> streamGetSize;
|
||||
stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
|
||||
if (streamGetSize)
|
||||
{
|
||||
if (streamGetSize->GetSize(&_size) == S_OK)
|
||||
_size_Defined = true;
|
||||
CMyComPtr<IStreamGetProps> 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<IStreamGetSize> 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<UInt64> &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 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz
|
|||
}
|
||||
|
||||
_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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,21 +23,37 @@ class CFolderInStream:
|
|||
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<IArchiveUpdateCallback> _updateCallback;
|
||||
|
||||
HRESULT OpenStream();
|
||||
void AddFileInfo(bool isProcessed);
|
||||
HRESULT AddFileInfo(bool isProcessed);
|
||||
|
||||
public:
|
||||
CRecordVector<bool> Processed;
|
||||
CRecordVector<UInt32> CRCs;
|
||||
CRecordVector<UInt64> Sizes;
|
||||
CRecordVector<UInt64> CTimes;
|
||||
CRecordVector<UInt64> ATimes;
|
||||
CRecordVector<UInt64> MTimes;
|
||||
CRecordVector<UInt32> Attribs;
|
||||
CRecordVector<bool> TimesDefined;
|
||||
|
||||
bool Need_CTime;
|
||||
bool Need_ATime;
|
||||
bool Need_MTime;
|
||||
bool Need_Attrib;
|
||||
|
||||
// CMyComPtr<IArchiveUpdateCallbackArcProp> _reportArcProp;
|
||||
|
||||
MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
|
@ -45,7 +61,7 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
size += Sizes[i];
|
||||
return size;
|
||||
}
|
||||
|
||||
CFolderInStream():
|
||||
Need_CTime(false),
|
||||
Need_ATime(false),
|
||||
Need_MTime(false),
|
||||
Need_Attrib(false)
|
||||
{}
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVe
|
|||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -49,9 +49,8 @@ public:
|
|||
bool _encryptHeaders;
|
||||
// bool _useParents; 9.26
|
||||
|
||||
CBoolPair Write_CTime;
|
||||
CBoolPair Write_ATime;
|
||||
CBoolPair Write_MTime;
|
||||
CHandlerTimeOptions TimeOptions;
|
||||
|
||||
CBoolPair Write_Attrib;
|
||||
|
||||
bool _useMultiThreadMixer;
|
||||
|
|
|
|||
|
|
@ -384,16 +384,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
|
||||
CObjectVector<CUpdateItem> 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 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
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 @@ void COutHandler::InitProps7z()
|
|||
_encryptHeaders = false;
|
||||
// _useParents = false;
|
||||
|
||||
Write_CTime.Init();
|
||||
Write_ATime.Init();
|
||||
Write_MTime.Init();
|
||||
TimeOptions.Init();
|
||||
Write_Attrib.Init();
|
||||
|
||||
_useMultiThreadMixer = true;
|
||||
|
|
@ -954,9 +957,19 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,13 @@ REGISTER_ARC_IO_DECREMENT_SIG(
|
|||
"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);
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -804,10 +804,20 @@ struct CAnalysis
|
|||
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 CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMo
|
|||
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<IStreamGetProps> 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 @@ HRESULT Update(
|
|||
CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;
|
||||
updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);
|
||||
|
||||
/*
|
||||
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
|
||||
*/
|
||||
|
||||
// size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
|
||||
|
||||
/*
|
||||
|
|
@ -1756,6 +1783,7 @@ HRESULT Update(
|
|||
|
||||
{
|
||||
CAnalysis analysis;
|
||||
// analysis.Need_ATime = options.Need_ATime;
|
||||
if (options.AnalysisLevel == 0)
|
||||
{
|
||||
analysis.ParseWav = false;
|
||||
|
|
@ -1790,7 +1818,15 @@ HRESULT Update(
|
|||
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 @@ HRESULT Update(
|
|||
|
||||
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<ISequentialInStream> 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 @@ HRESULT Update(
|
|||
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,6 +2462,8 @@ HRESULT Update(
|
|||
|
||||
CNum numUnpackStreams = 0;
|
||||
UInt64 skippedSize = 0;
|
||||
UInt64 procSize = 0;
|
||||
// unsigned numProcessedFiles = 0;
|
||||
|
||||
for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)
|
||||
{
|
||||
|
|
@ -2429,14 +2490,16 @@ HRESULT Update(
|
|||
*/
|
||||
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 @@ HRESULT Update(
|
|||
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 @@ HRESULT Update(
|
|||
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 @@ HRESULT Update(
|
|||
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));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ struct CUpdateItem
|
|||
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 @@ struct CUpdateItem
|
|||
CTimeDefined(false),
|
||||
ATimeDefined(false),
|
||||
MTimeDefined(false)
|
||||
// , ATime_WasReadByAnalysis(false)
|
||||
// SecureIndex(0)
|
||||
{}
|
||||
void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }
|
||||
|
|
@ -103,6 +106,11 @@ struct CUpdateOptions
|
|||
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 @@ struct CUpdateOptions
|
|||
SolidExtension(false),
|
||||
UseTypeSorting(true),
|
||||
RemoveSfxBlock(false),
|
||||
MultiThreadMixer(true)
|
||||
MultiThreadMixer(true),
|
||||
Need_CTime(false),
|
||||
Need_ATime(false),
|
||||
Need_MTime(false),
|
||||
Need_Attrib(false)
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
3546
CPP/7zip/Archive/ApfsHandler.cpp
Normal file
3546
CPP/7zip/Archive/ApfsHandler.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -322,8 +322,8 @@ static const Byte kProps[] =
|
|||
kpidSize,
|
||||
kpidMTime,
|
||||
kpidPosixAttrib,
|
||||
kpidUser,
|
||||
kpidGroup
|
||||
kpidUserId,
|
||||
kpidGroupId
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
|
|
@ -734,15 +734,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value
|
|||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -682,15 +682,7 @@ static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
|
|||
{
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -305,29 +305,91 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
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<ISequentialInStream> fileInStream;
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
CLocalProgress *localProgressSpec = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
|
||||
localProgressSpec->Init(updateCallback, true);
|
||||
NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
|
||||
CMyComPtr<ICompressCoder> encoder = encoderSpec;
|
||||
RINOK(props.SetCoderProps(encoderSpec, NULL));
|
||||
RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress));
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
if (!fileInStream)
|
||||
return S_FALSE;
|
||||
{
|
||||
CMyComPtr<IStreamGetSize> 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<ICompressProgressInfo> localProgress = localProgressSpec;
|
||||
localProgressSpec->Init(updateCallback, true);
|
||||
{
|
||||
NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
|
||||
CMyComPtr<ICompressCoder> 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 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
|
||||
|
||||
/*
|
||||
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
|
||||
*/
|
||||
|
||||
if (IntToBool(newProps))
|
||||
{
|
||||
{
|
||||
|
|
@ -396,6 +463,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
|
||||
return NCompress::CopyStream(_stream, outStream, progress);
|
||||
|
||||
// return ReportArcProps(reportArcProp, NULL, NULL);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
|
@ -410,7 +479,8 @@ REGISTER_ARC_IO(
|
|||
"bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
|
||||
k_Signature,
|
||||
0,
|
||||
NArcInfoFlags::kKeepName,
|
||||
IsArc_BZip2)
|
||||
NArcInfoFlags::kKeepName
|
||||
, 0
|
||||
, IsArc_BZip2)
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -295,15 +295,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,11 @@ struct CResetTable
|
|||
// unsigned BlockSizeBits;
|
||||
CRecordVector<UInt64> ResetOffsets;
|
||||
|
||||
CResetTable():
|
||||
UncompressedSize(0),
|
||||
CompressedSize(0)
|
||||
{}
|
||||
|
||||
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
|
||||
{
|
||||
if (blockIndex >= ResetOffsets.Size())
|
||||
|
|
@ -118,6 +123,12 @@ struct CLzxInfo
|
|||
|
||||
CResetTable ResetTable;
|
||||
|
||||
CLzxInfo():
|
||||
Version(0),
|
||||
ResetIntervalBits(0),
|
||||
CacheSize(0)
|
||||
{}
|
||||
|
||||
unsigned GetNumDictBits() const
|
||||
{
|
||||
if (Version == 2 || Version == 3)
|
||||
|
|
|
|||
|
|
@ -240,34 +240,42 @@ void CSingleMethodProps::Init()
|
|||
}
|
||||
|
||||
|
||||
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 @@ HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PR
|
|||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class CCommonMethodProps
|
|||
protected:
|
||||
void InitCommon()
|
||||
{
|
||||
// _Write_MTime = true;
|
||||
#ifndef _7ZIP_ST
|
||||
_numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
|
||||
_numThreads_WasForced = false;
|
||||
|
|
@ -118,11 +119,36 @@ public:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -79,6 +79,29 @@ void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool
|
|||
}
|
||||
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ UString GetOsPath(const UString &name);
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -652,11 +652,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -125,6 +125,24 @@ STDAPI SetCaseSensitive(Int32 caseSensitive)
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -343,6 +343,8 @@ struct CHeader
|
|||
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 @@ struct CNode
|
|||
CExtTime MTime;
|
||||
CExtTime ATime;
|
||||
CExtTime CTime;
|
||||
// CExtTime InodeChangeTime;
|
||||
CExtTime ChangeTime;
|
||||
// CExtTime DTime;
|
||||
|
||||
UInt64 NumBlocks;
|
||||
|
|
@ -674,14 +676,14 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
|
|||
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 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
|
|||
{
|
||||
// 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 @@ HRESULT CHandler::Open2(IInStream *inStream)
|
|||
}
|
||||
|
||||
_isArc = true;
|
||||
_phySize = _h.NumBlocks << _h.BlockBits;
|
||||
_phySize = _h.GetPhySize();
|
||||
|
||||
if (_openCallback)
|
||||
{
|
||||
|
|
@ -1744,8 +1746,8 @@ static const UInt32 kProps[] =
|
|||
kpidLinks,
|
||||
kpidSymLink,
|
||||
kpidCharacts,
|
||||
kpidUser,
|
||||
kpidGroup
|
||||
kpidUserId,
|
||||
kpidGroupId
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -1792,11 +1794,7 @@ static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVa
|
|||
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 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
|
|||
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 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
|
|||
// NTime::UnixTimeToFileTime(t.Val, ft); // for
|
||||
}
|
||||
*/
|
||||
prop = ft;
|
||||
prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2103,10 +2105,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
|||
}
|
||||
|
||||
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -111,14 +111,14 @@ static int GetLog(UInt32 num)
|
|||
|
||||
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 @@ static const CStatProp kArcProps[] =
|
|||
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 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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 @@ struct CPartition
|
|||
UInt64 FirstLba;
|
||||
UInt64 LastLba;
|
||||
UInt64 Flags;
|
||||
const char *Ext; // detected later
|
||||
Byte Name[kNameLen * 2];
|
||||
|
||||
bool IsUnused() const
|
||||
|
|
@ -73,6 +79,7 @@ struct CPartition
|
|||
LastLba = Get64(p + 40);
|
||||
Flags = Get64(p + 48);
|
||||
memcpy(Name, p + 56, kNameLen * 2);
|
||||
Ext = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -252,6 +259,28 @@ HRESULT CHandler::Open2(IInStream *stream)
|
|||
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 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
|
|||
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<ISequentialInStream> 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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
}
|
||||
{
|
||||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -475,6 +475,7 @@ class CHandler:
|
|||
NDecoder::CCOMCoder *_decoderSpec;
|
||||
|
||||
CSingleMethodProps _props;
|
||||
CHandlerTimeOptions _timeOptions;
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP4(
|
||||
|
|
@ -487,8 +488,15 @@ public:
|
|||
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 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
|
|||
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 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
|
|||
try
|
||||
{
|
||||
Close();
|
||||
CreateDecoder();
|
||||
_decoderSpec->SetInStream(stream);
|
||||
_decoderSpec->InitInStream(true);
|
||||
RINOK(_item.ReadHeader(_decoderSpec));
|
||||
|
|
@ -672,7 +682,8 @@ STDMETHODIMP CHandler::Close()
|
|||
_headerSize = 0;
|
||||
|
||||
_stream.Release();
|
||||
_decoderSpec->ReleaseInStream();
|
||||
if (_decoder)
|
||||
_decoderSpec->ReleaseInStream();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -699,6 +710,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
|
||||
extractCallback->PrepareOperation(askMode);
|
||||
|
||||
CreateDecoder();
|
||||
|
||||
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
|
||||
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
|
||||
outStreamSpec->SetStream(realOutStream);
|
||||
|
|
@ -873,21 +886,99 @@ static const Byte kHostOS =
|
|||
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<ISequentialInStream> fileInStream;
|
||||
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
|
||||
if (!fileInStream)
|
||||
return S_FALSE;
|
||||
|
||||
{
|
||||
CMyComPtr<IStreamGetProps> 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<ISequentialInStream> crcStream(inStreamSpec);
|
||||
inStreamSpec->SetStream(fileInStream);
|
||||
|
|
@ -911,14 +1002,50 @@ static HRESULT UpdateArchive(
|
|||
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 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
return E_FAIL;
|
||||
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
|
||||
|
||||
/*
|
||||
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
|
||||
*/
|
||||
|
||||
CItem newItem;
|
||||
|
||||
if (!IntToBool(newProps))
|
||||
|
|
@ -945,11 +1077,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
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 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
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 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
}
|
||||
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::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
|
||||
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)
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -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 @@ STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosit
|
|||
}
|
||||
|
||||
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 @@ static const char *GetImgExt(ISequentialInStream *stream)
|
|||
return "gpt";
|
||||
return "mbr";
|
||||
}
|
||||
if (NExt::IsArc_Ext(buf, kHeaderSize) == k_IsArc_Res_YES)
|
||||
return "ext";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -208,6 +215,33 @@ STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
class CHandlerImgProgress:
|
||||
public ICompressProgressInfo,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CHandlerImg &Handler;
|
||||
CMyComPtr<ICompressProgressInfo> _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 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
return S_OK;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
int opRes = NExtract::NOperationResult::kDataError;
|
||||
|
||||
ClearStreamVars();
|
||||
|
|
@ -242,6 +272,19 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
|
||||
if (hres == S_OK && inStream)
|
||||
{
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(extractCallback, false);
|
||||
|
||||
if (Init_PackSizeProcessed())
|
||||
{
|
||||
CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this);
|
||||
CMyComPtr<ICompressProgressInfo> imgProgress = imgProgressSpec;
|
||||
imgProgressSpec->_ratioProgress = progress;
|
||||
progress.Release();
|
||||
progress = imgProgress;
|
||||
}
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,19 @@ protected:
|
|||
|
||||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ struct CItem
|
|||
UInt32 ID;
|
||||
UInt32 CTime;
|
||||
UInt32 MTime;
|
||||
// UInt32 AttrMTime;
|
||||
UInt32 AttrMTime;
|
||||
UInt32 ATime;
|
||||
// UInt32 BackupDate;
|
||||
|
||||
|
|
@ -1000,7 +1000,7 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
|
|||
|
||||
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);
|
||||
|
||||
|
|
@ -1404,6 +1404,7 @@ static const Byte kProps[] =
|
|||
kpidCTime,
|
||||
kpidMTime,
|
||||
kpidATime,
|
||||
kpidChangeTime,
|
||||
kpidPosixAttrib
|
||||
};
|
||||
|
||||
|
|
@ -1421,9 +1422,11 @@ IMP_IInArchive_ArcProps
|
|||
|
||||
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)
|
||||
|
|
@ -1447,10 +1450,13 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
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;
|
||||
|
|
@ -1578,6 +1584,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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.AttrIndex < 0) prop = (UInt32)item.FileMode; break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,11 @@ namespace NFileTimeType
|
|||
{
|
||||
enum EEnum
|
||||
{
|
||||
kWindows,
|
||||
kNotDefined = -1,
|
||||
kWindows = 0,
|
||||
kUnix,
|
||||
kDOS
|
||||
kDOS,
|
||||
k1ns
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -60,8 +62,31 @@ namespace NArcInfoFlags
|
|||
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 @@ namespace NArchive
|
|||
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 @@ namespace NArchive
|
|||
kInArcIndex,
|
||||
kBlockIndex,
|
||||
kOutArcIndex
|
||||
// kArcProp
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +159,8 @@ namespace NArchive
|
|||
enum
|
||||
{
|
||||
kOK = 0
|
||||
// , kError
|
||||
// kError = 1,
|
||||
// kError_FileChanged
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -461,9 +488,10 @@ namespace NUpdateNotifyOp
|
|||
kSkip,
|
||||
kDelete,
|
||||
kHeader,
|
||||
kHashRead
|
||||
|
||||
// kNumDefined
|
||||
kHashRead,
|
||||
kInFileChanged
|
||||
// , kOpFinished
|
||||
// , kNumDefined
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -492,6 +520,20 @@ ARCHIVE_INTERFACE(IArchiveGetDiskProperty, 0x84)
|
|||
INTERFACE_IArchiveGetDiskProperty(PURE);
|
||||
};
|
||||
|
||||
/*
|
||||
#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 @@ extern "C"
|
|||
|
||||
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
|
||||
|
|
|
|||
BIN
CPP/7zip/Archive/Icons/apfs.ico
Normal file
BIN
CPP/7zip/Archive/Icons/apfs.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -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 @@ static const Byte kProps[] =
|
|||
// kpidCTime,
|
||||
// kpidATime,
|
||||
kpidPosixAttrib,
|
||||
// kpidUser,
|
||||
// kpidGroup,
|
||||
// kpidUserId,
|
||||
// kpidGroupId,
|
||||
// kpidLinks,
|
||||
kpidSymLink
|
||||
};
|
||||
|
|
@ -127,8 +124,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
case kpidPosixAttrib:
|
||||
/*
|
||||
case kpidLinks:
|
||||
case kpidUser:
|
||||
case kpidGroup:
|
||||
case kpidUserId:
|
||||
case kpidGroupId:
|
||||
*/
|
||||
{
|
||||
if (_archive.IsSusp)
|
||||
|
|
@ -254,8 +251,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
// case kpidCTime:
|
||||
// case kpidATime:
|
||||
{
|
||||
FILETIME utc;
|
||||
if (/* propID == kpidMTime && */ item.DateTime.GetFileTime(utc))
|
||||
prop = utc;
|
||||
// if
|
||||
item.DateTime.GetFileTime(prop);
|
||||
/*
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -587,6 +587,8 @@ HRESULT CInArchive::Open2()
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -127,17 +127,18 @@ struct CDateTime
|
|||
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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,17 +25,16 @@ struct CRecordingDateTime
|
|||
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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
1173
CPP/7zip/Archive/LpHandler.cpp
Normal file
1173
CPP/7zip/Archive/LpHandler.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -487,22 +487,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ struct CSiAttr
|
|||
{
|
||||
UInt64 CTime;
|
||||
UInt64 MTime;
|
||||
// UInt64 ThisRecMTime;
|
||||
UInt64 ThisRecMTime;
|
||||
UInt64 ATime;
|
||||
UInt32 Attrib;
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ bool CSiAttr::Parse(const Byte *p, unsigned size)
|
|||
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 @@ static const Byte kProps[] =
|
|||
kpidMTime,
|
||||
kpidCTime,
|
||||
kpidATime,
|
||||
kpidChangeTime,
|
||||
kpidAttrib,
|
||||
kpidLinks,
|
||||
kpidINode,
|
||||
|
|
@ -2577,7 +2578,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -885,11 +885,7 @@ IMP_IInArchive_ArcProps_WITH_NAME
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
|
|||
{
|
||||
// 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1591,14 +1591,14 @@ STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data
|
|||
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 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
|
|||
|
||||
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)
|
||||
|
|
@ -1621,19 +1621,27 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
|
|||
|
||||
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 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item)
|
|||
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 @@ bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
|
|||
|
||||
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 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
ext.IsEqualTo_Ascii_NoCase("r01"))
|
||||
{
|
||||
_changed = ext;
|
||||
_before = name.Left(dotPos + 1);
|
||||
_before.SetFrom(name.Ptr(), dotPos + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -60,16 +60,23 @@ public:
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -215,11 +215,7 @@ class CHandler: public CHandlerCont
|
|||
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
|
||||
|
|
|
|||
548
CPP/7zip/Archive/SparseHandler.cpp
Normal file
548
CPP/7zip/Archive/SparseHandler.cpp
Normal file
|
|
@ -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<CChunk> 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<ISequentialInStream> 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)
|
||||
|
||||
}}
|
||||
|
|
@ -162,7 +162,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
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 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
break;
|
||||
numLetters++;
|
||||
}
|
||||
if (numLetters != ext.Len())
|
||||
if (numLetters != ext2.Len())
|
||||
return S_FALSE;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ static const char * const k_Methods[] =
|
|||
, "XZ"
|
||||
};
|
||||
|
||||
static const UInt32 kMetadataBlockSizeLog = 13;
|
||||
static const unsigned kMetadataBlockSizeLog = 13;
|
||||
static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
|
||||
|
||||
enum
|
||||
|
|
@ -408,7 +408,7 @@ UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
|
|||
|
||||
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::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
|
|||
|
||||
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 @@ class CHandler:
|
|||
CData _inodesData;
|
||||
CData _dirs;
|
||||
CRecordVector<CFrag> _frags;
|
||||
// CByteBuffer _uids;
|
||||
// CByteBuffer _gids;
|
||||
CByteBuffer _uids;
|
||||
CByteBuffer _gids;
|
||||
CHeader _h;
|
||||
bool _noPropsLZMA;
|
||||
bool _needCheckLzma;
|
||||
|
|
@ -891,14 +891,20 @@ class CHandler:
|
|||
_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 @@ static const Byte kProps[] =
|
|||
kpidSize,
|
||||
kpidPackSize,
|
||||
kpidMTime,
|
||||
kpidPosixAttrib
|
||||
// kpidUser,
|
||||
// kpidGroup,
|
||||
kpidPosixAttrib,
|
||||
kpidUserId,
|
||||
kpidGroupId
|
||||
// kpidLinks,
|
||||
// kpidOffset
|
||||
};
|
||||
|
|
@ -1280,14 +1286,14 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool
|
|||
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 @@ HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
|
|||
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 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
|
|||
CRecordVector<CTempItem> 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 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
|
|||
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 @@ HRESULT CHandler::Open2(IInStream *inStream)
|
|||
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 @@ HRESULT CHandler::Open2(IInStream *inStream)
|
|||
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 @@ HRESULT CHandler::Open2(IInStream *inStream)
|
|||
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 @@ HRESULT CHandler::Open2(IInStream *inStream)
|
|||
}
|
||||
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 @@ AString CHandler::GetPath(int index) const
|
|||
{
|
||||
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 @@ bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets)
|
|||
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 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
|
|||
packBlockSize != _cachedPackBlockSize)
|
||||
{
|
||||
ClearCache();
|
||||
RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL));
|
||||
RINOK(Seek2(blockOffset));
|
||||
_limitedInStreamSpec->Init(packBlockSize);
|
||||
|
||||
if (compressed)
|
||||
|
|
|
|||
|
|
@ -36,22 +36,34 @@ static const Byte kProps[] =
|
|||
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 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
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 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
|
||||
case kpidWarningFlags:
|
||||
{
|
||||
if (_warning)
|
||||
if (_arc._is_Warning)
|
||||
prop = kpv_ErrorFlags_HeadersError;
|
||||
break;
|
||||
}
|
||||
|
|
@ -107,7 +119,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
case kpidComment:
|
||||
{
|
||||
if (_arc.PaxGlobal_Defined)
|
||||
{
|
||||
AString s;
|
||||
_arc.PaxGlobal.Print_To_String(s);
|
||||
if (!s.IsEmpty())
|
||||
prop = s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -115,32 +154,6 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *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;
|
||||
}
|
||||
_phySize += item.HeaderSize;
|
||||
_headersSize += item.HeaderSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CEncodingCharacts::Check(const AString &s)
|
||||
{
|
||||
|
|
@ -199,16 +212,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
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 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
|
||||
_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 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
break;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (callback)
|
||||
{
|
||||
if (_items.Size() == 1)
|
||||
|
|
@ -249,10 +267,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
}
|
||||
if ((_items.Size() & 0x3FF) == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
const UInt64 numFiles = _items.Size();
|
||||
RINOK(callback->SetCompleted(&numFiles, &_phySize));
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -266,7 +285,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
|
||||
if (_items.Size() == 0)
|
||||
{
|
||||
if (_error != k_ErrorType_OK)
|
||||
if (_arc._error != k_ErrorType_OK)
|
||||
{
|
||||
_isArc = false;
|
||||
return S_FALSE;
|
||||
|
|
@ -294,6 +313,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
|||
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::OpenSeq(ISequentialInStream *stream)
|
|||
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 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
|||
{
|
||||
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 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
|||
}
|
||||
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 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
{
|
||||
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)
|
||||
{
|
||||
FILETIME ft;
|
||||
if (NTime::UnixTime64ToFileTime(item->MTime, ft))
|
||||
prop = ft;
|
||||
}
|
||||
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 kpidCharacts:
|
||||
{
|
||||
AString s = item->EncodingCharacts.GetCharactsString();
|
||||
if (item->IsThereWarning())
|
||||
/*
|
||||
// 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)
|
||||
{
|
||||
s.Add_Space_if_NotEmpty();
|
||||
s += "HEADER_ERROR";
|
||||
// we allow (item->MTime == 0)
|
||||
FILETIME 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);
|
||||
}
|
||||
}
|
||||
prop = s;
|
||||
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:
|
||||
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;
|
||||
{
|
||||
s.Add_Space_if_NotEmpty();
|
||||
AddSpecCharToString(item->LinkFlag, 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 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
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 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
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 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
|
||||
Int32 opRes = NExtract::NOperationResult::kOK;
|
||||
CMyComPtr<ISequentialInStream> inStream2;
|
||||
if (!item->IsSparse())
|
||||
if (!item->Is_Sparse())
|
||||
inStream2 = inStream;
|
||||
else
|
||||
{
|
||||
|
|
@ -549,7 +768,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
}
|
||||
|
||||
{
|
||||
if (item->IsSymLink())
|
||||
if (item->Is_SymLink())
|
||||
{
|
||||
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
|
||||
}
|
||||
|
|
@ -557,9 +776,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
{
|
||||
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 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
|||
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 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
|||
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 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
|||
|
||||
const CItemEx &item = _items[index];
|
||||
|
||||
if (item.IsSparse())
|
||||
if (item.Is_Sparse())
|
||||
{
|
||||
CSparseStream *streamSpec = new CSparseStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
|
|
@ -718,24 +937,30 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
|||
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 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
#include "../Common/HandlerOut.h"
|
||||
|
||||
#include "TarIn.h"
|
||||
|
||||
|
|
@ -29,31 +29,26 @@ public:
|
|||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _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<ICompressCoder> 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;
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@
|
|||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#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 @@ namespace NTar {
|
|||
|
||||
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 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro
|
|||
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 int CompareUpdateItems(void *const *p1, void *const *p2, void *)
|
|||
}
|
||||
|
||||
|
||||
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<CUpdateItem> updateItems;
|
||||
const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
|
||||
|
|
@ -131,25 +244,30 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
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 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
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);
|
||||
}
|
||||
|
||||
return UpdateArchive(_stream, outStream, _items, updateItems, codePage, utfFlags, callback);
|
||||
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;
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,82 @@ namespace NFileHeader {
|
|||
// 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); }
|
||||
*/
|
||||
|
||||
}}}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ namespace NFileHeader
|
|||
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 @@ namespace NFileHeader
|
|||
- '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 @@ namespace NFileHeader
|
|||
// 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];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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 @@ enum EErrorType
|
|||
{
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 @@ struct CSparseBlock
|
|||
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<CSparseBlock> 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;
|
||||
|
|
@ -73,6 +170,17 @@ struct CItem
|
|||
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
|
||||
{
|
||||
switch (LinkFlag)
|
||||
|
|
@ -82,10 +190,10 @@ struct CItem
|
|||
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 @@ struct CItem
|
|||
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 (int i = 0; i < 5; i++)
|
||||
if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i])
|
||||
for (unsigned i = 0; i < 5; i++)
|
||||
if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
|
||||
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 (unsigned i = 0; i < 8; i++)
|
||||
if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
|
||||
|
||||
bool IsThereWarning() const
|
||||
{
|
||||
|
|
@ -163,18 +292,67 @@ struct CEncodingCharacts
|
|||
};
|
||||
|
||||
|
||||
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(); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
static bool WriteOctal_8(char *s, UInt32 val)
|
||||
// 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 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 @@ static void CopyString(char *dest, const AString &src, unsigned maxSize)
|
|||
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);
|
||||
cur += 8;
|
||||
if (item.DeviceMinorDefined)
|
||||
WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor);
|
||||
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.IsSparse())
|
||||
if (item.DeviceMinor_Defined)
|
||||
WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor)
|
||||
else if (needDevice)
|
||||
WRITE_OCTAL_8_CHECK (cur, 0)
|
||||
cur += 8;
|
||||
|
||||
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 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
|||
}
|
||||
|
||||
{
|
||||
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 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
|||
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 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
|||
}
|
||||
|
||||
|
||||
/* 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();
|
||||
*/
|
||||
unsigned namePos = 0;
|
||||
bool needPathCut = false;
|
||||
bool allowPrefix = false;
|
||||
|
||||
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++)
|
||||
if (!DOES_NAME_FIT_IN_FIELD(item.Name))
|
||||
{
|
||||
const AString *name;
|
||||
// We suppose that GNU TAR also writes item for long link before item for LongName?
|
||||
if (i == 0)
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
|
||||
name = &item.LinkName;
|
||||
}
|
||||
else
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::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;
|
||||
RINOK(WriteHeaderReal(mi));
|
||||
RINOK(WriteBytes(name->Ptr(), nameStreamSize));
|
||||
RINOK(FillDataResidual(nameStreamSize));
|
||||
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++)
|
||||
{
|
||||
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
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
|
||||
if (lastRecordSize == 0)
|
||||
return S_OK;
|
||||
unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
|
||||
Byte buf[NFileHeader::kRecordSize];
|
||||
memset(buf, 0, rem);
|
||||
return WriteBytes(buf, rem);
|
||||
Pos += size;
|
||||
return WriteStream(Stream, data, size);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize)
|
||||
{
|
||||
const unsigned v = ((unsigned)dataSize & (kRecordSize - 1));
|
||||
if (v == 0)
|
||||
return S_OK;
|
||||
const unsigned rem = kRecordSize - v;
|
||||
Byte buf[kRecordSize];
|
||||
memset(buf, 0, 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,21 +14,38 @@ namespace NTar {
|
|||
|
||||
class COutArchive
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> m_Stream;
|
||||
CMyComPtr<ISequentialOutStream> 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)
|
||||
{}
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,17 @@ REGISTER_ARC_IO(
|
|||
"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)
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#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<NArchive::NTar::CItemEx> &inputItems,
|
||||
const CObjectVector<CUpdateItem> &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<IOutStream> 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<IArchiveUpdateCallbackFile> opCallback;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
|
||||
|
|
@ -40,7 +185,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
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 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
|
||||
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 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
}
|
||||
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 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
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 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
}
|
||||
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 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
{
|
||||
RINOK(res);
|
||||
|
||||
if (fileInStream)
|
||||
{
|
||||
CMyComPtr<IStreamGetProps> getProps;
|
||||
fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
|
||||
if (getProps)
|
||||
{
|
||||
FILETIME mTime;
|
||||
UInt64 size2;
|
||||
if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
|
||||
{
|
||||
item.PackSize = size2;
|
||||
item.Size = size2;
|
||||
item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!fileInStream)
|
||||
{
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CMyComPtr<IStreamGetProps> getProps;
|
||||
CMyComPtr<IStreamGetProp> 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
|
||||
{
|
||||
fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
|
||||
if (getProps)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// 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 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
}
|
||||
}
|
||||
|
||||
// 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<IInStream> 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 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
|||
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();
|
||||
}
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -15,27 +15,60 @@ struct CUpdateItem
|
|||
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<CItemEx> &inputItems,
|
||||
const CObjectVector<CUpdateItem> &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
|
||||
|
|
|
|||
|
|
@ -27,11 +27,17 @@ static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop
|
|||
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,7 +47,8 @@ static const Byte kProps[] =
|
|||
kpidSize,
|
||||
kpidPackSize,
|
||||
kpidMTime,
|
||||
kpidATime
|
||||
kpidATime,
|
||||
kpidChangeTime
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
|
|
@ -205,6 +212,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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 kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ void CItem::Parse(const Byte *p)
|
|||
NumLogBlockRecorded = Get64(p + 64);
|
||||
ATime.Parse(p + 72);
|
||||
MTime.Parse(p + 84);
|
||||
// AttrtTime.Parse(p + 96);
|
||||
AttribTime.Parse(p + 96);
|
||||
// CheckPoint = Get32(p + 108);
|
||||
// ExtendedAttrIcb.Parse(p + 112);
|
||||
// ImplId.Parse(p + 128);
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ struct CItem
|
|||
UInt64 NumLogBlockRecorded;
|
||||
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.
|
||||
// UInt32 CheckPoint;
|
||||
// CLongAllocDesc ExtendedAttrIcb;
|
||||
// CRegId ImplId;
|
||||
|
|
|
|||
|
|
@ -921,7 +921,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
|
|||
CLimitedInStream *streamSpec = new CLimitedInStream;
|
||||
CMyComPtr<ISequentialInStream> 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;
|
||||
|
|
|
|||
|
|
@ -171,6 +171,20 @@ struct CHeader
|
|||
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 @@ HRESULT CHandler::Open3()
|
|||
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 @@ static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
|
|||
|
||||
void CHandler::AddComment(UString &s) const
|
||||
{
|
||||
AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
|
||||
AddComment_UInt64(s, "PhysicalSize", _phySize);
|
||||
|
||||
if (!_errorMessage.IsEmpty())
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ static bool Str_to_ValName(const AString &s, AString &name, AString &val)
|
|||
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();
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ static void GetFileTime(const Byte *p, NCOM::CPropVariant &prop)
|
|||
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 @@ public:
|
|||
int dotPos = name.ReverseFind_Dot();
|
||||
if (dotPos < 0)
|
||||
dotPos = name.Len();
|
||||
_before = name.Left(dotPos);
|
||||
_before.SetFrom(name.Ptr(), dotPos);
|
||||
_after = name.Ptr(dotPos);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ static int AddUniqHash(const CStreamInfo *streams, CUIntVector &sorted, const By
|
|||
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 @@ static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned
|
|||
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 @@ bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, u
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -567,9 +567,12 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,20 @@ namespace NArchive {
|
|||
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)
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1089,7 +1089,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
|||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
|
||||
{
|
||||
*timeType = NFileTimeType::kUnix;
|
||||
*timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
|
||||
// *timeType = NFileTimeType::kUnix;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -1136,7 +1137,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
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,14 +1266,27 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
}
|
||||
}
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
|
||||
CLocalProgress *lps = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = lps;
|
||||
lps->Init(updateCallback, true);
|
||||
|
||||
RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress));
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
RINOK(updateCallback->GetStream(0, &fileInStream));
|
||||
if (!fileInStream)
|
||||
return S_FALSE;
|
||||
{
|
||||
CMyComPtr<IStreamGetSize> 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<ICompressProgressInfo> 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 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
|||
|
||||
REGISTER_ARC_IO(
|
||||
"xz", "xz txz", "* .tar", 0xC,
|
||||
XZ_SIG,
|
||||
0,
|
||||
NArcInfoFlags::kKeepName,
|
||||
NULL)
|
||||
XZ_SIG, 0
|
||||
, NArcInfoFlags::kKeepName
|
||||
, 0
|
||||
, NULL)
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -190,6 +190,8 @@ static const Byte kProps[] =
|
|||
kpidVolumeIndex,
|
||||
kpidOffset
|
||||
// kpidIsAltStream
|
||||
// , kpidChangeTime // for debug
|
||||
// , 255 // for debug
|
||||
};
|
||||
|
||||
static const Byte kArcProps[] =
|
||||
|
|
@ -347,6 +349,34 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
|
||||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
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 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
|||
break;
|
||||
}
|
||||
|
||||
case kpidCTime:
|
||||
/*
|
||||
// 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:
|
||||
{
|
||||
FILETIME utc;
|
||||
bool defined = true;
|
||||
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc))
|
||||
if (NtfsUnixTimeToProp(item.FromCentral, extra,
|
||||
NFileHeader::NNtfsExtra::kMTime,
|
||||
NFileHeader::NUnixTime::kMTime, prop))
|
||||
{
|
||||
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
|
||||
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 @@ HRESULT CZipDecoder::Decode(
|
|||
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 @@ HRESULT CZipDecoder::Decode(
|
|||
|
||||
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 @@ HRESULT CZipDecoder::Decode(
|
|||
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<ICompressReadUnusedFromInBuf> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,9 @@ private:
|
|||
|
||||
int m_MainMethod;
|
||||
bool m_ForceAesMode;
|
||||
bool m_WriteNtfsTimeExtra;
|
||||
|
||||
CHandlerTimeOptions TimeOptions;
|
||||
|
||||
bool _removeSfxBlock;
|
||||
bool m_ForceLocal;
|
||||
bool m_ForceUtf8;
|
||||
|
|
@ -71,7 +73,8 @@ private:
|
|||
_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;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace NZip {
|
|||
|
||||
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
|
||||
{
|
||||
*timeType = NFileTimeType::kDOS;
|
||||
*timeType = TimeOptions.Prec;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
@ -207,27 +207,58 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
}
|
||||
*/
|
||||
|
||||
// 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));
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
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.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 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
|||
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 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
|||
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 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
|
|||
}
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,14 +88,15 @@ namespace NFileHeader
|
|||
{
|
||||
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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1045,8 +1045,23 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo
|
|||
|
||||
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 @@ static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
|
|||
{
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -30,11 +30,12 @@ static const CUInt32PCharPair g_ExtraTypes[] =
|
|||
{
|
||||
{ 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 @@ void CExtraSubBlock::PrintInfo(AString &s) const
|
|||
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 @@ bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
|
|||
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::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res
|
|||
}
|
||||
|
||||
|
||||
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 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
|
|||
{
|
||||
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 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ struct CExtraSubBlock
|
|||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "../../../../C/7zCrc.h"
|
||||
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
#include "../../Common/OffsetStream.h"
|
||||
|
||||
#include "ZipOut.h"
|
||||
|
|
@ -110,6 +111,40 @@ void COutArchive::WriteUtfName(const CItemOut &item)
|
|||
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 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
|
|||
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 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
|
|||
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::WriteDescriptor(const CItemOut &item)
|
|||
|
||||
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 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
|
|||
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 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
|
|||
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::WriteCentralHeader(const CItemOut &item)
|
|||
|
||||
void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &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
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ public:
|
|||
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 @@ public:
|
|||
return 4 + 5 + size;
|
||||
}
|
||||
|
||||
CItemOut(): NtfsTimeIsDefined(false) {}
|
||||
CItemOut():
|
||||
Write_NtfsTime(false),
|
||||
Write_UnixTime(false)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -62,6 +66,7 @@ class COutArchive
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -20,9 +20,19 @@ REGISTER_ARC_IO(
|
|||
"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)
|
||||
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,9 @@ static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &ite
|
|||
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 void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *o
|
|||
}
|
||||
|
||||
|
||||
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<IStreamGetProps> getProps;
|
||||
|
|
@ -506,35 +505,99 @@ static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileIn
|
|||
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<CItemEx> &inputItems,
|
||||
CObjectVector<CUpdateItem> &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<ICompressProgressInfo> progress = lps;
|
||||
|
|
@ -575,7 +638,8 @@ static HRESULT Update2St(
|
|||
}
|
||||
else
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
{
|
||||
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
|
||||
if (res == S_FALSE)
|
||||
{
|
||||
|
|
@ -596,7 +660,7 @@ static HRESULT Update2St(
|
|||
}
|
||||
// seqMode = true; // to test seqMode
|
||||
|
||||
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity);
|
||||
UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
|
||||
|
||||
CCompressingResult compressingResult;
|
||||
|
||||
|
|
@ -629,10 +693,11 @@ static HRESULT Update2St(
|
|||
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 @@ static HRESULT Update2St(
|
|||
|
||||
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 @@ static HRESULT Update2(
|
|||
CInArchive *inArchive,
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
CObjectVector<CUpdateItem> &updateItems,
|
||||
const CUpdateOptions &updateOptions,
|
||||
const CCompressionMethodMode &options, bool outSeqMode,
|
||||
const CByteBuffer *comment,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
|
|
@ -674,6 +748,11 @@ static HRESULT Update2(
|
|||
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
|
||||
|
||||
/*
|
||||
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
|
||||
*/
|
||||
|
||||
bool unknownComplexity = false;
|
||||
UInt64 complexity = 0;
|
||||
UInt64 numFilesToCompress = 0;
|
||||
|
|
@ -901,11 +980,23 @@ static HRESULT Update2(
|
|||
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<CItemOut> items;
|
||||
|
||||
CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
|
||||
|
|
@ -1021,7 +1112,7 @@ static HRESULT Update2(
|
|||
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 @@ static HRESULT Update2(
|
|||
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 @@ static HRESULT Update2(
|
|||
options.IsRealAesMode(), options.AesKeyMode, item);
|
||||
|
||||
archive.WriteLocalHeader_Replace(item);
|
||||
|
||||
/*
|
||||
if (reportArcProp)
|
||||
{
|
||||
stat.UpdateWithItem(item);
|
||||
RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1231,6 +1337,13 @@ static HRESULT Update2(
|
|||
|
||||
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 @@ HRESULT Update(
|
|||
CObjectVector<CUpdateItem> &updateItems,
|
||||
ISequentialOutStream *seqOutStream,
|
||||
CInArchive *inArchive, bool removeSfx,
|
||||
const CUpdateOptions &updateOptions,
|
||||
const CCompressionMethodMode &compressionMethodMode,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
|
|
@ -1529,6 +1643,7 @@ HRESULT Update(
|
|||
EXTERNAL_CODECS_LOC_VARS
|
||||
outArchive, inArchive,
|
||||
inputItems, updateItems,
|
||||
updateOptions,
|
||||
compressionMethodMode, outSeqMode,
|
||||
inArchive ? &inArchive->ArcInfo.Comment : NULL,
|
||||
updateCallback);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ struct CUpdateItem
|
|||
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 @@ struct CUpdateItem
|
|||
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<CItemEx> &inputItems,
|
||||
CObjectVector<CUpdateItem> &updateItems,
|
||||
ISequentialOutStream *seqOutStream,
|
||||
CInArchive *inArchive, bool removeSfx,
|
||||
const CUpdateOptions &updateOptions,
|
||||
const CCompressionMethodMode &compressionMethodMode,
|
||||
IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ WIN_OBJS = $(WIN_OBJS) \
|
|||
$O\FileLink.obj \
|
||||
$O\FileSystem.obj \
|
||||
$O\MemoryLock.obj \
|
||||
$O\PropVariantConv.obj \
|
||||
$O\Registry.obj \
|
||||
$O\SystemInfo.obj \
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ COMMON_OBJS_2 = \
|
|||
WIN_OBJS_2 = \
|
||||
$O/ErrorMsg.o \
|
||||
$O/FileLink.o \
|
||||
$O/PropVariantConv.o \
|
||||
$O/SystemInfo.o \
|
||||
|
||||
7ZIP_COMMON_OBJS_2 = \
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ WIN_OBJS = $(WIN_OBJS) \
|
|||
$O\MemoryLock.obj \
|
||||
$O\Menu.obj \
|
||||
$O\ProcessUtils.obj \
|
||||
$O\PropVariantConv.obj \
|
||||
$O\Registry.obj \
|
||||
$O\ResourceString.obj \
|
||||
$O\SystemInfo.obj \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ WIN_OBJS = \
|
|||
$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 @@ WIN_OBJS = \
|
|||
$O\VirtThread.obj \
|
||||
|
||||
AR_OBJS = \
|
||||
$O\ApfsHandler.obj \
|
||||
$O\ApmHandler.obj \
|
||||
$O\ArHandler.obj \
|
||||
$O\ArjHandler.obj \
|
||||
|
|
@ -72,6 +74,7 @@ AR_OBJS = \
|
|||
$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 @@ AR_OBJS = \
|
|||
$O\PpmdHandler.obj \
|
||||
$O\QcowHandler.obj \
|
||||
$O\RpmHandler.obj \
|
||||
$O\SparseHandler.obj \
|
||||
$O\SplitHandler.obj \
|
||||
$O\SquashfsHandler.obj \
|
||||
$O\SwfHandler.obj \
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ WIN_OBJS = \
|
|||
$O/FileIO.o \
|
||||
$O/FileName.o \
|
||||
$O/PropVariant.o \
|
||||
$O/PropVariantConv.o \
|
||||
$O/PropVariantUtils.o \
|
||||
$O/System.o \
|
||||
$O/TimeUtils.o \
|
||||
|
|
@ -82,6 +83,7 @@ WIN_OBJS = \
|
|||
$O/UniqBlocks.o \
|
||||
|
||||
AR_OBJS = \
|
||||
$O/ApfsHandler.o \
|
||||
$O/ApmHandler.o \
|
||||
$O/ArHandler.o \
|
||||
$O/ArjHandler.o \
|
||||
|
|
@ -101,6 +103,7 @@ AR_OBJS = \
|
|||
$O/HandlerCont.o \
|
||||
$O/HfsHandler.o \
|
||||
$O/IhexHandler.o \
|
||||
$O/LpHandler.o \
|
||||
$O/LzhHandler.o \
|
||||
$O/LzmaHandler.o \
|
||||
$O/MachoHandler.o \
|
||||
|
|
@ -112,6 +115,7 @@ AR_OBJS = \
|
|||
$O/PpmdHandler.o \
|
||||
$O/QcowHandler.o \
|
||||
$O/RpmHandler.o \
|
||||
$O/SparseHandler.o \
|
||||
$O/SplitHandler.o \
|
||||
$O/SquashfsHandler.o \
|
||||
$O/SwfHandler.o \
|
||||
|
|
|
|||
|
|
@ -2763,6 +2763,10 @@ SOURCE=..\..\Archive\Udf\UdfIn.h
|
|||
# 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
|
||||
|
|
@ -2851,6 +2855,10 @@ SOURCE=..\..\Archive\IhexHandler.cpp
|
|||
# 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 +2913,10 @@ SOURCE=..\..\Archive\RpmHandler.cpp
|
|||
# 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 +3041,14 @@ SOURCE=..\..\..\Windows\PropVariant.h
|
|||
# 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
|
||||
|
|
|
|||
|
|
@ -28,10 +28,11 @@ MY_VERSION_INFO_DLL("7z Plugin" , "7z")
|
|||
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
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ static int main2(int numArgs, const char *args[])
|
|||
|
||||
if (inStreamSpec)
|
||||
{
|
||||
if (!inStreamSpec->File.GetLength(fileSize))
|
||||
if (!inStreamSpec->GetLength(fileSize))
|
||||
throw "Cannot get file length";
|
||||
fileSizeDefined = true;
|
||||
if (!stdOutMode)
|
||||
|
|
|
|||
|
|
@ -2,18 +2,30 @@
|
|||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "../../Windows/FileFind.h"
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
|
||||
// for major minor
|
||||
// BSD: <sys/types.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#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 +49,19 @@ static const UInt32 kClusterSize = 1 << 18;
|
|||
#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 +75,7 @@ CInFileStream::~CInFileStream()
|
|||
#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 +325,14 @@ STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
|
|||
|
||||
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 +341,18 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
|
|||
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 +365,114 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
|
|||
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 +482,14 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
|
|||
|
||||
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 +503,9 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
|
|||
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 +518,130 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
|
|||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 @@ class CInFileStream:
|
|||
public IStreamGetSize,
|
||||
public IStreamGetProps,
|
||||
public IStreamGetProps2,
|
||||
public IStreamGetProp,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
NWindows::NFile::NIO::CInFile File;
|
||||
public:
|
||||
|
||||
#ifdef USE_WIN_FILE
|
||||
|
||||
|
|
@ -42,8 +47,20 @@ public:
|
|||
|
||||
#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;
|
||||
|
||||
|
|
@ -51,13 +68,25 @@ public:
|
|||
|
||||
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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
|
||||
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)
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@ bool CInBufferBase::ReadByte_FromNewBlock(Byte &b)
|
|||
{
|
||||
if (!ReadBlock())
|
||||
{
|
||||
NumExtraBytes++;
|
||||
// 22.00: we don't increment (NumExtraBytes) here
|
||||
// NumExtraBytes++;
|
||||
b = 0xFF;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,44 +154,70 @@ STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize
|
|||
{
|
||||
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 UInt64 rem = Extents[left + 1].Virt - virt;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
}
|
||||
|
||||
const CSeekExtent &extent = Extents[left];
|
||||
UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
|
||||
if (_needStartSeek || _phyPos != phyPos)
|
||||
|
||||
if (extent.Is_ZeroFill())
|
||||
{
|
||||
_needStartSeek = false;
|
||||
_phyPos = phyPos;
|
||||
RINOK(SeekToPhys());
|
||||
memset(data, 0, size);
|
||||
_virtPos += size;
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UInt64 rem = Extents[left + 1].Virt - _virtPos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
{
|
||||
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)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue