Update to 7-Zip Version 22.00

See: https://sourceforge.net/p/sevenzip/discussion/45797/thread/9c2d9061ce/
This commit is contained in:
Tino Reichardt
2022-08-07 09:59:33 +02:00
parent 6a4fe97fc3
commit 57558682a8
211 changed files with 15251 additions and 2482 deletions

View File

@@ -191,6 +191,8 @@ static const Byte kProps[] =
kpidVolumeIndex,
kpidOffset
// kpidIsAltStream
// , kpidChangeTime // for debug
// , 255 // for debug
};
static const Byte kArcProps[] =
@@ -348,6 +350,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
@@ -393,6 +423,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;
@@ -400,7 +454,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;
@@ -408,64 +462,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;
@@ -1149,7 +1167,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)
{
@@ -1372,6 +1401,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;
@@ -1456,33 +1487,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 = true;

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,9 +1045,24 @@ 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;
@@ -505,36 +504,100 @@ 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))
{
item.Time = 0;
NTime::FileTimeToDosTime(loc, item.Time);
}
}
if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime;
if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime;
if (options.Write_MTime)
if (!FILETIME_IsZero(mTime))
{
item.Ntfs_MTime = mTime;
NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time);
}
if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime;
if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime;
item.Attrib = attrib;
}
/*
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
{
@@ -1230,7 +1336,14 @@ static HRESULT Update2(
RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL));
archive.WriteCentralDir(items, comment);
/*
if (reportArcProp)
{
RINOK(ReportArcProps(reportArcProp, stat));
}
*/
complexity += kCentralHeaderSize * updateItems.Size() + 1;
mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL);
@@ -1472,6 +1585,7 @@ 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);