mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-09 14:07:08 -06:00
9.34
This commit is contained in:
committed by
Kornel Lesiński
parent
83f8ddcc5b
commit
f08f4dcc3c
3
CPP/7zip/Archive/Tar/StdAfx.h
Executable file → Normal file
3
CPP/7zip/Archive/Tar/StdAfx.h
Executable file → Normal file
@@ -3,7 +3,6 @@
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/MyWindows.h"
|
||||
#include "../../../Common/NewHandler.h"
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
|
||||
390
CPP/7zip/Archive/Tar/TarHandler.cpp
Executable file → Normal file
390
CPP/7zip/Archive/Tar/TarHandler.cpp
Executable file → Normal file
@@ -2,13 +2,15 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/IntToString.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
#include "../../../Common/UTFConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/MethodProps.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../Common/StreamObjects.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
@@ -16,32 +18,34 @@
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "TarHandler.h"
|
||||
#include "TarIn.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
static const char *kUnexpectedEnd = "Unexpected end of archive";
|
||||
static const UINT k_DefaultCodePage = CP_OEMCP; // it uses it if UTF8 check in names shows error
|
||||
|
||||
static const STATPROPSTG kProps[] =
|
||||
|
||||
static const Byte kProps[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsDir, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackSize, VT_UI8},
|
||||
{ NULL, kpidMTime, VT_FILETIME},
|
||||
{ NULL, kpidPosixAttrib, VT_UI4},
|
||||
{ NULL, kpidUser, VT_BSTR},
|
||||
{ NULL, kpidGroup, VT_BSTR},
|
||||
{ NULL, kpidLink, VT_BSTR}
|
||||
kpidPath,
|
||||
kpidIsDir,
|
||||
kpidSize,
|
||||
kpidPackSize,
|
||||
kpidMTime,
|
||||
kpidPosixAttrib,
|
||||
kpidUser,
|
||||
kpidGroup,
|
||||
kpidSymLink,
|
||||
kpidHardLink,
|
||||
// kpidLinkType
|
||||
};
|
||||
|
||||
static const STATPROPSTG kArcProps[] =
|
||||
static const Byte kArcProps[] =
|
||||
{
|
||||
{ NULL, kpidPhySize, VT_UI8},
|
||||
{ NULL, kpidHeadersSize, VT_UI8}
|
||||
kpidHeadersSize,
|
||||
kpidCodePage
|
||||
};
|
||||
|
||||
IMP_IInArchive_Props
|
||||
@@ -50,11 +54,42 @@ IMP_IInArchive_ArcProps
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
switch(propID)
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPhySize: if (_phySizeDefined) prop = _phySize; break;
|
||||
case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break;
|
||||
case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
|
||||
case kpidErrorFlags:
|
||||
{
|
||||
UInt32 flags = 0;
|
||||
if (!_isArc)
|
||||
flags |= kpv_ErrorFlags_IsNotArc;
|
||||
else switch (_error)
|
||||
{
|
||||
case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
|
||||
case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
|
||||
}
|
||||
prop = flags;
|
||||
break;
|
||||
}
|
||||
|
||||
case kpidCodePage:
|
||||
{
|
||||
const char *name = NULL;
|
||||
switch (_openCodePage)
|
||||
{
|
||||
case CP_OEMCP: name = "OEM"; break;
|
||||
case CP_UTF8: name = "UTF-8"; break;
|
||||
}
|
||||
if (name != NULL)
|
||||
prop = name;
|
||||
else
|
||||
{
|
||||
char sz[16];
|
||||
ConvertUInt32ToString(_openCodePage, sz);
|
||||
prop = sz;
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -63,9 +98,16 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
|
||||
HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item)
|
||||
{
|
||||
item.HeaderPos = _phySize;
|
||||
RINOK(ReadItem(stream, filled, item, _errorMessage));
|
||||
if (filled && item.IsSparse())
|
||||
_isSparse = true;
|
||||
RINOK(ReadItem(stream, filled, item, _error));
|
||||
if (filled)
|
||||
{
|
||||
/*
|
||||
if (item.IsSparse())
|
||||
_isSparse = true;
|
||||
*/
|
||||
if (item.IsPaxExtendedHeader())
|
||||
_thereIsPaxExtendedHeader = true;
|
||||
}
|
||||
_phySize += item.HeaderSize;
|
||||
_headersSize += item.HeaderSize;
|
||||
return S_OK;
|
||||
@@ -80,6 +122,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
}
|
||||
|
||||
_phySizeDefined = true;
|
||||
|
||||
bool utf8_OK = true;
|
||||
if (!_forceCodePage)
|
||||
{
|
||||
if (!utf8_OK)
|
||||
_curCodePage = k_DefaultCodePage;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
CItemEx item;
|
||||
@@ -87,12 +137,22 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
RINOK(ReadItem2(stream, filled, item));
|
||||
if (!filled)
|
||||
break;
|
||||
|
||||
_isArc = true;
|
||||
_items.Add(item);
|
||||
|
||||
if (!_forceCodePage)
|
||||
{
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.Name);
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.User);
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.Group);
|
||||
if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName);
|
||||
}
|
||||
|
||||
RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize));
|
||||
if (_phySize > endPos)
|
||||
{
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
_error = k_ErrorType_UnexpectedEnd;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
@@ -102,13 +162,13 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
break;
|
||||
}
|
||||
*/
|
||||
if (callback != NULL)
|
||||
if (callback)
|
||||
{
|
||||
if (_items.Size() == 1)
|
||||
{
|
||||
RINOK(callback->SetTotal(NULL, &endPos));
|
||||
}
|
||||
if (_items.Size() % 100 == 0)
|
||||
if ((_items.Size() & 0x3FF) == 0)
|
||||
{
|
||||
UInt64 numFiles = _items.Size();
|
||||
RINOK(callback->SetCompleted(&numFiles, &_phySize));
|
||||
@@ -116,8 +176,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
}
|
||||
}
|
||||
|
||||
if (!_forceCodePage)
|
||||
{
|
||||
if (!utf8_OK)
|
||||
_curCodePage = k_DefaultCodePage;
|
||||
}
|
||||
_openCodePage = _curCodePage;
|
||||
|
||||
if (_items.Size() == 0)
|
||||
{
|
||||
if (_error != k_ErrorType_OK)
|
||||
{
|
||||
_isArc = false;
|
||||
return S_FALSE;
|
||||
}
|
||||
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
|
||||
if (!callback)
|
||||
return S_FALSE;
|
||||
@@ -129,11 +201,12 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
|
||||
return S_FALSE;
|
||||
if (prop.vt != VT_BSTR)
|
||||
return S_FALSE;
|
||||
UString baseName = prop.bstrVal;
|
||||
baseName = baseName.Right(4);
|
||||
if (baseName.CompareNoCase(L".tar") != 0)
|
||||
unsigned len = MyStringLen(prop.bstrVal);
|
||||
if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
_isArc = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -158,13 +231,16 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
_errorMessage.Empty();
|
||||
_isArc = false;
|
||||
_error = k_ErrorType_OK;
|
||||
|
||||
_phySizeDefined = false;
|
||||
_phySize = 0;
|
||||
_headersSize = 0;
|
||||
_curIndex = 0;
|
||||
_latestIsRead = false;
|
||||
_isSparse = false;
|
||||
// _isSparse = false;
|
||||
_thereIsPaxExtendedHeader = false;
|
||||
_items.Clear();
|
||||
_seqStream.Release();
|
||||
_stream.Release();
|
||||
@@ -181,6 +257,8 @@ CHandler::CHandler()
|
||||
{
|
||||
copyCoderSpec = new NCompress::CCopyCoder();
|
||||
copyCoder = copyCoderSpec;
|
||||
_openCodePage = CP_UTF8;
|
||||
Init();
|
||||
}
|
||||
|
||||
HRESULT CHandler::SkipTo(UInt32 index)
|
||||
@@ -194,7 +272,7 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
||||
_phySize += copyCoderSpec->TotalSize;
|
||||
if (copyCoderSpec->TotalSize != packSize)
|
||||
{
|
||||
_errorMessage = kUnexpectedEnd;
|
||||
_error = k_ErrorType_UnexpectedEnd;
|
||||
return S_FALSE;
|
||||
}
|
||||
_latestIsRead = false;
|
||||
@@ -215,15 +293,29 @@ HRESULT CHandler::SkipTo(UInt32 index)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static UString TarStringToUnicode(const AString &s)
|
||||
void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const
|
||||
{
|
||||
return MultiByteToUnicodeString(s, CP_OEMCP);
|
||||
UString dest;
|
||||
if (_curCodePage == CP_UTF8)
|
||||
{
|
||||
if (!ConvertUTF8ToUnicode(s, dest))
|
||||
{
|
||||
prop = "[ERROR-NAME]";
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
dest = MultiByteToUnicodeString(s, _curCodePage);
|
||||
if (toOs)
|
||||
prop = NItemName::GetOSName2(dest);
|
||||
else
|
||||
prop = dest;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
NCOM::CPropVariant prop;
|
||||
|
||||
const CItemEx *item;
|
||||
if (_stream)
|
||||
@@ -239,9 +331,9 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
|
||||
}
|
||||
}
|
||||
|
||||
switch(propID)
|
||||
switch (propID)
|
||||
{
|
||||
case kpidPath: prop = NItemName::GetOSName2(TarStringToUnicode(item->Name)); break;
|
||||
case kpidPath: TarStringToUnicode(item->Name, prop, true); break;
|
||||
case kpidIsDir: prop = item->IsDir(); break;
|
||||
case kpidSize: prop = item->GetUnpackSize(); break;
|
||||
case kpidPackSize: prop = item->GetPackSizeAligned(); break;
|
||||
@@ -254,9 +346,11 @@ 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: TarStringToUnicode(item->User, prop); break;
|
||||
case kpidGroup: TarStringToUnicode(item->Group, prop); break;
|
||||
case kpidSymLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kSymLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
|
||||
case kpidHardLink: if (item->LinkFlag == NFileHeader::NLinkFlag::kHardLink && !item->LinkName.IsEmpty()) TarStringToUnicode(item->LinkName, prop); break;
|
||||
// case kpidLinkType: prop = (int)item->LinkFlag; break;
|
||||
}
|
||||
prop.Detach(value);
|
||||
return S_OK;
|
||||
@@ -272,7 +366,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
if (!seqMode)
|
||||
stream = _stream;
|
||||
|
||||
bool allFilesMode = (numItems == (UInt32)-1);
|
||||
bool allFilesMode = (numItems == (UInt32)(Int32)-1);
|
||||
if (allFilesMode)
|
||||
numItems = _items.Size();
|
||||
if (_stream && numItems == 0)
|
||||
@@ -333,7 +427,18 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
if (!testMode && !realOutStream)
|
||||
{
|
||||
if (!seqMode)
|
||||
{
|
||||
/*
|
||||
// probably we must show extracting info it callback handler instead
|
||||
if (item->IsHardLink() ||
|
||||
item->IsSymLink())
|
||||
{
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
|
||||
}
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
skipMode = true;
|
||||
askMode = NExtract::NAskMode::kSkip;
|
||||
}
|
||||
@@ -344,13 +449,20 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
|
||||
|
||||
Int32 opRes = NExtract::NOperationResult::kOK;
|
||||
if (item->IsSparse())
|
||||
opRes = NExtract::NOperationResult::kUnSupportedMethod;
|
||||
CMyComPtr<ISequentialInStream> inStream2;
|
||||
if (!item->IsSparse())
|
||||
inStream2 = inStream;
|
||||
else
|
||||
{
|
||||
if (item->IsLink())
|
||||
GetStream(index, &inStream2);
|
||||
if (!inStream2)
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
{
|
||||
if (item->IsSymLink())
|
||||
{
|
||||
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
|
||||
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -359,7 +471,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
}
|
||||
streamSpec->Init(item->GetPackSizeAligned());
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
|
||||
RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress));
|
||||
}
|
||||
if (outStreamSpec->GetRem() != 0)
|
||||
opRes = NExtract::NOperationResult::kDataError;
|
||||
@@ -376,22 +488,198 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
class CSparseStream:
|
||||
public IInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt64 _phyPos;
|
||||
UInt64 _virtPos;
|
||||
bool _needStartSeek;
|
||||
|
||||
public:
|
||||
CHandler *Handler;
|
||||
CMyComPtr<IUnknown> HandlerRef;
|
||||
unsigned ItemIndex;
|
||||
CRecordVector<UInt64> PhyOffsets;
|
||||
|
||||
MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
|
||||
void Init()
|
||||
{
|
||||
_virtPos = 0;
|
||||
_phyPos = 0;
|
||||
_needStartSeek = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
const CItemEx &item = Handler->_items[ItemIndex];
|
||||
if (_virtPos >= item.Size)
|
||||
return S_OK;
|
||||
{
|
||||
UInt64 rem = item.Size - _virtPos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
}
|
||||
|
||||
HRESULT res = S_OK;
|
||||
|
||||
if (item.SparseBlocks.IsEmpty())
|
||||
memset(data, 0, size);
|
||||
else
|
||||
{
|
||||
unsigned left = 0, right = item.SparseBlocks.Size();
|
||||
for (;;)
|
||||
{
|
||||
unsigned mid = (left + right) / 2;
|
||||
if (mid == left)
|
||||
break;
|
||||
if (_virtPos < item.SparseBlocks[mid].Offset)
|
||||
right = mid;
|
||||
else
|
||||
left = mid;
|
||||
}
|
||||
|
||||
const CSparseBlock &sb = item.SparseBlocks[left];
|
||||
UInt64 relat = _virtPos - sb.Offset;
|
||||
|
||||
if (_virtPos >= sb.Offset && relat < sb.Size)
|
||||
{
|
||||
UInt64 rem = sb.Size - relat;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
UInt64 phyPos = PhyOffsets[left] + relat;
|
||||
if (_needStartSeek || _phyPos != phyPos)
|
||||
{
|
||||
RINOK(Handler->_stream->Seek(item.GetDataPosition() + phyPos, STREAM_SEEK_SET, NULL));
|
||||
_needStartSeek = false;
|
||||
_phyPos = phyPos;
|
||||
}
|
||||
res = Handler->_stream->Read(data, size, &size);
|
||||
_phyPos += size;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 next = item.Size;
|
||||
if (_virtPos < sb.Offset)
|
||||
next = sb.Offset;
|
||||
else if (left + 1 < item.SparseBlocks.Size())
|
||||
next = item.SparseBlocks[left + 1].Offset;
|
||||
UInt64 rem = next - _virtPos;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
memset(data, 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
_virtPos += size;
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return res;
|
||||
}
|
||||
|
||||
STDMETHODIMP CSparseStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
switch (seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET: break;
|
||||
case STREAM_SEEK_CUR: offset += _virtPos; break;
|
||||
case STREAM_SEEK_END: offset += Handler->_items[ItemIndex].Size; break;
|
||||
default: return STG_E_INVALIDFUNCTION;
|
||||
}
|
||||
if (offset < 0)
|
||||
return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
|
||||
_virtPos = offset;
|
||||
if (newPosition)
|
||||
*newPosition = _virtPos;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
const CItemEx &item = _items[index];
|
||||
|
||||
if (item.IsSparse())
|
||||
return E_NOTIMPL;
|
||||
if (item.IsLink())
|
||||
{
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CSparseStream *streamSpec = new CSparseStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Length(), (IInArchive *)this);
|
||||
streamSpec->Init();
|
||||
streamSpec->Handler = this;
|
||||
streamSpec->HandlerRef = (IInArchive *)this;
|
||||
streamSpec->ItemIndex = index;
|
||||
streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size());
|
||||
UInt64 offs = 0;
|
||||
FOR_VECTOR(i, item.SparseBlocks)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
streamSpec->PhyOffsets.AddInReserved(offs);
|
||||
offs += sb.Size;
|
||||
}
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (item.IsSymLink())
|
||||
{
|
||||
CBufInStream *streamSpec = new CBufInStream;
|
||||
CMyComPtr<IInStream> streamTemp = streamSpec;
|
||||
streamSpec->Init((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this);
|
||||
*stream = streamTemp.Detach();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream);
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
void CHandler::Init()
|
||||
{
|
||||
_forceCodePage = false;
|
||||
// _codePage = CP_OEMCP;
|
||||
_curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
|
||||
{
|
||||
Init();
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
UString name = names[i];
|
||||
name.MakeLower_Ascii();
|
||||
if (name.IsEmpty())
|
||||
return E_INVALIDARG;
|
||||
|
||||
const PROPVARIANT &prop = values[i];
|
||||
|
||||
if (name[0] == L'x')
|
||||
{
|
||||
// some clients write 'x' property. So we support it
|
||||
UInt32 level = 0;
|
||||
RINOK(ParsePropToUInt32(name.Ptr(1), prop, level));
|
||||
}
|
||||
else if (name.IsEqualTo("cp"))
|
||||
{
|
||||
UInt32 cp = CP_OEMCP;
|
||||
RINOK(ParsePropToUInt32(L"", prop, cp));
|
||||
_forceCodePage = true;
|
||||
_curCodePage = _specifiedCodePage = cp;
|
||||
}
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
32
CPP/7zip/Archive/Tar/TarHandler.h
Executable file → Normal file
32
CPP/7zip/Archive/Tar/TarHandler.h
Executable file → Normal file
@@ -3,12 +3,15 @@
|
||||
#ifndef __TAR_HANDLER_H
|
||||
#define __TAR_HANDLER_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../IArchive.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "TarIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
@@ -17,13 +20,15 @@ class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveOpenSeq,
|
||||
public IInArchiveGetStream,
|
||||
public ISetProperties,
|
||||
public IOutArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
|
||||
private:
|
||||
UInt32 _curIndex;
|
||||
bool _latestIsRead;
|
||||
CItemEx _latestItem;
|
||||
@@ -31,8 +36,16 @@ class CHandler:
|
||||
UInt64 _phySize;
|
||||
UInt64 _headersSize;
|
||||
bool _phySizeDefined;
|
||||
AString _errorMessage;
|
||||
bool _isSparse;
|
||||
EErrorType _error;
|
||||
bool _isArc;
|
||||
|
||||
// bool _isSparse;
|
||||
bool _thereIsPaxExtendedHeader;
|
||||
|
||||
bool _forceCodePage;
|
||||
UInt32 _specifiedCodePage;
|
||||
UInt32 _curCodePage;
|
||||
UInt32 _openCodePage;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec;
|
||||
CMyComPtr<ICompressCoder> copyCoder;
|
||||
@@ -40,12 +53,13 @@ class CHandler:
|
||||
HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
|
||||
HRESULT SkipTo(UInt32 index);
|
||||
|
||||
void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const;
|
||||
public:
|
||||
MY_UNKNOWN_IMP4(
|
||||
MY_UNKNOWN_IMP5(
|
||||
IInArchive,
|
||||
IArchiveOpenSeq,
|
||||
IInArchiveGetStream,
|
||||
ISetProperties,
|
||||
IOutArchive
|
||||
)
|
||||
|
||||
@@ -53,7 +67,9 @@ public:
|
||||
INTERFACE_IOutArchive(;)
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps);
|
||||
|
||||
void Init();
|
||||
CHandler();
|
||||
};
|
||||
|
||||
|
||||
71
CPP/7zip/Archive/Tar/TarHandlerOut.cpp
Executable file → Normal file
71
CPP/7zip/Archive/Tar/TarHandlerOut.cpp
Executable file → Normal file
@@ -2,11 +2,13 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/ComTry.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "../../../Common/ComTry.h"
|
||||
#include "../../../Common/Defs.h"
|
||||
#include "../../../Common/StringConvert.h"
|
||||
#include "../../../Common/UTFConvert.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/Time.h"
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "TarHandler.h"
|
||||
#include "TarUpdate.h"
|
||||
@@ -22,24 +24,54 @@ STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res)
|
||||
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId,
|
||||
AString &res, UINT codePage, bool convertSlash = false)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(index, propId, &prop));
|
||||
if (prop.vt == VT_BSTR)
|
||||
res = UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP);
|
||||
{
|
||||
UString s = prop.bstrVal;
|
||||
if (convertSlash)
|
||||
s = NItemName::MakeLegalName(s);
|
||||
if (codePage == CP_UTF8)
|
||||
{
|
||||
if (!ConvertUnicodeToUTF8(s, res))
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
UnicodeStringToMultiByte2(res, s, codePage);
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// sort old files with original order.
|
||||
|
||||
static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
|
||||
{
|
||||
const CUpdateItem &u1 = *(*((const CUpdateItem **)p1));
|
||||
const CUpdateItem &u2 = *(*((const CUpdateItem **)p2));
|
||||
if (!u1.NewProps)
|
||||
{
|
||||
if (u2.NewProps)
|
||||
return -1;
|
||||
return MyCompare(u1.IndexInArchive, u2.IndexInArchive);
|
||||
}
|
||||
if (!u2.NewProps)
|
||||
return 1;
|
||||
return MyCompare(u1.IndexInClient, u2.IndexInClient);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
||||
IArchiveUpdateCallback *callback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if ((_stream && (!_errorMessage.IsEmpty() || _isSparse)) || _seqStream)
|
||||
if ((_stream && (_error != k_ErrorType_OK /* || _isSparse */)) || _seqStream)
|
||||
return E_NOTIMPL;
|
||||
CObjectVector<CUpdateItem> updateItems;
|
||||
UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
CUpdateItem ui;
|
||||
@@ -87,19 +119,13 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
else
|
||||
ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
|
||||
}
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(callback->GetProperty(i, kpidPath, &prop));
|
||||
if (prop.vt == VT_BSTR)
|
||||
ui.Name = UnicodeStringToMultiByte(NItemName::MakeLegalName(prop.bstrVal), CP_OEMCP);
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_INVALIDARG;
|
||||
if (ui.IsDir)
|
||||
ui.Name += '/';
|
||||
}
|
||||
RINOK(GetPropString(callback, i, kpidUser, ui.User));
|
||||
RINOK(GetPropString(callback, i, kpidGroup, ui.Group));
|
||||
RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, true));
|
||||
if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
|
||||
ui.Name += '/';
|
||||
RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage));
|
||||
RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage));
|
||||
}
|
||||
|
||||
if (IntToBool(newData))
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
@@ -115,7 +141,12 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
|
||||
}
|
||||
updateItems.Add(ui);
|
||||
}
|
||||
return UpdateArchive(_stream, outStream, _items, updateItems, callback);
|
||||
if (_thereIsPaxExtendedHeader)
|
||||
{
|
||||
// we restore original order of files, if there is pax header block
|
||||
updateItems.Sort(CompareUpdateItems, NULL);
|
||||
}
|
||||
return UpdateArchive(_stream, outStream, _items, updateItems, codePage, callback);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
12
CPP/7zip/Archive/Tar/TarHeader.cpp
Executable file → Normal file
12
CPP/7zip/Archive/Tar/TarHeader.cpp
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
// Archive/Tar/Header.h
|
||||
// Archive/TarHeader.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
@@ -8,18 +8,16 @@ namespace NArchive {
|
||||
namespace NTar {
|
||||
namespace NFileHeader {
|
||||
|
||||
// The checksum field is filled with this while the checksum is computed.
|
||||
const char *kCheckSumBlanks = " "; // 8 blanks, no null
|
||||
|
||||
const char *kLongLink = "././@LongLink";
|
||||
const char *kLongLink2 = "@LongLink";
|
||||
|
||||
// The magic field is filled with this if uname and gname are valid.
|
||||
namespace NMagic
|
||||
{
|
||||
const char *kUsTar = "ustar"; // 5 chars
|
||||
const char *kGNUTar = "GNUtar "; // 7 chars and a null
|
||||
const char *kEmpty = "\0\0\0\0\0\0\0\0"; // 7 chars and a null
|
||||
// const char *kUsTar = "ustar"; // 5 chars
|
||||
// const char *kGNUTar = "GNUtar "; // 7 chars and a null
|
||||
// const char *kEmpty = "\0\0\0\0\0\0\0\0";
|
||||
const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
65
CPP/7zip/Archive/Tar/TarHeader.h
Executable file → Normal file
65
CPP/7zip/Archive/Tar/TarHeader.h
Executable file → Normal file
@@ -1,20 +1,22 @@
|
||||
// Archive/Tar/Header.h
|
||||
// Archive/TarHeader.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_HEADER_H
|
||||
#define __ARCHIVE_TAR_HEADER_H
|
||||
|
||||
#include "Common/Types.h"
|
||||
#include "../../../Common/MyTypes.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
namespace NFileHeader
|
||||
{
|
||||
const int kRecordSize = 512;
|
||||
const int kNameSize = 100;
|
||||
const int kUserNameSize = 32;
|
||||
const int kGroupNameSize = 32;
|
||||
const int kPrefixSize = 155;
|
||||
const unsigned kRecordSize = 512;
|
||||
const unsigned kNameSize = 100;
|
||||
const unsigned kUserNameSize = 32;
|
||||
const unsigned kGroupNameSize = 32;
|
||||
const unsigned kPrefixSize = 155;
|
||||
|
||||
const unsigned kUstarMagic_Offset = 257;
|
||||
|
||||
/*
|
||||
struct CHeader
|
||||
@@ -42,66 +44,39 @@ namespace NFileHeader
|
||||
};
|
||||
*/
|
||||
|
||||
namespace NMode
|
||||
{
|
||||
const int kSetUID = 04000; // Set UID on execution
|
||||
const int kSetGID = 02000; // Set GID on execution
|
||||
const int kSaveText = 01000; // Save text (sticky bit)
|
||||
}
|
||||
|
||||
namespace NFilePermissions
|
||||
{
|
||||
const int kUserRead = 00400; // read by owner
|
||||
const int kUserWrite = 00200; // write by owner
|
||||
const int kUserExecute = 00100; // execute/search by owner
|
||||
const int kGroupRead = 00040; // read by group
|
||||
const int kGroupWrite = 00020; // write by group
|
||||
const int kGroupExecute = 00010; // execute/search by group
|
||||
const int kOtherRead = 00004; // read by other
|
||||
const int kOtherWrite = 00002; // write by other
|
||||
const int kOtherExecute = 00001; // execute/search by other
|
||||
}
|
||||
|
||||
|
||||
// The linkflag defines the type of file
|
||||
namespace NLinkFlag
|
||||
{
|
||||
const char kOldNormal = '\0'; // Normal disk file, Unix compatible
|
||||
const char kOldNormal = 0; // Normal disk file, Unix compatible
|
||||
const char kNormal = '0'; // Normal disk file
|
||||
const char kLink = '1'; // Link to previously dumped file
|
||||
const char kSymbolicLink = '2'; // Symbolic link
|
||||
const char kHardLink = '1'; // Link to previously dumped file
|
||||
const char kSymLink = '2'; // Symbolic link
|
||||
const char kCharacter = '3'; // Character special file
|
||||
const char kBlock = '4'; // Block special file
|
||||
const char kDirectory = '5'; // Directory
|
||||
const char kFIFO = '6'; // FIFO special file
|
||||
const char kContiguous = '7'; // Contiguous file
|
||||
|
||||
const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
|
||||
const char kGnu_LongLink = 'K';
|
||||
const char kGnu_LongName = 'L';
|
||||
const char kSparse = 'S';
|
||||
const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
|
||||
data: list of files created by the --incremental (-G) option
|
||||
Each file name is preceded by either
|
||||
- 'Y' (file should be in this archive)
|
||||
- 'N' (file is a directory, or is not stored in the archive.)
|
||||
Each file name is terminated by a null + an additional null after
|
||||
the last file name. */
|
||||
|
||||
const char kSparse = 'S';
|
||||
}
|
||||
// Further link types may be defined later.
|
||||
|
||||
// The checksum field is filled with this while the checksum is computed.
|
||||
extern const char *kCheckSumBlanks;// = " "; // 8 blanks, no null
|
||||
|
||||
extern const char *kLongLink; // = "././@LongLink";
|
||||
extern const char *kLongLink2; // = "@LongLink";
|
||||
|
||||
// The magic field is filled with this if uname and gname are valid.
|
||||
namespace NMagic
|
||||
{
|
||||
extern const char *kUsTar; // = "ustar"; // 5 chars
|
||||
extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null
|
||||
extern const char *kEmpty; // = "GNUtar "; // 7 chars and a null
|
||||
// extern const char *kUsTar; // = "ustar"; // 5 chars
|
||||
// extern const char *kGNUTar; // = "GNUtar "; // 7 chars and a null
|
||||
// extern const char *kEmpty; // = "\0\0\0\0\0\0\0\0"
|
||||
extern const char kUsTar_00[];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
239
CPP/7zip/Archive/Tar/TarIn.cpp
Executable file → Normal file
239
CPP/7zip/Archive/Tar/TarIn.cpp
Executable file → Normal file
@@ -4,18 +4,20 @@
|
||||
|
||||
#include "../../../../C/CpuArch.h"
|
||||
|
||||
#include "Common/StringToInt.h"
|
||||
#include "../../../Common/StringToInt.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "TarIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
static void MyStrNCpy(char *dest, const char *src, int size)
|
||||
static void MyStrNCpy(char *dest, const char *src, unsigned size)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
char c = src[i];
|
||||
dest[i] = c;
|
||||
@@ -24,19 +26,21 @@ static void MyStrNCpy(char *dest, const char *src, int size)
|
||||
}
|
||||
}
|
||||
|
||||
static bool OctalToNumber(const char *srcString, int size, UInt64 &res)
|
||||
static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res)
|
||||
{
|
||||
char sz[32];
|
||||
MyStrNCpy(sz, srcString, size);
|
||||
sz[size] = 0;
|
||||
const char *end;
|
||||
int i;
|
||||
unsigned i;
|
||||
for (i = 0; sz[i] == ' '; i++);
|
||||
res = ConvertOctStringToUInt64(sz + i, &end);
|
||||
if (end == sz + i)
|
||||
return false;
|
||||
return (*end == ' ' || *end == 0);
|
||||
}
|
||||
|
||||
static bool OctalToNumber32(const char *srcString, int size, UInt32 &res)
|
||||
static bool OctalToNumber32(const char *srcString, unsigned size, UInt32 &res)
|
||||
{
|
||||
UInt64 res64;
|
||||
if (!OctalToNumber(srcString, size, res64))
|
||||
@@ -45,17 +49,27 @@ static bool OctalToNumber32(const char *srcString, int size, UInt32 &res)
|
||||
return (res64 <= 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
#define RIF(x) { if (!(x)) return S_FALSE; }
|
||||
#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 (int i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
if (buf[i] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ReadString(const char *s, int size, AString &result)
|
||||
static void ReadString(const char *s, unsigned size, AString &result)
|
||||
{
|
||||
char temp[NFileHeader::kRecordSize + 1];
|
||||
MyStrNCpy(temp, s, size);
|
||||
@@ -88,12 +102,39 @@ static bool ParseSize(const char *p, UInt64 &val)
|
||||
return OctalToNumber(p, 12, val);
|
||||
}
|
||||
|
||||
static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
|
||||
#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; }
|
||||
|
||||
API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size)
|
||||
{
|
||||
if (size < NFileHeader::kRecordSize)
|
||||
return k_IsArc_Res_NEED_MORE;
|
||||
|
||||
const char *p = (const char *)p2;
|
||||
p += NFileHeader::kNameSize;
|
||||
|
||||
UInt32 mode;
|
||||
CHECK(OctalToNumber32(p, 8, mode)); p += 8;
|
||||
|
||||
// if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0;
|
||||
p += 8;
|
||||
// if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0;
|
||||
p += 8;
|
||||
|
||||
UInt64 packSize;
|
||||
Int64 time;
|
||||
UInt32 checkSum;
|
||||
CHECK(ParseSize(p, packSize)); p += 12;
|
||||
CHECK(ParseInt64(p, time)); p += 12;
|
||||
CHECK(OctalToNumber32(p, 8, checkSum));
|
||||
return k_IsArc_Res_YES;
|
||||
}
|
||||
|
||||
static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error)
|
||||
{
|
||||
char buf[NFileHeader::kRecordSize];
|
||||
char *p = buf;
|
||||
|
||||
error.Empty();
|
||||
error = k_ErrorType_OK;
|
||||
filled = false;
|
||||
|
||||
bool thereAreEmptyRecords = false;
|
||||
@@ -103,26 +144,41 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
|
||||
RINOK(ReadStream(stream, buf, &processedSize));
|
||||
if (processedSize == 0)
|
||||
{
|
||||
if (!thereAreEmptyRecords )
|
||||
error = "There are no trailing zero-filled records";
|
||||
if (!thereAreEmptyRecords)
|
||||
error = k_ErrorType_UnexpectedEnd; // "There are no trailing zero-filled records";
|
||||
return S_OK;
|
||||
}
|
||||
if (processedSize != NFileHeader::kRecordSize)
|
||||
{
|
||||
error = "There is no correct record at the end of archive";
|
||||
if (!thereAreEmptyRecords)
|
||||
error = k_ErrorType_UnexpectedEnd; // error = "There is no correct record at the end of archive";
|
||||
else
|
||||
{
|
||||
/*
|
||||
if (IsEmptyData(buf, processedSize))
|
||||
error = k_ErrorType_UnexpectedEnd;
|
||||
else
|
||||
{
|
||||
// extraReadSize = processedSize;
|
||||
// error = k_ErrorType_Corrupted; // some data after the end tail zeros
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
item.HeaderSize += NFileHeader::kRecordSize;
|
||||
if (!IsRecordLast(buf))
|
||||
break;
|
||||
item.HeaderSize += NFileHeader::kRecordSize;
|
||||
thereAreEmptyRecords = true;
|
||||
}
|
||||
if (thereAreEmptyRecords)
|
||||
{
|
||||
error = "There are data after end of archive";
|
||||
// error = "There are data after end of archive";
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
error = k_ErrorType_Corrupted;
|
||||
ReadString(p, NFileHeader::kNameSize, item.Name); p += NFileHeader::kNameSize;
|
||||
|
||||
RIF(OctalToNumber32(p, 8, item.Mode)); p += 8;
|
||||
@@ -137,7 +193,7 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
|
||||
|
||||
UInt32 checkSum;
|
||||
RIF(OctalToNumber32(p, 8, checkSum));
|
||||
memcpy(p, NFileHeader::kCheckSumBlanks, 8); p += 8;
|
||||
memset(p, ' ', 8); p += 8;
|
||||
|
||||
item.LinkFlag = *p++;
|
||||
|
||||
@@ -148,93 +204,170 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
|
||||
ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
|
||||
ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
|
||||
|
||||
item.DeviceMajorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMajor)); p += 8;
|
||||
item.DeviceMinorDefined = (p[0] != 0); RIF(OctalToNumber32(p, 8, item.DeviceMinor)); p += 8;
|
||||
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;
|
||||
|
||||
AString prefix;
|
||||
ReadString(p, NFileHeader::kPrefixSize, prefix);
|
||||
p += NFileHeader::kPrefixSize;
|
||||
if (!prefix.IsEmpty() && item.IsMagic() &&
|
||||
if (!prefix.IsEmpty() && item.IsUstarMagic() &&
|
||||
(item.LinkFlag != 'L' /* || prefix != "00000000000" */ ))
|
||||
item.Name = prefix + AString('/') + item.Name;
|
||||
|
||||
if (item.LinkFlag == NFileHeader::NLinkFlag::kLink)
|
||||
if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink)
|
||||
{
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
}
|
||||
else if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse)
|
||||
/*
|
||||
TAR standard requires sum of unsigned byte values.
|
||||
But some 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++)
|
||||
{
|
||||
if (buf[482] != 0)
|
||||
return S_FALSE;
|
||||
char c = buf[i];
|
||||
checkSumReal_Signed += (signed char)c;
|
||||
checkSumReal += (Byte)buf[i];
|
||||
}
|
||||
|
||||
if (checkSumReal != checkSum)
|
||||
{
|
||||
if ((UInt32)checkSumReal_Signed != checkSum)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
item.HeaderSize += NFileHeader::kRecordSize;
|
||||
|
||||
if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse)
|
||||
{
|
||||
Byte isExtended = buf[482];
|
||||
if (isExtended != 0 && isExtended != 1)
|
||||
return S_OK;
|
||||
RIF(ParseSize(buf + 483, item.Size));
|
||||
p = buf + 386;
|
||||
UInt64 min = 0;
|
||||
for (int i = 0; i < 4; i++, p += 24)
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
{
|
||||
p = buf + 386 + 24 * i;
|
||||
if (GetBe32(p) == 0)
|
||||
{
|
||||
if (isExtended != 0)
|
||||
return S_OK;
|
||||
break;
|
||||
}
|
||||
CSparseBlock sb;
|
||||
RIF(ParseSize(p, sb.Offset));
|
||||
RIF(ParseSize(p + 12, sb.Size));
|
||||
item.SparseBlocks.Add(sb);
|
||||
if (sb.Offset < min || sb.Offset > item.Size)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
min = sb.Offset + sb.Size;
|
||||
if (min < sb.Offset)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
if (min > item.Size)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
|
||||
while (isExtended != 0)
|
||||
{
|
||||
size_t processedSize = NFileHeader::kRecordSize;
|
||||
RINOK(ReadStream(stream, buf, &processedSize));
|
||||
if (processedSize != NFileHeader::kRecordSize)
|
||||
{
|
||||
error = k_ErrorType_UnexpectedEnd;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
item.HeaderSize += NFileHeader::kRecordSize;
|
||||
isExtended = buf[21 * 24];
|
||||
if (isExtended != 0 && isExtended != 1)
|
||||
return S_OK;
|
||||
for (unsigned i = 0; i < 21; i++)
|
||||
{
|
||||
p = buf + 24 * i;
|
||||
if (GetBe32(p) == 0)
|
||||
{
|
||||
if (isExtended != 0)
|
||||
return S_OK;
|
||||
break;
|
||||
}
|
||||
CSparseBlock sb;
|
||||
RIF(ParseSize(p, sb.Offset));
|
||||
RIF(ParseSize(p + 12, sb.Size));
|
||||
item.SparseBlocks.Add(sb);
|
||||
if (sb.Offset < min || sb.Offset > item.Size)
|
||||
return S_OK;
|
||||
if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0)
|
||||
return S_OK;
|
||||
min = sb.Offset + sb.Size;
|
||||
if (min < sb.Offset)
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
if (min > item.Size)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UInt32 checkSumReal = 0;
|
||||
for (int i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
checkSumReal += (Byte)buf[i];
|
||||
|
||||
if (checkSumReal != checkSum)
|
||||
return S_FALSE;
|
||||
|
||||
filled = true;
|
||||
error = k_ErrorType_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, EErrorType &error)
|
||||
{
|
||||
item.HeaderSize = 0;
|
||||
bool flagL = false;
|
||||
bool flagK = false;
|
||||
AString nameL;
|
||||
AString nameK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
RINOK(GetNextItemReal(stream, filled, item, error));
|
||||
if (!filled)
|
||||
{
|
||||
if (error == k_ErrorType_OK && (flagL || flagK))
|
||||
error = k_ErrorType_Corrupted;
|
||||
return S_OK;
|
||||
if (item.LinkFlag == 'L' || // NEXT file has a long name
|
||||
item.LinkFlag == 'K') // NEXT file has a long linkname
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
AString *name;
|
||||
if (item.LinkFlag == 'L')
|
||||
{ if (flagL) return S_FALSE; flagL = true; name = &nameL; }
|
||||
if (item.LinkFlag == NFileHeader::NLinkFlag::kGnu_LongName)
|
||||
{ if (flagL) return S_OK; flagL = true; name = &nameL; }
|
||||
else
|
||||
{ if (flagK) return S_FALSE; flagK = true; name = &nameK; }
|
||||
{ if (flagK) return S_OK; flagK = true; name = &nameK; }
|
||||
|
||||
if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
|
||||
item.Name.Compare(NFileHeader::kLongLink2) != 0)
|
||||
return S_FALSE;
|
||||
if (item.Name != NFileHeader::kLongLink &&
|
||||
item.Name != NFileHeader::kLongLink2)
|
||||
return S_OK;
|
||||
if (item.PackSize > (1 << 14))
|
||||
return S_FALSE;
|
||||
int packSize = (int)item.GetPackSizeAligned();
|
||||
return S_OK;
|
||||
unsigned packSize = (unsigned)item.GetPackSizeAligned();
|
||||
char *buf = name->GetBuffer(packSize);
|
||||
RINOK(ReadStream_FALSE(stream, buf, packSize));
|
||||
item.HeaderSize += packSize;
|
||||
buf[(size_t)item.PackSize] = '\0';
|
||||
size_t processedSize = packSize;
|
||||
HRESULT res = ReadStream(stream, buf, &processedSize);
|
||||
item.HeaderSize += (unsigned)processedSize;
|
||||
buf[(size_t)item.PackSize] = 0;
|
||||
name->ReleaseBuffer();
|
||||
RINOK(res);
|
||||
if (processedSize != packSize)
|
||||
{
|
||||
error = k_ErrorType_UnexpectedEnd;
|
||||
return S_OK;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (item.LinkFlag)
|
||||
{
|
||||
case 'g':
|
||||
@@ -256,10 +389,12 @@ HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AStri
|
||||
}
|
||||
default:
|
||||
if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (flagL) item.Name = nameL;
|
||||
if (flagK) item.LinkName = nameK;
|
||||
error = k_ErrorType_OK;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
11
CPP/7zip/Archive/Tar/TarIn.h
Executable file → Normal file
11
CPP/7zip/Archive/Tar/TarIn.h
Executable file → Normal file
@@ -10,7 +10,16 @@
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, AString &error);
|
||||
enum EErrorType
|
||||
{
|
||||
k_ErrorType_OK,
|
||||
k_ErrorType_Corrupted,
|
||||
k_ErrorType_UnexpectedEnd,
|
||||
};
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error);
|
||||
|
||||
API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);
|
||||
|
||||
}}
|
||||
|
||||
|
||||
23
CPP/7zip/Archive/Tar/TarItem.h
Executable file → Normal file
23
CPP/7zip/Archive/Tar/TarItem.h
Executable file → Normal file
@@ -40,28 +40,41 @@ struct CItem
|
||||
|
||||
CRecordVector<CSparseBlock> SparseBlocks;
|
||||
|
||||
bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
|
||||
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; }
|
||||
UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
|
||||
UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; }
|
||||
bool IsPaxExtendedHeader() const
|
||||
{
|
||||
switch (LinkFlag)
|
||||
{
|
||||
case 'g':
|
||||
case 'x':
|
||||
case 'X': // Check it
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsDir() const
|
||||
{
|
||||
switch(LinkFlag)
|
||||
switch (LinkFlag)
|
||||
{
|
||||
case NFileHeader::NLinkFlag::kDirectory:
|
||||
case NFileHeader::NLinkFlag::kDumpDir:
|
||||
return true;
|
||||
case NFileHeader::NLinkFlag::kOldNormal:
|
||||
case NFileHeader::NLinkFlag::kNormal:
|
||||
case NFileHeader::NLinkFlag::kSymLink:
|
||||
return NItemName::HasTailSlash(Name, CP_OEMCP);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsMagic() const
|
||||
bool IsUstarMagic() const
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
if (Magic[i] != NFileHeader::NMagic::kUsTar[i])
|
||||
if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
228
CPP/7zip/Archive/Tar/TarOut.cpp
Executable file → Normal file
228
CPP/7zip/Archive/Tar/TarOut.cpp
Executable file → Normal file
@@ -2,8 +2,6 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/IntToString.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "TarOut.h"
|
||||
@@ -11,26 +9,15 @@
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size)
|
||||
HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
|
||||
{
|
||||
return WriteStream(m_Stream, buffer, size);
|
||||
Pos += size;
|
||||
return WriteStream(m_Stream, data, size);
|
||||
}
|
||||
|
||||
void COutArchive::Create(ISequentialOutStream *outStream)
|
||||
static void MyStrNCpy(char *dest, const char *src, unsigned size)
|
||||
{
|
||||
m_Stream = outStream;
|
||||
}
|
||||
|
||||
static AString MakeOctalString(UInt64 value)
|
||||
{
|
||||
char s[32];
|
||||
ConvertUInt64ToString(value, s, 8);
|
||||
return AString(s) + ' ';
|
||||
}
|
||||
|
||||
static void MyStrNCpy(char *dest, const char *src, int size)
|
||||
{
|
||||
for (int i = 0; i < size; i++)
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
char c = src[i];
|
||||
dest[i] = c;
|
||||
@@ -39,54 +26,53 @@ static void MyStrNCpy(char *dest, const char *src, int size)
|
||||
}
|
||||
}
|
||||
|
||||
static bool MakeOctalString8(char *s, UInt32 value)
|
||||
static bool WriteOctal_8(char *s, UInt32 val)
|
||||
{
|
||||
AString tempString = MakeOctalString(value);
|
||||
|
||||
const int kMaxSize = 8;
|
||||
if (tempString.Length() >= kMaxSize)
|
||||
const unsigned kNumDigits = 8 - 1;
|
||||
if (val >= ((UInt32)1 << (kNumDigits * 3)))
|
||||
return false;
|
||||
int numSpaces = kMaxSize - (tempString.Length() + 1);
|
||||
for (int i = 0; i < numSpaces; i++)
|
||||
s[i] = ' ';
|
||||
MyStringCopy(s + numSpaces, (const char *)tempString);
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void MakeOctalString12(char *s, UInt64 value)
|
||||
static void WriteOctal_12(char *s, UInt64 val)
|
||||
{
|
||||
AString tempString = MakeOctalString(value);
|
||||
const int kMaxSize = 12;
|
||||
if (tempString.Length() > kMaxSize)
|
||||
const unsigned kNumDigits = 12 - 1;
|
||||
if (val >= ((UInt64)1 << (kNumDigits * 3)))
|
||||
{
|
||||
// GNU extension;
|
||||
s[0] = (char)(Byte)0x80;
|
||||
s[1] = s[2] = s[3] = 0;
|
||||
for (int i = 0; i < 8; i++, value <<= 8)
|
||||
s[4 + i] = (char)(value >> 56);
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
return;
|
||||
}
|
||||
int numSpaces = kMaxSize - tempString.Length();
|
||||
for (int i = 0; i < numSpaces; i++)
|
||||
s[i] = ' ';
|
||||
memmove(s + numSpaces, (const char *)tempString, tempString.Length());
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void MakeOctalString12_From_Int64(char *s, Int64 value)
|
||||
static void WriteOctal_12_Signed(char *s, Int64 val)
|
||||
{
|
||||
if (value >= 0)
|
||||
if (val >= 0)
|
||||
{
|
||||
MakeOctalString12(s, value);
|
||||
WriteOctal_12(s, val);
|
||||
return;
|
||||
}
|
||||
s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
|
||||
for (int i = 0; i < 8; i++, value <<= 8)
|
||||
s[4 + i] = (char)(value >> 56);
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
}
|
||||
|
||||
static bool CopyString(char *dest, const AString &src, int maxSize)
|
||||
static bool CopyString(char *dest, const AString &src, unsigned maxSize)
|
||||
{
|
||||
if (src.Length() >= maxSize)
|
||||
if (src.Len() >= maxSize)
|
||||
return false;
|
||||
MyStringCopy(dest, (const char *)src);
|
||||
return true;
|
||||
@@ -97,25 +83,22 @@ static bool CopyString(char *dest, const AString &src, int maxSize)
|
||||
HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
{
|
||||
char record[NFileHeader::kRecordSize];
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
char *cur = record;
|
||||
int i;
|
||||
for (i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
record[i] = 0;
|
||||
|
||||
// RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize));
|
||||
if (item.Name.Length() > NFileHeader::kNameSize)
|
||||
if (item.Name.Len() > NFileHeader::kNameSize)
|
||||
return E_FAIL;
|
||||
MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
|
||||
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;
|
||||
|
||||
MakeOctalString12(cur, item.PackSize); cur += 12;
|
||||
MakeOctalString12_From_Int64(cur, item.MTime); cur += 12;
|
||||
WriteOctal_12(cur, item.PackSize); cur += 12;
|
||||
WriteOctal_12_Signed(cur, item.MTime); cur += 12;
|
||||
|
||||
memmove(cur, NFileHeader::kCheckSumBlanks, 8);
|
||||
memset(cur, ' ', 8);
|
||||
cur += 8;
|
||||
|
||||
*cur++ = item.LinkFlag;
|
||||
@@ -123,7 +106,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
memmove(cur, item.Magic, 8);
|
||||
memcpy(cur, item.Magic, 8);
|
||||
cur += 8;
|
||||
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
|
||||
@@ -132,64 +115,127 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
cur += NFileHeader::kGroupNameSize;
|
||||
|
||||
|
||||
if (item.DeviceMajorDefined)
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor));
|
||||
cur += 8;
|
||||
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;
|
||||
|
||||
if (item.DeviceMinorDefined)
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor));
|
||||
cur += 8;
|
||||
if (item.IsSparse())
|
||||
{
|
||||
record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
|
||||
WriteOctal_12(record + 483, item.Size);
|
||||
for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 386 + 24 * i;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 checkSum = 0;
|
||||
{
|
||||
for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
checkSum += (Byte)record[i];
|
||||
}
|
||||
/* 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));
|
||||
const unsigned kNumDigits = 6;
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7));
|
||||
checkSum >>= 3;
|
||||
}
|
||||
record[148 + 6] = 0;
|
||||
}
|
||||
|
||||
UInt32 checkSumReal = 0;
|
||||
for (i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
checkSumReal += Byte(record[i]);
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
|
||||
RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal));
|
||||
if (item.IsSparse())
|
||||
{
|
||||
for (unsigned i = 4; i < item.SparseBlocks.Size();)
|
||||
{
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 24 * t;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
}
|
||||
|
||||
return WriteBytes(record, NFileHeader::kRecordSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteHeader(const CItem &item)
|
||||
{
|
||||
int nameSize = item.Name.Length();
|
||||
if (nameSize < NFileHeader::kNameSize)
|
||||
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)
|
||||
return WriteHeaderReal(item);
|
||||
|
||||
CItem modifiedItem = item;
|
||||
int nameStreamSize = nameSize + 1;
|
||||
modifiedItem.PackSize = nameStreamSize;
|
||||
modifiedItem.LinkFlag = 'L';
|
||||
modifiedItem.Name = NFileHeader::kLongLink;
|
||||
modifiedItem.LinkName.Empty();
|
||||
RINOK(WriteHeaderReal(modifiedItem));
|
||||
RINOK(WriteBytes(item.Name, nameStreamSize));
|
||||
RINOK(FillDataResidual(nameStreamSize));
|
||||
CItem mi = item;
|
||||
mi.Name = NFileHeader::kLongLink;
|
||||
mi.LinkName.Empty();
|
||||
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?
|
||||
if (i == 0)
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
|
||||
name = &item.LinkName;
|
||||
}
|
||||
else
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
|
||||
name = &item.Name;
|
||||
}
|
||||
if (name->Len() < NFileHeader::kNameSize)
|
||||
continue;
|
||||
unsigned nameStreamSize = name->Len() + 1;
|
||||
mi.PackSize = nameStreamSize;
|
||||
RINOK(WriteHeaderReal(mi));
|
||||
RINOK(WriteBytes((const char *)*name, nameStreamSize));
|
||||
RINOK(FillDataResidual(nameStreamSize));
|
||||
}
|
||||
|
||||
modifiedItem = item;
|
||||
modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1);
|
||||
return WriteHeaderReal(modifiedItem);
|
||||
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);
|
||||
return WriteHeaderReal(mi);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
|
||||
{
|
||||
UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1));
|
||||
unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
|
||||
if (lastRecordSize == 0)
|
||||
return S_OK;
|
||||
UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize;
|
||||
Byte residualBytes[NFileHeader::kRecordSize];
|
||||
for (UInt32 i = 0; i < residualSize; i++)
|
||||
residualBytes[i] = 0;
|
||||
return WriteBytes(residualBytes, residualSize);
|
||||
unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
|
||||
Byte buf[NFileHeader::kRecordSize];
|
||||
memset(buf, 0, rem);
|
||||
return WriteBytes(buf, rem);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteFinishHeader()
|
||||
{
|
||||
Byte record[NFileHeader::kRecordSize];
|
||||
int i;
|
||||
for (i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
record[i] = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
|
||||
18
CPP/7zip/Archive/Tar/TarOut.h
Executable file → Normal file
18
CPP/7zip/Archive/Tar/TarOut.h
Executable file → Normal file
@@ -3,21 +3,29 @@
|
||||
#ifndef __ARCHIVE_TAR_OUT_H
|
||||
#define __ARCHIVE_TAR_OUT_H
|
||||
|
||||
#include "TarItem.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
class COutArchive
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> m_Stream;
|
||||
HRESULT WriteBytes(const void *buffer, UInt32 size);
|
||||
public:
|
||||
void Create(ISequentialOutStream *outStream);
|
||||
|
||||
HRESULT WriteBytes(const void *data, unsigned size);
|
||||
HRESULT WriteHeaderReal(const CItem &item);
|
||||
public:
|
||||
UInt64 Pos;
|
||||
|
||||
void Create(ISequentialOutStream *outStream)
|
||||
{
|
||||
m_Stream = outStream;
|
||||
}
|
||||
|
||||
HRESULT WriteHeader(const CItem &item);
|
||||
HRESULT FillDataResidual(UInt64 dataSize);
|
||||
HRESULT WriteFinishHeader();
|
||||
|
||||
22
CPP/7zip/Archive/Tar/TarRegister.cpp
Executable file → Normal file
22
CPP/7zip/Archive/Tar/TarRegister.cpp
Executable file → Normal file
@@ -5,14 +5,22 @@
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "TarHandler.h"
|
||||
static IInArchive *CreateArc() { return new NArchive::NTar::CHandler; }
|
||||
#ifndef EXTRACT_ONLY
|
||||
static IOutArchive *CreateArcOut() { return new NArchive::NTar::CHandler; }
|
||||
#else
|
||||
#define CreateArcOut 0
|
||||
#endif
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
IMP_CreateArcIn
|
||||
IMP_CreateArcOut
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"tar", L"tar", 0, 0xEE, { 'u', 's', 't', 'a', 'r' }, 5, false, CreateArc, CreateArcOut };
|
||||
{ "tar", "tar", 0, 0xEE,
|
||||
5, { 'u', 's', 't', 'a', 'r' },
|
||||
NFileHeader::kUstarMagic_Offset,
|
||||
NArcInfoFlags::kStartOpen |
|
||||
NArcInfoFlags::kSymLinks |
|
||||
NArcInfoFlags::kHardLinks,
|
||||
REF_CreateArc_Pair, IsArc_Tar };
|
||||
|
||||
REGISTER_ARC(Tar)
|
||||
|
||||
}}
|
||||
|
||||
129
CPP/7zip/Archive/Tar/TarUpdate.cpp
Executable file → Normal file
129
CPP/7zip/Archive/Tar/TarUpdate.cpp
Executable file → Normal file
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
@@ -13,18 +15,26 @@
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId,
|
||||
AString &res, UINT codePage, bool convertSlash = false);
|
||||
|
||||
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
|
||||
const CObjectVector<CUpdateItem> &updateItems,
|
||||
UINT codePage,
|
||||
IArchiveUpdateCallback *updateCallback)
|
||||
{
|
||||
COutArchive outArchive;
|
||||
outArchive.Create(outStream);
|
||||
outArchive.Pos = 0;
|
||||
|
||||
CMyComPtr<IOutStream> outSeekStream;
|
||||
outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);
|
||||
|
||||
UInt64 complexity = 0;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < updateItems.Size(); i++)
|
||||
unsigned i;
|
||||
for (i = 0; i < updateItems.Size(); i++)
|
||||
{
|
||||
const CUpdateItem &ui = updateItems[i];
|
||||
if (ui.NewData)
|
||||
@@ -76,37 +86,101 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
item.DeviceMinorDefined = false;
|
||||
item.UID = 0;
|
||||
item.GID = 0;
|
||||
memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8);
|
||||
memcpy(item.Magic, NFileHeader::NMagic::kUsTar_00, 8);
|
||||
}
|
||||
else
|
||||
item = inputItems[ui.IndexInArchive];
|
||||
|
||||
AString symLink;
|
||||
if (ui.NewData || ui.NewProps)
|
||||
{
|
||||
RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink, codePage, true));
|
||||
if (!symLink.IsEmpty())
|
||||
{
|
||||
item.LinkFlag = NFileHeader::NLinkFlag::kSymLink;
|
||||
item.LinkName = symLink;
|
||||
}
|
||||
}
|
||||
|
||||
if (ui.NewData)
|
||||
{
|
||||
item.SparseBlocks.Clear();
|
||||
item.PackSize = ui.Size;
|
||||
item.Size = ui.Size;
|
||||
if (ui.Size == (UInt64)(Int64)-1)
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
item.PackSize = inputItems[ui.IndexInArchive].PackSize;
|
||||
|
||||
if (ui.NewData)
|
||||
{
|
||||
|
||||
CMyComPtr<ISequentialInStream> fileInStream;
|
||||
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
|
||||
if (res != S_FALSE)
|
||||
|
||||
bool needWrite = true;
|
||||
if (!symLink.IsEmpty())
|
||||
{
|
||||
RINOK(res);
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
|
||||
if (res == S_FALSE)
|
||||
needWrite = false;
|
||||
else
|
||||
{
|
||||
RINOK(res);
|
||||
|
||||
if (fileInStream)
|
||||
{
|
||||
CMyComPtr<IStreamGetProps> getProps;
|
||||
fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
|
||||
if (getProps)
|
||||
{
|
||||
FILETIME mTime;
|
||||
UInt64 size2;
|
||||
if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
|
||||
{
|
||||
item.PackSize = size2;
|
||||
item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
AString hardLink;
|
||||
RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink, codePage, true));
|
||||
if (!hardLink.IsEmpty())
|
||||
{
|
||||
item.LinkFlag = NFileHeader::NLinkFlag::kHardLink;
|
||||
item.LinkName = hardLink;
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
fileInStream.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needWrite)
|
||||
{
|
||||
UInt64 fileHeaderStartPos = outArchive.Pos;
|
||||
RINOK(outArchive.WriteHeader(item));
|
||||
if (!ui.IsDir)
|
||||
if (fileInStream)
|
||||
{
|
||||
RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
|
||||
outArchive.Pos += copyCoderSpec->TotalSize;
|
||||
if (copyCoderSpec->TotalSize != item.PackSize)
|
||||
return E_FAIL;
|
||||
{
|
||||
if (!outSeekStream)
|
||||
return E_FAIL;
|
||||
UInt64 backOffset = outArchive.Pos - fileHeaderStartPos;
|
||||
RINOK(outSeekStream->Seek(-(Int64)backOffset, STREAM_SEEK_CUR, NULL));
|
||||
outArchive.Pos = fileHeaderStartPos;
|
||||
item.PackSize = copyCoderSpec->TotalSize;
|
||||
RINOK(outArchive.WriteHeader(item));
|
||||
RINOK(outSeekStream->Seek(item.PackSize, STREAM_SEEK_CUR, NULL));
|
||||
outArchive.Pos += item.PackSize;
|
||||
}
|
||||
RINOK(outArchive.FillDataResidual(item.PackSize));
|
||||
}
|
||||
}
|
||||
complexity += ui.Size;
|
||||
complexity += item.PackSize;
|
||||
RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
|
||||
}
|
||||
else
|
||||
@@ -115,6 +189,30 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
UInt64 size;
|
||||
if (ui.NewProps)
|
||||
{
|
||||
// memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8);
|
||||
|
||||
if (!symLink.IsEmpty())
|
||||
{
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ui.IsDir == existItem.IsDir())
|
||||
item.LinkFlag = existItem.LinkFlag;
|
||||
|
||||
item.SparseBlocks = existItem.SparseBlocks;
|
||||
item.Size = existItem.Size;
|
||||
item.PackSize = existItem.PackSize;
|
||||
}
|
||||
|
||||
item.DeviceMajorDefined = existItem.DeviceMajorDefined;
|
||||
item.DeviceMinorDefined = existItem.DeviceMinorDefined;
|
||||
item.DeviceMajor = existItem.DeviceMajor;
|
||||
item.DeviceMinor = existItem.DeviceMinor;
|
||||
item.UID = existItem.UID;
|
||||
item.GID = existItem.GID;
|
||||
|
||||
RINOK(outArchive.WriteHeader(item));
|
||||
RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
|
||||
size = existItem.PackSize;
|
||||
@@ -129,6 +227,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
|
||||
if (copyCoderSpec->TotalSize != size)
|
||||
return E_FAIL;
|
||||
outArchive.Pos += size;
|
||||
RINOK(outArchive.FillDataResidual(existItem.PackSize));
|
||||
complexity += size;
|
||||
}
|
||||
|
||||
1
CPP/7zip/Archive/Tar/TarUpdate.h
Executable file → Normal file
1
CPP/7zip/Archive/Tar/TarUpdate.h
Executable file → Normal file
@@ -27,6 +27,7 @@ struct CUpdateItem
|
||||
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
const CObjectVector<CUpdateItem> &updateItems,
|
||||
UINT codePage,
|
||||
IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user