// Restores entries and keep going on in case of error. Returns the first seen // error. // Do not overwrite files. A file already present is considered an error. func restoreEntry(l *log.Logger, cas dumbcaslib.CasTable, entry *dumbcaslib.Entry, root string) (count int, out error) { if entry.Sha1 != "" { f, err := cas.Open(entry.Sha1) if err != nil { out = fmt.Errorf("Failed to fetch %s for %s: %s", entry.Sha1, root, err) } else { defer func() { _ = f.Close() }() baseDir := filepath.Dir(root) if err = os.MkdirAll(baseDir, 0755); err != nil && !os.IsExist(err) { out = fmt.Errorf("Failed to create %s: %s", baseDir, err) } else { dst, err := os.OpenFile(root, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) if err != nil { out = fmt.Errorf("Failed to create %s in %s: %s", root, baseDir, err) } else { size, err := io.Copy(dst, f) if err != nil { out = fmt.Errorf("Failed to copy %s: %s", root, err) } else if size != entry.Size { out = fmt.Errorf("Failed to write %s, expected %d, wrote %d", root, entry.Size, size) } else { count++ } } } } if out != nil { l.Printf("%s(%d): %s", root, entry.Size, out) } else { l.Printf("%s(%d)", root, entry.Size) } } for name, child := range entry.Files { c, err := restoreEntry(l, cas, child, filepath.Join(root, name)) if err != nil && out == nil { out = err } count += c } return }