175 lines
4.4 KiB
C++
175 lines
4.4 KiB
C++
// TarHandlerOut.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../../Common/ComTry.h"
|
|
#include "../../../Common/Defs.h"
|
|
#include "../../../Common/MyLinux.h"
|
|
#include "../../../Common/StringConvert.h"
|
|
#include "../../../Common/UTFConvert.h"
|
|
|
|
#include "../../../Windows/PropVariant.h"
|
|
#include "../../../Windows/TimeUtils.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;
|
|
}
|
|
|
|
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId,
|
|
AString &res, UINT codePage, bool convertSlash = false)
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
RINOK(callback->GetProperty(index, propId, &prop));
|
|
|
|
if (prop.vt == VT_BSTR)
|
|
{
|
|
UString s = prop.bstrVal;
|
|
if (convertSlash)
|
|
s = NItemName::MakeLegalName(s);
|
|
|
|
if (codePage == CP_UTF8)
|
|
{
|
|
ConvertUnicodeToUTF8(s, res);
|
|
// if (!ConvertUnicodeToUTF8(s, res)) // return E_INVALIDARG;
|
|
}
|
|
else
|
|
UnicodeStringToMultiByte2(res, s, codePage);
|
|
}
|
|
else if (prop.vt != VT_EMPTY)
|
|
return E_INVALIDARG;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// sort old files with original order.
|
|
|
|
static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
|
|
{
|
|
const CUpdateItem &u1 = *(*((const CUpdateItem **)p1));
|
|
const CUpdateItem &u2 = *(*((const CUpdateItem **)p2));
|
|
if (!u1.NewProps)
|
|
{
|
|
if (u2.NewProps)
|
|
return -1;
|
|
return MyCompare(u1.IndexInArc, u2.IndexInArc);
|
|
}
|
|
if (!u2.NewProps)
|
|
return 1;
|
|
return MyCompare(u1.IndexInClient, u2.IndexInClient);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
|
IArchiveUpdateCallback *callback)
|
|
{
|
|
COM_TRY_BEGIN
|
|
|
|
if ((_stream && (_error != k_ErrorType_OK /* || _isSparse */)) || _seqStream)
|
|
return E_NOTIMPL;
|
|
CObjectVector<CUpdateItem> updateItems;
|
|
UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
|
|
|
|
for (UInt32 i = 0; i < numItems; i++)
|
|
{
|
|
CUpdateItem ui;
|
|
Int32 newData;
|
|
Int32 newProps;
|
|
UInt32 indexInArc;
|
|
|
|
if (!callback)
|
|
return E_FAIL;
|
|
|
|
RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc));
|
|
|
|
ui.NewProps = IntToBool(newProps);
|
|
ui.NewData = IntToBool(newData);
|
|
ui.IndexInArc = indexInArc;
|
|
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 =
|
|
MY_LIN_S_IRWXO
|
|
| MY_LIN_S_IRWXG
|
|
| MY_LIN_S_IRWXU
|
|
| (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
|
|
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.MTime = 0;
|
|
else if (prop.vt != VT_FILETIME)
|
|
return E_INVALIDARG;
|
|
else
|
|
ui.MTime = NTime::FileTimeToUnixTime64(prop.filetime);
|
|
}
|
|
|
|
RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, true));
|
|
if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
|
|
ui.Name += '/';
|
|
RINOK(GetPropString(callback, i, kpidUser, ui.User, codePage));
|
|
RINOK(GetPropString(callback, i, kpidGroup, ui.Group, codePage));
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
if (_thereIsPaxExtendedHeader)
|
|
{
|
|
// we restore original order of files, if there is pax header block
|
|
updateItems.Sort(CompareUpdateItems, NULL);
|
|
}
|
|
|
|
return UpdateArchive(_stream, outStream, _items, updateItems, codePage, callback);
|
|
|
|
COM_TRY_END
|
|
}
|
|
|
|
}}
|