Merge lp:~widelands-dev/widelands/bug-1753230-working-with-tempfiles into lp:widelands

Proposed by Arty
Status: Merged
Merged at revision: 8917
Proposed branch: lp:~widelands-dev/widelands/bug-1753230-working-with-tempfiles
Merge into: lp:widelands
Diff against target: 365 lines (+164/-54)
8 files modified
src/editor/editorinteractive.cc (+1/-0)
src/editor/ui_menus/main_menu_save_map.cc (+34/-52)
src/io/filesystem/zip_filesystem.cc (+3/-0)
src/logic/editor_game_base.cc (+92/-2)
src/logic/editor_game_base.h (+9/-0)
src/logic/filesystem_constants.h (+7/-0)
src/wlapplication.cc (+16/-0)
src/wlapplication.h (+2/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/bug-1753230-working-with-tempfiles
Reviewer Review Type Date Requested Status
GunChleoc Approve
Review via email: mp+357656@code.launchpad.net

Commit message

Fix bugs with missing files/folders in savegames

- Whenever a map is fully loaded (editor/game/replay) the map is
  immediately saved to a temp file and the map's filesystem is
  reassigned to that temp file in a special directory.
  So, when map/save files are handled anywhere, there won't be any
  filesystem conflicts with or even accidentally deletion of the map
  filesystem (which would lead to corrupt save files later).

- Temp files are automatically deleted when not needed any more.

- Upon application start, any found temp files that are older than a week
  are considered accidental leftovers (e.g. from crashes) and deleted.

To post a comment you must log in.
Revision history for this message
GunChleoc (gunchleoc) wrote :

Code LGTM - just some minor nits.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4161. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/444762108.
Appveyor build 3959. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1753230_working_with_tempfiles-3959.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have tested this by allowing only 1 autosave file and sitting on wl_autosave_00.wgf with 7zip on Windows. Since wl_autosave_01.wgf - wl_autosave_05.wgf already existed, the autosaves that I got were wl_autosave_06.wgf - wl_autosave_09.wgf

I think this branch is good to go in after the other nits have been fixed, because it already improves the situation greatly, but maybe we could have some form of "is_writable" test rather than "file_exists"?

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4183. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/449653297.
Appveyor build 3981. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1753230_working_with_tempfiles-3981.

Revision history for this message
Arty (artydent) wrote :

1. Regarding the autosave stuff:

This wasn't anything this branch tried to solve. It only solved the the conflicts that arose from trying to modify files where the map fs pointed to, resulting in either some crash or error (if the file was currently locked) or resulting in corrupt savefiles.

Those other file conflicts (like trying to modify a savefile that is locked because you have it open with 7zip, or having a file write-protected or some such) are solved with the latest branch: https://code.launchpad.net/~widelands-dev/widelands/robust-saving

As for trying to specifically test "is_writable" instead of "file_exists" (or other potentially problematic file states) beforehand, I don't think it's worth it. For one thing, we might have to deal with the specifics of the various access control models on the different platforms. (Just looking at this stuff makes me nauseaous.) There is also the more general problem with any filesystem stuff that you can never be sure that the file state you just checked is still the same when you try your file operation next. Sure, it's very likely, but there can always be race conditions, and some other process might just have snatched the file away between your state check and your attempt to operate on a file.
So aside from a few minor exist checks I favour a simple, practical approach: just try the file operation, but catch and handle any errors. The error codes give a hint about what the actual problem was, but usually that doesn't matter much anyway: either it worked and we continue or it didn't and we abort.
Anyway, the latest branch https://code.launchpad.net/~widelands-dev/widelands/robust-saving does exactly that and handles file errors in all the map/game saving routines and cleanup routines. I still need to check in what other places we don't catch file errors but should. (Definitely when deleting files in the load/save menu, maybe synchstream creation, probably some other places.) That's going to be part of future branches though.

2. Those travis build errors

I hadn't actually seen this before. (I'm still a noob on Launchpad and don't know my way around very well, but I am trying to catch up. If there are any important features I might not but should know about, feel free to point something out.)

Anyway, those errors seem like minor nitpicks. I'll fix them.
Btw, are those builds made automatically here for any new branches? Or do I have to initiate them manually? (I haven't checked out the online building possibilities yet. Still on my todo list.)

Revision history for this message
Arty (artydent) wrote :

Btw, this autosave-thing you observed was a (I think even relatively recently introduced and somewhat dirty) error handling attempt by someone. When the wl_autosave_00.wgf couldn't be renamed (for backup purposes) then there was some "let's just try other filenames" approach, and the game would just find the next autosave filename (up to 09) where there didn't exist any file. At 09 it would just stop and not check any further, but use this as the target name, so from this point on wl_autosave_09.wgf would just have been overwritten with every autosave. (Which worked in your case, because this one wasn't file-locked.)

My latest branch is stricter in this regard. If some relevant renaming or deletion fails, then the autosaving is simply aborted, and there is a little message. I don't think the game needs to handle this in some special way. The player gets a message and can try to fix a problem (if there's a file lock for example) or has to save manually.

Revision history for this message
GunChleoc (gunchleoc) wrote :

The automatic builds are triggered by every push to a branch that has an active merge request.

For our testing environment, including our codecheck, see:

https://wl.widelands.org/wiki/RegressionTests/

If you scroll up to my first comment, you'll see a green "Show diff comments" link. Click on it and you'll see my comments in the diff. For longer diffs, I use the browser's search function and search for the reviewer's username to skip through the comments.

I agree with your reasoning about an "is writable" check, let's keep this branch as is. I'd like my diff comments addressed though.

Revision history for this message
GunChleoc (gunchleoc) wrote :

You have introduces a "rnrnrn " string in your last commit in a license header ;)

Revision history for this message
Arty (artydent) wrote :

No, I didn't. :-)

The string is already in the last trunk. I just noticed it and removed it together with the other small fix I commited. (It just didn't feel important enough to mention it in the log.)

Revision history for this message
GunChleoc (gunchleoc) wrote :

You're right, I read the diff the wrong way around. Thanks for fixing this too :)

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4188. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/450208008.
Appveyor build 3985. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1753230_working_with_tempfiles-3985.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have now fixed the nits myself, so that we can start reviewing your other branches

@bunnybot merge

review: Approve
Revision history for this message
Arty (artydent) wrote :

Huh? I had already fixed them. Did I miss something?

Revision history for this message
Arty (artydent) wrote :

Oh, I see you had some other nits that you fixed. Fair enough. I should have checked more thoroughly. Or did you mention some specifics before somewhere and I had missed them?

As for the naming of the temp dir, I also had it named "temp" first but felt that might encourage players to just delete it (possibly while the game is up, thus messing up their next save). I guess I was overreacting because a friend of mine notoriously does this kind of thing, always complaining that stupid programmers never clean up their temp stuff. But honestly, "temp" is perfectly fine.

Revision history for this message
Arty (artydent) wrote :

Oh, now I see where your original comments are. Don't know why I didn't notice them before. Sorry about that.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Don't worry about it - I know you're still finding your way around Launchpad and I'm happy to help.

If somebody decides to mess with the temp while playing, on their own head be it. At least everybody else will know it's temp files if they want to manually clean it out at a sensible point in time ;)

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4203. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/452768811.
Appveyor build 3999. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1753230_working_with_tempfiles-3999.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Refusing to merge, since Travis is not green. Use @bunnybot merge force for merging anyways.

Travis build 4203. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/452768811.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Travis error is a timeout

@bunnybot merge force

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/editor/editorinteractive.cc'
--- src/editor/editorinteractive.cc 2018-09-25 06:32:35 +0000
+++ src/editor/editorinteractive.cc 2018-11-09 08:01:52 +0000
@@ -187,6 +187,7 @@
187 }187 }
188188
189 ml->load_map_complete(egbase(), Widelands::MapLoader::LoadType::kEditor);189 ml->load_map_complete(egbase(), Widelands::MapLoader::LoadType::kEditor);
190 egbase().postload();
190 egbase().load_graphics(loader_ui);191 egbase().load_graphics(loader_ui);
191 map_changed(MapWas::kReplaced);192 map_changed(MapWas::kReplaced);
192}193}
193194
=== 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-09 08:01:52 +0000
@@ -273,15 +273,14 @@
273 return false;273 return false;
274 }274 }
275275
276 // save to a tmp file/dir first, rename later276 // Try deleting file (if it exists). If it fails, give a message and let the player choose a new name.
277 // (important to keep script files in the script directory)277 try {
278 const std::string tmp_name = complete_filename + ".tmp";278 g_fs->fs_unlink(complete_filename);
279 if (g_fs->file_exists(tmp_name)) {279 } catch (const std::exception& e) {
280 log("Unable to delete old map file %s while saving map: %s\n", complete_filename.c_str(), e.what());
280 const std::string s =281 const std::string s =
281 (boost::format(282 (boost::format(_("File ‘%’ could not be deleted.")) % FileSystem::fs_filename(filename.c_str())).str()
282 _("A file with the name ‘%s.tmp’ already exists. You have to remove it manually.")) %283 + " " + _("Try saving under a different name!");
283 FileSystem::fs_filename(filename.c_str()))
284 .str();
285 UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);284 UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);
286 mbox.run<UI::Panel::Returncodes>();285 mbox.run<UI::Panel::Returncodes>();
287 return false;286 return false;
@@ -290,51 +289,34 @@
290 Widelands::EditorGameBase& egbase = eia().egbase();289 Widelands::EditorGameBase& egbase = eia().egbase();
291 Widelands::Map* map = egbase.mutable_map();290 Widelands::Map* map = egbase.mutable_map();
292291
293 { // fs scope292 // Recompute seafaring tag
293 map->cleanup_port_spaces(egbase.world());
294 if (map->allows_seafaring()) {
295 map->add_tag("seafaring");
296 } else {
297 map->delete_tag("seafaring");
298 }
299
300 if (map->has_artifacts()) {
301 map->add_tag("artifacts");
302 } else {
303 map->delete_tag("artifacts");
304 }
305
306 // Try saving.
307 try {
294 std::unique_ptr<FileSystem> fs(308 std::unique_ptr<FileSystem> fs(
295 g_fs->create_sub_file_system(tmp_name, binary ? FileSystem::ZIP : FileSystem::DIR));309 g_fs->create_sub_file_system(complete_filename, binary ? FileSystem::ZIP : FileSystem::DIR));
296310 std::unique_ptr<Widelands::MapSaver> wms(new Widelands::MapSaver(*fs, egbase));
297 // Recompute seafaring tag311 wms->save();
298 map->cleanup_port_spaces(egbase.world());312 fs.reset();
299 if (map->allows_seafaring()) {313 } catch (const std::exception& e) {
300 map->add_tag("seafaring");314 std::string s = _("Error Saving Map!\nSaved map file may be corrupt!\n\nReason "
301 } else {315 "given:\n");
302 map->delete_tag("seafaring");316 s += e.what();
303 }317 UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);
304318 mbox.run<UI::Panel::Returncodes>();
305 if (map->has_artifacts()) {319 }
306 map->add_tag("artifacts");
307 } else {
308 map->delete_tag("artifacts");
309 }
310
311 try {
312 Widelands::MapSaver* wms = new Widelands::MapSaver(*fs, egbase);
313 wms->save();
314 delete wms;
315 // Reset filesystem to avoid file locks on saves
316 fs.reset();
317 map->reset_filesystem();
318 eia().set_need_save(false);
319 g_fs->fs_unlink(complete_filename);
320 g_fs->fs_rename(tmp_name, complete_filename);
321 // Also change fs, as we assign it to the map below
322 fs.reset(g_fs->make_sub_file_system(complete_filename));
323 // Set the filesystem of the map to the current save file / directory
324 map->swap_filesystem(fs);
325 // DONT use fs as of here, its garbage now!
326
327 } catch (const std::exception& e) {
328 std::string s = _("Error Saving Map!\nSaved map file may be corrupt!\n\nReason "
329 "given:\n");
330 s += e.what();
331 UI::WLMessageBox mbox(&eia(), _("Error Saving Map!"), s, UI::WLMessageBox::MBoxType::kOk);
332 mbox.run<UI::Panel::Returncodes>();
333
334 // cleanup tmp file if it was created
335 g_fs->fs_unlink(tmp_name);
336 }
337 } // end fs scope, dont use it
338320
339 die();321 die();
340 return true;322 return true;
341323
=== 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-09 08:01:52 +0000
@@ -262,6 +262,9 @@
262 * Create a sub filesystem out of this filesystem262 * Create a sub filesystem out of this filesystem
263 */263 */
264FileSystem* ZipFilesystem::make_sub_file_system(const std::string& path) {264FileSystem* ZipFilesystem::make_sub_file_system(const std::string& path) {
265 if (path == ".") {
266 return new ZipFilesystem(zip_file_, basedir_in_zip_file_);
267 }
265 if (!file_exists(path)) {268 if (!file_exists(path)) {
266 throw wexception(269 throw wexception(
267 "ZipFilesystem::make_sub_file_system: The path '%s' does not exist in zip file '%s'.",270 "ZipFilesystem::make_sub_file_system: The path '%s' does not exist in zip file '%s'.",
268271
=== 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-09 08:01:52 +0000
@@ -8,7 +8,7 @@
8 *8 *
9 * This program is distributed in the hope that it will be useful,9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11rnrnrn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.12 * GNU General Public License for more details.
13 *13 *
14 * You should have received a copy of the GNU General Public License14 * You should have received a copy of the GNU General Public License
@@ -26,10 +26,12 @@
26#include "base/i18n.h"26#include "base/i18n.h"
27#include "base/macros.h"27#include "base/macros.h"
28#include "base/scoped_timer.h"28#include "base/scoped_timer.h"
29#include "base/time_string.h"
29#include "base/wexception.h"30#include "base/wexception.h"
30#include "economy/flag.h"31#include "economy/flag.h"
31#include "economy/road.h"32#include "economy/road.h"
32#include "graphic/color.h"33#include "graphic/color.h"
34#include "logic/filesystem_constants.h"
33#include "logic/findimmovable.h"35#include "logic/findimmovable.h"
34#include "logic/game.h"36#include "logic/game.h"
35#include "logic/game_data_error.h"37#include "logic/game_data_error.h"
@@ -48,6 +50,7 @@
48#include "logic/player.h"50#include "logic/player.h"
49#include "logic/playersmanager.h"51#include "logic/playersmanager.h"
50#include "logic/roadtype.h"52#include "logic/roadtype.h"
53#include "map_io/map_saver.h"
51#include "scripting/logic.h"54#include "scripting/logic.h"
52#include "scripting/lua_table.h"55#include "scripting/lua_table.h"
53#include "ui_basic/progresswindow.h"56#include "ui_basic/progresswindow.h"
@@ -67,12 +70,87 @@
67 : gametime_(0),70 : gametime_(0),
68 lua_(lua_interface),71 lua_(lua_interface),
69 player_manager_(new PlayersManager(*this)),72 player_manager_(new PlayersManager(*this)),
70 ibase_(nullptr) {73 ibase_(nullptr),
74 tmp_fs_(nullptr) {
71 if (!lua_) // TODO(SirVer): this is sooo ugly, I can't say75 if (!lua_) // TODO(SirVer): this is sooo ugly, I can't say
72 lua_.reset(new LuaEditorInterface(this));76 lua_.reset(new LuaEditorInterface(this));
73}77}
7478
75EditorGameBase::~EditorGameBase() {79EditorGameBase::~EditorGameBase() {
80 delete_tempfile();
81}
82
83/**
84 * deletes the temporary file/dir
85 * also resets the map filesystem if it points to the temporary file
86 */
87void EditorGameBase::delete_tempfile() {
88 if (!tmp_fs_) {
89 return;
90 }
91
92 std::string fs_filename = tmp_fs_->get_basename();
93 std::string mapfs_filename = map_.filesystem()->get_basename();
94 if (mapfs_filename == fs_filename)
95 map_.reset_filesystem();
96 tmp_fs_.reset();
97 try {
98 g_fs->fs_unlink(fs_filename);
99 } catch (const std::exception& e) {
100 // if file deletion fails then we have an abandoned file lying around, but otherwise that's unproblematic
101 log("EditorGameBase::delete_tempfile: deleting temporary file/dir failed: %s\n", e.what());
102 }
103}
104
105/**
106 * creates a new file/dir, saves the map data, and reassigns the map filesystem
107 * does not delete the former temp file if one exists
108 * throws an exception if something goes wrong
109 */
110void EditorGameBase::create_tempfile_and_save_mapdata(FileSystem::Type const type) {
111 // should only be called when a map was already loaded
112 assert(map_.filesystem());
113
114 g_fs->ensure_directory_exists(kTempFileDir);
115
116 std::string filename = kTempFileDir + g_fs->file_separator() + timestring() + "_mapdata";
117 std::string complete_filename = filename + kTempFileExtension;
118
119 // if a file with that name already exists, then try a few name modifications
120 if (g_fs->file_exists(complete_filename))
121 {
122 int suffix;
123 for (suffix = 0; suffix <= 9; suffix++)
124 {
125 complete_filename = filename + "-" + std::to_string(suffix) + kTempFileExtension;
126 if (!g_fs->file_exists(complete_filename))
127 break;
128 }
129 if (suffix > 9) {
130 throw wexception("EditorGameBase::create_tempfile_and_save_mapdata(): for all considered filenames a file already existed");
131 }
132 }
133
134 // create tmp_fs_
135 tmp_fs_.reset(g_fs->create_sub_file_system(complete_filename, type));
136
137 // save necessary map data (we actually save the whole map)
138 std::unique_ptr<Widelands::MapSaver> wms(new Widelands::MapSaver(*tmp_fs_, *this));
139 wms->save();
140
141 // swap map fs
142 std::unique_ptr<FileSystem> mapfs(tmp_fs_->make_sub_file_system("."));
143 map_.swap_filesystem(mapfs);
144 mapfs.reset();
145
146 // This is just a convenience hack:
147 // If tmp_fs_ is a zip filesystem then - because of the way zip filesystems are currently implemented -
148 // the file is still in zip mode right now, which means that the file isn't finalized yet, i.e.,
149 // not even a valid zip file until zip mode ends. To force ending the zip mode (thus finalizing the file)
150 // we simply perform a (otherwise useless) filesystem request.
151 // It's not strictly necessary, but this way we get a valid zip file immediately istead of
152 // at some unkown later point (when an unzip operation happens or a filesystem object destructs).
153 tmp_fs_->file_exists("binary");
76}154}
77155
78void EditorGameBase::think() {156void EditorGameBase::think() {
@@ -196,6 +274,16 @@
196 * graphics are loaded.274 * graphics are loaded.
197 */275 */
198void EditorGameBase::postload() {276void EditorGameBase::postload() {
277 if (map_.filesystem()) {
278 // save map data to temporary file and reassign map fs
279 try {
280 create_tempfile_and_save_mapdata(FileSystem::ZIP);
281 } catch (const WException& e) {
282 log("EditorGameBase::postload: saving map to temporary file failed: %s", e.what());
283 throw;
284 }
285 }
286
199 // Postload tribes287 // Postload tribes
200 assert(tribes_);288 assert(tribes_);
201 tribes_->postload();289 tribes_->postload();
@@ -411,6 +499,8 @@
411 player_manager_->cleanup();499 player_manager_->cleanup();
412500
413 map_.cleanup();501 map_.cleanup();
502
503 delete_tempfile();
414}504}
415505
416void EditorGameBase::set_road(const FCoords& f, uint8_t const direction, uint8_t const roadtype) {506void EditorGameBase::set_road(const FCoords& f, uint8_t const direction, uint8_t const roadtype) {
417507
=== 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-09 08:01:52 +0000
@@ -255,6 +255,15 @@
255 std::unique_ptr<InteractiveBase> ibase_;255 std::unique_ptr<InteractiveBase> ibase_;
256 Map map_;256 Map map_;
257257
258 /// Even after a map is fully loaded, some static data (images, scripts)
259 /// will still be read from a filesystem whenever a map/game is saved.
260 /// To avoid potential filesystem conflicts when (pre)loading/saving/deleting
261 /// map/game files (and to avoid having to deal with this in many different places)
262 /// a temporary file (in a special dir) is created for such data.
263 std::unique_ptr<FileSystem> tmp_fs_;
264 void delete_tempfile();
265 void create_tempfile_and_save_mapdata(FileSystem::Type type);
266
258 DISALLOW_COPY_AND_ASSIGN(EditorGameBase);267 DISALLOW_COPY_AND_ASSIGN(EditorGameBase);
259};268};
260269
261270
=== 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-09 08:01:52 +0000
@@ -38,6 +38,13 @@
38const std::string kS2MapExtension1 = ".swd";38const std::string kS2MapExtension1 = ".swd";
39const std::string kS2MapExtension2 = ".wld";39const std::string kS2MapExtension2 = ".wld";
4040
41/// Filesystem names for temp files holding static data that needs to be accessible via filesystem
42/// Kept in a separate dir to avoid filesystem conflicts
43const std::string kTempFileDir = "temp";
44const std::string kTempFileExtension = ".tmp";
45// We delete (accidentally remaining) temp files older than a week
46constexpr double kTempFilesKeepAroundTime = 7 * 24 * 60 * 60;
47
41/// Filesystem names and timeouts for replays48/// Filesystem names and timeouts for replays
42const std::string kReplayDir = "replays";49const std::string kReplayDir = "replays";
43const std::string kReplayExtension = ".wrpl";50const std::string kReplayExtension = ".wrpl";
4451
=== modified file 'src/wlapplication.cc'
--- src/wlapplication.cc 2018-10-09 17:09:34 +0000
+++ src/wlapplication.cc 2018-11-09 08:01:52 +0000
@@ -339,6 +339,7 @@
339 changedir_on_mac();339 changedir_on_mac();
340 cleanup_replays();340 cleanup_replays();
341 cleanup_ai_files();341 cleanup_ai_files();
342 cleanup_temp_files();
342343
343 Section& config = g_options.pull_section("global");344 Section& config = g_options.pull_section("global");
344345
@@ -1498,6 +1499,21 @@
1498 }1499 }
1499}1500}
15001501
1502/**
1503 * Delete old temp files that might still lurk around (game crashes etc.)
1504 */
1505void WLApplication::cleanup_temp_files() {
1506 for (const std::string& filename :
1507 filter(g_fs->list_directory(kTempFileDir), [](const std::string& fn) {
1508 return boost::ends_with(fn, kTempFileExtension);
1509 })) {
1510 if (is_autogenerated_and_expired(filename, kTempFilesKeepAroundTime)) {
1511 log("Deleting old temp file: %s\n", filename.c_str());
1512 g_fs->fs_unlink(filename);
1513 }
1514 }
1515}
1516
1501bool WLApplication::redirect_output(std::string path) {1517bool WLApplication::redirect_output(std::string path) {
1502 if (path.empty()) {1518 if (path.empty()) {
1503#ifdef _WIN321519#ifdef _WIN32
15041520
=== modified file 'src/wlapplication.h'
--- src/wlapplication.h 2018-04-07 16:59:00 +0000
+++ src/wlapplication.h 2018-11-09 08:01:52 +0000
@@ -216,6 +216,8 @@
216216
217 void cleanup_ai_files();217 void cleanup_ai_files();
218218
219 void cleanup_temp_files();
220
219 bool redirect_output(std::string path = "");221 bool redirect_output(std::string path = "");
220222
221 // Handle the given pressed key. Returns true when key was223 // Handle the given pressed key. Returns true when key was

Subscribers

People subscribed via source and target branches

to status/vote changes: