diff options
author | Hugues Ross <hugues.ross@gmail.com> | 2020-07-28 13:16:57 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-28 19:16:57 +0200 |
commit | 3ce03d1c2a63d261c83f5962cd13212697f19472 (patch) | |
tree | f7c7db205866254865d18c711682c984c062b9cc /src/content | |
parent | f948e2c58570df6bc77226b6066fec5ed90051ee (diff) | |
download | minetest-3ce03d1c2a63d261c83f5962cd13212697f19472.tar.gz minetest-3ce03d1c2a63d261c83f5962cd13212697f19472.tar.bz2 minetest-3ce03d1c2a63d261c83f5962cd13212697f19472.zip |
Sanitize world directory names on create. Keep original name separate (#9432)
Blacklisted characters are replaced by '_' in the path. The display name is stored in world.mt, and duplicate file names are resolved by adding an incrementing suffix (_1, _2, _3, etc).
Diffstat (limited to 'src/content')
-rw-r--r-- | src/content/subgames.cpp | 54 | ||||
-rw-r--r-- | src/content/subgames.h | 5 |
2 files changed, 48 insertions, 11 deletions
diff --git a/src/content/subgames.cpp b/src/content/subgames.cpp index 170f54e20..695ba431f 100644 --- a/src/content/subgames.cpp +++ b/src/content/subgames.cpp @@ -31,6 +31,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/tile.h" // getImagePath #endif +// The maximum number of identical world names allowed +#define MAX_WORLD_NAMES 100 + bool getGameMinetestConfig(const std::string &game_path, Settings &conf) { std::string conf_path = game_path + DIR_DELIM + "minetest.conf"; @@ -213,6 +216,21 @@ bool getWorldExists(const std::string &world_path) fs::PathExists(world_path + DIR_DELIM + "world.mt")); } +//! Try to get the displayed name of a world +std::string getWorldName(const std::string &world_path, const std::string &default_name) +{ + std::string conf_path = world_path + DIR_DELIM + "world.mt"; + Settings conf; + bool succeeded = conf.readConfigFile(conf_path.c_str()); + if (!succeeded) { + return default_name; + } + + if (!conf.exists("world_name")) + return default_name; + return conf.get("world_name"); +} + std::string getWorldGameId(const std::string &world_path, bool can_be_legacy) { std::string conf_path = world_path + DIR_DELIM + "world.mt"; @@ -259,7 +277,7 @@ std::vector<WorldSpec> getAvailableWorlds() if (!dln.dir) continue; std::string fullpath = worldspath + DIR_DELIM + dln.name; - std::string name = dln.name; + std::string name = getWorldName(fullpath, dln.name); // Just allow filling in the gameid always for now bool can_be_legacy = true; std::string gameid = getWorldGameId(fullpath, can_be_legacy); @@ -288,8 +306,24 @@ std::vector<WorldSpec> getAvailableWorlds() return worlds; } -bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamespec) +void loadGameConfAndInitWorld(const std::string &path, const std::string &name, + const SubgameSpec &gamespec, bool create_world) { + std::string final_path = path; + + // If we're creating a new world, ensure that the path isn't already taken + if (create_world) { + int counter = 1; + while (fs::PathExists(final_path) && counter < MAX_WORLD_NAMES) { + final_path = path + "_" + std::to_string(counter); + counter++; + } + + if (fs::PathExists(final_path)) { + throw BaseException("Too many similar filenames"); + } + } + // Override defaults with those provided by the game. // We clear and reload the defaults because the defaults // might have been overridden by other subgame config @@ -300,15 +334,16 @@ bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamesp getGameMinetestConfig(gamespec.path, game_defaults); g_settings->overrideDefaults(&game_defaults); - infostream << "Initializing world at " << path << std::endl; + infostream << "Initializing world at " << final_path << std::endl; - fs::CreateAllDirs(path); + fs::CreateAllDirs(final_path); // Create world.mt if does not already exist - std::string worldmt_path = path + DIR_DELIM "world.mt"; + std::string worldmt_path = final_path + DIR_DELIM "world.mt"; if (!fs::PathExists(worldmt_path)) { Settings conf; + conf.set("world_name", name); conf.set("gameid", gamespec.id); conf.set("backend", "sqlite3"); conf.set("player_backend", "sqlite3"); @@ -316,16 +351,16 @@ bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamesp conf.setBool("creative_mode", g_settings->getBool("creative_mode")); conf.setBool("enable_damage", g_settings->getBool("enable_damage")); - if (!conf.updateConfigFile(worldmt_path.c_str())) - return false; + if (!conf.updateConfigFile(worldmt_path.c_str())) { + throw BaseException("Failed to update the config file"); + } } // Create map_meta.txt if does not already exist - std::string map_meta_path = path + DIR_DELIM + "map_meta.txt"; + std::string map_meta_path = final_path + DIR_DELIM + "map_meta.txt"; if (!fs::PathExists(map_meta_path)) { verbosestream << "Creating map_meta.txt (" << map_meta_path << ")" << std::endl; - fs::CreateAllDirs(path); std::ostringstream oss(std::ios_base::binary); Settings conf; @@ -338,5 +373,4 @@ bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamesp fs::safeWriteToFile(map_meta_path, oss.str()); } - return true; } diff --git a/src/content/subgames.h b/src/content/subgames.h index 4198ea860..35b619aaf 100644 --- a/src/content/subgames.h +++ b/src/content/subgames.h @@ -63,6 +63,8 @@ std::set<std::string> getAvailableGameIds(); std::vector<SubgameSpec> getAvailableGames(); bool getWorldExists(const std::string &world_path); +//! Try to get the displayed name of a world +std::string getWorldName(const std::string &world_path, const std::string &default_name); std::string getWorldGameId(const std::string &world_path, bool can_be_legacy = false); struct WorldSpec @@ -88,4 +90,5 @@ std::vector<WorldSpec> getAvailableWorlds(); // loads the subgame's config and creates world directory // and world.mt if they don't exist -bool loadGameConfAndInitWorld(const std::string &path, const SubgameSpec &gamespec); +void loadGameConfAndInitWorld(const std::string &path, const std::string &name, + const SubgameSpec &gamespec, bool create_world); |