This commit is contained in:
Igor Pavlov
2011-04-11 00:00:00 +00:00
committed by Kornel Lesiński
parent de4f8c22fe
commit 35596517f2
322 changed files with 9989 additions and 7759 deletions

View File

@@ -64,6 +64,8 @@ HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &
{
item.HeaderPos = _phySize;
RINOK(ReadItem(stream, filled, item, _errorMessage));
if (filled && item.IsSparse())
_isSparse = true;
_phySize += item.HeaderSize;
_headersSize += item.HeaderSize;
return S_OK;
@@ -87,7 +89,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
break;
_items.Add(item);
RINOK(stream->Seek(item.GetPackSize(), STREAM_SEEK_CUR, &_phySize));
RINOK(stream->Seek(item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize));
if (_phySize > endPos)
{
_errorMessage = kUnexpectedEnd;
@@ -162,6 +164,7 @@ STDMETHODIMP CHandler::Close()
_headersSize = 0;
_curIndex = 0;
_latestIsRead = false;
_isSparse = false;
_items.Clear();
_seqStream.Release();
_stream.Release();
@@ -186,7 +189,7 @@ HRESULT CHandler::SkipTo(UInt32 index)
{
if (_latestIsRead)
{
UInt64 packSize = _latestItem.GetPackSize();
UInt64 packSize = _latestItem.GetPackSizeAligned();
RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL));
_phySize += copyCoderSpec->TotalSize;
if (copyCoderSpec->TotalSize != packSize)
@@ -241,13 +244,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
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 kpidPackSize: prop = item->GetPackSizeAligned(); break;
case kpidMTime:
if (item->MTime != 0)
{
FILETIME ft;
NTime::UnixTimeToFileTime(item->MTime, ft);
prop = ft;
if (NTime::UnixTime64ToFileTime(item->MTime, ft))
prop = ft;
}
break;
case kpidPosixAttrib: prop = item->Mode; break;
@@ -319,7 +322,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
UInt64 unpackSize = item->GetUnpackSize();
totalSize += unpackSize;
totalPackSize += item->GetPackSize();
totalPackSize += item->GetPackSizeAligned();
if (item->IsDir())
{
RINOK(extractCallback->PrepareOperation(askMode));
@@ -340,18 +343,26 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
realOutStream.Release();
outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
if (item->IsLink())
{
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
}
Int32 opRes = NExtract::NOperationResult::kOK;
if (item->IsSparse())
opRes = NExtract::NOperationResult::kUnSupportedMethod;
else
{
if (!seqMode)
if (item->IsLink())
{
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Length()));
}
streamSpec->Init(item->GetPackSize());
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
else
{
if (!seqMode)
{
RINOK(_stream->Seek(item->GetDataPosition(), STREAM_SEEK_SET, NULL));
}
streamSpec->Init(item->GetPackSizeAligned());
RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
}
if (outStreamSpec->GetRem() != 0)
opRes = NExtract::NOperationResult::kDataError;
}
if (seqMode)
{
@@ -359,9 +370,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
_curIndex++;
}
outStreamSpec->ReleaseStream();
RINOK(extractCallback->SetOperationResult(outStreamSpec->GetRem() == 0 ?
NExtract::NOperationResult::kOK:
NExtract::NOperationResult::kDataError));
RINOK(extractCallback->SetOperationResult(opRes));
}
return S_OK;
COM_TRY_END
@@ -371,6 +380,8 @@ 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;
@@ -379,7 +390,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
*stream = streamTemp.Detach();
return S_OK;
}
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream);
COM_TRY_END
}

View File

@@ -32,6 +32,7 @@ class CHandler:
UInt64 _headersSize;
bool _phySizeDefined;
AString _errorMessage;
bool _isSparse;
NCompress::CCopyCoder *copyCoderSpec;
CMyComPtr<ICompressCoder> copyCoder;

View File

@@ -37,7 +37,7 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
IArchiveUpdateCallback *callback)
{
COM_TRY_BEGIN
if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)
if ((_stream && (!_errorMessage.IsEmpty() || _isSparse)) || _seqStream)
return E_NOTIMPL;
CObjectVector<CUpdateItem> updateItems;
for (UInt32 i = 0; i < numItems; i++)
@@ -81,11 +81,11 @@ STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numIt
NCOM::CPropVariant prop;
RINOK(callback->GetProperty(i, kpidMTime, &prop));
if (prop.vt == VT_EMPTY)
ui.Time = 0;
ui.MTime = 0;
else if (prop.vt != VT_FILETIME)
return E_INVALIDARG;
else if (!NTime::FileTimeToUnixTime(prop.filetime, ui.Time))
ui.Time = 0;
else
ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
}
{
NCOM::CPropVariant prop;

View File

@@ -84,6 +84,7 @@ namespace NFileHeader
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.

View File

@@ -63,6 +63,31 @@ static void ReadString(const char *s, int size, AString &result)
result = temp;
}
static bool ParseInt64(const char *p, Int64 &val)
{
UInt32 h = GetBe32(p);
val = GetBe64(p + 4);
if (h == (UInt32)1 << 31)
return ((val >> 63) & 1) == 0;
if (h == (UInt32)(Int32)-1)
return ((val >> 63) & 1) != 0;
UInt64 uv;
bool res = OctalToNumber(p, 12, uv);
val = uv;
return res;
}
static bool ParseSize(const char *p, UInt64 &val)
{
if (GetBe32(p) == (UInt32)1 << 31)
{
// GNU extension
val = GetBe64(p + 4);
return ((val >> 63) & 1) == 0;
}
return OctalToNumber(p, 12, val);
}
static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemEx &item, AString &error)
{
char buf[NFileHeader::kRecordSize];
@@ -105,17 +130,10 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
if (!OctalToNumber32(p, 8, item.UID)) item.UID = 0; p += 8;
if (!OctalToNumber32(p, 8, item.GID)) item.GID = 0; p += 8;
if (GetBe32(p) == (UInt32)1 << 31)
{
// GNU extension
item.Size = GetBe64(p + 4);
}
else
{
RIF(OctalToNumber(p, 12, item.Size));
}
RIF(ParseSize(p, item.PackSize));
item.Size = item.PackSize;
p += 12;
RIF(OctalToNumber32(p, 12, item.MTime)); p += 12;
RIF(ParseInt64(p, item.MTime)); p += 12;
UInt32 checkSum;
RIF(OctalToNumber32(p, 8, checkSum));
@@ -141,7 +159,36 @@ static HRESULT GetNextItemReal(ISequentialInStream *stream, bool &filled, CItemE
item.Name = prefix + AString('/') + item.Name;
if (item.LinkFlag == NFileHeader::NLinkFlag::kLink)
{
item.PackSize = 0;
item.Size = 0;
}
else if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse)
{
if (buf[482] != 0)
return S_FALSE;
RIF(ParseSize(buf + 483, item.Size));
p = buf + 386;
UInt64 min = 0;
for (int i = 0; i < 4; i++, p += 24)
{
if (GetBe32(p) == 0)
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;
if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0)
return S_FALSE;
min = sb.Offset + sb.Size;
if (min < sb.Offset)
return S_FALSE;
}
if (min > item.Size)
return S_FALSE;
}
UInt32 checkSumReal = 0;
for (int i = 0; i < NFileHeader::kRecordSize; i++)
@@ -178,26 +225,39 @@ HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &item, AStri
if (item.Name.Compare(NFileHeader::kLongLink) != 0 &&
item.Name.Compare(NFileHeader::kLongLink2) != 0)
return S_FALSE;
if (item.Size > (1 << 14))
if (item.PackSize > (1 << 14))
return S_FALSE;
int packSize = (int)item.GetPackSize();
int packSize = (int)item.GetPackSizeAligned();
char *buf = name->GetBuffer(packSize);
RINOK(ReadStream_FALSE(stream, buf, packSize));
item.HeaderSize += packSize;
buf[(size_t)item.Size] = '\0';
buf[(size_t)item.PackSize] = '\0';
name->ReleaseBuffer();
continue;
}
if (item.LinkFlag == 'g' || item.LinkFlag == 'x' || item.LinkFlag == 'X')
switch (item.LinkFlag)
{
// pax Extended Header
case 'g':
case 'x':
case 'X':
{
// pax Extended Header
break;
}
case NFileHeader::NLinkFlag::kDumpDir:
{
break;
// GNU Extensions to the Archive Format
}
case NFileHeader::NLinkFlag::kSparse:
{
break;
// GNU Extensions to the Archive Format
}
default:
if (item.LinkFlag > '7' || (item.LinkFlag < '0' && item.LinkFlag != 0))
return S_FALSE;
}
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;

View File

@@ -10,15 +10,22 @@
namespace NArchive {
namespace NTar {
struct CSparseBlock
{
UInt64 Offset;
UInt64 Size;
};
struct CItem
{
AString Name;
UInt64 PackSize;
UInt64 Size;
Int64 MTime;
UInt32 Mode;
UInt32 UID;
UInt32 GID;
UInt32 MTime;
UInt32 DeviceMajor;
UInt32 DeviceMinor;
@@ -31,7 +38,10 @@ struct CItem
bool DeviceMajorDefined;
bool DeviceMinorDefined;
CRecordVector<CSparseBlock> SparseBlocks;
bool IsLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymbolicLink && (Size == 0); }
bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
UInt64 GetUnpackSize() const { return IsLink() ? LinkName.Length() : Size; }
bool IsDir() const
@@ -56,15 +66,16 @@ struct CItem
return true;
}
UInt64 GetPackSize() const { return (Size + 0x1FF) & (~((UInt64)0x1FF)); }
UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
};
struct CItemEx: public CItem
{
UInt64 HeaderPos;
unsigned HeaderSize;
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
UInt64 GetFullSize() const { return HeaderSize + Size; }
UInt64 GetFullSize() const { return HeaderSize + PackSize; }
};
}}

View File

@@ -47,7 +47,7 @@ static bool MakeOctalString8(char *s, UInt32 value)
if (tempString.Length() >= kMaxSize)
return false;
int numSpaces = kMaxSize - (tempString.Length() + 1);
for(int i = 0; i < numSpaces; i++)
for (int i = 0; i < numSpaces; i++)
s[i] = ' ';
MyStringCopy(s + numSpaces, (const char *)tempString);
return true;
@@ -55,7 +55,7 @@ static bool MakeOctalString8(char *s, UInt32 value)
static void MakeOctalString12(char *s, UInt64 value)
{
AString tempString = MakeOctalString(value);
AString tempString = MakeOctalString(value);
const int kMaxSize = 12;
if (tempString.Length() > kMaxSize)
{
@@ -67,11 +67,23 @@ static void MakeOctalString12(char *s, UInt64 value)
return;
}
int numSpaces = kMaxSize - tempString.Length();
for(int i = 0; i < numSpaces; i++)
for (int i = 0; i < numSpaces; i++)
s[i] = ' ';
memmove(s + numSpaces, (const char *)tempString, tempString.Length());
}
static void MakeOctalString12_From_Int64(char *s, Int64 value)
{
if (value >= 0)
{
MakeOctalString12(s, value);
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);
}
static bool CopyString(char *dest, const AString &src, int maxSize)
{
if (src.Length() >= maxSize)
@@ -100,8 +112,8 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;
RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;
MakeOctalString12(cur, item.Size); cur += 12;
MakeOctalString12(cur, item.MTime); cur += 12;
MakeOctalString12(cur, item.PackSize); cur += 12;
MakeOctalString12_From_Int64(cur, item.MTime); cur += 12;
memmove(cur, NFileHeader::kCheckSumBlanks, 8);
cur += 8;
@@ -130,7 +142,7 @@ HRESULT COutArchive::WriteHeaderReal(const CItem &item)
UInt32 checkSumReal = 0;
for(i = 0; i < NFileHeader::kRecordSize; i++)
for (i = 0; i < NFileHeader::kRecordSize; i++)
checkSumReal += Byte(record[i]);
RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal));
@@ -146,7 +158,7 @@ HRESULT COutArchive::WriteHeader(const CItem &item)
CItem modifiedItem = item;
int nameStreamSize = nameSize + 1;
modifiedItem.Size = nameStreamSize;
modifiedItem.PackSize = nameStreamSize;
modifiedItem.LinkFlag = 'L';
modifiedItem.Name = NFileHeader::kLongLink;
modifiedItem.LinkName.Empty();

View File

@@ -48,7 +48,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
complexity = 0;
for(i = 0; i < updateItems.Size(); i++)
for (i = 0; i < updateItems.Size(); i++)
{
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
@@ -64,14 +64,14 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (ui.IsDir)
{
item.LinkFlag = NFileHeader::NLinkFlag::kDirectory;
item.Size = 0;
item.PackSize = 0;
}
else
{
item.LinkFlag = NFileHeader::NLinkFlag::kNormal;
item.Size = ui.Size;
item.PackSize = ui.Size;
}
item.MTime = ui.Time;
item.MTime = ui.MTime;
item.DeviceMajorDefined = false;
item.DeviceMinorDefined = false;
item.UID = 0;
@@ -83,12 +83,12 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (ui.NewData)
{
item.Size = ui.Size;
if (item.Size == (UInt64)(Int64)-1)
item.PackSize = ui.Size;
if (ui.Size == (UInt64)(Int64)-1)
return E_INVALIDARG;
}
else
item.Size = inputItems[ui.IndexInArchive].Size;
item.PackSize = inputItems[ui.IndexInArchive].PackSize;
if (ui.NewData)
{
@@ -101,9 +101,9 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
if (!ui.IsDir)
{
RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != item.Size)
if (copyCoderSpec->TotalSize != item.PackSize)
return E_FAIL;
RINOK(outArchive.FillDataResidual(item.Size));
RINOK(outArchive.FillDataResidual(item.PackSize));
}
}
complexity += ui.Size;
@@ -117,7 +117,7 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
{
RINOK(outArchive.WriteHeader(item));
RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL));
size = existItem.Size;
size = existItem.PackSize;
}
else
{
@@ -129,10 +129,12 @@ HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != size)
return E_FAIL;
RINOK(outArchive.FillDataResidual(existItem.Size));
RINOK(outArchive.FillDataResidual(existItem.PackSize));
complexity += size;
}
}
lps->InSize = lps->OutSize = complexity;
RINOK(lps->SetCur());
return outArchive.WriteFinishHeader();
}

View File

@@ -13,15 +13,15 @@ struct CUpdateItem
{
int IndexInArchive;
int IndexInClient;
UInt32 Time;
UInt32 Mode;
Int64 MTime;
UInt64 Size;
AString Name;
AString User;
AString Group;
UInt32 Mode;
bool NewData;
bool NewProps;
bool IsDir;
AString Name;
AString User;
AString Group;
};
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,