github.com/TrenchBoot/u-root@v6.0.1-0.20200623220532-550e36da3258+incompatible/cmds/core/cpio/cpio_test.go (about)

     1  // Copyright 2020 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 main
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"syscall"
    14  	"testing"
    15  
    16  	"github.com/u-root/u-root/pkg/testutil"
    17  )
    18  
    19  type dirEnt struct {
    20  	Name     string
    21  	Type     string
    22  	Content  string
    23  	Target   string
    24  	FileInfo os.FileInfo
    25  }
    26  
    27  func TestCpio(t *testing.T) {
    28  	// Create a temporary directory
    29  	tempDir, err := ioutil.TempDir("", "TestCpio")
    30  	if err != nil {
    31  		t.Fatalf("cannot create temporary directory: %v", err)
    32  	}
    33  	defer os.RemoveAll(tempDir)
    34  
    35  	var targets = []dirEnt{
    36  		{Name: "file1", Type: "file", Content: "Hello World"},
    37  		{Name: "file2", Type: "file", Content: ""},
    38  		{Name: "hardlinked", Type: "hardlink", Target: "file1"},
    39  		{Name: "hardlinkedtofile2", Type: "hardlink", Target: "file2"},
    40  		{Name: "directory1", Type: "dir"},
    41  	}
    42  	for _, ent := range targets {
    43  		var name = filepath.Join(tempDir, ent.Name)
    44  		switch ent.Type {
    45  		case "dir":
    46  			err := os.Mkdir(name, os.FileMode(0700))
    47  			if err != nil {
    48  				t.Fatalf("cannot create test directory: %v", err)
    49  			}
    50  
    51  		case "file":
    52  			f, err := os.Create(name)
    53  			if err != nil {
    54  				t.Fatalf("cannot create test file: %v", err)
    55  			}
    56  			defer f.Close()
    57  			_, err = f.WriteString(ent.Content)
    58  			if err != nil {
    59  				t.Fatal(err)
    60  			}
    61  
    62  		case "hardlink":
    63  			target := filepath.Join(tempDir, ent.Target)
    64  			err := os.Link(target, name)
    65  			if err != nil {
    66  				t.Fatalf("cannot create hard link: %v", err)
    67  			}
    68  		}
    69  	}
    70  
    71  	// Now that the temporary directory structure is complete, populate
    72  	// the FileInfo for each target. This needs to happen in a second
    73  	// pass because of the link count.
    74  	for key, ent := range targets {
    75  		var name = filepath.Join(tempDir, ent.Name)
    76  		targets[key].FileInfo, err = os.Stat(name)
    77  		if err != nil {
    78  			t.Fatalf("cannot stat temporary dirent: %v", err)
    79  		}
    80  	}
    81  
    82  	c := testutil.Command(t, "-v", "o")
    83  	c.Dir = tempDir
    84  
    85  	buffer := bytes.Buffer{}
    86  	for _, ent := range targets {
    87  		buffer.WriteString(ent.Name + "\n")
    88  	}
    89  	c.Stdin = &buffer
    90  
    91  	archive, err := c.Output()
    92  	if err != nil {
    93  		t.Fatalf("%s %v", c.Stderr, err)
    94  	}
    95  
    96  	// Cpio can't read from a non-seekable input (e.g. a pipe) in input mode.
    97  	// Write the archive to a file instead.
    98  	archiveFile, err := ioutil.TempFile("", "archive.cpio")
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	defer os.Remove(archiveFile.Name())
   103  	defer archiveFile.Close()
   104  
   105  	if _, err := archiveFile.Write(archive); err != nil {
   106  		t.Fatal(err)
   107  	}
   108  
   109  	// Extract to a new directory
   110  	tempExtractDir, err := ioutil.TempDir(tempDir, "extract")
   111  	if err != nil {
   112  		t.Fatalf("cannot create temporary directory: %v", err)
   113  	}
   114  
   115  	c = testutil.Command(t, "-v", "i")
   116  	c.Dir = tempExtractDir
   117  	c.Stdin = archiveFile
   118  
   119  	out, err := c.Output()
   120  	if err != nil {
   121  		t.Fatalf("Extraction failed:\n%s\n%s\n%v\n", out, c.Stderr, err)
   122  	}
   123  
   124  	for _, ent := range targets {
   125  		var name = filepath.Join(tempExtractDir, ent.Name)
   126  		newFileInfo, err := os.Stat(name)
   127  		if err != nil {
   128  			t.Fatal(err)
   129  		}
   130  		newStatT := newFileInfo.Sys().(*syscall.Stat_t)
   131  		statT := ent.FileInfo.Sys().(*syscall.Stat_t)
   132  		if ent.FileInfo.Name() != newFileInfo.Name() ||
   133  			ent.FileInfo.Size() != newFileInfo.Size() ||
   134  			ent.FileInfo.Mode() != newFileInfo.Mode() ||
   135  			ent.FileInfo.IsDir() != newFileInfo.IsDir() ||
   136  			statT.Mode != newStatT.Mode ||
   137  			statT.Uid != newStatT.Uid ||
   138  			statT.Gid != newStatT.Gid ||
   139  			statT.Nlink != newStatT.Nlink {
   140  			msg := "File has mismatched attributes:\n"
   141  			msg += "Property |   Original |  Extracted\n"
   142  			msg += fmt.Sprintf("Name:    | %10s | %10s\n", ent.FileInfo.Name(), newFileInfo.Name())
   143  			msg += fmt.Sprintf("Size:    | %10d | %10d\n", ent.FileInfo.Size(), newFileInfo.Size())
   144  			msg += fmt.Sprintf("Mode:    | %10d | %10d\n", ent.FileInfo.Mode(), newFileInfo.Mode())
   145  			msg += fmt.Sprintf("IsDir:   | %10t | %10t\n", ent.FileInfo.IsDir(), newFileInfo.IsDir())
   146  			msg += fmt.Sprintf("FI Mode: | %10d | %10d\n", statT.Mode, newStatT.Mode)
   147  			msg += fmt.Sprintf("Uid:     | %10d | %10d\n", statT.Uid, newStatT.Uid)
   148  			msg += fmt.Sprintf("Gid:     | %10d | %10d\n", statT.Gid, newStatT.Gid)
   149  			msg += fmt.Sprintf("NLink:   | %10d | %10d\n", statT.Nlink, newStatT.Nlink)
   150  			t.Fatal(msg)
   151  		}
   152  
   153  		if ent.Type == "file" {
   154  			content, err := ioutil.ReadFile(name)
   155  			if err != nil {
   156  				t.Fatal(err)
   157  			}
   158  			if string(content) != ent.Content {
   159  				t.Fatalf("File %s has mismatched contents", ent.Name)
   160  			}
   161  		}
   162  	}
   163  }
   164  
   165  func TestMain(m *testing.M) {
   166  	testutil.Run(m, main)
   167  }