Merge pull request #18123 from aidanhs/aphs-fail-on-broken-tar

Ensure adding a broken tar doesn't silently fail
This commit is contained in:
Tibor Vass 2015-12-07 14:38:21 +01:00
commit cf5299f8bc
2 changed files with 64 additions and 5 deletions

View file

@ -77,6 +77,11 @@ var (
defaultArchiver = &Archiver{Untar: Untar, UIDMaps: nil, GIDMaps: nil} defaultArchiver = &Archiver{Untar: Untar, UIDMaps: nil, GIDMaps: nil}
) )
const (
// HeaderSize is the size in bytes of a tar header
HeaderSize = 512
)
const ( const (
// Uncompressed represents the uncompressed. // Uncompressed represents the uncompressed.
Uncompressed Compression = iota Uncompressed Compression = iota
@ -88,7 +93,8 @@ const (
Xz Xz
) )
// IsArchive checks if it is a archive by the header. // IsArchive checks for the magic bytes of a tar or any supported compression
// algorithm.
func IsArchive(header []byte) bool { func IsArchive(header []byte) bool {
compression := DetectCompression(header) compression := DetectCompression(header)
if compression != Uncompressed { if compression != Uncompressed {
@ -99,6 +105,23 @@ func IsArchive(header []byte) bool {
return err == nil return err == nil
} }
// IsArchivePath checks if the (possibly compressed) file at the given path
// starts with a tar file header.
func IsArchivePath(path string) bool {
file, err := os.Open(path)
if err != nil {
return false
}
defer file.Close()
rdr, err := DecompressStream(file)
if err != nil {
return false
}
r := tar.NewReader(rdr)
_, err = r.Next()
return err == nil
}
// DetectCompression detects the compression algorithm of the source. // DetectCompression detects the compression algorithm of the source.
func DetectCompression(source []byte) Compression { func DetectCompression(source []byte) Compression {
for compression, m := range map[Compression][]byte{ for compression, m := range map[Compression][]byte{
@ -806,10 +829,7 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
GIDMaps: archiver.GIDMaps, GIDMaps: archiver.GIDMaps,
} }
} }
if err := archiver.Untar(archive, dst, options); err != nil { return archiver.Untar(archive, dst, options)
return err
}
return nil
} }
// UntarPath is a convenience function which looks for an archive // UntarPath is a convenience function which looks for an archive

View file

@ -49,6 +49,45 @@ func TestIsArchive7zip(t *testing.T) {
} }
} }
func TestIsArchivePathDir(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "mkdir -p /tmp/archivedir")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("Fail to create an archive file for test : %s.", output)
}
if IsArchivePath("/tmp/archivedir") {
t.Fatalf("Incorrectly recognised directory as an archive")
}
}
func TestIsArchivePathInvalidFile(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "dd if=/dev/zero bs=1K count=1 of=/tmp/archive && gzip --stdout /tmp/archive > /tmp/archive.gz")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("Fail to create an archive file for test : %s.", output)
}
if IsArchivePath("/tmp/archive") {
t.Fatalf("Incorrectly recognised invalid tar path as archive")
}
if IsArchivePath("/tmp/archive.gz") {
t.Fatalf("Incorrectly recognised invalid compressed tar path as archive")
}
}
func TestIsArchivePathTar(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "touch /tmp/archivedata && tar -cf /tmp/archive /tmp/archivedata && gzip --stdout /tmp/archive > /tmp/archive.gz")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("Fail to create an archive file for test : %s.", output)
}
if !IsArchivePath("/tmp/archive") {
t.Fatalf("Did not recognise valid tar path as archive")
}
if !IsArchivePath("/tmp/archive.gz") {
t.Fatalf("Did not recognise valid compressed tar path as archive")
}
}
func TestDecompressStreamGzip(t *testing.T) { func TestDecompressStreamGzip(t *testing.T) {
cmd := exec.Command("/bin/sh", "-c", "touch /tmp/archive && gzip -f /tmp/archive") cmd := exec.Command("/bin/sh", "-c", "touch /tmp/archive && gzip -f /tmp/archive")
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()