in Shared/Io/Tar.cpp [153:318]
void CreateTarball(
_In_ Windows::Storage::StorageFolder^ sourceFolder,
_In_ const std::vector<std::wstring>& sourceFileNames,
_In_ Windows::Storage::StorageFolder^ tarballFolder,
_In_ const std::wstring& tarballFileName)
{
Microsoft::WRL::ComPtr<IStorageFolderHandleAccess> tarballFolderHandleAccess =
GetStorageFolderHandleAccess(
tarballFolder);
HANDLE output = nullptr;
ASSERT_SUCCEEDED(tarballFolderHandleAccess->Create(
tarballFileName.c_str() /* fileName */,
HCO_CREATE_ALWAYS /* creationOptions */,
HAO_WRITE /* accessOptions */,
HSO_SHARE_NONE /* sharingOptions */,
HO_NONE /* options */,
nullptr /* oplockBreakingHandler */,
&output));
std::vector<uint8_t> alignmentBuffer(512);
std::vector<uint8_t> sourceFileBuffer;
std::fill(
alignmentBuffer.begin(),
alignmentBuffer.end(),
static_cast<uint8_t>(0) /* _Val */);
DWORD numberOfBytesWritten = 0;
DWORD numberOfBytesRead = 0;
Microsoft::WRL::ComPtr<IStorageFolderHandleAccess> sourceFolderHandleAccess =
GetStorageFolderHandleAccess(
sourceFolder);
for (const auto& sourceFileName : sourceFileNames)
{
HANDLE input = nullptr;
ASSERT_SUCCEEDED(sourceFolderHandleAccess->Create(
sourceFileName.c_str() /* fileName */,
HCO_OPEN_EXISTING /* creationOptions */,
HAO_READ /* accessOptions */,
HSO_SHARE_READ /* sharingOptions */,
HO_NONE /* options */,
nullptr /* oplockBreakingHandler */,
&input));
LARGE_INTEGER fileSize = {};
ASSERT(!!GetFileSizeEx(
input,
&fileSize));
FILETIME lastWriteTime = {};
ASSERT(!!GetFileTime(
input,
nullptr /* lpCreationTime */,
nullptr /* lpLastAccessTime */,
&lastWriteTime));
sourceFileBuffer.resize(
static_cast<size_t>(fileSize.QuadPart));
ASSERT(!!ReadFile(
input,
&sourceFileBuffer[0],
static_cast<DWORD>(sourceFileBuffer.size()),
&numberOfBytesRead,
nullptr /* lpOverlapped */));
ASSERT(sourceFileBuffer.size() == numberOfBytesRead);
TarHeader header;
static_assert(
512 == sizeof(TarHeader),
"Size of the TarHeader structure must be equal to 512 bytes.");
CopyStringToTarHeader<100>(
Utf16ToUtf8(sourceFileName),
header.FileName);
CopyUInt64ToTarHeaderAsOctets<12>(
static_cast<size_t>(fileSize.QuadPart),
header.FileSize);
CopyUInt64ToTarHeaderAsOctets<12>(
std::chrono::duration_cast<std::chrono::seconds>(
UniversalToUnixTime(lastWriteTime)).count(),
header.LastModificationTime);
uint64_t checksum = 0;
for (size_t i = 0; i < sizeof(header); ++i)
{
checksum +=
reinterpret_cast<uint8_t*>(&header)[i];
}
CopyUInt64ToTarHeaderAsOctets<7>(
checksum,
header.Checksum);
ASSERT(!!WriteFile(
output,
&header,
sizeof(header),
&numberOfBytesWritten,
nullptr /* lpOverlapped */));
ASSERT(sizeof(header) == numberOfBytesWritten);
ASSERT(!!WriteFile(
output,
&sourceFileBuffer[0],
static_cast<DWORD>(fileSize.QuadPart),
&numberOfBytesWritten,
nullptr /* lpOverlapped */));
ASSERT(fileSize.QuadPart == numberOfBytesWritten);
const size_t lastBlockSize =
fileSize.QuadPart % alignmentBuffer.size();
if (0 != lastBlockSize)
{
const size_t lastBlockPadding =
alignmentBuffer.size() - lastBlockSize;
ASSERT(lastBlockPadding < alignmentBuffer.size());
ASSERT(!!WriteFile(
output,
&alignmentBuffer[0],
static_cast<DWORD>(lastBlockPadding),
&numberOfBytesWritten,
nullptr /* lpOverlapped */));
ASSERT(lastBlockPadding == numberOfBytesWritten);
}
ASSERT(!!CloseHandle(
input));
}
//
// The TAR file ends with two blocks of zeroes:
//
for (size_t terminatorBlock = 0; terminatorBlock < 2; ++terminatorBlock)
{
ASSERT(!!WriteFile(
output,
&alignmentBuffer[0],
static_cast<DWORD>(alignmentBuffer.size()),
&numberOfBytesWritten,
nullptr /* lpOverlapped */));
ASSERT(alignmentBuffer.size() == numberOfBytesWritten);
}
ASSERT(!!CloseHandle(
output));
}