2021-05-03 02:47:29 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "VirtualizationUtilities.h"
|
2024-08-06 05:03:43 -04:00
|
|
|
#include "VirtualizationExperimentalUtilities.h"
|
2021-05-03 02:47:29 -04:00
|
|
|
|
2023-02-24 07:58:31 -05:00
|
|
|
#include "HAL/PlatformProcess.h"
|
2022-02-02 02:21:24 -05:00
|
|
|
#include "IO/IoHash.h"
|
2023-09-25 06:48:33 -04:00
|
|
|
#include "Misc/App.h"
|
2023-02-24 07:58:31 -05:00
|
|
|
#include "Misc/Paths.h"
|
2021-05-03 02:47:29 -04:00
|
|
|
#include "Misc/StringBuilder.h"
|
2023-02-14 04:12:26 -05:00
|
|
|
#include "UObject/PackageFileSummary.h"
|
|
|
|
|
#include "UObject/PackageResourceManager.h"
|
2024-08-06 05:03:43 -04:00
|
|
|
#include "Virtualization/VirtualizationSystem.h"
|
|
|
|
|
#include "Virtualization/VirtualizationTypes.h"
|
|
|
|
|
|
|
|
|
|
#include "VirtualizationManager.h"
|
2021-05-03 02:47:29 -04:00
|
|
|
|
|
|
|
|
namespace UE::Virtualization::Utils
|
|
|
|
|
{
|
|
|
|
|
|
2022-02-02 02:21:24 -05:00
|
|
|
void PayloadIdToPath(const FIoHash& Id, FStringBuilderBase& OutPath)
|
2021-05-03 02:47:29 -04:00
|
|
|
{
|
|
|
|
|
OutPath.Reset();
|
|
|
|
|
OutPath << Id;
|
|
|
|
|
|
|
|
|
|
TStringBuilder<10> Directory;
|
|
|
|
|
Directory << OutPath.ToView().Left(2) << TEXT("/");
|
|
|
|
|
Directory << OutPath.ToView().Mid(2, 2) << TEXT("/");
|
|
|
|
|
Directory << OutPath.ToView().Mid(4, 2) << TEXT("/");
|
|
|
|
|
|
|
|
|
|
OutPath.ReplaceAt(0, 6, Directory);
|
|
|
|
|
|
2022-02-25 16:06:09 -05:00
|
|
|
OutPath << TEXT(".upayload");
|
2021-05-03 02:47:29 -04:00
|
|
|
}
|
|
|
|
|
|
2022-02-02 02:21:24 -05:00
|
|
|
FString PayloadIdToPath(const FIoHash& Id)
|
2021-05-03 02:47:29 -04:00
|
|
|
{
|
|
|
|
|
TStringBuilder<52> Path;
|
|
|
|
|
PayloadIdToPath(Id, Path);
|
|
|
|
|
|
|
|
|
|
return FString(Path);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-12 21:21:22 -04:00
|
|
|
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)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-14 04:12:26 -05:00
|
|
|
ETrailerFailedReason FindTrailerFailedReason(const FPackagePath& PackagePath)
|
|
|
|
|
{
|
|
|
|
|
TUniquePtr<FArchive> Ar = IPackageResourceManager::Get().OpenReadExternalResource(EPackageExternalResource::WorkspaceDomainFile, PackagePath.GetPackageName());
|
|
|
|
|
|
|
|
|
|
if (!Ar)
|
|
|
|
|
{
|
|
|
|
|
return ETrailerFailedReason::NotFound;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FPackageFileSummary Summary;
|
|
|
|
|
*Ar << Summary;
|
|
|
|
|
|
|
|
|
|
if (Ar->IsError() || Summary.Tag != PACKAGE_FILE_TAG)
|
|
|
|
|
{
|
|
|
|
|
return ETrailerFailedReason::InvalidSummary;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Summary.GetFileVersionUE() < EUnrealEngineObjectUE5Version::PAYLOAD_TOC)
|
|
|
|
|
{
|
|
|
|
|
return ETrailerFailedReason::OutOfDate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ETrailerFailedReason::Unknown;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-24 07:58:31 -05:00
|
|
|
bool ExpandEnvironmentVariables(FStringView InputPath, FStringBuilderBase& OutExpandedPath)
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
const int32 EnvVarStart = InputPath.Find(TEXT("$("));
|
|
|
|
|
if (EnvVarStart == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
// If we haven't expanded anything yet we can just copy the input path
|
|
|
|
|
// If we have expanded then we need to append the remainder of the path
|
|
|
|
|
if (OutExpandedPath.Len() == 0)
|
|
|
|
|
{
|
|
|
|
|
OutExpandedPath = InputPath;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
OutExpandedPath << InputPath;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int32 EnvVarEnd = InputPath.Find(TEXT(")"), EnvVarStart + 2);
|
|
|
|
|
const int32 EnvVarNameLength = EnvVarEnd - (EnvVarStart + 2);
|
|
|
|
|
|
|
|
|
|
TStringBuilder<128> EnvVarName;
|
|
|
|
|
EnvVarName = InputPath.Mid(EnvVarStart + 2, EnvVarNameLength);
|
|
|
|
|
|
|
|
|
|
FString EnvVarValue;
|
|
|
|
|
if (EnvVarName.ToView() == TEXT("Temp") || EnvVarName.ToView() == TEXT("Tmp"))
|
|
|
|
|
{
|
|
|
|
|
// On windows the temp envvar is often in 8.3 format
|
|
|
|
|
// Either we need to expose ::GetLongPathName in some way or we need to consider
|
|
|
|
|
// calling it in WindowsPlatformMisc::GetEnvironmentVariable.
|
|
|
|
|
// Until we decide this is a quick work around, check for the Temp envvar and if
|
|
|
|
|
// it is being requested us the ::UserTempDir function which will convert 8.3
|
|
|
|
|
// format correctly.
|
|
|
|
|
// This should be solved before we consider moving this utility function into core
|
|
|
|
|
EnvVarValue = FPlatformProcess::UserTempDir();
|
|
|
|
|
|
|
|
|
|
FPaths::NormalizeDirectoryName(EnvVarValue);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
EnvVarValue = FPlatformMisc::GetEnvironmentVariable(EnvVarName.ToString());
|
|
|
|
|
if (EnvVarValue.IsEmpty())
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualization, Warning, TEXT("Could not find environment variable '%s' to expand"), EnvVarName.ToString());
|
|
|
|
|
OutExpandedPath.Reset();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OutExpandedPath << InputPath.Mid(0, EnvVarStart);
|
|
|
|
|
OutExpandedPath << EnvVarValue;
|
|
|
|
|
|
|
|
|
|
InputPath = InputPath.Mid(EnvVarEnd + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-25 06:48:33 -04:00
|
|
|
bool IsProcessInteractive()
|
|
|
|
|
{
|
2023-11-15 10:51:51 -05:00
|
|
|
if (FApp::IsUnattended())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsRunningCommandlet())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We used to check 'GIsRunningUnattendedScript' here as well but there
|
|
|
|
|
// are a number of places in the editor enabling this global during which
|
|
|
|
|
// the editor does stay interactive, such as when rendering thumbnail
|
|
|
|
|
// images for the content browser.
|
|
|
|
|
// Leaving this comment block here to show why we are not checking this
|
|
|
|
|
// value anymore.
|
|
|
|
|
|
|
|
|
|
if (IS_PROGRAM)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2023-09-25 06:48:33 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-06 05:03:43 -04:00
|
|
|
EPayloadFilterReason FixFilterFlags(FStringView PackagePath, uint64 SizeOnDisk, EPayloadFilterReason CurrentFilterFlags)
|
|
|
|
|
{
|
|
|
|
|
if (IVirtualizationSystem::IsInitialized() && IVirtualizationSystem::GetSystemName() == FName("Default") && IVirtualizationSystem::Get().IsEnabled())
|
|
|
|
|
{
|
|
|
|
|
// Very hacky but should be safe if the system name is "Default". Allows us to do this without actually modifying the public API.
|
|
|
|
|
FVirtualizationManager& Manager = static_cast<FVirtualizationManager&>(IVirtualizationSystem::Get());
|
|
|
|
|
|
|
|
|
|
return Manager.FixFilterFlags(PackagePath, SizeOnDisk, CurrentFilterFlags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CurrentFilterFlags;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 02:47:29 -04:00
|
|
|
} // namespace UE::Virtualization::Utils
|
2024-08-06 05:03:43 -04:00
|
|
|
|