widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #15187
[Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
Arty has proposed merging lp:~widelands-dev/widelands/filesystem-errors into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/filesystem-errors/+merge/358219
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/filesystem-errors into lp:widelands.
=== modified file 'src/editor/editorinteractive.cc'
--- src/editor/editorinteractive.cc 2018-09-25 06:32:35 +0000
+++ src/editor/editorinteractive.cc 2018-11-02 11:11:32 +0000
@@ -187,6 +187,7 @@
}
ml->load_map_complete(egbase(), Widelands::MapLoader::LoadType::kEditor);
+ egbase().postload();
egbase().load_graphics(loader_ui);
map_changed(MapWas::kReplaced);
}
=== modified file 'src/editor/ui_menus/main_menu_save_map.cc'
--- src/editor/ui_menus/main_menu_save_map.cc 2018-06-01 08:50:29 +0000
+++ src/editor/ui_menus/main_menu_save_map.cc 2018-11-02 11:11:32 +0000
@@ -272,16 +272,14 @@
if (mbox.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kBack)
return false;
}
-
- // save to a tmp file/dir first, rename later
- // (important to keep script files in the script directory)
- const std::string tmp_name = complete_filename + ".tmp";
- if (g_fs->file_exists(tmp_name)) {
+
+ // Try deleting file (if it exists). If it fails, give a message and let the player choose a new name.
+ try {
+ g_fs->fs_unlink(complete_filename);
+ } catch (const std::exception& e) {
const std::string s =
- (boost::format(
- _("A file with the name ‘%s.tmp’ already exists. You have to remove it manually.")) %
- FileSystem::fs_filename(filename.c_str()))
- .str();
+ (boost::format(_("File ‘%s.tmp’ could not be deleted.")) % FileSystem::fs_filename(filename.c_str())).str()
+ + " " + _("Try saving under a different name!");
UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);
mbox.run<UI::Panel::Returncodes>();
return false;
@@ -290,51 +288,35 @@
Widelands::EditorGameBase& egbase = eia().egbase();
Widelands::Map* map = egbase.mutable_map();
- { // fs scope
+ // Recompute seafaring tag
+ map->cleanup_port_spaces(egbase.world());
+ if (map->allows_seafaring()) {
+ map->add_tag("seafaring");
+ } else {
+ map->delete_tag("seafaring");
+ }
+
+ if (map->has_artifacts()) {
+ map->add_tag("artifacts");
+ } else {
+ map->delete_tag("artifacts");
+ }
+
+ // Try saving.
+ try {
std::unique_ptr<FileSystem> fs(
- g_fs->create_sub_file_system(tmp_name, binary ? FileSystem::ZIP : FileSystem::DIR));
-
- // Recompute seafaring tag
- map->cleanup_port_spaces(egbase.world());
- if (map->allows_seafaring()) {
- map->add_tag("seafaring");
- } else {
- map->delete_tag("seafaring");
- }
-
- if (map->has_artifacts()) {
- map->add_tag("artifacts");
- } else {
- map->delete_tag("artifacts");
- }
-
- try {
- Widelands::MapSaver* wms = new Widelands::MapSaver(*fs, egbase);
- wms->save();
- delete wms;
- // Reset filesystem to avoid file locks on saves
- fs.reset();
- map->reset_filesystem();
- eia().set_need_save(false);
- g_fs->fs_unlink(complete_filename);
- g_fs->fs_rename(tmp_name, complete_filename);
- // Also change fs, as we assign it to the map below
- fs.reset(g_fs->make_sub_file_system(complete_filename));
- // Set the filesystem of the map to the current save file / directory
- map->swap_filesystem(fs);
- // DONT use fs as of here, its garbage now!
-
- } catch (const std::exception& e) {
- std::string s = _("Error Saving Map!\nSaved map file may be corrupt!\n\nReason "
- "given:\n");
- s += e.what();
- UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);
- mbox.run<UI::Panel::Returncodes>();
-
- // cleanup tmp file if it was created
- g_fs->fs_unlink(tmp_name);
- }
- } // end fs scope, dont use it
+ g_fs->create_sub_file_system(complete_filename, binary ? FileSystem::ZIP : FileSystem::DIR));
+ Widelands::MapSaver* wms = new Widelands::MapSaver(*fs, egbase);
+ wms->save();
+ delete wms;
+ fs.reset();
+ } catch (const std::exception& e) {
+ std::string s = _("Error Saving Map!\nSaved map file may be corrupt!\n\nReason "
+ "given:\n");
+ s += e.what();
+ UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);
+ mbox.run<UI::Panel::Returncodes>();
+ }
die();
return true;
=== modified file 'src/io/filesystem/disk_filesystem.cc'
--- src/io/filesystem/disk_filesystem.cc 2018-04-07 16:59:00 +0000
+++ src/io/filesystem/disk_filesystem.cc 2018-11-02 11:11:32 +0000
@@ -167,15 +167,13 @@
}
/**
- * Create a sub filesystem out of this filesystem
+ * Make a sub filesystem out of this filesystem
*/
FileSystem* RealFSImpl::make_sub_file_system(const std::string& path) {
FileSystemPath fspath(canonicalize_name(path));
if (!fspath.exists_) {
- throw wexception("RealFSImpl: unable to create sub filesystem, path does not exist for '%s'"
- " in directory '%s'",
- fspath.c_str(), directory_.c_str());
+ throw FileNotFoundError("RealFSImpl::make_sub_file_system", fspath);
}
if (fspath.is_directory_)
@@ -190,10 +188,7 @@
FileSystem* RealFSImpl::create_sub_file_system(const std::string& path, Type const fs) {
FileSystemPath fspath(canonicalize_name(path));
if (fspath.exists_)
- throw wexception(
- "path '%s'' already exists in directory '%s', can not create a filesystem from it",
- path.c_str(), directory_.c_str());
-
+ throw FileError("RealFSImpl::create_sub_file_system", fspath, "path already exists, cannot create new filesystem from it");
if (fs == FileSystem::DIR) {
ensure_directory_exists(path);
return new RealFSImpl(fspath);
@@ -221,20 +216,22 @@
void RealFSImpl::unlink_file(const std::string& file) {
FileSystemPath fspath(canonicalize_name(file));
if (!fspath.exists_) {
- throw wexception(
- "RealFSImpl: unable to unlink file, path does not exist for '%s' in directory '%s'",
- fspath.c_str(), directory_.c_str());
+ throw FileNotFoundError("RealFSImpl::unlink_file", fspath);
}
if (fspath.is_directory_) {
- throw wexception(
- "RealFSImpl: unable to unlink file, path '%s' in directory '%s' is a directory",
- fspath.c_str(), directory_.c_str());
+ throw FileTypeError("RealFSImpl::unlink_file", fspath, "path is a directory");
}
-
#ifndef _WIN32
- unlink(fspath.c_str());
+ if (unlink(fspath.c_str()) == -1)
+ throw FileError("RealFSImpl::unlink_file", fspath, strerror(errno));
#else
- DeleteFile(fspath.c_str());
+ // Note: We could possibly replace this with _unlink()
+ // which would then also work with errno instead of GetLastError(),
+ // but I am not sure if this is available (and works properly)
+ // on all windows platforms or only with Visual Studio.
+ if (!DeleteFile(fspath.c_str()))
+ throw FileError("RealFSImpl::unlink_file", fspath, std::string("file error (Windows error code ")+std::to_string(GetLastError())+")");
+ // TODO: generate proper system message from GetLastError() via FormatMessage
#endif
}
@@ -244,14 +241,10 @@
void RealFSImpl::unlink_directory(const std::string& file) {
FileSystemPath fspath(canonicalize_name(file));
if (!fspath.exists_) {
- throw wexception("RealFSImpl: unable to unlink directory, path does not exist for '%s'"
- " in directory '%s'",
- fspath.c_str(), directory_.c_str());
+ throw FileNotFoundError("RealFSImpl::unlink_directory", fspath);
}
if (!fspath.is_directory_) {
- throw wexception("RealFSImpl: unable to unlink directory, path '%s' in directory '%s'"
- " is not a directory",
- fspath.c_str(), directory_.c_str());
+ throw FileTypeError("RealFSImpl::unlink_directory", fspath, "path is not a directory");
}
FilenameSet files = list_directory(file);
@@ -268,14 +261,18 @@
unlink_file(*pname);
}
-// NOTE: this might fail if this directory contains CVS dir,
-// so no error checking here
+// NOTE: this might fail if this directory contains CVS dir
#ifndef _WIN32
- rmdir(fspath.c_str());
+ if (rmdir(fspath.c_str()) == -1)
+ throw FileError("RealFSImpl::unlink_directory", fspath, strerror(errno));
#else
+ // Note: We could possibly replace this with _rmdir()
+ // which would then also work with errno instead of GetLastError(),
+ // but I am not sure if this is available (and works properly)
+ // on all windows platforms or only with Visual Studio.
if (!RemoveDirectory(fspath.c_str()))
- throw wexception(
- "'%s' could not be deleted in directory '%s'.", fspath.c_str(), directory_.c_str());
+ throw FileError("RealFSImpl::unlink_directory", fspath, std::string("file error (Windows error code ")+std::to_string(GetLastError())+")");
+ // TODO: generate proper system message from GetLastError() via FormatMessage
#endif
}
@@ -292,25 +289,20 @@
boost::replace_all(clean_dirname, "\\", "/");
#endif
- try {
- std::string::size_type it = 0;
- while (it < clean_dirname.size()) {
- it = clean_dirname.find('/', it);
-
- FileSystemPath fspath(canonicalize_name(clean_dirname.substr(0, it)));
- if (fspath.exists_ && !fspath.is_directory_)
- throw wexception("'%s' in directory '%s' exists and is not a directory",
- clean_dirname.substr(0, it).c_str(), directory_.c_str());
- if (!fspath.exists_)
- make_directory(clean_dirname.substr(0, it));
-
- if (it == std::string::npos)
- break;
- ++it;
- }
- } catch (const std::exception& e) {
- throw wexception("RealFSImpl::ensure_directory_exists(%s) in directory '%s': %s",
- clean_dirname.c_str(), directory_.c_str(), e.what());
+ std::string::size_type it = 0;
+ while (it < clean_dirname.size()) {
+ it = clean_dirname.find('/', it);
+
+ FileSystemPath fspath(canonicalize_name(clean_dirname.substr(0, it)));
+ if (fspath.exists_ && !fspath.is_directory_)
+ throw FileTypeError("RealFSImpl::ensure_directory_exists",
+ fspath, "path is not a directory");
+ if (!fspath.exists_)
+ make_directory(clean_dirname.substr(0, it));
+
+ if (it == std::string::npos)
+ break;
+ ++it;
}
}
@@ -318,33 +310,37 @@
* Create this directory, throw an error if it already exists or
* if a file is in the way or if the creation fails.
*
- * Pleas note, this function does not honor parents,
+ * Please note, this function does not honor parents,
* make_directory("onedir/otherdir/onemoredir") will fail
* if either onedir or otherdir is missing
*/
void RealFSImpl::make_directory(const std::string& dirname) {
FileSystemPath fspath(canonicalize_name(dirname));
if (fspath.exists_)
- throw wexception("a file/directory with the name '%s' already exists in directory '%s'",
- dirname.c_str(), directory_.c_str());
-
- if
-#ifdef _WIN32
- (!CreateDirectory(fspath.c_str(), NULL))
+ throw FileError("RealFSImpl::make_directory", fspath, "a file or directory with that name already exists");
+
+#ifndef _WIN32
+ if (!mkdir(fspath.c_str(), 0x1FF) == -1)
+ throw FileError("RealFSImpl::make_directory", fspath, strerror(errno));
#else
- (mkdir(fspath.c_str(), 0x1FF) == -1)
+ // Note: We could possibly replace this with _mkdir()
+ // which would then also work with errno instead of GetLastError(),
+ // but I am not sure if this is available (and works properly)
+ // on all windows platforms or only with Visual Studio.
+ if (!CreateDirectory(fspath.c_str(), NULL))
+ throw FileError("RealFSImpl::make_directory", fspath, std::string("file error (Windows error code ")+std::to_string(GetLastError())+")");
+ // TODO: generate proper system message from GetLastError() via FormatMessage
#endif
- throw DirectoryCannotCreateError("RealFSImpl::make_directory", dirname, strerror(errno));
}
/**
- * Read the given file into alloced memory; called by FileRead::open.
+ * Read the given file into allocated memory; called by FileRead::open.
* Throws an exception if the file couldn't be opened.
*/
void* RealFSImpl::load(const std::string& fname, size_t& length) {
const std::string fullname = canonicalize_name(fname);
if (is_directory(fullname)) {
- throw FileError("RealFSImpl::load", fullname);
+ throw FileTypeError("RealFSImpl::load", fullname, "path is a directory");
}
FILE* file = nullptr;
@@ -353,7 +349,7 @@
try {
file = fopen(fullname.c_str(), "rb");
if (!file)
- throw FileError("RealFSImpl::load", fullname);
+ throw FileError("RealFSImpl::load", fullname, "could not open file for reading");
// determine the size of the file (rather quirky, but it doesn't require
// potentially unportable functions)
@@ -371,6 +367,9 @@
// allocate a buffer and read the entire file into it
data = malloc(size + 1); // TODO(unknown): memory leak!
+ if (!data)
+ throw wexception("RealFSImpl::load: memory allocation failed for reading file %s (%s) with size %" PRIuS "",
+ fname.c_str(), fullname.c_str(), size);
int result = fread(data, size, 1, file);
if (size && (result != 1)) {
throw wexception("RealFSImpl::load: read failed for %s (%s) with size %" PRIuS "",
@@ -383,10 +382,10 @@
length = size;
} catch (...) {
- if (file) {
+ if (file)
fclose(file);
- }
- free(data);
+ if (data)
+ free(data);
throw;
}
@@ -410,7 +409,7 @@
FILE* const f = fopen(fullname.c_str(), append ? "a" : "wb");
if (!f)
- throw wexception("could not open %s (%s) for writing", fname.c_str(), fullname.c_str());
+ throw FileError("RealFSImpl::write", fullname, "could not open file for writing");
size_t const c = fwrite(data, length, 1, f);
fclose(f);
@@ -424,8 +423,7 @@
const std::string fullname1 = canonicalize_name(old_name);
const std::string fullname2 = canonicalize_name(new_name);
if (rename(fullname1.c_str(), fullname2.c_str()) != 0)
- throw wexception("DiskFileSystem: unable to rename %s to %s: %s", fullname1.c_str(),
- fullname2.c_str(), strerror(errno));
+ throw FileError("RealFSImpl::fs_rename", fullname1, std::string("unable to rename file to ") + fullname2 + ", " + strerror(errno));
}
/*****************************************************************************
@@ -439,7 +437,7 @@
struct RealFSStreamRead : public StreamRead {
explicit RealFSStreamRead(const std::string& fname) : file_(fopen(fname.c_str(), "rb")) {
if (!file_)
- throw wexception("could not open %s for reading", fname.c_str());
+ throw FileError("RealFSStreamRead::RealFSStreamRead", fname, "could not open file for reading");
}
~RealFSStreamRead() override {
@@ -477,7 +475,7 @@
explicit RealFSStreamWrite(const std::string& fname) : filename_(fname) {
file_ = fopen(fname.c_str(), "wb");
if (!file_)
- throw wexception("could not open %s for writing", fname.c_str());
+ throw FileError("RealFSStreamWrite::RealFSStreamWrite", fname, "could not open file for writing");
}
~RealFSStreamWrite() override {
=== modified file 'src/io/filesystem/filesystem.cc'
--- src/io/filesystem/filesystem.cc 2018-07-12 04:41:20 +0000
+++ src/io/filesystem/filesystem.cc 2018-11-02 11:11:32 +0000
@@ -306,7 +306,7 @@
std::list<std::string>::iterator i;
#ifdef _WIN32
- // remove all slashes with backslashes so following can work.
+ // replace all slashes with backslashes so following can work.
for (uint32_t j = 0; j < path.size(); ++j) {
if (path[j] == '/')
path[j] = '\\';
@@ -463,7 +463,7 @@
fs.ensure_directory_exists(".widelands");
fs.fs_unlink(".widelands");
return true;
- } catch (...) {
+ } catch (const FileError& e) {
log("Directory %s is not writeable - next try\n", path);
}
=== modified file 'src/io/filesystem/zip_filesystem.cc'
--- src/io/filesystem/zip_filesystem.cc 2018-04-07 16:59:00 +0000
+++ src/io/filesystem/zip_filesystem.cc 2018-11-02 11:11:32 +0000
@@ -262,15 +262,20 @@
* Create a sub filesystem out of this filesystem
*/
FileSystem* ZipFilesystem::make_sub_file_system(const std::string& path) {
+ if (path == ".") {
+ return new ZipFilesystem(zip_file_, basedir_in_zip_file_);
+ }
if (!file_exists(path)) {
throw wexception(
"ZipFilesystem::make_sub_file_system: The path '%s' does not exist in zip file '%s'.",
- path.c_str(), zip_file_->path().c_str());
+ (basedir_in_zip_file_.empty() ? path : basedir_in_zip_file_ + "/" + path).c_str(),
+ zip_file_->path().c_str());
}
if (!is_directory(path)) {
- throw wexception("ZipFilesystem::make_sub_file_system: "
- "The path '%s' needs to be a directory in zip file '%s'.",
- path.c_str(), zip_file_->path().c_str());
+ throw wexception(
+ "ZipFilesystem::make_sub_file_system: The path '%s' needs to be a directory in zip file '%s'.",
+ (basedir_in_zip_file_.empty()?path:basedir_in_zip_file_+"/"+path).c_str(),
+ zip_file_->path().c_str());
}
std::string localpath = path;
@@ -288,7 +293,10 @@
// see Filesystem::create
FileSystem* ZipFilesystem::create_sub_file_system(const std::string& path, Type const type) {
if (file_exists(path)) {
- throw wexception("ZipFilesystem::create_sub_file_system: Sub file system already exists.");
+ throw wexception(
+ "ZipFilesystem::create_sub_file_system: Path '%s' already exists in zip file %s.",
+ (basedir_in_zip_file_.empty() ? path : basedir_in_zip_file_ + "/" + path).c_str(),
+ zip_file_->path().c_str());
}
if (type != FileSystem::DIR)
@@ -435,8 +443,9 @@
"ZipFilesystem::write", complete_filename,
(boost::format("in path '%s'', Error") % zip_file_->path() % strerror(errno)).str());
default:
- throw FileError("ZipFilesystem::write", complete_filename,
- (boost::format("in path '%s'") % zip_file_->path()).str());
+ throw FileError(
+ "ZipFilesystem::write", complete_filename,
+ (boost::format("in path '%s'") % zip_file_->path()).str());
}
zipCloseFileInZip(zip_file_->write_handle());
=== modified file 'src/logic/editor_game_base.cc'
--- src/logic/editor_game_base.cc 2018-09-28 05:41:33 +0000
+++ src/logic/editor_game_base.cc 2018-11-02 11:11:32 +0000
@@ -26,10 +26,12 @@
#include "base/i18n.h"
#include "base/macros.h"
#include "base/scoped_timer.h"
+#include "base/time_string.h"
#include "base/wexception.h"
#include "economy/flag.h"
#include "economy/road.h"
#include "graphic/color.h"
+#include "logic/filesystem_constants.h"
#include "logic/findimmovable.h"
#include "logic/game.h"
#include "logic/game_data_error.h"
@@ -48,6 +50,7 @@
#include "logic/player.h"
#include "logic/playersmanager.h"
#include "logic/roadtype.h"
+#include "map_io/map_saver.h"
#include "scripting/logic.h"
#include "scripting/lua_table.h"
#include "ui_basic/progresswindow.h"
@@ -67,12 +70,86 @@
: gametime_(0),
lua_(lua_interface),
player_manager_(new PlayersManager(*this)),
- ibase_(nullptr) {
+ ibase_(nullptr),
+ tmp_fs_(nullptr) {
if (!lua_) // TODO(SirVer): this is sooo ugly, I can't say
lua_.reset(new LuaEditorInterface(this));
}
EditorGameBase::~EditorGameBase() {
+ delete_tempfile();
+}
+
+/**
+ * deletes the temporary file/dir
+ * also resets the map filesystem if it points to the temporary file
+ */
+void EditorGameBase::delete_tempfile() {
+ if (!tmp_fs_)
+ return;
+ std::string fs_filename = tmp_fs_->get_basename();
+ std::string mapfs_filename = map_.filesystem()->get_basename();
+ if (mapfs_filename == fs_filename)
+ map_.reset_filesystem();
+ tmp_fs_.reset();
+ try {
+ g_fs->fs_unlink(fs_filename);
+ } catch (const std::exception& e) {
+ // if file deletion fails then we have an abaondoned file lying around, but otherwise that's unproblematic
+ log("EditorGameBase::delete_tempfile: deleting temporary file/dir failed: %s\n", e.what());
+ }
+}
+
+/**
+ * creates a new file/dir, saves the map data, and reassigns the map filesystem
+ * does not delete the former temp file if one exists
+ * throws an exception if something goes wrong
+ */
+void EditorGameBase::create_tempfile_and_save_mapdata(FileSystem::Type const type) {
+ // should only be called when a map was already loaded
+ assert(map_.filesystem());
+
+ g_fs->ensure_directory_exists(kTempFileDir);
+
+ std::string filename = kTempFileDir + g_fs->file_separator() + timestring() + "_mapdata";
+ std::string complete_filename = filename + kTempFileExtension;
+
+ // if a file with that name already exists, then try a few name modifications
+ if (g_fs->file_exists(complete_filename))
+ {
+ int suffix;
+ for (suffix = 0; suffix <= 9; suffix++)
+ {
+ complete_filename = filename + "-" + std::to_string(suffix) + ".tmp";
+ if (!g_fs->file_exists(complete_filename))
+ break;
+ }
+ if (suffix > 9) {
+ throw wexception("EditorGameBase::create_tempfile_and_save_mapdata(): for all considered filenames a file already existed");
+ }
+ }
+
+ // create tmp_fs_
+ tmp_fs_.reset(g_fs->create_sub_file_system(complete_filename, type));
+
+ // save necessary map data (we actually save the whole map)
+ Widelands::MapSaver* wms = new Widelands::MapSaver(*tmp_fs_, *this);
+ wms->save();
+ delete wms;
+
+ // swap map fs
+ std::unique_ptr<FileSystem> mapfs(tmp_fs_->make_sub_file_system("."));
+ map_.swap_filesystem(mapfs);
+ mapfs.reset();
+
+ // This is just a convenience hack:
+ // If tmp_fs_ is a zip filesystem then - because of the way zip filesystems are currently implemented -
+ // the file is still in zip mode right now, which means that the file isn't finalized yet, i.e.,
+ // not even a valid zip file until zip mode ends. To force ending the zip mode (thus finalizing the file)
+ // we simply perform a (otherwise useless) filesystem request.
+ // It's not strictly necessary, but this way we get a valid zip file immediately istead of
+ // at some unkown later point (when an unzip operation happens or a filesystem object destructs).
+ tmp_fs_->file_exists("binary");
}
void EditorGameBase::think() {
@@ -196,6 +273,16 @@
* graphics are loaded.
*/
void EditorGameBase::postload() {
+ if (map_.filesystem()) {
+ // save map data to temporary file and reassign map fs
+ try {
+ create_tempfile_and_save_mapdata(FileSystem::ZIP);
+ } catch (const WException& e) {
+ log("EditorGameBase::postload: saving map to temporary file failed: %s", e.what());
+ throw;
+ }
+ }
+
// Postload tribes
assert(tribes_);
tribes_->postload();
@@ -411,6 +498,8 @@
player_manager_->cleanup();
map_.cleanup();
+
+ delete_tempfile();
}
void EditorGameBase::set_road(const FCoords& f, uint8_t const direction, uint8_t const roadtype) {
=== modified file 'src/logic/editor_game_base.h'
--- src/logic/editor_game_base.h 2018-04-07 16:59:00 +0000
+++ src/logic/editor_game_base.h 2018-11-02 11:11:32 +0000
@@ -254,6 +254,15 @@
std::unique_ptr<Tribes> tribes_;
std::unique_ptr<InteractiveBase> ibase_;
Map map_;
+
+ /// Even after a map is fully loaded, some static data (images, scripts)
+ /// will still be read from a filesystem whenever a map/game is saved.
+ /// To avoid potential filesystem conflicts when (pre)loading/saving/deleting
+ /// map/game files (and to avoid having to deal with this in many different places)
+ /// a temporary file (in a special dir) is created for such data.
+ std::unique_ptr<FileSystem> tmp_fs_;
+ void delete_tempfile();
+ void create_tempfile_and_save_mapdata(FileSystem::Type const type);
DISALLOW_COPY_AND_ASSIGN(EditorGameBase);
};
=== modified file 'src/logic/filesystem_constants.h'
--- src/logic/filesystem_constants.h 2018-04-22 16:01:32 +0000
+++ src/logic/filesystem_constants.h 2018-11-02 11:11:32 +0000
@@ -38,6 +38,13 @@
const std::string kS2MapExtension1 = ".swd";
const std::string kS2MapExtension2 = ".wld";
+/// Filesystem names for temp files holding static data that needs to be accessible via filesystem
+/// Kept in a separate dir to avoid filesystem conflicts
+const std::string kTempFileDir = "in_progress";
+const std::string kTempFileExtension = ".tmp";
+// We delete (accidentally remaining) temp files older than a week
+constexpr double kTempFilesKeepAroundTime = 7 * 24 * 60 * 60;
+
/// Filesystem names and timeouts for replays
const std::string kReplayDir = "replays";
const std::string kReplayExtension = ".wrpl";
=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc 2018-10-09 17:09:34 +0000
+++ src/wlapplication.cc 2018-11-02 11:11:32 +0000
@@ -339,6 +339,7 @@
changedir_on_mac();
cleanup_replays();
cleanup_ai_files();
+ cleanup_temp_files();
Section& config = g_options.pull_section("global");
@@ -1498,6 +1499,21 @@
}
}
+/**
+ * Delete old temp files that might still lurk around (game crashes etc.)
+ */
+void WLApplication::cleanup_temp_files() {
+ for (const std::string& filename :
+ filter(g_fs->list_directory(kTempFileDir), [](const std::string& fn) {
+ return boost::ends_with(fn, kTempFileExtension);
+ })) {
+ if (is_autogenerated_and_expired(filename, kTempFilesKeepAroundTime)) {
+ log("Deleting old temp file: %s\n", filename.c_str());
+ g_fs->fs_unlink(filename);
+ }
+ }
+}
+
bool WLApplication::redirect_output(std::string path) {
if (path.empty()) {
#ifdef _WIN32
=== modified file 'src/wlapplication.h'
--- src/wlapplication.h 2018-04-07 16:59:00 +0000
+++ src/wlapplication.h 2018-11-02 11:11:32 +0000
@@ -216,6 +216,8 @@
void cleanup_ai_files();
+ void cleanup_temp_files();
+
bool redirect_output(std::string path = "");
// Handle the given pressed key. Returns true when key was
Follow ups
-
[Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: noreply, 2018-11-14
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: GunChleoc, 2018-11-14
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: GunChleoc, 2018-11-13
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: Arty, 2018-11-12
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: kaputtnik, 2018-11-12
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: Arty, 2018-11-12
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: GunChleoc, 2018-11-12
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: Arty, 2018-11-12
-
Re: [Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: GunChleoc, 2018-11-12
-
[Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: GunChleoc, 2018-11-12
-
[Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: bunnybot, 2018-11-10
-
[Merge] lp:~widelands-dev/widelands/filesystem-errors into lp:widelands
From: bunnybot, 2018-11-02