func newDirFromSnapshot(repo restic.Repository, snapshot SnapshotWithId, ownerIsRoot bool) (*dir, error) { debug.Log("new dir for snapshot %v (%v)", snapshot.ID.Str(), snapshot.Tree.Str()) tree, err := repo.LoadTree(*snapshot.Tree) if err != nil { debug.Log(" loadTree(%v) failed: %v", snapshot.ID.Str(), err) return nil, err } items := make(map[string]*restic.Node) for _, n := range tree.Nodes { nodes, err := replaceSpecialNodes(repo, n) if err != nil { debug.Log(" replaceSpecialNodes(%v) failed: %v", n, err) return nil, err } for _, node := range nodes { items[node.Name] = node } } return &dir{ repo: repo, node: &restic.Node{ UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), AccessTime: snapshot.Time, ModTime: snapshot.Time, ChangeTime: snapshot.Time, Mode: os.ModeDir | 0555, }, items: items, inode: inodeFromBackendID(snapshot.ID), ownerIsRoot: ownerIsRoot, }, nil }
// replaceSpecialNodes replaces nodes with name "." and "/" by their contents. // Otherwise, the node is returned. func replaceSpecialNodes(repo restic.Repository, node *restic.Node) ([]*restic.Node, error) { if node.Type != "dir" || node.Subtree == nil { return []*restic.Node{node}, nil } if node.Name != "." && node.Name != "/" { return []*restic.Node{node}, nil } tree, err := repo.LoadTree(*node.Subtree) if err != nil { return nil, err } return tree.Nodes, nil }
func checkSavedFile(t *testing.T, repo restic.Repository, treeID restic.ID, name string, rd io.Reader) { tree, err := repo.LoadTree(treeID) if err != nil { t.Fatalf("LoadTree() returned error %v", err) } if len(tree.Nodes) != 1 { t.Fatalf("wrong number of nodes for tree, want %v, got %v", 1, len(tree.Nodes)) } node := tree.Nodes[0] if node.Name != "fakefile" { t.Fatalf("wrong filename, want %v, got %v", "fakefile", node.Name) } if len(node.Content) == 0 { t.Fatalf("node.Content has length 0") } // check blobs for i, id := range node.Content { size, err := repo.LookupBlobSize(id, restic.DataBlob) if err != nil { t.Fatal(err) } buf := make([]byte, int(size)) n := loadBlob(t, repo, id, buf) if n != len(buf) { t.Errorf("wrong number of bytes read, want %d, got %d", len(buf), n) } buf2 := make([]byte, int(size)) _, err = io.ReadFull(rd, buf2) if err != nil { t.Fatal(err) } if !bytes.Equal(buf, buf2) { t.Fatalf("blob %d (%v) is wrong", i, id.Str()) } } }
func newDir(repo restic.Repository, node *restic.Node, ownerIsRoot bool) (*dir, error) { debug.Log("new dir for %v (%v)", node.Name, node.Subtree.Str()) tree, err := repo.LoadTree(*node.Subtree) if err != nil { debug.Log(" error loading tree %v: %v", node.Subtree.Str(), err) return nil, err } items := make(map[string]*restic.Node) for _, node := range tree.Nodes { items[node.Name] = node } return &dir{ repo: repo, node: node, items: items, inode: node.Inode, ownerIsRoot: ownerIsRoot, }, nil }
// loadTreeWorker loads trees from repo and sends them to out. func loadTreeWorker(repo restic.Repository, in <-chan restic.ID, out chan<- treeJob, done <-chan struct{}, wg *sync.WaitGroup) { defer func() { debug.Log("exiting") wg.Done() }() var ( inCh = in outCh = out job treeJob ) outCh = nil for { select { case <-done: return case treeID, ok := <-inCh: if !ok { return } debug.Log("load tree %v", treeID.Str()) tree, err := repo.LoadTree(treeID) debug.Log("load tree %v (%v) returned err: %v", tree, treeID.Str(), err) job = treeJob{ID: treeID, error: err, Tree: tree} outCh = out inCh = nil case outCh <- job: debug.Log("sent tree %v", job.ID.Str()) outCh = nil inCh = in } } }