mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-11 07:02:44 +09:00
Unify backup write logic
Use the same backup write helper function for both periodic background backups and for temporary backups in safeWrite(). Besides just removing code duplication, this brings the advantages of both together: - Temporary backups in safeWrite() now use the same atomic mechanism when replacing an already existing backup. So that if micro crashes in the middle of writing the backup in safeWrite(), this corrupted backup will not overwrite a previous good backup. - Better error handling for periodic backups.
This commit is contained in:
@@ -92,35 +92,51 @@ func (b *SharedBuffer) keepBackup() bool {
|
||||
return b.forceKeepBackup || b.Settings["permbackup"].(bool)
|
||||
}
|
||||
|
||||
// Backup saves the current buffer to the backups directory
|
||||
func (b *SharedBuffer) writeBackup(path string) (string, error) {
|
||||
backupdir := b.backupDir()
|
||||
if _, err := os.Stat(backupdir); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return "", err
|
||||
}
|
||||
if err = os.Mkdir(backupdir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
name := util.DetermineEscapePath(backupdir, path)
|
||||
|
||||
// If no existing backup, just write the backup.
|
||||
if _, err := os.Stat(name); errors.Is(err, fs.ErrNotExist) {
|
||||
_, err = b.overwriteFile(name)
|
||||
if err != nil {
|
||||
os.Remove(name)
|
||||
}
|
||||
return name, err
|
||||
}
|
||||
|
||||
// If a backup already exists, replace it atomically.
|
||||
tmp := util.AppendBackupSuffix(name)
|
||||
_, err := b.overwriteFile(tmp)
|
||||
if err != nil {
|
||||
os.Remove(tmp)
|
||||
return name, err
|
||||
}
|
||||
err = os.Rename(tmp, name)
|
||||
if err != nil {
|
||||
os.Remove(tmp)
|
||||
return name, err
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// Backup saves the buffer to the backups directory
|
||||
func (b *SharedBuffer) Backup() error {
|
||||
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
|
||||
return nil
|
||||
}
|
||||
|
||||
backupdir := b.backupDir()
|
||||
if _, err := os.Stat(backupdir); errors.Is(err, fs.ErrNotExist) {
|
||||
os.Mkdir(backupdir, os.ModePerm)
|
||||
}
|
||||
|
||||
name := util.DetermineEscapePath(backupdir, b.AbsPath)
|
||||
if _, err := os.Stat(name); errors.Is(err, fs.ErrNotExist) {
|
||||
_, err = b.overwriteFile(name)
|
||||
return err
|
||||
}
|
||||
|
||||
tmp := util.AppendBackupSuffix(name)
|
||||
_, err := b.overwriteFile(tmp)
|
||||
if err != nil {
|
||||
os.Remove(tmp)
|
||||
return err
|
||||
}
|
||||
err = os.Rename(tmp, name)
|
||||
if err != nil {
|
||||
os.Remove(tmp)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := b.writeBackup(b.AbsPath)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -333,27 +333,6 @@ func (b *Buffer) saveToFile(filename string, withSudo bool, autoSave bool) error
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *SharedBuffer) writeBackup(path string) (string, error) {
|
||||
backupDir := b.backupDir()
|
||||
if _, err := os.Stat(backupDir); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return "", err
|
||||
}
|
||||
if err = os.Mkdir(backupDir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
backupName := util.DetermineEscapePath(backupDir, path)
|
||||
_, err := b.overwriteFile(backupName)
|
||||
if err != nil {
|
||||
os.Remove(backupName)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return backupName, nil
|
||||
}
|
||||
|
||||
// safeWrite writes the buffer to a file in a "safe" way, preventing loss of the
|
||||
// contents of the file if it fails to write the new contents.
|
||||
// This means that the file is not overwritten directly but by writing to the
|
||||
|
||||
Reference in New Issue
Block a user