Skip to content

Commit 51ebfae

Browse files
committed
chanbackup: archive old channel backups
In this commit, we first check if a previous backup file exists, if it does we copy it to archive folder before replacing it with a new backup file.
1 parent 5cec466 commit 51ebfae

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

chanbackup/backupfile.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package chanbackup
22

33
import (
44
"fmt"
5+
"io"
56
"os"
67
"path/filepath"
8+
"time"
79

810
"github.com/lightningnetwork/lnd/keychain"
911
)
@@ -17,6 +19,10 @@ const (
1719
// file that we'll use to atomically update the primary back up file
1820
// when new channel are detected.
1921
DefaultTempBackupFileName = "temp-dont-use.backup"
22+
23+
// DefaultChanBackupDirName is the default name of the directory that
24+
// we'll use to store old channel backups.
25+
DefaultChanBackupArchiveDirName = "channelarchives"
2026
)
2127

2228
var (
@@ -44,6 +50,9 @@ type MultiFile struct {
4450

4551
// tempFile is an open handle to the temp back up file.
4652
tempFile *os.File
53+
54+
// archiveDir is the directory where we'll store old channel backups.
55+
archiveDir string
4756
}
4857

4958
// NewMultiFile create a new multi-file instance at the target location on the
@@ -56,10 +65,14 @@ func NewMultiFile(fileName string) *MultiFile {
5665
tempFileName := filepath.Join(
5766
backupFileDir, DefaultTempBackupFileName,
5867
)
68+
archiveDir := filepath.Join(
69+
backupFileDir, DefaultChanBackupArchiveDirName,
70+
)
5971

6072
return &MultiFile{
6173
fileName: fileName,
6274
tempFileName: tempFileName,
75+
archiveDir: archiveDir,
6376
}
6477
}
6578

@@ -117,6 +130,19 @@ func (b *MultiFile) UpdateAndSwap(newBackup PackedMulti) error {
117130
return fmt.Errorf("unable to close file: %w", err)
118131
}
119132

133+
// We check if the main backup file exists, if it does we archive it
134+
// before replacing it with the new backup.
135+
if _, err := os.Stat(b.fileName); err == nil {
136+
log.Infof("Archiving old backup file at %v", b.fileName)
137+
138+
if err := createArchiveFile(
139+
b.archiveDir, b.fileName,
140+
); err != nil {
141+
return fmt.Errorf("unable to archive old backup file:"+
142+
" %w", err)
143+
}
144+
}
145+
120146
// Finally, we'll attempt to atomically rename the temporary file to
121147
// the main back up file. If this succeeds, then we'll only have a
122148
// single file on disk once this method exits.
@@ -147,3 +173,48 @@ func (b *MultiFile) ExtractMulti(keyChain keychain.KeyRing) (*Multi, error) {
147173
packedMulti := PackedMulti(multiBytes)
148174
return packedMulti.Unpack(keyChain)
149175
}
176+
177+
func createArchiveFile(archiveDir string, fileName string) error {
178+
// Generate archive file path with timestamped name.
179+
baseFileName := filepath.Base(fileName)
180+
timestamp := time.Now().Format("2006-01-02-15-04-05")
181+
182+
archiveFileName := fmt.Sprintf("%s-%s", baseFileName, timestamp)
183+
archiveFilePath := filepath.Join(archiveDir, archiveFileName)
184+
185+
oldBackupFile, err := os.Open(fileName)
186+
if err != nil {
187+
return fmt.Errorf("unable to open old backup file: %w", err)
188+
}
189+
defer func() {
190+
if cerr := oldBackupFile.Close(); cerr != nil && err == nil {
191+
err = fmt.Errorf("error closing old backup file: %w",
192+
cerr)
193+
}
194+
}()
195+
196+
// Ensure the archive directory exists. If it doesn't we create it.
197+
const archiveDirPermissions = 0o755
198+
err = os.MkdirAll(archiveDir, archiveDirPermissions)
199+
if err != nil {
200+
return fmt.Errorf("unable to create archive directory: %w", err)
201+
}
202+
203+
// Create new archive file.
204+
archiveFile, err := os.Create(archiveFilePath)
205+
if err != nil {
206+
return fmt.Errorf("unable to create archive file: %w", err)
207+
}
208+
defer func() {
209+
if cerr := archiveFile.Close(); cerr != nil && err == nil {
210+
err = fmt.Errorf("error closing archive file: %w", cerr)
211+
}
212+
}()
213+
214+
// Copy contents of old backup to the newly created archive file.
215+
if _, err := io.Copy(archiveFile, oldBackupFile); err != nil {
216+
return fmt.Errorf("error copying to archive file: %w", err)
217+
}
218+
219+
return nil
220+
}

0 commit comments

Comments
 (0)