diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2010-11-02 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:04 +0300 |
commit | c65230d8585317f7cd58ae2982067385269fdee9 (patch) | |
tree | 436513094ff5034da4c88def9609f0ea376065c6 /CPP/7zip/Archive/Tar | |
parent | 2eb60a059819da595efb8e1de49f04c241f5b981 (diff) |
9.189.18
Diffstat (limited to 'CPP/7zip/Archive/Tar')
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarHandler.cpp | 107 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarHandler.h | 4 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarHandlerOut.cpp | 2 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarIn.cpp | 104 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarIn.h | 5 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarItem.h | 11 | ||||
-rwxr-xr-x | CPP/7zip/Archive/Tar/TarUpdate.cpp | 12 |
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; } } |