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  }