123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- // License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
- package utils
- import (
- "archive/tar"
- "errors"
- "fmt"
- "io"
- "io/fs"
- "os"
- "path/filepath"
- "strings"
- )
- var _ = fmt.Print
- type TarExtractOptions struct {
- DontPreservePermissions bool
- }
- func ExtractAllFromTar(tr *tar.Reader, dest_path string, optss ...TarExtractOptions) (count int, err error) {
- opts := TarExtractOptions{}
- if len(optss) > 0 {
- opts = optss[0]
- }
- dest_path, err = filepath.Abs(dest_path)
- if err != nil {
- return
- }
- mode := func(hdr *tar.Header) fs.FileMode {
- return fs.FileMode(hdr.Mode) & (fs.ModePerm | fs.ModeSetgid | fs.ModeSetuid | fs.ModeSticky)
- }
- set_metadata := func(chmod func(mode fs.FileMode) error, hdr *tar.Header) (err error) {
- if !opts.DontPreservePermissions && chmod != nil {
- perms := mode(hdr)
- if err = chmod(perms); err != nil {
- return err
- }
- }
- count++
- return
- }
- for {
- var hdr *tar.Header
- hdr, err = tr.Next()
- if errors.Is(err, io.EOF) {
- break
- }
- if err != nil {
- return count, err
- }
- dest := hdr.Name
- dest = strings.TrimLeft(dest, "/")
- if !filepath.IsLocal(dest) {
- continue
- }
- dest = filepath.Join(dest_path, dest)
- switch hdr.Typeflag {
- case tar.TypeDir:
- err = os.MkdirAll(dest, 0o700)
- if err != nil {
- return
- }
- if err = set_metadata(func(m fs.FileMode) error { return os.Chmod(dest, m) }, hdr); err != nil {
- return
- }
- case tar.TypeReg, tar.TypeRegA:
- var d *os.File
- if d, err = os.Create(dest); err != nil {
- return
- }
- err = set_metadata(d.Chmod, hdr)
- if err == nil {
- _, err = io.Copy(d, tr)
- }
- d.Close()
- if err != nil {
- return
- }
- case tar.TypeLink:
- if err = os.Link(hdr.Linkname, dest); err != nil {
- return
- }
- if err = set_metadata(func(m fs.FileMode) error { return os.Chmod(dest, m) }, hdr); err != nil {
- return
- }
- case tar.TypeSymlink:
- if err = os.Symlink(hdr.Linkname, dest); err != nil {
- return
- }
- if err = set_metadata(nil, hdr); err != nil {
- return
- }
- }
- }
- return
- }
|