mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-14 22:11:38 -06:00
Normalize all the line endings
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,79 +1,79 @@
|
||||
// TarHandler.h
|
||||
|
||||
#ifndef __TAR_HANDLER_H
|
||||
#define __TAR_HANDLER_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "TarIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveOpenSeq,
|
||||
public IInArchiveGetStream,
|
||||
public ISetProperties,
|
||||
public IOutArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
private:
|
||||
UInt32 _curIndex;
|
||||
bool _latestIsRead;
|
||||
CItemEx _latestItem;
|
||||
|
||||
UInt64 _phySize;
|
||||
UInt64 _headersSize;
|
||||
bool _phySizeDefined;
|
||||
EErrorType _error;
|
||||
bool _warning;
|
||||
bool _isArc;
|
||||
|
||||
// bool _isSparse;
|
||||
bool _thereIsPaxExtendedHeader;
|
||||
|
||||
bool _forceCodePage;
|
||||
UInt32 _specifiedCodePage;
|
||||
UInt32 _curCodePage;
|
||||
UInt32 _openCodePage;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec;
|
||||
CMyComPtr<ICompressCoder> copyCoder;
|
||||
|
||||
HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
|
||||
HRESULT SkipTo(UInt32 index);
|
||||
void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const;
|
||||
public:
|
||||
MY_UNKNOWN_IMP5(
|
||||
IInArchive,
|
||||
IArchiveOpenSeq,
|
||||
IInArchiveGetStream,
|
||||
ISetProperties,
|
||||
IOutArchive
|
||||
)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IOutArchive(;)
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
|
||||
|
||||
void Init();
|
||||
CHandler();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// TarHandler.h
|
||||
|
||||
#ifndef __TAR_HANDLER_H
|
||||
#define __TAR_HANDLER_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "TarIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public IArchiveOpenSeq,
|
||||
public IInArchiveGetStream,
|
||||
public ISetProperties,
|
||||
public IOutArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
CObjectVector<CItemEx> _items;
|
||||
CMyComPtr<IInStream> _stream;
|
||||
CMyComPtr<ISequentialInStream> _seqStream;
|
||||
private:
|
||||
UInt32 _curIndex;
|
||||
bool _latestIsRead;
|
||||
CItemEx _latestItem;
|
||||
|
||||
UInt64 _phySize;
|
||||
UInt64 _headersSize;
|
||||
bool _phySizeDefined;
|
||||
EErrorType _error;
|
||||
bool _warning;
|
||||
bool _isArc;
|
||||
|
||||
// bool _isSparse;
|
||||
bool _thereIsPaxExtendedHeader;
|
||||
|
||||
bool _forceCodePage;
|
||||
UInt32 _specifiedCodePage;
|
||||
UInt32 _curCodePage;
|
||||
UInt32 _openCodePage;
|
||||
|
||||
NCompress::CCopyCoder *copyCoderSpec;
|
||||
CMyComPtr<ICompressCoder> copyCoder;
|
||||
|
||||
HRESULT ReadItem2(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo);
|
||||
HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
|
||||
HRESULT SkipTo(UInt32 index);
|
||||
void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const;
|
||||
public:
|
||||
MY_UNKNOWN_IMP5(
|
||||
IInArchive,
|
||||
IArchiveOpenSeq,
|
||||
IInArchiveGetStream,
|
||||
ISetProperties,
|
||||
IOutArchive
|
||||
)
|
||||
|
||||
INTERFACE_IInArchive(;)
|
||||
INTERFACE_IOutArchive(;)
|
||||
STDMETHOD(OpenSeq)(ISequentialInStream *stream);
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
|
||||
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
|
||||
|
||||
void Init();
|
||||
CHandler();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,176 +1,176 @@
|
||||
// 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)
|
||||
NItemName::ReplaceSlashes_OsToUnix(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 || _warning /* || _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;
|
||||
// FIXME : we can clear high file type bits to be more compatible with tars created by GNU TAR.
|
||||
// ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
|
||||
}
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
}}
|
||||
// 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)
|
||||
NItemName::ReplaceSlashes_OsToUnix(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 || _warning /* || _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;
|
||||
// FIXME : we can clear high file type bits to be more compatible with tars created by GNU TAR.
|
||||
// ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
|
||||
}
|
||||
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
// Archive/TarHeader.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "TarHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
namespace NFileHeader {
|
||||
|
||||
const char * const kLongLink = "././@LongLink";
|
||||
const char * const kLongLink2 = "@LongLink";
|
||||
|
||||
// The magic field is filled with this if uname and gname are valid.
|
||||
namespace NMagic
|
||||
{
|
||||
// const char * const kUsTar = "ustar"; // 5 chars
|
||||
// const char * const kGNUTar = "GNUtar "; // 7 chars and a null
|
||||
// const char * const kEmpty = "\0\0\0\0\0\0\0\0";
|
||||
const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
|
||||
}
|
||||
|
||||
}}}
|
||||
// Archive/TarHeader.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "TarHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
namespace NFileHeader {
|
||||
|
||||
const char * const kLongLink = "././@LongLink";
|
||||
const char * const kLongLink2 = "@LongLink";
|
||||
|
||||
// The magic field is filled with this if uname and gname are valid.
|
||||
namespace NMagic
|
||||
{
|
||||
// const char * const kUsTar = "ustar"; // 5 chars
|
||||
// const char * const kGNUTar = "GNUtar "; // 7 chars and a null
|
||||
// const char * const kEmpty = "\0\0\0\0\0\0\0\0";
|
||||
const char kUsTar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
// Archive/TarHeader.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_HEADER_H
|
||||
#define __ARCHIVE_TAR_HEADER_H
|
||||
|
||||
#include "../../../Common/MyTypes.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
namespace NFileHeader
|
||||
{
|
||||
const unsigned kRecordSize = 512;
|
||||
const unsigned kNameSize = 100;
|
||||
const unsigned kUserNameSize = 32;
|
||||
const unsigned kGroupNameSize = 32;
|
||||
const unsigned kPrefixSize = 155;
|
||||
|
||||
const unsigned kUstarMagic_Offset = 257;
|
||||
|
||||
/*
|
||||
struct CHeader
|
||||
{
|
||||
char Name[kNameSize];
|
||||
char Mode[8];
|
||||
char UID[8];
|
||||
char GID[8];
|
||||
char Size[12];
|
||||
char ModificationTime[12];
|
||||
char CheckSum[8];
|
||||
char LinkFlag;
|
||||
char LinkName[kNameSize];
|
||||
char Magic[8];
|
||||
char UserName[kUserNameSize];
|
||||
char GroupName[kGroupNameSize];
|
||||
char DeviceMajor[8];
|
||||
char DeviceMinor[8];
|
||||
char Prefix[155];
|
||||
};
|
||||
union CRecord
|
||||
{
|
||||
CHeader Header;
|
||||
Byte Padding[kRecordSize];
|
||||
};
|
||||
*/
|
||||
|
||||
namespace NLinkFlag
|
||||
{
|
||||
const char kOldNormal = 0; // Normal disk file, Unix compatible
|
||||
const char kNormal = '0'; // Normal disk file
|
||||
const char kHardLink = '1'; // Link to previously dumped file
|
||||
const char kSymLink = '2'; // Symbolic link
|
||||
const char kCharacter = '3'; // Character special file
|
||||
const char kBlock = '4'; // Block special file
|
||||
const char kDirectory = '5'; // Directory
|
||||
const char kFIFO = '6'; // FIFO special file
|
||||
const char kContiguous = '7'; // Contiguous file
|
||||
const char kGnu_LongLink = 'K';
|
||||
const char kGnu_LongName = 'L';
|
||||
const char kSparse = 'S';
|
||||
const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
|
||||
data: list of files created by the --incremental (-G) option
|
||||
Each file name is preceded by either
|
||||
- 'Y' (file should be in this archive)
|
||||
- 'N' (file is a directory, or is not stored in the archive.)
|
||||
Each file name is terminated by a null + an additional null after
|
||||
the last file name. */
|
||||
}
|
||||
|
||||
extern const char * const kLongLink; // = "././@LongLink";
|
||||
extern const char * const kLongLink2; // = "@LongLink";
|
||||
|
||||
namespace NMagic
|
||||
{
|
||||
// extern const char * const kUsTar; // = "ustar"; // 5 chars
|
||||
// extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null
|
||||
// extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0"
|
||||
extern const char kUsTar_00[8];
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// Archive/TarHeader.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_HEADER_H
|
||||
#define __ARCHIVE_TAR_HEADER_H
|
||||
|
||||
#include "../../../Common/MyTypes.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
namespace NFileHeader
|
||||
{
|
||||
const unsigned kRecordSize = 512;
|
||||
const unsigned kNameSize = 100;
|
||||
const unsigned kUserNameSize = 32;
|
||||
const unsigned kGroupNameSize = 32;
|
||||
const unsigned kPrefixSize = 155;
|
||||
|
||||
const unsigned kUstarMagic_Offset = 257;
|
||||
|
||||
/*
|
||||
struct CHeader
|
||||
{
|
||||
char Name[kNameSize];
|
||||
char Mode[8];
|
||||
char UID[8];
|
||||
char GID[8];
|
||||
char Size[12];
|
||||
char ModificationTime[12];
|
||||
char CheckSum[8];
|
||||
char LinkFlag;
|
||||
char LinkName[kNameSize];
|
||||
char Magic[8];
|
||||
char UserName[kUserNameSize];
|
||||
char GroupName[kGroupNameSize];
|
||||
char DeviceMajor[8];
|
||||
char DeviceMinor[8];
|
||||
char Prefix[155];
|
||||
};
|
||||
union CRecord
|
||||
{
|
||||
CHeader Header;
|
||||
Byte Padding[kRecordSize];
|
||||
};
|
||||
*/
|
||||
|
||||
namespace NLinkFlag
|
||||
{
|
||||
const char kOldNormal = 0; // Normal disk file, Unix compatible
|
||||
const char kNormal = '0'; // Normal disk file
|
||||
const char kHardLink = '1'; // Link to previously dumped file
|
||||
const char kSymLink = '2'; // Symbolic link
|
||||
const char kCharacter = '3'; // Character special file
|
||||
const char kBlock = '4'; // Block special file
|
||||
const char kDirectory = '5'; // Directory
|
||||
const char kFIFO = '6'; // FIFO special file
|
||||
const char kContiguous = '7'; // Contiguous file
|
||||
const char kGnu_LongLink = 'K';
|
||||
const char kGnu_LongName = 'L';
|
||||
const char kSparse = 'S';
|
||||
const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
|
||||
data: list of files created by the --incremental (-G) option
|
||||
Each file name is preceded by either
|
||||
- 'Y' (file should be in this archive)
|
||||
- 'N' (file is a directory, or is not stored in the archive.)
|
||||
Each file name is terminated by a null + an additional null after
|
||||
the last file name. */
|
||||
}
|
||||
|
||||
extern const char * const kLongLink; // = "././@LongLink";
|
||||
extern const char * const kLongLink2; // = "@LongLink";
|
||||
|
||||
namespace NMagic
|
||||
{
|
||||
// extern const char * const kUsTar; // = "ustar"; // 5 chars
|
||||
// extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null
|
||||
// extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0"
|
||||
extern const char kUsTar_00[8];
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +1,27 @@
|
||||
// TarIn.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_IN_H
|
||||
#define __ARCHIVE_TAR_IN_H
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
enum EErrorType
|
||||
{
|
||||
k_ErrorType_OK,
|
||||
k_ErrorType_Corrupted,
|
||||
k_ErrorType_UnexpectedEnd,
|
||||
k_ErrorType_Warning
|
||||
};
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error);
|
||||
|
||||
API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// TarIn.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_IN_H
|
||||
#define __ARCHIVE_TAR_IN_H
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
enum EErrorType
|
||||
{
|
||||
k_ErrorType_OK,
|
||||
k_ErrorType_Corrupted,
|
||||
k_ErrorType_UnexpectedEnd,
|
||||
k_ErrorType_Warning
|
||||
};
|
||||
|
||||
HRESULT ReadItem(ISequentialInStream *stream, bool &filled, CItemEx &itemInfo, EErrorType &error);
|
||||
|
||||
API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,126 +1,126 @@
|
||||
// TarItem.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_ITEM_H
|
||||
#define __ARCHIVE_TAR_ITEM_H
|
||||
|
||||
#include "../../../Common/MyLinux.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "TarHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
struct CSparseBlock
|
||||
{
|
||||
UInt64 Offset;
|
||||
UInt64 Size;
|
||||
};
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
UInt64 PackSize;
|
||||
UInt64 Size;
|
||||
Int64 MTime;
|
||||
|
||||
UInt32 Mode;
|
||||
UInt32 UID;
|
||||
UInt32 GID;
|
||||
UInt32 DeviceMajor;
|
||||
UInt32 DeviceMinor;
|
||||
|
||||
AString LinkName;
|
||||
AString User;
|
||||
AString Group;
|
||||
|
||||
char Magic[8];
|
||||
char LinkFlag;
|
||||
bool DeviceMajorDefined;
|
||||
bool DeviceMinorDefined;
|
||||
|
||||
CRecordVector<CSparseBlock> SparseBlocks;
|
||||
|
||||
bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
|
||||
bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
|
||||
bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
|
||||
UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; }
|
||||
bool IsPaxExtendedHeader() const
|
||||
{
|
||||
switch (LinkFlag)
|
||||
{
|
||||
case 'g':
|
||||
case 'x':
|
||||
case 'X': // Check it
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt32 Get_Combined_Mode() const
|
||||
{
|
||||
return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag();
|
||||
}
|
||||
|
||||
UInt32 Get_FileTypeMode_from_LinkFlag() const
|
||||
{
|
||||
switch (LinkFlag)
|
||||
{
|
||||
/*
|
||||
case NFileHeader::NLinkFlag::kDirectory:
|
||||
case NFileHeader::NLinkFlag::kDumpDir:
|
||||
return MY_LIN_S_IFDIR;
|
||||
*/
|
||||
case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
|
||||
case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
|
||||
case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
|
||||
case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
|
||||
// case return MY_LIN_S_IFSOCK;
|
||||
}
|
||||
|
||||
if (IsDir())
|
||||
return MY_LIN_S_IFDIR;
|
||||
return MY_LIN_S_IFREG;
|
||||
}
|
||||
|
||||
bool IsDir() const
|
||||
{
|
||||
switch (LinkFlag)
|
||||
{
|
||||
case NFileHeader::NLinkFlag::kDirectory:
|
||||
case NFileHeader::NLinkFlag::kDumpDir:
|
||||
return true;
|
||||
case NFileHeader::NLinkFlag::kOldNormal:
|
||||
case NFileHeader::NLinkFlag::kNormal:
|
||||
case NFileHeader::NLinkFlag::kSymLink:
|
||||
return NItemName::HasTailSlash(Name, CP_OEMCP);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsUstarMagic() const
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
|
||||
};
|
||||
|
||||
struct CItemEx: public CItem
|
||||
{
|
||||
UInt64 HeaderPos;
|
||||
unsigned HeaderSize;
|
||||
bool NameCouldBeReduced;
|
||||
bool LinkNameCouldBeReduced;
|
||||
|
||||
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
|
||||
UInt64 GetFullSize() const { return HeaderSize + PackSize; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// TarItem.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_ITEM_H
|
||||
#define __ARCHIVE_TAR_ITEM_H
|
||||
|
||||
#include "../../../Common/MyLinux.h"
|
||||
|
||||
#include "../Common/ItemNameUtils.h"
|
||||
|
||||
#include "TarHeader.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
struct CSparseBlock
|
||||
{
|
||||
UInt64 Offset;
|
||||
UInt64 Size;
|
||||
};
|
||||
|
||||
struct CItem
|
||||
{
|
||||
AString Name;
|
||||
UInt64 PackSize;
|
||||
UInt64 Size;
|
||||
Int64 MTime;
|
||||
|
||||
UInt32 Mode;
|
||||
UInt32 UID;
|
||||
UInt32 GID;
|
||||
UInt32 DeviceMajor;
|
||||
UInt32 DeviceMinor;
|
||||
|
||||
AString LinkName;
|
||||
AString User;
|
||||
AString Group;
|
||||
|
||||
char Magic[8];
|
||||
char LinkFlag;
|
||||
bool DeviceMajorDefined;
|
||||
bool DeviceMinorDefined;
|
||||
|
||||
CRecordVector<CSparseBlock> SparseBlocks;
|
||||
|
||||
bool IsSymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
|
||||
bool IsHardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
|
||||
bool IsSparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
|
||||
UInt64 GetUnpackSize() const { return IsSymLink() ? LinkName.Len() : Size; }
|
||||
bool IsPaxExtendedHeader() const
|
||||
{
|
||||
switch (LinkFlag)
|
||||
{
|
||||
case 'g':
|
||||
case 'x':
|
||||
case 'X': // Check it
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt32 Get_Combined_Mode() const
|
||||
{
|
||||
return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag();
|
||||
}
|
||||
|
||||
UInt32 Get_FileTypeMode_from_LinkFlag() const
|
||||
{
|
||||
switch (LinkFlag)
|
||||
{
|
||||
/*
|
||||
case NFileHeader::NLinkFlag::kDirectory:
|
||||
case NFileHeader::NLinkFlag::kDumpDir:
|
||||
return MY_LIN_S_IFDIR;
|
||||
*/
|
||||
case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
|
||||
case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
|
||||
case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
|
||||
case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
|
||||
// case return MY_LIN_S_IFSOCK;
|
||||
}
|
||||
|
||||
if (IsDir())
|
||||
return MY_LIN_S_IFDIR;
|
||||
return MY_LIN_S_IFREG;
|
||||
}
|
||||
|
||||
bool IsDir() const
|
||||
{
|
||||
switch (LinkFlag)
|
||||
{
|
||||
case NFileHeader::NLinkFlag::kDirectory:
|
||||
case NFileHeader::NLinkFlag::kDumpDir:
|
||||
return true;
|
||||
case NFileHeader::NLinkFlag::kOldNormal:
|
||||
case NFileHeader::NLinkFlag::kNormal:
|
||||
case NFileHeader::NLinkFlag::kSymLink:
|
||||
return NItemName::HasTailSlash(Name, CP_OEMCP);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsUstarMagic() const
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
if (Magic[i] != NFileHeader::NMagic::kUsTar_00[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
UInt64 GetPackSizeAligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
|
||||
};
|
||||
|
||||
struct CItemEx: public CItem
|
||||
{
|
||||
UInt64 HeaderPos;
|
||||
unsigned HeaderSize;
|
||||
bool NameCouldBeReduced;
|
||||
bool LinkNameCouldBeReduced;
|
||||
|
||||
UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
|
||||
UInt64 GetFullSize() const { return HeaderSize + PackSize; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,245 +1,245 @@
|
||||
// TarOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "TarOut.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
|
||||
{
|
||||
Pos += size;
|
||||
return WriteStream(m_Stream, data, size);
|
||||
}
|
||||
|
||||
static void MyStrNCpy(char *dest, const char *src, unsigned size)
|
||||
{
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
char c = src[i];
|
||||
dest[i] = c;
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool WriteOctal_8(char *s, UInt32 val)
|
||||
{
|
||||
const unsigned kNumDigits = 8 - 1;
|
||||
if (val >= ((UInt32)1 << (kNumDigits * 3)))
|
||||
return false;
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void WriteOctal_12(char *s, UInt64 val)
|
||||
{
|
||||
const unsigned kNumDigits = 12 - 1;
|
||||
if (val >= ((UInt64)1 << (kNumDigits * 3)))
|
||||
{
|
||||
// GNU extension;
|
||||
s[0] = (char)(Byte)0x80;
|
||||
s[1] = s[2] = s[3] = 0;
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
return;
|
||||
}
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteOctal_12_Signed(char *s, Int64 val)
|
||||
{
|
||||
if (val >= 0)
|
||||
{
|
||||
WriteOctal_12(s, val);
|
||||
return;
|
||||
}
|
||||
s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
}
|
||||
|
||||
static bool CopyString(char *dest, const AString &src, unsigned maxSize)
|
||||
{
|
||||
if (src.Len() >= maxSize)
|
||||
return false;
|
||||
MyStringCopy(dest, (const char *)src);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }
|
||||
|
||||
HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
{
|
||||
char record[NFileHeader::kRecordSize];
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
char *cur = record;
|
||||
|
||||
if (item.Name.Len() > NFileHeader::kNameSize)
|
||||
return E_FAIL;
|
||||
MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8;
|
||||
|
||||
WriteOctal_12(cur, item.PackSize); cur += 12;
|
||||
WriteOctal_12_Signed(cur, item.MTime); cur += 12;
|
||||
|
||||
memset(cur, ' ', 8);
|
||||
cur += 8;
|
||||
|
||||
*cur++ = item.LinkFlag;
|
||||
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
memcpy(cur, item.Magic, 8);
|
||||
cur += 8;
|
||||
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
|
||||
cur += NFileHeader::kUserNameSize;
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize));
|
||||
cur += NFileHeader::kGroupNameSize;
|
||||
|
||||
|
||||
if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8;
|
||||
if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8;
|
||||
|
||||
if (item.IsSparse())
|
||||
{
|
||||
record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
|
||||
WriteOctal_12(record + 483, item.Size);
|
||||
for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 386 + 24 * i;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 checkSum = 0;
|
||||
{
|
||||
for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
checkSum += (Byte)record[i];
|
||||
}
|
||||
/* we use GNU TAR scheme:
|
||||
checksum field is formatted differently from the
|
||||
other fields: it has [6] digits, a null, then a space. */
|
||||
// RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum));
|
||||
const unsigned kNumDigits = 6;
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7));
|
||||
checkSum >>= 3;
|
||||
}
|
||||
record[148 + 6] = 0;
|
||||
}
|
||||
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
|
||||
if (item.IsSparse())
|
||||
{
|
||||
for (unsigned i = 4; i < item.SparseBlocks.Size();)
|
||||
{
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 24 * t;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteHeader(const CItem &item)
|
||||
{
|
||||
unsigned nameSize = item.Name.Len();
|
||||
unsigned linkSize = item.LinkName.Len();
|
||||
|
||||
/* There two versions of GNU tar:
|
||||
OLDGNU_FORMAT: it writes short name and zero at the end
|
||||
GNU_FORMAT: it writes only short name without zero at the end
|
||||
we write it as OLDGNU_FORMAT with zero at the end */
|
||||
|
||||
if (nameSize < NFileHeader::kNameSize &&
|
||||
linkSize < NFileHeader::kNameSize)
|
||||
return WriteHeaderReal(item);
|
||||
|
||||
CItem mi = item;
|
||||
mi.Name = NFileHeader::kLongLink;
|
||||
mi.LinkName.Empty();
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
const AString *name;
|
||||
// We suppose that GNU tar also writes item for long link before item for LongName?
|
||||
if (i == 0)
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
|
||||
name = &item.LinkName;
|
||||
}
|
||||
else
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
|
||||
name = &item.Name;
|
||||
}
|
||||
if (name->Len() < NFileHeader::kNameSize)
|
||||
continue;
|
||||
unsigned nameStreamSize = name->Len() + 1;
|
||||
mi.PackSize = nameStreamSize;
|
||||
RINOK(WriteHeaderReal(mi));
|
||||
RINOK(WriteBytes((const char *)*name, nameStreamSize));
|
||||
RINOK(FillDataResidual(nameStreamSize));
|
||||
}
|
||||
|
||||
mi = item;
|
||||
if (mi.Name.Len() >= NFileHeader::kNameSize)
|
||||
mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1);
|
||||
if (mi.LinkName.Len() >= NFileHeader::kNameSize)
|
||||
mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1);
|
||||
return WriteHeaderReal(mi);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
|
||||
{
|
||||
unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
|
||||
if (lastRecordSize == 0)
|
||||
return S_OK;
|
||||
unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
|
||||
Byte buf[NFileHeader::kRecordSize];
|
||||
memset(buf, 0, rem);
|
||||
return WriteBytes(buf, rem);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteFinishHeader()
|
||||
{
|
||||
Byte record[NFileHeader::kRecordSize];
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
// TarOut.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "TarOut.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT COutArchive::WriteBytes(const void *data, unsigned size)
|
||||
{
|
||||
Pos += size;
|
||||
return WriteStream(m_Stream, data, size);
|
||||
}
|
||||
|
||||
static void MyStrNCpy(char *dest, const char *src, unsigned size)
|
||||
{
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
char c = src[i];
|
||||
dest[i] = c;
|
||||
if (c == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool WriteOctal_8(char *s, UInt32 val)
|
||||
{
|
||||
const unsigned kNumDigits = 8 - 1;
|
||||
if (val >= ((UInt32)1 << (kNumDigits * 3)))
|
||||
return false;
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void WriteOctal_12(char *s, UInt64 val)
|
||||
{
|
||||
const unsigned kNumDigits = 12 - 1;
|
||||
if (val >= ((UInt64)1 << (kNumDigits * 3)))
|
||||
{
|
||||
// GNU extension;
|
||||
s[0] = (char)(Byte)0x80;
|
||||
s[1] = s[2] = s[3] = 0;
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
return;
|
||||
}
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
|
||||
val >>= 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteOctal_12_Signed(char *s, Int64 val)
|
||||
{
|
||||
if (val >= 0)
|
||||
{
|
||||
WriteOctal_12(s, val);
|
||||
return;
|
||||
}
|
||||
s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
|
||||
for (unsigned i = 0; i < 8; i++, val <<= 8)
|
||||
s[4 + i] = (char)(val >> 56);
|
||||
}
|
||||
|
||||
static bool CopyString(char *dest, const AString &src, unsigned maxSize)
|
||||
{
|
||||
if (src.Len() >= maxSize)
|
||||
return false;
|
||||
MyStringCopy(dest, (const char *)src);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }
|
||||
|
||||
HRESULT COutArchive::WriteHeaderReal(const CItem &item)
|
||||
{
|
||||
char record[NFileHeader::kRecordSize];
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
char *cur = record;
|
||||
|
||||
if (item.Name.Len() > NFileHeader::kNameSize)
|
||||
return E_FAIL;
|
||||
MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.Mode)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.UID)); cur += 8;
|
||||
RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.GID)); cur += 8;
|
||||
|
||||
WriteOctal_12(cur, item.PackSize); cur += 12;
|
||||
WriteOctal_12_Signed(cur, item.MTime); cur += 12;
|
||||
|
||||
memset(cur, ' ', 8);
|
||||
cur += 8;
|
||||
|
||||
*cur++ = item.LinkFlag;
|
||||
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));
|
||||
cur += NFileHeader::kNameSize;
|
||||
|
||||
memcpy(cur, item.Magic, 8);
|
||||
cur += 8;
|
||||
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));
|
||||
cur += NFileHeader::kUserNameSize;
|
||||
RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize));
|
||||
cur += NFileHeader::kGroupNameSize;
|
||||
|
||||
|
||||
if (item.DeviceMajorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMajor)); cur += 8;
|
||||
if (item.DeviceMinorDefined) RETURN_IF_NOT_TRUE(WriteOctal_8(cur, item.DeviceMinor)); cur += 8;
|
||||
|
||||
if (item.IsSparse())
|
||||
{
|
||||
record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
|
||||
WriteOctal_12(record + 483, item.Size);
|
||||
for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 386 + 24 * i;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 checkSum = 0;
|
||||
{
|
||||
for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
|
||||
checkSum += (Byte)record[i];
|
||||
}
|
||||
/* we use GNU TAR scheme:
|
||||
checksum field is formatted differently from the
|
||||
other fields: it has [6] digits, a null, then a space. */
|
||||
// RETURN_IF_NOT_TRUE(WriteOctal_8(record + 148, checkSum));
|
||||
const unsigned kNumDigits = 6;
|
||||
for (unsigned i = 0; i < kNumDigits; i++)
|
||||
{
|
||||
record[148 + kNumDigits - 1 - i] = (char)('0' + (checkSum & 7));
|
||||
checkSum >>= 3;
|
||||
}
|
||||
record[148 + 6] = 0;
|
||||
}
|
||||
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
|
||||
if (item.IsSparse())
|
||||
{
|
||||
for (unsigned i = 4; i < item.SparseBlocks.Size();)
|
||||
{
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
|
||||
{
|
||||
const CSparseBlock &sb = item.SparseBlocks[i];
|
||||
char *p = record + 24 * t;
|
||||
WriteOctal_12(p, sb.Offset);
|
||||
WriteOctal_12(p + 12, sb.Size);
|
||||
}
|
||||
record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteHeader(const CItem &item)
|
||||
{
|
||||
unsigned nameSize = item.Name.Len();
|
||||
unsigned linkSize = item.LinkName.Len();
|
||||
|
||||
/* There two versions of GNU tar:
|
||||
OLDGNU_FORMAT: it writes short name and zero at the end
|
||||
GNU_FORMAT: it writes only short name without zero at the end
|
||||
we write it as OLDGNU_FORMAT with zero at the end */
|
||||
|
||||
if (nameSize < NFileHeader::kNameSize &&
|
||||
linkSize < NFileHeader::kNameSize)
|
||||
return WriteHeaderReal(item);
|
||||
|
||||
CItem mi = item;
|
||||
mi.Name = NFileHeader::kLongLink;
|
||||
mi.LinkName.Empty();
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
const AString *name;
|
||||
// We suppose that GNU tar also writes item for long link before item for LongName?
|
||||
if (i == 0)
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongLink;
|
||||
name = &item.LinkName;
|
||||
}
|
||||
else
|
||||
{
|
||||
mi.LinkFlag = NFileHeader::NLinkFlag::kGnu_LongName;
|
||||
name = &item.Name;
|
||||
}
|
||||
if (name->Len() < NFileHeader::kNameSize)
|
||||
continue;
|
||||
unsigned nameStreamSize = name->Len() + 1;
|
||||
mi.PackSize = nameStreamSize;
|
||||
RINOK(WriteHeaderReal(mi));
|
||||
RINOK(WriteBytes((const char *)*name, nameStreamSize));
|
||||
RINOK(FillDataResidual(nameStreamSize));
|
||||
}
|
||||
|
||||
mi = item;
|
||||
if (mi.Name.Len() >= NFileHeader::kNameSize)
|
||||
mi.Name.SetFrom(item.Name, NFileHeader::kNameSize - 1);
|
||||
if (mi.LinkName.Len() >= NFileHeader::kNameSize)
|
||||
mi.LinkName.SetFrom(item.LinkName, NFileHeader::kNameSize - 1);
|
||||
return WriteHeaderReal(mi);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::FillDataResidual(UInt64 dataSize)
|
||||
{
|
||||
unsigned lastRecordSize = ((unsigned)dataSize & (NFileHeader::kRecordSize - 1));
|
||||
if (lastRecordSize == 0)
|
||||
return S_OK;
|
||||
unsigned rem = NFileHeader::kRecordSize - lastRecordSize;
|
||||
Byte buf[NFileHeader::kRecordSize];
|
||||
memset(buf, 0, rem);
|
||||
return WriteBytes(buf, rem);
|
||||
}
|
||||
|
||||
HRESULT COutArchive::WriteFinishHeader()
|
||||
{
|
||||
Byte record[NFileHeader::kRecordSize];
|
||||
memset(record, 0, NFileHeader::kRecordSize);
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
{
|
||||
RINOK(WriteBytes(record, NFileHeader::kRecordSize));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
// Archive/TarOut.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_OUT_H
|
||||
#define __ARCHIVE_TAR_OUT_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
class COutArchive
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> m_Stream;
|
||||
|
||||
HRESULT WriteBytes(const void *data, unsigned size);
|
||||
HRESULT WriteHeaderReal(const CItem &item);
|
||||
public:
|
||||
UInt64 Pos;
|
||||
|
||||
void Create(ISequentialOutStream *outStream)
|
||||
{
|
||||
m_Stream = outStream;
|
||||
}
|
||||
|
||||
HRESULT WriteHeader(const CItem &item);
|
||||
HRESULT FillDataResidual(UInt64 dataSize);
|
||||
HRESULT WriteFinishHeader();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// Archive/TarOut.h
|
||||
|
||||
#ifndef __ARCHIVE_TAR_OUT_H
|
||||
#define __ARCHIVE_TAR_OUT_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../IStream.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
class COutArchive
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> m_Stream;
|
||||
|
||||
HRESULT WriteBytes(const void *data, unsigned size);
|
||||
HRESULT WriteHeaderReal(const CItem &item);
|
||||
public:
|
||||
UInt64 Pos;
|
||||
|
||||
void Create(ISequentialOutStream *outStream)
|
||||
{
|
||||
m_Stream = outStream;
|
||||
}
|
||||
|
||||
HRESULT WriteHeader(const CItem &item);
|
||||
HRESULT FillDataResidual(UInt64 dataSize);
|
||||
HRESULT WriteFinishHeader();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
// TarRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "TarHandler.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' };
|
||||
|
||||
REGISTER_ARC_IO(
|
||||
"tar", "tar ova", 0, 0xEE,
|
||||
k_Signature,
|
||||
NFileHeader::kUstarMagic_Offset,
|
||||
NArcInfoFlags::kStartOpen |
|
||||
NArcInfoFlags::kSymLinks |
|
||||
NArcInfoFlags::kHardLinks,
|
||||
IsArc_Tar)
|
||||
|
||||
}}
|
||||
// TarRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "TarHandler.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' };
|
||||
|
||||
REGISTER_ARC_IO(
|
||||
"tar", "tar ova", 0, 0xEE,
|
||||
k_Signature,
|
||||
NFileHeader::kUstarMagic_Offset,
|
||||
NArcInfoFlags::kStartOpen |
|
||||
NArcInfoFlags::kSymLinks |
|
||||
NArcInfoFlags::kHardLinks,
|
||||
IsArc_Tar)
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,266 +1,266 @@
|
||||
// TarUpdate.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "TarOut.h"
|
||||
#include "TarUpdate.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId,
|
||||
AString &res, UINT codePage, bool convertSlash = false);
|
||||
|
||||
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);
|
||||
|
||||
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
|
||||
|
||||
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.IndexInArc].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.IndexInArc];
|
||||
|
||||
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.Size = size2;
|
||||
item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
}
|
||||
|
||||
{
|
||||
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.IndexInArc];
|
||||
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);
|
||||
|
||||
if (opCallback)
|
||||
{
|
||||
RINOK(opCallback->ReportOperation(
|
||||
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
|
||||
NUpdateNotifyOp::kReplicate))
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}}
|
||||
// TarUpdate.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../Windows/TimeUtils.h"
|
||||
|
||||
#include "../../Common/LimitedStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "../../Compress/CopyCoder.h"
|
||||
|
||||
#include "TarOut.h"
|
||||
#include "TarUpdate.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId,
|
||||
AString &res, UINT codePage, bool convertSlash = false);
|
||||
|
||||
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);
|
||||
|
||||
CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
|
||||
updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
|
||||
|
||||
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.IndexInArc].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.IndexInArc];
|
||||
|
||||
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.Size = size2;
|
||||
item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.PackSize = 0;
|
||||
item.Size = 0;
|
||||
}
|
||||
|
||||
{
|
||||
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.IndexInArc];
|
||||
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);
|
||||
|
||||
if (opCallback)
|
||||
{
|
||||
RINOK(opCallback->ReportOperation(
|
||||
NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
|
||||
NUpdateNotifyOp::kReplicate))
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
// TarUpdate.h
|
||||
|
||||
#ifndef __TAR_UPDATE_H
|
||||
#define __TAR_UPDATE_H
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
struct CUpdateItem
|
||||
{
|
||||
int IndexInArc;
|
||||
int IndexInClient;
|
||||
UInt64 Size;
|
||||
Int64 MTime;
|
||||
UInt32 Mode;
|
||||
bool NewData;
|
||||
bool NewProps;
|
||||
bool IsDir;
|
||||
AString Name;
|
||||
AString User;
|
||||
AString Group;
|
||||
|
||||
CUpdateItem(): Size(0), IsDir(false) {}
|
||||
};
|
||||
|
||||
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
const CObjectVector<CUpdateItem> &updateItems,
|
||||
UINT codePage,
|
||||
IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
// TarUpdate.h
|
||||
|
||||
#ifndef __TAR_UPDATE_H
|
||||
#define __TAR_UPDATE_H
|
||||
|
||||
#include "../IArchive.h"
|
||||
|
||||
#include "TarItem.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NTar {
|
||||
|
||||
struct CUpdateItem
|
||||
{
|
||||
int IndexInArc;
|
||||
int IndexInClient;
|
||||
UInt64 Size;
|
||||
Int64 MTime;
|
||||
UInt32 Mode;
|
||||
bool NewData;
|
||||
bool NewProps;
|
||||
bool IsDir;
|
||||
AString Name;
|
||||
AString User;
|
||||
AString Group;
|
||||
|
||||
CUpdateItem(): Size(0), IsDir(false) {}
|
||||
};
|
||||
|
||||
HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
|
||||
const CObjectVector<CItemEx> &inputItems,
|
||||
const CObjectVector<CUpdateItem> &updateItems,
|
||||
UINT codePage,
|
||||
IArchiveUpdateCallback *updateCallback);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user