Update to 7-Zip Version 21.07

See: https://sourceforge.net/p/sevenzip/discussion/45797/thread/0a7b47970b/
This commit is contained in:
Tino Reichardt
2022-08-07 09:51:50 +02:00
parent e3067bf67b
commit 6a4fe97fc3
89 changed files with 3476 additions and 441 deletions

View File

@@ -107,8 +107,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidCharacts:
{
AString s = _encodingCharacts.GetCharactsString();
prop = s;
prop = _encodingCharacts.GetCharactsString();
break;
}
}

View File

@@ -130,8 +130,8 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
return E_INVALIDARG;
else
ui.Mode = prop.ulVal;
// FIXME : we can clear high file type bits to be more compatible with tars created by GNU TAR.
// ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
// 21.07 : we clear high file type bits as GNU TAR.
ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
}
{

View File

@@ -17,7 +17,10 @@ namespace NFileHeader {
// const char * const kUsTar = "ustar"; // 5 chars
// const char * const kGNUTar = "GNUtar "; // 7 chars and a null
// const char * const kEmpty = "\0\0\0\0\0\0\0\0";
const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
// 7-Zip used kUsTar_00 before 21.07:
// const char kUsTar_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 } ;
}
}}}

View File

@@ -76,7 +76,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_00[8];
extern const char kUsTar_GNU[8];
}
}

View File

@@ -72,10 +72,7 @@ static bool IsRecordLast(const char *buf)
static void ReadString(const char *s, unsigned size, AString &result)
{
char temp[NFileHeader::kRecordSize + 1];
MyStrNCpy(temp, s, size);
temp[size] = '\0';
result = temp;
result.SetFrom_CalcLen(s, size);
}
static bool ParseInt64(const char *p, Int64 &val)

View File

@@ -43,6 +43,15 @@ struct CItem
CRecordVector<CSparseBlock> SparseBlocks;
void SetDefaultWriteFields()
{
DeviceMajorDefined = false;
DeviceMinorDefined = false;
UID = 0;
GID = 0;
memcpy(Magic, NFileHeader::NMagic::kUsTar_GNU, 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; }
@@ -103,7 +112,7 @@ struct CItem
bool IsUstarMagic() const
{
for (int i = 0; i < 5; i++)
if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i])
if (Magic[i] != NFileHeader::NMagic::kUsTar_GNU[i])
return false;
return true;
}

View File

@@ -15,17 +15,6 @@ HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
return WriteStream(m_Stream, data, size);
}
static void MyStrNCpy(char *dest, const char *src, unsigned size)
{
for (unsigned i = 0; i < size; i++)
{
char c = src[i];
dest[i] = c;
if (c == 0)
break;
}
}
static bool WriteOctal_8(char *s, UInt32 val)
{
const unsigned kNumDigits = 8 - 1;
@@ -39,6 +28,12 @@ static bool WriteOctal_8(char *s, UInt32 val)
return true;
}
static void WriteBin_64bit(char *s, UInt64 val)
{
for (unsigned i = 0; i < 8; i++, val <<= 8)
s[i] = (char)(val >> 56);
}
static void WriteOctal_12(char *s, UInt64 val)
{
const unsigned kNumDigits = 12 - 1;
@@ -47,8 +42,7 @@ static void WriteOctal_12(char *s, UInt64 val)
// GNU extension;
s[0] = (char)(Byte)0x80;
s[1] = s[2] = s[3] = 0;
for (unsigned i = 0; i < 8; i++, val <<= 8)
s[4 + i] = (char)(val >> 56);
WriteBin_64bit(s + 4, val);
return;
}
for (unsigned i = 0; i < kNumDigits; i++)
@@ -66,61 +60,67 @@ static void WriteOctal_12_Signed(char *s, Int64 val)
return;
}
s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
for (unsigned i = 0; i < 8; i++, val <<= 8)
s[4 + i] = (char)(val >> 56);
WriteBin_64bit(s + 4, val);
}
static bool CopyString(char *dest, const AString &src, unsigned maxSize)
static void CopyString(char *dest, const AString &src, unsigned maxSize)
{
if (src.Len() >= maxSize)
return false;
MyStringCopy(dest, (const char *)src);
return true;
unsigned len = src.Len();
if (len == 0)
return;
// 21.07: we don't require additional 0 character at the end
if (len > maxSize)
{
len = maxSize;
// return false;
}
memcpy(dest, src.Ptr(), len);
// return true;
}
#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }
#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));
HRESULT COutArchive::WriteHeaderReal(const CItem &item)
{
char record[NFileHeader::kRecordSize];
memset(record, 0, NFileHeader::kRecordSize);
char *cur = record;
if (item.Name.Len() > NFileHeader::kNameSize)
return E_FAIL;
MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
cur += NFileHeader::kNameSize;
COPY_STRING_CHECK (cur, item.Name, NFileHeader::kNameSize);
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8;
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8;
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8;
WRITE_OCTAL_8_CHECK (cur, item.Mode); cur += 8;
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;
memset(cur, ' ', 8);
memset(cur, ' ', 8); // checksum field
cur += 8;
*cur++ = item.LinkFlag;
RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
cur += NFileHeader::kNameSize;
COPY_STRING_CHECK (cur, item.LinkName, NFileHeader::kNameSize);
memcpy(cur, item.Magic, 8);
cur += 8;
RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
cur += NFileHeader::kUserNameSize;
RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize));
cur += NFileHeader::kGroupNameSize;
COPY_STRING_CHECK (cur, item.User, NFileHeader::kUserNameSize);
COPY_STRING_CHECK (cur, item.Group, NFileHeader::kGroupNameSize);
/* temp fix for #202
* if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8;
* if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8;
*/
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajorDefined ? item.DeviceMajor : 0)); cur += 8;
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinorDefined ? item.DeviceMinor : 0)); cur += 8;
if (item.DeviceMajorDefined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor);
cur += 8;
if (item.DeviceMinorDefined)
WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor);
cur += 8;
if (item.IsSparse())
{
@@ -144,7 +144,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
/* we use GNU TAR scheme:
checksum field is formatted differently from the
other fields: it has [6] digits, a null, then a space. */
// RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum));
// WRITE_OCTAL_8_CHECK(record + 148, checkSum);
const unsigned kNumDigits = 6;
for (unsigned i = 0; i < kNumDigits; i++)
{
@@ -176,27 +176,42 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
return S_OK;
}
/* OLD_GNU_TAR: writes short name with zero at the end
NEW_GNU_TAR: writes short name without zero at the end */
static const unsigned kNameSize_Max =
NFileHeader::kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
// NFileHeader::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)
{
unsigned nameSize = item.Name.Len();
unsigned linkSize = item.LinkName.Len();
/* There two versions of GNU tar:
OLDGNU_FORMAT: it writes short name and zero at the end
GNU_FORMAT: it writes only short name without zero at the end
we write it as OLDGNU_FORMAT with zero at the end */
if (nameSize < NFileHeader::kNameSize &&
linkSize < NFileHeader::kNameSize)
if (DOES_NAME_FIT_IN_FIELD(item.Name) &&
DOES_NAME_FIT_IN_FIELD(item.LinkName))
return WriteHeaderReal(item);
// here we can get all fields from main (item) or create new empty item
/*
CItem mi;
mi.SetDefaultWriteFields();
*/
CItem mi = item;
mi.Name = NFileHeader::kLongLink;
mi.LinkName.Empty();
// SparseBlocks will be ignored by IsSparse()
// mi.SparseBlocks.Clear();
mi.Name = NFileHeader::kLongLink;
// 21.07 : we set Mode and MTime props as in GNU TAR:
mi.Mode = 0644; // octal
mi.MTime = 0;
for (int i = 0; i < 2; i++)
{
const AString *name;
// We suppose that GNU tar also writes item for long link before item for LongName?
// We suppose that GNU TAR also writes item for long link before item for LongName?
if (i == 0)
{
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
@@ -207,21 +222,26 @@ HRESULT COutArchive::WriteHeader(const CItem &item)
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
name = &item.Name;
}
if (name->Len() < NFileHeader::kNameSize)
if (DOES_NAME_FIT_IN_FIELD(*name))
continue;
unsigned nameStreamSize = name->Len() + 1;
// 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((const char *)*name, nameStreamSize));
RINOK(WriteBytes(name->Ptr(), nameStreamSize));
RINOK(FillDataResidual(nameStreamSize));
}
// 21.07: WriteHeaderReal() writes short part of (Name) and (LinkName).
return WriteHeaderReal(item);
/*
mi = item;
if (mi.Name.Len() >= NFileHeader::kNameSize)
mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1);
if (mi.LinkName.Len() >= NFileHeader::kNameSize)
mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1);
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)
@@ -239,7 +259,17 @@ HRESULT COutArchive::WriteFinishHeader()
{
Byte record[NFileHeader::kRecordSize];
memset(record, 0, NFileHeader::kRecordSize);
for (unsigned i = 0; i < 2; i++)
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 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));
}

View File

@@ -68,6 +68,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (ui.NewProps)
{
item.SetDefaultWriteFields();
item.Mode = ui.Mode;
item.Name = ui.Name;
item.User = ui.User;
@@ -85,11 +86,6 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
item.MTime = ui.MTime;
item.DeviceMajorDefined = false;
item.DeviceMinorDefined = false;
item.UID = 0;
item.GID = 0;
memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8);
}
else
item = inputItems[(unsigned)ui.IndexInArc];