love.filesystem canonicalizes internal full paths where possible.

resolves #1693.
resolves #1100.
This commit is contained in:
Sasha Szpakowski
2024-08-03 19:33:55 -03:00
parent 29ae5e6273
commit e94b8c3d04
5 changed files with 53 additions and 26 deletions
+15
View File
@@ -38,6 +38,9 @@
#include <unistd.h>
#endif
// C++17 std::filesystem
#include <filesystem>
namespace love
{
namespace filesystem
@@ -182,6 +185,18 @@ bool Filesystem::createRealDirectory(const std::string &path)
return true;
}
std::string Filesystem::canonicalizeRealPath(const std::string &p) const
{
try
{
return std::filesystem::weakly_canonical(p).string();
}
catch (std::exception &)
{
return p;
}
}
std::string Filesystem::getExecutablePath() const
{
#if defined(LOVE_MACOS) || defined(LOVE_IOS)
+6
View File
@@ -303,6 +303,12 @@ public:
**/
virtual bool createRealDirectory(const std::string &path);
/**
* Converts the given real path to its canonical version (e.g. resolving
* '..', '.', relative paths, etc).
**/
virtual std::string canonicalizeRealPath(const std::string &path) const;
/**
* Gets the full platform-dependent path to the executable.
**/
+21 -12
View File
@@ -172,9 +172,14 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath)
continue;
// If a file is still open, unmount will fail.
std::string fullPath = getFullCommonPath(p);
if (!fullPath.empty() && !PHYSFS_canUnmount(fullPath.c_str()))
return false;
std::string fullpath = getFullCommonPath(p);
if (!fullpath.empty())
{
std::string canonpath = canonicalizeRealPath(fullpath);
if (!PHYSFS_canUnmount(canonpath.c_str()))
return false;
}
}
bool oldMountedCommonPaths[COMMONPATH_MAX_ENUM] = {false};
@@ -237,7 +242,7 @@ bool Filesystem::setSource(const char *source)
if (!gameSource.empty())
return false;
std::string new_search_path = source;
std::string new_search_path = canonicalizeRealPath(source);
#ifdef LOVE_ANDROID
if (!love::android::createStorageDirectories())
@@ -395,10 +400,12 @@ bool Filesystem::mountFullPath(const char *archive, const char *mountpoint, Moun
if (!PHYSFS_isInit() || !archive)
return false;
if (permissions == MOUNT_PERMISSIONS_READWRITE)
return PHYSFS_mountRW(archive, mountpoint, appendToPath) != 0;
std::string canonarchive = canonicalizeRealPath(archive);
return PHYSFS_mount(archive, mountpoint, appendToPath) != 0;
if (permissions == MOUNT_PERMISSIONS_READWRITE)
return PHYSFS_mountRW(canonarchive.c_str(), mountpoint, appendToPath) != 0;
return PHYSFS_mount(canonarchive.c_str(), mountpoint, appendToPath) != 0;
}
bool Filesystem::mountCommonPathInternal(CommonPath path, const char *mountpoint, MountPermissions permissions, bool appendToPath, bool createDir)
@@ -474,10 +481,12 @@ bool Filesystem::unmount(const char *archive)
realPath += LOVE_PATH_SEPARATOR;
realPath += archive;
if (PHYSFS_getMountPoint(realPath.c_str()) == nullptr)
std::string canonpath = canonicalizeRealPath(realPath.c_str());
if (PHYSFS_getMountPoint(canonpath.c_str()) == nullptr)
return false;
return PHYSFS_unmount(realPath.c_str()) != 0;
return PHYSFS_unmount(canonpath.c_str()) != 0;
}
bool Filesystem::unmountFullPath(const char *fullpath)
@@ -485,7 +494,9 @@ bool Filesystem::unmountFullPath(const char *fullpath)
if (!PHYSFS_isInit() || !fullpath)
return false;
return PHYSFS_unmount(fullpath) != 0;
std::string canonpath = canonicalizeRealPath(fullpath);
return PHYSFS_unmount(canonpath.c_str()) != 0;
}
bool Filesystem::unmount(CommonPath path)
@@ -725,8 +736,6 @@ std::string Filesystem::getSourceBaseDirectory() const
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 = gameSource.find_last_of("/\\", source_len - 2);
@@ -498,6 +498,13 @@ int w_getRealDirectory(lua_State *L)
return 1;
}
int w_canonicalizeRealPath(lua_State *L)
{
const char *path = luaL_checkstring(L, 1);
luax_pushstring(L, instance()->canonicalizeRealPath(path));
return 1;
}
int w_getExecutablePath(lua_State *L)
{
luax_pushstring(L, instance()->getExecutablePath());
@@ -1033,6 +1040,7 @@ static const luaL_Reg functions[] =
{ "getSaveDirectory", w_getSaveDirectory },
{ "getSourceBaseDirectory", w_getSourceBaseDirectory },
{ "getRealDirectory", w_getRealDirectory },
{ "canonicalizeRealPath", w_canonicalizeRealPath },
{ "getExecutablePath", w_getExecutablePath },
{ "createDirectory", w_createDirectory },
{ "remove", w_remove },
+3 -14
View File
@@ -66,20 +66,9 @@ end
-- Converts any path into a full path.
function love.path.getFull(p)
if love.path.abs(p) then
return love.path.normalslashes(p)
end
local cwd = love.filesystem.getWorkingDirectory()
cwd = love.path.normalslashes(cwd)
cwd = love.path.endslash(cwd)
-- Construct a full path.
local full = cwd .. love.path.normalslashes(p)
-- Remove trailing /., if applicable
return full:match("(.-)/%.$") or full
p = love.filesystem.canonicalizeRealPath(p)
p = love.path.normalslashes(p)
return p
end
-- Returns the leaf of a full path.