github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/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 "os" 11 "path/filepath" 12 "runtime" 13 "testing" 14 ) 15 16 type dirEnt struct { 17 Name string 18 Type string 19 Content string 20 Target string 21 FileInfo os.FileInfo 22 } 23 24 func TestCpio(t *testing.T) { 25 debug = t.Logf 26 // Create a temporary directory 27 tempDir := t.TempDir() 28 29 targets := []dirEnt{ 30 {Name: "file1", Type: "file", Content: "Hello World"}, 31 {Name: "file2", Type: "file", Content: ""}, 32 {Name: "directory1", Type: "dir"}, 33 } 34 if runtime.GOOS != "plan9" { 35 targets = append(targets, []dirEnt{ 36 {Name: "hardlinked", Type: "hardlink", Target: "file1", Content: "Hello World"}, 37 {Name: "hardlinkedtofile2", Type: "hardlink", Target: "file2"}, 38 }...) 39 } 40 for _, ent := range targets { 41 name := filepath.Join(tempDir, ent.Name) 42 switch ent.Type { 43 case "dir": 44 err := os.Mkdir(name, os.FileMode(0o700)) 45 if err != nil { 46 t.Fatalf("cannot create test directory: %v", err) 47 } 48 49 case "file": 50 f, err := os.Create(name) 51 if err != nil { 52 t.Fatalf("cannot create test file: %v", err) 53 } 54 defer f.Close() 55 _, err = f.WriteString(ent.Content) 56 if err != nil { 57 t.Fatal(err) 58 } 59 60 case "hardlink": 61 target := filepath.Join(tempDir, ent.Target) 62 err := os.Link(target, name) 63 if err != nil { 64 t.Fatalf("cannot create hard link: %v", err) 65 } 66 } 67 } 68 69 // Now that the temporary directory structure is complete, populate 70 // the FileInfo for each target. This needs to happen in a second 71 // pass because of the link count. 72 for key, ent := range targets { 73 var err error 74 name := filepath.Join(tempDir, ent.Name) 75 targets[key].FileInfo, err = os.Stat(name) 76 if err != nil { 77 t.Fatalf("cannot stat temporary dirent: %v", err) 78 } 79 } 80 81 inputFile, err := os.CreateTemp(tempDir, "") 82 if err != nil { 83 t.Fatalf("%v", err) 84 } 85 86 for _, ent := range targets { 87 name := filepath.Join(tempDir, ent.Name) 88 if _, err := fmt.Fprintln(inputFile, name); err != nil { 89 t.Fatalf("failed to write file path %v to input file: %v", ent.Name, err) 90 } 91 } 92 inputFile.Seek(0, 0) 93 94 archive := &bytes.Buffer{} 95 err = run([]string{"o"}, inputFile, archive, true, "newc") 96 if err != nil { 97 t.Fatalf("failed to build archive from filepaths: %v", err) 98 } 99 100 // Cpio can't read from a non-seekable input (e.g. a pipe) in input mode. 101 // Write the archive to a file instead. 102 archiveFile, err := os.CreateTemp(tempDir, "archive.cpio") 103 if err != nil { 104 t.Fatal(err) 105 } 106 107 if _, err := archiveFile.Write(archive.Bytes()); err != nil { 108 t.Fatal(err) 109 } 110 111 // Extract to a new directory 112 tempExtractDir := t.TempDir() 113 114 out := &bytes.Buffer{} 115 // Change directory back afterwards to not interfer with the subsequent tests 116 wd, err := os.Getwd() 117 if err != nil { 118 t.Fatalf("Could not get current working directory: %v", err) 119 } 120 defer os.Chdir(wd) 121 122 err = os.Chdir(tempExtractDir) 123 if err != nil { 124 t.Fatalf("Change to extraction directory %v failed: %#v", tempExtractDir, err) 125 } 126 127 err = run([]string{"i"}, archiveFile, out, true, "newc") 128 if err != nil { 129 t.Fatalf("Extraction failed:\n%#v\n%v\n", out, err) 130 } 131 132 for _, ent := range targets { 133 name := filepath.Join(tempExtractDir, tempDir, ent.Name) 134 135 newFileInfo, err := os.Stat(name) 136 if err != nil { 137 t.Error(err) 138 continue 139 } 140 checkFileInfo(t, &ent, newFileInfo) 141 142 if ent.Type != "dir" { 143 content, err := os.ReadFile(name) 144 if err != nil { 145 t.Error(err) 146 } 147 if string(content) != ent.Content { 148 t.Errorf("File %s has mismatched contents", ent.Name) 149 } 150 } 151 } 152 } 153 154 func TestDirectoryHardLink(t *testing.T) { 155 156 // Open an archive containing two directories with the same inode (0). 157 // We're trying to test if having the same inode will trigger a hard link. 158 archiveFile, err := os.Open("testdata/dir-hard-link.cpio") 159 if err != nil { 160 t.Fatal(err) 161 } 162 163 // Change directory back afterwards to not interfer with the subsequent tests 164 wd, err := os.Getwd() 165 if err != nil { 166 t.Fatalf("Could not get current working directory: %v", err) 167 } 168 defer os.Chdir(wd) 169 tempExtractDir := t.TempDir() 170 err = os.Chdir(tempExtractDir) 171 if err != nil { 172 t.Fatalf("Change to dir %v failed: %v", tempExtractDir, err) 173 } 174 175 want := &bytes.Buffer{} 176 err = run([]string{"i"}, archiveFile, want, true, "newc") 177 178 if err != nil { 179 t.Fatalf("Extraction failed:\n%v\n%v\n", want, err) 180 } 181 182 }