This commit is contained in:
Igor Pavlov 2022-06-20 00:00:00 +00:00
parent f19f813537
commit a3e1d22737
211 changed files with 15242 additions and 2443 deletions

View file

@ -1,7 +1,12 @@
; 7zAsm.asm -- ASM macros ; 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 ifdef @wordsize
; @wordsize is defined only in JWASM and ASMC and is not defined in MASM ; @wordsize is defined only in JWASM and ASMC and is not defined in MASM
; @wordsize eq 8 for 64-bit x64 ; @wordsize eq 8 for 64-bit x64

View file

@ -1,5 +1,5 @@
; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions ; 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 include 7zAsm.asm
@ -54,14 +54,20 @@ ifndef x64
.686 .686
.xmm .xmm
endif 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 ifdef x64
rNum equ REG_ABI_PARAM_2 rNum equ REG_ABI_PARAM_2
if (IS_LINUX eq 0) if (IS_LINUX eq 0)
LOCAL_SIZE equ (16 * 2) LOCAL_SIZE equ (16 * 2)
endif endif
else else
rNum equ r0 rNum equ r3
LOCAL_SIZE equ (16 * 1) LOCAL_SIZE equ (16 * 1)
endif endif
@ -103,15 +109,18 @@ MY_PROLOG macro
movdqa [r4 + 16], xmm9 movdqa [r4 + 16], xmm9
endif endif
else ; x86 else ; x86
if (IS_CDECL gt 0) push r3
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 r5 push r5
mov r5, r4 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 and r4, -16
sub r4, LOCAL_SIZE sub r4, LOCAL_SIZE
endif endif
@ -129,6 +138,7 @@ MY_EPILOG macro
else ; x86 else ; x86
mov r4, r5 mov r4, r5
pop r5 pop r5
pop r3
endif endif
MY_ENDP MY_ENDP
endm endm
@ -171,7 +181,7 @@ pre2 equ 2
RND4 macro k 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))) paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4)))
MY_sha256rnds2 state0_N, state1_N MY_sha256rnds2 state0_N, state1_N
pshufd msg, msg, 0eH pshufd msg, msg, 0eH
@ -210,6 +220,8 @@ endm
MY_PROC Sha256_UpdateBlocks_HW, 3 MY_PROC Sha256_UpdateBlocks_HW, 3
MY_PROLOG MY_PROLOG
lea rTable, [K_CONST]
cmp rNum, 0 cmp rNum, 0
je end_c je end_c

View file

@ -1,5 +1,5 @@
/* 7zTypes.h -- Basic types /* 7zTypes.h -- Basic types
2021-12-25 : Igor Pavlov : Public domain */ 2022-04-01 : Igor Pavlov : Public domain */
#ifndef __7Z_TYPES_H #ifndef __7Z_TYPES_H
#define __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) #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 TEXT(quote) quote
#define FILE_ATTRIBUTE_READONLY 0x0001 #define FILE_ATTRIBUTE_READONLY 0x0001
@ -520,6 +516,14 @@ struct ISzAlloc
#endif #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 EXTERN_C_END
#endif #endif

View file

@ -1,7 +1,7 @@
#define MY_VER_MAJOR 21 #define MY_VER_MAJOR 22
#define MY_VER_MINOR 07 #define MY_VER_MINOR 00
#define MY_VER_BUILD 0 #define MY_VER_BUILD 0
#define MY_VERSION_NUMBERS "21.07" #define MY_VERSION_NUMBERS "22.00"
#define MY_VERSION MY_VERSION_NUMBERS #define MY_VERSION MY_VERSION_NUMBERS
#ifdef MY_CPU_NAME #ifdef MY_CPU_NAME
@ -10,12 +10,12 @@
#define MY_VERSION_CPU MY_VERSION #define MY_VERSION_CPU MY_VERSION
#endif #endif
#define MY_DATE "2021-12-26" #define MY_DATE "2022-06-15"
#undef MY_COPYRIGHT #undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE #undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov" #define MY_AUTHOR_NAME "Igor Pavlov"
#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain" #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 #ifdef USE_COPYRIGHT_CR
#define MY_COPYRIGHT MY_COPYRIGHT_CR #define MY_COPYRIGHT MY_COPYRIGHT_CR

View file

@ -382,6 +382,8 @@ $O/VirtThread.o: ../../Common/VirtThread.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/ApfsHandler.o: ../../Archive/ApfsHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/ApmHandler.o: ../../Archive/ApmHandler.cpp $O/ApmHandler.o: ../../Archive/ApmHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp $O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp
@ -390,6 +392,8 @@ $O/ArHandler.o: ../../Archive/ArHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/ArjHandler.o: ../../Archive/ArjHandler.cpp $O/ArjHandler.o: ../../Archive/ArjHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/AvbHandler.o: ../../Archive/AvbHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/Base64Handler.o: ../../Archive/Base64Handler.cpp $O/Base64Handler.o: ../../Archive/Base64Handler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp $O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp
@ -426,6 +430,8 @@ $O/HfsHandler.o: ../../Archive/HfsHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/IhexHandler.o: ../../Archive/IhexHandler.cpp $O/IhexHandler.o: ../../Archive/IhexHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/LpHandler.o: ../../Archive/LpHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/LzhHandler.o: ../../Archive/LzhHandler.cpp $O/LzhHandler.o: ../../Archive/LzhHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp $O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp
@ -448,6 +454,8 @@ $O/QcowHandler.o: ../../Archive/QcowHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/RpmHandler.o: ../../Archive/RpmHandler.cpp $O/RpmHandler.o: ../../Archive/RpmHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/SparseHandler.o: ../../Archive/SparseHandler.cpp
$(CXX) $(CXXFLAGS) $<
$O/SplitHandler.o: ../../Archive/SplitHandler.cpp $O/SplitHandler.o: ../../Archive/SplitHandler.cpp
$(CXX) $(CXXFLAGS) $< $(CXX) $(CXXFLAGS) $<
$O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp $O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp

View file

@ -2,6 +2,8 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../../Windows/TimeUtils.h"
#include "7zFolderInStream.h" #include "7zFolderInStream.h"
namespace NArchive { namespace NArchive {
@ -13,17 +15,17 @@ void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
_updateCallback = updateCallback; _updateCallback = updateCallback;
_indexes = indexes; _indexes = indexes;
_numFiles = numFiles; _numFiles = numFiles;
_index = 0;
Processed.ClearAndReserve(numFiles); Processed.ClearAndReserve(numFiles);
CRCs.ClearAndReserve(numFiles); CRCs.ClearAndReserve(numFiles);
Sizes.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(); _stream.Release();
} }
@ -32,44 +34,101 @@ HRESULT CFolderInStream::OpenStream()
_pos = 0; _pos = 0;
_crc = CRC_INIT_VAL; _crc = CRC_INIT_VAL;
_size_Defined = false; _size_Defined = false;
_times_Defined = false;
_size = 0; _size = 0;
FILETIME_Clear(_cTime);
FILETIME_Clear(_aTime);
FILETIME_Clear(_mTime);
_attrib = 0;
while (_index < _numFiles) while (Processed.Size() < _numFiles)
{ {
CMyComPtr<ISequentialInStream> stream; CMyComPtr<ISequentialInStream> stream;
HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream); const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream);
if (result != S_OK) if (result != S_OK && result != S_FALSE)
{ return result;
if (result != S_FALSE)
return result;
}
_stream = stream; _stream = stream;
if (stream) if (stream)
{ {
CMyComPtr<IStreamGetSize> streamGetSize;
stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
if (streamGetSize)
{ {
if (streamGetSize->GetSize(&_size) == S_OK) CMyComPtr<IStreamGetProps> getProps;
_size_Defined = true; 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(AddFileInfo(result == S_OK));
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
AddFileInfo(result == S_OK);
} }
return S_OK; return S_OK;
} }
void CFolderInStream::AddFileInfo(bool isProcessed) static void AddFt(CRecordVector<UInt64> &vec, const FILETIME &ft)
{ {
Processed.Add(isProcessed); vec.AddInReserved(FILETIME_To_UInt64(ft));
Sizes.Add(_pos); }
CRCs.Add(CRC_GET_DIGEST(_crc));
/*
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) STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
@ -95,18 +154,10 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz
} }
_stream.Release(); _stream.Release();
_index++; RINOK(AddFileInfo(true));
AddFileInfo(true);
_pos = 0;
_crc = CRC_INIT_VAL;
_size_Defined = false;
_size = 0;
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
} }
if (_index >= _numFiles) if (Processed.Size() >= _numFiles)
break; break;
RINOK(OpenStream()); RINOK(OpenStream());
} }

View file

@ -23,21 +23,37 @@ class CFolderInStream:
UInt64 _pos; UInt64 _pos;
UInt32 _crc; UInt32 _crc;
bool _size_Defined; bool _size_Defined;
bool _times_Defined;
UInt64 _size; UInt64 _size;
FILETIME _cTime;
FILETIME _aTime;
FILETIME _mTime;
UInt32 _attrib;
const UInt32 *_indexes;
unsigned _numFiles; unsigned _numFiles;
unsigned _index; const UInt32 *_indexes;
CMyComPtr<IArchiveUpdateCallback> _updateCallback; CMyComPtr<IArchiveUpdateCallback> _updateCallback;
HRESULT OpenStream(); HRESULT OpenStream();
void AddFileInfo(bool isProcessed); HRESULT AddFileInfo(bool isProcessed);
public: public:
CRecordVector<bool> Processed; CRecordVector<bool> Processed;
CRecordVector<UInt32> CRCs; CRecordVector<UInt32> CRCs;
CRecordVector<UInt64> Sizes; 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) MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
@ -45,7 +61,7 @@ public:
void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles); 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 UInt64 GetFullSize() const
{ {
@ -54,6 +70,13 @@ public:
size += Sizes[i]; size += Sizes[i];
return size; return size;
} }
CFolderInStream():
Need_CTime(false),
Need_ATime(false),
Need_MTime(false),
Need_Attrib(false)
{}
}; };
}} }}

View file

@ -278,7 +278,7 @@ static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVe
{ {
UInt64 value; UInt64 value;
if (v.GetItem(index, 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 bool CHandler::IsFolderEncrypted(CNum folderIndex) const

View file

@ -49,9 +49,8 @@ public:
bool _encryptHeaders; bool _encryptHeaders;
// bool _useParents; 9.26 // bool _useParents; 9.26
CBoolPair Write_CTime; CHandlerTimeOptions TimeOptions;
CBoolPair Write_ATime;
CBoolPair Write_MTime;
CBoolPair Write_Attrib; CBoolPair Write_Attrib;
bool _useMultiThreadMixer; bool _useMultiThreadMixer;

View file

@ -384,16 +384,16 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
CObjectVector<CUpdateItem> updateItems; CObjectVector<CUpdateItem> updateItems;
bool need_CTime = (Write_CTime.Def && Write_CTime.Val); bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val);
bool need_ATime = (Write_ATime.Def && Write_ATime.Val); bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val);
bool need_MTime = (Write_MTime.Def ? Write_MTime.Val : true); bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true);
bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true); bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true);
if (db && !db->Files.IsEmpty()) if (db && !db->Files.IsEmpty())
{ {
if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
if (!Write_Attrib.Def) need_Attrib = !db->Attrib.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(); int level = GetLevel();
CUpdateOptions options; 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.Method = &methodMode;
options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
@ -817,9 +822,7 @@ void COutHandler::InitProps7z()
_encryptHeaders = false; _encryptHeaders = false;
// _useParents = false; // _useParents = false;
Write_CTime.Init(); TimeOptions.Init();
Write_ATime.Init();
Write_MTime.Init();
Write_Attrib.Init(); Write_Attrib.Init();
_useMultiThreadMixer = true; _useMultiThreadMixer = true;
@ -954,10 +957,20 @@ HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &val
return S_OK; 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); bool processed;
if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); RINOK(TimeOptions.Parse(name, value, processed));
if (processed)
{
if ( TimeOptions.Prec != (UInt32)(Int32)-1
&& TimeOptions.Prec != k_PropVar_TimePrec_0
&& TimeOptions.Prec != k_PropVar_TimePrec_HighPrec
&& TimeOptions.Prec != k_PropVar_TimePrec_100ns)
return E_INVALIDARG;
return S_OK;
}
}
if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib); if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);

View file

@ -15,7 +15,13 @@ REGISTER_ARC_IO_DECREMENT_SIG(
"7z", "7z", NULL, 7, "7z", "7z", NULL, 7,
k_Signature_Dec, k_Signature_Dec,
0, 0,
NArcInfoFlags::kFindSignature, NArcInfoFlags::kFindSignature
NULL); | 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);
}} }}

View file

@ -804,10 +804,20 @@ struct CAnalysis
bool ParseExe; bool ParseExe;
bool ParseAll; bool ParseAll;
/*
bool Need_ATime;
bool ATime_Defined;
FILETIME ATime;
*/
CAnalysis(): CAnalysis():
ParseWav(true), ParseWav(true),
ParseExe(false), ParseExe(false),
ParseAll(false) ParseAll(false)
/*
, Need_ATime(false)
, ATime_Defined(false)
*/
{} {}
HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode); 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); HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);
if (result == S_OK && stream) 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; size_t size = kAnalysisBufSize;
result = ReadStream(stream, Buffer, &size); result = ReadStream(stream, Buffer, &size);
stream.Release(); stream.Release();
@ -1586,6 +1608,11 @@ HRESULT Update(
CMyComPtr<IArchiveExtractCallbackMessage> extractCallback; CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;
updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback); updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);
/*
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
*/
// size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
/* /*
@ -1756,6 +1783,7 @@ HRESULT Update(
{ {
CAnalysis analysis; CAnalysis analysis;
// analysis.Need_ATime = options.Need_ATime;
if (options.AnalysisLevel == 0) if (options.AnalysisLevel == 0)
{ {
analysis.ParseWav = false; analysis.ParseWav = false;
@ -1790,7 +1818,15 @@ HRESULT Update(
CFilterMode2 fm; CFilterMode2 fm;
if (useFilters) if (useFilters)
{ {
// analysis.ATime_Defined = false;
RINOK(analysis.GetFilterGroup(i, ui, fm)); 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; fm.Encrypted = method.PasswordIsDefined;
@ -2374,13 +2410,33 @@ HRESULT Update(
RINOK(lps->SetCur()); RINOK(lps->SetCur());
/*
const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size();
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kBlockIndex, (UInt32)folderIndex,
NUpdateNotifyOp::kAdd));
}
*/
CFolderInStream *inStreamSpec = new CFolderInStream; CFolderInStream *inStreamSpec = new CFolderInStream;
CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec); 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); inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
unsigned startPackIndex = newDatabase.PackSizes.Size(); unsigned startPackIndex = newDatabase.PackSizes.Size();
UInt64 curFolderUnpackSize = totalSize; UInt64 curFolderUnpackSize = totalSize;
// curFolderUnpackSize = (UInt64)(Int64)-1; // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug
RINOK(encoder.Encode( RINOK(encoder.Encode(
EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS
@ -2393,8 +2449,11 @@ HRESULT Update(
if (!inStreamSpec->WasFinished()) if (!inStreamSpec->WasFinished())
return E_FAIL; return E_FAIL;
UInt64 packSize = 0;
// const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex;
for (; startPackIndex < 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; lps->InSize += curFolderUnpackSize;
// for () // for ()
@ -2403,7 +2462,9 @@ HRESULT Update(
CNum numUnpackStreams = 0; CNum numUnpackStreams = 0;
UInt64 skippedSize = 0; UInt64 skippedSize = 0;
UInt64 procSize = 0;
// unsigned numProcessedFiles = 0;
for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++) for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)
{ {
const CUpdateItem &ui = updateItems[indices[i + subIndex]]; const CUpdateItem &ui = updateItems[indices[i + subIndex]];
@ -2429,14 +2490,16 @@ HRESULT Update(
*/ */
if (!inStreamSpec->Processed[subIndex]) if (!inStreamSpec->Processed[subIndex])
{ {
// we don't add file here
skippedSize += ui.Size; skippedSize += ui.Size;
continue; continue; // comment it for debug
// file.Name += ".locked"; // name += ".locked"; // for debug
} }
file.Crc = inStreamSpec->CRCs[subIndex]; file.Crc = inStreamSpec->CRCs[subIndex];
file.Size = inStreamSpec->Sizes[subIndex]; file.Size = inStreamSpec->Sizes[subIndex];
procSize += file.Size;
// if (file.Size >= 0) // test purposes // if (file.Size >= 0) // test purposes
if (file.Size != 0) if (file.Size != 0)
{ {
@ -2450,6 +2513,23 @@ HRESULT Update(
file.HasStream = false; 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; file.Parent = ui.ParentFolderIndex;
if (ui.TreeFolderIndex >= 0) if (ui.TreeFolderIndex >= 0)
@ -2457,9 +2537,22 @@ HRESULT Update(
if (totalSecureDataSize != 0) if (totalSecureDataSize != 0)
newDatabase.SecureIDs.Add(ui.SecureIndex); 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); 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 // numUnpackStreams = 0 is very bad case for locked files
// v3.13 doesn't understand it. // v3.13 doesn't understand it.
newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
@ -2470,6 +2563,44 @@ HRESULT Update(
complexity -= skippedSize; complexity -= skippedSize;
RINOK(updateCallback->SetTotal(complexity)); 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));
}
*/
} }
} }

View file

@ -62,6 +62,8 @@ struct CUpdateItem
bool ATimeDefined; bool ATimeDefined;
bool MTimeDefined; bool MTimeDefined;
// bool ATime_WasReadByAnalysis;
// int SecureIndex; // 0 means (no_security) // int SecureIndex; // 0 means (no_security)
bool HasStream() const { return !IsDir && !IsAnti && Size != 0; } bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
@ -76,6 +78,7 @@ struct CUpdateItem
CTimeDefined(false), CTimeDefined(false),
ATimeDefined(false), ATimeDefined(false),
MTimeDefined(false) MTimeDefined(false)
// , ATime_WasReadByAnalysis(false)
// SecureIndex(0) // SecureIndex(0)
{} {}
void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); } void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }
@ -103,6 +106,11 @@ struct CUpdateOptions
bool RemoveSfxBlock; bool RemoveSfxBlock;
bool MultiThreadMixer; bool MultiThreadMixer;
bool Need_CTime;
bool Need_ATime;
bool Need_MTime;
bool Need_Attrib;
CUpdateOptions(): CUpdateOptions():
Method(NULL), Method(NULL),
HeaderMethod(NULL), HeaderMethod(NULL),
@ -114,7 +122,11 @@ struct CUpdateOptions
SolidExtension(false), SolidExtension(false),
UseTypeSorting(true), UseTypeSorting(true),
RemoveSfxBlock(false), RemoveSfxBlock(false),
MultiThreadMixer(true) MultiThreadMixer(true),
Need_CTime(false),
Need_ATime(false),
Need_MTime(false),
Need_Attrib(false)
{} {}
}; };

File diff suppressed because it is too large Load diff

View file

@ -322,8 +322,8 @@ static const Byte kProps[] =
kpidSize, kpidSize,
kpidMTime, kpidMTime,
kpidPosixAttrib, kpidPosixAttrib,
kpidUser, kpidUserId,
kpidGroup kpidGroupId
}; };
IMP_IInArchive_Props IMP_IInArchive_Props
@ -734,15 +734,11 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime: case kpidMTime:
{ {
if (item.MTime != 0) if (item.MTime != 0)
{ PropVariant_SetFrom_UnixTime(prop, item.MTime);
FILETIME fileTime;
NTime::UnixTimeToFileTime(item.MTime, fileTime);
prop = fileTime;
}
break; break;
} }
case kpidUser: if (item.User != 0) prop = item.User; break; case kpidUserId: if (item.User != 0) prop = item.User; break;
case kpidGroup: if (item.Group != 0) prop = item.Group; break; case kpidGroupId: if (item.Group != 0) prop = item.Group; break;
case kpidPosixAttrib: case kpidPosixAttrib:
if (item.TextFileIndex < 0) if (item.TextFileIndex < 0)
prop = item.Mode; prop = item.Mode;

View file

@ -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::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break;
case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 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::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::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break;
// case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break; // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break;

View file

@ -682,15 +682,7 @@ static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
{ {
if (dosTime == 0) if (dosTime == 0)
return; return;
FILETIME localFileTime, utc; PropVariant_SetFrom_DosTime(prop, dosTime);
if (NTime::DosTimeToFileTime(dosTime, localFileTime))
{
if (!LocalFileTimeToFileTime(&localFileTime, &utc))
utc.dwHighDateTime = utc.dwLowDateTime = 0;
}
else
utc.dwHighDateTime = utc.dwLowDateTime = 0;
prop = utc;
} }
static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop) static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop)

View file

@ -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( static HRESULT UpdateArchive(
UInt64 unpackSize, UInt64 unpackSize,
ISequentialOutStream *outStream, ISequentialOutStream *outStream,
const CProps &props, const CProps &props,
IArchiveUpdateCallback *updateCallback) IArchiveUpdateCallback *updateCallback
// , ArchiveUpdateCallbackArcProp *reportArcProp
)
{ {
RINOK(updateCallback->SetTotal(unpackSize)); {
CMyComPtr<ISequentialInStream> fileInStream; CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream)); RINOK(updateCallback->GetStream(0, &fileInStream));
CLocalProgress *localProgressSpec = new CLocalProgress; if (!fileInStream)
CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec; return S_FALSE;
localProgressSpec->Init(updateCallback, true); {
NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder; CMyComPtr<IStreamGetSize> streamGetSize;
CMyComPtr<ICompressCoder> encoder = encoderSpec; fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
RINOK(props.SetCoderProps(encoderSpec, NULL)); if (streamGetSize)
RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress)); {
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); 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; return S_OK;
} }
@ -345,6 +407,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_FAIL; return E_FAIL;
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
/*
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
*/
if (IntToBool(newProps)) if (IntToBool(newProps))
{ {
{ {
@ -396,6 +463,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return NCompress::CopyStream(_stream, outStream, progress); return NCompress::CopyStream(_stream, outStream, progress);
// return ReportArcProps(reportArcProp, NULL, NULL);
COM_TRY_END COM_TRY_END
} }
@ -410,7 +479,8 @@ REGISTER_ARC_IO(
"bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2, "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
k_Signature, k_Signature,
0, 0,
NArcInfoFlags::kKeepName, NArcInfoFlags::kKeepName
IsArc_BZip2) , 0
, IsArc_BZip2)
}} }}

View file

@ -295,15 +295,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime: case kpidMTime:
{ {
FILETIME localFileTime, utcFileTime; PropVariant_SetFrom_DosTime(prop, item.Time);
if (NTime::DosTimeToFileTime(item.Time, localFileTime))
{
if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
}
else
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
prop = utcFileTime;
break; break;
} }

View file

@ -84,6 +84,11 @@ struct CResetTable
// unsigned BlockSizeBits; // unsigned BlockSizeBits;
CRecordVector<UInt64> ResetOffsets; CRecordVector<UInt64> ResetOffsets;
CResetTable():
UncompressedSize(0),
CompressedSize(0)
{}
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
{ {
if (blockIndex >= ResetOffsets.Size()) if (blockIndex >= ResetOffsets.Size())
@ -118,6 +123,12 @@ struct CLzxInfo
CResetTable ResetTable; CResetTable ResetTable;
CLzxInfo():
Version(0),
ResetIntervalBits(0),
CacheSize(0)
{}
unsigned GetNumDictBits() const unsigned GetNumDictBits() const
{ {
if (Version == 2 || Version == 3) if (Version == 2 || Version == 3)

View file

@ -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) HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{ {
Init(); Init();
for (UInt32 i = 0; i < numProps; i++) for (UInt32 i = 0; i < numProps; i++)
{ {
UString name = names[i]; RINOK(SetProperty(names[i], values[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));
} }
return S_OK; return S_OK;
@ -275,4 +283,29 @@ HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PR
#endif #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;
}
} }

View file

@ -16,6 +16,7 @@ class CCommonMethodProps
protected: protected:
void InitCommon() void InitCommon()
{ {
// _Write_MTime = true;
#ifndef _7ZIP_ST #ifndef _7ZIP_ST
_numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors(); _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
_numThreads_WasForced = false; _numThreads_WasForced = false;
@ -118,11 +119,36 @@ public:
CSingleMethodProps() { InitSingle(); } CSingleMethodProps() { InitSingle(); }
int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; } 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); HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
}; };
#endif #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 #endif

View file

@ -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 bool HasTailSlash(const AString &name, UINT
#if defined(_WIN32) && !defined(UNDER_CE) #if defined(_WIN32) && !defined(UNDER_CE)
codePage codePage

View file

@ -14,6 +14,8 @@ UString GetOsPath(const UString &name);
UString GetOsPath_Remove_TailSlash(const UString &name); UString GetOsPath_Remove_TailSlash(const UString &name);
void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false); 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); bool HasTailSlash(const AString &name, UINT codePage);

View file

@ -652,11 +652,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime: case kpidMTime:
{ {
if (item.MTime != 0) if (item.MTime != 0)
{ PropVariant_SetFrom_UnixTime(prop, item.MTime);
FILETIME utc;
NTime::UnixTimeToFileTime(item.MTime, utc);
prop = utc;
}
break; break;
} }
case kpidPosixAttrib: prop = item.Mode; break; case kpidPosixAttrib: prop = item.Mode; break;

View file

@ -125,6 +125,24 @@ STDAPI SetCaseSensitive(Int32 caseSensitive)
return S_OK; 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 #ifdef EXTERNAL_CODECS
CExternalCodecs g_ExternalCodecs; CExternalCodecs g_ExternalCodecs;

View file

@ -343,6 +343,8 @@ struct CHeader
bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; } bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; }
bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; } bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; }
UInt64 GetPhySize() const { return NumBlocks << BlockBits; }
bool Parse(const Byte *p); bool Parse(const Byte *p);
}; };
@ -638,7 +640,7 @@ struct CNode
CExtTime MTime; CExtTime MTime;
CExtTime ATime; CExtTime ATime;
CExtTime CTime; CExtTime CTime;
// CExtTime InodeChangeTime; CExtTime ChangeTime;
// CExtTime DTime; // CExtTime DTime;
UInt64 NumBlocks; UInt64 NumBlocks;
@ -674,14 +676,14 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
ATime.Extra = 0; ATime.Extra = 0;
CTime.Extra = 0; CTime.Extra = 0;
CTime.Val = 0; CTime.Val = 0;
// InodeChangeTime.Extra = 0; ChangeTime.Extra = 0;
// DTime.Extra = 0; // DTime.Extra = 0;
LE_16 (0x00, Mode); LE_16 (0x00, Mode);
LE_16 (0x02, Uid); LE_16 (0x02, Uid);
LE_32 (0x04, FileSize); LE_32 (0x04, FileSize);
LE_32 (0x08, ATime.Val); LE_32 (0x08, ATime.Val);
// LE_32 (0x0C, InodeChangeTime.Val); LE_32 (0x0C, ChangeTime.Val);
LE_32 (0x10, MTime.Val); LE_32 (0x10, MTime.Val);
// LE_32 (0x14, DTime.Val); // LE_32 (0x14, DTime.Val);
LE_16 (0x18, Gid); LE_16 (0x18, Gid);
@ -742,7 +744,7 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
{ {
// UInt16 checksumUpper; // UInt16 checksumUpper;
// LE_16 (0x82, checksumUpper); // LE_16 (0x82, checksumUpper);
// LE_32 (0x84, InodeChangeTime.Extra); LE_32 (0x84, ChangeTime.Extra);
LE_32 (0x88, MTime.Extra); LE_32 (0x88, MTime.Extra);
LE_32 (0x8C, ATime.Extra); LE_32 (0x8C, ATime.Extra);
LE_32 (0x90, CTime.Val); LE_32 (0x90, CTime.Val);
@ -1148,7 +1150,7 @@ HRESULT CHandler::Open2(IInStream *inStream)
} }
_isArc = true; _isArc = true;
_phySize = _h.NumBlocks << _h.BlockBits; _phySize = _h.GetPhySize();
if (_openCallback) if (_openCallback)
{ {
@ -1744,8 +1746,8 @@ static const UInt32 kProps[] =
kpidLinks, kpidLinks,
kpidSymLink, kpidSymLink,
kpidCharacts, kpidCharacts,
kpidUser, kpidUserId,
kpidGroup 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) static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop)
{ {
if (val != 0) if (val != 0)
{ PropVariant_SetFrom_UnixTime(prop, val);
FILETIME ft;
NTime::UnixTimeToFileTime(val, ft);
prop = ft;
}
} }
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
@ -1988,15 +1986,19 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
return; return;
FILETIME ft; FILETIME ft;
unsigned low100ns = 0;
// if (t.Extra != 0) // if (t.Extra != 0)
{ {
// 1901-2446 : // 1901-2446 :
Int64 v = (Int64)(Int32)t.Val; Int64 v = (Int64)(Int32)t.Val;
v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp 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); const UInt32 ns = (t.Extra >> 2);
if (ns < 1000000000) if (ns < 1000000000)
{
ft64 += ns / 100; ft64 += ns / 100;
low100ns = (unsigned)(ns % 100);
}
ft.dwLowDateTime = (DWORD)ft64; ft.dwLowDateTime = (DWORD)ft64;
ft.dwHighDateTime = (DWORD)(ft64 >> 32); ft.dwHighDateTime = (DWORD)(ft64 >> 32);
} }
@ -2011,7 +2013,7 @@ static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
// NTime::UnixTimeToFileTime(t.Val, ft); // for // 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 kpidCTime: ExtTimeToProp(node.CTime, prop); break;
case kpidATime: ExtTimeToProp(node.ATime, prop); break; case kpidATime: ExtTimeToProp(node.ATime, prop); break;
// case kpidDTime: ExtTimeToProp(node.DTime, prop); break; // case kpidDTime: ExtTimeToProp(node.DTime, prop); break;
// case kpidChangeTime: ExtTimeToProp(node.InodeChangeTime, prop); break; case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break;
case kpidUserId: prop = (UInt32)node.Uid; break;
case kpidUser: prop = (UInt32)node.Uid; break; case kpidGroupId: prop = (UInt32)node.Gid; break;
case kpidGroup: prop = (UInt32)node.Gid; break;
case kpidLinks: prop = node.NumLinks; break; case kpidLinks: prop = node.NumLinks; break;
case kpidINode: prop = (UInt32)item.Node; break; case kpidINode: prop = (UInt32)item.Node; break;
case kpidStreamId: if (!isDir) 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) if (size < kHeaderSize)
return k_IsArc_Res_NEED_MORE; return k_IsArc_Res_NEED_MORE;
CHeader h; CHeader h;
if (!h.Parse(p + kHeaderDataOffset)) if (!h.Parse(p + kHeaderDataOffset))
return k_IsArc_Res_NO; return k_IsArc_Res_NO;
if (phySize)
*phySize = h.GetPhySize();
return k_IsArc_Res_YES; 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 }; static const Byte k_Signature[] = { 0x53, 0xEF };
REGISTER_ARC_I( REGISTER_ARC_I(

View file

@ -111,14 +111,14 @@ static int GetLog(UInt32 num)
static const UInt32 kHeaderSize = 512; 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) if (size < kHeaderSize)
return k_IsArc_Res_NEED_MORE; return k_IsArc_Res_NEED_MORE;
CHeader h; CHeader h;
return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO; return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO;
} }
}
bool CHeader::Parse(const Byte *p) bool CHeader::Parse(const Byte *p)
{ {
@ -846,17 +846,18 @@ static const CStatProp kArcProps[] =
IMP_IInArchive_Props IMP_IInArchive_Props
IMP_IInArchive_ArcProps_WITH_NAME IMP_IInArchive_ArcProps_WITH_NAME
static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop) static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
{ {
FILETIME localFileTime, utc; FILETIME localFileTime, utc;
if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime)) if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
if (LocalFileTimeToFileTime(&localFileTime, &utc)) if (LocalFileTimeToFileTime(&localFileTime, &utc))
{ {
UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime; UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
t64 += ms10 * 100000; t64 += ms10 * 100000;
utc.dwLowDateTime = (DWORD)t64; utc.dwLowDateTime = (DWORD)t64;
utc.dwHighDateTime = (DWORD)(t64 >> 32); 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 kpidPhySize: prop = PhySize; break;
case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break; case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
case kpidHeadersSize: prop = GetHeadersSize(); 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 kpidShortComment:
case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break; case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; 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 kpidPath: prop = GetItemPath(index); break;
case kpidShortName: prop = item.GetShortName(); break; case kpidShortName: prop = item.GetShortName(); break;
case kpidIsDir: prop = item.IsDir(); 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 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 kpidAttrib: prop = (UInt32)item.Attrib; break;
case kpidSize: if (!item.IsDir()) prop = item.Size; break; case kpidSize: if (!item.IsDir()) prop = item.Size; break;
case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break; case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;

View file

@ -23,6 +23,11 @@
using namespace NWindows; using namespace NWindows;
namespace NArchive { namespace NArchive {
namespace NFat {
API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
}
namespace NGpt { namespace NGpt {
#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 } #define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }
@ -51,6 +56,7 @@ struct CPartition
UInt64 FirstLba; UInt64 FirstLba;
UInt64 LastLba; UInt64 LastLba;
UInt64 Flags; UInt64 Flags;
const char *Ext; // detected later
Byte Name[kNameLen * 2]; Byte Name[kNameLen * 2];
bool IsUnused() const bool IsUnused() const
@ -73,6 +79,7 @@ struct CPartition
LastLba = Get64(p + 40); LastLba = Get64(p + 40);
Flags = Get64(p + 48); Flags = Get64(p + 48);
memcpy(Name, p + 56, kNameLen * 2); memcpy(Name, p + 56, kNameLen * 2);
Ext = NULL;
} }
}; };
@ -252,6 +259,28 @@ HRESULT CHandler::Open2(IInStream *stream)
return S_OK; 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, STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */, const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback * /* openArchiveCallback */) IArchiveOpenCallback * /* openArchiveCallback */)
@ -260,6 +289,42 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
Close(); Close();
RINOK(Open2(stream)); RINOK(Open2(stream));
_stream = 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; return S_OK;
COM_TRY_END COM_TRY_END
} }
@ -355,13 +420,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
} }
{ {
s += '.'; s += '.';
const char *ext = NULL; s += (item.Ext ? item.Ext : "img");
int typeIndex = FindPartType(item.Type);
if (typeIndex >= 0)
ext = kPartTypes[(unsigned)typeIndex].Ext;
if (!ext)
ext = "img";
s += ext;
} }
prop = s; prop = s;
break; break;
@ -375,7 +434,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{ {
char s[48]; char s[48];
const char *res; const char *res;
int typeIndex = FindPartType(item.Type); const int typeIndex = FindPartType(item.Type);
if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type) if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type)
res = kPartTypes[(unsigned)typeIndex].Type; res = kPartTypes[(unsigned)typeIndex].Type;
else else

View file

@ -475,6 +475,7 @@ class CHandler:
NDecoder::CCOMCoder *_decoderSpec; NDecoder::CCOMCoder *_decoderSpec;
CSingleMethodProps _props; CSingleMethodProps _props;
CHandlerTimeOptions _timeOptions;
public: public:
MY_UNKNOWN_IMP4( MY_UNKNOWN_IMP4(
@ -487,8 +488,15 @@ public:
STDMETHOD(OpenSeq)(ISequentialInStream *stream); STDMETHOD(OpenSeq)(ISequentialInStream *stream);
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps); 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; _decoderSpec = new NDecoder::CCOMCoder;
_decoder = _decoderSpec; _decoder = _decoderSpec;
} }
@ -528,7 +536,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidErrorFlags: case kpidErrorFlags:
{ {
UInt32 v = 0; UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
prop = v; prop = v;
@ -567,12 +575,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
break; break;
// case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break; // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
case kpidMTime: case kpidMTime:
// gzip specification: MTIME = 0 means no time stamp is available.
if (_item.Time != 0) if (_item.Time != 0)
{ PropVariant_SetFrom_UnixTime(prop, _item.Time);
FILETIME utc; break;
NTime::UnixTimeToFileTime(_item.Time, utc); case kpidTimeType:
prop = utc; if (_item.Time != 0)
} prop = (UInt32)NFileTimeType::kUnix;
break; break;
case kpidSize: case kpidSize:
{ {
@ -644,6 +653,7 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
try try
{ {
Close(); Close();
CreateDecoder();
_decoderSpec->SetInStream(stream); _decoderSpec->SetInStream(stream);
_decoderSpec->InitInStream(true); _decoderSpec->InitInStream(true);
RINOK(_item.ReadHeader(_decoderSpec)); RINOK(_item.ReadHeader(_decoderSpec));
@ -672,7 +682,8 @@ STDMETHODIMP CHandler::Close()
_headerSize = 0; _headerSize = 0;
_stream.Release(); _stream.Release();
_decoderSpec->ReleaseInStream(); if (_decoder)
_decoderSpec->ReleaseInStream();
return S_OK; return S_OK;
} }
@ -699,6 +710,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
extractCallback->PrepareOperation(askMode); extractCallback->PrepareOperation(askMode);
CreateDecoder();
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec); CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
outStreamSpec->SetStream(realOutStream); outStreamSpec->SetStream(realOutStream);
@ -873,21 +886,99 @@ static const Byte kHostOS =
NHostOS::kUnix; NHostOS::kUnix;
#endif #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( static HRESULT UpdateArchive(
ISequentialOutStream *outStream, ISequentialOutStream *outStream,
UInt64 unpackSize, UInt64 unpackSize,
CItem &item, CItem &item,
const CSingleMethodProps &props, const CSingleMethodProps &props,
IArchiveUpdateCallback *updateCallback) const CHandlerTimeOptions &timeOptions,
IArchiveUpdateCallback *updateCallback
// , IArchiveUpdateCallbackArcProp *reportArcProp
)
{ {
UInt64 complexity = 0; UInt64 unpackSizeReal;
RINOK(updateCallback->SetTotal(unpackSize)); {
RINOK(updateCallback->SetCompleted(&complexity));
CMyComPtr<ISequentialInStream> fileInStream; CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &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; CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
CMyComPtr<ISequentialInStream> crcStream(inStreamSpec); CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
inStreamSpec->SetStream(fileInStream); inStreamSpec->SetStream(fileInStream);
@ -911,14 +1002,50 @@ static HRESULT UpdateArchive(
RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress)); RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
item.Crc = inStreamSpec->GetCRC(); item.Crc = inStreamSpec->GetCRC();
item.Size32 = (UInt32)inStreamSpec->GetSize(); unpackSizeReal = inStreamSpec->GetSize();
item.Size32 = (UInt32)unpackSizeReal;
RINOK(item.WriteFooter(outStream)); 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); return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
} }
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) 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; return S_OK;
} }
@ -936,6 +1063,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_FAIL; return E_FAIL;
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive)); RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
/*
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
*/
CItem newItem; CItem newItem;
if (!IntToBool(newProps)) if (!IntToBool(newProps))
@ -945,11 +1077,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else else
{ {
newItem.HostOS = kHostOS; newItem.HostOS = kHostOS;
if (_timeOptions.Write_MTime.Val)
{ {
NCOM::CPropVariant prop; NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(0, kpidMTime, &prop)); RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
if (prop.vt == VT_FILETIME) 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) else if (prop.vt == VT_EMPTY)
newItem.Time = 0; newItem.Time = 0;
else else
@ -990,7 +1123,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_INVALIDARG; return E_INVALIDARG;
size = prop.uhVal.QuadPart; size = prop.uhVal.QuadPart;
} }
return UpdateArchive(outStream, size, newItem, _props, updateCallback); return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback);
} }
if (indexInArchive != 0) if (indexInArchive != 0)
@ -1022,6 +1155,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
} }
RINOK(_stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL)); 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); return NCompress::CopyStream(_stream, outStream, progress);
COM_TRY_END 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) 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 }; static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 };
REGISTER_ARC_IO( REGISTER_ARC_IO(
"gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF, "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF,
k_Signature, k_Signature, 0,
0, NArcInfoFlags::kKeepName
NArcInfoFlags::kKeepName, | NArcInfoFlags::kMTime
IsArc_Gz) | NArcInfoFlags::kMTime_Default
, TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
| TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
, IsArc_Gz)
}} }}

View file

@ -14,6 +14,10 @@
namespace NArchive { namespace NArchive {
namespace NExt {
API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
}
STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems, STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback) 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_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) static const char *GetImgExt(ISequentialInStream *stream)
{ {
const size_t kHeaderSize = 1 << 10; const size_t kHeaderSize = 1 << 11;
Byte buf[kHeaderSize]; Byte buf[kHeaderSize];
if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK) if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
{ {
@ -146,6 +151,8 @@ static const char *GetImgExt(ISequentialInStream *stream)
return "gpt"; return "gpt";
return "mbr"; return "mbr";
} }
if (NExt::IsArc_Ext(buf, kHeaderSize) == k_IsArc_Res_YES)
return "ext";
} }
return NULL; return NULL;
} }
@ -208,6 +215,33 @@ STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems)
return S_OK; 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, STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback) Int32 testMode, IArchiveExtractCallback *extractCallback)
{ {
@ -227,10 +261,6 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
return S_OK; return S_OK;
RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->PrepareOperation(askMode));
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
int opRes = NExtract::NOperationResult::kDataError; int opRes = NExtract::NOperationResult::kDataError;
ClearStreamVars(); ClearStreamVars();
@ -242,6 +272,19 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
if (hres == S_OK && inStream) 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(); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

View file

@ -94,7 +94,19 @@ protected:
virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0; virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0;
virtual void CloseAtError(); virtual void CloseAtError();
// returns (true), if Get_PackSizeProcessed() is required in Extract()
virtual bool Init_PackSizeProcessed()
{
return false;
}
public: public:
virtual bool Get_PackSizeProcessed(UInt64 &size)
{
size = 0;
return false;
}
MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream) MY_UNKNOWN_IMP3(IInArchive, IInArchiveGetStream, IInStream)
INTERFACE_IInArchive_Img(PURE) INTERFACE_IInArchive_Img(PURE)

View file

@ -240,7 +240,7 @@ struct CItem
UInt32 ID; UInt32 ID;
UInt32 CTime; UInt32 CTime;
UInt32 MTime; UInt32 MTime;
// UInt32 AttrMTime; UInt32 AttrMTime;
UInt32 ATime; UInt32 ATime;
// UInt32 BackupDate; // UInt32 BackupDate;
@ -1000,7 +1000,7 @@ HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents
item.CTime = Get32(r + 0xC); item.CTime = Get32(r + 0xC);
item.MTime = Get32(r + 0x10); item.MTime = Get32(r + 0x10);
// item.AttrMTime = Get32(r + 0x14); item.AttrMTime = Get32(r + 0x14);
item.ATime = Get32(r + 0x18); item.ATime = Get32(r + 0x18);
// item.BackupDate = Get32(r + 0x1C); // item.BackupDate = Get32(r + 0x1C);
@ -1404,6 +1404,7 @@ static const Byte kProps[] =
kpidCTime, kpidCTime,
kpidMTime, kpidMTime,
kpidATime, kpidATime,
kpidChangeTime,
kpidPosixAttrib kpidPosixAttrib
}; };
@ -1421,9 +1422,11 @@ IMP_IInArchive_ArcProps
static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop) static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
{ {
if (hfsTime == 0)
return;
FILETIME ft; FILETIME ft;
HfsTimeToFileTime(hfsTime, ft); HfsTimeToFileTime(hfsTime, ft);
prop = ft; prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
} }
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) 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 kpidMTime: HfsTimeToProp(Header.MTime, prop); break;
case kpidCTime: case kpidCTime:
{ {
FILETIME localFt, ft; if (Header.CTime != 0)
HfsTimeToFileTime(Header.CTime, localFt); {
if (LocalFileTimeToFileTime(&localFt, &ft)) FILETIME localFt, ft;
prop = ft; HfsTimeToFileTime(Header.CTime, localFt);
if (LocalFileTimeToFileTime(&localFt, &ft))
prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
}
break; break;
} }
case kpidIsTree: prop = true; 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 kpidCTime: HfsTimeToProp(item.CTime, prop); break;
case kpidMTime: HfsTimeToProp(item.MTime, prop); break; case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
case kpidATime: HfsTimeToProp(item.ATime, 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; case kpidPosixAttrib: if (ref.AttrIndex < 0) prop = (UInt32)item.FileMode; break;
} }

View file

@ -38,9 +38,11 @@ namespace NFileTimeType
{ {
enum EEnum enum EEnum
{ {
kWindows, kNotDefined = -1,
kWindows = 0,
kUnix, kUnix,
kDOS kDOS,
k1ns
}; };
} }
@ -60,8 +62,31 @@ namespace NArcInfoFlags
const UInt32 kHardLinks = 1 << 11; // the handler supports hard links const UInt32 kHardLinks = 1 << 11; // the handler supports hard links
const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches 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 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 NArchive
{ {
namespace NHandlerPropID namespace NHandlerPropID
@ -79,8 +104,8 @@ namespace NArchive
kSignatureOffset, // VT_UI4 kSignatureOffset, // VT_UI4
kAltStreams, // VT_BOOL kAltStreams, // VT_BOOL
kNtSecure, // VT_BOOL kNtSecure, // VT_BOOL
kFlags // VT_UI4 kFlags, // VT_UI4
// kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR) kTimeFlags // VT_UI4
}; };
} }
@ -123,6 +148,7 @@ namespace NArchive
kInArcIndex, kInArcIndex,
kBlockIndex, kBlockIndex,
kOutArcIndex kOutArcIndex
// kArcProp
}; };
} }
@ -133,7 +159,8 @@ namespace NArchive
enum enum
{ {
kOK = 0 kOK = 0
// , kError // kError = 1,
// kError_FileChanged
}; };
} }
} }
@ -461,9 +488,10 @@ namespace NUpdateNotifyOp
kSkip, kSkip,
kDelete, kDelete,
kHeader, kHeader,
kHashRead kHashRead,
kInFileChanged
// kNumDefined // , kOpFinished
// , kNumDefined
}; };
}; };
@ -492,6 +520,20 @@ ARCHIVE_INTERFACE(IArchiveGetDiskProperty, 0x84)
INTERFACE_IArchiveGetDiskProperty(PURE); 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() UpdateItems()
------------- -------------
@ -636,9 +678,40 @@ extern "C"
typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
typedef HRESULT (WINAPI *Func_SetLargePageMode)(); typedef HRESULT (WINAPI *Func_SetLargePageMode)();
// typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version);
typedef IOutArchive * (*Func_CreateOutArchive)(); typedef IOutArchive * (*Func_CreateOutArchive)();
typedef IInArchive * (*Func_CreateInArchive)(); 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 #endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -6,9 +6,6 @@
#include "../../../Common/MyLinux.h" #include "../../../Common/MyLinux.h"
#include "../../../Common/StringConvert.h" #include "../../../Common/StringConvert.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/TimeUtils.h"
#include "../../Common/LimitedStreams.h" #include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h" #include "../../Common/ProgressUtils.h"
@ -34,8 +31,8 @@ static const Byte kProps[] =
// kpidCTime, // kpidCTime,
// kpidATime, // kpidATime,
kpidPosixAttrib, kpidPosixAttrib,
// kpidUser, // kpidUserId,
// kpidGroup, // kpidGroupId,
// kpidLinks, // kpidLinks,
kpidSymLink kpidSymLink
}; };
@ -127,8 +124,8 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = s; prop = s;
break; break;
} }
case kpidCTime: { FILETIME utc; if (vol.CTime.GetFileTime(utc)) prop = utc; break; } case kpidCTime: { vol.CTime.GetFileTime(prop); break; }
case kpidMTime: { FILETIME utc; if (vol.MTime.GetFileTime(utc)) prop = utc; break; } case kpidMTime: { vol.MTime.GetFileTime(prop); break; }
} }
} }
@ -242,8 +239,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPosixAttrib: case kpidPosixAttrib:
/* /*
case kpidLinks: case kpidLinks:
case kpidUser: case kpidUserId:
case kpidGroup: case kpidGroupId:
*/ */
{ {
if (_archive.IsSusp) if (_archive.IsSusp)
@ -254,8 +251,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPosixAttrib: t = k_Px_Mode; break; case kpidPosixAttrib: t = k_Px_Mode; break;
/* /*
case kpidLinks: t = k_Px_Links; break; case kpidLinks: t = k_Px_Links; break;
case kpidUser: t = k_Px_User; break; case kpidUserId: t = k_Px_User; break;
case kpidGroup: t = k_Px_Group; break; case kpidGroupId: t = k_Px_Group; break;
*/ */
} }
UInt32 v; UInt32 v;
@ -276,9 +273,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
// case kpidCTime: // case kpidCTime:
// case kpidATime: // case kpidATime:
{ {
FILETIME utc; // if
if (/* propID == kpidMTime && */ item.DateTime.GetFileTime(utc)) item.DateTime.GetFileTime(prop);
prop = utc;
/* /*
else else
{ {

View file

@ -587,6 +587,8 @@ HRESULT CInArchive::Open2()
for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
if (VolDescs[MainVolDescIndex].IsJoliet()) if (VolDescs[MainVolDescIndex].IsJoliet())
break; 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 // MainVolDescIndex = 0; // to read primary volume
const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
if (vd.LogicalBlockSize != kBlockSize) if (vd.LogicalBlockSize != kBlockSize)

View file

@ -127,17 +127,18 @@ struct CDateTime
bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 && bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; } Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
bool GetFileTime(FILETIME &ft) const bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
{ {
UInt64 value; UInt64 v;
bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value); const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v);
if (res) if (res)
{ {
value -= (Int64)((Int32)GmtOffset * 15 * 60); v -= (Int64)((Int32)GmtOffset * 15 * 60);
value *= 10000000; 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; return res;
} }
}; };

View file

@ -25,17 +25,16 @@ struct CRecordingDateTime
Byte Second; Byte Second;
signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded. 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; UInt64 v;
bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, value); const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v);
if (res) if (res)
{ {
value -= (Int64)((Int32)GmtOffset * 15 * 60); v -= (Int64)((Int32)GmtOffset * 15 * 60);
value *= 10000000; v *= 10000000;
prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base);
} }
ft.dwLowDateTime = (DWORD)value;
ft.dwHighDateTime = (DWORD)(value >> 32);
return res; return res;
} }
}; };

File diff suppressed because it is too large Load diff

View file

@ -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 kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break;
case kpidMTime: case kpidMTime:
{ {
FILETIME utc;
UInt32 unixTime; UInt32 unixTime;
if (item.GetUnixTime(unixTime)) if (item.GetUnixTime(unixTime))
NTime::UnixTimeToFileTime(unixTime, utc); PropVariant_SetFrom_UnixTime(prop, unixTime);
else else
{ PropVariant_SetFrom_DosTime(prop, item.ModifiedTime);
FILETIME localFileTime;
if (DosTimeToFileTime(item.ModifiedTime, localFileTime))
{
if (!LocalFileTimeToFileTime(&localFileTime, &utc))
utc.dwHighDateTime = utc.dwLowDateTime = 0;
}
else
utc.dwHighDateTime = utc.dwLowDateTime = 0;
}
prop = utc;
break; break;
} }
// case kpidAttrib: prop = (UInt32)item.Attributes; break; // case kpidAttrib: prop = (UInt32)item.Attributes; break;

View file

@ -278,7 +278,7 @@ struct CSiAttr
{ {
UInt64 CTime; UInt64 CTime;
UInt64 MTime; UInt64 MTime;
// UInt64 ThisRecMTime; UInt64 ThisRecMTime;
UInt64 ATime; UInt64 ATime;
UInt32 Attrib; UInt32 Attrib;
@ -300,7 +300,7 @@ bool CSiAttr::Parse(const Byte *p, unsigned size)
return false; return false;
G64(p + 0x00, CTime); G64(p + 0x00, CTime);
G64(p + 0x08, MTime); G64(p + 0x08, MTime);
// G64(p + 0x10, ThisRecMTime); G64(p + 0x10, ThisRecMTime);
G64(p + 0x18, ATime); G64(p + 0x18, ATime);
G32(p + 0x20, Attrib); G32(p + 0x20, Attrib);
SecurityId = 0; SecurityId = 0;
@ -2301,6 +2301,7 @@ static const Byte kProps[] =
kpidMTime, kpidMTime,
kpidCTime, kpidCTime,
kpidATime, kpidATime,
kpidChangeTime,
kpidAttrib, kpidAttrib,
kpidLinks, kpidLinks,
kpidINode, kpidINode,
@ -2577,7 +2578,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break; case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break;
case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break; case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break;
case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, 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; case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break;

View file

@ -885,11 +885,7 @@ IMP_IInArchive_ArcProps_WITH_NAME
static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop) static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
{ {
if (unixTime != 0) if (unixTime != 0)
{ PropVariant_SetFrom_UnixTime(prop, unixTime);
FILETIME ft;
NTime::UnixTimeToFileTime(unixTime, ft);
prop = ft;
}
} }
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)

View file

@ -174,7 +174,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
{ {
// time can be in Unix format ??? // time can be in Unix format ???
FILETIME utc; FILETIME utc;
if (NTime::DosTimeToFileTime(_item.Time, utc)) if (NTime::DosTime_To_FileTime(_item.Time, utc))
prop = utc; prop = utc;
break; break;
} }

View file

@ -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) static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop)
{ {
unsigned size; unsigned size;
int offset = item.FindExtra(NExtraID::kTime, size); const int offset = item.FindExtra(NExtraID::kTime, size);
if (offset < 0) if (offset < 0)
return; return;
const Byte *p = item.Extra + (unsigned)offset; const Byte *p = item.Extra + (unsigned)offset;
UInt64 flags; UInt64 flags;
{ {
unsigned num = ReadVarInt(p, size, &flags); const unsigned num = ReadVarInt(p, size, &flags);
if (num == 0) if (num == 0)
return; return;
p += num; p += num;
@ -1610,8 +1610,8 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
unsigned numStamps = 0; unsigned numStamps = 0;
unsigned curStamp = 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 ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0)
{ {
if (i == stampIndex) if (i == stampIndex)
@ -1620,20 +1620,28 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
} }
FILETIME ft; FILETIME ft;
unsigned timePrec = 0;
unsigned ns100 = 0;
if ((flags & NTimeRecord::NFlags::kUnixTime) != 0) if ((flags & NTimeRecord::NFlags::kUnixTime) != 0)
{ {
curStamp *= 4; curStamp *= 4;
if (curStamp + 4 > size) if (curStamp + 4 > size)
return; return;
const Byte *p2 = p + curStamp; p += curStamp;
UInt64 val = NTime::UnixTimeToFileTime64(Get32(p2)); UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p));
numStamps *= 4; numStamps *= 4;
timePrec = k_PropVar_TimePrec_Unix;
if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size) 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) if (ns < 1000000000)
{
val += ns / 100; val += ns / 100;
ns100 = (unsigned)(ns % 100);
timePrec = k_PropVar_TimePrec_1ns;
}
} }
ft.dwLowDateTime = (DWORD)val; ft.dwLowDateTime = (DWORD)val;
ft.dwHighDateTime = (DWORD)(val >> 32); ft.dwHighDateTime = (DWORD)(val >> 32);
@ -1643,12 +1651,12 @@ static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CProp
curStamp *= 8; curStamp *= 8;
if (curStamp + 8 > size) if (curStamp + 8 > size)
return; return;
const Byte *p2 = p + curStamp; p += curStamp;
ft.dwLowDateTime = Get32(p2); ft.dwLowDateTime = Get32(p);
ft.dwHighDateTime = Get32(p2 + 4); 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); TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop);
if (prop.vt == VT_EMPTY && item.Has_UnixMTime()) if (prop.vt == VT_EMPTY && item.Has_UnixMTime())
{ PropVariant_SetFrom_UnixTime(prop, item.UnixMTime);
FILETIME ft;
NWindows::NTime::UnixTimeToFileTime(item.UnixMTime, ft);
prop = ft;
}
if (prop.vt == VT_EMPTY && ref.Parent >= 0) if (prop.vt == VT_EMPTY && ref.Parent >= 0)
{ {
const CItem &baseItem = _items[_refs[ref.Parent].Item]; const CItem &baseItem = _items[_refs[ref.Parent].Item];
TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop); TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop);
if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime()) if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime())
{ PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime);
FILETIME ft;
NWindows::NTime::UnixTimeToFileTime(baseItem.UnixMTime, ft);
prop = ft;
}
} }
break; break;
} }

View file

@ -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) static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime)
{ {
rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0); rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
unsigned numDigits = (mask & 3); const unsigned numDigits = (mask & 3);
rarTime.SubTime[0] = rarTime.SubTime[0] =
rarTime.SubTime[1] = rarTime.SubTime[1] =
rarTime.SubTime[2] = 0; rarTime.SubTime[2] = 0;
@ -405,8 +405,8 @@ bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
item.MTime.LowSecond = 0; item.MTime.LowSecond = 0;
item.MTime.SubTime[0] = item.MTime.SubTime[0] =
item.MTime.SubTime[1] = item.MTime.SubTime[1] =
item.MTime.SubTime[2] = 0; item.MTime.SubTime[2] = 0;
p += kFileHeaderSize; p += kFileHeaderSize;
size -= kFileHeaderSize; size -= kFileHeaderSize;
@ -941,31 +941,32 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK; 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; return false;
UInt64 value = (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime; UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
value += (UInt64)rarTime.LowSecond * 10000000; v += (UInt32)rarTime.LowSecond * 10000000;
value += ((UInt64)rarTime.SubTime[2] << 16) + v +=
((UInt64)rarTime.SubTime[1] << 8) + ((UInt32)rarTime.SubTime[2] << 16) +
((UInt64)rarTime.SubTime[0]); ((UInt32)rarTime.SubTime[1] << 8) +
result.dwLowDateTime = (DWORD)value; ((UInt32)rarTime.SubTime[0]);
result.dwHighDateTime = DWORD(value >> 32); ft.dwLowDateTime = (DWORD)v;
ft.dwHighDateTime = (DWORD)(v >> 32);
return true; return true;
} }
static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop) static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop)
{ {
FILETIME localFileTime, utcFileTime; FILETIME localFileTime, utc;
if (RarTimeToFileTime(rarTime, localFileTime)) if (RarTimeToFileTime(rarTime, localFileTime)
{ && LocalFileTimeToFileTime(&localFileTime, &utc))
if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; /*
}
else else
utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; utc.dwHighDateTime = utc.dwLowDateTime = 0;
prop = utcFileTime; // prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
*/
} }
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)

View file

@ -52,7 +52,7 @@ public:
ext.IsEqualTo_Ascii_NoCase("r01")) ext.IsEqualTo_Ascii_NoCase("r01"))
{ {
_changed = ext; _changed = ext;
_before = name.Left(dotPos + 1); _before.SetFrom(name.Ptr(), dotPos + 1);
return true; return true;
} }
} }
@ -60,16 +60,23 @@ public:
if (newStyle) 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--) for (; i != 0; i--)
if (!IsDigit(base[i - 1])) if (!IsDigit(base[i - 1]))
break; break;
if (i != base.Len()) if (i != k)
{ {
_before = base.Left(i); _before.SetFrom(base.Ptr(), i);
_changed = base.Ptr(i); _changed.SetFrom(base.Ptr(i), k - i);
_after.Insert(0, base.Ptr(k));
return true; return true;
} }
} }

View file

@ -215,11 +215,7 @@ class CHandler: public CHandlerCont
void SetTime(NCOM::CPropVariant &prop) const void SetTime(NCOM::CPropVariant &prop) const
{ {
if (_time_Defined && _buildTime != 0) if (_time_Defined && _buildTime != 0)
{ PropVariant_SetFrom_UnixTime(prop, _buildTime);
FILETIME ft;
NTime::UnixTimeToFileTime(_buildTime, ft);
prop = ft;
}
} }
void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const

View 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)
}}

View file

@ -162,7 +162,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
numLetters++; 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()) while (numLetters < ext2.Len())
{ {
@ -170,7 +173,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
break; break;
numLetters++; numLetters++;
} }
if (numLetters != ext.Len()) if (numLetters != ext2.Len())
return S_FALSE; return S_FALSE;
} }
else else

View file

@ -76,7 +76,7 @@ static const char * const k_Methods[] =
, "XZ" , "XZ"
}; };
static const UInt32 kMetadataBlockSizeLog = 13; static const unsigned kMetadataBlockSizeLog = 13;
static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog); static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
enum 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) UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
{ {
bool be = _h.be; const bool be = _h.be;
if (size < 4) if (size < 4)
return 0; 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) UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h)
{ {
bool be = _h.be; const bool be = _h.be;
if (size < 12) if (size < 12)
return 0; return 0;
@ -843,8 +843,8 @@ class CHandler:
CData _inodesData; CData _inodesData;
CData _dirs; CData _dirs;
CRecordVector<CFrag> _frags; CRecordVector<CFrag> _frags;
// CByteBuffer _uids; CByteBuffer _uids;
// CByteBuffer _gids; CByteBuffer _gids;
CHeader _h; CHeader _h;
bool _noPropsLZMA; bool _noPropsLZMA;
bool _needCheckLzma; bool _needCheckLzma;
@ -891,14 +891,20 @@ class CHandler:
_cachedUnpackBlockSize = 0; _cachedUnpackBlockSize = 0;
} }
HRESULT Seek2(UInt64 offset)
{
return _stream->Seek(offset, STREAM_SEEK_SET, NULL);
}
HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize,
UInt32 inSize, UInt32 outSizeMax); UInt32 inSize, UInt32 outSizeMax);
HRESULT ReadMetadataBlock(UInt32 &packSize); HRESULT ReadMetadataBlock(UInt32 &packSize);
HRESULT ReadMetadataBlock2();
HRESULT ReadData(CData &data, UInt64 start, UInt64 end); HRESULT ReadData(CData &data, UInt64 start, UInt64 end);
HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex); HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex);
HRESULT ScanInodes(UInt64 ptr); HRESULT ScanInodes(UInt64 ptr);
// HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids); HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
HRESULT Open2(IInStream *inStream); HRESULT Open2(IInStream *inStream);
AString GetPath(int index) const; AString GetPath(int index) const;
bool GetPackSize(int index, UInt64 &res, bool fillOffsets); bool GetPackSize(int index, UInt64 &res, bool fillOffsets);
@ -938,9 +944,9 @@ static const Byte kProps[] =
kpidSize, kpidSize,
kpidPackSize, kpidPackSize,
kpidMTime, kpidMTime,
kpidPosixAttrib kpidPosixAttrib,
// kpidUser, kpidUserId,
// kpidGroup, kpidGroupId
// kpidLinks, // kpidLinks,
// kpidOffset // kpidOffset
}; };
@ -1280,14 +1286,14 @@ HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool
HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize) HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
{ {
Byte temp[3]; Byte temp[3];
unsigned offset = _h.NeedCheckData() ? 3 : 2; const unsigned offset = _h.NeedCheckData() ? 3 : 2;
if (offset > packSize) if (offset > packSize)
return S_FALSE; return S_FALSE;
RINOK(ReadStream_FALSE(_stream, temp, offset)); RINOK(ReadStream_FALSE(_stream, temp, offset));
// if (NeedCheckData && Major < 4) checkByte must be = 0xFF // if (NeedCheckData && Major < 4) checkByte must be = 0xFF
bool be = _h.be; const bool be = _h.be;
UInt32 size = Get16(temp); UInt32 size = Get16(temp);
bool isCompressed = ((size & kNotCompressedBit16) == 0); const bool isCompressed = ((size & kNotCompressedBit16) == 0);
if (size != kNotCompressedBit16) if (size != kNotCompressedBit16)
size &= ~kNotCompressedBit16; size &= ~kNotCompressedBit16;
@ -1311,12 +1317,20 @@ HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
return S_OK; 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) HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end)
{ {
if (end < start || end - start >= ((UInt64)1 << 32)) if (end < start || end - start >= ((UInt64)1 << 32))
return S_FALSE; return S_FALSE;
const UInt32 size = (UInt32)(end - start); const UInt32 size = (UInt32)(end - start);
RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); RINOK(Seek2(start));
_dynOutStreamSpec->Init(); _dynOutStreamSpec->Init();
UInt32 packPos = 0; UInt32 packPos = 0;
while (packPos != size) while (packPos != size)
@ -1395,7 +1409,7 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
CRecordVector<CTempItem> tempItems; CRecordVector<CTempItem> tempItems;
while (rem != 0) while (rem != 0)
{ {
bool be = _h.be; const bool be = _h.be;
UInt32 count; UInt32 count;
CTempItem tempItem; CTempItem tempItem;
if (_h.Major <= 2) if (_h.Major <= 2)
@ -1519,15 +1533,15 @@ HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned
return S_OK; return S_OK;
} }
/*
HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids) HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids)
{ {
size_t size = num * 4; const size_t size = (size_t)num * 4;
ids.SetCapacity(size); ids.Alloc(size);
RINOK(_stream->Seek(start, STREAM_SEEK_SET, NULL)); if (num == 0)
return S_OK;
RINOK(Seek2(start));
return ReadStream_FALSE(_stream, ids, size); return ReadStream_FALSE(_stream, ids, size);
} }
*/
HRESULT CHandler::Open2(IInStream *inStream) HRESULT CHandler::Open2(IInStream *inStream)
{ {
@ -1560,24 +1574,22 @@ HRESULT CHandler::Open2(IInStream *inStream)
if (_h.NumFrags > kNumFilesMax) if (_h.NumFrags > kNumFilesMax)
return S_FALSE; return S_FALSE;
_frags.ClearAndReserve(_h.NumFrags); _frags.ClearAndReserve(_h.NumFrags);
unsigned bigFrag = (_h.Major > 2); const unsigned bigFrag = (_h.Major > 2);
unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag); const unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag);
UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog; const UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog;
size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag); const size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag);
CByteBuffer data(numBlocksBytes); CByteBuffer data(numBlocksBytes);
RINOK(inStream->Seek(_h.FragTable, STREAM_SEEK_SET, NULL)); RINOK(Seek2(_h.FragTable));
RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
bool be = _h.be; const bool be = _h.be;
for (UInt32 i = 0; i < numBlocks; i++) for (UInt32 i = 0; i < numBlocks; i++)
{ {
UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4); const UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4);
RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); RINOK(Seek2(offset));
_dynOutStreamSpec->Init(); RINOK(ReadMetadataBlock2());
UInt32 packSize = kMetadataBlockSize + 3; const UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
RINOK(ReadMetadataBlock(packSize));
UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
if (unpackSize != kMetadataBlockSize) if (unpackSize != kMetadataBlockSize)
if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1))) if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1)))
return S_FALSE; return S_FALSE;
@ -1605,8 +1617,6 @@ HRESULT CHandler::Open2(IInStream *inStream)
return S_FALSE; return S_FALSE;
} }
// RINOK(inStream->Seek(_h.InodeTable, STREAM_SEEK_SET, NULL));
RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable)); RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable));
RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable)); RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable));
@ -1655,7 +1665,6 @@ HRESULT CHandler::Open2(IInStream *inStream)
int rootNodeIndex; int rootNodeIndex;
RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex)); RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex));
/*
if (_h.Major < 4) if (_h.Major < 4)
{ {
RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids)); RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids));
@ -1663,33 +1672,34 @@ HRESULT CHandler::Open2(IInStream *inStream)
} }
else else
{ {
UInt32 size = _h.NumIDs * 4; const UInt32 size = (UInt32)_h.NumIDs * 4;
_uids.SetCapacity(size); _uids.Alloc(size);
UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize; const UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
UInt32 numBlocksBytes = numBlocks << 3; const UInt32 numBlocksBytes = numBlocks << 3;
CByteBuffer data; CByteBuffer data;
data.SetCapacity(numBlocksBytes); data.Alloc(numBlocksBytes);
RINOK(inStream->Seek(_h.UidTable, STREAM_SEEK_SET, NULL)); RINOK(Seek2(_h.UidTable));
RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes)); RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes));
for (UInt32 i = 0; i < numBlocks; i++) for (UInt32 i = 0; i < numBlocks; i++)
{ {
UInt64 offset = GetUi64(data + i * 8); const UInt64 offset = GetUi64(data + i * 8);
UInt32 unpackSize, packSize; RINOK(Seek2(offset));
RINOK(_stream->Seek(offset, STREAM_SEEK_SET, NULL)); // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize)); RINOK(ReadMetadataBlock2());
const size_t unpackSize = _dynOutStreamSpec->GetSize();
if (unpackSize != kMetadataBlockSize) if (unpackSize != kMetadataBlockSize)
if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1))) if (i != numBlocks - 1 || unpackSize != (size & (kMetadataBlockSize - 1)))
return S_FALSE; return S_FALSE;
memcpy(_uids + kMetadataBlockSize * i, _dynOutStreamSpec->GetBuffer(), unpackSize);
} }
} }
*/
{ {
const UInt32 alignSize = 1 << 12; const UInt32 alignSize = 1 << 12;
Byte buf[alignSize]; Byte buf[alignSize];
RINOK(inStream->Seek(_h.Size, STREAM_SEEK_SET, NULL)); RINOK(Seek2(_h.Size));
UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1); UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1);
_sizeCalculated = _h.Size; _sizeCalculated = _h.Size;
if (rem != 0) if (rem != 0)
@ -1710,7 +1720,7 @@ AString CHandler::GetPath(int index) const
{ {
unsigned len = 0; unsigned len = 0;
int indexMem = index; int indexMem = index;
bool be = _h.be; const bool be = _h.be;
do do
{ {
const CItem &item = _items[index]; const CItem &item = _items[index];
@ -1804,9 +1814,9 @@ bool CHandler::GetPackSize(int index, UInt64 &totalPack, bool fillOffsets)
totalPack = 0; totalPack = 0;
const CItem &item = _items[index]; const CItem &item = _items[index];
const CNode &node = _nodes[item.Node]; const CNode &node = _nodes[item.Node];
UInt32 ptr = _nodesPos[item.Node]; const UInt32 ptr = _nodesPos[item.Node];
const Byte *p = _inodesData.Data + ptr; const Byte *p = _inodesData.Data + ptr;
bool be = _h.be; const bool be = _h.be;
UInt32 type = node.Type; UInt32 type = node.Type;
UInt32 offset; UInt32 offset;
@ -1936,11 +1946,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidBigEndian: prop = _h.be; break; case kpidBigEndian: prop = _h.be; break;
case kpidCTime: case kpidCTime:
if (_h.CTime != 0) if (_h.CTime != 0)
{ PropVariant_SetFrom_UnixTime(prop, _h.CTime);
FILETIME ft;
NWindows::NTime::UnixTimeToFileTime(_h.CTime, ft);
prop = ft;
}
break; break;
case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break; case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
// case kpidNumBlocks: prop = _h.NumFrags; break; // case kpidNumBlocks: prop = _h.NumFrags; break;
@ -1979,8 +1985,8 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
NWindows::NCOM::CPropVariant prop; NWindows::NCOM::CPropVariant prop;
const CItem &item = _items[index]; const CItem &item = _items[index];
const CNode &node = _nodes[item.Node]; const CNode &node = _nodes[item.Node];
bool isDir = node.IsDir(); const bool isDir = node.IsDir();
bool be = _h.be; const bool be = _h.be;
switch (propID) switch (propID)
{ {
@ -2031,9 +2037,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
if (offset != 0) if (offset != 0)
{ {
const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset; const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset;
FILETIME ft; PropVariant_SetFrom_UnixTime(prop, Get32(p));
NWindows::NTime::UnixTimeToFileTime(Get32(p), ft);
prop = ft;
} }
break; break;
} }
@ -2043,31 +2047,38 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type]; prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
break; break;
} }
/* case kpidUserId:
case kpidUser:
{ {
UInt32 offset = node.Uid * 4; const UInt32 offset = (UInt32)node.Uid * 4;
if (offset < _uids.Size()) if (offset < _uids.Size())
prop = (UInt32)Get32(_uids + offset); prop = (UInt32)Get32(_uids + offset);
break; break;
} }
case kpidGroup: case kpidGroupId:
{ {
if (_h.Major == 4 || node.Gid == _h.GetSpecGuidIndex()) if (_h.Major < 4)
{ {
UInt32 offset = node.Uid * 4; if (node.Gid == _h.GetSpecGuidIndex())
if (offset < _uids.Size()) {
prop = (UInt32)Get32(_uids + offset); 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 else
{ {
UInt32 offset = node.Gid * 4; const UInt32 offset = (UInt32)node.Gid * 4;
if (offset < _gids.Size()) if (offset < _uids.Size())
prop = (UInt32)Get32(_gids + offset); prop = (UInt32)Get32(_uids + offset);
} }
break; break;
} }
*/
/* /*
case kpidLinks: case kpidLinks:
if (_h.Major >= 3 && node.Type != kType_FILE) if (_h.Major >= 3 && node.Type != kType_FILE)
@ -2128,7 +2139,7 @@ HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
packBlockSize != _cachedPackBlockSize) packBlockSize != _cachedPackBlockSize)
{ {
ClearCache(); ClearCache();
RINOK(_stream->Seek(blockOffset, STREAM_SEEK_SET, NULL)); RINOK(Seek2(blockOffset));
_limitedInStreamSpec->Init(packBlockSize); _limitedInStreamSpec->Init(packBlockSize);
if (compressed) if (compressed)

View file

@ -36,22 +36,34 @@ static const Byte kProps[] =
kpidSize, kpidSize,
kpidPackSize, kpidPackSize,
kpidMTime, kpidMTime,
kpidCTime,
kpidATime,
kpidPosixAttrib, kpidPosixAttrib,
kpidUser, kpidUser,
kpidGroup, kpidGroup,
kpidUserId,
kpidGroupId,
kpidSymLink, kpidSymLink,
kpidHardLink, kpidHardLink,
kpidCharacts kpidCharacts,
// kpidLinkType kpidComment
, kpidDeviceMajor
, kpidDeviceMinor
// , kpidDevice
// , kpidHeadersSize // for debug
// , kpidOffset // for debug
}; };
static const Byte kArcProps[] = static const Byte kArcProps[] =
{ {
kpidHeadersSize, kpidHeadersSize,
kpidCodePage, kpidCodePage,
kpidCharacts kpidCharacts,
kpidComment
}; };
static const char *k_Characts_Prefix = "PREFIX";
IMP_IInArchive_Props IMP_IInArchive_Props
IMP_IInArchive_ArcProps IMP_IInArchive_ArcProps
@ -60,14 +72,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
NCOM::CPropVariant prop; NCOM::CPropVariant prop;
switch (propID) switch (propID)
{ {
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break;
case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break;
case kpidErrorFlags: case kpidErrorFlags:
{ {
UInt32 flags = 0; UInt32 flags = 0;
if (!_isArc) if (!_isArc)
flags |= kpv_ErrorFlags_IsNotArc; flags |= kpv_ErrorFlags_IsNotArc;
else switch (_error) else switch (_arc._error)
{ {
case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
@ -82,7 +94,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidWarningFlags: case kpidWarningFlags:
{ {
if (_warning) if (_arc._is_Warning)
prop = kpv_ErrorFlags_HeadersError; prop = kpv_ErrorFlags_HeadersError;
break; break;
} }
@ -107,7 +119,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidCharacts: 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; break;
} }
} }
@ -115,32 +154,6 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
return S_OK; 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) 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)); RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
} }
_phySizeDefined = true; _arc._phySize_Defined = true;
// bool utf8_OK = true; // bool utf8_OK = true;
_arc.SeqStream = stream;
_arc.InStream = stream;
_arc.OpenCallback = callback;
CItemEx item;
for (;;) for (;;)
{ {
CItemEx item; _arc.NumFiles = _items.Size();
bool filled; RINOK(_arc.ReadItem(item));
RINOK(ReadItem2(stream, filled, item)); if (!_arc.filled)
if (!filled)
break; break;
_isArc = true; _isArc = true;
@ -228,10 +245,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
_items.Add(item); _items.Add(item);
RINOK(stream->Seek((Int64)item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize));
if (_phySize > endPos) if (_arc._phySize > endPos)
{ {
_error = k_ErrorType_UnexpectedEnd; _arc._error = k_ErrorType_UnexpectedEnd;
break; break;
} }
/* /*
@ -241,6 +258,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
break; break;
} }
*/ */
/*
if (callback) if (callback)
{ {
if (_items.Size() == 1) if (_items.Size() == 1)
@ -249,10 +267,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
} }
if ((_items.Size() & 0x3FF) == 0) if ((_items.Size() & 0x3FF) == 0)
{ {
UInt64 numFiles = _items.Size(); const UInt64 numFiles = _items.Size();
RINOK(callback->SetCompleted(&numFiles, &_phySize)); RINOK(callback->SetCompleted(&numFiles, &_phySize));
} }
} }
*/
} }
/* /*
@ -266,7 +285,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
if (_items.Size() == 0) if (_items.Size() == 0)
{ {
if (_error != k_ErrorType_OK) if (_arc._error != k_ErrorType_OK)
{ {
_isArc = false; _isArc = false;
return S_FALSE; return S_FALSE;
@ -294,6 +313,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback) STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
// for (int i = 0; i < 10; i++) // for debug
{ {
Close(); Close();
RINOK(Open2(stream, openArchiveCallback)); RINOK(Open2(stream, openArchiveCallback));
@ -314,16 +334,11 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close() STDMETHODIMP CHandler::Close()
{ {
_isArc = false; _isArc = false;
_warning = false;
_error = k_ErrorType_OK;
_phySizeDefined = false; _arc.Clear();
_phySize = 0;
_headersSize = 0;
_curIndex = 0; _curIndex = 0;
_latestIsRead = false; _latestIsRead = false;
// _isSparse = false;
_thereIsPaxExtendedHeader = false;
_encodingCharacts.Clear(); _encodingCharacts.Clear();
_items.Clear(); _items.Clear();
_seqStream.Release(); _seqStream.Release();
@ -351,12 +366,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
{ {
if (_latestIsRead) if (_latestIsRead)
{ {
UInt64 packSize = _latestItem.GetPackSizeAligned(); const UInt64 packSize = _latestItem.Get_PackSize_Aligned();
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
_phySize += copyCoderSpec->TotalSize; _arc._phySize += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != packSize) if (copyCoderSpec->TotalSize != packSize)
{ {
_error = k_ErrorType_UnexpectedEnd; _arc._error = k_ErrorType_UnexpectedEnd;
return S_FALSE; return S_FALSE;
} }
_latestIsRead = false; _latestIsRead = false;
@ -364,11 +379,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
} }
else else
{ {
bool filled; _arc.SeqStream = _seqStream;
RINOK(ReadItem2(_seqStream, filled, _latestItem)); _arc.InStream = NULL;
if (!filled) RINOK(_arc.ReadItem(_latestItem));
if (!_arc.filled)
{ {
_phySizeDefined = true; _arc._phySize_Defined = true;
return E_INVALIDARG; return E_INVALIDARG;
} }
_latestIsRead = true; _latestIsRead = true;
@ -390,6 +406,69 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant
prop = dest; 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) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{ {
COM_TRY_BEGIN 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 kpidPath: TarStringToUnicode(item->Name, prop, true); break;
case kpidIsDir: prop = item->IsDir(); break; case kpidIsDir: prop = item->IsDir(); break;
case kpidSize: prop = item->GetUnpackSize(); break; case kpidSize: prop = item->Get_UnpackSize(); break;
case kpidPackSize: prop = item->GetPackSizeAligned(); break; case kpidPackSize: prop = item->Get_PackSize_Aligned(); break;
case kpidMTime: 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(); // we allow (item->MTime == 0)
s += "HEADER_ERROR"; 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; 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); prop.Detach(value);
return S_OK; return S_OK;
COM_TRY_END COM_TRY_END
} }
HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback) Int32 testMode, IArchiveExtractCallback *extractCallback)
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
ISequentialInStream *stream = _seqStream; ISequentialInStream *stream = _seqStream;
bool seqMode = (_stream == NULL); const bool seqMode = (_stream == NULL);
if (!seqMode) if (!seqMode)
stream = _stream; stream = _stream;
bool allFilesMode = (numItems == (UInt32)(Int32)-1); const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode) if (allFilesMode)
numItems = _items.Size(); numItems = _items.Size();
if (_stream && numItems == 0) if (_stream && numItems == 0)
@ -463,7 +682,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalSize = 0; UInt64 totalSize = 0;
UInt32 i; UInt32 i;
for (i = 0; i < numItems; 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); extractCallback->SetTotal(totalSize);
UInt64 totalPackSize; UInt64 totalPackSize;
@ -503,9 +722,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
item = &_items[index]; item = &_items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
UInt64 unpackSize = item->GetUnpackSize(); const UInt64 unpackSize = item->Get_UnpackSize();
totalSize += unpackSize; totalSize += unpackSize;
totalPackSize += item->GetPackSizeAligned(); totalPackSize += item->Get_PackSize_Aligned();
if (item->IsDir()) if (item->IsDir())
{ {
RINOK(extractCallback->PrepareOperation(askMode)); RINOK(extractCallback->PrepareOperation(askMode));
@ -539,7 +758,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 opRes = NExtract::NOperationResult::kOK; Int32 opRes = NExtract::NOperationResult::kOK;
CMyComPtr<ISequentialInStream> inStream2; CMyComPtr<ISequentialInStream> inStream2;
if (!item->IsSparse()) if (!item->Is_Sparse())
inStream2 = inStream; inStream2 = inStream;
else 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())); RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
} }
@ -557,9 +776,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{ {
if (!seqMode) 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)); RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress));
} }
if (outStreamSpec->GetRem() != 0) if (outStreamSpec->GetRem() != 0)
@ -628,7 +847,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
unsigned left = 0, right = item.SparseBlocks.Size(); unsigned left = 0, right = item.SparseBlocks.Size();
for (;;) for (;;)
{ {
unsigned mid = (left + right) / 2; const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
if (mid == left) if (mid == left)
break; break;
if (_virtPos < item.SparseBlocks[mid].Offset) if (_virtPos < item.SparseBlocks[mid].Offset)
@ -648,7 +867,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
UInt64 phyPos = PhyOffsets[left] + relat; UInt64 phyPos = PhyOffsets[left] + relat;
if (_needStartSeek || _phyPos != phyPos) 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; _needStartSeek = false;
_phyPos = phyPos; _phyPos = phyPos;
} }
@ -698,7 +917,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
const CItemEx &item = _items[index]; const CItemEx &item = _items[index];
if (item.IsSparse()) if (item.Is_Sparse())
{ {
CSparseStream *streamSpec = new CSparseStream; CSparseStream *streamSpec = new CSparseStream;
CMyComPtr<IInStream> streamTemp = streamSpec; CMyComPtr<IInStream> streamTemp = streamSpec;
@ -718,24 +937,30 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
return S_OK; 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); Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream);
return S_OK; return S_OK;
} }
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream);
COM_TRY_END COM_TRY_END
} }
void CHandler::Init() void CHandler::Init()
{ {
_forceCodePage = false; _forceCodePage = false;
_curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; _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) STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{ {
Init(); 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.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 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 E_INVALIDARG;
}
} }
return S_OK; return S_OK;
} }

View file

@ -9,7 +9,7 @@
#include "../../Compress/CopyCoder.h" #include "../../Compress/CopyCoder.h"
#include "../IArchive.h" #include "../Common/HandlerOut.h"
#include "TarIn.h" #include "TarIn.h"
@ -29,31 +29,26 @@ public:
CMyComPtr<IInStream> _stream; CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream; CMyComPtr<ISequentialInStream> _seqStream;
private: private:
UInt32 _curIndex;
bool _latestIsRead;
CItemEx _latestItem;
UInt64 _phySize;
UInt64 _headersSize;
bool _phySizeDefined;
EErrorType _error;
bool _warning;
bool _isArc; bool _isArc;
bool _posixMode_WasForced;
// bool _isSparse; bool _posixMode;
bool _thereIsPaxExtendedHeader;
bool _forceCodePage; bool _forceCodePage;
UInt32 _specifiedCodePage; UInt32 _specifiedCodePage;
UInt32 _curCodePage; UInt32 _curCodePage;
UInt32 _openCodePage; UInt32 _openCodePage;
// CTimeOptions TimeOptions;
CHandlerTimeOptions _handlerTimeOptions;
CEncodingCharacts _encodingCharacts; CEncodingCharacts _encodingCharacts;
UInt32 _curIndex;
bool _latestIsRead;
CItemEx _latestItem;
CArchive _arc;
NCompress::CCopyCoder *copyCoderSpec; NCompress::CCopyCoder *copyCoderSpec;
CMyComPtr<ICompressCoder> copyCoder; CMyComPtr<ICompressCoder> copyCoder;
HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback); HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
HRESULT SkipTo(UInt32 index); HRESULT SkipTo(UInt32 index);
void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const; void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const;

View file

@ -2,15 +2,16 @@
#include "StdAfx.h" #include "StdAfx.h"
// #include <stdio.h>
#include "../../../Common/ComTry.h" #include "../../../Common/ComTry.h"
#include "../../../Common/Defs.h"
#include "../../../Common/MyLinux.h" #include "../../../Common/MyLinux.h"
#include "../../../Common/StringConvert.h" #include "../../../Common/StringConvert.h"
#include "../../../Common/UTFConvert.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/TimeUtils.h" #include "../../../Windows/TimeUtils.h"
#include "../Common/ItemNameUtils.h"
#include "TarHandler.h" #include "TarHandler.h"
#include "TarUpdate.h" #include "TarUpdate.h"
@ -21,10 +22,35 @@ namespace NTar {
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) 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; 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, HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
UINT codePage, unsigned utfFlags, bool convertSlash) UINT codePage, unsigned utfFlags, bool convertSlash)
{ {
@ -36,14 +62,7 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro
UString s = prop.bstrVal; UString s = prop.bstrVal;
if (convertSlash) if (convertSlash)
NItemName::ReplaceSlashes_OsToUnix(s); NItemName::ReplaceSlashes_OsToUnix(s);
Get_AString_From_UString(s, res, codePage, utfFlags);
if (codePage == CP_UTF8)
{
ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
// if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG;
}
else
UnicodeStringToMultiByte2(res, s, codePage);
} }
else if (prop.vt != VT_EMPTY) else if (prop.vt != VT_EMPTY)
return E_INVALIDARG; 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, STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *callback) IArchiveUpdateCallback *callback)
{ {
COM_TRY_BEGIN 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; return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems; CObjectVector<CUpdateItem> updateItems;
const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage); const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
@ -131,25 +244,30 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else else
ui.Mode = prop.ulVal; ui.Mode = prop.ulVal;
// 21.07 : we clear high file type bits as GNU TAR. // 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;
} }
{ if (_handlerTimeOptions.Write_MTime.Val)
NCOM::CPropVariant prop; RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime))
RINOK(callback->GetProperty(i, kpidMTime, &prop)); if (_handlerTimeOptions.Write_ATime.Val)
if (prop.vt == VT_EMPTY) RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime))
ui.MTime = 0; if (_handlerTimeOptions.Write_CTime.Val)
else if (prop.vt != VT_FILETIME) RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime))
return E_INVALIDARG;
else
ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
}
RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true)); RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true));
if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/') if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
ui.Name += '/'; ui.Name += '/';
RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage, utfFlags, false)); // ui.Name += '/'; // for debug
RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage, utfFlags, false));
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)) if (IntToBool(newData))
@ -169,13 +287,44 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
updateItems.Add(ui); 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); updateItems.Sort(CompareUpdateItems, NULL);
} }
CUpdateOptions options;
options.CodePage = codePage;
options.UtfFlags = utfFlags;
options.PosixMode = _posixMode;
return UpdateArchive(_stream, outStream, _items, updateItems, codePage, utfFlags, callback); 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 COM_TRY_END
} }

View file

@ -18,9 +18,82 @@ namespace NFileHeader {
// const char * const kGNUTar = "GNUtar "; // 7 chars and a null // const char * const kGNUTar = "GNUtar "; // 7 chars and a null
// const char * const kEmpty = "\0\0\0\0\0\0\0\0"; // const char * const kEmpty = "\0\0\0\0\0\0\0\0";
// 7-Zip used kUsTar_00 before 21.07: // 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: // 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); }
*/
}}} }}}

View file

@ -59,6 +59,9 @@ namespace NFileHeader
const char kGnu_LongName = 'L'; const char kGnu_LongName = 'L';
const char kSparse = 'S'; const char kSparse = 'S';
const char kLabel = 'V'; 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. const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
data: list of files created by the --incremental (-G) option data: list of files created by the --incremental (-G) option
Each file name is preceded by either 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.) - 'N' (file is a directory, or is not stored in the archive.)
Each file name is terminated by a null + an additional null after Each file name is terminated by a null + an additional null after
the last file name. */ the last file name. */
// 'A'-'Z' Vendor specific extensions (POSIX.1-1988)
} }
extern const char * const kLongLink; // = "././@LongLink"; extern const char * const kLongLink; // = "././@LongLink";
@ -76,8 +80,8 @@ namespace NFileHeader
// extern const char * const kUsTar; // = "ustar"; // 5 chars // extern const char * const kUsTar; // = "ustar"; // 5 chars
// extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null // 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 * const kEmpty; // = "\0\0\0\0\0\0\0\0"
// extern const char kUsTar_00[8]; extern const char k_Posix_ustar_00[8];
extern const char kUsTar_GNU[8]; extern const char k_GNU_ustar__[8];
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
#ifndef __ARCHIVE_TAR_IN_H #ifndef __ARCHIVE_TAR_IN_H
#define __ARCHIVE_TAR_IN_H #define __ARCHIVE_TAR_IN_H
#include "../../IStream.h" #include "../IArchive.h"
#include "TarItem.h" #include "TarItem.h"
@ -14,11 +14,133 @@ enum EErrorType
{ {
k_ErrorType_OK, k_ErrorType_OK,
k_ErrorType_Corrupted, k_ErrorType_Corrupted,
k_ErrorType_UnexpectedEnd, k_ErrorType_UnexpectedEnd
k_ErrorType_Warning // , 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); API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);

View file

@ -6,8 +6,6 @@
#include "../../../Common/MyLinux.h" #include "../../../Common/MyLinux.h"
#include "../../../Common/UTFConvert.h" #include "../../../Common/UTFConvert.h"
#include "../Common/ItemNameUtils.h"
#include "TarHeader.h" #include "TarHeader.h"
namespace NArchive { namespace NArchive {
@ -19,50 +17,149 @@ struct CSparseBlock
UInt64 Size; 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 struct CItem
{ {
AString Name;
UInt64 PackSize; UInt64 PackSize;
UInt64 Size; UInt64 Size;
Int64 MTime; Int64 MTime;
char LinkFlag;
bool DeviceMajor_Defined;
bool DeviceMinor_Defined;
UInt32 Mode; UInt32 Mode;
UInt32 UID; UInt32 UID;
UInt32 GID; UInt32 GID;
UInt32 DeviceMajor; UInt32 DeviceMajor;
UInt32 DeviceMinor; UInt32 DeviceMinor;
AString Name;
AString LinkName; AString LinkName;
AString User; AString User;
AString Group; AString Group;
char Magic[8]; char Magic[8];
char LinkFlag;
bool DeviceMajorDefined; CPaxTimes PaxTimes;
bool DeviceMinorDefined;
CRecordVector<CSparseBlock> SparseBlocks; CRecordVector<CSparseBlock> SparseBlocks;
void SetDefaultWriteFields() void SetMagic_Posix(bool posixMode)
{ {
DeviceMajorDefined = false; memcpy(Magic, posixMode ?
DeviceMinorDefined = false; NFileHeader::NMagic::k_Posix_ustar_00 :
UID = 0; NFileHeader::NMagic::k_GNU_ustar__,
GID = 0; 8);
memcpy(Magic, NFileHeader::NMagic::kUsTar_GNU, 8);
} }
bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); } bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; } bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; } bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; }
bool IsPaxExtendedHeader() const UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; }
bool Is_PaxExtendedHeader() const
{ {
switch (LinkFlag) switch (LinkFlag)
{ {
case 'g': case NFileHeader::NLinkFlag::kPax:
case 'x': case NFileHeader::NLinkFlag::kPax_2:
case 'X': // Check it case NFileHeader::NLinkFlag::kGlobal:
return true; return true;
} }
return false; return false;
@ -72,6 +169,17 @@ struct CItem
{ {
return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag(); 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 UInt32 Get_FileTypeMode_from_LinkFlag() const
{ {
@ -82,10 +190,10 @@ struct CItem
case NFileHeader::NLinkFlag::kDumpDir: case NFileHeader::NLinkFlag::kDumpDir:
return MY_LIN_S_IFDIR; return MY_LIN_S_IFDIR;
*/ */
case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK; case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK; case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR; case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO; case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
// case return MY_LIN_S_IFSOCK; // case return MY_LIN_S_IFSOCK;
} }
@ -104,20 +212,41 @@ struct CItem
case NFileHeader::NLinkFlag::kOldNormal: case NFileHeader::NLinkFlag::kOldNormal:
case NFileHeader::NLinkFlag::kNormal: case NFileHeader::NLinkFlag::kNormal:
case NFileHeader::NLinkFlag::kSymLink: 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; return false;
} }
bool IsUstarMagic() const bool IsMagic_ustar_5chars() const
{ {
for (int i = 0; i < 5; i++) for (unsigned i = 0; i < 5; i++)
if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i]) if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
return false; return false;
return true; 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 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 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; UInt64 HeaderPos;
unsigned HeaderSize; UInt64 HeaderSize;
bool NameCouldBeReduced;
bool LinkNameCouldBeReduced; UInt64 Num_Pax_Records;
CPaxExtra PaxExtra;
CEncodingCharacts EncodingCharacts; CEncodingCharacts EncodingCharacts;
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; } UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; }
UInt64 GetFullSize() const { return HeaderSize + PackSize; } // UInt64 GetFullSize() const { return HeaderSize + PackSize; }
UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); }
}; };
}} }}

View file

@ -2,6 +2,10 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../../../C/7zCrc.h"
#include "../../../Common/IntToString.h"
#include "../../Common/StreamUtils.h" #include "../../Common/StreamUtils.h"
#include "TarOut.h" #include "TarOut.h"
@ -9,23 +13,27 @@
namespace NArchive { namespace NArchive {
namespace NTar { namespace NTar {
HRESULT COutArchive::WriteBytes(const void *data, unsigned size) using namespace NFileHeader;
{
Pos += size;
return WriteStream(m_Stream, data, size);
}
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; const unsigned kNumDigits = 8 - 1;
if (val >= ((UInt32)1 << (kNumDigits * 3))) if (val >= ((UInt32)1 << (kNumDigits * 3)))
return false; {
val = 0;
// return false;
}
for (unsigned i = 0; i < kNumDigits; i++) for (unsigned i = 0; i < kNumDigits; i++)
{ {
s[kNumDigits - 1 - i] = (char)('0' + (val & 7)); s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
val >>= 3; val >>= 3;
} }
return true; // return true;
} }
static void WriteBin_64bit(char *s, UInt64 val) 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(); unsigned len = src.Len();
if (len == 0) if (len == 0)
return; 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) if (len > maxSize)
{ {
len = maxSize; len = maxSize;
// return false; /*
// oldgnu needs 0 character at the end
len = maxSize - 1;
dest[len] = 0;
*/
} }
memcpy(dest, src.Ptr(), len); 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) \ #define COPY_STRING_CHECK(dest, src, size) \
CopyString(dest, src, size); dest += (size); CopyString(dest, src, size); dest += (size);
#define WRITE_OCTAL_8_CHECK(dest, src) \ #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; 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.UID); cur += 8;
WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8; WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8;
WriteOctal_12(cur, item.PackSize); cur += 12; WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12;
WriteOctal_12_Signed(cur, item.MTime); 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 += 8;
*cur++ = item.LinkFlag; *cur++ = item.LinkFlag;
COPY_STRING_CHECK (cur, item.LinkName, NFileHeader::kNameSize); COPY_STRING_CHECK (cur, item.LinkName, kNameSize);
memcpy(cur, item.Magic, 8); memcpy(cur, item.Magic, 8);
cur += 8; cur += 8;
COPY_STRING_CHECK (cur, item.User, NFileHeader::kUserNameSize); COPY_STRING_CHECK (cur, item.User, kUserNameSize);
COPY_STRING_CHECK (cur, item.Group, NFileHeader::kGroupNameSize); COPY_STRING_CHECK (cur, item.Group, kGroupNameSize);
if (item.DeviceMajorDefined) const bool needDevice = (IsPosixMode && !isPax);
WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor);
if (item.DeviceMajor_Defined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor)
else if (needDevice)
WRITE_OCTAL_8_CHECK (cur, 0)
cur += 8; cur += 8;
if (item.DeviceMinorDefined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor); if (item.DeviceMinor_Defined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor)
else if (needDevice)
WRITE_OCTAL_8_CHECK (cur, 0)
cur += 8; cur += 8;
if (item.IsSparse()) if (!isPax && !Prefix.IsEmpty())
{
COPY_STRING_CHECK (cur, Prefix, kPrefixSize);
}
if (item.Is_Sparse())
{ {
record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0); record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
WriteOctal_12(record + 483, item.Size); 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++) for (unsigned i = 0; i < kRecordSize; i++)
checkSum += (Byte)record[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. */ 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; const unsigned kNumDigits = 6;
for (unsigned i = 0; i < kNumDigits; i++) for (unsigned i = 0; i < kNumDigits; i++)
{ {
record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7)); record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7));
checkSum >>= 3; 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();) 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++) for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
{ {
const CSparseBlock &sb = item.SparseBlocks[i]; const CSparseBlock &sb = item.SparseBlocks[i];
@ -169,7 +209,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
WriteOctal_12(p + 12, sb.Size); WriteOctal_12(p + 12, sb.Size);
} }
record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0); 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 static void AddPaxLine(AString &s, const char *name, const AString &val)
NEW_GNU_TAR: writes short name without zero at the end */ {
// 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 = static const unsigned kNameSize_Max =
NFileHeader::kNameSize; // NEW_GNU_TAR / 7-Zip 21.07 kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
// NFileHeader::kNameSize - 1; // OLD_GNU_TAR / old 7-Zip // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max) #define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max)
HRESULT COutArchive::WriteHeader(const CItem &item) HRESULT COutArchive::WriteHeader(const CItem &item)
{ {
if (DOES_NAME_FIT_IN_FIELD(item.Name) && Glob_Name.Empty();
DOES_NAME_FIT_IN_FIELD(item.LinkName)) Prefix.Empty();
return WriteHeaderReal(item);
// here we can get all fields from main (item) or create new empty item unsigned namePos = 0;
/* bool needPathCut = false;
CItem mi; bool allowPrefix = false;
mi.SetDefaultWriteFields();
*/
CItem mi = item;
mi.LinkName.Empty();
// SparseBlocks will be ignored by IsSparse()
// mi.SparseBlocks.Clear();
mi.Name = NFileHeader::kLongLink; if (!DOES_NAME_FIT_IN_FIELD(item.Name))
// 21.07 : we set Mode and MTime props as in GNU TAR:
mi.Mode = 0644; // octal
mi.MTime = 0;
for (int i = 0; i < 2; i++)
{ {
const AString *name; const char *s = item.Name;
// We suppose that GNU TAR also writes item for long link before item for LongName? const char *p = s + item.Name.Len() - 1;
if (i == 0) for (; *p == '/' && p != s; p--)
{ {}
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink; for (; p != s && p[-1] != '/'; p--)
name = &item.LinkName; {}
} namePos = (unsigned)(p - s);
else needPathCut = true;
{ }
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
name = &item.Name; if (IsPosixMode)
} {
if (DOES_NAME_FIT_IN_FIELD(*name)) AString s;
continue;
// GNU TAR writes null character after NAME to file. We do same here: if (needPathCut)
const unsigned nameStreamSize = name->Len() + 1; {
mi.PackSize = nameStreamSize; const unsigned nameLen = item.Name.Len() - namePos;
RINOK(WriteHeaderReal(mi)); if ( item.LinkFlag >= NLinkFlag::kNormal
RINOK(WriteBytes(name->Ptr(), nameStreamSize)); && item.LinkFlag <= NLinkFlag::kDirectory
RINOK(FillDataResidual(nameStreamSize)); && 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); 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)); Pos += size;
if (lastRecordSize == 0) return WriteStream(Stream, data, size);
return S_OK;
unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
Byte buf[NFileHeader::kRecordSize];
memset(buf, 0, rem);
return WriteBytes(buf, rem);
} }
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() HRESULT COutArchive::WriteFinishHeader()
{ {
Byte record[NFileHeader::kRecordSize]; Byte record[kRecordSize];
memset(record, 0, NFileHeader::kRecordSize); memset(record, 0, kRecordSize);
const unsigned kNumFinishRecords = 2; const unsigned kNumFinishRecords = 2;
/* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB) /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB)
we also can use cluster alignment: 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 kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB
const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1)); const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1));
*/ */
for (unsigned i = 0; i < kNumFinishRecords; i++) for (unsigned i = 0; i < kNumFinishRecords; i++)
{ {
RINOK(WriteBytes(record, NFileHeader::kRecordSize)); RINOK(Write_Data(record, kRecordSize));
} }
return S_OK; return S_OK;
} }

View file

@ -14,21 +14,38 @@ namespace NTar {
class COutArchive 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: public:
UInt64 Pos; UInt64 Pos;
bool IsPosixMode;
// bool IsPrefixAllowed; // it's used only if (IsPosixMode == true)
CTimeOptions TimeOptions;
void Create(ISequentialOutStream *outStream) void Create(ISequentialOutStream *outStream)
{ {
m_Stream = outStream; Stream = outStream;
} }
HRESULT WriteHeader(const CItem &item); HRESULT WriteHeader(const CItem &item);
HRESULT FillDataResidual(UInt64 dataSize); HRESULT Write_AfterDataResidual(UInt64 dataSize);
HRESULT WriteFinishHeader(); HRESULT WriteFinishHeader();
COutArchive():
Pos(0),
IsPosixMode(false)
// , IsPrefixAllowed(true)
{}
}; };
}} }}

View file

@ -15,9 +15,17 @@ REGISTER_ARC_IO(
"tar", "tar ova", 0, 0xEE, "tar", "tar ova", 0, 0xEE,
k_Signature, k_Signature,
NFileHeader::kUstarMagic_Offset, NFileHeader::kUstarMagic_Offset,
NArcInfoFlags::kStartOpen | NArcInfoFlags::kStartOpen
NArcInfoFlags::kSymLinks | | NArcInfoFlags::kSymLinks
NArcInfoFlags::kHardLinks, | NArcInfoFlags::kHardLinks
IsArc_Tar) | 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)
}} }}

View file

@ -2,6 +2,8 @@
#include "StdAfx.h" #include "StdAfx.h"
// #include <stdio.h>
#include "../../../Windows/TimeUtils.h" #include "../../../Windows/TimeUtils.h"
#include "../../Common/LimitedStreams.h" #include "../../Common/LimitedStreams.h"
@ -15,18 +17,161 @@
namespace NArchive { namespace NArchive {
namespace NTar { 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, HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CObjectVector<NArchive::NTar::CItemEx> &inputItems, const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems, const CObjectVector<CUpdateItem> &updateItems,
UINT codePage, unsigned utfFlags, const CUpdateOptions &options,
IArchiveUpdateCallback *updateCallback) IArchiveUpdateCallback *updateCallback)
{ {
COutArchive outArchive; COutArchive outArchive;
outArchive.Create(outStream); outArchive.Create(outStream);
outArchive.Pos = 0; outArchive.Pos = 0;
outArchive.IsPosixMode = options.PosixMode;
outArchive.TimeOptions = options.TimeOptions;
CMyComPtr<IOutStream> outSeekStream; CMyComPtr<IOutStream> outSeekStream;
outStream->QueryInterface(IID_IOutStream, (void **)&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; CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
@ -40,7 +185,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (ui.NewData) if (ui.NewData)
complexity += ui.Size; complexity += ui.Size;
else else
complexity += inputItems[(unsigned)ui.IndexInArc].GetFullSize(); complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned();
} }
RINOK(updateCallback->SetTotal(complexity)); RINOK(updateCallback->SetTotal(complexity));
@ -58,21 +203,31 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
complexity = 0; complexity = 0;
for (i = 0; i < updateItems.Size(); i++) // const int kNumReduceDigits = -1; // for debug
for (i = 0;; i++)
{ {
lps->InSize = lps->OutSize = complexity; lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur()); RINOK(lps->SetCur());
if (i == updateItems.Size())
return outArchive.WriteFinishHeader();
const CUpdateItem &ui = updateItems[i]; const CUpdateItem &ui = updateItems[i];
CItem item; CItem item;
if (ui.NewProps) if (ui.NewProps)
{ {
item.SetDefaultWriteFields(); item.SetMagic_Posix(options.PosixMode);
item.Mode = ui.Mode;
item.Name = ui.Name; item.Name = ui.Name;
item.User = ui.User; item.User = ui.User;
item.Group = ui.Group; 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) if (ui.IsDir)
{ {
@ -81,11 +236,15 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
} }
else else
{ {
item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
item.PackSize = ui.Size; 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 else
item = inputItems[(unsigned)ui.IndexInArc]; item = inputItems[(unsigned)ui.IndexInArc];
@ -93,7 +252,8 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
AString symLink; AString symLink;
if (ui.NewData || ui.NewProps) 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()) if (!symLink.IsEmpty())
{ {
item.LinkFlag = NFileHeader::NLinkFlag::kSymLink; item.LinkFlag = NFileHeader::NLinkFlag::kSymLink;
@ -120,7 +280,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
} }
else else
{ {
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
if (res == S_FALSE) if (res == S_FALSE)
needWrite = false; needWrite = false;
@ -128,31 +288,105 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
{ {
RINOK(res); RINOK(res);
if (fileInStream) 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
{ {
item.PackSize = 0; item.PackSize = 0;
item.Size = 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; 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()) if (!hardLink.IsEmpty())
{ {
item.LinkFlag = NFileHeader::NLinkFlag::kHardLink; 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) if (needWrite)
{ {
UInt64 fileHeaderStartPos = outArchive.Pos; const UInt64 headerPos = outArchive.Pos;
// item.PackSize = ((UInt64)1 << 33); // for debug
RINOK(outArchive.WriteHeader(item)); RINOK(outArchive.WriteHeader(item));
if (fileInStream) if (fileInStream)
{ {
RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); for (unsigned numPasses = 0;; numPasses++)
outArchive.Pos += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != item.PackSize)
{ {
/* 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) if (!outSeekStream)
return E_FAIL; return E_FAIL;
UInt64 backOffset = outArchive.Pos - fileHeaderStartPos; const UInt64 nextPos = outArchive.Pos;
RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL)); RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL));
outArchive.Pos = fileHeaderStartPos; outArchive.Pos = headerPos;
item.PackSize = copyCoderSpec->TotalSize; item.PackSize = copyCoderSpec->TotalSize;
RINOK(outArchive.WriteHeader(item)); 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; complexity += item.PackSize;
fileInStream.Release();
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
} }
else else
{ {
// (ui.NewData == false)
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
NUpdateNotifyOp::kReplicate))
}
const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc]; const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc];
UInt64 size; UInt64 size, pos;
if (ui.NewProps) if (ui.NewProps)
{ {
@ -216,44 +511,37 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
item.PackSize = existItem.PackSize; item.PackSize = existItem.PackSize;
} }
item.DeviceMajorDefined = existItem.DeviceMajorDefined; item.DeviceMajor_Defined = existItem.DeviceMajor_Defined;
item.DeviceMinorDefined = existItem.DeviceMinorDefined; item.DeviceMinor_Defined = existItem.DeviceMinor_Defined;
item.DeviceMajor = existItem.DeviceMajor; item.DeviceMajor = existItem.DeviceMajor;
item.DeviceMinor = existItem.DeviceMinor; item.DeviceMinor = existItem.DeviceMinor;
item.UID = existItem.UID; item.UID = existItem.UID;
item.GID = existItem.GID; item.GID = existItem.GID;
RINOK(outArchive.WriteHeader(item)); RINOK(outArchive.WriteHeader(item));
RINOK(inStream->Seek((Int64)existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); size = existItem.Get_PackSize_Aligned();
size = existItem.PackSize; pos = existItem.Get_DataPos();
} }
else else
{ {
RINOK(inStream->Seek((Int64)existItem.HeaderPos, STREAM_SEEK_SET, NULL)); size = existItem.Get_FullSize_Aligned();
size = existItem.GetFullSize(); pos = existItem.HeaderPos;
} }
streamSpec->Init(size);
if (opCallback) if (size != 0)
{ {
RINOK(opCallback->ReportOperation( RINOK(inStream->Seek((Int64)pos, STREAM_SEEK_SET, NULL));
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc, streamSpec->Init(size);
NUpdateNotifyOp::kReplicate)) // 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();
} }
}} }}

View file

@ -15,27 +15,60 @@ struct CUpdateItem
int IndexInArc; int IndexInArc;
unsigned IndexInClient; unsigned IndexInClient;
UInt64 Size; UInt64 Size;
Int64 MTime; // Int64 MTime;
UInt32 Mode; UInt32 Mode;
bool NewData; bool NewData;
bool NewProps; bool NewProps;
bool IsDir; bool IsDir;
bool DeviceMajor_Defined;
bool DeviceMinor_Defined;
UInt32 UID;
UInt32 GID;
UInt32 DeviceMajor;
UInt32 DeviceMinor;
AString Name; AString Name;
AString User; AString User;
AString Group; 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, HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CObjectVector<CItemEx> &inputItems, const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems, const CObjectVector<CUpdateItem> &updateItems,
UINT codePage, unsigned utfFlags, const CUpdateOptions &options,
IArchiveUpdateCallback *updateCallback); IArchiveUpdateCallback *updateCallback);
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res, HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
UINT codePage, unsigned utfFlags, bool convertSlash); 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 #endif

View file

@ -27,11 +27,17 @@ static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop
return; return;
if (t.IsLocal()) if (t.IsLocal())
numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60); numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60);
FILETIME ft; const UInt32 m0 = d[9];
UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10; const UInt32 m1 = d[10];
ft.dwLowDateTime = (UInt32)v; const UInt32 m2 = d[11];
ft.dwHighDateTime = (UInt32)(v >> 32); unsigned numDigits = 0;
prop = ft; 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[] = static const Byte kProps[] =
@ -41,7 +47,8 @@ static const Byte kProps[] =
kpidSize, kpidSize,
kpidPackSize, kpidPackSize,
kpidMTime, kpidMTime,
kpidATime kpidATime,
kpidChangeTime
}; };
static const Byte kArcProps[] = 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 kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break; case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
case kpidATime: UdfTimeToFileTime(item.ATime, prop); break; case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break;
} }
} }
prop.Detach(value); prop.Detach(value);

View file

@ -333,7 +333,7 @@ void CItem::Parse(const Byte *p)
NumLogBlockRecorded = Get64(p + 64); NumLogBlockRecorded = Get64(p + 64);
ATime.Parse(p + 72); ATime.Parse(p + 72);
MTime.Parse(p + 84); MTime.Parse(p + 84);
// AttrtTime.Parse(p + 96); AttribTime.Parse(p + 96);
// CheckPoint = Get32(p + 108); // CheckPoint = Get32(p + 108);
// ExtendedAttrIcb.Parse(p + 112); // ExtendedAttrIcb.Parse(p + 112);
// ImplId.Parse(p + 128); // ImplId.Parse(p + 128);

View file

@ -243,7 +243,7 @@ struct CItem
UInt64 NumLogBlockRecorded; UInt64 NumLogBlockRecorded;
CTime ATime; CTime ATime;
CTime MTime; 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; // UInt32 CheckPoint;
// CLongAllocDesc ExtendedAttrIcb; // CLongAllocDesc ExtendedAttrIcb;
// CRegId ImplId; // CRegId ImplId;

View file

@ -921,7 +921,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
CLimitedInStream *streamSpec = new CLimitedInStream; CLimitedInStream *streamSpec = new CLimitedInStream;
CMyComPtr<ISequentialInStream> streamTemp = streamSpec; CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
streamSpec->SetStream(Stream); streamSpec->SetStream(Stream);
streamSpec->InitAndSeek(0, Footer.CurrentSize); // fixme : check (startOffset = 0)
streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize);
RINOK(streamSpec->SeekToStart()); RINOK(streamSpec->SeekToStart());
*stream = streamTemp.Detach(); *stream = streamTemp.Detach();
return S_OK; return S_OK;

View file

@ -171,6 +171,20 @@ struct CHeader
UInt64 LogOffset; UInt64 LogOffset;
CGuid Guids[3]; 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); bool Parse(Byte *p);
}; };
@ -1174,7 +1188,18 @@ HRESULT CHandler::Open3()
unsigned mainIndex; unsigned mainIndex;
if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0; if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0;
else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1; 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]; const CHeader &h = headers[mainIndex];
Header = h; Header = h;
@ -1567,6 +1592,7 @@ static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
void CHandler::AddComment(UString &s) const void CHandler::AddComment(UString &s) const
{ {
AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
AddComment_UInt64(s, "PhysicalSize", _phySize); AddComment_UInt64(s, "PhysicalSize", _phySize);
if (!_errorMessage.IsEmpty()) if (!_errorMessage.IsEmpty())

View file

@ -138,7 +138,7 @@ static bool Str_to_ValName(const AString &s, AString &name, AString &val)
int eq = s.Find('='); int eq = s.Find('=');
if (eq < 0 || (qu >= 0 && eq > qu)) if (eq < 0 || (qu >= 0 && eq > qu))
return false; return false;
name = s.Left(eq); name.SetFrom(s.Ptr(), eq);
name.Trim(); name.Trim();
val = s.Ptr(eq + 1); val = s.Ptr(eq + 1);
val.Trim(); val.Trim();

View file

@ -355,6 +355,7 @@ static void GetFileTime(const Byte *p, NCOM::CPropVariant &prop)
prop.vt = VT_FILETIME; prop.vt = VT_FILETIME;
prop.filetime.dwLowDateTime = Get32(p); prop.filetime.dwLowDateTime = Get32(p);
prop.filetime.dwHighDateTime = Get32(p + 4); prop.filetime.dwHighDateTime = Get32(p + 4);
prop.Set_FtPrec(k_PropVar_TimePrec_100ns);
} }
@ -842,7 +843,7 @@ public:
int dotPos = name.ReverseFind_Dot(); int dotPos = name.ReverseFind_Dot();
if (dotPos < 0) if (dotPos < 0)
dotPos = name.Len(); dotPos = name.Len();
_before = name.Left(dotPos); _before.SetFrom(name.Ptr(), dotPos);
_after = name.Ptr(dotPos); _after = name.Ptr(dotPos);
} }

View file

@ -32,8 +32,8 @@ static int AddUniqHash(const CStreamInfo *streams, CUIntVector &sorted, const By
unsigned left = 0, right = sorted.Size(); unsigned left = 0, right = sorted.Size();
while (left != right) while (left != right)
{ {
unsigned mid = (left + right) / 2; const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
unsigned index = sorted[mid]; const unsigned index = sorted[mid];
const Byte *hash2 = streams[index].Hash; const Byte *hash2 = streams[index].Hash;
unsigned i; unsigned i;
@ -124,9 +124,9 @@ static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned
unsigned left = 0, right = indexes.Size(); unsigned left = 0, right = indexes.Size();
while (left != right) while (left != right)
{ {
unsigned mid = (left + right) / 2; const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
unsigned index = indexes[mid]; const unsigned index = indexes[mid];
int comp = Compare_HardLink_MetaItems(mi, metaItems[index]); const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]);
if (comp == 0) if (comp == 0)
return index; return index;
if (comp < 0) if (comp < 0)
@ -203,8 +203,8 @@ bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, u
unsigned left = 0, right = Dirs.Size(); unsigned left = 0, right = Dirs.Size();
while (left != right) while (left != right)
{ {
unsigned mid = (left + right) / 2; const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name); const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name);
if (comp == 0) if (comp == 0)
{ {
index = mid; index = mid;

View file

@ -567,9 +567,12 @@ void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCO
for (unsigned i = 0; i < len; i++) for (unsigned i = 0; i < len; i++)
{ {
wchar_t c = Get16(meta + i * 2); wchar_t c = Get16(meta + i * 2);
// 18.06 if (c == L'/')
if (c == CHAR_PATH_SEPARATOR || c == '/') c = L'_';
c = '_'; #if WCHAR_PATH_SEPARATOR != L'/'
else if (c == L'\\')
c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // 22.00 : WSL scheme
#endif
dest[i] = c; dest[i] = c;
} }
} }

View file

@ -10,13 +10,20 @@ namespace NArchive {
namespace NWim { namespace NWim {
REGISTER_ARC_IO( REGISTER_ARC_IO(
"wim", "wim swm esd ppkg", 0, 0xE6, "wim", "wim swm esd ppkg", NULL, 0xE6
kSignature, , kSignature, 0
0, , NArcInfoFlags::kAltStreams
NArcInfoFlags::kAltStreams | | NArcInfoFlags::kNtSecure
NArcInfoFlags::kNtSecure | | NArcInfoFlags::kSymLinks
NArcInfoFlags::kSymLinks | | NArcInfoFlags::kHardLinks
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) , NULL)
}} }}

View file

@ -1089,7 +1089,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{ {
*timeType = NFileTimeType::kUnix; *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
// *timeType = NFileTimeType::kUnix;
return S_OK; return S_OK;
} }
@ -1136,7 +1137,6 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (prop.vt != VT_UI8) if (prop.vt != VT_UI8)
return E_INVALIDARG; return E_INVALIDARG;
dataSize = prop.uhVal.QuadPart; dataSize = prop.uhVal.QuadPart;
RINOK(updateCallback->SetTotal(dataSize));
} }
NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder; NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
@ -1266,15 +1266,28 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
} }
} }
CMyComPtr<ISequentialInStream> fileInStream; {
RINOK(updateCallback->GetStream(0, &fileInStream)); CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream));
CLocalProgress *lps = new CLocalProgress; if (!fileInStream)
CMyComPtr<ICompressProgressInfo> progress = lps; return S_FALSE;
lps->Init(updateCallback, true); {
CMyComPtr<IStreamGetSize> streamGetSize;
RINOK(encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress)); 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); return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
} }
@ -1415,9 +1428,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
REGISTER_ARC_IO( REGISTER_ARC_IO(
"xz", "xz txz", "* .tar", 0xC, "xz", "xz txz", "* .tar", 0xC,
XZ_SIG, XZ_SIG, 0
0, , NArcInfoFlags::kKeepName
NArcInfoFlags::kKeepName, , 0
NULL) , NULL)
}} }}

View file

@ -190,6 +190,8 @@ static const Byte kProps[] =
kpidVolumeIndex, kpidVolumeIndex,
kpidOffset kpidOffset
// kpidIsAltStream // kpidIsAltStream
// , kpidChangeTime // for debug
// , 255 // for debug
}; };
static const Byte kArcProps[] = static const Byte kArcProps[] =
@ -347,6 +349,34 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK; 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) STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{ {
COM_TRY_BEGIN COM_TRY_BEGIN
@ -392,6 +422,30 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPackSize: prop = item.PackSize; break; 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: case kpidTimeType:
{ {
FILETIME ft; FILETIME ft;
@ -399,7 +453,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
UInt32 type; UInt32 type;
if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft)) if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
type = NFileTimeType::kWindows; 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; type = NFileTimeType::kUnix;
else else
type = NFileTimeType::kDOS; type = NFileTimeType::kDOS;
@ -407,64 +461,28 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
break; 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; if (NtfsUnixTimeToProp(item.FromCentral, extra,
bool defined = true; NFileHeader::NNtfsExtra::kMTime,
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc)) NFileHeader::NUnixTime::kMTime, prop))
{ {
UInt32 unixTime = 0; FILETIME localFileTime;
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime)) if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime))
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; UInt64 t1 = FILETIME_To_UInt64(prop.filetime);
if (item.Time == 0) UInt64 t2 = FILETIME_To_UInt64(localFileTime);
defined = false; prop.Set_Int64(t2 - t1);
else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
!LocalFileTimeToFileTime(&localFileTime, &utc))
utc.dwHighDateTime = utc.dwLowDateTime = 0;
} }
} }
if (defined)
prop = utc;
break; break;
} }
*/
case kpidAttrib: prop = item.GetWinAttrib(); break; case kpidAttrib: prop = item.GetWinAttrib(); break;
@ -1122,7 +1140,18 @@ HRESULT CZipDecoder::Decode(
AString_Wipe charPassword; AString_Wipe charPassword;
if (password) 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) if (wzAesMode || pkAesMode)
{ {
@ -1341,6 +1370,8 @@ HRESULT CZipDecoder::Decode(
if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted()) 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; readFromFilter = false;
COutStreamWithPadPKCS7 *padStreamSpec = NULL; COutStreamWithPadPKCS7 *padStreamSpec = NULL;
@ -1425,33 +1456,44 @@ HRESULT CZipDecoder::Decode(
const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed); const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed);
if (processed + padSize > coderPackSize) if (processed + padSize > coderPackSize)
truncatedError = true; truncatedError = true;
else if (processed + padSize < coderPackSize)
dataAfterEnd = true;
else 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; CMyComPtr<ICompressReadUnusedFromInBuf> readInStream;
coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&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 // change pad size, if we support another block size in ZipStrong.
// here we request more to detect error with data after end. // here we request more data to detect error with data after end.
const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16; const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16;
Byte buf[kBufSize]; Byte buf[kBufSize];
UInt32 processedSize; UInt32 processedSize = 0;
RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize)); if (readInStream)
{
RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize));
}
if (processedSize > padSize) if (processedSize > padSize)
dataAfterEnd = true; dataAfterEnd = true;
else else
{ {
if (ReadStream_FALSE(filterStream, buf + processedSize, padSize - processedSize) != S_OK) size_t processedSize2 = kBufSize - processedSize;
padError = true; result = ReadStream(filterStream, buf + processedSize, &processedSize2);
else if (result == S_OK)
for (unsigned i = 0; i < padSize; i++) {
if (buf[i] != padSize) processedSize2 += processedSize;
padError = true; 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;
}
} }
} }
} }

View file

@ -57,7 +57,9 @@ private:
int m_MainMethod; int m_MainMethod;
bool m_ForceAesMode; bool m_ForceAesMode;
bool m_WriteNtfsTimeExtra;
CHandlerTimeOptions TimeOptions;
bool _removeSfxBlock; bool _removeSfxBlock;
bool m_ForceLocal; bool m_ForceLocal;
bool m_ForceUtf8; bool m_ForceUtf8;
@ -71,7 +73,8 @@ private:
_props.Init(); _props.Init();
m_MainMethod = -1; m_MainMethod = -1;
m_ForceAesMode = false; m_ForceAesMode = false;
m_WriteNtfsTimeExtra = true; TimeOptions.Init();
TimeOptions.Prec = k_PropVar_TimePrec_0;
_removeSfxBlock = false; _removeSfxBlock = false;
m_ForceLocal = false; m_ForceLocal = false;
m_ForceUtf8 = false; m_ForceUtf8 = false;

View file

@ -30,7 +30,7 @@ namespace NZip {
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType) STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{ {
*timeType = NFileTimeType::kDOS; *timeType = TimeOptions.Prec;
return S_OK; 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; CPropVariant prop;
RINOK(callback->GetProperty(i, kpidTimeType, &prop)); RINOK(callback->GetProperty(i, kpidTimeType, &prop));
if (prop.vt == VT_UI4) if (prop.vt == VT_UI4)
ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows); ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows);
else 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 (TimeOptions.Prec == k_PropVar_TimePrec_Unix ||
if (ui.Ntfs_MTime.dwHighDateTime != 0 || TimeOptions.Prec == k_PropVar_TimePrec_Base)
ui.Ntfs_MTime.dwLowDateTime != 0) ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime);
if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime)) else
return E_INVALIDARG; {
FileTimeToDosTime(localFileTime, ui.Time); /*
// 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); NItemName::ReplaceSlashes_OsToUnix(name);
bool needSlash = ui.IsDir; bool needSlash = ui.IsDir;
@ -441,11 +472,21 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (mainMethod != NFileHeader::NCompressionMethod::kStore) if (mainMethod != NFileHeader::NCompressionMethod::kStore)
options.MethodSequence.Add(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( return Update(
EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS
m_Items, updateItems, outStream, m_Items, updateItems, outStream,
m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock, m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock,
options, callback); uo, options, callback);
COM_TRY_END2 COM_TRY_END2
} }
@ -494,10 +535,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
return E_INVALIDARG; return E_INVALIDARG;
} }
} }
else if (name.IsEqualTo("tc"))
{
RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra));
}
else if (name.IsEqualTo("cl")) else if (name.IsEqualTo("cl"))
{ {
RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal)); RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal));
@ -532,7 +572,12 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
} }
else 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)); // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
} }

View file

@ -88,14 +88,15 @@ namespace NFileHeader
{ {
kZip64 = 0x01, kZip64 = 0x01,
kNTFS = 0x0A, kNTFS = 0x0A,
kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK
kStrongEncrypt = 0x17, kStrongEncrypt = 0x17,
kIzNtSecurityDescriptor = 0x4453, kIzNtSecurityDescriptor = 0x4453,
kUnixTime = 0x5455, kUnixTime = 0x5455, // "UT" (time) Info-ZIP
kUnixExtra = 0x5855, kUnix1 = 0x5855, // Info-ZIP
kIzUnicodeComment = 0x6375, kIzUnicodeComment = 0x6375,
kIzUnicodeName = 0x7075, kIzUnicodeName = 0x7075,
kUnix2Extra = 0x7855, kUnix2 = 0x7855, // Info-ZIP
kUnix3Extra = 0x7875, kUnixN = 0x7875, // Info-ZIP
kWzAES = 0x9901, kWzAES = 0x9901,
kApkAlign = 0xD935 kApkAlign = 0xD935
}; };

View file

@ -1045,9 +1045,24 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo
if (cdItem) if (cdItem)
{ {
if (isOK && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos)) if (isOK)
{ if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }} {
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 (isOK && ZIP64_IS_16_MAX(cdItem->Disk))
{ if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }} { 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) if (left >= right)
return -1; return -1;
const unsigned index = (left + right) / 2; const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2);
const CItemEx &item2 = items[index]; const CItemEx &item2 = items[index];
if (item.Disk < item2.Disk) if (item.Disk < item2.Disk)
right = index; right = index;

View file

@ -30,11 +30,12 @@ static const CUInt32PCharPair g_ExtraTypes[] =
{ {
{ NExtraID::kZip64, "Zip64" }, { NExtraID::kZip64, "Zip64" },
{ NExtraID::kNTFS, "NTFS" }, { NExtraID::kNTFS, "NTFS" },
{ NExtraID::kUnix0, "UNIX" },
{ NExtraID::kStrongEncrypt, "StrongCrypto" }, { NExtraID::kStrongEncrypt, "StrongCrypto" },
{ NExtraID::kUnixTime, "UT" }, { NExtraID::kUnixTime, "UT" },
{ NExtraID::kUnixExtra, "UX" }, { NExtraID::kUnix1, "UX" },
{ NExtraID::kUnix2Extra, "Ux" }, { NExtraID::kUnix2, "Ux" },
{ NExtraID::kUnix3Extra, "ux" }, { NExtraID::kUnixN, "ux" },
{ NExtraID::kIzUnicodeComment, "uc" }, { NExtraID::kIzUnicodeComment, "uc" },
{ NExtraID::kIzUnicodeName, "up" }, { NExtraID::kIzUnicodeName, "up" },
{ NExtraID::kIzNtSecurityDescriptor, "SD" }, { NExtraID::kIzNtSecurityDescriptor, "SD" },
@ -50,6 +51,23 @@ void CExtraSubBlock::PrintInfo(AString &s) const
if (pair.Value == ID) if (pair.Value == ID)
{ {
s += pair.Name; 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) if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
{ {
@ -133,14 +151,22 @@ bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
return false; 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; res = 0;
UInt32 size = (UInt32)Data.Size(); UInt32 size = (UInt32)Data.Size();
if (ID != NExtraID::kUnixTime || size < 5) if (ID != NExtraID::kUnixTime || size < 5)
return false; return false;
const Byte *p = (const Byte *)Data; const Byte *p = (const Byte *)Data;
Byte flags = *p++; const Byte flags = *p++;
size--; size--;
if (isCentral) 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; res = 0;
const size_t size = Data.Size(); const unsigned offset = index * 4;
unsigned offset = index * 4; if (Data.Size() < offset + 4)
if (ID != NExtraID::kUnixExtra || size < offset + 4) return false;
if (ID != NExtraID::kUnix0 &&
ID != NExtraID::kUnix1)
return false; return false;
const Byte *p = (const Byte *)Data + offset; const Byte *p = (const Byte *)Data + offset;
res = GetUi32(p); res = GetUi32(p);
return true; 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 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]; const CExtraSubBlock &sb = SubBlocks[i];
if (sb.ID == NFileHeader::NExtraID::kUnixTime) 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) FOR_VECTOR (i, SubBlocks)
{ {
const CExtraSubBlock &sb = SubBlocks[i]; const CExtraSubBlock &sb = SubBlocks[i];
if (sb.ID == NFileHeader::NExtraID::kUnixExtra) if (sb.ID == NFileHeader::NExtraID::kUnix0 ||
return sb.ExtractUnixExtraTime(index, res); sb.ID == NFileHeader::NExtraID::kUnix1)
return sb.Extract_Unix01_Time(index, res);
} }
} }
return false; return false;

View file

@ -31,8 +31,9 @@ struct CExtraSubBlock
CByteBuffer Data; CByteBuffer Data;
bool ExtractNtfsTime(unsigned index, FILETIME &ft) const; bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const; bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const;
bool ExtractUnixExtraTime(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; bool CheckIzUnicode(const AString &s) const;

View file

@ -4,6 +4,7 @@
#include "../../../../C/7zCrc.h" #include "../../../../C/7zCrc.h"
#include "../../../Windows/TimeUtils.h"
#include "../../Common/OffsetStream.h" #include "../../Common/OffsetStream.h"
#include "ZipOut.h" #include "ZipOut.h"
@ -110,6 +111,40 @@ void COutArchive::WriteUtfName(const CItemOut &item)
WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size()); 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) void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
{ {
m_LocalHeaderPos = m_CurPos; m_LocalHeaderPos = m_CurPos;
@ -122,8 +157,14 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
if (needCheck && m_IsZip64) if (needCheck && m_IsZip64)
isZip64 = true; 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)( const UInt32 localExtraSize = (UInt32)(
(isZip64 ? (4 + 8 + 8): 0) (isZip64 ? (4 + 8 + 8): 0)
+ (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
+ (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
+ item.Get_UtfName_ExtraSize() + item.Get_UtfName_ExtraSize()
+ item.LocalExtra.GetSize()); + item.LocalExtra.GetSize());
if ((UInt16)localExtraSize != localExtraSize) if ((UInt16)localExtraSize != localExtraSize)
@ -168,13 +209,12 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
Write64(packSize); Write64(packSize);
} }
WriteTimeExtra(item, writeNtfs);
WriteUtfName(item); WriteUtfName(item);
WriteExtra(item.LocalExtra); 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); const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize) if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
throw CSystemException(E_FAIL); throw CSystemException(E_FAIL);
@ -231,10 +271,10 @@ void COutArchive::WriteDescriptor(const CItemOut &item)
void COutArchive::WriteCentralHeader(const CItemOut &item) void COutArchive::WriteCentralHeader(const CItemOut &item)
{ {
bool isUnPack64 = DOES_NEED_ZIP64(item.Size); const bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
bool isPack64 = DOES_NEED_ZIP64(item.PackSize); const bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos); const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
bool isZip64 = isPack64 || isUnPack64 || isPosition64; const bool isZip64 = isPack64 || isUnPack64 || isPosition64;
Write32(NSignature::kCentralFileHeader); Write32(NSignature::kCentralFileHeader);
Write8(item.MadeByVersion.Version); Write8(item.MadeByVersion.Version);
@ -249,10 +289,11 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
Write16((UInt16)item.Name.Len()); Write16((UInt16)item.Name.Len());
const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0)); 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 = const size_t centralExtraSize =
(isZip64 ? 4 + zip64ExtraSize : 0) (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.Get_UtfName_ExtraSize()
+ item.CentralExtra.GetSize(); + item.CentralExtra.GetSize();
@ -283,18 +324,7 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
Write64(item.LocalHeaderPos); Write64(item.LocalHeaderPos);
} }
if (item.NtfsTimeIsDefined) WriteTimeExtra(item, writeNtfs);
{
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);
}
WriteUtfName(item); WriteUtfName(item);
WriteExtra(item.CentralExtra); WriteExtra(item.CentralExtra);
@ -304,15 +334,15 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment) void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
{ {
UInt64 cdOffset = GetCurPos(); const UInt64 cdOffset = GetCurPos();
FOR_VECTOR (i, items) FOR_VECTOR (i, items)
WriteCentralHeader(items[i]); WriteCentralHeader(items[i]);
UInt64 cd64EndOffset = GetCurPos(); const UInt64 cd64EndOffset = GetCurPos();
UInt64 cdSize = cd64EndOffset - cdOffset; const UInt64 cdSize = cd64EndOffset - cdOffset;
bool cdOffset64 = DOES_NEED_ZIP64(cdOffset); const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
bool cdSize64 = DOES_NEED_ZIP64(cdSize); const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
bool items64 = items.Size() >= 0xFFFF; const bool items64 = items.Size() >= 0xFFFF;
bool isZip64 = (cdOffset64 || cdSize64 || items64); const bool isZip64 = (cdOffset64 || cdSize64 || items64);
// isZip64 = true; // to test Zip64 // isZip64 = true; // to test Zip64

View file

@ -18,7 +18,8 @@ public:
FILETIME Ntfs_MTime; FILETIME Ntfs_MTime;
FILETIME Ntfs_ATime; FILETIME Ntfs_ATime;
FILETIME Ntfs_CTime; 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. // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra.
@ -32,7 +33,10 @@ public:
return 4 + 5 + size; return 4 + 5 + size;
} }
CItemOut(): NtfsTimeIsDefined(false) {} CItemOut():
Write_NtfsTime(false),
Write_UnixTime(false)
{}
}; };
@ -62,6 +66,7 @@ class COutArchive
Write32(ft.dwHighDateTime); Write32(ft.dwHighDateTime);
} }
void WriteTimeExtra(const CItemOut &item, bool writeNtfs);
void WriteUtfName(const CItemOut &item); void WriteUtfName(const CItemOut &item);
void WriteExtra(const CExtraBlock &extra); void WriteExtra(const CExtraBlock &extra);
void WriteCommonItemInfo(const CLocalItem &item, bool isZip64); void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);

View file

@ -20,9 +20,19 @@ REGISTER_ARC_IO(
"zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1, "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", 0, 1,
k_Signature, k_Signature,
0, 0,
NArcInfoFlags::kFindSignature | NArcInfoFlags::kFindSignature
NArcInfoFlags::kMultiSignature | | NArcInfoFlags::kMultiSignature
NArcInfoFlags::kUseGlobalOffset, | NArcInfoFlags::kUseGlobalOffset
IsArc_Zip) | 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)
}} }}

View file

@ -74,7 +74,9 @@ static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &ite
item.Ntfs_MTime = ui.Ntfs_MTime; item.Ntfs_MTime = ui.Ntfs_MTime;
item.Ntfs_ATime = ui.Ntfs_ATime; item.Ntfs_ATime = ui.Ntfs_ATime;
item.Ntfs_CTime = ui.Ntfs_CTime; 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( static void SetFileHeader(
@ -476,12 +478,9 @@ static void WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *o
} }
static inline bool IsZero_FILETIME(const FILETIME &ft) static void UpdatePropsFromStream(
{ const CUpdateOptions &options,
return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0); CUpdateItem &item, ISequentialInStream *fileInStream,
}
static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream,
IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity) IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity)
{ {
CMyComPtr<IStreamGetProps> getProps; CMyComPtr<IStreamGetProps> getProps;
@ -505,36 +504,100 @@ static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileIn
} }
item.Size = size; item.Size = size;
} }
if (!IsZero_FILETIME(mTime))
{
item.Ntfs_MTime = mTime;
FILETIME loc = { 0, 0 };
if (FileTimeToLocalFileTime(&mTime, &loc))
{
item.Time = 0;
NTime::FileTimeToDosTime(loc, item.Time);
}
}
if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime; if (options.Write_MTime)
if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime; if (!FILETIME_IsZero(mTime))
{
item.Ntfs_MTime = mTime;
NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time);
}
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; 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( static HRESULT Update2St(
DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS
COutArchive &archive, COutArchive &archive,
CInArchive *inArchive, CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems, const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems, CObjectVector<CUpdateItem> &updateItems,
const CUpdateOptions &updateOptions,
const CCompressionMethodMode *options, bool outSeqMode, const CCompressionMethodMode *options, bool outSeqMode,
const CByteBuffer *comment, const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback, IArchiveUpdateCallback *updateCallback,
UInt64 &totalComplexity, UInt64 &totalComplexity,
IArchiveUpdateCallbackFile *opCallback) IArchiveUpdateCallbackFile *opCallback
// , IArchiveUpdateCallbackArcProp *reportArcProp
)
{ {
CLocalProgress *lps = new CLocalProgress; CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps; CMyComPtr<ICompressProgressInfo> progress = lps;
@ -575,7 +638,8 @@ static HRESULT Update2St(
} }
else else
{ {
CMyComPtr<ISequentialInStream> fileInStream; CMyComPtr<ISequentialInStream> fileInStream;
{
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream); HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
if (res == S_FALSE) if (res == S_FALSE)
{ {
@ -596,7 +660,7 @@ static HRESULT Update2St(
} }
// seqMode = true; // to test seqMode // seqMode = true; // to test seqMode
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
CCompressingResult compressingResult; CCompressingResult compressingResult;
@ -629,10 +693,11 @@ static HRESULT Update2St(
SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item); SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
archive.WriteLocalHeader_Replace(item); archive.WriteLocalHeader_Replace(item);
}
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode()))
unpackSizeTotal += item.Size; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
packSizeTotal += item.PackSize; unpackSizeTotal += item.Size;
packSizeTotal += item.PackSize;
} }
} }
else else
@ -656,6 +721,14 @@ static HRESULT Update2St(
archive.WriteCentralDir(items, comment); archive.WriteCentralDir(items, comment);
/*
CTotalStats stat;
stat.Size = unpackSizeTotal;
stat.PackSize = packSizeTotal;
if (reportArcProp)
RINOK(ReportArcProps(reportArcProp, stat))
*/
lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1; lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1;
return lps->SetCur(); return lps->SetCur();
} }
@ -667,6 +740,7 @@ static HRESULT Update2(
CInArchive *inArchive, CInArchive *inArchive,
const CObjectVector<CItemEx> &inputItems, const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems, CObjectVector<CUpdateItem> &updateItems,
const CUpdateOptions &updateOptions,
const CCompressionMethodMode &options, bool outSeqMode, const CCompressionMethodMode &options, bool outSeqMode,
const CByteBuffer *comment, const CByteBuffer *comment,
IArchiveUpdateCallback *updateCallback) IArchiveUpdateCallback *updateCallback)
@ -674,6 +748,11 @@ static HRESULT Update2(
CMyComPtr<IArchiveUpdateCallbackFile> opCallback; CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback); updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
/*
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
*/
bool unknownComplexity = false; bool unknownComplexity = false;
UInt64 complexity = 0; UInt64 complexity = 0;
UInt64 numFilesToCompress = 0; UInt64 numFilesToCompress = 0;
@ -901,11 +980,23 @@ static HRESULT Update2(
return Update2St( return Update2St(
EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS
archive, inArchive, archive, inArchive,
inputItems, updateItems, &options2, outSeqMode, comment, updateCallback, totalComplexity, opCallback); inputItems, updateItems,
updateOptions,
&options2, outSeqMode,
comment, updateCallback, totalComplexity,
opCallback
// , reportArcProp
);
#ifndef _7ZIP_ST #ifndef _7ZIP_ST
/*
CTotalStats stat;
stat.Size = 0;
stat.PackSize = 0;
*/
CObjectVector<CItemOut> items; CObjectVector<CItemOut> items;
CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer; CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
@ -1021,7 +1112,7 @@ static HRESULT Update2(
RINOK(res); RINOK(res);
if (!fileInStream) if (!fileInStream)
return E_INVALIDARG; return E_INVALIDARG;
UpdatePropsFromStream(ui, fileInStream, updateCallback, totalComplexity); UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
} }
@ -1122,6 +1213,13 @@ static HRESULT Update2(
memRef.WriteToStream(memManager.GetBlockSize(), outStream); memRef.WriteToStream(memManager.GetBlockSize(), outStream);
archive.MoveCurPos(item.PackSize); archive.MoveCurPos(item.PackSize);
memRef.FreeOpt(&memManager); memRef.FreeOpt(&memManager);
/*
if (reportArcProp)
{
stat.UpdateWithItem(item);
RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
}
*/
} }
else else
{ {
@ -1202,6 +1300,14 @@ static HRESULT Update2(
options.IsRealAesMode(), options.AesKeyMode, item); options.IsRealAesMode(), options.AesKeyMode, item);
archive.WriteLocalHeader_Replace(item); archive.WriteLocalHeader_Replace(item);
/*
if (reportArcProp)
{
stat.UpdateWithItem(item);
RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
}
*/
} }
else else
{ {
@ -1230,7 +1336,14 @@ static HRESULT Update2(
RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL)); RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL));
archive.WriteCentralDir(items, comment); archive.WriteCentralDir(items, comment);
/*
if (reportArcProp)
{
RINOK(ReportArcProps(reportArcProp, stat));
}
*/
complexity += kCentralHeaderSize * updateItems.Size() + 1; complexity += kCentralHeaderSize * updateItems.Size() + 1;
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity); mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL); return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL);
@ -1472,6 +1585,7 @@ HRESULT Update(
CObjectVector<CUpdateItem> &updateItems, CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream, ISequentialOutStream *seqOutStream,
CInArchive *inArchive, bool removeSfx, CInArchive *inArchive, bool removeSfx,
const CUpdateOptions &updateOptions,
const CCompressionMethodMode &compressionMethodMode, const CCompressionMethodMode &compressionMethodMode,
IArchiveUpdateCallback *updateCallback) IArchiveUpdateCallback *updateCallback)
{ {
@ -1529,6 +1643,7 @@ HRESULT Update(
EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS
outArchive, inArchive, outArchive, inArchive,
inputItems, updateItems, inputItems, updateItems,
updateOptions,
compressionMethodMode, outSeqMode, compressionMethodMode, outSeqMode,
inArchive ? &inArchive->ArcInfo.Comment : NULL, inArchive ? &inArchive->ArcInfo.Comment : NULL,
updateCallback); updateCallback);

View file

@ -30,7 +30,9 @@ struct CUpdateItem
bool NewData; bool NewData;
bool NewProps; bool NewProps;
bool IsDir; bool IsDir;
bool NtfsTimeIsDefined; bool Write_NtfsTime;
bool Write_UnixTime;
// bool Write_UnixTime_ATime;
bool IsUtf8; bool IsUtf8;
// bool IsAltStream; // bool IsAltStream;
int IndexInArc; int IndexInArc;
@ -50,30 +52,50 @@ struct CUpdateItem
void Clear() void Clear()
{ {
IsDir = false; IsDir = false;
NtfsTimeIsDefined = false;
Write_NtfsTime = false;
Write_UnixTime = false;
IsUtf8 = false; IsUtf8 = false;
// IsAltStream = false; // IsAltStream = false;
Time = 0;
Size = 0; Size = 0;
Name.Empty(); Name.Empty();
Name_Utf.Free(); Name_Utf.Free();
Comment.Free(); Comment.Free();
FILETIME_Clear(Ntfs_MTime);
FILETIME_Clear(Ntfs_ATime);
FILETIME_Clear(Ntfs_CTime);
} }
CUpdateItem(): CUpdateItem():
IsDir(false), IsDir(false),
NtfsTimeIsDefined(false), Write_NtfsTime(false),
Write_UnixTime(false),
IsUtf8(false), IsUtf8(false),
// IsAltStream(false), // IsAltStream(false),
Time(0),
Size(0) Size(0)
{} {}
}; };
struct CUpdateOptions
{
bool Write_MTime;
bool Write_ATime;
bool Write_CTime;
};
HRESULT Update( HRESULT Update(
DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS
const CObjectVector<CItemEx> &inputItems, const CObjectVector<CItemEx> &inputItems,
CObjectVector<CUpdateItem> &updateItems, CObjectVector<CUpdateItem> &updateItems,
ISequentialOutStream *seqOutStream, ISequentialOutStream *seqOutStream,
CInArchive *inArchive, bool removeSfx, CInArchive *inArchive, bool removeSfx,
const CUpdateOptions &updateOptions,
const CCompressionMethodMode &compressionMethodMode, const CCompressionMethodMode &compressionMethodMode,
IArchiveUpdateCallback *updateCallback); IArchiveUpdateCallback *updateCallback);

View file

@ -18,7 +18,6 @@ WIN_OBJS = $(WIN_OBJS) \
$O\FileLink.obj \ $O\FileLink.obj \
$O\FileSystem.obj \ $O\FileSystem.obj \
$O\MemoryLock.obj \ $O\MemoryLock.obj \
$O\PropVariantConv.obj \
$O\Registry.obj \ $O\Registry.obj \
$O\SystemInfo.obj \ $O\SystemInfo.obj \

View file

@ -81,7 +81,6 @@ COMMON_OBJS_2 = \
WIN_OBJS_2 = \ WIN_OBJS_2 = \
$O/ErrorMsg.o \ $O/ErrorMsg.o \
$O/FileLink.o \ $O/FileLink.o \
$O/PropVariantConv.o \
$O/SystemInfo.o \ $O/SystemInfo.o \
7ZIP_COMMON_OBJS_2 = \ 7ZIP_COMMON_OBJS_2 = \

View file

@ -20,7 +20,6 @@ WIN_OBJS = $(WIN_OBJS) \
$O\MemoryLock.obj \ $O\MemoryLock.obj \
$O\Menu.obj \ $O\Menu.obj \
$O\ProcessUtils.obj \ $O\ProcessUtils.obj \
$O\PropVariantConv.obj \
$O\Registry.obj \ $O\Registry.obj \
$O\ResourceString.obj \ $O\ResourceString.obj \
$O\SystemInfo.obj \ $O\SystemInfo.obj \

View file

@ -3,5 +3,5 @@
STRINGTABLE STRINGTABLE
BEGIN 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 END

View file

@ -24,6 +24,7 @@ WIN_OBJS = \
$O\FileIO.obj \ $O\FileIO.obj \
$O\FileName.obj \ $O\FileName.obj \
$O\PropVariant.obj \ $O\PropVariant.obj \
$O\PropVariantConv.obj \
$O\PropVariantUtils.obj \ $O\PropVariantUtils.obj \
$O\Synchronization.obj \ $O\Synchronization.obj \
$O\System.obj \ $O\System.obj \
@ -53,6 +54,7 @@ WIN_OBJS = \
$O\VirtThread.obj \ $O\VirtThread.obj \
AR_OBJS = \ AR_OBJS = \
$O\ApfsHandler.obj \
$O\ApmHandler.obj \ $O\ApmHandler.obj \
$O\ArHandler.obj \ $O\ArHandler.obj \
$O\ArjHandler.obj \ $O\ArjHandler.obj \
@ -72,6 +74,7 @@ AR_OBJS = \
$O\HandlerCont.obj \ $O\HandlerCont.obj \
$O\HfsHandler.obj \ $O\HfsHandler.obj \
$O\IhexHandler.obj \ $O\IhexHandler.obj \
$O\LpHandler.obj \
$O\LzhHandler.obj \ $O\LzhHandler.obj \
$O\LzmaHandler.obj \ $O\LzmaHandler.obj \
$O\MachoHandler.obj \ $O\MachoHandler.obj \
@ -83,6 +86,7 @@ AR_OBJS = \
$O\PpmdHandler.obj \ $O\PpmdHandler.obj \
$O\QcowHandler.obj \ $O\QcowHandler.obj \
$O\RpmHandler.obj \ $O\RpmHandler.obj \
$O\SparseHandler.obj \
$O\SplitHandler.obj \ $O\SplitHandler.obj \
$O\SquashfsHandler.obj \ $O\SquashfsHandler.obj \
$O\SwfHandler.obj \ $O\SwfHandler.obj \

View file

@ -59,6 +59,7 @@ WIN_OBJS = \
$O/FileIO.o \ $O/FileIO.o \
$O/FileName.o \ $O/FileName.o \
$O/PropVariant.o \ $O/PropVariant.o \
$O/PropVariantConv.o \
$O/PropVariantUtils.o \ $O/PropVariantUtils.o \
$O/System.o \ $O/System.o \
$O/TimeUtils.o \ $O/TimeUtils.o \
@ -82,6 +83,7 @@ WIN_OBJS = \
$O/UniqBlocks.o \ $O/UniqBlocks.o \
AR_OBJS = \ AR_OBJS = \
$O/ApfsHandler.o \
$O/ApmHandler.o \ $O/ApmHandler.o \
$O/ArHandler.o \ $O/ArHandler.o \
$O/ArjHandler.o \ $O/ArjHandler.o \
@ -101,6 +103,7 @@ AR_OBJS = \
$O/HandlerCont.o \ $O/HandlerCont.o \
$O/HfsHandler.o \ $O/HfsHandler.o \
$O/IhexHandler.o \ $O/IhexHandler.o \
$O/LpHandler.o \
$O/LzhHandler.o \ $O/LzhHandler.o \
$O/LzmaHandler.o \ $O/LzmaHandler.o \
$O/MachoHandler.o \ $O/MachoHandler.o \
@ -112,6 +115,7 @@ AR_OBJS = \
$O/PpmdHandler.o \ $O/PpmdHandler.o \
$O/QcowHandler.o \ $O/QcowHandler.o \
$O/RpmHandler.o \ $O/RpmHandler.o \
$O/SparseHandler.o \
$O/SplitHandler.o \ $O/SplitHandler.o \
$O/SquashfsHandler.o \ $O/SquashfsHandler.o \
$O/SwfHandler.o \ $O/SwfHandler.o \

View file

@ -2763,6 +2763,10 @@ SOURCE=..\..\Archive\Udf\UdfIn.h
# End Group # End Group
# Begin Source File # Begin Source File
SOURCE=..\..\Archive\ApfsHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\ApmHandler.cpp SOURCE=..\..\Archive\ApmHandler.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -2851,6 +2855,10 @@ SOURCE=..\..\Archive\IhexHandler.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\..\Archive\LpHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\LzhHandler.cpp SOURCE=..\..\Archive\LzhHandler.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -2905,6 +2913,10 @@ SOURCE=..\..\Archive\RpmHandler.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\..\Archive\SparseHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\SplitHandler.cpp SOURCE=..\..\Archive\SplitHandler.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File
@ -3029,6 +3041,14 @@ SOURCE=..\..\..\Windows\PropVariant.h
# End Source File # End Source File
# Begin 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 SOURCE=..\..\..\Windows\PropVariantUtils.cpp
# End Source File # End Source File
# Begin Source File # Begin Source File

View file

@ -28,10 +28,11 @@ MY_VERSION_INFO_DLL("7z Plugin" , "7z")
22 ICON "../../Archive/Icons/ntfs.ico" 22 ICON "../../Archive/Icons/ntfs.ico"
23 ICON "../../Archive/Icons/xz.ico" 23 ICON "../../Archive/Icons/xz.ico"
24 ICON "../../Archive/Icons/squashfs.ico" 24 ICON "../../Archive/Icons/squashfs.ico"
25 ICON "../../Archive/Icons/apfs.ico"
STRINGTABLE STRINGTABLE
BEGIN 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 END

View file

@ -515,7 +515,7 @@ static int main2(int numArgs, const char *args[])
if (inStreamSpec) if (inStreamSpec)
{ {
if (!inStreamSpec->File.GetLength(fileSize)) if (!inStreamSpec->GetLength(fileSize))
throw "Cannot get file length"; throw "Cannot get file length";
fileSizeDefined = true; fileSizeDefined = true;
if (!stdOutMode) if (!stdOutMode)

View file

@ -2,18 +2,30 @@
#include "StdAfx.h" #include "StdAfx.h"
// #include <stdio.h>
#ifndef _WIN32 #ifndef _WIN32
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <errno.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 #endif
#include "../../Windows/FileFind.h"
#ifdef SUPPORT_DEVICE_FILE #ifdef SUPPORT_DEVICE_FILE
#include "../../../C/Alloc.h" #include "../../../C/Alloc.h"
#include "../../Common/Defs.h" #include "../../Common/Defs.h"
#endif #endif
#include "../PropID.h"
#include "FileStreams.h" #include "FileStreams.h"
static inline HRESULT GetLastError_HRESULT() static inline HRESULT GetLastError_HRESULT()
@ -37,12 +49,19 @@ static const UInt32 kClusterSize = 1 << 18;
#endif #endif
CInFileStream::CInFileStream(): CInFileStream::CInFileStream():
#ifdef SUPPORT_DEVICE_FILE #ifdef SUPPORT_DEVICE_FILE
VirtPos(0), VirtPos(0),
PhyPos(0), PhyPos(0),
Buf(0), Buf(0),
BufSize(0), BufSize(0),
#endif #endif
#ifndef _WIN32
_uid(0),
_gid(0),
StoreOwnerId(false),
StoreOwnerName(false),
#endif
_info_WasLoaded(false),
SupportHardLinks(false), SupportHardLinks(false),
Callback(NULL), Callback(NULL),
CallbackRef(0) CallbackRef(0)
@ -56,7 +75,7 @@ CInFileStream::~CInFileStream()
#endif #endif
if (Callback) if (Callback)
Callback->InFileStream_On_Destroy(CallbackRef); Callback->InFileStream_On_Destroy(this, CallbackRef);
} }
STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) 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) 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; 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 (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
if (cTime) *cTime = info.ftCreationTime; if (cTime) *cTime = info.ftCreationTime;
@ -316,13 +341,18 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
if (attrib) *attrib = info.dwFileAttributes; if (attrib) *attrib = info.dwFileAttributes;
return S_OK; return S_OK;
} }
return GetLastError_HRESULT();
} }
STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
{ {
if (!_info_WasLoaded)
RINOK(ReloadProps());
const BY_HANDLE_FILE_INFORMATION &info = _info;
/*
BY_HANDLE_FILE_INFORMATION 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->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
props->VolID = info.dwVolumeSerialNumber; props->VolID = info.dwVolumeSerialNumber;
@ -335,27 +365,114 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
props->MTime = info.ftLastWriteTime; props->MTime = info.ftLastWriteTime;
return S_OK; 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) #elif !defined(_WIN32)
STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) 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; struct stat st;
if (File.my_fstat(&st) != 0) if (File.my_fstat(&st) != 0)
return GetLastError_HRESULT(); return GetLastError_HRESULT();
*/
if (size) *size = (UInt64)st.st_size; if (size) *size = (UInt64)st.st_size;
#ifdef __APPLE__ if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime);
if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, *cTime); if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime);
if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, *aTime); if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime);
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 (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode); if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
return S_OK; return S_OK;
@ -365,9 +482,14 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props) STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
{ {
if (!_info_WasLoaded)
RINOK(ReloadProps());
const struct stat &st = _info;
/*
struct stat st; struct stat st;
if (File.my_fstat(&st) != 0) if (File.my_fstat(&st) != 0)
return GetLastError_HRESULT(); return GetLastError_HRESULT();
*/
props->Size = (UInt64)st.st_size; 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->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); props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
#ifdef __APPLE__ FiTime_To_FILETIME (ST_CTIME(st), props->CTime);
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, props->CTime); FiTime_To_FILETIME (ST_ATIME(st), props->ATime);
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, props->ATime); FiTime_To_FILETIME (ST_MTIME(st), props->MTime);
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
/* /*
printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n" printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n"
@ -402,8 +518,130 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
return S_OK; 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 #endif
////////////////////////// //////////////////////////
// COutFileStream // COutFileStream

View file

@ -14,10 +14,14 @@
#include "../IStream.h" #include "../IStream.h"
#include "UniqBlocks.h"
class CInFileStream;
struct IInFileStream_Callback struct IInFileStream_Callback
{ {
virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0; 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: class CInFileStream:
@ -25,10 +29,11 @@ class CInFileStream:
public IStreamGetSize, public IStreamGetSize,
public IStreamGetProps, public IStreamGetProps,
public IStreamGetProps2, public IStreamGetProps2,
public IStreamGetProp,
public CMyUnknownImp public CMyUnknownImp
{ {
public:
NWindows::NFile::NIO::CInFile File; NWindows::NFile::NIO::CInFile File;
public:
#ifdef USE_WIN_FILE #ifdef USE_WIN_FILE
@ -42,22 +47,46 @@ public:
#endif #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; IInFileStream_Callback *Callback;
UINT_PTR CallbackRef; UINT_PTR CallbackRef;
virtual ~CInFileStream(); virtual ~CInFileStream();
CInFileStream(); CInFileStream();
void Set_PreserveATime(bool v)
{
File.PreserveATime = v;
}
bool GetLength(UInt64 &length) const throw()
{
return File.GetLength(length);
}
bool Open(CFSTR fileName) bool Open(CFSTR fileName)
{ {
_info_WasLoaded = false;
return File.Open(fileName); return File.Open(fileName);
} }
bool OpenShared(CFSTR fileName, bool shareForWrite) bool OpenShared(CFSTR fileName, bool shareForWrite)
{ {
_info_WasLoaded = false;
return File.OpenShared(fileName, shareForWrite); return File.OpenShared(fileName, shareForWrite);
} }
@ -65,6 +94,7 @@ public:
MY_QUERYINTERFACE_ENTRY(IStreamGetSize) MY_QUERYINTERFACE_ENTRY(IStreamGetSize)
MY_QUERYINTERFACE_ENTRY(IStreamGetProps) MY_QUERYINTERFACE_ENTRY(IStreamGetProps)
MY_QUERYINTERFACE_ENTRY(IStreamGetProps2) MY_QUERYINTERFACE_ENTRY(IStreamGetProps2)
MY_QUERYINTERFACE_ENTRY(IStreamGetProp)
MY_QUERYINTERFACE_END MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE MY_ADDREF_RELEASE
@ -74,6 +104,8 @@ public:
STDMETHOD(GetSize)(UInt64 *size); STDMETHOD(GetSize)(UInt64 *size);
STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib); STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib);
STDMETHOD(GetProps2)(CStreamFileProps *props); STDMETHOD(GetProps2)(CStreamFileProps *props);
STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value);
STDMETHOD(ReloadProps)();
}; };
class CStdInFileStream: class CStdInFileStream:
@ -110,11 +142,11 @@ public:
UInt64 ProcessedSize; 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); 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) MY_UNKNOWN_IMP1(IOutStream)

View file

@ -77,7 +77,8 @@ bool CInBufferBase::ReadByte_FromNewBlock(Byte &b)
{ {
if (!ReadBlock()) if (!ReadBlock())
{ {
NumExtraBytes++; // 22.00: we don't increment (NumExtraBytes) here
// NumExtraBytes++;
b = 0xFF; b = 0xFF;
return false; return false;
} }

View file

@ -154,44 +154,70 @@ STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize
{ {
if (processedSize) if (processedSize)
*processedSize = 0; *processedSize = 0;
if (_virtPos >= Extents.Back().Virt) const UInt64 virt = _virtPos;
if (virt >= Extents.Back().Virt)
return S_OK; return S_OK;
if (size == 0) if (size == 0)
return S_OK; return S_OK;
unsigned left = 0, right = Extents.Size() - 1; unsigned left = _prevExtentIndex;
for (;;) if (virt < Extents[left].Virt ||
virt >= Extents[left + 1].Virt)
{ {
unsigned mid = (left + right) / 2; left = 0;
if (mid == left) unsigned right = Extents.Size() - 1;
break; for (;;)
if (_virtPos < Extents[mid].Virt) {
right = mid; const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
else if (mid == left)
left = mid; 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]; const CSeekExtent &extent = Extents[left];
UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
if (_needStartSeek || _phyPos != phyPos) if (extent.Is_ZeroFill())
{ {
_needStartSeek = false; memset(data, 0, size);
_phyPos = phyPos; _virtPos += size;
RINOK(SeekToPhys()); if (processedSize)
*processedSize = size;
return S_OK;
}
{
const UInt64 phy = extent.Phy + (virt - extent.Virt);
if (_phyPos != phy)
{
_phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
RINOK(Stream->Seek((Int64)phy, STREAM_SEEK_SET, NULL));
_phyPos = phy;
}
} }
UInt64 rem = Extents[left + 1].Virt - _virtPos; const HRESULT res = Stream->Read(data, size, &size);
if (size > rem)
size = (UInt32)rem;
HRESULT res = Stream->Read(data, size, &size);
_phyPos += size;
_virtPos += 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) if (processedSize)
*processedSize = size; *processedSize = size;
return res; return res;
} }
STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{ {
switch (seekOrigin) switch (seekOrigin)

Some files were not shown because too many files have changed in this diff Show more