UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
IPlatformFileManagedStorageWrapper.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Algo/Find.h"
6#include "Algo/IndexOf.h"
7#include "Async/Async.h"
9#include "Containers/Array.h"
11#include "Containers/Map.h"
14#include "CoreGlobals.h"
15#include "CoreTypes.h"
17#include "HAL/CriticalSection.h"
18#include "HAL/PlatformCrt.h"
19#include "HAL/PlatformString.h"
20#include "Logging/LogCategory.h"
21#include "Logging/LogMacros.h"
22#include "Math/NumericLimits.h"
25#include "Misc/CommandLine.h"
26#include "Misc/ConfigCacheIni.h"
27#include "Misc/EnumClassFlags.h"
28#include "Misc/Optional.h"
29#include "Misc/Parse.h"
30#include "Misc/Paths.h"
31#include "Misc/ScopeLock.h"
32#include "Misc/ScopeRWLock.h"
33#include "Templates/UniquePtr.h"
36
37#include <atomic>
38
40
42{
43 // Same as FPaths::IsUnderDirectory, but assume the paths are already full
44 // Also is *always* case insensitive since we are concerned with filtering and
45 // not whether a directory actually exists.
46 CORE_API bool IsUnderDirectory(const FString& InPath, const FString& InDirectory);
47}
48
50{
51 FString FullFilename;
53
54 bool IsValid() const { return Category >= 0; }
55 explicit operator bool() const { return Category >= 0; }
56
57 // Helpers to avoid unnecessarily attempting to manage multiple times, use empty string as sentinel
58 bool HasFailedTryToManage() const { return FullFilename.IsEmpty(); }
60
61 void Clear()
62 {
64 }
65};
66
68{
69private:
71
72 FCriticalSection* GetLock(const FString& InFilename)
73 {
74 uint32 KeyHash = GetTypeHash(InFilename);
75
76 FScopeLock Lock(&FileLockMapCS);
77
78 FLockData& LockData = FileLockMap.FindOrAddByHash(KeyHash, InFilename);
79 ++LockData.RefCount;
80
81 return LockData.CS.Get();
82 }
83
84 void ReleaseLock(const FString& InFilename)
85 {
86 uint32 KeyHash = GetTypeHash(InFilename);
87
88 FScopeLock Lock(&FileLockMapCS);
89
90 FLockData* LockData = FileLockMap.FindByHash(KeyHash, InFilename);
92
93 --LockData->RefCount;
94
95 if (LockData->RefCount == 0)
96 {
97 FileLockMap.RemoveByHash(KeyHash, InFilename);
98 }
99 }
100
101private:
102
103 struct FLockData
104 {
106 int32 RefCount = 0;
107 };
108
109 TMap<FString, FLockData> FileLockMap;
110 FCriticalSection FileLockMapCS;
111};
112
142
144{
145 None = 0,
146 OnlyUpdateIfLess = (1 << 0),
147 RespectQuota = (1 << 1)
148};
150
152{
153public:
155 : CategoryName(MoveTemp(InCategoryName))
156 , Directories(MoveTemp(InDirectories))
157 , StorageQuota(InQuota)
158 , OptionalStorageQuota(InOptionalQuota)
159 {
160 check(OptionalStorageQuota < StorageQuota || StorageQuota <= 0); // optional storage quota should be a subset of the total storage quota
161 }
162
163 const FString& GetCategoryName() const
164 {
165 return CategoryName;
166 }
167
169 {
170 return StorageQuota;
171 }
172
174 {
175 return OptionalStorageQuota;
176 }
177
179 {
180 return UsedQuota;
181 }
182
184 {
185 int64 ActualStorageQuota = StorageQuota;
186 if (ActualStorageQuota < 0)
187 {
189 }
190 return ActualStorageQuota - UsedQuota;
191 }
192
193 bool IsInCategory(const FString& Path) const
194 {
195 return ShouldManageFile(Path);
196 }
197
198 bool IsCategoryFull() const
199 {
200 return GetAvailableSize() <= 0;
201 }
202
204 {
205 uint32 KeyHash = GetTypeHash(Filename);
206
207 int64 OldFileSize = 0;
208 {
209 FReadScopeLock ScopeLock(FileSizesLock);
210 int64* pOldFileSize = FileSizes.FindByHash(KeyHash, Filename);
211 if (pOldFileSize)
212 {
214 }
215 }
216
217 EPersistentStorageManagerFileSizeFlags Result = TryUpdateQuota(OldFileSize, FileSize, Flags);
219 {
220 FWriteScopeLock ScopeLock(FileSizesLock);
221 FileSizes.AddByHash(KeyHash, Filename, FileSize);
222
223 UE_LOG(LogPlatformFileManagedStorage, Verbose, TEXT("File %s is added to category %s"), *Filename, *CategoryName);
224 }
225
226 return Result;
227 }
228
229 bool RemoveFile(const FString& Filename)
230 {
231 FileSizesLock.WriteLock(); // FWriteScopeLock doesn't have an early unlock :(
232
233 int64 OldSize;
234 if (FileSizes.RemoveAndCopyValue(Filename, OldSize))
235 {
236 FileSizesLock.WriteUnlock();
237
238 UsedQuota -= OldSize;
239
240 UE_LOG(LogPlatformFileManagedStorage, Verbose, TEXT("File %s is removed from category %s"), *Filename, *CategoryName);
241
242 return true;
243 }
244
245 FileSizesLock.WriteUnlock();
246 return false;
247 }
248
249 const TArray<FString>& GetDirectories() const { return Directories; }
250
252 {
253 FString Print() const
254 {
255 if (TotalSize < 0)
256 {
257 return FString::Printf(TEXT("Category %s: %.3f MiB (%" INT64_FMT ") / unlimited used"), *CategoryName, (float)UsedSize / 1024.f / 1024.f, UsedSize);
258 }
259 else
260 {
261 return FString::Printf(TEXT("Category %s: %.3f MiB (%" INT64_FMT ") / %.3f MiB used"), *CategoryName, (float)UsedSize / 1024.f / 1024.f, UsedSize, (float)TotalSize / 1024.f / 1024.f);
262 }
263 }
264
271 };
272
273 // Note this will not be accurate if the category is being modified while this is called but it is low level thread safe
275 {
276 FReadScopeLock ScopeLock(FileSizesLock);
277 return CategoryStat{ CategoryName, UsedQuota, StorageQuota, OptionalStorageQuota, FileSizes, Directories };
278 }
279
280 FManagedStorageFileLockRegistry& GetLockRegistry() { return FileLockRegistry; }
281
282private:
284 {
285 check(OldFileSize >= 0);
286 check(NewFileSize >= 0);
287
289 {
290 UsedQuota -= (OldFileSize - NewFileSize);
292 }
293
295 {
297 }
298
300 {
301 int64 OldUsedQuota = UsedQuota;
303 do
304 {
306 if (NewUsedQuota > StorageQuota)
307 {
309 }
310 } while (!UsedQuota.compare_exchange_weak(OldUsedQuota, NewUsedQuota));
311
313 }
314
315 UsedQuota += (NewFileSize - OldFileSize);
317 }
318
319 bool ShouldManageFile(const FString& Filename) const
320 {
321 for (const FString& Directory : Directories)
322 {
323 if (ManagedStorageInternal::IsUnderDirectory(Filename, Directory))
324 {
325 return true;
326 }
327 }
328
329 return false;
330 }
331
332private:
333 const FString CategoryName;
334 const TArray<FString> Directories;
335
336 const int64 StorageQuota = -1;
337 const int64 OptionalStorageQuota = 0;
338
339 std::atomic<int64> UsedQuota{ 0 };
340
341 TMap<FString, int64> FileSizes;
342 mutable FRWLock FileSizesLock;
343
344 FManagedStorageFileLockRegistry FileLockRegistry;
345};
346
347// NOTE: CORE_API is not used on the whole class because then FCategoryInfo is exported which appears to force the generation
348// of copy constructors for FPersistentStorageCategory which causes a compile error because std::atomic can't be copied.
350{
351public:
352 static bool IsReady()
353 {
354 // FPersistentStorageManager depends on FPaths which depends on the command line being initialized.
355 // FPersistentStorageManager depends on GConfig.
356 // FPersistentStorageManager can't be constructed until its dependencies are ready
357 // FPersistentStorageManager will try and allocate memory during a crash but this could hang during log file flushing
359 }
360
363
365
367 {
368 if (bInitialized)
369 {
370 return;
371 }
372
373 // Check to add files
375 {
377 {
378 public:
380 {}
381
382 virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory)
383 {
384 if (FilenameOrDirectory && !bIsDirectory)
385 {
388 {
390
391 // This must be done under the lock because another thread may be modifying or deleting the file while we scan
393 if (ensureAlways(StatData.bIsValid))
394 {
395 if (!ensureAlways(StatData.FileSize >= 0))
396 {
397 UE_LOG(LogPlatformFileManagedStorage, Error, TEXT("Invalid File Size for %s!"), FilenameOrDirectory);
398 }
399
400 Man.AddOrUpdateFile(File, StatData.FileSize);
401 }
402 else
403 {
404 UE_LOG(LogPlatformFileManagedStorage, Error, TEXT("Invalid Stat Data for %s!"), FilenameOrDirectory);
405 }
406 }
407 }
408
409 return true;
410 }
411 };
412
413 FInitStorageVisitor Visitor;
414
415 for (const FString& RootDir : FPersistentStorageManager::Get().GetRootDirectories())
416 {
417 UE_LOG(LogPlatformFileManagedStorage, Display, TEXT("Scan directory %s"), *RootDir);
418
420 }
421
422 UE_LOG(LogPlatformFileManagedStorage, Display, TEXT("Done scanning root directories"));
423 });
424
425 bInitialized = true;
426 }
427
428 FPersistentManagedFile TryManageFile(const FString& Filename)
429 {
432
433 TryManageFileInternal(OutFile);
434
435 return OutFile;
436 }
437
439 {
442
443 TryManageFileInternal(OutFile);
444
445 return OutFile;
446 }
447
449 {
450 check(!InOutFile.IsValid());
451 TryManageFileInternal(InOutFile);
452 if (InOutFile.IsValid())
453 {
454 return true;
455 }
456 InOutFile.SetHasFailedTryToManage();
457 return false;
458 }
459
460private:
461 void TryManageFileInternal(FPersistentManagedFile& OutFile)
462 {
463 int32 CategoryIndex = 0;
464 for (const FPersistentStorageCategory& Category : Categories.GetCategories())
465 {
466 if (Category.IsInCategory(OutFile.FullFilename))
467 {
468 OutFile.Category = CategoryIndex;
469 return;
470 }
471 ++CategoryIndex;
472 }
473
474 bool bIsUnderRootDir = !!Algo::FindByPredicate(RootDirectories.GetRootDirectories(), [&OutFile](const FString& RootDir) { return ManagedStorageInternal::IsUnderDirectory(OutFile.FullFilename, RootDir); });
475 if (bIsUnderRootDir)
476 {
477 OutFile.Category = Categories.GetDefaultCategoryIndex();
478 }
479 }
480
481public:
484 {
485 if (!File)
486 {
488 }
489
490 return Categories.GetCategories()[File.Category].AddOrUpdateFile(File.FullFilename, FileSize, Flags);
491 }
492
494 {
495 if (!File)
496 {
497 return false;
498 }
499
500 return Categories.GetCategories()[File.Category].RemoveFile(File.FullFilename);
501 }
502
504 {
506 for(const FPersistentStorageCategory& Category : Categories.GetCategories())
507 {
508 TotalUsedSize += Category.GetUsedSize();
509 }
510
511 return TotalUsedSize;
512 }
513
523 bool GetPersistentStorageUsage(FString Path, int64& UsedSpace, int64 &RemainingSpace, int64& Quota, int64* OptionalQuota = nullptr)
524 {
525 FString FullPath = FPaths::ConvertRelativePathToFull(MoveTemp(Path));
526
527 for (const FPersistentStorageCategory& Category : Categories.GetCategories())
528 {
529 if (Category.IsInCategory(FullPath))
530 {
531 UsedSpace = Category.GetUsedSize();
532 RemainingSpace = Category.GetAvailableSize();
533 Quota = Category.GetCategoryQuota();
534 if (OptionalQuota != nullptr)
535 {
536 *OptionalQuota = Category.GetCategoryOptionalQuota();
537 }
538 return true;
539 }
540 }
541 return false;
542 }
543
545 {
546 FPersistentStorageCategory* Category = Algo::FindBy(Categories.GetCategories(), InCategory, [](const FPersistentStorageCategory& Cat) { return Cat.GetCategoryName(); });
547 if (Category)
548 {
549 UsedSpace = Category->GetUsedSize();
550 RemainingSpace = Category->GetAvailableSize();
551 Quota = Category->GetCategoryQuota();
552 if (OptionalQuota != nullptr)
553 {
554 *OptionalQuota = Category->GetCategoryOptionalQuota();
555 }
556 return true;
557 }
558 return false;
559 }
560
567 bool GetPersistentStorageSize(int64& UsedSpace, int64& RequiredSpace, int64& OptionalSpace) const
568 {
569 for (const FPersistentStorageCategory& Category : Categories.GetCategories())
570 {
571 UsedSpace += Category.GetUsedSize();
572 RequiredSpace += Category.GetCategoryQuota();
573 OptionalSpace += Category.GetCategoryOptionalQuota();
574 }
575 return true;
576 }
577
578 bool IsInitialized() const
579 {
580 return bInitialized;
581 }
582
584 {
585 if (!File)
586 {
587 return false;
588 }
589
590 return Categories.GetCategories()[File.Category].IsCategoryFull();
591 }
592
594 {
596 CategoryStats.Reserve(Categories.GetCategories().Num());
597
598 for (const FPersistentStorageCategory& Category : Categories.GetCategories())
599 {
600 CategoryStats.Add(Category.GetCategoryName(), Category.GetStat());
601 }
602
603 return CategoryStats;
604 }
605
607 {
609
610 for (const FPersistentStorageCategory& Category : Categories.GetCategories())
611 {
612 if (Category.GetCategoryName() == InCategory)
613 {
614 Result.Emplace(Category.GetStat());
615 break;
616 }
617 }
618
619 return Result;
620 }
621
622 TArrayView<const FString> GetRootDirectories() const { return RootDirectories.GetRootDirectories(); }
623
624private:
625 friend class FManagedStorageScopeFileLock; // For access to Categories
626
627 bool bInitialized;
628
629 // Top level of all managed storage
630 // Wrapper to prevent changing or resizing after init
631 struct FRootDirInfo
632 {
633 private:
634 TArray<FString> RootDirectories;
635
636 public:
638 TArrayView<const FString> GetRootDirectories() const { return MakeArrayView(RootDirectories); }
639 };
640 FRootDirInfo RootDirectories;
641
642 // Wrapper for Category Array to prevent resizing after init
643 struct FCategoryInfo
644 {
645 private:
647 int32 DefaultCategory = -1;
648
649 public:
651
652 TArrayView<FPersistentStorageCategory> GetCategories() { return MakeArrayView(Categories); }
653 TArrayView<const FPersistentStorageCategory> GetCategories() const { return MakeArrayView(Categories); }
654
655 FPersistentStorageCategory* GetDefaultCategory() { return DefaultCategory >= 0 ? &Categories[DefaultCategory] : nullptr; }
656 const FPersistentStorageCategory* GetDefaultCategory() const { return DefaultCategory >= 0 ? &Categories[DefaultCategory] : nullptr; }
657
658 int32 GetDefaultCategoryIndex() const { return DefaultCategory; }
659 };
660 FCategoryInfo Categories;
661
662 static FCategoryInfo InitCategories();
663};
664
665// Only write handle
667{
668private:
669 bool TryManageFile()
670 {
671 if (File.IsValid())
672 {
673 return true;
674 }
675
677 {
679 }
680
681 return false;
682 }
683
684public:
690
692 {
693 if (!TryManageFile())
694 {
695 return;
696 }
697
699
701 }
702
703 virtual int64 Tell() override
704 {
705 return FileHandle->Tell();
706 }
707
708 virtual bool Seek(int64 NewPosition) override
709 {
710 return FileHandle->Seek(NewPosition);
711 }
712
713 virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd = 0) override
714 {
715 return FileHandle->SeekFromEnd(NewPositionRelativeToEnd);
716 }
717
718 virtual bool Read(uint8* Destination, int64 BytesToRead) override
719 {
720 return FileHandle->Read(Destination, BytesToRead);
721 }
722
723 virtual bool ReadAt(uint8* Destination, int64 BytesToRead, int64 Offset) override
724 {
725 return FileHandle->ReadAt(Destination, BytesToRead, Offset);
726 }
727
728 virtual bool Write(const uint8* Source, int64 BytesToWrite) override
729 {
730 if (!TryManageFile())
731 {
732 return FileHandle->Write(Source, BytesToWrite);
733 }
734
736
738
739 int64 NewSize = FMath::Max(FileHandle->Tell() + BytesToWrite, FileHandle->Size());
740
744 {
745 UE_LOG(LogPlatformFileManagedStorage, Error, TEXT("Failed to write to file %s. The category of the file has reach quota limit in peristent storage."), *File.FullFilename);
746 return false;
747 }
748
749 bool bSuccess = FileHandle->Write(Source, BytesToWrite);
750 if (!bSuccess)
751 {
752 int64 FileSize = FileHandle->Size();
753 if (ensureAlways(FileSize >= 0))
754 {
756 }
757 }
758
759 return bSuccess;
760 }
761
762 virtual int64 Size() override
763 {
764 return FileHandle->Size();
765 }
766
767 virtual bool Flush(const bool bFullFlush = false) override
768 {
769 const bool bOldIsValid = File.IsValid();
770 if (!TryManageFile())
771 {
772 return FileHandle->Flush(bFullFlush);
773 }
774
776
777 const bool bSuccess = FileHandle->Flush(bFullFlush);
778 const bool bForceSizeUpdate = !bOldIsValid;
780 {
781 int64 FileSize = FileHandle->Size();
782 if (ensureAlways(FileSize >= 0))
783 {
785 }
786 }
787
788 return bSuccess;
789 }
790
791 virtual bool Truncate(int64 NewSize) override
792 {
793 if (!TryManageFile())
794 {
795 return FileHandle->Truncate(NewSize);
796 }
797
799
801
802 int64 FileSize = FileHandle->Size();
803
804 if (NewSize <= FileSize)
805 {
806 bool bSuccess = FileHandle->Truncate(NewSize);
807 FileSize = FileHandle->Size();
809 return bSuccess;
810 }
811
813 {
814 UE_LOG(LogPlatformFileManagedStorage, Error, TEXT("Failed to truncate file %s. The category of the file has reach quota limit in peristent storage."), *File.FullFilename);
815 return false;
816 }
817
818 if (!FileHandle->Truncate(NewSize))
819 {
820 FileSize = FileHandle->Size();
822 return false;
823 }
824
825 return true;
826 }
827
828 virtual void ShrinkBuffers() override
829 {
830 FileHandle->ShrinkBuffers();
831 }
832
833private:
834 TUniquePtr<IFileHandle> FileHandle;
836};
837
838// NOTE: This is templated rather than a polymorphic wrapper because a lot code expects the physical layer not to be a wrapper.
839// It also has the benefit of not needing updating every time a new function is added to IPlatformFile.
840template<class BaseClass>
841class TManagedStoragePlatformFile : public BaseClass
842{
843private:
844 static bool IsReady()
845 {
846 // FManagedStoragePlatformFile will just pass through to LowerLevel until FPersistentStorageManager is ready
848 }
849
850public:
851
853 {
854 // NOTE: using LowLevelFatalError here because UE_LOG is not yet available at static init time
855
856 // Book keeping is handled by the base implementation calling DeleteFile()
857 bool bUsingGenericDeleteDirectoryRecursively = (&BaseClass::DeleteDirectoryRecursively == &IPlatformFile::DeleteDirectoryRecursively);
860 {
861 LowLevelFatalError(TEXT("TManagedStoragePlatformFile cannot track all deletes!"));
862 }
863
864 // Book keeping is handled by DeleteFile() and CopyFile() which will be called by the base implementation
865 bool bUsingGenericCopyDirectoryTree = (&BaseClass::CopyDirectoryTree == &IPlatformFile::CopyDirectoryTree);
868 {
869 LowLevelFatalError(TEXT("TManagedStoragePlatformFile cannot track all deletes and copies!"));
870 }
871 }
872
873 virtual bool DeleteFile(const TCHAR* Filename) override
874 {
875 if (!IsReady())
876 {
877 return BaseClass::DeleteFile(Filename);
878 }
879
881
882 FPersistentManagedFile ManagedFile = Manager.TryManageFile(Filename);
883
885
886 bool bSuccess = BaseClass::DeleteFile(Filename);
887 if (bSuccess)
888 {
889 Manager.RemoveFileFromManager(ManagedFile);
890 }
891
892 return bSuccess;
893 }
894
895 virtual bool DeleteFiles(const TArrayView<const TCHAR*>& Filenames) override
896 {
897 if (!IsReady())
898 {
899 return BaseClass::DeleteFiles(Filenames);
900 }
901
903
906 for (const TCHAR* Filename : Filenames)
907 {
908 FPersistentManagedFile ManagedFile = Manager.TryManageFile(Filename);
909 FileLocks.Emplace(ManagedFile, MoveTemp(ManagedFile));
910 }
911
912 bool bSuccess = BaseClass::DeleteFiles(Filenames);
913
914 const int32 Count = Filenames.Num();
915 for (int32 i = 0; i < Count; i++)
916 {
917 if (!BaseClass::FileExists(Filenames[i]))
918 {
919 UE_LOG(LogPlatformFileManagedStorage, Display, TEXT("Removing deleted file %s."), *(FileLocks[i].Key.FullFilename));
920 Manager.RemoveFileFromManager(FileLocks[i].Key);
921 }
922 else
923 {
924 UE_LOG(LogPlatformFileManagedStorage, Warning, TEXT("Not removing deleted file %s. It still exists on disk."), *(FileLocks[i].Key.FullFilename));
925 }
926 }
927
928 return bSuccess;
929 }
930
931 virtual bool MoveFile(const TCHAR* To, const TCHAR* From) override
932 {
933 if (!IsReady())
934 {
935 return BaseClass::MoveFile(To, From);
936 }
937
939
942
945
946 const int64 SizeFrom = this->FileSize(From);
947 if (SizeFrom < 0)
948 {
949 return false;
950 }
951
954 {
955 UE_LOG(LogPlatformFileManagedStorage, Error, TEXT("Failed to move file to %s. The target category of the destination has reach quota limit in peristent storage."), To);
956 return false;
957 }
958
959 bool bSuccess = BaseClass::MoveFile(To, From);
960 if (bSuccess)
961 {
964 }
965 else
966 {
967 // On some implementations MoveFile can operate across volumes, so don't make assumptions about the state of
968 // of the file system in the case of failure.
969
970 if (ManagedFrom && !this->FileExists(From))
971 {
973 }
974
975 if (ManagedTo)
976 {
977 if (!this->FileExists(To))
978 {
980 }
981 else
982 {
983 const int64 SizeTo = this->FileSize(To);
984 if (ensureAlways(SizeTo >= 0))
985 {
987 }
988 else
989 {
991 }
992 }
993 }
994 }
995
996 return bSuccess;
997 }
998
999 virtual IFileHandle* OpenWrite(const TCHAR* Filename, bool bAppend = false, bool bAllowRead = false) override
1000 {
1001 if (!IsReady())
1002 {
1003 // Always wrap handle if not ready. FManagedStorageFileWriteHandle will start managing the file
1004 // internally when we become ready.
1005 IFileHandle* InnerHandle = BaseClass::OpenWrite(Filename, bAppend, bAllowRead);
1006 if (!InnerHandle)
1007 {
1008 return nullptr;
1009 }
1010
1011 FPersistentManagedFile ManagedFile;
1012 ManagedFile.FullFilename = FPaths::ConvertRelativePathToFull(Filename);
1013 return new FManagedStorageFileWriteHandle(InnerHandle, MoveTemp(ManagedFile));
1014 }
1015
1017
1018 FPersistentManagedFile ManagedFile = Manager.TryManageFile(Filename);
1019
1020 if (Manager.IsCategoryForFileFull(ManagedFile))
1021 {
1022 UE_LOG(LogPlatformFileManagedStorage, Error, TEXT("Failed to open file %s for write. The category of the file has reach quota limit in peristent storage."), Filename);
1023 return nullptr;
1024 }
1025
1027
1028 IFileHandle* InnerHandle = BaseClass::OpenWrite(Filename, bAppend, bAllowRead);
1029 if (!InnerHandle)
1030 {
1031 return nullptr;
1032 }
1033
1034 Manager.AddOrUpdateFile(ManagedFile, InnerHandle->Size());
1035 if (ManagedFile)
1036 {
1037 return new FManagedStorageFileWriteHandle(InnerHandle, MoveTemp(ManagedFile));
1038 }
1039 else
1040 {
1041 return InnerHandle;
1042 }
1043 }
1044
1046 {
1047 if (!IsReady())
1048 {
1049 return BaseClass::CopyFile(To, From, ReadFlags, WriteFlags);
1050 }
1051
1053
1056
1059
1060 const int64 SizeFrom = this->FileSize(From);
1061 if (SizeFrom < 0)
1062 {
1063 return false;
1064 }
1065
1068 {
1069 UE_LOG(LogPlatformFileManagedStorage, Error, TEXT("Failed to copy file to %s. The category of the destination has reach quota limit in peristent storage."), To);
1070 return false;
1071 }
1072
1073 bool bSuccess = BaseClass::CopyFile(To, From, ReadFlags, WriteFlags);
1074 if (bSuccess)
1075 {
1077 }
1078 else if(ManagedTo)
1079 {
1080 if (!this->FileExists(To))
1081 {
1083 }
1084 else
1085 {
1086 const int64 SizeTo = this->FileSize(To);
1087 if (ensureAlways(SizeTo >= 0))
1088 {
1090 }
1091 else
1092 {
1094 }
1095 }
1096 }
1097
1098 return bSuccess;
1099 }
1100};
#define INT64_FMT
Definition AndroidPlatformString.h:59
constexpr auto MakeArrayView(OtherRangeType &&Other)
Definition ArrayView.h:873
#define ensureAlways( InExpression)
Definition AssertionMacros.h:466
#define check(expr)
Definition AssertionMacros.h:314
#define LowLevelFatalError(Format,...)
Definition AssertionMacros.h:554
#define verify(expr)
Definition AssertionMacros.h:319
void AsyncTask(ENamedThreads::Type Thread, TUniqueFunction< void()> Function)
Definition Async.cpp:54
bool bSuccess
Definition ConvexDecomposition3.cpp:819
FConfigCacheIni * GConfig
Definition CoreGlobals.cpp:54
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::FPlatformRecursiveMutex FCriticalSection
Definition CriticalSection.h:53
DIRECTLINK_API Display
Definition DirectLinkLog.h:8
constexpr bool EnumHasAnyFlags(Enum Flags, Enum Contains)
Definition EnumClassFlags.h:35
#define ENUM_CLASS_FLAGS(Enum)
Definition EnumClassFlags.h:6
EPlatformFileRead
Definition GenericPlatformFile.h:59
EPlatformFileWrite
Definition GenericPlatformFile.h:70
EPersistentStorageManagerFileSizeFlags
Definition IPlatformFileManagedStorageWrapper.h:144
void Init()
Definition LockFreeList.h:4
#define DECLARE_LOG_CATEGORY_EXTERN(CategoryName, DefaultVerbosity, CompileTimeVerbosity)
Definition LogMacros.h:361
#define UE_LOG(CategoryName, Verbosity, Format,...)
Definition LogMacros.h:270
const bool
Definition NetworkReplayStreaming.h:178
#define MAX_int64
Definition NumericLimits.h:26
decltype(auto) Visit(Func &&Callable, Variants &&... Args)
Definition TVariant.h:271
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
FRWLock Lock
Definition UnversionedPropertySerialization.cpp:921
uint32 Offset
Definition VulkanMemory.cpp:4033
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
bool IsReadyForUse()
Definition ConfigCacheIni.h:1268
Definition IPlatformFileManagedStorageWrapper.h:68
Definition IPlatformFileManagedStorageWrapper.h:667
virtual int64 Tell() override
Definition IPlatformFileManagedStorageWrapper.h:703
virtual int64 Size() override
Definition IPlatformFileManagedStorageWrapper.h:762
virtual ~FManagedStorageFileWriteHandle()
Definition IPlatformFileManagedStorageWrapper.h:691
virtual void ShrinkBuffers() override
Definition IPlatformFileManagedStorageWrapper.h:828
virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd=0) override
Definition IPlatformFileManagedStorageWrapper.h:713
virtual bool Write(const uint8 *Source, int64 BytesToWrite) override
Definition IPlatformFileManagedStorageWrapper.h:728
virtual bool ReadAt(uint8 *Destination, int64 BytesToRead, int64 Offset) override
Definition IPlatformFileManagedStorageWrapper.h:723
FManagedStorageFileWriteHandle(IFileHandle *InFileHandle, FPersistentManagedFile InFile)
Definition IPlatformFileManagedStorageWrapper.h:685
virtual bool Truncate(int64 NewSize) override
Definition IPlatformFileManagedStorageWrapper.h:791
virtual bool Flush(const bool bFullFlush=false) override
Definition IPlatformFileManagedStorageWrapper.h:767
virtual bool Seek(int64 NewPosition) override
Definition IPlatformFileManagedStorageWrapper.h:708
virtual bool Read(uint8 *Destination, int64 BytesToRead) override
Definition IPlatformFileManagedStorageWrapper.h:718
Definition IPlatformFileManagedStorageWrapper.h:114
FManagedStorageScopeFileLock(FPersistentManagedFile InManagedFile)
Definition IPlatformFileManagedStorageWrapper.h:116
FManagedStorageScopeFileLock(const FManagedStorageScopeFileLock &)=delete
~FManagedStorageScopeFileLock()
Definition IPlatformFileManagedStorageWrapper.h:122
FManagedStorageScopeFileLock & operator=(const FManagedStorageScopeFileLock &)=delete
CORE_API void Unlock()
Definition IPlatformFileManagedStorageWrapper.cpp:181
FManagedStorageScopeFileLock & operator=(FManagedStorageScopeFileLock &&InOther)=delete
FManagedStorageScopeFileLock(FManagedStorageScopeFileLock &&InOther)=delete
static CORE_API FString ConvertRelativePathToFull(const FString &InPath)
Definition Paths.cpp:1586
Definition IPlatformFileManagedStorageWrapper.h:350
FPersistentManagedFile TryManageFile(FString &&Filename)
Definition IPlatformFileManagedStorageWrapper.h:438
int64 GetTotalUsedSize() const
Definition IPlatformFileManagedStorageWrapper.h:503
bool IsInitialized() const
Definition IPlatformFileManagedStorageWrapper.h:578
EPersistentStorageManagerFileSizeFlags AddOrUpdateFile(const FPersistentManagedFile &File, const int64 FileSize, EPersistentStorageManagerFileSizeFlags Flags=EPersistentStorageManagerFileSizeFlags::None)
Definition IPlatformFileManagedStorageWrapper.h:482
static bool IsReady()
Definition IPlatformFileManagedStorageWrapper.h:352
TMap< FString, FPersistentStorageCategory::CategoryStat > GenerateCategoryStats() const
Definition IPlatformFileManagedStorageWrapper.h:593
void Initialize()
Definition IPlatformFileManagedStorageWrapper.h:366
static CORE_API FPersistentStorageManager & Get()
Definition IPlatformFileManagedStorageWrapper.cpp:200
bool GetPersistentStorageUsageByCategory(const FString &InCategory, int64 &UsedSpace, int64 &RemainingSpace, int64 &Quota, int64 *OptionalQuota=nullptr)
Definition IPlatformFileManagedStorageWrapper.h:544
FPersistentStorageManager()
Definition IPlatformFileManagedStorageWrapper.cpp:207
TArrayView< const FString > GetRootDirectories() const
Definition IPlatformFileManagedStorageWrapper.h:622
bool IsCategoryForFileFull(const FPersistentManagedFile &File) const
Definition IPlatformFileManagedStorageWrapper.h:583
FPersistentManagedFile TryManageFile(const FString &Filename)
Definition IPlatformFileManagedStorageWrapper.h:428
TOptional< FPersistentStorageCategory::CategoryStat > GetCategoryStat(const FString &InCategory) const
Definition IPlatformFileManagedStorageWrapper.h:606
bool GetPersistentStorageSize(int64 &UsedSpace, int64 &RequiredSpace, int64 &OptionalSpace) const
Returns any additional required free space and optional free space.
Definition IPlatformFileManagedStorageWrapper.h:567
bool GetPersistentStorageUsage(FString Path, int64 &UsedSpace, int64 &RemainingSpace, int64 &Quota, int64 *OptionalQuota=nullptr)
Definition IPlatformFileManagedStorageWrapper.h:523
bool TryManageFile(FPersistentManagedFile &InOutFile)
Definition IPlatformFileManagedStorageWrapper.h:448
bool RemoveFileFromManager(FPersistentManagedFile &File)
Definition IPlatformFileManagedStorageWrapper.h:493
Definition ScopeRWLock.h:93
Definition ScopeLock.h:141
Definition ScopeRWLock.h:114
Definition GenericPlatformFile.h:117
virtual bool ReadAt(uint8 *Destination, int64 BytesToRead, int64 Offset)=0
virtual void ShrinkBuffers()
Definition GenericPlatformFile.h:179
virtual bool Flush(const bool bFullFlush=false)=0
virtual bool Seek(int64 NewPosition)=0
virtual bool Read(uint8 *Destination, int64 BytesToRead)=0
virtual int64 Tell()=0
virtual bool Truncate(int64 NewSize)=0
virtual bool Write(const uint8 *Source, int64 BytesToWrite)=0
virtual bool SeekFromEnd(int64 NewPositionRelativeToEnd=0)=0
virtual CORE_API int64 Size()
Definition GenericPlatformFile.cpp:578
Definition GenericPlatformFile.h:576
virtual CORE_API bool IterateDirectoryRecursively(const TCHAR *Directory, FDirectoryVisitor &Visitor)
Definition GenericPlatformFile.cpp:677
static CORE_API IPlatformFile & GetPlatformPhysical()
Definition IOSPlatformFile.cpp:1045
virtual FFileStatData GetStatData(const TCHAR *FilenameOrDirectory)=0
virtual CORE_API bool DeleteDirectoryRecursively(const TCHAR *Directory)
Definition GenericPlatformFile.cpp:822
virtual CORE_API bool CopyDirectoryTree(const TCHAR *DestinationDirectory, const TCHAR *Source, bool bOverwriteAllExisting)
Definition GenericPlatformFile.cpp:913
Definition ArrayView.h:139
Definition Array.h:670
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition IPlatformFileManagedStorageWrapper.h:842
virtual bool MoveFile(const TCHAR *To, const TCHAR *From) override
Definition IPlatformFileManagedStorageWrapper.h:931
TManagedStoragePlatformFile()
Definition IPlatformFileManagedStorageWrapper.h:852
virtual bool CopyFile(const TCHAR *To, const TCHAR *From, EPlatformFileRead ReadFlags=EPlatformFileRead::None, EPlatformFileWrite WriteFlags=EPlatformFileWrite::None) override
Definition IPlatformFileManagedStorageWrapper.h:1045
virtual bool DeleteFiles(const TArrayView< const TCHAR * > &Filenames) override
Definition IPlatformFileManagedStorageWrapper.h:895
virtual IFileHandle * OpenWrite(const TCHAR *Filename, bool bAppend=false, bool bAllowRead=false) override
Definition IPlatformFileManagedStorageWrapper.h:999
virtual bool DeleteFile(const TCHAR *Filename) override
Definition IPlatformFileManagedStorageWrapper.h:873
Definition UnrealString.h.inl:34
Definition UniquePtr.h:107
Definition CriticalSection.h:14
UE_REWRITE void WriteLock()
Definition CriticalSection.h:21
UE_REWRITE void WriteUnlock()
Definition CriticalSection.h:26
UE_REWRITE constexpr auto FindBy(RangeType &&Range, const ValueType &Value, ProjectionType Proj) -> decltype(AlgoImpl::FindBy(Forward< RangeType >(Range), Value, MoveTemp(Proj)))
Definition Find.h:68
UE_REWRITE constexpr auto FindByPredicate(RangeType &&Range, PredicateType Pred) -> decltype(AlgoImpl::FindByPredicate(Forward< RangeType >(Range), MoveTemp(Pred)))
Definition Find.h:83
@ AnyBackgroundThreadNormalTask
Definition TaskGraphInterfaces.h:106
Definition IPlatformFileManagedStorageWrapper.h:42
CORE_API bool IsUnderDirectory(const FString &InPath, const FString &InDirectory)
Definition IPlatformFileManagedStorageWrapper.cpp:163
static CORE_API bool IsInitialized()
Definition CommandLine.cpp:41
Definition GenericPlatformFile.h:195
Definition IPlatformFileManagedStorageWrapper.h:50
int32 Category
Definition IPlatformFileManagedStorageWrapper.h:52
void Clear()
Definition IPlatformFileManagedStorageWrapper.h:61
bool HasFailedTryToManage() const
Definition IPlatformFileManagedStorageWrapper.h:58
FString FullFilename
Definition IPlatformFileManagedStorageWrapper.h:51
bool IsValid() const
Definition IPlatformFileManagedStorageWrapper.h:54
void SetHasFailedTryToManage()
Definition IPlatformFileManagedStorageWrapper.h:59
Definition IPlatformFileManagedStorageWrapper.h:252
int64 UsedSize
Definition IPlatformFileManagedStorageWrapper.h:266
TMap< FString, int64 > FileSizes
Definition IPlatformFileManagedStorageWrapper.h:269
FString Print() const
Definition IPlatformFileManagedStorageWrapper.h:253
int64 TotalSize
Definition IPlatformFileManagedStorageWrapper.h:267
int64 TotalOptionalSize
Definition IPlatformFileManagedStorageWrapper.h:268
FString CategoryName
Definition IPlatformFileManagedStorageWrapper.h:265
TArray< FString > Directories
Definition IPlatformFileManagedStorageWrapper.h:270
Definition IPlatformFileManagedStorageWrapper.h:152
bool IsInCategory(const FString &Path) const
Definition IPlatformFileManagedStorageWrapper.h:193
const FString & GetCategoryName() const
Definition IPlatformFileManagedStorageWrapper.h:163
int64 GetUsedSize() const
Definition IPlatformFileManagedStorageWrapper.h:178
int64 GetCategoryOptionalQuota() const
Definition IPlatformFileManagedStorageWrapper.h:173
FPersistentStorageCategory(FString InCategoryName, TArray< FString > InDirectories, const int64 InQuota, const int64 InOptionalQuota)
Definition IPlatformFileManagedStorageWrapper.h:154
int64 GetCategoryQuota() const
Definition IPlatformFileManagedStorageWrapper.h:168
FManagedStorageFileLockRegistry & GetLockRegistry()
Definition IPlatformFileManagedStorageWrapper.h:280
CategoryStat GetStat() const
Definition IPlatformFileManagedStorageWrapper.h:274
EPersistentStorageManagerFileSizeFlags AddOrUpdateFile(const FString &Filename, const int64 FileSize, EPersistentStorageManagerFileSizeFlags Flags)
Definition IPlatformFileManagedStorageWrapper.h:203
bool RemoveFile(const FString &Filename)
Definition IPlatformFileManagedStorageWrapper.h:229
const TArray< FString > & GetDirectories() const
Definition IPlatformFileManagedStorageWrapper.h:249
bool IsCategoryFull() const
Definition IPlatformFileManagedStorageWrapper.h:198
int64 GetAvailableSize() const
Definition IPlatformFileManagedStorageWrapper.h:183
Definition Optional.h:131