Example #1
0
// 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
}