func (c CmdFind) findInSnapshot(repo *repository.Repository, id backend.ID) error { debug.Log("restic.find", "searching in snapshot %s\n for entries within [%s %s]", id.Str(), c.oldest, c.newest) sn, err := restic.LoadSnapshot(repo, id) if err != nil { return err } results, err := c.findInTree(repo, *sn.Tree, "") if err != nil { return err } if len(results) == 0 { return nil } fmt.Printf("found %d matching entries in snapshot %s\n", len(results), id) for _, res := range results { res.node.Name = filepath.Join(res.path, res.node.Name) fmt.Printf(" %s\n", res.node) } return nil }
func (cmd CmdSnapshots) Execute(args []string) error { if len(args) != 0 { return fmt.Errorf("wrong number of arguments, usage: %s", cmd.Usage()) } s, err := cmd.global.OpenRepository() if err != nil { return err } tab := NewTable() tab.Header = fmt.Sprintf("%-8s %-19s %-10s %s", "ID", "Date", "Source", "Directory") tab.RowFormat = "%-8s %-19s %-10s %s" done := make(chan struct{}) defer close(done) list := []*restic.Snapshot{} for id := range s.List(backend.Snapshot, done) { sn, err := restic.LoadSnapshot(s, id) if err != nil { fmt.Fprintf(os.Stderr, "error loading snapshot %s: %v\n", id, err) continue } pos := sort.Search(len(list), func(i int) bool { return list[i].Time.After(sn.Time) }) if pos < len(list) { list = append(list, nil) copy(list[pos+1:], list[pos:]) list[pos] = sn } else { list = append(list, sn) } } plen, err := s.PrefixLength(backend.Snapshot) if err != nil { return err } for _, sn := range list { if len(sn.Paths) == 0 { continue } tab.Rows = append(tab.Rows, []interface{}{sn.ID()[:plen/2], sn.Time.Format(TimeFormat), sn.Hostname, sn.Paths[0]}) if len(sn.Paths) > 1 { for _, path := range sn.Paths { tab.Rows = append(tab.Rows, []interface{}{"", "", "", path}) } } } tab.Write(os.Stdout) return nil }
func (cmd CmdLs) Execute(args []string) error { if len(args) < 1 || len(args) > 2 { return fmt.Errorf("wrong number of arguments, Usage: %s", cmd.Usage()) } repo, err := cmd.global.OpenRepository() if err != nil { return err } err = repo.LoadIndex() if err != nil { return err } id, err := restic.FindSnapshot(repo, args[0]) if err != nil { return err } sn, err := restic.LoadSnapshot(repo, id) if err != nil { return err } cmd.global.Verbosef("snapshot of %v at %s:\n", sn.Paths, sn.Time) return cmd.printTree("", repo, sn.Tree) }
func findLatestSnapshot(repo *repository.Repository, targets []string) (backend.ID, error) { var ( latest time.Time latestID backend.ID found bool ) for snapshotID := range repo.List(backend.Snapshot, make(chan struct{})) { snapshot, err := restic.LoadSnapshot(repo, snapshotID) if err != nil { return backend.ID{}, fmt.Errorf("Error listing snapshot: %v", err) } if snapshot.Time.After(latest) && samePaths(snapshot.Paths, targets) { latest = snapshot.Time latestID = snapshotID found = true } } if !found { return backend.ID{}, errNoSnapshotFound } return latestID, nil }
func (sn *SnapshotsDir) updateCache(ctx context.Context) error { sn.Lock() defer sn.Unlock() for id := range sn.repo.List(backend.Snapshot, ctx.Done()) { snapshot, err := restic.LoadSnapshot(sn.repo, id) if err != nil { return err } sn.knownSnapshots[snapshot.Time.Format(time.RFC3339)] = SnapshotWithId{snapshot, id} } return nil }
func loadTreeFromSnapshot(repo *repository.Repository, id backend.ID) (backend.ID, error) { sn, err := restic.LoadSnapshot(repo, id) if err != nil { debug.Log("Checker.loadTreeFromSnapshot", "error loading snapshot %v: %v", id.Str(), err) return backend.ID{}, err } if sn.Tree == nil { debug.Log("Checker.loadTreeFromSnapshot", "snapshot %v has no tree", id.Str()) return backend.ID{}, fmt.Errorf("snapshot %v has no tree", id) } return *sn.Tree, nil }
func fsckSnapshot(global CmdFsck, repo *repository.Repository, id backend.ID) error { debug.Log("restic.fsck", "checking snapshot %v\n", id) sn, err := restic.LoadSnapshot(repo, id) if err != nil { return fmt.Errorf("loading snapshot %v failed: %v", id, err) } err = fsckTree(global, repo, sn.Tree) if err != nil { debug.Log("restic.fsck", " checking tree %v for snapshot %v\n", sn.Tree, id) fmt.Fprintf(os.Stderr, "snapshot %v:\n error for tree %v:\n %v\n", id, sn.Tree, err) } return err }
func printSnapshots(repo *repository.Repository, wr io.Writer) error { done := make(chan struct{}) defer close(done) for id := range repo.List(backend.Snapshot, done) { snapshot, err := restic.LoadSnapshot(repo, id) if err != nil { fmt.Fprintf(os.Stderr, "LoadSnapshot(%v): %v", id.Str(), err) continue } fmt.Fprintf(wr, "snapshot_id: %v\n", id) err = prettyPrintJSON(wr, snapshot) if err != nil { return err } } return nil }
func TestMount(t *testing.T) { if !RunFuseTest { t.Skip("Skipping fuse tests") } checkSnapshots := func(repo *repository.Repository, mountpoint string, snapshotIDs []backend.ID) { snapshotsDir, err := os.Open(filepath.Join(mountpoint, "snapshots")) OK(t, err) namesInSnapshots, err := snapshotsDir.Readdirnames(-1) OK(t, err) Assert(t, len(namesInSnapshots) == len(snapshotIDs), "Invalid number of snapshots: expected %d, got %d", len(snapshotIDs), len(namesInSnapshots)) namesMap := make(map[string]bool) for _, name := range namesInSnapshots { namesMap[name] = false } for _, id := range snapshotIDs { snapshot, err := restic.LoadSnapshot(repo, id) OK(t, err) _, ok := namesMap[snapshot.Time.Format(time.RFC3339)] Assert(t, ok, "Snapshot %s isn't present in fuse dir", snapshot.Time.Format(time.RFC3339)) namesMap[snapshot.Time.Format(time.RFC3339)] = true } for name, present := range namesMap { Assert(t, present, "Directory %s is present in fuse dir but is not a snapshot", name) } OK(t, snapshotsDir.Close()) } withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { cmdInit(t, global) repo, err := global.OpenRepository() OK(t, err) mountpoint, err := ioutil.TempDir(TestTempDir, "restic-test-mount-") OK(t, err) // We remove the mountpoint now to check that cmdMount creates it OK(t, os.RemoveAll(mountpoint)) ready := make(chan struct{}, 1) done := make(chan struct{}) go cmdMount(t, global, mountpoint, ready, done) <-ready defer close(done) OK(t, waitForMount(mountpoint)) mountpointDir, err := os.Open(mountpoint) OK(t, err) names, err := mountpointDir.Readdirnames(-1) OK(t, err) Assert(t, len(names) == 1 && names[0] == "snapshots", `The fuse virtual directory "snapshots" doesn't exist`) OK(t, mountpointDir.Close()) checkSnapshots(repo, mountpoint, []backend.ID{}) datafile := filepath.Join("testdata", "backup-data.tar.gz") fd, err := os.Open(datafile) if os.IsNotExist(err) { t.Skipf("unable to find data file %q, skipping", datafile) return } OK(t, err) OK(t, fd.Close()) SetupTarTestFixture(t, env.testdata, datafile) // first backup cmdBackup(t, global, []string{env.testdata}, nil) snapshotIDs := cmdList(t, global, "snapshots") Assert(t, len(snapshotIDs) == 1, "expected one snapshot, got %v", snapshotIDs) checkSnapshots(repo, mountpoint, snapshotIDs) // second backup, implicit incremental cmdBackup(t, global, []string{env.testdata}, nil) snapshotIDs = cmdList(t, global, "snapshots") Assert(t, len(snapshotIDs) == 2, "expected two snapshots, got %v", snapshotIDs) checkSnapshots(repo, mountpoint, snapshotIDs) // third backup, explicit incremental cmdBackup(t, global, []string{env.testdata}, &snapshotIDs[0]) snapshotIDs = cmdList(t, global, "snapshots") Assert(t, len(snapshotIDs) == 3, "expected three snapshots, got %v", snapshotIDs) checkSnapshots(repo, mountpoint, snapshotIDs) }) }