mirror of
https://github.com/juanfont/headscale.git
synced 2025-07-14 11:21:54 -04:00
101 lines
2.4 KiB
Go
101 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"archive/tar"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
var (
|
|
// ErrFileNotFoundInTar indicates a file was not found in the tar archive.
|
|
ErrFileNotFoundInTar = errors.New("file not found in tar")
|
|
)
|
|
|
|
// extractFileFromTar extracts a single file from a tar reader.
|
|
func extractFileFromTar(tarReader io.Reader, fileName, outputPath string) error {
|
|
tr := tar.NewReader(tarReader)
|
|
|
|
for {
|
|
header, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read tar header: %w", err)
|
|
}
|
|
|
|
// Check if this is the file we're looking for
|
|
if filepath.Base(header.Name) == fileName {
|
|
if header.Typeflag == tar.TypeReg {
|
|
// Create the output file
|
|
outFile, err := os.Create(outputPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create output file: %w", err)
|
|
}
|
|
defer outFile.Close()
|
|
|
|
// Copy file contents
|
|
if _, err := io.Copy(outFile, tr); err != nil {
|
|
return fmt.Errorf("failed to copy file contents: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("%w: %s", ErrFileNotFoundInTar, fileName)
|
|
}
|
|
|
|
// extractDirectoryFromTar extracts all files from a tar reader to a target directory.
|
|
func extractDirectoryFromTar(tarReader io.Reader, targetDir string) error {
|
|
tr := tar.NewReader(tarReader)
|
|
|
|
for {
|
|
header, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read tar header: %w", err)
|
|
}
|
|
|
|
// Clean the path to prevent directory traversal
|
|
cleanName := filepath.Clean(header.Name)
|
|
if strings.Contains(cleanName, "..") {
|
|
continue // Skip potentially dangerous paths
|
|
}
|
|
|
|
targetPath := filepath.Join(targetDir, filepath.Base(cleanName))
|
|
|
|
switch header.Typeflag {
|
|
case tar.TypeDir:
|
|
// Create directory
|
|
if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil {
|
|
return fmt.Errorf("failed to create directory %s: %w", targetPath, err)
|
|
}
|
|
case tar.TypeReg:
|
|
// Create file
|
|
outFile, err := os.Create(targetPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create file %s: %w", targetPath, err)
|
|
}
|
|
|
|
if _, err := io.Copy(outFile, tr); err != nil {
|
|
outFile.Close()
|
|
return fmt.Errorf("failed to copy file contents: %w", err)
|
|
}
|
|
outFile.Close()
|
|
|
|
// Set file permissions
|
|
if err := os.Chmod(targetPath, os.FileMode(header.Mode)); err != nil {
|
|
return fmt.Errorf("failed to set file permissions: %w", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
} |