HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CObjectVector<NArchive::NTar::CItemEx> &inputItems, const CObjectVector<CUpdateItemInfo> &updateItems, IArchiveUpdateCallback *updateCallback) { COutArchive outArchive; outArchive.Create(outStream); UInt64 complexity = 0; int i; for(i = 0; i < updateItems.Size(); i++) { const CUpdateItemInfo &updateItem = updateItems[i]; if (updateItem.NewData) complexity += updateItem.Size; else complexity += inputItems[updateItem.IndexInArchive].GetFullSize(); complexity += kOneItemComplexity; } RINOK(updateCallback->SetTotal(complexity)); complexity = 0; for(i = 0; i < updateItems.Size(); i++) { RINOK(updateCallback->SetCompleted(&complexity)); CLocalProgress *localProgressSpec = new CLocalProgress; CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec; localProgressSpec->Init(updateCallback, true); CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo; CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec; localCompressProgressSpec->Init(localProgress, &complexity, NULL); const CUpdateItemInfo &updateItem = updateItems[i]; CItem item; if (updateItem.NewProperties) { item.Mode = 0777; item.Name = (updateItem.Name); if (updateItem.IsDirectory) { item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; item.Size = 0; } else { item.LinkFlag = NFileHeader::NLinkFlag::kNormal; item.Size = updateItem.Size; } item.ModificationTime = updateItem.Time; item.DeviceMajorDefined = false; item.DeviceMinorDefined = false; item.UID = 0; item.GID = 0; memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8); } else { const CItemEx &existItemInfo = inputItems[updateItem.IndexInArchive]; item = existItemInfo; } if (updateItem.NewData) { item.Size = updateItem.Size; if (item.Size == UInt64(Int64(-1))) return E_INVALIDARG; } else { const CItemEx &existItemInfo = inputItems[updateItem.IndexInArchive]; item.Size = existItemInfo.Size; } if (updateItem.NewData) { CMyComPtr<ISequentialInStream> fileInStream; HRESULT res = updateCallback->GetStream(updateItem.IndexInClient, &fileInStream); if (res != S_FALSE) { RINOK(res); RINOK(outArchive.WriteHeader(item)); if (!updateItem.IsDirectory) { UInt64 totalSize; RINOK(CopyBlock(fileInStream, outStream, compressProgress, &totalSize)); if (totalSize != item.Size) return E_FAIL; RINOK(outArchive.FillDataResidual(item.Size)); } } complexity += updateItem.Size; RINOK(updateCallback->SetOperationResult( NArchive::NUpdate::NOperationResult::kOK)); } else { CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec); const CItemEx &existItemInfo = inputItems[updateItem.IndexInArchive]; if (updateItem.NewProperties) { RINOK(outArchive.WriteHeader(item)); RINOK(inStream->Seek(existItemInfo.GetDataPosition(), STREAM_SEEK_SET, NULL)); streamSpec->Init(inStream, existItemInfo.Size); } else { RINOK(inStream->Seek(existItemInfo.HeaderPosition, STREAM_SEEK_SET, NULL)); streamSpec->Init(inStream, existItemInfo.GetFullSize()); } RINOK(CopyBlock(inStreamLimited, outStream, compressProgress)); RINOK(outArchive.FillDataResidual(existItemInfo.Size)); complexity += existItemInfo.GetFullSize(); } complexity += kOneItemComplexity; } return outArchive.WriteFinishHeader(); }
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; unsigned i; for (i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) complexity += ui.Size; else complexity += inputItems[ui.IndexInArchive].GetFullSize(); } RINOK(updateCallback->SetTotal(complexity)); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec); streamSpec->SetStream(inStream); complexity = 0; for (i = 0; i < updateItems.Size(); i++) { lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); const CUpdateItem &ui = updateItems[i]; CItem item; if (ui.NewProps) { item.Mode = ui.Mode; item.Name = ui.Name; item.User = ui.User; item.Group = ui.Group; if (ui.IsDir) { item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; item.PackSize = 0; } else { item.LinkFlag = NFileHeader::NLinkFlag::kNormal; item.PackSize = ui.Size; } item.MTime = ui.MTime; item.DeviceMajorDefined = false; item.DeviceMinorDefined = false; item.UID = 0; item.GID = 0; 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; CMyComPtr<ISequentialInStream> fileInStream; bool needWrite = true; if (!symLink.IsEmpty()) { 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 (fileInStream) { RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); outArchive.Pos += copyCoderSpec->TotalSize; if (copyCoderSpec->TotalSize != item.PackSize) { 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 += item.PackSize; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } else { const CItemEx &existItem = inputItems[ui.IndexInArchive]; 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; } else { RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL)); size = existItem.GetFullSize(); } streamSpec->Init(size); RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != size) return E_FAIL; outArchive.Pos += size; RINOK(outArchive.FillDataResidual(existItem.PackSize)); complexity += size; } } lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); return outArchive.WriteFinishHeader(); }
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream, const CObjectVector<NArchive::NTar::CItemEx> &inputItems, const CObjectVector<CUpdateItem> &updateItems, IArchiveUpdateCallback *updateCallback) { COutArchive outArchive; outArchive.Create(outStream); UInt64 complexity = 0; int i; for(i = 0; i < updateItems.Size(); i++) { const CUpdateItem &ui = updateItems[i]; if (ui.NewData) complexity += ui.Size; else complexity += inputItems[ui.IndexInArchive].GetFullSize(); } RINOK(updateCallback->SetTotal(complexity)); NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; CLocalProgress *lps = new CLocalProgress; CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(updateCallback, true); CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; CMyComPtr<CLimitedSequentialInStream> inStreamLimited(streamSpec); streamSpec->SetStream(inStream); complexity = 0; for (i = 0; i < updateItems.Size(); i++) { lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); const CUpdateItem &ui = updateItems[i]; CItem item; if (ui.NewProps) { item.Mode = ui.Mode; item.Name = ui.Name; item.User = ui.User; item.Group = ui.Group; if (ui.IsDir) { item.LinkFlag = NFileHeader::NLinkFlag::kDirectory; item.PackSize = 0; } else { item.LinkFlag = NFileHeader::NLinkFlag::kNormal; item.PackSize = ui.Size; } item.MTime = ui.MTime; item.DeviceMajorDefined = false; item.DeviceMinorDefined = false; item.UID = 0; item.GID = 0; memmove(item.Magic, NFileHeader::NMagic::kEmpty, 8); } else item = inputItems[ui.IndexInArchive]; if (ui.NewData) { item.PackSize = 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) { RINOK(res); RINOK(outArchive.WriteHeader(item)); if (!ui.IsDir) { RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != item.PackSize) return E_FAIL; RINOK(outArchive.FillDataResidual(item.PackSize)); } } complexity += ui.Size; RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK)); } else { const CItemEx &existItem = inputItems[ui.IndexInArchive]; UInt64 size; if (ui.NewProps) { RINOK(outArchive.WriteHeader(item)); RINOK(inStream->Seek(existItem.GetDataPosition(), STREAM_SEEK_SET, NULL)); size = existItem.PackSize; } else { RINOK(inStream->Seek(existItem.HeaderPos, STREAM_SEEK_SET, NULL)); size = existItem.GetFullSize(); } streamSpec->Init(size); RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)); if (copyCoderSpec->TotalSize != size) return E_FAIL; RINOK(outArchive.FillDataResidual(existItem.PackSize)); complexity += size; } } lps->InSize = lps->OutSize = complexity; RINOK(lps->SetCur()); return outArchive.WriteFinishHeader(); }