Пример #1
0
static void UpdatePropsFromStream(CUpdateItem &item, ISequentialInStream *fileInStream,
    IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity)
{
  CMyComPtr<IStreamGetProps> getProps;
  fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
  if (!getProps)
    return;

  FILETIME cTime, aTime, mTime;
  UInt64 size;
  // UInt32 attrib;
  if (getProps->GetProps(&size, &cTime, &aTime, &mTime, NULL) != S_OK)
    return;
  
  if (size != item.Size && size != (UInt64)(Int64)-1)
  {
    Int64 newComplexity = totalComplexity + ((Int64)size - (Int64)item.Size);
    if (newComplexity > 0)
    {
      totalComplexity = newComplexity;
      updateCallback->SetTotal(totalComplexity);
    }
    item.Size = size;
  }
  
  if (!IsZero_FILETIME(mTime))
  {
    item.Ntfs_MTime = mTime;
    FILETIME loc = { 0, 0 };
    if (FileTimeToLocalFileTime(&mTime, &loc))
    {
      item.Time = 0;
      NTime::FileTimeToDosTime(loc, item.Time);
    }
  }

  if (!IsZero_FILETIME(cTime)) item.Ntfs_CTime = cTime;
  if (!IsZero_FILETIME(aTime)) item.Ntfs_ATime = aTime;

  // item.Attrib = attrib;
}
Пример #2
0
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();
}