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 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; }

View file

@ -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> 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);

View file

@ -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);

View file

@ -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<u32, s64> entries_;

View file

@ -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;

View file

@ -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<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 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; }
};

View file

@ -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<IFileSystem> isoFileSystem_;
};

View file

@ -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<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;
}
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;
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.

View file

@ -96,7 +96,7 @@ static void MemoryStick_CalcInitialFree() {
std::unique_lock<std::mutex> 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<std::mutex> 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;
}