]> git.lyx.org Git - features.git/commitdiff
Backup the existing LyX file before attempting to write the new one.
authorRichard Heck <rgheck@lyx.org>
Mon, 9 Jun 2014 21:35:17 +0000 (17:35 -0400)
committerRichard Heck <rgheck@lyx.org>
Sat, 14 Jun 2014 21:42:27 +0000 (17:42 -0400)
This avoids dataloss in case we are unable to write the new one after
all.

A more sophisticated approach, due to Georg, is in master, but it needs
more testing that it will be able to get before the release of 2.1.1.
That should be committed to 2.1.x when it is ready and this patch backed
out again.

ANNOUNCE
src/Buffer.cpp
status.21x

index 2efed590f810b424aad95bc7f2e01b6e4cfe7d4d..a2ddfabd0c6ae67e12a27028117c2105b92348c1 100644 (file)
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -21,11 +21,11 @@ known reports seem to involve documents that contain tables, and the corrupt
 file always ends with: \begin_inset Tabular. Users who work with tables a lot
 may therefore wish to disable auto-save.
 
-To prevent dataloss, we have changed the way LyX saves files. Rather than
-over-write the original file immediately, LyX now saves the new file to a
-temporary name and then renames the new file to the original filename only
-after it has been written successfully. 
-
+To prevent dataloss, we have changed the way LyX saves files if the user
+has not enabled backups. LyX now renames the existing file before 
+attempting to save the new one (in effect, making a temporary backup). 
+Then, if the save fails, the original file can be restored.
+  
 LyX is a document processor that encourages an approach to writing based 
 on the structure of your documents and not simply their appearance. It is
 released under a Free and Open Source Software license.
index ab2164b82b7949d3f68254ea7717d4e95d212517..dcd74bcbb5c41009ab89b6683b7c744b36f5f8d2 100644 (file)
@@ -1276,44 +1276,90 @@ bool Buffer::save() const
        // We don't need autosaves in the immediate future. (Asger)
        resetAutosaveTimers();
 
+       // none of the backup activity that follows is necessary if the
+       // file does not exist
+       if (!fileName().exists())
+               return writeFile(fileName());
+
+       // this will hold the name of the location to which we backup
+       // the existing file, if we do that.
        FileName backupName;
-       bool madeBackup = false;
 
        // make a backup if the file already exists
-       if (lyxrc.make_backup && fileName().exists()) {
+       if (lyxrc.make_backup) {
                backupName = FileName(absFileName() + '~');
                if (!lyxrc.backupdir_path.empty()) {
                        string const mangledName =
                                subst(subst(backupName.absFileName(), '/', '!'), ':', '!');
                        backupName = FileName(addName(lyxrc.backupdir_path,
-                                                     mangledName));
-               }
-
-               // 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);
-
-               if (!madeBackup) {
-                       Alert::error(_("Backup failure"),
-                                    bformat(_("Cannot create backup file %1$s.\n"
-                                              "Please check whether the directory exists and is writable."),
-                                            from_utf8(backupName.absFileName())));
-                       //LYXERR(Debug::DEBUG, "Fs error: " << fe.what());
+                                                                       mangledName));
                }
+       } else {
+               // we make a backup anyway, to avoid over-writing the original file
+               // before the new one has been saved.
+               //
+               // FIXME A more sophisticated approach is in master and should
+               // be moved into 2.1.x once it has been properly tested.
+               string const savepath = fileName().onlyPath().absFileName();
+               string const fname = fileName().onlyFileName();
+               string savename;
+               int fnum = 0;
+
+               // try to find a temporary filename to which we can backup the
+               // existing  LyX file
+               do {
+                       fnum += 1;
+                       if (fnum > 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(backupName.absFileName())));
+                               return false;
+                       }
+                       savename = "lyxbak-" + convert<string>(fnum) + "-" + fname;
+                       backupName.set(addName(savepath, savename));
+               } while (backupName.exists());
+       }
+
+       LYXERR(Debug::FILES, "Backup being made at " << backupName);
+       // We make the backup by moving the original file unless it is
+       // a symlink, in which case we copy it because of #6587. 
+       // Hard links are broken: The new file we write will not be hard
+       // linked as the original file was. Sorry!
+       bool const madeBackup = fileName().isSymLink() ?
+             fileName().copyTo(backupName) :
+                               fileName().moveTo(backupName);
+
+       if (!madeBackup) {
+               int const ret = Alert::prompt(_("Backup failure"),
+                       bformat(_("Cannot create backup file:\n  %1$s.\n"
+                                 "Do you want to try to save the file anyway?\n"
+                           "This will over-write the original file."),
+                         from_utf8(backupName.absFileName())),
+                       1, 1, _("&Overwrite"), _("&Cancel"));
+               if (ret != 0)
+                       return false;
        }
 
        if (writeFile(d->filename)) {
                markClean();
+               if (madeBackup && !lyxrc.make_backup)
+                       backupName.removeFile();
                return true;
-       } else {
-               // Saving failed, so backup is not backup
-               if (madeBackup)
-                       backupName.moveTo(d->filename);
-               return false;
        }
+
+       // else saving failed, so backup is not backup
+       if (madeBackup) {
+               if (!backupName.moveTo(d->filename)) {
+                       Alert::error(_("Write failure"),
+                                bformat(_("Cannot restore original file to:\n  %1$s.\n"
+                                                "But it can be found at:\n  %2$s."),
+                                        from_utf8(fileName().absFileName()),
+                                        from_utf8(backupName.absFileName())));
+               }
+       }
+       return false;
 }
 
 
index f3cf3a73ccda3d836c8c9560d38b7f821af756ab..4f32e8893eb09e43192a95a107200c57c47b72ea 100644 (file)
@@ -28,10 +28,14 @@ What's new
 
 * DOCUMENT INPUT/OUTPUT
 
-
 - We now flush the output stream more frequently, as a temporary measure
   to help us gather information about the crash mentioned above.
 
+- To prevent dataloss, we have changed the way LyX saves files if the user
+  has not enabled backups. LyX now renames the existing file before 
+  attempting to save the new one (in effect, making a temporary backup). 
+  Then, if the save fails, the original file can be restored.
+
 
 * TEX2LYX IMPROVEMENTS
 
@@ -82,10 +86,9 @@ What's new
 
 * LYX2LYX
 
-We have fixed several significant issues involving conversion of 2.0
-  format into 2.1 format, and conversely. This mostly affects the new
-  argument insets and, in particular, beamer documents. These are
-  detailed below.
+We have fixed several significant issues involving conversion of 2.0 format into 
+2.1 format, and conversely. This mostly affects the new argument insets and, in 
+particular, beamer documents. These are detailed below.
 
 - Fix conversion of beamer block titles ending with non-ERT insets to 2.1 format.