From 4270985df1e5ea82c1693af9657a563b7ee63319 Mon Sep 17 00:00:00 2001 From: Miku AuahDark Date: Thu, 25 Apr 2024 11:54:13 +0800 Subject: [PATCH] Android: Fix missing directories and files with externalstorage when trying to browse it through MTP. --- src/common/android.cpp | 66 ++++++++++++++++++-- src/common/android.h | 4 ++ src/modules/filesystem/physfs/File.cpp | 19 ++++++ src/modules/filesystem/physfs/Filesystem.cpp | 10 +++ 4 files changed, 94 insertions(+), 5 deletions(-) diff --git a/src/common/android.cpp b/src/common/android.cpp index 1ec823536..e659f592d 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -24,6 +24,7 @@ #ifdef LOVE_ANDROID #include +#include #include #include @@ -184,21 +185,76 @@ bool mkdir(const char *path) return true; } +inline bool tryCreateDirectory(const char *path) +{ + SDL_Log("Trying to create directory '%s'", path); + + if (directoryExists(path)) + return true; + else if (mkdir(path)) + return true; + return false; +} + bool createStorageDirectories() { - std::string internal_storage_path = SDL_AndroidGetInternalStoragePath(); + std::string internalStoragePath = SDL_AndroidGetInternalStoragePath(); + std::string externalStoragePath = SDL_AndroidGetExternalStoragePath(); - std::string save_directory = internal_storage_path + "/save"; - if (!directoryExists(save_directory.c_str()) && !mkdir(save_directory.c_str())) + std::string saveDirectoryInternal = internalStoragePath + "/save"; + if (!tryCreateDirectory(saveDirectoryInternal.c_str())) return false; - std::string game_directory = internal_storage_path + "/game"; - if (!directoryExists (game_directory.c_str()) && !mkdir(game_directory.c_str())) + std::string saveDirectoryExternal = externalStoragePath + "/save"; + if (!tryCreateDirectory(saveDirectoryExternal.c_str())) + return false; + + std::string game_directory = externalStoragePath + "/game"; + if (!tryCreateDirectory (game_directory.c_str())) return false; return true; } +void fixupPermissionSingleFile(const std::string &savedir, const std::string &path) +{ + std::string fixedSavedir = savedir.back() == '/' ? savedir : (savedir + "/"); + std::string target = fixedSavedir + path; + ::chmod(target.c_str(), 0660); +} + +void fixupExternalStoragePermission(const std::string &savedir, const std::string &path) +{ + std::set pathsToFix; + size_t start = 0; + + while (true) + { + size_t pos = path.find('/', start); + if (pos == std::string::npos) + { + pathsToFix.insert(path); + break; + } + + pathsToFix.insert(path.substr(0, pos)); + start = pos + 1; + } + + std::string fixedSavedir = savedir.back() == '/' ? savedir : (savedir + "/"); + ::chmod(savedir.c_str(), 0770); + + for (const std::string &dir: pathsToFix) + { + const char *realPath = PHYSFS_getRealDir(dir.c_str()); + if (!dir.empty() && strcmp(realPath, savedir.c_str()) == 0) + { + std::string target = fixedSavedir + dir; + ::chmod(target.c_str(), 0770); + } + } +} + bool hasBackgroundMusic() { JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); diff --git a/src/common/android.h b/src/common/android.h index 1969d3bd4..ef597908c 100644 --- a/src/common/android.h +++ b/src/common/android.h @@ -65,6 +65,10 @@ bool mkdir(const char *path); bool createStorageDirectories(); +void fixupPermissionSingleFile(const std::string &savedir, const std::string &path); + +void fixupExternalStoragePermission(const std::string &savedir, const std::string &path); + bool hasBackgroundMusic(); bool hasRecordingPermission(); diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 99ee0a80c..45727c530 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -27,6 +27,10 @@ #include "Filesystem.h" #include "filesystem/FileData.h" +#ifdef LOVE_ANDROID +#include "common/android.h" +#endif + namespace love { namespace filesystem @@ -50,6 +54,21 @@ File::File(const std::string &filename, Mode mode) { if (!open(mode)) throw love::Exception("Could not open file at path %s", filename.c_str()); + +#ifdef LOVE_ANDROID + // In Android with t.externalstorage = true, make sure the file opened or + // created in the save directory has permissions of ug+rw (0660) so that + // it's accessible through MTP. + auto fs = Module::getInstance(Module::M_FILESYSTEM); + if (fs != nullptr && fs->isAndroidSaveExternal()) + { + const char *realdir = PHYSFS_getRealDir(filename.c_str()); + const std::string &savedir = fs->getFullCommonPath(Filesystem::COMMONPATH_APP_SAVEDIR); + + if (realdir != nullptr && strcmp(realdir, savedir.c_str()) == 0) + love::android::fixupPermissionSingleFile(savedir, filename); +#endif + } } File::File(const File &other) diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index 52e190c56..5b5afd0aa 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -796,6 +796,16 @@ bool Filesystem::createDirectory(const char *dir) if (!PHYSFS_mkdir(dir)) return false; +#ifdef LOVE_ANDROID + // In Android with t.externalstorage = true, make sure the directory + // created in the save directory has permissions of ug+rwx (0770) so that + // it's accessible through MTP. + if (isAndroidSaveExternal()) + love::android::fixupExternalStoragePermission( + getFullCommonPath(CommonPath::COMMONPATH_APP_SAVEDIR), + dir + ); +#endif return true; }