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  }