github.com/ttys3/engine@v17.12.1-ce-rc2+incompatible/pkg/chrootarchive/archive_test.go (about) 1 package chrootarchive 2 3 import ( 4 "bytes" 5 "fmt" 6 "hash/crc32" 7 "io" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "runtime" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/docker/docker/pkg/archive" 17 "github.com/docker/docker/pkg/reexec" 18 "github.com/docker/docker/pkg/system" 19 ) 20 21 func init() { 22 reexec.Init() 23 } 24 25 var chrootArchiver = NewArchiver(nil) 26 27 func TarUntar(src, dst string) error { 28 return chrootArchiver.TarUntar(src, dst) 29 } 30 31 func CopyFileWithTar(src, dst string) (err error) { 32 return chrootArchiver.CopyFileWithTar(src, dst) 33 } 34 35 func UntarPath(src, dst string) error { 36 return chrootArchiver.UntarPath(src, dst) 37 } 38 39 func CopyWithTar(src, dst string) error { 40 return chrootArchiver.CopyWithTar(src, dst) 41 } 42 43 func TestChrootTarUntar(t *testing.T) { 44 tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntar") 45 if err != nil { 46 t.Fatal(err) 47 } 48 defer os.RemoveAll(tmpdir) 49 src := filepath.Join(tmpdir, "src") 50 if err := system.MkdirAll(src, 0700, ""); err != nil { 51 t.Fatal(err) 52 } 53 if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { 54 t.Fatal(err) 55 } 56 if err := ioutil.WriteFile(filepath.Join(src, "lolo"), []byte("hello lolo"), 0644); err != nil { 57 t.Fatal(err) 58 } 59 stream, err := archive.Tar(src, archive.Uncompressed) 60 if err != nil { 61 t.Fatal(err) 62 } 63 dest := filepath.Join(tmpdir, "src") 64 if err := system.MkdirAll(dest, 0700, ""); err != nil { 65 t.Fatal(err) 66 } 67 if err := Untar(stream, dest, &archive.TarOptions{ExcludePatterns: []string{"lolo"}}); err != nil { 68 t.Fatal(err) 69 } 70 } 71 72 // gh#10426: Verify the fix for having a huge excludes list (like on `docker load` with large # of 73 // local images) 74 func TestChrootUntarWithHugeExcludesList(t *testing.T) { 75 tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarHugeExcludes") 76 if err != nil { 77 t.Fatal(err) 78 } 79 defer os.RemoveAll(tmpdir) 80 src := filepath.Join(tmpdir, "src") 81 if err := system.MkdirAll(src, 0700, ""); err != nil { 82 t.Fatal(err) 83 } 84 if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil { 85 t.Fatal(err) 86 } 87 stream, err := archive.Tar(src, archive.Uncompressed) 88 if err != nil { 89 t.Fatal(err) 90 } 91 dest := filepath.Join(tmpdir, "dest") 92 if err := system.MkdirAll(dest, 0700, ""); err != nil { 93 t.Fatal(err) 94 } 95 options := &archive.TarOptions{} 96 //65534 entries of 64-byte strings ~= 4MB of environment space which should overflow 97 //on most systems when passed via environment or command line arguments 98 excludes := make([]string, 65534) 99 for i := 0; i < 65534; i++ { 100 excludes[i] = strings.Repeat(string(i), 64) 101 } 102 options.ExcludePatterns = excludes 103 if err := Untar(stream, dest, options); err != nil { 104 t.Fatal(err) 105 } 106 } 107 108 func TestChrootUntarEmptyArchive(t *testing.T) { 109 tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarEmptyArchive") 110 if err != nil { 111 t.Fatal(err) 112 } 113 defer os.RemoveAll(tmpdir) 114 if err := Untar(nil, tmpdir, nil); err == nil { 115 t.Fatal("expected error on empty archive") 116 } 117 } 118 119 func prepareSourceDirectory(numberOfFiles int, targetPath string, makeSymLinks bool) (int, error) { 120 fileData := []byte("fooo") 121 for n := 0; n < numberOfFiles; n++ { 122 fileName := fmt.Sprintf("file-%d", n) 123 if err := ioutil.WriteFile(filepath.Join(targetPath, fileName), fileData, 0700); err != nil { 124 return 0, err 125 } 126 if makeSymLinks { 127 if err := os.Symlink(filepath.Join(targetPath, fileName), filepath.Join(targetPath, fileName+"-link")); err != nil { 128 return 0, err 129 } 130 } 131 } 132 totalSize := numberOfFiles * len(fileData) 133 return totalSize, nil 134 } 135 136 func getHash(filename string) (uint32, error) { 137 stream, err := ioutil.ReadFile(filename) 138 if err != nil { 139 return 0, err 140 } 141 hash := crc32.NewIEEE() 142 hash.Write(stream) 143 return hash.Sum32(), nil 144 } 145 146 func compareDirectories(src string, dest string) error { 147 changes, err := archive.ChangesDirs(dest, src) 148 if err != nil { 149 return err 150 } 151 if len(changes) > 0 { 152 return fmt.Errorf("Unexpected differences after untar: %v", changes) 153 } 154 return nil 155 } 156 157 func compareFiles(src string, dest string) error { 158 srcHash, err := getHash(src) 159 if err != nil { 160 return err 161 } 162 destHash, err := getHash(dest) 163 if err != nil { 164 return err 165 } 166 if srcHash != destHash { 167 return fmt.Errorf("%s is different from %s", src, dest) 168 } 169 return nil 170 } 171 172 func TestChrootTarUntarWithSymlink(t *testing.T) { 173 // TODO Windows: Figure out why this is failing 174 if runtime.GOOS == "windows" { 175 t.Skip("Failing on Windows") 176 } 177 tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntarWithSymlink") 178 if err != nil { 179 t.Fatal(err) 180 } 181 defer os.RemoveAll(tmpdir) 182 src := filepath.Join(tmpdir, "src") 183 if err := system.MkdirAll(src, 0700, ""); err != nil { 184 t.Fatal(err) 185 } 186 if _, err := prepareSourceDirectory(10, src, false); err != nil { 187 t.Fatal(err) 188 } 189 dest := filepath.Join(tmpdir, "dest") 190 if err := TarUntar(src, dest); err != nil { 191 t.Fatal(err) 192 } 193 if err := compareDirectories(src, dest); err != nil { 194 t.Fatal(err) 195 } 196 } 197 198 func TestChrootCopyWithTar(t *testing.T) { 199 // TODO Windows: Figure out why this is failing 200 if runtime.GOOS == "windows" { 201 t.Skip("Failing on Windows") 202 } 203 tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyWithTar") 204 if err != nil { 205 t.Fatal(err) 206 } 207 defer os.RemoveAll(tmpdir) 208 src := filepath.Join(tmpdir, "src") 209 if err := system.MkdirAll(src, 0700, ""); err != nil { 210 t.Fatal(err) 211 } 212 if _, err := prepareSourceDirectory(10, src, true); err != nil { 213 t.Fatal(err) 214 } 215 216 // Copy directory 217 dest := filepath.Join(tmpdir, "dest") 218 if err := CopyWithTar(src, dest); err != nil { 219 t.Fatal(err) 220 } 221 if err := compareDirectories(src, dest); err != nil { 222 t.Fatal(err) 223 } 224 225 // Copy file 226 srcfile := filepath.Join(src, "file-1") 227 dest = filepath.Join(tmpdir, "destFile") 228 destfile := filepath.Join(dest, "file-1") 229 if err := CopyWithTar(srcfile, destfile); err != nil { 230 t.Fatal(err) 231 } 232 if err := compareFiles(srcfile, destfile); err != nil { 233 t.Fatal(err) 234 } 235 236 // Copy symbolic link 237 srcLinkfile := filepath.Join(src, "file-1-link") 238 dest = filepath.Join(tmpdir, "destSymlink") 239 destLinkfile := filepath.Join(dest, "file-1-link") 240 if err := CopyWithTar(srcLinkfile, destLinkfile); err != nil { 241 t.Fatal(err) 242 } 243 if err := compareFiles(srcLinkfile, destLinkfile); err != nil { 244 t.Fatal(err) 245 } 246 } 247 248 func TestChrootCopyFileWithTar(t *testing.T) { 249 tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyFileWithTar") 250 if err != nil { 251 t.Fatal(err) 252 } 253 defer os.RemoveAll(tmpdir) 254 src := filepath.Join(tmpdir, "src") 255 if err := system.MkdirAll(src, 0700, ""); err != nil { 256 t.Fatal(err) 257 } 258 if _, err := prepareSourceDirectory(10, src, true); err != nil { 259 t.Fatal(err) 260 } 261 262 // Copy directory 263 dest := filepath.Join(tmpdir, "dest") 264 if err := CopyFileWithTar(src, dest); err == nil { 265 t.Fatal("Expected error on copying directory") 266 } 267 268 // Copy file 269 srcfile := filepath.Join(src, "file-1") 270 dest = filepath.Join(tmpdir, "destFile") 271 destfile := filepath.Join(dest, "file-1") 272 if err := CopyFileWithTar(srcfile, destfile); err != nil { 273 t.Fatal(err) 274 } 275 if err := compareFiles(srcfile, destfile); err != nil { 276 t.Fatal(err) 277 } 278 279 // Copy symbolic link 280 srcLinkfile := filepath.Join(src, "file-1-link") 281 dest = filepath.Join(tmpdir, "destSymlink") 282 destLinkfile := filepath.Join(dest, "file-1-link") 283 if err := CopyFileWithTar(srcLinkfile, destLinkfile); err != nil { 284 t.Fatal(err) 285 } 286 if err := compareFiles(srcLinkfile, destLinkfile); err != nil { 287 t.Fatal(err) 288 } 289 } 290 291 func TestChrootUntarPath(t *testing.T) { 292 // TODO Windows: Figure out why this is failing 293 if runtime.GOOS == "windows" { 294 t.Skip("Failing on Windows") 295 } 296 tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarPath") 297 if err != nil { 298 t.Fatal(err) 299 } 300 defer os.RemoveAll(tmpdir) 301 src := filepath.Join(tmpdir, "src") 302 if err := system.MkdirAll(src, 0700, ""); err != nil { 303 t.Fatal(err) 304 } 305 if _, err := prepareSourceDirectory(10, src, false); err != nil { 306 t.Fatal(err) 307 } 308 dest := filepath.Join(tmpdir, "dest") 309 // Untar a directory 310 if err := UntarPath(src, dest); err == nil { 311 t.Fatal("Expected error on untaring a directory") 312 } 313 314 // Untar a tar file 315 stream, err := archive.Tar(src, archive.Uncompressed) 316 if err != nil { 317 t.Fatal(err) 318 } 319 buf := new(bytes.Buffer) 320 buf.ReadFrom(stream) 321 tarfile := filepath.Join(tmpdir, "src.tar") 322 if err := ioutil.WriteFile(tarfile, buf.Bytes(), 0644); err != nil { 323 t.Fatal(err) 324 } 325 if err := UntarPath(tarfile, dest); err != nil { 326 t.Fatal(err) 327 } 328 if err := compareDirectories(src, dest); err != nil { 329 t.Fatal(err) 330 } 331 } 332 333 type slowEmptyTarReader struct { 334 size int 335 offset int 336 chunkSize int 337 } 338 339 // Read is a slow reader of an empty tar (like the output of "tar c --files-from /dev/null") 340 func (s *slowEmptyTarReader) Read(p []byte) (int, error) { 341 time.Sleep(100 * time.Millisecond) 342 count := s.chunkSize 343 if len(p) < s.chunkSize { 344 count = len(p) 345 } 346 for i := 0; i < count; i++ { 347 p[i] = 0 348 } 349 s.offset += count 350 if s.offset > s.size { 351 return count, io.EOF 352 } 353 return count, nil 354 } 355 356 func TestChrootUntarEmptyArchiveFromSlowReader(t *testing.T) { 357 tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarEmptyArchiveFromSlowReader") 358 if err != nil { 359 t.Fatal(err) 360 } 361 defer os.RemoveAll(tmpdir) 362 dest := filepath.Join(tmpdir, "dest") 363 if err := system.MkdirAll(dest, 0700, ""); err != nil { 364 t.Fatal(err) 365 } 366 stream := &slowEmptyTarReader{size: 10240, chunkSize: 1024} 367 if err := Untar(stream, dest, nil); err != nil { 368 t.Fatal(err) 369 } 370 } 371 372 func TestChrootApplyEmptyArchiveFromSlowReader(t *testing.T) { 373 tmpdir, err := ioutil.TempDir("", "docker-TestChrootApplyEmptyArchiveFromSlowReader") 374 if err != nil { 375 t.Fatal(err) 376 } 377 defer os.RemoveAll(tmpdir) 378 dest := filepath.Join(tmpdir, "dest") 379 if err := system.MkdirAll(dest, 0700, ""); err != nil { 380 t.Fatal(err) 381 } 382 stream := &slowEmptyTarReader{size: 10240, chunkSize: 1024} 383 if _, err := ApplyLayer(dest, stream); err != nil { 384 t.Fatal(err) 385 } 386 } 387 388 func TestChrootApplyDotDotFile(t *testing.T) { 389 tmpdir, err := ioutil.TempDir("", "docker-TestChrootApplyDotDotFile") 390 if err != nil { 391 t.Fatal(err) 392 } 393 defer os.RemoveAll(tmpdir) 394 src := filepath.Join(tmpdir, "src") 395 if err := system.MkdirAll(src, 0700, ""); err != nil { 396 t.Fatal(err) 397 } 398 if err := ioutil.WriteFile(filepath.Join(src, "..gitme"), []byte(""), 0644); err != nil { 399 t.Fatal(err) 400 } 401 stream, err := archive.Tar(src, archive.Uncompressed) 402 if err != nil { 403 t.Fatal(err) 404 } 405 dest := filepath.Join(tmpdir, "dest") 406 if err := system.MkdirAll(dest, 0700, ""); err != nil { 407 t.Fatal(err) 408 } 409 if _, err := ApplyLayer(dest, stream); err != nil { 410 t.Fatal(err) 411 } 412 }