github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/pkg/tarsum/tarsum_test.go (about)

     1  package tarsum // import "github.com/docker/docker/pkg/tarsum"
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"compress/gzip"
     7  	"crypto/md5" // #nosec G501
     8  	"crypto/rand"
     9  	"crypto/sha1" // #nosec G505
    10  	"crypto/sha256"
    11  	"crypto/sha512"
    12  	"encoding/hex"
    13  	"fmt"
    14  	"io"
    15  	"os"
    16  	"strings"
    17  	"testing"
    18  
    19  	"gotest.tools/v3/assert"
    20  	is "gotest.tools/v3/assert/cmp"
    21  )
    22  
    23  type testLayer struct {
    24  	filename string
    25  	options  *sizedOptions
    26  	jsonfile string
    27  	gzip     bool
    28  	tarsum   string
    29  	version  Version
    30  	hash     THash
    31  }
    32  
    33  var testLayers = []testLayer{
    34  	{
    35  		filename: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar",
    36  		jsonfile: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/json",
    37  		version:  Version0,
    38  		tarsum:   "tarsum+sha256:4095cc12fa5fdb1ab2760377e1cd0c4ecdd3e61b4f9b82319d96fcea6c9a41c6"},
    39  	{
    40  		filename: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar",
    41  		jsonfile: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/json",
    42  		version:  VersionDev,
    43  		tarsum:   "tarsum.dev+sha256:db56e35eec6ce65ba1588c20ba6b1ea23743b59e81fb6b7f358ccbde5580345c"},
    44  	{
    45  		filename: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar",
    46  		jsonfile: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/json",
    47  		gzip:     true,
    48  		tarsum:   "tarsum+sha256:4095cc12fa5fdb1ab2760377e1cd0c4ecdd3e61b4f9b82319d96fcea6c9a41c6"},
    49  	{
    50  		// Tests existing version of TarSum when xattrs are present
    51  		filename: "testdata/xattr/layer.tar",
    52  		jsonfile: "testdata/xattr/json",
    53  		version:  Version0,
    54  		tarsum:   "tarsum+sha256:07e304a8dbcb215b37649fde1a699f8aeea47e60815707f1cdf4d55d25ff6ab4"},
    55  	{
    56  		// Tests next version of TarSum when xattrs are present
    57  		filename: "testdata/xattr/layer.tar",
    58  		jsonfile: "testdata/xattr/json",
    59  		version:  VersionDev,
    60  		tarsum:   "tarsum.dev+sha256:6c58917892d77b3b357b0f9ad1e28e1f4ae4de3a8006bd3beb8beda214d8fd16"},
    61  	{
    62  		filename: "testdata/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/layer.tar",
    63  		jsonfile: "testdata/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/json",
    64  		tarsum:   "tarsum+sha256:c66bd5ec9f87b8f4c6135ca37684618f486a3dd1d113b138d0a177bfa39c2571"},
    65  	{
    66  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    67  		tarsum:  "tarsum+sha256:75258b2c5dcd9adfe24ce71eeca5fc5019c7e669912f15703ede92b1a60cb11f"},
    68  	{
    69  		// this tar has two files with the same path
    70  		filename: "testdata/collision/collision-0.tar",
    71  		tarsum:   "tarsum+sha256:7cabb5e9128bb4a93ff867b9464d7c66a644ae51ea2e90e6ef313f3bef93f077"},
    72  	{
    73  		// this tar has the same two files (with the same path), but reversed order. ensuring is has different hash than above
    74  		filename: "testdata/collision/collision-1.tar",
    75  		tarsum:   "tarsum+sha256:805fd393cfd58900b10c5636cf9bab48b2406d9b66523122f2352620c85dc7f9"},
    76  	{
    77  		// this tar has newer of collider-0.tar, ensuring is has different hash
    78  		filename: "testdata/collision/collision-2.tar",
    79  		tarsum:   "tarsum+sha256:85d2b8389f077659d78aca898f9e632ed9161f553f144aef100648eac540147b"},
    80  	{
    81  		// this tar has newer of collider-1.tar, ensuring is has different hash
    82  		filename: "testdata/collision/collision-3.tar",
    83  		tarsum:   "tarsum+sha256:cbe4dee79fe979d69c16c2bccd032e3205716a562f4a3c1ca1cbeed7b256eb19"},
    84  	{
    85  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    86  		tarsum:  "tarsum+md5:3a6cdb475d90459ac0d3280703d17be2",
    87  		hash:    md5THash,
    88  	},
    89  	{
    90  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    91  		tarsum:  "tarsum+sha1:14b5e0d12a0c50a4281e86e92153fa06d55d00c6",
    92  		hash:    sha1Hash,
    93  	},
    94  	{
    95  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    96  		tarsum:  "tarsum+sha224:dd8925b7a4c71b13f3a68a0f9428a757c76b93752c398f272a9062d5",
    97  		hash:    sha224Hash,
    98  	},
    99  	{
   100  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
   101  		tarsum:  "tarsum+sha384:e39e82f40005134bed13fb632d1a5f2aa4675c9ddb4a136fbcec202797e68d2f635e1200dee2e3a8d7f69d54d3f2fd27",
   102  		hash:    sha384Hash,
   103  	},
   104  	{
   105  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
   106  		tarsum:  "tarsum+sha512:7c56de40b2d1ed3863ff25d83b59cdc8f53e67d1c01c3ee8f201f8e4dec3107da976d0c0ec9109c962a152b32699fe329b2dab13966020e400c32878a0761a7e",
   107  		hash:    sha512Hash,
   108  	},
   109  }
   110  
   111  type sizedOptions struct {
   112  	num      int64
   113  	size     int64
   114  	isRand   bool
   115  	realFile bool
   116  }
   117  
   118  // make a tar:
   119  // * num is the number of files the tar should have
   120  // * size is the bytes per file
   121  // * isRand is whether the contents of the files should be a random chunk (otherwise it's all zeros)
   122  // * realFile will write to a TempFile, instead of an in memory buffer
   123  func sizedTar(opts sizedOptions) io.Reader {
   124  	var (
   125  		fh  io.ReadWriter
   126  		err error
   127  	)
   128  	if opts.realFile {
   129  		fh, err = os.CreateTemp("", "tarsum")
   130  		if err != nil {
   131  			return nil
   132  		}
   133  	} else {
   134  		fh = bytes.NewBuffer([]byte{})
   135  	}
   136  	tarW := tar.NewWriter(fh)
   137  	defer tarW.Close()
   138  	for i := int64(0); i < opts.num; i++ {
   139  		err := tarW.WriteHeader(&tar.Header{
   140  			Name:     fmt.Sprintf("/testdata%d", i),
   141  			Mode:     0755,
   142  			Uid:      0,
   143  			Gid:      0,
   144  			Size:     opts.size,
   145  			Typeflag: tar.TypeReg,
   146  		})
   147  		if err != nil {
   148  			return nil
   149  		}
   150  		var rBuf []byte
   151  		if opts.isRand {
   152  			rBuf = make([]byte, 8)
   153  			_, err = rand.Read(rBuf)
   154  			if err != nil {
   155  				return nil
   156  			}
   157  		} else {
   158  			rBuf = []byte{0, 0, 0, 0, 0, 0, 0, 0}
   159  		}
   160  
   161  		for i := int64(0); i < opts.size/int64(8); i++ {
   162  			tarW.Write(rBuf)
   163  		}
   164  	}
   165  	return fh
   166  }
   167  
   168  func emptyTarSum(gzip bool) (TarSum, error) {
   169  	reader, writer := io.Pipe()
   170  	tarWriter := tar.NewWriter(writer)
   171  
   172  	// Immediately close tarWriter and write-end of the
   173  	// Pipe in a separate goroutine so we don't block.
   174  	go func() {
   175  		tarWriter.Close()
   176  		writer.Close()
   177  	}()
   178  
   179  	return NewTarSum(reader, !gzip, Version0)
   180  }
   181  
   182  // Test errors on NewTarsumForLabel
   183  func TestNewTarSumForLabelInvalid(t *testing.T) {
   184  	reader := strings.NewReader("")
   185  
   186  	if _, err := NewTarSumForLabel(reader, true, "invalidlabel"); err == nil {
   187  		t.Fatalf("Expected an error, got nothing.")
   188  	}
   189  
   190  	if _, err := NewTarSumForLabel(reader, true, "invalid+sha256"); err == nil {
   191  		t.Fatalf("Expected an error, got nothing.")
   192  	}
   193  	if _, err := NewTarSumForLabel(reader, true, "tarsum.v1+invalid"); err == nil {
   194  		t.Fatalf("Expected an error, got nothing.")
   195  	}
   196  }
   197  
   198  func TestNewTarSumForLabel(t *testing.T) {
   199  	layer := testLayers[0]
   200  
   201  	reader, err := os.Open(layer.filename)
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  	defer reader.Close()
   206  
   207  	label := strings.Split(layer.tarsum, ":")[0]
   208  	ts, err := NewTarSumForLabel(reader, false, label)
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  
   213  	// Make sure it actually worked by reading a little bit of it
   214  	nbByteToRead := 8 * 1024
   215  	dBuf := make([]byte, nbByteToRead)
   216  	_, err = ts.Read(dBuf)
   217  	if err != nil {
   218  		t.Errorf("failed to read %vKB from %s: %s", nbByteToRead, layer.filename, err)
   219  	}
   220  }
   221  
   222  // TestEmptyTar tests that tarsum does not fail to read an empty tar
   223  // and correctly returns the hex digest of an empty hash.
   224  func TestEmptyTar(t *testing.T) {
   225  	// Test without gzip.
   226  	ts, err := emptyTarSum(false)
   227  	assert.NilError(t, err)
   228  
   229  	zeroBlock := make([]byte, 1024)
   230  	buf := new(bytes.Buffer)
   231  
   232  	n, err := io.Copy(buf, ts)
   233  	assert.NilError(t, err)
   234  
   235  	if n != int64(len(zeroBlock)) || !bytes.Equal(buf.Bytes(), zeroBlock) {
   236  		t.Fatalf("tarSum did not write the correct number of zeroed bytes: %d", n)
   237  	}
   238  
   239  	expectedSum := ts.Version().String() + "+sha256:" + hex.EncodeToString(sha256.New().Sum(nil))
   240  	resultSum := ts.Sum(nil)
   241  
   242  	if resultSum != expectedSum {
   243  		t.Fatalf("expected [%s] but got [%s]", expectedSum, resultSum)
   244  	}
   245  
   246  	// Test with gzip.
   247  	ts, err = emptyTarSum(true)
   248  	assert.NilError(t, err)
   249  	buf.Reset()
   250  
   251  	_, err = io.Copy(buf, ts)
   252  	assert.NilError(t, err)
   253  
   254  	bufgz := new(bytes.Buffer)
   255  	gz := gzip.NewWriter(bufgz)
   256  	n, err = io.Copy(gz, bytes.NewBuffer(zeroBlock))
   257  	assert.NilError(t, err)
   258  	gz.Close()
   259  	gzBytes := bufgz.Bytes()
   260  
   261  	if n != int64(len(zeroBlock)) || !bytes.Equal(buf.Bytes(), gzBytes) {
   262  		t.Fatalf("tarSum did not write the correct number of gzipped-zeroed bytes: %d", n)
   263  	}
   264  
   265  	resultSum = ts.Sum(nil)
   266  
   267  	if resultSum != expectedSum {
   268  		t.Fatalf("expected [%s] but got [%s]", expectedSum, resultSum)
   269  	}
   270  
   271  	// Test without ever actually writing anything.
   272  	if ts, err = NewTarSum(bytes.NewReader([]byte{}), true, Version0); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	resultSum = ts.Sum(nil)
   277  	assert.Check(t, is.Equal(expectedSum, resultSum))
   278  }
   279  
   280  var (
   281  	md5THash   = NewTHash("md5", md5.New)
   282  	sha1Hash   = NewTHash("sha1", sha1.New)
   283  	sha224Hash = NewTHash("sha224", sha256.New224)
   284  	sha384Hash = NewTHash("sha384", sha512.New384)
   285  	sha512Hash = NewTHash("sha512", sha512.New)
   286  )
   287  
   288  // Test all the build-in read size : buf8K, buf16K, buf32K and more
   289  func TestTarSumsReadSize(t *testing.T) {
   290  	// Test always on the same layer (that is big enough)
   291  	layer := testLayers[0]
   292  
   293  	for i := 0; i < 5; i++ {
   294  		reader, err := os.Open(layer.filename)
   295  		if err != nil {
   296  			t.Fatal(err)
   297  		}
   298  		defer reader.Close()
   299  
   300  		ts, err := NewTarSum(reader, false, layer.version)
   301  		if err != nil {
   302  			t.Fatal(err)
   303  		}
   304  
   305  		// Read and discard bytes so that it populates sums
   306  		nbByteToRead := (i + 1) * 8 * 1024
   307  		dBuf := make([]byte, nbByteToRead)
   308  		_, err = ts.Read(dBuf)
   309  		if err != nil {
   310  			t.Errorf("failed to read %vKB from %s: %s", nbByteToRead, layer.filename, err)
   311  			continue
   312  		}
   313  	}
   314  }
   315  
   316  func TestTarSums(t *testing.T) {
   317  	for _, layer := range testLayers {
   318  		var (
   319  			fh  io.Reader
   320  			err error
   321  		)
   322  		if len(layer.filename) > 0 {
   323  			fh, err = os.Open(layer.filename)
   324  			if err != nil {
   325  				t.Errorf("failed to open %s: %s", layer.filename, err)
   326  				continue
   327  			}
   328  		} else if layer.options != nil {
   329  			fh = sizedTar(*layer.options)
   330  		} else {
   331  			// What else is there to test?
   332  			t.Errorf("what to do with %#v", layer)
   333  			continue
   334  		}
   335  		if file, ok := fh.(*os.File); ok {
   336  			defer file.Close()
   337  		}
   338  
   339  		var ts TarSum
   340  		if layer.hash == nil {
   341  			//                           double negatives!
   342  			ts, err = NewTarSum(fh, !layer.gzip, layer.version)
   343  		} else {
   344  			ts, err = NewTarSumHash(fh, !layer.gzip, layer.version, layer.hash)
   345  		}
   346  		if err != nil {
   347  			t.Errorf("%q :: %q", err, layer.filename)
   348  			continue
   349  		}
   350  
   351  		// Read variable number of bytes to test dynamic buffer
   352  		dBuf := make([]byte, 1)
   353  		_, err = ts.Read(dBuf)
   354  		if err != nil {
   355  			t.Errorf("failed to read 1B from %s: %s", layer.filename, err)
   356  			continue
   357  		}
   358  		dBuf = make([]byte, 16*1024)
   359  		_, err = ts.Read(dBuf)
   360  		if err != nil {
   361  			t.Errorf("failed to read 16KB from %s: %s", layer.filename, err)
   362  			continue
   363  		}
   364  
   365  		// Read and discard remaining bytes
   366  		_, err = io.Copy(io.Discard, ts)
   367  		if err != nil {
   368  			t.Errorf("failed to copy from %s: %s", layer.filename, err)
   369  			continue
   370  		}
   371  		var gotSum string
   372  		if len(layer.jsonfile) > 0 {
   373  			jfh, err := os.Open(layer.jsonfile)
   374  			if err != nil {
   375  				t.Errorf("failed to open %s: %s", layer.jsonfile, err)
   376  				continue
   377  			}
   378  			defer jfh.Close()
   379  
   380  			buf, err := io.ReadAll(jfh)
   381  			if err != nil {
   382  				t.Errorf("failed to readAll %s: %s", layer.jsonfile, err)
   383  				continue
   384  			}
   385  			gotSum = ts.Sum(buf)
   386  		} else {
   387  			gotSum = ts.Sum(nil)
   388  		}
   389  
   390  		if layer.tarsum != gotSum {
   391  			t.Errorf("expecting [%s], but got [%s]", layer.tarsum, gotSum)
   392  		}
   393  		var expectedHashName string
   394  		if layer.hash != nil {
   395  			expectedHashName = layer.hash.Name()
   396  		} else {
   397  			expectedHashName = DefaultTHash.Name()
   398  		}
   399  		if expectedHashName != ts.Hash().Name() {
   400  			t.Errorf("expecting hash [%v], but got [%s]", expectedHashName, ts.Hash().Name())
   401  		}
   402  	}
   403  }
   404  
   405  func TestIteration(t *testing.T) {
   406  	headerTests := []struct {
   407  		expectedSum string // TODO(vbatts) it would be nice to get individual sums of each
   408  		version     Version
   409  		hdr         *tar.Header
   410  		data        []byte
   411  	}{
   412  		{
   413  			"tarsum+sha256:626c4a2e9a467d65c33ae81f7f3dedd4de8ccaee72af73223c4bc4718cbc7bbd",
   414  			Version0,
   415  			&tar.Header{
   416  				Name:     "file.txt",
   417  				Size:     0,
   418  				Typeflag: tar.TypeReg,
   419  				Devminor: 0,
   420  				Devmajor: 0,
   421  			},
   422  			[]byte(""),
   423  		},
   424  		{
   425  			"tarsum.dev+sha256:6ffd43a1573a9913325b4918e124ee982a99c0f3cba90fc032a65f5e20bdd465",
   426  			VersionDev,
   427  			&tar.Header{
   428  				Name:     "file.txt",
   429  				Size:     0,
   430  				Typeflag: tar.TypeReg,
   431  				Devminor: 0,
   432  				Devmajor: 0,
   433  			},
   434  			[]byte(""),
   435  		},
   436  		{
   437  			"tarsum.dev+sha256:862964db95e0fa7e42836ae4caab3576ab1df8d275720a45bdd01a5a3730cc63",
   438  			VersionDev,
   439  			&tar.Header{
   440  				Name:     "another.txt",
   441  				Uid:      1000,
   442  				Gid:      1000,
   443  				Uname:    "slartibartfast",
   444  				Gname:    "users",
   445  				Size:     4,
   446  				Typeflag: tar.TypeReg,
   447  				Devminor: 0,
   448  				Devmajor: 0,
   449  			},
   450  			[]byte("test"),
   451  		},
   452  		{
   453  			"tarsum.dev+sha256:4b1ba03544b49d96a32bacc77f8113220bd2f6a77e7e6d1e7b33cd87117d88e7",
   454  			VersionDev,
   455  			&tar.Header{
   456  				Name:     "xattrs.txt",
   457  				Uid:      1000,
   458  				Gid:      1000,
   459  				Uname:    "slartibartfast",
   460  				Gname:    "users",
   461  				Size:     4,
   462  				Typeflag: tar.TypeReg,
   463  				Xattrs: map[string]string{
   464  					"user.key1": "value1",
   465  					"user.key2": "value2",
   466  				},
   467  			},
   468  			[]byte("test"),
   469  		},
   470  		{
   471  			"tarsum.dev+sha256:410b602c898bd4e82e800050f89848fc2cf20fd52aa59c1ce29df76b878b84a6",
   472  			VersionDev,
   473  			&tar.Header{
   474  				Name:     "xattrs.txt",
   475  				Uid:      1000,
   476  				Gid:      1000,
   477  				Uname:    "slartibartfast",
   478  				Gname:    "users",
   479  				Size:     4,
   480  				Typeflag: tar.TypeReg,
   481  				Xattrs: map[string]string{
   482  					"user.KEY1": "value1", // adding different case to ensure different sum
   483  					"user.key2": "value2",
   484  				},
   485  			},
   486  			[]byte("test"),
   487  		},
   488  		{
   489  			"tarsum+sha256:b1f97eab73abd7593c245e51070f9fbdb1824c6b00a0b7a3d7f0015cd05e9e86",
   490  			Version0,
   491  			&tar.Header{
   492  				Name:     "xattrs.txt",
   493  				Uid:      1000,
   494  				Gid:      1000,
   495  				Uname:    "slartibartfast",
   496  				Gname:    "users",
   497  				Size:     4,
   498  				Typeflag: tar.TypeReg,
   499  				Xattrs: map[string]string{
   500  					"user.NOT": "CALCULATED",
   501  				},
   502  			},
   503  			[]byte("test"),
   504  		},
   505  	}
   506  	for _, htest := range headerTests {
   507  		s, err := renderSumForHeader(htest.version, htest.hdr, htest.data)
   508  		if err != nil {
   509  			t.Fatal(err)
   510  		}
   511  
   512  		if s != htest.expectedSum {
   513  			t.Errorf("expected sum: %q, got: %q", htest.expectedSum, s)
   514  		}
   515  	}
   516  }
   517  
   518  func renderSumForHeader(v Version, h *tar.Header, data []byte) (string, error) {
   519  	buf := bytes.NewBuffer(nil)
   520  	// first build our test tar
   521  	tw := tar.NewWriter(buf)
   522  	if err := tw.WriteHeader(h); err != nil {
   523  		return "", err
   524  	}
   525  	if _, err := tw.Write(data); err != nil {
   526  		return "", err
   527  	}
   528  	tw.Close()
   529  
   530  	ts, err := NewTarSum(buf, true, v)
   531  	if err != nil {
   532  		return "", err
   533  	}
   534  	tr := tar.NewReader(ts)
   535  	for {
   536  		hdr, err := tr.Next()
   537  		if hdr == nil || err == io.EOF {
   538  			// Signals the end of the archive.
   539  			break
   540  		}
   541  		if err != nil {
   542  			return "", err
   543  		}
   544  		if _, err = io.Copy(io.Discard, tr); err != nil {
   545  			return "", err
   546  		}
   547  	}
   548  	return ts.Sum(nil), nil
   549  }
   550  
   551  func Benchmark9kTar(b *testing.B) {
   552  	buf := bytes.NewBuffer([]byte{})
   553  	fh, err := os.Open("testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar")
   554  	if err != nil {
   555  		b.Error(err)
   556  		return
   557  	}
   558  	defer fh.Close()
   559  
   560  	n, err := io.Copy(buf, fh)
   561  	if err != nil {
   562  		b.Error(err)
   563  		return
   564  	}
   565  
   566  	reader := bytes.NewReader(buf.Bytes())
   567  
   568  	b.SetBytes(n)
   569  	b.ResetTimer()
   570  	for i := 0; i < b.N; i++ {
   571  		reader.Seek(0, 0)
   572  		ts, err := NewTarSum(reader, true, Version0)
   573  		if err != nil {
   574  			b.Error(err)
   575  			return
   576  		}
   577  		io.Copy(io.Discard, ts)
   578  		ts.Sum(nil)
   579  	}
   580  }
   581  
   582  func Benchmark9kTarGzip(b *testing.B) {
   583  	buf := bytes.NewBuffer([]byte{})
   584  	fh, err := os.Open("testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar")
   585  	if err != nil {
   586  		b.Error(err)
   587  		return
   588  	}
   589  	defer fh.Close()
   590  
   591  	n, err := io.Copy(buf, fh)
   592  	if err != nil {
   593  		b.Error(err)
   594  		return
   595  	}
   596  
   597  	reader := bytes.NewReader(buf.Bytes())
   598  
   599  	b.SetBytes(n)
   600  	b.ResetTimer()
   601  	for i := 0; i < b.N; i++ {
   602  		reader.Seek(0, 0)
   603  		ts, err := NewTarSum(reader, false, Version0)
   604  		if err != nil {
   605  			b.Error(err)
   606  			return
   607  		}
   608  		io.Copy(io.Discard, ts)
   609  		ts.Sum(nil)
   610  	}
   611  }
   612  
   613  // this is a single big file in the tar archive
   614  func Benchmark1mbSingleFileTar(b *testing.B) {
   615  	benchmarkTar(b, sizedOptions{1, 1024 * 1024, true, true}, false)
   616  }
   617  
   618  // this is a single big file in the tar archive
   619  func Benchmark1mbSingleFileTarGzip(b *testing.B) {
   620  	benchmarkTar(b, sizedOptions{1, 1024 * 1024, true, true}, true)
   621  }
   622  
   623  // this is 1024 1k files in the tar archive
   624  func Benchmark1kFilesTar(b *testing.B) {
   625  	benchmarkTar(b, sizedOptions{1024, 1024, true, true}, false)
   626  }
   627  
   628  // this is 1024 1k files in the tar archive
   629  func Benchmark1kFilesTarGzip(b *testing.B) {
   630  	benchmarkTar(b, sizedOptions{1024, 1024, true, true}, true)
   631  }
   632  
   633  func benchmarkTar(b *testing.B, opts sizedOptions, isGzip bool) {
   634  	var fh *os.File
   635  	tarReader := sizedTar(opts)
   636  	if br, ok := tarReader.(*os.File); ok {
   637  		fh = br
   638  	}
   639  	defer os.Remove(fh.Name())
   640  	defer fh.Close()
   641  
   642  	b.SetBytes(opts.size * opts.num)
   643  	b.ResetTimer()
   644  	for i := 0; i < b.N; i++ {
   645  		ts, err := NewTarSum(fh, !isGzip, Version0)
   646  		if err != nil {
   647  			b.Error(err)
   648  			return
   649  		}
   650  		io.Copy(io.Discard, ts)
   651  		ts.Sum(nil)
   652  		fh.Seek(0, 0)
   653  	}
   654  }