diff options
| -rw-r--r-- | pkg/osutil/tar.go | 67 | ||||
| -rw-r--r-- | pkg/osutil/tar_test.go | 60 |
2 files changed, 127 insertions, 0 deletions
diff --git a/pkg/osutil/tar.go b/pkg/osutil/tar.go new file mode 100644 index 000000000..32500e7e4 --- /dev/null +++ b/pkg/osutil/tar.go @@ -0,0 +1,67 @@ +// Copyright 2025 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package osutil + +import ( + "archive/tar" + "compress/gzip" + "io" + "io/fs" + "os" + "path/filepath" + "strings" +) + +func TarGzDirectory(dir string, writer io.Writer) error { + gzw := gzip.NewWriter(writer) + defer gzw.Close() + return tarDirectory(dir, gzw) +} + +func tarDirectory(dir string, writer io.Writer) error { + tw := tar.NewWriter(writer) + defer tw.Close() + + return filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if err != nil || path == dir { + return err + } + typ := d.Type() + if !typ.IsDir() && !typ.IsRegular() { + // Only folders and regular files. + return nil + } + relPath, err := filepath.Rel(dir, path) + if err != nil { + return err + } + relPath = filepath.ToSlash(relPath) + info, err := d.Info() + if err != nil { + return err + } + header, err := tar.FileInfoHeader(info, "") + if err != nil { + return err + } + header.Name = relPath + if typ.IsDir() && !strings.HasSuffix(header.Name, "/") { + header.Name += "/" + } + if err := tw.WriteHeader(header); err != nil { + return err + } + if typ.IsDir() { + return nil + } + // Write the file content. + f, err := os.Open(path) + if err != nil { + return err + } + _, err = io.Copy(tw, f) + f.Close() + return err + }) +} diff --git a/pkg/osutil/tar_test.go b/pkg/osutil/tar_test.go new file mode 100644 index 000000000..a0e5a22bd --- /dev/null +++ b/pkg/osutil/tar_test.go @@ -0,0 +1,60 @@ +// Copyright 2025 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package osutil + +import ( + "archive/tar" + "bytes" + "io" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTarDirectory(t *testing.T) { + dir := t.TempDir() + + items := map[string]string{ + "file1.txt": "first file content", + "dir/file2.txt": "second file content", + "empty.txt": "", + } + + for path, content := range items { + fullPath := filepath.Join(dir, path) + dirPath := filepath.Dir(fullPath) + if err := MkdirAll(dirPath); err != nil { + t.Fatalf("mkdir %q failed: %v", dirPath, err) + } + if err := WriteFile(fullPath, []byte(content)); err != nil { + t.Fatalf("write file failed: %v", err) + } + } + + var buf bytes.Buffer + err := tarDirectory(dir, &buf) + assert.NoError(t, err) + + tr := tar.NewReader(&buf) + found := make(map[string]string) + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + t.Fatal(err) + } + if hdr.Typeflag == tar.TypeReg { + contentBytes, err := io.ReadAll(tr) + if err != nil { + t.Fatal(err) + } + found[hdr.Name] = string(contentBytes) + } + } + + assert.Equal(t, items, found) +} |
