Browse Source

Android: Fix missing directories and files with externalstorage when trying to browse it through MTP.

Miku AuahDark 1 year ago
parent
commit
4270985df1

+ 61 - 5
src/common/android.cpp

@@ -24,6 +24,7 @@
 #ifdef LOVE_ANDROID
 #ifdef LOVE_ANDROID
 
 
 #include <cerrno>
 #include <cerrno>
+#include <set>
 #include <unordered_map>
 #include <unordered_map>
 
 
 #include <SDL.h>
 #include <SDL.h>
@@ -184,21 +185,76 @@ bool mkdir(const char *path)
 	return true;
 	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()
 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;
 		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 false;
 
 
 	return true;
 	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<std::string> 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()
 bool hasBackgroundMusic()
 {
 {
 	JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
 	JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();

+ 4 - 0
src/common/android.h

@@ -65,6 +65,10 @@ bool mkdir(const char *path);
 
 
 bool createStorageDirectories();
 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 hasBackgroundMusic();
 
 
 bool hasRecordingPermission();
 bool hasRecordingPermission();

+ 19 - 0
src/modules/filesystem/physfs/File.cpp

@@ -27,6 +27,10 @@
 #include "Filesystem.h"
 #include "Filesystem.h"
 #include "filesystem/FileData.h"
 #include "filesystem/FileData.h"
 
 
+#ifdef LOVE_ANDROID
+#include "common/android.h"
+#endif
+
 namespace love
 namespace love
 {
 {
 namespace filesystem
 namespace filesystem
@@ -50,6 +54,21 @@ File::File(const std::string &filename, Mode mode)
 {
 {
 	if (!open(mode))
 	if (!open(mode))
 		throw love::Exception("Could not open file at path %s", filename.c_str());
 		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<love::filesystem::Filesystem>(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)
 File::File(const File &other)

+ 10 - 0
src/modules/filesystem/physfs/Filesystem.cpp

@@ -796,6 +796,16 @@ bool Filesystem::createDirectory(const char *dir)
 	if (!PHYSFS_mkdir(dir))
 	if (!PHYSFS_mkdir(dir))
 		return false;
 		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;
 	return true;
 }
 }