2021-06-15 16:38:03 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "StorageServerPlatformFile.h"
2023-08-23 19:13:18 -04:00
# include "Algo/Replace.h"
# include "CookOnTheFly.h"
# include "CookOnTheFlyPackageStore.h"
2023-04-21 08:56:22 -04:00
# include "HAL/FileManagerGeneric.h"
2023-08-23 19:13:18 -04:00
# include "Misc/App.h"
2021-07-14 10:40:16 -04:00
# include "Misc/CommandLine.h"
2023-08-23 19:13:18 -04:00
# include "Misc/CoreDelegates.h"
2024-03-24 22:03:42 -04:00
# include "Misc/FileHelper.h"
2021-06-15 16:38:03 -04:00
# include "Misc/Paths.h"
2024-04-25 17:44:31 -04:00
# include "Misc/PathViews.h"
2021-06-15 16:38:03 -04:00
# include "Misc/ScopeRWLock.h"
# include "Misc/StringBuilder.h"
# include "Modules/ModuleManager.h"
2023-08-23 19:13:18 -04:00
# include "Modules/ModuleManager.h"
2023-04-21 08:56:22 -04:00
# include "Serialization/CompactBinarySerialization.h"
2024-03-24 22:03:42 -04:00
# include "Serialization/JsonReader.h"
# include "Serialization/JsonSerializer.h"
2024-08-15 10:01:59 -04:00
# include "ProfilingDebugging/PlatformFileTrace.h"
2023-08-23 19:13:18 -04:00
# include "StorageServerConnection.h"
# include "StorageServerIoDispatcherBackend.h"
# include "StorageServerPackageStore.h"
2021-06-15 16:38:03 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogStorageServerPlatformFile , Log , All ) ;
# if !UE_BUILD_SHIPPING
2024-04-25 17:44:31 -04:00
# ifndef EXCLUDE_NONSERVER_UE_EXTENSIONS
# define EXCLUDE_NONSERVER_UE_EXTENSIONS 1 // Use .Build.cs file to disable this if the game relies on accessing loose files on the local filesystem
# endif
2024-08-02 05:15:03 -04:00
static FDateTime GAssumedImmutableTimeStamp = FDateTime : : Now ( ) ;
2021-06-15 16:38:03 -04:00
FStorageServerFileSystemTOC : : ~ FStorageServerFileSystemTOC ( )
{
FWriteScopeLock _ ( TocLock ) ;
for ( auto & KV : Directories )
{
delete KV . Value ;
}
}
FStorageServerFileSystemTOC : : FDirectory * FStorageServerFileSystemTOC : : AddDirectoriesRecursive ( const FString & DirectoryPath )
{
FDirectory * Directory = new FDirectory ( ) ;
Directories . Add ( DirectoryPath , Directory ) ;
FString ParentDirectoryPath = FPaths : : GetPath ( DirectoryPath ) ;
FDirectory * ParentDirectory ;
if ( ParentDirectoryPath . IsEmpty ( ) )
{
ParentDirectory = & Root ;
}
else
{
ParentDirectory = Directories . FindRef ( ParentDirectoryPath ) ;
if ( ! ParentDirectory )
{
ParentDirectory = AddDirectoriesRecursive ( ParentDirectoryPath ) ;
}
}
ParentDirectory - > Directories . Add ( DirectoryPath ) ;
return Directory ;
}
2024-06-06 19:05:45 -04:00
void FStorageServerFileSystemTOC : : AddFile ( const FIoChunkId & FileChunkId , FStringView PathView , int64 RawSize )
2021-06-15 16:38:03 -04:00
{
FWriteScopeLock _ ( TocLock ) ;
2021-08-19 06:42:05 -04:00
const int32 FileIndex = Files . Num ( ) ;
FFile & NewFile = Files . AddDefaulted_GetRef ( ) ;
NewFile . FileChunkId = FileChunkId ;
NewFile . FilePath = PathView ;
2024-06-06 19:05:45 -04:00
NewFile . RawSize = RawSize ;
2021-08-19 06:42:05 -04:00
FilePathToIndexMap . Add ( NewFile . FilePath , FileIndex ) ;
FString DirectoryPath = FPaths : : GetPath ( NewFile . FilePath ) ;
2021-06-15 16:38:03 -04:00
FDirectory * Directory = Directories . FindRef ( DirectoryPath ) ;
if ( ! Directory )
{
Directory = AddDirectoriesRecursive ( DirectoryPath ) ;
}
2021-08-19 06:42:05 -04:00
Directory - > Files . Add ( FileIndex ) ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerFileSystemTOC : : FileExists ( const FString & Path )
{
FReadScopeLock _ ( TocLock ) ;
return FilePathToIndexMap . Contains ( Path ) ;
}
bool FStorageServerFileSystemTOC : : DirectoryExists ( const FString & Path )
{
FReadScopeLock _ ( TocLock ) ;
return Directories . Contains ( Path ) ;
}
2021-08-19 06:42:05 -04:00
const FIoChunkId * FStorageServerFileSystemTOC : : GetFileChunkId ( const FString & Path )
2021-06-15 16:38:03 -04:00
{
FReadScopeLock _ ( TocLock ) ;
2021-08-19 06:42:05 -04:00
if ( const int32 * FileIndex = FilePathToIndexMap . Find ( Path ) )
{
return & Files [ * FileIndex ] . FileChunkId ;
}
return nullptr ;
2021-06-15 16:38:03 -04:00
}
2024-06-06 19:05:45 -04:00
int64 FStorageServerFileSystemTOC : : GetFileSize ( const FString & Path )
{
FReadScopeLock _ ( TocLock ) ;
if ( const int32 * FileIndex = FilePathToIndexMap . Find ( Path ) )
{
return Files [ * FileIndex ] . RawSize ;
}
return STORAGE_SERVER_FILE_UNKOWN_SIZE ;
}
bool FStorageServerFileSystemTOC : : GetFileData ( const FString & Path , FIoChunkId & OutChunkId , int64 & OutRawSize )
{
FReadScopeLock _ ( TocLock ) ;
if ( const int32 * FileIndex = FilePathToIndexMap . Find ( Path ) )
{
const FFile & File = Files [ * FileIndex ] ;
OutChunkId = File . FileChunkId ;
OutRawSize = File . RawSize ;
return true ;
}
return false ;
}
bool FStorageServerFileSystemTOC : : IterateDirectory ( const FString & Path , TFunctionRef < bool ( const FIoChunkId & , const TCHAR * , int64 RawSize ) > Callback )
2021-06-15 16:38:03 -04:00
{
UE_LOG ( LogStorageServerPlatformFile , Verbose , TEXT ( " IterateDirectory '%s' " ) , * Path ) ;
FReadScopeLock _ ( TocLock ) ;
FDirectory * Directory = Directories . FindRef ( Path ) ;
if ( ! Directory )
{
return false ;
}
for ( int32 FileIndex : Directory - > Files )
{
2021-08-19 06:42:05 -04:00
const FFile & File = Files [ FileIndex ] ;
2024-06-06 19:05:45 -04:00
if ( ! Callback ( File . FileChunkId , * File . FilePath , File . RawSize ) )
2021-06-15 16:38:03 -04:00
{
return false ;
}
}
for ( const FString & ChildDirectoryPath : Directory - > Directories )
{
2024-06-06 19:05:45 -04:00
if ( ! Callback ( FIoChunkId ( ) , * ChildDirectoryPath , 0 ) )
2021-06-15 16:38:03 -04:00
{
return false ;
}
}
return true ;
}
class FStorageServerFileHandle
: public IFileHandle
{
enum
{
BufferSize = 64 < < 10
} ;
FStorageServerPlatformFile & Owner ;
2021-08-19 06:42:05 -04:00
FIoChunkId FileChunkId ;
2021-06-15 16:38:03 -04:00
FString Filename ;
int64 FilePos = 0 ;
int64 FileSize = - 1 ;
int64 BufferStart = - 1 ;
int64 BufferEnd = - 1 ;
uint8 Buffer [ BufferSize ] ;
public :
2024-06-06 19:05:45 -04:00
FStorageServerFileHandle ( FStorageServerPlatformFile & InOwner , FIoChunkId InFileChunkId , int64 InFileSize , const TCHAR * InFilename )
2021-06-15 16:38:03 -04:00
: Owner ( InOwner )
2021-08-19 06:42:05 -04:00
, FileChunkId ( InFileChunkId )
2021-06-15 16:38:03 -04:00
, Filename ( InFilename )
2024-06-06 19:05:45 -04:00
, FileSize ( InFileSize )
2021-06-15 16:38:03 -04:00
{
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_BEGIN_OPEN ( * FString : : Printf ( TEXT ( " zen:%s " ) , InFilename ) ) ;
TRACE_PLATFORMFILE_END_OPEN ( this ) ;
2021-06-15 16:38:03 -04:00
}
~ FStorageServerFileHandle ( )
{
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_BEGIN_CLOSE ( this ) ;
TRACE_PLATFORMFILE_END_CLOSE ( this ) ;
2021-06-15 16:38:03 -04:00
}
virtual int64 Size ( ) override
{
if ( FileSize < 0 )
{
2021-08-19 06:42:05 -04:00
const FFileStatData FileStatData = Owner . SendGetStatDataMessage ( FileChunkId ) ;
2021-06-15 16:38:03 -04:00
if ( FileStatData . bIsValid )
{
FileSize = FileStatData . FileSize ;
}
else
{
UE_LOG ( LogStorageServerPlatformFile , Warning , TEXT ( " Failed to obtain size of file '%s' " ) , * Filename ) ;
FileSize = 0 ;
}
}
return FileSize ;
}
virtual int64 Tell ( ) override
{
return FilePos ;
}
virtual bool Seek ( int64 NewPosition ) override
{
FilePos = NewPosition ;
return true ;
}
virtual bool SeekFromEnd ( int64 NewPositionRelativeToEnd = 0 ) override
{
return Seek ( Size ( ) + NewPositionRelativeToEnd ) ;
}
virtual bool Read ( uint8 * Destination , int64 BytesToRead ) override
{
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_BEGIN_READ ( Destination , this , FilePos , BytesToRead ) ;
2021-06-15 16:38:03 -04:00
if ( BytesToRead = = 0 )
{
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_END_READ ( Destination , 0 ) ;
2021-06-15 16:38:03 -04:00
return true ;
}
if ( BytesToRead > BufferSize )
{
2021-08-19 06:42:05 -04:00
const int64 BytesRead = Owner . SendReadMessage ( Destination , FileChunkId , FilePos , BytesToRead ) ;
2021-06-15 16:38:03 -04:00
if ( BytesRead = = BytesToRead )
{
FilePos + = BytesRead ;
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_END_READ ( Destination , BytesRead ) ;
2021-06-15 16:38:03 -04:00
return true ;
}
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_END_READ ( Destination , 0 ) ;
2023-07-31 10:12:18 -04:00
return false ;
2021-06-15 16:38:03 -04:00
}
2023-07-31 10:12:18 -04:00
int64 BytesReadFromBuffer = 0 ;
if ( FilePos > = BufferStart & & FilePos < BufferEnd )
2021-06-15 16:38:03 -04:00
{
2023-07-31 10:12:18 -04:00
const int64 BufferOffset = FilePos - BufferStart ;
check ( BufferOffset < BufferSize ) ;
BytesReadFromBuffer = FMath : : Min ( BufferSize - BufferOffset , BytesToRead ) ;
FMemory : : Memcpy ( Destination , Buffer + BufferOffset , BytesReadFromBuffer ) ;
if ( BytesReadFromBuffer = = BytesToRead )
{
FilePos + = BytesReadFromBuffer ;
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_END_READ ( this , BytesReadFromBuffer ) ;
2023-07-31 10:12:18 -04:00
return true ;
}
2021-06-15 16:38:03 -04:00
}
2023-07-31 10:12:18 -04:00
const int64 BytesRead = Owner . SendReadMessage ( Buffer , FileChunkId , FilePos + BytesReadFromBuffer , BufferSize ) ;
BufferStart = FilePos + BytesReadFromBuffer ;
BufferEnd = BufferStart + BytesRead ;
const int64 BytesToReadFromBuffer = FMath : : Min ( BytesRead , BytesToRead - BytesReadFromBuffer ) ;
FMemory : : Memcpy ( Destination + BytesReadFromBuffer , Buffer , BytesToReadFromBuffer ) ;
BytesReadFromBuffer + = BytesToReadFromBuffer ;
if ( BytesReadFromBuffer = = BytesToRead )
2021-06-15 16:38:03 -04:00
{
2023-07-31 10:12:18 -04:00
FilePos + = BytesReadFromBuffer ;
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_END_READ ( Destination , BytesReadFromBuffer ) ;
2021-06-15 16:38:03 -04:00
return true ;
}
2024-08-15 10:01:59 -04:00
TRACE_PLATFORMFILE_END_READ ( Destination , 0 ) ;
2021-06-15 16:38:03 -04:00
return false ;
}
virtual bool Write ( const uint8 * Source , int64 BytesToWrite ) override
{
check ( false ) ;
return false ;
}
virtual bool Flush ( const bool bFullFlush = false ) override
{
return false ;
}
virtual bool Truncate ( int64 NewSize ) override
{
return false ;
}
} ;
FStorageServerPlatformFile : : FStorageServerPlatformFile ( )
{
}
FStorageServerPlatformFile : : ~ FStorageServerPlatformFile ( )
{
}
2023-04-21 08:56:22 -04:00
TUniquePtr < FArchive > FStorageServerPlatformFile : : TryFindProjectStoreMarkerFile ( IPlatformFile * Inner ) const
{
if ( Inner = = nullptr )
{
return nullptr ;
}
2023-06-20 10:53:32 -04:00
TArray < FString > PotentialProjectStorePaths ;
2024-08-06 11:00:25 -04:00
if ( CustomProjectStorePath . IsEmpty ( ) )
{
FString RelativeStagedPath = TEXT ( " ../../../ " ) ;
FString RootPath = FPaths : : RootDir ( ) ;
FString PlatformName = FPlatformProperties : : PlatformName ( ) ;
FString CookedOutputPath = FPaths : : Combine ( FPaths : : ProjectDir ( ) , TEXT ( " Saved " ) , TEXT ( " Cooked " ) , PlatformName ) ;
PotentialProjectStorePaths . Add ( RelativeStagedPath ) ;
PotentialProjectStorePaths . Add ( CookedOutputPath ) ;
PotentialProjectStorePaths . Add ( RootPath ) ;
}
else
{
PotentialProjectStorePaths . Add ( CustomProjectStorePath ) ;
}
2023-06-20 10:53:32 -04:00
for ( const FString & ProjectStorePath : PotentialProjectStorePaths )
2023-04-21 08:56:22 -04:00
{
2024-01-31 13:01:29 -05:00
FString ProjectMarkerPath = ProjectStorePath / TEXT ( " ue.projectstore " ) ;
2023-06-20 10:53:32 -04:00
if ( IFileHandle * ProjectStoreMarkerHandle = Inner - > OpenRead ( * ProjectMarkerPath ) ; ProjectStoreMarkerHandle ! = nullptr )
{
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Found '%s' " ) , * ProjectMarkerPath ) ;
return TUniquePtr < FArchive > ( new FArchiveFileReaderGeneric ( ProjectStoreMarkerHandle , * ProjectMarkerPath , ProjectStoreMarkerHandle - > Size ( ) ) ) ;
}
2023-04-21 08:56:22 -04:00
}
return nullptr ;
}
2024-06-11 01:27:00 -04:00
FAnsiString FStorageServerPlatformFile : : MakeBaseURI ( )
{
TAnsiStringBuilder < 256 > BaseURIBuilder ;
if ( ! BaseURI . IsEmpty ( ) )
{
BaseURIBuilder . Append ( BaseURI ) ;
}
else
{
BaseURIBuilder . Append ( " /prj/ " ) ;
if ( ServerProject . IsEmpty ( ) )
{
BaseURIBuilder . Append ( TCHAR_TO_ANSI ( * FApp : : GetZenStoreProjectId ( ) ) ) ;
}
else
{
BaseURIBuilder . Append ( ServerProject ) ;
}
BaseURIBuilder . Append ( " /oplog/ " ) ;
if ( ServerPlatform . IsEmpty ( ) )
{
TArray < FString > TargetPlatformNames ;
FPlatformMisc : : GetValidTargetPlatforms ( TargetPlatformNames ) ;
check ( TargetPlatformNames . Num ( ) > 0 ) ;
BaseURIBuilder . Append ( TCHAR_TO_ANSI ( * TargetPlatformNames [ 0 ] ) ) ;
}
else
{
BaseURIBuilder . Append ( ServerPlatform ) ;
}
}
return BaseURIBuilder . ToString ( ) ;
}
2021-06-15 16:38:03 -04:00
bool FStorageServerPlatformFile : : ShouldBeUsed ( IPlatformFile * Inner , const TCHAR * CmdLine ) const
{
2023-04-03 01:51:40 -04:00
# if WITH_COTF
UE : : Cook : : ICookOnTheFlyModule & CookOnTheFlyModule = FModuleManager : : LoadModuleChecked < UE : : Cook : : ICookOnTheFlyModule > ( TEXT ( " CookOnTheFly " ) ) ;
TSharedPtr < UE : : Cook : : ICookOnTheFlyServerConnection > DefaultConnection = CookOnTheFlyModule . GetDefaultServerConnection ( ) ;
if ( DefaultConnection . IsValid ( ) & & ! DefaultConnection - > GetZenProjectName ( ) . IsEmpty ( ) )
{
2023-06-20 10:53:32 -04:00
HostAddrs . Append ( DefaultConnection - > GetZenHostNames ( ) ) ;
2023-04-03 01:51:40 -04:00
HostPort = DefaultConnection - > GetZenHostPort ( ) ;
return true ;
}
# endif
2023-04-21 08:56:22 -04:00
TUniquePtr < FArchive > ProjectStoreMarkerReader = TryFindProjectStoreMarkerFile ( Inner ) ;
if ( ProjectStoreMarkerReader ! = nullptr )
{
2024-03-24 22:03:42 -04:00
TSharedPtr < FJsonObject > ProjectStoreObject ;
TSharedRef < TJsonReader < UTF8CHAR > > Reader = TJsonReaderFactory < UTF8CHAR > : : Create ( ProjectStoreMarkerReader . Get ( ) ) ;
if ( FJsonSerializer : : Deserialize ( Reader , ProjectStoreObject ) & & ProjectStoreObject . IsValid ( ) )
2023-04-21 08:56:22 -04:00
{
2024-03-24 22:03:42 -04:00
const TSharedPtr < FJsonObject > * ZenServerObjectPtr = nullptr ;
if ( ProjectStoreObject - > TryGetObjectField ( TEXT ( " zenserver " ) , ZenServerObjectPtr ) & & ( ZenServerObjectPtr ! = nullptr ) )
{
const TSharedPtr < FJsonObject > & ZenServerObject = * ZenServerObjectPtr ;
2024-04-23 12:00:52 -04:00
# if PLATFORM_DESKTOP || PLATFORM_ANDROID
2024-03-24 22:03:42 -04:00
FString HostName ;
if ( ZenServerObject - > TryGetStringField ( TEXT ( " hostname " ) , HostName ) & & ! HostName . IsEmpty ( ) )
2023-06-15 04:51:13 -04:00
{
2024-03-24 22:03:42 -04:00
HostAddrs . Add ( HostName ) ;
}
# endif
const TArray < TSharedPtr < FJsonValue > > * RemoteHostNamesArrayPtr = nullptr ;
if ( ZenServerObject - > TryGetArrayField ( TEXT ( " remotehostnames " ) , RemoteHostNamesArrayPtr ) & & ( RemoteHostNamesArrayPtr ! = nullptr ) )
{
for ( TSharedPtr < FJsonValue > RemoteHostName : * RemoteHostNamesArrayPtr )
{
if ( FString RemoteHostNameStr = RemoteHostName - > AsString ( ) ; ! RemoteHostNameStr . IsEmpty ( ) )
{
HostAddrs . Add ( RemoteHostNameStr ) ;
}
}
2023-06-15 04:51:13 -04:00
}
2024-03-24 22:03:42 -04:00
uint16 SerializedHostPort = 0 ;
if ( ZenServerObject - > TryGetNumberField ( TEXT ( " hostport " ) , SerializedHostPort ) & & ( SerializedHostPort ! = 0 ) )
{
HostPort = SerializedHostPort ;
}
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Using connection settings from ue.projectstore: HostAddrs='%s' and HostPort='%d' " ) , * FString : : Join ( HostAddrs , TEXT ( " + " ) ) , HostPort ) ;
}
2023-04-21 08:56:22 -04:00
}
2024-04-03 10:02:35 -04:00
else
{
UE_LOG ( LogStorageServerPlatformFile , Error , TEXT ( " Failed to Deserialize ue.projectstore!' " ) ) ;
}
2023-04-21 08:56:22 -04:00
}
2021-07-14 10:40:16 -04:00
FString Host ;
if ( FParse : : Value ( FCommandLine : : Get ( ) , TEXT ( " -ZenStoreHost= " ) , Host ) )
{
2023-06-20 10:53:32 -04:00
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Adding connection settings from command line: -ZenStoreHost='%s' " ) , * Host ) ;
2021-07-14 10:40:16 -04:00
if ( ! Host . ParseIntoArray ( HostAddrs , TEXT ( " + " ) , true ) )
{
HostAddrs . Add ( Host ) ;
}
}
2023-06-20 10:53:32 -04:00
if ( FParse : : Value ( CmdLine , TEXT ( " -ZenStorePort= " ) , HostPort ) )
{
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Using connection settings from command line: -ZenStorePort='%d' " ) , HostPort ) ;
}
2021-07-14 10:40:16 -04:00
return HostAddrs . Num ( ) > 0 ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerPlatformFile : : Initialize ( IPlatformFile * Inner , const TCHAR * CmdLine )
{
LowerLevel = Inner ;
2021-07-14 10:40:16 -04:00
if ( HostAddrs . Num ( ) > 0 )
2021-06-15 16:38:03 -04:00
{
2024-04-25 17:44:31 -04:00
# if EXCLUDE_NONSERVER_UE_EXTENSIONS && !WITH_EDITOR
// Extensions for file types that should only ever be on the server. Used to stop unnecessary access to the lower level platform file.
ExcludedNonServerExtensions . Add ( TEXT ( " uasset " ) ) ;
ExcludedNonServerExtensions . Add ( TEXT ( " umap " ) ) ;
ExcludedNonServerExtensions . Add ( TEXT ( " ubulk " ) ) ;
ExcludedNonServerExtensions . Add ( TEXT ( " uexp " ) ) ;
ExcludedNonServerExtensions . Add ( TEXT ( " uptnl " ) ) ;
ExcludedNonServerExtensions . Add ( TEXT ( " ushaderbytecode " ) ) ;
2024-05-01 16:53:53 -04:00
ExcludedNonServerExtensions . Add ( TEXT ( " ini " ) ) ; //special cases of local only ini file needs to be managed as special exclusion
2024-04-25 17:44:31 -04:00
# endif
2024-08-02 05:15:03 -04:00
# if !WITH_EDITOR
// Extensions for file types that will be assumed to be immutable - their time stamp will remain unchanged.
AssumedImmutableTimeStampExtensions . Add ( TEXT ( " uplugin " ) ) ;
# endif
2021-12-10 18:06:39 -05:00
// Don't initialize the connection yet because we want to incorporate project file path information into the initialization.
2023-04-21 08:56:22 -04:00
TUniquePtr < FArchive > ProjectStoreMarkerReader = TryFindProjectStoreMarkerFile ( Inner ) ;
if ( ProjectStoreMarkerReader ! = nullptr )
{
2024-03-24 22:03:42 -04:00
TSharedPtr < FJsonObject > ProjectStoreObject ;
TSharedRef < TJsonReader < UTF8CHAR > > Reader = TJsonReaderFactory < UTF8CHAR > : : Create ( ProjectStoreMarkerReader . Get ( ) ) ;
if ( FJsonSerializer : : Deserialize ( Reader , ProjectStoreObject ) & & ProjectStoreObject . IsValid ( ) )
2023-04-21 08:56:22 -04:00
{
2024-03-24 22:03:42 -04:00
const TSharedPtr < FJsonObject > * ZenServerObjectPtr = nullptr ;
if ( ProjectStoreObject - > TryGetObjectField ( TEXT ( " zenserver " ) , ZenServerObjectPtr ) & & ( ZenServerObjectPtr ! = nullptr ) )
{
const TSharedPtr < FJsonObject > & ZenServerObject = * ZenServerObjectPtr ;
ServerProject = ZenServerObject - > GetStringField ( TEXT ( " projectid " ) ) ;
ServerPlatform = ZenServerObject - > GetStringField ( TEXT ( " oplogid " ) ) ;
2024-08-06 11:00:25 -04:00
if ( ! ZenServerObject - > TryGetStringField ( TEXT ( " baseuri " ) , BaseURI ) )
{
BaseURI . Empty ( ) ;
}
2024-03-24 22:03:42 -04:00
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Using settings from ue.projectstore: ServerProject='%s' and ServerPlatform='%s' " ) , * ServerProject , * ServerPlatform ) ;
}
2023-04-21 08:56:22 -04:00
}
}
2023-06-20 10:53:32 -04:00
if ( FParse : : Value ( CmdLine , TEXT ( " -ZenStoreProject= " ) , ServerProject ) )
{
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Using settings from command line: -ZenStoreProject='%s' " ) , * ServerProject ) ;
}
if ( FParse : : Value ( CmdLine , TEXT ( " -ZenStorePlatform= " ) , ServerPlatform ) )
{
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Using settings from command line: -ZenStorePlatform='%s' " ) , * ServerPlatform ) ;
}
2024-06-11 01:27:00 -04:00
if ( FParse : : Value ( CmdLine , TEXT ( " -ZenStoreBaseURI= " ) , BaseURI ) )
{
UE_LOG ( LogStorageServerPlatformFile , Display , TEXT ( " Using settings from command line: -ZenStoreBaseURI='%s' " ) , * BaseURI ) ;
}
2021-12-10 18:06:39 -05:00
return true ;
}
return false ;
}
void FStorageServerPlatformFile : : InitializeAfterProjectFilePath ( )
{
2022-05-24 02:50:39 -04:00
# if WITH_COTF
UE : : Cook : : ICookOnTheFlyModule & CookOnTheFlyModule = FModuleManager : : LoadModuleChecked < UE : : Cook : : ICookOnTheFlyModule > ( TEXT ( " CookOnTheFly " ) ) ;
CookOnTheFlyServerConnection = CookOnTheFlyModule . GetDefaultServerConnection ( ) ;
if ( CookOnTheFlyServerConnection )
{
CookOnTheFlyServerConnection - > OnMessage ( ) . AddRaw ( this , & FStorageServerPlatformFile : : OnCookOnTheFlyMessage ) ;
ServerProject = CookOnTheFlyServerConnection - > GetZenProjectName ( ) ;
ServerPlatform = CookOnTheFlyServerConnection - > GetPlatformName ( ) ;
}
# endif
2021-12-10 18:06:39 -05:00
Connection . Reset ( new FStorageServerConnection ( ) ) ;
2024-06-11 01:27:00 -04:00
if ( Connection - > Initialize ( HostAddrs , HostPort , MakeBaseURI ( ) ) )
2021-12-10 18:06:39 -05:00
{
if ( SendGetFileListMessage ( ) )
2021-06-15 16:38:03 -04:00
{
2024-08-06 11:00:25 -04:00
if ( bAllowPackageIo )
{
FIoDispatcher & IoDispatcher = FIoDispatcher : : Get ( ) ;
TSharedRef < FStorageServerIoDispatcherBackend > IoDispatcherBackend = MakeShared < FStorageServerIoDispatcherBackend > ( * Connection . Get ( ) ) ;
IoDispatcher . Mount ( IoDispatcherBackend ) ;
2021-09-28 04:00:33 -04:00
# if WITH_COTF
2024-08-06 11:00:25 -04:00
if ( CookOnTheFlyServerConnection )
{
FPackageStore : : Get ( ) . Mount ( MakeShared < FCookOnTheFlyPackageStoreBackend > ( * CookOnTheFlyServerConnection . Get ( ) ) ) ;
}
else
2021-09-28 04:00:33 -04:00
# endif
2024-08-06 11:00:25 -04:00
{
FPackageStore : : Get ( ) . Mount ( MakeShared < FStorageServerPackageStoreBackend > ( * Connection . Get ( ) ) ) ;
}
2022-06-01 02:12:33 -04:00
}
2021-06-15 16:38:03 -04:00
}
else
{
2024-08-06 11:00:25 -04:00
FStringView HostAddr = Connection - > GetHostAddr ( ) ;
UE_LOG ( LogStorageServerPlatformFile , Fatal , TEXT ( " Failed to get file list from Zen at '%.*s' " ) , HostAddr . Len ( ) , HostAddr . GetData ( ) ) ;
2021-06-15 16:38:03 -04:00
}
2024-08-15 10:01:59 -04:00
// optional debugging module depends on a valid Connection
if ( FModuleManager : : Get ( ) . ModuleExists ( TEXT ( " StorageServerClientDebug " ) ) )
{
FModuleManager : : Get ( ) . LoadModule ( " StorageServerClientDebug " ) ;
}
2021-06-15 16:38:03 -04:00
}
2021-12-10 18:06:39 -05:00
else
2021-06-15 16:38:03 -04:00
{
2023-08-23 19:13:18 -04:00
if ( ! FApp : : IsUnattended ( ) )
{
2024-04-27 15:46:34 -04:00
FString FailedConnectionTitle = TEXT ( " Failed to connect " ) ;
FString FailedConnectionText = FString : : Printf ( TEXT (
" Network data streaming failed to connect to any of the following data sources: \n \n %s \n \n "
2024-02-01 14:04:44 -05:00
" This can be due to the sources being offline, the Unreal Zen Storage process not currently running, "
" invalid addresses, firewall blocking, or the sources being on a different network from this device. "
" Please verify that your Unreal Zen Storage process is running using the ZenDashboard utility. "
" If these issues can't be addressed, you can use an installed build without network data streaming by "
" building with the '-pak' argument. This process will now exit. " ) ,
2024-04-27 15:46:34 -04:00
* FString : : Join ( HostAddrs , TEXT ( " \n " ) ) ) ;
FPlatformMisc : : MessageBoxExt ( EAppMsgType : : Ok , * FailedConnectionText , * FailedConnectionTitle ) ;
2023-08-23 19:13:18 -04:00
}
2024-02-01 14:04:44 -05:00
UE_LOG ( LogStorageServerPlatformFile , Error , TEXT ( " Failed to initialize connection to %s " ) , * FString : : Join ( HostAddrs , TEXT ( " \n " ) ) ) ;
FPlatformMisc : : RequestExit ( true ) ;
2021-06-15 16:38:03 -04:00
}
}
bool FStorageServerPlatformFile : : FileExists ( const TCHAR * Filename )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) & & ServerToc . FileExists ( * StorageServerFilename ) )
{
return true ;
}
2024-04-25 17:44:31 -04:00
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > FileExists ( Filename ) : false ;
2021-06-15 16:38:03 -04:00
}
FDateTime FStorageServerPlatformFile : : GetTimeStamp ( const TCHAR * Filename )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) )
{
2024-04-27 16:25:03 -04:00
if ( ServerToc . FileExists ( * StorageServerFilename ) )
2021-06-15 16:38:03 -04:00
{
2024-08-02 05:15:03 -04:00
return IsAssumedImmutableTimeStampFilename ( * StorageServerFilename ) ? GAssumedImmutableTimeStamp : FDateTime : : Now ( ) ;
2021-06-15 16:38:03 -04:00
}
}
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > GetTimeStamp ( Filename ) : FDateTime : : MinValue ( ) ;
2021-06-15 16:38:03 -04:00
}
FDateTime FStorageServerPlatformFile : : GetAccessTimeStamp ( const TCHAR * Filename )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) )
{
2024-04-27 16:25:03 -04:00
if ( ServerToc . FileExists ( * StorageServerFilename ) )
2021-06-15 16:38:03 -04:00
{
2024-08-02 05:15:03 -04:00
return IsAssumedImmutableTimeStampFilename ( * StorageServerFilename ) ? GAssumedImmutableTimeStamp : FDateTime : : Now ( ) ;
2021-06-15 16:38:03 -04:00
}
}
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > GetAccessTimeStamp ( Filename ) : FDateTime : : MinValue ( ) ;
2021-06-15 16:38:03 -04:00
}
int64 FStorageServerPlatformFile : : FileSize ( const TCHAR * Filename )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) )
{
2024-06-06 19:05:45 -04:00
int64 FileSize = ServerToc . GetFileSize ( * StorageServerFilename ) ;
if ( FileSize > STORAGE_SERVER_FILE_UNKOWN_SIZE )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
return FileSize ;
2021-06-15 16:38:03 -04:00
}
}
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > FileSize ( Filename ) : STORAGE_SERVER_FILE_UNKOWN_SIZE ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerPlatformFile : : IsReadOnly ( const TCHAR * Filename )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) & & ServerToc . FileExists ( * StorageServerFilename ) )
{
return true ;
}
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > IsReadOnly ( Filename ) : false ;
2021-06-15 16:38:03 -04:00
}
FFileStatData FStorageServerPlatformFile : : GetStatData ( const TCHAR * FilenameOrDirectory )
{
TStringBuilder < 1024 > StorageServerFilenameOrDirectory ;
if ( MakeStorageServerPath ( FilenameOrDirectory , StorageServerFilenameOrDirectory ) )
{
2024-06-06 19:05:45 -04:00
int64 FileSize = ServerToc . GetFileSize ( * StorageServerFilenameOrDirectory ) ;
if ( FileSize > STORAGE_SERVER_FILE_UNKOWN_SIZE )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
return FFileStatData (
FDateTime : : Now ( ) ,
FDateTime : : Now ( ) ,
FDateTime : : Now ( ) ,
FileSize ,
false ,
true ) ;
2021-06-15 16:38:03 -04:00
}
else if ( ServerToc . DirectoryExists ( * StorageServerFilenameOrDirectory ) )
{
return FFileStatData (
FDateTime : : MinValue ( ) ,
FDateTime : : MinValue ( ) ,
FDateTime : : MinValue ( ) ,
0 ,
true ,
true ) ;
}
}
2024-04-25 17:44:31 -04:00
FFileStatData FileStatData ;
2024-08-15 22:33:11 -04:00
if ( LowerLevel & & IsNonServerFilenameAllowed ( FilenameOrDirectory ) )
2024-04-25 17:44:31 -04:00
{
FileStatData = LowerLevel - > GetStatData ( FilenameOrDirectory ) ;
}
return FileStatData ;
2021-06-15 16:38:03 -04:00
}
2024-06-06 19:05:45 -04:00
IFileHandle * FStorageServerPlatformFile : : InternalOpenFile ( const FIoChunkId & FileChunkId , int64 RawSize , const TCHAR * LocalFilename )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
return new FStorageServerFileHandle ( * this , FileChunkId , RawSize , LocalFilename ) ;
2021-06-15 16:38:03 -04:00
}
IFileHandle * FStorageServerPlatformFile : : OpenRead ( const TCHAR * Filename , bool bAllowWrite )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) )
{
2024-06-06 19:05:45 -04:00
FIoChunkId FileChunkId ;
int64 RawSize = STORAGE_SERVER_FILE_UNKOWN_SIZE ;
if ( ServerToc . GetFileData ( * StorageServerFilename , FileChunkId , RawSize ) )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
return InternalOpenFile ( FileChunkId , RawSize , Filename ) ;
2021-06-15 16:38:03 -04:00
}
}
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > OpenRead ( Filename , bAllowWrite ) : nullptr ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerPlatformFile : : IterateDirectory ( const TCHAR * Directory , IPlatformFile : : FDirectoryVisitor & Visitor )
{
TStringBuilder < 1024 > StorageServerDirectory ;
bool bResult = false ;
2021-06-22 09:34:33 -04:00
if ( MakeStorageServerPath ( Directory , StorageServerDirectory ) & & ServerToc . DirectoryExists ( * StorageServerDirectory ) )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
bResult | = ServerToc . IterateDirectory ( * StorageServerDirectory , [ this , & Visitor ] ( const FIoChunkId & FileChunkId , const TCHAR * FilenameOrDirectory , int64 RawSize )
2021-06-15 16:38:03 -04:00
{
TStringBuilder < 1024 > LocalPath ;
bool bConverted = MakeLocalPath ( FilenameOrDirectory , LocalPath ) ;
check ( bConverted ) ;
2021-08-19 06:42:05 -04:00
const bool bDirectory = ! FileChunkId . IsValid ( ) ;
2023-09-19 16:51:05 -04:00
return Visitor . CallShouldVisitAndVisit ( * LocalPath , bDirectory ) ;
2021-06-15 16:38:03 -04:00
} ) ;
}
2024-08-15 22:33:11 -04:00
else if ( LowerLevel )
2021-06-22 09:34:33 -04:00
{
bResult | = LowerLevel - > IterateDirectory ( Directory , Visitor ) ;
}
2021-06-15 16:38:03 -04:00
return bResult ;
}
bool FStorageServerPlatformFile : : IterateDirectoryStat ( const TCHAR * Directory , FDirectoryStatVisitor & Visitor )
{
TStringBuilder < 1024 > StorageServerDirectory ;
bool bResult = false ;
2021-06-22 09:34:33 -04:00
if ( MakeStorageServerPath ( Directory , StorageServerDirectory ) & & ServerToc . DirectoryExists ( * StorageServerDirectory ) )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
bResult | = ServerToc . IterateDirectory ( * StorageServerDirectory , [ this , & Visitor ] ( const FIoChunkId & FileChunkId , const TCHAR * ServerFilenameOrDirectory , int64 RawSize )
2021-06-15 16:38:03 -04:00
{
TStringBuilder < 1024 > LocalPath ;
bool bConverted = MakeLocalPath ( ServerFilenameOrDirectory , LocalPath ) ;
check ( bConverted ) ;
FFileStatData FileStatData ;
2021-08-19 06:42:05 -04:00
if ( FileChunkId . IsValid ( ) )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
FileStatData = FFileStatData (
FDateTime : : Now ( ) ,
FDateTime : : Now ( ) ,
FDateTime : : Now ( ) ,
RawSize ,
false ,
true ) ;
2021-06-15 16:38:03 -04:00
check ( FileStatData . bIsValid ) ;
}
else
{
FileStatData = FFileStatData (
FDateTime : : MinValue ( ) ,
FDateTime : : MinValue ( ) ,
FDateTime : : MinValue ( ) ,
0 ,
true ,
true ) ;
}
2023-09-19 16:51:05 -04:00
return Visitor . CallShouldVisitAndVisit ( * LocalPath , FileStatData ) ;
2021-06-15 16:38:03 -04:00
} ) ;
}
2024-08-15 22:33:11 -04:00
else if ( LowerLevel )
2021-06-22 09:34:33 -04:00
{
bResult | = LowerLevel - > IterateDirectoryStat ( Directory , Visitor ) ;
}
2021-06-15 16:38:03 -04:00
return bResult ;
}
2024-04-18 08:53:55 -04:00
IMappedFileHandle * FStorageServerPlatformFile : : OpenMapped ( const TCHAR * Filename )
{
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > OpenMapped ( Filename ) : nullptr ;
2024-04-18 08:53:55 -04:00
}
2021-06-15 16:38:03 -04:00
bool FStorageServerPlatformFile : : DirectoryExists ( const TCHAR * Directory )
{
TStringBuilder < 1024 > StorageServerDirectory ;
if ( MakeStorageServerPath ( Directory , StorageServerDirectory ) & & ServerToc . DirectoryExists ( * StorageServerDirectory ) )
{
return true ;
}
2024-08-15 22:33:11 -04:00
return LowerLevel & & LowerLevel - > DirectoryExists ( Directory ) ;
2021-06-15 16:38:03 -04:00
}
FString FStorageServerPlatformFile : : GetFilenameOnDisk ( const TCHAR * Filename )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) & & ServerToc . FileExists ( * StorageServerFilename ) )
{
UE_LOG ( LogStorageServerPlatformFile , Warning , TEXT ( " Attempting to get disk filename of remote file '%s' " ) , Filename ) ;
return Filename ;
}
2024-08-15 22:33:11 -04:00
return ( LowerLevel & & IsNonServerFilenameAllowed ( Filename ) ) ? LowerLevel - > GetFilenameOnDisk ( Filename ) : Filename ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerPlatformFile : : DeleteFile ( const TCHAR * Filename )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) & & ServerToc . FileExists ( * StorageServerFilename ) )
{
return false ;
}
2024-08-15 22:33:11 -04:00
return LowerLevel & & LowerLevel - > DeleteFile ( Filename ) ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerPlatformFile : : MoveFile ( const TCHAR * To , const TCHAR * From )
{
2024-08-15 22:33:11 -04:00
if ( ! LowerLevel )
{
return false ;
}
2021-06-15 16:38:03 -04:00
TStringBuilder < 1024 > StorageServerTo ;
if ( MakeStorageServerPath ( To , StorageServerTo ) & & ServerToc . FileExists ( * StorageServerTo ) )
{
return false ;
}
TStringBuilder < 1024 > StorageServerFrom ;
if ( MakeStorageServerPath ( From , StorageServerFrom ) )
{
2024-06-06 19:05:45 -04:00
FIoChunkId FromFileChunkId ;
int64 FromFileRawSize = STORAGE_SERVER_FILE_UNKOWN_SIZE ;
if ( ServerToc . GetFileData ( * StorageServerFrom , FromFileChunkId , FromFileRawSize ) )
2021-06-15 16:38:03 -04:00
{
TUniquePtr < IFileHandle > ToFile ( LowerLevel - > OpenWrite ( To , false , false ) ) ;
if ( ! ToFile )
{
return false ;
}
2024-06-06 19:05:45 -04:00
TUniquePtr < IFileHandle > FromFile ( InternalOpenFile ( FromFileChunkId , FromFileRawSize , * StorageServerFrom ) ) ;
2021-06-15 16:38:03 -04:00
if ( ! FromFile )
{
return false ;
}
const int64 BufferSize = 64 < < 10 ;
TArray < uint8 > Buffer ;
Buffer . SetNum ( BufferSize ) ;
int64 BytesLeft = FromFile - > Size ( ) ;
while ( BytesLeft )
{
int64 BytesToWrite = FMath : : Min ( BufferSize , BytesLeft ) ;
if ( ! FromFile - > Read ( Buffer . GetData ( ) , BytesToWrite ) )
{
return false ;
}
if ( ! ToFile - > Write ( Buffer . GetData ( ) , BytesToWrite ) )
{
return false ;
}
BytesLeft - = BytesToWrite ;
}
return true ;
}
}
return LowerLevel - > MoveFile ( To , From ) ;
}
bool FStorageServerPlatformFile : : SetReadOnly ( const TCHAR * Filename , bool bNewReadOnlyValue )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) & & ServerToc . FileExists ( * StorageServerFilename ) )
{
return bNewReadOnlyValue ;
}
2024-08-15 22:33:11 -04:00
return LowerLevel & & LowerLevel - > SetReadOnly ( Filename , bNewReadOnlyValue ) ;
2021-06-15 16:38:03 -04:00
}
void FStorageServerPlatformFile : : SetTimeStamp ( const TCHAR * Filename , FDateTime DateTime )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) & & ServerToc . FileExists ( * StorageServerFilename ) )
{
return ;
}
2024-08-15 22:33:11 -04:00
if ( LowerLevel )
{
LowerLevel - > SetTimeStamp ( Filename , DateTime ) ;
}
2021-06-15 16:38:03 -04:00
}
IFileHandle * FStorageServerPlatformFile : : OpenWrite ( const TCHAR * Filename , bool bAppend , bool bAllowRead )
{
TStringBuilder < 1024 > StorageServerFilename ;
if ( MakeStorageServerPath ( Filename , StorageServerFilename ) & & ServerToc . FileExists ( * StorageServerFilename ) )
{
return nullptr ;
}
2024-08-15 22:33:11 -04:00
if ( LowerLevel )
{
LowerLevel - > OpenWrite ( Filename , bAppend , bAllowRead ) ;
}
return nullptr ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerPlatformFile : : CreateDirectory ( const TCHAR * Directory )
{
TStringBuilder < 1024 > StorageServerDirectory ;
if ( MakeStorageServerPath ( Directory , StorageServerDirectory ) & & ServerToc . DirectoryExists ( * StorageServerDirectory ) )
{
return true ;
}
2024-08-15 22:33:11 -04:00
return LowerLevel & & LowerLevel - > CreateDirectory ( Directory ) ;
2021-06-15 16:38:03 -04:00
}
bool FStorageServerPlatformFile : : DeleteDirectory ( const TCHAR * Directory )
{
TStringBuilder < 1024 > StorageServerDirectory ;
if ( MakeStorageServerPath ( Directory , StorageServerDirectory ) & & ServerToc . DirectoryExists ( * StorageServerDirectory ) )
{
return false ;
}
2024-08-15 22:33:11 -04:00
return LowerLevel & & LowerLevel - > DeleteDirectory ( Directory ) ;
2021-06-15 16:38:03 -04:00
}
2022-02-03 07:25:17 -05:00
FString FStorageServerPlatformFile : : ConvertToAbsolutePathForExternalAppForRead ( const TCHAR * Filename )
{
# if PLATFORM_DESKTOP && (UE_GAME || UE_SERVER)
TStringBuilder < 1024 > Result ;
// New code should not end up in here and should instead be written in such a
// way that data can be served from a (remote) server.
// Some data must exist in files on disk such that it can be accessed by external
// APIs. Any such data required by a title should have been written to Saved/Cooked
// at cook time. If a file prefix with UE's canonical ../../../ is requested we
// look inside Saved/Cooked. A read-only filesystem overlay if you will.
static FString * CookedDir = nullptr ;
if ( CookedDir = = nullptr )
{
static FString Inner ;
CookedDir = & Inner ;
Result < < * FPaths : : ProjectDir ( ) ;
Result < < TEXT ( " Saved/Cooked/ " ) ;
Result < < FPlatformProperties : : PlatformName ( ) ;
Result < < TEXT ( " / " ) ;
Inner = Result . ToString ( ) ;
}
else
{
Result < < * ( * CookedDir ) ;
}
const TCHAR * DotSlashSkip = Filename ;
for ( ; * DotSlashSkip = = ' . ' | | * DotSlashSkip = = ' / ' ; + + DotSlashSkip ) ;
if ( PTRINT ( DotSlashSkip - Filename ) = = 9 ) // 9 == ../../../
{
Result < < DotSlashSkip ;
2024-08-15 22:33:11 -04:00
if ( LowerLevel & & LowerLevel - > FileExists ( Result . ToString ( ) ) )
2022-02-03 07:25:17 -05:00
{
2024-06-24 06:49:39 -04:00
return FString : : ConstructFromPtrSize ( Result . GetData ( ) , Result . Len ( ) ) ;
2022-02-03 07:25:17 -05:00
}
}
# endif
2024-08-15 22:33:11 -04:00
if ( LowerLevel )
{
return LowerLevel - > ConvertToAbsolutePathForExternalAppForRead ( Filename ) ;
}
return IStorageServerPlatformFile : : ConvertToAbsolutePathForExternalAppForRead ( Filename ) ;
2022-02-03 07:25:17 -05:00
}
2024-04-25 17:44:31 -04:00
bool FStorageServerPlatformFile : : IsNonServerFilenameAllowed ( FStringView InFilename )
{
bool bAllowed = true ;
# if EXCLUDE_NONSERVER_UE_EXTENSIONS
if ( ! HostAddrs . IsEmpty ( ) & & ( LowerLevel = = & IPlatformFile : : GetPlatformPhysical ( ) ) )
{
2024-05-01 16:53:53 -04:00
bool bRelative = FPathViews : : IsRelativePath ( InFilename ) ;
if ( bRelative )
{
FName Ext = FName ( FPathViews : : GetExtension ( InFilename ) ) ;
bAllowed = ! ExcludedNonServerExtensions . Contains ( Ext ) ;
UE_CLOG ( ! bAllowed , LogStorageServerPlatformFile , VeryVerbose ,
TEXT ( " Access to file '%.*s' is limited to server contents due to file extension being listed in ExcludedNonServerExtensions. " ) ,
InFilename . Len ( ) , InFilename . GetData ( ) )
}
2024-04-25 17:44:31 -04:00
}
# endif
return bAllowed ;
}
2024-08-02 05:15:03 -04:00
bool FStorageServerPlatformFile : : IsAssumedImmutableTimeStampFilename ( FStringView InFilename ) const
{
FName Ext = FName ( FPathViews : : GetExtension ( InFilename ) ) ;
return AssumedImmutableTimeStampExtensions . Contains ( Ext ) ;
}
2021-06-15 16:38:03 -04:00
bool FStorageServerPlatformFile : : MakeStorageServerPath ( const TCHAR * LocalFilenameOrDirectory , FStringBuilderBase & OutPath ) const
{
FStringView LocalEngineDirView ( FPlatformMisc : : EngineDir ( ) ) ;
FStringView LocalProjectDirView ( FPlatformMisc : : ProjectDir ( ) ) ;
FStringView LocalFilenameOrDirectoryView ( LocalFilenameOrDirectory ) ;
bool bValid = false ;
if ( LocalFilenameOrDirectoryView . StartsWith ( LocalEngineDirView , ESearchCase : : IgnoreCase ) )
{
OutPath . Append ( ServerEngineDirView ) ;
OutPath . Append ( LocalFilenameOrDirectoryView . RightChop ( LocalEngineDirView . Len ( ) ) ) ;
bValid = true ;
}
else if ( LocalFilenameOrDirectoryView . StartsWith ( LocalProjectDirView , ESearchCase : : IgnoreCase ) )
{
OutPath . Append ( ServerProjectDirView ) ;
OutPath . Append ( LocalFilenameOrDirectoryView . RightChop ( LocalProjectDirView . Len ( ) ) ) ;
bValid = true ;
}
if ( bValid )
{
Algo : : Replace ( MakeArrayView ( OutPath ) , ' \\ ' , ' / ' ) ;
OutPath . RemoveSuffix ( LocalFilenameOrDirectoryView . EndsWith ( ' / ' ) ? 1 : 0 ) ;
}
return bValid ;
}
bool FStorageServerPlatformFile : : MakeLocalPath ( const TCHAR * ServerFilenameOrDirectory , FStringBuilderBase & OutPath ) const
{
FStringView ServerFilenameOrDirectoryView ( ServerFilenameOrDirectory ) ;
if ( ServerFilenameOrDirectoryView . StartsWith ( ServerEngineDirView , ESearchCase : : IgnoreCase ) )
{
OutPath . Append ( FPlatformMisc : : EngineDir ( ) ) ;
OutPath . Append ( ServerFilenameOrDirectoryView . RightChop ( ServerEngineDirView . Len ( ) ) ) ;
return true ;
}
else if ( ServerFilenameOrDirectoryView . StartsWith ( ServerProjectDirView , ESearchCase : : IgnoreCase ) )
{
OutPath . Append ( FPlatformMisc : : ProjectDir ( ) ) ;
OutPath . Append ( ServerFilenameOrDirectoryView . RightChop ( ServerProjectDirView . Len ( ) ) ) ;
return true ;
}
return false ;
}
bool FStorageServerPlatformFile : : SendGetFileListMessage ( )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( StorageServerPlatformFileGetFileList ) ;
2024-06-06 19:05:45 -04:00
Connection - > FileManifestRequest ( [ & ] ( FIoChunkId Id , FStringView Path , int64 RawSize )
2021-06-15 16:38:03 -04:00
{
2024-06-06 19:05:45 -04:00
ServerToc . AddFile ( Id , Path , RawSize ) ;
2021-06-15 16:38:03 -04:00
} ) ;
return true ;
}
2021-08-19 06:42:05 -04:00
FFileStatData FStorageServerPlatformFile : : SendGetStatDataMessage ( const FIoChunkId & FileChunkId )
2021-06-15 16:38:03 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( StorageServerPlatformFileGetStatData ) ;
2021-08-19 06:42:05 -04:00
const int64 FileSize = Connection - > ChunkSizeRequest ( FileChunkId ) ;
2021-06-15 16:38:03 -04:00
if ( FileSize < 0 )
{
return FFileStatData ( ) ;
}
FDateTime CreationTime = FDateTime : : Now ( ) ;
FDateTime AccessTime = FDateTime : : Now ( ) ;
FDateTime ModificationTime = FDateTime : : Now ( ) ;
return FFileStatData ( CreationTime , AccessTime , ModificationTime , FileSize , false , true ) ;
}
2021-08-19 06:42:05 -04:00
int64 FStorageServerPlatformFile : : SendReadMessage ( uint8 * Destination , const FIoChunkId & FileChunkId , int64 Offset , int64 BytesToRead )
2021-06-15 16:38:03 -04:00
{
TRACE_CPUPROFILER_EVENT_SCOPE ( StorageServerPlatformFileRead ) ;
2024-06-13 07:54:06 -04:00
TIoStatusOr < FIoBuffer > Result = Connection - > ReadChunkRequest ( FileChunkId , Offset , BytesToRead , FIoBuffer ( FIoBuffer : : Wrap , Destination , BytesToRead ) , false ) ;
return Result . IsOk ( ) ? Result . ValueOrDie ( ) . GetSize ( ) : 0 ;
2021-06-15 16:38:03 -04:00
}
2022-01-28 08:30:42 -05:00
bool FStorageServerPlatformFile : : SendMessageToServer ( const TCHAR * Message , IPlatformFile : : IFileServerMessageHandler * Handler )
{
# if WITH_COTF
2022-04-06 02:31:41 -04:00
if ( ! CookOnTheFlyServerConnection - > IsConnected ( ) )
{
return false ;
}
2022-01-28 08:30:42 -05:00
if ( FCString : : Stricmp ( Message , TEXT ( " RecompileShaders " ) ) = = 0 )
{
UE : : Cook : : FCookOnTheFlyRequest Request ( UE : : Cook : : ECookOnTheFlyMessage : : RecompileShaders ) ;
{
TUniquePtr < FArchive > Ar = Request . WriteBody ( ) ;
Handler - > FillPayload ( * Ar ) ;
}
UE : : Cook : : FCookOnTheFlyResponse Response = CookOnTheFlyServerConnection - > SendRequest ( Request ) . Get ( ) ;
if ( Response . IsOk ( ) )
{
TUniquePtr < FArchive > Ar = Response . ReadBody ( ) ;
Handler - > ProcessResponse ( * Ar ) ;
}
return Response . IsOk ( ) ;
}
# endif
return false ;
}
2024-08-06 11:00:25 -04:00
FStringView FStorageServerPlatformFile : : GetHostAddr ( ) const
{
return Connection - > GetHostAddr ( ) ;
}
void FStorageServerPlatformFile : : GetAndResetConnectionStats ( FConnectionStats & OutStats )
{
return Connection - > GetAndResetStats ( OutStats ) ;
}
2021-06-15 16:38:03 -04:00
# if WITH_COTF
void FStorageServerPlatformFile : : OnCookOnTheFlyMessage ( const UE : : Cook : : FCookOnTheFlyMessage & Message )
{
switch ( Message . GetHeader ( ) . MessageType )
{
case UE : : Cook : : ECookOnTheFlyMessage : : FilesAdded :
{
UE_LOG ( LogCookOnTheFly , Verbose , TEXT ( " Received '%s' message " ) , LexToString ( Message . GetHeader ( ) . MessageType ) ) ;
TArray < FString > Filenames ;
TArray < FIoChunkId > ChunkIds ;
{
TUniquePtr < FArchive > Ar = Message . ReadBody ( ) ;
* Ar < < Filenames ;
* Ar < < ChunkIds ;
}
check ( Filenames . Num ( ) = = ChunkIds . Num ( ) ) ;
for ( int32 Idx = 0 , Num = Filenames . Num ( ) ; Idx < Num ; + + Idx )
{
UE_LOG ( LogCookOnTheFly , Verbose , TEXT ( " Adding file '%s' " ) , * Filenames [ Idx ] ) ;
2024-06-06 19:05:45 -04:00
ServerToc . AddFile ( ChunkIds [ Idx ] , Filenames [ Idx ] , STORAGE_SERVER_FILE_UNKOWN_SIZE ) ;
2021-06-15 16:38:03 -04:00
}
break ;
}
}
}
# endif
# endif