Skip to content

Commit

Permalink
Merge pull request #18740 from hrydgard/store-improvements
Browse files Browse the repository at this point in the history
Store improvements
  • Loading branch information
hrydgard committed Jan 22, 2024
2 parents a233c80 + c2850ff commit f347e84
Show file tree
Hide file tree
Showing 52 changed files with 202 additions and 112 deletions.
5 changes: 5 additions & 0 deletions Common/File/AndroidStorage.h
Expand Up @@ -47,7 +47,10 @@ StorageError Android_CreateDirectory(const std::string &parentTreeUri, const std
StorageError Android_CreateFile(const std::string &parentTreeUri, const std::string &fileName);
StorageError Android_MoveFile(const std::string &fileUri, const std::string &srcParentUri, const std::string &destParentUri);
StorageError Android_CopyFile(const std::string &fileUri, const std::string &destParentUri);

// WARNING: This is very powerful, it will delete directories recursively!
StorageError Android_RemoveFile(const std::string &fileUri);

StorageError Android_RenameFileTo(const std::string &fileUri, const std::string &newName);
bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *info);
bool Android_FileExists(const std::string &fileUri);
Expand All @@ -65,6 +68,8 @@ void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj);

// Stub out the Android Storage wrappers, so that we can avoid ifdefs everywhere.

// See comments for the corresponding functions above.

inline bool Android_IsContentUri(std::string_view uri) { return false; }
inline int Android_OpenContentUriFd(std::string_view uri, const Android_OpenContentUriMode mode) { return -1; }
inline StorageError Android_CreateDirectory(const std::string &parentTreeUri, const std::string &dirName) { return StorageError::UNKNOWN; }
Expand Down
85 changes: 44 additions & 41 deletions Common/File/FileUtil.cpp
Expand Up @@ -613,41 +613,6 @@ bool CreateFullPath(const Path &path) {
return true;
}

// Deletes an empty directory, returns true on success
bool DeleteDir(const Path &path) {
switch (path.Type()) {
case PathType::NATIVE:
break; // OK
case PathType::CONTENT_URI:
return Android_RemoveFile(path.ToString()) == StorageError::SUCCESS;
default:
return false;
}
INFO_LOG(COMMON, "DeleteDir: directory %s", path.c_str());

// check if a directory
if (!File::IsDirectory(path)) {
ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", path.c_str());
return false;
}

#ifdef _WIN32
#if PPSSPP_PLATFORM(UWP)
if (RemoveDirectoryFromAppW(path.ToWString().c_str()))
return true;
#else
if (::RemoveDirectory(path.ToWString().c_str()))
return true;
#endif
#else
if (rmdir(path.c_str()) == 0)
return true;
#endif
ERROR_LOG(COMMON, "DeleteDir: %s: %s", path.c_str(), GetLastErrorMsg().c_str());

return false;
}

// renames file srcFilename to destFilename, returns true on success
bool Rename(const Path &srcFilename, const Path &destFilename) {
if (srcFilename.Type() != destFilename.Type()) {
Expand Down Expand Up @@ -936,27 +901,65 @@ bool CreateEmptyFile(const Path &filename) {
return true;
}

// Deletes the given directory and anything under it. Returns true on success.
bool DeleteDirRecursively(const Path &directory) {
switch (directory.Type()) {
// Deletes an empty directory, returns true on success
// WARNING: On Android with content URIs, it will delete recursively!
bool DeleteDir(const Path &path) {
switch (path.Type()) {
case PathType::NATIVE:
break; // OK
case PathType::CONTENT_URI:
return Android_RemoveFile(path.ToString()) == StorageError::SUCCESS;
default:
return false;
}
INFO_LOG(COMMON, "DeleteDir: directory %s", path.c_str());

// check if a directory
if (!File::IsDirectory(path)) {
ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", path.c_str());
return false;
}

#ifdef _WIN32
#if PPSSPP_PLATFORM(UWP)
if (RemoveDirectoryFromAppW(path.ToWString().c_str()))
return true;
#else
if (::RemoveDirectory(path.ToWString().c_str()))
return true;
#endif
#else
if (rmdir(path.c_str()) == 0)
return true;
#endif
ERROR_LOG(COMMON, "DeleteDir: %s: %s", path.c_str(), GetLastErrorMsg().c_str());

return false;
}

// Deletes the given directory and anything under it. Returns true on success.
bool DeleteDirRecursively(const Path &path) {
switch (path.Type()) {
case PathType::NATIVE:
break; // OK
break;
case PathType::CONTENT_URI:
// We make use of the dangerous auto-recursive property of Android_RemoveFile.
return Android_RemoveFile(path.ToString()) == StorageError::SUCCESS;
default:
ERROR_LOG(COMMON, "DeleteDirRecursively: Path type not supported");
return false;
}

std::vector<FileInfo> files;
GetFilesInDir(directory, &files, nullptr, GETFILES_GETHIDDEN);
GetFilesInDir(path, &files, nullptr, GETFILES_GETHIDDEN);
for (const auto &file : files) {
if (file.isDirectory) {
DeleteDirRecursively(file.fullName);
} else {
Delete(file.fullName);
}
}
return DeleteDir(directory);
return DeleteDir(path);
}

bool OpenFileInEditor(const Path &fileName) {
Expand Down
6 changes: 3 additions & 3 deletions Common/File/FileUtil.h
Expand Up @@ -86,11 +86,11 @@ bool CreateDir(const Path &filename);
// Creates the full path of fullPath returns true on success
bool CreateFullPath(const Path &fullPath);

// Deletes a given filename, return true on success
// Doesn't supports deleting a directory
// Deletes a given file by name, return true on success
// Doesn't support deleting a directory (although it will work on some platforms - ideally shouldn't)
bool Delete(const Path &filename);

// Deletes a directory filename, returns true on success
// Deletes a directory by name, returns true on success
// Directory must be empty.
bool DeleteDir(const Path &filename);

Expand Down
30 changes: 25 additions & 5 deletions Core/Util/GameManager.cpp
Expand Up @@ -134,7 +134,6 @@ void GameManager::UninstallGame(const std::string &name) {
AndroidJNIThreadContext context; // Destructor detaches.

Path gameDir = GetSysDirectory(DIRECTORY_GAME) / name;

auto st = GetI18NCategory(I18NCat::STORE);

INFO_LOG(HLE, "Uninstalling '%s'", gameDir.c_str());
Expand Down Expand Up @@ -303,15 +302,12 @@ bool GameManager::InstallGame(const Path &url, const Path &fileName, bool delete
auto di = GetI18NCategory(I18NCat::DIALOG);
auto sy = GetI18NCategory(I18NCat::SYSTEM);

g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f);

std::string extension = url.GetFileExtension();
// Examine the URL to guess out what we're installing.
if (extension == ".cso" || extension == ".iso") {
// It's a raw ISO or CSO file. We just copy it to the destination.
std::string shortFilename = url.GetFilename();
bool success = InstallRawISO(fileName, shortFilename, deleteAfter);
g_OSD.RemoveProgressBar("install", success, 0.5f);
return success;
}

Expand Down Expand Up @@ -570,9 +566,12 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const
return true;
};

auto di = GetI18NCategory(I18NCat::DIALOG);

// Create all the directories first in one pass
std::set<Path> createdDirs;
for (int i = 0; i < info.numFiles; i++) {
// Let's count the directories as the first 10%.
const char *fn = zip_get_name(z, i, 0);
std::string zippedName = fn;
if (zippedName.length() < (size_t)info.stripChars) {
Expand All @@ -598,6 +597,7 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const
allBytes += zstat.size;
}
}
g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, info.numFiles, (i + 1) * 0.1f, 0.1f);
}

// Now, loop through again in a second pass, writing files.
Expand All @@ -621,7 +621,9 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const
createdFiles.push_back(outFilename);
}
}
g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 1.0f, 0.1f + (i + 1) / (float)info.numFiles * 0.9f, 0.1f);
}

INFO_LOG(HLE, "Extracted %d files from zip (%d bytes / %d).", info.numFiles, (int)bytesCopied, (int)allBytes);
zip_close(z);
z = nullptr;
Expand All @@ -632,6 +634,7 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const
}
InstallDone();
ResetInstallError();
g_OSD.RemoveProgressBar("install", true, 0.5f);
return true;

bail:
Expand All @@ -645,6 +648,7 @@ bool GameManager::InstallMemstickGame(struct zip *z, const Path &zipfile, const
File::DeleteDir(iter);
}
SetInstallError(sy->T("Storage full"));
g_OSD.RemoveProgressBar("install", false, 0.5f);
return false;
}

Expand All @@ -671,6 +675,8 @@ bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const P
return false;
}

auto di = GetI18NCategory(I18NCat::DIALOG);

const size_t blockSize = 1024 * 128;
u8 *buffer = new u8[blockSize];
while (bytesCopied < allBytes) {
Expand All @@ -681,6 +687,7 @@ bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const P
break;
bytesCopied += readSize;
installProgress_ = (float)bytesCopied / (float)allBytes;
g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 1.0f, installProgress_, 0.1f);
}

delete[] buffer;
Expand All @@ -689,6 +696,7 @@ bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const P

if (bytesCopied < allBytes) {
File::Delete(dest);
g_OSD.RemoveProgressBar("install", false, 0.5f);
SetInstallError(sy->T("Storage full"));
return false;
}
Expand All @@ -699,6 +707,7 @@ bool GameManager::InstallMemstickZip(struct zip *z, const Path &zipfile, const P
}
InstallDone();
ResetInstallError();
g_OSD.RemoveProgressBar("install", true, 0.5f);
return true;
}

Expand All @@ -719,13 +728,19 @@ bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, const Path &

Path outputISOFilename = Path(g_Config.currentDirectory) / fn.substr(nameOffset);
size_t bytesCopied = 0;
bool success = false;
auto di = GetI18NCategory(I18NCat::DIALOG);
g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f);
if (ExtractFile(z, isoFileIndex, outputISOFilename, &bytesCopied, allBytes)) {
INFO_LOG(IO, "Successfully extracted ISO file to '%s'", outputISOFilename.c_str());
success = true;
}
zip_close(z);
if (deleteAfter) {
if (success && deleteAfter) {
File::Delete(zipfile);
g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f);
}
g_OSD.RemoveProgressBar("install", success, 0.5f);

z = 0;
installProgress_ = 1.0f;
Expand Down Expand Up @@ -756,11 +771,16 @@ bool GameManager::UninstallGameOnThread(const std::string &name) {

bool GameManager::InstallRawISO(const Path &file, const std::string &originalName, bool deleteAfter) {
Path destPath = Path(g_Config.currentDirectory) / originalName;
auto di = GetI18NCategory(I18NCat::DIALOG);
g_OSD.SetProgressBar("install", di->T("Installing..."), 0.0f, 0.0f, 0.0f, 0.1f);
// TODO: To save disk space, we should probably attempt a move first.
if (File::Copy(file, destPath)) {
if (deleteAfter) {
File::Delete(file);
}
g_OSD.RemoveProgressBar("install", true, 0.5f);
} else {
g_OSD.RemoveProgressBar("install", false, 0.5f);
}
installProgress_ = 1.0f;
InstallDone();
Expand Down
6 changes: 5 additions & 1 deletion UI/GameInfoCache.cpp
Expand Up @@ -74,6 +74,7 @@ bool GameInfo::Delete() {
{
// Just delete the one file (TODO: handle two-disk games as well somehow).
Path fileToRemove = filePath_;
INFO_LOG(SYSTEM, "Deleting file %s", fileToRemove.c_str());
File::Delete(fileToRemove);
g_Config.RemoveRecent(filePath_.ToString());
return true;
Expand All @@ -83,7 +84,7 @@ bool GameInfo::Delete() {
{
// TODO: This could be handled by Core/Util/GameManager too somehow.
Path directoryToRemove = ResolvePBPDirectory(filePath_);
INFO_LOG(SYSTEM, "Deleting %s", directoryToRemove.c_str());
INFO_LOG(SYSTEM, "Deleting directory %s", directoryToRemove.c_str());
if (!File::DeleteDirRecursively(directoryToRemove)) {
ERROR_LOG(SYSTEM, "Failed to delete file");
return false;
Expand All @@ -101,6 +102,7 @@ bool GameInfo::Delete() {
case IdentifiedFileType::PPSSPP_GE_DUMP:
{
const Path &fileToRemove = filePath_;
INFO_LOG(SYSTEM, "Deleting file %s", fileToRemove.c_str());
File::Delete(fileToRemove);
g_Config.RemoveRecent(filePath_.ToString());
return true;
Expand All @@ -109,6 +111,7 @@ bool GameInfo::Delete() {
case IdentifiedFileType::PPSSPP_SAVESTATE:
{
const Path &ppstPath = filePath_;
INFO_LOG(SYSTEM, "Deleting file %s", ppstPath.c_str());
File::Delete(ppstPath);
const Path screenshotPath = filePath_.WithReplacedExtension(".ppst", ".jpg");
if (File::Exists(screenshotPath)) {
Expand All @@ -118,6 +121,7 @@ bool GameInfo::Delete() {
}

default:
INFO_LOG(SYSTEM, "Don't know how to delete this type of file: %s", filePath_.c_str());
return false;
}
}
Expand Down

0 comments on commit f347e84

Please sign in to comment.