Browse Source

Fixed creating and setting the write directory on some sandboxed operating systems

Alex Szpakowski 11 years ago
parent
commit
e25cdfc71c

+ 32 - 12
src/modules/filesystem/physfs/Filesystem.cpp

@@ -176,16 +176,36 @@ bool Filesystem::setupWriteDirectory()
 	if (save_identity.empty() || save_path_full.empty() || save_path_relative.empty())
 		return false;
 
-	// Set the appdata folder as writable directory.
+	// We need to make sure the write directory is created. To do that, we also
+	// need to make sure all its parent directories are also created.
+	std::string temp_writedir = getDriveRoot(save_path_full);
+	std::string temp_createdir = skipDriveRoot(save_path_full);
+
+	// On some sandboxed platforms, physfs will break when its write directory
+	// is the root of the drive and it tries to create a folder (even if the
+	// folder's path is in a writable location.) If the user's home folder is
+	// in the save path, we'll try starting from there instead.
+	if (save_path_full.find(getUserDirectory()) == 0)
+	{
+		temp_writedir = getUserDirectory();
+		temp_createdir = save_path_full.substr(getUserDirectory().length());
+
+		// Strip leading '/' characters from the path we want to create.
+		size_t startpos = temp_createdir.find_first_not_of('/');
+		if (startpos != std::string::npos)
+			temp_createdir = temp_createdir.substr(startpos);
+	}
+
+	// Set either '/' or the user's home as a writable directory.
 	// (We must create the save folder before mounting it).
-	if (!PHYSFS_setWriteDir(getDriveRoot(save_path_full).c_str()))
+	if (!PHYSFS_setWriteDir(temp_writedir.c_str()))
 		return false;
 
-	// Create the save folder. (We're now "at" %APPDATA%).
-	if (!createDirectory(skipDriveRoot(save_path_full).c_str()))
+	// Create the save folder. (We're now "at" either '/' or the user's home).
+	if (!createDirectory(temp_createdir.c_str()))
 	{
 		// Clear the write directory in case of error.
-		PHYSFS_setWriteDir(0);
+		PHYSFS_setWriteDir(nullptr);
 		return false;
 	}
 
@@ -196,7 +216,7 @@ bool Filesystem::setupWriteDirectory()
 	// Add the directory. (Will not be readded if already present).
 	if (!PHYSFS_addToSearchPath(save_path_full.c_str(), 0))
 	{
-		PHYSFS_setWriteDir(0); // Clear the write directory in case of error.
+		PHYSFS_setWriteDir(nullptr); // Clear the write directory in case of error.
 		return false;
 	}
 
@@ -332,12 +352,12 @@ const char *Filesystem::getWorkingDirectory()
 	return cwd.c_str();
 }
 
-const char *Filesystem::getUserDirectory()
+std::string Filesystem::getUserDirectory()
 {
-	return PHYSFS_getUserDir();
+	return std::string(PHYSFS_getUserDir());
 }
 
-const char *Filesystem::getAppdataDirectory()
+std::string Filesystem::getAppdataDirectory()
 {
 #ifdef LOVE_WINDOWS
 	if (appdata.empty())
@@ -346,7 +366,7 @@ const char *Filesystem::getAppdataDirectory()
 		appdata = to_utf8(w_appdata);
 		replace_char(appdata, '\\', '/');
 	}
-	return appdata.c_str();
+	return appdata;
 #elif defined(LOVE_MACOSX)
 	if (appdata.empty())
 	{
@@ -354,7 +374,7 @@ const char *Filesystem::getAppdataDirectory()
 		udir.append("/Library/Application Support");
 		appdata = udir;
 	}
-	return appdata.c_str();
+	return appdata;
 #elif defined(LOVE_LINUX)
 	if (appdata.empty())
 	{
@@ -364,7 +384,7 @@ const char *Filesystem::getAppdataDirectory()
 		else
 			appdata = xdgdatahome;
 	}
-	return appdata.c_str();
+	return appdata;
 #else
 	return getUserDirectory();
 #endif

+ 2 - 2
src/modules/filesystem/physfs/Filesystem.h

@@ -145,14 +145,14 @@ public:
 	/**
 	 * Gets the user home directory.
 	 **/
-	const char *getUserDirectory();
+	std::string getUserDirectory();
 
 	/**
 	 * Gets the APPDATA directory. On Windows, this is the folder
 	 * in the %APPDATA% enviroment variable. On Linux, this is the
 	 * user home folder.
 	 **/
-	const char *getAppdataDirectory();
+	std::string getAppdataDirectory();
 
 	/**
 	 * Gets the full path of the save folder.

+ 2 - 2
src/modules/filesystem/physfs/wrap_Filesystem.cpp

@@ -211,13 +211,13 @@ int w_getWorkingDirectory(lua_State *L)
 
 int w_getUserDirectory(lua_State *L)
 {
-	lua_pushstring(L, instance->getUserDirectory());
+	luax_pushstring(L, instance->getUserDirectory());
 	return 1;
 }
 
 int w_getAppdataDirectory(lua_State *L)
 {
-	lua_pushstring(L, instance->getAppdataDirectory());
+	luax_pushstring(L, instance->getAppdataDirectory());
 	return 1;
 }