Browse Source

Added love.filesystem.getSourceBaseDirectory and changed love.filesystem.mount to allow mounting the path returned by love.filesystem.getSourceBaseDirectory in fused mode.

Alex Szpakowski 12 years ago
parent
commit
daf50698b8

+ 84 - 29
src/modules/filesystem/physfs/Filesystem.cpp

@@ -137,6 +137,11 @@ bool Filesystem::setSource(const char *source)
 	return true;
 	return true;
 }
 }
 
 
+const char *Filesystem::getSource() const
+{
+	return game_source.c_str();
+}
+
 bool Filesystem::setupWriteDirectory()
 bool Filesystem::setupWriteDirectory()
 {
 {
 	if (!initialized)
 	if (!initialized)
@@ -160,7 +165,8 @@ bool Filesystem::setupWriteDirectory()
 
 
 	if (!success)
 	if (!success)
 	{
 	{
-		PHYSFS_setWriteDir(0); // Clear the write directory in case of error.
+		// Clear the write directory in case of error.
+		PHYSFS_setWriteDir(0);
 		return false;
 		return false;
 	}
 	}
 
 
@@ -183,23 +189,38 @@ bool Filesystem::mount(const char *archive, const char *mountpoint, SearchOrder
 	if (!initialized || !archive)
 	if (!initialized || !archive)
 		return false;
 		return false;
 
 
-	// Not allowed for safety reasons.
-	if (strlen(archive) == 0 || strstr(archive, "..") || strcmp(archive, "/") == 0)
-		return false;
+	std::string realPath;
+	std::string sourceBase = getSourceBaseDirectory();
 
 
-	const char *realDir = PHYSFS_getRealDir(archive);
-	if (!realDir)
-		return false;
+	if (isFused() && sourceBase.compare(archive) == 0)
+	{
+		// Special case: if the game is fused and the archive is the source's
+		// base directory, mount it even though it's outside of the save dir.
+		realPath = sourceBase;
+	}
+	else
+	{
+		// Not allowed for safety reasons.
+		if (strlen(archive) == 0 || strstr(archive, "..") || strcmp(archive, "/") == 0)
+			return false;
 
 
-	std::string realPath(realDir);
+		const char *realDir = PHYSFS_getRealDir(archive);
+		if (!realDir)
+			return false;
 
 
-	// Always disallow mounting of files inside the game source, since it won't
-	// work anyway if the game source is a zipped .love file.
-	if (realPath.find(game_source) == 0)
-		return false;
+		realPath = realDir;
+
+		// Always disallow mounting of files inside the game source, since it
+		// won't work anyway if the game source is a zipped .love file.
+		if (realPath.find(game_source) == 0)
+			return false;
+
+		realPath += LOVE_PATH_SEPARATOR;
+		realPath += archive;
+	}
 
 
-	realPath += LOVE_PATH_SEPARATOR;
-	realPath += archive;
+	if (realPath.length() == 0)
+		return false;
 
 
 	bool append = (searchorder == SEARCH_ORDER_LAST);
 	bool append = (searchorder == SEARCH_ORDER_LAST);
 
 
@@ -211,17 +232,29 @@ bool Filesystem::unmount(const char *archive)
 	if (!initialized || !archive)
 	if (!initialized || !archive)
 		return false;
 		return false;
 
 
-	// Not allowed for safety reasons.
-	if (strlen(archive) == 0 || strstr(archive, "..") || strcmp(archive, "/") == 0)
-		return false;
+	std::string realPath;
+	std::string sourceBase = getSourceBaseDirectory();
 
 
-	const char *realDir = PHYSFS_getRealDir(archive);
-	if (!realDir)
-		return false;
+	if (isFused() && sourceBase.compare(archive) == 0)
+	{
+		// Special case: if the game is fused and the archive is the source's
+		// base directory, unmount it even though it's outside of the save dir.
+		realPath = sourceBase;
+	}
+	else
+	{
+		// Not allowed for safety reasons.
+		if (strlen(archive) == 0 || strstr(archive, "..") || strcmp(archive, "/") == 0)
+			return false;
 
 
-	std::string realPath(realDir);
-	realPath += LOVE_PATH_SEPARATOR;
-	realPath += archive;
+		const char *realDir = PHYSFS_getRealDir(archive);
+		if (!realDir)
+			return false;
+
+		realPath = realDir;
+		realPath += LOVE_PATH_SEPARATOR;
+		realPath += archive;
+	}
 
 
 	const char *mountPoint = PHYSFS_getMountPoint(realPath.c_str());
 	const char *mountPoint = PHYSFS_getMountPoint(realPath.c_str());
 	if (!mountPoint)
 	if (!mountPoint)
@@ -326,18 +359,40 @@ const char *Filesystem::getSaveDirectory()
 	return save_path_full.c_str();
 	return save_path_full.c_str();
 }
 }
 
 
+std::string Filesystem::getSourceBaseDirectory() const
+{
+	size_t source_len = game_source.length();
+
+	if (source_len == 0)
+		return "";
+
+	// FIXME: This doesn't take into account parent and current directory
+	// symbols (i.e. '..' and '.')
+#ifdef LOVE_WINDOWS
+	// In windows, delimiters can be either '/' or '\'.
+	size_t base_end_pos = game_source.find_last_of("/\\", source_len - 2);
+#else
+	size_t base_end_pos = game_source.find_last_of('/', source_len - 2);
+#endif
+
+	if (base_end_pos == std::string::npos)
+		return "";
+
+	// If the source is in the unix root (aka '/'), we want to keep the '/'.
+	if (base_end_pos == 0)
+		base_end_pos = 1;
+
+	return game_source.substr(0, base_end_pos);
+}
+
 bool Filesystem::exists(const char *file) const
 bool Filesystem::exists(const char *file) const
 {
 {
-	if (PHYSFS_exists(file))
-		return true;
-	return false;
+	return PHYSFS_exists(file);
 }
 }
 
 
 bool Filesystem::isDirectory(const char *file) const
 bool Filesystem::isDirectory(const char *file) const
 {
 {
-	if (PHYSFS_isDirectory(file))
-		return true;
-	return false;
+	return PHYSFS_isDirectory(file);
 }
 }
 
 
 bool Filesystem::isFile(const char *file) const
 bool Filesystem::isFile(const char *file) const

+ 13 - 0
src/modules/filesystem/physfs/Filesystem.h

@@ -118,6 +118,12 @@ public:
 	 **/
 	 **/
 	bool setSource(const char *source);
 	bool setSource(const char *source);
 
 
+	/**
+	 * Gets the path to the game source.
+	 * Returns a 0-length string if the source has not been set.
+	 **/
+	const char *getSource() const;
+
 	bool mount(const char *archive, const char *mountpoint, SearchOrder searchorder = SEARCH_ORDER_FIRST);
 	bool mount(const char *archive, const char *mountpoint, SearchOrder searchorder = SEARCH_ORDER_FIRST);
 	bool unmount(const char *archive);
 	bool unmount(const char *archive);
 
 
@@ -162,6 +168,13 @@ public:
 	 **/
 	 **/
 	const char *getSaveDirectory();
 	const char *getSaveDirectory();
 
 
+	/**
+	 * Gets the full path to the directory containing the game source.
+	 * For example if the game source is C:\Games\mygame.love, this will return
+	 * C:\Games.
+	 **/
+	std::string getSourceBaseDirectory() const;
+
 	/**
 	/**
 	 * Checks whether a file exists in the current search path
 	 * Checks whether a file exists in the current search path
 	 * or not.
 	 * or not.

+ 14 - 0
src/modules/filesystem/physfs/wrap_Filesystem.cpp

@@ -111,6 +111,12 @@ int w_setSource(lua_State *L)
 	return 0;
 	return 0;
 }
 }
 
 
+int w_getSource(lua_State *L)
+{
+	lua_pushstring(L, instance->getSource());
+	return 1;
+}
+
 int w_mount(lua_State *L)
 int w_mount(lua_State *L)
 {
 {
 	const char *archive = luaL_checkstring(L, 1);
 	const char *archive = luaL_checkstring(L, 1);
@@ -249,6 +255,12 @@ int w_getSaveDirectory(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
+int w_getSourceBaseDirectory(lua_State *L)
+{
+	luax_pushstring(L, instance->getSourceBaseDirectory());
+	return 1;
+}
+
 int w_exists(lua_State *L)
 int w_exists(lua_State *L)
 {
 {
 	const char *arg = luaL_checkstring(L, 1);
 	const char *arg = luaL_checkstring(L, 1);
@@ -580,6 +592,7 @@ static const luaL_Reg functions[] =
 	{ "setIdentity",  w_setIdentity },
 	{ "setIdentity",  w_setIdentity },
 	{ "getIdentity", w_getIdentity },
 	{ "getIdentity", w_getIdentity },
 	{ "setSource",  w_setSource },
 	{ "setSource",  w_setSource },
+	{ "getSource", w_getSource },
 	{ "mount", w_mount },
 	{ "mount", w_mount },
 	{ "unmount", w_unmount },
 	{ "unmount", w_unmount },
 	{ "newFile",  w_newFile },
 	{ "newFile",  w_newFile },
@@ -587,6 +600,7 @@ static const luaL_Reg functions[] =
 	{ "getUserDirectory",  w_getUserDirectory },
 	{ "getUserDirectory",  w_getUserDirectory },
 	{ "getAppdataDirectory",  w_getAppdataDirectory },
 	{ "getAppdataDirectory",  w_getAppdataDirectory },
 	{ "getSaveDirectory",  w_getSaveDirectory },
 	{ "getSaveDirectory",  w_getSaveDirectory },
+	{ "getSourceBaseDirectory", w_getSourceBaseDirectory },
 	{ "exists",  w_exists },
 	{ "exists",  w_exists },
 	{ "isDirectory",  w_isDirectory },
 	{ "isDirectory",  w_isDirectory },
 	{ "isFile",  w_isFile },
 	{ "isFile",  w_isFile },

+ 2 - 0
src/modules/filesystem/physfs/wrap_Filesystem.h

@@ -43,6 +43,7 @@ int w_isFused(lua_State *L);
 int w_setIdentity(lua_State *L);
 int w_setIdentity(lua_State *L);
 int w_getIdentity(lua_State *L);
 int w_getIdentity(lua_State *L);
 int w_setSource(lua_State *L);
 int w_setSource(lua_State *L);
+int w_getSource(lua_State *L);
 int w_mount(lua_State *L);
 int w_mount(lua_State *L);
 int w_unmount(lua_State *L);
 int w_unmount(lua_State *L);
 int w_newFile(lua_State *L);
 int w_newFile(lua_State *L);
@@ -51,6 +52,7 @@ int w_getWorkingDirectory(lua_State *L);
 int w_getUserDirectory(lua_State *L);
 int w_getUserDirectory(lua_State *L);
 int w_getAppdataDirectory(lua_State *L);
 int w_getAppdataDirectory(lua_State *L);
 int w_getSaveDirectory(lua_State *L);
 int w_getSaveDirectory(lua_State *L);
+int w_getSourceBaseDirectory(lua_State *L);
 int w_exists(lua_State *L);
 int w_exists(lua_State *L);
 int w_isDirectory(lua_State *L);
 int w_isDirectory(lua_State *L);
 int w_isFile(lua_State *L);
 int w_isFile(lua_State *L);