diff options
Diffstat (limited to 'archive.go')
-rw-r--r-- | archive.go | 235 |
1 files changed, 0 insertions, 235 deletions
diff --git a/archive.go b/archive.go deleted file mode 100644 index 76c16b8..0000000 --- a/archive.go +++ /dev/null @@ -1,235 +0,0 @@ -package pkgtools - -import ( - "archive/tar" - "fmt" - "io" - "os" - "path" - "path/filepath" - - "github.com/pkg/errors" - "golang.org/x/sys/unix" -) - -type TarReader interface { - Next() (*tar.Header, error) - Read([]byte) (int, error) -} - -const NewDirMod = 0755 - -func tarCreateBlockDev(target string, header *tar.Header) error { - mode := uint32(header.Mode & 07777) - mode |= unix.S_IFBLK - dev := unix.Mkdev(uint32(header.Devmajor), uint32(header.Devminor)) - err := unix.Mknod(target, mode, int(dev)) - return err -} - -func tarCreateCharDev(target string, header *tar.Header) error { - mode := uint32(header.Mode & 07777) - mode |= unix.S_IFCHR - dev := unix.Mkdev(uint32(header.Devmajor), uint32(header.Devminor)) - err := unix.Mknod(target, mode, int(dev)) - return err -} - -func tarCreateDir(target string) error { - err := os.MkdirAll(target, NewDirMod) - return err -} - -func tarCreateFifo(target string, header *tar.Header) error { - mode := uint32(header.Mode & 07777) - mode |= unix.S_IFIFO - dev := unix.Mkdev(uint32(header.Devmajor), uint32(header.Devminor)) - err := unix.Mknod(target, mode, int(dev)) - return err -} - -func tarCreateReg(target string, r io.Reader, header *tar.Header) error { - f, err := os.OpenFile( - target, - os.O_CREATE|os.O_RDWR, - os.FileMode(header.Mode), - ) - if err != nil { - // it could be an error due to writing over a running executable. - err = os.Remove(target) - if err != nil { - return err - } - - f, err = os.OpenFile( - target, - os.O_CREATE|os.O_RDWR, - os.FileMode(header.Mode), - ) - if err != nil { - return err - } - } - defer f.Close() - - // copy over contents - if _, err := io.Copy(f, r); err != nil { - return err - } - return nil -} - -func tarCreateLink(root string, header *tar.Header) error { - oldName := filepath.Join(root, header.Linkname) - if filepath.IsAbs(header.Linkname) { - filepath.Join(root, oldName) - } - newName := filepath.Join(root, header.Name) - err := os.Link(oldName, newName) - if err != nil { - _ = os.Remove(newName) - err = os.Link(oldName, newName) - } - return err -} - -func tarCreateSymlink(root string, header *tar.Header) error { - oldName := filepath.Join(root, header.Linkname) - if filepath.IsAbs(header.Linkname) { - filepath.Join(root, oldName) - } - newName := filepath.Join(root, header.Name) - err := os.Symlink(oldName, newName) - if err != nil { - _ = os.Remove(newName) - err = os.Symlink(oldName, newName) - } - return err -} - -type TarFilter interface { - FilterTar(header *tar.Header, r io.Reader) error -} - -type TarFilterFunc func( - header *tar.Header, - r io.Reader, -) error - -func (f TarFilterFunc) FilterTar(h *tar.Header, r io.Reader) error { - return f(h, r) -} - -type TarCfg struct { - Root string - Chown bool - Chmod bool - // Strict bails out when anything unexpected is encountered. - Strict bool -} - -type TarExtracter struct { - cfg *TarCfg -} - -func NewTarExtractor(cfg *TarCfg) *TarExtracter { - return &TarExtracter{cfg} -} - -func (s *TarExtracter) FilterTar( - header *tar.Header, - r io.Reader, -) error { - target := path.Join(s.cfg.Root, header.Name) - - if s.cfg.Strict { - if len(header.PAXRecords) > 0 { - return errors.Errorf( - "%s: contains unsupported PAXRecords, bailing out", - header.Name, - ) - } - if len(header.Xattrs) > 0 { - return errors.Errorf( - "%s: contains unsupported extended attributes, bailing out", - header.Name, - ) - } - } - - var err error - switch header.Typeflag { - case tar.TypeBlock: - err = tarCreateBlockDev(target, header) - case tar.TypeChar: - err = tarCreateCharDev(target, header) - case tar.TypeFifo: - err = tarCreateFifo(target, header) - case tar.TypeDir: - err = tarCreateDir(target) - case tar.TypeReg: - err = tarCreateReg(target, r, header) - case tar.TypeLink: - err = tarCreateLink(s.cfg.Root, header) - case tar.TypeSymlink: - err = tarCreateSymlink(s.cfg.Root, header) - default: - err = errors.Errorf("unhandled file type '%c'", header.Typeflag) - } - if err != nil { - return errors.Wrap(err, "unpacking tar archive") - } - - if s.cfg.Chown { - if err = os.Chown(target, header.Uid, header.Gid); err != nil { - fmt.Fprintln(os.Stderr, err) - } - } - if s.cfg.Chmod { - if err = os.Chmod(target, header.FileInfo().Mode()); err != nil { - fmt.Fprintln(os.Stderr, err) - } - } - return nil -} - -func FilterTar( - r TarReader, - filters ...TarFilter, -) error { - for { - header, err := r.Next() - if err == io.EOF { - break - } else if err != nil { - return err - } - if header == nil { - continue - } - - for _, f := range filters { - // TODO: how do we dup r? - err := f.FilterTar(header, r) - if err != nil { - return err - } - } - } - - return nil -} - -func ExtractTar( - cfg *TarCfg, - fp string, -) error { - f, err := os.Open(fp) - if err != nil { - return err - } - defer f.Close() - r := tar.NewReader(f) - err = FilterTar(r, NewTarExtractor(cfg)) - return errors.Wrap(err, "extracting tar file") -} |