Mercurial > octave
changeset 31830:354ed032ba50
load-save.cc: Save to temporary file first to prevent data loss (bug #63803)
load-save.cc: To prevent any crashes with saving individual variables from
corrupting a file with already-saved data, save first to an in-progress
temp file, then after that is successful rename it to the desired filename.
If there is a failure in the writing, the old file is not affected.
author | Arun Giridhar <arungiridhar@gmail.com> |
---|---|
date | Wed, 15 Feb 2023 17:41:53 -0500 |
parents | 2ea6344450e3 |
children | 45ac4c5272e9 |
files | libinterp/corefcn/load-save.cc |
diffstat | 1 files changed, 23 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/load-save.cc Wed Feb 15 16:41:58 2023 +0100 +++ b/libinterp/corefcn/load-save.cc Wed Feb 15 17:41:53 2023 -0500 @@ -29,6 +29,7 @@ #include <cstring> +#include <filesystem> #include <fstream> #include <iomanip> #include <iostream> @@ -1465,7 +1466,14 @@ print_usage (); else { - std::string fname = sys::file_ops::tilde_expand (argv[i]); + // We make a new temporary filename, write to that instead of the + // file specified, then try renaming it at the end. + // That way, if something goes wrong during the save like OOM, + // we won't overwrite already-saved data in a file. + // See bug #63803 for context. + + std::string desiredname = sys::file_ops::tilde_expand (argv[i]); + std::string fname = desiredname + ".saving_in_progress"; i++; @@ -1542,6 +1550,20 @@ file.close (); } } + + // If we are all the way here without Octave crashing or running out of + // memory etc, then we can say that writing to the temporary file + // was successful. So now we try to rename it to the actual file + // that was specified. + try + { + std::filesystem::rename (fname, desiredname); + } + catch (std::filesystem::filesystem_error& e) + { + error ("save: unable to save to %s %s", + desiredname.c_str (), e.what ()); + } } return retval;