// 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 }) }