diff options
Diffstat (limited to 'CPP/7zip/Archive/Tar/TarHandler.cpp')
-rwxr-xr-x[-rw-r--r--] | CPP/7zip/Archive/Tar/TarHandler.cpp | 445 |
1 files changed, 358 insertions, 87 deletions
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp index 2f23dd85..bd04bd7d 100644..100755 --- a/CPP/7zip/Archive/Tar/TarHandler.cpp +++ b/CPP/7zip/Archive/Tar/TarHandler.cpp @@ -36,22 +36,34 @@ static const Byte kProps[] = kpidSize, kpidPackSize, kpidMTime, + kpidCTime, + kpidATime, kpidPosixAttrib, kpidUser, kpidGroup, + kpidUserId, + kpidGroupId, kpidSymLink, kpidHardLink, - kpidCharacts - // kpidLinkType + kpidCharacts, + kpidComment + , kpidDeviceMajor + , kpidDeviceMinor + // , kpidDevice + // , kpidHeadersSize // for debug + // , kpidOffset // for debug }; static const Byte kArcProps[] = { kpidHeadersSize, kpidCodePage, - kpidCharacts + kpidCharacts, + kpidComment }; +static const char *k_Characts_Prefix = "PREFIX"; + IMP_IInArchive_Props IMP_IInArchive_ArcProps @@ -60,14 +72,14 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) NCOM::CPropVariant prop; switch (propID) { - case kpidPhySize: if (_phySizeDefined) prop = _phySize; break; - case kpidHeadersSize: if (_phySizeDefined) prop = _headersSize; break; + case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break; + case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break; case kpidErrorFlags: { UInt32 flags = 0; if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc; - else switch (_error) + else switch (_arc._error) { case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break; case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break; @@ -82,7 +94,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidWarningFlags: { - if (_warning) + if (_arc._is_Warning) prop = kpv_ErrorFlags_HeadersError; break; } @@ -107,37 +119,38 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) case kpidCharacts: { - prop = _encodingCharacts.GetCharactsString(); + AString s; + if (_arc._are_Gnu) s.Add_OptSpaced("GNU"); + if (_arc._are_Posix) s.Add_OptSpaced("POSIX"); + if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM"); + if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix); + if (_arc._are_LongName) s.Add_OptSpaced("LongName"); + if (_arc._are_LongLink) s.Add_OptSpaced("LongLink"); + if (_arc._are_Pax) s.Add_OptSpaced("PAX"); + if (_arc._are_pax_path) s.Add_OptSpaced("path"); + if (_arc._are_pax_link) s.Add_OptSpaced("linkpath"); + if (_arc._are_mtime) s.Add_OptSpaced("mtime"); + if (_arc._are_atime) s.Add_OptSpaced("atime"); + if (_arc._are_ctime) s.Add_OptSpaced("ctime"); + if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR"); + s.Add_OptSpaced(_encodingCharacts.GetCharactsString()); + prop = s; break; } - } - prop.Detach(value); - return S_OK; -} -HRESULT CHandler::ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &item) -{ - item.HeaderPos = _phySize; - EErrorType error; - HRESULT res = ReadItem(stream, filled, item, error); - if (error == k_ErrorType_Warning) - _warning = true; - else if (error != k_ErrorType_OK) - _error = error; - RINOK(res); - if (filled) - { - /* - if (item.IsSparse()) - _isSparse = true; - */ - if (item.IsPaxExtendedHeader()) - _thereIsPaxExtendedHeader = true; - if (item.IsThereWarning()) - _warning = true; + case kpidComment: + { + if (_arc.PaxGlobal_Defined) + { + AString s; + _arc.PaxGlobal.Print_To_String(s); + if (!s.IsEmpty()) + prop = s; + } + break; + } } - _phySize += item.HeaderSize; - _headersSize += item.HeaderSize; + prop.Detach(value); return S_OK; } @@ -199,16 +212,20 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL)); } - _phySizeDefined = true; + _arc._phySize_Defined = true; // bool utf8_OK = true; + _arc.SeqStream = stream; + _arc.InStream = stream; + _arc.OpenCallback = callback; + + CItemEx item; for (;;) { - CItemEx item; - bool filled; - RINOK(ReadItem2(stream, filled, item)); - if (!filled) + _arc.NumFiles = _items.Size(); + RINOK(_arc.ReadItem(item)); + if (!_arc.filled) break; _isArc = true; @@ -228,10 +245,10 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) _items.Add(item); - RINOK(stream->Seek((Int64)item.GetPackSizeAligned(), STREAM_SEEK_CUR, &_phySize)); - if (_phySize > endPos) + RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize)); + if (_arc._phySize > endPos) { - _error = k_ErrorType_UnexpectedEnd; + _arc._error = k_ErrorType_UnexpectedEnd; break; } /* @@ -241,6 +258,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) break; } */ + /* if (callback) { if (_items.Size() == 1) @@ -249,10 +267,11 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) } if ((_items.Size() & 0x3FF) == 0) { - UInt64 numFiles = _items.Size(); + const UInt64 numFiles = _items.Size(); RINOK(callback->SetCompleted(&numFiles, &_phySize)); } } + */ } /* @@ -266,7 +285,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) if (_items.Size() == 0) { - if (_error != k_ErrorType_OK) + if (_arc._error != k_ErrorType_OK) { _isArc = false; return S_FALSE; @@ -294,6 +313,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback) STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback) { COM_TRY_BEGIN + // for (int i = 0; i < 10; i++) // for debug { Close(); RINOK(Open2(stream, openArchiveCallback)); @@ -314,16 +334,11 @@ STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) STDMETHODIMP CHandler::Close() { _isArc = false; - _warning = false; - _error = k_ErrorType_OK; - _phySizeDefined = false; - _phySize = 0; - _headersSize = 0; + _arc.Clear(); + _curIndex = 0; _latestIsRead = false; - // _isSparse = false; - _thereIsPaxExtendedHeader = false; _encodingCharacts.Clear(); _items.Clear(); _seqStream.Release(); @@ -351,12 +366,12 @@ HRESULT CHandler::SkipTo(UInt32 index) { if (_latestIsRead) { - UInt64 packSize = _latestItem.GetPackSizeAligned(); + const UInt64 packSize = _latestItem.Get_PackSize_Aligned(); RINOK(copyCoderSpec->Code(_seqStream, NULL, &packSize, &packSize, NULL)); - _phySize += copyCoderSpec->TotalSize; + _arc._phySize += copyCoderSpec->TotalSize; if (copyCoderSpec->TotalSize != packSize) { - _error = k_ErrorType_UnexpectedEnd; + _arc._error = k_ErrorType_UnexpectedEnd; return S_FALSE; } _latestIsRead = false; @@ -364,11 +379,12 @@ HRESULT CHandler::SkipTo(UInt32 index) } else { - bool filled; - RINOK(ReadItem2(_seqStream, filled, _latestItem)); - if (!filled) + _arc.SeqStream = _seqStream; + _arc.InStream = NULL; + RINOK(_arc.ReadItem(_latestItem)); + if (!_arc.filled) { - _phySizeDefined = true; + _arc._phySize_Defined = true; return E_INVALIDARG; } _latestIsRead = true; @@ -390,6 +406,69 @@ void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant prop = dest; } + +static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop) +{ + UInt64 v; + if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v)) + return; + if (pt.Ns != 0) + v += pt.Ns / 100; + FILETIME ft; + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + prop.SetAsTimeFrom_FT_Prec_Ns100(ft, + k_PropVar_TimePrec_Base + pt.NumDigits, pt.Ns % 100); +} + + +#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10)))) + +static void AddByteToHex2(unsigned val, AString &s) +{ + unsigned t; + t = val >> 4; + s += ValToHex(t); + t = val & 0xF; + s += ValToHex(t); +} + +static void AddSpecCharToString(const char c, AString &s) +{ + if ((Byte)c <= 0x20 || (Byte)c > 127) + { + s += '['; + AddByteToHex2((Byte)(c), s); + s += ']'; + } + else + s += c; +} + +static void AddSpecUInt64(AString &s, const char *name, UInt64 v) +{ + if (v != 0) + { + s.Add_OptSpaced(name); + if (v > 1) + { + s += ':'; + s.Add_UInt64(v); + } + } +} + +static void AddSpecBools(AString &s, const char *name, bool b1, bool b2) +{ + if (b1) + { + s.Add_OptSpaced(name); + if (b2) + s += '*'; + } +} + + STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN @@ -413,49 +492,189 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val { 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; + case kpidSize: prop = item->Get_UnpackSize(); break; + case kpidPackSize: prop = item->Get_PackSize_Aligned(); break; case kpidMTime: - if (item->MTime != 0) + { + /* + // for debug: + PropVariant_SetFrom_UnixTime(prop, 1 << 30); + prop.wReserved1 = k_PropVar_TimePrec_Base + 1; + prop.wReserved2 = 12; + break; + */ + + if (item->PaxTimes.MTime.IsDefined()) + PaxTimeToProp(item->PaxTimes.MTime, prop); + else + // if (item->MTime != 0) { + // we allow (item->MTime == 0) FILETIME ft; - if (NTime::UnixTime64ToFileTime(item->MTime, ft)) - prop = ft; + if (NTime::UnixTime64_To_FileTime(item->MTime, ft)) + { + unsigned prec = k_PropVar_TimePrec_Unix; + if (item->MTime_IsBin) + { + /* we report here that it's Int64-UnixTime + instead of basic UInt32-UnixTime range */ + prec = k_PropVar_TimePrec_Base; + } + prop.SetAsTimeFrom_FT_Prec(ft, prec); + } } break; + } + case kpidATime: + if (item->PaxTimes.ATime.IsDefined()) + PaxTimeToProp(item->PaxTimes.ATime, prop); + break; + case kpidCTime: + if (item->PaxTimes.CTime.IsDefined()) + PaxTimeToProp(item->PaxTimes.CTime, prop); + break; case kpidPosixAttrib: prop = item->Get_Combined_Mode(); 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; + + case kpidUser: + if (!item->User.IsEmpty()) + TarStringToUnicode(item->User, prop); + break; + case kpidGroup: + if (!item->Group.IsEmpty()) + TarStringToUnicode(item->Group, prop); + break; + + case kpidUserId: + // if (item->UID != 0) + prop = (UInt32)item->UID; + break; + case kpidGroupId: + // if (item->GID != 0) + prop = (UInt32)item->GID; + break; + + case kpidDeviceMajor: + if (item->DeviceMajor_Defined) + // if (item->DeviceMajor != 0) + prop = (UInt32)item->DeviceMajor; + break; + + case kpidDeviceMinor: + if (item->DeviceMinor_Defined) + // if (item->DeviceMinor != 0) + prop = (UInt32)item->DeviceMinor; + break; + /* + case kpidDevice: + if (item->DeviceMajor_Defined) + if (item->DeviceMinor_Defined) + prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor); + break; + */ + + case kpidSymLink: + if (item->Is_SymLink()) + if (!item->LinkName.IsEmpty()) + TarStringToUnicode(item->LinkName, prop); + break; + case kpidHardLink: + if (item->Is_HardLink()) + if (!item->LinkName.IsEmpty()) + TarStringToUnicode(item->LinkName, prop); + break; + case kpidCharacts: { - AString s = item->EncodingCharacts.GetCharactsString(); - if (item->IsThereWarning()) + AString s; { s.Add_Space_if_NotEmpty(); - s += "HEADER_ERROR"; + AddSpecCharToString(item->LinkFlag, s); } - prop = s; + if (item->IsMagic_GNU()) + s.Add_OptSpaced("GNU"); + else if (item->IsMagic_Posix_ustar_00()) + s.Add_OptSpaced("POSIX"); + else + { + s.Add_Space_if_NotEmpty(); + for (unsigned i = 0; i < sizeof(item->Magic); i++) + AddSpecCharToString(item->Magic[i], s); + } + + if (item->IsSignedChecksum) + s.Add_OptSpaced("SignedChecksum"); + + if (item->Prefix_WasUsed) + s.Add_OptSpaced(k_Characts_Prefix); + + s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString()); + + // AddSpecUInt64(s, "LongName", item->Num_LongName_Records); + // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records); + AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2); + AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2); + + if (item->MTime_IsBin) + s.Add_OptSpaced("bin_mtime"); + if (item->PackSize_IsBin) + s.Add_OptSpaced("bin_psize"); + if (item->Size_IsBin) + s.Add_OptSpaced("bin_size"); + + AddSpecUInt64(s, "PAX", item->Num_Pax_Records); + + if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime"); + if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime"); + if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime"); + + if (item->pax_path_WasUsed) + s.Add_OptSpaced("pax_path"); + if (item->pax_link_WasUsed) + s.Add_OptSpaced("pax_linkpath"); + if (item->pax_size_WasUsed) + s.Add_OptSpaced("pax_size"); + + if (item->IsThereWarning()) + s.Add_OptSpaced("WARNING"); + if (item->HeaderError) + s.Add_OptSpaced("ERROR"); + if (item->Pax_Error) + s.Add_OptSpaced("PAX_error"); + if (!item->PaxExtra.RawLines.IsEmpty()) + s.Add_OptSpaced("PAX_unsupported_line"); + if (item->Pax_Overflow) + s.Add_OptSpaced("PAX_overflow"); + if (!s.IsEmpty()) + prop = s; break; } + case kpidComment: + { + AString s; + item->PaxExtra.Print_To_String(s); + if (!s.IsEmpty()) + prop = s; + break; + } + // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug + // case kpidOffset: prop = item->HeaderPos; break; // for debug } prop.Detach(value); return S_OK; COM_TRY_END } + HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN ISequentialInStream *stream = _seqStream; - bool seqMode = (_stream == NULL); + const bool seqMode = (_stream == NULL); if (!seqMode) stream = _stream; - bool allFilesMode = (numItems == (UInt32)(Int32)-1); + const bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = _items.Size(); if (_stream && numItems == 0) @@ -463,7 +682,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]].GetUnpackSize(); + totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize(); extractCallback->SetTotal(totalSize); UInt64 totalPackSize; @@ -503,9 +722,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, item = &_items[index]; RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); - UInt64 unpackSize = item->GetUnpackSize(); + const UInt64 unpackSize = item->Get_UnpackSize(); totalSize += unpackSize; - totalPackSize += item->GetPackSizeAligned(); + totalPackSize += item->Get_PackSize_Aligned(); if (item->IsDir()) { RINOK(extractCallback->PrepareOperation(askMode)); @@ -539,7 +758,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 opRes = NExtract::NOperationResult::kOK; CMyComPtr<ISequentialInStream> inStream2; - if (!item->IsSparse()) + if (!item->Is_Sparse()) inStream2 = inStream; else { @@ -549,7 +768,7 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, } { - if (item->IsSymLink()) + if (item->Is_SymLink()) { RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len())); } @@ -557,9 +776,9 @@ HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems, { if (!seqMode) { - RINOK(_stream->Seek((Int64)item->GetDataPosition(), STREAM_SEEK_SET, NULL)); + RINOK(_stream->Seek((Int64)item->Get_DataPos(), STREAM_SEEK_SET, NULL)); } - streamSpec->Init(item->GetPackSizeAligned()); + streamSpec->Init(item->Get_PackSize_Aligned()); RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress)); } if (outStreamSpec->GetRem() != 0) @@ -628,7 +847,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize) unsigned left = 0, right = item.SparseBlocks.Size(); for (;;) { - unsigned mid = (left + right) / 2; + const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2); if (mid == left) break; if (_virtPos < item.SparseBlocks[mid].Offset) @@ -648,7 +867,7 @@ STDMETHODIMP CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize) UInt64 phyPos = PhyOffsets[left] + relat; if (_needStartSeek || _phyPos != phyPos) { - RINOK(Handler->_stream->Seek((Int64)(item.GetDataPosition() + phyPos), STREAM_SEEK_SET, NULL)); + RINOK(Handler->_stream->Seek((Int64)(item.Get_DataPos() + phyPos), STREAM_SEEK_SET, NULL)); _needStartSeek = false; _phyPos = phyPos; } @@ -698,7 +917,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) const CItemEx &item = _items[index]; - if (item.IsSparse()) + if (item.Is_Sparse()) { CSparseStream *streamSpec = new CSparseStream; CMyComPtr<IInStream> streamTemp = streamSpec; @@ -718,24 +937,30 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) return S_OK; } - if (item.IsSymLink()) + if (item.Is_SymLink()) { Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream); return S_OK; } - return CreateLimitedInStream(_stream, item.GetDataPosition(), item.PackSize, stream); + return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream); COM_TRY_END } + void CHandler::Init() { _forceCodePage = false; _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP; - _thereIsPaxExtendedHeader = false; + _posixMode = false; + _posixMode_WasForced = false; + // TimeOptions.Clear(); + _handlerTimeOptions.Init(); + // _handlerTimeOptions.Write_MTime.Val = true; // it's default already } + STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) { Init(); @@ -768,8 +993,54 @@ STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVAR else if (name.IsPrefixedBy_Ascii_NoCase("memuse")) { } + else if (name.IsEqualTo("m")) + { + if (prop.vt != VT_BSTR) + return E_INVALIDARG; + const UString s = prop.bstrVal; + if (s.IsEqualTo_Ascii_NoCase("pax") || + s.IsEqualTo_Ascii_NoCase("posix")) + _posixMode = true; + else if (s.IsEqualTo_Ascii_NoCase("gnu")) + _posixMode = false; + else + return E_INVALIDARG; + _posixMode_WasForced = true; + } else + { + /* + if (name.IsPrefixedBy_Ascii_NoCase("td")) + { + name.Delete(0, 3); + if (prop.vt == VT_EMPTY) + { + if (name.IsEqualTo_Ascii_NoCase("n")) + { + // TimeOptions.UseNativeDigits = true; + } + else if (name.IsEqualTo_Ascii_NoCase("r")) + { + // TimeOptions.RemoveZeroDigits = true; + } + else + return E_INVALIDARG; + } + else + { + UInt32 numTimeDigits = 0; + RINOK(ParsePropToUInt32(name, prop, numTimeDigits)); + TimeOptions.NumDigits_WasForced = true; + TimeOptions.NumDigits = numTimeDigits; + } + } + */ + bool processed = false; + RINOK(_handlerTimeOptions.Parse(name, prop, processed)); + if (processed) + continue; return E_INVALIDARG; + } } return S_OK; } |