github.com/freddyisaac/sicortex-golang@v0.0.0-20231019035217-e03519e66f60/src/archive/tar/writer_test.go (about)

     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  }