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