You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb Mikko.Mononen #rnx #preflight 612cbc029db30900012a0dca - Added a header file and moved the class declaration thereto make it easier for people to find the ini file documentation. - Split some logging into multiple lines to reduce the overall width of the file. #ROBOMERGE-SOURCE: CL 17365675 in //UE5/Main/... #ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v865-17346139) [CL 17365683 by paul chipchase in ue5-release-engine-test branch]
177 lines
5.2 KiB
C++
177 lines
5.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "VirtualizationFileBackend.h"
|
|
|
|
#include "HAL/FileManager.h"
|
|
#include "Misc/Parse.h"
|
|
#include "Misc/Paths.h"
|
|
#include "Virtualization/VirtualizationManager.h"
|
|
#include "VirtualizationUtilities.h"
|
|
|
|
namespace UE::Virtualization
|
|
{
|
|
/**
|
|
* Fill in the given string builder with the human readable message of the current system
|
|
* code, followed by the code value itself.
|
|
* In the system value is currently 0, then we assume that it was cleared before this was
|
|
* able to be called and write that the error is unknown instead of assuming that the
|
|
* operation was a success.
|
|
*/
|
|
void GetFormattedSystemError(FStringBuilderBase& SystemErrorMessage)
|
|
{
|
|
SystemErrorMessage.Reset();
|
|
|
|
const uint32 SystemError = FPlatformMisc::GetLastError();
|
|
// If we have a system error we can give a more informative error message but don't output it if the error is zero as
|
|
// this can lead to very confusing error messages.
|
|
if (SystemError != 0)
|
|
{
|
|
TCHAR SystemErrorMsg[MAX_SPRINTF] = { 0 };
|
|
FPlatformMisc::GetSystemErrorMessage(SystemErrorMsg, sizeof(SystemErrorMsg), SystemError);
|
|
|
|
SystemErrorMessage.Appendf(TEXT("'%s' (%d)"), SystemErrorMsg, SystemError);
|
|
}
|
|
else
|
|
{
|
|
SystemErrorMessage << TEXT("'unknown reason' (0)");
|
|
}
|
|
}
|
|
|
|
|
|
FFileSystemBackend::FFileSystemBackend(FStringView ConfigName)
|
|
: IVirtualizationBackend(EOperations::Both)
|
|
{
|
|
Name = WriteToString<256>(TEXT("FFileSystemBackend - "), ConfigName).ToString();
|
|
}
|
|
|
|
bool FFileSystemBackend::Initialize(const FString& ConfigEntry)
|
|
{
|
|
if (!FParse::Value(*ConfigEntry, TEXT("Path="), RootDirectory))
|
|
{
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] 'Path=' not found in the config file"), *GetDebugString());
|
|
return false;
|
|
}
|
|
|
|
FPaths::NormalizeDirectoryName(RootDirectory);
|
|
|
|
if (RootDirectory.IsEmpty())
|
|
{
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] Config file entry 'Path=' was empty"), *GetDebugString());
|
|
return false;
|
|
}
|
|
|
|
// TODO: Validate that the given path is usable?
|
|
|
|
UE_LOG(LogVirtualization, Log, TEXT("[%s] Using path: '%s'"), *GetDebugString(), *RootDirectory);
|
|
|
|
return true;
|
|
}
|
|
|
|
EPushResult FFileSystemBackend::PushData(const FPayloadId& Id, const FCompressedBuffer& Payload)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::PushData);
|
|
|
|
if (DoesExist(Id))
|
|
{
|
|
UE_LOG(LogVirtualization, Verbose, TEXT("[%s] Already has a copy of the payload '%s'."), *GetDebugString(), *Id.ToString());
|
|
return EPushResult::PayloadAlreadyExisted;
|
|
}
|
|
|
|
TStringBuilder<512> FilePath;
|
|
CreateFilePath(Id, FilePath);
|
|
|
|
// TODO: Should we write to a temp file and then move it once it has written?
|
|
TUniquePtr<FArchive> FileAr(IFileManager::Get().CreateFileWriter(FilePath.ToString()));
|
|
|
|
if (FileAr == nullptr)
|
|
{
|
|
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
|
|
GetFormattedSystemError(SystemErrorMsg);
|
|
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to write payload '%s' to '%s' due to system error: %s"),
|
|
*GetDebugString(),
|
|
*Id.ToString(),
|
|
FilePath.ToString(),
|
|
SystemErrorMsg.ToString());
|
|
|
|
return EPushResult::Failed;
|
|
}
|
|
|
|
for (const FSharedBuffer& Buffer : Payload.GetCompressed().GetSegments())
|
|
{
|
|
// Const cast because FArchive requires a non-const pointer!
|
|
FileAr->Serialize(const_cast<void*>(Buffer.GetData()), static_cast<int64>(Buffer.GetSize()));
|
|
}
|
|
|
|
if (FileAr->Close())
|
|
{
|
|
return EPushResult::Success;
|
|
}
|
|
else
|
|
{
|
|
// TODO: If we were first saving to a tmp file we could avoid the need to delete the
|
|
// potentially corrupt output file.
|
|
IFileManager::Get().Delete(FilePath.ToString());
|
|
return EPushResult::Failed;
|
|
}
|
|
}
|
|
|
|
FCompressedBuffer FFileSystemBackend::PullData(const FPayloadId& Id)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::PullData);
|
|
|
|
TStringBuilder<512> FilePath;
|
|
CreateFilePath(Id, FilePath);
|
|
|
|
// TODO: Should we allow the error severity to be configured via ini or just not report this case at all?
|
|
if (!IFileManager::Get().FileExists(FilePath.ToString()))
|
|
{
|
|
UE_LOG(LogVirtualization, Verbose, TEXT("[%s] Does not contain the payload '%s'"), *GetDebugString(), *Id.ToString());
|
|
return FCompressedBuffer();
|
|
}
|
|
|
|
TUniquePtr<FArchive> FileAr(IFileManager::Get().CreateFileReader(FilePath.ToString()));
|
|
if (FileAr == nullptr)
|
|
{
|
|
TStringBuilder<MAX_SPRINTF> SystemErrorMsg;
|
|
GetFormattedSystemError(SystemErrorMsg);
|
|
|
|
UE_LOG(LogVirtualization, Error, TEXT("[%s] Failed to load payload '%s' from file '%s' due to system error: %s"),
|
|
*GetDebugString(),
|
|
*Id.ToString(),
|
|
FilePath.ToString(),
|
|
SystemErrorMsg.ToString());
|
|
|
|
return FCompressedBuffer();
|
|
}
|
|
|
|
return FCompressedBuffer::FromCompressed(*FileAr);
|
|
}
|
|
|
|
FString FFileSystemBackend::GetDebugString() const
|
|
{
|
|
return Name;
|
|
}
|
|
|
|
bool FFileSystemBackend::DoesExist(const FPayloadId& Id)
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(FFileSystemBackend::DoesExist);
|
|
|
|
TStringBuilder<512> FilePath;
|
|
CreateFilePath(Id, FilePath);
|
|
|
|
return IFileManager::Get().FileExists(FilePath.ToString());
|
|
}
|
|
|
|
void FFileSystemBackend::CreateFilePath(const FPayloadId& PayloadId, FStringBuilderBase& OutPath)
|
|
{
|
|
TStringBuilder<52> PayloadPath;
|
|
Utils::PayloadIdToPath(PayloadId, PayloadPath);
|
|
|
|
OutPath << RootDirectory << TEXT("/") << PayloadPath;
|
|
}
|
|
|
|
UE_REGISTER_VIRTUALIZATION_BACKEND_FACTORY(FFileSystemBackend, FileSystem);
|
|
|
|
} // namespace UE::Virtualization
|