From e21b607f2d2da645d2e0a431250ccb8308850612 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 15 Feb 2024 11:19:51 +0300 Subject: [PATCH] lua filesystem access fix --- src/files/engine_paths.cpp | 39 ++++++++++++++++++++++++----- src/files/engine_paths.h | 6 +++++ src/logic/scripting/api/api_lua.cpp | 34 ++++++++++++------------- 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/files/engine_paths.cpp b/src/files/engine_paths.cpp index 585268dc..e8798f40 100644 --- a/src/files/engine_paths.cpp +++ b/src/files/engine_paths.cpp @@ -1,12 +1,13 @@ #include "engine_paths.h" -#include +#include #include +#include #include "../typedefs.h" #include "WorldFiles.h" -#define SCREENSHOTS_FOLDER "screenshots" +const fs::path SCREENSHOTS_FOLDER {"screenshots"}; fs::path EnginePaths::getUserfiles() const { return userfiles; @@ -93,22 +94,48 @@ void EnginePaths::setContentPacks(std::vector* contentPacks) { this->contentPacks = contentPacks; } +#include + +static fs::path toCanonic(fs::path path) { + std::stack parts; + path = path.lexically_normal(); + while (true) { + parts.push(path.filename().u8string()); + path = path.parent_path(); + if (path.empty()) + break; + } + path = fs::u8path(""); + while (!parts.empty()) { + const std::string part = parts.top(); + parts.pop(); + if (part == ".") { + continue; + } + if (part == "..") { + throw files_access_error("entry point reached"); + } + + path = path / fs::path(part); + } + return path; +} + fs::path EnginePaths::resolve(std::string path) { size_t separator = path.find(':'); if (separator == std::string::npos) { - return fs::u8path(path); + throw files_access_error("no entry point specified"); } std::string prefix = path.substr(0, separator); std::string filename = path.substr(separator+1); + filename = toCanonic(fs::u8path(filename)).u8string(); if (prefix == "res" || prefix == "core") { return resources/fs::u8path(filename); } - if (prefix == "user") { return userfiles/fs::u8path(filename); } - if (prefix == "world") { return worldFolder/fs::u8path(filename); } @@ -120,7 +147,7 @@ fs::path EnginePaths::resolve(std::string path) { } } } - return fs::u8path("./"+filename); + throw files_access_error("unknown entry point '"+prefix+"'"); } ResPaths::ResPaths(fs::path mainRoot, std::vector roots) diff --git a/src/files/engine_paths.h b/src/files/engine_paths.h index 04fcca67..cc9ee863 100644 --- a/src/files/engine_paths.h +++ b/src/files/engine_paths.h @@ -3,12 +3,18 @@ #include #include +#include #include #include "../content/ContentPack.h" namespace fs = std::filesystem; +class files_access_error : public std::runtime_error { +public: + files_access_error(const std::string& msg) : std::runtime_error(msg) {} +}; + class EnginePaths { fs::path userfiles {"."}; fs::path resources {"res"}; diff --git a/src/logic/scripting/api/api_lua.cpp b/src/logic/scripting/api/api_lua.cpp index 27878066..9d3c7c01 100644 --- a/src/logic/scripting/api/api_lua.cpp +++ b/src/logic/scripting/api/api_lua.cpp @@ -24,17 +24,23 @@ #include "../../../window/Window.h" #include "../../../engine.h" +fs::path resolve_path(lua_State* L, const std::string& path) { + try { + return scripting::engine->getPaths()->resolve(path); + } catch (const files_access_error& err) { + luaL_error(L, err.what()); + } +} + /* == file library == */ int l_file_resolve(lua_State* L) { - std::string path = lua_tostring(L, 1); - fs::path resolved = scripting::engine->getPaths()->resolve(path); - lua_pushstring(L, resolved.u8string().c_str()); + fs::path path = resolve_path(L, lua_tostring(L, 1)); + lua_pushstring(L, path.u8string().c_str()); return 1; } int l_file_read(lua_State* L) { - auto paths = scripting::engine->getPaths(); - fs::path path = paths->resolve(lua_tostring(L, 1)); + fs::path path = resolve_path(L, lua_tostring(L, 1)); if (fs::is_regular_file(path)) { lua_pushstring(L, files::read_string(path).c_str()); return 1; @@ -43,37 +49,32 @@ int l_file_read(lua_State* L) { } int l_file_write(lua_State* L) { - auto paths = scripting::engine->getPaths(); - fs::path path = paths->resolve(lua_tostring(L, 1)); + fs::path path = resolve_path(L, lua_tostring(L, 1)); const char* text = lua_tostring(L, 2); files::write_string(path, text); return 1; } int l_file_exists(lua_State* L) { - auto paths = scripting::engine->getPaths(); - fs::path path = paths->resolve(lua_tostring(L, 1)); + fs::path path = resolve_path(L, lua_tostring(L, 1)); lua_pushboolean(L, fs::exists(path)); return 1; } int l_file_isfile(lua_State* L) { - auto paths = scripting::engine->getPaths(); - fs::path path = paths->resolve(lua_tostring(L, 1)); + fs::path path = resolve_path(L, lua_tostring(L, 1)); lua_pushboolean(L, fs::is_regular_file(path)); return 1; } int l_file_isdir(lua_State* L) { - auto paths = scripting::engine->getPaths(); - fs::path path = paths->resolve(lua_tostring(L, 1)); + fs::path path = resolve_path(L, lua_tostring(L, 1)); lua_pushboolean(L, fs::is_directory(path)); return 1; } int l_file_length(lua_State* L) { - auto paths = scripting::engine->getPaths(); - fs::path path = paths->resolve(lua_tostring(L, 1)); + fs::path path = resolve_path(L, lua_tostring(L, 1)); if (fs::exists(path)){ lua_pushinteger(L, fs::file_size(path)); } else { @@ -83,8 +84,7 @@ int l_file_length(lua_State* L) { } int l_file_mkdir(lua_State* L) { - auto paths = scripting::engine->getPaths(); - fs::path path = paths->resolve(lua_tostring(L, 1)); + fs::path path = resolve_path(L, lua_tostring(L, 1)); lua_pushboolean(L, fs::create_directory(path)); return 1; }