Add metafilesystem hook to add optimized implementations of compute recursive directory size

This commit is contained in:
Henrik Rydgård 2021-09-11 17:18:39 +02:00
parent e842d395fa
commit 48310d15a9
11 changed files with 88 additions and 13 deletions

View file

@ -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 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_GetFileInfo(const std::string &fileUri, File::FileInfo *info) { return false; }
inline bool Android_FileExists(const std::string &fileUri) { 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_GetFreeSpaceByContentUri(const std::string &uri) { return -1; }
inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; } inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; }
inline bool Android_IsExternalStoragePreservedLegacy() { return false; } inline bool Android_IsExternalStoragePreservedLegacy() { return false; }

View file

@ -324,6 +324,34 @@ std::string ResolvePath(const std::string &path) {
#endif #endif
} }
static int64_t RecursiveSize(const Path &path) {
// TODO: Some file systems can optimize this.
std::vector<FileInfo> 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. // Returns true if file filename exists. Will return true on directories.
bool ExistsInDir(const Path &path, const std::string &filename) { bool ExistsInDir(const Path &path, const std::string &filename) {
return Exists(path / filename); return Exists(path / filename);

View file

@ -79,6 +79,9 @@ uint64_t GetFileSize(const Path &filename);
// Overloaded GetSize, accepts FILE* // Overloaded GetSize, accepts FILE*
uint64_t GetFileSize(FILE *f); 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. // Returns true if successful, or path already exists.
bool CreateDir(const Path &filename); bool CreateDir(const Path &filename);

View file

@ -54,6 +54,8 @@ public:
bool RemoveFile(const std::string &filename) override; bool RemoveFile(const std::string &filename) override;
u64 FreeSpace(const std::string &path) override; u64 FreeSpace(const std::string &path) override;
bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; }
private: private:
// File positions. // File positions.
std::map<u32, s64> entries_; std::map<u32, s64> entries_;

View file

@ -115,6 +115,9 @@ public:
FileSystemFlags Flags() override { return flags; } FileSystemFlags Flags() override { return flags; }
u64 FreeSpace(const std::string &path) override; 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: private:
struct OpenFileEntry { struct OpenFileEntry {
DirectoryFileHandle hFile; DirectoryFileHandle hFile;
@ -159,6 +162,8 @@ public:
FileSystemFlags Flags() override { return FileSystemFlags::FLASH; } FileSystemFlags Flags() override { return FileSystemFlags::FLASH; }
u64 FreeSpace(const std::string &path) override { return 0; } u64 FreeSpace(const std::string &path) override { return 0; }
bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; }
private: private:
struct OpenFileEntry { struct OpenFileEntry {
u8 *fileData; u8 *fileData;

View file

@ -136,11 +136,11 @@ public:
virtual PSPDevType DevType(u32 handle) = 0; virtual PSPDevType DevType(u32 handle) = 0;
virtual FileSystemFlags Flags() = 0; virtual FileSystemFlags Flags() = 0;
virtual u64 FreeSpace(const std::string &path) = 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: public:
virtual void DoState(PointerWrap &p) override {} virtual void DoState(PointerWrap &p) override {}
std::vector<PSPFileInfo> GetDirListing(std::string path) override {std::vector<PSPFileInfo> vec; return vec;} std::vector<PSPFileInfo> GetDirListing(std::string path) override {std::vector<PSPFileInfo> vec; return vec;}
@ -161,6 +161,7 @@ public:
virtual PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; } virtual PSPDevType DevType(u32 handle) override { return PSPDevType::INVALID; }
virtual FileSystemFlags Flags() override { return FileSystemFlags::NONE; } virtual FileSystemFlags Flags() override { return FileSystemFlags::NONE; }
virtual u64 FreeSpace(const std::string &path) override { return 0; } virtual u64 FreeSpace(const std::string &path) override { return 0; }
bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; }
}; };

View file

@ -54,6 +54,8 @@ public:
int RenameFile(const std::string &from, const std::string &to) override { return -1; } int RenameFile(const std::string &from, const std::string &to) override { return -1; }
bool RemoveFile(const std::string &filename) override { return false; } bool RemoveFile(const std::string &filename) override { return false; }
bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; }
private: private:
struct TreeEntry { struct TreeEntry {
~TreeEntry(); ~TreeEntry();
@ -150,6 +152,8 @@ public:
int RenameFile(const std::string &from, const std::string &to) override { return -1; } int RenameFile(const std::string &from, const std::string &to) override { return -1; }
bool RemoveFile(const std::string &filename) override { return false; } bool RemoveFile(const std::string &filename) override { return false; }
bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; }
private: private:
std::shared_ptr<IFileSystem> isoFileSystem_; std::shared_ptr<IFileSystem> isoFileSystem_;
}; };

View file

@ -500,12 +500,9 @@ bool MetaFileSystem::RemoveFile(const std::string &filename)
std::string of; std::string of;
IFileSystem *system; IFileSystem *system;
int error = MapFilePath(filename, of, &system); int error = MapFilePath(filename, of, &system);
if (error == 0) if (error == 0) {
{
return system->RemoveFile(of); return system->RemoveFile(of);
} } else {
else
{
return false; 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; u64 result = 0;
auto allFiles = GetDirListing(dirPath); auto allFiles = GetDirListing(dirPath);
for (auto file : allFiles) { for (auto file : allFiles) {
if (file.name == "." || file.name == "..") if (file.name == "." || file.name == "..")
continue; continue;
if (file.type == FILETYPE_DIRECTORY) { if (file.type == FILETYPE_DIRECTORY) {
result += getDirSize(dirPath + file.name); result += RecursiveSize(dirPath + file.name);
} else { } else {
result += file.size; result += file.size;
} }
} }
return result; return result;
} }
int64_t MetaFileSystem::ComputeRecursiveDirectorySize(const std::string &filename) {
std::lock_guard<std::recursive_mutex> 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;
}
}

View file

@ -136,5 +136,19 @@ public:
startingDirectory = dir; 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);
}; };

View file

@ -52,6 +52,8 @@ public:
int RenameFile(const std::string &from, const std::string &to) override; int RenameFile(const std::string &from, const std::string &to) override;
bool RemoveFile(const std::string &filename) override; bool RemoveFile(const std::string &filename) override;
bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; }
private: private:
void LoadFileListIndex(); void LoadFileListIndex();
// Warning: modifies input string. // Warning: modifies input string.

View file

@ -96,7 +96,7 @@ static void MemoryStick_CalcInitialFree() {
std::unique_lock<std::mutex> guard(freeCalcMutex); std::unique_lock<std::mutex> guard(freeCalcMutex);
freeCalcStatus = FreeCalcStatus::RUNNING; freeCalcStatus = FreeCalcStatus::RUNNING;
freeCalcThread = std::thread([] { freeCalcThread = std::thread([] {
memstickInitialFree = pspFileSystem.FreeSpace("ms0:/") + pspFileSystem.getDirSize("ms0:/PSP/SAVEDATA/"); memstickInitialFree = pspFileSystem.FreeSpace("ms0:/") + pspFileSystem.ComputeRecursiveDirectorySize("ms0:/PSP/SAVEDATA/");
std::unique_lock<std::mutex> guard(freeCalcMutex); std::unique_lock<std::mutex> guard(freeCalcMutex);
freeCalcStatus = FreeCalcStatus::DONE; freeCalcStatus = FreeCalcStatus::DONE;
@ -127,7 +127,7 @@ u64 MemoryStick_FreeSpace() {
// Assume the memory stick is only used to store savedata. // Assume the memory stick is only used to store savedata.
if (!memstickCurrentUseValid) { if (!memstickCurrentUseValid) {
memstickCurrentUse = pspFileSystem.getDirSize("ms0:/PSP/SAVEDATA/"); memstickCurrentUse = pspFileSystem.ComputeRecursiveDirectorySize("ms0:/PSP/SAVEDATA/");
memstickCurrentUseValid = true; memstickCurrentUseValid = true;
} }