From e25cdfc71c4809b9f616a11fe69ba15154288779 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 5 May 2014 00:27:42 -0300 Subject: [PATCH] Fixed creating and setting the write directory on some sandboxed operating systems --- src/modules/filesystem/physfs/Filesystem.cpp | 44 ++++++++++++++----- src/modules/filesystem/physfs/Filesystem.h | 4 +- .../filesystem/physfs/wrap_Filesystem.cpp | 4 +- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index 914b28178..66cbd2b35 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/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 diff --git a/src/modules/filesystem/physfs/Filesystem.h b/src/modules/filesystem/physfs/Filesystem.h index f9ccfecb3..025da9ac9 100644 --- a/src/modules/filesystem/physfs/Filesystem.h +++ b/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. diff --git a/src/modules/filesystem/physfs/wrap_Filesystem.cpp b/src/modules/filesystem/physfs/wrap_Filesystem.cpp index 0a89387e6..77845ef12 100644 --- a/src/modules/filesystem/physfs/wrap_Filesystem.cpp +++ b/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; }