hughesjr / rpms / golang

Forked from rpms/golang 5 years ago
Clone

Blame SOURCES/golang-1.2-archive_tar-xattr.patch

4d1d36
# HG changeset patch
4d1d36
# User Alexander Larsson <alexander.larsson@gmail.com>
4d1d36
# Date 1392282510 -39600
4d1d36
# Node ID a15f344a9efa35ef168c8feaa92a15a1cdc93db5
4d1d36
# Parent  1a32fe60e0798d82bbff6c945001c7f0ba8de5ea
4d1d36
archive/tar: support extended attributes
4d1d36
4d1d36
This adds support for archives with the SCHILY.xattr field in the
4d1d36
pax header. This is what gnu tar and star generate.
4d1d36
Fixes issue 7154.
4d1d36
4d1d36
LGTM=dsymonds
4d1d36
R=golang-codereviews, gobot, dsymonds
4d1d36
CC=golang-codereviews
4d1d36
https://codereview.appspot.com/54570043
4d1d36
4d1d36
Committer: David Symonds <dsymonds@golang.org>
4d1d36
4d1d36
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/common.go
4d1d36
--- a/src/pkg/archive/tar/common.go	Thu Feb 13 03:09:03 2014 -0500
4d1d36
+++ b/src/pkg/archive/tar/common.go	Thu Feb 13 20:08:30 2014 +1100
4d1d36
@@ -57,6 +57,7 @@
4d1d36
 	Devminor   int64     // minor number of character or block device
4d1d36
 	AccessTime time.Time // access time
4d1d36
 	ChangeTime time.Time // status change time
4d1d36
+	Xattrs     map[string]string
4d1d36
 }
4d1d36
 
4d1d36
 // File name constants from the tar spec.
4d1d36
@@ -189,6 +190,7 @@
4d1d36
 	paxSize     = "size"
4d1d36
 	paxUid      = "uid"
4d1d36
 	paxUname    = "uname"
4d1d36
+	paxXattr    = "SCHILY.xattr."
4d1d36
 	paxNone     = ""
4d1d36
 )
4d1d36
 
4d1d36
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/reader.go
4d1d36
--- a/src/pkg/archive/tar/reader.go	Thu Feb 13 03:09:03 2014 -0500
4d1d36
+++ b/src/pkg/archive/tar/reader.go	Thu Feb 13 20:08:30 2014 +1100
4d1d36
@@ -139,8 +139,14 @@
4d1d36
 				return err
4d1d36
 			}
4d1d36
 			hdr.Size = int64(size)
4d1d36
+		default:
4d1d36
+			if strings.HasPrefix(k, paxXattr) {
4d1d36
+				if hdr.Xattrs == nil {
4d1d36
+					hdr.Xattrs = make(map[string]string)
4d1d36
+				}
4d1d36
+				hdr.Xattrs[k[len(paxXattr):]] = v
4d1d36
+			}
4d1d36
 		}
4d1d36
-
4d1d36
 	}
4d1d36
 	return nil
4d1d36
 }
4d1d36
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/reader_test.go
4d1d36
--- a/src/pkg/archive/tar/reader_test.go	Thu Feb 13 03:09:03 2014 -0500
4d1d36
+++ b/src/pkg/archive/tar/reader_test.go	Thu Feb 13 20:08:30 2014 +1100
4d1d36
@@ -161,6 +161,46 @@
4d1d36
 			},
4d1d36
 		},
4d1d36
 	},
4d1d36
+	{
4d1d36
+		file: "testdata/xattrs.tar",
4d1d36
+		headers: []*Header{
4d1d36
+			{
4d1d36
+				Name:       "small.txt",
4d1d36
+				Mode:       0644,
4d1d36
+				Uid:        1000,
4d1d36
+				Gid:        10,
4d1d36
+				Size:       5,
4d1d36
+				ModTime:    time.Unix(1386065770, 448252320),
4d1d36
+				Typeflag:   '0',
4d1d36
+				Uname:      "alex",
4d1d36
+				Gname:      "wheel",
4d1d36
+				AccessTime: time.Unix(1389782991, 419875220),
4d1d36
+				ChangeTime: time.Unix(1389782956, 794414986),
4d1d36
+				Xattrs: map[string]string{
4d1d36
+					"user.key":  "value",
4d1d36
+					"user.key2": "value2",
4d1d36
+					// Interestingly, selinux encodes the terminating null inside the xattr
4d1d36
+					"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
4d1d36
+				},
4d1d36
+			},
4d1d36
+			{
4d1d36
+				Name:       "small2.txt",
4d1d36
+				Mode:       0644,
4d1d36
+				Uid:        1000,
4d1d36
+				Gid:        10,
4d1d36
+				Size:       11,
4d1d36
+				ModTime:    time.Unix(1386065770, 449252304),
4d1d36
+				Typeflag:   '0',
4d1d36
+				Uname:      "alex",
4d1d36
+				Gname:      "wheel",
4d1d36
+				AccessTime: time.Unix(1389782991, 419875220),
4d1d36
+				ChangeTime: time.Unix(1386065770, 449252304),
4d1d36
+				Xattrs: map[string]string{
4d1d36
+					"security.selinux": "unconfined_u:object_r:default_t:s0\x00",
4d1d36
+				},
4d1d36
+			},
4d1d36
+		},
4d1d36
+	},
4d1d36
 }
4d1d36
 
4d1d36
 func TestReader(t *testing.T) {
4d1d36
@@ -180,7 +220,7 @@
4d1d36
 				f.Close()
4d1d36
 				continue testLoop
4d1d36
 			}
4d1d36
-			if *hdr != *header {
4d1d36
+			if !reflect.DeepEqual(*hdr, *header) {
4d1d36
 				t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
4d1d36
 					i, j, *hdr, *header)
4d1d36
 			}
4d1d36
@@ -253,7 +293,7 @@
4d1d36
 		}
4d1d36
 
4d1d36
 		// check the header
4d1d36
-		if *hdr != *headers[nread] {
4d1d36
+		if !reflect.DeepEqual(*hdr, *headers[nread]) {
4d1d36
 			t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
4d1d36
 				*hdr, headers[nread])
4d1d36
 		}
4d1d36
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/writer.go
4d1d36
--- a/src/pkg/archive/tar/writer.go	Thu Feb 13 03:09:03 2014 -0500
4d1d36
+++ b/src/pkg/archive/tar/writer.go	Thu Feb 13 20:08:30 2014 +1100
4d1d36
@@ -236,6 +236,12 @@
4d1d36
 		return tw.err
4d1d36
 	}
4d1d36
 
4d1d36
+	if allowPax {
4d1d36
+		for k, v := range hdr.Xattrs {
4d1d36
+			paxHeaders[paxXattr+k] = v
4d1d36
+		}
4d1d36
+	}
4d1d36
+
4d1d36
 	if len(paxHeaders) > 0 {
4d1d36
 		if !allowPax {
4d1d36
 			return errInvalidHeader
4d1d36
diff -r 1a32fe60e079 -r a15f344a9efa src/pkg/archive/tar/writer_test.go
4d1d36
--- a/src/pkg/archive/tar/writer_test.go	Thu Feb 13 03:09:03 2014 -0500
4d1d36
+++ b/src/pkg/archive/tar/writer_test.go	Thu Feb 13 20:08:30 2014 +1100
4d1d36
@@ -10,6 +10,7 @@
4d1d36
 	"io"
4d1d36
 	"io/ioutil"
4d1d36
 	"os"
4d1d36
+	"reflect"
4d1d36
 	"strings"
4d1d36
 	"testing"
4d1d36
 	"testing/iotest"
4d1d36
@@ -338,6 +339,45 @@
4d1d36
 	}
4d1d36
 }
4d1d36
 
4d1d36
+func TestPaxXattrs(t *testing.T) {
4d1d36
+	xattrs := map[string]string{
4d1d36
+		"user.key": "value",
4d1d36
+	}
4d1d36
+
4d1d36
+	// Create an archive with an xattr
4d1d36
+	fileinfo, err := os.Stat("testdata/small.txt")
4d1d36
+	if err != nil {
4d1d36
+		t.Fatal(err)
4d1d36
+	}
4d1d36
+	hdr, err := FileInfoHeader(fileinfo, "")
4d1d36
+	if err != nil {
4d1d36
+		t.Fatalf("os.Stat: %v", err)
4d1d36
+	}
4d1d36
+	contents := "Kilts"
4d1d36
+	hdr.Xattrs = xattrs
4d1d36
+	var buf bytes.Buffer
4d1d36
+	writer := NewWriter(&buf)
4d1d36
+	if err := writer.WriteHeader(hdr); err != nil {
4d1d36
+		t.Fatal(err)
4d1d36
+	}
4d1d36
+	if _, err = writer.Write([]byte(contents)); err != nil {
4d1d36
+		t.Fatal(err)
4d1d36
+	}
4d1d36
+	if err := writer.Close(); err != nil {
4d1d36
+		t.Fatal(err)
4d1d36
+	}
4d1d36
+	// Test that we can get the xattrs back out of the archive.
4d1d36
+	reader := NewReader(&buf)
4d1d36
+	hdr, err = reader.Next()
4d1d36
+	if err != nil {
4d1d36
+		t.Fatal(err)
4d1d36
+	}
4d1d36
+	if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
4d1d36
+		t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
4d1d36
+			hdr.Xattrs, xattrs)
4d1d36
+	}
4d1d36
+}
4d1d36
+
4d1d36
 func TestPAXHeader(t *testing.T) {
4d1d36
 	medName := strings.Repeat("CD", 50)
4d1d36
 	longName := strings.Repeat("AB", 100)