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