1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
20 type writerTestEntry
struct {
25 type writerTest
struct {
26 file
string // filename of expected output
27 entries
[]*writerTestEntry
30 var writerTests
= []*writerTest
{
31 // The writer test file was produced with this command:
33 // ln -s small.txt link.txt
34 // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
36 file
: "testdata/writer.tar",
37 entries
: []*writerTestEntry
{
45 ModTime
: time
.Unix(1246508266, 0),
59 ModTime
: time
.Unix(1245217492, 0),
64 contents
: "Google.com\n",
73 ModTime
: time
.Unix(1314603082, 0),
75 Linkname
: "small.txt",
83 // The truncated test file was produced using these commands:
84 // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
85 // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
87 file
: "testdata/writer-big.tar",
88 entries
: []*writerTestEntry
{
91 Name
: "tmp/16gig.txt",
96 ModTime
: time
.Unix(1254699560, 0),
102 contents
: strings
.Repeat("\x00", 4<<10),
106 // The truncated test file was produced using these commands:
107 // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
108 // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
110 file
: "testdata/writer-big-long.tar",
111 entries
: []*writerTestEntry
{
114 Name
: strings
.Repeat("longname/", 15) + "16gig.txt",
119 ModTime
: time
.Unix(1399583047, 0),
125 contents
: strings
.Repeat("\x00", 4<<10),
129 // This file was produced using gnu tar 1.17
130 // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
132 file
: "testdata/ustar.tar",
133 entries
: []*writerTestEntry
{
136 Name
: strings
.Repeat("longname/", 15) + "file.txt",
141 ModTime
: time
.Unix(1360135598, 0),
152 // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
153 func bytestr(offset
int, b
[]byte) string {
155 s
:= fmt
.Sprintf("%04x ", offset
)
156 for _
, ch
:= range b
{
158 case '0' <= ch
&& ch
<= '9', 'A' <= ch
&& ch
<= 'Z', 'a' <= ch
&& ch
<= 'z':
159 s
+= fmt
.Sprintf(" %c", ch
)
161 s
+= fmt
.Sprintf(" %02x", ch
)
167 // Render a pseudo-diff between two blocks of bytes.
168 func bytediff(a
[]byte, b
[]byte) string {
170 s
:= fmt
.Sprintf("(%d bytes vs. %d bytes)\n", len(a
), len(b
))
171 for offset
:= 0; len(a
)+len(b
) > 0; offset
+= rowLen
{
172 na
, nb
:= rowLen
, rowLen
179 sa
:= bytestr(offset
, a
[0:na
])
180 sb
:= bytestr(offset
, b
[0:nb
])
182 s
+= fmt
.Sprintf("-%v\n+%v\n", sa
, sb
)
190 func TestWriter(t
*testing
.T
) {
192 for i
, test
:= range writerTests
{
193 expected
, err
:= ioutil
.ReadFile(test
.file
)
195 t
.Errorf("test %d: Unexpected error: %v", i
, err
)
199 buf
:= new(bytes
.Buffer
)
200 tw
:= NewWriter(iotest
.TruncateWriter(buf
, 4<<10)) // only catch the first 4 KB
202 for j
, entry
:= range test
.entries
{
203 big
= big || entry
.header
.Size
> 1<<10
204 if err
:= tw
.WriteHeader(entry
.header
); err
!= nil {
205 t
.Errorf("test %d, entry %d: Failed writing header: %v", i
, j
, err
)
208 if _
, err
:= io
.WriteString(tw
, entry
.contents
); err
!= nil {
209 t
.Errorf("test %d, entry %d: Failed writing contents: %v", i
, j
, err
)
213 // Only interested in Close failures for the small tests.
214 if err
:= tw
.Close(); err
!= nil && !big
{
215 t
.Errorf("test %d: Failed closing archive: %v", i
, err
)
219 actual
:= buf
.Bytes()
220 if !bytes
.Equal(expected
, actual
) {
221 t
.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
222 i
, bytediff(expected
, actual
))
224 if testing
.Short() { // The second test is expensive.
230 func TestPax(t
*testing
.T
) {
231 // Create an archive with a large name
232 fileinfo
, err
:= os
.Stat("testdata/small.txt")
236 hdr
, err
:= FileInfoHeader(fileinfo
, "")
238 t
.Fatalf("os.Stat: %v", err
)
240 // Force a PAX long name to be written
241 longName
:= strings
.Repeat("ab", 100)
242 contents
:= strings
.Repeat(" ", int(hdr
.Size
))
245 writer
:= NewWriter(&buf
)
246 if err
:= writer
.WriteHeader(hdr
); err
!= nil {
249 if _
, err
= writer
.Write([]byte(contents
)); err
!= nil {
252 if err
:= writer
.Close(); err
!= nil {
255 // Simple test to make sure PAX extensions are in effect
256 if !bytes
.Contains(buf
.Bytes(), []byte("PaxHeaders.")) {
257 t
.Fatal("Expected at least one PAX header to be written.")
259 // Test that we can get a long name back out of the archive.
260 reader
:= NewReader(&buf
)
261 hdr
, err
= reader
.Next()
265 if hdr
.Name
!= longName
{
266 t
.Fatal("Couldn't recover long file name")
270 func TestPaxSymlink(t
*testing
.T
) {
271 // Create an archive with a large linkname
272 fileinfo
, err
:= os
.Stat("testdata/small.txt")
276 hdr
, err
:= FileInfoHeader(fileinfo
, "")
277 hdr
.Typeflag
= TypeSymlink
279 t
.Fatalf("os.Stat:1 %v", err
)
281 // Force a PAX long linkname to be written
282 longLinkname
:= strings
.Repeat("1234567890/1234567890", 10)
283 hdr
.Linkname
= longLinkname
287 writer
:= NewWriter(&buf
)
288 if err
:= writer
.WriteHeader(hdr
); err
!= nil {
291 if err
:= writer
.Close(); err
!= nil {
294 // Simple test to make sure PAX extensions are in effect
295 if !bytes
.Contains(buf
.Bytes(), []byte("PaxHeaders.")) {
296 t
.Fatal("Expected at least one PAX header to be written.")
298 // Test that we can get a long name back out of the archive.
299 reader
:= NewReader(&buf
)
300 hdr
, err
= reader
.Next()
304 if hdr
.Linkname
!= longLinkname
{
305 t
.Fatal("Couldn't recover long link name")
309 func TestPaxNonAscii(t
*testing
.T
) {
310 // Create an archive with non ascii. These should trigger a pax header
311 // because pax headers have a defined utf-8 encoding.
312 fileinfo
, err
:= os
.Stat("testdata/small.txt")
317 hdr
, err
:= FileInfoHeader(fileinfo
, "")
319 t
.Fatalf("os.Stat:1 %v", err
)
323 chineseFilename
:= "文件名"
324 chineseGroupname
:= "組"
325 chineseUsername
:= "用戶名"
327 hdr
.Name
= chineseFilename
328 hdr
.Gname
= chineseGroupname
329 hdr
.Uname
= chineseUsername
331 contents
:= strings
.Repeat(" ", int(hdr
.Size
))
334 writer
:= NewWriter(&buf
)
335 if err
:= writer
.WriteHeader(hdr
); err
!= nil {
338 if _
, err
= writer
.Write([]byte(contents
)); err
!= nil {
341 if err
:= writer
.Close(); err
!= nil {
344 // Simple test to make sure PAX extensions are in effect
345 if !bytes
.Contains(buf
.Bytes(), []byte("PaxHeaders.")) {
346 t
.Fatal("Expected at least one PAX header to be written.")
348 // Test that we can get a long name back out of the archive.
349 reader
:= NewReader(&buf
)
350 hdr
, err
= reader
.Next()
354 if hdr
.Name
!= chineseFilename
{
355 t
.Fatal("Couldn't recover unicode name")
357 if hdr
.Gname
!= chineseGroupname
{
358 t
.Fatal("Couldn't recover unicode group")
360 if hdr
.Uname
!= chineseUsername
{
361 t
.Fatal("Couldn't recover unicode user")
365 func TestPaxXattrs(t
*testing
.T
) {
366 xattrs
:= map[string]string{
370 // Create an archive with an xattr
371 fileinfo
, err
:= os
.Stat("testdata/small.txt")
375 hdr
, err
:= FileInfoHeader(fileinfo
, "")
377 t
.Fatalf("os.Stat: %v", err
)
382 writer
:= NewWriter(&buf
)
383 if err
:= writer
.WriteHeader(hdr
); err
!= nil {
386 if _
, err
= writer
.Write([]byte(contents
)); err
!= nil {
389 if err
:= writer
.Close(); err
!= nil {
392 // Test that we can get the xattrs back out of the archive.
393 reader
:= NewReader(&buf
)
394 hdr
, err
= reader
.Next()
398 if !reflect
.DeepEqual(hdr
.Xattrs
, xattrs
) {
399 t
.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
404 func TestPAXHeader(t
*testing
.T
) {
405 medName
:= strings
.Repeat("CD", 50)
406 longName
:= strings
.Repeat("AB", 100)
407 paxTests
:= [][2]string{
408 {paxPath
+ "=/etc/hosts", "19 path=/etc/hosts\n"},
409 {"a=b", "6 a=b\n"}, // Single digit length
410 {"a=names", "11 a=names\n"}, // Test case involving carries
411 {paxPath
+ "=" + longName
, fmt
.Sprintf("210 path=%s\n", longName
)},
412 {paxPath
+ "=" + medName
, fmt
.Sprintf("110 path=%s\n", medName
)}}
414 for _
, test
:= range paxTests
{
415 key
, expected
:= test
[0], test
[1]
416 if result
:= paxHeader(key
); result
!= expected
{
417 t
.Fatalf("paxHeader: got %s, expected %s", result
, expected
)
422 func TestUSTARLongName(t
*testing
.T
) {
423 // Create an archive with a path that failed to split with USTAR extension in previous versions.
424 fileinfo
, err
:= os
.Stat("testdata/small.txt")
428 hdr
, err
:= FileInfoHeader(fileinfo
, "")
429 hdr
.Typeflag
= TypeDir
431 t
.Fatalf("os.Stat:1 %v", err
)
433 // Force a PAX long name to be written. The name was taken from a practical example
434 // that fails and replaced ever char through numbers to anonymize the sample.
435 longName
:= "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"
440 writer
:= NewWriter(&buf
)
441 if err
:= writer
.WriteHeader(hdr
); err
!= nil {
444 if err
:= writer
.Close(); err
!= nil {
447 // Test that we can get a long name back out of the archive.
448 reader
:= NewReader(&buf
)
449 hdr
, err
= reader
.Next()
453 if hdr
.Name
!= longName
{
454 t
.Fatal("Couldn't recover long name")