github.com/akerouanton/docker@v1.11.0-rc3/pkg/archive/archive_unix_test.go (about) 1 // +build !windows 2 3 package archive 4 5 import ( 6 "bytes" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "syscall" 12 "testing" 13 14 "github.com/docker/docker/pkg/system" 15 ) 16 17 func TestCanonicalTarNameForPath(t *testing.T) { 18 cases := []struct{ in, expected string }{ 19 {"foo", "foo"}, 20 {"foo/bar", "foo/bar"}, 21 {"foo/dir/", "foo/dir/"}, 22 } 23 for _, v := range cases { 24 if out, err := CanonicalTarNameForPath(v.in); err != nil { 25 t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err) 26 } else if out != v.expected { 27 t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out) 28 } 29 } 30 } 31 32 func TestCanonicalTarName(t *testing.T) { 33 cases := []struct { 34 in string 35 isDir bool 36 expected string 37 }{ 38 {"foo", false, "foo"}, 39 {"foo", true, "foo/"}, 40 {"foo/bar", false, "foo/bar"}, 41 {"foo/bar", true, "foo/bar/"}, 42 } 43 for _, v := range cases { 44 if out, err := canonicalTarName(v.in, v.isDir); err != nil { 45 t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err) 46 } else if out != v.expected { 47 t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out) 48 } 49 } 50 } 51 52 func TestChmodTarEntry(t *testing.T) { 53 cases := []struct { 54 in, expected os.FileMode 55 }{ 56 {0000, 0000}, 57 {0777, 0777}, 58 {0644, 0644}, 59 {0755, 0755}, 60 {0444, 0444}, 61 } 62 for _, v := range cases { 63 if out := chmodTarEntry(v.in); out != v.expected { 64 t.Fatalf("wrong chmod. expected:%v got:%v", v.expected, out) 65 } 66 } 67 } 68 69 func TestTarWithHardLink(t *testing.T) { 70 origin, err := ioutil.TempDir("", "docker-test-tar-hardlink") 71 if err != nil { 72 t.Fatal(err) 73 } 74 defer os.RemoveAll(origin) 75 if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil { 76 t.Fatal(err) 77 } 78 if err := os.Link(filepath.Join(origin, "1"), filepath.Join(origin, "2")); err != nil { 79 t.Fatal(err) 80 } 81 82 var i1, i2 uint64 83 if i1, err = getNlink(filepath.Join(origin, "1")); err != nil { 84 t.Fatal(err) 85 } 86 // sanity check that we can hardlink 87 if i1 != 2 { 88 t.Skipf("skipping since hardlinks don't work here; expected 2 links, got %d", i1) 89 } 90 91 dest, err := ioutil.TempDir("", "docker-test-tar-hardlink-dest") 92 if err != nil { 93 t.Fatal(err) 94 } 95 defer os.RemoveAll(dest) 96 97 // we'll do this in two steps to separate failure 98 fh, err := Tar(origin, Uncompressed) 99 if err != nil { 100 t.Fatal(err) 101 } 102 103 // ensure we can read the whole thing with no error, before writing back out 104 buf, err := ioutil.ReadAll(fh) 105 if err != nil { 106 t.Fatal(err) 107 } 108 109 bRdr := bytes.NewReader(buf) 110 err = Untar(bRdr, dest, &TarOptions{Compression: Uncompressed}) 111 if err != nil { 112 t.Fatal(err) 113 } 114 115 if i1, err = getInode(filepath.Join(dest, "1")); err != nil { 116 t.Fatal(err) 117 } 118 if i2, err = getInode(filepath.Join(dest, "2")); err != nil { 119 t.Fatal(err) 120 } 121 122 if i1 != i2 { 123 t.Errorf("expected matching inodes, but got %d and %d", i1, i2) 124 } 125 } 126 127 func getNlink(path string) (uint64, error) { 128 stat, err := os.Stat(path) 129 if err != nil { 130 return 0, err 131 } 132 statT, ok := stat.Sys().(*syscall.Stat_t) 133 if !ok { 134 return 0, fmt.Errorf("expected type *syscall.Stat_t, got %t", stat.Sys()) 135 } 136 // We need this conversion on ARM64 137 return uint64(statT.Nlink), nil 138 } 139 140 func getInode(path string) (uint64, error) { 141 stat, err := os.Stat(path) 142 if err != nil { 143 return 0, err 144 } 145 statT, ok := stat.Sys().(*syscall.Stat_t) 146 if !ok { 147 return 0, fmt.Errorf("expected type *syscall.Stat_t, got %t", stat.Sys()) 148 } 149 return statT.Ino, nil 150 } 151 152 func TestTarWithBlockCharFifo(t *testing.T) { 153 origin, err := ioutil.TempDir("", "docker-test-tar-hardlink") 154 if err != nil { 155 t.Fatal(err) 156 } 157 defer os.RemoveAll(origin) 158 if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil { 159 t.Fatal(err) 160 } 161 if err := system.Mknod(filepath.Join(origin, "2"), syscall.S_IFBLK, int(system.Mkdev(int64(12), int64(5)))); err != nil { 162 t.Fatal(err) 163 } 164 if err := system.Mknod(filepath.Join(origin, "3"), syscall.S_IFCHR, int(system.Mkdev(int64(12), int64(5)))); err != nil { 165 t.Fatal(err) 166 } 167 if err := system.Mknod(filepath.Join(origin, "4"), syscall.S_IFIFO, int(system.Mkdev(int64(12), int64(5)))); err != nil { 168 t.Fatal(err) 169 } 170 171 dest, err := ioutil.TempDir("", "docker-test-tar-hardlink-dest") 172 if err != nil { 173 t.Fatal(err) 174 } 175 defer os.RemoveAll(dest) 176 177 // we'll do this in two steps to separate failure 178 fh, err := Tar(origin, Uncompressed) 179 if err != nil { 180 t.Fatal(err) 181 } 182 183 // ensure we can read the whole thing with no error, before writing back out 184 buf, err := ioutil.ReadAll(fh) 185 if err != nil { 186 t.Fatal(err) 187 } 188 189 bRdr := bytes.NewReader(buf) 190 err = Untar(bRdr, dest, &TarOptions{Compression: Uncompressed}) 191 if err != nil { 192 t.Fatal(err) 193 } 194 195 changes, err := ChangesDirs(origin, dest) 196 if err != nil { 197 t.Fatal(err) 198 } 199 if len(changes) > 0 { 200 t.Fatalf("Tar with special device (block, char, fifo) should keep them (recreate them when untar) : %v", changes) 201 } 202 } 203 204 // TestTarUntarWithXattr is Unix as Lsetxattr is not supported on Windows 205 func TestTarUntarWithXattr(t *testing.T) { 206 origin, err := ioutil.TempDir("", "docker-test-untar-origin") 207 if err != nil { 208 t.Fatal(err) 209 } 210 defer os.RemoveAll(origin) 211 if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil { 212 t.Fatal(err) 213 } 214 if err := ioutil.WriteFile(filepath.Join(origin, "2"), []byte("welcome!"), 0700); err != nil { 215 t.Fatal(err) 216 } 217 if err := ioutil.WriteFile(filepath.Join(origin, "3"), []byte("will be ignored"), 0700); err != nil { 218 t.Fatal(err) 219 } 220 if err := system.Lsetxattr(filepath.Join(origin, "2"), "security.capability", []byte{0x00}, 0); err != nil { 221 t.Fatal(err) 222 } 223 224 for _, c := range []Compression{ 225 Uncompressed, 226 Gzip, 227 } { 228 changes, err := tarUntar(t, origin, &TarOptions{ 229 Compression: c, 230 ExcludePatterns: []string{"3"}, 231 }) 232 233 if err != nil { 234 t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err) 235 } 236 237 if len(changes) != 1 || changes[0].Path != "/3" { 238 t.Fatalf("Unexpected differences after tarUntar: %v", changes) 239 } 240 capability, _ := system.Lgetxattr(filepath.Join(origin, "2"), "security.capability") 241 if capability == nil && capability[0] != 0x00 { 242 t.Fatalf("Untar should have kept the 'security.capability' xattr.") 243 } 244 } 245 }