backup
API
backup
packageAPI reference for the backup
package.
Imports
(14)
STD
os
STD
path/filepath
STD
syscall
STD
crypto/rand
STD
encoding/hex
STD
encoding/json
STD
fmt
STD
sort
STD
time
PKG
github.com/mirkobrombin/dabadee/pkg/dabadee
PKG
github.com/mirkobrombin/dabadee/pkg/hash
PKG
github.com/mirkobrombin/dabadee/pkg/processor
PKG
github.com/mirkobrombin/dabadee/pkg/storage
INT
github.com/vanilla-os/sdk/pkg/v1/fs
S
struct
repoLock
pkg/v1/backup/lock_linux.go:19-21
type repoLock struct
Methods
Fields
| Name | Type | Description |
|---|---|---|
| f | *os.File |
S
struct
repoLock
pkg/v1/backup/lock_other.go:13-13
type repoLock struct
S
struct
Repository
pkg/v1/backup/repo.go:28-32
type Repository struct
Methods
lockExclusive
Method
Returns
error
func (*Repository) lockExclusive() (*repoLock, error)
{
return r.lock(syscall.LOCK_EX)
}
lock
Method
Parameters
flag
int
Returns
error
func (*Repository) lock(flag int) (*repoLock, error)
{
lockPath := filepath.Join(r.Root, ".repo.lock")
f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0o600)
if err != nil {
return nil, err
}
if err := syscall.Flock(int(f.Fd()), flag); err != nil {
_ = f.Close()
return nil, err
}
return &repoLock{f: f}, nil
}
lockExclusive
Method
Returns
error
func (*Repository) lockExclusive() (*repoLock, error)
{ return &repoLock{}, nil }
CreateSnapshot
Method
CreateSnapshot copies sourcePath into a new snapshot directory.
Parameters
sourcePath
string
Returns
error
func (*Repository) CreateSnapshot(sourcePath string, opts CreateSnapshotOptions) (*Snapshot, error)
{
l, err := r.lockExclusive()
if err != nil {
return nil, err
}
defer func() { _ = l.Close() }()
id := opts.ID
if id == "" {
id = newSnapshotID()
}
finalPath := filepath.Join(r.SnapshotsDir, id)
tmpBase := filepath.Join(r.SnapshotsDir, ".tmp")
tmpPath := filepath.Join(tmpBase, id)
treePath := filepath.Join(tmpPath, "tree")
if err := os.MkdirAll(tmpBase, 0o755); err != nil {
return nil, err
}
_ = os.RemoveAll(tmpPath)
if err := os.MkdirAll(treePath, 0o755); err != nil {
return nil, err
}
copyOpts := opts.CopyOptions
if copyOpts.Workers == 0 {
copyOpts = DefaultCopyOptions()
}
if err := fs.CopyTree(sourcePath, treePath, copyOpts); err != nil {
_ = os.RemoveAll(tmpPath)
return nil, err
}
if opts.Deduplicate {
workers := opts.DedupWorkers
if workers <= 0 {
workers = 2
}
s, err := storage.NewStorage(storage.StorageOptions{Root: r.ObjectsDir, WithMetadata: opts.DedupWithMetadata})
if err != nil {
_ = os.RemoveAll(tmpPath)
return nil, err
}
h := hash.NewSHA256Generator()
p := processor.NewDedupProcessor(treePath, "", s, h, workers)
d := dabadee.NewDaBaDee(p, false)
if err := d.Run(); err != nil {
_ = os.RemoveAll(tmpPath)
return nil, err
}
}
m := SnapshotManifest{
ID: id,
CreatedAt: time.Now().UTC(),
SourcePath: sourcePath,
Deduplicate: opts.Deduplicate,
}
if err := writeManifest(filepath.Join(tmpPath, "manifest.json"), m); err != nil {
_ = os.RemoveAll(tmpPath)
return nil, err
}
if _, err := os.Stat(finalPath); err == nil {
_ = os.RemoveAll(tmpPath)
return nil, fmt.Errorf("snapshot already exists: %s", id)
}
if err := os.Rename(tmpPath, finalPath); err != nil {
_ = os.RemoveAll(tmpPath)
return nil, err
}
return &Snapshot{Manifest: m, Path: finalPath, TreePath: filepath.Join(finalPath, "tree")}, nil
}
Example
snap, err := repo.CreateSnapshot("/home/user", backup.CreateSnapshotOptions{Deduplicate: true})
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Snapshot: %s\n", snap.Manifest.ID)
RestoreSnapshot
Method
RestoreSnapshot restores snapshotID into destination.
Parameters
Returns
error
func (*Repository) RestoreSnapshot(snapshotID, destination string, copyOpts fs.CopyTreeOptions) error
{
l, err := r.lockShared()
if err != nil {
return err
}
defer func() { _ = l.Close() }()
tree := filepath.Join(r.SnapshotsDir, snapshotID, "tree")
if _, err := os.Stat(tree); err != nil {
return err
}
if copyOpts.Workers == 0 {
copyOpts = DefaultCopyOptions()
}
return fs.CopyTree(tree, destination, copyOpts)
}
Example
err := repo.RestoreSnapshot("20260218T120000Z-acde1234", "/restore", backup.DefaultCopyOptions())
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
ListSnapshots
Method
ListSnapshots lists known snapshot manifests.
Returns
error
func (*Repository) ListSnapshots() ([]SnapshotManifest, error)
{
l, err := r.lockShared()
if err != nil {
return nil, err
}
defer func() { _ = l.Close() }()
entries, err := os.ReadDir(r.SnapshotsDir)
if err != nil {
return nil, err
}
snaps := make([]SnapshotManifest, 0)
for _, e := range entries {
if !e.IsDir() {
continue
}
m, err := readManifest(filepath.Join(r.SnapshotsDir, e.Name(), "manifest.json"))
if err != nil {
continue
}
snaps = append(snaps, m)
}
sort.Slice(snaps, func(i, j int) bool { return snaps[i].CreatedAt.After(snaps[j].CreatedAt) })
return snaps, nil
}
Example
snaps, err := repo.ListSnapshots()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
for _, s := range snaps {
fmt.Printf("%s %s\n", s.ID, s.CreatedAt)
}
listSnapshotsUnlocked
Method
Returns
error
func (*Repository) listSnapshotsUnlocked() ([]SnapshotManifest, error)
{
entries, err := os.ReadDir(r.SnapshotsDir)
if err != nil {
return nil, err
}
snaps := make([]SnapshotManifest, 0)
for _, e := range entries {
if !e.IsDir() {
continue
}
m, err := readManifest(filepath.Join(r.SnapshotsDir, e.Name(), "manifest.json"))
if err != nil {
continue
}
snaps = append(snaps, m)
}
sort.Slice(snaps, func(i, j int) bool { return snaps[i].CreatedAt.After(snaps[j].CreatedAt) })
return snaps, nil
}
PruneKeepLast
Method
PruneKeepLast removes snapshots keeping only the most recent keepLast.
Parameters
keepLast
int
Returns
[]string
error
func (*Repository) PruneKeepLast(keepLast int) ([]string, error)
{
l, err := r.lockExclusive()
if err != nil {
return nil, err
}
defer func() { _ = l.Close() }()
if keepLast < 0 {
return nil, fmt.Errorf("keepLast must be >= 0")
}
snaps, err := r.listSnapshotsUnlocked()
if err != nil {
return nil, err
}
if len(snaps) <= keepLast {
return nil, nil
}
removed := make([]string, 0)
for _, s := range snaps[keepLast:] {
_ = os.RemoveAll(filepath.Join(r.SnapshotsDir, s.ID))
removed = append(removed, s.ID)
}
// Best-effort object cleanup if DaBaDee storage exists.
if _, err := os.Stat(filepath.Join(r.ObjectsDir, ".dabadee")); err == nil {
if st, err := storage.NewStorage(storage.StorageOptions{Root: r.ObjectsDir}); err == nil {
_ = st.RemoveOrphans()
}
}
return removed, nil
}
Example
removed, err := repo.PruneKeepLast(7)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Removed: %v\n", removed)
Fields
| Name | Type | Description |
|---|---|---|
| Root | string | |
| SnapshotsDir | string | |
| ObjectsDir | string |
S
struct
CreateSnapshotOptions
pkg/v1/backup/repo.go:34-40
type CreateSnapshotOptions struct
Fields
| Name | Type | Description |
|---|---|---|
| ID | string | |
| Deduplicate | bool | |
| DedupWorkers | int | |
| DedupWithMetadata | bool | |
| CopyOptions | fs.CopyTreeOptions |
S
struct
Snapshot
pkg/v1/backup/repo.go:42-46
type Snapshot struct
Fields
| Name | Type | Description |
|---|---|---|
| Manifest | SnapshotManifest | |
| Path | string | |
| TreePath | string |
F
function
OpenRepository
OpenRepository opens (or initializes) a snapshot repository under root.
Parameters
root
string
Returns
error
pkg/v1/backup/repo.go:58-73
func OpenRepository(root string) (*Repository, error)
{
snapshots := filepath.Join(root, "snapshots")
objects := filepath.Join(root, "objects")
if err := os.MkdirAll(snapshots, 0o755); err != nil {
return nil, err
}
if err := os.MkdirAll(filepath.Join(snapshots, ".tmp"), 0o755); err != nil {
return nil, err
}
if err := os.MkdirAll(objects, 0o755); err != nil {
return nil, err
}
return &Repository{Root: root, SnapshotsDir: snapshots, ObjectsDir: objects}, nil
}
Example
repo, err := backup.OpenRepository("/var/lib/myrepo")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
_ = repo
S
struct
SnapshotManifest
pkg/v1/backup/repo.go:296-301
type SnapshotManifest struct
Fields
| Name | Type | Description |
|---|---|---|
| ID | string | json:"id" |
| CreatedAt | time.Time | json:"created_at" |
| SourcePath | string | json:"source_path" |
| Deduplicate | bool | json:"deduplicate" |
F
function
writeManifest
Parameters
path
string
Returns
error
pkg/v1/backup/repo.go:303-309
func writeManifest(path string, m SnapshotManifest) error
{
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return err
}
return os.WriteFile(path, b, 0o644)
}
F
function
readManifest
Parameters
path
string
Returns
error
pkg/v1/backup/repo.go:311-321
func readManifest(path string) (SnapshotManifest, error)
{
b, err := os.ReadFile(path)
if err != nil {
return SnapshotManifest{}, err
}
var m SnapshotManifest
if err := json.Unmarshal(b, &m); err != nil {
return SnapshotManifest{}, err
}
return m, nil
}
F
function
newSnapshotID
Returns
string
pkg/v1/backup/repo.go:323-328
func newSnapshotID() string
{
stamp := time.Now().UTC().Format("20060102T150405Z")
suffix := make([]byte, 4)
_, _ = rand.Read(suffix)
return fmt.Sprintf("%s-%s", stamp, hex.EncodeToString(suffix))
}
F
function
DefaultCopyOptions
DefaultCopyOptions returns sane defaults for snapshot copy/restore.
Returns
pkg/v1/backup/repo.go:336-338
func DefaultCopyOptions() fs.CopyTreeOptions
{
return fs.CopyTreeOptions{Workers: 2}
}
Example
opts := backup.DefaultCopyOptions()
_ = opts