From 12fc11efd07e57bfd00aef211ab4ae8f2da829e3 Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Fri, 20 Nov 2015 16:49:33 +0000 Subject: [PATCH] Ensure adding a broken tar doesn't silently fail Signed-off-by: Aidan Hobson Sayers --- archive/archive.go | 30 +++++++++++++++++++++++++----- archive/archive_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/archive/archive.go b/archive/archive.go index 1c8e115..2394e40 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -77,6 +77,11 @@ var ( defaultArchiver = &Archiver{Untar: Untar, UIDMaps: nil, GIDMaps: nil} ) +const ( + // HeaderSize is the size in bytes of a tar header + HeaderSize = 512 +) + const ( // Uncompressed represents the uncompressed. Uncompressed Compression = iota @@ -88,7 +93,8 @@ const ( 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 { compression := DetectCompression(header) if compression != Uncompressed { @@ -99,6 +105,23 @@ func IsArchive(header []byte) bool { 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. func DetectCompression(source []byte) Compression { for compression, m := range map[Compression][]byte{ @@ -800,10 +823,7 @@ func (archiver *Archiver) UntarPath(src, dst string) error { GIDMaps: archiver.GIDMaps, } } - if err := archiver.Untar(archive, dst, options); err != nil { - return err - } - return nil + return archiver.Untar(archive, dst, options) } // UntarPath is a convenience function which looks for an archive diff --git a/archive/archive_test.go b/archive/archive_test.go index 6c54c02..882e1cc 100644 --- a/archive/archive_test.go +++ b/archive/archive_test.go @@ -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) { cmd := exec.Command("/bin/sh", "-c", "touch /tmp/archive && gzip -f /tmp/archive") output, err := cmd.CombinedOutput()