func buildWalker(root string, aw aci.ArchiveWriter, rootfs bool) filepath.WalkFunc { // cache of inode -> filepath, used to leverage hard links in the archive inos := map[uint64]string{} return func(path string, info os.FileInfo, err error) error { if err != nil { return err } relpath, err := filepath.Rel(root, path) if err != nil { return err } if rootfs { if relpath == "." { relpath = "" } relpath = "rootfs/" + relpath } if relpath == "." { return nil } link := "" var file *os.File switch info.Mode() & os.ModeType { default: file, err = os.Open(path) if err != nil { return err } defer file.Close() case os.ModeSymlink: target, err := os.Readlink(path) if err != nil { return err } link = target } hdr, err := tar.FileInfoHeader(info, link) if err != nil { panic(err) } // Because os.FileInfo's Name method returns only the base // name of the file it describes, it may be necessary to // modify the Name field of the returned header to provide the // full path name of the file. hdr.Name = relpath tarheader.Populate(hdr, info, inos) // If the file is a hard link we don't need the contents if hdr.Typeflag == tar.TypeLink { hdr.Size = 0 file = nil } aw.AddFile(relpath, hdr, file) return nil } }