| // TarHandlerOut.cpp |
| |
| #include "StdAfx.h" |
| |
| #include "Common/ComTry.h" |
| #include "Common/StringConvert.h" |
| |
| #include "Windows/PropVariant.h" |
| #include "Windows/Time.h" |
| |
| #include "TarHandler.h" |
| #include "TarUpdate.h" |
| |
| using namespace NWindows; |
| |
| namespace NArchive { |
| namespace NTar { |
| |
| STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) |
| { |
| *type = NFileTimeType::kUnix; |
| return S_OK; |
| } |
| |
| static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res) |
| { |
| NCOM::CPropVariant prop; |
| RINOK(callback->GetProperty(index, propId, &prop)); |
| if (prop.vt == VT_BSTR) |
| res = UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP); |
| else if (prop.vt != VT_EMPTY) |
| return E_INVALIDARG; |
| return S_OK; |
| } |
| |
| STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, |
| IArchiveUpdateCallback *callback) |
| { |
| COM_TRY_BEGIN |
| if ((_stream && !_errorMessage.IsEmpty()) || _seqStream) |
| return E_NOTIMPL; |
| CObjectVector<CUpdateItem> updateItems; |
| for (UInt32 i = 0; i < numItems; i++) |
| { |
| CUpdateItem ui; |
| Int32 newData; |
| Int32 newProps; |
| UInt32 indexInArchive; |
| if (!callback) |
| return E_FAIL; |
| RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); |
| ui.NewProps = IntToBool(newProps); |
| ui.NewData = IntToBool(newData); |
| ui.IndexInArchive = indexInArchive; |
| ui.IndexInClient = i; |
| |
| if (IntToBool(newProps)) |
| { |
| { |
| NCOM::CPropVariant prop; |
| RINOK(callback->GetProperty(i, kpidIsDir, &prop)); |
| if (prop.vt == VT_EMPTY) |
| ui.IsDir = false; |
| else if (prop.vt != VT_BOOL) |
| return E_INVALIDARG; |
| else |
| ui.IsDir = (prop.boolVal != VARIANT_FALSE); |
| } |
| |
| { |
| NCOM::CPropVariant prop; |
| RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop)); |
| if (prop.vt == VT_EMPTY) |
| ui.Mode = 0777 | (ui.IsDir ? 0040000 : 0100000); |
| else if (prop.vt != VT_UI4) |
| return E_INVALIDARG; |
| else |
| ui.Mode = prop.ulVal; |
| } |
| { |
| NCOM::CPropVariant prop; |
| RINOK(callback->GetProperty(i, kpidMTime, &prop)); |
| if (prop.vt == VT_EMPTY) |
| ui.Time = 0; |
| else if (prop.vt != VT_FILETIME) |
| return E_INVALIDARG; |
| else if (!NTime::FileTimeToUnixTime(prop.filetime, ui.Time)) |
| ui.Time = 0; |
| } |
| { |
| 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)); |
| } |
| if (IntToBool(newData)) |
| { |
| NCOM::CPropVariant prop; |
| RINOK(callback->GetProperty(i, kpidSize, &prop)); |
| if (prop.vt != VT_UI8) |
| return E_INVALIDARG; |
| ui.Size = prop.uhVal.QuadPart; |
| /* |
| // now we support GNU extension for big files |
| if (ui.Size >= ((UInt64)1 << 33)) |
| return E_INVALIDARG; |
| */ |
| } |
| updateItems.Add(ui); |
| } |
| return UpdateArchive(_stream, outStream, _items, updateItems, callback); |
| COM_TRY_END |
| } |
| |
| }} |