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 }