// 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 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 } }}