github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/tarutil/tar_test.go (about)

     1  // Copyright 2019-2021 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package tarutil
     6  
     7  import (
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"runtime"
    12  	"testing"
    13  )
    14  
    15  func extractAndCompare(t *testing.T, tarFile string, files []struct{ name, body string }) {
    16  	tmpDir := t.TempDir()
    17  
    18  	// Extract tar to tmpDir.
    19  	f, err := os.Open(tarFile)
    20  	if err != nil {
    21  		t.Fatal(err)
    22  	}
    23  	defer f.Close()
    24  	if err := ExtractDir(f, tmpDir, &Opts{Filters: []Filter{SafeFilter}}); err != nil {
    25  		t.Fatal(err)
    26  	}
    27  
    28  	for _, f := range files {
    29  		body, err := os.ReadFile(filepath.Join(tmpDir, f.name))
    30  		if err != nil {
    31  			t.Errorf("could not read %s: %v", f.name, err)
    32  			continue
    33  		}
    34  		if string(body) != f.body {
    35  			t.Errorf("for file %s, got %q, want %q",
    36  				f.name, string(body), f.body)
    37  		}
    38  	}
    39  }
    40  
    41  func TestExtractDir(t *testing.T) {
    42  	files := []struct {
    43  		name, body string
    44  	}{
    45  		{"a.txt", "hello\n"},
    46  		{"dir/b.txt", "world\n"},
    47  	}
    48  	extractAndCompare(t, "test.tar", files)
    49  }
    50  
    51  func TestCreateTarSingleFile(t *testing.T) {
    52  	tmpDir := t.TempDir()
    53  
    54  	// Create the tar file.
    55  	filename := filepath.Join(tmpDir, "test.tar")
    56  	f, err := os.Create(filename)
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  	if err := CreateTar(f, []string{"test0"}, nil); err != nil {
    61  		f.Close()
    62  		t.Fatal(err)
    63  	}
    64  	if err := f.Close(); err != nil {
    65  		t.Fatal(err)
    66  	}
    67  
    68  	out, err := exec.Command("tar", "-tf", filename).CombinedOutput()
    69  	if err != nil {
    70  		t.Fatalf("system tar could not parse the file: %v", err)
    71  	}
    72  	expected := `test0
    73  test0/a.txt
    74  test0/dir
    75  test0/dir/b.txt
    76  `
    77  	if string(out) != expected {
    78  		t.Fatalf("got %q, want %q", string(out), expected)
    79  	}
    80  }
    81  
    82  func TestCreateTarMultFiles(t *testing.T) {
    83  	tmpDir := t.TempDir()
    84  
    85  	// Create the tar file.
    86  	filename := filepath.Join(tmpDir, "test.tar")
    87  	f, err := os.Create(filename)
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	files := []string{"test0", "test1", "test2.txt"}
    92  	if err := CreateTar(f, files, nil); err != nil {
    93  		f.Close()
    94  		t.Fatal(err)
    95  	}
    96  	if err := f.Close(); err != nil {
    97  		t.Fatal(err)
    98  	}
    99  
   100  	out, err := exec.Command("tar", "-tf", filename).CombinedOutput()
   101  	if err != nil {
   102  		t.Fatalf("system tar could not parse the file: %v", err)
   103  	}
   104  	expected := `test0
   105  test0/a.txt
   106  test0/dir
   107  test0/dir/b.txt
   108  test1
   109  test1/a1.txt
   110  test2.txt
   111  `
   112  	if string(out) != expected {
   113  		t.Fatalf("got %q, want %q", string(out), expected)
   114  	}
   115  }
   116  
   117  // TestCreateTarProcfsFile exercises the special case where stat on the file
   118  // reports a size of 0, but the file actually has contents. For example, most
   119  // of the files in /proc and /sys.
   120  func TestCreateTarProcfsFile(t *testing.T) {
   121  	if runtime.GOOS != "linux" {
   122  		t.Skipf("/proc/version is only on linux, but GOOS=%s", runtime.GOOS)
   123  	}
   124  
   125  	tmpDir := t.TempDir()
   126  
   127  	// /proc/version won't change during the test. The size according to
   128  	// stat should also be 0.
   129  	procfsFile := "/proc/version"
   130  	contents, err := os.ReadFile(procfsFile)
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	if fi, err := os.Stat(procfsFile); err != nil {
   135  		t.Fatal(err)
   136  	} else if fi.Size() != 0 {
   137  		t.Fatalf("Expected the size of %q to be 0, got %d", procfsFile, fi.Size())
   138  	}
   139  
   140  	// Create the tar file containing /proc/version.
   141  	filename := filepath.Join(tmpDir, "test.tar")
   142  	f, err := os.Create(filename)
   143  	if err != nil {
   144  		t.Fatal(err)
   145  	}
   146  
   147  	opts := &Opts{
   148  		NoRecursion: true,
   149  		// We want the path names in the tar archive to be relative to
   150  		// root. We cannot store absolute paths in the tar file because
   151  		// it will fail the zipslip check on extraction.
   152  		ChangeDirectory: "/",
   153  	}
   154  	if err := CreateTar(f, []string{"proc", "proc/version"}, opts); err != nil {
   155  		f.Close()
   156  		t.Fatal(err)
   157  	}
   158  	if err := f.Close(); err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	expected := []struct {
   163  		name, body string
   164  	}{
   165  		{procfsFile, string(contents)},
   166  	}
   167  	extractAndCompare(t, filename, expected)
   168  }
   169  
   170  func TestListArchive(t *testing.T) {
   171  	f, err := os.Open("test.tar")
   172  	if err != nil {
   173  		t.Fatal(err)
   174  	}
   175  	defer f.Close()
   176  
   177  	if err := ListArchive(f); err != nil {
   178  		t.Fatal(err)
   179  	}
   180  }