Home | History | Annotate | Download | only in tar
      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.
      4 
      5 package tar
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"io"
     11 	"io/ioutil"
     12 	"os"
     13 	"reflect"
     14 	"sort"
     15 	"strings"
     16 	"testing"
     17 	"testing/iotest"
     18 	"time"
     19 )
     20 
     21 // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
     22 func bytestr(offset int, b []byte) string {
     23 	const rowLen = 32
     24 	s := fmt.Sprintf("%04x ", offset)
     25 	for _, ch := range b {
     26 		switch {
     27 		case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z':
     28 			s += fmt.Sprintf("  %c", ch)
     29 		default:
     30 			s += fmt.Sprintf(" %02x", ch)
     31 		}
     32 	}
     33 	return s
     34 }
     35 
     36 // Render a pseudo-diff between two blocks of bytes.
     37 func bytediff(a []byte, b []byte) string {
     38 	const rowLen = 32
     39 	s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b))
     40 	for offset := 0; len(a)+len(b) > 0; offset += rowLen {
     41 		na, nb := rowLen, rowLen
     42 		if na > len(a) {
     43 			na = len(a)
     44 		}
     45 		if nb > len(b) {
     46 			nb = len(b)
     47 		}
     48 		sa := bytestr(offset, a[0:na])
     49 		sb := bytestr(offset, b[0:nb])
     50 		if sa != sb {
     51 			s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
     52 		}
     53 		a = a[na:]
     54 		b = b[nb:]
     55 	}
     56 	return s
     57 }
     58 
     59 func TestWriter(t *testing.T) {
     60 	type entry struct {
     61 		header   *Header
     62 		contents string
     63 	}
     64 
     65 	vectors := []struct {
     66 		file    string // filename of expected output
     67 		entries []*entry
     68 	}{{
     69 		// The writer test file was produced with this command:
     70 		// tar (GNU tar) 1.26
     71 		//   ln -s small.txt link.txt
     72 		//   tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
     73 		file: "testdata/writer.tar",
     74 		entries: []*entry{{
     75 			header: &Header{
     76 				Name:     "small.txt",
     77 				Mode:     0640,
     78 				Uid:      73025,
     79 				Gid:      5000,
     80 				Size:     5,
     81 				ModTime:  time.Unix(1246508266, 0),
     82 				Typeflag: '0',
     83 				Uname:    "dsymonds",
     84 				Gname:    "eng",
     85 			},
     86 			contents: "Kilts",
     87 		}, {
     88 			header: &Header{
     89 				Name:     "small2.txt",
     90 				Mode:     0640,
     91 				Uid:      73025,
     92 				Gid:      5000,
     93 				Size:     11,
     94 				ModTime:  time.Unix(1245217492, 0),
     95 				Typeflag: '0',
     96 				Uname:    "dsymonds",
     97 				Gname:    "eng",
     98 			},
     99 			contents: "Google.com\n",
    100 		}, {
    101 			header: &Header{
    102 				Name:     "link.txt",
    103 				Mode:     0777,
    104 				Uid:      1000,
    105 				Gid:      1000,
    106 				Size:     0,
    107 				ModTime:  time.Unix(1314603082, 0),
    108 				Typeflag: '2',
    109 				Linkname: "small.txt",
    110 				Uname:    "strings",
    111 				Gname:    "strings",
    112 			},
    113 			// no contents
    114 		}},
    115 	}, {
    116 		// The truncated test file was produced using these commands:
    117 		//   dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
    118 		//   tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
    119 		file: "testdata/writer-big.tar",
    120 		entries: []*entry{{
    121 			header: &Header{
    122 				Name:     "tmp/16gig.txt",
    123 				Mode:     0640,
    124 				Uid:      73025,
    125 				Gid:      5000,
    126 				Size:     16 << 30,
    127 				ModTime:  time.Unix(1254699560, 0),
    128 				Typeflag: '0',
    129 				Uname:    "dsymonds",
    130 				Gname:    "eng",
    131 			},
    132 			// fake contents
    133 			contents: strings.Repeat("\x00", 4<<10),
    134 		}},
    135 	}, {
    136 		// This truncated file was produced using this library.
    137 		// It was verified to work with GNU tar 1.27.1 and BSD tar 3.1.2.
    138 		//  dd if=/dev/zero bs=1G count=16 >> writer-big-long.tar
    139 		//  gnutar -xvf writer-big-long.tar
    140 		//  bsdtar -xvf writer-big-long.tar
    141 		//
    142 		// This file is in PAX format.
    143 		file: "testdata/writer-big-long.tar",
    144 		entries: []*entry{{
    145 			header: &Header{
    146 				Name:     strings.Repeat("longname/", 15) + "16gig.txt",
    147 				Mode:     0644,
    148 				Uid:      1000,
    149 				Gid:      1000,
    150 				Size:     16 << 30,
    151 				ModTime:  time.Unix(1399583047, 0),
    152 				Typeflag: '0',
    153 				Uname:    "guillaume",
    154 				Gname:    "guillaume",
    155 			},
    156 			// fake contents
    157 			contents: strings.Repeat("\x00", 4<<10),
    158 		}},
    159 	}, {
    160 		// TODO(dsnet): The Writer output should match the following file.
    161 		// To fix an issue (see https://golang.org/issue/12594), we disabled
    162 		// prefix support, which alters the generated output.
    163 		/*
    164 			// This file was produced using gnu tar 1.17
    165 			// gnutar  -b 4 --format=ustar (longname/)*15 + file.txt
    166 			file: "testdata/ustar.tar"
    167 		*/
    168 		file: "testdata/ustar.issue12594.tar", // This is a valid tar file, but not expected
    169 		entries: []*entry{{
    170 			header: &Header{
    171 				Name:     strings.Repeat("longname/", 15) + "file.txt",
    172 				Mode:     0644,
    173 				Uid:      0765,
    174 				Gid:      024,
    175 				Size:     06,
    176 				ModTime:  time.Unix(1360135598, 0),
    177 				Typeflag: '0',
    178 				Uname:    "shane",
    179 				Gname:    "staff",
    180 			},
    181 			contents: "hello\n",
    182 		}},
    183 	}, {
    184 		// This file was produced using gnu tar 1.26
    185 		// echo "Slartibartfast" > file.txt
    186 		// ln file.txt hard.txt
    187 		// tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
    188 		file: "testdata/hardlink.tar",
    189 		entries: []*entry{{
    190 			header: &Header{
    191 				Name:     "file.txt",
    192 				Mode:     0644,
    193 				Uid:      1000,
    194 				Gid:      100,
    195 				Size:     15,
    196 				ModTime:  time.Unix(1425484303, 0),
    197 				Typeflag: '0',
    198 				Uname:    "vbatts",
    199 				Gname:    "users",
    200 			},
    201 			contents: "Slartibartfast\n",
    202 		}, {
    203 			header: &Header{
    204 				Name:     "hard.txt",
    205 				Mode:     0644,
    206 				Uid:      1000,
    207 				Gid:      100,
    208 				Size:     0,
    209 				ModTime:  time.Unix(1425484303, 0),
    210 				Typeflag: '1',
    211 				Linkname: "file.txt",
    212 				Uname:    "vbatts",
    213 				Gname:    "users",
    214 			},
    215 			// no contents
    216 		}},
    217 	}}
    218 
    219 testLoop:
    220 	for i, v := range vectors {
    221 		expected, err := ioutil.ReadFile(v.file)
    222 		if err != nil {
    223 			t.Errorf("test %d: Unexpected error: %v", i, err)
    224 			continue
    225 		}
    226 
    227 		buf := new(bytes.Buffer)
    228 		tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
    229 		big := false
    230 		for j, entry := range v.entries {
    231 			big = big || entry.header.Size > 1<<10
    232 			if err := tw.WriteHeader(entry.header); err != nil {
    233 				t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
    234 				continue testLoop
    235 			}
    236 			if _, err := io.WriteString(tw, entry.contents); err != nil {
    237 				t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err)
    238 				continue testLoop
    239 			}
    240 		}
    241 		// Only interested in Close failures for the small tests.
    242 		if err := tw.Close(); err != nil && !big {
    243 			t.Errorf("test %d: Failed closing archive: %v", i, err)
    244 			continue testLoop
    245 		}
    246 
    247 		actual := buf.Bytes()
    248 		if !bytes.Equal(expected, actual) {
    249 			t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
    250 				i, bytediff(expected, actual))
    251 		}
    252 		if testing.Short() { // The second test is expensive.
    253 			break
    254 		}
    255 	}
    256 }
    257 
    258 func TestPax(t *testing.T) {
    259 	// Create an archive with a large name
    260 	fileinfo, err := os.Stat("testdata/small.txt")
    261 	if err != nil {
    262 		t.Fatal(err)
    263 	}
    264 	hdr, err := FileInfoHeader(fileinfo, "")
    265 	if err != nil {
    266 		t.Fatalf("os.Stat: %v", err)
    267 	}
    268 	// Force a PAX long name to be written
    269 	longName := strings.Repeat("ab", 100)
    270 	contents := strings.Repeat(" ", int(hdr.Size))
    271 	hdr.Name = longName
    272 	var buf bytes.Buffer
    273 	writer := NewWriter(&buf)
    274 	if err := writer.WriteHeader(hdr); err != nil {
    275 		t.Fatal(err)
    276 	}
    277 	if _, err = writer.Write([]byte(contents)); err != nil {
    278 		t.Fatal(err)
    279 	}
    280 	if err := writer.Close(); err != nil {
    281 		t.Fatal(err)
    282 	}
    283 	// Simple test to make sure PAX extensions are in effect
    284 	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
    285 		t.Fatal("Expected at least one PAX header to be written.")
    286 	}
    287 	// Test that we can get a long name back out of the archive.
    288 	reader := NewReader(&buf)
    289 	hdr, err = reader.Next()
    290 	if err != nil {
    291 		t.Fatal(err)
    292 	}
    293 	if hdr.Name != longName {
    294 		t.Fatal("Couldn't recover long file name")
    295 	}
    296 }
    297 
    298 func TestPaxSymlink(t *testing.T) {
    299 	// Create an archive with a large linkname
    300 	fileinfo, err := os.Stat("testdata/small.txt")
    301 	if err != nil {
    302 		t.Fatal(err)
    303 	}
    304 	hdr, err := FileInfoHeader(fileinfo, "")
    305 	hdr.Typeflag = TypeSymlink
    306 	if err != nil {
    307 		t.Fatalf("os.Stat:1 %v", err)
    308 	}
    309 	// Force a PAX long linkname to be written
    310 	longLinkname := strings.Repeat("1234567890/1234567890", 10)
    311 	hdr.Linkname = longLinkname
    312 
    313 	hdr.Size = 0
    314 	var buf bytes.Buffer
    315 	writer := NewWriter(&buf)
    316 	if err := writer.WriteHeader(hdr); err != nil {
    317 		t.Fatal(err)
    318 	}
    319 	if err := writer.Close(); err != nil {
    320 		t.Fatal(err)
    321 	}
    322 	// Simple test to make sure PAX extensions are in effect
    323 	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
    324 		t.Fatal("Expected at least one PAX header to be written.")
    325 	}
    326 	// Test that we can get a long name back out of the archive.
    327 	reader := NewReader(&buf)
    328 	hdr, err = reader.Next()
    329 	if err != nil {
    330 		t.Fatal(err)
    331 	}
    332 	if hdr.Linkname != longLinkname {
    333 		t.Fatal("Couldn't recover long link name")
    334 	}
    335 }
    336 
    337 func TestPaxNonAscii(t *testing.T) {
    338 	// Create an archive with non ascii. These should trigger a pax header
    339 	// because pax headers have a defined utf-8 encoding.
    340 	fileinfo, err := os.Stat("testdata/small.txt")
    341 	if err != nil {
    342 		t.Fatal(err)
    343 	}
    344 
    345 	hdr, err := FileInfoHeader(fileinfo, "")
    346 	if err != nil {
    347 		t.Fatalf("os.Stat:1 %v", err)
    348 	}
    349 
    350 	// some sample data
    351 	chineseFilename := ""
    352 	chineseGroupname := ""
    353 	chineseUsername := ""
    354 
    355 	hdr.Name = chineseFilename
    356 	hdr.Gname = chineseGroupname
    357 	hdr.Uname = chineseUsername
    358 
    359 	contents := strings.Repeat(" ", int(hdr.Size))
    360 
    361 	var buf bytes.Buffer
    362 	writer := NewWriter(&buf)
    363 	if err := writer.WriteHeader(hdr); err != nil {
    364 		t.Fatal(err)
    365 	}
    366 	if _, err = writer.Write([]byte(contents)); err != nil {
    367 		t.Fatal(err)
    368 	}
    369 	if err := writer.Close(); err != nil {
    370 		t.Fatal(err)
    371 	}
    372 	// Simple test to make sure PAX extensions are in effect
    373 	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
    374 		t.Fatal("Expected at least one PAX header to be written.")
    375 	}
    376 	// Test that we can get a long name back out of the archive.
    377 	reader := NewReader(&buf)
    378 	hdr, err = reader.Next()
    379 	if err != nil {
    380 		t.Fatal(err)
    381 	}
    382 	if hdr.Name != chineseFilename {
    383 		t.Fatal("Couldn't recover unicode name")
    384 	}
    385 	if hdr.Gname != chineseGroupname {
    386 		t.Fatal("Couldn't recover unicode group")
    387 	}
    388 	if hdr.Uname != chineseUsername {
    389 		t.Fatal("Couldn't recover unicode user")
    390 	}
    391 }
    392 
    393 func TestPaxXattrs(t *testing.T) {
    394 	xattrs := map[string]string{
    395 		"user.key": "value",
    396 	}
    397 
    398 	// Create an archive with an xattr
    399 	fileinfo, err := os.Stat("testdata/small.txt")
    400 	if err != nil {
    401 		t.Fatal(err)
    402 	}
    403 	hdr, err := FileInfoHeader(fileinfo, "")
    404 	if err != nil {
    405 		t.Fatalf("os.Stat: %v", err)
    406 	}
    407 	contents := "Kilts"
    408 	hdr.Xattrs = xattrs
    409 	var buf bytes.Buffer
    410 	writer := NewWriter(&buf)
    411 	if err := writer.WriteHeader(hdr); err != nil {
    412 		t.Fatal(err)
    413 	}
    414 	if _, err = writer.Write([]byte(contents)); err != nil {
    415 		t.Fatal(err)
    416 	}
    417 	if err := writer.Close(); err != nil {
    418 		t.Fatal(err)
    419 	}
    420 	// Test that we can get the xattrs back out of the archive.
    421 	reader := NewReader(&buf)
    422 	hdr, err = reader.Next()
    423 	if err != nil {
    424 		t.Fatal(err)
    425 	}
    426 	if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
    427 		t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
    428 			hdr.Xattrs, xattrs)
    429 	}
    430 }
    431 
    432 func TestPaxHeadersSorted(t *testing.T) {
    433 	fileinfo, err := os.Stat("testdata/small.txt")
    434 	if err != nil {
    435 		t.Fatal(err)
    436 	}
    437 	hdr, err := FileInfoHeader(fileinfo, "")
    438 	if err != nil {
    439 		t.Fatalf("os.Stat: %v", err)
    440 	}
    441 	contents := strings.Repeat(" ", int(hdr.Size))
    442 
    443 	hdr.Xattrs = map[string]string{
    444 		"foo": "foo",
    445 		"bar": "bar",
    446 		"baz": "baz",
    447 		"qux": "qux",
    448 	}
    449 
    450 	var buf bytes.Buffer
    451 	writer := NewWriter(&buf)
    452 	if err := writer.WriteHeader(hdr); err != nil {
    453 		t.Fatal(err)
    454 	}
    455 	if _, err = writer.Write([]byte(contents)); err != nil {
    456 		t.Fatal(err)
    457 	}
    458 	if err := writer.Close(); err != nil {
    459 		t.Fatal(err)
    460 	}
    461 	// Simple test to make sure PAX extensions are in effect
    462 	if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.0")) {
    463 		t.Fatal("Expected at least one PAX header to be written.")
    464 	}
    465 
    466 	// xattr bar should always appear before others
    467 	indices := []int{
    468 		bytes.Index(buf.Bytes(), []byte("bar=bar")),
    469 		bytes.Index(buf.Bytes(), []byte("baz=baz")),
    470 		bytes.Index(buf.Bytes(), []byte("foo=foo")),
    471 		bytes.Index(buf.Bytes(), []byte("qux=qux")),
    472 	}
    473 	if !sort.IntsAreSorted(indices) {
    474 		t.Fatal("PAX headers are not sorted")
    475 	}
    476 }
    477 
    478 func TestUSTARLongName(t *testing.T) {
    479 	// Create an archive with a path that failed to split with USTAR extension in previous versions.
    480 	fileinfo, err := os.Stat("testdata/small.txt")
    481 	if err != nil {
    482 		t.Fatal(err)
    483 	}
    484 	hdr, err := FileInfoHeader(fileinfo, "")
    485 	hdr.Typeflag = TypeDir
    486 	if err != nil {
    487 		t.Fatalf("os.Stat:1 %v", err)
    488 	}
    489 	// Force a PAX long name to be written. The name was taken from a practical example
    490 	// that fails and replaced ever char through numbers to anonymize the sample.
    491 	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/"
    492 	hdr.Name = longName
    493 
    494 	hdr.Size = 0
    495 	var buf bytes.Buffer
    496 	writer := NewWriter(&buf)
    497 	if err := writer.WriteHeader(hdr); err != nil {
    498 		t.Fatal(err)
    499 	}
    500 	if err := writer.Close(); err != nil {
    501 		t.Fatal(err)
    502 	}
    503 	// Test that we can get a long name back out of the archive.
    504 	reader := NewReader(&buf)
    505 	hdr, err = reader.Next()
    506 	if err != nil {
    507 		t.Fatal(err)
    508 	}
    509 	if hdr.Name != longName {
    510 		t.Fatal("Couldn't recover long name")
    511 	}
    512 }
    513 
    514 func TestValidTypeflagWithPAXHeader(t *testing.T) {
    515 	var buffer bytes.Buffer
    516 	tw := NewWriter(&buffer)
    517 
    518 	fileName := strings.Repeat("ab", 100)
    519 
    520 	hdr := &Header{
    521 		Name:     fileName,
    522 		Size:     4,
    523 		Typeflag: 0,
    524 	}
    525 	if err := tw.WriteHeader(hdr); err != nil {
    526 		t.Fatalf("Failed to write header: %s", err)
    527 	}
    528 	if _, err := tw.Write([]byte("fooo")); err != nil {
    529 		t.Fatalf("Failed to write the file's data: %s", err)
    530 	}
    531 	tw.Close()
    532 
    533 	tr := NewReader(&buffer)
    534 
    535 	for {
    536 		header, err := tr.Next()
    537 		if err == io.EOF {
    538 			break
    539 		}
    540 		if err != nil {
    541 			t.Fatalf("Failed to read header: %s", err)
    542 		}
    543 		if header.Typeflag != 0 {
    544 			t.Fatalf("Typeflag should've been 0, found %d", header.Typeflag)
    545 		}
    546 	}
    547 }
    548 
    549 func TestWriteAfterClose(t *testing.T) {
    550 	var buffer bytes.Buffer
    551 	tw := NewWriter(&buffer)
    552 
    553 	hdr := &Header{
    554 		Name: "small.txt",
    555 		Size: 5,
    556 	}
    557 	if err := tw.WriteHeader(hdr); err != nil {
    558 		t.Fatalf("Failed to write header: %s", err)
    559 	}
    560 	tw.Close()
    561 	if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose {
    562 		t.Fatalf("Write: got %v; want ErrWriteAfterClose", err)
    563 	}
    564 }
    565 
    566 func TestSplitUSTARPath(t *testing.T) {
    567 	sr := strings.Repeat
    568 
    569 	vectors := []struct {
    570 		input  string // Input path
    571 		prefix string // Expected output prefix
    572 		suffix string // Expected output suffix
    573 		ok     bool   // Split success?
    574 	}{
    575 		{"", "", "", false},
    576 		{"abc", "", "", false},
    577 		{"", "", "", false},
    578 		{sr("a", nameSize), "", "", false},
    579 		{sr("a", nameSize) + "/", "", "", false},
    580 		{sr("a", nameSize) + "/a", sr("a", nameSize), "a", true},
    581 		{sr("a", prefixSize) + "/", "", "", false},
    582 		{sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true},
    583 		{sr("a", nameSize+1), "", "", false},
    584 		{sr("/", nameSize+1), sr("/", nameSize-1), "/", true},
    585 		{sr("a", prefixSize) + "/" + sr("b", nameSize),
    586 			sr("a", prefixSize), sr("b", nameSize), true},
    587 		{sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false},
    588 		{sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true},
    589 	}
    590 
    591 	for _, v := range vectors {
    592 		prefix, suffix, ok := splitUSTARPath(v.input)
    593 		if prefix != v.prefix || suffix != v.suffix || ok != v.ok {
    594 			t.Errorf("splitUSTARPath(%q):\ngot  (%q, %q, %v)\nwant (%q, %q, %v)",
    595 				v.input, prefix, suffix, ok, v.prefix, v.suffix, v.ok)
    596 		}
    597 	}
    598 }
    599 
    600 // TestIssue12594 tests that the Writer does not attempt to populate the prefix
    601 // field when encoding a header in the GNU format. The prefix field is valid
    602 // in USTAR and PAX, but not GNU.
    603 func TestIssue12594(t *testing.T) {
    604 	names := []string{
    605 		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/file.txt",
    606 		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/file.txt",
    607 		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/333/file.txt",
    608 		"0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/file.txt",
    609 		"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/file.txt",
    610 		"/home/support/.openoffice.org/3/user/uno_packages/cache/registry/com.sun.star.comp.deployment.executable.PackageRegistryBackend",
    611 	}
    612 
    613 	for i, name := range names {
    614 		var b bytes.Buffer
    615 
    616 		tw := NewWriter(&b)
    617 		if err := tw.WriteHeader(&Header{
    618 			Name: name,
    619 			Uid:  1 << 25, // Prevent USTAR format
    620 		}); err != nil {
    621 			t.Errorf("test %d, unexpected WriteHeader error: %v", i, err)
    622 		}
    623 		if err := tw.Close(); err != nil {
    624 			t.Errorf("test %d, unexpected Close error: %v", i, err)
    625 		}
    626 
    627 		// The prefix field should never appear in the GNU format.
    628 		var blk block
    629 		copy(blk[:], b.Bytes())
    630 		prefix := string(blk.USTAR().Prefix())
    631 		if i := strings.IndexByte(prefix, 0); i >= 0 {
    632 			prefix = prefix[:i] // Truncate at the NUL terminator
    633 		}
    634 		if blk.GetFormat() == formatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
    635 			t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
    636 		}
    637 
    638 		tr := NewReader(&b)
    639 		hdr, err := tr.Next()
    640 		if err != nil {
    641 			t.Errorf("test %d, unexpected Next error: %v", i, err)
    642 		}
    643 		if hdr.Name != name {
    644 			t.Errorf("test %d, hdr.Name = %s, want %s", i, hdr.Name, name)
    645 		}
    646 	}
    647 }
    648