github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/osutil/tar.go (about)

     1  // Copyright 2025 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package osutil
     5  
     6  import (
     7  	"archive/tar"
     8  	"compress/gzip"
     9  	"io"
    10  	"io/fs"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  )
    15  
    16  func TarGzDirectory(dir string, writer io.Writer) error {
    17  	gzw := gzip.NewWriter(writer)
    18  	defer gzw.Close()
    19  	return tarDirectory(dir, gzw)
    20  }
    21  
    22  func tarDirectory(dir string, writer io.Writer) error {
    23  	tw := tar.NewWriter(writer)
    24  	defer tw.Close()
    25  
    26  	return filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
    27  		if err != nil || path == dir {
    28  			return err
    29  		}
    30  		typ := d.Type()
    31  		if !typ.IsDir() && !typ.IsRegular() {
    32  			// Only folders and regular files.
    33  			return nil
    34  		}
    35  		relPath, err := filepath.Rel(dir, path)
    36  		if err != nil {
    37  			return err
    38  		}
    39  		relPath = filepath.ToSlash(relPath)
    40  		info, err := d.Info()
    41  		if err != nil {
    42  			return err
    43  		}
    44  		header, err := tar.FileInfoHeader(info, "")
    45  		if err != nil {
    46  			return err
    47  		}
    48  		header.Name = relPath
    49  		if typ.IsDir() && !strings.HasSuffix(header.Name, "/") {
    50  			header.Name += "/"
    51  		}
    52  		if err := tw.WriteHeader(header); err != nil {
    53  			return err
    54  		}
    55  		if typ.IsDir() {
    56  			return nil
    57  		}
    58  		// Write the file content.
    59  		f, err := os.Open(path)
    60  		if err != nil {
    61  			return err
    62  		}
    63  		_, err = io.Copy(tw, f)
    64  		f.Close()
    65  		return err
    66  	})
    67  }