Skip to content

Commit a862c97

Browse files
committed
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.
1 parent 04b878b commit a862c97

File tree

2 files changed

+28
-33
lines changed

2 files changed

+28
-33
lines changed

internal/buffer/backup.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,35 +92,51 @@ func (b *SharedBuffer) keepBackup() bool {
9292
return b.forceKeepBackup || b.Settings["permbackup"].(bool)
9393
}
9494

95-
// Backup saves the current buffer to the backups directory
96-
func (b *SharedBuffer) Backup() error {
97-
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
98-
return nil
99-
}
100-
95+
func (b *SharedBuffer) writeBackup(path string) (string, error) {
10196
backupdir := b.backupDir()
102-
if _, err := os.Stat(backupdir); errors.Is(err, fs.ErrNotExist) {
103-
os.Mkdir(backupdir, os.ModePerm)
97+
if _, err := os.Stat(backupdir); err != nil {
98+
if !errors.Is(err, fs.ErrNotExist) {
99+
return "", err
100+
}
101+
if err = os.Mkdir(backupdir, os.ModePerm); err != nil {
102+
return "", err
103+
}
104104
}
105105

106-
name := util.DetermineEscapePath(backupdir, b.AbsPath)
106+
name := util.DetermineEscapePath(backupdir, path)
107+
108+
// If no existing backup, just write the backup.
107109
if _, err := os.Stat(name); errors.Is(err, fs.ErrNotExist) {
108110
_, err = b.overwriteFile(name)
109-
return err
111+
if err != nil {
112+
os.Remove(name)
113+
}
114+
return name, err
110115
}
111116

117+
// If a backup already exists, replace it atomically.
112118
tmp := util.AppendBackupSuffix(name)
113119
_, err := b.overwriteFile(tmp)
114120
if err != nil {
115121
os.Remove(tmp)
116-
return err
122+
return name, err
117123
}
118124
err = os.Rename(tmp, name)
119125
if err != nil {
120126
os.Remove(tmp)
121-
return err
127+
return name, err
128+
}
129+
130+
return name, nil
131+
}
132+
133+
// Backup saves the buffer to the backups directory
134+
func (b *SharedBuffer) Backup() error {
135+
if !b.Settings["backup"].(bool) || b.Path == "" || b.Type != BTDefault {
136+
return nil
122137
}
123138

139+
_, err := b.writeBackup(b.AbsPath)
124140
return err
125141
}
126142

internal/buffer/save.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -333,27 +333,6 @@ func (b *Buffer) saveToFile(filename string, withSudo bool, autoSave bool) error
333333
return err
334334
}
335335

336-
func (b *SharedBuffer) writeBackup(path string) (string, error) {
337-
backupDir := b.backupDir()
338-
if _, err := os.Stat(backupDir); err != nil {
339-
if !errors.Is(err, fs.ErrNotExist) {
340-
return "", err
341-
}
342-
if err = os.Mkdir(backupDir, os.ModePerm); err != nil {
343-
return "", err
344-
}
345-
}
346-
347-
backupName := util.DetermineEscapePath(backupDir, path)
348-
_, err := b.overwriteFile(backupName)
349-
if err != nil {
350-
os.Remove(backupName)
351-
return "", err
352-
}
353-
354-
return backupName, nil
355-
}
356-
357336
// safeWrite writes the buffer to a file in a "safe" way, preventing loss of the
358337
// contents of the file if it fails to write the new contents.
359338
// This means that the file is not overwritten directly but by writing to the

0 commit comments

Comments
 (0)