github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/blob/blob.go (about) 1 package blob 2 3 import ( 4 "bytes" 5 "compress/gzip" 6 "io" 7 "os" 8 9 "github.com/docker/docker/pkg/ioutils" 10 "github.com/pkg/errors" 11 12 "github.com/buildpacks/pack/pkg/archive" 13 ) 14 15 type Blob interface { 16 Open() (io.ReadCloser, error) 17 } 18 19 type blob struct { 20 path string 21 } 22 23 func NewBlob(path string) Blob { 24 return &blob{path: path} 25 } 26 27 // Open returns an io.ReadCloser whose contents are in tar archive format 28 func (b blob) Open() (r io.ReadCloser, err error) { 29 fi, err := os.Stat(b.path) 30 if err != nil { 31 return nil, errors.Wrapf(err, "read blob at path '%s'", b.path) 32 } 33 if fi.IsDir() { 34 return archive.ReadDirAsTar(b.path, ".", 0, 0, -1, true, false, nil), nil 35 } 36 37 fh, err := os.Open(b.path) 38 if err != nil { 39 return nil, errors.Wrap(err, "open buildpack archive") 40 } 41 defer func() { 42 if err != nil { 43 fh.Close() 44 } 45 }() 46 47 if ok, err := isGZip(fh); err != nil { 48 return nil, errors.Wrap(err, "check header") 49 } else if !ok { 50 return fh, nil 51 } 52 gzr, err := gzip.NewReader(fh) 53 if err != nil { 54 return nil, errors.Wrap(err, "create gzip reader") 55 } 56 57 rc := ioutils.NewReadCloserWrapper(gzr, func() error { 58 defer fh.Close() 59 return gzr.Close() 60 }) 61 return rc, nil 62 } 63 64 func isGZip(file io.ReadSeeker) (bool, error) { 65 b := make([]byte, 3) 66 if _, err := file.Seek(0, 0); err != nil { 67 return false, err 68 } 69 _, err := file.Read(b) 70 if err != nil && err != io.EOF { 71 return false, err 72 } else if err == io.EOF { 73 return false, nil 74 } 75 if _, err := file.Seek(0, 0); err != nil { 76 return false, err 77 } 78 return bytes.Equal(b, []byte("\x1f\x8b\x08")), nil 79 }