Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Tar/TarIn.cpp')
-rwxr-xr-x[-rw-r--r--]CPP/7zip/Archive/Tar/TarIn.cpp945
1 files changed, 774 insertions, 171 deletions
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
index 58399d0c..4fd8c5b1 100644..100755
--- a/CPP/7zip/Archive/Tar/TarIn.cpp
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -12,6 +12,45 @@
#include "TarIn.h"
+#define NUM_UNROLL_BYTES (8 * 4)
+
+MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size);
+MY_NO_INLINE static bool IsBufNonZero(const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+
+ for (; size != 0 && ((unsigned)(ptrdiff_t)p & (NUM_UNROLL_BYTES - 1)) != 0; size--)
+ if (*p++ != 0)
+ return true;
+
+ if (size >= NUM_UNROLL_BYTES)
+ {
+ const Byte *lim = p + size;
+ size &= (NUM_UNROLL_BYTES - 1);
+ lim -= size;
+ do
+ {
+ if (*(const UInt64 *)(const void *)(p ) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 1) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 2) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 3) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p ) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 1) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 2) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 3) != 0) return true;
+ p += NUM_UNROLL_BYTES;
+ }
+ while (p != lim);
+ }
+
+ for (; size != 0; size--)
+ if (*p++ != 0)
+ return true;
+
+ return false;
+}
+
+
namespace NArchive {
namespace NTar {
@@ -41,10 +80,11 @@ static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res, boo
return (*end == ' ' || *end == 0);
}
-static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, bool allowEmpty = false)
+static bool OctalToNumber32(const char *srcString, UInt32 &res, bool allowEmpty = false)
{
+ const unsigned kSize = 8;
UInt64 res64;
- if (!OctalToNumber(srcString, size, res64, allowEmpty))
+ if (!OctalToNumber(srcString, kSize, res64, allowEmpty))
return false;
res = (UInt32)res64;
return (res64 <= 0xFFFFFFFF);
@@ -52,68 +92,61 @@ static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res, b
#define RIF(x) { if (!(x)) return S_OK; }
-/*
-static bool IsEmptyData(const char *buf, size_t size)
-{
- for (unsigned i = 0; i < size; i++)
- if (buf[i] != 0)
- return false;
- return true;
-}
-*/
-
-static bool IsRecordLast(const char *buf)
-{
- for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
- if (buf[i] != 0)
- return false;
- return true;
-}
-
static void ReadString(const char *s, unsigned size, AString &result)
{
result.SetFrom_CalcLen(s, size);
}
-static bool ParseInt64(const char *p, Int64 &val)
+static bool ParseInt64(const char *p, Int64 &val, bool &isBin)
{
- UInt32 h = GetBe32(p);
+ const UInt32 h = GetBe32(p);
val = (Int64)GetBe64(p + 4);
+ isBin = true;
if (h == (UInt32)1 << 31)
return ((val >> 63) & 1) == 0;
if (h == (UInt32)(Int32)-1)
return ((val >> 63) & 1) != 0;
- UInt64 uv;
- bool res = OctalToNumber(p, 12, uv);
- val = (Int64)uv;
+ isBin = false;
+ UInt64 u;
+ const bool res = OctalToNumber(p, 12, u);
+ val = (Int64)u;
return res;
}
-static bool ParseInt64_MTime(const char *p, Int64 &val)
+static bool ParseInt64_MTime(const char *p, Int64 &val, bool &isBin)
{
// rare case tar : ZEROs in Docker-Windows TARs
// rare case tar : spaces
+ isBin = false;
if (GetUi32(p) != 0)
for (unsigned i = 0; i < 12; i++)
if (p[i] != ' ')
- return ParseInt64(p, val);
+ return ParseInt64(p, val, isBin);
val = 0;
return true;
}
-static bool ParseSize(const char *p, UInt64 &val)
+static bool ParseSize(const char *p, UInt64 &val, bool &isBin)
{
if (GetBe32(p) == (UInt32)1 << 31)
{
// GNU extension
+ isBin = true;
val = GetBe64(p + 4);
return ((val >> 63) & 1) == 0;
}
+ isBin = false;
return OctalToNumber(p, 12, val,
true // 20.03: allow empty size for 'V' Label entry
);
}
+static bool ParseSize(const char *p, UInt64 &val)
+{
+ bool isBin;
+ return ParseSize(p, val, isBin);
+}
+
#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; }
API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size)
@@ -126,26 +159,27 @@ API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size)
UInt32 mode;
// we allow empty Mode value for LongName prefix items
- CHECK(OctalToNumber32(p, 8, mode, true)); p += 8;
+ CHECK(OctalToNumber32(p, mode, true)); p += 8;
- // if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0;
+ // if (!OctalToNumber32(p, item.UID)) item.UID = 0;
p += 8;
- // if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0;
+ // if (!OctalToNumber32(p, item.GID)) item.GID = 0;
p += 8;
UInt64 packSize;
Int64 time;
UInt32 checkSum;
- CHECK(ParseSize(p, packSize)); p += 12;
- CHECK(ParseInt64_MTime(p, time)); p += 12;
- CHECK(OctalToNumber32(p, 8, checkSum));
+ bool isBin;
+ CHECK(ParseSize(p, packSize, isBin)); p += 12;
+ CHECK(ParseInt64_MTime(p, time, isBin)); p += 12;
+ CHECK(OctalToNumber32(p, checkSum));
return k_IsArc_Res_YES;
}
-static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error)
+
+HRESULT CArchive::GetNextItemReal(CItemEx &item)
{
char buf[NFileHeader::kRecordSize];
- char *p = buf;
error = k_ErrorType_OK;
filled = false;
@@ -154,7 +188,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
for (;;)
{
size_t processedSize = NFileHeader::kRecordSize;
- RINOK(ReadStream(stream, buf, &processedSize));
+ RINOK(ReadStream(SeqStream, buf, &processedSize));
if (processedSize == 0)
{
if (!thereAreEmptyRecords)
@@ -180,10 +214,14 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK;
}
- if (!IsRecordLast(buf))
+ if (IsBufNonZero(buf, NFileHeader::kRecordSize))
break;
item.HeaderSize += NFileHeader::kRecordSize;
thereAreEmptyRecords = true;
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0));
+ }
}
if (thereAreEmptyRecords)
{
@@ -191,52 +229,69 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK;
}
+ char *p = buf;
+
error = k_ErrorType_Corrupted;
- ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
- item.NameCouldBeReduced =
+
+ // ReadString(p, NFileHeader::kNameSize, item.Name);
+ p += NFileHeader::kNameSize;
+
+ /*
+ item.Name_CouldBeReduced =
(item.Name.Len() == NFileHeader::kNameSize ||
item.Name.Len() == NFileHeader::kNameSize - 1);
+ */
// we allow empty Mode value for LongName prefix items
- RIF(OctalToNumber32(p, 8, item.Mode, true)); p += 8;
+ RIF(OctalToNumber32(p, item.Mode, true)); p += 8;
- if (!OctalToNumber32(p, 8, item.UID)) { item.UID = 0; } p += 8;
- if (!OctalToNumber32(p, 8, item.GID)) { item.GID = 0; } p += 8;
+ if (!OctalToNumber32(p, item.UID)) { item.UID = 0; } p += 8;
+ if (!OctalToNumber32(p, item.GID)) { item.GID = 0; } p += 8;
- RIF(ParseSize(p, item.PackSize));
+ RIF(ParseSize(p, item.PackSize, item.PackSize_IsBin));
item.Size = item.PackSize;
+ item.Size_IsBin = item.PackSize_IsBin;
p += 12;
- RIF(ParseInt64_MTime(p, item.MTime)); p += 12;
+ RIF(ParseInt64_MTime(p, item.MTime, item.MTime_IsBin)); p += 12;
UInt32 checkSum;
- RIF(OctalToNumber32(p, 8, checkSum));
+ RIF(OctalToNumber32(p, checkSum));
memset(p, ' ', 8); p += 8;
item.LinkFlag = *p++;
ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
- item.LinkNameCouldBeReduced =
+
+ /*
+ item.LinkName_CouldBeReduced =
(item.LinkName.Len() == NFileHeader::kNameSize ||
item.LinkName.Len() == NFileHeader::kNameSize - 1);
+ */
memcpy(item.Magic, p, 8); p += 8;
ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
- item.DeviceMajorDefined = (p[0] != 0); if (item.DeviceMajorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMajor)); } p += 8;
- item.DeviceMinorDefined = (p[0] != 0); if (item.DeviceMinorDefined) { RIF(OctalToNumber32(p, 8, item.DeviceMinor)); } p += 8;
+ item.DeviceMajor_Defined = (p[0] != 0); if (item.DeviceMajor_Defined) { RIF(OctalToNumber32(p, item.DeviceMajor)); } p += 8;
+ item.DeviceMinor_Defined = (p[0] != 0); if (item.DeviceMinor_Defined) { RIF(OctalToNumber32(p, item.DeviceMinor)); } p += 8;
- if (p[0] != 0)
+ if (p[0] != 0
+ && item.IsMagic_ustar_5chars()
+ && (item.LinkFlag != 'L' ))
{
- AString prefix;
- ReadString(p, NFileHeader::kPrefixSize, prefix);
- if (!prefix.IsEmpty()
- && item.IsUstarMagic()
- && (item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
- item.Name = prefix + '/' + item.Name;
+ item.Prefix_WasUsed = true;
+ ReadString(p, NFileHeader::kPrefixSize, item.Name);
+ item.Name += '/';
+ unsigned i;
+ for (i = 0; i < NFileHeader::kNameSize; i++)
+ if (buf[i] == 0)
+ break;
+ item.Name.AddFrom(buf, i);
}
-
+ else
+ ReadString(buf, NFileHeader::kNameSize, item.Name);
+
p += NFileHeader::kPrefixSize;
if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink)
@@ -255,22 +310,25 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
/*
TAR standard requires sum of unsigned byte values.
- But some TAR programs use sum of signed byte values.
+ But some old TAR programs use sum of signed byte values.
So we check both values.
*/
- UInt32 checkSumReal = 0;
- Int32 checkSumReal_Signed = 0;
- for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ // for (int y = 0; y < 100; y++) // for debug
{
- char c = buf[i];
- checkSumReal_Signed += (signed char)c;
- checkSumReal += (Byte)buf[i];
- }
-
- if (checkSumReal != checkSum)
- {
- if ((UInt32)checkSumReal_Signed != checkSum)
- return S_OK;
+ UInt32 sum0 = 0;
+ {
+ for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ sum0 += (Byte)buf[i];
+ }
+ if (sum0 != checkSum)
+ {
+ Int32 sum = 0;
+ for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ sum += (signed char)buf[i];
+ if ((UInt32)sum != checkSum)
+ return S_OK;
+ item.IsSignedChecksum = true;
+ }
}
item.HeaderSize += NFileHeader::kRecordSize;
@@ -280,7 +338,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
Byte isExtended = (Byte)buf[482];
if (isExtended != 0 && isExtended != 1)
return S_OK;
- RIF(ParseSize(buf + 483, item.Size));
+ RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin));
UInt64 min = 0;
for (unsigned i = 0; i < 4; i++)
{
@@ -309,7 +367,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
while (isExtended != 0)
{
size_t processedSize = NFileHeader::kRecordSize;
- RINOK(ReadStream(stream, buf, &processedSize));
+ RINOK(ReadStream(SeqStream, buf, &processedSize));
if (processedSize != NFileHeader::kRecordSize)
{
error = k_ErrorType_UnexpectedEnd;
@@ -317,6 +375,12 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
}
item.HeaderSize += NFileHeader::kRecordSize;
+
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0));
+ }
+
isExtended = (Byte)buf[21 * 24];
if (isExtended != 0 && isExtended != 1)
return S_OK;
@@ -346,172 +410,711 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK;
}
+ if (item.PackSize >= (UInt64)1 << 63)
+ return S_OK;
+
filled = true;
error = k_ErrorType_OK;
return S_OK;
}
-static HRESULT ReadDataToString(ISequentialInStream *stream, CItemEx &item, AString &s, EErrorType &error)
+HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset)
{
- const unsigned packSize = (unsigned)item.GetPackSizeAligned();
- size_t processedSize = packSize;
- HRESULT res = ReadStream(stream, s.GetBuf(packSize), &processedSize);
- item.HeaderSize += (unsigned)processedSize;
- s.ReleaseBuf_CalcLen((unsigned)item.PackSize);
- RINOK(res);
- if (processedSize != packSize)
- error = k_ErrorType_UnexpectedEnd;
+ const UInt64 pos = item.Get_DataPos() + posOffset;
+ if (NumFiles - NumFiles_Prev < (1 << 16)
+ // && NumRecords - NumRecords_Prev < (1 << 16)
+ && pos - Pos_Prev < ((UInt32)1 << 28))
+ return S_OK;
+ {
+ Pos_Prev = pos;
+ NumFiles_Prev = NumFiles;
+ // NumRecords_Prev = NumRecords;
+ // Sleep(100); // for debug
+ return OpenCallback->SetCompleted(&NumFiles, &pos);
+ }
+}
+
+
+HRESULT CArchive::ReadDataToBuffer(const CItemEx &item,
+ CTempBuffer &tb, size_t stringLimit)
+{
+ tb.Init();
+ UInt64 packSize = item.Get_PackSize_Aligned();
+ if (packSize == 0)
+ return S_OK;
+
+ UInt64 pos;
+
+ {
+ size_t size = stringLimit;
+ if (size > packSize)
+ size = (size_t)packSize;
+ tb.Buffer.AllocAtLeast(size);
+ size_t processedSize = size;
+ const HRESULT res = ReadStream(SeqStream, tb.Buffer, &processedSize);
+ pos = processedSize;
+ if (processedSize != size)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return res;
+ }
+ RINOK(res);
+
+ packSize -= size;
+
+ size_t i;
+ const Byte *p = tb.Buffer;
+ for (i = 0; i < size; i++)
+ if (p[i] == 0)
+ break;
+ if (i >= item.PackSize)
+ tb.StringSize_IsConfirmed = true;
+ if (i > item.PackSize)
+ {
+ tb.StringSize = (size_t)item.PackSize;
+ tb.IsNonZeroTail = true;
+ }
+ else
+ {
+ tb.StringSize = i;
+ if (i != size)
+ {
+ tb.StringSize_IsConfirmed = true;
+ if (IsBufNonZero(p + i, size - i))
+ tb.IsNonZeroTail = true;
+ }
+ }
+
+ if (packSize == 0)
+ return S_OK;
+ }
+
+ if (InStream)
+ {
+ RINOK(InStream->Seek((Int64)packSize, STREAM_SEEK_CUR, NULL));
+ return S_OK;
+ }
+ const unsigned kBufSize = 1 << 15;
+ Buffer.AllocAtLeast(kBufSize);
+
+ do
+ {
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, pos));
+ }
+
+ unsigned size = kBufSize;
+ if (size > packSize)
+ size = (unsigned)packSize;
+ size_t processedSize = size;
+ const HRESULT res = ReadStream(SeqStream, Buffer, &processedSize);
+ if (processedSize != size)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return res;
+ }
+ if (!tb.IsNonZeroTail)
+ {
+ if (IsBufNonZero(Buffer, size))
+ tb.IsNonZeroTail = true;
+ }
+ packSize -= size;
+ pos += size;
+ }
+ while (packSize != 0);
return S_OK;
}
+
-static bool ParsePaxLongName(const AString &src, AString &dest)
+
+struct CPaxInfo: public CPaxTimes
{
- dest.Empty();
- for (unsigned pos = 0;;)
+ bool DoubleTagError;
+ bool TagParsingError;
+ bool UnknownLines_Overflow;
+ bool Size_Defined;
+ bool UID_Defined;
+ bool GID_Defined;
+ bool Path_Defined;
+ bool Link_Defined;
+ bool User_Defined;
+ bool Group_Defined;
+
+ UInt64 Size;
+ UInt32 UID;
+ UInt32 GID;
+
+ AString Path;
+ AString Link;
+ AString User;
+ AString Group;
+ AString UnknownLines;
+
+ bool ParseID(const AString &val, bool &defined, UInt32 &res)
{
- if (pos >= src.Len())
+ if (defined)
+ DoubleTagError = true;
+ if (val.IsEmpty())
return false;
- const char *start = src.Ptr(pos);
- const char *end;
- const UInt32 lineLen = ConvertStringToUInt32(start, &end);
- if (end == start)
+ const char *end2;
+ res = ConvertStringToUInt32(val.Ptr(), &end2);
+ if (*end2 != 0)
return false;
- if (*end != ' ')
+ defined = true;
+ return true;
+ }
+
+ bool ParsePax(const CTempBuffer &tb, bool isFile);
+};
+
+
+static bool ParsePaxTime(const AString &src, CPaxTime &pt, bool &doubleTagError)
+{
+ if (pt.IsDefined())
+ doubleTagError = true;
+ pt.Clear();
+ const char *s = src.Ptr();
+ bool isNegative = false;
+ if (*s == '-')
+ {
+ isNegative = true;
+ s++;
+ }
+ const char *end;
+ {
+ UInt64 sec = ConvertStringToUInt64(s, &end);
+ if (s == end)
return false;
- if (lineLen > src.Len() - pos)
+ if (sec >= ((UInt64)1 << 63))
return false;
- unsigned offset = (unsigned)(end - start) + 1;
- if (lineLen < offset)
+ if (isNegative)
+ sec = -(Int64)sec;
+ pt.Sec = sec;
+ }
+ if (*end == 0)
+ {
+ pt.Ns = 0;
+ pt.NumDigits = 0;
+ return true;
+ }
+ if (*end != '.')
+ return false;
+ s = end + 1;
+
+ UInt32 ns = 0;
+ unsigned i;
+ const unsigned kNsDigits = 9;
+ for (i = 0;; i++)
+ {
+ const char c = s[i];
+ if (c == 0)
+ break;
+ if (c < '0' || c > '9')
return false;
- if (IsString1PrefixedByString2(src.Ptr(pos + offset), "path="))
+ // we ignore digits after 9 digits as GNU TAR
+ if (i < kNsDigits)
+ {
+ ns *= 10;
+ ns += c - '0';
+ }
+ }
+ pt.NumDigits = (i < kNsDigits ? i : kNsDigits);
+ while (i < kNsDigits)
+ {
+ ns *= 10;
+ i++;
+ }
+ if (isNegative && ns != 0)
+ {
+ pt.Sec--;
+ ns = (UInt32)1000 * 1000 * 1000 - ns;
+ }
+ pt.Ns = ns;
+ return true;
+}
+
+
+bool CPaxInfo::ParsePax(const CTempBuffer &tb, bool isFile)
+{
+ DoubleTagError = false;
+ TagParsingError = false;
+ UnknownLines_Overflow = false;
+ Size_Defined = false;
+ UID_Defined = false;
+ GID_Defined = false;
+ Path_Defined = false;
+ Link_Defined = false;
+ User_Defined = false;
+ Group_Defined = false;
+
+ // CPaxTimes::Clear();
+
+ const char *s = (const char *)(const void *)(const Byte *)tb.Buffer;
+ size_t rem = tb.StringSize;
+
+ Clear();
+
+ AString name, val;
+
+ while (rem != 0)
+ {
+ unsigned i;
+ for (i = 0;; i++)
{
- offset += 5; // "path="
- dest = src.Mid(pos + offset, lineLen - offset);
- if (dest.IsEmpty())
+ if (i > 24 || i >= rem) // we use limitation for size of (size) field
return false;
- if (dest.Back() != '\n')
+ if (s[i] == ' ')
+ break;
+ }
+ if (i == 0)
+ return false;
+ const char *end;
+ const UInt32 size = ConvertStringToUInt32(s, &end);
+ const unsigned offset = (unsigned)(end - s) + 1;
+ if (size > rem
+ || size <= offset + 1
+ || offset != i + 1
+ || s[size - 1] != '\n')
+ return false;
+
+ for (i = offset; i < size; i++)
+ if (s[i] == 0)
return false;
- dest.DeleteBack();
- return true;
+
+ for (i = offset; i < size - 1; i++)
+ if (s[i] == '=')
+ break;
+ if (i == size - 1)
+ return false;
+
+ name.SetFrom(s + offset, i - offset);
+ val.SetFrom(s + i + 1, size - 1 - (i + 1));
+
+ bool parsed = false;
+ if (isFile)
+ {
+ bool isDetectedName = true;
+ // only lower case (name) is supported
+ if (name.IsEqualTo("path"))
+ {
+ if (Path_Defined)
+ DoubleTagError = true;
+ Path = val;
+ Path_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("linkpath"))
+ {
+ if (Link_Defined)
+ DoubleTagError = true;
+ Link = val;
+ Link_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("uname"))
+ {
+ if (User_Defined)
+ DoubleTagError = true;
+ User = val;
+ User_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("gname"))
+ {
+ if (Group_Defined)
+ DoubleTagError = true;
+ Group = val;
+ Group_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("uid"))
+ {
+ parsed = ParseID(val, UID_Defined, UID);
+ }
+ else if (name.IsEqualTo("gid"))
+ {
+ parsed = ParseID(val, GID_Defined, GID);
+ }
+ else if (name.IsEqualTo("size"))
+ {
+ if (Size_Defined)
+ DoubleTagError = true;
+ Size_Defined = false;
+ if (!val.IsEmpty())
+ {
+ const char *end2;
+ Size = ConvertStringToUInt64(val.Ptr(), &end2);
+ if (*end2 == 0)
+ {
+ Size_Defined = true;
+ parsed = true;
+ }
+ }
+ }
+ else if (name.IsEqualTo("mtime"))
+ { parsed = ParsePaxTime(val, MTime, DoubleTagError); }
+ else if (name.IsEqualTo("atime"))
+ { parsed = ParsePaxTime(val, ATime, DoubleTagError); }
+ else if (name.IsEqualTo("ctime"))
+ { parsed = ParsePaxTime(val, CTime, DoubleTagError); }
+ else
+ isDetectedName = false;
+ if (isDetectedName && !parsed)
+ TagParsingError = true;
}
- pos += lineLen;
+ if (!parsed)
+ {
+ if (!UnknownLines_Overflow)
+ {
+ const unsigned addSize = size - offset;
+ if (UnknownLines.Len() + addSize < (1 << 16))
+ UnknownLines.AddFrom(s + offset, addSize);
+ else
+ UnknownLines_Overflow = true;
+ }
+ }
+
+ s += size;
+ rem -= size;
}
+ return true;
}
-HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error)
+
+HRESULT CArchive::ReadItem2(CItemEx &item)
{
+ // CItem
+
+ item.SparseBlocks.Clear();
+ item.PaxTimes.Clear();
+
+ // CItemEx
+
item.HeaderSize = 0;
+ item.Num_Pax_Records = 0;
- bool flagL = false;
- bool flagK = false;
- AString nameL;
- AString nameK;
- AString pax;
+ item.LongName_WasUsed = false;
+ item.LongName_WasUsed_2 = false;
+
+ item.LongLink_WasUsed = false;
+ item.LongLink_WasUsed_2 = false;
+
+ item.HeaderError = false;
+ item.IsSignedChecksum = false;
+ item.Prefix_WasUsed = false;
- for (;;)
+ item.Pax_Error = false;
+ item.Pax_Overflow = false;
+ item.pax_path_WasUsed = false;
+ item.pax_link_WasUsed = false;
+ item.pax_size_WasUsed = false;
+
+ item.PaxExtra.Clear();
+
+ item.EncodingCharacts.Clear();
+
+ // CArchive temp variable
+
+ NameBuf.Init();
+ LinkBuf.Init();
+ PaxBuf.Init();
+ PaxBuf_global.Init();
+
+ for (unsigned recordIndex = 0;; recordIndex++)
{
- RINOK(GetNextItemReal(stream, filled, item, error));
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0));
+ }
+
+ RINOK(GetNextItemReal(item));
+
+ // NumRecords++;
+
if (!filled)
{
- if (error == k_ErrorType_OK && (flagL || flagK))
+ if (error == k_ErrorType_OK)
+ if (item.LongName_WasUsed ||
+ item.LongLink_WasUsed ||
+ item.Num_Pax_Records != 0)
error = k_ErrorType_Corrupted;
- return S_OK;
}
if (error != k_ErrorType_OK)
return S_OK;
- if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName || // file contains a long name
- item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongLink) // file contains a long linkname
+ const char lf = item.LinkFlag;
+ if (lf == NFileHeader::NLinkFlag::kGnu_LongName ||
+ lf == NFileHeader::NLinkFlag::kGnu_LongLink)
{
- AString *name;
- if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName)
- { if (flagL) return S_OK; flagL = true; name = &nameL; }
- else
- { if (flagK) return S_OK; flagK = true; name = &nameK; }
-
+ // GNU tar ignores item.Name after LinkFlag test
+ // 22.00 : now we also ignore item.Name here
+ /*
if (item.Name != NFileHeader::kLongLink &&
item.Name != NFileHeader::kLongLink2)
+ {
+ break;
+ // return S_OK;
+ }
+ */
+
+ CTempBuffer *tb =
+ lf == NFileHeader::NLinkFlag::kGnu_LongName ?
+ &NameBuf :
+ &LinkBuf;
+
+ /*
+ if (item.PackSize > (1 << 29))
+ {
+ // break;
return S_OK;
- if (item.PackSize > (1 << 14))
- return S_OK;
+ }
+ */
- RINOK(ReadDataToString(stream, item, *name, error));
+ const unsigned kLongNameSizeMax = (unsigned)1 << 14;
+ RINOK(ReadDataToBuffer(item, *tb, kLongNameSizeMax));
if (error != k_ErrorType_OK)
return S_OK;
+ if (lf == NFileHeader::NLinkFlag::kGnu_LongName)
+ {
+ item.LongName_WasUsed_2 =
+ item.LongName_WasUsed;
+ item.LongName_WasUsed = true;
+ }
+ else
+ {
+ item.LongLink_WasUsed_2 =
+ item.LongLink_WasUsed;
+ item.LongLink_WasUsed = true;
+ }
+
+ if (!tb->StringSize_IsConfirmed)
+ tb->StringSize = 0;
+ item.HeaderSize += item.Get_PackSize_Aligned();
+ if (tb->StringSize == 0 ||
+ tb->StringSize + 1 != item.PackSize)
+ item.HeaderError = true;
+ if (tb->IsNonZeroTail)
+ item.HeaderError = true;
continue;
}
- switch (item.LinkFlag)
+ if (lf == NFileHeader::NLinkFlag::kGlobal ||
+ lf == NFileHeader::NLinkFlag::kPax ||
+ lf == NFileHeader::NLinkFlag::kPax_2)
{
- case 'g':
- case 'x':
- case 'X':
+ // GNU tar ignores item.Name after LinkFlag test
+ // 22.00 : now we also ignore item.Name here
+ /*
+ if (item.PackSize > (UInt32)1 << 26)
{
- const char *s = item.Name.Ptr();
- if (IsString1PrefixedByString2(s, "./"))
- s += 2;
- if (IsString1PrefixedByString2(s, "./"))
- s += 2;
- if ( IsString1PrefixedByString2(s, "PaxHeader/")
- || IsString1PrefixedByString2(s, "PaxHeaders.X/")
- || IsString1PrefixedByString2(s, "PaxHeaders.4467/")
- || StringsAreEqual_Ascii(s, "@PaxHeader")
- )
- {
- RINOK(ReadDataToString(stream, item, pax, error));
- if (error != k_ErrorType_OK)
- return S_OK;
- continue;
- }
- break;
+ break; // we don't want big PaxBuf files
+ // return S_OK;
}
- case NFileHeader::NLinkFlag::kDumpDir:
+ */
+ const unsigned kParsingPaxSizeMax = (unsigned)1 << 26;
+
+ const bool isStartHeader = (item.HeaderSize == NFileHeader::kRecordSize);
+
+ CTempBuffer *tb = (lf == NFileHeader::NLinkFlag::kGlobal ? &PaxBuf_global : &PaxBuf);
+
+ RINOK(ReadDataToBuffer(item, *tb, kParsingPaxSizeMax));
+ if (error != k_ErrorType_OK)
+ return S_OK;
+
+ item.HeaderSize += item.Get_PackSize_Aligned();
+
+ if (tb->StringSize != item.PackSize
+ || tb->StringSize == 0
+ || tb->IsNonZeroTail)
+ item.Pax_Error = true;
+
+ item.Num_Pax_Records++;
+ if (lf != NFileHeader::NLinkFlag::kGlobal)
{
- break;
- // GNU Extensions to the Archive Format
+ item.PaxExtra.RecordPath = item.Name;
+ continue;
}
- case NFileHeader::NLinkFlag::kSparse:
+ // break; // for debug
{
- break;
- // GNU Extensions to the Archive Format
+ if (PaxGlobal_Defined)
+ _is_PaxGlobal_Error = true;
+ CPaxInfo paxInfo;
+ if (paxInfo.ParsePax(PaxBuf_global, false))
+ {
+ PaxGlobal.RawLines = paxInfo.UnknownLines;
+ PaxGlobal.RecordPath = item.Name;
+ PaxGlobal_Defined = true;
+ }
+ else
+ _is_PaxGlobal_Error = true;
+ if (isStartHeader)
+ {
+ // we skip global pax header info after parsing
+ item.HeaderPos += item.HeaderSize;
+ item.HeaderSize = 0;
+ }
}
- default:
- if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
- return S_OK;
+ continue;
}
- if (flagL)
+ /*
+ if (lf == NFileHeader::NLinkFlag::kDumpDir ||
+ lf == NFileHeader::NLinkFlag::kSparse)
{
- item.Name = nameL;
- item.NameCouldBeReduced = false;
+ // GNU Extensions to the Archive Format
+ break;
}
-
- if (flagK)
+ if (lf > '7' || (lf < '0' && lf != 0))
{
- item.LinkName = nameK;
- item.LinkNameCouldBeReduced = false;
+ break;
+ // return S_OK;
}
-
- error = k_ErrorType_OK;
-
- if (!pax.IsEmpty())
+ */
+ break;
+ }
+
+ // we still use name from main header, if long_name is bad
+ if (item.LongName_WasUsed && NameBuf.StringSize != 0)
+ {
+ NameBuf.CopyToString(item.Name);
+ // item.Name_CouldBeReduced = false;
+ }
+
+ if (item.LongLink_WasUsed)
+ {
+ // we use empty link, if long_link is bad
+ LinkBuf.CopyToString(item.LinkName);
+ // item.LinkName_CouldBeReduced = false;
+ }
+
+ error = k_ErrorType_OK;
+
+ if (PaxBuf.StringSize != 0)
+ {
+ CPaxInfo paxInfo;
+ if (!paxInfo.ParsePax(PaxBuf, true))
+ item.Pax_Error = true;
+ else
{
- AString name;
- if (ParsePaxLongName(pax, name))
- item.Name = name;
- else
+ if (paxInfo.Path_Defined) // if (!paxInfo.Path.IsEmpty())
+ {
+ item.Name = paxInfo.Path;
+ item.pax_path_WasUsed = true;
+ }
+ if (paxInfo.Link_Defined) // (!paxInfo.Link.IsEmpty())
+ {
+ item.LinkName = paxInfo.Link;
+ item.pax_link_WasUsed = true;
+ }
+ if (paxInfo.User_Defined)
+ {
+ item.User = paxInfo.User;
+ // item.pax_uname_WasUsed = true;
+ }
+ if (paxInfo.Group_Defined)
+ {
+ item.Group = paxInfo.Group;
+ // item.pax_gname_WasUsed = true;
+ }
+ if (paxInfo.UID_Defined)
{
- // no "path" property is allowed in pax4467
- // error = k_ErrorType_Warning;
+ item.UID = (UInt32)paxInfo.UID;
}
- pax.Empty();
+ if (paxInfo.GID_Defined)
+ {
+ item.GID = (UInt32)paxInfo.GID;
+ }
+
+ if (paxInfo.Size_Defined)
+ {
+ const UInt64 piSize = paxInfo.Size;
+ // GNU TAR ignores (item.Size) in that case
+ if (item.Size != 0 && item.Size != piSize)
+ item.Pax_Error = true;
+ item.Size = piSize;
+ item.PackSize = piSize;
+ item.pax_size_WasUsed = true;
+ }
+
+ item.PaxTimes = paxInfo;
+ item.PaxExtra.RawLines = paxInfo.UnknownLines;
+ if (paxInfo.UnknownLines_Overflow)
+ item.Pax_Overflow = true;
+ if (paxInfo.TagParsingError)
+ item.Pax_Error = true;
+ if (paxInfo.DoubleTagError)
+ item.Pax_Error = true;
}
+ }
- return S_OK;
+ return S_OK;
+}
+
+
+
+HRESULT CArchive::ReadItem(CItemEx &item)
+{
+ item.HeaderPos = _phySize;
+
+ const HRESULT res = ReadItem2(item);
+
+ /*
+ if (error == k_ErrorType_Warning)
+ _is_Warning = true;
+ else
+ */
+
+ if (error != k_ErrorType_OK)
+ _error = error;
+
+ RINOK(res);
+
+ if (filled)
+ {
+ if (item.IsMagic_GNU())
+ _are_Gnu = true;
+ else if (item.IsMagic_Posix_ustar_00())
+ _are_Posix = true;
+
+ if (item.Num_Pax_Records != 0)
+ _are_Pax = true;
+
+ if (item.PaxTimes.MTime.IsDefined()) _are_mtime = true;
+ if (item.PaxTimes.ATime.IsDefined()) _are_atime = true;
+ if (item.PaxTimes.CTime.IsDefined()) _are_ctime = true;
+
+ if (item.pax_path_WasUsed)
+ _are_pax_path = true;
+ if (item.pax_link_WasUsed)
+ _are_pax_link = true;
+ if (item.LongName_WasUsed)
+ _are_LongName = true;
+ if (item.LongLink_WasUsed)
+ _are_LongLink = true;
+ if (item.Prefix_WasUsed)
+ _pathPrefix_WasUsed = true;
+ /*
+ if (item.IsSparse())
+ _isSparse = true;
+ */
+ if (item.Is_PaxExtendedHeader())
+ _are_Pax_Items = true;
+ if (item.IsThereWarning()
+ || item.HeaderError
+ || item.Pax_Error)
+ _is_Warning = true;
}
+
+ const UInt64 headerEnd = item.HeaderPos + item.HeaderSize;
+ // _headersSize += headerEnd - _phySize;
+ // we don't count skipped records
+ _headersSize += item.HeaderSize;
+ _phySize = headerEnd;
+ return S_OK;
}
}}