aboutsummaryrefslogtreecommitdiffsponsor
path: root/archive.go
diff options
context:
space:
mode:
Diffstat (limited to 'archive.go')
-rw-r--r--archive.go124
1 files changed, 88 insertions, 36 deletions
diff --git a/archive.go b/archive.go
index fa1886f..6610936 100644
--- a/archive.go
+++ b/archive.go
@@ -12,7 +12,7 @@ import (
"golang.org/x/sys/unix"
)
-type ArchiveReader interface {
+type TarReader interface {
Next() (*tar.Header, error)
Read([]byte) (int, error)
}
@@ -107,15 +107,78 @@ func tarCreateSymlink(root string, header *tar.Header) error {
return err
}
-type InstallArchiveCfg struct {
+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
}
-func InstallArchive(
- r ArchiveReader,
- cfg *InstallArchiveCfg,
+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)
+
+ 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()
@@ -127,40 +190,29 @@ func InstallArchive(
if header == nil {
continue
}
- target := path.Join(cfg.Root, header.Name)
-
- 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(cfg.Root, header)
- case tar.TypeSymlink:
- err = tarCreateSymlink(cfg.Root, header)
- default:
- err = errors.Errorf("unhandled file type '%c'", header.Typeflag)
- }
- if err != nil {
- return errors.Wrap(err, "unpacking tar archive")
- }
- if cfg.Chown {
- if err = os.Chown(target, header.Uid, header.Gid); err != nil {
- fmt.Fprintln(os.Stderr, err)
- }
- }
- if cfg.Chmod {
- if err = os.Chmod(target, header.FileInfo().Mode()); err != nil {
- fmt.Fprintln(os.Stderr, err)
+
+ 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")
+}