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:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2010-11-02 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:04 +0300
commitc65230d8585317f7cd58ae2982067385269fdee9 (patch)
tree436513094ff5034da4c88def9609f0ea376065c6 /CPP/7zip/Archive/Tar
parent2eb60a059819da595efb8e1de49f04c241f5b981 (diff)
9.189.18
Diffstat (limited to 'CPP/7zip/Archive/Tar')
-rwxr-xr-xCPP/7zip/Archive/Tar/TarHandler.cpp107
-rwxr-xr-xCPP/7zip/Archive/Tar/TarHandler.h4
-rwxr-xr-xCPP/7zip/Archive/Tar/TarHandlerOut.cpp2
-rwxr-xr-xCPP/7zip/Archive/Tar/TarIn.cpp104
-rwxr-xr-xCPP/7zip/Archive/Tar/TarIn.h5
-rwxr-xr-xCPP/7zip/Archive/Tar/TarItem.h11
-rwxr-xr-xCPP/7zip/Archive/Tar/TarUpdate.cpp12
7 files changed, 153 insertions, 92 deletions
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
index e25463de..4db0cae8 100755
--- a/CPP/7zip/Archive/Tar/TarHandler.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -10,6 +10,8 @@
#include "../../Common/LimitedStreams.h"
#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
#include "../Common/ItemNameUtils.h"
@@ -21,7 +23,9 @@ using namespace NWindows;
namespace NArchive {
namespace NTar {
-static STATPROPSTG kProps[] =
+static const char *kUnexpectedEnd = "Unexpected end of archive";
+
+static const STATPROPSTG kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL},
@@ -34,8 +38,14 @@ static STATPROPSTG kProps[] =
{ NULL, kpidLink, VT_BSTR}
};
+static const STATPROPSTG kArcProps[] =
+{
+ { NULL, kpidPhySize, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8}
+};
+
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO_Table
+IMP_IInArchive_ArcProps
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
@@ -43,11 +53,22 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
switch(propID)
{
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
+ case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
}
prop.Detach(value);
return S_OK;
}
+HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
+{
+ item.HeaderPos = _phySize;
+ RINOK(ReadItem(stream, filled, item, _errorMessage));
+ _phySize += item.HeaderSize;
+ _headersSize += item.HeaderSize;
+ return S_OK;
+}
+
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
{
UInt64 endPos = 0;
@@ -56,26 +77,29 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
}
- _isGood = true;
- UInt64 pos = 0;
+ _phySizeDefined = true;
for (;;)
{
CItemEx item;
bool filled;
- item.HeaderPosition = pos;
- RINOK(ReadItem(stream, filled, item));
+ RINOK(ReadItem2(stream, filled, item));
if (!filled)
break;
_items.Add(item);
- RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &pos));
- if (pos > endPos)
- return S_FALSE;
- if (pos == endPos)
+ RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize));
+ if (_phySize > endPos)
+ {
+ _errorMessage = kUnexpectedEnd;
+ break;
+ }
+ /*
+ if (_phySize == endPos)
{
- _isGood = false;
+ _errorMessage = "There are no trailing zero-filled records";
break;
}
+ */
if (callback != NULL)
{
if (_items.Size() == 1)
@@ -85,7 +109,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
if (_items.Size() % 100 == 0)
{
UInt64 numFiles = _items.Size();
- RINOK(callback->SetCompleted(&numFiles, &pos));
+ RINOK(callback->SetCompleted(&numFiles, &_phySize));
}
}
}
@@ -132,7 +156,10 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
STDMETHODIMP CHandler::Close()
{
+ _errorMessage.Empty();
_phySizeDefined = false;
+ _phySize = 0;
+ _headersSize = 0;
_curIndex = 0;
_latestIsRead = false;
_items.Clear();
@@ -161,16 +188,24 @@ HRESULT CHandler::SkipTo(UInt32 index)
{
UInt64 packSize = _latestItem.GetPackSize();
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
+ _phySize += copyCoderSpec->TotalSize;
+ if (copyCoderSpec->TotalSize != packSize)
+ {
+ _errorMessage = kUnexpectedEnd;
+ return S_FALSE;
+ }
_latestIsRead = false;
_curIndex++;
}
else
{
bool filled;
- // item.HeaderPosition = pos;
- RINOK(ReadItem(_seqStream, filled, _latestItem));
+ RINOK(ReadItem2(_seqStream, filled, _latestItem));
if (!filled)
+ {
+ _phySizeDefined = true;
return E_INVALIDARG;
+ }
_latestIsRead = true;
}
}
@@ -203,10 +238,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
switch(propID)
{
- case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
- case kpidIsDir: prop = item->IsDir(); break;
- case kpidSize: prop = item->Size; break;
- case kpidPackSize: prop = item->GetPackSize(); break;
+ case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
+ case kpidIsDir: prop = item->IsDir(); break;
+ case kpidSize: prop = item->GetUnpackSize(); break;
+ case kpidPackSize: prop = item->GetPackSize(); break;
case kpidMTime:
if (item->MTime != 0)
{
@@ -216,9 +251,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
break;
case kpidPosixAttrib: prop = item->Mode; break;
- case kpidUser: prop = TarStringToUnicode(item->User); break;
- case kpidGroup: prop = TarStringToUnicode(item->Group); break;
- case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
+ case kpidUser: prop = TarStringToUnicode(item->User); break;
+ case kpidGroup: prop = TarStringToUnicode(item->Group); break;
+ case kpidLink: prop = TarStringToUnicode(item->LinkName); break;
}
prop.Detach(value);
return S_OK;
@@ -242,7 +277,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]].Size;
+ totalSize += _items[allFilesMode ? i : indices[i]].GetUnpackSize();
extractCallback->SetTotal(totalSize);
UInt64 totalPackSize;
@@ -282,7 +317,8 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
item = &_items[index];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
- totalSize += item->Size;
+ UInt64 unpackSize = item->GetUnpackSize();
+ totalSize += unpackSize;
totalPackSize += item->GetPackSize();
if (item->IsDir())
{
@@ -302,14 +338,21 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
outStreamSpec->SetStream(realOutStream);
realOutStream.Release();
- outStreamSpec->Init(skipMode ? 0 : item->Size, true);
+ outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
- if (!seqMode)
+ if (item->IsLink())
+ {
+ RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
+ }
+ else
{
- RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
+ if (!seqMode)
+ {
+ RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
+ }
+ streamSpec->Init(item->GetPackSize());
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
}
- streamSpec->Init(item->GetPackSize());
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
if (seqMode)
{
_latestIsRead = false;
@@ -328,6 +371,14 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
const CItemEx &item = _items[index];
+ if (item.IsLink())
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
COM_TRY_END
}
diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h
index d2def9a1..b1967061 100755
--- a/CPP/7zip/Archive/Tar/TarHandler.h
+++ b/CPP/7zip/Archive/Tar/TarHandler.h
@@ -23,18 +23,20 @@ class CHandler:
CObjectVector<CItemEx> _items;
CMyComPtr<IInStream> _stream;
CMyComPtr<ISequentialInStream> _seqStream;
- bool _isGood;
UInt32 _curIndex;
bool _latestIsRead;
CItemEx _latestItem;
UInt64 _phySize;
+ UInt64 _headersSize;
bool _phySizeDefined;
+ AString _errorMessage;
NCompress::CCopyCoder *copyCoderSpec;
CMyComPtr<ICompressCoder> copyCoder;
+ HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
HRESULT SkipTo(UInt32 index);
diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
index a999f838..ffdf2b13 100755
--- a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
+++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -37,7 +37,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
- if ((_stream && !_isGood) || _seqStream)
+ if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)
return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems;
for (UInt32 i = 0; i < numItems; i++)
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
index c9c3c422..5ceaa509 100755
--- a/CPP/7zip/Archive/Tar/TarIn.cpp
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -63,29 +63,40 @@ static void ReadString(const char *s, int size, AString &result)
result = temp;
}
-static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, size_t &processedSize)
+static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
{
- item.LongLinkSize = 0;
char buf[NFileHeader::kRecordSize];
char *p = buf;
+ error.Empty();
filled = false;
bool thereAreEmptyRecords = false;
for (;;)
{
- processedSize = NFileHeader::kRecordSize;
+ size_t processedSize = NFileHeader::kRecordSize;
RINOK(ReadStream(stream, buf, &processedSize));
if (processedSize == 0)
+ {
+ if (!thereAreEmptyRecords )
+ error = "There are no trailing zero-filled records";
return S_OK;
+ }
if (processedSize != NFileHeader::kRecordSize)
- return S_FALSE;
+ {
+ error = "There is no correct record at the end of archive";
+ return S_OK;
+ }
+ item.HeaderSize += NFileHeader::kRecordSize;
if (!IsRecordLast(buf))
break;
thereAreEmptyRecords = true;
}
if (thereAreEmptyRecords)
- return S_FALSE;
+ {
+ error = "There are data after end of archive";
+ return S_OK;
+ }
ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
@@ -143,59 +154,54 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
return S_OK;
}
-HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item)
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
{
- size_t processedSize;
- RINOK(GetNextItemReal(stream, filled, item, processedSize));
- if (!filled)
- return S_OK;
- // GNUtar extension
- if (item.LinkFlag == 'L' || // NEXT file has a long name
- item.LinkFlag == 'K') // NEXT file has a long linkname
+ item.HeaderSize = 0;
+ bool flagL = false;
+ bool flagK = false;
+ AString nameL;
+ AString nameK;
+ for (;;)
{
- if (item.Name.Compare(NFileHeader::kLongLink) != 0)
- if (item.Name.Compare(NFileHeader::kLongLink2) != 0)
+ RINOK(GetNextItemReal(stream, filled, item, error));
+ if (!filled)
+ return S_OK;
+ if (item.LinkFlag == 'L' || // NEXT file has a long name
+ item.LinkFlag == 'K') // NEXT file has a long linkname
+ {
+ AString *name;
+ if (item.LinkFlag == 'L')
+ { if (flagL) return S_FALSE; flagL = true; name = &nameL; }
+ else
+ { if (flagK) return S_FALSE; flagK = true; name = &nameK; }
+
+ if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
+ item.Name.Compare(NFileHeader::kLongLink2) != 0)
return S_FALSE;
-
- AString fullName;
- if (item.Size > (1 << 15))
- return S_FALSE;
- int packSize = (int)item.GetPackSize();
- char *buffer = fullName.GetBuffer(packSize + 1);
-
- RINOK(ReadStream_FALSE(stream, buffer, packSize));
- processedSize += packSize;
- buffer[item.Size] = '\0';
- fullName.ReleaseBuffer();
-
- UInt64 headerPosition = item.HeaderPosition;
- if (item.LinkFlag == 'L')
+ if (item.Size > (1 << 14))
+ return S_FALSE;
+ int packSize = (int)item.GetPackSize();
+ char *buf = name->GetBuffer(packSize);
+ RINOK(ReadStream_FALSE(stream, buf, packSize));
+ item.HeaderSize += packSize;
+ buf[(size_t)item.Size] = '\0';
+ name->ReleaseBuffer();
+ continue;
+ }
+ if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
{
- size_t processedSize2;
- RINOK(GetNextItemReal(stream, filled, item, processedSize2));
- item.LongLinkSize = (unsigned)processedSize;
+ // pax Extended Header
}
- else
+ else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
{
- item.LongLinkSize = (unsigned)processedSize - NFileHeader::kRecordSize;
- item.Size = 0;
+ // GNU Extensions to the Archive Format
}
- item.Name = fullName;
- item.HeaderPosition = headerPosition;
- }
- else if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
- {
- // pax Extended Header
- return S_OK;
- }
- else if (item.LinkFlag == NFileHeader::NLinkFlag::kDumpDir)
- {
- // GNU Extensions to the Archive Format
+ else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
+ return S_FALSE;
+ if (flagL) item.Name = nameL;
+ if (flagK) item.LinkName = nameK;
return S_OK;
}
- else if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
- return S_FALSE;
- return S_OK;
}
}}
diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h
index cc6e3f5b..a5491ebe 100755
--- a/CPP/7zip/Archive/Tar/TarIn.h
+++ b/CPP/7zip/Archive/Tar/TarIn.h
@@ -1,9 +1,8 @@
-// Archive/TarIn.h
+// TarIn.h
#ifndef __ARCHIVE_TAR_IN_H
#define __ARCHIVE_TAR_IN_H
-#include "Common/MyCom.h"
#include "../../IStream.h"
#include "TarItem.h"
@@ -11,7 +10,7 @@
namespace NArchive {
namespace NTar {
-HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
+HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
}}
diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h
index afe8997d..859e66dd 100755
--- a/CPP/7zip/Archive/Tar/TarItem.h
+++ b/CPP/7zip/Archive/Tar/TarItem.h
@@ -31,6 +31,9 @@ struct CItem
bool DeviceMajorDefined;
bool DeviceMinorDefined;
+ bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
+ UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
+
bool IsDir() const
{
switch(LinkFlag)
@@ -58,10 +61,10 @@ struct CItem
struct CItemEx: public CItem
{
- UInt64 HeaderPosition;
- unsigned LongLinkSize;
- UInt64 GetDataPosition() const { return HeaderPosition + LongLinkSize + NFileHeader::kRecordSize; }
- UInt64 GetFullSize() const { return LongLinkSize + NFileHeader::kRecordSize + Size; }
+ UInt64 HeaderPos;
+ unsigned HeaderSize;
+ UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
+ UInt64 GetFullSize() const { return HeaderSize + Size; }
};
}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp
index 0577848f..c1633218 100755
--- a/CPP/7zip/Archive/Tar/TarUpdate.cpp
+++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -111,25 +111,25 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
}
else
{
- const CItemEx &existItemInfo = inputItems[ui.IndexInArchive];
+ const CItemEx &existItem = inputItems[ui.IndexInArchive];
UInt64 size;
if (ui.NewProps)
{
RINOK(outArchive.WriteHeader(item));
- RINOK(inStream->Seek(existItemInfo.GetDataPosition(), STREAM_SEEK_SET, NULL));
- size = existItemInfo.Size;
+ RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
+ size = existItem.Size;
}
else
{
- RINOK(inStream->Seek(existItemInfo.HeaderPosition, STREAM_SEEK_SET, NULL));
- size = existItemInfo.GetFullSize();
+ RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL));
+ size = existItem.GetFullSize();
}
streamSpec->Init(size);
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != size)
return E_FAIL;
- RINOK(outArchive.FillDataResidual(existItemInfo.Size));
+ RINOK(outArchive.FillDataResidual(existItem.Size));
complexity += size;
}
}