]> Cypherpunks repositories - gostls13.git/commitdiff
archive/tar: automatically promote TypeRegA
authorCaio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Tue, 2 Jan 2018 00:16:43 +0000 (16:16 -0800)
committerJoe Tsai <thebrokentoaster@gmail.com>
Tue, 13 Feb 2018 18:36:49 +0000 (18:36 +0000)
Change Reader to promote TypeRegA to TypeReg in headers, unless their
name have a trailing slash which is already promoted to TypeDir. This
will allow client code to handle just TypeReg instead both TypeReg and
TypeRegA.

Change Writer to promote TypeRegA to TypeReg or TypeDir in the headers
depending on whether the name has a trailing slash. This normalization
is motivated by the specification (in pax(1)):

   0 represents a regular file. For backwards-compatibility, a
   typeflag value of binary zero ( '\0' ) should be recognized as
   meaning a regular file when extracting files from the
   archive. Archives written with this version of the archive file
   format create regular files with a typeflag value of the
   ISO/IEC 646:1991 standard IRV '0'.

Fixes #22768.

Change-Id: I149ec55824580d446cdde5a0d7a0457ad7b03466
Reviewed-on: https://go-review.googlesource.com/85656
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/archive/tar/common.go
src/archive/tar/reader.go
src/archive/tar/reader_test.go
src/archive/tar/tar_test.go
src/archive/tar/testdata/file-and-dir.tar [new file with mode: 0644]
src/archive/tar/testdata/trailing-slash.tar
src/archive/tar/writer.go
src/archive/tar/writer_test.go

index 4a2c173bf3a7c669b56db744a2e1627ef4b3f402..89d1f38732b61b3f760458e1026a095a0b972d69 100644 (file)
@@ -56,7 +56,7 @@ func (he headerError) Error() string {
 const (
        // Type '0' indicates a regular file.
        TypeReg  = '0'
-       TypeRegA = '\x00' // For legacy support; use TypeReg instead
+       TypeRegA = '\x00' // Deprecated: Use TypeReg instead.
 
        // Type '1' to '6' are header-only flags and may not have a data body.
        TypeLink    = '1' // Hard link
@@ -138,7 +138,10 @@ var basicKeys = map[string]bool{
 // should do so by creating a new Header and copying the fields
 // that they are interested in preserving.
 type Header struct {
-       Typeflag byte // Type of header entry (should be TypeReg for most files)
+       // Typeflag is the type of header entry.
+       // The zero value is automatically promoted to either TypeReg or TypeDir
+       // depending on the presence of a trailing slash in Name.
+       Typeflag byte
 
        Name     string // Name of file entry
        Linkname string // Target name of link (valid for TypeLink or TypeSymlink)
index f4eeb557be9805a112bb56eeb1fc14904ce178cd..6025e82b1b266995a318270f12747bf340d92b74 100644 (file)
@@ -131,8 +131,12 @@ loop:
                        if gnuLongLink != "" {
                                hdr.Linkname = gnuLongLink
                        }
-                       if hdr.Typeflag == TypeRegA && strings.HasSuffix(hdr.Name, "/") {
-                               hdr.Typeflag = TypeDir // Legacy archives use trailing slash for directories
+                       if hdr.Typeflag == TypeRegA {
+                               if strings.HasSuffix(hdr.Name, "/") {
+                                       hdr.Typeflag = TypeDir // Legacy archives use trailing slash for directories
+                               } else {
+                                       hdr.Typeflag = TypeReg
+                               }
                        }
 
                        // The extended headers may have updated the size.
index a6832d33b1b58575ba42dbfb602f2dab770ef992..0fc29eaab6f813a3cc9140f0678c3209957fc849 100644 (file)
@@ -189,7 +189,7 @@ func TestReader(t *testing.T) {
                        Gid:      5000,
                        Size:     5,
                        ModTime:  time.Unix(1244593104, 0),
-                       Typeflag: '\x00',
+                       Typeflag: '0',
                }, {
                        Name:     "small2.txt",
                        Mode:     0444,
@@ -197,7 +197,7 @@ func TestReader(t *testing.T) {
                        Gid:      5000,
                        Size:     11,
                        ModTime:  time.Unix(1244593104, 0),
-                       Typeflag: '\x00',
+                       Typeflag: '0',
                }},
        }, {
                file: "testdata/pax.tar",
@@ -534,9 +534,10 @@ func TestReader(t *testing.T) {
                // a buggy pre-Go1.8 tar.Writer.
                file: "testdata/invalid-go17.tar",
                headers: []*Header{{
-                       Name:    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo",
-                       Uid:     010000000,
-                       ModTime: time.Unix(0, 0),
+                       Name:     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo",
+                       Uid:      010000000,
+                       ModTime:  time.Unix(0, 0),
+                       Typeflag: '0',
                }},
        }, {
                // USTAR archive with a regular entry with non-zero device numbers.
index af80d6e0c1536a051baf9d7907b5bb7a3e84cd23..2676853122a5605d9751192357d092d43a4a0680 100644 (file)
@@ -306,6 +306,7 @@ func TestRoundTrip(t *testing.T) {
                ModTime:    time.Now().Round(time.Second),
                PAXRecords: map[string]string{"uid": "2097152"},
                Format:     FormatPAX,
+               Typeflag:   TypeReg,
        }
        if err := tw.WriteHeader(hdr); err != nil {
                t.Fatalf("tw.WriteHeader: %v", err)
diff --git a/src/archive/tar/testdata/file-and-dir.tar b/src/archive/tar/testdata/file-and-dir.tar
new file mode 100644 (file)
index 0000000..c18d428
Binary files /dev/null and b/src/archive/tar/testdata/file-and-dir.tar differ
index bf1b2ec426b4999b111c7f0914fb1f2d52b91728..93718b3034879fba292186c38fae7a9e7be69801 100644 (file)
Binary files a/src/archive/tar/testdata/trailing-slash.tar and b/src/archive/tar/testdata/trailing-slash.tar differ
index 97d23f80388ee86c8be72f080e8d3d53e2f983b6..d6f69314e0453708db30208fbc2a8df54ba79958 100644 (file)
@@ -71,6 +71,16 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
        }
        tw.hdr = *hdr // Shallow copy of Header
 
+       // Avoid usage of the legacy TypeRegA flag, and automatically promote
+       // it to use TypeReg or TypeDir.
+       if tw.hdr.Typeflag == TypeRegA {
+               if strings.HasSuffix(tw.hdr.Name, "/") {
+                       tw.hdr.Typeflag = TypeDir
+               } else {
+                       tw.hdr.Typeflag = TypeReg
+               }
+       }
+
        // Round ModTime and ignore AccessTime and ChangeTime unless
        // the format is explicitly chosen.
        // This ensures nominal usage of WriteHeader (without specifying the format)
index 24e8da271c220798f84f2f01ef48357c68e00219..30556d27d027f370bd88396aae497526a3a8488a 100644 (file)
@@ -461,6 +461,15 @@ func TestWriter(t *testing.T) {
                        testHeader{Header{Name: strings.Repeat("123456789/", 30)}, nil},
                        testClose{nil},
                },
+       }, {
+               // Automatically promote zero value of Typeflag depending on the name.
+               file: "testdata/file-and-dir.tar",
+               tests: []testFnc{
+                       testHeader{Header{Name: "small.txt", Size: 5}, nil},
+                       testWrite{"Kilts", 5, nil},
+                       testHeader{Header{Name: "dir/"}, nil},
+                       testClose{nil},
+               },
        }}
 
        equalError := func(x, y error) bool {
@@ -809,8 +818,8 @@ func TestValidTypeflagWithPAXHeader(t *testing.T) {
                if err != nil {
                        t.Fatalf("Failed to read header: %s", err)
                }
-               if header.Typeflag != 0 {
-                       t.Fatalf("Typeflag should've been 0, found %d", header.Typeflag)
+               if header.Typeflag != TypeReg {
+                       t.Fatalf("Typeflag should've been %d, found %d", TypeReg, header.Typeflag)
                }
        }
 }