From 10364082c8351b0f4a258699742370195aadde6b Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Tue, 3 Jun 2014 10:42:07 -0400 Subject: [PATCH] Per a suggestion of JMarc's, first write the saved file to a temporary name, then move it to its real location if we succeed. This prevents our over-writing the existing file with a corrupt one. --- src/Buffer.cpp | 61 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index cbd46266e9..b531127c9c 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1276,12 +1276,38 @@ bool Buffer::save() const // We don't need autosaves in the immediate future. (Asger) resetAutosaveTimers(); - FileName backupName; - bool madeBackup = false; + // if the file does not yet exist, none of the backup activity + // that follows is necessary + if (!fileName().exists()) + return writeFile(fileName()); + + // we first write the file to a new name, then move it to its + // proper location once that has been done successfully. that + // way we preserve the original file if something goes wrong. + string const savepath = fileName().onlyPath().absFileName(); + string savename = "tmp-" + fileName().onlyFileName(); + FileName savefile(addName(savepath, savename)); + while (savefile.exists()) { + if (savefile.absFileName().size() > 1024) { + Alert::error(_("Write failure"), + bformat(_("Cannot find temporary filename for:\n %1$s.\n" + "Even %2$s exists!"), + from_utf8(fileName().absFileName()), + from_utf8(savefile.absFileName()))); + return false; + } + savename = "tmp-" + savename; + savefile.set(addName(savepath, savename)); + } + + LYXERR(Debug::FILES, "Saving to " << savefile.absFileName()); + if (!writeFile(savefile)) + return false; - // make a backup if the file already exists - if (lyxrc.make_backup && fileName().exists()) { - backupName = FileName(absFileName() + '~'); + // we will set this to false if we fail + bool made_backup = true; + if (lyxrc.make_backup) { + FileName backupName(absFileName() + '~'); if (!lyxrc.backupdir_path.empty()) { string const mangledName = subst(subst(backupName.absFileName(), '/', '!'), ':', '!'); @@ -1291,12 +1317,11 @@ bool Buffer::save() const // Except file is symlink do not copy because of #6587. // Hard links have bad luck. - if (fileName().isSymLink()) - madeBackup = fileName().copyTo(backupName); - else - madeBackup = fileName().moveTo(backupName); + made_backup = fileName().isSymLink() ? + fileName().copyTo(backupName): + fileName().moveTo(backupName); - if (!madeBackup) { + if (!made_backup) { Alert::error(_("Backup failure"), bformat(_("Cannot create backup file %1$s.\n" "Please check whether the directory exists and is writable."), @@ -1304,16 +1329,18 @@ bool Buffer::save() const //LYXERR(Debug::DEBUG, "Fs error: " << fe.what()); } } - - if (writeFile(d->filename)) { + + if (made_backup && savefile.moveTo(fileName())) { markClean(); return true; - } else { - // Saving failed, so backup is not backup - if (madeBackup) - backupName.moveTo(d->filename); - return false; } + // else + Alert::error(_("Write failure"), + bformat(_("Cannot move saved file to:\n %1$s.\n" + "But the file has successfully been saved as:\n %2$s."), + from_utf8(fileName().absFileName()), + from_utf8(savefile.absFileName()))); + return false; } -- 2.39.5