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
; 2021-12-25 : Igor Pavlov : Public domain
; 2022-05-16 : Igor Pavlov : Public domain
; UASM can require these changes
; OPTION FRAMEPRESERVEFLAGS:ON
; OPTION PROLOGUE:NONE
; OPTION EPILOGUE:NONE
ifdef @wordsize
; @wordsize is defined only in JWASM and ASMC and is not defined in MASM
; @wordsize eq 8 for 64-bit x64

View file

@ -1,5 +1,5 @@
; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions
; 2021-03-10 : Igor Pavlov : Public domain
; 2022-04-17 : Igor Pavlov : Public domain
include 7zAsm.asm
@ -55,13 +55,19 @@ ifndef x64
.xmm
endif
; jwasm-based assemblers for linux and linker from new versions of binutils
; can generate incorrect code for load [ARRAY + offset] instructions.
; 22.00: we load K_CONST offset to (rTable) register to avoid jwasm+binutils problem
rTable equ r0
; rTable equ K_CONST
ifdef x64
rNum equ REG_ABI_PARAM_2
if (IS_LINUX eq 0)
LOCAL_SIZE equ (16 * 2)
endif
else
rNum equ r0
rNum equ r3
LOCAL_SIZE equ (16 * 1)
endif
@ -103,15 +109,18 @@ MY_PROLOG macro
movdqa [r4 + 16], xmm9
endif
else ; x86
if (IS_CDECL gt 0)
mov rState, [r4 + REG_SIZE * 1]
mov rData, [r4 + REG_SIZE * 2]
mov rNum, [r4 + REG_SIZE * 3]
else ; fastcall
mov rNum, [r4 + REG_SIZE * 1]
endif
push r3
push r5
mov r5, r4
NUM_PUSH_REGS equ 2
PARAM_OFFSET equ (REG_SIZE * (1 + NUM_PUSH_REGS))
if (IS_CDECL gt 0)
mov rState, [r4 + PARAM_OFFSET]
mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1]
mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2]
else ; fastcall
mov rNum, [r4 + PARAM_OFFSET]
endif
and r4, -16
sub r4, LOCAL_SIZE
endif
@ -129,6 +138,7 @@ MY_EPILOG macro
else ; x86
mov r4, r5
pop r5
pop r3
endif
MY_ENDP
endm
@ -171,7 +181,7 @@ pre2 equ 2
RND4 macro k
movdqa msg, xmmword ptr [K_CONST + (k) * 16]
movdqa msg, xmmword ptr [rTable + (k) * 16]
paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4)))
MY_sha256rnds2 state0_N, state1_N
pshufd msg, msg, 0eH
@ -210,6 +220,8 @@ endm
MY_PROC Sha256_UpdateBlocks_HW, 3
MY_PROLOG
lea rTable, [K_CONST]
cmp rNum, 0
je end_c

View file

@ -1,5 +1,5 @@
/* 7zTypes.h -- Basic types
2021-12-25 : Igor Pavlov : Public domain */
2022-04-01 : Igor Pavlov : Public domain */
#ifndef __7Z_TYPES_H
#define __7Z_TYPES_H
@ -133,10 +133,6 @@ typedef int WRes;
#define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
*/
// gcc / clang : (sizeof(long) == sizeof(void*)) in 32/64 bits
typedef long INT_PTR;
typedef unsigned long UINT_PTR;
#define TEXT(quote) quote
#define FILE_ATTRIBUTE_READONLY 0x0001
@ -520,6 +516,14 @@ struct ISzAlloc
#endif
#define k_PropVar_TimePrec_0 0
#define k_PropVar_TimePrec_Unix 1
#define k_PropVar_TimePrec_DOS 2
#define k_PropVar_TimePrec_HighPrec 3
#define k_PropVar_TimePrec_Base 16
#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7)
#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9)
EXTERN_C_END
#endif

View file

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

View file

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

View file

@ -2,6 +2,8 @@
#include "StdAfx.h"
#include "../../../Windows/TimeUtils.h"
#include "7zFolderInStream.h"
namespace NArchive {
@ -13,16 +15,16 @@ void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
_updateCallback = updateCallback;
_indexes = indexes;
_numFiles = numFiles;
_index = 0;
Processed.ClearAndReserve(numFiles);
CRCs.ClearAndReserve(numFiles);
Sizes.ClearAndReserve(numFiles);
_pos = 0;
_crc = CRC_INIT_VAL;
_size_Defined = false;
_size = 0;
if (Need_CTime) CTimes.ClearAndReserve(numFiles);
if (Need_ATime) ATimes.ClearAndReserve(numFiles);
if (Need_MTime) MTimes.ClearAndReserve(numFiles);
if (Need_Attrib) Attribs.ClearAndReserve(numFiles);
TimesDefined.ClearAndReserve(numFiles);
_stream.Release();
}
@ -32,44 +34,101 @@ HRESULT CFolderInStream::OpenStream()
_pos = 0;
_crc = CRC_INIT_VAL;
_size_Defined = false;
_times_Defined = false;
_size = 0;
FILETIME_Clear(_cTime);
FILETIME_Clear(_aTime);
FILETIME_Clear(_mTime);
_attrib = 0;
while (_index < _numFiles)
while (Processed.Size() < _numFiles)
{
CMyComPtr<ISequentialInStream> stream;
HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream);
if (result != S_OK)
{
if (result != S_FALSE)
return result;
}
const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream);
if (result != S_OK && result != S_FALSE)
return result;
_stream = stream;
if (stream)
{
CMyComPtr<IStreamGetSize> streamGetSize;
stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
if (streamGetSize)
{
if (streamGetSize->GetSize(&_size) == S_OK)
_size_Defined = true;
CMyComPtr<IStreamGetProps> getProps;
stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
if (getProps)
{
// access could be changed in first myx pass
if (getProps->GetProps(&_size,
Need_CTime ? &_cTime : NULL,
Need_ATime ? &_aTime : NULL,
Need_MTime ? &_mTime : NULL,
Need_Attrib ? &_attrib : NULL)
== S_OK)
{
_size_Defined = true;
_times_Defined = true;
}
return S_OK;
}
}
{
CMyComPtr<IStreamGetSize> streamGetSize;
stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
if (streamGetSize)
{
if (streamGetSize->GetSize(&_size) == S_OK)
_size_Defined = true;
}
return S_OK;
}
return S_OK;
}
_index++;
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
AddFileInfo(result == S_OK);
RINOK(AddFileInfo(result == S_OK));
}
return S_OK;
}
void CFolderInStream::AddFileInfo(bool isProcessed)
static void AddFt(CRecordVector<UInt64> &vec, const FILETIME &ft)
{
Processed.Add(isProcessed);
Sizes.Add(_pos);
CRCs.Add(CRC_GET_DIGEST(_crc));
vec.AddInReserved(FILETIME_To_UInt64(ft));
}
/*
HRESULT ReportItemProps(IArchiveUpdateCallbackArcProp *reportArcProp,
UInt32 index, UInt64 size, const UInt32 *crc)
{
PROPVARIANT prop;
prop.vt = VT_EMPTY;
prop.wReserved1 = 0;
NWindows::NCOM::PropVarEm_Set_UInt64(&prop, size);
RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
if (crc)
{
NWindows::NCOM::PropVarEm_Set_UInt32(&prop, *crc);
RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
}
return reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK);
}
*/
HRESULT CFolderInStream::AddFileInfo(bool isProcessed)
{
// const UInt32 index = _indexes[Processed.Size()];
Processed.AddInReserved(isProcessed);
Sizes.AddInReserved(_pos);
const UInt32 crc = CRC_GET_DIGEST(_crc);
CRCs.AddInReserved(crc);
TimesDefined.AddInReserved(_times_Defined);
if (Need_CTime) AddFt(CTimes, _cTime);
if (Need_ATime) AddFt(ATimes, _aTime);
if (Need_MTime) AddFt(MTimes, _mTime);
if (Need_Attrib) Attribs.AddInReserved(_attrib);
/*
if (isProcessed && _reportArcProp)
RINOK(ReportItemProps(_reportArcProp, index, _pos, &crc))
*/
return _updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
}
STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
@ -95,18 +154,10 @@ STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSiz
}
_stream.Release();
_index++;
AddFileInfo(true);
_pos = 0;
_crc = CRC_INIT_VAL;
_size_Defined = false;
_size = 0;
RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
RINOK(AddFileInfo(true));
}
if (_index >= _numFiles)
if (Processed.Size() >= _numFiles)
break;
RINOK(OpenStream());
}

View file

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

View file

@ -278,7 +278,7 @@ static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVe
{
UInt64 value;
if (v.GetItem(index, value))
PropVarEm_Set_FileTime64(prop, value);
PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns);
}
bool CHandler::IsFolderEncrypted(CNum folderIndex) const

View file

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

View file

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

View file

@ -15,7 +15,13 @@ REGISTER_ARC_IO_DECREMENT_SIG(
"7z", "7z", NULL, 7,
k_Signature_Dec,
0,
NArcInfoFlags::kFindSignature,
NULL);
NArcInfoFlags::kFindSignature
| NArcInfoFlags::kCTime
| NArcInfoFlags::kATime
| NArcInfoFlags::kMTime
| NArcInfoFlags::kMTime_Default
, TIME_PREC_TO_ARC_FLAGS_MASK(NFileTimeType::kWindows)
| TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(NFileTimeType::kWindows)
, NULL);
}}

View file

@ -804,10 +804,20 @@ struct CAnalysis
bool ParseExe;
bool ParseAll;
/*
bool Need_ATime;
bool ATime_Defined;
FILETIME ATime;
*/
CAnalysis():
ParseWav(true),
ParseExe(false),
ParseAll(false)
/*
, Need_ATime(false)
, ATime_Defined(false)
*/
{}
HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode);
@ -887,6 +897,18 @@ HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMo
HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);
if (result == S_OK && stream)
{
/*
if (Need_ATime)
{
// access time could be changed in analysis pass
CMyComPtr<IStreamGetProps> getProps;
stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
if (getProps)
if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK)
ATime_Defined = true;
}
*/
size_t size = kAnalysisBufSize;
result = ReadStream(stream, Buffer, &size);
stream.Release();
@ -1586,6 +1608,11 @@ HRESULT Update(
CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;
updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);
/*
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
*/
// size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
/*
@ -1756,6 +1783,7 @@ HRESULT Update(
{
CAnalysis analysis;
// analysis.Need_ATime = options.Need_ATime;
if (options.AnalysisLevel == 0)
{
analysis.ParseWav = false;
@ -1790,7 +1818,15 @@ HRESULT Update(
CFilterMode2 fm;
if (useFilters)
{
// analysis.ATime_Defined = false;
RINOK(analysis.GetFilterGroup(i, ui, fm));
/*
if (analysis.ATime_Defined)
{
ui.ATime = FILETIME_To_UInt64(analysis.ATime);
ui.ATime_WasReadByAnalysis = true;
}
*/
}
fm.Encrypted = method.PasswordIsDefined;
@ -2374,13 +2410,33 @@ HRESULT Update(
RINOK(lps->SetCur());
/*
const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size();
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kBlockIndex, (UInt32)folderIndex,
NUpdateNotifyOp::kAdd));
}
*/
CFolderInStream *inStreamSpec = new CFolderInStream;
CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
// inStreamSpec->_reportArcProp = reportArcProp;
inStreamSpec->Need_CTime = options.Need_CTime;
inStreamSpec->Need_ATime = options.Need_ATime;
inStreamSpec->Need_MTime = options.Need_MTime;
inStreamSpec->Need_Attrib = options.Need_Attrib;
inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
unsigned startPackIndex = newDatabase.PackSizes.Size();
UInt64 curFolderUnpackSize = totalSize;
// curFolderUnpackSize = (UInt64)(Int64)-1;
// curFolderUnpackSize = (UInt64)(Int64)-1; // for debug
RINOK(encoder.Encode(
EXTERNAL_CODECS_LOC_VARS
@ -2393,8 +2449,11 @@ HRESULT Update(
if (!inStreamSpec->WasFinished())
return E_FAIL;
UInt64 packSize = 0;
// const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex;
for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
lps->OutSize += newDatabase.PackSizes[startPackIndex];
packSize += newDatabase.PackSizes[startPackIndex];
lps->OutSize += packSize;
lps->InSize += curFolderUnpackSize;
// for ()
@ -2403,6 +2462,8 @@ HRESULT Update(
CNum numUnpackStreams = 0;
UInt64 skippedSize = 0;
UInt64 procSize = 0;
// unsigned numProcessedFiles = 0;
for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)
{
@ -2429,14 +2490,16 @@ HRESULT Update(
*/
if (!inStreamSpec->Processed[subIndex])
{
// we don't add file here
skippedSize += ui.Size;
continue;
// file.Name += ".locked";
continue; // comment it for debug
// name += ".locked"; // for debug
}
file.Crc = inStreamSpec->CRCs[subIndex];
file.Size = inStreamSpec->Sizes[subIndex];
procSize += file.Size;
// if (file.Size >= 0) // test purposes
if (file.Size != 0)
{
@ -2450,6 +2513,23 @@ HRESULT Update(
file.HasStream = false;
}
if (inStreamSpec->TimesDefined[subIndex])
{
if (inStreamSpec->Need_CTime)
{ file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; }
if (inStreamSpec->Need_ATime
// && !ui.ATime_WasReadByAnalysis
)
{ file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; }
if (inStreamSpec->Need_MTime)
{ file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; }
if (inStreamSpec->Need_Attrib)
{
file2.AttribDefined = true;
file2.Attrib = inStreamSpec->Attribs[subIndex];
}
}
/*
file.Parent = ui.ParentFolderIndex;
if (ui.TreeFolderIndex >= 0)
@ -2457,9 +2537,22 @@ HRESULT Update(
if (totalSecureDataSize != 0)
newDatabase.SecureIDs.Add(ui.SecureIndex);
*/
/*
if (reportArcProp)
{
RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size,
file.CrcDefined ? &file.Crc : NULL))
}
*/
// numProcessedFiles++;
newDatabase.AddFile(file, file2, name);
}
// it's optional check to ensure that sizes are correct
if (procSize != curFolderUnpackSize)
return E_FAIL;
// numUnpackStreams = 0 is very bad case for locked files
// v3.13 doesn't understand it.
newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
@ -2470,6 +2563,44 @@ HRESULT Update(
complexity -= skippedSize;
RINOK(updateCallback->SetTotal(complexity));
}
/*
if (reportArcProp)
{
PROPVARIANT prop;
prop.vt = VT_EMPTY;
prop.wReserved1 = 0;
{
NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles);
RINOK(reportArcProp->ReportProp(
NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop));
}
{
NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize);
RINOK(reportArcProp->ReportProp(
NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop));
}
{
NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize);
RINOK(reportArcProp->ReportProp(
NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop));
}
{
NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams);
RINOK(reportArcProp->ReportProp(
NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop));
}
RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK));
}
*/
/*
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kBlockIndex, (UInt32)folderIndex,
NUpdateNotifyOp::kOpFinished));
}
*/
}
}

View file

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

File diff suppressed because it is too large Load diff

View file

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

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

View file

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

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

View file

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

View file

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

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)
{
Init();
for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &value = values[i];
if (name[0] == L'x')
{
UInt32 a = 9;
RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
_level = a;
AddProp_Level(a);
continue;
}
{
HRESULT hres;
if (SetCommonProperty(name, value, hres))
{
RINOK(hres)
continue;
}
}
RINOK(ParseMethodFromPROPVARIANT(names[i], value));
RINOK(SetProperty(names[i], values[i]));
}
return S_OK;
@ -275,4 +283,29 @@ HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PR
#endif
static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
{
RINOK(PROPVARIANT_to_bool(prop, dest.Val));
dest.Def = true;
return S_OK;
}
HRESULT CHandlerTimeOptions::Parse(const UString &name, const PROPVARIANT &prop, bool &processed)
{
processed = true;
if (name.IsEqualTo_Ascii_NoCase("tm")) { return PROPVARIANT_to_BoolPair(prop, Write_MTime); }
if (name.IsEqualTo_Ascii_NoCase("ta")) { return PROPVARIANT_to_BoolPair(prop, Write_ATime); }
if (name.IsEqualTo_Ascii_NoCase("tc")) { return PROPVARIANT_to_BoolPair(prop, Write_CTime); }
if (name.IsPrefixedBy_Ascii_NoCase("tp"))
{
UInt32 v = 0;
RINOK(ParsePropToUInt32(name.Ptr(2), prop, v));
Prec = v;
return S_OK;
}
processed = false;
return S_OK;
}
}

View file

@ -16,6 +16,7 @@ class CCommonMethodProps
protected:
void InitCommon()
{
// _Write_MTime = true;
#ifndef _7ZIP_ST
_numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
_numThreads_WasForced = false;
@ -118,11 +119,36 @@ public:
CSingleMethodProps() { InitSingle(); }
int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &values);
HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
};
#endif
struct CHandlerTimeOptions
{
CBoolPair Write_MTime;
CBoolPair Write_ATime;
CBoolPair Write_CTime;
UInt32 Prec;
void Init()
{
Write_MTime.Init();
Write_MTime.Val = true;
Write_ATime.Init();
Write_CTime.Init();
Prec = (UInt32)(Int32)-1;
}
CHandlerTimeOptions()
{
Init();
}
HRESULT Parse(const UString &name, const PROPVARIANT &prop, bool &processed);
};
}
#endif

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
#if defined(_WIN32) && !defined(UNDER_CE)
codePage

View file

@ -14,6 +14,8 @@ UString GetOsPath(const UString &name);
UString GetOsPath_Remove_TailSlash(const UString &name);
void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false);
void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len);
void NormalizeSlashes_in_FileName_for_OsPath(UString &name);
bool HasTailSlash(const AString &name, UINT codePage);

View file

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

View file

@ -125,6 +125,24 @@ STDAPI SetCaseSensitive(Int32 caseSensitive)
return S_OK;
}
/*
UInt32 g_ClientVersion;
STDAPI SetClientVersion(UInt32 version);
STDAPI SetClientVersion(UInt32 version)
{
g_ClientVersion = version;
return S_OK;
}
*/
/*
STDAPI SetProperty(Int32 id, const PROPVARIANT *value);
STDAPI SetProperty(Int32 id, const PROPVARIANT *value)
{
return S_OK;
}
*/
#ifdef EXTERNAL_CODECS
CExternalCodecs g_ExternalCodecs;

View file

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

View file

@ -111,14 +111,14 @@ static int GetLog(UInt32 num)
static const UInt32 kHeaderSize = 512;
API_FUNC_static_IsArc IsArc_Fat(const Byte *p, size_t size)
API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
{
if (size < kHeaderSize)
return k_IsArc_Res_NEED_MORE;
CHeader h;
return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO;
}
}
bool CHeader::Parse(const Byte *p)
{
@ -846,17 +846,18 @@ static const CStatProp kArcProps[] =
IMP_IInArchive_Props
IMP_IInArchive_ArcProps_WITH_NAME
static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
{
FILETIME localFileTime, utc;
if (NWindows::NTime::DosTimeToFileTime(dosTime, localFileTime))
if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
if (LocalFileTimeToFileTime(&localFileTime, &utc))
{
UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
t64 += ms10 * 100000;
utc.dwLowDateTime = (DWORD)t64;
utc.dwHighDateTime = (DWORD)(t64 >> 32);
prop = utc;
prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2);
}
}
@ -892,7 +893,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidPhySize: prop = PhySize; break;
case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
case kpidHeadersSize: prop = GetHeadersSize(); break;
case kpidMTime: if (VolItemDefined) FatTimeToProp(VolItem.MTime, 0, prop); break;
case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break;
case kpidShortComment:
case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
@ -920,9 +921,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPath: prop = GetItemPath(index); break;
case kpidShortName: prop = item.GetShortName(); break;
case kpidIsDir: prop = item.IsDir(); break;
case kpidMTime: FatTimeToProp(item.MTime, 0, prop); break;
case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break;
case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
case kpidATime: FatTimeToProp(((UInt32)item.ADate << 16), 0, prop); break;
case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break;
case kpidAttrib: prop = (UInt32)item.Attrib; break;
case kpidSize: if (!item.IsDir()) prop = item.Size; break;
case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;

View file

@ -23,6 +23,11 @@
using namespace NWindows;
namespace NArchive {
namespace NFat {
API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
}
namespace NGpt {
#define SIGNATURE { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 }
@ -51,6 +56,7 @@ struct CPartition
UInt64 FirstLba;
UInt64 LastLba;
UInt64 Flags;
const char *Ext; // detected later
Byte Name[kNameLen * 2];
bool IsUnused() const
@ -73,6 +79,7 @@ struct CPartition
LastLba = Get64(p + 40);
Flags = Get64(p + 48);
memcpy(Name, p + 56, kNameLen * 2);
Ext = NULL;
}
};
@ -252,6 +259,28 @@ HRESULT CHandler::Open2(IInStream *stream)
return S_OK;
}
static const unsigned k_Ntfs_Fat_HeaderSize = 512;
static const Byte k_NtfsSignature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
static bool IsNtfs(const Byte *p)
{
if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
return false;
if (memcmp(p + 3, k_NtfsSignature, ARRAY_SIZE(k_NtfsSignature)) != 0)
return false;
switch (p[0])
{
case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break;
case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break;
default: return false;
}
return true;
}
STDMETHODIMP CHandler::Open(IInStream *stream,
const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback * /* openArchiveCallback */)
@ -260,6 +289,42 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
Close();
RINOK(Open2(stream));
_stream = stream;
FOR_VECTOR (fileIndex, _items)
{
CPartition &item = _items[fileIndex];
const int typeIndex = FindPartType(item.Type);
if (typeIndex < 0)
continue;
const CPartType &t = kPartTypes[(unsigned)typeIndex];
if (t.Ext)
{
item.Ext = t.Ext;
continue;
}
if (t.Type && IsString1PrefixedByString2_NoCase_Ascii(t.Type, "Windows"))
{
CMyComPtr<ISequentialInStream> inStream;
if (GetStream(fileIndex, &inStream) == S_OK && inStream)
{
Byte temp[k_Ntfs_Fat_HeaderSize];
if (ReadStream_FAIL(inStream, temp, k_Ntfs_Fat_HeaderSize) == S_OK)
{
if (IsNtfs(temp))
{
item.Ext = "ntfs";
continue;
}
if (NFat::IsArc_Fat(temp, k_Ntfs_Fat_HeaderSize) == k_IsArc_Res_YES)
{
item.Ext = "fat";
continue;
}
}
}
}
}
return S_OK;
COM_TRY_END
}
@ -355,13 +420,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
{
s += '.';
const char *ext = NULL;
int typeIndex = FindPartType(item.Type);
if (typeIndex >= 0)
ext = kPartTypes[(unsigned)typeIndex].Ext;
if (!ext)
ext = "img";
s += ext;
s += (item.Ext ? item.Ext : "img");
}
prop = s;
break;
@ -375,7 +434,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
char s[48];
const char *res;
int typeIndex = FindPartType(item.Type);
const int typeIndex = FindPartType(item.Type);
if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type)
res = kPartTypes[(unsigned)typeIndex].Type;
else

View file

@ -475,6 +475,7 @@ class CHandler:
NDecoder::CCOMCoder *_decoderSpec;
CSingleMethodProps _props;
CHandlerTimeOptions _timeOptions;
public:
MY_UNKNOWN_IMP4(
@ -487,8 +488,15 @@ public:
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
CHandler()
CHandler():
_isArc(false),
_decoderSpec(NULL)
{}
void CreateDecoder()
{
if (_decoder)
return;
_decoderSpec = new NDecoder::CCOMCoder;
_decoder = _decoderSpec;
}
@ -528,7 +536,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
prop = v;
@ -567,12 +575,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
break;
// case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
case kpidMTime:
// gzip specification: MTIME = 0 means no time stamp is available.
if (_item.Time != 0)
{
FILETIME utc;
NTime::UnixTimeToFileTime(_item.Time, utc);
prop = utc;
}
PropVariant_SetFrom_UnixTime(prop, _item.Time);
break;
case kpidTimeType:
if (_item.Time != 0)
prop = (UInt32)NFileTimeType::kUnix;
break;
case kpidSize:
{
@ -644,6 +653,7 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
try
{
Close();
CreateDecoder();
_decoderSpec->SetInStream(stream);
_decoderSpec->InitInStream(true);
RINOK(_item.ReadHeader(_decoderSpec));
@ -672,7 +682,8 @@ STDMETHODIMP CHandler::Close()
_headerSize = 0;
_stream.Release();
_decoderSpec->ReleaseInStream();
if (_decoder)
_decoderSpec->ReleaseInStream();
return S_OK;
}
@ -699,6 +710,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
extractCallback->PrepareOperation(askMode);
CreateDecoder();
COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
outStreamSpec->SetStream(realOutStream);
@ -873,21 +886,99 @@ static const Byte kHostOS =
NHostOS::kUnix;
#endif
/*
static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
{
return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
}
static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
{
return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
}
static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
const CItem &item,
bool needTime,
bool needCrc,
const UInt64 *unpackSize)
{
NCOM::CPropVariant timeProp;
NCOM::CPropVariant sizeProp;
if (needTime)
{
FILETIME ft;
NTime::UnixTimeToFileTime(item.Time, ft);
timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
}
if (unpackSize)
{
sizeProp = *unpackSize;
RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
}
if (needCrc)
{
NCOM::CPropVariant prop;
prop = item.Crc;
RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop));
}
{
RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp));
}
RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
if (unpackSize)
{
RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
}
{
RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp));
}
return S_OK;
}
*/
static HRESULT UpdateArchive(
ISequentialOutStream *outStream,
UInt64 unpackSize,
CItem &item,
const CSingleMethodProps &props,
IArchiveUpdateCallback *updateCallback)
const CHandlerTimeOptions &timeOptions,
IArchiveUpdateCallback *updateCallback
// , IArchiveUpdateCallbackArcProp *reportArcProp
)
{
UInt64 complexity = 0;
RINOK(updateCallback->SetTotal(unpackSize));
RINOK(updateCallback->SetCompleted(&complexity));
UInt64 unpackSizeReal;
{
CMyComPtr<ISequentialInStream> fileInStream;
RINOK(updateCallback->GetStream(0, &fileInStream));
if (!fileInStream)
return S_FALSE;
{
CMyComPtr<IStreamGetProps> getProps;
fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
if (getProps)
{
FILETIME mTime;
UInt64 size;
if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK)
{
unpackSize = size;
if (timeOptions.Write_MTime.Val)
NTime::FileTime_To_UnixTime(mTime, item.Time);
}
}
}
UInt64 complexity = 0;
RINOK(updateCallback->SetTotal(unpackSize));
RINOK(updateCallback->SetCompleted(&complexity));
CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
inStreamSpec->SetStream(fileInStream);
@ -911,14 +1002,50 @@ static HRESULT UpdateArchive(
RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress));
item.Crc = inStreamSpec->GetCRC();
item.Size32 = (UInt32)inStreamSpec->GetSize();
unpackSizeReal = inStreamSpec->GetSize();
item.Size32 = (UInt32)unpackSizeReal;
RINOK(item.WriteFooter(outStream));
}
/*
if (reportArcProp)
{
RINOK(ReportArcProps(reportArcProp,
item,
props._Write_MTime, // item.Time != 0,
true, // writeCrc
&unpackSizeReal));
}
*/
return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
}
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{
*timeType = NFileTimeType::kUnix;
/*
if (_item.Time != 0)
{
we set NFileTimeType::kUnix in precision,
and we return NFileTimeType::kUnix in kpidTimeType
so GetFileTimeType() value is not used in any version of 7-zip.
}
else // (_item.Time == 0)
{
kpidMTime and kpidTimeType are not defined
before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList();
22.00 : GetFileTimeType() value is not used
}
*/
UInt32 t;
t = NFileTimeType::kUnix;
if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val)
{
t = GET_FileTimeType_NotDefined_for_GetFileTimeType;
// t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21
// t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21
}
*timeType = t;
return S_OK;
}
@ -936,6 +1063,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_FAIL;
RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
/*
CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
*/
CItem newItem;
if (!IntToBool(newProps))
@ -945,11 +1077,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
{
newItem.HostOS = kHostOS;
if (_timeOptions.Write_MTime.Val)
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(0, kpidMTime, &prop));
if (prop.vt == VT_FILETIME)
NTime::FileTimeToUnixTime(prop.filetime, newItem.Time);
NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time);
else if (prop.vt == VT_EMPTY)
newItem.Time = 0;
else
@ -990,7 +1123,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_INVALIDARG;
size = prop.uhVal.QuadPart;
}
return UpdateArchive(outStream, size, newItem, _props, updateCallback);
return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback);
}
if (indexInArchive != 0)
@ -1022,6 +1155,14 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
RINOK(_stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL));
/*
if (reportArcProp)
ReportArcProps(reportArcProp, newItem,
_props._Write_MTime,
false, // writeCrc
NULL); // unpacksize
*/
return NCompress::CopyStream(_stream, outStream, progress);
COM_TRY_END
@ -1029,16 +1170,48 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{
return _props.SetProperties(names, values, numProps);
_timeOptions.Init();
_props.Init();
for (UInt32 i = 0; i < numProps; i++)
{
UString name = names[i];
name.MakeLower_Ascii();
if (name.IsEmpty())
return E_INVALIDARG;
const PROPVARIANT &value = values[i];
{
bool processed = false;
RINOK(_timeOptions.Parse(name, value, processed));
if (processed)
{
if (_timeOptions.Write_CTime.Val ||
_timeOptions.Write_ATime.Val)
return E_INVALIDARG;
if ( _timeOptions.Prec != (UInt32)(Int32)-1
&& _timeOptions.Prec != k_PropVar_TimePrec_0
&& _timeOptions.Prec != k_PropVar_TimePrec_Unix
&& _timeOptions.Prec != k_PropVar_TimePrec_HighPrec
&& _timeOptions.Prec != k_PropVar_TimePrec_Base)
return E_INVALIDARG;
continue;
}
}
RINOK(_props.SetProperty(name, value));
}
return S_OK;
}
static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 };
REGISTER_ARC_IO(
"gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF,
k_Signature,
0,
NArcInfoFlags::kKeepName,
IsArc_Gz)
k_Signature, 0,
NArcInfoFlags::kKeepName
| NArcInfoFlags::kMTime
| NArcInfoFlags::kMTime_Default
, TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
| TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
, IsArc_Gz)
}}

View file

@ -14,6 +14,10 @@
namespace NArchive {
namespace NExt {
API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
}
STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
@ -132,11 +136,12 @@ STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosit
}
static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
// static const Byte k_Ext_Signature[] = { 0x53, 0xEF };
// static const unsigned k_Ext_Signature_offset = 0x438;
static const char *GetImgExt(ISequentialInStream *stream)
{
const size_t kHeaderSize = 1 << 10;
const size_t kHeaderSize = 1 << 11;
Byte buf[kHeaderSize];
if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
{
@ -146,6 +151,8 @@ static const char *GetImgExt(ISequentialInStream *stream)
return "gpt";
return "mbr";
}
if (NExt::IsArc_Ext(buf, kHeaderSize) == k_IsArc_Res_YES)
return "ext";
}
return NULL;
}
@ -208,6 +215,33 @@ STDMETHODIMP CHandlerImg::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
class CHandlerImgProgress:
public ICompressProgressInfo,
public CMyUnknownImp
{
public:
CHandlerImg &Handler;
CMyComPtr<ICompressProgressInfo> _ratioProgress;
CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {}
// MY_UNKNOWN_IMP1(ICompressProgressInfo)
MY_UNKNOWN_IMP
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
};
STDMETHODIMP CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
{
UInt64 inSize2;
if (Handler.Get_PackSizeProcessed(inSize2))
inSize = &inSize2;
return _ratioProgress->SetRatioInfo(inSize, outSize);
}
STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
@ -227,10 +261,6 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
return S_OK;
RINOK(extractCallback->PrepareOperation(askMode));
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
int opRes = NExtract::NOperationResult::kDataError;
ClearStreamVars();
@ -242,6 +272,19 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
if (hres == S_OK && inStream)
{
CLocalProgress *lps = new CLocalProgress;
CMyComPtr<ICompressProgressInfo> progress = lps;
lps->Init(extractCallback, false);
if (Init_PackSizeProcessed())
{
CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this);
CMyComPtr<ICompressProgressInfo> imgProgress = imgProgressSpec;
imgProgressSpec->_ratioProgress = progress;
progress.Release();
progress = imgProgress;
}
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;

View file

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

View file

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

View file

@ -38,9 +38,11 @@ namespace NFileTimeType
{
enum EEnum
{
kWindows,
kNotDefined = -1,
kWindows = 0,
kUnix,
kDOS
kDOS,
k1ns
};
}
@ -60,8 +62,31 @@ namespace NArcInfoFlags
const UInt32 kHardLinks = 1 << 11; // the handler supports hard links
const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches
const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums)
const UInt32 kCTime = 1 << 14;
const UInt32 kCTime_Default = 1 << 15;
const UInt32 kATime = 1 << 16;
const UInt32 kATime_Default = 1 << 17;
const UInt32 kMTime = 1 << 18;
const UInt32 kMTime_Default = 1 << 19;
// const UInt32 kTTime_Reserved = 1 << 20;
// const UInt32 kTTime_Reserved_Default = 1 << 21;
}
namespace NArcInfoTimeFlags
{
const unsigned kTime_Prec_Mask_bit_index = 0;
const unsigned kTime_Prec_Mask_num_bits = 26;
const unsigned kTime_Prec_Default_bit_index = 27;
const unsigned kTime_Prec_Default_num_bits = 5;
}
#define TIME_PREC_TO_ARC_FLAGS_MASK(x) \
((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (x)))
#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(x) \
((UInt32)(x) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index)
namespace NArchive
{
namespace NHandlerPropID
@ -79,8 +104,8 @@ namespace NArchive
kSignatureOffset, // VT_UI4
kAltStreams, // VT_BOOL
kNtSecure, // VT_BOOL
kFlags // VT_UI4
// kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR)
kFlags, // VT_UI4
kTimeFlags // VT_UI4
};
}
@ -123,6 +148,7 @@ namespace NArchive
kInArcIndex,
kBlockIndex,
kOutArcIndex
// kArcProp
};
}
@ -133,7 +159,8 @@ namespace NArchive
enum
{
kOK = 0
// , kError
// kError = 1,
// kError_FileChanged
};
}
}
@ -461,9 +488,10 @@ namespace NUpdateNotifyOp
kSkip,
kDelete,
kHeader,
kHashRead
// kNumDefined
kHashRead,
kInFileChanged
// , kOpFinished
// , kNumDefined
};
};
@ -492,6 +520,20 @@ ARCHIVE_INTERFACE(IArchiveGetDiskProperty, 0x84)
INTERFACE_IArchiveGetDiskProperty(PURE);
};
/*
#define INTERFACE_IArchiveUpdateCallbackArcProp(x) \
STDMETHOD(ReportProp)(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x; \
STDMETHOD(ReportRawProp)(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x; \
STDMETHOD(ReportFinished)(UInt32 indexType, UInt32 index, Int32 opRes) x; \
STDMETHOD(DoNeedArcProp)(PROPID propID, Int32 *answer) x; \
ARCHIVE_INTERFACE(IArchiveUpdateCallbackArcProp, 0x85)
{
INTERFACE_IArchiveUpdateCallbackArcProp(PURE);
};
*/
/*
UpdateItems()
-------------
@ -636,9 +678,40 @@ extern "C"
typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
typedef HRESULT (WINAPI *Func_SetLargePageMode)();
// typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version);
typedef IOutArchive * (*Func_CreateOutArchive)();
typedef IInArchive * (*Func_CreateInArchive)();
}
/*
if there is no time in archive, external MTime of archive
will be used instead of _item.Time from archive.
For 7-zip before 22.00 we need to return some supported value.
But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00.
So we return highest precision value supported by old 7-Zip.
new 7-Zip 22.00 doesn't use that value in usual cases.
*/
#define DECLARE_AND_SET_CLIENT_VERSION_VAR
#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
NFileTimeType::kWindows
/*
extern UInt32 g_ClientVersion;
#define GET_CLIENT_VERSION(major, minor) \
((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor)))
#define DECLARE_AND_SET_CLIENT_VERSION_VAR \
UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR);
#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \
(UInt32)(Int32)NFileTimeType::kNotDefined : \
NFileTimeType::kWindows))
*/
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

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

View file

@ -587,6 +587,8 @@ HRESULT CInArchive::Open2()
for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
if (VolDescs[MainVolDescIndex].IsJoliet())
break;
/* FIXME: some volume can contain Rock Ridge, that is better than
Joliet volume. So we need some way to detect such case */
// MainVolDescIndex = 0; // to read primary volume
const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
if (vd.LogicalBlockSize != kBlockSize)

View file

@ -127,17 +127,18 @@ struct CDateTime
bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
bool GetFileTime(FILETIME &ft) const
bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
{
UInt64 value;
bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, value);
UInt64 v;
const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v);
if (res)
{
value -= (Int64)((Int32)GmtOffset * 15 * 60);
value *= 10000000;
v -= (Int64)((Int32)GmtOffset * 15 * 60);
v *= 10000000;
if (Hundredths < 100)
v += (UInt32)Hundredths * 100000;
prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2);
}
ft.dwLowDateTime = (DWORD)value;
ft.dwHighDateTime = (DWORD)(value >> 32);
return res;
}
};

View file

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

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

View file

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

View file

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

View file

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

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

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

View file

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

View file

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

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

View file

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

View file

@ -36,22 +36,34 @@ static const Byte kProps[] =
kpidSize,
kpidPackSize,
kpidMTime,
kpidCTime,
kpidATime,
kpidPosixAttrib,
kpidUser,
kpidGroup,
kpidUserId,
kpidGroupId,
kpidSymLink,
kpidHardLink,
kpidCharacts
// kpidLinkType
kpidCharacts,
kpidComment
, kpidDeviceMajor
, kpidDeviceMinor
// , kpidDevice
// , kpidHeadersSize // for debug
// , kpidOffset // for debug
};
static const Byte kArcProps[] =
{
kpidHeadersSize,
kpidCodePage,
kpidCharacts
kpidCharacts,
kpidComment
};
static const char *k_Characts_Prefix = "PREFIX";
IMP_IInArchive_Props
IMP_IInArchive_ArcProps
@ -60,14 +72,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
NCOM::CPropVariant prop;
switch (propID)
{
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break;
case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break;
case kpidErrorFlags:
{
UInt32 flags = 0;
if (!_isArc)
flags |= kpv_ErrorFlags_IsNotArc;
else switch (_error)
else switch (_arc._error)
{
case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
@ -82,7 +94,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidWarningFlags:
{
if (_warning)
if (_arc._is_Warning)
prop = kpv_ErrorFlags_HeadersError;
break;
}
@ -107,7 +119,34 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidCharacts:
{
prop = _encodingCharacts.GetCharactsString();
AString s;
if (_arc._are_Gnu) s.Add_OptSpaced("GNU");
if (_arc._are_Posix) s.Add_OptSpaced("POSIX");
if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM");
if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix);
if (_arc._are_LongName) s.Add_OptSpaced("LongName");
if (_arc._are_LongLink) s.Add_OptSpaced("LongLink");
if (_arc._are_Pax) s.Add_OptSpaced("PAX");
if (_arc._are_pax_path) s.Add_OptSpaced("path");
if (_arc._are_pax_link) s.Add_OptSpaced("linkpath");
if (_arc._are_mtime) s.Add_OptSpaced("mtime");
if (_arc._are_atime) s.Add_OptSpaced("atime");
if (_arc._are_ctime) s.Add_OptSpaced("ctime");
if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR");
s.Add_OptSpaced(_encodingCharacts.GetCharactsString());
prop = s;
break;
}
case kpidComment:
{
if (_arc.PaxGlobal_Defined)
{
AString s;
_arc.PaxGlobal.Print_To_String(s);
if (!s.IsEmpty())
prop = s;
}
break;
}
}
@ -115,32 +154,6 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
return S_OK;
}
HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
{
item.HeaderPos = _phySize;
EErrorType error;
HRESULT res = ReadItem(stream, filled, item, error);
if (error == k_ErrorType_Warning)
_warning = true;
else if (error != k_ErrorType_OK)
_error = error;
RINOK(res);
if (filled)
{
/*
if (item.IsSparse())
_isSparse = true;
*/
if (item.IsPaxExtendedHeader())
_thereIsPaxExtendedHeader = true;
if (item.IsThereWarning())
_warning = true;
}
_phySize += item.HeaderSize;
_headersSize += item.HeaderSize;
return S_OK;
}
void CEncodingCharacts::Check(const AString &s)
{
@ -199,16 +212,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
}
_phySizeDefined = true;
_arc._phySize_Defined = true;
// bool utf8_OK = true;
_arc.SeqStream = stream;
_arc.InStream = stream;
_arc.OpenCallback = callback;
CItemEx item;
for (;;)
{
CItemEx item;
bool filled;
RINOK(ReadItem2(stream, filled, item));
if (!filled)
_arc.NumFiles = _items.Size();
RINOK(_arc.ReadItem(item));
if (!_arc.filled)
break;
_isArc = true;
@ -228,10 +245,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
_items.Add(item);
RINOK(stream->Seek((Int64)item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize));
if (_phySize > endPos)
RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize));
if (_arc._phySize > endPos)
{
_error = k_ErrorType_UnexpectedEnd;
_arc._error = k_ErrorType_UnexpectedEnd;
break;
}
/*
@ -241,6 +258,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
break;
}
*/
/*
if (callback)
{
if (_items.Size() == 1)
@ -249,10 +267,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
}
if ((_items.Size() & 0x3FF) == 0)
{
UInt64 numFiles = _items.Size();
const UInt64 numFiles = _items.Size();
RINOK(callback->SetCompleted(&numFiles, &_phySize));
}
}
*/
}
/*
@ -266,7 +285,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
if (_items.Size() == 0)
{
if (_error != k_ErrorType_OK)
if (_arc._error != k_ErrorType_OK)
{
_isArc = false;
return S_FALSE;
@ -294,6 +313,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback)
{
COM_TRY_BEGIN
// for (int i = 0; i < 10; i++) // for debug
{
Close();
RINOK(Open2(stream, openArchiveCallback));
@ -314,16 +334,11 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close()
{
_isArc = false;
_warning = false;
_error = k_ErrorType_OK;
_phySizeDefined = false;
_phySize = 0;
_headersSize = 0;
_arc.Clear();
_curIndex = 0;
_latestIsRead = false;
// _isSparse = false;
_thereIsPaxExtendedHeader = false;
_encodingCharacts.Clear();
_items.Clear();
_seqStream.Release();
@ -351,12 +366,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
{
if (_latestIsRead)
{
UInt64 packSize = _latestItem.GetPackSizeAligned();
const UInt64 packSize = _latestItem.Get_PackSize_Aligned();
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
_phySize += copyCoderSpec->TotalSize;
_arc._phySize += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != packSize)
{
_error = k_ErrorType_UnexpectedEnd;
_arc._error = k_ErrorType_UnexpectedEnd;
return S_FALSE;
}
_latestIsRead = false;
@ -364,11 +379,12 @@ HRESULT CHandler::SkipTo(UInt32 index)
}
else
{
bool filled;
RINOK(ReadItem2(_seqStream, filled, _latestItem));
if (!filled)
_arc.SeqStream = _seqStream;
_arc.InStream = NULL;
RINOK(_arc.ReadItem(_latestItem));
if (!_arc.filled)
{
_phySizeDefined = true;
_arc._phySize_Defined = true;
return E_INVALIDARG;
}
_latestIsRead = true;
@ -390,6 +406,69 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant
prop = dest;
}
static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop)
{
UInt64 v;
if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v))
return;
if (pt.Ns != 0)
v += pt.Ns / 100;
FILETIME ft;
ft.dwLowDateTime = (DWORD)v;
ft.dwHighDateTime = (DWORD)(v >> 32);
prop.SetAsTimeFrom_FT_Prec_Ns100(ft,
k_PropVar_TimePrec_Base + pt.NumDigits, pt.Ns % 100);
}
#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
static void AddByteToHex2(unsigned val, AString &s)
{
unsigned t;
t = val >> 4;
s += ValToHex(t);
t = val & 0xF;
s += ValToHex(t);
}
static void AddSpecCharToString(const char c, AString &s)
{
if ((Byte)c <= 0x20 || (Byte)c > 127)
{
s += '[';
AddByteToHex2((Byte)(c), s);
s += ']';
}
else
s += c;
}
static void AddSpecUInt64(AString &s, const char *name, UInt64 v)
{
if (v != 0)
{
s.Add_OptSpaced(name);
if (v > 1)
{
s += ':';
s.Add_UInt64(v);
}
}
}
static void AddSpecBools(AString &s, const char *name, bool b1, bool b2)
{
if (b1)
{
s.Add_OptSpaced(name);
if (b2)
s += '*';
}
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
@ -413,49 +492,189 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
case kpidPath: TarStringToUnicode(item->Name, prop, true); break;
case kpidIsDir: prop = item->IsDir(); break;
case kpidSize: prop = item->GetUnpackSize(); break;
case kpidPackSize: prop = item->GetPackSizeAligned(); break;
case kpidSize: prop = item->Get_UnpackSize(); break;
case kpidPackSize: prop = item->Get_PackSize_Aligned(); break;
case kpidMTime:
if (item->MTime != 0)
{
FILETIME ft;
if (NTime::UnixTime64ToFileTime(item->MTime, ft))
prop = ft;
}
break;
case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break;
case kpidUser: TarStringToUnicode(item->User, prop); break;
case kpidGroup: TarStringToUnicode(item->Group, prop); break;
case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
// case kpidLinkType: prop = (int)item->LinkFlag; break;
case kpidCharacts:
{
AString s = item->EncodingCharacts.GetCharactsString();
if (item->IsThereWarning())
/*
// for debug:
PropVariant_SetFrom_UnixTime(prop, 1 << 30);
prop.wReserved1 = k_PropVar_TimePrec_Base + 1;
prop.wReserved2 = 12;
break;
*/
if (item->PaxTimes.MTime.IsDefined())
PaxTimeToProp(item->PaxTimes.MTime, prop);
else
// if (item->MTime != 0)
{
s.Add_Space_if_NotEmpty();
s += "HEADER_ERROR";
// we allow (item->MTime == 0)
FILETIME ft;
if (NTime::UnixTime64_To_FileTime(item->MTime, ft))
{
unsigned prec = k_PropVar_TimePrec_Unix;
if (item->MTime_IsBin)
{
/* we report here that it's Int64-UnixTime
instead of basic UInt32-UnixTime range */
prec = k_PropVar_TimePrec_Base;
}
prop.SetAsTimeFrom_FT_Prec(ft, prec);
}
}
prop = s;
break;
}
case kpidATime:
if (item->PaxTimes.ATime.IsDefined())
PaxTimeToProp(item->PaxTimes.ATime, prop);
break;
case kpidCTime:
if (item->PaxTimes.CTime.IsDefined())
PaxTimeToProp(item->PaxTimes.CTime, prop);
break;
case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break;
case kpidUser:
if (!item->User.IsEmpty())
TarStringToUnicode(item->User, prop);
break;
case kpidGroup:
if (!item->Group.IsEmpty())
TarStringToUnicode(item->Group, prop);
break;
case kpidUserId:
// if (item->UID != 0)
prop = (UInt32)item->UID;
break;
case kpidGroupId:
// if (item->GID != 0)
prop = (UInt32)item->GID;
break;
case kpidDeviceMajor:
if (item->DeviceMajor_Defined)
// if (item->DeviceMajor != 0)
prop = (UInt32)item->DeviceMajor;
break;
case kpidDeviceMinor:
if (item->DeviceMinor_Defined)
// if (item->DeviceMinor != 0)
prop = (UInt32)item->DeviceMinor;
break;
/*
case kpidDevice:
if (item->DeviceMajor_Defined)
if (item->DeviceMinor_Defined)
prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor);
break;
*/
case kpidSymLink:
if (item->Is_SymLink())
if (!item->LinkName.IsEmpty())
TarStringToUnicode(item->LinkName, prop);
break;
case kpidHardLink:
if (item->Is_HardLink())
if (!item->LinkName.IsEmpty())
TarStringToUnicode(item->LinkName, prop);
break;
case kpidCharacts:
{
AString s;
{
s.Add_Space_if_NotEmpty();
AddSpecCharToString(item->LinkFlag, s);
}
if (item->IsMagic_GNU())
s.Add_OptSpaced("GNU");
else if (item->IsMagic_Posix_ustar_00())
s.Add_OptSpaced("POSIX");
else
{
s.Add_Space_if_NotEmpty();
for (unsigned i = 0; i < sizeof(item->Magic); i++)
AddSpecCharToString(item->Magic[i], s);
}
if (item->IsSignedChecksum)
s.Add_OptSpaced("SignedChecksum");
if (item->Prefix_WasUsed)
s.Add_OptSpaced(k_Characts_Prefix);
s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString());
// AddSpecUInt64(s, "LongName", item->Num_LongName_Records);
// AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records);
AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2);
AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2);
if (item->MTime_IsBin)
s.Add_OptSpaced("bin_mtime");
if (item->PackSize_IsBin)
s.Add_OptSpaced("bin_psize");
if (item->Size_IsBin)
s.Add_OptSpaced("bin_size");
AddSpecUInt64(s, "PAX", item->Num_Pax_Records);
if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime");
if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime");
if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime");
if (item->pax_path_WasUsed)
s.Add_OptSpaced("pax_path");
if (item->pax_link_WasUsed)
s.Add_OptSpaced("pax_linkpath");
if (item->pax_size_WasUsed)
s.Add_OptSpaced("pax_size");
if (item->IsThereWarning())
s.Add_OptSpaced("WARNING");
if (item->HeaderError)
s.Add_OptSpaced("ERROR");
if (item->Pax_Error)
s.Add_OptSpaced("PAX_error");
if (!item->PaxExtra.RawLines.IsEmpty())
s.Add_OptSpaced("PAX_unsupported_line");
if (item->Pax_Overflow)
s.Add_OptSpaced("PAX_overflow");
if (!s.IsEmpty())
prop = s;
break;
}
case kpidComment:
{
AString s;
item->PaxExtra.Print_To_String(s);
if (!s.IsEmpty())
prop = s;
break;
}
// case kpidHeadersSize: prop = item->HeaderSize; break; // for debug
// case kpidOffset: prop = item->HeaderPos; break; // for debug
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
ISequentialInStream *stream = _seqStream;
bool seqMode = (_stream == NULL);
const bool seqMode = (_stream == NULL);
if (!seqMode)
stream = _stream;
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _items.Size();
if (_stream && numItems == 0)
@ -463,7 +682,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize();
extractCallback->SetTotal(totalSize);
UInt64 totalPackSize;
@ -503,9 +722,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
item = &_items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
UInt64 unpackSize = item->GetUnpackSize();
const UInt64 unpackSize = item->Get_UnpackSize();
totalSize += unpackSize;
totalPackSize += item->GetPackSizeAligned();
totalPackSize += item->Get_PackSize_Aligned();
if (item->IsDir())
{
RINOK(extractCallback->PrepareOperation(askMode));
@ -539,7 +758,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 opRes = NExtract::NOperationResult::kOK;
CMyComPtr<ISequentialInStream> inStream2;
if (!item->IsSparse())
if (!item->Is_Sparse())
inStream2 = inStream;
else
{
@ -549,7 +768,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
{
if (item->IsSymLink())
if (item->Is_SymLink())
{
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
}
@ -557,9 +776,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
if (!seqMode)
{
RINOK(_stream->Seek((Int64)item->GetDataPosition(), STREAM_SEEK_SET, NULL));
RINOK(_stream->Seek((Int64)item->Get_DataPos(), STREAM_SEEK_SET, NULL));
}
streamSpec->Init(item->GetPackSizeAligned());
streamSpec->Init(item->Get_PackSize_Aligned());
RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress));
}
if (outStreamSpec->GetRem() != 0)
@ -628,7 +847,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
unsigned left = 0, right = item.SparseBlocks.Size();
for (;;)
{
unsigned mid = (left + right) / 2;
const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
if (mid == left)
break;
if (_virtPos < item.SparseBlocks[mid].Offset)
@ -648,7 +867,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
UInt64 phyPos = PhyOffsets[left] + relat;
if (_needStartSeek || _phyPos != phyPos)
{
RINOK(Handler->_stream->Seek((Int64)(item.GetDataPosition() + phyPos), STREAM_SEEK_SET, NULL));
RINOK(Handler->_stream->Seek((Int64)(item.Get_DataPos() + phyPos), STREAM_SEEK_SET, NULL));
_needStartSeek = false;
_phyPos = phyPos;
}
@ -698,7 +917,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
const CItemEx &item = _items[index];
if (item.IsSparse())
if (item.Is_Sparse())
{
CSparseStream *streamSpec = new CSparseStream;
CMyComPtr<IInStream> streamTemp = streamSpec;
@ -718,24 +937,30 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
return S_OK;
}
if (item.IsSymLink())
if (item.Is_SymLink())
{
Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream);
return S_OK;
}
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream);
return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream);
COM_TRY_END
}
void CHandler::Init()
{
_forceCodePage = false;
_curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP;
_thereIsPaxExtendedHeader = false;
_posixMode = false;
_posixMode_WasForced = false;
// TimeOptions.Clear();
_handlerTimeOptions.Init();
// _handlerTimeOptions.Write_MTime.Val = true; // it's default already
}
STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
{
Init();
@ -768,8 +993,54 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
else if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
{
}
else if (name.IsEqualTo("m"))
{
if (prop.vt != VT_BSTR)
return E_INVALIDARG;
const UString s = prop.bstrVal;
if (s.IsEqualTo_Ascii_NoCase("pax") ||
s.IsEqualTo_Ascii_NoCase("posix"))
_posixMode = true;
else if (s.IsEqualTo_Ascii_NoCase("gnu"))
_posixMode = false;
else
return E_INVALIDARG;
_posixMode_WasForced = true;
}
else
{
/*
if (name.IsPrefixedBy_Ascii_NoCase("td"))
{
name.Delete(0, 3);
if (prop.vt == VT_EMPTY)
{
if (name.IsEqualTo_Ascii_NoCase("n"))
{
// TimeOptions.UseNativeDigits = true;
}
else if (name.IsEqualTo_Ascii_NoCase("r"))
{
// TimeOptions.RemoveZeroDigits = true;
}
else
return E_INVALIDARG;
}
else
{
UInt32 numTimeDigits = 0;
RINOK(ParsePropToUInt32(name, prop, numTimeDigits));
TimeOptions.NumDigits_WasForced = true;
TimeOptions.NumDigits = numTimeDigits;
}
}
*/
bool processed = false;
RINOK(_handlerTimeOptions.Parse(name, prop, processed));
if (processed)
continue;
return E_INVALIDARG;
}
}
return S_OK;
}

View file

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

View file

@ -2,15 +2,16 @@
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../Common/ComTry.h"
#include "../../../Common/Defs.h"
#include "../../../Common/MyLinux.h"
#include "../../../Common/StringConvert.h"
#include "../../../Common/UTFConvert.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/TimeUtils.h"
#include "../Common/ItemNameUtils.h"
#include "TarHandler.h"
#include "TarUpdate.h"
@ -21,10 +22,35 @@ namespace NTar {
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
{
*type = NFileTimeType::kUnix;
UInt32 t = NFileTimeType::kUnix;
const UInt32 prec = _handlerTimeOptions.Prec;
if (prec != (UInt32)(Int32)-1)
{
t = NFileTimeType::kWindows;
if (prec == k_PropVar_TimePrec_0 ||
prec == k_PropVar_TimePrec_100ns)
t = NFileTimeType::kWindows;
else if (prec == k_PropVar_TimePrec_HighPrec)
t = k_PropVar_TimePrec_1ns;
else if (prec >= k_PropVar_TimePrec_Base)
t = prec;
}
// 7-Zip before 22.00 fails, if unknown typeType.
*type = t;
return S_OK;
}
void Get_AString_From_UString(const UString &s, AString &res,
UINT codePage, unsigned utfFlags)
{
if (codePage == CP_UTF8)
ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
else
UnicodeStringToMultiByte2(res, s, codePage);
}
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
UINT codePage, unsigned utfFlags, bool convertSlash)
{
@ -36,14 +62,7 @@ HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID pro
UString s = prop.bstrVal;
if (convertSlash)
NItemName::ReplaceSlashes_OsToUnix(s);
if (codePage == CP_UTF8)
{
ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
// if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG;
}
else
UnicodeStringToMultiByte2(res, s, codePage);
Get_AString_From_UString(s, res, codePage, utfFlags);
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
@ -70,12 +89,106 @@ static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
}
static HRESULT GetTime(UInt32 i, UInt32 pid, IArchiveUpdateCallback *callback,
CPaxTime &pt)
{
pt.Clear();
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, pid, &prop));
return Prop_To_PaxTime(prop, pt);
}
/*
static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
{
NWindows::NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidDevice, &prop));
if (prop.vt == VT_EMPTY)
return S_OK;
if (prop.vt != VT_UI8)
return E_INVALIDARG;
{
const UInt64 v = prop.uhVal.QuadPart;
majo = MY_dev_major(v);
mino = MY_dev_minor(v);
majo_defined = true;
mino_defined = true;
}
return S_OK;
}
*/
static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
UInt32 pid, UInt32 &id, bool &defined)
{
defined = false;
NWindows::NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, pid, &prop));
if (prop.vt == VT_EMPTY)
return S_OK;
if (prop.vt == VT_UI4)
{
id = prop.ulVal;
defined = true;
return S_OK;
}
return E_INVALIDARG;
}
static HRESULT GetUser(IArchiveUpdateCallback *callback, UInt32 i,
UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
UINT codePage, unsigned utfFlags)
{
// printf("\ncallback->GetProperty(i, pidId, &prop))\n");
bool isSet = false;
{
NWindows::NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, pidId, &prop));
if (prop.vt == VT_UI4)
{
isSet = true;
id = prop.ulVal;
// printf("\ncallback->GetProperty(i, pidId, &prop)); = %d \n", (unsigned)id);
name.Empty();
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
}
{
NWindows::NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, pidName, &prop));
if (prop.vt == VT_BSTR)
{
const UString s = prop.bstrVal;
Get_AString_From_UString(s, name, codePage, utfFlags);
if (!isSet)
id = 0;
}
else if (prop.vt == VT_UI4)
{
id = prop.ulVal;
name.Empty();
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
}
return S_OK;
}
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
if ((_stream && (_error != k_ErrorType_OK || _warning /* || _isSparse */)) || _seqStream)
if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning
/* || _isSparse */
)) || _seqStream)
return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems;
const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
@ -131,25 +244,30 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
else
ui.Mode = prop.ulVal;
// 21.07 : we clear high file type bits as GNU TAR.
ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
// we will clear it later
// ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
}
{
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidMTime, &prop));
if (prop.vt == VT_EMPTY)
ui.MTime = 0;
else if (prop.vt != VT_FILETIME)
return E_INVALIDARG;
else
ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
}
if (_handlerTimeOptions.Write_MTime.Val)
RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime))
if (_handlerTimeOptions.Write_ATime.Val)
RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime))
if (_handlerTimeOptions.Write_CTime.Val)
RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime))
RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true));
if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
ui.Name += '/';
RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage, utfFlags, false));
RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage, utfFlags, false));
// ui.Name += '/'; // for debug
if (_posixMode)
{
RINOK(GetDevice(callback, i, kpidDeviceMajor, ui.DeviceMajor, ui.DeviceMajor_Defined));
RINOK(GetDevice(callback, i, kpidDeviceMinor, ui.DeviceMinor, ui.DeviceMinor_Defined));
}
RINOK(GetUser(callback, i, kpidUser, kpidUserId, ui.User, ui.UID, codePage, utfFlags));
RINOK(GetUser(callback, i, kpidGroup, kpidGroupId, ui.Group, ui.GID, codePage, utfFlags));
}
if (IntToBool(newData))
@ -169,13 +287,44 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
updateItems.Add(ui);
}
if (_thereIsPaxExtendedHeader)
if (_arc._are_Pax_Items)
{
// we restore original order of files, if there is pax header block
// we restore original order of files, if there are pax items
updateItems.Sort(CompareUpdateItems, NULL);
}
return UpdateArchive(_stream, outStream, _items, updateItems, codePage, utfFlags, callback);
CUpdateOptions options;
options.CodePage = codePage;
options.UtfFlags = utfFlags;
options.PosixMode = _posixMode;
options.Write_MTime = _handlerTimeOptions.Write_MTime;
options.Write_ATime = _handlerTimeOptions.Write_ATime;
options.Write_CTime = _handlerTimeOptions.Write_CTime;
// options.TimeOptions = TimeOptions;
const UInt32 prec = _handlerTimeOptions.Prec;
if (prec != (UInt32)(Int32)-1)
{
unsigned numDigits = 0;
if (prec == 0)
numDigits = 7;
else if (prec == k_PropVar_TimePrec_HighPrec
|| prec >= k_PropVar_TimePrec_1ns)
numDigits = 9;
else if (prec >= k_PropVar_TimePrec_Base)
numDigits = prec - k_PropVar_TimePrec_Base;
options.TimeOptions.NumDigitsMax = numDigits;
// options.TimeOptions.RemoveZeroMode =
// k_PaxTimeMode_DontRemoveZero; // pure for debug
// k_PaxTimeMode_RemoveZero_if_PureSecondOnly; // optimized code
// k_PaxTimeMode_RemoveZero_Always; // original pax code
}
return UpdateArchive(_stream, outStream, _items, updateItems,
options, callback);
COM_TRY_END
}

View file

@ -18,9 +18,82 @@ namespace NFileHeader {
// const char * const kGNUTar = "GNUtar "; // 7 chars and a null
// const char * const kEmpty = "\0\0\0\0\0\0\0\0";
// 7-Zip used kUsTar_00 before 21.07:
// const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
const char k_Posix_ustar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
// GNU TAR uses such header:
const char kUsTar_GNU[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ;
const char k_GNU_ustar__[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ;
}
/*
pre-POSIX.1-1988 (i.e. v7) tar header:
-----
Link indicator:
'0' or 0 : Normal file
'1' : Hard link
'2' : Symbolic link
Some pre-POSIX.1-1988 tar implementations indicated a directory by having
a trailing slash (/) in the name.
Numeric values : octal with leading zeroes.
For historical reasons, a final NUL or space character should also be used.
Thus only 11 octal digits can be stored from 12 bytes field.
2001 star : introduced a base-256 coding that is indicated by
setting the high-order bit of the leftmost byte of a numeric field.
GNU-tar and BSD-tar followed this idea.
versions of tar from before the first POSIX standard from 1988
pad the values with spaces instead of zeroes.
UStar
-----
UStar (Unix Standard TAR) : POSIX IEEE P1003.1 : 1988.
257 signature: "ustar", 0, "00"
265 32 Owner user name
297 32 Owner group name
329 8 Device major number
337 8 Device minor number
345 155 Filename prefix
POSIX.1-2001/pax
----
format is known as extended tar format or pax format
vendor-tagged vendor-specific enhancements.
tags Defined by the POSIX standard:
atime, mtime, path, linkpath, uname, gname, size, uid, gid, ...
PAX EXTENSION
-----------
Hard links
A further difference from the ustar header block is that data blocks
for files of typeflag 1 (hard link) may be included,
which means that the size field may be greater than zero.
Archives created by pax -o linkdata shall include these data
blocks with the hard links.
*
compatiblity
------------
7-Zip 16.03 supports "PaxHeader/"
7-Zip 20.01 supports "PaxHeaders.X/" with optional "./"
7-Zip 21.02 supports "@PaxHeader" with optional "./" "./"
GNU tar --format=posix uses "PaxHeaders/" in folder of file
GNU TAR format
==============
v7 - Unix V7
oldgnu - GNU tar <=1.12 : writes zero in last character in name
gnu - GNU tar 1.13 : doesn't write zero in last character in name
as 7-zip 21.07
ustar - POSIX.1-1988
posix (pax) - POSIX.1-2001
gnu tar:
if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) {
major_t devmajor = major (st->stat.st_rdev);
minor_t devminor = minor (st->stat.st_rdev); }
*/
}}}

View file

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

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
#ifndef __ARCHIVE_TAR_IN_H
#define __ARCHIVE_TAR_IN_H
#include "../../IStream.h"
#include "../IArchive.h"
#include "TarItem.h"
@ -14,11 +14,133 @@ enum EErrorType
{
k_ErrorType_OK,
k_ErrorType_Corrupted,
k_ErrorType_UnexpectedEnd,
k_ErrorType_Warning
k_ErrorType_UnexpectedEnd
// , k_ErrorType_Warning
};
struct CTempBuffer
{
CByteBuffer Buffer;
size_t StringSize; // num characters before zero Byte (StringSize <= item.PackSize)
bool IsNonZeroTail;
bool StringSize_IsConfirmed;
void CopyToString(AString &s)
{
s.Empty();
if (StringSize != 0)
s.SetFrom((const char *)(const void *)(const Byte *)Buffer, (unsigned)StringSize);
}
void Init()
{
StringSize = 0;
IsNonZeroTail = false;
StringSize_IsConfirmed = false;
}
};
class CArchive
{
public:
bool _phySize_Defined;
bool _is_Warning;
bool PaxGlobal_Defined;
bool _is_PaxGlobal_Error;
bool _are_Pax_Items;
bool _are_Gnu;
bool _are_Posix;
bool _are_Pax;
bool _are_mtime;
bool _are_atime;
bool _are_ctime;
bool _are_pax_path;
bool _are_pax_link;
bool _are_LongName;
bool _are_LongLink;
bool _pathPrefix_WasUsed;
// bool _isSparse;
// temp internal vars for ReadItem():
bool filled;
private:
EErrorType error;
public:
UInt64 _phySize;
UInt64 _headersSize;
EErrorType _error;
ISequentialInStream *SeqStream;
IInStream *InStream;
IArchiveOpenCallback *OpenCallback;
UInt64 NumFiles;
UInt64 NumFiles_Prev;
UInt64 Pos_Prev;
// UInt64 NumRecords;
// UInt64 NumRecords_Prev;
CPaxExtra PaxGlobal;
void Clear()
{
SeqStream = NULL;
InStream = NULL;
OpenCallback = NULL;
NumFiles = 0;
NumFiles_Prev = 0;
Pos_Prev = 0;
// NumRecords = 0;
// NumRecords_Prev = 0;
PaxGlobal.Clear();
PaxGlobal_Defined = false;
_is_PaxGlobal_Error = false;
_are_Pax_Items = false; // if there are final paxItems
_are_Gnu = false;
_are_Posix = false;
_are_Pax = false;
_are_mtime = false;
_are_atime = false;
_are_ctime = false;
_are_pax_path = false;
_are_pax_link = false;
_are_LongName = false;
_are_LongLink = false;
_pathPrefix_WasUsed = false;
// _isSparse = false;
_is_Warning = false;
_error = k_ErrorType_OK;
_phySize_Defined = false;
_phySize = 0;
_headersSize = 0;
}
private:
CTempBuffer NameBuf;
CTempBuffer LinkBuf;
CTempBuffer PaxBuf;
CTempBuffer PaxBuf_global;
CByteBuffer Buffer;
HRESULT ReadDataToBuffer(const CItemEx &item, CTempBuffer &tb, size_t stringLimit);
HRESULT Progress(const CItemEx &item, UInt64 posOffset);
HRESULT GetNextItemReal(CItemEx &item);
HRESULT ReadItem2(CItemEx &itemInfo);
public:
CArchive()
{
// we will call Clear() in CHandler::Close().
// Clear(); // it's not required here
}
HRESULT ReadItem(CItemEx &itemInfo);
};
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error);
API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);

View file

@ -6,8 +6,6 @@
#include "../../../Common/MyLinux.h"
#include "../../../Common/UTFConvert.h"
#include "../Common/ItemNameUtils.h"
#include "TarHeader.h"
namespace NArchive {
@ -19,50 +17,149 @@ struct CSparseBlock
UInt64 Size;
};
enum EPaxTimeRemoveZeroMode
{
k_PaxTimeMode_DontRemoveZero,
k_PaxTimeMode_RemoveZero_if_PureSecondOnly,
k_PaxTimeMode_RemoveZero_Always
};
struct CTimeOptions
{
EPaxTimeRemoveZeroMode RemoveZeroMode;
unsigned NumDigitsMax;
void Init()
{
RemoveZeroMode = k_PaxTimeMode_RemoveZero_if_PureSecondOnly;
NumDigitsMax = 0;
}
CTimeOptions() { Init(); }
};
struct CPaxTime
{
Int32 NumDigits; // -1 means undefined
UInt32 Ns; // it's smaller than 1G. Even if (Sec < 0), larger (Ns) value means newer files.
Int64 Sec; // can be negative
Int64 GetSec() const { return NumDigits != -1 ? Sec : 0; }
bool IsDefined() const { return NumDigits != -1; }
// bool IsDefined_And_nonZero() const { return NumDigits != -1 && (Sec != 0 || Ns != 0); }
void Clear()
{
NumDigits = -1;
Ns = 0;
Sec = 0;
}
CPaxTime() { Clear(); }
/*
void ReducePrecison(int numDigits)
{
// we don't use this->NumDigits here
if (numDigits > 0)
{
if (numDigits >= 9)
return;
UInt32 r = 1;
for (unsigned i = numDigits; i < 9; i++)
r *= 10;
Ns /= r;
Ns *= r;
return;
}
Ns = 0;
if (numDigits == 0)
return;
UInt32 r;
if (numDigits == -1) r = 60;
else if (numDigits == -2) r = 60 * 60;
else if (numDigits == -3) r = 60 * 60 * 24;
else return;
Sec /= r;
Sec *= r;
}
*/
};
struct CPaxTimes
{
CPaxTime MTime;
CPaxTime ATime;
CPaxTime CTime;
void Clear()
{
MTime.Clear();
ATime.Clear();
CTime.Clear();
}
/*
void ReducePrecison(int numDigits)
{
MTime.ReducePrecison(numDigits);
CTime.ReducePrecison(numDigits);
ATime.ReducePrecison(numDigits);
}
*/
};
struct CItem
{
AString Name;
UInt64 PackSize;
UInt64 Size;
Int64 MTime;
char LinkFlag;
bool DeviceMajor_Defined;
bool DeviceMinor_Defined;
UInt32 Mode;
UInt32 UID;
UInt32 GID;
UInt32 DeviceMajor;
UInt32 DeviceMinor;
AString Name;
AString LinkName;
AString User;
AString Group;
char Magic[8];
char LinkFlag;
bool DeviceMajorDefined;
bool DeviceMinorDefined;
CPaxTimes PaxTimes;
CRecordVector<CSparseBlock> SparseBlocks;
void SetDefaultWriteFields()
void SetMagic_Posix(bool posixMode)
{
DeviceMajorDefined = false;
DeviceMinorDefined = false;
UID = 0;
GID = 0;
memcpy(Magic, NFileHeader::NMagic::kUsTar_GNU, 8);
memcpy(Magic, posixMode ?
NFileHeader::NMagic::k_Posix_ustar_00 :
NFileHeader::NMagic::k_GNU_ustar__,
8);
}
bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; }
bool IsPaxExtendedHeader() const
bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; }
bool Is_PaxExtendedHeader() const
{
switch (LinkFlag)
{
case 'g':
case 'x':
case 'X': // Check it
case NFileHeader::NLinkFlag::kPax:
case NFileHeader::NLinkFlag::kPax_2:
case NFileHeader::NLinkFlag::kGlobal:
return true;
}
return false;
@ -73,6 +170,17 @@ struct CItem
return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag();
}
void Set_LinkFlag_for_File(UInt32 mode)
{
Byte lf = NFileHeader::NLinkFlag::kNormal;
if (MY_LIN_S_ISCHR(mode)) lf = NFileHeader::NLinkFlag::kCharacter;
else if (MY_LIN_S_ISBLK(mode)) lf = NFileHeader::NLinkFlag::kBlock;
else if (MY_LIN_S_ISFIFO(mode)) lf = NFileHeader::NLinkFlag::kFIFO;
// else if (MY_LIN_S_ISDIR(mode)) lf = NFileHeader::NLinkFlag::kDirectory;
// else if (MY_LIN_S_ISLNK(mode)) lf = NFileHeader::NLinkFlag::kSymLink;
LinkFlag = lf;
}
UInt32 Get_FileTypeMode_from_LinkFlag() const
{
switch (LinkFlag)
@ -82,10 +190,10 @@ struct CItem
case NFileHeader::NLinkFlag::kDumpDir:
return MY_LIN_S_IFDIR;
*/
case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
// case return MY_LIN_S_IFSOCK;
}
@ -104,20 +212,41 @@ struct CItem
case NFileHeader::NLinkFlag::kOldNormal:
case NFileHeader::NLinkFlag::kNormal:
case NFileHeader::NLinkFlag::kSymLink:
return NItemName::HasTailSlash(Name, CP_OEMCP);
if (Name.IsEmpty())
return false;
// GNU TAR uses last character as directory marker
// we also do it
return Name.Back() == '/';
// return NItemName::HasTailSlash(Name, CP_OEMCP);
}
return false;
}
bool IsUstarMagic() const
bool IsMagic_ustar_5chars() const
{
for (int i = 0; i < 5; i++)
if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i])
for (unsigned i = 0; i < 5; i++)
if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
return false;
return true;
}
UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
bool IsMagic_Posix_ustar_00() const
{
for (unsigned i = 0; i < 8; i++)
if (Magic[i] != NFileHeader::NMagic::k_Posix_ustar_00[i])
return false;
return true;
}
bool IsMagic_GNU() const
{
for (unsigned i = 0; i < 8; i++)
if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar__[i])
return false;
return true;
}
UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
bool IsThereWarning() const
{
@ -163,18 +292,67 @@ struct CEncodingCharacts
};
struct CPaxExtra
{
AString RecordPath;
AString RawLines;
void Clear()
{
RecordPath.Empty();
RawLines.Empty();
}
void Print_To_String(AString &s) const
{
if (!RecordPath.IsEmpty())
{
s += RecordPath;
s.Add_LF();
}
if (!RawLines.IsEmpty())
s += RawLines;
}
};
struct CItemEx: public CItem
{
bool HeaderError;
bool IsSignedChecksum;
bool Prefix_WasUsed;
bool Pax_Error;
bool Pax_Overflow;
bool pax_path_WasUsed;
bool pax_link_WasUsed;
bool pax_size_WasUsed;
bool MTime_IsBin;
bool PackSize_IsBin;
bool Size_IsBin;
bool LongName_WasUsed;
bool LongName_WasUsed_2;
bool LongLink_WasUsed;
bool LongLink_WasUsed_2;
// bool Name_CouldBeReduced;
// bool LinkName_CouldBeReduced;
UInt64 HeaderPos;
unsigned HeaderSize;
bool NameCouldBeReduced;
bool LinkNameCouldBeReduced;
UInt64 HeaderSize;
UInt64 Num_Pax_Records;
CPaxExtra PaxExtra;
CEncodingCharacts EncodingCharacts;
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
UInt64 GetFullSize() const { return HeaderSize + PackSize; }
UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; }
// UInt64 GetFullSize() const { return HeaderSize + PackSize; }
UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); }
};
}}

View file

@ -2,6 +2,10 @@
#include "StdAfx.h"
#include "../../../../C/7zCrc.h"
#include "../../../Common/IntToString.h"
#include "../../Common/StreamUtils.h"
#include "TarOut.h"
@ -9,23 +13,27 @@
namespace NArchive {
namespace NTar {
HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
{
Pos += size;
return WriteStream(m_Stream, data, size);
}
using namespace NFileHeader;
static bool WriteOctal_8(char *s, UInt32 val)
// it's path prefix assigned by 7-Zip to show that file path was cut
#define K_PREFIX_PATH_CUT "@PathCut"
static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1;
static void WriteOctal_8(char *s, UInt32 val)
{
const unsigned kNumDigits = 8 - 1;
if (val >= ((UInt32)1 << (kNumDigits * 3)))
return false;
{
val = 0;
// return false;
}
for (unsigned i = 0; i < kNumDigits; i++)
{
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
val >>= 3;
}
return true;
// return true;
}
static void WriteBin_64bit(char *s, UInt64 val)
@ -68,61 +76,93 @@ static void CopyString(char *dest, const AString &src, unsigned maxSize)
unsigned len = src.Len();
if (len == 0)
return;
// 21.07: we don't require additional 0 character at the end
// 21.07: new gnu : we don't require additional 0 character at the end
// if (len >= maxSize)
if (len > maxSize)
{
len = maxSize;
// return false;
/*
// oldgnu needs 0 character at the end
len = maxSize - 1;
dest[len] = 0;
*/
}
memcpy(dest, src.Ptr(), len);
// return true;
}
#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }
// #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; }
#define RETURN_IF_NOT_TRUE(x) { x; }
#define COPY_STRING_CHECK(dest, src, size) \
CopyString(dest, src, size); dest += (size);
#define WRITE_OCTAL_8_CHECK(dest, src) \
RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src));
RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src))
HRESULT COutArchive::WriteHeaderReal(const CItem &item)
HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax
// , bool zero_PackSize
// , bool zero_MTime
)
{
char record[NFileHeader::kRecordSize];
memset(record, 0, NFileHeader::kRecordSize);
/*
if (isPax) { we don't use Glob_Name and Prefix }
if (!isPax)
{
we use Glob_Name if it's not empty
we use Prefix if it's not empty
}
*/
char record[kRecordSize];
memset(record, 0, kRecordSize);
char *cur = record;
COPY_STRING_CHECK (cur, item.Name, NFileHeader::kNameSize);
COPY_STRING_CHECK (cur,
(!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name,
kNameSize);
WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8;
WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8; // & k_7_oct_digits_Val_Max
WRITE_OCTAL_8_CHECK (cur, item.UID); cur += 8;
WRITE_OCTAL_8_CHECK (cur, item.GID); cur += 8;
WriteOctal_12(cur, item.PackSize); cur += 12;
WriteOctal_12_Signed(cur, item.MTime); cur += 12;
WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12;
WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12;
memset(cur, ' ', 8); // checksum field
// we will use binary init for checksum instead of memset
// checksum field:
// memset(cur, ' ', 8);
cur += 8;
*cur++ = item.LinkFlag;
COPY_STRING_CHECK (cur, item.LinkName, NFileHeader::kNameSize);
COPY_STRING_CHECK (cur, item.LinkName, kNameSize);
memcpy(cur, item.Magic, 8);
cur += 8;
COPY_STRING_CHECK (cur, item.User, NFileHeader::kUserNameSize);
COPY_STRING_CHECK (cur, item.Group, NFileHeader::kGroupNameSize);
COPY_STRING_CHECK (cur, item.User, kUserNameSize);
COPY_STRING_CHECK (cur, item.Group, kGroupNameSize);
if (item.DeviceMajorDefined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor);
cur += 8;
if (item.DeviceMinorDefined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor);
const bool needDevice = (IsPosixMode && !isPax);
if (item.DeviceMajor_Defined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor)
else if (needDevice)
WRITE_OCTAL_8_CHECK (cur, 0)
cur += 8;
if (item.IsSparse())
if (item.DeviceMinor_Defined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor)
else if (needDevice)
WRITE_OCTAL_8_CHECK (cur, 0)
cur += 8;
if (!isPax && !Prefix.IsEmpty())
{
COPY_STRING_CHECK (cur, Prefix, kPrefixSize);
}
if (item.Is_Sparse())
{
record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
WriteOctal_12(record + 483, item.Size);
@ -136,31 +176,31 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
}
{
UInt32 checkSum = 0;
UInt32 sum = (unsigned)(' ') * 8; // we use binary init
{
for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
checkSum += (Byte)record[i];
for (unsigned i = 0; i < kRecordSize; i++)
sum += (Byte)record[i];
}
/* we use GNU TAR scheme:
checksum field is formatted differently from the
/* checksum field is formatted differently from the
other fields: it has [6] digits, a null, then a space. */
// WRITE_OCTAL_8_CHECK(record + 148, checkSum);
// WRITE_OCTAL_8_CHECK(record + 148, sum);
const unsigned kNumDigits = 6;
for (unsigned i = 0; i < kNumDigits; i++)
{
record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7));
checkSum >>= 3;
record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7));
sum >>= 3;
}
record[148 + 6] = 0;
// record[148 + 6] = 0; // we need it, if we use memset(' ') init
record[148 + 7] = ' '; // we need it, if we use binary init
}
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
RINOK(Write_Data(record, kRecordSize));
if (item.IsSparse())
if (item.Is_Sparse())
{
for (unsigned i = 4; i < item.SparseBlocks.Size();)
{
memset(record, 0, NFileHeader::kRecordSize);
memset(record, 0, kRecordSize);
for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
{
const CSparseBlock &sb = item.SparseBlocks[i];
@ -169,7 +209,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
WriteOctal_12(p + 12, sb.Size);
}
record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
RINOK(Write_Data(record, kRecordSize));
}
}
@ -177,101 +217,426 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
}
/* OLD_GNU_TAR: writes short name with zero at the end
NEW_GNU_TAR: writes short name without zero at the end */
static void AddPaxLine(AString &s, const char *name, const AString &val)
{
// s.Add_LF(); // for debug
const unsigned len = 3 + (unsigned)strlen(name) + val.Len();
AString n;
for (unsigned numDigits = 1;; numDigits++)
{
n.Empty();
n.Add_UInt32(numDigits + len);
if (numDigits == n.Len())
break;
}
s += n;
s.Add_Space();
s += name;
s += '=';
s += val;
s.Add_LF();
}
static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt,
const CTimeOptions &options)
{
unsigned numDigits = pt.NumDigits;
if (numDigits > options.NumDigitsMax)
numDigits = options.NumDigitsMax;
bool needNs = false;
UInt32 ns = 0;
if (numDigits != 0)
{
ns = pt.Ns;
// if (ns != 0) before reduction, we show all digits after digits reduction
needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero);
UInt32 d = 1;
for (unsigned k = numDigits; k < 9; k++)
d *= 10;
ns /= d;
ns *= d;
}
AString v;
{
Int64 sec = pt.Sec;
if (pt.Sec < 0)
{
sec = -sec;
v += '-';
if (ns != 0)
{
ns = 1000*1000*1000 - ns;
sec--;
}
}
v.Add_UInt64(sec);
}
if (needNs)
{
AString d;
d.Add_UInt32(ns);
while (d.Len() < 9)
d.InsertAtFront('0');
// here we have precision
while (d.Len() > (unsigned)numDigits)
d.DeleteBack();
// GNU TAR reduces '0' digits.
if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always)
while (!d.IsEmpty() && d.Back() == '0')
d.DeleteBack();
if (!d.IsEmpty())
{
v += '.';
v += d;
// v += "1234567009999"; // for debug
// for (int y = 0; y < 1000; y++) v += '8'; // for debug
}
}
AddPaxLine(s, name, v);
}
static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v)
{
if (v > k_7_oct_digits_Val_Max)
{
AString s2;
s2.Add_UInt32(v);
AddPaxLine(s, name, s2);
}
}
/* OLD_GNU_TAR: writes name with zero at the end
NEW_GNU_TAR: can write name filled with all kNameSize characters */
static const unsigned kNameSize_Max =
NFileHeader::kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
// NFileHeader::kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
// kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max)
HRESULT COutArchive::WriteHeader(const CItem &item)
{
if (DOES_NAME_FIT_IN_FIELD(item.Name) &&
DOES_NAME_FIT_IN_FIELD(item.LinkName))
return WriteHeaderReal(item);
Glob_Name.Empty();
Prefix.Empty();
// here we can get all fields from main (item) or create new empty item
/*
CItem mi;
mi.SetDefaultWriteFields();
*/
unsigned namePos = 0;
bool needPathCut = false;
bool allowPrefix = false;
CItem mi = item;
mi.LinkName.Empty();
// SparseBlocks will be ignored by IsSparse()
// mi.SparseBlocks.Clear();
mi.Name = NFileHeader::kLongLink;
// 21.07 : we set Mode and MTime props as in GNU TAR:
mi.Mode = 0644; // octal
mi.MTime = 0;
for (int i = 0; i < 2; i++)
if (!DOES_NAME_FIT_IN_FIELD(item.Name))
{
const AString *name;
// We suppose that GNU TAR also writes item for long link before item for LongName?
if (i == 0)
{
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
name = &item.LinkName;
}
else
{
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
name = &item.Name;
}
if (DOES_NAME_FIT_IN_FIELD(*name))
continue;
// GNU TAR writes null character after NAME to file. We do same here:
const unsigned nameStreamSize = name->Len() + 1;
mi.PackSize = nameStreamSize;
RINOK(WriteHeaderReal(mi));
RINOK(WriteBytes(name->Ptr(), nameStreamSize));
RINOK(FillDataResidual(nameStreamSize));
const char *s = item.Name;
const char *p = s + item.Name.Len() - 1;
for (; *p == '/' && p != s; p--)
{}
for (; p != s && p[-1] != '/'; p--)
{}
namePos = (unsigned)(p - s);
needPathCut = true;
}
if (IsPosixMode)
{
AString s;
if (needPathCut)
{
const unsigned nameLen = item.Name.Len() - namePos;
if ( item.LinkFlag >= NLinkFlag::kNormal
&& item.LinkFlag <= NLinkFlag::kDirectory
&& namePos > 1
&& nameLen != 0
// && IsPrefixAllowed
&& item.IsMagic_Posix_ustar_00())
{
/* GNU TAR decoder supports prefix field, only if (magic)
signature matches 6-bytes "ustar\0".
so here we use prefix field only in posix mode with posix signature */
allowPrefix = true;
// allowPrefix = false; // for debug
if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max)
{
needPathCut = false;
/* we will set Prefix and Glob_Name later, for such conditions:
if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */
}
}
if (needPathCut)
AddPaxLine(s, "path", item.Name);
}
// AddPaxLine(s, "testname", AString("testval")); // for debug
if (item.LinkName.Len() > kNameSize_Max)
AddPaxLine(s, "linkpath", item.LinkName);
const UInt64 kPaxSize_Limit = ((UInt64)1 << 33);
// const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug
// bool zero_PackSize = false;
if (item.PackSize >= kPaxSize_Limit)
{
/* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB
But old 7-Zip doesn't detect "size" property from pax header.
So we write real size (>= 8 GiB) to main record in binary format,
and old 7-Zip can decode size correctly */
// zero_PackSize = true;
AString v;
v.Add_UInt64(item.PackSize);
AddPaxLine(s, "size", v);
}
/* GNU TAR encoder can set "devmajor" / "devminor" attributes,
but GNU TAR decoder doesn't parse "devmajor" / "devminor" */
if (item.DeviceMajor_Defined)
AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor);
if (item.DeviceMinor_Defined)
AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor);
AddPax_UInt32_ifBig(s, "uid", item.UID);
AddPax_UInt32_ifBig(s, "gid", item.GID);
const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33);
const bool zero_MTime = (
item.MTime < 0 ||
item.MTime >= (Int64)kPax_MTime_Limit);
const CPaxTime &mtime = item.PaxTimes.MTime;
if (mtime.IsDefined())
{
bool needPax = false;
if (zero_MTime)
needPax = true;
else if (TimeOptions.NumDigitsMax > 0)
if (mtime.Ns != 0 ||
(mtime.NumDigits != 0 &&
TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero))
needPax = true;
if (needPax)
AddPaxTime(s, "mtime", mtime, TimeOptions);
}
if (item.PaxTimes.ATime.IsDefined())
AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions);
if (item.PaxTimes.CTime.IsDefined())
AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions);
if (item.User.Len() > kUserNameSize)
AddPaxLine(s, "uname", item.User);
if (item.Group.Len() > kGroupNameSize)
AddPaxLine(s, "gname", item.Group);
/*
// for debug
AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a);
*/
const unsigned paxSize = s.Len();
if (paxSize != 0)
{
CItem mi = item;
mi.LinkName.Empty();
// SparseBlocks will be ignored by Is_Sparse()
// mi.SparseBlocks.Clear();
// we use "PaxHeader/*" for compatibility with previous 7-Zip decoder
// GNU TAR writes empty for these fields;
mi.User.Empty();
mi.Group.Empty();
mi.UID = 0;
mi.GID = 0;
mi.DeviceMajor_Defined = false;
mi.DeviceMinor_Defined = false;
mi.Name = "PaxHeader/@PaxHeader";
mi.Mode = 0644; // octal
if (zero_MTime)
mi.MTime = 0;
mi.LinkFlag = NLinkFlag::kPax;
// mi.LinkFlag = 'Z'; // for debug
mi.PackSize = paxSize;
// for (unsigned y = 0; y < 1; y++) { // for debug
RINOK(WriteHeaderReal(mi, true)); // isPax
RINOK(Write_Data_And_Residual(s, paxSize));
// } // for debug
/*
we can send (zero_MTime) for compatibility with gnu tar output.
we can send (zero_MTime = false) for better compatibility with old 7-Zip
*/
// return WriteHeaderReal(item);
/*
false, // isPax
false, // zero_PackSize
false); // zero_MTime
*/
}
}
else // !PosixMode
if (!DOES_NAME_FIT_IN_FIELD(item.Name) ||
!DOES_NAME_FIT_IN_FIELD(item.LinkName))
{
// here we can get all fields from main (item) or create new empty item
/*
CItem mi;
mi.SetDefaultWriteFields();
*/
CItem mi = item;
mi.LinkName.Empty();
// SparseBlocks will be ignored by Is_Sparse()
// mi.SparseBlocks.Clear();
mi.Name = kLongLink;
// mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug
// 21.07 : we set Mode and MTime props as in GNU TAR:
mi.Mode = 0644; // octal
mi.MTime = 0;
mi.User.Empty();
mi.Group.Empty();
/*
gnu tar sets "root" for such items:
uid_to_uname (0, &uname);
gid_to_gname (0, &gname);
*/
/*
mi.User = "root";
mi.Group = "root";
*/
mi.UID = 0;
mi.GID = 0;
mi.DeviceMajor_Defined = false;
mi.DeviceMinor_Defined = false;
for (unsigned i = 0; i < 2; i++)
{
const AString *name;
// We suppose that GNU TAR also writes item for long link before item for LongName?
if (i == 0)
{
mi.LinkFlag = NLinkFlag::kGnu_LongLink;
name = &item.LinkName;
}
else
{
mi.LinkFlag = NLinkFlag::kGnu_LongName;
name = &item.Name;
}
if (DOES_NAME_FIT_IN_FIELD(*name))
continue;
// GNU TAR writes null character after NAME to file. We do same here:
const unsigned nameStreamSize = name->Len() + 1;
mi.PackSize = nameStreamSize;
// for (unsigned y = 0; y < 3; y++) { // for debug
RINOK(WriteHeaderReal(mi));
RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize));
// }
// for debug
/*
const unsigned kSize = (1 << 29) + 16;
CByteBuffer buf;
buf.Alloc(kSize);
memset(buf, 0, kSize);
memcpy(buf, name->Ptr(), name->Len());
const unsigned nameStreamSize = kSize;
mi.PackSize = nameStreamSize;
// for (unsigned y = 0; y < 3; y++) { // for debug
RINOK(WriteHeaderReal(mi));
RINOK(WriteBytes(buf, nameStreamSize));
RINOK(FillDataResidual(nameStreamSize));
*/
}
}
// bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR
if (!DOES_NAME_FIT_IN_FIELD(item.Name))
{
const unsigned nameLen = item.Name.Len() - namePos;
if (!needPathCut)
Prefix.SetFrom(item.Name, namePos - 1);
else
{
Glob_Name = K_PREFIX_PATH_CUT "/_pc_";
if (namePos == 0)
Glob_Name += "root";
else
{
Glob_Name += "crc32/";
char temp[12];
ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp);
Glob_Name += temp;
}
if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max)
Glob_Name.Add_Slash();
else
{
Prefix = Glob_Name;
Glob_Name.Empty();
}
}
Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen);
}
// 21.07: WriteHeaderReal() writes short part of (Name) and (LinkName).
return WriteHeaderReal(item);
/*
mi = item;
if (!DOES_NAME_FIT_IN_FIELD(mi.Name))
mi.Name.SetFrom(item.Name, kNameSize_Max);
if (!DOES_NAME_FIT_IN_FIELD(mi.LinkName))
mi.LinkName.SetFrom(item.LinkName, kNameSize_Max);
return WriteHeaderReal(mi);
*/
}
HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
HRESULT COutArchive::Write_Data(const void *data, unsigned size)
{
unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
if (lastRecordSize == 0)
return S_OK;
unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
Byte buf[NFileHeader::kRecordSize];
memset(buf, 0, rem);
return WriteBytes(buf, rem);
Pos += size;
return WriteStream(Stream, data, size);
}
HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize)
{
const unsigned v = ((unsigned)dataSize & (kRecordSize - 1));
if (v == 0)
return S_OK;
const unsigned rem = kRecordSize - v;
Byte buf[kRecordSize];
memset(buf, 0, rem);
return Write_Data(buf, rem);
}
HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size)
{
RINOK(Write_Data(data, size));
return Write_AfterDataResidual(size);
}
HRESULT COutArchive::WriteFinishHeader()
{
Byte record[NFileHeader::kRecordSize];
memset(record, 0, NFileHeader::kRecordSize);
Byte record[kRecordSize];
memset(record, 0, kRecordSize);
const unsigned kNumFinishRecords = 2;
/* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB)
we also can use cluster alignment:
const unsigned numBlocks = (unsigned)(Pos / NFileHeader::kRecordSize) + kNumFinishRecords;
const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords;
const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB
const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1));
*/
for (unsigned i = 0; i < kNumFinishRecords; i++)
{
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
RINOK(Write_Data(record, kRecordSize));
}
return S_OK;
}

View file

@ -14,21 +14,38 @@ namespace NTar {
class COutArchive
{
CMyComPtr<ISequentialOutStream> m_Stream;
CMyComPtr<ISequentialOutStream> Stream;
AString Glob_Name;
AString Prefix;
HRESULT WriteHeaderReal(const CItem &item, bool isPax = false
// , bool zero_PackSize = false
// , bool zero_MTime = false
);
HRESULT Write_Data(const void *data, unsigned size);
HRESULT Write_Data_And_Residual(const void *data, unsigned size);
HRESULT WriteBytes(const void *data, unsigned size);
HRESULT WriteHeaderReal(const CItem &item);
public:
UInt64 Pos;
bool IsPosixMode;
// bool IsPrefixAllowed; // it's used only if (IsPosixMode == true)
CTimeOptions TimeOptions;
void Create(ISequentialOutStream *outStream)
{
m_Stream = outStream;
Stream = outStream;
}
HRESULT WriteHeader(const CItem &item);
HRESULT FillDataResidual(UInt64 dataSize);
HRESULT Write_AfterDataResidual(UInt64 dataSize);
HRESULT WriteFinishHeader();
COutArchive():
Pos(0),
IsPosixMode(false)
// , IsPrefixAllowed(true)
{}
};
}}

View file

@ -15,9 +15,17 @@ REGISTER_ARC_IO(
"tar", "tar ova", 0, 0xEE,
k_Signature,
NFileHeader::kUstarMagic_Offset,
NArcInfoFlags::kStartOpen |
NArcInfoFlags::kSymLinks |
NArcInfoFlags::kHardLinks,
IsArc_Tar)
NArcInfoFlags::kStartOpen
| NArcInfoFlags::kSymLinks
| NArcInfoFlags::kHardLinks
| NArcInfoFlags::kMTime
| NArcInfoFlags::kMTime_Default
// | NArcInfoTimeFlags::kCTime
// | NArcInfoTimeFlags::kATime
, TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
| TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
| TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::k1ns)
| TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
, IsArc_Tar)
}}

View file

@ -2,6 +2,8 @@
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../Windows/TimeUtils.h"
#include "../../Common/LimitedStreams.h"
@ -15,18 +17,161 @@
namespace NArchive {
namespace NTar {
static void FILETIME_To_PaxTime(const FILETIME &ft, CPaxTime &pt)
{
UInt32 ns;
pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, ns);
pt.Ns = ns * 100;
pt.NumDigits = 7;
}
HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt)
{
pt.Clear();
if (prop.vt == VT_EMPTY)
{
// pt.Sec = 0;
return S_OK;
}
if (prop.vt != VT_FILETIME)
return E_INVALIDARG;
{
UInt32 ns;
pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(prop.filetime, ns);
ns *= 100;
pt.NumDigits = 7;
const unsigned prec = prop.wReserved1;
if (prec >= k_PropVar_TimePrec_Base)
{
pt.NumDigits = prec - k_PropVar_TimePrec_Base;
if (prop.wReserved2 < 100)
ns += prop.wReserved2;
}
pt.Ns = ns;
return S_OK;
}
}
static HRESULT GetTime(IStreamGetProp *getProp, UInt32 pid, CPaxTime &pt)
{
pt.Clear();
NWindows::NCOM::CPropVariant prop;
RINOK(getProp->GetProperty(pid, &prop));
return Prop_To_PaxTime(prop, pt);
}
static HRESULT GetUser(IStreamGetProp *getProp,
UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
UINT codePage, unsigned utfFlags)
{
// printf("\nGetUser\n");
// we keep old values, if both GetProperty() return VT_EMPTY
// we clear old values, if any of GetProperty() returns non-VT_EMPTY;
bool isSet = false;
{
NWindows::NCOM::CPropVariant prop;
RINOK(getProp->GetProperty(pidId, &prop));
if (prop.vt == VT_UI4)
{
isSet = true;
id = prop.ulVal;
name.Empty();
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
}
{
NWindows::NCOM::CPropVariant prop;
RINOK(getProp->GetProperty(pidName, &prop));
if (prop.vt == VT_BSTR)
{
const UString s = prop.bstrVal;
Get_AString_From_UString(s, name, codePage, utfFlags);
// printf("\ngetProp->GetProperty(pidName, &prop) : %s" , name.Ptr());
if (!isSet)
id = 0;
}
else if (prop.vt == VT_UI4)
{
id = prop.ulVal;
name.Empty();
}
else if (prop.vt != VT_EMPTY)
return E_INVALIDARG;
}
return S_OK;
}
/*
static HRESULT GetDevice(IStreamGetProp *getProp,
UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
{
NWindows::NCOM::CPropVariant prop;
RINOK(getProp->GetProperty(kpidDevice, &prop));
if (prop.vt == VT_EMPTY)
return S_OK;
if (prop.vt != VT_UI8)
return E_INVALIDARG;
{
printf("\nTarUpdate.cpp :: GetDevice()\n");
const UInt64 v = prop.uhVal.QuadPart;
majo = MY_dev_major(v);
mino = MY_dev_minor(v);
majo_defined = true;
mino_defined = true;
}
return S_OK;
}
*/
static HRESULT GetDevice(IStreamGetProp *getProp,
UInt32 pid, UInt32 &id, bool &defined)
{
defined = false;
NWindows::NCOM::CPropVariant prop;
RINOK(getProp->GetProperty(pid, &prop));
if (prop.vt == VT_EMPTY)
return S_OK;
if (prop.vt == VT_UI4)
{
id = prop.ulVal;
defined = true;
return S_OK;
}
return E_INVALIDARG;
}
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
UINT codePage, unsigned utfFlags,
const CUpdateOptions &options,
IArchiveUpdateCallback *updateCallback)
{
COutArchive outArchive;
outArchive.Create(outStream);
outArchive.Pos = 0;
outArchive.IsPosixMode = options.PosixMode;
outArchive.TimeOptions = options.TimeOptions;
CMyComPtr<IOutStream> outSeekStream;
outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);
if (outSeekStream)
{
/*
// for debug
Byte buf[1 << 14];
memset (buf, 0, sizeof(buf));
RINOK(outStream->Write(buf, sizeof(buf), NULL));
*/
// we need real outArchive.Pos, if outSeekStream->SetSize() will be used.
RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &outArchive.Pos));
}
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
@ -40,7 +185,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (ui.NewData)
complexity += ui.Size;
else
complexity += inputItems[(unsigned)ui.IndexInArc].GetFullSize();
complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned();
}
RINOK(updateCallback->SetTotal(complexity));
@ -58,21 +203,31 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
complexity = 0;
for (i = 0; i < updateItems.Size(); i++)
// const int kNumReduceDigits = -1; // for debug
for (i = 0;; i++)
{
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
if (i == updateItems.Size())
return outArchive.WriteFinishHeader();
const CUpdateItem &ui = updateItems[i];
CItem item;
if (ui.NewProps)
{
item.SetDefaultWriteFields();
item.Mode = ui.Mode;
item.SetMagic_Posix(options.PosixMode);
item.Name = ui.Name;
item.User = ui.User;
item.Group = ui.Group;
item.UID = ui.UID;
item.GID = ui.GID;
item.DeviceMajor = ui.DeviceMajor;
item.DeviceMinor = ui.DeviceMinor;
item.DeviceMajor_Defined = ui.DeviceMajor_Defined;
item.DeviceMinor_Defined = ui.DeviceMinor_Defined;
if (ui.IsDir)
{
@ -81,11 +236,15 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
else
{
item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
item.PackSize = ui.Size;
item.Set_LinkFlag_for_File(ui.Mode);
}
item.MTime = ui.MTime;
// 22.00
item.Mode = ui.Mode & ~(UInt32)MY_LIN_S_IFMT;
item.PaxTimes = ui.PaxTimes;
// item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
item.MTime = ui.PaxTimes.MTime.GetSec();
}
else
item = inputItems[(unsigned)ui.IndexInArc];
@ -93,7 +252,8 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
AString symLink;
if (ui.NewData || ui.NewProps)
{
RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, utfFlags, true));
RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink,
options.CodePage, options.UtfFlags, true));
if (!symLink.IsEmpty())
{
item.LinkFlag = NFileHeader::NLinkFlag::kSymLink;
@ -120,7 +280,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
else
{
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
if (res == S_FALSE)
needWrite = false;
@ -128,31 +288,105 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
{
RINOK(res);
if (fileInStream)
{
CMyComPtr<IStreamGetProps> getProps;
fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
if (getProps)
{
FILETIME mTime;
UInt64 size2;
if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
{
item.PackSize = size2;
item.Size = size2;
item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
}
}
}
else
if (!fileInStream)
{
item.PackSize = 0;
item.Size = 0;
}
else
{
CMyComPtr<IStreamGetProps> getProps;
CMyComPtr<IStreamGetProp> getProp;
fileInStream->QueryInterface(IID_IStreamGetProp, (void **)&getProp);
if (getProp)
{
if (options.Write_MTime.Val) RINOK(GetTime(getProp, kpidMTime, item.PaxTimes.MTime))
if (options.Write_ATime.Val) RINOK(GetTime(getProp, kpidATime, item.PaxTimes.ATime))
if (options.Write_CTime.Val) RINOK(GetTime(getProp, kpidCTime, item.PaxTimes.CTime))
if (options.PosixMode)
{
/*
RINOK(GetDevice(getProp, item.DeviceMajor, item.DeviceMinor,
item.DeviceMajor_Defined, item.DeviceMinor_Defined));
*/
bool defined = false;
UInt32 val = 0;
RINOK(GetDevice(getProp, kpidDeviceMajor, val, defined));
if (defined)
{
item.DeviceMajor = val;
item.DeviceMajor_Defined = true;
item.DeviceMinor = 0;
item.DeviceMinor_Defined = false;
RINOK(GetDevice(getProp, kpidDeviceMinor, item.DeviceMinor, item.DeviceMinor_Defined));
}
}
RINOK(GetUser(getProp, kpidUser, kpidUserId, item.User, item.UID, options.CodePage, options.UtfFlags));
RINOK(GetUser(getProp, kpidGroup, kpidGroupId, item.Group, item.GID, options.CodePage, options.UtfFlags));
{
NWindows::NCOM::CPropVariant prop;
RINOK(getProp->GetProperty(kpidPosixAttrib, &prop));
if (prop.vt == VT_EMPTY)
item.Mode =
MY_LIN_S_IRWXO
| MY_LIN_S_IRWXG
| MY_LIN_S_IRWXU
| (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
else if (prop.vt != VT_UI4)
return E_INVALIDARG;
else
item.Mode = prop.ulVal;
// 21.07 : we clear high file type bits as GNU TAR.
item.Set_LinkFlag_for_File(item.Mode);
item.Mode &= ~(UInt32)MY_LIN_S_IFMT;
}
{
NWindows::NCOM::CPropVariant prop;
RINOK(getProp->GetProperty(kpidSize, &prop));
if (prop.vt != VT_UI8)
return E_INVALIDARG;
const UInt64 size = prop.uhVal.QuadPart;
item.PackSize = size;
item.Size = size;
}
/*
printf("\nNum digits = %d %d\n",
(int)item.PaxTimes.MTime.NumDigits,
(int)item.PaxTimes.MTime.Ns);
*/
}
else
{
fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
if (getProps)
{
FILETIME mTime, aTime, cTime;
UInt64 size2;
if (getProps->GetProps(&size2,
options.Write_CTime.Val ? &cTime : NULL,
options.Write_ATime.Val ? &aTime : NULL,
options.Write_MTime.Val ? &mTime : NULL,
NULL) == S_OK)
{
item.PackSize = size2;
item.Size = size2;
if (options.Write_MTime.Val) FILETIME_To_PaxTime(mTime, item.PaxTimes.MTime);
if (options.Write_ATime.Val) FILETIME_To_PaxTime(aTime, item.PaxTimes.ATime);
if (options.Write_CTime.Val) FILETIME_To_PaxTime(cTime, item.PaxTimes.CTime);
}
}
}
}
{
// we must request kpidHardLink after updateCallback->GetStream()
AString hardLink;
RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, utfFlags, true));
RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink,
options.CodePage, options.UtfFlags, true));
if (!hardLink.IsEmpty())
{
item.LinkFlag = NFileHeader::NLinkFlag::kHardLink;
@ -165,37 +399,98 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
}
// item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
if (ui.NewProps)
item.MTime = item.PaxTimes.MTime.GetSec();
if (needWrite)
{
UInt64 fileHeaderStartPos = outArchive.Pos;
const UInt64 headerPos = outArchive.Pos;
// item.PackSize = ((UInt64)1 << 33); // for debug
RINOK(outArchive.WriteHeader(item));
if (fileInStream)
{
RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
outArchive.Pos += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != item.PackSize)
for (unsigned numPasses = 0;; numPasses++)
{
/* we support 2 attempts to write header:
pass-0: main pass:
pass-1: additional pass, if size_of_file and size_of_header are changed */
if (numPasses >= 2)
{
// opRes = NArchive::NUpdate::NOperationResult::kError_FileChanged;
// break;
return E_FAIL;
}
const UInt64 dataPos = outArchive.Pos;
RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
outArchive.Pos += copyCoderSpec->TotalSize;
RINOK(outArchive.Write_AfterDataResidual(copyCoderSpec->TotalSize));
// if (numPasses >= 10) // for debug
if (copyCoderSpec->TotalSize == item.PackSize)
break;
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kOutArcIndex, (UInt32)ui.IndexInClient,
NUpdateNotifyOp::kInFileChanged))
}
if (!outSeekStream)
return E_FAIL;
UInt64 backOffset = outArchive.Pos - fileHeaderStartPos;
RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL));
outArchive.Pos = fileHeaderStartPos;
const UInt64 nextPos = outArchive.Pos;
RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL));
outArchive.Pos = headerPos;
item.PackSize = copyCoderSpec->TotalSize;
RINOK(outArchive.WriteHeader(item));
RINOK(outSeekStream->Seek((Int64)item.PackSize, STREAM_SEEK_CUR, NULL));
outArchive.Pos += item.PackSize;
// if (numPasses >= 10) // for debug
if (outArchive.Pos == dataPos)
{
const UInt64 alignedSize = nextPos - dataPos;
if (alignedSize != 0)
{
RINOK(outSeekStream->Seek(alignedSize, STREAM_SEEK_CUR, NULL));
outArchive.Pos += alignedSize;
}
break;
}
// size of header was changed.
// we remove data after header and try new attempt, if required
CMyComPtr<IInStream> fileSeekStream;
fileInStream->QueryInterface(IID_IInStream, (void **)&fileSeekStream);
if (!fileSeekStream)
return E_FAIL;
RINOK(fileSeekStream->Seek(0, STREAM_SEEK_SET, NULL));
RINOK(outSeekStream->SetSize(outArchive.Pos));
if (item.PackSize == 0)
break;
}
RINOK(outArchive.FillDataResidual(item.PackSize));
}
}
complexity += item.PackSize;
fileInStream.Release();
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
}
else
{
// (ui.NewData == false)
if (opCallback)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
NUpdateNotifyOp::kReplicate))
}
const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc];
UInt64 size;
UInt64 size, pos;
if (ui.NewProps)
{
@ -216,44 +511,37 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
item.PackSize = existItem.PackSize;
}
item.DeviceMajorDefined = existItem.DeviceMajorDefined;
item.DeviceMinorDefined = existItem.DeviceMinorDefined;
item.DeviceMajor_Defined = existItem.DeviceMajor_Defined;
item.DeviceMinor_Defined = existItem.DeviceMinor_Defined;
item.DeviceMajor = existItem.DeviceMajor;
item.DeviceMinor = existItem.DeviceMinor;
item.UID = existItem.UID;
item.GID = existItem.GID;
RINOK(outArchive.WriteHeader(item));
RINOK(inStream->Seek((Int64)existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
size = existItem.PackSize;
size = existItem.Get_PackSize_Aligned();
pos = existItem.Get_DataPos();
}
else
{
RINOK(inStream->Seek((Int64)existItem.HeaderPos, STREAM_SEEK_SET, NULL));
size = existItem.GetFullSize();
size = existItem.Get_FullSize_Aligned();
pos = existItem.HeaderPos;
}
streamSpec->Init(size);
if (opCallback)
if (size != 0)
{
RINOK(opCallback->ReportOperation(
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
NUpdateNotifyOp::kReplicate))
RINOK(inStream->Seek((Int64)pos, STREAM_SEEK_SET, NULL));
streamSpec->Init(size);
// 22.00 : we copy Residual data from old archive to new archive instead of zeroing
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != size)
return E_FAIL;
outArchive.Pos += size;
// RINOK(outArchive.Write_AfterDataResidual(existItem.PackSize));
complexity += size;
}
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != size)
return E_FAIL;
outArchive.Pos += size;
RINOK(outArchive.FillDataResidual(existItem.PackSize));
complexity += size;
}
}
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
return outArchive.WriteFinishHeader();
}
}}

View file

@ -15,27 +15,60 @@ struct CUpdateItem
int IndexInArc;
unsigned IndexInClient;
UInt64 Size;
Int64 MTime;
// Int64 MTime;
UInt32 Mode;
bool NewData;
bool NewProps;
bool IsDir;
bool DeviceMajor_Defined;
bool DeviceMinor_Defined;
UInt32 UID;
UInt32 GID;
UInt32 DeviceMajor;
UInt32 DeviceMinor;
AString Name;
AString User;
AString Group;
CUpdateItem(): Size(0), IsDir(false) {}
CPaxTimes PaxTimes;
CUpdateItem():
Size(0),
IsDir(false),
DeviceMajor_Defined(false),
DeviceMinor_Defined(false),
UID(0),
GID(0)
{}
};
struct CUpdateOptions
{
UINT CodePage;
unsigned UtfFlags;
bool PosixMode;
CBoolPair Write_MTime;
CBoolPair Write_ATime;
CBoolPair Write_CTime;
CTimeOptions TimeOptions;
};
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
const CObjectVector<CItemEx> &inputItems,
const CObjectVector<CUpdateItem> &updateItems,
UINT codePage, unsigned utfFlags,
const CUpdateOptions &options,
IArchiveUpdateCallback *updateCallback);
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
UINT codePage, unsigned utfFlags, bool convertSlash);
HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt);
void Get_AString_From_UString(const UString &s, AString &res,
UINT codePage, unsigned utfFlags);
}}
#endif

View file

@ -27,11 +27,17 @@ static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop
return;
if (t.IsLocal())
numSecs -= (Int64)((Int32)t.GetMinutesOffset() * 60);
FILETIME ft;
UInt64 v = (((numSecs * 100 + d[9]) * 100 + d[10]) * 100 + d[11]) * 10;
ft.dwLowDateTime = (UInt32)v;
ft.dwHighDateTime = (UInt32)(v >> 32);
prop = ft;
const UInt32 m0 = d[9];
const UInt32 m1 = d[10];
const UInt32 m2 = d[11];
unsigned numDigits = 0;
UInt64 v = numSecs * 10000000;
if (m0 < 100 && m1 < 100 && m2 < 100)
{
v += m0 * 100000 + m1 * 1000 + m2 * 10;
numDigits = 6;
}
prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + numDigits);
}
static const Byte kProps[] =
@ -41,7 +47,8 @@ static const Byte kProps[] =
kpidSize,
kpidPackSize,
kpidMTime,
kpidATime
kpidATime,
kpidChangeTime
};
static const Byte kArcProps[] =
@ -205,6 +212,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break;
}
}
prop.Detach(value);

View file

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

View file

@ -243,7 +243,7 @@ struct CItem
UInt64 NumLogBlockRecorded;
CTime ATime;
CTime MTime;
// CTime AttrtTime;
CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of.
// UInt32 CheckPoint;
// CLongAllocDesc ExtendedAttrIcb;
// CRegId ImplId;

View file

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

View file

@ -171,6 +171,20 @@ struct CHeader
UInt64 LogOffset;
CGuid Guids[3];
bool IsEqualTo(const CHeader &h) const
{
if (SequenceNumber != h.SequenceNumber)
return false;
if (LogLength != h.LogLength)
return false;
if (LogOffset != h.LogOffset)
return false;
for (unsigned i = 0; i < 3; i++)
if (!Guids[i].IsEqualTo(h.Guids[i]))
return false;
return true;
};
bool Parse(Byte *p);
};
@ -1174,7 +1188,18 @@ HRESULT CHandler::Open3()
unsigned mainIndex;
if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0;
else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1;
else return S_FALSE;
else
{
/* Disk2vhd v2.02 can create image with 2 full copies of headers.
It's violation of VHDX specification:
"A header is current if it is the only valid header
or if it is valid and its SequenceNumber field is
greater than the other header's SequenceNumber".
but we support such Disk2vhd archives. */
if (!headers[0].IsEqualTo(headers[1]))
return S_FALSE;
mainIndex = 0;
}
const CHeader &h = headers[mainIndex];
Header = h;
@ -1567,6 +1592,7 @@ static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
void CHandler::AddComment(UString &s) const
{
AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
AddComment_UInt64(s, "PhysicalSize", _phySize);
if (!_errorMessage.IsEmpty())

View file

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

View file

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

View file

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

View file

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

View file

@ -10,13 +10,20 @@ namespace NArchive {
namespace NWim {
REGISTER_ARC_IO(
"wim", "wim swm esd ppkg", 0, 0xE6,
kSignature,
0,
NArcInfoFlags::kAltStreams |
NArcInfoFlags::kNtSecure |
NArcInfoFlags::kSymLinks |
NArcInfoFlags::kHardLinks
"wim", "wim swm esd ppkg", NULL, 0xE6
, kSignature, 0
, NArcInfoFlags::kAltStreams
| NArcInfoFlags::kNtSecure
| NArcInfoFlags::kSymLinks
| NArcInfoFlags::kHardLinks
| NArcInfoFlags::kCTime
// | NArcInfoFlags::kCTime_Default
| NArcInfoFlags::kATime
// | NArcInfoFlags::kATime_Default
| NArcInfoFlags::kMTime
| NArcInfoFlags::kMTime_Default
, TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
| TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
, NULL)
}}

View file

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

View file

@ -190,6 +190,8 @@ static const Byte kProps[] =
kpidVolumeIndex,
kpidOffset
// kpidIsAltStream
// , kpidChangeTime // for debug
// , 255 // for debug
};
static const Byte kArcProps[] =
@ -347,6 +349,34 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
static bool NtfsUnixTimeToProp(bool fromCentral,
const CExtraBlock &extra,
unsigned ntfsIndex, unsigned unixIndex, NWindows::NCOM::CPropVariant &prop)
{
{
FILETIME ft;
if (extra.GetNtfsTime(ntfsIndex, ft))
{
PropVariant_SetFrom_NtfsTime(prop, ft);
return true;
}
}
{
UInt32 unixTime = 0;
if (!extra.GetUnixTime(fromCentral, unixIndex, unixTime))
return false;
/*
// we allow unixTime == 0
if (unixTime == 0)
return false;
*/
PropVariant_SetFrom_UnixTime(prop, unixTime);
return true;
}
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
@ -392,6 +422,30 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
case kpidPackSize: prop = item.PackSize; break;
case kpidCTime:
NtfsUnixTimeToProp(item.FromCentral, extra,
NFileHeader::NNtfsExtra::kCTime,
NFileHeader::NUnixTime::kCTime, prop);
break;
case kpidATime:
NtfsUnixTimeToProp(item.FromCentral, extra,
NFileHeader::NNtfsExtra::kATime,
NFileHeader::NUnixTime::kATime, prop);
break;
case kpidMTime:
{
if (!NtfsUnixTimeToProp(item.FromCentral, extra,
NFileHeader::NNtfsExtra::kMTime,
NFileHeader::NUnixTime::kMTime, prop))
{
if (item.Time != 0)
PropVariant_SetFrom_DosTime(prop, item.Time);
}
break;
}
case kpidTimeType:
{
FILETIME ft;
@ -399,7 +453,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
UInt32 type;
if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
type = NFileTimeType::kWindows;
else if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime))
else if (extra.GetUnixTime(item.FromCentral, NFileHeader::NUnixTime::kMTime, unixTime))
type = NFileTimeType::kUnix;
else
type = NFileTimeType::kDOS;
@ -407,64 +461,28 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
break;
}
case kpidCTime:
/*
// for debug to get Dos time values:
case kpidChangeTime: if (item.Time != 0) PropVariant_SetFrom_DosTime(prop, item.Time); break;
// for debug
// time difference (dos - utc)
case 255:
{
FILETIME utc;
bool defined = true;
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, utc))
if (NtfsUnixTimeToProp(item.FromCentral, extra,
NFileHeader::NNtfsExtra::kMTime,
NFileHeader::NUnixTime::kMTime, prop))
{
UInt32 unixTime = 0;
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kCTime, unixTime))
NTime::UnixTimeToFileTime(unixTime, utc);
else
defined = false;
}
if (defined)
prop = utc;
break;
}
case kpidATime:
{
FILETIME utc;
bool defined = true;
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, utc))
{
UInt32 unixTime = 0;
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kATime, unixTime))
NTime::UnixTimeToFileTime(unixTime, utc);
else
defined = false;
}
if (defined)
prop = utc;
break;
}
case kpidMTime:
{
FILETIME utc;
bool defined = true;
if (!extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc))
{
UInt32 unixTime = 0;
if (extra.GetUnixTime(true, NFileHeader::NUnixTime::kMTime, unixTime))
NTime::UnixTimeToFileTime(unixTime, utc);
else
FILETIME localFileTime;
if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime))
{
FILETIME localFileTime;
if (item.Time == 0)
defined = false;
else if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
!LocalFileTimeToFileTime(&localFileTime, &utc))
utc.dwHighDateTime = utc.dwLowDateTime = 0;
UInt64 t1 = FILETIME_To_UInt64(prop.filetime);
UInt64 t2 = FILETIME_To_UInt64(localFileTime);
prop.Set_Int64(t2 - t1);
}
}
if (defined)
prop = utc;
break;
}
*/
case kpidAttrib: prop = item.GetWinAttrib(); break;
@ -1122,7 +1140,18 @@ HRESULT CZipDecoder::Decode(
AString_Wipe charPassword;
if (password)
{
UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP);
/*
// 22.00: do we need UTF-8 passwords here ?
if (item.IsUtf8()) // 22.00
{
// throw 1;
ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword);
}
else
*/
{
UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP);
}
/*
if (wzAesMode || pkAesMode)
{
@ -1341,6 +1370,8 @@ HRESULT CZipDecoder::Decode(
if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted())
{
// for debug : we can disable this code (kStore + 50), if we want to test CopyCoder+Filter
// here we use filter without CopyCoder
readFromFilter = false;
COutStreamWithPadPKCS7 *padStreamSpec = NULL;
@ -1425,33 +1456,44 @@ HRESULT CZipDecoder::Decode(
const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed);
if (processed + padSize > coderPackSize)
truncatedError = true;
else if (processed + padSize < coderPackSize)
dataAfterEnd = true;
else
{
if (processed + padSize < coderPackSize)
dataAfterEnd = true;
else
{
// here we can PKCS7 padding data from reminder (it can be inside stream buffer in coder).
// here we check PKCS7 padding data from reminder (it can be inside stream buffer in coder).
CMyComPtr<ICompressReadUnusedFromInBuf> readInStream;
coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream);
if (readInStream)
// CCopyCoder() for kStore doesn't read data outside of (item.Size)
if (readInStream || id == NFileHeader::NCompressionMethod::kStore)
{
// change pad size, it we support another block size in ZipStron
// here we request more to detect error with data after end.
// change pad size, if we support another block size in ZipStrong.
// here we request more data to detect error with data after end.
const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16;
Byte buf[kBufSize];
UInt32 processedSize;
RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize));
UInt32 processedSize = 0;
if (readInStream)
{
RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize));
}
if (processedSize > padSize)
dataAfterEnd = true;
else
{
if (ReadStream_FALSE(filterStream, buf + processedSize, padSize - processedSize) != S_OK)
padError = true;
else
for (unsigned i = 0; i < padSize; i++)
if (buf[i] != padSize)
padError = true;
size_t processedSize2 = kBufSize - processedSize;
result = ReadStream(filterStream, buf + processedSize, &processedSize2);
if (result == S_OK)
{
processedSize2 += processedSize;
if (processedSize2 > padSize)
dataAfterEnd = true;
else if (processedSize2 < padSize)
truncatedError = true;
else
for (unsigned i = 0; i < padSize; i++)
if (buf[i] != padSize)
padError = true;
}
}
}
}

View file

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

View file

@ -30,7 +30,7 @@ namespace NZip {
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
{
*timeType = NFileTimeType::kDOS;
*timeType = TimeOptions.Prec;
return S_OK;
}
@ -207,27 +207,58 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
}
*/
// 22.00 : kpidTimeType is useless here : the code was disabled
/*
{
CPropVariant prop;
RINOK(callback->GetProperty(i, kpidTimeType, &prop));
if (prop.vt == VT_UI4)
ui.NtfsTimeIsDefined = (prop.ulVal == NFileTimeType::kWindows);
ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows);
else
ui.NtfsTimeIsDefined = m_WriteNtfsTimeExtra;
ui.NtfsTime_IsDefined = _Write_NtfsTime;
}
RINOK(GetTime(callback, i, kpidMTime, ui.Ntfs_MTime));
RINOK(GetTime(callback, i, kpidATime, ui.Ntfs_ATime));
RINOK(GetTime(callback, i, kpidCTime, ui.Ntfs_CTime));
*/
if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime));
if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime));
if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime));
if (TimeOptions.Prec != k_PropVar_TimePrec_DOS)
{
FILETIME localFileTime = { 0, 0 };
if (ui.Ntfs_MTime.dwHighDateTime != 0 ||
ui.Ntfs_MTime.dwLowDateTime != 0)
if (!FileTimeToLocalFileTime(&ui.Ntfs_MTime, &localFileTime))
return E_INVALIDARG;
FileTimeToDosTime(localFileTime, ui.Time);
if (TimeOptions.Prec == k_PropVar_TimePrec_Unix ||
TimeOptions.Prec == k_PropVar_TimePrec_Base)
ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime);
else
{
/*
// if we want to store zero timestamps as zero timestamp, use the following:
ui.Write_NtfsTime =
_Write_MTime ||
_Write_ATime ||
_Write_CTime;
*/
// We treat zero timestamp as no timestamp
ui.Write_NtfsTime =
! FILETIME_IsZero (ui.Ntfs_MTime) ||
! FILETIME_IsZero (ui.Ntfs_ATime) ||
! FILETIME_IsZero (ui.Ntfs_CTime);
}
}
/*
how 0 in dos time works:
win10 explorer extract : some random date 1601-04-25.
winrar 6.10 : write time.
7zip : MTime of archive is used
how 0 in tar works:
winrar 6.10 : 1970
0 in dos field can show that there is no timestamp.
we write correct 1970-01-01 in dos field, to support correct extraction in Win10.
*/
UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time);
NItemName::ReplaceSlashes_OsToUnix(name);
bool needSlash = ui.IsDir;
@ -441,11 +472,21 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
if (mainMethod != NFileHeader::NCompressionMethod::kStore)
options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore);
CUpdateOptions uo;
uo.Write_MTime = TimeOptions.Write_MTime.Val;
uo.Write_ATime = TimeOptions.Write_ATime.Val;
uo.Write_CTime = TimeOptions.Write_CTime.Val;
/*
uo.Write_NtfsTime = _Write_NtfsTime &&
(_Write_MTime || _Write_ATime || _Write_CTime);
uo.Write_UnixTime = _Write_UnixTime;
*/
return Update(
EXTERNAL_CODECS_VARS
m_Items, updateItems, outStream,
m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock,
options, callback);
uo, options, callback);
COM_TRY_END2
}
@ -494,10 +535,9 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
return E_INVALIDARG;
}
}
else if (name.IsEqualTo("tc"))
{
RINOK(PROPVARIANT_to_bool(prop, m_WriteNtfsTimeExtra));
}
else if (name.IsEqualTo("cl"))
{
RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal));
@ -532,7 +572,12 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR
}
else
{
RINOK(_props.SetProperty(name, prop));
bool processed = false;
RINOK(TimeOptions.Parse(name, prop, processed));
if (!processed)
{
RINOK(_props.SetProperty(name, prop));
}
}
// RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
}

View file

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

View file

@ -1045,8 +1045,23 @@ bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlo
if (cdItem)
{
if (isOK && ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
{ if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
if (isOK)
{
if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
{ if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
/*
else if (size == 8)
{
size -= 8;
const UInt64 v = ReadUInt64();
// soong_zip, an AOSP tool (written in the Go) writes incorrect value.
// we can ignore that minor error here
if (v != cdItem->LocalHeaderPos)
isOK = false; // ignore error
// isOK = false; // force error
}
*/
}
if (isOK && ZIP64_IS_16_MAX(cdItem->Disk))
{ if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }}
@ -1926,7 +1941,7 @@ static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
{
if (left >= right)
return -1;
const unsigned index = (left + right) / 2;
const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2);
const CItemEx &item2 = items[index];
if (item.Disk < item2.Disk)
right = index;

View file

@ -30,11 +30,12 @@ static const CUInt32PCharPair g_ExtraTypes[] =
{
{ NExtraID::kZip64, "Zip64" },
{ NExtraID::kNTFS, "NTFS" },
{ NExtraID::kUnix0, "UNIX" },
{ NExtraID::kStrongEncrypt, "StrongCrypto" },
{ NExtraID::kUnixTime, "UT" },
{ NExtraID::kUnixExtra, "UX" },
{ NExtraID::kUnix2Extra, "Ux" },
{ NExtraID::kUnix3Extra, "ux" },
{ NExtraID::kUnix1, "UX" },
{ NExtraID::kUnix2, "Ux" },
{ NExtraID::kUnixN, "ux" },
{ NExtraID::kIzUnicodeComment, "uc" },
{ NExtraID::kIzUnicodeName, "up" },
{ NExtraID::kIzNtSecurityDescriptor, "SD" },
@ -50,6 +51,23 @@ void CExtraSubBlock::PrintInfo(AString &s) const
if (pair.Value == ID)
{
s += pair.Name;
if (ID == NExtraID::kUnixTime)
{
if (Data.Size() >= 1)
{
s += ':';
const Byte flags = Data[0];
if (flags & 1) s += 'M';
if (flags & 2) s += 'A';
if (flags & 4) s += 'C';
const UInt32 size = (UInt32)(Data.Size()) - 1;
if (size % 4 == 0)
{
s += ':';
s.Add_UInt32(size / 4);
}
}
}
/*
if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
{
@ -133,14 +151,22 @@ bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
return false;
}
bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const
bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const
{
/* Info-Zip :
The central-header extra field contains the modification
time only, or no timestamp at all.
Size of Data is used to flag its presence or absence
If "Flags" indicates that Modtime is present in the local header
field, it MUST be present in the central header field, too
*/
res = 0;
UInt32 size = (UInt32)Data.Size();
if (ID != NExtraID::kUnixTime || size < 5)
return false;
const Byte *p = (const Byte *)Data;
Byte flags = *p++;
const Byte flags = *p++;
size--;
if (isCentral)
{
@ -168,18 +194,35 @@ bool CExtraSubBlock::ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res
}
bool CExtraSubBlock::ExtractUnixExtraTime(unsigned index, UInt32 &res) const
// Info-ZIP's abandoned "Unix1 timestamps & owner ID info"
bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const
{
res = 0;
const size_t size = Data.Size();
unsigned offset = index * 4;
if (ID != NExtraID::kUnixExtra || size < offset + 4)
const unsigned offset = index * 4;
if (Data.Size() < offset + 4)
return false;
if (ID != NExtraID::kUnix0 &&
ID != NExtraID::kUnix1)
return false;
const Byte *p = (const Byte *)Data + offset;
res = GetUi32(p);
return true;
}
/*
// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps"
bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const
{
res = 0;
const unsigned offset = index * 4;
if (ID != NExtraID::kUnix0 || Data.Size() < offset)
return false;
const Byte *p = (const Byte *)Data + offset;
res = GetUi32(p);
return true;
}
*/
bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
{
@ -199,7 +242,7 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
{
const CExtraSubBlock &sb = SubBlocks[i];
if (sb.ID == NFileHeader::NExtraID::kUnixTime)
return sb.ExtractUnixTime(isCentral, index, res);
return sb.Extract_UnixTime(isCentral, index, res);
}
}
@ -214,8 +257,9 @@ bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
FOR_VECTOR (i, SubBlocks)
{
const CExtraSubBlock &sb = SubBlocks[i];
if (sb.ID == NFileHeader::NExtraID::kUnixExtra)
return sb.ExtractUnixExtraTime(index, res);
if (sb.ID == NFileHeader::NExtraID::kUnix0 ||
sb.ID == NFileHeader::NExtraID::kUnix1)
return sb.Extract_Unix01_Time(index, res);
}
}
return false;

View file

@ -31,8 +31,9 @@ struct CExtraSubBlock
CByteBuffer Data;
bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
bool ExtractUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
bool ExtractUnixExtraTime(unsigned index, UInt32 &res) const;
bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const;
bool Extract_Unix01_Time(unsigned index, UInt32 &res) const;
// bool Extract_Unix_Time(unsigned index, UInt32 &res) const;
bool CheckIzUnicode(const AString &s) const;

View file

@ -4,6 +4,7 @@
#include "../../../../C/7zCrc.h"
#include "../../../Windows/TimeUtils.h"
#include "../../Common/OffsetStream.h"
#include "ZipOut.h"
@ -110,6 +111,40 @@ void COutArchive::WriteUtfName(const CItemOut &item)
WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size());
}
static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8);
static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4);
void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
{
if (writeNtfs)
{
// windows explorer ignores that extra
Write16(NFileHeader::NExtraID::kNTFS);
Write16(k_Ntfs_ExtraSize);
Write32(0); // reserved
Write16(NFileHeader::NNtfsExtra::kTagTime);
Write16(8 * 3);
WriteNtfsTime(item.Ntfs_MTime);
WriteNtfsTime(item.Ntfs_ATime);
WriteNtfsTime(item.Ntfs_CTime);
}
if (item.Write_UnixTime)
{
// windows explorer ignores that extra
// by specification : should we write to local header also?
Write16(NFileHeader::NExtraID::kUnixTime);
Write16(k_UnixTime_ExtraSize);
const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime);
Write8(flags);
UInt32 unixTime;
NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime);
Write32(unixTime);
}
}
void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
{
m_LocalHeaderPos = m_CurPos;
@ -122,8 +157,14 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
if (needCheck && m_IsZip64)
isZip64 = true;
// Why don't we write NTFS timestamps to local header?
// Probably we want to reduce size of archive?
const bool writeNtfs = false; // do not write NTFS timestamp to local header
// const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header
const UInt32 localExtraSize = (UInt32)(
(isZip64 ? (4 + 8 + 8): 0)
+ (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
+ (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
+ item.Get_UtfName_ExtraSize()
+ item.LocalExtra.GetSize());
if ((UInt16)localExtraSize != localExtraSize)
@ -168,13 +209,12 @@ void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
Write64(packSize);
}
WriteTimeExtra(item, writeNtfs);
WriteUtfName(item);
WriteExtra(item.LocalExtra);
// Why don't we write NTFS timestamps to local header?
// Probably we want to reduce size of archive?
const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
throw CSystemException(E_FAIL);
@ -231,10 +271,10 @@ void COutArchive::WriteDescriptor(const CItemOut &item)
void COutArchive::WriteCentralHeader(const CItemOut &item)
{
bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
bool isZip64 = isPack64 || isUnPack64 || isPosition64;
const bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
const bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
const bool isZip64 = isPack64 || isUnPack64 || isPosition64;
Write32(NSignature::kCentralFileHeader);
Write8(item.MadeByVersion.Version);
@ -249,10 +289,11 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
Write16((UInt16)item.Name.Len());
const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
const bool writeNtfs = item.Write_NtfsTime;
const size_t centralExtraSize =
(isZip64 ? 4 + zip64ExtraSize : 0)
+ (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0)
+ (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
+ (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
+ item.Get_UtfName_ExtraSize()
+ item.CentralExtra.GetSize();
@ -283,18 +324,7 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
Write64(item.LocalHeaderPos);
}
if (item.NtfsTimeIsDefined)
{
Write16(NFileHeader::NExtraID::kNTFS);
Write16(kNtfsExtraSize);
Write32(0); // reserved
Write16(NFileHeader::NNtfsExtra::kTagTime);
Write16(8 * 3);
WriteNtfsTime(item.Ntfs_MTime);
WriteNtfsTime(item.Ntfs_ATime);
WriteNtfsTime(item.Ntfs_CTime);
}
WriteTimeExtra(item, writeNtfs);
WriteUtfName(item);
WriteExtra(item.CentralExtra);
@ -304,15 +334,15 @@ void COutArchive::WriteCentralHeader(const CItemOut &item)
void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
{
UInt64 cdOffset = GetCurPos();
const UInt64 cdOffset = GetCurPos();
FOR_VECTOR (i, items)
WriteCentralHeader(items[i]);
UInt64 cd64EndOffset = GetCurPos();
UInt64 cdSize = cd64EndOffset - cdOffset;
bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
bool cdSize64 = DOES_NEED_ZIP64(cdSize);
bool items64 = items.Size() >= 0xFFFF;
bool isZip64 = (cdOffset64 || cdSize64 || items64);
const UInt64 cd64EndOffset = GetCurPos();
const UInt64 cdSize = cd64EndOffset - cdOffset;
const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
const bool items64 = items.Size() >= 0xFFFF;
const bool isZip64 = (cdOffset64 || cdSize64 || items64);
// isZip64 = true; // to test Zip64

View file

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

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,
k_Signature,
0,
NArcInfoFlags::kFindSignature |
NArcInfoFlags::kMultiSignature |
NArcInfoFlags::kUseGlobalOffset,
IsArc_Zip)
NArcInfoFlags::kFindSignature
| NArcInfoFlags::kMultiSignature
| NArcInfoFlags::kUseGlobalOffset
| NArcInfoFlags::kCTime
// | NArcInfoFlags::kCTime_Default
| NArcInfoFlags::kATime
// | NArcInfoFlags::kATime_Default
| NArcInfoFlags::kMTime
| NArcInfoFlags::kMTime_Default
, TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
| TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
| TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS)
| TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
, IsArc_Zip)
}}

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,5 +3,5 @@
STRINGTABLE
BEGIN
100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs"
100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs apfs"
END

View file

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

View file

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

View file

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

View file

@ -28,10 +28,11 @@ MY_VERSION_INFO_DLL("7z Plugin" , "7z")
22 ICON "../../Archive/Icons/ntfs.ico"
23 ICON "../../Archive/Icons/xz.ico"
24 ICON "../../Archive/Icons/squashfs.ico"
25 ICON "../../Archive/Icons/apfs.ico"
STRINGTABLE
BEGIN
100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24"
100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 apfs:25"
END

View file

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

View file

@ -2,18 +2,30 @@
#include "StdAfx.h"
// #include <stdio.h>
#ifndef _WIN32
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "../../Windows/FileFind.h"
#include <grp.h>
#include <pwd.h>
// for major minor
// BSD: <sys/types.h>
#include <sys/sysmacros.h>
#endif
#include "../../Windows/FileFind.h"
#ifdef SUPPORT_DEVICE_FILE
#include "../../../C/Alloc.h"
#include "../../Common/Defs.h"
#endif
#include "../PropID.h"
#include "FileStreams.h"
static inline HRESULT GetLastError_HRESULT()
@ -37,12 +49,19 @@ static const UInt32 kClusterSize = 1 << 18;
#endif
CInFileStream::CInFileStream():
#ifdef SUPPORT_DEVICE_FILE
#ifdef SUPPORT_DEVICE_FILE
VirtPos(0),
PhyPos(0),
Buf(0),
BufSize(0),
#endif
#endif
#ifndef _WIN32
_uid(0),
_gid(0),
StoreOwnerId(false),
StoreOwnerName(false),
#endif
_info_WasLoaded(false),
SupportHardLinks(false),
Callback(NULL),
CallbackRef(0)
@ -56,7 +75,7 @@ CInFileStream::~CInFileStream()
#endif
if (Callback)
Callback->InFileStream_On_Destroy(CallbackRef);
Callback->InFileStream_On_Destroy(this, CallbackRef);
}
STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
@ -306,8 +325,14 @@ STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
{
if (!_info_WasLoaded)
RINOK(ReloadProps());
const BY_HANDLE_FILE_INFORMATION &info = _info;
/*
BY_HANDLE_FILE_INFORMATION info;
if (File.GetFileInformation(&info))
if (!File.GetFileInformation(&info))
return GetLastError_HRESULT();
*/
{
if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
if (cTime) *cTime = info.ftCreationTime;
@ -316,13 +341,18 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
if (attrib) *attrib = info.dwFileAttributes;
return S_OK;
}
return GetLastError_HRESULT();
}
STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
{
if (!_info_WasLoaded)
RINOK(ReloadProps());
const BY_HANDLE_FILE_INFORMATION &info = _info;
/*
BY_HANDLE_FILE_INFORMATION info;
if (File.GetFileInformation(&info))
if (!File.GetFileInformation(&info))
return GetLastError_HRESULT();
*/
{
props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
props->VolID = info.dwVolumeSerialNumber;
@ -335,27 +365,114 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
props->MTime = info.ftLastWriteTime;
return S_OK;
}
return GetLastError_HRESULT();
}
STDMETHODIMP CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)
{
if (!_info_WasLoaded)
RINOK(ReloadProps());
if (!_info_WasLoaded)
return S_OK;
NWindows::NCOM::CPropVariant prop;
#ifdef SUPPORT_DEVICE_FILE
if (File.IsDeviceFile)
{
switch (propID)
{
case kpidSize:
if (File.SizeDefined)
prop = File.Size;
break;
// case kpidAttrib: prop = (UInt32)0; break;
case kpidPosixAttrib:
{
prop = (UInt32)NWindows::NFile::NFind::NAttributes::
Get_PosixMode_From_WinAttrib(0);
/* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute
so we don't use MY_LIN_S_IFBLK here */
// prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug
break;
}
/*
case kpidDeviceMajor:
prop = (UInt32)8; // id for SCSI type device (sda)
break;
case kpidDeviceMinor:
prop = (UInt32)0;
break;
*/
}
}
else
#endif
{
switch (propID)
{
case kpidSize:
{
const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow;
prop = size;
break;
}
case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break;
case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break;
case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break;
case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break;
case kpidPosixAttrib:
prop = (UInt32)NWindows::NFile::NFind::NAttributes::
Get_PosixMode_From_WinAttrib(_info.dwFileAttributes);
// | (UInt32)(1 << 21); // for debug
break;
}
}
prop.Detach(value);
return S_OK;
}
STDMETHODIMP CInFileStream::ReloadProps()
{
#ifdef SUPPORT_DEVICE_FILE
if (File.IsDeviceFile)
{
memset(&_info, 0, sizeof(_info));
if (File.SizeDefined)
{
_info.nFileSizeHigh = (DWORD)(File.Size >> 32);
_info.nFileSizeLow = (DWORD)(File.Size);
}
_info.nNumberOfLinks = 1;
_info_WasLoaded = true;
return S_OK;
}
#endif
_info_WasLoaded = File.GetFileInformation(&_info);
if (!_info_WasLoaded)
return GetLastError_HRESULT();
return S_OK;
}
#elif !defined(_WIN32)
STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
{
if (!_info_WasLoaded)
RINOK(ReloadProps());
const struct stat &st = _info;
/*
struct stat st;
if (File.my_fstat(&st) != 0)
return GetLastError_HRESULT();
*/
if (size) *size = (UInt64)st.st_size;
#ifdef __APPLE__
if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, *cTime);
if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, *aTime);
if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, *mTime);
#else
if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, *cTime);
if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, *aTime);
if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, *mTime);
#endif
if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime);
if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime);
if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime);
if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
return S_OK;
@ -365,9 +482,14 @@ STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aT
STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
{
if (!_info_WasLoaded)
RINOK(ReloadProps());
const struct stat &st = _info;
/*
struct stat st;
if (File.my_fstat(&st) != 0)
return GetLastError_HRESULT();
*/
props->Size = (UInt64)st.st_size;
/*
@ -381,15 +503,9 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long)
props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
#ifdef __APPLE__
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, props->CTime);
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, props->ATime);
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, props->MTime);
#else
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, props->CTime);
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, props->ATime);
NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, props->MTime);
#endif
FiTime_To_FILETIME (ST_CTIME(st), props->CTime);
FiTime_To_FILETIME (ST_ATIME(st), props->ATime);
FiTime_To_FILETIME (ST_MTIME(st), props->MTime);
/*
printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n"
@ -402,8 +518,130 @@ STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
return S_OK;
}
STDMETHODIMP CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value)
{
if (!_info_WasLoaded)
RINOK(ReloadProps());
if (!_info_WasLoaded)
return S_OK;
const struct stat &st = _info;
NWindows::NCOM::CPropVariant prop;
{
switch (propID)
{
case kpidSize: prop = (UInt64)st.st_size; break;
case kpidAttrib:
prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
break;
case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break;
case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break;
case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break;
case kpidPosixAttrib: prop = (UInt32)st.st_mode; break;
case kpidDeviceMajor:
{
// printf("\nst.st_rdev = %d\n", st.st_rdev);
if (S_ISCHR(st.st_mode) ||
S_ISBLK(st.st_mode))
prop = (UInt32)(major(st.st_rdev)); // + 1000);
// prop = (UInt32)12345678; // for debug
break;
}
case kpidDeviceMinor:
if (S_ISCHR(st.st_mode) ||
S_ISBLK(st.st_mode))
prop = (UInt32)(minor(st.st_rdev)); // + 100);
// prop = (UInt32)(st.st_rdev); // for debug
// printf("\nst.st_rdev = %d\n", st.st_rdev);
// prop = (UInt32)123456789; // for debug
break;
/*
case kpidDevice:
if (S_ISCHR(st.st_mode) ||
S_ISBLK(st.st_mode))
prop = (UInt64)(st.st_rdev);
break;
*/
case kpidUserId:
{
if (StoreOwnerId)
prop = (UInt32)st.st_uid;
break;
}
case kpidGroupId:
{
if (StoreOwnerId)
prop = (UInt32)st.st_gid;
break;
}
case kpidUser:
{
if (StoreOwnerName)
{
const uid_t uid = st.st_uid;
{
if (!OwnerName.IsEmpty() && _uid == uid)
prop = OwnerName;
else
{
const passwd *pw = getpwuid(uid);
if (pw)
{
// we can use utf-8 here.
// prop = pw->pw_name;
}
}
}
}
break;
}
case kpidGroup:
{
if (StoreOwnerName)
{
const uid_t gid = st.st_gid;
{
if (!OwnerGroup.IsEmpty() && _gid == gid)
prop = OwnerGroup;
else
{
const group *gr = getgrgid(gid);
if (gr)
{
// we can use utf-8 here.
// prop = gr->gr_name;
}
}
}
}
break;
}
}
}
prop.Detach(value);
return S_OK;
}
STDMETHODIMP CInFileStream::ReloadProps()
{
_info_WasLoaded = (File.my_fstat(&_info) == 0);
if (!_info_WasLoaded)
return GetLastError_HRESULT();
return S_OK;
}
#endif
//////////////////////////
// COutFileStream

View file

@ -14,10 +14,14 @@
#include "../IStream.h"
#include "UniqBlocks.h"
class CInFileStream;
struct IInFileStream_Callback
{
virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0;
virtual void InFileStream_On_Destroy(UINT_PTR val) = 0;
virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) = 0;
};
class CInFileStream:
@ -25,10 +29,11 @@ class CInFileStream:
public IStreamGetSize,
public IStreamGetProps,
public IStreamGetProps2,
public IStreamGetProp,
public CMyUnknownImp
{
public:
NWindows::NFile::NIO::CInFile File;
public:
#ifdef USE_WIN_FILE
@ -42,8 +47,20 @@ public:
#endif
bool SupportHardLinks;
#ifdef _WIN32
BY_HANDLE_FILE_INFORMATION _info;
#else
struct stat _info;
UInt32 _uid;
UInt32 _gid;
UString OwnerName;
UString OwnerGroup;
bool StoreOwnerId;
bool StoreOwnerName;
#endif
bool _info_WasLoaded;
bool SupportHardLinks;
IInFileStream_Callback *Callback;
UINT_PTR CallbackRef;
@ -51,13 +68,25 @@ public:
CInFileStream();
void Set_PreserveATime(bool v)
{
File.PreserveATime = v;
}
bool GetLength(UInt64 &length) const throw()
{
return File.GetLength(length);
}
bool Open(CFSTR fileName)
{
_info_WasLoaded = false;
return File.Open(fileName);
}
bool OpenShared(CFSTR fileName, bool shareForWrite)
{
_info_WasLoaded = false;
return File.OpenShared(fileName, shareForWrite);
}
@ -65,6 +94,7 @@ public:
MY_QUERYINTERFACE_ENTRY(IStreamGetSize)
MY_QUERYINTERFACE_ENTRY(IStreamGetProps)
MY_QUERYINTERFACE_ENTRY(IStreamGetProps2)
MY_QUERYINTERFACE_ENTRY(IStreamGetProp)
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
@ -74,6 +104,8 @@ public:
STDMETHOD(GetSize)(UInt64 *size);
STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib);
STDMETHOD(GetProps2)(CStreamFileProps *props);
STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value);
STDMETHOD(ReloadProps)();
};
class CStdInFileStream:
@ -110,11 +142,11 @@ public:
UInt64 ProcessedSize;
bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
{
return File.SetTime(cTime, aTime, mTime);
}
bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); }
bool SetMTime(const CFiTime *mTime) { return File.SetMTime(mTime); }
MY_UNKNOWN_IMP1(IOutStream)

View file

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

View file

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

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