Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions fileutil/compressor_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type Compressor interface {

DecompressFileToDir(path string, dir string, options CompressorOptions) (err error)

IsNonCompressedTarball(path string) bool

// CleanUp cleans up compressed file after it was used
CleanUp(path string) error
}
8 changes: 8 additions & 0 deletions fileutil/fakes/fake_compressor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type FakeCompressor struct {
DecompressFileToDirErr error
DecompressFileToDirCallBack func()

IsNonCompressedTarballPath string
IsNonCompressedTarballReturns bool

CleanUpTarballPath string
CleanUpErr error
}
Expand Down Expand Up @@ -65,6 +68,11 @@ func (fc *FakeCompressor) DecompressFileToDir(tarballPath string, dir string, op
return fc.DecompressFileToDirErr
}

func (fc *FakeCompressor) IsNonCompressedTarball(path string) bool {
fc.IsNonCompressedTarballPath = path
return fc.IsNonCompressedTarballReturns
}

func (fc *FakeCompressor) CleanUp(tarballPath string) error {
fc.CleanUpTarballPath = tarballPath
return fc.CleanUpErr
Expand Down
44 changes: 44 additions & 0 deletions fileutil/tarball_compressor.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package fileutil

import (
"bytes"
"fmt"
"os"
"runtime"

bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshsys "github.com/cloudfoundry/bosh-utils/system"
)

var (
gzipMagic = []byte{0x1f, 0x8b}
bzip2Magic = []byte{0x42, 0x5a, 0x68} // "BZh"
xzMagic = []byte{0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00}
zstdMagic = []byte{0x28, 0xb5, 0x2f, 0xfd}
ustarMagic = []byte("ustar")
ustarOffset = 257 // Offset of the TAR magic string in the file
)

type tarballCompressor struct {
cmdRunner boshsys.CmdRunner
fs boshsys.FileSystem
Expand Down Expand Up @@ -80,6 +91,39 @@ func (c tarballCompressor) DecompressFileToDir(tarballPath string, dir string, o
return nil
}

func (c tarballCompressor) IsNonCompressedTarball(path string) bool {
f, err := c.fs.OpenFile(path, os.O_RDONLY, 0644)
if err != nil {
// If we cannot open the file, we assume it is not compressed
return false
}
defer f.Close() //nolint:errcheck

// Read the first 512 bytes to check both compression headers and the TAR header.
// Ignore the error from reading a partial buffer, which is fine for short files.
buffer := make([]byte, 512)
_, _ = f.Read(buffer) //nolint:errcheck

// 1. Check for compression first.
if bytes.HasPrefix(buffer, gzipMagic) ||
bytes.HasPrefix(buffer, bzip2Magic) ||
bytes.HasPrefix(buffer, xzMagic) ||
bytes.HasPrefix(buffer, zstdMagic) {
return false
}

// 2. If NOT compressed, check for the TAR magic string at its specific offset.
// Ensure the buffer is long enough to contain the TAR header magic string.
if len(buffer) > ustarOffset+len(ustarMagic) {
magicBytes := buffer[ustarOffset : ustarOffset+len(ustarMagic)]
if bytes.Equal(magicBytes, ustarMagic) {
return true
}
}

return false
}

func (c tarballCompressor) CleanUp(tarballPath string) error {
return c.fs.RemoveAll(tarballPath)
}
20 changes: 20 additions & 0 deletions fileutil/tarball_compressor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,26 @@ var _ = Describe("tarballCompressor", func() {
})
})

Describe("IsNonCompressedTarball", func() {
It("returns false for compressed tarball", func() {
tgzName, err := compressor.CompressFilesInDir(testAssetsFixtureDir, CompressorOptions{NoCompression: false})
Expect(err).ToNot(HaveOccurred())
defer os.Remove(tgzName)

result := compressor.IsNonCompressedTarball(tgzName)
Expect(result).To(BeFalse())
})

It("returns true for uncompressed tarball", func() {
tgzName, err := compressor.CompressFilesInDir(testAssetsFixtureDir, CompressorOptions{NoCompression: true})
Expect(err).ToNot(HaveOccurred())
defer os.Remove(tgzName)

result := compressor.IsNonCompressedTarball(tgzName)
Expect(result).To(BeTrue())
})
})

Describe("CleanUp", func() {
It("removes tarball path", func() {
fs := fakesys.NewFakeFileSystem()
Expand Down
Loading