Files
Yuriy ODonnell b5709042fb Import Unsync into the main source tree
This is a binary patching and incremental downloading tool, similar to rsync or zsync. It aims to improve the large binary download processes that previously were served by robocopy (i.e. full packages produced by the build farm).

The original code can be found in `//depot/usr/yuriy.odonnell/unsync`. This commit is a branch from the original location to preserve history.

While the codebase is designed to be self-contained and does not depend on any engine libraries, it mostly follows the UE coding guidelines and can be built with UBT.

Currently only Windows is supported, however the tool is expected to also work on Mac and Linux in the future.

#rb Martin.Ridgers
#preflight skip

[CL 18993571 by Yuriy ODonnell in ue5-main branch]
2022-02-15 04:30:27 -05:00

78 lines
2.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "UnsyncCmdDiff.h"
#include "UnsyncFile.h"
namespace unsync {
int32 // TODO: return a TResult
CmdDiff(const FCmdDiffOptions& Options)
{
if (!Options.Output.empty())
{
UNSYNC_VERBOSE(L"Generating patch for '%ls' -> '%ls'", Options.Base.wstring().c_str(), Options.Source.wstring().c_str());
UNSYNC_VERBOSE(L"Output file '%ls'", Options.Output.wstring().c_str());
}
else
{
UNSYNC_VERBOSE(L"Comparing base '%ls' and source '%ls'", Options.Base.wstring().c_str(), Options.Source.wstring().c_str());
UNSYNC_VERBOSE(L"Dry run mode (no output path given).");
GDryRun = true;
}
FBuffer BaseFile = ReadFileToBuffer(Options.Base);
if (BaseFile.Empty())
{
UNSYNC_ERROR(L"Failed to read file '%ls'", Options.Base.wstring().c_str());
return 1;
}
FBuffer SourceFile = ReadFileToBuffer(Options.Source);
if (SourceFile.Empty())
{
UNSYNC_ERROR(L"Failed to open file '%ls'", Options.Source.wstring().c_str());
return 1;
}
UNSYNC_VERBOSE(L"Generating patch");
FBuffer PatchData = GeneratePatch(BaseFile.Data(),
BaseFile.Size(),
SourceFile.Data(),
SourceFile.Size(),
Options.BlockSize,
Options.WeakHasher,
Options.StrongHasher,
Options.CompressionLevel);
if (PatchData.Empty())
{
UNSYNC_LOG(L"Input files are identical. No patch required.");
}
else
{
UNSYNC_LOG(L"Patch size: %.2f MB", SizeMb(PatchData.Size()));
#if 1 // test patch application process
{
FBuffer TargetData = BuildTargetWithPatch(PatchData.Data(), PatchData.Size(), BaseFile.Data(), BaseFile.Size());
if (TargetData.Size() != SourceFile.Size() || memcmp(TargetData.Data(), SourceFile.Data(), SourceFile.Size()))
{
UNSYNC_LOG(L"Patched file does not match source");
return 1;
}
}
#endif // test patch application process
if (!GDryRun && !Options.Output.empty())
{
UNSYNC_VERBOSE(L"Writing output file to '%ls'", Options.Output.wstring().c_str());
return WriteBufferToFile(Options.Output, PatchData.Data(), PatchData.Size()) ? 0 : 1;
}
}
return 0;
}
} // namespace unsync