Browse code

Correct tarsum finish logic

Tarsum now correctly closes the internal TarWriter which appends
a block of 1024 zeros to the end of the returned archive.

Signed-off-by: Josh Hawn <josh.hawn@docker.com>

Josh Hawn authored on 2014/09/16 15:52:06
Showing 2 changed files
... ...
@@ -148,6 +148,12 @@ func (ts *tarSum) Read(buf []byte) (int, error) {
148 148
 			currentHeader, err := ts.tarR.Next()
149 149
 			if err != nil {
150 150
 				if err == io.EOF {
151
+					if err := ts.tarW.Close(); err != nil {
152
+						return 0, err
153
+					}
154
+					if _, err := io.Copy(ts.gz, ts.bufTar); err != nil {
155
+						return 0, err
156
+					}
151 157
 					if err := ts.gz.Close(); err != nil {
152 158
 						return 0, err
153 159
 					}
... ...
@@ -2,7 +2,10 @@ package tarsum
2 2
 
3 3
 import (
4 4
 	"bytes"
5
+	"compress/gzip"
5 6
 	"crypto/rand"
7
+	"crypto/sha256"
8
+	"encoding/hex"
6 9
 	"fmt"
7 10
 	"io"
8 11
 	"io/ioutil"
... ...
@@ -101,6 +104,77 @@ func sizedTar(opts sizedOptions) io.Reader {
101 101
 	return fh
102 102
 }
103 103
 
104
+func emptyTarSum(gzip bool) (TarSum, error) {
105
+	reader, writer := io.Pipe()
106
+	tarWriter := tar.NewWriter(writer)
107
+
108
+	// Immediately close tarWriter and write-end of the
109
+	// Pipe in a separate goroutine so we don't block.
110
+	go func() {
111
+		tarWriter.Close()
112
+		writer.Close()
113
+	}()
114
+
115
+	return NewTarSum(reader, !gzip, Version0)
116
+}
117
+
118
+// TestEmptyTar tests that tarsum does not fail to read an empty tar
119
+// and correctly returns the hex digest of an empty hash.
120
+func TestEmptyTar(t *testing.T) {
121
+	// Test without gzip.
122
+	ts, err := emptyTarSum(false)
123
+	if err != nil {
124
+		t.Fatal(err)
125
+	}
126
+
127
+	zeroBlock := make([]byte, 1024)
128
+	buf := new(bytes.Buffer)
129
+
130
+	n, err := io.Copy(buf, ts)
131
+	if err != nil {
132
+		t.Fatal(err)
133
+	}
134
+
135
+	if n != int64(len(zeroBlock)) || !bytes.Equal(buf.Bytes(), zeroBlock) {
136
+		t.Fatalf("tarSum did not write the correct number of zeroed bytes: %d", n)
137
+	}
138
+
139
+	expectedSum := ts.Version().String() + "+sha256:" + hex.EncodeToString(sha256.New().Sum(nil))
140
+	resultSum := ts.Sum(nil)
141
+
142
+	if resultSum != expectedSum {
143
+		t.Fatalf("expected [%s] but got [%s]", expectedSum, resultSum)
144
+	}
145
+
146
+	// Test with gzip.
147
+	ts, err = emptyTarSum(true)
148
+	if err != nil {
149
+		t.Fatal(err)
150
+	}
151
+	buf.Reset()
152
+
153
+	n, err = io.Copy(buf, ts)
154
+	if err != nil {
155
+		t.Fatal(err)
156
+	}
157
+
158
+	bufgz := new(bytes.Buffer)
159
+	gz := gzip.NewWriter(bufgz)
160
+	n, err = io.Copy(gz, bytes.NewBuffer(zeroBlock))
161
+	gz.Close()
162
+	gzBytes := bufgz.Bytes()
163
+
164
+	if n != int64(len(zeroBlock)) || !bytes.Equal(buf.Bytes(), gzBytes) {
165
+		t.Fatalf("tarSum did not write the correct number of gzipped-zeroed bytes: %d", n)
166
+	}
167
+
168
+	resultSum = ts.Sum(nil)
169
+
170
+	if resultSum != expectedSum {
171
+		t.Fatalf("expected [%s] but got [%s]", expectedSum, resultSum)
172
+	}
173
+}
174
+
104 175
 func TestTarSums(t *testing.T) {
105 176
 	for _, layer := range testLayers {
106 177
 		var (