// Package client provides ZFS snapshot backup client functionality. // This file contains snapshot management functions for creating and sending snapshots. package client import ( "fmt" "os/exec" "strings" "github.com/mistifyio/go-zfs" ) // CreateBookmark creates a ZFS bookmark from a snapshot. // Bookmarks allow incremental sends even after the source snapshot is deleted. func (c *Client) CreateBookmark(snapshot *zfs.Dataset) error { // Extract snapshot name from full path (dataset@snapshot -> snapshot) parts := strings.Split(snapshot.Name, "@") if len(parts) != 2 { return fmt.Errorf("invalid snapshot name format: %s", snapshot.Name) } snapshotName := parts[1] bookmarkName := fmt.Sprintf("%s#%s", c.config.LocalDataset, snapshotName) // Create bookmark using zfs command cmd := exec.Command("zfs", "bookmark", snapshot.Name, bookmarkName) output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to create bookmark: %v: %s", err, string(output)) } fmt.Printf("✓ Created bookmark: %s\n", bookmarkName) return nil } // GetLastBookmark returns the most recent bookmark for the dataset. // Bookmarks are used as the base for incremental sends. func (c *Client) GetLastBookmark() (string, error) { // List all bookmarks for the dataset cmd := exec.Command("zfs", "list", "-t", "bookmark", "-o", "name", "-H", "-r", c.config.LocalDataset) output, err := cmd.Output() if err != nil { return "", nil // No bookmarks yet } bookmarks := strings.Split(strings.TrimSpace(string(output)), "\n") if len(bookmarks) == 0 || bookmarks[0] == "" { return "", nil } // Return the last bookmark (most recent) return bookmarks[len(bookmarks)-1], nil } // GetLastSnapshot returns the most recent snapshot for the dataset. func (c *Client) GetLastSnapshot() (*zfs.Dataset, error) { ds, err := zfs.GetDataset(c.config.LocalDataset) if err != nil { return nil, fmt.Errorf("failed to get dataset: %v", err) } snapshots, err := ds.Snapshots() if err != nil { return nil, fmt.Errorf("failed to list snapshots: %v", err) } if len(snapshots) == 0 { return nil, nil } // Return the last snapshot (most recent) return snapshots[len(snapshots)-1], nil } // SendIncremental is kept for API compatibility - now just calls HTTP version func (c *Client) SendIncremental(snapshot *zfs.Dataset, base string) error { return c.SendIncrementalHTTP(snapshot, base) }