diff --git a/Common/File/AndroidStorage.h b/Common/File/AndroidStorage.h index 40ab19f1b..a9a88055d 100644 --- a/Common/File/AndroidStorage.h +++ b/Common/File/AndroidStorage.h @@ -73,7 +73,7 @@ inline StorageError Android_RemoveFile(const std::string &fileUri) { return Stor inline StorageError Android_RenameFileTo(const std::string &fileUri, const std::string &newName) { return StorageError::UNKNOWN; } inline bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info) { return false; } inline bool Android_FileExists(const std::string &fileUri) { return false; } -inline int64_t Android_GetRecursiveDirectorySize(const std::string &fileUri) { return -1; } +inline int64_t Android_ComputeRecursiveDirectorySize(const std::string &fileUri) { return -1; } inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return -1; } inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; } inline bool Android_IsExternalStoragePreservedLegacy() { return false; } diff --git a/Common/File/FileUtil.cpp b/Common/File/FileUtil.cpp index 91c0aee6b..2de9d8959 100644 --- a/Common/File/FileUtil.cpp +++ b/Common/File/FileUtil.cpp @@ -324,6 +324,34 @@ std::string ResolvePath(const std::string &path) { #endif } +static int64_t RecursiveSize(const Path &path) { + // TODO: Some file systems can optimize this. + std::vector fileInfo; + if (!GetFilesInDir(path, &fileInfo)) { + return -1; + } + int64_t result = 0; + for (const auto &file : fileInfo) { + if (file.name == "." || file.name == "..") + continue; + if (file.isDirectory) { + result += RecursiveSize(file.fullName); + } else { + result += file.size; + } + } + return result; +} + +uint64_t ComputeRecursiveDirectorySize(const Path &path) { + if (path.Type() == PathType::CONTENT_URI) { + return Android_ComputeRecursiveDirectorySize(path.ToString()); + } + + // Generic solution. + return RecursiveSize(path); +} + // Returns true if file filename exists. Will return true on directories. bool ExistsInDir(const Path &path, const std::string &filename) { return Exists(path / filename); diff --git a/Common/File/FileUtil.h b/Common/File/FileUtil.h index ed0581b66..ae77f859a 100644 --- a/Common/File/FileUtil.h +++ b/Common/File/FileUtil.h @@ -79,6 +79,9 @@ uint64_t GetFileSize(const Path &filename); // Overloaded GetSize, accepts FILE* uint64_t GetFileSize(FILE *f); +// Computes the recursive size of a directory. Warning: Might be slow! +uint64_t ComputeRecursiveDirectorySize(const Path &path); + // Returns true if successful, or path already exists. bool CreateDir(const Path &filename); diff --git a/Core/FileSystems/BlobFileSystem.h b/Core/FileSystems/BlobFileSystem.h index faab90004..f45576d6a 100644 --- a/Core/FileSystems/BlobFileSystem.h +++ b/Core/FileSystems/BlobFileSystem.h @@ -54,6 +54,8 @@ public: bool RemoveFile(const std::string &filename) override; u64 FreeSpace(const std::string &path) override; + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } + private: // File positions. std::map entries_; diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index 9d8478d69..daf900a16 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -115,6 +115,9 @@ public: FileSystemFlags Flags() override { return flags; } u64 FreeSpace(const std::string &path) override; + // TODO: Replace with optimized implementation. + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } + private: struct OpenFileEntry { DirectoryFileHandle hFile; @@ -159,6 +162,8 @@ public: FileSystemFlags Flags() override { return FileSystemFlags::FLASH; } u64 FreeSpace(const std::string &path) override { return 0; } + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } + private: struct OpenFileEntry { u8 *fileData; diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 5df227dd1..87c87ae56 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -136,11 +136,11 @@ public: virtual PSPDevType DevType(u32 handle) = 0; virtual FileSystemFlags Flags() = 0; virtual u64 FreeSpace(const std::string &path) = 0; + virtual bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) = 0; }; -class EmptyFileSystem : public IFileSystem -{ +class EmptyFileSystem : public IFileSystem { public: virtual void DoState(PointerWrap &p) override {} std::vector GetDirListing(std::string path) override {std::vector vec; return vec;} @@ -161,6 +161,7 @@ public: virtual PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; } virtual FileSystemFlags Flags() override { return FileSystemFlags::NONE; } virtual u64 FreeSpace(const std::string &path) override { return 0; } + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } }; diff --git a/Core/FileSystems/ISOFileSystem.h b/Core/FileSystems/ISOFileSystem.h index 0b8c00512..608fa444e 100644 --- a/Core/FileSystems/ISOFileSystem.h +++ b/Core/FileSystems/ISOFileSystem.h @@ -54,6 +54,8 @@ public: int RenameFile(const std::string &from, const std::string &to) override { return -1; } bool RemoveFile(const std::string &filename) override { return false; } + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } + private: struct TreeEntry { ~TreeEntry(); @@ -150,6 +152,8 @@ public: int RenameFile(const std::string &from, const std::string &to) override { return -1; } bool RemoveFile(const std::string &filename) override { return false; } + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } + private: std::shared_ptr isoFileSystem_; }; diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 173cf4a86..c726a87b5 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -500,12 +500,9 @@ bool MetaFileSystem::RemoveFile(const std::string &filename) std::string of; IFileSystem *system; int error = MapFilePath(filename, of, &system); - if (error == 0) - { + if (error == 0) { return system->RemoveFile(of); - } - else - { + } else { return false; } } @@ -648,17 +645,36 @@ void MetaFileSystem::DoState(PointerWrap &p) } } -u64 MetaFileSystem::getDirSize(const std::string &dirPath) { +int64_t MetaFileSystem::RecursiveSize(const std::string &dirPath) { u64 result = 0; auto allFiles = GetDirListing(dirPath); for (auto file : allFiles) { if (file.name == "." || file.name == "..") continue; if (file.type == FILETYPE_DIRECTORY) { - result += getDirSize(dirPath + file.name); + result += RecursiveSize(dirPath + file.name); } else { result += file.size; } } return result; } + +int64_t MetaFileSystem::ComputeRecursiveDirectorySize(const std::string &filename) { + std::lock_guard guard(lock); + std::string of; + IFileSystem *system; + int error = MapFilePath(filename, of, &system); + if (error == 0) { + int64_t size; + if (system->ComputeRecursiveDirSizeIfFast(of, &size)) { + // Some file systems can optimize this. + return size; + } else { + // Those that can't, we just run a generic implementation. + return RecursiveSize(filename); + } + } else { + return false; + } +} diff --git a/Core/FileSystems/MetaFileSystem.h b/Core/FileSystems/MetaFileSystem.h index f980fc190..9a3b041c9 100644 --- a/Core/FileSystems/MetaFileSystem.h +++ b/Core/FileSystems/MetaFileSystem.h @@ -136,5 +136,19 @@ public: startingDirectory = dir; } - u64 getDirSize(const std::string &dirPath); + int64_t ComputeRecursiveDirectorySize(const std::string &dirPath); + + // Shouldn't ever be called, but meh. + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { + int64_t sizeTemp = ComputeRecursiveDirectorySize(path); + if (sizeTemp >= 0) { + *size = sizeTemp; + return true; + } else { + return false; + } + } + +private: + int64_t RecursiveSize(const std::string &dirPath); }; diff --git a/Core/FileSystems/VirtualDiscFileSystem.h b/Core/FileSystems/VirtualDiscFileSystem.h index 6c76d6b6f..0c1b6db87 100644 --- a/Core/FileSystems/VirtualDiscFileSystem.h +++ b/Core/FileSystems/VirtualDiscFileSystem.h @@ -52,6 +52,8 @@ public: int RenameFile(const std::string &from, const std::string &to) override; bool RemoveFile(const std::string &filename) override; + bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } + private: void LoadFileListIndex(); // Warning: modifies input string. diff --git a/Core/HW/MemoryStick.cpp b/Core/HW/MemoryStick.cpp index 2efec86c7..964a00290 100644 --- a/Core/HW/MemoryStick.cpp +++ b/Core/HW/MemoryStick.cpp @@ -96,7 +96,7 @@ static void MemoryStick_CalcInitialFree() { std::unique_lock guard(freeCalcMutex); freeCalcStatus = FreeCalcStatus::RUNNING; freeCalcThread = std::thread([] { - memstickInitialFree = pspFileSystem.FreeSpace("ms0:/") + pspFileSystem.getDirSize("ms0:/PSP/SAVEDATA/"); + memstickInitialFree = pspFileSystem.FreeSpace("ms0:/") + pspFileSystem.ComputeRecursiveDirectorySize("ms0:/PSP/SAVEDATA/"); std::unique_lock guard(freeCalcMutex); freeCalcStatus = FreeCalcStatus::DONE; @@ -127,7 +127,7 @@ u64 MemoryStick_FreeSpace() { // Assume the memory stick is only used to store savedata. if (!memstickCurrentUseValid) { - memstickCurrentUse = pspFileSystem.getDirSize("ms0:/PSP/SAVEDATA/"); + memstickCurrentUse = pspFileSystem.ComputeRecursiveDirectorySize("ms0:/PSP/SAVEDATA/"); memstickCurrentUseValid = true; }